whateverthing.com

Vax Bean Counter

It's been over a year since the beginning of the COVID-19 global pandemic. I've been doing my part - staying home, socially isolating, etc. Of course, since I've been working remotely for four years now, it's almost as if nothing has changed. About the only changes for me are that I wash my hands more and wear a mask the rare times I'm out and about.

I've noticed that the pandemic has resulted in kind of an onslaught of data. Last year, I was watching the data and thinking to myself that I could probably harness it in some way and tie it into Twilio to create some kind of SMS-based service. I was wondering if there might be some way I could "do my part" in that sense.

I felt there wasn't. I didn't want to dwell on the bad numbers. I didn't want to bolster the already-overwhelming senses of dread and fear.

However, now there's a new source of data. Data that is uplifting, and encouraging:

Vaccinations.

So with that in mind, I've created a project that I'm calling "Vax Bean Counter". It sends text messages when vaccination information for British Columbia is updated. These updates usually happen on weekday afternoons, and my text message tries to show the progress and deliver a small piece of hope that this long international nightmare may be in its waning days.

Try It Out

If you want to try it out, and your cell number has a British Columbia area code (e.g., 250, 604, or 778), then you can text "start" (without the quotes) to ###-###-####. (Number redacted due to retiring the service)

You'll eventually begin receiving a message that looks like this:

Mar 26

Total Given: 637,856 (+27,185)
Last Update Delta: -852

Doses:
1st: 550,623 (+27,164)
2nd: 87,233 (+21)

Total Supplied: 810,220 (+17,600)

Delta? Like, the city?

One of the line items in the text message is a bit unintuitive. I'd like to be more descriptive, but text messages have a pretty strict character limit. Anyway, "Last Update Delta" is intended to show the difference between the current message's number of new vaccinations administered compared to the previous report's new vaccinations administered. It's trying to show if the vaccination rate is speeding up or slowing down.

The technical part of the blog post

Given that this is a technology blog, it might be a good idea to summarize what I've built and how it runs.

The Breakdown

VaxBeanCounter is a custom PHP 8.0 command-line project that uses PHP League's dependency injection container, the Symfony Console Component, the Twilio SDK, Doctrine Database Abstraction Layer, and a few other packages.

It consists of multiple "commands" that are tied together in a Bash shell script that runs in a loop.

Every half hour, it reaches out. It checks for updated vaccination data. If new info is found, it compares it to the most recent "old" info and checks for differences. If differences are found, it logs them as a new update and schedules a text message to be sent to all registered recipients.

Between the half hour marks, the loop in the Bash shell script monitors the SMS API to look for new incoming text messages. If it detects any new messages, it responds and reacts accordingly (enrolling, disenrolling, sending help messages, sending debug messages, ignoring, etc). It checks once every 60 seconds for these new messages.

Database and Network Considerations

These timings ("every half hour", "every 60 seconds") might seem odd, but there's a purpose behind it. Two, actually.

Firstly, instead of using MySQL or some other RDBMS, I'm using something super simple as the database: sqlite3. Because I'm using Doctrine DBAL, I'm sure I could switch to MySQL or something similar when the time comes, but for now sqlite is working nicely. The one drawback is that parallel writes are not going to make it a happy camper, as far as I know, so it is best to only have one script accessing the database at any one time. This is why the fetching of data, sending of notifications, and monitoring of SMS messages is all handled on those specific timing schedules in that very specific loop.

Secondly, I'm not exactly using Twilio in a recommended way. This whole project is running on a Raspberry Pi, behind a firewall. Twilio is designed to use Webhooks to handle communication, but I did not want to open up the firewall and risk exposing experimental PHP code to the dangers of the wider internet. So it sits in my basement, checking every 60 seconds for new messages to be processed. Slower, due to not using webhooks, but safer.

PHP 8.0

One other quirk of the script is that I wanted to write it for PHP 8, the latest version, but my particular Raspberry Pi's OS is so out of date that it only had access to PHP 7.0, which had already been dead for a year before the pandemic started.

I had to compile PHP from the source code.

It was a bit frustrating to get all the flags figured out, and the result I ended up with is still a bit inflexible about INI file locations and such. All things considered, I'm very happy that I was able to get it working. Much safer than trying an in-place OS upgrade, which has killed at least one of my Raspberry Pi SD cards in the past.

According to my command history, the final list of flags I ended up with was:

./configure --with-readline --enable-bcmath --enable-simplexml \
    --enable-pdo --enable-session --enable-xml --enable-xmlreader \
    --enable-xmlwriter --with-libxml --with-openssl --enable-mbstring \
    --with-curl

There is much room for improvement to create a "robust" installation, but for this experiment it has been working fine.

Phone Numbers

One other interesting tidbit is that Twilio prefers international-compatible E.164 phone numbers (+15555555555) instead of traditional North American numbers (1-555-555-5555).

To address this, I wrote a PhoneNumber class that accepts several different North American phone number formats and normalizes them to the International spec. I'm sure existing libraries could handle this, but it was fun to come up with the regular expressions and test cases to confirm it was working.

The Future of the Project

I've been trying to avoid making future plans for the project. I'd like to say "I'll shut it down when the pandemic is over", but indications are that Covid might become as seasonal and inescapable as Influenza. And that really sucks. It feels like we, as a global society, failed to defend ourselves against something that was completely avoidable.

All of those Hollywood movies about outbreaks came true, right down to the "ignoring the scientists" part. And the main reasons seem to be a mixture of science denial, leadership vacuums, and downright selfishness. And the fact that it takes so long to incubate, and is so contagious during that timeframe, that people don't understand the danger they are in, or are causing.

This does not bode well for the fight against climate change, which has an even broader timescale; similarly, people don't seem able to grasp the severity.

But for now, vaccinations are rolling out. They'll protect us from the main virus as well as a number of variants.

That's good news.

A Minor Update

Now that the initial wave of vaccinations is over and we're into Booster territory, and the Omicron variant has sent everything to hell in a handbasket, I've retired this service. An ignominous end, where I had once hoped for a celebratory one.

One day we'll wake up, we'll go outside, and without even realizing at first we'll be on the other side of this. And we'll look back and we'll be thankful for some of the things that happened during this time. Such as novel vaccines against things that have plagued us for millennia (literally). And, I hope, a clear idea of what needs to be improved in our society - coupled with the grim determination to actually get it the fuck done.

Published: March 27, 2021

Categories: ideas

Tags: dev, development, coding, php, twilio, covid19, projects, command-line