rtl_433 icon indicating copy to clipboard operation
rtl_433 copied to clipboard

Lux and UV incorrect for Cotech 36-7959

Open biuklija opened this issue 2 years ago • 64 comments

UV and light_lux were added for Cotech 36-7959 in commit 7f14007 , but light_lux is not decoded correctly. Maximum decoded light_lux value in decoded samples is always 69627 and I'm getting the same value although the console itself properly displays higher values and the value should go up to 200.000.

biuklija avatar May 17 '22 17:05 biuklija

It was added from #1575 with 67ee1d6 and is 16 (or 17?) bit, noted to reach 200.000? https://github.com/merbanan/rtl_433/blob/master/src/devices/cotech_36_7959.c#L42 This looks strange

    int flags     = (b[7] & 0xf0) >> 4;                           // [56:4]
    int light_lux = (b[10] << 8) + b[11] + ((flags & 0x08) << 9); // [80:16]

So top bit of b[7] goes to bit 12? I guess it should be 16, i.e.

    int light_lux = (b[10] << 8) | b[11] | ((b[7] & 0x80) << 9); // [56:1][80:16]

Can you modify your source code, recompile and test?

@andrewpile can you double-check that line?

zuckschwerdt avatar May 17 '22 18:05 zuckschwerdt

Recompiled, will test and report back tomorrow when the sun comes up to see how it behaves. I've tried some test samples, but they don't look promising. While one of my samples does decode over 69627 (77661 to be exact), all my other samples had lower values and all the samples in rtl_433_tests now decode as 131067 instead of 69627, which is suspicious.

Additionally, it seems that UV index is scaled by 10 so it might be a good idea to map it as a float, but I'll test this out as well.

biuklija avatar May 17 '22 19:05 biuklija

It's been a long time since I looked at this, but the origins of this code were always a little suspicious and undocumented, so I suspect it needs more research.

andrewpile avatar May 17 '22 20:05 andrewpile

As expected, lux values are now capped at 131069, all those below are properly decoded.

time      : 2022-05-18 12:41:48
model     : Cotech-367959 ID        : 28
Battery   : 1            Temperature: 66.6 F       Humidity  : 45 %          Rain      : 9.3 mm        Wind direction: 85        Wind      : 2.0 m/s       Gust      : 3.0 m/s       Light Intensity: 78155 lux
UV Index  : 4.0          Integrity : CRC

time      : 2022-05-18 12:42:52
model     : Cotech-367959 ID        : 28
Battery   : 1            Temperature: 67.1 F       Humidity  : 45 %          Rain      : 9.3 mm        Wind direction: 82        Wind      : 1.8 m/s       Gust      : 2.3 m/s       Light Intensity: 131069 lux
UV Index  : 6.9          Integrity : CRC

The lux value is not a 16-bit integer. We do have a few spare bits of unknown purpose (block J), could they belong here? My knowledge of C and bitwise operation is limited, how would I go about testing this?

biuklija avatar May 18 '22 10:05 biuklija

Record some samples and their corresponding reading from the official receiver. Then we can look for what bits belong to what value.

merbanan avatar May 18 '22 11:05 merbanan

Even better add decoder_log_bitrow(decoder, 0, __func__, b, sizeof(b) * 8, "bitrow"); at https://github.com/merbanan/rtl_433/blob/master/src/devices/cotech_36_7959.c#L85 (the line before // Extract data from buffer), recompile and run. Note the decoded rows you get and the light values you expect.

zuckschwerdt avatar May 18 '22 11:05 zuckschwerdt

