From 0a6618be4a664b4b34ba9a443277a3f44e6355ff Mon Sep 17 00:00:00 2001 From: Deadeye5589 Date: Wed, 7 May 2025 11:26:35 +0200 Subject: [PATCH 1/9] Create readme.md --- usermods/LM75_Temperature/readme.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 usermods/LM75_Temperature/readme.md diff --git a/usermods/LM75_Temperature/readme.md b/usermods/LM75_Temperature/readme.md new file mode 100644 index 0000000000..a0990367ef --- /dev/null +++ b/usermods/LM75_Temperature/readme.md @@ -0,0 +1 @@ +TBD From e87e1a395af8d802984f3029a37a5acc9b8ad77c Mon Sep 17 00:00:00 2001 From: Deadeye5589 Date: Thu, 8 May 2025 12:41:10 +0200 Subject: [PATCH 2/9] First protoype of LM75 mod --- usermods/LM75_Temperature/LM75.cpp | 315 +++++++++++++++++++++++++ usermods/LM75_Temperature/LM75.h | 109 +++++++++ usermods/LM75_Temperature/library.json | 8 + usermods/LM75_Temperature/readme.md | 59 ++++- 4 files changed, 490 insertions(+), 1 deletion(-) create mode 100644 usermods/LM75_Temperature/LM75.cpp create mode 100644 usermods/LM75_Temperature/LM75.h create mode 100644 usermods/LM75_Temperature/library.json diff --git a/usermods/LM75_Temperature/LM75.cpp b/usermods/LM75_Temperature/LM75.cpp new file mode 100644 index 0000000000..f13a3af5cc --- /dev/null +++ b/usermods/LM75_Temperature/LM75.cpp @@ -0,0 +1,315 @@ +#include "LM75.h" + +static Generic_LM75 LM75temperature(USERMOD_LM75TEMPERATURE_I2C_ADRESS); + +void UsermodLM75Temperature::overtempfailure(){ + overtemptriggered = true; + if(bri >0){ + toggleOnOff(); + stateUpdated(CALL_MODE_BUTTON); + } + } + + void UsermodLM75Temperature::overtempreset(){ + overtemptriggered = false; + if(bri == 0){ + toggleOnOff(); + stateUpdated(CALL_MODE_BUTTON); + } + } + + + /** + * Get auto off Temperature at which WLED Output is swiched off + */ + int8_t UsermodLM75Temperature::getAutoOffHighThreshold() + { + return autoOffHighThreshold; + } + + /** + * Get auto off Temperature at which WLED Output is swiched on again + */ + int8_t UsermodLM75Temperature::getAutoOffLowThreshold() + { + return autoOffLowThreshold; + } + + /** + * Set auto off Temperature at which WLED Output is swiched off + */ + void UsermodLM75Temperature::setAutoOffHighThreshold(uint8_t threshold) + { + autoOffHighThreshold = min((uint8_t)212, max((uint8_t)1, threshold)); + } + + /** + * Set auto off Temperature at which WLED Output is swiched on again + */ + void UsermodLM75Temperature::setAutoOffLowThreshold(uint8_t threshold) + { + autoOffLowThreshold = min((uint8_t)211, max((uint8_t)0, threshold)); + // when low power indicator is enabled the auto-off threshold cannot be above indicator threshold + autoOffLowThreshold = autoOffEnabled ? min(autoOffHighThreshold-1, (int)autoOffLowThreshold) : autoOffLowThreshold; + } + + bool UsermodLM75Temperature::findSensor() { + uint8_t devicepresent; + //Let's try to communicate with the LM75 sensor + Wire.beginTransmission(USERMOD_LM75TEMPERATURE_I2C_ADRESS); + // End Transmission will return 0 is device has acknowledged communication + devicepresent = Wire.endTransmission(); + if(devicepresent == 0){ + DEBUG_PRINTLN(F("Sensor found.")); + sensorFound = 1; + return true; + } + else{ + DEBUG_PRINTLN(F("Sensor NOT found.")); + return false; + } + } + +void UsermodLM75Temperature::readTemperature() { + if(degC){ + temperature = LM75temperature.readTemperatureC(); + } + else + temperature = LM75temperature.readTemperatureF(); + + lastMeasurement = millis(); + + DEBUG_PRINT(F("Read temperature ")); + DEBUG_PRINTLN(temperature); + } + + + #ifndef WLED_DISABLE_MQTT + void UsermodLM75Temperature::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; + strcpy(buf, mqttDeviceTopic); + strcat_P(buf, PSTR("/temperature")); + json[F("state_topic")] = buf; + json[F("device_class")] = F("temperature"); + json[F("unique_id")] = escapedMac.c_str(); + json[F("unit_of_measurement")] = F(getTemperatureUnit()); + payload_size = serializeJson(json, json_str); + + sprintf_P(buf, PSTR("homeassistant/sensor/%s/config"), escapedMac.c_str()); + mqtt->publish(buf, 0, true, json_str, payload_size); + HApublished = true; + } + #endif + + void UsermodLM75Temperature::setup() { + int retries = 5; + sensorFound = 0; + if (enabled) { + // config says we are enabled + DEBUG_PRINTLN(F("Searching LM75 IC...")); + while (!findSensor() && retries--) { + delay(25); // try to find sensor + } + if (sensorFound && !initDone) DEBUG_PRINTLN(F("Init not completed")); + } + lastMeasurement = millis() - readingInterval + 10000; + initDone = true; + } + + void UsermodLM75Temperature::loop() { + if (!enabled || !sensorFound || strip.isUpdating()) return; + + unsigned long now = millis(); + + // check to see if we are due for taking a measurement + // lastMeasurement will not be updated until the conversion + // is complete the the reading is finished + if (now - lastMeasurement < readingInterval) return; + + DEBUG_PRINTLN(F("IDKFA")); + readTemperature(); + + if(autoOffEnabled){ + if (!overtemptriggered && temperature >= autoOffHighThreshold){ + overtempfailure(); + } + else if(overtemptriggered && temperature <= autoOffLowThreshold){ + overtempreset(); + } + } + + + + #ifndef WLED_DISABLE_MQTT + if (WLED_MQTT_CONNECTED) { + char subuf[64]; + strcpy(subuf, mqttDeviceTopic); + strcat_P(subuf, PSTR("/temperature")); + mqtt->publish(subuf, 0, false, String(temperature).c_str()); + } + #endif + } + + + /** + * connected() is called every time the WiFi is (re)connected + * Use it to initialize network interfaces + */ + //void UsermodLM75Temperature::connected() {} + + #ifndef WLED_DISABLE_MQTT + /** + * subscribe to MQTT topic if needed + */ + void UsermodLM75Temperature::onMqttConnect(bool sessionPresent) { + //(re)subscribe to required topics + //char subuf[64]; + if (mqttDeviceTopic[0] != 0) { + publishHomeAssistantAutodiscovery(); + } + } + #endif + + /* + * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. + * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. + * Below it is shown how this could be used for e.g. a light sensor + */ + void UsermodLM75Temperature::addToJsonInfo(JsonObject& root) { + // dont add temperature to info if we are disabled + if (!enabled) return; + + JsonObject user = root["u"]; + if (user.isNull()) user = root.createNestedObject("u"); + + JsonArray temp = user.createNestedArray(FPSTR(_name)); + + if (!sensorFound) { + temp.add(0); + temp.add(F(" Sensor Error!")); + return; + } + + temp.add(getTemperature()); + temp.add(getTemperatureUnit()); + + JsonObject sensor = root[F("sensor")]; + if (sensor.isNull()) sensor = root.createNestedObject(F("sensor")); + temp = sensor.createNestedArray(F("temperature")); + temp.add(getTemperature()); + temp.add(getTemperatureUnit()); + } + + /** + * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). + * Values in the state object may be modified by connected clients + */ + //void UsermodLM75Temperature::addToJsonState(JsonObject &root) + //{ + //} + + /** + * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object). + * Values in the state object may be modified by connected clients + * Read "_" from json state and and change settings (i.e. GPIO pin) used. + */ + //void UsermodLM75Temperature::readFromJsonState(JsonObject &root) { + // if (!initDone) return; // prevent crash on boot applyPreset() + //} + + /** + * addToConfig() (called from set.cpp) stores persistent properties to cfg.json + */ + void UsermodLM75Temperature::addToConfig(JsonObject &root) { + // we add JSON object: {"Temperature":} + JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname + top[FPSTR(_enabled)] = enabled; + top["degC"] = degC; // usermodparam + top[FPSTR(_readInterval)] = readingInterval / 1000; + + JsonObject ao = top.createNestedObject(FPSTR(_ao)); // auto off section + ao[FPSTR(_enabled)] = autoOffEnabled; + ao[FPSTR(_thresholdhigh)] = autoOffHighThreshold; + ao[FPSTR(_thresholdlow)] = autoOffLowThreshold; + DEBUG_PRINTLN(F("Temperature config saved.")); + } + + /** + * 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 UsermodLM75Temperature::readFromConfig(JsonObject &root) { + // we look for JSON object: {"Temperature":} + DEBUG_PRINT(FPSTR(_name)); + + JsonObject top = root[FPSTR(_name)]; + if (top.isNull()) { + DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + return false; + } + + enabled = top[FPSTR(_enabled)] | enabled; + degC = top["degC"] | degC; + readingInterval = top[FPSTR(_readInterval)] | readingInterval/1000; + readingInterval = min(120,max(10,(int)readingInterval)) * 1000; // convert to ms + + JsonObject ao = top[FPSTR(_ao)]; + autoOffEnabled = ao[FPSTR(_enabled)] | autoOffEnabled; + setAutoOffHighThreshold (ao[FPSTR(_thresholdhigh)] | autoOffHighThreshold); + setAutoOffLowThreshold (ao[FPSTR(_thresholdlow)] | autoOffLowThreshold); + + if (!initDone) { + // first run: reading from cfg.json + DEBUG_PRINTLN(F(" config loaded.")); + } + else { + // changing parameters from settings page + setup(); + DEBUG_PRINTLN(F(" config (re)loaded.")); + } + // use "return !top["newestParameter"].isNull();" when updating Usermod with new features + return !top[FPSTR(_name)].isNull(); + } + + void UsermodLM75Temperature::appendConfigData() { + if(degC){ + oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_ao)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_thresholdhigh)).c_str()); + oappend(SET_F("',1,'°C');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_ao)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_thresholdlow)).c_str()); + oappend(SET_F("',1,'°C');")); // 0 is field type, 1 is actual field + } + else{ + oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_ao)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_thresholdhigh)).c_str()); + oappend(SET_F("',1,'°F');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_ao)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_thresholdlow)).c_str()); + oappend(SET_F("',1,'°F');")); // 0 is field type, 1 is actual field + } + + } + + float UsermodLM75Temperature::getTemperature() { + return temperature; + } + + const char *UsermodLM75Temperature::getTemperatureUnit() { + return degC ? "°C" : "°F"; + } + + // strings to reduce flash memory usage (used more than twice) + const char UsermodLM75Temperature::_name[] PROGMEM = "Temperature"; + const char UsermodLM75Temperature::_enabled[] PROGMEM = "enabled"; + const char UsermodLM75Temperature::_readInterval[] PROGMEM = "read-interval-s"; + const char UsermodLM75Temperature::_ao[] PROGMEM = "Overtemperature-Protection"; + const char UsermodLM75Temperature::_thresholdhigh[] PROGMEM = "shutdown-temperature"; + const char UsermodLM75Temperature::_thresholdlow[] PROGMEM = "reactivate-temperature"; + +static UsermodLM75Temperature temperature; +REGISTER_USERMOD(temperature); \ No newline at end of file diff --git a/usermods/LM75_Temperature/LM75.h b/usermods/LM75_Temperature/LM75.h new file mode 100644 index 0000000000..cdf7e3711b --- /dev/null +++ b/usermods/LM75_Temperature/LM75.h @@ -0,0 +1,109 @@ +#pragma once + +#include "wled.h" +#include "Temperature_LM75_Derived.h" + +// the frequency to check temperature, 1 minute +#ifndef USERMOD_LM75TEMPERATURE_MEASUREMENT_INTERVAL +#define USERMOD_LM75TEMPERATURE_MEASUREMENT_INTERVAL 60000 +#endif + +// auto-off feature +#ifndef USERMOD_LM75TEMPERATURE_AUTO_OFF_ENABLED + #define USERMOD_LM75TEMPERATURE_AUTO_OFF_ENABLED true +#endif + +#ifndef USERMOD_LM75TEMPERATURE_AUTO_OFF_HIGH_THRESHOLD + #define USERMOD_LM75TEMPERATURE_AUTO_OFF_HIGH_THRESHOLD 60 +#endif + +#ifndef USERMOD_LM75TEMPERATURE_AUTO_OFF_LOW_THRESHOLD + #define USERMOD_LM75TEMPERATURE_AUTO_OFF_LOW_THRESHOLD 40 +#endif + +#ifndef USERMOD_LM75TEMPERATURE_AUTO_TEMPERATURE_OFF_ENABLED + #define USERMOD_LM75TEMPERATURE_AUTO_TEMPERATURE_OFF_ENABLED true +#endif + +#ifndef USERMOD_LM75TEMPERATURE_I2C_ADRESS + #define USERMOD_LM75TEMPERATURE_I2C_ADRESS 0x48 +#endif + +//Generic_LM75 LM75temperature(0x4F); + +class UsermodLM75Temperature : public Usermod { + + private: + bool initDone = false; + + // measurement unit (true==°C, false==°F) + bool degC = true; + + // how often do we read from sensor? + unsigned long readingInterval = USERMOD_LM75TEMPERATURE_MEASUREMENT_INTERVAL; + // set last reading as "40 sec before boot", so first reading is taken after 20 sec + unsigned long lastMeasurement = UINT32_MAX - USERMOD_LM75TEMPERATURE_MEASUREMENT_INTERVAL; + // last time requestTemperatures was called + // used to determine when we can read the sensors temperature + // we have to wait at least 93.75 ms after requestTemperatures() is called + unsigned long lastTemperaturesRequest; + float temperature; + // flag set at startup if LM75 sensor not found, avoids trying to keep getting + // temperature if flashed to a board without a sensor attached + byte sensorFound; + // Temperature limits for master off feature + uint8_t autoOffHighThreshold = USERMOD_LM75TEMPERATURE_AUTO_OFF_HIGH_THRESHOLD; + uint8_t autoOffLowThreshold = USERMOD_LM75TEMPERATURE_AUTO_OFF_LOW_THRESHOLD; + // Has an overtemperature event occured ? + bool overtemptriggered = false; + + bool enabled = USERMOD_LM75TEMPERATURE_AUTO_OFF_ENABLED; + + bool HApublished = false; + + // auto shutdown/shutoff/master off feature + bool autoOffEnabled = USERMOD_LM75TEMPERATURE_AUTO_TEMPERATURE_OFF_ENABLED; + + // strings to reduce flash memory usage (used more than twice) + static const char _name[]; + static const char _enabled[]; + static const char _readInterval[]; + static const char _ao[]; + static const char _thresholdhigh[]; + static const char _thresholdlow[]; + + // Functions for LM75 sensor + void readTemperature(); + bool findSensor(); +#ifndef WLED_DISABLE_MQTT + void publishHomeAssistantAutodiscovery(); +#endif + + /* + * API calls te enable data exchan)ge between WLED modules + */ + float getTemperature(); + const char *getTemperatureUnit(); + uint16_t getId() { return USERMOD_ID_LM75TEMPERATURE; } + + void setup(); + void loop(); + //void connected(); +#ifndef WLED_DISABLE_MQTT + void onMqttConnect(bool sessionPresent); +#endif + + void addToJsonInfo(JsonObject& root); + void addToConfig(JsonObject &root); + bool readFromConfig(JsonObject &root); + + void appendConfigData(); + + void overtempfailure(); + void overtempreset(); + int8_t getAutoOffHighThreshold(); + int8_t getAutoOffLowThreshold(); + void setAutoOffHighThreshold(uint8_t threshold); + void setAutoOffLowThreshold(uint8_t threshold); +}; + diff --git a/usermods/LM75_Temperature/library.json b/usermods/LM75_Temperature/library.json new file mode 100644 index 0000000000..97afacde51 --- /dev/null +++ b/usermods/LM75_Temperature/library.json @@ -0,0 +1,8 @@ +{ + "name": "LM75Temperature", + "build": { "libArchive": false}, + "dependencies": { + "jeremycole/I2C Temperature Sensors derived from the LM75":"~1.0.3" + } + } + \ No newline at end of file diff --git a/usermods/LM75_Temperature/readme.md b/usermods/LM75_Temperature/readme.md index a0990367ef..712e268b74 100644 --- a/usermods/LM75_Temperature/readme.md +++ b/usermods/LM75_Temperature/readme.md @@ -1 +1,58 @@ -TBD +# LM75 temperature sensor with overtemperature protection + +This usermod utilizes LM75 style I2C temperature sensors. +It is based on the regular temperature usermod for One Wire sensors. + +## Parameters: +| Parameter | Effect | Default | +| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| Temperature Enable | Activates the LM75 mod | Enabled | +| DegC | Switch between °C and °F | °C | +| Read Interval | Time between temperature measurements | 60 s | +| Overtemperature Enable | Enables or disables temperature protection. According to the defined limits | Enabled | +| Shutdown Temperature | Temperature at which the WLED output is switched off. Can be between 1 and 100 | 60°C | +| Reactivate Temperature | Switches the WLED output back on once the temperature drops below set value. Has a hystersis of minimum 1 towards the shutdown temperature. Can be beween 0 and 99°C | 40°C | + +## Compilation: +- modify `platformio.ini` and add wanted `build_flags` to your configuration +
+ + +- `-D USERMOD_LM75TEMPERATURE_MEASUREMENT_INTERVAL=60000` + Parameter time in ms +
+ +- `-D USERMOD_LM75TEMPERATURE_AUTO_OFF_ENABLED=true` + Paremeter true or flase +
+ +- `-D USERMOD_LM75TEMPERATURE_AUTO_OFF_HIGH_THRESHOLD=60` + Parameter 1 to 212 °C +
+ +- `-D USERMOD_LM75TEMPERATURE_AUTO_OFF_LOW_THRESHOLD=40` + Parameter 0 to 211 °C +
+ +- `-D USERMOD_LM75TEMPERATURE_AUTO_TEMPERATURE_OFF_ENABLED=true` + Paremeter true or flase +
+ +- `-D USERMOD_LM75TEMPERATURE_I2C_ADRESS=0x48` + Parameter I2C Adress of the LM75 IC in Hex 0x** + +## Remarks +The °F setting is not optimal to be used in combination with the overtemperature protection feature. WLED only allows uint8 values as inputs. Hence the maxium Temperature at capped at 212 °F or 100 °C. Also be carefull not to set the lower limit below 32 °F to avoid negative values in the inner workings of the mod. + +
+ +To avoid flickering of the WLED output the overtemperature feature has a hystersis of minimum 1. It is advised to use a bigger hystersis when setting the limits. Still the mod checks the inputs and adjust the lower value not to equal or higher than the upper limit. + +
+ +Temperature can be published via MQTT, but the feature is as of now untested. + +
+ +During power up the mod tries to scan for the I2C devices under the configured adress. The info page shows an error message if the sensor can not be reached. + From f313dae5d09fb43e69ab5e738ec52e0d55b31367 Mon Sep 17 00:00:00 2001 From: Deadeye5589 Date: Thu, 8 May 2025 12:59:15 +0200 Subject: [PATCH 3/9] =?UTF-8?q?User=20ID=2058=20f=C3=BCr=20den=20LM75=20ve?= =?UTF-8?q?rgeben?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wled00/const.h | 1 + 1 file changed, 1 insertion(+) diff --git a/wled00/const.h b/wled00/const.h index 2b460f3f18..88aee5b3dd 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -210,6 +210,7 @@ #define USERMOD_ID_DEEP_SLEEP 55 //Usermod "usermod_deep_sleep.h" #define USERMOD_ID_RF433 56 //Usermod "usermod_v2_RF433.h" #define USERMOD_ID_BRIGHTNESS_FOLLOW_SUN 57 //Usermod "usermod_v2_brightness_follow_sun.h" +#define USERMOD_ID_LM75TEMPERATURE 58 //Usermod "LM75.h" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot From 9b00293642fde453205ad84ada7bbc007aad5b51 Mon Sep 17 00:00:00 2001 From: Deadeye5589 Date: Thu, 8 May 2025 19:49:33 +0200 Subject: [PATCH 4/9] Changes according to Coderabbit review --- usermods/LM75_Temperature/LM75.cpp | 32 ++++++++++++-------------- usermods/LM75_Temperature/LM75.h | 25 +++++++++----------- usermods/LM75_Temperature/library.json | 3 +-- usermods/LM75_Temperature/readme.md | 12 +++++----- 4 files changed, 33 insertions(+), 39 deletions(-) diff --git a/usermods/LM75_Temperature/LM75.cpp b/usermods/LM75_Temperature/LM75.cpp index f13a3af5cc..44abb12717 100644 --- a/usermods/LM75_Temperature/LM75.cpp +++ b/usermods/LM75_Temperature/LM75.cpp @@ -1,17 +1,17 @@ #include "LM75.h" -static Generic_LM75 LM75temperature(USERMOD_LM75TEMPERATURE_I2C_ADRESS); +static Generic_LM75 LM75temperature(USERMOD_LM75TEMPERATURE_I2C_ADDRESS); -void UsermodLM75Temperature::overtempfailure(){ - overtemptriggered = true; +void UsermodLM75Temperature::overtempFailure(){ + overtempTriggered = true; if(bri >0){ toggleOnOff(); stateUpdated(CALL_MODE_BUTTON); } } - void UsermodLM75Temperature::overtempreset(){ - overtemptriggered = false; + void UsermodLM75Temperature::overtempReset(){ + overtempTriggered = false; if(bri == 0){ toggleOnOff(); stateUpdated(CALL_MODE_BUTTON); @@ -56,7 +56,7 @@ void UsermodLM75Temperature::overtempfailure(){ bool UsermodLM75Temperature::findSensor() { uint8_t devicepresent; //Let's try to communicate with the LM75 sensor - Wire.beginTransmission(USERMOD_LM75TEMPERATURE_I2C_ADRESS); + Wire.beginTransmission(USERMOD_LM75TEMPERATURE_I2C_ADDRESS); // End Transmission will return 0 is device has acknowledged communication devicepresent = Wire.endTransmission(); if(devicepresent == 0){ @@ -133,15 +133,14 @@ void UsermodLM75Temperature::readTemperature() { // is complete the the reading is finished if (now - lastMeasurement < readingInterval) return; - DEBUG_PRINTLN(F("IDKFA")); readTemperature(); if(autoOffEnabled){ - if (!overtemptriggered && temperature >= autoOffHighThreshold){ - overtempfailure(); + if (!overtempTriggered && temperature >= autoOffHighThreshold){ + overtempFailure(); } - else if(overtemptriggered && temperature <= autoOffLowThreshold){ - overtempreset(); + else if(overtempTriggered && temperature <= autoOffLowThreshold){ + overtempReset(); } } @@ -158,12 +157,6 @@ void UsermodLM75Temperature::readTemperature() { } - /** - * connected() is called every time the WiFi is (re)connected - * Use it to initialize network interfaces - */ - //void UsermodLM75Temperature::connected() {} - #ifndef WLED_DISABLE_MQTT /** * subscribe to MQTT topic if needed @@ -295,6 +288,11 @@ void UsermodLM75Temperature::readTemperature() { } + + /** ++ * Gets the current temperature in the configured unit (C or F) ++ * @return Temperature in the unit specified by degC setting ++ */ float UsermodLM75Temperature::getTemperature() { return temperature; } diff --git a/usermods/LM75_Temperature/LM75.h b/usermods/LM75_Temperature/LM75.h index cdf7e3711b..9ac25cff40 100644 --- a/usermods/LM75_Temperature/LM75.h +++ b/usermods/LM75_Temperature/LM75.h @@ -9,8 +9,8 @@ #endif // auto-off feature -#ifndef USERMOD_LM75TEMPERATURE_AUTO_OFF_ENABLED - #define USERMOD_LM75TEMPERATURE_AUTO_OFF_ENABLED true +#ifndef USERMOD_LM75TEMPERATURE_ENABLED + #define USERMOD_LM75TEMPERATURE_ENABLED true #endif #ifndef USERMOD_LM75TEMPERATURE_AUTO_OFF_HIGH_THRESHOLD @@ -25,12 +25,10 @@ #define USERMOD_LM75TEMPERATURE_AUTO_TEMPERATURE_OFF_ENABLED true #endif -#ifndef USERMOD_LM75TEMPERATURE_I2C_ADRESS - #define USERMOD_LM75TEMPERATURE_I2C_ADRESS 0x48 +#ifndef USERMOD_LM75TEMPERATURE_I2C_ADDRESS + #define USERMOD_LM75TEMPERATURE_I2C_ADDRESS 0x48 #endif -//Generic_LM75 LM75temperature(0x4F); - class UsermodLM75Temperature : public Usermod { private: @@ -43,9 +41,7 @@ class UsermodLM75Temperature : public Usermod { unsigned long readingInterval = USERMOD_LM75TEMPERATURE_MEASUREMENT_INTERVAL; // set last reading as "40 sec before boot", so first reading is taken after 20 sec unsigned long lastMeasurement = UINT32_MAX - USERMOD_LM75TEMPERATURE_MEASUREMENT_INTERVAL; - // last time requestTemperatures was called - // used to determine when we can read the sensors temperature - // we have to wait at least 93.75 ms after requestTemperatures() is called + // Tracks the last time temperature was requested from the sensor unsigned long lastTemperaturesRequest; float temperature; // flag set at startup if LM75 sensor not found, avoids trying to keep getting @@ -55,10 +51,11 @@ class UsermodLM75Temperature : public Usermod { uint8_t autoOffHighThreshold = USERMOD_LM75TEMPERATURE_AUTO_OFF_HIGH_THRESHOLD; uint8_t autoOffLowThreshold = USERMOD_LM75TEMPERATURE_AUTO_OFF_LOW_THRESHOLD; // Has an overtemperature event occured ? - bool overtemptriggered = false; + bool overtempTriggered = false; - bool enabled = USERMOD_LM75TEMPERATURE_AUTO_OFF_ENABLED; + bool enabled = USERMOD_LM75TEMPERATURE_ENABLED; + // Tracks whether Home Assistant autodiscovery has been published bool HApublished = false; // auto shutdown/shutoff/master off feature @@ -80,7 +77,7 @@ class UsermodLM75Temperature : public Usermod { #endif /* - * API calls te enable data exchan)ge between WLED modules + * API calls to enable data exchange between WLED modules */ float getTemperature(); const char *getTemperatureUnit(); @@ -99,8 +96,8 @@ class UsermodLM75Temperature : public Usermod { void appendConfigData(); - void overtempfailure(); - void overtempreset(); + void overtempFailure(); + void overtempReset(); int8_t getAutoOffHighThreshold(); int8_t getAutoOffLowThreshold(); void setAutoOffHighThreshold(uint8_t threshold); diff --git a/usermods/LM75_Temperature/library.json b/usermods/LM75_Temperature/library.json index 97afacde51..b1027ad8fc 100644 --- a/usermods/LM75_Temperature/library.json +++ b/usermods/LM75_Temperature/library.json @@ -4,5 +4,4 @@ "dependencies": { "jeremycole/I2C Temperature Sensors derived from the LM75":"~1.0.3" } - } - \ No newline at end of file + } \ No newline at end of file diff --git a/usermods/LM75_Temperature/readme.md b/usermods/LM75_Temperature/readme.md index 712e268b74..dc8fd4bf8b 100644 --- a/usermods/LM75_Temperature/readme.md +++ b/usermods/LM75_Temperature/readme.md @@ -10,8 +10,8 @@ It is based on the regular temperature usermod for One Wire sensors. | DegC | Switch between °C and °F | °C | | Read Interval | Time between temperature measurements | 60 s | | Overtemperature Enable | Enables or disables temperature protection. According to the defined limits | Enabled | -| Shutdown Temperature | Temperature at which the WLED output is switched off. Can be between 1 and 100 | 60°C | -| Reactivate Temperature | Switches the WLED output back on once the temperature drops below set value. Has a hystersis of minimum 1 towards the shutdown temperature. Can be beween 0 and 99°C | 40°C | +| Shutdown Temperature | Temperature at which the WLED output is switched off. Value can be between 1 and 100 | 60°C | +| Reactivate Temperature | Switches the WLED output back on once the temperature drops below set value. Has a hysteresis of minimum 1 towards the shutdown temperature. Value can be beween 0 and 99°C | 40°C | ## Compilation: - modify `platformio.ini` and add wanted `build_flags` to your configuration @@ -23,7 +23,7 @@ It is based on the regular temperature usermod for One Wire sensors.
- `-D USERMOD_LM75TEMPERATURE_AUTO_OFF_ENABLED=true` - Paremeter true or flase + Parameter true or false
- `-D USERMOD_LM75TEMPERATURE_AUTO_OFF_HIGH_THRESHOLD=60` @@ -42,11 +42,11 @@ It is based on the regular temperature usermod for One Wire sensors. Parameter I2C Adress of the LM75 IC in Hex 0x** ## Remarks -The °F setting is not optimal to be used in combination with the overtemperature protection feature. WLED only allows uint8 values as inputs. Hence the maxium Temperature at capped at 212 °F or 100 °C. Also be carefull not to set the lower limit below 32 °F to avoid negative values in the inner workings of the mod. +The °F setting is not optimal to be used in combination with the overtemperature protection feature. WLED only allows uint8 values as inputs. Hence, the maximum temperature is capped at 212 °F or 100 °C. Also be carefull not to set the lower limit below 32 °F to avoid negative values in the inner workings of the mod.
-To avoid flickering of the WLED output the overtemperature feature has a hystersis of minimum 1. It is advised to use a bigger hystersis when setting the limits. Still the mod checks the inputs and adjust the lower value not to equal or higher than the upper limit. +To avoid flickering of the WLED output, the overtemperature feature has a hysteresis of minimum 1. It is advised to use a bigger hysteresis when setting the limits. Still the mod checks the inputs and adjust the lower value not to be equal or higher than the upper limit.
@@ -54,5 +54,5 @@ Temperature can be published via MQTT, but the feature is as of now untested.
-During power up the mod tries to scan for the I2C devices under the configured adress. The info page shows an error message if the sensor can not be reached. +During power up, the mod tries to scan for the I2C devices under the configured adress. The info page shows an error message if the sensor cannot be reached. From 43d30936000599c3497e0912ea50467b8a1843de Mon Sep 17 00:00:00 2001 From: Deadeye5589 Date: Thu, 8 May 2025 20:08:09 +0200 Subject: [PATCH 5/9] Furhter Coderabbit corrections --- usermods/LM75_Temperature/readme.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/usermods/LM75_Temperature/readme.md b/usermods/LM75_Temperature/readme.md index dc8fd4bf8b..46741ae181 100644 --- a/usermods/LM75_Temperature/readme.md +++ b/usermods/LM75_Temperature/readme.md @@ -10,8 +10,8 @@ It is based on the regular temperature usermod for One Wire sensors. | DegC | Switch between °C and °F | °C | | Read Interval | Time between temperature measurements | 60 s | | Overtemperature Enable | Enables or disables temperature protection. According to the defined limits | Enabled | -| Shutdown Temperature | Temperature at which the WLED output is switched off. Value can be between 1 and 100 | 60°C | -| Reactivate Temperature | Switches the WLED output back on once the temperature drops below set value. Has a hysteresis of minimum 1 towards the shutdown temperature. Value can be beween 0 and 99°C | 40°C | +| Shutdown Temperature | Temperature at which the WLED output is switched off. Value can be between 1 and 100°C | 60°C | +| Reactivate Temperature | Switches the WLED output back on once the temperature drops below set value. Has a hysteresis of minimum 1 towards the shutdown temperature. Value can be between 0 and 99°C | 40°C | ## Compilation: - modify `platformio.ini` and add wanted `build_flags` to your configuration @@ -22,7 +22,7 @@ It is based on the regular temperature usermod for One Wire sensors. Parameter time in ms
-- `-D USERMOD_LM75TEMPERATURE_AUTO_OFF_ENABLED=true` +- `-D USERMOD_LM75TEMPERATURE_ENABLED=true` Parameter true or false
@@ -35,11 +35,11 @@ It is based on the regular temperature usermod for One Wire sensors.
- `-D USERMOD_LM75TEMPERATURE_AUTO_TEMPERATURE_OFF_ENABLED=true` - Paremeter true or flase + Paremeter true or false
-- `-D USERMOD_LM75TEMPERATURE_I2C_ADRESS=0x48` - Parameter I2C Adress of the LM75 IC in Hex 0x** +- `-D USERMOD_LM75TEMPERATURE_I2C_ADDRESS=0x48` + Parameter I2C Address of the LM75 IC in Hex 0x** ## Remarks The °F setting is not optimal to be used in combination with the overtemperature protection feature. WLED only allows uint8 values as inputs. Hence, the maximum temperature is capped at 212 °F or 100 °C. Also be carefull not to set the lower limit below 32 °F to avoid negative values in the inner workings of the mod. From f4e7ed3fd26ca2caf5ab28d471240cb9c2f5a8f7 Mon Sep 17 00:00:00 2001 From: Deadeye5589 Date: Sun, 11 May 2025 10:04:51 +0200 Subject: [PATCH 6/9] Corrected formatting No functional changes, just corrected formatting --- usermods/LM75_Temperature/LM75.cpp | 56 ++++++++++++------------------ 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/usermods/LM75_Temperature/LM75.cpp b/usermods/LM75_Temperature/LM75.cpp index 44abb12717..29f0dad9ce 100644 --- a/usermods/LM75_Temperature/LM75.cpp +++ b/usermods/LM75_Temperature/LM75.cpp @@ -2,52 +2,47 @@ static Generic_LM75 LM75temperature(USERMOD_LM75TEMPERATURE_I2C_ADDRESS); -void UsermodLM75Temperature::overtempFailure(){ +void UsermodLM75Temperature::overtempFailure() { overtempTriggered = true; - if(bri >0){ + if(bri >0) { toggleOnOff(); stateUpdated(CALL_MODE_BUTTON); } } - void UsermodLM75Temperature::overtempReset(){ + void UsermodLM75Temperature::overtempReset() { overtempTriggered = false; - if(bri == 0){ + if(bri == 0) { toggleOnOff(); stateUpdated(CALL_MODE_BUTTON); } } - /** * Get auto off Temperature at which WLED Output is swiched off */ - int8_t UsermodLM75Temperature::getAutoOffHighThreshold() - { + int8_t UsermodLM75Temperature::getAutoOffHighThreshold() { return autoOffHighThreshold; } /** * Get auto off Temperature at which WLED Output is swiched on again */ - int8_t UsermodLM75Temperature::getAutoOffLowThreshold() - { + int8_t UsermodLM75Temperature::getAutoOffLowThreshold() { return autoOffLowThreshold; } /** * Set auto off Temperature at which WLED Output is swiched off */ - void UsermodLM75Temperature::setAutoOffHighThreshold(uint8_t threshold) - { + void UsermodLM75Temperature::setAutoOffHighThreshold(uint8_t threshold) { autoOffHighThreshold = min((uint8_t)212, max((uint8_t)1, threshold)); } /** * Set auto off Temperature at which WLED Output is swiched on again */ - void UsermodLM75Temperature::setAutoOffLowThreshold(uint8_t threshold) - { + void UsermodLM75Temperature::setAutoOffLowThreshold(uint8_t threshold) { autoOffLowThreshold = min((uint8_t)211, max((uint8_t)0, threshold)); // when low power indicator is enabled the auto-off threshold cannot be above indicator threshold autoOffLowThreshold = autoOffEnabled ? min(autoOffHighThreshold-1, (int)autoOffLowThreshold) : autoOffLowThreshold; @@ -59,26 +54,23 @@ void UsermodLM75Temperature::overtempFailure(){ Wire.beginTransmission(USERMOD_LM75TEMPERATURE_I2C_ADDRESS); // End Transmission will return 0 is device has acknowledged communication devicepresent = Wire.endTransmission(); - if(devicepresent == 0){ + if(devicepresent == 0) DEBUG_PRINTLN(F("Sensor found.")); sensorFound = 1; return true; - } - else{ + } else { DEBUG_PRINTLN(F("Sensor NOT found.")); return false; } } void UsermodLM75Temperature::readTemperature() { - if(degC){ + if(degC) { temperature = LM75temperature.readTemperatureC(); - } - else + } else { temperature = LM75temperature.readTemperatureF(); - + } lastMeasurement = millis(); - DEBUG_PRINT(F("Read temperature ")); DEBUG_PRINTLN(temperature); } @@ -114,8 +106,8 @@ void UsermodLM75Temperature::readTemperature() { if (enabled) { // config says we are enabled DEBUG_PRINTLN(F("Searching LM75 IC...")); - while (!findSensor() && retries--) { - delay(25); // try to find sensor + while (!findSensor() && retries--) { + delay(25); // try to find sensor } if (sensorFound && !initDone) DEBUG_PRINTLN(F("Init not completed")); } @@ -135,17 +127,14 @@ void UsermodLM75Temperature::readTemperature() { readTemperature(); - if(autoOffEnabled){ - if (!overtempTriggered && temperature >= autoOffHighThreshold){ + if(autoOffEnabled) { + if (!overtempTriggered && temperature >= autoOffHighThreshold) { overtempFailure(); - } - else if(overtempTriggered && temperature <= autoOffLowThreshold){ + } else if(overtempTriggered && temperature <= autoOffLowThreshold) { overtempReset(); } } - - - + #ifndef WLED_DISABLE_MQTT if (WLED_MQTT_CONNECTED) { char subuf[64]; @@ -273,13 +262,12 @@ void UsermodLM75Temperature::readTemperature() { } void UsermodLM75Temperature::appendConfigData() { - if(degC){ + if(degC) { oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_ao)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_thresholdhigh)).c_str()); oappend(SET_F("',1,'°C');")); // 0 is field type, 1 is actual field oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_ao)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_thresholdlow)).c_str()); oappend(SET_F("',1,'°C');")); // 0 is field type, 1 is actual field - } - else{ + } else { oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_ao)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_thresholdhigh)).c_str()); oappend(SET_F("',1,'°F');")); // 0 is field type, 1 is actual field oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_ao)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_thresholdlow)).c_str()); @@ -310,4 +298,4 @@ void UsermodLM75Temperature::readTemperature() { const char UsermodLM75Temperature::_thresholdlow[] PROGMEM = "reactivate-temperature"; static UsermodLM75Temperature temperature; -REGISTER_USERMOD(temperature); \ No newline at end of file +REGISTER_USERMOD(temperature); From cd6b511ecffb1c38a0c6799a5d6c4face7e39bbe Mon Sep 17 00:00:00 2001 From: Deadeye5589 Date: Sun, 11 May 2025 15:46:35 +0200 Subject: [PATCH 7/9] Lost bracked during last commit --- usermods/LM75_Temperature/LM75.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/LM75_Temperature/LM75.cpp b/usermods/LM75_Temperature/LM75.cpp index 29f0dad9ce..ad958f2d49 100644 --- a/usermods/LM75_Temperature/LM75.cpp +++ b/usermods/LM75_Temperature/LM75.cpp @@ -54,7 +54,7 @@ void UsermodLM75Temperature::overtempFailure() { Wire.beginTransmission(USERMOD_LM75TEMPERATURE_I2C_ADDRESS); // End Transmission will return 0 is device has acknowledged communication devicepresent = Wire.endTransmission(); - if(devicepresent == 0) + if(devicepresent == 0) { DEBUG_PRINTLN(F("Sensor found.")); sensorFound = 1; return true; From 1cadf8df609ea36c89903620753f59571e71f9c1 Mon Sep 17 00:00:00 2001 From: Deadeye5589 Date: Thu, 15 May 2025 16:49:16 +0200 Subject: [PATCH 8/9] Fixed error in publishHomeAssistantAutoDiscovery illegal macro used on a run-time string --- usermods/LM75_Temperature/LM75.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/LM75_Temperature/LM75.cpp b/usermods/LM75_Temperature/LM75.cpp index ad958f2d49..087d2a8dc3 100644 --- a/usermods/LM75_Temperature/LM75.cpp +++ b/usermods/LM75_Temperature/LM75.cpp @@ -91,7 +91,7 @@ void UsermodLM75Temperature::readTemperature() { json[F("state_topic")] = buf; json[F("device_class")] = F("temperature"); json[F("unique_id")] = escapedMac.c_str(); - json[F("unit_of_measurement")] = F(getTemperatureUnit()); + json[F("unit_of_measurement")] = getTemperatureUnit(); payload_size = serializeJson(json, json_str); sprintf_P(buf, PSTR("homeassistant/sensor/%s/config"), escapedMac.c_str()); From 1521640455a188f175aea6b445901afd1bcee143 Mon Sep 17 00:00:00 2001 From: Deadeye5589 Date: Thu, 15 May 2025 17:22:14 +0200 Subject: [PATCH 9/9] Elaborated loop hole in user experience Elaborated the fact, that the mod might switch a light on due to an overtemperature event. Also removed remark with untested MQTT, since feature was now tested successfull. --- usermods/LM75_Temperature/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/LM75_Temperature/readme.md b/usermods/LM75_Temperature/readme.md index 46741ae181..a1a730b9c9 100644 --- a/usermods/LM75_Temperature/readme.md +++ b/usermods/LM75_Temperature/readme.md @@ -50,7 +50,7 @@ To avoid flickering of the WLED output, the overtemperature feature has a hyster
-Temperature can be published via MQTT, but the feature is as of now untested. +There is no cross check if the user enables or disables the master light output during an overtemperature event. For example this can lead to the following behavior. User switches light off. Still an overtemperature event occurs. Since the light is already switched off, the mod does not change the current status. Now the temperature drops. And the mod will reenable the light, switching it on.