From a466c5abf33386c3dda34696e11ae975c7ac6649 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 8 Oct 2021 13:59:11 +0200 Subject: [PATCH] Add support for HM330X Add support for HM330X SeedStudio Grove Particule sensor (#13250) --- BUILDS.md | 2 + CHANGELOG.md | 1 + I2CDEVICES.md | 1 + RELEASENOTES.md | 1 + tasmota/language/af_AF.h | 1 + tasmota/language/bg_BG.h | 1 + tasmota/language/cs_CZ.h | 1 + tasmota/language/de_DE.h | 1 + tasmota/language/el_GR.h | 1 + tasmota/language/en_GB.h | 1 + tasmota/language/es_ES.h | 1 + tasmota/language/fr_FR.h | 1 + tasmota/language/fy_NL.h | 1 + tasmota/language/he_HE.h | 1 + tasmota/language/hu_HU.h | 1 + tasmota/language/it_IT.h | 1 + tasmota/language/ko_KO.h | 1 + tasmota/language/nl_NL.h | 1 + tasmota/language/pl_PL.h | 1 + tasmota/language/pt_BR.h | 1 + tasmota/language/pt_PT.h | 1 + tasmota/language/ro_RO.h | 1 + tasmota/language/ru_RU.h | 1 + tasmota/language/sk_SK.h | 1 + tasmota/language/sv_SE.h | 1 + tasmota/language/tr_TR.h | 1 + tasmota/language/uk_UA.h | 1 + tasmota/language/vi_VN.h | 1 + tasmota/language/zh_CN.h | 1 + tasmota/language/zh_TW.h | 1 + tasmota/my_user_config.h | 5 + tasmota/support_features.ino | 4 +- tasmota/tasmota_template.h | 13 +- tasmota/xsns_93_hm330x.ino | 361 +++++++++++++++++++++++++++++++++++ tools/decode-status.py | 10 +- 35 files changed, 415 insertions(+), 9 deletions(-) create mode 100644 tasmota/xsns_93_hm330x.ino diff --git a/BUILDS.md b/BUILDS.md index 1998788c232f..4a55f149831f 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -160,6 +160,8 @@ m = minimal, l = lite, t = tasmota, k = knx, s = sensors, i = ir, d = display | USE_SEESAW_SOIL | - | - | - / - | - | - | - | - | | USE_TOF10120 | - | - | - / - | - | - | - | - | | USE_AM2320 | - | - | - / - | - | - | - | - | +| USE_T67XX | - | - | - / - | - | - | - | - | +| USE_HM330X | - | - | - / - | - | - | - | - | | | | | | | | | | | Feature or Sensor | m | l | t | k | s | i | d | Remarks | USE_SPI | - | - | - / - | - | - | - | x | diff --git a/CHANGELOG.md b/CHANGELOG.md index f9b2cafdff20..5045a43eec3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file. - Commands ``EnergyUsage`` and ``EnergyExport`` to (re)set energy usage and export values - Berry add module ``import persist`` - Support for BL0942 energy monitor (#13259) +- Support for HM330X SeedStudio Grove Particule sensor (#13250) ### Breaking Changed - ESP32 LVGL updated to v8.0.2 diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 5264557caec7..07094954b564 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -96,3 +96,4 @@ Index | Define | Driver | Device | Address(es) | Description 60 | USE_AM2320 | xsns_88 | AM2320 | 0x5C | Temperature and Humidity sensor 61 | USE_T67XX | xsns_89 | T67XX | 0x15 | CO2 sensor 62 | USE_SCD40 | xsns_92 | SCD40 | 0x62 | CO2 sensor Sensirion SCD40/SCD41 + 63 | USE_HM330X | xsns_93 | HM330X | 0x40 | Particule sensor diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 1d0532b24659..6c9f57403bc9 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -126,6 +126,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo - Support for Sensirion SCD40/SCD41 CO2 sensor [#13139](https://github.com/arendst/Tasmota/issues/13139) - Support for BL0939 energy monitor as used in ESP32 based Sonoff Dual R3 V2 Pow [#13195](https://github.com/arendst/Tasmota/issues/13195) - Support for BL0942 energy monitor [#13259](https://github.com/arendst/Tasmota/issues/13259) +- Support for HM330X SeedStudio Grove Particule sensor [#13250](https://github.com/arendst/Tasmota/issues/13250) - Initial support for Tasmota Mesh (TasMesh) providing node/broker communication using ESP-NOW [#11939](https://github.com/arendst/Tasmota/issues/11939) - Initial support for Wi-Fi extender [#12784](https://github.com/arendst/Tasmota/issues/12784) - Rule event support as JSON payload [#12496](https://github.com/arendst/Tasmota/issues/12496) diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h index c2c99390859d..90f07ad0033d 100644 --- a/tasmota/language/af_AF.h +++ b/tasmota/language/af_AF.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index 535490e2e8cc..ac51c3ef688a 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -711,6 +711,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index 5869c70b82e3..61f2a502e109 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index 19801605e0fa..e17fc15a69bf 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 40924a999ced..cbddc2e29c7d 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index c2dd499b8bd6..55275c9bbc6f 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 867b6c5382f3..ecfd956e85da 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 3274dc358d29..f8f91108fc52 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 TX" #define D_SENSOR_PN532_RX "PN532 RX" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/fy_NL.h b/tasmota/language/fy_NL.h index c8de5552825d..2d181d0e4954 100644 --- a/tasmota/language/fy_NL.h +++ b/tasmota/language/fy_NL.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index 0f26efe5e711..ef306ac58a6e 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index f2d13f08c178..cfb08ce4e80b 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 2655f28856e9..88f2dd216b91 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 - RX" #define D_SENSOR_CSE7766_TX "CSE7766 - TX" #define D_SENSOR_CSE7766_RX "CSE7766 - RX" +#define D_SENSOR_HM330X_SET "HM330X - SET" #define D_SENSOR_PN532_TX "PN532 - TX" #define D_SENSOR_PN532_RX "PN532 - RX" #define D_SENSOR_SM16716_CLK "SM16716 - CLK" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index 2b866a3bf00c..8f0335fac447 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index d14b74087918..3097e59b781b 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 713df76ad75b..599e96d476d8 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index 70c596063185..fff1c23316c3 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index b430481e3527..2952e153ab5a 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index b0c62eb4df28..ac695b69943d 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index e25356cae223..b5e1435c1636 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 824ddac76a3d..f483d3eb7e4a 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index fa394a22ed7c..8bd50eda5cad 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 3730512bcda2..c05701137a69 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 423eb770bf78..4ce422a8dbb4 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index abec88be90bc..c7b8b84f1702 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index 3461ccae1b53..22c0e684c2b7 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 10ec030fe7c1..61054f7bf6fd 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -712,6 +712,7 @@ #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" +#define D_SENSOR_HM330X_SET "HM330X SET" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index a5d87ceae045..69d7a1ac2613 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -653,6 +653,11 @@ // #define USE_BM8563 // [I2cDriver59] Enable BM8563 RTC - found in M5Stack - support both I2C buses on ESP32 (I2C address 0x51) (+2k5 code) // #define USE_AM2320 // [I2cDriver60] Enable AM2320 temperature and humidity Sensor (I2C address 0x5C) (+1k code) // #define USE_T67XX // [I2cDriver61] Enable Telaire T67XX CO2 sensor (I2C address 0x15) (+1k3 code) +// #define USE_HM330X // [I2cDriver63] Enable support for SeedStudio Grove Particule sensor (I2C address 0x40) (+1k5 code) +// #define HM330X_DEFAULT_ADDRESS 0x40 // Option: change default I2C address for HM330X used in SeedSTudio Particucle Sensor +// #define HM330X_WARMUP_DELAY 30 // Option: change warmup delay during which data are not read from sensor after a power up +// #define HM330X_HIDE_OUT_OF_DATE false // Option: change to true to hide data from web GUI and SENSOR while sensor is asleep + // #define USE_DISPLAY // Add I2C Display Support (+2k code) #define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0 #define USE_DISPLAY_LCD // [DisplayModel 1] [I2cDriver3] Enable Lcd display (I2C addresses 0x27 and 0x3F) (+6k code) diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 16827dc02510..6a2d73b37a23 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -771,7 +771,9 @@ void ResponseAppendFeatures(void) #if defined(USE_I2C) && defined(USE_SCD40) feature8 |= 0x00004000; // xsns_92_scd40.ino #endif -// feature8 |= 0x00008000; +#if defined(USE_I2C) && defined(USE_HM330X) + feature8 |= 0x00008000; +#endif // feature8 |= 0x00010000; // feature8 |= 0x00020000; diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index f363d068f7dc..8b5ffae8ad93 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -174,6 +174,7 @@ enum UserSelectablePins { GPIO_VINDRIKTNING_RX, // IKEA VINDRIKTNING Serial interface GPIO_BL0939_RX, // BL0939 Serial interface (Dual R3 v2) GPIO_BL0942_RX, // BL0942 Serial interface + GPIO_HM330X_SET, // HM330X SET pin (sleep when low) GPIO_SENSOR_END }; enum ProgramSelectablePins { @@ -367,7 +368,8 @@ const char kSensorNames[] PROGMEM = D_SENSOR_HRG15_TX "|" D_SENSOR_HRG15_RX "|" D_SENSOR_VINDRIKTNING_RX "|" D_SENSOR_BL0939_RX "|" - D_SENSOR_BL0942_RX + D_SENSOR_BL0942_RX "|" + D_SENSOR_HM330X_SET ; const char kSensorNamesFixed[] PROGMEM = @@ -755,6 +757,12 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_PMS5003_TX), // Plantower PMS5003 Serial interface AGPIO(GPIO_PMS5003_RX), // Plantower PMS5003 Serial interface #endif +#ifdef USE_VINDRIKTNING + AGPIO(GPIO_VINDRIKTNING_RX), +#endif +#ifdef USE_HM330X + AGPIO(GPIO_HM330X_SET), // HM330X Sleep pin (active low) +#endif #if defined(USE_TX20_WIND_SENSOR) || defined(USE_TX23_WIND_SENSOR) || defined(USE_WS2300_WIND_SENSOR) AGPIO(GPIO_TX2X_TXD_BLACK), // TX20/TX23 Transmission Pin #endif @@ -805,9 +813,6 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_HRG15_TX), AGPIO(GPIO_HRG15_RX), #endif -#ifdef USE_VINDRIKTNING - AGPIO(GPIO_VINDRIKTNING_RX), -#endif /*-------------------------------------------------------------------------------------------*\ * Other sensors diff --git a/tasmota/xsns_93_hm330x.ino b/tasmota/xsns_93_hm330x.ino new file mode 100644 index 000000000000..3ddc51ccb848 --- /dev/null +++ b/tasmota/xsns_93_hm330x.ino @@ -0,0 +1,361 @@ +/* + xsns_92_hm330x.ino - Driver for Seedstudio Grove HM3301 particle sensor + + Copyright (C) 2021 Barbudor, SeedStudio + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#ifdef USE_I2C +#ifdef USE_HM330X +/************************************************************************************************** + * Driver for Particule sensor SeedStudio Grove HM3301 + * ================================================================================================ + * This driver use the I2C mode. Only address 0x40 is supported by the sensor so it is hardcoded in + * the driver without any possibility to change it (without editing and recompiling) + * By default the sensor remains active all the time but no data are provided for the first + * HM330X_WARMUP_DELAY seconds (to allow the sensor to warm up). During warmup, no data are + * returned in the GUI or through SENSOR message in order to provide invalid data. In case + * of any doubt, logs with level 3 will confirm right at boot if the sensor has been detected. + * + * Low power / life extension + * -------------------------- + * It is possible to connect a GPIO to pin SET of the module and assign it to "HM330X SET" for + * automatic sleep in order to extend the life time of the sensor. When this is used, activity of + * the sensor in synced with Teleperiod as follow + * 1) At start, sensor is immediately enabled by setting "HM330X SET" HI and start warmup + * If any Telemetry occurs before the end of the warmup, no data are provided and warmup + * goes on. + * 2) After HM330X_WARMUP_DELAY, data are available and reported in web and SENSOR + * 3) Immediately after the next teleperiod SENSOR message, if Teleperiod is greater than + * (HM330X_WARMUP_DELAY + 2) the sensor is put to sleep by taking the pin "HM330X SET" LOW + * and a new cycle start + * New cycle + * 4) (HM330X_WARMUP_DELAY + 2) seconds before the next teleperiod, the sensor is awaken by taking + * the pin "HM330X SET" HI for warmup. No data are available yet + * 5) 2 seconds before Telemetry, warmup is completed and data are available to Web until + * Telemetry messages are sent + * 6) Back to 2) + * + * Overridables (in user_config_override.h) + * ---------------------------------------- + * HM330X_DEFAULT_ADDRESS 0x40 in case SeedStudio makes this changeable in the future + * HM330X_WARMUP_DELAY 30 time for warmup, data are not pulled before that delay + * HM330X_HIDE_OUT_OF_DATE false if changed to true web data and sensor will not be + * published when outdated + *************************************************************************************************/ + +//#define HM330X_SIM + +#define XSNS_93 93 +#define XI2C_63 63 // See I2CDEVICES.md + +#ifndef HM330X_DEFAULT_ADDRESS +#define HM330X_DEFAULT_ADDRESS 0x40 +#endif + +#define HM330X_SELECT_COMM_CMD 0X88 + +#define HM330X_FRAME_SIZE 29 + +#ifndef HM330X_WARMUP_DELAY +#define HM330X_WARMUP_DELAY 30 // Ignore HM330X data for XX seconds after start +#endif + +#define HM330X_PRE_TELEPERIOD_ENABLE 3 // Sensor made active before teleperiod + +#ifndef HM330X_HIDE_OUT_OF_DATE +#define HM330X_HIDE_OUT_OF_DATE false // override to true to disable display when the data are out of date +#endif + +enum { + HM330X_NO_ERROR = 0, + HM330X_ERROR_PARAM = -1, + HM330X_ERROR_NOT_FOUND = -2, + HM330X_ERROR_COMM = -3, + HM330X_ERROR_TIMEOUT = -4, + HM330X_ERROR_CHECKSUM = -5, + HM330X_ERROR_MEMALLOC = -6, + HM330X_ERROR_OTHERS = -128 +}; + +struct HM330XFrame { + uint16_t reserved; + uint16_t sensor_num; + uint16_t pm1_0_standard, pm2_5_standard, pm10_0_standard; + uint16_t pm1_0_env, pm2_5_env, pm10_0_env; + uint16_t particles_0_3um, particles_0_5um, particles_1_0um, particles_2_5um, particles_5_0um, particles_10_0um; + uint8_t checksum; +}; + +enum HM330X_State { + HM330X_SLEEP = 0, // sensor is sleeping + HM330X_WARMUP = 1, // sensor is in warmup + HM330X_ACTIVE = 2 // sensor is active and can be polled for data +}; + +struct HM330XDATA { + uint8_t warmup_counter; // count for warmup + bool valid; // valid data have been retrieved from the sensor + uint8_t state; // state machine + int8_t set_pin; // pin to set the device asleep or active + struct HM330XFrame rx_buffer; +}; + +struct HM330XDATA *HM330Xdata = nullptr; + + +int HM330XUpdate() { +#ifdef HM330X_SIM + HM330Xdata->rx_buffer.pm1_0_standard = 10; + HM330Xdata->rx_buffer.pm2_5_standard = 25; + HM330Xdata->rx_buffer.pm10_0_standard = 100; + HM330Xdata->rx_buffer.pm1_0_env = 1010; + HM330Xdata->rx_buffer.pm2_5_env = 1025; + HM330Xdata->rx_buffer.pm10_0_env = 1100; + HM330Xdata->rx_buffer.particles_0_3um = 2003; + HM330Xdata->rx_buffer.particles_0_5um = 2005; + HM330Xdata->rx_buffer.particles_1_0um = 2010; + HM330Xdata->rx_buffer.particles_2_5um = 2025; + HM330Xdata->rx_buffer.particles_5_0um = 2050; + HM330Xdata->rx_buffer.particles_10_0um = 2100; +#else + uint32_t time_out_count = 0; +#if HM330X_HIDE_OUT_OF_DATE + HM330Xdata->valid = false; +#endif + Wire.requestFrom((uint8_t)HM330X_DEFAULT_ADDRESS, (uint8_t)HM330X_FRAME_SIZE); + while (HM330X_FRAME_SIZE != Wire.available()) { + time_out_count++; + if (time_out_count > 10) { + return HM330X_ERROR_TIMEOUT; + } + delay(1); + } + uint8_t checksum = 0; + uint8_t *data = (uint8_t*)&(HM330Xdata->rx_buffer); + int i = 0; + for (; i < HM330X_FRAME_SIZE-1; i++) { + checksum += data[i] = Wire.read(); + } + data[i] = Wire.read(); + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, data, HM330X_FRAME_SIZE); + if (checksum != data[i]) { + AddLog(LOG_LEVEL_DEBUG, PSTR("HM3: checksum error")); + return HM330X_ERROR_CHECKSUM; + } + + for (i = 0; i < (HM330X_FRAME_SIZE/2); i++) { + uint8_t tmp = data[2*i]; // revert endianness + data[2*i] = data[2*i+1], + data[2*i+1] = tmp; + } +#endif + HM330Xdata->valid = true; + return HM330X_NO_ERROR; +} + +int HM330XSendI2CCommand(uint8_t cmd) { + int ret = HM330X_NO_ERROR; +#ifdef HM330X_SIM +#else + Wire.beginTransmission(HM330X_DEFAULT_ADDRESS); + Wire.write(cmd); + ret = Wire.endTransmission(); + if (ret != 0) { + ret = HM330X_ERROR_NOT_FOUND; + } +#endif + return ret; +} + +int HM330XInit() { + int8_t set_pin = Pin(GPIO_HM330X_SET); + if (set_pin >= 0) { + pinMode(set_pin, OUTPUT); + digitalWrite(set_pin, 1); + delay(5); + } + + if (I2cActive(HM330X_DEFAULT_ADDRESS)) { + AddLog(LOG_LEVEL_DEBUG, PSTR("HM3: Address 0x%02X already in use"), HM330X_DEFAULT_ADDRESS); + return HM330X_ERROR_PARAM; + } + + if (HM330X_NO_ERROR != HM330XSendI2CCommand(HM330X_SELECT_COMM_CMD)) { + AddLog(LOG_LEVEL_DEBUG, PSTR("HM3: no response from address 0x%02X"), HM330X_DEFAULT_ADDRESS); + return HM330X_ERROR_COMM; + } + + HM330Xdata = (HM330XDATA*)calloc(1,sizeof(HM330XDATA)); + if (!HM330Xdata) { + AddLog(LOG_LEVEL_DEBUG, PSTR("HM3: out of memory")); + return HM330X_ERROR_MEMALLOC; + } + + HM330Xdata->valid = false; + HM330Xdata->set_pin = set_pin; + HM330Xdata->state = HM330X_WARMUP; + HM330Xdata->warmup_counter = HM330X_WARMUP_DELAY; + + I2cSetActiveFound(HM330X_DEFAULT_ADDRESS, "HM330X"); + + return HM330X_NO_ERROR; +} + +void HM330XEverySecond() { + uint16_t time_until_tp = Settings->tele_period - TasmotaGlobal.tele_period; + + // if (HM330Xdata) + // AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("HM3: EverySec wu:%d, v:%d, s:%d, sp:%d"), + // HM330Xdata->warmup_counter, + // HM330Xdata->valid, + // HM330Xdata->state, + // HM330Xdata->set_pin + // ); + // else + // AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("HM3: nullptr")); + + if (HM330X_SLEEP == HM330Xdata->state) { + if (time_until_tp < (HM330X_WARMUP_DELAY+HM330X_PRE_TELEPERIOD_ENABLE)) { + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HM3: Exit sleep mode")); + if (HM330Xdata->set_pin >= 0) { + digitalWrite(HM330Xdata->set_pin, 1); + } + HM330Xdata->state = HM330X_WARMUP; + HM330Xdata->warmup_counter = HM330X_WARMUP_DELAY; +#if HM330X_HIDE_OUT_OF_DATE + HM330Xdata->valid = false; +#endif + } + } + if (HM330X_WARMUP == HM330Xdata->state) { + HM330Xdata->warmup_counter--; + if (0 == HM330Xdata->warmup_counter) { + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HM3: Warmup done")); + if (HM330X_NO_ERROR != HM330XSendI2CCommand(HM330X_SELECT_COMM_CMD)) { + AddLog(LOG_LEVEL_DEBUG, PSTR("HM3: no response from address 0x%02X"), HM330X_DEFAULT_ADDRESS); + } + HM330Xdata->state = HM330X_ACTIVE; + } + } + if (HM330X_ACTIVE == HM330Xdata->state) { + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HM3: Update")); + HM330XUpdate(); + } +} + +void HM330XEnterSleep() +{ + if (HM330Xdata->set_pin >= 0 && HM330X_ACTIVE == HM330Xdata->state && Settings->tele_period > (HM330X_WARMUP_DELAY+HM330X_PRE_TELEPERIOD_ENABLE)) { + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HM3: Enter sleep mode")); + digitalWrite(HM330Xdata->set_pin, 0); + HM330Xdata->state = HM330X_SLEEP; +#if HM330X_HIDE_OUT_OF_DATE + HM330Xdata->valid = false; +#endif + } +} + + +/*********************************************************************************************\ + * SNS Interface +\*********************************************************************************************/ + +const char JSON_HM330X_SNS[] PROGMEM = ",\"HM330X\":{" + "\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d," + "\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d," + "\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,\"PB5\":%d,\"PB10\":%d}"; + +const char HTTP_HM330X_SNS[] PROGMEM = + // "{s}HM330X " D_STANDARD_CONCENTRATION " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" + // "{s}HM330X " D_STANDARD_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" + // "{s}HM330X " D_STANDARD_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" + "{s}HM330X " D_ENVIRONMENTAL_CONCENTRATION " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" + "{s}HM330X " D_ENVIRONMENTAL_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" + "{s}HM330X " D_ENVIRONMENTAL_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" + "{s}HM330X " D_PARTICALS_BEYOND " 0.3 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" + "{s}HM330X " D_PARTICALS_BEYOND " 0.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" + "{s}HM330X " D_PARTICALS_BEYOND " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" + "{s}HM330X " D_PARTICALS_BEYOND " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" + "{s}HM330X " D_PARTICALS_BEYOND " 5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" + "{s}HM330X " D_PARTICALS_BEYOND " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"; // {s} = , {m} = , {e} = + + +void HM330XShow(bool json) +{ + if (HM330Xdata->valid) + { + if (json) { + ResponseAppend_P(JSON_HM330X_SNS, + HM330Xdata->rx_buffer.pm1_0_standard, HM330Xdata->rx_buffer.pm2_5_standard, HM330Xdata->rx_buffer.pm10_0_standard, + HM330Xdata->rx_buffer.pm1_0_env, HM330Xdata->rx_buffer.pm2_5_env, HM330Xdata->rx_buffer.pm10_0_env, + HM330Xdata->rx_buffer.particles_0_3um, HM330Xdata->rx_buffer.particles_0_5um, HM330Xdata->rx_buffer.particles_1_0um, + HM330Xdata->rx_buffer.particles_2_5um, HM330Xdata->rx_buffer.particles_5_0um, HM330Xdata->rx_buffer.particles_10_0um); +#ifdef USE_DOMOTICZ + if (0 == TasmotaGlobal.tele_period) { + DomoticzSensor(DZ_COUNT, HM330Xdata->rx_buffer.pm1_0_env); // PM1 + DomoticzSensor(DZ_VOLTAGE, HM330Xdata->rx_buffer.pm2_5_env); // PM2.5 + DomoticzSensor(DZ_CURRENT, HM330Xdata->rx_buffer.pm10_0_env); // PM10 + } +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_HM330X_SNS, + // HM330Xdata->rx_buffer.pm1_0_standard, HM330Xdata->rx_buffer.pm2_5_standard, HM330Xdata->rx_buffer.pm10_0_standard, + HM330Xdata->rx_buffer.pm1_0_env, HM330Xdata->rx_buffer.pm2_5_env, HM330Xdata->rx_buffer.pm10_0_env, + HM330Xdata->rx_buffer.particles_0_3um, HM330Xdata->rx_buffer.particles_0_5um, HM330Xdata->rx_buffer.particles_1_0um, + HM330Xdata->rx_buffer.particles_2_5um, HM330Xdata->rx_buffer.particles_5_0um, HM330Xdata->rx_buffer.particles_10_0um); +#endif // USE_WEBSERVER + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns93(byte function) +{ + if (!I2cEnabled(XI2C_63)) { return false; } + + bool result = false; + + if (FUNC_INIT == function) { + HM330XInit(); + } + else if (HM330Xdata) { + switch (function) { + case FUNC_EVERY_SECOND: + HM330XEverySecond(); + break; + case FUNC_AFTER_TELEPERIOD: + HM330XEnterSleep(); + break; + case FUNC_JSON_APPEND: + HM330XShow(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + HM330XShow(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_HM330X +#endif // USE_I2C diff --git a/tools/decode-status.py b/tools/decode-status.py index 77f70e268e92..0fef90db9237 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -182,8 +182,10 @@ "(Zigbee) Hide bridge topic from zigbee topic (use with SetOption89) (1)", "(DS18x20) Enable arithmetic mean over teleperiod for JSON temperature (1)", "(Wifi) Keep wifi in no-sleep mode, prevents some occasional unresponsiveness", - "","", - "","","","", + "(Web) Allow access without referer check", + "(Energy) Show phase information", + "(Debug) Show heap with logging timestamp", + "","","", "","","","", "","","","", "","","","" @@ -256,7 +258,7 @@ "USE_MPU_ACCEL","USE_TFMINIPLUS","USE_CSE7761","USE_BERRY", "USE_BM8563","USE_ENERGY_DUMMY","USE_AM2320","USE_T67XX", "USE_MCP2515","USE_TASMESH","USE_WIFI_RANGE_EXTENDER","USE_INFLUXDB", - "USE_HRG15","USE_VINDRIKTNING","USE_SCD40","", + "USE_HRG15","USE_VINDRIKTNING","USE_SCD40","USE_HM330X", "","","","", "","","","", "","","","", @@ -288,7 +290,7 @@ obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v20210901 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v20211008 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj))