My initial plan was not to play with my weather station, but with remote control to my vacuum cleaner :) I have Miele brand vacuum cleaner with remote control buttons located on gripping part of pipe where you usually hold cleaning pipe.
I was trying to reverse engineer that. There were no markings on device about its working frequency so I use cheap DVB-T dongle supported by rtl_sdr libray as my spectrum analyzer and GNU Radio as a frontend. First step is of course to find working frequency. I assumed that it will work on 433MHz or 868MHz or 2.4GHz band. That was easy - I spotted nice signal on 433.82Mhz My initial step was to discover modulation used by this device.
Since this is only home appliance I was not expecting QAM256 :) I focused on trying to get some bit stream by experimenting with ASK,FSK,GMSK. I started with ASK and that was first good shot. In fact my vacum cleaner is using OOK (On Off Keying) modulation which is extreme type of ASK where you switch on/off carrier.
By using GNU Radio FFT and Scope sink with low pass filter I saw that I have regular pulses of something what was interferences from my perspective. You can see this as decaying line close to the right of main signal. It is hard to catch < 1 s pulse..
I knew that this must be some other devices in my vicinity. Since pulses were rare this must be something energy efficient. My first suspects were SMART Water meter with radio transmitter or heat logger mounted on my water powered heaters. Both are made by Ista and have radio interface. They are waiting for my free time to start hacking them :) After some walking over my house with laptop and DVB-T dongle I ruled out both of them, and then I remembered about my weather station since signal was strongest near part of house where it was located.
Some time ago I bought cheap 30 PLN (~7,5 EURO) weather station in Biedronka shop. For those who are not familiar with this name it is a shop network directly competing with Lidl on Polish market. They sell mostly grocery but they have some home cheap china electronic stuff also. Quality is mostly crap but you can find some rare oportunieties..
Remote unit model part number is WS-9941-M. As you can see there is a mark that it is working on 433 MHz band. Clearly it was my source of interference. Unfortunatelly I'm still learning GNURadio and I was able to see data on screen however I was unable to make setup to dump this data to file. I went to my neighbor radio shack shop AVT. It is really neat to have such well stocked electronics shop just 10 minutes bike drive. I bought ZS-RR10-433MHZ 433.92 MHz radio reciever for 20 PLN (~5 EURO). This is really neat device - you just plug in to power, put some antena and you get demodulated signal on one of the pins.
After connecting Salae Logic Analyzer look what I got:
As you can see there is clearly pattern here. First what you see is sync packet contains three pulses and then delay ~ 9ms. Then is pattern repeated 10 times. We have pattern here but what exacly "0" and "1" are represented ?
I search web page for any similar devices. Unfortunately there is not many such pages. I found Fred's webpage, and rc-switch Arduino library. I looked into source files and none protocol was similar to mine.
I dumped data from Salae to CSV file and started write some python stuff that will try to get something from those data.
As you can see this signal have constant high pulse time so no duty modulation was possible. Period is changing and this was the clue. Like in every reverse hack you must start with some assumptions and check if they are wrong or not. I made one that bits are coded with time distance between two rising edges or two falling edges (since high state period is constant). With such assumption and data in csv file i wrote simple python code that will check time between two rising edges and if one is smaller than <VALUE_0> it is one bit, and second time period <VALUE_1> is zero bit. Of course you need some samples with knowledge what is expected to be inside, so I dumped packets for different temperature readings on my weather display and this is what I got
Temperature (Celsius) | Data |
18,8 C | 101001101000000010111100111100000000 |
20,1 C | 101001101000000011001001111100000000 |
20,7 C | 101001101000000011010000111100000000 |
Temperature (Celsius) | Data |
18,8 C | 188 |
20,1 C | 201 |
20,7 C | 207 |
Since such chip devices shouldn't be very efficient with float operations and temperature resolution was 0.1 deg I expected that station will multiply temp value by 10 and this should be value - and assumption was right.
I was happy and started to check my script until i measured first negative temperature. Since we have nice winter in Poland I put weather transmitter outside where it should be and started measurement. It was < -13 C deg and going down. Results were at least weird. Here is what I got with my previous method:
Temperature (Celsius) | Data | Data decimal |
-14.1 C | 101001101000111101110011111100000000 | 115 |
-14.2 C | 101001101000111101110010111100000000 | 114 |
-14.5 C | 101001101000111101101111111100000000 | 111 |
I noticed that encoded number is going down along with temperature drop. So what is minimum temperature device can measure so all bits will be zeroes ? Simple extrapolation and result is -25,6 C deg. Now this is very nice and special number for binary system :) So 0 deg will be 256 or "11111111". Simple math and we have formula for negative temperature schema:
Negative TEMP = ( VALUE - 256)/10
Where is "-" mark ? The only difference between negative and positive data are next 4 most significant bits you see on bold in table.
This is python based algorythm for decoding my wireless station data:
def decode(data): # convert 36 bits to long integer value=int(data,2) # remove 12 least significant bits by shifting >> 12 value=value >> 12 # remove preambule - only 12 least significant bits are important # 0xfff is in binary 111111111111. All other bits will be ignored value=value & 0xfff # lets check do we have negative temperature by comparing bits 10-12 # 0xf00 is 111100000000. We are checking value of 3 most significant bits # if set to 111 - negative temp. If set 000 - positive if (value & 0xe00) == 0xe00: # Negative algorythm return ((value & 0xff) - 256) / 10.0 else: # Positive temp algorythm return (value & 0x1ff)/10.0Now it is time to make some hardware to receive data from my unit and put them to PC via USB/UART, and put my temp data public. I have some STM32, PIC32, KL25Z,Atmega MCU's laying arround. But this is story for next part.
Update:
Jakub mention in comments that maybe my assuption about positive values is not perfect because that would mean max + temperature is 25.6 C deg. He was right. This is perfect example of working with not sufficient data samples :)
In fact temperature is encoded (probably) in 12 bits signed format. I tested only up to ~ 40 C deg by warm up sensor above 25,6 C deg. In order to check if bits 10 and 11 also containg temp data I would have to warm up device above 51.2 C deg. :-) Maximum temperature with 9 bits would be 51,2 C deg and this comply with sensor range from specification which is -25 - +50 C de, and I don't need higher values so example above decodes just 9 bits.
I updated python code