MoreRSS

site iconSix ColorsModify

Six Colors provides daily coverage of Apple, other technology companies, and the intersection of technology and culture.
Please copy the RSS to your reader, or quickly subscribe to:

Inoreader Feedly Follow Feedbin Local Reader

Rss preview of Blog of Six Colors

更新我的 smart On Air 电子墨水标牌

2025-04-02 03:23:24

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.1 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.2

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.3

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.4

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.”5

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.6

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.


  1. No, I’m not listening to you, but I can’t believe you would say that, Greg. 
  2. Arduino’s IDE is also slow and clunky, so no real loss there. 
  3. I got very close to having to reach out to our pal Dr. Drang, but ended up figuring it out before I threw myself on his mercy. 
  4. My initial—and I thought brilliant—idea was to have the code simply grab the time from my webserver when it requested the details of the “on air” status. After all, it’s already making the request and the server is on my local time. Alas, the urequest module that’s included in the firmware only retrieves a limited number of headers from the server, date not among them. 
  5. Would it maybe have been simpler to ignore DST and have it sleep for a shorter time, assuming that it would go to sleep at, say, 1AM, no matter what? Sure. But it would also be simpler to close my door when I’m podcasting and have that tell people if I’m on air or not. I’m clearly not here for simple solutions. 
  6. Even using macOS’s built in sntp tool to query that server yielded a lot of errors including timeouts and “Server not synchronized”, suggesting to me that Synology’s implementation of ntp may itself be unreliable. 

我进入 Netflix 广告层的不成功之旅

2025-04-02 00:10:33

So, last month, in a fit of pique over the continual increases in the cost of a Netflix plan, I decided to cancel Netflix.

This is a big deal because I’ve been a Netflix subscriber since the very beginning—back when it was all DVDs and no streaming. I checked in with my kids because I was worried Netflix was more popular with the youths than with people like me. But even my kids didn’t care and thought there wasn’t much to watch on Netflix.

So, I canceled it, figuring I’d pick it back up again on a case-by-case basis. “When there’s something to watch, I’ll resubscribe for a month, watch what I want, and then cancel again,” I thought.

This month, though, I already had some reasons to watch. Everybody’s talking about “Adolescence,” and I hadn’t seen the newest iteration of John Mulaney’s live talk show—which means I wasn’t able to talk about it on Downstream last week, which felt like a mistake.

(It turns out that even when there’s nothing you think you want to watch on Netflix, there’s still some stuff you sort of want to watch on Netflix.)

So I figured I’d resubscribe for the month—but I’d stick it to Netflix by opting for the ad plan, which is only $8 a month. Netflix insists that the ads on that plan are “short and seamless” and “won’t interrupt the action”—and it really pushes that ad plan hard because it makes a lot of money from it. (The price hikes for the ad-free plans are largely because the ad plan has such a high average revenue per user that Netflix has needed to jack up the price of the ad-free plans so that they earn similar amounts of money per user.)

netflix ad tout

My plan did not survive even the briefest of contact with the enemy.

The first thing my wife and I watched on our reactivated Netflix was episode one of “Adolescence,” a tense, serious, dark drama about children and crime. Each episode is one continuous shot—a technical marvel. But the flow was broken numerous times by bright, shiny, noisy ads, disrupting the mood repeatedly with 30 to 45-second interruptions.

I feel sympathy for whomever Netflix is paying to tag content for the best places to insert ads. There are no clear act breaks in “Adolescence,” and the fact that it’s one continuous shot means that literally any interruption is going to be incredibly disruptive to the content of the show. It was never intended to be shown with advertising inserted mid-stream.

Netflix programmed four separate ad breaks.

Netflix says ads won't interrupt the action.
Oh yeah?

The truth is, outside of live sports, I haven’t really watched a commercial in 25 years. Back in 2000, I got my first TiVo, and since then, ad skipping has been the norm for me. I’ve been fast-forwarding through ads or, in some cases, clicking a button to skip ads automatically ever since.

So, to sit there in 2025, watching a countdown timer tick down during a loud, colorful ad, all while in the middle of a grim, dark, contemplative show… was unbearable. After 25 years of mostly ad-free viewing, I am irretrievably broken. I just couldn’t take it.

While the ads played on, I began creating a thought experiment: There’s a $10 difference between the ad and ad-free plans. If Mr. Netflix (he wears a top hat) came to my house and said, “Jason, I’ve got a great deal for you. I’m going to pay you $120 a year, and all you have to do is watch ads while you watch Netflix,” what would I do? When I started thinking about it, I thought it might be an interesting intellectual question. What would I accept in exchange for having Mean Mr. Netflix beam ads into every show I watch?

