Hey, @merbanan.
Sorry to reach out to you like this. I'm new to GitHub and was unable to find your contact info.
I've been using Tellstick Net with Home Assistant, and ordered some Chinese temperature/hygrometers which use a WH2A sensor. I was hoping that Tellstick Net would support these since they already support the WH2 sensor, but unfortunately I was wrong.
So I reached out to them and asked if they were willing to do the necessary work. Basically, they were not. I was told that they don't have the resources to implement it at the time, but that they would take a closer look if _a)_ it is a simple rewrite from the WH2 sensor or _b)_ I can provide them much or most of the necessary code for decoding the WH2A RF packets.
Since rtl_433 supports the WH2A sensor, I was hoping you'd be able to provide me _b_. I've looked through the repo, but haven't been able to locate the relevant section(s). A link to it/those, would suffice.
Thanks for your amazing work. :)
There is code for WH2 and WH5 in https://github.com/merbanan/rtl_433/blob/master/src/devices/fineoffset.c -- they differ in sync bits and the temperature decoding. I havn't seen mention of some WH2A in rtl_433?`
@zuckschwerdt you're right, my bad. I was thinking of RF Link, who added WH2A support in version R46. Guess I'll reach out to them, then.
Thanks.
I too am interested in connecting a WH2A. I am also new to this so not sure if the best place to post. I have this output for the WH2A
Detected OOK package @ 2018-02-11 21:57:25
Analyzing pulses...
Total count: 55, width: 26990 (108.0 ms)
Pulse width distribution:
[ 0] count: 26, width: 128 [126;132] ( 512 us)
[ 1] count: 29, width: 372 [371;374] (1488 us)
Gap width distribution:
[ 0] count: 54, width: 238 [237;239] ( 952 us)
Pulse period distribution:
[ 0] count: 25, width: 366 [364;371] (1464 us)
[ 1] count: 29, width: 610 [609;612] (2440 us)
Level estimates [high, low]: 15877, 4
Frequency offsets [F1, F2]: -9958, 0 (-38.0 kHz, +0.0 kHz)
Guessing modulation: Pulse Width Modulation with fixed gap
Attempting demodulation... short_limit: 250, long_limit: 240, reset_limit: 240, sync_width: 0
pulse_demod_pwm(): Analyzer Device
bitbuffer:: Number of rows: 1
[00] {55} fe 80 c1 d2 44 75 ca
and have hacked and confirmed that the temp and humidity is accurately represented in the code taking a few different readings.
1111111010000000110 000011100111 00011110 111011111101000
1111111010000000110 000100000011 01001011 110101111
start ______________________ temp________humidity
I also found this link https://www.wxforum.net/index.php?topic=31937.0
I have tried to hack about with a copy of fineoffset.c but run out of talent.
I wonder if it possible to get a bit of help or potentially get it included in the standard file. Maybe editing the fineoffset file alone is insufficient and would require a re-install? Any help would be greatly appreciated.
Steve
Any help with this is dependent on sample signal files. Submit a few of them and then we might be able to help.
@merbanan
Thanks for the speedy reply. I believe I have created something called WH2A in the tests folder. This is the first time i have tried to post anything and i don't fully understand the terminology. I believe i have uploaded a zip file with 5 x samples and text detailing the associated readings.
Steve
I might have missed that. Where did you upload something? The prefered way is to clone and PR on https://github.com/merbanan/rtl_433_tests/
I think I have now successfully created fineoffset_wh2A and have contact GitHub to help me delete my previous attempt.
Steve
Did I successfully create the folder in the correct place?
No. You need to fork the rtl_433_tests repo, clone it to your computer, add files, commit that, upload the commit and request a pull (PR) via the Github UI.
Or just drop a zip file here if all else fails.
Thanks for patience, i have tried: Authentication failed. You may not have permission to access the repository or the repository may have been archived. Open options and verify that you're signed in with an account that has permission to access this repository.
so have attached a zip.
fineoffset_wh2A.zip
Hopefully this is more successful.
Clean sample files and good documentation. I'll check this in and work on supporting this device.
@zuckschwerdt thanks for picking this up.
I have been away for about 5 days and just looking back through the data I question my notes for sample +g003_433.92M_250k.cu8 = Temp 22.2 59%RH
I suspect the 59%RH may actually be 54%RH. Poor handwriting.
Steve
It does not look like the other Fineoffsets. For a start
rtl_433 -q -F json -R 0 -X wh2a:OOK_PWM:500:1500:2700:1200 -r tests/fineoffset_wh2A/01/g001_433.92M_250k.cu8
etc. shows:
tests/fineoffset_wh2A/01/g001_433.92M_250k.cu8 {55}fe80c1be6caa14 (22.3 C, 54 %RH)
tests/fineoffset_wh2A/01/g002_433.92M_250k.cu8 {55}fe80c1bc77db4c (22.2 C, 59 %RH)
tests/fineoffset_wh2A/01/g003_433.92M_250k.cu8 {55}fe80c1bc6d42aa (22.2 C, 54 %RH)
tests/fineoffset_wh2A/01/g004_433.92M_250k.cu8 {55}fe80c1be652284 (22.3 C, 50 %RH)
tests/fineoffset_wh2A/01/g005_433.92M_250k.cu8 {55}fe80c1c05baf08 (22.4 C, 45 %RH)
So I guess fe80c 1be 6c aa14 is id temp hum chk.
Actually 6c hex is 108 dec i.e. the expected hum x2 so we need to shift one bit right, or more likely drop 7 leading bits.
Dropping the 7 bit preamble fe80c1be6caa14 becomes 406 0df 36 550a -- now 36 is your hum (54%) and 0df incidentally is the plain temp value scaled by 10 (223).
@zuckschwerdt
Did you spot this further up the thread?
https://www.wxforum.net/index.php?topic=31937.0
it discusses the packet format and checksum MOD256.
I have also seen a discussion somewhere to represent the "-" sign for the temp.
Should i stick the WH2A in the freezer for a reading?
found it:
Bit 20 when set represents the "-" sign. So the 12 bit temperature field is what is known as signed integer.
I missed that, but it was quicker to look at the sample than to read the whole thread ;)
Their picture is really nice. I want something like that for all our protocols.
Maybe a protocol syntax and a graphics renderer ?
Christian,
In the background i have tried to modify fineoffset.c in the ~/rtl_433/src/devices directory to get my WH2A to work. I have now removed pretty much everything e.g. all the error correction, all the other devices etc and can't seem to get anything reported when i issue rtl_433 -R 18. I only have a WH2A. Is editing the fineoffset.c file alone insufficient? e.g. do i need to issue a make or install again? Am i editing a non-live file? I am not expecting the correct values but am at least expecting something to be reported.
my fineoffset.c file now looks like this:
static int fineoffset_WH2A_callback(bitbuffer_t *bitbuffer) {
bitrow_t *bb = bitbuffer->bb;
uint8_t b[40] = {0};
data_t *data;
char time_str[LOCAL_TIME_BUFLEN];
char *model;
int type;
uint8_t id;
int16_t temp;
float temperature;
uint8_t humidity;
bitbuffer_extract_bytes(bitbuffer, 0, 7, b, 40);
model = "Fine Offset Electronics, WH2A Temperature/Humidity sensor";
temp = ((b[1] & 0x0F) << 8) | b[2];
if (temp & 0x800) {
temp &= 0x7FF; // remove sign bit
temp = -temp; // reverse magnitude
}
temperature = (float)temp / 10;
// Nibble 8,9 contains humidity
humidity = b[3];
/* Get time now */
local_time_str(0, time_str);
}
static char *output_fields[] = {
"time",
"model",
"temperature_C",
"humidity",
NULL
};
r_device fineoffset_WH2A = {
.name = "Fine Offset Electronics, WH2A Temperature/Humidity Sensor",
.modulation = OOK_PULSE_PWM_RAW,
.short_limit = 500, // Short pulse 544µs, long pulse 1524µs, fixed gap 1036µs
.long_limit = 1500, // Maximum pulse period (long pulse + fixed gap)
.reset_limit = 2700, // We just want 1 package
.json_callback = &fineoffset_WH2A_callback,
.disabled = 0,
.demod_arg = 0,
.fields = output_fields
};
You need to build, yes. From the rtl_433 folder do:
mkdir build
cd build
cmake ..
make
Now run ./build/src/rtl_433
Christian,
Thanks for speedy response.
Is there an easier way to do what i am trying to do.
It appears that i have broken everything.
(Doxygen was always broken)
Steve
/rtl_433/build $ cmake ..
-- Build type not specified: defaulting to release.
-- Using Git version tag: 0.1-383-gc1b1f36 on master at 201802031107 (refs/heads /master commit c1b1f3614cbe017abd78babc6224b807803bcadd)
-- Could NOT find Doxygen (missing: DOXYGEN_EXECUTABLE)
-- Configuring done
-- Generating done
-- Build files have been written to: /home/pi/rtl_433/build
pi@control:~/rtl_433/build $ make
Scanning dependencies of target rtl_433
[ 1%] Building C object src/CMakeFiles/rtl_433.dir/devices/fineoffset.c.o
/home/pi/rtl_433/src/devices/fineoffset.c: In function ‘fineoffset_WH2A_callbac ’:
/home/pi/rtl_433/src/devices/fineoffset.c:41:1: warning: no return statement in function returning non-void [-Wreturn-type]
}
^
[ 2%] Linking C executable rtl_433
CMakeFiles/rtl_433.dir/rtl_433.c.o: In function main':
rtl_433.c:(.text.startup+0x47c): undefined reference tofineoffset_WH2'
rtl_433.c:(.text.startup+0x56c): undefined reference to fineoffset_WH25'
rtl_433.c:(.text.startup+0x570): undefined reference tofineoffset_WH0530'
collect2: error: ld returned 1 exit status
src/CMakeFiles/rtl_433.dir/build.make:2539: recipe for target 'src/rtl_433' fail ed
make[2]: * [src/rtl_433] Error 1
CMakeFiles/Makefile2:137: recipe for target 'src/CMakeFiles/rtl_433.dir/all' fai led
make[1]: [src/CMakeFiles/rtl_433.dir/all] Error 2
Makefile:127: recipe for target 'all' failed
make: ** [all] Error 2
The r_deviceshould stay r_device fineoffset_WH2 = {, otherwise looks good. (Doxygen is optional.)
OK - making progress
I have rolled back to the original and am adding a section for the wh2a.
// Nibble 5,6,7 contains 12 bits of temperature
temp = ((b[1] & 0x0F) << 8) | b[2];
How do i change this so that i am looking at nibbles 4-6 instead?
why is there a difference running rtl_443 from home vs running ./rtl_433/build/src/rtl_433?
The former reports nothing and the latter picks up the WH2A
It's two different programs. One is installed to (likely) /usr/local/bin the other is in the build folder.
temp = (b[1] << 4) | (b[2] >> 4); should be one nibble "earlier".
ok - not making progress
I have edited my local copy of fineoffset.c.
I have copied the WH2 fields and modified them to be called WH2A
e.g.
static char *output_fields_WH2A[] = {
"time",
"model",
"id",
"temperature_C",
"humidity",
"mic",
NULL
};
r_device fineoffset_WH2A = {
.name = "Fine Offset Electronics, WH2A Temperature/Humidity Sensor",
.modulation = OOK_PULSE_PWM_RAW,
.short_limit = 500,
.long_limit = 1500,
.reset_limit = 1500, // We just want 1 package
.json_callback = &fineoffset_WH2A_callback,
.disabled = 0,
.demod_arg = 0,
.fields = output_fields_WH2A
};
etc....
I have added this bit at the start:
} else if (bitbuffer->bits_per_row[0] == 55){ //&& //SB
// bb[0][0] == 0xFE) { // WH2A
I have commented out any section I could get wrong so only looking for 55 bits
I have commented out nearly everything
//if (b[4] != crc8(&b[0], 4, 0x31, 0)) // x8 + x5 + x4 + 1 (x8 is implicit)
// return 0;
// Nibble 2 contains type, must be 0x04 -- or is this a (battery) flag maybe? please report.
//type = b[0] >> 4;
//if (type != 4) {
// if (debug_output) {
// fprintf(stderr, "%s: Unknown type: %d\n", model, type);
// }
// return 0;
//}
//const float temperature = (float)((uint16_t)(buffer[1] & 0xF)<< 8 | buffer[2]) / 10.0 - 40.0;//from below
// Nibble 3,4 contains id
id = ((b[0]&0x0F) << 4) | ((b[1]&0xF0) >> 4);
// Nibble 4-6 contains 12 bits of temperature
temp = (b[1] << 4) | (b[2] >> 4);
//if (bb[0][0] == 0xFE) { // WH2A
// The temperature is signed magnitude and scaled by 10
if (temp & 0x800) {
temp &= 0x7FF; // remove sign bit
temp = -temp; // reverse magnitude
}
//} else { // WH5
// The temperature is unsigned offset by 40 C and scaled by 10
// temp -= 400;
//}
temperature = (float) / 10;
// Nibble 8,9 contains humidity
humidity = b[3];
/* Get time now */
local_time_str(0, time_str);
// Thermo
//if (b[3] == 0xFE) {
data = data_make("time", "", DATA_STRING, time_str,
"model", "", DATA_STRING, model,
"id", "ID", DATA_INT, id,
"temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temperature,
"mic", "Integrity", DATA_STRING, "CRC",
NULL);
data_acquired_handler(data);
//}
// Thermo/Hygro
//else {
// data = data_make("time", "", DATA_STRING, time_str,
// "model", "", DATA_STRING, model,
// "id", "ID", DATA_INT, id,
// "temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temperature,
// "humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity,
// "mic", "Integrity", DATA_STRING, "CRC",
// NULL);
// data_acquired_handler(data);
//}
return 1;
}
The output is as follows:
2018-04-01 12:20:00 : Fine Offset WH2A sensor
ID: 55
Temperature: -18.1 C
Humidity: 40 %
Integrity: CRC
The humidity reads perfectly, but it does't matter what i do with the temperature i seem to always get ~-18.1.
e.g i have tried removing the /10 and it makes no change. I have tried referencing different bytes - no change. I have tried setting the temperature to 100, no change.
when i make i get a warning:
make
Scanning dependencies of target rtl_433
[ 1%] Building C object src/CMakeFiles/rtl_433.dir/devices/fineoffset.c.o
/home/pi/rtl_433/src/devices/fineoffset.c: In function ‘fineoffset_WH2A_callback’:
/home/pi/rtl_433/src/devices/fineoffset.c:182:14: warning: ‘model’ is used uninitialized in this function [-Wuninitialized]
data = data_make("time", "", DATA_STRING, time_str,
~^~~~~~~~~~~~~~
"model", "", DATA_STRING, model,
~~~~~~~~~~~
"id", "ID", DATA_INT, id,
~~~~~~~~~
"temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temperature,
~~~~~~~~~~~~~~~~~
"mic", "Integrity", DATA_STRING, "CRC",
~~~~~~~~~~~
NULL);
~
[ 2%] Linking C executable rtl_433
[ 96%] Built target rtl_433
[ 98%] Built target data
[100%] Built target data-test
any help would be appreciated.
Maybe i should attempt to somehow get rtl_433 -q -F json -X wh2a:OOK_PWM:500:1500:2700 into node-red and do it in javascript.
I plan to use the output in node-red anyway.
Steve
I did note you suggested keeping the r_device but i believe I needed to change the .short_limit, .long_limit etc parameters.
it should be temperature = (float)temp / 10.0;
re: r_device: keep just the name, it's registered.
If it works in your tests, I'll use that and add it cleanly to the existing code :)
ok - started again by editing the original and modifying the wh2 section.
fineoffset.zip
I think i have attached a zip of the modified file.
I have put the WH2A in the freezer and confirmed the negative temps work.
I still get 3 readings so the timing is not quite right
2018-04-01 15:52:59 : Fine Offset Electronics, WH2 Temperature/Humidity sensor
ID: 127
Temperature: 28.0 C
Humidity: 24 %
Integrity: CRC
2018-04-01 15:52:59 : Fine Offset Electronics, WH2 Temperature/Humidity sensor
ID: 127
Temperature: 28.0 C
Humidity: 24 %
Integrity: CRC
2018-04-01 15:52:59 : Fine Offset Electronics, WH2 Temperature/Humidity sensor
ID: 127
Temperature: 28.0 C
Humidity: 24 %
Integrity: CRC
2018-04-01 15:53:47 : Fine Offset Electronics, WH2 Temperature/Humidity sensor
All readings match the machine.
I have checked that the crc8 is contained in byte 5 and represents the entire string byte 0-4 but am lost when trying to implement it. Internet searching did not help.
I also found the default r_device for the WH2 worked to get this far
r_device fineoffset_WH2 = {
.name = "Fine Offset Electronics, WH2 Temperature/Humidity Sensor",
.modulation = OOK_PULSE_PWM_RAW,
.short_limit = 800, // Short pulse 544µs, long pulse 1524µs, fixed gap 1036µs
.long_limit = 2800, // Maximum pulse period (long pulse + fixed gap)
.reset_limit = 2800, // We just want 1 package
.json_callback = &fineoffset_WH2_callback,
.disabled = 0,
.demod_arg = 0,
.fields = output_fields
Hopefully this is a good step forward.
Kudos to you guys for keeping at it. Hoping this works out!
Christian,
I "think" I have sorted out the checksum. (lucked in)
// Validate package
const uint8_t checksum = (b[0]+b[1]+b[2]+b[3]+b[4]);
const uint8_t crc = (b[5]);
if (crc != checksum) {
return 0;
}
I have had reliable data over the last week from a range of sensors into node-red.
I'm using Node-Red code based on work created by Pete Scargill (https://tech.scargill.net) and piping the data in - I couldn't get paho to work.
//node-red
var the433 = {};
garage = parseInt(211);
computer = parseInt(130);
kitchen = parseInt(139);
master = parseInt(0);
airing = parseInt(77);
payload = msg.payload.replace(/(rn|n|r)/gm,"");
var parts433 = msg.payload.split(",");
the433.P1 = parts433[0];
the433.P2 = parts433[1];
the433.P3 = parts433[2];
the433.P4 = parts433[3];
the433.P5 = parts433[4];
the433.time = the433.P1.split(":");
the433.min = the433.time[3];
var a = 0;
while (a < parts433.length) {
var bits433 = parts433[a].split(":");
switch (bits433[0]) {
case '{"time" ': the433.time = bits433[1]; break;
case ' "model" ': the433.model = bits433[1]; break;
case ' "id" ': the433.id = bits433[1]; break;
case ' "temperature_C" ': the433.temp = parseFloat(bits433[1]); break;//case '"temperature_C"': the433.temp = parseFloat(bits433[1], 10); break
case ' "humidity" ': the433.hum = parseFloat(bits433[1]); break;//case '"humidity"': the433.hum = parseFloat(bits433[1], 16) / 10; break;
case ' "data" ': the433.data = (bits433[1]); break;
}
a++;
}
if (the433.model == ' "WH2A"'){
if (typeof the433.temp !== 'undefined') temp = {payload: parseFloat(the433.temp)};
if (typeof the433.hum !== 'undefined') hum = {payload: parseFloat(the433.hum)};
if (typeof the433.id !== 'undefined') id = {payload: parseInt(the433.id)};
if (typeof the433.time !== 'undefined') time = {payload: String(the433.P1)};
temp.topic = the433.id;
hum.topic = the433.id;
if (the433.id == garage) {
temp.topic = "Outside";
hum.topic = "Outside";
}
if (the433.id == computer) {
temp.topic = "Computer";
hum.topic = "Computer";
}
if (the433.id == kitchen) {
temp.topic = "Kitchen";
hum.topic = "Kitchen";
}
if (the433.id == master) {
temp.topic = "MasterBedRoom";
hum.topic = "MasterBedRoom";
}
if (the433.id == airing) {
temp.topic = "AiringCupboard";
hum.topic = "AiringCupboard";
}
return [ [temp], [hum], [id], time];
}

I spotted my first corrupt data point hence the focus on the CRC. This shows the temperature data.

Thanks for all your help in getting this to work.
Steve
No activity here in quite some time. Any conclusions?
Oh, thanks for reminding. I'll integrate this in the next days now.
Awesome, much appreciated. Have a great summer! :)
Hello, any news about this sensor?
Thank you very much.
WH2A is supported with the WH2 device (-R 18) now.
Awesome! Cheers for all the help.
Steve
@sblakegit thanks, but you really did all the work here :) Happy to help.