Wednesday, November 29, 2023

Return of the Christmas Tree Project (ch 5): More LEDs!

It's been two years since I started my Christmas tree project. Last year, I didn't work on the project at all, but this year, we're back in full force. And I bought more led lights to put in my tree. In fact, we'll be doing five times as many LEDs as before!

Because it had been so long and because I had moved since I worked on it last, the first thing was to get the project up and running again. And the first thing to work on was my Raspberry Pi. Unfortunately, the sd card in the Pi that I was using before had gotten corrupted.

I spent quite a bit of time looking for my card reader, but all it did was confirm that the sd card did not work at all. Luckily having found the card reader also made it very easy to get a new sd card ready. The next thing was to find the code. It wasn't on my desktop, so it had to be on my private git server. However, that server failed a while ago, so I had to track down the storage I used in that server. This took some effort, but I found it eventually. And then it turned out that the code wasn't on there either...

The code had apparently only been on the sd card, so I would have to write it again. The amount and complexity of the code was such that that was feasible enough, but it was still a bummer. I took a look at the code from the project that had been the inspiration for this one to look at what libraries had been used. Looking at that repository made me remember that I had shared my own code with the world as well. And that was where the code was! You see, I only kept my private projects on my private git server. My public projects were all on GitHub. And indeed, the lost code was right there on GitHub.

It seems that I did have some code that was only on the sd card. In particular, I seem to be missing the three dimensional effects that I wrote. One was a rainbow effect and that should be easy enough to recreate, especially because the one effect that I still have does have much of the general structure I'd want to use. The other effect was an effect that never really worked that well, and isn't really that much of a loss.

With the pi running again and the code being back in my possession, I could get to working on the thing again. I was unsure if I would be able to run all the LEDs from one power source, so that was the first thing to test. I connected all my new LEDs and set them to white light at 25% brightness.

Several interpretations of white...

To be fair, all lights turned on and all of them being white is the worst case. But, 25% brightness is roughly 75% below the worst case. And the results were pretty bad. However, this looked like the power adapter was handling it just fine. Instead, it looked like voltage drop to me, which is not related to the adapter but to the lights and the wires between them.

So, I rigged up a quick test and saw that indeed, things looked a lot better if I connected the power source to each string of lights separately, even if it was still the same single adapter. The light strings do have extra wires that help you do this, but the bare wires aren't too easy to use. So, I decided to take some of my Dupont cables, cut them in half and splice the halves onto those wires to make them much easier to use. Using these tools and this skill set was a lot of fun, which surprised me because I had forgotten how much I liked doing this.

A bit of solder
Some tape
And some more tape

I added a breadboard to map from one input coming from my micro-usb breakout boar to multiple wires going to the different strings. This actually made for a surprisingly good setup.

Now, that's what I'd call white

I also worked a bit on my code. I took some of my old one-dimensional code and cleaned it up. I also wrote a simple rainbow effect. It's not as good as an effect that includes a tree and coordinates of the LEDs, of course, but it's still quite nice. And I did use some of the lessons I remembered from making the rainbow effect for in the tree two years ago.

The next step will be to try to cram all these LEDs into my small tree. (I'm at half the number of LEDs Matt Parker used, but my tree is also a lot smaller.) And then I can start using the most essential and complex code I wrote last year to map all the LEDs. I'm happy I won't have to rewrite that code!

Saturday, September 30, 2023

Unopiniated variable binding

I'm a bit crazy. I like vanilla front-end work. I just like it when you do not need a compile step and what you've written is what is executed. I've always been like that, even when it made a lot less sense than it does right now, like in the times of Internet Explorer and browsers having lots of incompatibilities and some not supporting standards well at all.

In the light of using vanilla javascript, seeing the technology making progress is really nice. Sometimes, that means that you get shiny new tools built into the browser. Other times it means that you no longer need a library to do what you were already doing. I loved learning about document.querySelector(), as it covered one of the two things I used jquery for. The other thing I used it for was later covered by the fetch api. Learning about css variables was far more exciting to me than learning about the css preprocessors of the time.

When I do use a framework (for personal projects), I like using something that isn't very opinionated. The big front-end frameworks generally tell you how to set up your whole project. I prefer something that I can introduce in that one place if I want. And if the project grows big enough, I will refactor it to have a better structure. I probably end up with something similar to what the frameworks prescribe. Or I might end up with something slightly better or a lot worse. In any case, it'll probably be more tailored to my project.

In the past few years, my goto front-end framework has been Knockout.js. When I was first introduced to it at a previous job, I thought it was just another AngularJS with a slightly different syntax, but in the years after that I started appreciating it for how unopinionated it was. There was one major part of its usage that I didn't like, but adding knockout-es5 solved that. The es5 library doesn't work well with knockout's component functionality, though, which is essential once you start refactoring. So I wrote a script that worked around that. The script was a quintessential hack: it does some pretty ugly manipulation and leaves things in a state where it usually works. Together, all of these basically gave me what I wanted: unopinionated variable binding.

The time to let go of knockout has been steadily approaching for a while, though. There really hasn't been much development of the project for years. The project's website has had trouble several times recently. There is tko.js which aims to be the next version of knockout, but development seems stalled in an alpha state and it doesn't actually address most of what I want to see changed. I just don't really see a path towards not needing the knockout-es5 or my own script on top of it, and both of those feel more like temporary fixes than true solutions. For projects that I expect to live for a long time, it just doesn't seem to be sustainable enough to keep using it.

Recently, I have been working on a very old project. This project is built around the google maps API. Because of that, it doesn't actually do a lot of html manipulation. So, even when redoing most of the project six years ago or so, I just did that little bit of manipulation in vanilla javascript. But now I'm adding features, and some of those do require a lot more manipulation.

That sent me into a bit of a panic. Not using a framework was starting to weigh down the project. Using knockout doesn't feel like a sustainable option, but other frameworks are much more opinionated than I like. Even the ones that are minimal and/or proclaim not to be opinionated require you to work in components and thus don't just drop right into your project to do that one task you need from them. I felt like I was at a crossroad with none of the paths leading where I wanted to go.

I think I have a solution, though. I started looking at WebComponents recently. It's a collection of three javascript APIs that are mostly used by frameworks. That's because using them without one is complicated and doesn't really manage to compete with using a framework. I have been using two of those APIs to prototype what is basically my own framework. It provides the unopinionated variable binding that I was looking for and not much more than that.

It's only some three hundred lines of code, but it's able to bind variables to text, attributes and events, and it's able to repeat parts of your html or remove them. About a third of the code is dedicated to a solution for tables, as the default looping solution clashed with the way those are special in html. And because it is built on top of WebComponents, the system to upgrade to when refactoring is built right in.

There's definitely more to be done. When you use the prototype incorrectly, it doesn't tell you what you need to change. There will probably also end up being more things that the library needs to do to. But I do believe this pretty small prototype already covers most of what I want.

I compared total byte size of my prototype to Alpine.js (just because it came up in a search for small frameworks) and the byte sizes are about the same. That's more impressive than it sounds, because we're comparing a minified and gzipped version of Alpine with the plain sources of my prototype. While size comparisons aren't actually that useful, size does matter. It matters in how sustainable maintaining the code base is. It's also a part of how close it is to vanilla javascript, which is a part of how it stays unopinionated and how it can interoperate with existing codebases and other frameworks. For neither of those it's the whole story, but it is an important part of it.

I think I'll be using this for the time being. And I'm starting to think that a version of this may end up being my tool of choice for a long time to come...