Introduction: Mercury RF Remote Socket Control From Raspberry Pi
How to control Mercury RF remote sockets from the Raspberry Pi using Python.
Step 1: Preamble
I wanted to build a custom controller to monitor and control the environment in my (sub)tropical greenhouses, and the first steps were to monitor and control the humidity (heating is already controlled by thermostatic systems attached to the heaters). I wanted to use mains switching controls (in the UK 240 volts AC) and did not wish to have mains electricity anywhere close to the computer (Raspberry Pi) especially in a humid environment. This then requires the use of Mains remote switching, and I selected the AVSL Mercury RF Remote Socket Adaptor sold by Amazon (Mercury Part Number 350.115UK, Amazon ref. http://www.amazon.co.uk/Mercury-350-115-Remote-Control-Adaptor-Black/dp/B0051NIJA4 ) pictured above. These are relatively low cost, and had good reviews.
The next step was to get these sockets to work with the Raspberry Pi, and for this I selected the RF modules described as "433Mhz RF transmitter and receiver kit" by Amazon (search for"rf transmitter") shown here, and these are ridiculously cheap at £1.08 for the set (as of Jan 2016).
Step 2: Initial Investigations
Having assembled the parts that I needed, it was now time to investigate the software further. I had already planned to use software on the Pi that required the use of the GPIO Library, and to write the main controller in Python. Reading several web pages that describe how to control RF transmissions (for example https://github.com/lexruee/pi-switch-python ) and reading how to use RF Sniffer ( http://www.princetronics.com/how-to-read-433-mhz-codes-w-raspberry-pi-433-mhz-receiver/ ) plus other articles ( http://blog.rot13.org/2013/10/433-mhz-power-sockets-with-rc-switch-arduino-or-raspberry-pi.html ) I eventually got to the stage of recording a received signal from the Mercury hand-held controller through RF Sniffer on the Pi, and then sending the same signal out through "codesend" and it did not work.
At this stage I started to look for Mercury articles on the web, and found an interesting article ( http://npham.dk/?p=34 ), and this led me investigate the signal sent from the hand-held controller to see if I could decode it in detail.
I found that the blocks of signal codes sent by (and received by) the Mercury system are not straightforward, and are not easy to interpret for use by "codesend". For example, my RF Sniffer returned values of 5330227 for socket 1 "on" and 5330236 for socket 1 "off". Sending these via "codesend" did not switch the socket. Furthermore the sockets and hand-held controller had the numbers 1114 printed on them, so I converted the values to binary to see if there was a pattern that could be useful. Here are the table of switch states with their values as binary patterns, followed by the number on the socket and its binary pattern:-
- 1 on 5330227 10 1 0001 0101 0101 0011 0011
- 1 off 5330236 10 1 0001 0101 0101 0011 1100
- 2 on 5330371 10 1 0001 0101 1010 1100 0011
- 2 off 5330380 10 1 0001 0101 0101 1100 1100
- 3 on 5330691 10 1 0001 0101 0111 0000 0011
- 3 off 5330700 10 1 0001 0101 0111 0000 1100
- 4 on 5332227 10 1 0001 0101 1101 0000 0011
- 4 off 5332236 10 1 0001 0101 1101 0000 1100
- 5 on 5338371 10 1 0001 0111 0101 0000 0011
- 5 off 5338380 10 1 0001 0111 0101 0000 1100
- 1114 1 0001 0110 10
The obvious elements here are the least significant quartet of bits (Right Hand Side) which represent "on" and "off".
The pattern of bits shown divided into groups is purely for readability and to see any obvious patterns, and it can be seen that the next innermost quartets represent the switch numbers, and then there is a problem because there seems to be a combination of bits that is not straightforward to interpret as the switch numbers increase.
Anyway, none of this was much use as the "codesend" did not produce any switching, so I decided to search elsewhere for information, and a method to get it all to work.
An approach to Mercury brought no response.
Step 3: Breakthrough!
Further (essential) reading got me to the most useful piece of work that I have found on the web for this project, and I recommend it for anyone wishing to decode RF at 433MHz. You can find it here ( http://www.hoagieshouse.com/RaspberryPi/RCSockets/RCPlug.html ) REF 1.
With this information to hand I connected the 433MHz receiver board to the Pi power rail (3.3v) and the ground to the Pi ground, and constructed a cable rescued from an old microphone headset with a 1Megohm resistor to be used as a scope probe. The probe has the resistor soldered to the core of the microphone cable, and the braided sheath of the cable soldered to a solid copper wire to plug in to the ground rail on a breadboard. The other end of the cable has the 3.5mm jack still attached, and this plugs in the sound board on a PC. With this assembly, it is possible to use Audacity ( http://audacityteam.org/ ) as an oscilloscope. Of course the sound board on the PC has to be able to accept the signal from the cable (not all sound boards are suitable!), and the inline resistor helps to protect the sound board from over-voltage inputs. The sound board on my system is a Realtek, and works well with this setup.
Armed with my makeshift scope, I am now able to see the signal sent from the Mercury controller, and to try to mimic the pattern on the Pi, to be sent from the transmitter.
Step 4: Decoding the Mercury Controller Signals
The picture above shows the Audacity output with annotation. This matches the bit pattern from the RFSniffer in broad outline, but with some significant additional short pulses. The obvious short pulses are at the start (LHS) forming a Start Bit, and at the end (RHS) forming a Stop Bit, but there are additional short pulses in the block. I interpret these as some form of framing as they appear in all the expanded pulse streams.
The task now is to mimic all these pulses in an output array for onward transmission as a signal from the Pi to the socket.
Step 5: Modifying the Code
Using the switch code provided from the link (REF 1 above) I changed the bit patterns to match those recorded from the Mercury hand-held controller, so to switch the Mercury switch number one, I used
// 1 sniffer on 0 1 0 1 0 0 0 1 0 1 0 1 0 1 0 1 0 0 1 1 0 0 1 1
strcpy(szOn, "0000000000001000111010001110100010001000111010001110100011101000111010001110100 010001110111010001000111011101000000000000000000000");
where you can see that the original RFSniffer bit pattern corresponds to the reproduced detected pattern (in broad outline only!).
The timing of the output of bits from the switch code had to be modified from the original so that the bit spacing (and total message length) corresponded to the pattern transmitted from the Mercury controller.
Testing the new code from the terminal window switched the remote switch - IT WORKED!
The modified mercuryswitch.cpp is available from here .
Step 6: Finally - Calling the Mercury Switch Control Code From Raspberry Pi Python
It is required to call the mercuryswitch code (compiled from mercuryswitch.cpp - use the command in the Pi terminal window)
g++ -o mercuryswitch mercuryswitch.cpp
This is called in the Python script by using a call to "subprocess" thus
subprocess.call( ["sudo","./mercuryswitch","1","on"] )
Note that the function "subprocess" requires a list as its parameter as one of its optional parameter structures, hence the use of the square brackets around the set of parameters. Also, "mercuryswitch" has to be run from superuser and requires "sudo" to achieve this.
A test program written in Python for the Pi is given here .
Don't expect these RF modules to work over long distances. Mine are working at up to four feet, above which they become unreliable, and fail to switch sometimes. I am running them at 3.3 volts straight from the Pi GPIO pins, and have modified the tiny boards by adding an aerial of the appropriate length for the wavelength (17.2cms for 433MHz quarter length), but I haven't yet investigated using a ground plane to support a better signal quality.
We have a be nice policy.
Please be positive and constructive.