From c8f48168b4893540b248f75d04cb37ffd9484545 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 18 Feb 2024 15:52:36 +0100 Subject: [PATCH 01/19] fixed touch buttons for ESP32 S2 and S3 touch is implemented differently on S2 and S3, these changes make touch buttons work on S2 and S3 --- wled00/button.cpp | 27 +++++++++++++++++++++++---- wled00/cfg.cpp | 13 +++++++++++-- wled00/fcn_declare.h | 1 + 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/wled00/button.cpp b/wled00/button.cpp index 29cb0abeb..bf093a207 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -99,11 +99,21 @@ bool isButtonPressed(uint8_t i) case BTN_TYPE_TOUCH: case BTN_TYPE_TOUCH_SWITCH: #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) - if (digitalPinToTouchChannel(btnPin[i]) >= 0 && touchRead(pin) <= touchThreshold) return true; + #ifdef SOC_TOUCH_VERSION_2 //ESP32 S2 and S3 provide a function to check touch state (state is updated in interrupt) + if (touchInterruptGetLastStatus(pin)) + { + return true; + } + #else + if (digitalPinToTouchChannel(btnPin[i]) >= 0 && touchRead(pin) <= touchThreshold) + { + return true; + } + #endif #endif - break; - } - return false; + break; + } + return false; } void handleSwitch(uint8_t b) @@ -406,3 +416,12 @@ void handleIO() offMode = true; } } + +void IRAM_ATTR touchButtonISR() +{ + +#if defined SOC_TOUCH_VERSION_1 //ESP32 original + touchInterruptSetThresholdDirection(flase); //todo: need to flip direction, for that proably need to read current state or something. +#endif + // For S2 and S3: nothing to do, ISR is just used to update registers of HAL driver +} \ No newline at end of file diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 449182fe7..5b8032667 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -228,6 +228,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { // read multiple button configuration JsonObject btn_obj = hw["btn"]; + CJSON(touchThreshold, btn_obj[F("tt")]); bool pull = btn_obj[F("pull")] | (!disablePullUp); // if true, pullup is enabled disablePullUp = !pull; JsonArray hw_btn_ins = btn_obj["ins"]; @@ -252,8 +253,16 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { btnPin[s] = -1; pinManager.deallocatePin(pin,PinOwner::Button); } + //if touch pin, enable the touch interrupt on ESP32 S2 & S3 + #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state but need to attach an interrupt to do so + else if ((buttonType[s] == BTN_TYPE_TOUCH || buttonType[s] == BTN_TYPE_TOUCH_SWITCH)) + { + touchAttachInterrupt(btnPin[s], touchButtonISR, touchThreshold<<2); //threshold on Touch V2 is much higher (TODO: may need shift by 3 if very noisy) + } + #endif + else - #endif + #endif { if (disablePullUp) { pinMode(btnPin[s], INPUT); @@ -299,7 +308,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { } } } - CJSON(touchThreshold,btn_obj[F("tt")]); + CJSON(buttonPublishMqtt,btn_obj["mqtt"]); int hw_ir_pin = hw["ir"]["pin"] | -2; // 4 diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 20ac21129..9b032d031 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -20,6 +20,7 @@ void doublePressAction(uint8_t b=0); bool isButtonPressed(uint8_t b=0); void handleButton(); void handleIO(); +void IRAM_ATTR touchButtonISR(); //cfg.cpp bool deserializeConfig(JsonObject doc, bool fromFS = false); From 15526bd6e8c7a75ee1e36cf24ae397a674f63c56 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 21 Feb 2024 18:38:34 +0100 Subject: [PATCH 02/19] some tuning for touch buttons on S2/S3 now better fits the default threshold value of 32 --- wled00/button.cpp | 17 ++++++++--------- wled00/cfg.cpp | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/wled00/button.cpp b/wled00/button.cpp index bf093a207..05c6ad4bb 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -100,10 +100,8 @@ bool isButtonPressed(uint8_t i) case BTN_TYPE_TOUCH_SWITCH: #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) #ifdef SOC_TOUCH_VERSION_2 //ESP32 S2 and S3 provide a function to check touch state (state is updated in interrupt) - if (touchInterruptGetLastStatus(pin)) - { - return true; - } + if (touchInterruptGetLastStatus(pin)) + return true; #else if (digitalPinToTouchChannel(btnPin[i]) >= 0 && touchRead(pin) <= touchThreshold) { @@ -419,9 +417,10 @@ void handleIO() void IRAM_ATTR touchButtonISR() { - -#if defined SOC_TOUCH_VERSION_1 //ESP32 original - touchInterruptSetThresholdDirection(flase); //todo: need to flip direction, for that proably need to read current state or something. -#endif - // For S2 and S3: nothing to do, ISR is just used to update registers of HAL driver + // used for ESP32 S2 and S3: nothing to do, ISR is just used to update registers of HAL driver + // asm volatile("nop" ::); //prevent compiler to remove this function (TODO: is this really needed? probably not) + + // #if defined SOC_TOUCH_VERSION_1 //ESP32 original -> unused + // touchInterruptSetThresholdDirection(false); //todo: need to flip direction, for that proably need to read current state or something. + // #endif } \ No newline at end of file diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 5b8032667..905566bf2 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -257,7 +257,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state but need to attach an interrupt to do so else if ((buttonType[s] == BTN_TYPE_TOUCH || buttonType[s] == BTN_TYPE_TOUCH_SWITCH)) { - touchAttachInterrupt(btnPin[s], touchButtonISR, touchThreshold<<2); //threshold on Touch V2 is much higher (TODO: may need shift by 3 if very noisy) + touchAttachInterrupt(btnPin[s], touchButtonISR, touchThreshold<<4); //threshold on Touch V2 is much higher (1500 is a value given by Espressif example) } #endif From 5c09ee29db4b31110e8750a07c2fbcd0cb62c8fa Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 4 Mar 2024 14:42:50 +0100 Subject: [PATCH 03/19] removed notes --- wled00/button.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/wled00/button.cpp b/wled00/button.cpp index 05c6ad4bb..e3bd47882 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -418,9 +418,4 @@ void handleIO() void IRAM_ATTR touchButtonISR() { // used for ESP32 S2 and S3: nothing to do, ISR is just used to update registers of HAL driver - // asm volatile("nop" ::); //prevent compiler to remove this function (TODO: is this really needed? probably not) - - // #if defined SOC_TOUCH_VERSION_1 //ESP32 original -> unused - // touchInterruptSetThresholdDirection(false); //todo: need to flip direction, for that proably need to read current state or something. - // #endif } \ No newline at end of file From 509675fe6607a35243b478ab05ceb6e1ccad292f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 9 Mar 2024 16:03:01 +0100 Subject: [PATCH 04/19] added touch interrupt activation to set.cpp for S2/S3 --- wled00/set.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/wled00/set.cpp b/wled00/set.cpp index 7137e0cd8..70e7d0470 100755 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -252,15 +252,24 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) btnPin[i] = -1; pinManager.deallocatePin(hw_btn_pin,PinOwner::Button); } - else if ((buttonType[i] == BTN_TYPE_TOUCH || buttonType[i] == BTN_TYPE_TOUCH_SWITCH) && digitalPinToTouchChannel(btnPin[i]) < 0) + else if ((buttonType[i] == BTN_TYPE_TOUCH || buttonType[i] == BTN_TYPE_TOUCH_SWITCH)) { - // not a touch pin - DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for touch button #%d is not an touch pin!\n"), btnPin[i], i); - btnPin[i] = -1; - pinManager.deallocatePin(hw_btn_pin,PinOwner::Button); + if (digitalPinToTouchChannel(btnPin[i]) < 0) + { + // not a touch pin + DEBUG_PRINTF_P(PSTR("PIN ALLOC error: GPIO%d for touch button #%d is not an touch pin!\n"), btnPin[i], i); + btnPin[i] = -1; + pinManager.deallocatePin(hw_btn_pin,PinOwner::Button); + } + #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state but need to attach an interrupt to do so + else + { + touchAttachInterrupt(btnPin[i], touchButtonISR, touchThreshold << 4); // threshold on Touch V2 is much higher (1500 is a value given by Espressif example) + } + #endif } else - #endif +#endif { if (disablePullUp) { pinMode(btnPin[i], INPUT); From ab13db73e7abc2aa15b202d3b8efae717442065a Mon Sep 17 00:00:00 2001 From: Carlos Cruz Date: Sat, 9 Mar 2024 13:06:30 -0500 Subject: [PATCH 05/19] Added files to usermod directory and changes to platform.ini to support Adafruit MAX17048 module. (#2) Co-authored-by: Azots <78281612+Azots@users.noreply.github.com> --- platformio.ini | 3 + usermods/MAX17048_v2/readme.md | 64 ++++++ usermods/MAX17048_v2/usermod_max17048.h | 281 ++++++++++++++++++++++++ wled00/const.h | 1 + wled00/pin_manager.h | 3 +- wled00/usermods_list.cpp | 8 + 6 files changed, 359 insertions(+), 1 deletion(-) create mode 100644 usermods/MAX17048_v2/readme.md create mode 100644 usermods/MAX17048_v2/usermod_max17048.h diff --git a/platformio.ini b/platformio.ini index 8b5c11bd4..d1f71ea0b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -164,6 +164,9 @@ lib_deps = #For ADS1115 sensor uncomment following ;adafruit/Adafruit BusIO @ 1.13.2 ;adafruit/Adafruit ADS1X15 @ 2.4.0 + #For MAX1704x Lipo Monitor / Fuel Gauge uncomment following + ; https://github.com/adafruit/Adafruit_BusIO @ 1.14.5 + ; https://github.com/adafruit/Adafruit_MAX1704X @ 1.0.2 #For MPU6050 IMU uncomment follwoing ;electroniccats/MPU6050 @1.0.1 # For -D USERMOD_ANIMARTRIX diff --git a/usermods/MAX17048_v2/readme.md b/usermods/MAX17048_v2/readme.md new file mode 100644 index 000000000..958e6def2 --- /dev/null +++ b/usermods/MAX17048_v2/readme.md @@ -0,0 +1,64 @@ +# Adafruit MAX17048 Usermod (LiPo & LiIon Battery Monitor & Fuel Gauge) +This usermod reads information from an Adafruit MAX17048 and outputs the following: +- Battery Voltage +- Battery Level Percentage + + +## Dependencies +Libraries: +- `Adafruit_BusIO@~1.14.5` (by [adafruit](https://github.com/adafruit/Adafruit_BusIO)) +- `Adafruit_MAX1704X@~1.0.2` (by [adafruit](https://github.com/adafruit/Adafruit_MAX1704X)) + +These must be added under `lib_deps` in your `platform.ini` (or `platform_override.ini`). +Data is published over MQTT - make sure you've enabled the MQTT sync interface. + +## Compilation + +To enable, compile with `USERMOD_MAX17048` define in the build_flags (e.g. in `platformio.ini` or `platformio_override.ini`) such as in the example below: +```ini +[env:usermod_max17048_d1_mini] +extends = env:d1_mini +build_flags = + ${common.build_flags_esp8266} + -D USERMOD_MAX17048 +lib_deps = + ${esp8266.lib_deps} + https://github.com/adafruit/Adafruit_BusIO @ 1.14.5 + https://github.com/adafruit/Adafruit_MAX1704X @ 1.0.2 +``` + +### Configuration Options +The following settings can be set at compile-time but are configurable on the usermod menu (except First Monitor time): +- USERMOD_MAX17048_MIN_MONITOR_INTERVAL (the min number of milliseconds between checks, defaults to 10,000 ms) +- USERMOD_MAX17048_MAX_MONITOR_INTERVAL (the max number of milliseconds between checks, defaults to 10,000 ms) +- USERMOD_MAX17048_FIRST_MONITOR_AT + + +Additionally, the Usermod Menu allows you to: +- Enable or Disable the usermod +- Enable or Disable Home Assistant Discovery (turn on/off to sent MQTT Discovery entries for Home Assistant) +- Configure SCL/SDA GPIO Pins + +## API +The following method is available to interact with the usermod from other code modules: +- `getBatteryVoltageV` read the last battery voltage (in Volt) obtained from the sensor +- `getBatteryPercent` reads the last battery percentage obtained from the sensor + +## MQTT +MQTT topics are as follows (`` is set in MQTT section of Sync Setup menu): +Measurement type | MQTT topic +--- | --- +Battery Voltage | `/batteryVoltage` +Battery Percent | `/batteryPercent` + +## Authors +Carlos Cruz [@ccruz09](https://github.com/ccruz09) + + +## Revision History +Jan 2024 +- Added Home Assistant Discovery +- Implemented PinManager to register pins +- Added API call for other modules to read battery voltage and percentage +- Added info-screen outputs +- Updated `readme.md` \ No newline at end of file diff --git a/usermods/MAX17048_v2/usermod_max17048.h b/usermods/MAX17048_v2/usermod_max17048.h new file mode 100644 index 000000000..c3a2664ab --- /dev/null +++ b/usermods/MAX17048_v2/usermod_max17048.h @@ -0,0 +1,281 @@ +// force the compiler to show a warning to confirm that this file is included +#warning **** Included USERMOD_MAX17048 V2.0 **** + +#pragma once + +#include "wled.h" +#include "Adafruit_MAX1704X.h" + + +// the max interval to check battery level, 10 seconds +#ifndef USERMOD_MAX17048_MAX_MONITOR_INTERVAL +#define USERMOD_MAX17048_MAX_MONITOR_INTERVAL 10000 +#endif + +// the min interval to check battery level, 500 ms +#ifndef USERMOD_MAX17048_MIN_MONITOR_INTERVAL +#define USERMOD_MAX17048_MIN_MONITOR_INTERVAL 500 +#endif + +// how many seconds after boot to perform the first check, 10 seconds +#ifndef USERMOD_MAX17048_FIRST_MONITOR_AT +#define USERMOD_MAX17048_FIRST_MONITOR_AT 10000 +#endif + +/* + * Usermod to display Battery Life using Adafruit's MAX17048 LiPoly/ LiIon Fuel Gauge and Battery Monitor. + */ +class Usermod_MAX17048 : public Usermod { + + private: + + bool enabled = true; + + unsigned long maxReadingInterval = USERMOD_MAX17048_MAX_MONITOR_INTERVAL; + unsigned long minReadingInterval = USERMOD_MAX17048_MIN_MONITOR_INTERVAL; + unsigned long lastCheck = UINT32_MAX - (USERMOD_MAX17048_MAX_MONITOR_INTERVAL - USERMOD_MAX17048_FIRST_MONITOR_AT); + unsigned long lastSend = UINT32_MAX - (USERMOD_MAX17048_MAX_MONITOR_INTERVAL - USERMOD_MAX17048_FIRST_MONITOR_AT); + + + uint8_t VoltageDecimals = 3; // Number of decimal places in published voltage values + uint8_t PercentDecimals = 1; // Number of decimal places in published percent values + + // string that are used multiple time (this will save some flash memory) + static const char _name[]; + static const char _enabled[]; + static const char _maxReadInterval[]; + static const char _minReadInterval[]; + static const char _HomeAssistantDiscovery[]; + + bool monitorFound = false; + bool firstReadComplete = false; + bool initDone = false; + + Adafruit_MAX17048 maxLipo; + float lastBattVoltage = -10; + float lastBattPercent = -1; + + // MQTT and Home Assistant Variables + bool HomeAssistantDiscovery = false; // Publish Home Assistant Device Information + bool mqttInitialized = false; + + void _mqttInitialize() + { + char mqttBatteryVoltageTopic[128]; + char mqttBatteryPercentTopic[128]; + + snprintf_P(mqttBatteryVoltageTopic, 127, PSTR("%s/batteryVoltage"), mqttDeviceTopic); + snprintf_P(mqttBatteryPercentTopic, 127, PSTR("%s/batteryPercent"), mqttDeviceTopic); + + if (HomeAssistantDiscovery) { + _createMqttSensor(F("BatteryVoltage"), mqttBatteryVoltageTopic, "voltage", F("V")); + _createMqttSensor(F("BatteryPercent"), mqttBatteryPercentTopic, "battery", F("%")); + } + } + + void _createMqttSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement) + { + String t = String(F("homeassistant/sensor/")) + mqttClientID + F("/") + name + F("/config"); + + StaticJsonDocument<600> doc; + + doc[F("name")] = String(serverDescription) + " " + name; + doc[F("state_topic")] = topic; + doc[F("unique_id")] = String(mqttClientID) + name; + if (unitOfMeasurement != "") + doc[F("unit_of_measurement")] = unitOfMeasurement; + if (deviceClass != "") + doc[F("device_class")] = deviceClass; + doc[F("expire_after")] = 1800; + + JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device + device[F("name")] = serverDescription; + device[F("identifiers")] = "wled-sensor-" + String(mqttClientID); + device[F("manufacturer")] = F("WLED"); + device[F("model")] = F("FOSS"); + device[F("sw_version")] = versionString; + + String temp; + serializeJson(doc, temp); + DEBUG_PRINTLN(t); + DEBUG_PRINTLN(temp); + + mqtt->publish(t.c_str(), 0, true, temp.c_str()); + } + + void publishMqtt(const char *topic, const char* state) { + #ifndef WLED_DISABLE_MQTT + //Check if MQTT Connected, otherwise it will crash the 8266 + if (WLED_MQTT_CONNECTED){ + char subuf[128]; + snprintf_P(subuf, 127, PSTR("%s/%s"), mqttDeviceTopic, topic); + mqtt->publish(subuf, 0, false, state); + } + #endif + } + + public: + + inline void enable(bool enable) { enabled = enable; } + + inline bool isEnabled() { return enabled; } + + void setup() { + // do your set-up here + if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; } + monitorFound = maxLipo.begin(); + initDone = true; + } + + 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 (!enabled || strip.isUpdating()) return; + + unsigned long now = millis(); + + if (now - lastCheck < minReadingInterval) { return; } + + bool shouldUpdate = now - lastSend > maxReadingInterval; + + float battVoltage = maxLipo.cellVoltage(); + float battPercent = maxLipo.cellPercent(); + lastCheck = millis(); + firstReadComplete = true; + + if (shouldUpdate) + { + lastBattVoltage = roundf(battVoltage * powf(10, VoltageDecimals)) / powf(10, VoltageDecimals); + lastBattPercent = roundf(battPercent * powf(10, PercentDecimals)) / powf(10, PercentDecimals); + lastSend = millis(); + + publishMqtt("batteryVoltage", String(lastBattVoltage, VoltageDecimals).c_str()); + publishMqtt("batteryPercent", String(lastBattPercent, PercentDecimals).c_str()); + DEBUG_PRINTLN(F("Battery Voltage: ") + String(lastBattVoltage, VoltageDecimals) + F("V")); + DEBUG_PRINTLN(F("Battery Percent: ") + String(lastBattPercent, PercentDecimals) + F("%")); + } + } + + void onMqttConnect(bool sessionPresent) + { + if (WLED_MQTT_CONNECTED && !mqttInitialized) + { + _mqttInitialize(); + mqttInitialized = true; + } + } + + inline float getBatteryVoltageV() { + return (float) lastBattVoltage; + } + + inline float getBatteryPercent() { + return (float) lastBattPercent; + } + + void addToJsonInfo(JsonObject& root) + { + // if "u" object does not exist yet wee need to create it + JsonObject user = root["u"]; + if (user.isNull()) user = root.createNestedObject("u"); + + + JsonArray battery_json = user.createNestedArray(F("Battery Monitor")); + if (!enabled) { + battery_json.add(F("Disabled")); + } + else if(!monitorFound) { + battery_json.add(F("MAX17048 Not Found")); + } + else if (!firstReadComplete) { + // if we haven't read the sensor yet, let the user know + // that we are still waiting for the first measurement + battery_json.add((USERMOD_MAX17048_FIRST_MONITOR_AT - millis()) / 1000); + battery_json.add(F(" sec until read")); + } else { + battery_json.add(F("Enabled")); + JsonArray voltage_json = user.createNestedArray(F("Battery Voltage")); + voltage_json.add(lastBattVoltage); + voltage_json.add(F("V")); + JsonArray percent_json = user.createNestedArray(F("Battery Percent")); + percent_json.add(lastBattPercent); + percent_json.add(F("%")); + } + } + + void addToJsonState(JsonObject& root) + { + JsonObject usermod = root[FPSTR(_name)]; + if (usermod.isNull()) + { + usermod = root.createNestedObject(FPSTR(_name)); + } + usermod[FPSTR(_enabled)] = enabled; + } + + void readFromJsonState(JsonObject& root) + { + JsonObject usermod = root[FPSTR(_name)]; + if (!usermod.isNull()) + { + if (usermod[FPSTR(_enabled)].is()) + { + enabled = usermod[FPSTR(_enabled)].as(); + } + } + } + + void addToConfig(JsonObject& root) + { + JsonObject top = root.createNestedObject(FPSTR(_name)); + top[FPSTR(_enabled)] = enabled; + top[FPSTR(_maxReadInterval)] = maxReadingInterval; + top[FPSTR(_minReadInterval)] = minReadingInterval; + top[FPSTR(_HomeAssistantDiscovery)] = HomeAssistantDiscovery; + DEBUG_PRINT(F(_name)); + DEBUG_PRINTLN(F(" config saved.")); + } + + bool readFromConfig(JsonObject& root) + { + JsonObject top = root[FPSTR(_name)]; + + if (top.isNull()) { + DEBUG_PRINT(F(_name)); + DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + return false; + } + + bool configComplete = !top.isNull(); + + configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled); + configComplete &= getJsonValue(top[FPSTR(_maxReadInterval)], maxReadingInterval, USERMOD_MAX17048_MAX_MONITOR_INTERVAL); + configComplete &= getJsonValue(top[FPSTR(_minReadInterval)], minReadingInterval, USERMOD_MAX17048_MIN_MONITOR_INTERVAL); + configComplete &= getJsonValue(top[FPSTR(_HomeAssistantDiscovery)], HomeAssistantDiscovery, false); + + DEBUG_PRINT(FPSTR(_name)); + if (!initDone) { + // first run: reading from cfg.json + DEBUG_PRINTLN(F(" config loaded.")); + } else { + DEBUG_PRINTLN(F(" config (re)loaded.")); + // changing parameters from settings page + } + + return configComplete; + } + + uint16_t getId() + { + return USERMOD_ID_MAX17048; + } + +}; + + +// add more strings here to reduce flash memory usage +const char Usermod_MAX17048::_name[] PROGMEM = "Adafruit MAX17048 Battery Monitor"; +const char Usermod_MAX17048::_enabled[] PROGMEM = "enabled"; +const char Usermod_MAX17048::_maxReadInterval[] PROGMEM = "max-read-interval-ms"; +const char Usermod_MAX17048::_minReadInterval[] PROGMEM = "min-read-interval-ms"; +const char Usermod_MAX17048::_HomeAssistantDiscovery[] PROGMEM = "HomeAssistantDiscovery"; diff --git a/wled00/const.h b/wled00/const.h index dd965bc40..11e761cd0 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -180,6 +180,7 @@ #define USERMOD_ID_STAIRWAY_WIPE 44 //Usermod "stairway-wipe-usermod-v2.h" #define USERMOD_ID_ANIMARTRIX 45 //Usermod "usermod_v2_animartrix.h" #define USERMOD_ID_HTTP_PULL_LIGHT_CONTROL 46 //usermod "usermod_v2_HttpPullLightControl.h" +#define USERMOD_ID_MAX17048 47 //Usermod "usermod_max17048.h" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index 6a50df588..a94dc7a28 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -61,7 +61,8 @@ enum struct PinOwner : uint8_t { UM_Audioreactive = USERMOD_ID_AUDIOREACTIVE, // 0x20 // Usermod "audio_reactive.h" UM_SdCard = USERMOD_ID_SD_CARD, // 0x25 // Usermod "usermod_sd_card.h" UM_PWM_OUTPUTS = USERMOD_ID_PWM_OUTPUTS, // 0x26 // Usermod "usermod_pwm_outputs.h" - UM_LDR_DUSK_DAWN = USERMOD_ID_LDR_DUSK_DAWN // 0x2B // Usermod "usermod_LDR_Dusk_Dawn_v2.h" + UM_LDR_DUSK_DAWN = USERMOD_ID_LDR_DUSK_DAWN, // 0x2B // Usermod "usermod_LDR_Dusk_Dawn_v2.h" + UM_MAX17048 = USERMOD_ID_MAX17048 // 0x2F // Usermod "usermod_max17048.h" }; static_assert(0u == static_cast(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected"); diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index bcfb41fa3..a5ddb06a8 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -209,6 +209,10 @@ #include "../usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h" #endif +#ifdef USERMOD_MAX17048 + #include "../usermods/MAX17048_v2/usermod_max17048.h" +#endif + void registerUsermods() { /* @@ -405,4 +409,8 @@ void registerUsermods() #ifdef USERMOD_STAIRCASE_WIPE usermods.add(new StairwayWipeUsermod()); #endif + + #ifdef USERMOD_MAX17048 + usermods.add(new Usermod_MAX17048()); + #endif } From 0453a5fb3ded8851011cbe65db747b2118555f43 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 10 Mar 2024 16:54:25 +0100 Subject: [PATCH 06/19] added interrupt detach to cfg.cpp --- wled00/cfg.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 905566bf2..e59a342c5 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -235,6 +235,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { if (!hw_btn_ins.isNull()) { for (uint8_t b = 0; b < WLED_MAX_BUTTONS; b++) { // deallocate existing button pins pinManager.deallocatePin(btnPin[b], PinOwner::Button); // does nothing if trying to deallocate a pin with PinOwner != Button + #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state, detach any previous assignments + touchDetachInterrupt(btnPin[b]); + #endif } uint8_t s = 0; for (JsonObject btn : hw_btn_ins) { @@ -260,9 +263,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { touchAttachInterrupt(btnPin[s], touchButtonISR, touchThreshold<<4); //threshold on Touch V2 is much higher (1500 is a value given by Espressif example) } #endif - else - #endif + #endif { if (disablePullUp) { pinMode(btnPin[s], INPUT); From 0637c1c9d4524bfe8efa83fcd4622fcd89bb8ab8 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 10 Mar 2024 19:44:27 +0100 Subject: [PATCH 07/19] bugfixes -added minimum threshold, had some crashes when setting threshold to zero before -moved interrupt detach to GPIO deallocation where it belongs -added check for touchbutton before detaching interrupt -moved thochThreshold readout up so it gets updated before passing it to the system call --- wled00/cfg.cpp | 5 +---- wled00/pin_manager.cpp | 5 +++++ wled00/set.cpp | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index e59a342c5..91689aab4 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -235,9 +235,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { if (!hw_btn_ins.isNull()) { for (uint8_t b = 0; b < WLED_MAX_BUTTONS; b++) { // deallocate existing button pins pinManager.deallocatePin(btnPin[b], PinOwner::Button); // does nothing if trying to deallocate a pin with PinOwner != Button - #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state, detach any previous assignments - touchDetachInterrupt(btnPin[b]); - #endif } uint8_t s = 0; for (JsonObject btn : hw_btn_ins) { @@ -260,7 +257,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state but need to attach an interrupt to do so else if ((buttonType[s] == BTN_TYPE_TOUCH || buttonType[s] == BTN_TYPE_TOUCH_SWITCH)) { - touchAttachInterrupt(btnPin[s], touchButtonISR, touchThreshold<<4); //threshold on Touch V2 is much higher (1500 is a value given by Espressif example) + touchAttachInterrupt(btnPin[s], touchButtonISR, 256 + (touchThreshold << 4)); // threshold on Touch V2 is much higher (1500 is a value given by Espressif example, I measured changes of over 5000) } #endif else diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 044dc6c92..e80583464 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -32,6 +32,11 @@ bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag) return false; } + #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state, detach any previous assignments + if (digitalPinToTouchChannel(gpio) >= 0) //if touch capable pin + touchDetachInterrupt(gpio); + #endif + byte by = gpio >> 3; byte bi = gpio - 8*by; bitWrite(pinAlloc[by], bi, false); diff --git a/wled00/set.cpp b/wled00/set.cpp index 70e7d0470..8a461fbc8 100755 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -236,6 +236,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) rlyMde = (bool)request->hasArg(F("RM")); disablePullUp = (bool)request->hasArg(F("IP")); + touchThreshold = request->arg(F("TT")).toInt(); for (uint8_t i=0; i10) char be[4] = "BE"; be[2] = (i<10?48:55)+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10) @@ -264,7 +265,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state but need to attach an interrupt to do so else { - touchAttachInterrupt(btnPin[i], touchButtonISR, touchThreshold << 4); // threshold on Touch V2 is much higher (1500 is a value given by Espressif example) + touchAttachInterrupt(btnPin[i], touchButtonISR, 256 + (touchThreshold << 4)); // threshold on Touch V2 is much higher (1500 is a value given by Espressif example, I measured changes of over 5000) } #endif } @@ -286,7 +287,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) buttonType[i] = BTN_TYPE_NONE; } } - touchThreshold = request->arg(F("TT")).toInt(); briS = request->arg(F("CA")).toInt(); From a7e17eabff784daa1599ad0dd21a4bb6e1a529a9 Mon Sep 17 00:00:00 2001 From: Woody Date: Tue, 2 Apr 2024 20:12:14 +0200 Subject: [PATCH 08/19] add cdata test for package.json & fix a small bug --- tools/cdata-test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/cdata-test.js b/tools/cdata-test.js index 55f068073..7c2f11bd9 100644 --- a/tools/cdata-test.js +++ b/tools/cdata-test.js @@ -131,7 +131,7 @@ describe('Script', () => { // run script cdata.js again and wait for it to finish await execPromise('node tools/cdata.js'); - checkIfFileWasNewlyCreated(path.join(folderPath, resultFile)); + await checkIfFileWasNewlyCreated(path.join(folderPath, resultFile)); } describe('should build if', () => { @@ -182,6 +182,10 @@ describe('Script', () => { it('cdata.js changes', async () => { await testFileModification('tools/cdata.js', 'html_ui.h'); }); + + it('package.json changes', async () => { + await testFileModification('package.json', 'html_ui.h'); + }); }); describe('should not build if', () => { From 4db88cf86b7e91fd9c2f50656c17da1fd7bf0ccb Mon Sep 17 00:00:00 2001 From: Woody Date: Tue, 2 Apr 2024 20:38:56 +0200 Subject: [PATCH 09/19] update cdata.js to rebuild if package.json changes --- tools/cdata.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/cdata.js b/tools/cdata.js index 3b8af46da..12dda1cbe 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -2,7 +2,7 @@ * Writes compressed C arrays of data files (web interface) * How to use it? * - * 1) Install Node 11+ and npm + * 1) Install Node 20+ and npm * 2) npm install * 3) npm run build * @@ -207,7 +207,7 @@ function isAnyFileInFolderNewerThan(folderPath, time) { } // Check if the web UI is already built -function isAlreadyBuilt(folderPath) { +function isAlreadyBuilt(webUIPath, packageJsonPath = "package.json") { let lastBuildTime = Infinity; for (const file of output) { @@ -220,7 +220,7 @@ function isAlreadyBuilt(folderPath) { } } - return !isAnyFileInFolderNewerThan(folderPath, lastBuildTime) && !isFileNewerThan("tools/cdata.js", lastBuildTime); + return !isAnyFileInFolderNewerThan(webUIPath, lastBuildTime) && !isFileNewerThan(packageJsonPath, lastBuildTime) && !isFileNewerThan(__filename, lastBuildTime); } // Don't run this script if we're in a test environment From 78b37b592e72e5abdf9d06a307bc1b56277a306e Mon Sep 17 00:00:00 2001 From: Woody Date: Tue, 2 Apr 2024 20:59:31 +0200 Subject: [PATCH 10/19] backup & restore package.json in cdata tests --- tools/cdata-test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/cdata-test.js b/tools/cdata-test.js index 7c2f11bd9..6f27fb717 100644 --- a/tools/cdata-test.js +++ b/tools/cdata-test.js @@ -83,6 +83,7 @@ describe('Script', () => { // Backup files fs.cpSync("wled00/data", "wled00Backup", { recursive: true }); fs.cpSync("tools/cdata.js", "cdata.bak.js"); + fs.cpSync("package.json", "package.bak.json"); }); after(() => { // Restore backup @@ -90,6 +91,8 @@ describe('Script', () => { fs.renameSync("wled00Backup", "wled00/data"); fs.rmSync("tools/cdata.js"); fs.renameSync("cdata.bak.js", "tools/cdata.js"); + fs.rmSync("package.json"); + fs.renameSync("package.bak.json", "package.json"); }); // delete all html_*.h files From a106342439017882a7756e00ed1d1696108e7a88 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Thu, 4 Apr 2024 23:09:59 +0200 Subject: [PATCH 11/19] PICO & WROVER runtime support return of GPIO16 --- wled00/const.h | 8 ++++---- wled00/pin_manager.cpp | 3 ++- wled00/wled.cpp | 8 ++------ wled00/xml.cpp | 11 +++-------- 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/wled00/const.h b/wled00/const.h index cd0deed57..0ce7b27d5 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -508,11 +508,11 @@ //this is merely a default now and can be changed at runtime #ifndef LEDPIN -//#if defined(ESP8266) || (defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(ARDUINO_ESP32_PICO) +#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) //|| (defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)) || defined(ARDUINO_ESP32_PICO) #define LEDPIN 2 // GPIO2 (D4) on Wemos D1 mini compatible boards, safe to use on any board -//#else -// #define LEDPIN 16 // aligns with GPIO2 (D4) on Wemos D1 mini32 compatible boards -//#endif +#else + #define LEDPIN 16 // aligns with GPIO2 (D4) on Wemos D1 mini32 compatible boards (if it is unusable it will be reassigned in WS2812FX::finalizeInit()) +#endif #endif #ifdef WLED_ENABLE_DMX diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 34705ee94..dd00943d8 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -248,7 +248,7 @@ bool PinManagerClass::isPinOk(byte gpio, bool output) const // 00 to 18 are for general use. Be careful about straping pins GPIO0 and GPIO3 - these may be pulled-up or pulled-down on your board. if (gpio > 18 && gpio < 21) return false; // 19 + 20 = USB-JTAG. Not recommended for other uses. if (gpio > 21 && gpio < 33) return false; // 22 to 32: not connected + SPI FLASH - //if (gpio > 32 && gpio < 38) return false; // 33 to 37: not available if using _octal_ SPI Flash or _octal_ PSRAM + if (gpio > 32 && gpio < 38) return !psramFound(); // 33 to 37: not available if using _octal_ SPI Flash or _octal_ PSRAM // 38 to 48 are for general use. Be careful about straping pins GPIO45 and GPIO46 - these may be pull-up or pulled-down on your board. #elif defined(CONFIG_IDF_TARGET_ESP32S2) // strapping pins: 0, 45 & 46 @@ -257,6 +257,7 @@ bool PinManagerClass::isPinOk(byte gpio, bool output) const // GPIO46 is input only and pulled down #else if (gpio > 5 && gpio < 12) return false; //SPI flash pins + if (strncmp_P(PSTR("ESP32-PICO"), ESP.getChipModel(), 10) == 0 && (gpio == 16 || gpio == 17)) return false; // PICO-D4: gpio16+17 are in use for onboard SPI FLASH if (gpio == 16 || gpio == 17) return !psramFound(); //PSRAM pins on ESP32 (these are IO) #endif if (output) return digitalPinCanOutput(gpio); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index c64ea935c..c0d17beb7 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -368,7 +368,8 @@ void WLED::setup() DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); #if defined(ARDUINO_ARCH_ESP32) - #ifndef BOARD_HAS_PSRAM + // BOARD_HAS_PSRAM also means that a compiler flag "-mfix-esp32-psram-cache-issue" was used and so PSRAM is safe to use on rev.1 ESP32 + #if !defined(BOARD_HAS_PSRAM) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)) if (psramFound() && ESP.getChipRevision() < 3) psramSafe = false; if (!psramSafe) DEBUG_PRINTLN(F("Not using PSRAM.")); #endif @@ -380,11 +381,6 @@ void WLED::setup() DEBUG_PRINT(F("Free PSRAM : ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB"); } #endif -#if defined(ARDUINO_ESP32_PICO) - // special handling for PICO-D4: gpio16+17 are in use for onboard SPI FLASH (not PSRAM) - managed_pin_type pins[] = { {16, true}, {17, true} }; - pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM); -#endif #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) pinManager.allocatePin(hardwareTX, true, PinOwner::DebugOut); // TX (GPIO1 on ESP32) reserved for debug output diff --git a/wled00/xml.cpp b/wled00/xml.cpp index c91f0dd7e..3915d9b0e 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -145,10 +145,13 @@ void appendGPIOinfo() { oappend(SET_F("d.rsvd=[22,23,24,25,26,27,28,29,30,31,32")); #elif defined(CONFIG_IDF_TARGET_ESP32S3) oappend(SET_F("d.rsvd=[19,20,22,23,24,25,26,27,28,29,30,31,32")); // includes 19+20 for USB OTG (JTAG) + if (psramFound()) oappend(SET_F(",33,34,35,36,37")); // in use for "octal" PSRAM or "octal" FLASH -seems that octal PSRAM is very common on S3. #elif defined(CONFIG_IDF_TARGET_ESP32C3) oappend(SET_F("d.rsvd=[11,12,13,14,15,16,17")); #elif defined(ESP32) oappend(SET_F("d.rsvd=[6,7,8,9,10,11,24,28,29,30,31,37,38")); + if (!pinManager.isPinOk(16,false)) oappend(SET_F(",16")); // covers PICO & WROVER + if (!pinManager.isPinOk(17,false)) oappend(SET_F(",17")); // covers PICO & WROVER #else oappend(SET_F("d.rsvd=[6,7,8,9,10,11")); #endif @@ -163,14 +166,6 @@ void appendGPIOinfo() { //Note: Using pin 3 (RX) disables Adalight / Serial JSON - #if defined(ARDUINO_ARCH_ESP32) - #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C3) - if (psramFound()) oappend(SET_F(",16,17")); // GPIO16 & GPIO17 reserved for SPI RAM on ESP32 (not on S2, S3 or C3) - #elif defined(CONFIG_IDF_TARGET_ESP32S3) - if (psramFound()) oappend(SET_F(",33,34,35,36,37")); // in use for "octal" PSRAM or "octal" FLASH -seems that octal PSRAM is very common on S3. - #endif - #endif - #ifdef WLED_USE_ETHERNET if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { for (uint8_t p=0; p Date: Fri, 5 Apr 2024 07:23:28 +0200 Subject: [PATCH 12/19] Bugfix: millis rollover (fix for #3870) millis()/1000 rollover after 18h was not handled, truncating to 16bits after division fixes it. --- wled00/FX_fcn.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 617558ffa..fcf6cd0cb 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -455,9 +455,9 @@ CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, u // relies on WS2812FX::service() to call it for each frame void Segment::handleRandomPalette() { // is it time to generate a new palette? - if ((millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) { + if (((millis()/1000U) & 0xFFFF) - _lastPaletteChange > randomPaletteChangeTime) { _newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette(); - _lastPaletteChange = millis()/1000U; + _lastPaletteChange = millis()/1000U; //take lower 16bits _lastPaletteBlend = (uint16_t)(millis() & 0xFFFF)-512; // starts blending immediately } @@ -466,7 +466,7 @@ void Segment::handleRandomPalette() { // assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less) // in reality there need to be 255 blends to fully blend two entirely different palettes if ((millis() & 0xFFFF) - _lastPaletteBlend < strip.getTransition() >> 7) return; // not yet time to fade, delay the update - _lastPaletteBlend = millis(); + _lastPaletteBlend = millis(); //take lower 16bits } nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48); } From aa970d6ca5773affe33a1c5a322bfe359802e048 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 5 Apr 2024 19:26:09 +0200 Subject: [PATCH 13/19] Extend JSON API info object - add "clock" - CPU clock in MHz - add "flash" - flash size in MB Fix for #3879 --- wled00/data/index.js | 6 +++--- wled00/json.cpp | 4 ++++ wled00/wled.cpp | 3 ++- wled00/wled.h | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/wled00/data/index.js b/wled00/data/index.js index 4ad2044ad..03ee276a8 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -694,8 +694,6 @@ function parseInfo(i) { function populateInfo(i) { var cn=""; - var heap = i.freeheap/1024; - heap = heap.toFixed(1); var pwr = i.leds.pwr; var pwru = "Not calculated"; if (pwr > 1000) {pwr /= 1000; pwr = pwr.toFixed((pwr > 10) ? 0 : 1); pwru = pwr + " A";} @@ -720,11 +718,13 @@ ${inforow("Build",i.vid)} ${inforow("Signal strength",i.wifi.signal +"% ("+ i.wifi.rssi, " dBm)")} ${inforow("Uptime",getRuntimeStr(i.uptime))} ${inforow("Time",i.time)} -${inforow("Free heap",heap," kB")} +${inforow("Free heap",(i.freeheap/1024).toFixed(1)," kB")} ${i.psram?inforow("Free PSRAM",(i.psram/1024).toFixed(1)," kB"):""} ${inforow("Estimated current",pwru)} ${inforow("Average FPS",i.leds.fps)} ${inforow("MAC address",i.mac)} +${inforow("CPU clock",i.clock," MHz")} +${inforow("Flash size",i.flash," MB")} ${inforow("Filesystem",i.fs.u + "/" + i.fs.t + " kB (" +Math.round(i.fs.u*100/i.fs.t) + "%)")} ${inforow("Environment",i.arch + " " + i.core + " (" + i.lwip + ")")} `; diff --git a/wled00/json.cpp b/wled00/json.cpp index fd1527a21..bc4d1808a 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -749,6 +749,8 @@ void serializeInfo(JsonObject root) root[F("arch")] = ESP.getChipModel(); #endif root[F("core")] = ESP.getSdkVersion(); + root[F("clock")] = ESP.getCpuFreqMHz(); + root[F("flash")] = (ESP.getFlashChipSize()/1024)/1024; #ifdef WLED_DEBUG root[F("maxalloc")] = ESP.getMaxAllocHeap(); root[F("resetReason0")] = (int)rtc_get_reset_reason(0); @@ -758,6 +760,8 @@ void serializeInfo(JsonObject root) #else root[F("arch")] = "esp8266"; root[F("core")] = ESP.getCoreVersion(); + root[F("clock")] = ESP.getCpuFreqMHz(); + root[F("flash")] = (ESP.getFlashChipSize()/1024)/1024; #ifdef WLED_DEBUG root[F("maxalloc")] = ESP.getMaxFreeBlockSize(); root[F("resetReason")] = (int)ESP.getResetInfoPtr()->reason; diff --git a/wled00/wled.cpp b/wled00/wled.cpp index c0d17beb7..eb7860851 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -362,8 +362,9 @@ void WLED::setup() DEBUG_PRINT(F(", speed ")); DEBUG_PRINT(ESP.getFlashChipSpeed()/1000000);DEBUG_PRINTLN(F("MHz.")); #else - DEBUG_PRINT(F("esp8266 ")); + DEBUG_PRINT(F("esp8266 @ ")); DEBUG_PRINT(ESP.getCpuFreqMHz()); DEBUG_PRINT(F("MHz.\nCore: ")); DEBUG_PRINTLN(ESP.getCoreVersion()); + DEBUG_PRINT(F("FLASH: ")); DEBUG_PRINT((ESP.getFlashChipSize()/1024)/1024); DEBUG_PRINTLN(F(" MB")); #endif DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); diff --git a/wled00/wled.h b/wled00/wled.h index 35b99260a..f96be3c1b 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2403280 +#define VERSION 2404050 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG From 9ffcde878ac3500d8c00e3288f9296a6dceac6e8 Mon Sep 17 00:00:00 2001 From: gaaat98 <67930088+gaaat98@users.noreply.github.com> Date: Sat, 6 Apr 2024 15:40:32 +0200 Subject: [PATCH 14/19] fix for #3884 --- wled00/bus_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 764ab6e2b..82e81a387 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -505,7 +505,7 @@ void BusPwm::show() { uint8_t numPins = NUM_PWM_PINS(_type); unsigned maxBri = (1<<_depth) - 1; #ifdef ESP8266 - unsigned pwmBri = (unsigned)(roundf(powf((float)_bri / 255.0f, 1.7f) * (float)maxBri + 0.5f)); // using gamma 1.7 to extrapolate PWM duty cycle + unsigned pwmBri = (unsigned)(roundf(powf((float)_bri / 255.0f, 1.7f) * (float)maxBri)); // using gamma 1.7 to extrapolate PWM duty cycle #else unsigned pwmBri = cieLUT[_bri] >> (12 - _depth); // use CIE LUT #endif From d3a97f106222d208011dd84f3aa5781579afd20e Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 7 Apr 2024 13:49:17 +0200 Subject: [PATCH 15/19] removed detachinterrupt from pin manager, added it to set.cpp instead --- wled00/pin_manager.cpp | 5 ----- wled00/set.cpp | 6 +++++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index e80583464..044dc6c92 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -32,11 +32,6 @@ bool PinManagerClass::deallocatePin(byte gpio, PinOwner tag) return false; } - #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state, detach any previous assignments - if (digitalPinToTouchChannel(gpio) >= 0) //if touch capable pin - touchDetachInterrupt(gpio); - #endif - byte by = gpio >> 3; byte bi = gpio - 8*by; bitWrite(pinAlloc[by], bi, false); diff --git a/wled00/set.cpp b/wled00/set.cpp index 8a461fbc8..0920588fe 100755 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -108,6 +108,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) for (uint8_t s=0; s=0 && pinManager.isPinAllocated(btnPin[s], PinOwner::Button)) { pinManager.deallocatePin(btnPin[s], PinOwner::Button); + #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a function to check touch state, detach interrupt + if (digitalPinToTouchChannel(btnPin[i]) >= 0) // if touch capable pin + touchDetachInterrupt(btnPin[i]); // if not assigned previously, this will do nothing + #endif } } @@ -270,7 +274,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) #endif } else -#endif + #endif { if (disablePullUp) { pinMode(btnPin[i], INPUT); From 18c17168e19eb41f63dd29319146a96160192393 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 7 Apr 2024 16:07:37 +0200 Subject: [PATCH 16/19] replaced &0xFFFF with explicit casts --- wled00/FX_fcn.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index fcf6cd0cb..2a3cd0897 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -455,18 +455,18 @@ CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, u // relies on WS2812FX::service() to call it for each frame void Segment::handleRandomPalette() { // is it time to generate a new palette? - if (((millis()/1000U) & 0xFFFF) - _lastPaletteChange > randomPaletteChangeTime) { + if ((uint16_t)((uint16_t)(millis() / 1000U) - _lastPaletteChange) > randomPaletteChangeTime){ _newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette(); - _lastPaletteChange = millis()/1000U; //take lower 16bits - _lastPaletteBlend = (uint16_t)(millis() & 0xFFFF)-512; // starts blending immediately + _lastPaletteChange = (uint16_t)(millis() / 1000U); + _lastPaletteBlend = (uint16_t)((uint16_t)millis() - 512); // starts blending immediately } // if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls) if (strip.paletteFade) { // assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less) // in reality there need to be 255 blends to fully blend two entirely different palettes - if ((millis() & 0xFFFF) - _lastPaletteBlend < strip.getTransition() >> 7) return; // not yet time to fade, delay the update - _lastPaletteBlend = millis(); //take lower 16bits + if ((uint16_t)((uint16_t)millis() - _lastPaletteBlend) < strip.getTransition() >> 7) return; // not yet time to fade, delay the update + _lastPaletteBlend = (uint16_t)millis(); } nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48); } From 954f26308b66e19f4a1ad11fc5772b9c79f1e508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 7 Apr 2024 22:12:01 +0200 Subject: [PATCH 17/19] Update button.cpp Indentation fix --- wled00/button.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/wled00/button.cpp b/wled00/button.cpp index e3bd47882..06683e17a 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -100,18 +100,14 @@ bool isButtonPressed(uint8_t i) case BTN_TYPE_TOUCH_SWITCH: #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) #ifdef SOC_TOUCH_VERSION_2 //ESP32 S2 and S3 provide a function to check touch state (state is updated in interrupt) - if (touchInterruptGetLastStatus(pin)) - return true; + if (touchInterruptGetLastStatus(pin)) return true; #else - if (digitalPinToTouchChannel(btnPin[i]) >= 0 && touchRead(pin) <= touchThreshold) - { - return true; - } + if (digitalPinToTouchChannel(btnPin[i]) >= 0 && touchRead(pin) <= touchThreshold) return true; #endif #endif break; - } - return false; + } + return false; } void handleSwitch(uint8_t b) @@ -418,4 +414,4 @@ void handleIO() void IRAM_ATTR touchButtonISR() { // used for ESP32 S2 and S3: nothing to do, ISR is just used to update registers of HAL driver -} \ No newline at end of file +} From d1d54ce9c8aacf93541dba34b457a947eed5e625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 7 Apr 2024 22:15:58 +0200 Subject: [PATCH 18/19] Update cfg.cpp Indentation fix --- wled00/cfg.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 91689aab4..9d36134f0 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -255,10 +255,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { } //if touch pin, enable the touch interrupt on ESP32 S2 & S3 #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a fucntion to check touch state but need to attach an interrupt to do so - else if ((buttonType[s] == BTN_TYPE_TOUCH || buttonType[s] == BTN_TYPE_TOUCH_SWITCH)) - { - touchAttachInterrupt(btnPin[s], touchButtonISR, 256 + (touchThreshold << 4)); // threshold on Touch V2 is much higher (1500 is a value given by Espressif example, I measured changes of over 5000) - } + if ((buttonType[s] == BTN_TYPE_TOUCH || buttonType[s] == BTN_TYPE_TOUCH_SWITCH)) + { + touchAttachInterrupt(btnPin[s], touchButtonISR, 256 + (touchThreshold << 4)); // threshold on Touch V2 is much higher (1500 is a value given by Espressif example, I measured changes of over 5000) + } #endif else #endif From b72f3baab7ecf74d56c7caacb1aa177b3ad72140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 7 Apr 2024 22:21:41 +0200 Subject: [PATCH 19/19] Update set.cpp Compile fix --- wled00/set.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wled00/set.cpp b/wled00/set.cpp index 0920588fe..0b84160c9 100755 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -108,10 +108,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) for (uint8_t s=0; s=0 && pinManager.isPinAllocated(btnPin[s], PinOwner::Button)) { pinManager.deallocatePin(btnPin[s], PinOwner::Button); - #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a function to check touch state, detach interrupt - if (digitalPinToTouchChannel(btnPin[i]) >= 0) // if touch capable pin - touchDetachInterrupt(btnPin[i]); // if not assigned previously, this will do nothing - #endif + #ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a function to check touch state, detach interrupt + if (digitalPinToTouchChannel(btnPin[s]) >= 0) // if touch capable pin + touchDetachInterrupt(btnPin[s]); // if not assigned previously, this will do nothing + #endif } }