From e8edb99bb0a44733ec7fe09e986bd314410c058d Mon Sep 17 00:00:00 2001 From: ezcGman Date: Sun, 11 Dec 2022 01:16:14 +0100 Subject: [PATCH 01/11] UM SHT: Added SHT usermod --- usermods/sht/readme.md | 45 ++++++ usermods/sht/usermod_sht.h | 312 +++++++++++++++++++++++++++++++++++++ wled00/const.h | 1 + wled00/usermods_list.cpp | 10 +- 4 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 usermods/sht/readme.md create mode 100644 usermods/sht/usermod_sht.h diff --git a/usermods/sht/readme.md b/usermods/sht/readme.md new file mode 100644 index 00000000..1e17bdef --- /dev/null +++ b/usermods/sht/readme.md @@ -0,0 +1,45 @@ +# SHT +Usermod to support various SHT i2c sensors like the SHT30, SHT31, SHT35 and SHT85 + +## Requirements +* "SHT85" by Rob Tillaart, v0.2 or higher: https://github.com/RobTillaart/SHT85 + +## Usermod installation +1. Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one, add the buildflag `-D USERMOD_SHT` and the below library dependencies. +2. If you're not using thr SHT30 sensor, change the `-D USERMOD_SHT_TYPE_SHT30` build flag to one of these: `USERMOD_SHT_TYPE_SHT31`, `USERMOD_SHT_TYPE_SHT35` or `USERMOD_SHT_TYPE_SHT85`. + +ESP32: +``` +[env:custom_esp32dev_usermod_sht] +extends = env:esp32dev +build_flags = ${common.build_flags_esp32} + -D USERMOD_SHT + -D USERMOD_SHT_TYPE_SHT30 +lib_deps = ${esp32.lib_deps} + robtillaart/SHT85@~0.3.3 +``` + +ESP8266: +``` +[env:custom_d1_mini_usermod_quinled_an_penta] +extends = env:d1_mini +build_flags = ${common.build_flags_esp8266} + -D USERMOD_SHT + -D USERMOD_SHT_TYPE_SHT30 +lib_deps = ${esp8266.lib_deps} + olikraus/U8g2@~2.28.8 + robtillaart/SHT85@~0.2.0 +``` + +## MQTT Discovery for Home Assistant +If you're using Home Assistant and want to have the temperature and humidity available as entities in HA, you can tick the "Add-To-Home-Assistant-MQTT-Discovery" option in the usermod settings. If you have an MQTT broker configured under "Sync Settings" and it is connected, the mod will publish the auto discovery message to your broker and HA will instantly find it and create an entity each for the temperature and humidity. + +### Publishing readings via MQTT +Regardless of having MQTT discovery ticked or not, the mod will always report temperature and humidity to the WLED MQTT topic of that instance, if you have a broker configured and it's connected. + +## Change log +2022-12 +* First implementation. + +## Credits +ezcGman | Andy: Find me on the Intermit.Tech (QuinLED) Discord server: https://discord.gg/WdbAauG \ No newline at end of file diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h new file mode 100644 index 00000000..2fbaa7e6 --- /dev/null +++ b/usermods/sht/usermod_sht.h @@ -0,0 +1,312 @@ +#pragma once + +#include "SHT85.h" + + +class ShtUsermod : public Usermod +{ + private: + bool enabled = false; + bool firstRunDone = false; + bool initDone = false; + bool haMqttDiscovery = false; + SHT *shtTempHumidSensor; + + // SHT vars + bool shtInitDone = false; + bool shtReadDataSuccess = false; + byte shtI2cAddress = 0x44; + unsigned long shtLastTimeUpdated = 0; + bool shtDataRequested = false; + float shtCurrentTemp = 0; + float shtLastKnownTemp = 0; + float shtCurrentHumidity = 0; + float shtLastKnownHumidity = 0; + + + void initShtTempHumiditySensor() + { + PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; + if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { + DEBUG_PRINTF("[%s] SHT pin allocation failed!\n", _name); + shtInitDone = false; + cleanupShtTempHumiditySensor(); + cleanup(); + return; + } + + #ifdef USERMOD_SHT_TYPE_SHT31 + shtTempHumidSensor = (SHT *) new SHT31(); + #else + #ifdef USERMOD_SHT_TYPE_SHT35 + shtTempHumidSensor = (SHT *) new SHT35(); + #else + #ifdef USERMOD_SHT_TYPE_SHT85 + shtTempHumidSensor = (SHT *) new SHT85(); + #else + shtTempHumidSensor = (SHT *) new SHT30(); + #endif + #endif + #endif + + shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl); + if (shtTempHumidSensor->readStatus() == 0xFFFF) { + DEBUG_PRINTF("[%s] SHT init failed!\n", _name); + shtInitDone = false; + cleanupShtTempHumiditySensor(); + cleanup(); + return; + } + + shtInitDone = true; + } + + void cleanupShtTempHumiditySensor() + { + if (shtInitDone) { + shtTempHumidSensor->reset(); + } + + pinManager.deallocatePin(i2c_sda, PinOwner::HW_I2C); + pinManager.deallocatePin(i2c_scl, PinOwner::HW_I2C); + + delete shtTempHumidSensor; + + shtInitDone = false; + } + + void cleanup() + { + if (isShtReady()) { + cleanupShtTempHumiditySensor(); + } + + enabled = false; + } + + bool isShtReady() + { + return shtInitDone; + } + + + public: + // strings to reduce flash memory usage (used more than twice) + static const char _name[]; + static const char _enabled[]; + static const char _haMqttDiscovery[]; + + /* + * setup() is called once at boot. WiFi is not yet connected at this point. + * You can use it to initialize variables, sensors or similar. + */ + void setup() + { + if (enabled) { + initShtTempHumiditySensor(); + + initDone = true; + } + + firstRunDone = true; + } + + /* + * loop() is called continuously. Here you can check for events, read sensors, etc. + * + * Tips: + * 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection. + * Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker. + * + * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. + * Instead, use a timer check as shown here. + */ + void loop() + { + if (!enabled || !initDone || strip.isUpdating()) return; + + if (isShtReady()) { + if (millis() - shtLastTimeUpdated > 30000 && !shtDataRequested) { + shtTempHumidSensor->requestData(); + shtDataRequested = true; + + shtLastTimeUpdated = millis(); + } + + if (shtDataRequested) { + if (shtTempHumidSensor->dataReady()) { + if (shtTempHumidSensor->readData(false)) { + shtCurrentTemp = shtTempHumidSensor->getTemperature(); + shtCurrentHumidity = shtTempHumidSensor->getHumidity(); + + publishTemperatureAndHumidityViaMqtt(); + shtReadDataSuccess = true; + } + else { + shtReadDataSuccess = false; + } + + shtDataRequested = false; + } + } + } + } + + void onMqttConnect(bool sessionPresent) { + if (haMqttDiscovery) publishHomeAssistantAutodiscovery(); + } + + void addToConfig(JsonObject &root) + { + JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname + + top[FPSTR(_enabled)] = enabled; + top[FPSTR(_haMqttDiscovery)] = haMqttDiscovery; + } + + /** + * readFromConfig() is called before setup() to populate properties from values stored in cfg.json + * + * The function should return true if configuration was successfully loaded or false if there was no configuration. + */ + bool readFromConfig(JsonObject &root) + { + JsonObject top = root[FPSTR(_name)]; + if (top.isNull()) { + DEBUG_PRINTF("[%s] No config found. (Using defaults.)\n", _name); + return false; + } + + bool oldEnabled = enabled; + bool oldHaMqttDiscovery = haMqttDiscovery; + + getJsonValue(top[FPSTR(_enabled)], enabled); + getJsonValue(top[FPSTR(_haMqttDiscovery)], haMqttDiscovery); + + // First run: reading from cfg.json, nothing to do here, will be all done in setup() + if (!firstRunDone) { + DEBUG_PRINTF("[%s] First run, nothing to do\n", _name); + } + // Check if mod has been en-/disabled + else if (enabled != oldEnabled) { + enabled ? setup() : cleanup(); + DEBUG_PRINTF("[%s] Usermod has been en-/disabled\n", _name); + } + // Config has been changed, so adopt to changes + else if (enabled) { + if (oldHaMqttDiscovery != haMqttDiscovery && haMqttDiscovery) { + publishHomeAssistantAutodiscovery(); + } + + DEBUG_PRINTF("[%s] Config (re)loaded\n", _name); + } + + return true; + } + + void addToJsonInfo(JsonObject& root) + { + if (!enabled && !isShtReady()) { + return; + } + + JsonObject user = root["u"]; + if (user.isNull()) user = root.createNestedObject("u"); + + JsonArray jsonTemp = user.createNestedArray("Temperature"); + JsonArray jsonHumidity = user.createNestedArray("Humidity"); + + if (shtLastTimeUpdated == 0 || !shtReadDataSuccess) { + jsonTemp.add(0); + jsonHumidity.add(0); + if (shtLastTimeUpdated == 0) { + jsonTemp.add(" Not read yet"); + jsonHumidity.add(" Not read yet"); + } + else { + jsonTemp.add(" Error"); + jsonHumidity.add(" Error"); + } + + return; + } + + jsonHumidity.add(shtCurrentHumidity); + jsonHumidity.add(" RH"); + + jsonTemp.add(shtCurrentTemp); + jsonTemp.add(" °C"); + } + + void publishTemperatureAndHumidityViaMqtt() { + if (!WLED_MQTT_CONNECTED) return; + char buf[128]; + + sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic); + mqtt->publish(buf, 0, false, String(shtCurrentTemp).c_str()); + sprintf_P(buf, PSTR("%s/humidity"), mqttDeviceTopic); + mqtt->publish(buf, 0, false, String(shtCurrentHumidity).c_str()); + } + + void publishHomeAssistantAutodiscovery() { + if (!WLED_MQTT_CONNECTED) return; + + char json_str[1024], buf[128]; + size_t payload_size; + StaticJsonDocument<1024> json; + + sprintf_P(buf, PSTR("%s Temperature"), serverDescription); + json[F("name")] = buf; + sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic); + json[F("stat_t")] = buf; + json[F("dev_cla")] = F("temperature"); + json[F("stat_cla")] = F("measurement"); + sprintf_P(buf, PSTR("%s-temperature"), escapedMac.c_str()); + json[F("uniq_id")] = buf; + json[F("unit_of_meas")] = F("°C"); + appendDeviceToMqttDiscoveryMessage(json); + payload_size = serializeJson(json, json_str); + sprintf_P(buf, PSTR("homeassistant/sensor/%s/%s-temperature/config"), escapedMac.c_str(), escapedMac.c_str()); + mqtt->publish(buf, 0, true, json_str, payload_size); + + json.clear(); + + sprintf_P(buf, PSTR("%s Humidity"), serverDescription); + json[F("name")] = buf; + sprintf_P(buf, PSTR("%s/humidity"), mqttDeviceTopic); + json[F("stat_t")] = buf; + json[F("dev_cla")] = F("humidity"); + json[F("stat_cla")] = F("measurement"); + sprintf_P(buf, PSTR("%s-humidity"), escapedMac.c_str()); + json[F("uniq_id")] = buf; + json[F("unit_of_meas")] = F("%"); + appendDeviceToMqttDiscoveryMessage(json); + payload_size = serializeJson(json, json_str); + sprintf_P(buf, PSTR("homeassistant/sensor/%s/%s-humidity/config"), escapedMac.c_str(), escapedMac.c_str()); + mqtt->publish(buf, 0, true, json_str, payload_size); + } + + void appendDeviceToMqttDiscoveryMessage(JsonDocument& root) { + JsonObject device = root.createNestedObject("dev"); + device["ids"] = escapedMac.c_str(); + device["name"] = serverDescription; + device["sw"] = versionString; + device["mdl"] = ESP.getChipModel(); + device["mf"] = "espressif"; + } + + /* + * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). + * This could be used in the future for the system to determine whether your usermod is installed. + */ + uint16_t getId() + { + return USERMOD_ID_SHT; + } +}; + +// strings to reduce flash memory usage (used more than twice) +// Config settings +const char ShtUsermod::_name[] PROGMEM = "SHT Temperature & Humidity Sensor"; +const char ShtUsermod::_enabled[] PROGMEM = "Enabled"; +const char ShtUsermod::_haMqttDiscovery[] PROGMEM = "Add-To-Home-Assistant-MQTT-Discovery"; \ No newline at end of file diff --git a/wled00/const.h b/wled00/const.h index d863ee2e..8d445197 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -100,6 +100,7 @@ #define USERMOD_ID_BOBLIGHT 36 //Usermod "boblight.h" #define USERMOD_ID_SD_CARD 37 //Usermod "usermod_sd_card.h" #define USERMOD_ID_PWM_OUTPUTS 38 //Usermod "usermod_pwm_outputs.h +#define USERMOD_ID_SHT 39 //Usermod "usermod_sht.h //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 52c0f001..5472ab03 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -180,6 +180,10 @@ #include "../usermods/pwm_outputs/usermod_pwm_outputs.h" #endif +#ifdef USERMOD_SHT +#include "../usermods/sht/usermod_sht.h" +#endif + void registerUsermods() { @@ -292,7 +296,7 @@ void registerUsermods() #ifdef QUINLED_AN_PENTA usermods.add(new QuinLEDAnPentaUsermod()); #endif - + #ifdef USERMOD_WIZLIGHTS usermods.add(new WizLightsUsermod()); #endif @@ -340,4 +344,8 @@ void registerUsermods() #ifdef USERMOD_PWM_OUTPUTS usermods.add(new PwmOutputsUsermod()); #endif + + #ifdef USERMOD_SHT + usermods.add(new ShtUsermod()); + #endif } From 987dd364012889b6a627105ff22373b97d1a6f41 Mon Sep 17 00:00:00 2001 From: ezcGman Date: Sun, 11 Dec 2022 22:32:03 +0100 Subject: [PATCH 02/11] UM SHT: Using F() helper on some strings --- usermods/sht/usermod_sht.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index 2fbaa7e6..a384b38d 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -213,29 +213,29 @@ class ShtUsermod : public Usermod JsonObject user = root["u"]; if (user.isNull()) user = root.createNestedObject("u"); - JsonArray jsonTemp = user.createNestedArray("Temperature"); - JsonArray jsonHumidity = user.createNestedArray("Humidity"); + JsonArray jsonTemp = user.createNestedArray(F("Temperature")); + JsonArray jsonHumidity = user.createNestedArray(F("Humidity")); if (shtLastTimeUpdated == 0 || !shtReadDataSuccess) { jsonTemp.add(0); jsonHumidity.add(0); if (shtLastTimeUpdated == 0) { - jsonTemp.add(" Not read yet"); - jsonHumidity.add(" Not read yet"); + jsonTemp.add(F(" Not read yet")); + jsonHumidity.add(F(" Not read yet")); } else { - jsonTemp.add(" Error"); - jsonHumidity.add(" Error"); + jsonTemp.add(F(" Error")); + jsonHumidity.add(F(" Error")); } return; } jsonHumidity.add(shtCurrentHumidity); - jsonHumidity.add(" RH"); + jsonHumidity.add(F(" RH")); jsonTemp.add(shtCurrentTemp); - jsonTemp.add(" °C"); + jsonTemp.add(F(" °C")); } void publishTemperatureAndHumidityViaMqtt() { @@ -288,11 +288,11 @@ class ShtUsermod : public Usermod void appendDeviceToMqttDiscoveryMessage(JsonDocument& root) { JsonObject device = root.createNestedObject("dev"); - device["ids"] = escapedMac.c_str(); - device["name"] = serverDescription; - device["sw"] = versionString; - device["mdl"] = ESP.getChipModel(); - device["mf"] = "espressif"; + device[F("ids")] = escapedMac.c_str(); + device[F("name")] = serverDescription; + device[F("sw")] = versionString; + device[F("mdl")] = ESP.getChipModel(); + device[F("mf")] = F("espressif"); } /* @@ -307,6 +307,6 @@ class ShtUsermod : public Usermod // strings to reduce flash memory usage (used more than twice) // Config settings -const char ShtUsermod::_name[] PROGMEM = "SHT Temperature & Humidity Sensor"; +const char ShtUsermod::_name[] PROGMEM = "SHT Sensor"; const char ShtUsermod::_enabled[] PROGMEM = "Enabled"; const char ShtUsermod::_haMqttDiscovery[] PROGMEM = "Add-To-Home-Assistant-MQTT-Discovery"; \ No newline at end of file From 19146d8012bb726844e67d4f972098617f2ad9e4 Mon Sep 17 00:00:00 2001 From: ezcGman Date: Mon, 12 Dec 2022 02:05:02 +0100 Subject: [PATCH 03/11] UM SHT: Made type a setting instead of buildflag --- usermods/sht/usermod_sht.h | 76 ++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index a384b38d..7a5f8082 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -2,6 +2,10 @@ #include "SHT85.h" +#define USERMOD_SHT_TYPE_SHT30 0 +#define USERMOD_SHT_TYPE_SHT31 1 +#define USERMOD_SHT_TYPE_SHT35 2 +#define USERMOD_SHT_TYPE_SHT85 3 class ShtUsermod : public Usermod { @@ -10,9 +14,10 @@ class ShtUsermod : public Usermod bool firstRunDone = false; bool initDone = false; bool haMqttDiscovery = false; - SHT *shtTempHumidSensor; // SHT vars + SHT *shtTempHumidSensor; + byte shtType = 0; bool shtInitDone = false; bool shtReadDataSuccess = false; byte shtI2cAddress = 0x44; @@ -26,29 +31,13 @@ class ShtUsermod : public Usermod void initShtTempHumiditySensor() { - PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; - if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { - DEBUG_PRINTF("[%s] SHT pin allocation failed!\n", _name); - shtInitDone = false; - cleanupShtTempHumiditySensor(); - cleanup(); - return; + switch (shtType) { + case USERMOD_SHT_TYPE_SHT30: shtTempHumidSensor = (SHT *) new SHT30(); break; + case USERMOD_SHT_TYPE_SHT31: shtTempHumidSensor = (SHT *) new SHT31(); break; + case USERMOD_SHT_TYPE_SHT35: shtTempHumidSensor = (SHT *) new SHT35(); break; + case USERMOD_SHT_TYPE_SHT85: shtTempHumidSensor = (SHT *) new SHT85(); break; } - #ifdef USERMOD_SHT_TYPE_SHT31 - shtTempHumidSensor = (SHT *) new SHT31(); - #else - #ifdef USERMOD_SHT_TYPE_SHT35 - shtTempHumidSensor = (SHT *) new SHT35(); - #else - #ifdef USERMOD_SHT_TYPE_SHT85 - shtTempHumidSensor = (SHT *) new SHT85(); - #else - shtTempHumidSensor = (SHT *) new SHT30(); - #endif - #endif - #endif - shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl); if (shtTempHumidSensor->readStatus() == 0xFFFF) { DEBUG_PRINTF("[%s] SHT init failed!\n", _name); @@ -67,9 +56,6 @@ class ShtUsermod : public Usermod shtTempHumidSensor->reset(); } - pinManager.deallocatePin(i2c_sda, PinOwner::HW_I2C); - pinManager.deallocatePin(i2c_scl, PinOwner::HW_I2C); - delete shtTempHumidSensor; shtInitDone = false; @@ -81,6 +67,9 @@ class ShtUsermod : public Usermod cleanupShtTempHumiditySensor(); } + pinManager.deallocatePin(i2c_sda, PinOwner::HW_I2C); + pinManager.deallocatePin(i2c_scl, PinOwner::HW_I2C); + enabled = false; } @@ -95,6 +84,7 @@ class ShtUsermod : public Usermod static const char _name[]; static const char _enabled[]; static const char _haMqttDiscovery[]; + static const char _shtType[]; /* * setup() is called once at boot. WiFi is not yet connected at this point. @@ -103,6 +93,15 @@ class ShtUsermod : public Usermod void setup() { if (enabled) { + PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; + if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { + DEBUG_PRINTF("[%s] SHT pin allocation failed!\n", _name); + shtInitDone = false; + cleanupShtTempHumiditySensor(); + cleanup(); + return; + } + initShtTempHumiditySensor(); initDone = true; @@ -156,12 +155,25 @@ class ShtUsermod : public Usermod if (haMqttDiscovery) publishHomeAssistantAutodiscovery(); } + void appendConfigData() { + oappend(SET_F("dd=addDropdown('")); + oappend(_name); + oappend(SET_F("','")); + oappend(_shtType); + oappend(SET_F("');")); + oappend(SET_F("addOption(dd,'SHT30',0);")); + oappend(SET_F("addOption(dd,'SHT31',1);")); + oappend(SET_F("addOption(dd,'SHT35',2);")); + oappend(SET_F("addOption(dd,'SHT85',3);")); + } + void addToConfig(JsonObject &root) { JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname top[FPSTR(_enabled)] = enabled; top[FPSTR(_haMqttDiscovery)] = haMqttDiscovery; + top[FPSTR(_shtType)] = shtType; } /** @@ -179,9 +191,11 @@ class ShtUsermod : public Usermod bool oldEnabled = enabled; bool oldHaMqttDiscovery = haMqttDiscovery; - + byte oldShtType = shtType; + getJsonValue(top[FPSTR(_enabled)], enabled); getJsonValue(top[FPSTR(_haMqttDiscovery)], haMqttDiscovery); + getJsonValue(top[FPSTR(_shtType)], shtType); // First run: reading from cfg.json, nothing to do here, will be all done in setup() if (!firstRunDone) { @@ -198,6 +212,11 @@ class ShtUsermod : public Usermod publishHomeAssistantAutodiscovery(); } + if (oldShtType != shtType) { + cleanupShtTempHumiditySensor(); + initShtTempHumiditySensor(); + } + DEBUG_PRINTF("[%s] Config (re)loaded\n", _name); } @@ -307,6 +326,7 @@ class ShtUsermod : public Usermod // strings to reduce flash memory usage (used more than twice) // Config settings -const char ShtUsermod::_name[] PROGMEM = "SHT Sensor"; +const char ShtUsermod::_name[] PROGMEM = "SHT-Sensor"; const char ShtUsermod::_enabled[] PROGMEM = "Enabled"; -const char ShtUsermod::_haMqttDiscovery[] PROGMEM = "Add-To-Home-Assistant-MQTT-Discovery"; \ No newline at end of file +const char ShtUsermod::_haMqttDiscovery[] PROGMEM = "Add-To-Home-Assistant-MQTT-Discovery"; +const char ShtUsermod::_shtType[] PROGMEM = "SHT-Type"; \ No newline at end of file From 2123e43490c17ac9d7f79f3e0443a47c8ff8b8d2 Mon Sep 17 00:00:00 2001 From: ezcGman Date: Mon, 12 Dec 2022 02:33:31 +0100 Subject: [PATCH 04/11] UM SHT: Added Fahrenheit support --- usermods/sht/usermod_sht.h | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index 7a5f8082..31def055 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -17,14 +17,15 @@ class ShtUsermod : public Usermod // SHT vars SHT *shtTempHumidSensor; - byte shtType = 0; + byte shtType = 0; // Default: SHT30 + byte unitOfTemp = 0; // Default: Celsius (0 = Celsius, 1 = Fahrenheit) bool shtInitDone = false; bool shtReadDataSuccess = false; byte shtI2cAddress = 0x44; unsigned long shtLastTimeUpdated = 0; bool shtDataRequested = false; - float shtCurrentTemp = 0; - float shtLastKnownTemp = 0; + float shtCurrentTempC = 0; + float shtCurrentTempF = 0; float shtCurrentHumidity = 0; float shtLastKnownHumidity = 0; @@ -85,6 +86,7 @@ class ShtUsermod : public Usermod static const char _enabled[]; static const char _haMqttDiscovery[]; static const char _shtType[]; + static const char _unitOfTemp[]; /* * setup() is called once at boot. WiFi is not yet connected at this point. @@ -135,7 +137,8 @@ class ShtUsermod : public Usermod if (shtDataRequested) { if (shtTempHumidSensor->dataReady()) { if (shtTempHumidSensor->readData(false)) { - shtCurrentTemp = shtTempHumidSensor->getTemperature(); + shtCurrentTempC = shtTempHumidSensor->getTemperature(); + shtCurrentTempF = shtTempHumidSensor->getFahrenheit(); shtCurrentHumidity = shtTempHumidSensor->getHumidity(); publishTemperatureAndHumidityViaMqtt(); @@ -165,6 +168,13 @@ class ShtUsermod : public Usermod oappend(SET_F("addOption(dd,'SHT31',1);")); oappend(SET_F("addOption(dd,'SHT35',2);")); oappend(SET_F("addOption(dd,'SHT85',3);")); + oappend(SET_F("dd=addDropdown('")); + oappend(_name); + oappend(SET_F("','")); + oappend(_unitOfTemp); + oappend(SET_F("');")); + oappend(SET_F("addOption(dd,'Celsius',0);")); + oappend(SET_F("addOption(dd,'Fahrenheit',1);")); } void addToConfig(JsonObject &root) @@ -174,6 +184,7 @@ class ShtUsermod : public Usermod top[FPSTR(_enabled)] = enabled; top[FPSTR(_haMqttDiscovery)] = haMqttDiscovery; top[FPSTR(_shtType)] = shtType; + top[FPSTR(_unitOfTemp)] = unitOfTemp; } /** @@ -196,6 +207,7 @@ class ShtUsermod : public Usermod getJsonValue(top[FPSTR(_enabled)], enabled); getJsonValue(top[FPSTR(_haMqttDiscovery)], haMqttDiscovery); getJsonValue(top[FPSTR(_shtType)], shtType); + getJsonValue(top[FPSTR(_unitOfTemp)], unitOfTemp); // First run: reading from cfg.json, nothing to do here, will be all done in setup() if (!firstRunDone) { @@ -253,8 +265,8 @@ class ShtUsermod : public Usermod jsonHumidity.add(shtCurrentHumidity); jsonHumidity.add(F(" RH")); - jsonTemp.add(shtCurrentTemp); - jsonTemp.add(F(" °C")); + unitOfTemp ? jsonTemp.add(getTemperatureF()) : jsonTemp.add(getTemperatureC()); + unitOfTemp ? jsonTemp.add(F(" °F")) : jsonTemp.add(F(" °C")); } void publishTemperatureAndHumidityViaMqtt() { @@ -262,7 +274,7 @@ class ShtUsermod : public Usermod char buf[128]; sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic); - mqtt->publish(buf, 0, false, String(shtCurrentTemp).c_str()); + mqtt->publish(buf, 0, false, String((unitOfTemp ? getTemperatureF() : getTemperatureC())).c_str()); sprintf_P(buf, PSTR("%s/humidity"), mqttDeviceTopic); mqtt->publish(buf, 0, false, String(shtCurrentHumidity).c_str()); } @@ -314,6 +326,14 @@ class ShtUsermod : public Usermod device[F("mf")] = F("espressif"); } + float getTemperatureC() { + return shtCurrentTempC; + } + + float getTemperatureF() { + return shtCurrentTempF; + } + /* * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. @@ -329,4 +349,5 @@ class ShtUsermod : public Usermod const char ShtUsermod::_name[] PROGMEM = "SHT-Sensor"; const char ShtUsermod::_enabled[] PROGMEM = "Enabled"; const char ShtUsermod::_haMqttDiscovery[] PROGMEM = "Add-To-Home-Assistant-MQTT-Discovery"; -const char ShtUsermod::_shtType[] PROGMEM = "SHT-Type"; \ No newline at end of file +const char ShtUsermod::_shtType[] PROGMEM = "SHT-Type"; +const char ShtUsermod::_unitOfTemp[] PROGMEM = "Unit"; \ No newline at end of file From 9587480e29947c8e76395e51619ff195d9a05150 Mon Sep 17 00:00:00 2001 From: ezcGman Date: Thu, 15 Dec 2022 00:41:08 +0100 Subject: [PATCH 05/11] UM SHT: Updated ReadMe --- usermods/sht/readme.md | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/usermods/sht/readme.md b/usermods/sht/readme.md index 1e17bdef..78ec80a2 100644 --- a/usermods/sht/readme.md +++ b/usermods/sht/readme.md @@ -5,8 +5,7 @@ Usermod to support various SHT i2c sensors like the SHT30, SHT31, SHT35 and SHT8 * "SHT85" by Rob Tillaart, v0.2 or higher: https://github.com/RobTillaart/SHT85 ## Usermod installation -1. Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one, add the buildflag `-D USERMOD_SHT` and the below library dependencies. -2. If you're not using thr SHT30 sensor, change the `-D USERMOD_SHT_TYPE_SHT30` build flag to one of these: `USERMOD_SHT_TYPE_SHT31`, `USERMOD_SHT_TYPE_SHT35` or `USERMOD_SHT_TYPE_SHT85`. +Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one, add the buildflag `-D USERMOD_SHT` and the below library dependencies. ESP32: ``` @@ -14,7 +13,6 @@ ESP32: extends = env:esp32dev build_flags = ${common.build_flags_esp32} -D USERMOD_SHT - -D USERMOD_SHT_TYPE_SHT30 lib_deps = ${esp32.lib_deps} robtillaart/SHT85@~0.3.3 ``` @@ -25,10 +23,8 @@ ESP8266: extends = env:d1_mini build_flags = ${common.build_flags_esp8266} -D USERMOD_SHT - -D USERMOD_SHT_TYPE_SHT30 lib_deps = ${esp8266.lib_deps} - olikraus/U8g2@~2.28.8 - robtillaart/SHT85@~0.2.0 + robtillaart/SHT85@~0.3.3 ``` ## MQTT Discovery for Home Assistant @@ -37,6 +33,21 @@ If you're using Home Assistant and want to have the temperature and humidity ava ### Publishing readings via MQTT Regardless of having MQTT discovery ticked or not, the mod will always report temperature and humidity to the WLED MQTT topic of that instance, if you have a broker configured and it's connected. +## Configuration +Navigate to the "Config" and then to the "Usermods" section. If you compiled WLED with `-D USERMOD_SHT`, you will see the config for it there: +* SHT-Type: + * What it does: Select the SHT sensor type you want to use + * Possible values: SHT30, SHT31, SHT35, SHT85 + * Default: SHT30 +* Unit: + * What it does: Select which unit should be used to display the temperature in the info section. Also used when sending via MQTT discovery, see below. + * Possible values: Celsius, Fahrenheit + * Default: Celsius +* Add-To-HA-MQTT-Discovery: + * What it does: Makes the temperature and humidity available via MQTT discovery, so they're automatically added to Home Assistant, because that way it's typesafe. + * Possible values: Enabled/Disabled + * Default: Disabled + ## Change log 2022-12 * First implementation. From a3f6717c591e33938a683cdb1bc77d8e5ef0c4d1 Mon Sep 17 00:00:00 2001 From: ezcGman Date: Thu, 15 Dec 2022 00:42:27 +0100 Subject: [PATCH 06/11] UM SHT: Avoid inline methods --- usermods/sht/usermod_sht.h | 605 ++++++++++++++++++++----------------- 1 file changed, 321 insertions(+), 284 deletions(-) diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index 31def055..e7e4b10d 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -30,87 +30,28 @@ class ShtUsermod : public Usermod float shtLastKnownHumidity = 0; - void initShtTempHumiditySensor() - { - switch (shtType) { - case USERMOD_SHT_TYPE_SHT30: shtTempHumidSensor = (SHT *) new SHT30(); break; - case USERMOD_SHT_TYPE_SHT31: shtTempHumidSensor = (SHT *) new SHT31(); break; - case USERMOD_SHT_TYPE_SHT35: shtTempHumidSensor = (SHT *) new SHT35(); break; - case USERMOD_SHT_TYPE_SHT85: shtTempHumidSensor = (SHT *) new SHT85(); break; - } - - shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl); - if (shtTempHumidSensor->readStatus() == 0xFFFF) { - DEBUG_PRINTF("[%s] SHT init failed!\n", _name); - shtInitDone = false; - cleanupShtTempHumiditySensor(); - cleanup(); - return; - } - - shtInitDone = true; - } - - void cleanupShtTempHumiditySensor() - { - if (shtInitDone) { - shtTempHumidSensor->reset(); - } - - delete shtTempHumidSensor; - - shtInitDone = false; - } - - void cleanup() - { - if (isShtReady()) { - cleanupShtTempHumiditySensor(); - } - - pinManager.deallocatePin(i2c_sda, PinOwner::HW_I2C); - pinManager.deallocatePin(i2c_scl, PinOwner::HW_I2C); - - enabled = false; - } - - bool isShtReady() - { - return shtInitDone; - } + void initShtTempHumiditySensor(); + void cleanupShtTempHumiditySensor(); + void cleanup(); + bool isShtReady(); + void publishTemperatureAndHumidityViaMqtt(); + void publishHomeAssistantAutodiscovery(); + void appendDeviceToMqttDiscoveryMessage(JsonDocument& root); public: // strings to reduce flash memory usage (used more than twice) static const char _name[]; static const char _enabled[]; - static const char _haMqttDiscovery[]; static const char _shtType[]; static const char _unitOfTemp[]; + static const char _haMqttDiscovery[]; /* * setup() is called once at boot. WiFi is not yet connected at this point. * You can use it to initialize variables, sensors or similar. */ - void setup() - { - if (enabled) { - PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; - if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { - DEBUG_PRINTF("[%s] SHT pin allocation failed!\n", _name); - shtInitDone = false; - cleanupShtTempHumiditySensor(); - cleanup(); - return; - } - - initShtTempHumiditySensor(); - - initDone = true; - } - - firstRunDone = true; - } + void setup(); /* * loop() is called continuously. Here you can check for events, read sensors, etc. @@ -122,232 +63,328 @@ class ShtUsermod : public Usermod * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. * Instead, use a timer check as shown here. */ - void loop() - { - if (!enabled || !initDone || strip.isUpdating()) return; + void loop(); + void onMqttConnect(bool sessionPresent); + void appendConfigData(); + void addToConfig(JsonObject &root); + bool readFromConfig(JsonObject &root); + void addToJsonInfo(JsonObject& root); - if (isShtReady()) { - if (millis() - shtLastTimeUpdated > 30000 && !shtDataRequested) { - shtTempHumidSensor->requestData(); - shtDataRequested = true; - - shtLastTimeUpdated = millis(); - } - - if (shtDataRequested) { - if (shtTempHumidSensor->dataReady()) { - if (shtTempHumidSensor->readData(false)) { - shtCurrentTempC = shtTempHumidSensor->getTemperature(); - shtCurrentTempF = shtTempHumidSensor->getFahrenheit(); - shtCurrentHumidity = shtTempHumidSensor->getHumidity(); - - publishTemperatureAndHumidityViaMqtt(); - shtReadDataSuccess = true; - } - else { - shtReadDataSuccess = false; - } - - shtDataRequested = false; - } - } - } - } - - void onMqttConnect(bool sessionPresent) { - if (haMqttDiscovery) publishHomeAssistantAutodiscovery(); - } - - void appendConfigData() { - oappend(SET_F("dd=addDropdown('")); - oappend(_name); - oappend(SET_F("','")); - oappend(_shtType); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'SHT30',0);")); - oappend(SET_F("addOption(dd,'SHT31',1);")); - oappend(SET_F("addOption(dd,'SHT35',2);")); - oappend(SET_F("addOption(dd,'SHT85',3);")); - oappend(SET_F("dd=addDropdown('")); - oappend(_name); - oappend(SET_F("','")); - oappend(_unitOfTemp); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'Celsius',0);")); - oappend(SET_F("addOption(dd,'Fahrenheit',1);")); - } - - void addToConfig(JsonObject &root) - { - JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname - - top[FPSTR(_enabled)] = enabled; - top[FPSTR(_haMqttDiscovery)] = haMqttDiscovery; - top[FPSTR(_shtType)] = shtType; - top[FPSTR(_unitOfTemp)] = unitOfTemp; - } - - /** - * readFromConfig() is called before setup() to populate properties from values stored in cfg.json - * - * The function should return true if configuration was successfully loaded or false if there was no configuration. - */ - bool readFromConfig(JsonObject &root) - { - JsonObject top = root[FPSTR(_name)]; - if (top.isNull()) { - DEBUG_PRINTF("[%s] No config found. (Using defaults.)\n", _name); - return false; - } - - bool oldEnabled = enabled; - bool oldHaMqttDiscovery = haMqttDiscovery; - byte oldShtType = shtType; - - getJsonValue(top[FPSTR(_enabled)], enabled); - getJsonValue(top[FPSTR(_haMqttDiscovery)], haMqttDiscovery); - getJsonValue(top[FPSTR(_shtType)], shtType); - getJsonValue(top[FPSTR(_unitOfTemp)], unitOfTemp); - - // First run: reading from cfg.json, nothing to do here, will be all done in setup() - if (!firstRunDone) { - DEBUG_PRINTF("[%s] First run, nothing to do\n", _name); - } - // Check if mod has been en-/disabled - else if (enabled != oldEnabled) { - enabled ? setup() : cleanup(); - DEBUG_PRINTF("[%s] Usermod has been en-/disabled\n", _name); - } - // Config has been changed, so adopt to changes - else if (enabled) { - if (oldHaMqttDiscovery != haMqttDiscovery && haMqttDiscovery) { - publishHomeAssistantAutodiscovery(); - } - - if (oldShtType != shtType) { - cleanupShtTempHumiditySensor(); - initShtTempHumiditySensor(); - } - - DEBUG_PRINTF("[%s] Config (re)loaded\n", _name); - } - - return true; - } - - void addToJsonInfo(JsonObject& root) - { - if (!enabled && !isShtReady()) { - return; - } - - JsonObject user = root["u"]; - if (user.isNull()) user = root.createNestedObject("u"); - - JsonArray jsonTemp = user.createNestedArray(F("Temperature")); - JsonArray jsonHumidity = user.createNestedArray(F("Humidity")); - - if (shtLastTimeUpdated == 0 || !shtReadDataSuccess) { - jsonTemp.add(0); - jsonHumidity.add(0); - if (shtLastTimeUpdated == 0) { - jsonTemp.add(F(" Not read yet")); - jsonHumidity.add(F(" Not read yet")); - } - else { - jsonTemp.add(F(" Error")); - jsonHumidity.add(F(" Error")); - } - - return; - } - - jsonHumidity.add(shtCurrentHumidity); - jsonHumidity.add(F(" RH")); - - unitOfTemp ? jsonTemp.add(getTemperatureF()) : jsonTemp.add(getTemperatureC()); - unitOfTemp ? jsonTemp.add(F(" °F")) : jsonTemp.add(F(" °C")); - } - - void publishTemperatureAndHumidityViaMqtt() { - if (!WLED_MQTT_CONNECTED) return; - char buf[128]; - - sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic); - mqtt->publish(buf, 0, false, String((unitOfTemp ? getTemperatureF() : getTemperatureC())).c_str()); - sprintf_P(buf, PSTR("%s/humidity"), mqttDeviceTopic); - mqtt->publish(buf, 0, false, String(shtCurrentHumidity).c_str()); - } - - void publishHomeAssistantAutodiscovery() { - if (!WLED_MQTT_CONNECTED) return; - - char json_str[1024], buf[128]; - size_t payload_size; - StaticJsonDocument<1024> json; - - sprintf_P(buf, PSTR("%s Temperature"), serverDescription); - json[F("name")] = buf; - sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic); - json[F("stat_t")] = buf; - json[F("dev_cla")] = F("temperature"); - json[F("stat_cla")] = F("measurement"); - sprintf_P(buf, PSTR("%s-temperature"), escapedMac.c_str()); - json[F("uniq_id")] = buf; - json[F("unit_of_meas")] = F("°C"); - appendDeviceToMqttDiscoveryMessage(json); - payload_size = serializeJson(json, json_str); - sprintf_P(buf, PSTR("homeassistant/sensor/%s/%s-temperature/config"), escapedMac.c_str(), escapedMac.c_str()); - mqtt->publish(buf, 0, true, json_str, payload_size); - - json.clear(); - - sprintf_P(buf, PSTR("%s Humidity"), serverDescription); - json[F("name")] = buf; - sprintf_P(buf, PSTR("%s/humidity"), mqttDeviceTopic); - json[F("stat_t")] = buf; - json[F("dev_cla")] = F("humidity"); - json[F("stat_cla")] = F("measurement"); - sprintf_P(buf, PSTR("%s-humidity"), escapedMac.c_str()); - json[F("uniq_id")] = buf; - json[F("unit_of_meas")] = F("%"); - appendDeviceToMqttDiscoveryMessage(json); - payload_size = serializeJson(json, json_str); - sprintf_P(buf, PSTR("homeassistant/sensor/%s/%s-humidity/config"), escapedMac.c_str(), escapedMac.c_str()); - mqtt->publish(buf, 0, true, json_str, payload_size); - } - - void appendDeviceToMqttDiscoveryMessage(JsonDocument& root) { - JsonObject device = root.createNestedObject("dev"); - device[F("ids")] = escapedMac.c_str(); - device[F("name")] = serverDescription; - device[F("sw")] = versionString; - device[F("mdl")] = ESP.getChipModel(); - device[F("mf")] = F("espressif"); - } - - float getTemperatureC() { - return shtCurrentTempC; - } - - float getTemperatureF() { - return shtCurrentTempF; - } + float getTemperatureC(); + float getTemperatureF(); + float getHumidity(); /* * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. */ - uint16_t getId() - { - return USERMOD_ID_SHT; - } + uint16_t getId() { return USERMOD_ID_SHT; } }; // strings to reduce flash memory usage (used more than twice) // Config settings const char ShtUsermod::_name[] PROGMEM = "SHT-Sensor"; const char ShtUsermod::_enabled[] PROGMEM = "Enabled"; -const char ShtUsermod::_haMqttDiscovery[] PROGMEM = "Add-To-Home-Assistant-MQTT-Discovery"; const char ShtUsermod::_shtType[] PROGMEM = "SHT-Type"; -const char ShtUsermod::_unitOfTemp[] PROGMEM = "Unit"; \ No newline at end of file +const char ShtUsermod::_unitOfTemp[] PROGMEM = "Unit"; +const char ShtUsermod::_haMqttDiscovery[] PROGMEM = "Add-To-HA-MQTT-Discovery"; + + +void ShtUsermod::initShtTempHumiditySensor() +{ + switch (shtType) { + case USERMOD_SHT_TYPE_SHT30: shtTempHumidSensor = (SHT *) new SHT30(); break; + case USERMOD_SHT_TYPE_SHT31: shtTempHumidSensor = (SHT *) new SHT31(); break; + case USERMOD_SHT_TYPE_SHT35: shtTempHumidSensor = (SHT *) new SHT35(); break; + case USERMOD_SHT_TYPE_SHT85: shtTempHumidSensor = (SHT *) new SHT85(); break; + } + + shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl); + if (shtTempHumidSensor->readStatus() == 0xFFFF) { + DEBUG_PRINTF("[%s] SHT init failed!\n", _name); + shtInitDone = false; + cleanupShtTempHumiditySensor(); + cleanup(); + return; + } + + shtInitDone = true; +} + +void ShtUsermod::cleanupShtTempHumiditySensor() +{ + if (shtInitDone) { + shtTempHumidSensor->reset(); + } + + delete shtTempHumidSensor; + + shtInitDone = false; +} + +void ShtUsermod::cleanup() +{ + if (isShtReady()) { + cleanupShtTempHumiditySensor(); + } + + pinManager.deallocatePin(i2c_sda, PinOwner::HW_I2C); + pinManager.deallocatePin(i2c_scl, PinOwner::HW_I2C); + + enabled = false; +} + +bool ShtUsermod::isShtReady() +{ + return shtInitDone; +} + +void ShtUsermod::publishTemperatureAndHumidityViaMqtt() { + if (!WLED_MQTT_CONNECTED) return; + char buf[128]; + + sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic); + mqtt->publish(buf, 0, false, String((unitOfTemp ? getTemperatureF() : getTemperatureC())).c_str()); + sprintf_P(buf, PSTR("%s/humidity"), mqttDeviceTopic); + mqtt->publish(buf, 0, false, String(shtCurrentHumidity).c_str()); +} + +void ShtUsermod::publishHomeAssistantAutodiscovery() { + if (!WLED_MQTT_CONNECTED) return; + + char json_str[1024], buf[128]; + size_t payload_size; + StaticJsonDocument<1024> json; + + sprintf_P(buf, PSTR("%s Temperature"), serverDescription); + json[F("name")] = buf; + sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic); + json[F("stat_t")] = buf; + json[F("dev_cla")] = F("temperature"); + json[F("stat_cla")] = F("measurement"); + sprintf_P(buf, PSTR("%s-temperature"), escapedMac.c_str()); + json[F("uniq_id")] = buf; + json[F("unit_of_meas")] = F("°C"); + appendDeviceToMqttDiscoveryMessage(json); + payload_size = serializeJson(json, json_str); + sprintf_P(buf, PSTR("homeassistant/sensor/%s/%s-temperature/config"), escapedMac.c_str(), escapedMac.c_str()); + mqtt->publish(buf, 0, true, json_str, payload_size); + + json.clear(); + + sprintf_P(buf, PSTR("%s Humidity"), serverDescription); + json[F("name")] = buf; + sprintf_P(buf, PSTR("%s/humidity"), mqttDeviceTopic); + json[F("stat_t")] = buf; + json[F("dev_cla")] = F("humidity"); + json[F("stat_cla")] = F("measurement"); + sprintf_P(buf, PSTR("%s-humidity"), escapedMac.c_str()); + json[F("uniq_id")] = buf; + json[F("unit_of_meas")] = F("%"); + appendDeviceToMqttDiscoveryMessage(json); + payload_size = serializeJson(json, json_str); + sprintf_P(buf, PSTR("homeassistant/sensor/%s/%s-humidity/config"), escapedMac.c_str(), escapedMac.c_str()); + mqtt->publish(buf, 0, true, json_str, payload_size); +} + +void ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) { + JsonObject device = root.createNestedObject("dev"); + device[F("ids")] = escapedMac.c_str(); + device[F("name")] = serverDescription; + device[F("sw")] = versionString; + device[F("mdl")] = ESP.getChipModel(); + device[F("mf")] = F("espressif"); +} + +/* + * setup() is called once at boot. WiFi is not yet connected at this point. + * You can use it to initialize variables, sensors or similar. + */ +void ShtUsermod::setup() +{ + if (enabled) { + PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; + if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { + DEBUG_PRINTF("[%s] SHT pin allocation failed!\n", _name); + shtInitDone = false; + cleanupShtTempHumiditySensor(); + cleanup(); + return; + } + + initShtTempHumiditySensor(); + + initDone = true; + } + + firstRunDone = true; +} + +/* + * loop() is called continuously. Here you can check for events, read sensors, etc. + * + * Tips: + * 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection. + * Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker. + * + * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. + * Instead, use a timer check as shown here. + */ +void ShtUsermod::loop() +{ + if (!enabled || !initDone || strip.isUpdating()) return; + + if (isShtReady()) { + if (millis() - shtLastTimeUpdated > 30000 && !shtDataRequested) { + shtTempHumidSensor->requestData(); + shtDataRequested = true; + + shtLastTimeUpdated = millis(); + } + + if (shtDataRequested) { + if (shtTempHumidSensor->dataReady()) { + if (shtTempHumidSensor->readData(false)) { + shtCurrentTempC = shtTempHumidSensor->getTemperature(); + shtCurrentTempF = shtTempHumidSensor->getFahrenheit(); + shtCurrentHumidity = shtTempHumidSensor->getHumidity(); + + publishTemperatureAndHumidityViaMqtt(); + shtReadDataSuccess = true; + } + else { + shtReadDataSuccess = false; + } + + shtDataRequested = false; + } + } + } +} + +void ShtUsermod::onMqttConnect(bool sessionPresent) { + if (haMqttDiscovery) publishHomeAssistantAutodiscovery(); +} + +void ShtUsermod::appendConfigData() { + oappend(SET_F("dd=addDropdown('")); + oappend(_name); + oappend(SET_F("','")); + oappend(_shtType); + oappend(SET_F("');")); + oappend(SET_F("addOption(dd,'SHT30',0);")); + oappend(SET_F("addOption(dd,'SHT31',1);")); + oappend(SET_F("addOption(dd,'SHT35',2);")); + oappend(SET_F("addOption(dd,'SHT85',3);")); + oappend(SET_F("dd=addDropdown('")); + oappend(_name); + oappend(SET_F("','")); + oappend(_unitOfTemp); + oappend(SET_F("');")); + oappend(SET_F("addOption(dd,'Celsius',0);")); + oappend(SET_F("addOption(dd,'Fahrenheit',1);")); +} + +void ShtUsermod::addToConfig(JsonObject &root) +{ + JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname + + top[FPSTR(_enabled)] = enabled; + top[FPSTR(_shtType)] = shtType; + top[FPSTR(_unitOfTemp)] = unitOfTemp; + top[FPSTR(_haMqttDiscovery)] = haMqttDiscovery; +} + +/** + * readFromConfig() is called before setup() to populate properties from values stored in cfg.json + * + * The function should return true if configuration was successfully loaded or false if there was no configuration. + */ +bool ShtUsermod::readFromConfig(JsonObject &root) +{ + JsonObject top = root[FPSTR(_name)]; + if (top.isNull()) { + DEBUG_PRINTF("[%s] No config found. (Using defaults.)\n", _name); + return false; + } + + bool oldEnabled = enabled; + byte oldShtType = shtType; + bool oldHaMqttDiscovery = haMqttDiscovery; + + getJsonValue(top[FPSTR(_enabled)], enabled); + getJsonValue(top[FPSTR(_shtType)], shtType); + getJsonValue(top[FPSTR(_unitOfTemp)], unitOfTemp); + getJsonValue(top[FPSTR(_haMqttDiscovery)], haMqttDiscovery); + + // First run: reading from cfg.json, nothing to do here, will be all done in setup() + if (!firstRunDone) { + DEBUG_PRINTF("[%s] First run, nothing to do\n", _name); + } + // Check if mod has been en-/disabled + else if (enabled != oldEnabled) { + enabled ? setup() : cleanup(); + DEBUG_PRINTF("[%s] Usermod has been en-/disabled\n", _name); + } + // Config has been changed, so adopt to changes + else if (enabled) { + if (oldHaMqttDiscovery != haMqttDiscovery && haMqttDiscovery) { + publishHomeAssistantAutodiscovery(); + } + + if (oldShtType != shtType) { + cleanupShtTempHumiditySensor(); + initShtTempHumiditySensor(); + } + + DEBUG_PRINTF("[%s] Config (re)loaded\n", _name); + } + + return true; +} + +void ShtUsermod::addToJsonInfo(JsonObject& root) +{ + if (!enabled && !isShtReady()) { + return; + } + + JsonObject user = root["u"]; + if (user.isNull()) user = root.createNestedObject("u"); + + JsonArray jsonTemp = user.createNestedArray(F("Temperature")); + JsonArray jsonHumidity = user.createNestedArray(F("Humidity")); + + if (shtLastTimeUpdated == 0 || !shtReadDataSuccess) { + jsonTemp.add(0); + jsonHumidity.add(0); + if (shtLastTimeUpdated == 0) { + jsonTemp.add(F(" Not read yet")); + jsonHumidity.add(F(" Not read yet")); + } + else { + jsonTemp.add(F(" Error")); + jsonHumidity.add(F(" Error")); + } + + return; + } + + jsonHumidity.add(shtCurrentHumidity); + jsonHumidity.add(F(" RH")); + + unitOfTemp ? jsonTemp.add(getTemperatureF()) : jsonTemp.add(getTemperatureC()); + unitOfTemp ? jsonTemp.add(F(" °F")) : jsonTemp.add(F(" °C")); +} + +float ShtUsermod::getTemperatureC() { + return shtCurrentTempC; +} + +float ShtUsermod::getTemperatureF() { + return shtCurrentTempF; +} + +float ShtUsermod::getHumidity() { + return shtCurrentHumidity; +} \ No newline at end of file From 44790e99ea99088a7ff9ac035e7e9ff87a9fa8b4 Mon Sep 17 00:00:00 2001 From: ezcGman Date: Thu, 15 Dec 2022 00:52:21 +0100 Subject: [PATCH 07/11] UM SHT: use snprintf_P instead of sprintf_P --- usermods/sht/usermod_sht.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index e7e4b10d..e646f747 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -143,9 +143,9 @@ void ShtUsermod::publishTemperatureAndHumidityViaMqtt() { if (!WLED_MQTT_CONNECTED) return; char buf[128]; - sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic); + snprintf_P(buf, 127, PSTR("%s/temperature"), mqttDeviceTopic); mqtt->publish(buf, 0, false, String((unitOfTemp ? getTemperatureF() : getTemperatureC())).c_str()); - sprintf_P(buf, PSTR("%s/humidity"), mqttDeviceTopic); + snprintf_P(buf, 127, PSTR("%s/humidity"), mqttDeviceTopic); mqtt->publish(buf, 0, false, String(shtCurrentHumidity).c_str()); } @@ -156,34 +156,34 @@ void ShtUsermod::publishHomeAssistantAutodiscovery() { size_t payload_size; StaticJsonDocument<1024> json; - sprintf_P(buf, PSTR("%s Temperature"), serverDescription); + snprintf_P(buf, 127, PSTR("%s Temperature"), serverDescription); json[F("name")] = buf; - sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic); + snprintf_P(buf, 127, PSTR("%s/temperature"), mqttDeviceTopic); json[F("stat_t")] = buf; json[F("dev_cla")] = F("temperature"); json[F("stat_cla")] = F("measurement"); - sprintf_P(buf, PSTR("%s-temperature"), escapedMac.c_str()); + snprintf_P(buf, 127, PSTR("%s-temperature"), escapedMac.c_str()); json[F("uniq_id")] = buf; json[F("unit_of_meas")] = F("°C"); appendDeviceToMqttDiscoveryMessage(json); payload_size = serializeJson(json, json_str); - sprintf_P(buf, PSTR("homeassistant/sensor/%s/%s-temperature/config"), escapedMac.c_str(), escapedMac.c_str()); + snprintf_P(buf, 127, PSTR("homeassistant/sensor/%s/%s-temperature/config"), escapedMac.c_str(), escapedMac.c_str()); mqtt->publish(buf, 0, true, json_str, payload_size); json.clear(); - sprintf_P(buf, PSTR("%s Humidity"), serverDescription); + snprintf_P(buf, 127, PSTR("%s Humidity"), serverDescription); json[F("name")] = buf; - sprintf_P(buf, PSTR("%s/humidity"), mqttDeviceTopic); + snprintf_P(buf, 127, PSTR("%s/humidity"), mqttDeviceTopic); json[F("stat_t")] = buf; json[F("dev_cla")] = F("humidity"); json[F("stat_cla")] = F("measurement"); - sprintf_P(buf, PSTR("%s-humidity"), escapedMac.c_str()); + snprintf_P(buf, 127, PSTR("%s-humidity"), escapedMac.c_str()); json[F("uniq_id")] = buf; json[F("unit_of_meas")] = F("%"); appendDeviceToMqttDiscoveryMessage(json); payload_size = serializeJson(json, json_str); - sprintf_P(buf, PSTR("homeassistant/sensor/%s/%s-humidity/config"), escapedMac.c_str(), escapedMac.c_str()); + snprintf_P(buf, 127, PSTR("homeassistant/sensor/%s/%s-humidity/config"), escapedMac.c_str(), escapedMac.c_str()); mqtt->publish(buf, 0, true, json_str, payload_size); } From a8a549e8fcc19cc533eddc388e7c885debe24841 Mon Sep 17 00:00:00 2001 From: ezcGman Date: Thu, 15 Dec 2022 01:38:41 +0100 Subject: [PATCH 08/11] UM SHT: Lots of documentation added --- usermods/sht/usermod_sht.h | 219 +++++++++++++++++++++++++++---------- 1 file changed, 159 insertions(+), 60 deletions(-) diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index e646f747..404cfdd9 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -10,24 +10,24 @@ class ShtUsermod : public Usermod { private: - bool enabled = false; - bool firstRunDone = false; - bool initDone = false; - bool haMqttDiscovery = false; + bool enabled = false; // Is usermod enabled or not + bool firstRunDone = false; // Remembers if the first config load run had been done + bool initDone = false; // Remembers if the mod has been completely initialised + bool haMqttDiscovery = false; // Is MQTT discovery enabled or not + bool haMqttDiscoveryDone = false; // Remembers if we already published the HA discovery topics // SHT vars - SHT *shtTempHumidSensor; - byte shtType = 0; // Default: SHT30 - byte unitOfTemp = 0; // Default: Celsius (0 = Celsius, 1 = Fahrenheit) - bool shtInitDone = false; - bool shtReadDataSuccess = false; - byte shtI2cAddress = 0x44; - unsigned long shtLastTimeUpdated = 0; - bool shtDataRequested = false; - float shtCurrentTempC = 0; - float shtCurrentTempF = 0; - float shtCurrentHumidity = 0; - float shtLastKnownHumidity = 0; + SHT *shtTempHumidSensor; // Instance of SHT lib + byte shtType = 0; // SHT sensor type to be used. Default: SHT30 + byte unitOfTemp = 0; // Temperature unit to be used. Default: Celsius (0 = Celsius, 1 = Fahrenheit) + bool shtInitDone = false; // Remembers if SHT sensor has been initialised + bool shtReadDataSuccess = false; // Did we have a successful data read and is a valid temperature and humidity available? + const byte shtI2cAddress = 0x44; // i2c address of the sensor. 0x44 is the default for all SHT sensors. Change this, if needed + unsigned long shtLastTimeUpdated = 0; // Remembers when we read data the last time + bool shtDataRequested = false; // Reading data is done async. This remembers if we asked the sensor to read data + float shtCurrentTempC = 0; // Last read temperature in Celsius + float shtCurrentTempF = 0; // Last read temperature in Fahrenheit + float shtCurrentHumidity = 0; // Last read humidity in RH% void initShtTempHumiditySensor(); @@ -40,29 +40,14 @@ class ShtUsermod : public Usermod void appendDeviceToMqttDiscoveryMessage(JsonDocument& root); public: - // strings to reduce flash memory usage (used more than twice) + // Strings to reduce flash memory usage (used more than twice) static const char _name[]; static const char _enabled[]; static const char _shtType[]; static const char _unitOfTemp[]; static const char _haMqttDiscovery[]; - /* - * setup() is called once at boot. WiFi is not yet connected at this point. - * You can use it to initialize variables, sensors or similar. - */ void setup(); - - /* - * loop() is called continuously. Here you can check for events, read sensors, etc. - * - * Tips: - * 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection. - * Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker. - * - * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. - * Instead, use a timer check as shown here. - */ void loop(); void onMqttConnect(bool sessionPresent); void appendConfigData(); @@ -74,22 +59,24 @@ class ShtUsermod : public Usermod float getTemperatureF(); float getHumidity(); - /* - * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). - * This could be used in the future for the system to determine whether your usermod is installed. - */ uint16_t getId() { return USERMOD_ID_SHT; } }; -// strings to reduce flash memory usage (used more than twice) -// Config settings +// Strings to reduce flash memory usage (used more than twice) const char ShtUsermod::_name[] PROGMEM = "SHT-Sensor"; const char ShtUsermod::_enabled[] PROGMEM = "Enabled"; const char ShtUsermod::_shtType[] PROGMEM = "SHT-Type"; const char ShtUsermod::_unitOfTemp[] PROGMEM = "Unit"; const char ShtUsermod::_haMqttDiscovery[] PROGMEM = "Add-To-HA-MQTT-Discovery"; - +/** + * Initialise SHT sensor. + * + * Using the correct constructor according to config and initialises it using the + * global i2c pins. + * + * @return void + */ void ShtUsermod::initShtTempHumiditySensor() { switch (shtType) { @@ -111,6 +98,13 @@ void ShtUsermod::initShtTempHumiditySensor() shtInitDone = true; } +/** + * Cleanup the SHT sensor. + * + * Properly calls "reset" for the sensor then releases it from memory. + * + * @return void + */ void ShtUsermod::cleanupShtTempHumiditySensor() { if (shtInitDone) { @@ -122,6 +116,14 @@ void ShtUsermod::cleanupShtTempHumiditySensor() shtInitDone = false; } +/** + * Cleanup the mod completely. + * + * Calls ::cleanupShtTempHumiditySensor() to cleanup the SHT sensor and + * deallocates pins. + * + * @return void + */ void ShtUsermod::cleanup() { if (isShtReady()) { @@ -134,11 +136,24 @@ void ShtUsermod::cleanup() enabled = false; } +/** + * Checks if the SHT sensor has been initialised. + * + * @return bool + */ bool ShtUsermod::isShtReady() { return shtInitDone; } +/** + * Publish temperature and humidity to WLED device topic. + * + * Will add a "/temperature" and "/humidity" topic to the WLED device topic. + * Temperature will be written in configured unit. + * + * @return void + */ void ShtUsermod::publishTemperatureAndHumidityViaMqtt() { if (!WLED_MQTT_CONNECTED) return; char buf[128]; @@ -149,6 +164,15 @@ void ShtUsermod::publishTemperatureAndHumidityViaMqtt() { mqtt->publish(buf, 0, false, String(shtCurrentHumidity).c_str()); } +/** + * If enabled, publishes HA MQTT device discovery topics. + * + * Will make Home Assistant add temperature and humidity as entities automatically. + * + * Note: Whenever usermods are part of the WLED integration in HA, this can be dropped. + * + * @return void + */ void ShtUsermod::publishHomeAssistantAutodiscovery() { if (!WLED_MQTT_CONNECTED) return; @@ -185,8 +209,15 @@ void ShtUsermod::publishHomeAssistantAutodiscovery() { payload_size = serializeJson(json, json_str); snprintf_P(buf, 127, PSTR("homeassistant/sensor/%s/%s-humidity/config"), escapedMac.c_str(), escapedMac.c_str()); mqtt->publish(buf, 0, true, json_str, payload_size); + + haMqttDiscoveryDone = true; } +/** + * Helper to add device information to MQTT discovery topic. + * + * @return void + */ void ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) { JsonObject device = root.createNestedObject("dev"); device[F("ids")] = escapedMac.c_str(); @@ -196,10 +227,17 @@ void ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) { device[F("mf")] = F("espressif"); } -/* - * setup() is called once at boot. WiFi is not yet connected at this point. - * You can use it to initialize variables, sensors or similar. - */ +/** + * Setup the mod. + * + * Allocates i2c pins as PinOwner::HW_I2C, so they can be allocated multiple times. + * And calls ::initShtTempHumiditySensor() to initialise the sensor. + * + * @see Usermod::setup() + * @see UsermodManager::setup() + * + * @return void + */ void ShtUsermod::setup() { if (enabled) { @@ -220,16 +258,19 @@ void ShtUsermod::setup() firstRunDone = true; } -/* - * loop() is called continuously. Here you can check for events, read sensors, etc. - * - * Tips: - * 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection. - * Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker. - * - * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. - * Instead, use a timer check as shown here. - */ +/** + * Actually reading data (async) from the sensor every 30 seconds. + * + * If last reading is at least 30 seconds, it will trigger a reading using + * SHT::requestData(). We will then continiously check SHT::dataReady() if + * data is ready to be read. If so, it's read, stored locally and published + * via MQTT. + * + * @see Usermod::loop() + * @see UsermodManager::loop() + * + * @return void + */ void ShtUsermod::loop() { if (!enabled || !initDone || strip.isUpdating()) return; @@ -262,10 +303,28 @@ void ShtUsermod::loop() } } +/** + * Whenever MQTT is connected, publish HA autodiscovery topics. + * + * Is only donce once. + * + * @see Usermod::onMqttConnect() + * @see UsermodManager::onMqttConnect() + * + * @return void + */ void ShtUsermod::onMqttConnect(bool sessionPresent) { - if (haMqttDiscovery) publishHomeAssistantAutodiscovery(); + if (haMqttDiscovery && !haMqttDiscoveryDone) publishHomeAssistantAutodiscovery(); } +/** + * Add dropdown for sensor type and unit to UM config page. + * + * @see Usermod::appendConfigData() + * @see UsermodManager::appendConfigData() + * + * @return void + */ void ShtUsermod::appendConfigData() { oappend(SET_F("dd=addDropdown('")); oappend(_name); @@ -285,6 +344,14 @@ void ShtUsermod::appendConfigData() { oappend(SET_F("addOption(dd,'Fahrenheit',1);")); } +/** + * Add config data to be stored in cfg.json. + * + * @see Usermod::addToConfig() + * @see UsermodManager::addToConfig() + * + * @return void + */ void ShtUsermod::addToConfig(JsonObject &root) { JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname @@ -296,9 +363,16 @@ void ShtUsermod::addToConfig(JsonObject &root) } /** - * readFromConfig() is called before setup() to populate properties from values stored in cfg.json + * Apply config on boot or save of UM config page. * - * The function should return true if configuration was successfully loaded or false if there was no configuration. + * This is called whenever WLED boots and loads cfg.json, or when the UM config + * page is saved. Will properly re-instantiate the SHT class upon type change and + * publish HA discovery after enabling. + * + * @see Usermod::readFromConfig() + * @see UsermodManager::readFromConfig() + * + * @return bool */ bool ShtUsermod::readFromConfig(JsonObject &root) { @@ -328,21 +402,31 @@ bool ShtUsermod::readFromConfig(JsonObject &root) } // Config has been changed, so adopt to changes else if (enabled) { - if (oldHaMqttDiscovery != haMqttDiscovery && haMqttDiscovery) { - publishHomeAssistantAutodiscovery(); - } - if (oldShtType != shtType) { cleanupShtTempHumiditySensor(); initShtTempHumiditySensor(); } + if (oldHaMqttDiscovery != haMqttDiscovery && haMqttDiscovery) { + publishHomeAssistantAutodiscovery(); + } + DEBUG_PRINTF("[%s] Config (re)loaded\n", _name); } return true; } +/** + * Adds the temperature and humidity actually to the info section and /json info. + * + * This is called every time the info section is opened ot /json is called. + * + * @see Usermod::addToJsonInfo() + * @see UsermodManager::addToJsonInfo() + * + * @return void + */ void ShtUsermod::addToJsonInfo(JsonObject& root) { if (!enabled && !isShtReady()) { @@ -377,14 +461,29 @@ void ShtUsermod::addToJsonInfo(JsonObject& root) unitOfTemp ? jsonTemp.add(F(" °F")) : jsonTemp.add(F(" °C")); } +/** + * Getter for last read temperature in Celsius. + * + * @return float + */ float ShtUsermod::getTemperatureC() { return shtCurrentTempC; } +/** + * Getter for last read temperature in Fahrenheit. + * + * @return float + */ float ShtUsermod::getTemperatureF() { return shtCurrentTempF; } +/** + * Getter for last read humidity in RH%. + * + * @return float + */ float ShtUsermod::getHumidity() { return shtCurrentHumidity; } \ No newline at end of file From 1dcef87e1cbf15d55fedd618958e05f59e7b1431 Mon Sep 17 00:00:00 2001 From: Andy Hofmann Date: Thu, 15 Dec 2022 11:27:35 +0100 Subject: [PATCH 09/11] UM SHT: Fixed typo in readme --- usermods/sht/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usermods/sht/readme.md b/usermods/sht/readme.md index 78ec80a2..0337805b 100644 --- a/usermods/sht/readme.md +++ b/usermods/sht/readme.md @@ -19,7 +19,7 @@ lib_deps = ${esp32.lib_deps} ESP8266: ``` -[env:custom_d1_mini_usermod_quinled_an_penta] +[env:custom_d1_mini_usermod_sht] extends = env:d1_mini build_flags = ${common.build_flags_esp8266} -D USERMOD_SHT @@ -53,4 +53,4 @@ Navigate to the "Config" and then to the "Usermods" section. If you compiled WLE * First implementation. ## Credits -ezcGman | Andy: Find me on the Intermit.Tech (QuinLED) Discord server: https://discord.gg/WdbAauG \ No newline at end of file +ezcGman | Andy: Find me on the Intermit.Tech (QuinLED) Discord server: https://discord.gg/WdbAauG From 13cfc2d7bc276e7358bac308e007473d185aa241 Mon Sep 17 00:00:00 2001 From: ezcGman Date: Fri, 16 Dec 2022 02:22:13 +0100 Subject: [PATCH 10/11] UM SHT: Improved pin de/allocation --- usermods/sht/usermod_sht.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index 404cfdd9..effe44c7 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -12,6 +12,7 @@ class ShtUsermod : public Usermod private: bool enabled = false; // Is usermod enabled or not bool firstRunDone = false; // Remembers if the first config load run had been done + bool pinAllocDone = true; // Remembers if we have allocated pins bool initDone = false; // Remembers if the mod has been completely initialised bool haMqttDiscovery = false; // Is MQTT discovery enabled or not bool haMqttDiscoveryDone = false; // Remembers if we already published the HA discovery topics @@ -89,7 +90,6 @@ void ShtUsermod::initShtTempHumiditySensor() shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl); if (shtTempHumidSensor->readStatus() == 0xFFFF) { DEBUG_PRINTF("[%s] SHT init failed!\n", _name); - shtInitDone = false; cleanupShtTempHumiditySensor(); cleanup(); return; @@ -107,7 +107,7 @@ void ShtUsermod::initShtTempHumiditySensor() */ void ShtUsermod::cleanupShtTempHumiditySensor() { - if (shtInitDone) { + if (isShtReady()) { shtTempHumidSensor->reset(); } @@ -130,8 +130,11 @@ void ShtUsermod::cleanup() cleanupShtTempHumiditySensor(); } - pinManager.deallocatePin(i2c_sda, PinOwner::HW_I2C); - pinManager.deallocatePin(i2c_scl, PinOwner::HW_I2C); + if (pinAllocDone) { + PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; + pinManager.deallocateMultiplePins(pins, 2, PinOwner::HW_I2C); + pinAllocDone = false; + } enabled = false; } @@ -244,11 +247,10 @@ void ShtUsermod::setup() PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { DEBUG_PRINTF("[%s] SHT pin allocation failed!\n", _name); - shtInitDone = false; - cleanupShtTempHumiditySensor(); cleanup(); return; } + pinAllocDone = true; initShtTempHumiditySensor(); From b7034d321327d92b31bf7219d33739f89ce4119c Mon Sep 17 00:00:00 2001 From: ezcGman Date: Sun, 18 Dec 2022 21:33:25 +0100 Subject: [PATCH 11/11] UM SHT: Check for IOs gt zero --- usermods/sht/usermod_sht.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index effe44c7..42b22a79 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -245,7 +245,8 @@ void ShtUsermod::setup() { if (enabled) { PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; - if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { + // GPIOs can be set to -1 and allocateMultiplePins() will return true, so check they're gt zero + if (i2c_sda < 0 || i2c_scl < 0 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { DEBUG_PRINTF("[%s] SHT pin allocation failed!\n", _name); cleanup(); return;