#include "wled.h" class InternalTemperatureUsermod : public Usermod { private: static constexpr unsigned long minLoopInterval = 1000; // minimum allowable interval (ms) unsigned long loopInterval = 10000; unsigned long lastTime = 0; bool isEnabled = false; float temperature = 0.0f; uint8_t previousPlaylist = 0; // Stores the playlist that was active before high-temperature activation uint8_t previousPreset = 0; // Stores the preset that was active before high-temperature activation uint8_t presetToActivate = 0; // Preset to activate when temp goes above threshold (0 = disabled) float activationThreshold = 95.0f; // Temperature threshold to trigger high-temperature actions float resetMargin = 2.0f; // Margin below the activation threshold (Prevents frequent toggling when close to threshold) bool isAboveThreshold = false; // Flag to track if the high temperature preset is currently active static const char _name[]; static const char _enabled[]; static const char _loopInterval[]; static const char _activationThreshold[]; static const char _presetToActivate[]; // any private methods should go here (non-inline method should be defined out of class) void publishMqtt(const char *state, bool retain = false); // example for publishing MQTT message public: void setup() { } void loop() { // if usermod is disabled or called during strip updating just exit // NOTE: on very long strips strip.isUpdating() may always return true so update accordingly if (!isEnabled || strip.isUpdating() || millis() - lastTime <= loopInterval) return; lastTime = millis(); // Measure the temperature #ifdef ESP8266 // ESP8266 // does not seem possible temperature = -1; #elif defined(CONFIG_IDF_TARGET_ESP32S2) // ESP32S2 temperature = -1; #else // ESP32 ESP32S3 and ESP32C3 temperature = roundf(temperatureRead() * 10) / 10; #endif if(presetToActivate != 0){ // Check if temperature has exceeded the activation threshold if (temperature >= activationThreshold) { // Update the state flag if not already set if (!isAboveThreshold) { isAboveThreshold = true; } // Check if a 'high temperature' preset is configured and it's not already active if (currentPreset != presetToActivate) { // If a playlist is active, store it for reactivation later if (currentPlaylist > 0) { previousPlaylist = currentPlaylist; } // If a preset is active, store it for reactivation later else if (currentPreset > 0) { previousPreset = currentPreset; // If no playlist or preset is active, save current state for reactivation later } else { saveTemporaryPreset(); } // Activate the 'high temperature' preset applyPreset(presetToActivate); } } // Check if temperature is back below the threshold else if (temperature <= (activationThreshold - resetMargin)) { // Update the state flag if not already set if (isAboveThreshold){ isAboveThreshold = false; } // Check if the 'high temperature' preset is active if (currentPreset == presetToActivate) { // Check if a previous playlist was stored if (previousPlaylist > 0) { // Reactivate the stored playlist applyPreset(previousPlaylist); // Clear the stored playlist previousPlaylist = 0; } // Check if a previous preset was stored else if (previousPreset > 0) { // Reactivate the stored preset applyPreset(previousPreset); // Clear the stored preset previousPreset = 0; // If no previous playlist or preset was stored, revert to the stored state } else { applyTemporaryPreset(); } } } } #ifndef WLED_DISABLE_MQTT if (WLED_MQTT_CONNECTED) { char array[10]; snprintf(array, sizeof(array), "%f", temperature); publishMqtt(array); } #endif } void addToJsonInfo(JsonObject &root) { if (!isEnabled) return; // if "u" object does not exist yet wee need to create it JsonObject user = root["u"]; if (user.isNull()) user = root.createNestedObject("u"); JsonArray userTempArr = user.createNestedArray(FPSTR(_name)); userTempArr.add(temperature); userTempArr.add(F(" °C")); // if "sensor" object does not exist yet wee need to create it JsonObject sensor = root[F("sensor")]; if (sensor.isNull()) sensor = root.createNestedObject(F("sensor")); JsonArray sensorTempArr = sensor.createNestedArray(FPSTR(_name)); sensorTempArr.add(temperature); sensorTempArr.add(F("°C")); } void addToConfig(JsonObject &root) { JsonObject top = root.createNestedObject(FPSTR(_name)); top[FPSTR(_enabled)] = isEnabled; top[FPSTR(_loopInterval)] = loopInterval; top[FPSTR(_activationThreshold)] = activationThreshold; top[FPSTR(_presetToActivate)] = presetToActivate; } // Append useful info to the usermod settings gui void appendConfigData() { // Display 'ms' next to the 'Loop Interval' setting oappend(F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');")); // Display '°C' next to the 'Activation Threshold' setting oappend(F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');")); // Display '0 = Disabled' next to the 'Preset To Activate' setting oappend(F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');")); } bool readFromConfig(JsonObject &root) { JsonObject top = root[FPSTR(_name)]; bool configComplete = !top.isNull(); configComplete &= getJsonValue(top[FPSTR(_enabled)], isEnabled); configComplete &= getJsonValue(top[FPSTR(_loopInterval)], loopInterval); loopInterval = max(loopInterval, minLoopInterval); // Makes sure the loop interval isn't too small. configComplete &= getJsonValue(top[FPSTR(_presetToActivate)], presetToActivate); configComplete &= getJsonValue(top[FPSTR(_activationThreshold)], activationThreshold); return configComplete; } uint16_t getId() { return USERMOD_ID_INTERNAL_TEMPERATURE; } }; const char InternalTemperatureUsermod::_name[] PROGMEM = "Internal Temperature"; const char InternalTemperatureUsermod::_enabled[] PROGMEM = "Enabled"; const char InternalTemperatureUsermod::_loopInterval[] PROGMEM = "Loop Interval"; const char InternalTemperatureUsermod::_activationThreshold[] PROGMEM = "Activation Threshold"; const char InternalTemperatureUsermod::_presetToActivate[] PROGMEM = "Preset To Activate"; void InternalTemperatureUsermod::publishMqtt(const char *state, bool retain) { #ifndef WLED_DISABLE_MQTT // Check if MQTT Connected, otherwise it will crash the 8266 if (WLED_MQTT_CONNECTED) { char subuf[64]; strcpy(subuf, mqttDeviceTopic); strcat_P(subuf, PSTR("/mcutemp")); mqtt->publish(subuf, 0, retain, state); } #endif } static InternalTemperatureUsermod internal_temperature_v2; REGISTER_USERMOD(internal_temperature_v2);