Skip to content

Add support for Bresser CO2 PN 7009977 and HCHO/VOC PN 7009978 sensors #2815

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ See [CONTRIBUTING.md](./docs/CONTRIBUTING.md).
[170] LaCrosse Technology View LTV-WR1 Multi Sensor
[171] LaCrosse Technology View LTV-TH Thermo/Hygro Sensor
[172] Bresser Weather Center 6-in-1, 7-in-1 indoor, soil, new 5-in-1, 3-in-1 wind gauge, Froggit WH6000, Ventus C8488A
[173] Bresser Weather Center 7-in-1, Air Quality PM2.5 / PM10
[173] Bresser Weather Center 7-in-1, Air Quality PM2.5/PM10 7009970, CO2 7009977, HCHO/VOC 7009978
[174] EcoDHOME Smart Socket and MCEE Solar monitor
[175] LaCrosse Technology View LTV-R1, LTV-R3 Rainfall Gauge, LTV-W1/W2 Wind Sensor
[176] BlueLine Innovations Power Cost Monitor
Expand Down
2 changes: 1 addition & 1 deletion conf/rtl_433.example.conf
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ convert si
protocol 170 # LaCrosse Technology View LTV-WR1 Multi Sensor
protocol 171 # LaCrosse Technology View LTV-TH Thermo/Hygro Sensor
protocol 172 # Bresser Weather Center 6-in-1, 7-in-1 indoor, soil, new 5-in-1, 3-in-1 wind gauge, Froggit WH6000, Ventus C8488A
protocol 173 # Bresser Weather Center 7-in-1, Air Quality PM2.5 / PM10
protocol 173 # Bresser Weather Center 7-in-1, Air Quality PM2.5/PM10 7009970, CO2 7009977, HCHO/VOC 7009978
protocol 174 # EcoDHOME Smart Socket and MCEE Solar monitor
protocol 175 # LaCrosse Technology View LTV-R1, LTV-R3 Rainfall Gauge, LTV-W1/W2 Wind Sensor
protocol 176 # BlueLine Innovations Power Cost Monitor
Expand Down
125 changes: 117 additions & 8 deletions src/devices/bresser_7in1.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @file
Decoder for Bresser Weather Center 7-in-1.
Decoder for Bresser Weather Center 7-in-1 and Air quality sensors.

Copyright (C) 2019 Christian W. Zuckschwerdt <[email protected]>

Expand All @@ -11,11 +11,16 @@

#include "decoder.h"

#define SENSOR_TYPE_WEATHER 1
#define SENSOR_TYPE_AIR_PM 8
#define SENSOR_TYPE_WEATHER 1
#define SENSOR_TYPE_AIR_PM 8
#define SENSOR_TYPE_CO2 10
#define SENSOR_TYPE_HCHO_VOC 11