The console displays higher values as klux, the following samples should be either 164.4 klux or 164.9 klux (although I'm not absolutely certain about the last one).

cotech_36_7959_decode: bitrow: {112} c1 c0 0c 11 5a 00 5d 84 37 2c ff fd 45 b2 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
time      : @0.324652s
model     : Cotech-367959 ID        : 28
Battery   : 1            Temperature: 67.9 F       Humidity  : 44 %          Rain      : 9.3 mm        Wind direction: 90        Wind      : 1.2 m/s       Gust      : 1.7 m/s       Light Intensity: 131069 lux
UV Index  : 6.9          Integrity : CRC

cotech_36_7959_decode: bitrow: {112} c1 c0 04 07 20 00 5d 84 3a 2d ff fd 45 e6 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
time      : @0.193760s
model     : Cotech-367959 ID        : 28
Battery   : 1            Temperature: 68.2 F       Humidity  : 45 %          Rain      : 9.3 mm        Wind direction: 32        Wind      : 0.4 m/s       Gust      : 0.7 m/s       Light Intensity: 131069 lux
UV Index  : 6.9          Integrity : CRC

cotech_36_7959_decode: bitrow: {112} c1 c4 08 0a 37 00 5d 84 3d 2b ff fd 44 c7 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
time      : @0.325144s
model     : Cotech-367959 ID        : 28
Battery   : 1            Temperature: 68.5 F       Humidity  : 43 %          Rain      : 9.3 mm        Wind direction: 311       Wind      : 0.8 m/s       Gust      : 1.0 m/s       Light Intensity: 131069 lux
UV Index  : 6.8          Integrity : CRC

biuklija avatar May 18 '22 11:05 biuklija

Before I forget, the UV value is indeed scaled by 10, ranges from 0 to 150, so it should be formatted as a float to avoid confusion (to prevent UV 0.9 being interpreted as UV 9). The original display console rounds this value up and only displays 0-15.

biuklija avatar May 18 '22 11:05 biuklija

The value of ff fd (b[10] b[11]) does look more like an error code than a reading. Can you grab values over a wider range and paste lines this here?

  • {112} c1 c0 0c 11 5a 00 5d 84 37 2c ff fd 45 b2 : 164.4 klux or 164.9 klux

zuckschwerdt avatar May 18 '22 12:05 zuckschwerdt

I'll see what I can do, might take a while because they have to be in a precise range. I have a bunch of eligible samples, but not their expected values.

biuklija avatar May 18 '22 14:05 biuklija

Here's a few I managed to force with a flashlight, they're the best I can do today.

{112} c1 c0 0c 14 12 00 5d 84 47 1f ff fd 22 8b : probably 147.7 klux
{112} c1 c0 1c 21 3d 00 5d 84 48 1e ff fd 1f 3c : probably 146.2 klux
{112} c1 c0 16 21 48 00 5d 84 48 1e ff fd 1f 10 : possibly 146.2 klux

{112} c1 c0 0d 11 8b 00 5d 84 48 1d ff fd 1b 66 : 144.2 klux
{112} c1 c0 02 03 4a 00 5d 84 4a 1e ff fd 20 df : 146.7 klux
{112} c1 c0 00 03 69 00 5d 84 4c 1e ff fd 18 7d : 142.8 klux
{112} c1 c4 07 14 3d 00 5d 84 4d 1d ff fd 13 80 : 140.3 klux
{112} c1 c4 13 17 32 00 5d 84 4e 1d ff fd 12 9a : 139.8 klux
{112} c1 c4 0f 14 39 00 5d 84 4c 1d ff fd 1e 0e : 145.7 klux
{112} c1 c0 09 0d 04 00 5d 84 4d 1e ff fd 19 f0 : 143.3 klux 

biuklija avatar May 18 '22 14:05 biuklija

If you need values that properly decode across the entire range, I have plenty of that.

{112} c1 c0 16 1e 6e 00 5d 84 29 2c e8 ba 37 1b : 124812 lux
{112} c1 c0 1a 28 5c 00 5d 84 24 2c e8 4d 32 43 : 125005 lux
{112} c1 c0 1f 28 47 00 5d 84 22 2c fc ce 2f 63 : 130254 lux
{112} c1 c0 14 21 45 00 5d 84 16 3d 22 75 1a 0b : 74357 lux
{112} c1 c0 07 0d 2c 00 5d 84 13 3d 17 b5 14 60 : 71605 lux
{112} c1 c0 19 2b 44 00 5d 84 11 3d 01 3c 14 2f : 65852 lux

biuklija avatar May 18 '22 15:05 biuklija

Oh, those all have ff fd in the bytes we expect the light value to be in. Here is a BitBench with the codes. I don't see where the light value might be? It just seems to be "overflow".

zuckschwerdt avatar May 18 '22 15:05 zuckschwerdt

If it's overflowing, there's a chance that the light value is broadcast in a different message?

biuklija avatar May 18 '22 15:05 biuklija

Am I completely misreading this or is there a different package before the main one which we decode? rtl_433 -X "n=Cotech-TEST,m=OOK_MC_ZEROBIT,s=488,l=0,r=988" -Y minsnr=20 -S all

time      : 2022-05-18 20:33:48
model     : Cotech-TEST  count     : 1             num_rows  : 1             rows      : 
len       : 127          data      : 0029838000006600ba07e04600960080
codes     : {127}0029838000006600ba07e04600960080
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
time      : 2022-05-18 20:33:48
model     : Cotech-TEST  count     : 1             num_rows  : 1             rows      : 
len       : 128          data      : 0014c1c0000033005d03f023004b0040
codes     : {128}0014c1c0000033005d03f023004b0040
cotech_36_7959_decode: bitrow: {112} c1 c0 00 00 33 00 5d 03 f0 23 00 4b 00 40 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
time      : 2022-05-18 20:33:48
model     : Cotech-367959 ID        : 28
Battery   : 1            Temperature: 60.8 F       Humidity  : 35 %          Rain      : 9.3 mm        Wind direction: 51        Wind      : 0.0 m/s       Gust      : 0.0 m/s       Light Intensity: 75 lux
UV Index  : 0.0          Integrity : CRC
cotech_36_7959_decode: bitrow: {112} c1 c0 00 00 33 00 5d 03 f0 23 00 4b 00 40 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
time      : 2022-05-18 20:33:48
model     : Cotech-367959 ID        : 28
Battery   : 1            Temperature: 60.8 F       Humidity  : 35 %          Rain      : 9.3 mm        Wind direction: 51        Wind      : 0.0 m/s       Gust      : 0.0 m/s       Light Intensity: 75 lux
UV Index  : 0.0          Integrity : CRC

*** Saving signal to file g001_433.92M_250k.cu8 (99015 samples, 262144 bytes)

biuklija avatar May 18 '22 18:05 biuklija

Yes, in the spectrogram (https://triq.org/pdv/) and looking at the data it very much looks like a proper transmission. And it's already a valid Manchester decode. Can you capture more of those?

zuckschwerdt avatar May 18 '22 19:05 zuckschwerdt

Oh and the original author of the decoder knew that too ;) https://github.com/merbanan/rtl_433/blob/master/src/devices/cotech_36_7959.c#L57-L62

zuckschwerdt avatar May 18 '22 19:05 zuckschwerdt

Yes, in the spectrogram (https://triq.org/pdv/) and looking at the data it very much looks like a proper transmission. And it's already a valid Manchester decode. Can you capture more of those?

Not a problem capturing them, I have them from my tests above (when light_lux goes into overflow). I have a sneaking suspicion that this package might also contain the watts per square metre because the display console can display both. I initially thought that it just approximated the w/m2 value from the illumination using a fixed conversion factor, but the conversion factor varied between readings.

biuklija avatar May 18 '22 19:05 biuklija

Here's that batch, in transmission order, along with the expected values of klux.

{127}002983801a231600bb08903bfffa36cc
{112} c1 c0 0d 11 8b 00 5d 84 48 1d ff fd 1b 66 : 144.2 klux

{127}0029838004069400bb08943dfffa41be
{112} c1 c0 02 03 4a 00 5d 84 4a 1e ff fd 20 df : 146.7 klux

{127}002983800006d200bb08983dfffa30fa
{112} c1 c0 00 03 69 00 5d 84 4c 1e ff fd 18 7d : 142.8 klux

{127}00298388262e6400bb089c3bfffa2534
{112} c1 c4 13 17 32 00 5d 84 4e 1d ff fd 12 9a : 139.8 klux

{127}002983881e287200bb08983bfffa3c1c
{112} c1 c4 0f 14 39 00 5d 84 4c 1d ff fd 1e 0e : 145.7 klux

{127}00298380121a0800bb089a3dfffa33e0
{112} c1 c0 09 0d 04 00 5d 84 4d 1e ff fd 19 f0 : 143.3 klux 

EDIT: corrected second value.

biuklija avatar May 18 '22 19:05 biuklija

Sorry, false alarm. Those are identical packets, just shifted one bit. I should have checked that first. So no second transmission. Only the ff fd you see on overflow.

zuckschwerdt avatar May 19 '22 06:05 zuckschwerdt

Okay, how about this? On every other (unrepeated) package, I get the 25-28 extra rows:

Detected OOK package	2022-05-19 12:04:13
cotech_36_7959_decode: bitrow: {112} c1 c0 07 0a 5a 00 5d 84 51 1d ff fd 2c d7 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
time      : 2022-05-19 12:04:13
model     : Cotech-367959 ID        : 28
Battery   : 1            Temperature: 70.5 F       Humidity  : 29 %          Rain      : 9.3 mm        Wind direction: 90        Wind      : 0.7 m/s       Gust      : 1.0 m/s       Light Intensity: 131069 lux
UV Index  : 4.4          Integrity : CRC
Analyzing pulses...
Total count:  102,  width: 123.55 ms		(30887 S)
Pulse width distribution:
 [ 0] count:   77,  width:  504 us [472;532]	( 126 S)
 [ 1] count:   25,  width:  992 us [984;1000]	( 248 S)
Gap width distribution:
 [ 0] count:   76,  width:  472 us [448;496]	( 118 S)
 [ 1] count:   25,  width:  956 us [948;964]	( 239 S)
Pulse period distribution:
 [ 0] count:   65,  width:  976 us [964;992]	( 244 S)
 [ 1] count:   22,  width: 1464 us [1444;1488]	( 366 S)
 [ 2] count:   14,  width: 1948 us [1944;1956]	( 487 S)
Pulse timing distribution:
 [ 0] count:  153,  width:  488 us [448;532]	( 122 S)
 [ 1] count:   50,  width:  972 us [948;1000]	( 243 S)
 [ 2] count:    1,  width: 10004 us [10004;10004]	(2501 S)
Level estimates [high, low]:  15956,    671
RSSI: -0.1 dB SNR: 13.8 dB Noise: -13.9 dB
Frequency offsets [F1, F2]:   -1676,      0	(-6.4 kHz, +0.0 kHz)
Guessing modulation: Manchester coding
view at https://triq.org/pdv/#AAB10301E803CC271480808080808080808191918090818080808090808180808080808080808080908081808080919180919081918080808080808080809190808190818080809180809191808091808090808190808080808080808080808080808191809190818090819190808255
Attempting demodulation... short_width: 504, long_width: 0, reset_limit: 968, sync_width: 0
Use a flex decoder with -X 'n=name,m=OOK_MC_ZEROBIT,s=504,l=0,r=968'
pulse_slicer_manchester_zerobit(): Analyzer Device
bitbuffer:: Number of rows: 1 
[00] {127} 00 29 83 80 0e 14 b4 00 bb 08 a2 3b ff fa 59 ae 

*** signal_start = 6390574, signal_end = 6441455, signal_len = 50881, pulses_found = 102
Iteration 1. t: 178    min: 117 (77)    max: 239 (25)    delta 65
Iteration 2. t: 178    min: 117 (77)    max: 239 (25)    delta 0
Pulse coding: Short pulse length 117 - Long pulse length 239

Short distance: 122, long distance: 130, packet distance: 248

p_limit: 178
bitbuffer:: Number of rows: 26 
[00] { 9} 00 00     : 00000000 0
[01] { 1} 80        : 1
[02] { 1} 80        : 1
[03] { 3} 40        : 010
[04] { 7} 08        : 0000100
[05] {13} 00 20     : 00000000 00100
[06] { 4} 10        : 0001
[07] { 1} 80        : 1
[08] { 2} 40        : 01
[09] { 2} 80        : 10
[10] { 1} 80        : 1
[11] {10} 00 40     : 00000000 01
[12] { 3} 80        : 100
[13] { 2} 80        : 10
[14] { 4} 10        : 0001
[15] { 3} 20        : 001
[16] { 1} 80        : 1
[17] { 3} 20        : 001
[18] { 5} 20        : 00100
[19] {15} 80 00     : 10000000 0000000
[20] { 1} 80        : 1
[21] { 2} 40        : 01
[22] { 2} 80        : 10
[23] { 3} 40        : 010
[24] { 1} 80        : 1
[25] { 3} 80        : 100

*** Saving signal to file g013_433.92M_250k.cu8 (66156 samples, 262144 bytes)

biuklija avatar May 19 '22 10:05 biuklija

Ignore, it's just a wrong guess by the analyzer. This is getting really weird. The data has to be somewhere in the package because it gets regularly updated every 15 seconds along with all other data.

biuklija avatar May 19 '22 11:05 biuklija

klux is derived from the UV value. I played around with it a bit and found that the formula (131000 + (UV * 491) ) / 1000 gets the same klux values as reported (after rounding). The constants could be further tuned or confirmed with values closer to the point of lux overflow.

anthyz avatar May 19 '22 23:05 anthyz

It's certainly good to extract what the official receiver sees. This rant is slightly off (illuminance vs irradiance, rather than illuminance vs UV index), but might be useful in understanding that converting UV to lux is an unsound hack, even if equipment manufacturers are willing to do it.

https://github.com/weewx/weewx/wiki/Watts-and-lux

gdt avatar May 20 '22 00:05 gdt

Interesting! Yeah, it’s likely a hack, but personally knowing nothing about the properties of the sensors I’d want more data before deciding how bad of a hack it is. It would be interesting to see how a camera lens UV filter in front of the sensors affected the readings.

anthyz avatar May 20 '22 04:05 anthyz

I'll test this out, I should have an UV filter somewhere.

It's certainly good to extract what the official receiver sees. This rant is slightly off (illuminance vs irradiance, rather than illuminance vs UV index), but might be useful in understanding that converting UV to lux is an unsound hack, even if equipment manufacturers are willing to do it.

As far as I can see, there's actually just the UV sensor in the window on the integrated sensor unit and, to be fair, the manufacturer does specify in the manual that the accuracy and resolution for UV index are ±1, while "sunlight" has ±15% accuracy and resolution.

Additionally, this would explain why I was unable to establish a fixed conversion factor between w/m2 and lux. Rounding errors.

biuklija avatar May 20 '22 05:05 biuklija

In any case, what would be our best course of action in regards to RTL_433? Should it just report the (likely derived) lux value until it overflows and stop reporting it while it's capped, with a note somewhere in the documentation that it's derived and how to do so, thus letting the end-recipient of the data (weewx, for example) deal with approximations upwards from 131 klux? I don't think we should ignore this value altogether because it's bound to raise issues in the future, but we also can't let it report "capped" values. Is there an official stance for situations such as this?

biuklija avatar May 20 '22 06:05 biuklija

Matching the official receiver is fine, unless it does really strange things.

merbanan avatar May 20 '22 06:05 merbanan

But do I get it right that when the sensor maxes out it just makes up values together with the UV index ?

merbanan avatar May 20 '22 06:05 merbanan

The receiver probably just rounds the received lux value (derived by the sensor unit from UV) to four digits until it maxes out, after that it does the calculations on its own. I assume my version of the receiver derives values for w/m2 and lm/ft2 directly from the UV index and doesn't bother with lux.

biuklija avatar May 20 '22 06:05 biuklija