So, I was listening to the Hackaday Podcast last week, and Elliot was saying how easy it is to control 433 MHz light switches with these cheap OOK transmitter modules. As I was listening, I realized I already had everything I needed to put this system together. The office lights were already on a 433 MHz switch I use to turn them off when I forget and head up to bed. And somewhere in a box with a dozen other random RF modules were two of those 433 MHz deals.
I decided to try to make this a zero-time hack, too, because I've got other stuff going on at the moment. It ended up taking a couple of hours, but mostly because I did a little experimenting along the way that will probably help with another effort.
Step 1: Capture the Codes
I fired up GQRX with an RTL-SDR dongle and recorded audio of AM-decoded transmissions from the light-control transmitter. They look like this:
I ended up writing python code to trigger on the leading edge of this pattern and average a number of them because I need that functionality for another project. Then, I thresholded the result, and calculated the run lengths of the on and off times. The dwell times are in a 3:1 ratio, so I called them "dit" and "dah" in the code, because the timing reminded me of Morse. Rather than coming up with some fancy encoding for the bitstream, I had the python code dump out in-lined C++ that I could paste right into arduino-land. It's terribly ugly, but it works, and looks like this:
... digitalWrite(RF_PIN, 1); delayMicroseconds(dit); digitalWrite(RF_PIN, 0); delayMicroseconds(dah); digitalWrite(RF_PIN, 1); delayMicroseconds(dah); digitalWrite(RF_PIN, 0); delayMicroseconds(dit); digitalWrite(RF_PIN, 1); ...
But there are many, many more lines :-)
Step 2: Program the Arduino
I found an unused arduino nano around and connected it to the 433 MHz TX module with three jumpers (+5, GND, DATA). The arduino code listens to the serial port. If it receives a '0', it sends the code to turn off the light, while a '1' sends the on-code. Again, I'll just link the code here for anyone interested.
Step 3: Monitor DBUS for Screensaver Status
I wrote some more quick python code to monitor the cinnamon screensaver on my desktop Linux Mint 19 install. This code polls the screensaver status about once a second. If a change in status is detected, it turns the office lights on or off (as appropriate) by sending a "1" or "0" to the serial port where the arduino nano is connected. This is the whole code, but here's a link anyway.
#!/usr/bin/env python3 import dbus import time import serial dev = '/dev/ttyUSB0' port = serial.Serial(dev, 9600) old_val = 0 while True: bus = dbus.SessionBus() screensaver = bus.get_object('org.cinnamon.ScreenSaver', '/org/cinnamon/ScreenSaver') interface = dbus.Interface(screensaver, 'org.cinnamon.ScreenSaver') val = interface.GetActive() if val != old_val: if val: port.write(bytes('0', 'utf-8')) time.sleep(1) port.write(bytes('0', 'utf-8')) else: port.write(bytes('1', 'utf-8')) time.sleep(1) port.write(bytes('1', 'utf-8')) old_val = val time.sleep(1)
I send the on-codes twice because there's no feedback to tell that the lights actually came on, and there are lots of random signals on 433 MHz that could interfere with a single TX. Ideally, I could monitor the light in the room and see if it increased, but that's too complex for right now.
I'll have to set this up to run automatically at start-up, and probably make a few adjustments, but it seems to work OK for now.
Step 4: Clean it all up
Yeah, right. Maybe when it stops working :-)