/**
Decoder for Bresser Weather Center 7-in-1 and Air Quality PM2.5 / PM10, outdoor sensors.
Decoder for Bresser Weather Center 7-in-1 and Air quality sensors.
- Air Quality PM2.5/PM10 PN 7009970
- CO2 sensor PN 7009977
- HCHO/VOC sensor PN 7009978

See
https://github.com/merbanan/rtl_433/issues/1492
Expand Down Expand Up @@ -53,6 +58,70 @@ Data layout:

DIGEST:8h8h ID?8h8h ?8h8h STYPE:4h STARTUP:1b CH:3b ?8h 4h ?4h8h4h PM_2_5:4h8h4h PM10:4h8h4h ?4h ?8h4h BATT:1b ?3b ?8h8h8h8h8h8h TRAILER:8h8h8h

Air Quality Sensor CO2 (PN 7009977) : issue #2813

From user manual , co2 ppm is from 400 to 5000 ppm, so it's 16 bits coded.

Samples :
Raw :
SType Startup & Channel

| |
{207}dab6d782acd9 a 1 ad9aad9aad9aaaaaaaaaaaaaaaaae99aaaaa00 Type = 0xa = 10, Startup = 0, ch = 1
{207}04a9d782acd8 a 1 ad9aad9aad9aaaaaaaaaaaaaaaaae99aaaaa00 Type = 0xa = 10, Startup = 0, ch = 1
{207}04a9d782acd8 a 1 ad9aad9aad9aaaaaaaaaaaaaaaaae99aaaaa00 Type = 0xa = 10, Startup = 0, ch = 1
{207}0dd1d782b8ee a 1 ad9aad9aad9aaaaaaaaaaaaaaaaae99aaaaa00 Type = 0xa = 10, Startup = 0, ch = 1

Data layout raw :
DIGEST:16h ID:16h 8x8x STYPE:4h STARTUP:1b CH:3d 8x8x8x8x8x8x8x8x8x8x8x8x8x8x8x8x8x8x TRAILER:8x

XOR / de-whitened :

0 1 2 3 4 5 6 7 8 9101112131415161718192021222324
DIGEST ID ppm bat
| | | |
{200}701c 7d28 0673 0b073007300730000000000000000043300000 [ XOR from g001_868.34M_1000k.cu8 co2 ppm 673]
{200}ae03 7d28 0672 0b073007300730000000000000000043300000 [ XOR from g001_868.34M_250k.cu8 co2 ppm 672]
{200}ae03 7d28 0672 0b073007300730000000000000000043300000 [ XOR from g002_868.34M_1000k.cu8 co2 ppm 672]
{200}a77b 7d28 1244 0b073007300730000000000000000043300000 [ XOR from g002_868.34M_250k.cu8 co2 ppm 1244]

Data layout de-whitened :
DIGEST:16h ID:16h PPM:16h 8x8x8x8x8x8x8x8x8x8x4x BATT:1b 3x8x8x8x8x8x8x TRAILER:16x

Air Quality Sensor HCHO/VOC (PN 7009978) : issue #2814

From user manual , hcho ppb is from 0 to 1000 ppm, so it's 16 bits coded.
and voc level is from 1 (bad air quality) to 5 (good air quality), so it's 4 bits coded.

Samples:
Raw :
SType Startup & Channel
| |
{207}3f2dc4a5aaaf b 1 aaa8aaa8aaa8aaaaaaaaaaaaaaaae9feaaaa00 Type = 0xb = 11, Startup = 0, ch = 1
{207}0c1cc4a5aaaf b 1 aaa8aaa8aaa8aaaaaaaaaaaaaaaae9ffaaaa00 Type = 0xb = 11, Startup = 0, ch = 1
{207}3f2dc4a5aaaf b 1 aaa8aaa8aaa8aaaaaaaaaaaaaaaae9feaaaa00 Type = 0xb = 11, Startup = 0, ch = 1
{207}0c1cc4a5aaaf b 1 aaa8aaa8aaa8aaaaaaaaaaaaaaaae9ffaaaa00 Type = 0xb = 11, Startup = 0, ch = 1
{207}61afc4a5aaa2 b 9 aaa8aaa8aaa9aaaaaaaaaaaaaaaae9f8aaaa00 Type = 0xb = 11, Startup = 1, ch = 1
{207}ecddc4a5aaae b 9 aaa8aaa8aaa9aaaaaaaaaaaaaaaae9fbaaaa00 Type = 0xb = 11, Startup = 1, ch = 1

Data layout raw :
DIGEST:16h ID:16h 8x8x STYPE:4h STARTUP:1b CH:3d 8x8x8x8x8x8x8x8x8x8x8x8x8x8x8x8x8x8x TRAILER:8x

XOR / de-whitened :

0 1 2 3 4 5 6 7 8 9101112131415161718192021 22 2324
DIGEST ID ppb bat voc
| | | | |
{200}9587 6e0f 0005 1b0002000200020000000000000000435 4 0000 [XOR from g001_868.34M_1000k.cu8 hcho_ppb 5 voc_level 4]
{200}a6b6 6e0f 0005 1b0002000200020000000000000000435 5 0000 [XOR from g001_868.34M_250k.cu8 hcho_ppb 5 voc_level 5]
{200}9587 6e0f 0005 1b0002000200020000000000000000435 4 0000 [XOR from g002_868.34M_1000k.cu8 hcho_ppb 5 voc_level 4]
{200}a6b6 6e0f 0005 1b0002000200020000000000000000435 5 0000 [XOR from g001_868.34M_250k.cu8 hcho_ppb 5 voc_level 5]
{200}cb05 6e0f 0008 130002000200030000000000000000435 2 0000 [XOR from g003_868.34M_1000k.cu8 hcho_ppb 8 voc_level 2]
{200}4677 6e0f 0004 130002000200030000000000000000435 1 0000 [XOR from g004_868.34M_1000k.cu8 hcho_ppb 4 voc_level 1]

Data layout de-whitened :
DIGEST:16h ID:16h PPB:16h 8x8x8x8x8x8x8x8x8x8x4x BATT:1b 3x8x8x8x8x8x4x VOC:4h TRAILER:16x

First two bytes are an LFSR-16 digest, generator 0x8810 key 0xba95 with a final xor 0x6df1, which likely means we got that wrong.
*/