It turns out that whatever my price is, it’s a whole lot more than $120 a year. The next day, I upgraded back to the $18 ad-free plan.

(播客)升级 557:我要跑四分钟一英里

2025-04-01 00:20:01

Dan Moren joins Jason to discuss folding iPhones, long individual takes in TV shows, new OS features, and what WWDC 2025 might really bring.

Go to the podcast page.

(赞助商)魔术套索广告块: 难以置信的私密和安全的 Safari 浏览器

2025-04-01 00:00:24

Online privacy isn’t just something you should be hoping for – it’s something you should expect. You should ensure your browsing history stays private and is not harvested by ad networks.

By blocking ad trackers, Magic Lasso Adblock stops you being followed by ads around the web.

As an efficient, high performance and native Safari ad blocker, Magic Lasso blocks all intrusive ads, trackers and annoyances on your iPhone, iPad and Mac. And it’s been designed from the ground up to protect your privacy.

Users rely on Magic Lasso Adblock to:

With over 5,000 five star reviews; it’s simply the best ad blocker for your iPhone, iPad and Mac.

And unlike some other ad blockers, Magic Lasso Adblock respects your privacy, doesn’t accept payment from advertisers and is 100% supported by its community of users.

So, join over 350,000 users and download Magic Lasso Adblock from the App Store, Mac App Store or via the Magic Lasso website.

捷径正陷入 "自动化鸿沟" ↦

2025-03-29 04:46:09

John Voorhees, writing on Club MacStories (subscription required):

Nearly three years ago, I wrote AppleScript: Shortcuts Bridge or Crutch?, questioning whether accessing AppleScript via Shortcuts on the Mac was a feature to be celebrated or a red flag, fearing that Apple would use the integration to postpone or never release many of the system-level actions that were missing from Shortcuts’ debut on the Mac.

As I put it then, “if Shortcuts is to become the default way to automate tasks on the Mac, there needs to be steady, yearly progress to make macOS and its default system apps as Shortcuts-friendly as possible. There’s a role for AppleScript to play in Shortcuts that won’t go away anytime soon, but not as a way to fill the potholes left by missing Shortcuts actions.”

Shortcuts’ progress on the Mac has been anything but steady and yearly.

A few days ago, while writing my Podcast Notes update, I realized that I had (inadvertently?) created an automation that begins with a Stream Deck keypress that executes a Keyboard Maestro macro that kicks off a JavaScript script in Audio Hijack that runs an AppleScript applet that executes a Shortcuts shortcut. In recent days I’ve also edited shortcuts that run Python and AppleScript scripts, including some where the shortcut is really nothing more than a Mac UI-friendly wrapper around a bare script, much in the same way you can use Automator as a simple wrapper around AppleScript scripts.

That all these things are possible on the Mac is amazing, and it’s a testament to how flexible and powerful the Mac can be. But it also says something quite profound about how little progress Apple has made with Shortcuts on the Mac (or in general) in the last few years. (And of course, all these workarounds fail on iOS entirely.)

Maybe the drive toward App Intents will help make Shortcuts more powerful and less reliant on tools like AppleScript, Keyboard Maestro, and the rest. But even that isn’t enough, since the Shortcuts app is way too rickety and limited. Just the other day, Dan Moren said to me, “I was working on a shortcut and I needed an if-else-if statement,” and we both began laughing because conditionals are just so bad in Shortcuts.

Apple gave itself a lot of leeway by declaring that Shortcuts was the “beginning of a years-long process” to make Shortcuts the “future of automation on the Mac.” But that was almost four years ago. There’s not a lot of leeway left for me to give.

Go to the linked site.

Read on Six Colors.

(赞助商)FlashFinder:首款与苹果 "找回我的钱包 "兼容的钥匙扣手电筒

2025-03-29 00:00:51

My thanks to Footnote Accessories and FlashFinder for sponsoring Six Colors this week.

FlashFinder is the first keychain flashlight that supports Find My. Wherever you put it—your keychain, your backpack, whatever—you’ll be able to find it later. And the flashlight itself is six times brighter than the flash on your phone, so you’ll always be able to find your way.

It’s discreet, USB-C rechargeable, and it’s a multitasker. I love a multitasker.

Learn more and purchase now at footnoteaccessories.com.