Contrary to what most people are attempting to do on similar hot tub projects, I wasn't trying to replace the main controller in my hot tub (an old Caldera Alpine, 1998). Everything works just fine. I wanted to be able to remote control the hot tub from the house, and have it run on a schedule (i.e. change the temp depending on the time of the day).
The top controller only has 2 buttons, and 3 7-segment digits for the temperature (and one small LED to indicate that the heater is on):
I needed to:
- Be able to continue using the current main board, including the top display where you can see the temp and push buttons for jets and temp
- Be able to read the temp from the main board
- Be able to read and adjust the "set temp" (the hot tub target temperature)
- Have remote access to the info, remote control it, and have a schedule, accessible via a small web page.
Of course, my hot tub was too old to allow that, and since I didn't want to break anything, I had to find a way to get the info out of the main board, and into a raspberry pi (which I chose because it had everything I thought I needed for this, GPIOs, wifi support, python, and linux for ssh'ing in, and hosting a small web site).
The connection between the main board (that has all the relays and all the electronics) and the top controller (with the temp display and the buttons) is done via a RJ12 connection with only 6 wires. An RJ12 connector looks like a phone connector, but has 6 wires instead of 4 for regular telephone.
I reverse engineered the "protocol" the tub uses to talk to the display, thanks to a friend's scope that allowed me to look at the signals on each of the 6 lines.
Wh: Clock line. +5.5V roughly 40kHz
Bk: Data line. +5.5V
Ye: Temp button when connected to +5V with 500 Ohm resistor
Gr: Jets button when connected to +5V with 500 Ohm resistor
Bl: DC 5V.
Here's an image of the clock signal
And here's an image of the data signal
The protocol used by the tub is very ad hoc, it's not using SPI or I2C or anything like that. In fact, it's a lot simpler:
30 times per second the clock line becomes active, at approximately 40kHz.
Each clock signals a data bit, and there are 21 data bits sent, after which the clock and data lines become inactive for about 1/30th of a second.
I quickly determined that each bit corresponds to each segment of the 3 7-segment digits (the fact that there was 21 values was a big hint!). A 1 if the segment was lit, and 0 if not. The first digit can only display "1" or be blank (the temp can't go beyond 104) so they used one of the unused segments to indicate the heater status).
So it seemed like the project would be easy! All I needed to do was read the data line, parse out which segments were lit, go from that to a temp value. To control the temperature, I could use a GPIO to take the level of the Yellow line to +5V (in fact, the +3.3V of the PI was enough).
So here's what I did:
I simply made a Y connection on the RJ12 line (you can buy Y connectors online) so it was easy to keep the system functional while adding the pi to it. I connected the clock, data, ground and temp lines to a small proto board I made. The ground goes to the PI ground (on the GPIO connector) and the others go to GPIOs, see below.
- I used 4 identical resistors to create two voltage dividers to take the 5V of the data and clock line down to 2.5V which was enough for the PI to read and connected that to two GPIOs configured as inputs.
- I configured a GPIO as output and connected it to the yellow line via a 500 Ohm resistor and a diode (just to be safe)
- For kicks a added another output GPIO to drive a white LED to indicate a heart beat (to show that the PI was alive, reading the temp etc)
Reading the temp was a bit tricky because the clock is at 40kHz which if you use python is getting close to how fast you can read a GPIO (with a PI3) using RPi.GPIO. At first I tried to use wait_for_edge(), event_detected() to synchronize reading the data with the clock. But these calls are far too slow to keep up with a 40kHz clock. Instead, I found that I could reliably read the clock and the data by repeated calls to input() and simply monitor the edge on the clock to save the data. You still have to be very careful to do as little as possible in your python loop if you don't want to miss clock edges.
Later on, I discovered that things would have been far easier with pigpio using a callback function, as described in http://abyz.co.uk/rpi/pigpio/examples.h ... SPI_mon_py.
The rest was just a matter of coding:
- Create a python module to read the temperature at regular intervals, with the ability to set the temperature by faking a temp button press.
- Write a tiny "scheduler" to set the temp according to a schedule saved in a text file
I found this page http://electronicsbyexamples.blogspot.c ... evice.html that got me almost 100% of the way.
If you want the server to be more robust (for example, if you plan on accessing it from multiple devices) then you can use gunicorn to turn your small flask server into a very robust one.
Here's an image of the board on top of the PI:
And of the main control unit with the pi sitting on top of it:
And a picture of the web page:
Of course, I went over the top with much more info I had intended to put on the page! I keep a log of the heater activity to see how much electricity the hot tub uses etc etc ....
All in all this has been a totally fun project! I hope this report is useful to someone who's contemplating the same idea. I'll be more than happy to share my code if that's useful to anyone.