Updating my smart On Air e-ink sign – Six Colors


Hi, I’m the problem, it’s me.

Some people can leave well enough alone, but not us nerds! You may recall a few years ago, I detailed my creation of a smart On Air sign using a color e-ink display.

While I feel that project was largely a success, one major obstacle has kept it from being as useful as I’d hoped: the long battery life.

What? How is long battery life a problem, I can hear you asking. The issue is that the battery life is just long enough that I forget to recharge it until I happen to check and see that it’s dead, invariably right before I start recording a podcast.

Now, I could just set a reminder to go off every few days to plug in the sign and recharge it, but simple solutions aren’t how we ended up here in the first place, are they? Time for some OverEngineering™!

The idea that came to me one day was sheer elegance in its simplicity: what if I built a system that let me know what the current battery level was so that I could charge it when it was getting low but before it had died?

Yep: here we go again.

Easy as Python

As long as I was about to embark upon revising my code, I figured I might as well go whole hog. Back when I first set up my Inkplate e-ink display, I opted to use the standard firmware and write my code in the Arduino IDE. As I noted at the time, my expertise with the language wasn’t high, but I figured I could muddle through with some help.

However, I knew that the other available option was to flash the board with the MicroPython firmware and I have spent more time working with Python in recent months, so it seemed like a good opportunity to take a crack at that as well. Fortunately, the instructions for installing the firmware on the Inkplate are fairly straightforward, though I did have to do the usual amount of tweaking and looking up details to get it working.

The switch to MicroPython also meant I would be relying on command line tools instead of Arduino’s GUI IDE, but as someone who’s spent a fair amount of his life in Terminal, this wasn’t really a drawback.

The next step was translating my existing code to run in Python. And while I probably could have done so myself, checking references as I went like I was moving text from English to French, it struck me that this is exactly the kind of task where an AI actually excels.

Enter ChatGPT. I fed it my Arduino script and asked it to convert it to Python, making sure to specify I was using MicroPython. That’s important because, though MicroPython is Python, it is more limited in the availability of modules and has some of its own particular quirks. I was even able to point the AI directly to Inkplate’s MicroPython GitHub repository so it could see exactly what it was working with. And, of course, I made sure to read it all through to make sure everything seemed correct. But my code was pretty simple, so it was quick work to confirm that it did what I wanted; I was even able to remove a few little quirks that had been required by the strictures of the Arduino code.

The one big challenge I had to duplicate my existing functionality was in encoding of the images. As I mentioned in my previous piece, Inkplate provided a handy online tool to convert bitmap images to bytecode so the display could render them, but it turns out that Python’s formatting of bytecode wasn’t close enough that I could easily just reuse the existing versions. Instead, I spent quite some time working with ChatGPT to try and create a script that would convert bitmaps into compatible images—this is one of those places where I quickly ran up against my own knowledge and limitations.

Much of that happened later in the process, but the important point was that I basically had the display up and running on MicroPython and doing everything it did before. Now for the fun part: adding new functionality.

Battery of tests

My idea to monitor battery life meant having the charge level available online somewhere, which in turn required the board to send that information periodically. Good news: it’s basic functionality already involved waking up every five minutes to check if it needed to change the graphic; I figured I could just piggyback on that cycle and have it send out the battery level when finished.

I store the battery info in a .json file on my server.

The first step, though, was figuring out the battery level, which is itself more art than science as the Inkplate doesn’t calculate its own battery percentage. But thanks to the Inkplate code examples I knew that I could access the current level of battery voltage, and based on checking the voltage both when the display was dead as well as after it had been charging long enough to presumably be full, I could come up with a very rough calculation of its current percentage—enough to handle my situation of simply needing to know when it was getting low enough that I should charge it.

Once I had a way to calculate the battery level on device, I had to send it to my server. For this I turned to a different technology entirely: PHP. As a language that’s designed to interact with a web server, this turned out to be the best option for collecting the information sent by the Inkplate. I had it send a small payload to my server with the current voltage, calculated percentage, and timestamp as a JSON file.

Now I just had to read it.

Swiftly now

If I needed to display some arbitrary data in my menu bar, SwiftBar was, of course, my first stop. I ran into a challenge, though, when I tried to use Python to build a plugin for it: due to macOS’s handling of Python versions, it’s a pain to use anything that requires modules or to use virtual environments. I debated using PHP for this as well, but then stumbled across a simpler solution: SwiftBar recently added support for running plugins created in Shortcuts.

This actually turned out to be ideal for my solution. I wrote a simple Shortcut that grabbed the JSON file from my server and piped it out. I even went ahead and used SwiftBar’s support for SF Symbols to add some a battery icon, complete with color coding: a full green battery for 50% and above, a yellow partially full battery for below that, and a red empty battery when it dropped beneath 10%.

I also added the calculated percentage and timestamp in the dropdown part of the plugin so I could get more information if I needed it.

It’s all in the timing

As long as I was making changes, I dabbled with some other possible enhancements.

The biggest weakness of my On Air sign is that it only refreshes every five minutes. Ideally, I’d like it to be instant, which would require some way to essentially ping it when to update. Unfortunately, my attempts along this line have remained fruitless.

While it is possible to connect wirelessly to the Inkplate and issue commands via a feature called webrepl, there are two issues here: one, the Wi-Fi support in the ESP32 chip at the heart of the Inkplate can be finicky, taking a long time to connect or occasionally not connecting at all. Second, and more importantly, there appears to be no way to put the device to sleep and have it wake via the network, which means that it would have to be on all the time, drastically reducing the overall battery life.

I also experimented with having it sleep for just a minute between checks, but that proved so short an interval as to still take a big toll on the battery. It then occurred to me that I could have it sleep longer at times when I knew I wouldn’t need it—say, overnight.

Unfortunately, determining what “overnight” is turns out to be a fraught pursuit. The Inkplate itself does not innately know the current time, so I have to use the ntptime package baked into the MicroPython firmware to sync with a network time server.

That’s not without its own problems. For one thing, the package’s functionality is basic. Most critically, it has no way to account for daylight saving time which means, yes, I had to write my own function for figuring out whether it’s DST or not, since the difference does impact when it’s “overnight.”

Moreover, the default ntptime package can fail with a timeout that kills the entire running program. There is the option to drop in a replacement package which allows for more graceful failures, but I was unable to get that package to work with the NTP server that I deployed on my Synology.

So, for the moment, I’ve stuck with using the built-in ntptime functionality to add in long sleeps overnight in addition to checking every five minutes. I also updated my SwiftBar plugin to throw an alert if it’s been more than 10 minutes since the battery status has been updated, which will help me track how often timeout errors become a problem. If it ends up recurring too often, I can always revert back to just the five minute check or figure out how to use that replacement module.

The battery life in this mode continues to be outstanding, and now that I have the information in the menu bar of my Mac, I can more easily track when I need to plug in the sign to charge it. While it may be a little ways off from my ideal version of this project, it’s taken a small step forward that at least makes it more usable.

[Dan Moren is the East Coast Bureau Chief of Six Colors. You can find him on Mastodon at @dmoren@zeppelin.flights or reach him by email at dan@sixcolors.com. His latest novel, the sci-fi spy thriller The Armageddon Protocol, is out now.]

If you appreciate articles like this one, support us by becoming a Six Colors subscriber. Subscribers get access to an exclusive podcast, members-only stories, and a special community.

We will be happy to hear your thoughts

Leave a reply

Som2ny Network
Logo
Compare items
  • Total (0)
Compare
0