-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for Bresser CO2 PN 7009977 and HCHO/VOC PN 7009978 sensors (
- Loading branch information
Showing
3 changed files
with
119 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]> | ||
|
@@ -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 | ||
|
@@ -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. | ||
*/ | ||
|
||
|
@@ -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, | ||
|
@@ -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; | ||
|
@@ -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, | ||
|