mirror of https://github.com/arendst/Tasmota.git
Add support for HM330X
Add support for HM330X SeedStudio Grove Particule sensor (#13250)
This commit is contained in:
parent
eaeacbfa93
commit
a466c5abf3
|
@ -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 |
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#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} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
||||
|
||||
|
||||
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
|
|
@ -182,8 +182,10 @@ a_setoption = [[
|
|||
"(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 @@ a_features = [[
|
|||
"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 @@ else:
|
|||
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))
|
||||
|
||||
|
|
Loading…
Reference in New Issue