To start with, I’ll explain my situation. I’ve got a bad back. A really bad back. I’ve had three operations on it now, back when I was a teenager, then a revision in 2006, and then a second revision about three weeks ago. What I’ve ended up with is a fusion of ten of my vertebrae and a lot of metalwork. Going into this latest surgery, I knew I was going to be recovering for a long time: up to a year. A lot of that would be spent in bed. Even without the surgery, the chronic back pain from which I’ve suffered has given me a lot to deal with, so having my environment under control is important to me.
So, this is a perfect opportunity for hardware hacking.
First up, I’ve built my own bedroom clock, the Pi-Clock-O-Matic 2000™. I have a thing for catchy names. This is a Raspberry Pi with a screen, covered in red transparent acrylic, so as not to dazzle me during the night. It displays the time (duh), date, indoor and outdoor temperature, humidity, barometric pressure and change in pressure.
These sensor readings are to help me pre-empt migraines, as I’ve found (through extensive manual journalling and data logging of various suspected factors) that the change in barometric pressure is a trigger: if there’s a sudden change in pressure, my head starts going woolly and it’s time to reach for the drugs. The graph shows the last three hours of barometric pressure data.
Right now, the screen's also showing the number of days since my surgery (+24 days); my current estimated level of Oramorph — oral morphine syrup — in my system; and the time since I last took my meds. Once this passes six hours, it inverts video to remind me to take my pills.
This clock is actually one of two in my bedroom, so I can see it no matter which side I’m lying on. To achieve this, I’ve changed most of the system over to a client/server mechanism based on MQTT. The client software is written in Python using pygame, as it seemed an excellent way of controlling the Pi official screen in console mode.
The clocks also act as hosts for several USB (and wireless) keypads for controlling the entire system:
These keypads issue MQTT messages, which are picked up elsewhere for transformation and processing.
Originally, these converted the keystrokes directly into concrete commands, to control various things. Over time, I’ve moved it to a Node-RED based system; the keypads just publish raw keycodes to MQTT, and a flow in Node-RED interprets them. This allows for simpler, centralised, on-the-fly configuration of the intents without having to restart loads of scripts.
The actions break down into several categories:
- Lights and fans, controlled via mains relay switches over 433MHz RF.
- The venetian blind slat tilt, controlled via a servo motor and a Python script running on an Onion Omega, reading MQTT directly via WiFi. This device also supplies the indoor temperature, humidity and pressure data from a BME280 device on I2C.
- The roller blind control for black-out, controlled via a DC motor and a 3D-printed bracket, running on a NodeMCU board programmed with Arduino, receiving serial commands over USB, from a Python script acting as an MQTT-to-serial proxy, running on one of the Pi clocks.
- Time recording for meds: one button to signal an Oramorph dose, and one button to reset the scheduled medication timer.
The Node-RED flow converts raw keycodes from MQTT messages into more concrete actions, sent back out as MQTT messages.
The lights and fans are controlled remotely by the Remote-Switch-Network-Izer 2000™: a NodeMCU programmed with Arduino that listens for
rf action MQTT messages and sends out the appropriate control codes using a cheap 433MHz transmitter. These codes are picked up by consumer-grade remote sockets around the room to switch lights and fans on and off.
These sockets are the kind you buy for £20 with a flimsy remote control, rather than the more substantial (and much more expensive) WiFi or Bluetooth-enabled WeMo or SmartThings.
It’s not ideal, as the switches have no real concept of state; and because it’s possible (and not uncommon) for a command to get lost in transit, keeping track of state is not reliable. If I’d bought WeMo sockets (for example) I could query them for state. The main ceiling light is even worse: as I replaced the mechanical wall switch with an RF-controlled remote wall switch that does not accept on/off but only toggle, there isn’t even a good way to reset back to a known value.
However, as my keypads are interactive and only offer toggle capability, it doesn’t matter that much: if pressing the button doesn’t work, press it again…
The medication tracking has an interesting implementation. The medication last dose tracker is fairly straightforward; when the button is pressed, an MQTT message is published with the current epoch timestamp, with
retain set. That way, if/when the clocks are rebooted, they get the last known value.
The Oramorph tracker’s a bit smarter: Node-RED keeps track of the current estimated quantity in my body, and then regularly decreases it using exponential decay based on the average metabolic half-life of morphine in the body (roughly 2.5 hours), publishing the new value and timestamp with
retain set. If a dose is signalled (typically 10mg per press) it’ll add 10 to the value and update the timestamp. Then, on the next update, Node-RED can calculate the difference in timestamps between the last retained value and “now”, and perform an exponential decay calculation on it. It’s all very rough, but it does give me an idea of when I’m overdoing it on the morphine, or whether it’s reasonable to take another dose if I’m in pain.
halfLife = 2.5 * 60 * 60;
dt = t - ot;
q = oq * Math.exp(-dt * Math.LN2 / halfLife);
The venetian and roller blinds really deserve separate posts, which I’ll consider later. The venetian blind was originally going to have a full lift motor, but I never got around to it, partly because I never really needed to lift the blind. Instead, I hacked the cheap venetian blind’s tilt function to take a high-torque servo motor, by way of a 3D-printed herringbone gear mechanism.
- Link Amazon Echo Dot (Alexa) for voice command. I’ve managed to get a custom skill to pass an MQTT message from AWS Lambda to the MQTT broker on AWS IoT, which my home Node-RED subscribes to. This should be more secure than opening up an HTTP endpoint on my home network for Amazon to hit directly. Getting this rigged up has been a major chore, as Amazon AWS loves to overcomplicate everything. It should be straightforward to use the Smart Home API thing to give a voice interface to the whole Node-RED / MQTT flows I have set up.
UPDATE: Finally got it working… “Alexa, Turn On Lights”. They really don’t make it easy, though.
- Position reckoning for the roller blind: it has a rotary encoder fitted, but I still haven’t got the NodeMCU tracking it precisely, even using interrupts. The rotary encoder is the main reason I went for Arduino rather than one of the Espruino (eg. Puck.js) or MicroPython, or even micro:bit boards I have available; Arduino gives me a low-level interrupt that should track rotary encoders well enough. Even so, it seems to be dropping a few clicks occasionally. This is all so I can have a single button click for open/closed/halfway rather than having to hold the button down.
- Integration with the new tilting/profiling bed I commissioned from a local engineer: in addition to the profiling slats which allow me to raise the head and/or foot end of the mattress, this new bed frame has integrated linear actuator rams to allow the bed to tilt roughly 15º to the left or right, to help me roll over when my back is bad. Unfortunately, the project has run over for various reasons, so it’s not really ready to use yet.
- Reliability. I’m still having trouble with the ESP8266-based boards and the ropey Python code on the Pi Clocks successfully reconnecting to the MQTT broker. In addition, the broker is running on a FreeNAS jail on my home fileserver, whereas the Node-RED flows are currently on a Gigabyte Brix mini-PC running Ubuntu. This is solely because the FreeNAS jail had trouble installing the Node-RED software. It just means there are too many points-of-failure. In addition, use of WiFi is not ideal: I’ve finally got the clocks on Ethernet (so the keypads are more responsive) but the venetian blind and the RF controller are still connecting via WiFi. As a result, occasionally there’s a lag of a few seconds when activating something. So, either Ethernet, or use of a lower-level, simpler, more reliable radio protocol.
- Integration of the spare 433MHz outdoor temperature/humidity sensor I found. The protocol is unknown, and I haven’t managed to get any sense out of it. In desperation, I’ve put my only RuuviTag device outside, which is a bit of a waste of a nice platform… it also means I’ve had to use a hack to read the data from it: it broadcasts the weather data using an Eddystone beacon URL (I think). The EspruinoHub software being developed to bridge the Puck.js devices’ Bluetooth-LE comms to IP comes in handy for reading the beacon data, as all BLE discovery (incl. the beacon URL) gets blatted to MQTT.
- Use of the Matrix Creator developers’ kit I picked up a while ago. It looks like an astonishingly capable platform, but I just haven’t had time to explore it.
- Development of a better web dashboard for my tablet and phone. I did build a basic dashboard using Bootstrap and some hack PHP, but Node-RED’s HTML dashboard capability is the obvious next step. I just have to get it done.
- Integration with Apple HomeKit, using
homebridge. I have managed to do this partially: I can control a couple of the devices from my iPad’s dock panel and read humidity, but it’s rudimentary at best.
I’d also love to tell you about some of my other hacks, including:
- the venerable iPad-Hold-A-Tron 2000™, a hacked and almost completely rebuilt Ikea anglepoise lamp repurposed to hold my iPad Pro over my bed while I’m recovering from back pain;
- the invaluable Page-Turn-O-Matic 4000™, a BLE remote control to allow me to turn pages on iBooks on my iPad without having to reach up and touch the screen, thereby ruining my back/shoulder relaxation;
- the postponed i-Mattress-Sens-U-Pedic 2000™, a really wacky homemade pressure detection pad to use AI to detect when I’m lying on my back (bad) rather than sides (good), and take action. Currently on hold while my back is in rehab;
- the unfinished Telebot Rov-A-Tron 2000™, a video telepresence robot to allow me to video-chat with my daughter while I’m away recovering;
- the obsolete Posture-U-Like 2000™, a homemade bad posture sensor along the lines of Lumo Lift, before such devices became ubiquitous like now. My prototype did work really well!
- Mister Gidden’s Patent Cough-B-Gon™ Instant Antitussive Miracle Elixir, my foray into Small Pharma. A homemade cough remedy based on 100% cacao and relying on a hefty slug of theobromine. It actually works.