Expand Down Expand Up @@ -158,11 +227,9 @@ static int bresser_7in1_decode(r_device *decoder, bitbuffer_t *bitbuffer)
int pm_2_5 = (msg[10] & 0x0f) * 1000 + (msg[11] >> 4) * 100 + (msg[11] & 0x0f) * 10 + (msg[12] >> 4);
int pm_10 = (msg[12] & 0x0f) * 1000 + (msg[13] >> 4) * 100 + (msg[13] & 0x0f) * 10 + (msg[14] >> 4);

// To Do: identify further data

/* clang-format off */
data = data_make(
"model", "", DATA_STRING, "Bresser-7in1",
"model", "", DATA_STRING, "Bresser-7in1", // should be Bresser-Air-PM
"id", "", DATA_INT, id,
"channel", "", DATA_INT, chan,
"startup", "Startup", DATA_COND, !nstartup, DATA_INT, !nstartup,
Expand All @@ -176,6 +243,45 @@ static int bresser_7in1_decode(r_device *decoder, bitbuffer_t *bitbuffer)
decoder_output_data(decoder, data);
return 1;

} else if (s_type == SENSOR_TYPE_CO2) {
int co2 = ((msg[4]& 0xf0) >> 4) * 1000 + (msg[4]& 0x0f) * 100 + ((msg[5]& 0xf0) >> 4) * 10 + (msg[5] & 0x0f);

/* clang-format off */
data = data_make(
"model", "", DATA_STRING, "Bresser-CO2",
"id", "", DATA_INT, id,
"channel", "", DATA_INT, chan,
"startup", "Startup", DATA_COND, !nstartup, DATA_INT, !nstartup,
"battery_ok", "Battery", DATA_INT, !battery_low,
"co2_ppm", "Carbon Dioxide", DATA_FORMAT, "%i ppm", DATA_INT, co2,
"mic", "Integrity", DATA_STRING, "CRC",
NULL);
/* clang-format on */

decoder_output_data(decoder, data);
return 1;

} else if (s_type == SENSOR_TYPE_HCHO_VOC) {
int hcho = ((msg[4]& 0xf0) >> 4) * 1000 + (msg[4]& 0x0f) * 100 + ((msg[5]& 0xf0) >> 4) * 10 + (msg[5] & 0x0f);
int voc = (msg[22]& 0x0f);
/* clang-format off */
data = data_make(
"model", "", DATA_STRING, "Bresser-HCHO-VOC",
"id", "", DATA_INT, id,
"channel", "", DATA_INT, chan,
"startup", "Startup", DATA_COND, !nstartup, DATA_INT, !nstartup,
"battery_ok", "Battery", DATA_INT, !battery_low,
"hcho_ppb", "Formaldehyde", DATA_FORMAT, "%i ppb", DATA_INT, hcho,
"voc_level", "Volatile Organic Compounds",DATA_FORMAT, "%i", DATA_INT, voc, // from 1 bad air quality to 5 very good air quality
"mic", "Integrity", DATA_STRING, "CRC",
NULL);
/* clang-format on */

decoder_output_data(decoder, data);
return 1;

// To Do: identify further data

} else {
decoder_logf(decoder, 2, __func__, "DECODE_FAIL_SANITY, s_type=%d not implemented", s_type);
return DECODE_FAIL_SANITY;
Expand All @@ -200,12 +306,15 @@ static char const *const output_fields[] = {
"pm_2_5_ug_m3",
"pm_10_ug_m3",
"battery_ok",
"co2_ppm",
"hcho_ppb",
"voc_level",
"mic",
NULL,
};

r_device const bresser_7in1 = {
.name = "Bresser Weather Center 7-in-1, Air Quality PM2.5 / PM10",
.name = "Bresser Weather Center 7-in-1, Air Quality PM2.5/PM10 7009970, CO2 7009977, HCHO/VOC 7009978 sensors",
.modulation = FSK_PULSE_PCM,
.short_width = 124,
.long_width = 124,
Expand Down