From 8dd17451495fa96cc87fe6f9a145d7c041b35e86 Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Thu, 5 Jan 2023 19:48:53 +0100 Subject: [PATCH 01/66] =?UTF-8?q?Add=20base=20battery=20=F0=9F=94=8B=20cla?= =?UTF-8?q?ss,=20Add=20Lipo,=20Lion=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- usermods/Battery/battery.h | 149 +++++++++++++++++ usermods/Battery/battery_defaults.h | 11 +- usermods/Battery/lion.h | 37 +++++ usermods/Battery/lipo.h | 51 ++++++ usermods/Battery/usermod_v2_Battery.h | 221 +++++--------------------- 5 files changed, 290 insertions(+), 179 deletions(-) create mode 100644 usermods/Battery/battery.h create mode 100644 usermods/Battery/lion.h create mode 100644 usermods/Battery/lipo.h diff --git a/usermods/Battery/battery.h b/usermods/Battery/battery.h new file mode 100644 index 000000000..f3daf05c4 --- /dev/null +++ b/usermods/Battery/battery.h @@ -0,0 +1,149 @@ +#ifndef UMBBattery_h +#define UMBBattery_h + +#include "battery_defaults.h" + +/** + * Battery base class + * all other battery classes should inherit from this + */ +class Battery +{ + private: + + protected: + float minVoltage = USERMOD_BATTERY_MIN_VOLTAGE; + float maxVoltage = USERMOD_BATTERY_MAX_VOLTAGE; + unsigned int capacity = USERMOD_BATTERY_TOTAL_CAPACITY; // current capacity + float voltage = this->maxVoltage; // current voltage + int8_t level = 100; // current level + float calibration = USERMOD_BATTERY_CALIBRATION; // offset or calibration value to fine tune the calculated voltage + + float linearMapping(float v, float min, float max, float oMin = 0.0f, float oMax = 100.0f) + { + return (v-min) * (oMax-oMin) / (max-min) + oMin; + } + + public: + Battery() + { + + } + + /** + * Corresponding battery curves + * calculates the capacity in % (0-100) with given voltage and possible voltage range + */ + virtual float mapVoltage(float v, float min, float max) = 0; + // { + // example implementation, linear mapping + // return (v-min) * 100 / (max-min); + // }; + + virtual void calculateAndSetLevel(float voltage) = 0; + + + + /* + * + * Getter and Setter + * + */ + + /* + * Get lowest configured battery voltage + */ + virtual float getMinVoltage() + { + return this->minVoltage; + } + + /* + * Set lowest battery voltage + * can't be below 0 volt + */ + virtual void setMinVoltage(float voltage) + { + this->minVoltage = max(0.0f, voltage); + } + + /* + * Get highest configured battery voltage + */ + virtual float getMaxVoltage() + { + return this->maxVoltage; + } + + /* + * Set highest battery voltage + * can't be below minVoltage + */ + virtual void setMaxVoltage(float voltage) + { + #ifdef USERMOD_BATTERY_USE_LIPO + this->maxVoltage = max(getMinVoltage()+0.7f, voltage); + #else + this->maxVoltage = max(getMinVoltage()+1.0f, voltage); + #endif + } + + /* + * Get the capacity of all cells in parralel sumed up + * unit: mAh + */ + unsigned int getCapacity() + { + return this->capacity; + } + + void setCapacity(unsigned int capacity) + { + this->capacity = capacity; + } + + float getVoltage() + { + return this->voltage; + } + + /** + * check if voltage is within specified voltage range, allow 10% over/under voltage + */ + void setVoltage(float voltage) + { + this->voltage = ( (voltage < this->getMinVoltage() * 0.85f) || (voltage > this->getMaxVoltage() * 1.1f) ) + ? -1.0f + : voltage; + } + + float getLevel() + { + return this->level; + } + + void setLevel(float level) + { + this->level = constrain(level, 0.0f, 110.0f);; + } + + /* + * Get the configured calibration value + * a offset value to fine-tune the calculated voltage. + */ + virtual float getCalibration() + { + return calibration; + } + + /* + * Set the voltage calibration offset value + * a offset value to fine-tune the calculated voltage. + */ + virtual void setCalibration(float offset) + { + calibration = offset; + } +}; + +#endif \ No newline at end of file diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h index c682cb45d..73f14f62a 100644 --- a/usermods/Battery/battery_defaults.h +++ b/usermods/Battery/battery_defaults.h @@ -14,6 +14,15 @@ #define USERMOD_BATTERY_MEASUREMENT_INTERVAL 30000 #endif + +/* Default Battery Type + * 1 = Lipo + * 2 = Lion + */ +#ifndef USERMOB_BATTERY_DEFAULT_TYPE + #define USERMOB_BATTERY_DEFAULT_TYPE 1 +#endif + // default for 18650 battery // https://batterybro.com/blogs/18650-wholesale-battery-reviews/18852515-when-to-recycle-18650-batteries-and-how-to-start-a-collection-center-in-your-vape-shop // Discharge voltage: 2.5 volt + .1 for personal safety @@ -69,4 +78,4 @@ #ifndef USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION #define USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION 5 -#endif \ No newline at end of file +#endif diff --git a/usermods/Battery/lion.h b/usermods/Battery/lion.h new file mode 100644 index 000000000..e8d78cc72 --- /dev/null +++ b/usermods/Battery/lion.h @@ -0,0 +1,37 @@ +#ifndef UMBLion_h +#define UMBLion_h + +#include "battery_defaults.h" +#include "battery.h" + +/** + * Lion Battery + * + */ +class Lion : public Battery +{ + private: + + public: + Lion() : Battery() + { + + } + + float mapVoltage(float v, float min, float max) override + { + return 0.0f; + }; + + void calculateAndSetLevel(float voltage) override + { + + }; + + virtual void setMaxVoltage(float voltage) override + { + this->maxVoltage = max(getMinVoltage()+1.0f, voltage); + } +}; + +#endif \ No newline at end of file diff --git a/usermods/Battery/lipo.h b/usermods/Battery/lipo.h new file mode 100644 index 000000000..4e9b0be7c --- /dev/null +++ b/usermods/Battery/lipo.h @@ -0,0 +1,51 @@ +#ifndef UMBLipo_h +#define UMBLipo_h + +#include "battery_defaults.h" +#include "battery.h" + +/** + * Lipo Battery + * + */ +class Lipo : public Battery +{ + private: + + public: + Lipo() : Battery() + { + + } + + /** + * LiPo batteries have a differnt dischargin curve, see + * https://blog.ampow.com/lipo-voltage-chart/ + */ + float mapVoltage(float v, float min, float max) override + { + float lvl = 0.0f; + lvl = this->linearMapping(v, min, max); // basic mapping + + if (lvl < 40.0f) + lvl = this->linearMapping(lvl, 0, 40, 0, 12); // last 45% -> drops very quickly + else { + if (lvl < 90.0f) + lvl = this->linearMapping(lvl, 40, 90, 12, 95); // 90% ... 40% -> almost linear drop + else // level > 90% + lvl = this->linearMapping(lvl, 90, 105, 95, 100); // highest 15% -> drop slowly + } + }; + + void calculateAndSetLevel(float voltage) override + { + this->setLevel(this->mapVoltage(voltage, this->getMinVoltage(), this->getMaxVoltage())); + }; + + virtual void setMaxVoltage(float voltage) override + { + this->maxVoltage = max(getMinVoltage()+0.7f, voltage); + } +}; + +#endif \ No newline at end of file diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index ac34a7e4d..4c77ca5dd 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -2,6 +2,9 @@ #include "wled.h" #include "battery_defaults.h" +#include "battery.h" +#include "lion.h" +#include "lipo.h" /* * Usermod by Maximilian Mewes @@ -15,28 +18,12 @@ class UsermodBattery : public Usermod private: // battery pin can be defined in my_config.h int8_t batteryPin = USERMOD_BATTERY_MEASUREMENT_PIN; + // Battery object + Battery* bat; // how often to read the battery voltage unsigned long readingInterval = USERMOD_BATTERY_MEASUREMENT_INTERVAL; unsigned long nextReadTime = 0; unsigned long lastReadTime = 0; - // battery min. voltage - float minBatteryVoltage = USERMOD_BATTERY_MIN_VOLTAGE; - // battery max. voltage - float maxBatteryVoltage = USERMOD_BATTERY_MAX_VOLTAGE; - // all battery cells summed up - unsigned int totalBatteryCapacity = USERMOD_BATTERY_TOTAL_CAPACITY; - // raw analog reading - float rawValue = 0.0f; - // calculated voltage - float voltage = maxBatteryVoltage; - // mapped battery level based on voltage - int8_t batteryLevel = 100; - // offset or calibration value to fine tune the calculated voltage - float calibration = USERMOD_BATTERY_CALIBRATION; - - // time left estimation feature - // bool calculateTimeLeftEnabled = USERMOD_BATTERY_CALCULATE_TIME_LEFT_ENABLED; - // float estimatedTimeLeft = 0.0; // auto shutdown/shutoff/master off feature bool autoOffEnabled = USERMOD_BATTERY_AUTO_OFF_ENABLED; @@ -63,14 +50,6 @@ class UsermodBattery : public Usermod static const char _preset[]; static const char _duration[]; static const char _init[]; - - - // custom map function - // https://forum.arduino.cc/t/floating-point-using-map-function/348113/2 - double mapf(double x, double in_min, double in_max, double out_min, double out_max) - { - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; - } float dot2round(float x) { @@ -94,8 +73,8 @@ class UsermodBattery : public Usermod { if (!lowPowerIndicatorEnabled) return; if (batteryPin < 0) return; // no measurement - if (lowPowerIndicationDone && lowPowerIndicatorReactivationThreshold <= batteryLevel) lowPowerIndicationDone = false; - if (lowPowerIndicatorThreshold <= batteryLevel) return; + if (lowPowerIndicationDone && lowPowerIndicatorReactivationThreshold <= bat->getLevel()) lowPowerIndicationDone = false; + if (lowPowerIndicatorThreshold <= bat->getLevel()) return; if (lowPowerIndicationDone) return; if (lowPowerActivationTime <= 1) { lowPowerActivationTime = millis(); @@ -139,6 +118,16 @@ class UsermodBattery : public Usermod pinMode(batteryPin, INPUT); #endif + // this could also be handled with a factory class but for only 2 types now it should be sufficient + if(USERMOB_BATTERY_DEFAULT_TYPE == 1) { + bat = new Lipo(); + } else + if(USERMOB_BATTERY_DEFAULT_TYPE == 2) { + bat = new Lion(); + } else { + bat = new Lipo(); + } + nextReadTime = millis() + readingInterval; lastReadTime = millis(); @@ -174,8 +163,9 @@ class UsermodBattery : public Usermod if (batteryPin < 0) return; // nothing to read - initializing = false; - + initializing = false; + float voltage = -1.0f; + float rawValue = 0.0f; #ifdef ARDUINO_ARCH_ESP32 // use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV) rawValue = analogReadMilliVolts(batteryPin); @@ -188,40 +178,15 @@ class UsermodBattery : public Usermod rawValue = analogRead(batteryPin); // calculate the voltage - voltage = ((rawValue / getAdcPrecision()) * maxBatteryVoltage) + calibration; + voltage = ((rawValue / getAdcPrecision()) * bat->getMaxVoltage()) + bat->getCalibration(); #endif - // check if voltage is within specified voltage range, allow 10% over/under voltage - voltage = ((voltage < minBatteryVoltage * 0.85f) || (voltage > maxBatteryVoltage * 1.1f)) ? -1.0f : voltage; + bat->setVoltage(voltage); // translate battery voltage into percentage - /* - the standard "map" function doesn't work - https://www.arduino.cc/reference/en/language/functions/math/map/ notes and warnings at the bottom - */ - #ifdef USERMOD_BATTERY_USE_LIPO - batteryLevel = mapf(voltage, minBatteryVoltage, maxBatteryVoltage, 0, 100); // basic mapping - // LiPo batteries have a differnt dischargin curve, see - // https://blog.ampow.com/lipo-voltage-chart/ - if (batteryLevel < 40.0f) - batteryLevel = mapf(batteryLevel, 0, 40, 0, 12); // last 45% -> drops very quickly - else { - if (batteryLevel < 90.0f) - batteryLevel = mapf(batteryLevel, 40, 90, 12, 95); // 90% ... 40% -> almost linear drop - else // level > 90% - batteryLevel = mapf(batteryLevel, 90, 105, 95, 100); // highest 15% -> drop slowly - } - #else - batteryLevel = mapf(voltage, minBatteryVoltage, maxBatteryVoltage, 0, 100); - #endif - if (voltage > -1.0f) batteryLevel = constrain(batteryLevel, 0.0f, 110.0f); - - // if (calculateTimeLeftEnabled) { - // float currentBatteryCapacity = totalBatteryCapacity; - // estimatedTimeLeft = (currentBatteryCapacity/strip.currentMilliamps)*60; - // } + bat->calculateAndSetLevel(voltage); // Auto off -- Master power off - if (autoOffEnabled && (autoOffThreshold >= batteryLevel)) + if (autoOffEnabled && (autoOffThreshold >= bat->getLevel())) turnOff(); // SmartHome stuff @@ -254,16 +219,6 @@ class UsermodBattery : public Usermod // info modal display names JsonArray infoPercentage = user.createNestedArray(F("Battery level")); JsonArray infoVoltage = user.createNestedArray(F("Battery voltage")); - // if (calculateTimeLeftEnabled) - // { - // JsonArray infoEstimatedTimeLeft = user.createNestedArray(F("Estimated time left")); - // if (initializing) { - // infoEstimatedTimeLeft.add(FPSTR(_init)); - // } else { - // infoEstimatedTimeLeft.add(estimatedTimeLeft); - // infoEstimatedTimeLeft.add(F(" min")); - // } - // } JsonArray infoNextUpdate = user.createNestedArray(F("Next update")); infoNextUpdate.add((nextReadTime - millis()) / 1000); @@ -275,17 +230,17 @@ class UsermodBattery : public Usermod return; } - if (batteryLevel < 0) { + if (bat->getLevel() < 0) { infoPercentage.add(F("invalid")); } else { - infoPercentage.add(batteryLevel); + infoPercentage.add(bat->getLevel()); } infoPercentage.add(F(" %")); - if (voltage < 0) { + if (bat->getVoltage() < 0) { infoVoltage.add(F("invalid")); } else { - infoVoltage.add(dot2round(voltage)); + infoVoltage.add(dot2round(bat->getVoltage())); } infoVoltage.add(F(" V")); } @@ -298,7 +253,7 @@ class UsermodBattery : public Usermod /* void addToJsonState(JsonObject& root) { - + // TBD } */ @@ -310,6 +265,7 @@ class UsermodBattery : public Usermod /* void readFromJsonState(JsonObject& root) { + // TBD } */ @@ -356,18 +312,17 @@ class UsermodBattery : public Usermod battery[F("pin")] = batteryPin; #endif - // battery[F("time-left")] = calculateTimeLeftEnabled; - battery[F("min-voltage")] = minBatteryVoltage; - battery[F("max-voltage")] = maxBatteryVoltage; - battery[F("capacity")] = totalBatteryCapacity; - battery[F("calibration")] = calibration; + battery[F("min-voltage")] = bat->getMinVoltage(); + battery[F("max-voltage")] = bat->getMaxVoltage(); + battery[F("capacity")] = bat->getCapacity(); + battery[F("calibration")] = bat->getCalibration(); battery[FPSTR(_readInterval)] = readingInterval; - JsonObject ao = battery.createNestedObject(F("auto-off")); // auto off section + JsonObject ao = battery.createNestedObject(F("auto-off")); // auto off section ao[FPSTR(_enabled)] = autoOffEnabled; ao[FPSTR(_threshold)] = autoOffThreshold; - JsonObject lp = battery.createNestedObject(F("indicator")); // low power section + JsonObject lp = battery.createNestedObject(F("indicator")); // low power section lp[FPSTR(_enabled)] = lowPowerIndicatorEnabled; lp[FPSTR(_preset)] = lowPowerIndicatorPreset; // dropdown trickery (String)lowPowerIndicatorPreset; lp[FPSTR(_threshold)] = lowPowerIndicatorThreshold; @@ -432,11 +387,11 @@ class UsermodBattery : public Usermod #ifdef ARDUINO_ARCH_ESP32 newBatteryPin = battery[F("pin")] | newBatteryPin; #endif - // calculateTimeLeftEnabled = battery[F("time-left")] | calculateTimeLeftEnabled; - setMinBatteryVoltage(battery[F("min-voltage")] | minBatteryVoltage); - setMaxBatteryVoltage(battery[F("max-voltage")] | maxBatteryVoltage); - setTotalBatteryCapacity(battery[F("capacity")] | totalBatteryCapacity); - setCalibration(battery[F("calibration")] | calibration); + + bat->setMinVoltage(battery[F("min-voltage")] | bat->getMinVoltage()); + bat->setMaxVoltage(battery[F("max-voltage")] | bat->getMaxVoltage()); + bat->setCapacity(battery[F("capacity")] | bat->getCapacity()); + bat->setCalibration(battery[F("calibration")] | bat->getCalibration()); setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); JsonObject ao = battery[F("auto-off")]; @@ -479,7 +434,8 @@ class UsermodBattery : public Usermod } /* - * Generate a preset sample for low power indication + * TBD: Generate a preset sample for low power indication + * a button on the config page would be cool, currently not possible */ void generateExamplePreset() { @@ -539,60 +495,6 @@ class UsermodBattery : public Usermod readingInterval = max((unsigned long)3000, newReadingInterval); } - - /* - * Get lowest configured battery voltage - */ - float getMinBatteryVoltage() - { - return minBatteryVoltage; - } - - /* - * Set lowest battery voltage - * can't be below 0 volt - */ - void setMinBatteryVoltage(float voltage) - { - minBatteryVoltage = max(0.0f, voltage); - } - - /* - * Get highest configured battery voltage - */ - float getMaxBatteryVoltage() - { - return maxBatteryVoltage; - } - - /* - * Set highest battery voltage - * can't be below minBatteryVoltage - */ - void setMaxBatteryVoltage(float voltage) - { - #ifdef USERMOD_BATTERY_USE_LIPO - maxBatteryVoltage = max(getMinBatteryVoltage()+0.7f, voltage); - #else - maxBatteryVoltage = max(getMinBatteryVoltage()+1.0f, voltage); - #endif - } - - - /* - * Get the capacity of all cells in parralel sumed up - * unit: mAh - */ - unsigned int getTotalBatteryCapacity() - { - return totalBatteryCapacity; - } - - void setTotalBatteryCapacity(unsigned int capacity) - { - totalBatteryCapacity = capacity; - } - /* * Get the choosen adc precision * esp8266 = 10bit resolution = 1024.0f @@ -609,43 +511,6 @@ class UsermodBattery : public Usermod #endif } - /* - * Get the calculated voltage - * formula: (adc pin value / adc precision * max voltage) + calibration - */ - float getVoltage() - { - return voltage; - } - - /* - * Get the mapped battery level (0 - 100) based on voltage - * important: voltage can drop when a load is applied, so its only an estimate - */ - int8_t getBatteryLevel() - { - return batteryLevel; - } - - /* - * Get the configured calibration value - * a offset value to fine-tune the calculated voltage. - */ - float getCalibration() - { - return calibration; - } - - /* - * Set the voltage calibration offset value - * a offset value to fine-tune the calculated voltage. - */ - void setCalibration(float offset) - { - calibration = offset; - } - - /* * Get auto-off feature enabled status * is auto-off enabled, true/false From 4c8b490c89635a647b9b7e30a519b8a358a1fc47 Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Thu, 5 Jan 2023 20:38:55 +0100 Subject: [PATCH 02/66] minor changes --- usermods/Battery/battery.h | 6 +----- usermods/Battery/battery_defaults.h | 7 +------ usermods/Battery/lion.h | 4 ++-- usermods/Battery/lipo.h | 2 ++ usermods/Battery/usermod_v2_Battery.h | 18 ++++++++++++++---- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/usermods/Battery/battery.h b/usermods/Battery/battery.h index f3daf05c4..c678f775d 100644 --- a/usermods/Battery/battery.h +++ b/usermods/Battery/battery.h @@ -81,11 +81,7 @@ class Battery */ virtual void setMaxVoltage(float voltage) { - #ifdef USERMOD_BATTERY_USE_LIPO - this->maxVoltage = max(getMinVoltage()+0.7f, voltage); - #else - this->maxVoltage = max(getMinVoltage()+1.0f, voltage); - #endif + this->maxVoltage = max(getMinVoltage()+.5f, voltage); } /* diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h index 73f14f62a..4a04ac352 100644 --- a/usermods/Battery/battery_defaults.h +++ b/usermods/Battery/battery_defaults.h @@ -27,7 +27,7 @@ // https://batterybro.com/blogs/18650-wholesale-battery-reviews/18852515-when-to-recycle-18650-batteries-and-how-to-start-a-collection-center-in-your-vape-shop // Discharge voltage: 2.5 volt + .1 for personal safety #ifndef USERMOD_BATTERY_MIN_VOLTAGE - #ifdef USERMOD_BATTERY_USE_LIPO + #if USERMOB_BATTERY_DEFAULT_TYPE == 1 // LiPo "1S" Batteries should not be dischared below 3V !! #define USERMOD_BATTERY_MIN_VOLTAGE 3.2f #else @@ -49,11 +49,6 @@ #define USERMOD_BATTERY_CALIBRATION 0 #endif -// calculate remaining time / the time that is left before the battery runs out of power -// #ifndef USERMOD_BATTERY_CALCULATE_TIME_LEFT_ENABLED -// #define USERMOD_BATTERY_CALCULATE_TIME_LEFT_ENABLED false -// #endif - // auto-off feature #ifndef USERMOD_BATTERY_AUTO_OFF_ENABLED #define USERMOD_BATTERY_AUTO_OFF_ENABLED true diff --git a/usermods/Battery/lion.h b/usermods/Battery/lion.h index e8d78cc72..69095ac09 100644 --- a/usermods/Battery/lion.h +++ b/usermods/Battery/lion.h @@ -20,12 +20,12 @@ class Lion : public Battery float mapVoltage(float v, float min, float max) override { - return 0.0f; + return this->linearMapping(v, min, max); // basic mapping }; void calculateAndSetLevel(float voltage) override { - + this->setLevel(this->mapVoltage(voltage, this->getMinVoltage(), this->getMaxVoltage())); }; virtual void setMaxVoltage(float voltage) override diff --git a/usermods/Battery/lipo.h b/usermods/Battery/lipo.h index 4e9b0be7c..92ede8f81 100644 --- a/usermods/Battery/lipo.h +++ b/usermods/Battery/lipo.h @@ -35,6 +35,8 @@ class Lipo : public Battery else // level > 90% lvl = this->linearMapping(lvl, 90, 105, 95, 100); // highest 15% -> drop slowly } + + return lvl; }; void calculateAndSetLevel(float voltage) override diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index 4c77ca5dd..87b73ec6d 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -18,8 +18,11 @@ class UsermodBattery : public Usermod private: // battery pin can be defined in my_config.h int8_t batteryPin = USERMOD_BATTERY_MEASUREMENT_PIN; + + int8_t batteryType = USERMOB_BATTERY_DEFAULT_TYPE; // Battery object Battery* bat; + // how often to read the battery voltage unsigned long readingInterval = USERMOD_BATTERY_MEASUREMENT_INTERVAL; unsigned long nextReadTime = 0; @@ -118,14 +121,14 @@ class UsermodBattery : public Usermod pinMode(batteryPin, INPUT); #endif - // this could also be handled with a factory class but for only 2 types now it should be sufficient - if(USERMOB_BATTERY_DEFAULT_TYPE == 1) { + // this could also be handled with a factory class but for only 2 types it should be sufficient for now + if(batteryType == 1) { bat = new Lipo(); } else - if(USERMOB_BATTERY_DEFAULT_TYPE == 2) { + if(batteryType == 2) { bat = new Lion(); } else { - bat = new Lipo(); + bat = new Lipo(); // in the future one could create a nullObject } nextReadTime = millis() + readingInterval; @@ -317,6 +320,10 @@ class UsermodBattery : public Usermod battery[F("capacity")] = bat->getCapacity(); battery[F("calibration")] = bat->getCalibration(); battery[FPSTR(_readInterval)] = readingInterval; + + // JsonArray type = battery[F("Type")]; + // type[0] = 1; + // type[1] = 2; JsonObject ao = battery.createNestedObject(F("auto-off")); // auto off section ao[FPSTR(_enabled)] = autoOffEnabled; @@ -393,6 +400,9 @@ class UsermodBattery : public Usermod bat->setCapacity(battery[F("capacity")] | bat->getCapacity()); bat->setCalibration(battery[F("calibration")] | bat->getCalibration()); setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); + + // JsonArray type = battery[F("Type")]; + // batteryType = type["bt"] | batteryType; JsonObject ao = battery[F("auto-off")]; setAutoOffEnabled(ao[FPSTR(_enabled)] | autoOffEnabled); From 85d59945a0ffaaa8907ce69cc1cb3f7548de2775 Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Fri, 6 Jan 2023 00:19:16 +0100 Subject: [PATCH 03/66] =?UTF-8?q?runtime=20exception=20fix=20=F0=9F=90=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- usermods/Battery/usermod_v2_Battery.h | 38 ++++++++++++++++----------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index 87b73ec6d..f9bfc96fb 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -20,9 +20,15 @@ class UsermodBattery : public Usermod int8_t batteryPin = USERMOD_BATTERY_MEASUREMENT_PIN; int8_t batteryType = USERMOB_BATTERY_DEFAULT_TYPE; - // Battery object - Battery* bat; - + + float minVoltage = USERMOD_BATTERY_MIN_VOLTAGE; + float maxVoltage = USERMOD_BATTERY_MAX_VOLTAGE; + unsigned int capacity = USERMOD_BATTERY_TOTAL_CAPACITY; // current capacity + float voltage = this->maxVoltage; // current voltage + int8_t level = 100; // current level + float calibration = USERMOD_BATTERY_CALIBRATION; // offset or calibration value to fine tune the calculated voltage + Battery* bat = nullptr; + // how often to read the battery voltage unsigned long readingInterval = USERMOD_BATTERY_MEASUREMENT_INTERVAL; unsigned long nextReadTime = 0; @@ -121,7 +127,7 @@ class UsermodBattery : public Usermod pinMode(batteryPin, INPUT); #endif - // this could also be handled with a factory class but for only 2 types it should be sufficient for now + //this could also be handled with a factory class but for only 2 types it should be sufficient for now if(batteryType == 1) { bat = new Lipo(); } else @@ -315,15 +321,13 @@ class UsermodBattery : public Usermod battery[F("pin")] = batteryPin; #endif - battery[F("min-voltage")] = bat->getMinVoltage(); - battery[F("max-voltage")] = bat->getMaxVoltage(); - battery[F("capacity")] = bat->getCapacity(); - battery[F("calibration")] = bat->getCalibration(); + if(bat) { + battery[F("min-voltage")] = bat->getMinVoltage(); + battery[F("max-voltage")] = bat->getMaxVoltage(); + battery[F("capacity")] = bat->getCapacity(); + battery[F("calibration")] = bat->getCalibration(); + } battery[FPSTR(_readInterval)] = readingInterval; - - // JsonArray type = battery[F("Type")]; - // type[0] = 1; - // type[1] = 2; JsonObject ao = battery.createNestedObject(F("auto-off")); // auto off section ao[FPSTR(_enabled)] = autoOffEnabled; @@ -395,10 +399,12 @@ class UsermodBattery : public Usermod newBatteryPin = battery[F("pin")] | newBatteryPin; #endif - bat->setMinVoltage(battery[F("min-voltage")] | bat->getMinVoltage()); - bat->setMaxVoltage(battery[F("max-voltage")] | bat->getMaxVoltage()); - bat->setCapacity(battery[F("capacity")] | bat->getCapacity()); - bat->setCalibration(battery[F("calibration")] | bat->getCalibration()); + if(bat) { + bat->setMinVoltage(battery[F("min-voltage")] | bat->getMinVoltage()); + bat->setMaxVoltage(battery[F("max-voltage")] | bat->getMaxVoltage()); + bat->setCapacity(battery[F("capacity")] | bat->getCapacity()); + bat->setCalibration(battery[F("calibration")] | bat->getCalibration()); + } setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); // JsonArray type = battery[F("Type")]; From 375907144966e37e9a8dad3efc92343fec892052 Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Fri, 6 Jan 2023 17:00:29 +0100 Subject: [PATCH 04/66] =?UTF-8?q?Fix=20previous=20bug=20again=20?= =?UTF-8?q?=F0=9F=90=9B,=20Add=20Type=20Dropdown=20to=20config=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- usermods/Battery/battery.h | 21 +++-- usermods/Battery/battery_defaults.h | 111 +++++++++++++++++++------- usermods/Battery/lion.h | 8 +- usermods/Battery/lipo.h | 10 ++- usermods/Battery/unkown.h | 36 +++++++++ usermods/Battery/usermod_v2_Battery.h | 62 +++++++------- 6 files changed, 178 insertions(+), 70 deletions(-) create mode 100644 usermods/Battery/unkown.h diff --git a/usermods/Battery/battery.h b/usermods/Battery/battery.h index c678f775d..ad3fb2703 100644 --- a/usermods/Battery/battery.h +++ b/usermods/Battery/battery.h @@ -12,12 +12,12 @@ class Battery private: protected: - float minVoltage = USERMOD_BATTERY_MIN_VOLTAGE; - float maxVoltage = USERMOD_BATTERY_MAX_VOLTAGE; - unsigned int capacity = USERMOD_BATTERY_TOTAL_CAPACITY; // current capacity - float voltage = this->maxVoltage; // current voltage - int8_t level = 100; // current level - float calibration = USERMOD_BATTERY_CALIBRATION; // offset or calibration value to fine tune the calculated voltage + float minVoltage; + float maxVoltage; + unsigned int capacity; + float voltage; + int8_t level = 100; + float calibration; // offset or calibration value to fine tune the calculated voltage float linearMapping(float v, float min, float max, float oMin = 0.0f, float oMax = 100.0f) { @@ -30,6 +30,15 @@ class Battery } + virtual void update(batteryConfig cfg) + { + if(cfg.minVoltage) this->setMinVoltage(cfg.minVoltage); + if(cfg.maxVoltage) this->setMaxVoltage(cfg.maxVoltage); + if(cfg.calibration) this->setCapacity(cfg.calibration); + if(cfg.level) this->setLevel(cfg.level); + if(cfg.calibration) this->setCalibration(cfg.calibration); + } + /** * Corresponding battery curves * calculates the capacity in % (0-100) with given voltage and possible voltage range diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h index 4a04ac352..f4060ca60 100644 --- a/usermods/Battery/battery_defaults.h +++ b/usermods/Battery/battery_defaults.h @@ -1,3 +1,6 @@ +#ifndef UMBDefaults_h +#define UMBDefaults_h + // pin defaults // for the esp32 it is best to use the ADC1: GPIO32 - GPIO39 // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html @@ -16,38 +19,70 @@ /* Default Battery Type + * 0 = unkown * 1 = Lipo * 2 = Lion */ -#ifndef USERMOB_BATTERY_DEFAULT_TYPE - #define USERMOB_BATTERY_DEFAULT_TYPE 1 +#ifndef USERMOD_BATTERY_DEFAULT_TYPE + #define USERMOD_BATTERY_DEFAULT_TYPE 0 +#endif +/* + * + * Unkown 'Battery' defaults + * + */ +#ifndef USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE + #define USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE 3.3f +#endif +#ifndef USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE + #define USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE 4.2f +#endif +#ifndef USERMOD_BATTERY_UNKOWN_CAPACITY + #define USERMOD_BATTERY_UNKOWN_CAPACITY 2500 +#endif +#ifndef USERMOD_BATTERY_UNKOWN_CALIBRATION + // offset or calibration value to fine tune the calculated voltage + #define USERMOD_BATTERY_UNKOWN_CALIBRATION 0 +#endif +/* + * + * Lithium polymer (Li-Po) defaults + * + */ +#ifndef USERMOD_BATTERY_LIPO_MIN_VOLTAGE + // LiPo "1S" Batteries should not be dischared below 3V !! + #define USERMOD_BATTERY_LIPO_MIN_VOLTAGE 3.2f +#endif +#ifndef USERMOD_BATTERY_LIPO_MAX_VOLTAGE + #define USERMOD_BATTERY_LIPO_MAX_VOLTAGE 4.2f +#endif +#ifndef USERMOD_BATTERY_LIPO_CAPACITY + #define USERMOD_BATTERY_LIPO_CAPACITY 5000 +#endif +#ifndef USERMOD_BATTERY_LIPO_CALIBRATION + #define USERMOD_BATTERY_LIPO_CALIBRATION 0 +#endif +/* + * + * Lithium-ion (Li-Ion) defaults + * + */ +#ifndef USERMOD_BATTERY_LION_MIN_VOLTAGE + // default for 18650 battery + #define USERMOD_BATTERY_LION_MIN_VOLTAGE 2.6f +#endif +#ifndef USERMOD_BATTERY_LION_MAX_VOLTAGE + #define USERMOD_BATTERY_LION_MAX_VOLTAGE 4.2f +#endif +#ifndef USERMOD_BATTERY_LION_CAPACITY + // a common capacity for single 18650 battery cells is between 2500 and 3600 mAh + #define USERMOD_BATTERY_LION_CAPACITY 3100 +#endif +#ifndef USERMOD_BATTERY_LION_CALIBRATION + // offset or calibration value to fine tune the calculated voltage + #define USERMOD_BATTERY_LION_CALIBRATION 0 #endif -// default for 18650 battery -// https://batterybro.com/blogs/18650-wholesale-battery-reviews/18852515-when-to-recycle-18650-batteries-and-how-to-start-a-collection-center-in-your-vape-shop -// Discharge voltage: 2.5 volt + .1 for personal safety -#ifndef USERMOD_BATTERY_MIN_VOLTAGE - #if USERMOB_BATTERY_DEFAULT_TYPE == 1 - // LiPo "1S" Batteries should not be dischared below 3V !! - #define USERMOD_BATTERY_MIN_VOLTAGE 3.2f - #else - #define USERMOD_BATTERY_MIN_VOLTAGE 2.6f - #endif -#endif - -#ifndef USERMOD_BATTERY_MAX_VOLTAGE - #define USERMOD_BATTERY_MAX_VOLTAGE 4.2f -#endif - -// a common capacity for single 18650 battery cells is between 2500 and 3600 mAh -#ifndef USERMOD_BATTERY_TOTAL_CAPACITY - #define USERMOD_BATTERY_TOTAL_CAPACITY 3100 -#endif - -// offset or calibration value to fine tune the calculated voltage -#ifndef USERMOD_BATTERY_CALIBRATION - #define USERMOD_BATTERY_CALIBRATION 0 -#endif // auto-off feature #ifndef USERMOD_BATTERY_AUTO_OFF_ENABLED @@ -74,3 +109,25 @@ #ifndef USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION #define USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION 5 #endif + +typedef enum +{ + unknown=0, + lipo=1, + lion=2 +} batteryType; + +// used for initial configuration after boot +typedef struct bconfig_t +{ + batteryType type; + float minVoltage; + float maxVoltage; + unsigned int capacity; // current capacity + float voltage; // current voltage + int8_t level; // current level + float calibration; // offset or calibration value to fine tune the calculated voltage +} batteryConfig; + + +#endif \ No newline at end of file diff --git a/usermods/Battery/lion.h b/usermods/Battery/lion.h index 69095ac09..4016af7e3 100644 --- a/usermods/Battery/lion.h +++ b/usermods/Battery/lion.h @@ -13,9 +13,13 @@ class Lion : public Battery private: public: - Lion() : Battery() + Lion() { - + this->setMinVoltage(USERMOD_BATTERY_LION_MIN_VOLTAGE); + this->setMaxVoltage(USERMOD_BATTERY_LION_MAX_VOLTAGE); + this->setCapacity(USERMOD_BATTERY_LION_CAPACITY); + this->setVoltage(this->getVoltage()); + this->setCalibration(USERMOD_BATTERY_LION_CALIBRATION); } float mapVoltage(float v, float min, float max) override diff --git a/usermods/Battery/lipo.h b/usermods/Battery/lipo.h index 92ede8f81..03eed7b86 100644 --- a/usermods/Battery/lipo.h +++ b/usermods/Battery/lipo.h @@ -5,7 +5,7 @@ #include "battery.h" /** - * Lipo Battery + * Lipo Battery * */ class Lipo : public Battery @@ -13,9 +13,13 @@ class Lipo : public Battery private: public: - Lipo() : Battery() + Lipo() { - + this->setMinVoltage(USERMOD_BATTERY_LIPO_MIN_VOLTAGE); + this->setMaxVoltage(USERMOD_BATTERY_LIPO_MAX_VOLTAGE); + this->setCapacity(USERMOD_BATTERY_LIPO_CAPACITY); + this->setVoltage(this->getVoltage()); + this->setCalibration(USERMOD_BATTERY_LIPO_CALIBRATION); } /** diff --git a/usermods/Battery/unkown.h b/usermods/Battery/unkown.h new file mode 100644 index 000000000..63b2674f3 --- /dev/null +++ b/usermods/Battery/unkown.h @@ -0,0 +1,36 @@ +#ifndef UMBUnkown_h +#define UMBUnkown_h + +#include "battery_defaults.h" +#include "battery.h" + +/** + * Lion Battery + * + */ +class Unkown : public Battery +{ + private: + + public: + Unkown() + { + this->setMinVoltage(USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE); + this->setMaxVoltage(USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE); + this->setCapacity(USERMOD_BATTERY_UNKOWN_CAPACITY); + this->setVoltage(this->getVoltage()); + this->setCalibration(USERMOD_BATTERY_UNKOWN_CALIBRATION); + } + + float mapVoltage(float v, float min, float max) override + { + return this->linearMapping(v, min, max); // basic mapping + }; + + void calculateAndSetLevel(float voltage) override + { + this->setLevel(this->mapVoltage(voltage, this->getMinVoltage(), this->getMaxVoltage())); + }; +}; + +#endif \ No newline at end of file diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index f9bfc96fb..ab2ab908d 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -3,6 +3,7 @@ #include "wled.h" #include "battery_defaults.h" #include "battery.h" +#include "unkown.h" #include "lion.h" #include "lipo.h" @@ -18,16 +19,9 @@ class UsermodBattery : public Usermod private: // battery pin can be defined in my_config.h int8_t batteryPin = USERMOD_BATTERY_MEASUREMENT_PIN; - - int8_t batteryType = USERMOB_BATTERY_DEFAULT_TYPE; - - float minVoltage = USERMOD_BATTERY_MIN_VOLTAGE; - float maxVoltage = USERMOD_BATTERY_MAX_VOLTAGE; - unsigned int capacity = USERMOD_BATTERY_TOTAL_CAPACITY; // current capacity - float voltage = this->maxVoltage; // current voltage - int8_t level = 100; // current level - float calibration = USERMOD_BATTERY_CALIBRATION; // offset or calibration value to fine tune the calculated voltage + Battery* bat = nullptr; + batteryConfig bcfg; // how often to read the battery voltage unsigned long readingInterval = USERMOD_BATTERY_MEASUREMENT_INTERVAL; @@ -127,16 +121,17 @@ class UsermodBattery : public Usermod pinMode(batteryPin, INPUT); #endif - //this could also be handled with a factory class but for only 2 types it should be sufficient for now - if(batteryType == 1) { - bat = new Lipo(); - } else - if(batteryType == 2) { - bat = new Lion(); - } else { - bat = new Lipo(); // in the future one could create a nullObject - } + //this could also be handled with a factory class but for only 2 types it should be sufficient for now + if(bcfg.type == (batteryType)lipo) { + bat = new Lipo(); + } else + if(bcfg.type == (batteryType)lion) { + bat = new Lion(); + } else { + bat = new Unkown(); // nullObject + } + bat->update(bcfg); nextReadTime = millis() + readingInterval; lastReadTime = millis(); @@ -321,12 +316,11 @@ class UsermodBattery : public Usermod battery[F("pin")] = batteryPin; #endif - if(bat) { - battery[F("min-voltage")] = bat->getMinVoltage(); - battery[F("max-voltage")] = bat->getMaxVoltage(); - battery[F("capacity")] = bat->getCapacity(); - battery[F("calibration")] = bat->getCalibration(); - } + battery[F("type")] = (String)bcfg.type; + battery[F("min-voltage")] = bat->getMinVoltage(); + battery[F("max-voltage")] = bat->getMaxVoltage(); + battery[F("capacity")] = bat->getCapacity(); + battery[F("calibration")] = bat->getCalibration(); battery[FPSTR(_readInterval)] = readingInterval; JsonObject ao = battery.createNestedObject(F("auto-off")); // auto off section @@ -344,6 +338,11 @@ class UsermodBattery : public Usermod void appendConfigData() { + oappend(SET_F("td=addDropdown('Battery', 'type');")); + oappend(SET_F("addOption(td, 'Unkown', '0');")); + oappend(SET_F("addOption(td, 'LiPo', '1');")); + oappend(SET_F("addOption(td, 'LiOn', '2');")); + oappend(SET_F("addInfo('Battery:type',1,'requires reboot');")); oappend(SET_F("addInfo('Battery:min-voltage', 1, 'v');")); oappend(SET_F("addInfo('Battery:max-voltage', 1, 'v');")); oappend(SET_F("addInfo('Battery:capacity', 1, 'mAh');")); @@ -399,16 +398,15 @@ class UsermodBattery : public Usermod newBatteryPin = battery[F("pin")] | newBatteryPin; #endif - if(bat) { - bat->setMinVoltage(battery[F("min-voltage")] | bat->getMinVoltage()); - bat->setMaxVoltage(battery[F("max-voltage")] | bat->getMaxVoltage()); - bat->setCapacity(battery[F("capacity")] | bat->getCapacity()); - bat->setCalibration(battery[F("calibration")] | bat->getCalibration()); - } + getJsonValue(battery[F("type")], bcfg.type); + getJsonValue(battery[F("min-voltage")], bcfg.minVoltage); + getJsonValue(battery[F("max-voltage")], bcfg.maxVoltage); + getJsonValue(battery[F("capacity")], bcfg.capacity); + getJsonValue(battery[F("calibration")], bcfg.calibration); setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); // JsonArray type = battery[F("Type")]; - // batteryType = type["bt"] | batteryType; + // batteryType = type["bt"] | btype; JsonObject ao = battery[F("auto-off")]; setAutoOffEnabled(ao[FPSTR(_enabled)] | autoOffEnabled); @@ -446,7 +444,7 @@ class UsermodBattery : public Usermod } #endif - return !battery[FPSTR(_readInterval)].isNull(); + return !battery[F("min-voltage")].isNull(); } /* From 8ba5dfe447ac73111ff2a244be44a6ec08389417 Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Fri, 6 Jan 2023 19:07:39 +0100 Subject: [PATCH 05/66] =?UTF-8?q?Another=20Bugfx=20=F0=9F=A7=91=E2=80=8D?= =?UTF-8?q?=F0=9F=94=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- usermods/Battery/battery.h | 9 +-------- usermods/Battery/lion.h | 9 +++++++++ usermods/Battery/lipo.h | 9 +++++++++ usermods/Battery/usermod_v2_Battery.h | 11 ++++++----- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/usermods/Battery/battery.h b/usermods/Battery/battery.h index ad3fb2703..3a792aadb 100644 --- a/usermods/Battery/battery.h +++ b/usermods/Battery/battery.h @@ -30,14 +30,7 @@ class Battery } - virtual void update(batteryConfig cfg) - { - if(cfg.minVoltage) this->setMinVoltage(cfg.minVoltage); - if(cfg.maxVoltage) this->setMaxVoltage(cfg.maxVoltage); - if(cfg.calibration) this->setCapacity(cfg.calibration); - if(cfg.level) this->setLevel(cfg.level); - if(cfg.calibration) this->setCalibration(cfg.calibration); - } + virtual void update(batteryConfig cfg) = 0; /** * Corresponding battery curves diff --git a/usermods/Battery/lion.h b/usermods/Battery/lion.h index 4016af7e3..17a4b3593 100644 --- a/usermods/Battery/lion.h +++ b/usermods/Battery/lion.h @@ -22,6 +22,15 @@ class Lion : public Battery this->setCalibration(USERMOD_BATTERY_LION_CALIBRATION); } + void update(batteryConfig cfg) + { + if(cfg.minVoltage) this->setMinVoltage(cfg.minVoltage); + if(cfg.maxVoltage) this->setMaxVoltage(cfg.maxVoltage); + if(cfg.calibration) this->setCapacity(cfg.calibration); + if(cfg.level) this->setLevel(cfg.level); + if(cfg.calibration) this->setCalibration(cfg.calibration); + } + float mapVoltage(float v, float min, float max) override { return this->linearMapping(v, min, max); // basic mapping diff --git a/usermods/Battery/lipo.h b/usermods/Battery/lipo.h index 03eed7b86..dcd44567f 100644 --- a/usermods/Battery/lipo.h +++ b/usermods/Battery/lipo.h @@ -22,6 +22,15 @@ class Lipo : public Battery this->setCalibration(USERMOD_BATTERY_LIPO_CALIBRATION); } + void update(batteryConfig cfg) + { + if(cfg.minVoltage) this->setMinVoltage(cfg.minVoltage); + if(cfg.maxVoltage) this->setMaxVoltage(cfg.maxVoltage); + if(cfg.calibration) this->setCapacity(cfg.calibration); + if(cfg.level) this->setLevel(cfg.level); + if(cfg.calibration) this->setCalibration(cfg.calibration); + } + /** * LiPo batteries have a differnt dischargin curve, see * https://blog.ampow.com/lipo-voltage-chart/ diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index ab2ab908d..5cf6ac792 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -132,6 +132,7 @@ class UsermodBattery : public Usermod } bat->update(bcfg); + nextReadTime = millis() + readingInterval; lastReadTime = millis(); @@ -316,7 +317,7 @@ class UsermodBattery : public Usermod battery[F("pin")] = batteryPin; #endif - battery[F("type")] = (String)bcfg.type; + battery[F("type")] = (String)bcfg.type; // has to be a String otherwise it won't get converted to a Dropdown battery[F("min-voltage")] = bat->getMinVoltage(); battery[F("max-voltage")] = bat->getMaxVoltage(); battery[F("capacity")] = bat->getCapacity(); @@ -404,9 +405,6 @@ class UsermodBattery : public Usermod getJsonValue(battery[F("capacity")], bcfg.capacity); getJsonValue(battery[F("calibration")], bcfg.calibration); setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); - - // JsonArray type = battery[F("Type")]; - // batteryType = type["bt"] | btype; JsonObject ao = battery[F("auto-off")]; setAutoOffEnabled(ao[FPSTR(_enabled)] | autoOffEnabled); @@ -444,7 +442,10 @@ class UsermodBattery : public Usermod } #endif - return !battery[F("min-voltage")].isNull(); + if(initDone) + bat->update(bcfg); + + return !battery[FPSTR(_readInterval)].isNull(); } /* From d16f9efeecd9f182a150354479f885eb9e2d9bee Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Fri, 6 Jan 2023 19:09:12 +0100 Subject: [PATCH 06/66] =?UTF-8?q?Added=20forgotten=20file=20=F0=9F=98=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- usermods/Battery/unkown.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/usermods/Battery/unkown.h b/usermods/Battery/unkown.h index 63b2674f3..f36c3195e 100644 --- a/usermods/Battery/unkown.h +++ b/usermods/Battery/unkown.h @@ -22,6 +22,14 @@ class Unkown : public Battery this->setCalibration(USERMOD_BATTERY_UNKOWN_CALIBRATION); } + void update(batteryConfig cfg) + { + if(cfg.minVoltage) this->setMinVoltage(cfg.minVoltage); else this->setMinVoltage(USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE); + if(cfg.maxVoltage) this->setMaxVoltage(cfg.maxVoltage); else this->setMaxVoltage(USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE); + if(cfg.calibration) this->setCapacity(cfg.calibration); else this->setCapacity(USERMOD_BATTERY_UNKOWN_CAPACITY); + if(cfg.calibration) this->setCalibration(cfg.calibration); else this->setCalibration(USERMOD_BATTERY_UNKOWN_CALIBRATION); + } + float mapVoltage(float v, float min, float max) override { return this->linearMapping(v, min, max); // basic mapping From bb82bf762fd4becdf6dc1ed92b4e97eb03e18aed Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Thu, 12 Jan 2023 21:50:46 +0100 Subject: [PATCH 07/66] Update Readme, my_config type config options with examples --- usermods/Battery/battery_defaults.h | 2 ++ usermods/Battery/readme.md | 16 +++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h index f4060ca60..fbdaf4877 100644 --- a/usermods/Battery/battery_defaults.h +++ b/usermods/Battery/battery_defaults.h @@ -1,6 +1,8 @@ #ifndef UMBDefaults_h #define UMBDefaults_h +#include "wled.h" + // pin defaults // for the esp32 it is best to use the ADC1: GPIO32 - GPIO39 // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html diff --git a/usermods/Battery/readme.md b/usermods/Battery/readme.md index d55573abe..1ca229763 100644 --- a/usermods/Battery/readme.md +++ b/usermods/Battery/readme.md @@ -36,13 +36,12 @@ define `USERMOD_BATTERY` in `wled00/my_config.h` | Name | Unit | Description | | ----------------------------------------------- | ----------- |-------------------------------------------------------------------------------------- | | `USERMOD_BATTERY` | | define this (in `my_config.h`) to have this usermod included wled00\usermods_list.cpp | -| `USERMOD_BATTERY_USE_LIPO` | | define this (in `my_config.h`) if you use LiPo rechargeables (1S) | | `USERMOD_BATTERY_MEASUREMENT_PIN` | | defaults to A0 on ESP8266 and GPIO35 on ESP32 | | `USERMOD_BATTERY_MEASUREMENT_INTERVAL` | ms | battery check interval. defaults to 30 seconds | -| `USERMOD_BATTERY_MIN_VOLTAGE` | v | minimum battery voltage. default is 2.6 (18650 battery standard) | -| `USERMOD_BATTERY_MAX_VOLTAGE` | v | maximum battery voltage. default is 4.2 (18650 battery standard) | -| `USERMOD_BATTERY_TOTAL_CAPACITY` | mAh | the capacity of all cells in parralel sumed up | -| `USERMOD_BATTERY_CALIBRATION` | | offset / calibration number, fine tune the measured voltage by the microcontroller | +| `USERMOD_BATTERY_{TYPE}_MIN_VOLTAGE` | v | minimum battery voltage. default is 2.6 (18650 battery standard) | +| `USERMOD_BATTERY_{TYPE}_MAX_VOLTAGE` | v | maximum battery voltage. default is 4.2 (18650 battery standard) | +| `USERMOD_BATTERY_{TYPE}_TOTAL_CAPACITY` | mAh | the capacity of all cells in parralel sumed up | +| `USERMOD_BATTERY_{TYPE}_CALIBRATION` | | offset / calibration number, fine tune the measured voltage by the microcontroller | | Auto-Off | --- | --- | | `USERMOD_BATTERY_AUTO_OFF_ENABLED` | true/false | enables auto-off | | `USERMOD_BATTERY_AUTO_OFF_THRESHOLD` | % (0-100) | when this threshold is reached master power turns off | @@ -54,6 +53,13 @@ define `USERMOD_BATTERY` in `wled00/my_config.h` All parameters can be configured at runtime via the Usermods settings page. +**NOTICE:** Each Battery type can be pre-configured individualy (in `my_config.h`) + +| Name | Alias | `my_config.h` example | +| --------------- | ------------- | ------------------------------------- | +| Lithium Polymer | lipo (Li-Po) | `USERMOD_BATTERY_lipo_MIN_VOLTAGE` | +| Lithium Ionen | lion (Li-Ion) | `USERMOD_BATTERY_lion_TOTAL_CAPACITY` | + ## ⚠️ Important - Make sure you know your battery specifications! All batteries are **NOT** the same! From f97b79bc16a5027d35219e015162c7b58e154ef9 Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Sat, 21 Jan 2023 00:39:51 +0100 Subject: [PATCH 08/66] Exposing the Battery state to JSON API - Part 1 --- usermods/Battery/battery_defaults.h | 9 +-- usermods/Battery/usermod_v2_Battery.h | 99 +++++++++++++++------------ 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h index fbdaf4877..092e3dd36 100644 --- a/usermods/Battery/battery_defaults.h +++ b/usermods/Battery/battery_defaults.h @@ -34,6 +34,7 @@ * */ #ifndef USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE + // Extra save defaults #define USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE 3.3f #endif #ifndef USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE @@ -125,10 +126,10 @@ typedef struct bconfig_t batteryType type; float minVoltage; float maxVoltage; - unsigned int capacity; // current capacity - float voltage; // current voltage - int8_t level; // current level - float calibration; // offset or calibration value to fine tune the calculated voltage + unsigned int capacity; // current capacity + float voltage; // current voltage + int8_t level; // current level + float calibration; // offset or calibration value to fine tune the calculated voltage } batteryConfig; diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index bf123a79d..390bd96b4 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -30,17 +30,17 @@ class UsermodBattery : public Usermod // auto shutdown/shutoff/master off feature bool autoOffEnabled = USERMOD_BATTERY_AUTO_OFF_ENABLED; - int8_t autoOffThreshold = USERMOD_BATTERY_AUTO_OFF_THRESHOLD; + uint8_t autoOffThreshold = USERMOD_BATTERY_AUTO_OFF_THRESHOLD; // low power indicator feature bool lowPowerIndicatorEnabled = USERMOD_BATTERY_LOW_POWER_INDICATOR_ENABLED; - int8_t lowPowerIndicatorPreset = USERMOD_BATTERY_LOW_POWER_INDICATOR_PRESET; - int8_t lowPowerIndicatorThreshold = USERMOD_BATTERY_LOW_POWER_INDICATOR_THRESHOLD; - int8_t lowPowerIndicatorReactivationThreshold = lowPowerIndicatorThreshold+10; - int8_t lowPowerIndicatorDuration = USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION; + uint8_t lowPowerIndicatorPreset = USERMOD_BATTERY_LOW_POWER_INDICATOR_PRESET; + uint8_t lowPowerIndicatorThreshold = USERMOD_BATTERY_LOW_POWER_INDICATOR_THRESHOLD; + uint8_t lowPowerIndicatorReactivationThreshold = lowPowerIndicatorThreshold+10; + uint8_t lowPowerIndicatorDuration = USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION; bool lowPowerIndicationDone = false; unsigned long lowPowerActivationTime = 0; // used temporary during active time - int8_t lastPreset = 0; + uint8_t lastPreset = 0; bool initDone = false; bool initializing = true; @@ -128,7 +128,7 @@ class UsermodBattery : public Usermod if(bcfg.type == (batteryType)lion) { bat = new Lion(); } else { - bat = new Unkown(); // nullObject + bat = new Unkown(); // nullObject pattern } bat->update(bcfg); @@ -181,7 +181,6 @@ class UsermodBattery : public Usermod #else // read battery raw input rawValue = analogRead(batteryPin); - // calculate the voltage voltage = ((rawValue / getAdcPrecision()) * bat->getMaxVoltage()) + bat->getCalibration(); #endif @@ -252,17 +251,42 @@ class UsermodBattery : public Usermod infoVoltage.add(F(" V")); } + void addBatteryToJsonObject(JsonObject& battery, bool forJsonState) + { + if(forJsonState) { battery[F("type")] = bcfg.type; } else {battery[F("type")] = (String)bcfg.type; } // has to be a String otherwise it won't get converted to a Dropdown + battery[F("min-voltage")] = bat->getMinVoltage(); + battery[F("max-voltage")] = bat->getMaxVoltage(); + battery[F("capacity")] = bat->getCapacity(); + battery[F("calibration")] = bat->getCalibration(); + battery[FPSTR(_readInterval)] = readingInterval; + + JsonObject ao = battery.createNestedObject(F("auto-off")); // auto off section + ao[FPSTR(_enabled)] = autoOffEnabled; + ao[FPSTR(_threshold)] = autoOffThreshold; + + JsonObject lp = battery.createNestedObject(F("indicator")); // low power section + lp[FPSTR(_enabled)] = lowPowerIndicatorEnabled; + lp[FPSTR(_preset)] = lowPowerIndicatorPreset; // dropdown trickery (String)lowPowerIndicatorPreset; + lp[FPSTR(_threshold)] = lowPowerIndicatorThreshold; + lp[FPSTR(_duration)] = lowPowerIndicatorDuration; + } /* * 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 addToJsonState(JsonObject& root) { - // TBD + JsonObject battery = root.createNestedObject(FPSTR(_name)); + + if (battery.isNull()) { + battery = root.createNestedObject(FPSTR(_name)); + } + + addBatteryToJsonObject(battery, true); + + DEBUG_PRINTLN(F("Battery state exposed in JSON API.")); } - */ /* @@ -314,48 +338,39 @@ class UsermodBattery : public Usermod */ void addToConfig(JsonObject& root) { - JsonObject battery = root.createNestedObject(FPSTR(_name)); // usermodname + JsonObject battery = root.createNestedObject(FPSTR(_name)); + + if (battery.isNull()) { + battery = root.createNestedObject(FPSTR(_name)); + } + #ifdef ARDUINO_ARCH_ESP32 battery[F("pin")] = batteryPin; #endif - - battery[F("type")] = (String)bcfg.type; // has to be a String otherwise it won't get converted to a Dropdown - battery[F("min-voltage")] = bat->getMinVoltage(); - battery[F("max-voltage")] = bat->getMaxVoltage(); - battery[F("capacity")] = bat->getCapacity(); - battery[F("calibration")] = bat->getCalibration(); - battery[FPSTR(_readInterval)] = readingInterval; - JsonObject ao = battery.createNestedObject(F("auto-off")); // auto off section - ao[FPSTR(_enabled)] = autoOffEnabled; - ao[FPSTR(_threshold)] = autoOffThreshold; - - JsonObject lp = battery.createNestedObject(F("indicator")); // low power section - lp[FPSTR(_enabled)] = lowPowerIndicatorEnabled; - lp[FPSTR(_preset)] = lowPowerIndicatorPreset; // dropdown trickery (String)lowPowerIndicatorPreset; - lp[FPSTR(_threshold)] = lowPowerIndicatorThreshold; - lp[FPSTR(_duration)] = lowPowerIndicatorDuration; + addBatteryToJsonObject(battery, false); DEBUG_PRINTLN(F("Battery config saved.")); } void appendConfigData() { - oappend(SET_F("td=addDropdown('Battery', 'type');")); - oappend(SET_F("addOption(td, 'Unkown', '0');")); - oappend(SET_F("addOption(td, 'LiPo', '1');")); - oappend(SET_F("addOption(td, 'LiOn', '2');")); - oappend(SET_F("addInfo('Battery:type',1,'requires reboot');")); - oappend(SET_F("addInfo('Battery:min-voltage', 1, 'v');")); - oappend(SET_F("addInfo('Battery:max-voltage', 1, 'v');")); - oappend(SET_F("addInfo('Battery:capacity', 1, 'mAh');")); - oappend(SET_F("addInfo('Battery:interval', 1, 'ms');")); - oappend(SET_F("addInfo('Battery:auto-off:threshold', 1, '%');")); - oappend(SET_F("addInfo('Battery:indicator:threshold', 1, '%');")); - oappend(SET_F("addInfo('Battery:indicator:duration', 1, 's');")); + // Total: 501 Bytes + oappend(SET_F("td=addDropdown('Battery', 'type');")); // 35 Bytes + oappend(SET_F("addOption(td, 'Unkown', '0');")); // 30 Bytes + oappend(SET_F("addOption(td, 'LiPo', '1');")); // 28 Bytes + oappend(SET_F("addOption(td, 'LiOn', '2');")); // 28 Bytes + oappend(SET_F("addInfo('Battery:type',1,'requires reboot');")); // 81 Bytes + oappend(SET_F("addInfo('Battery:min-voltage', 1, 'v');")); // 40 Bytes + oappend(SET_F("addInfo('Battery:max-voltage', 1, 'v');")); // 40 Bytes + oappend(SET_F("addInfo('Battery:capacity', 1, 'mAh');")); // 39 Bytes + oappend(SET_F("addInfo('Battery:interval', 1, 'ms');")); // 38 Bytes + oappend(SET_F("addInfo('Battery:auto-off:threshold', 1, '%');")); // 47 Bytes + oappend(SET_F("addInfo('Battery:indicator:threshold', 1, '%');")); // 48 Bytes + oappend(SET_F("addInfo('Battery:indicator:duration', 1, 's');")); // 47 Bytes - // cannot quite get this mf to work. its exeeding some buffer limit i think - // what i wanted is a list of all presets to select one from + // this option list would exeed the oappend() buffer + // a list of all presets to select one from // oappend(SET_F("bd=addDropdown('Battery:low-power-indicator', 'preset');")); // the loop generates: oappend(SET_F("addOption(bd, 'preset name', preset id);")); // for(int8_t i=1; i < 42; i++) { From f78f8b6b127203295cc0e22965c51a1f71415915 Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Sat, 21 Jan 2023 01:44:50 +0100 Subject: [PATCH 09/66] Exposing the Battery state to JSON API - Part 2 --- usermods/Battery/usermod_v2_Battery.h | 59 +++++++++++++++------------ 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index 390bd96b4..bd4d7778c 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -271,6 +271,30 @@ class UsermodBattery : public Usermod lp[FPSTR(_duration)] = lowPowerIndicatorDuration; } + void getUsermodConfigFromJsonObject(JsonObject& battery) + { + getJsonValue(battery[F("type")], bcfg.type); + getJsonValue(battery[F("min-voltage")], bcfg.minVoltage); + getJsonValue(battery[F("max-voltage")], bcfg.maxVoltage); + getJsonValue(battery[F("capacity")], bcfg.capacity); + getJsonValue(battery[F("calibration")], bcfg.calibration); + setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); + + JsonObject ao = battery[F("auto-off")]; + setAutoOffEnabled(ao[FPSTR(_enabled)] | autoOffEnabled); + setAutoOffThreshold(ao[FPSTR(_threshold)] | autoOffThreshold); + + JsonObject lp = battery[F("indicator")]; + setLowPowerIndicatorEnabled(lp[FPSTR(_enabled)] | lowPowerIndicatorEnabled); + setLowPowerIndicatorPreset(lp[FPSTR(_preset)] | lowPowerIndicatorPreset); + setLowPowerIndicatorThreshold(lp[FPSTR(_threshold)] | lowPowerIndicatorThreshold); + lowPowerIndicatorReactivationThreshold = lowPowerIndicatorThreshold+10; + setLowPowerIndicatorDuration(lp[FPSTR(_duration)] | lowPowerIndicatorDuration); + + if(initDone) + bat->update(bcfg); + } + /* * 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 @@ -296,7 +320,15 @@ class UsermodBattery : public Usermod /* void readFromJsonState(JsonObject& root) { - // TBD + if (!initDone) return; // prevent crash on boot applyPreset() + + JsonObject battery = root[FPSTR(_name)]; + + if (!battery.isNull()) { + getUsermodConfigFromJsonObject(battery); + + DEBUG_PRINTLN(F("Battery state read from JSON API.")); + } } */ @@ -416,25 +448,7 @@ class UsermodBattery : public Usermod newBatteryPin = battery[F("pin")] | newBatteryPin; #endif - getJsonValue(battery[F("type")], bcfg.type); - getJsonValue(battery[F("min-voltage")], bcfg.minVoltage); - getJsonValue(battery[F("max-voltage")], bcfg.maxVoltage); - getJsonValue(battery[F("capacity")], bcfg.capacity); - getJsonValue(battery[F("calibration")], bcfg.calibration); - setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); - - JsonObject ao = battery[F("auto-off")]; - setAutoOffEnabled(ao[FPSTR(_enabled)] | autoOffEnabled); - setAutoOffThreshold(ao[FPSTR(_threshold)] | autoOffThreshold); - - JsonObject lp = battery[F("indicator")]; - setLowPowerIndicatorEnabled(lp[FPSTR(_enabled)] | lowPowerIndicatorEnabled); - setLowPowerIndicatorPreset(lp[FPSTR(_preset)] | lowPowerIndicatorPreset); // dropdown trickery (int)lp["preset"] - setLowPowerIndicatorThreshold(lp[FPSTR(_threshold)] | lowPowerIndicatorThreshold); - lowPowerIndicatorReactivationThreshold = lowPowerIndicatorThreshold+10; - setLowPowerIndicatorDuration(lp[FPSTR(_duration)] | lowPowerIndicatorDuration); - - DEBUG_PRINT(FPSTR(_name)); + getUsermodConfigFromJsonObject(battery); #ifdef ARDUINO_ARCH_ESP32 if (!initDone) @@ -459,9 +473,6 @@ class UsermodBattery : public Usermod } #endif - if(initDone) - bat->update(bcfg); - return !battery[FPSTR(_readInterval)].isNull(); } @@ -578,7 +589,6 @@ class UsermodBattery : public Usermod autoOffThreshold = lowPowerIndicatorEnabled /*&& autoOffEnabled*/ ? min(lowPowerIndicatorThreshold-1, (int)autoOffThreshold) : autoOffThreshold; } - /* * Get low-power-indicator feature enabled status * is the low-power-indicator enabled, true/false @@ -648,7 +658,6 @@ class UsermodBattery : public Usermod lowPowerIndicatorDuration = duration; } - /* * Get low-power-indicator status when the indication is done thsi returns true */ From b8c61b52366a567d57860ada080c30ced9725777 Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Sat, 9 Sep 2023 21:01:55 +0200 Subject: [PATCH 10/66] =?UTF-8?q?Move=20battery=20types=20to=20a=20separat?= =?UTF-8?q?e=20folder=20=F0=9F=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- usermods/Battery/battery.h | 17 +---- usermods/Battery/battery_defaults.h | 16 +--- usermods/Battery/{ => types}/lion.h | 6 +- usermods/Battery/{ => types}/lipo.h | 14 ++-- usermods/Battery/{ => types}/unkown.h | 6 +- usermods/Battery/usermod_v2_Battery.h | 105 ++++++-------------------- 6 files changed, 37 insertions(+), 127 deletions(-) rename usermods/Battery/{ => types}/lion.h (87%) rename usermods/Battery/{ => types}/lipo.h (82%) rename usermods/Battery/{ => types}/unkown.h (83%) diff --git a/usermods/Battery/battery.h b/usermods/Battery/battery.h index 3a792aadb..8a8042ff3 100644 --- a/usermods/Battery/battery.h +++ b/usermods/Battery/battery.h @@ -14,7 +14,6 @@ class Battery protected: float minVoltage; float maxVoltage; - unsigned int capacity; float voltage; int8_t level = 100; float calibration; // offset or calibration value to fine tune the calculated voltage @@ -34,7 +33,7 @@ class Battery /** * Corresponding battery curves - * calculates the capacity in % (0-100) with given voltage and possible voltage range + * calculates the level in % (0-100) with given voltage and possible voltage range */ virtual float mapVoltage(float v, float min, float max) = 0; // { @@ -86,20 +85,6 @@ class Battery this->maxVoltage = max(getMinVoltage()+.5f, voltage); } - /* - * Get the capacity of all cells in parralel sumed up - * unit: mAh - */ - unsigned int getCapacity() - { - return this->capacity; - } - - void setCapacity(unsigned int capacity) - { - this->capacity = capacity; - } - float getVoltage() { return this->voltage; diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h index 668009680..199ee3432 100644 --- a/usermods/Battery/battery_defaults.h +++ b/usermods/Battery/battery_defaults.h @@ -40,9 +40,6 @@ #ifndef USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE #define USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE 4.2f #endif -#ifndef USERMOD_BATTERY_UNKOWN_CAPACITY - #define USERMOD_BATTERY_UNKOWN_CAPACITY 2500 -#endif #ifndef USERMOD_BATTERY_UNKOWN_CALIBRATION // offset or calibration value to fine tune the calculated voltage #define USERMOD_BATTERY_UNKOWN_CALIBRATION 0 @@ -59,9 +56,6 @@ #ifndef USERMOD_BATTERY_LIPO_MAX_VOLTAGE #define USERMOD_BATTERY_LIPO_MAX_VOLTAGE 4.2f #endif -#ifndef USERMOD_BATTERY_LIPO_CAPACITY - #define USERMOD_BATTERY_LIPO_CAPACITY 5000 -#endif #ifndef USERMOD_BATTERY_LIPO_CALIBRATION #define USERMOD_BATTERY_LIPO_CALIBRATION 0 #endif @@ -77,10 +71,6 @@ #ifndef USERMOD_BATTERY_LION_MAX_VOLTAGE #define USERMOD_BATTERY_LION_MAX_VOLTAGE 4.2f #endif -#ifndef USERMOD_BATTERY_LION_CAPACITY - // a common capacity for single 18650 battery cells is between 2500 and 3600 mAh - #define USERMOD_BATTERY_LION_CAPACITY 3100 -#endif #ifndef USERMOD_BATTERY_LION_CALIBRATION // offset or calibration value to fine tune the calculated voltage #define USERMOD_BATTERY_LION_CALIBRATION 0 @@ -109,11 +99,6 @@ #define USERMOD_BATTERY_CALIBRATION 0 #endif -// calculate remaining time / the time that is left before the battery runs out of power -// #ifndef USERMOD_BATTERY_CALCULATE_TIME_LEFT_ENABLED -// #define USERMOD_BATTERY_CALCULATE_TIME_LEFT_ENABLED false -// #endif - // auto-off feature #ifndef USERMOD_BATTERY_AUTO_OFF_ENABLED #define USERMOD_BATTERY_AUTO_OFF_ENABLED true @@ -157,6 +142,7 @@ typedef struct bconfig_t float voltage; // current voltage int8_t level; // current level float calibration; // offset or calibration value to fine tune the calculated voltage + float voltageMultiplier; } batteryConfig; diff --git a/usermods/Battery/lion.h b/usermods/Battery/types/lion.h similarity index 87% rename from usermods/Battery/lion.h rename to usermods/Battery/types/lion.h index 17a4b3593..2ff54a1ea 100644 --- a/usermods/Battery/lion.h +++ b/usermods/Battery/types/lion.h @@ -1,8 +1,8 @@ #ifndef UMBLion_h #define UMBLion_h -#include "battery_defaults.h" -#include "battery.h" +#include "../battery_defaults.h" +#include "../battery.h" /** * Lion Battery @@ -17,7 +17,6 @@ class Lion : public Battery { this->setMinVoltage(USERMOD_BATTERY_LION_MIN_VOLTAGE); this->setMaxVoltage(USERMOD_BATTERY_LION_MAX_VOLTAGE); - this->setCapacity(USERMOD_BATTERY_LION_CAPACITY); this->setVoltage(this->getVoltage()); this->setCalibration(USERMOD_BATTERY_LION_CALIBRATION); } @@ -26,7 +25,6 @@ class Lion : public Battery { if(cfg.minVoltage) this->setMinVoltage(cfg.minVoltage); if(cfg.maxVoltage) this->setMaxVoltage(cfg.maxVoltage); - if(cfg.calibration) this->setCapacity(cfg.calibration); if(cfg.level) this->setLevel(cfg.level); if(cfg.calibration) this->setCalibration(cfg.calibration); } diff --git a/usermods/Battery/lipo.h b/usermods/Battery/types/lipo.h similarity index 82% rename from usermods/Battery/lipo.h rename to usermods/Battery/types/lipo.h index dcd44567f..264d3251e 100644 --- a/usermods/Battery/lipo.h +++ b/usermods/Battery/types/lipo.h @@ -1,8 +1,8 @@ #ifndef UMBLipo_h #define UMBLipo_h -#include "battery_defaults.h" -#include "battery.h" +#include "../battery_defaults.h" +#include "../battery.h" /** * Lipo Battery @@ -17,7 +17,6 @@ class Lipo : public Battery { this->setMinVoltage(USERMOD_BATTERY_LIPO_MIN_VOLTAGE); this->setMaxVoltage(USERMOD_BATTERY_LIPO_MAX_VOLTAGE); - this->setCapacity(USERMOD_BATTERY_LIPO_CAPACITY); this->setVoltage(this->getVoltage()); this->setCalibration(USERMOD_BATTERY_LIPO_CALIBRATION); } @@ -26,13 +25,12 @@ class Lipo : public Battery { if(cfg.minVoltage) this->setMinVoltage(cfg.minVoltage); if(cfg.maxVoltage) this->setMaxVoltage(cfg.maxVoltage); - if(cfg.calibration) this->setCapacity(cfg.calibration); if(cfg.level) this->setLevel(cfg.level); if(cfg.calibration) this->setCalibration(cfg.calibration); } /** - * LiPo batteries have a differnt dischargin curve, see + * LiPo batteries have a differnt discharge curve, see * https://blog.ampow.com/lipo-voltage-chart/ */ float mapVoltage(float v, float min, float max) override @@ -41,12 +39,12 @@ class Lipo : public Battery lvl = this->linearMapping(v, min, max); // basic mapping if (lvl < 40.0f) - lvl = this->linearMapping(lvl, 0, 40, 0, 12); // last 45% -> drops very quickly + lvl = this->linearMapping(lvl, 0, 40, 0, 12); // last 45% -> drops very quickly else { if (lvl < 90.0f) - lvl = this->linearMapping(lvl, 40, 90, 12, 95); // 90% ... 40% -> almost linear drop + lvl = this->linearMapping(lvl, 40, 90, 12, 95); // 90% ... 40% -> almost linear drop else // level > 90% - lvl = this->linearMapping(lvl, 90, 105, 95, 100); // highest 15% -> drop slowly + lvl = this->linearMapping(lvl, 90, 105, 95, 100); // highest 15% -> drop slowly } return lvl; diff --git a/usermods/Battery/unkown.h b/usermods/Battery/types/unkown.h similarity index 83% rename from usermods/Battery/unkown.h rename to usermods/Battery/types/unkown.h index f36c3195e..2b38da96c 100644 --- a/usermods/Battery/unkown.h +++ b/usermods/Battery/types/unkown.h @@ -1,8 +1,8 @@ #ifndef UMBUnkown_h #define UMBUnkown_h -#include "battery_defaults.h" -#include "battery.h" +#include "../battery_defaults.h" +#include "../battery.h" /** * Lion Battery @@ -17,7 +17,6 @@ class Unkown : public Battery { this->setMinVoltage(USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE); this->setMaxVoltage(USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE); - this->setCapacity(USERMOD_BATTERY_UNKOWN_CAPACITY); this->setVoltage(this->getVoltage()); this->setCalibration(USERMOD_BATTERY_UNKOWN_CALIBRATION); } @@ -26,7 +25,6 @@ class Unkown : public Battery { if(cfg.minVoltage) this->setMinVoltage(cfg.minVoltage); else this->setMinVoltage(USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE); if(cfg.maxVoltage) this->setMaxVoltage(cfg.maxVoltage); else this->setMaxVoltage(USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE); - if(cfg.calibration) this->setCapacity(cfg.calibration); else this->setCapacity(USERMOD_BATTERY_UNKOWN_CAPACITY); if(cfg.calibration) this->setCalibration(cfg.calibration); else this->setCalibration(USERMOD_BATTERY_UNKOWN_CALIBRATION); } diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index 7f6738e10..a91331cb7 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -3,9 +3,9 @@ #include "wled.h" #include "battery_defaults.h" #include "battery.h" -#include "unkown.h" -#include "lion.h" -#include "lipo.h" +#include "types/unkown.h" +#include "types/lion.h" +#include "types/lipo.h" /* * Usermod by Maximilian Mewes @@ -28,7 +28,7 @@ class UsermodBattery : public Usermod unsigned long nextReadTime = 0; unsigned long lastReadTime = 0; // battery min. voltage - float minBatteryVoltage = USERMOD_BATTERY_MIN_VOLTAGE; + float minBatteryVoltage = 3.3f; // battery max. voltage float maxBatteryVoltage = USERMOD_BATTERY_MAX_VOLTAGE; // all battery cells summed up @@ -39,16 +39,10 @@ class UsermodBattery : public Usermod float voltage = maxBatteryVoltage; // between 0 and 1, to control strength of voltage smoothing filter float alpha = 0.05f; - // multiplier for the voltage divider that is in place between ADC pin and battery, default will be 2 but might be adapted to readout voltages over ~5v ESP32 or ~6.6v ESP8266 - float voltageMultiplier = USERMOD_BATTERY_VOLTAGE_MULTIPLIER; // mapped battery level based on voltage int8_t batteryLevel = 100; // offset or calibration value to fine tune the calculated voltage float calibration = USERMOD_BATTERY_CALIBRATION; - - // time left estimation feature - // bool calculateTimeLeftEnabled = USERMOD_BATTERY_CALCULATE_TIME_LEFT_ENABLED; - // float estimatedTimeLeft = 0.0; // auto shutdown/shutoff/master off feature bool autoOffEnabled = USERMOD_BATTERY_AUTO_OFF_ENABLED; @@ -114,18 +108,22 @@ class UsermodBattery : public Usermod } } - float readVoltage() - { - #ifdef ARDUINO_ARCH_ESP32 - // use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV default attentuation) and divide by 1000 to get from milivolts to volts and multiply by voltage multiplier and apply calibration value - return (analogReadMilliVolts(batteryPin) / 1000.0f) * voltageMultiplier + calibration; - #else - // use analog read on esp8266 ( 0V ~ 1V no attenuation options) and divide by ADC precision 1023 and multiply by voltage multiplier and apply calibration value - return (analogRead(batteryPin) / 1023.0f) * voltageMultiplier + calibration; - #endif - } + // float readVoltage() + // { + // #ifdef ARDUINO_ARCH_ESP32 + // // use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV default attentuation) and divide by 1000 to get from milivolts to volts and multiply by voltage multiplier and apply calibration value + // return (analogReadMilliVolts(batteryPin) / 1000.0f) * voltageMultiplier + calibration; + // #else + // // use analog read on esp8266 ( 0V ~ 1V no attenuation options) and divide by ADC precision 1023 and multiply by voltage multiplier and apply calibration value + // return (analogRead(batteryPin) / 1023.0f) * voltageMultiplier + calibration; + // #endif + // } public: + UsermodBattery() + { + bat = new Unkown(); + } //Functions called by WLED /* @@ -152,14 +150,13 @@ class UsermodBattery : public Usermod } #else //ESP8266 boards have only one analog input pin A0 pinMode(batteryPin, INPUT); - voltage = readVoltage(); + // voltage = readVoltage(); #endif //this could also be handled with a factory class but for only 2 types it should be sufficient for now if(bcfg.type == (batteryType)lipo) { bat = new Lipo(); - } else - if(bcfg.type == (batteryType)lion) { + } else if(bcfg.type == (batteryType)lion) { bat = new Lion(); } else { bat = new Unkown(); // nullObject pattern @@ -218,14 +215,8 @@ class UsermodBattery : public Usermod // calculate the voltage voltage = ((rawValue / getAdcPrecision()) * bat->getMaxVoltage()) + bat->getCalibration(); #endif - // initializing = false; - - // rawValue = readVoltage(); - // // filter with exponential smoothing because ADC in esp32 is fluctuating too much for a good single readout - // voltage = voltage + alpha * (rawValue - voltage); - - // check if voltage is within specified voltage range, allow 10% over/under voltage - removed cause this just makes it hard for people to troubleshoot as the voltage in the web gui will say invalid instead of displaying a voltage - //voltage = ((voltage < minBatteryVoltage * 0.85f) || (voltage > maxBatteryVoltage * 1.1f)) ? -1.0f : voltage; + // filter with exponential smoothing because ADC in esp32 is fluctuating too much for a good single readout + voltage = voltage + alpha * (rawValue - voltage); bat->setVoltage(voltage); // translate battery voltage into percentage @@ -298,7 +289,6 @@ class UsermodBattery : public Usermod if(forJsonState) { battery[F("type")] = bcfg.type; } else {battery[F("type")] = (String)bcfg.type; } // has to be a String otherwise it won't get converted to a Dropdown battery[F("min-voltage")] = bat->getMinVoltage(); battery[F("max-voltage")] = bat->getMaxVoltage(); - battery[F("capacity")] = bat->getCapacity(); battery[F("calibration")] = bat->getCalibration(); battery[FPSTR(_readInterval)] = readingInterval; @@ -318,8 +308,8 @@ class UsermodBattery : public Usermod getJsonValue(battery[F("type")], bcfg.type); getJsonValue(battery[F("min-voltage")], bcfg.minVoltage); getJsonValue(battery[F("max-voltage")], bcfg.maxVoltage); - getJsonValue(battery[F("capacity")], bcfg.capacity); getJsonValue(battery[F("calibration")], bcfg.calibration); + setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); JsonObject ao = battery[F("auto-off")]; @@ -421,26 +411,18 @@ class UsermodBattery : public Usermod #ifdef ARDUINO_ARCH_ESP32 battery[F("pin")] = batteryPin; #endif - - // battery[F("time-left")] = calculateTimeLeftEnabled; - battery[F("min-voltage")] = minBatteryVoltage; - battery[F("max-voltage")] = maxBatteryVoltage; - battery[F("capacity")] = totalBatteryCapacity; - battery[F("calibration")] = calibration; - battery[F("voltage-multiplier")] = voltageMultiplier; - battery[FPSTR(_readInterval)] = readingInterval; addBatteryToJsonObject(battery, false); // read voltage in case calibration or voltage multiplier changed to see immediate effect - voltage = readVoltage(); + // voltage = readVoltage(); DEBUG_PRINTLN(F("Battery config saved.")); } void appendConfigData() { - // Total: 501 Bytes + // Total: 462 Bytes oappend(SET_F("td=addDropdown('Battery', 'type');")); // 35 Bytes oappend(SET_F("addOption(td, 'Unkown', '0');")); // 30 Bytes oappend(SET_F("addOption(td, 'LiPo', '1');")); // 28 Bytes @@ -448,7 +430,6 @@ class UsermodBattery : public Usermod oappend(SET_F("addInfo('Battery:type',1,'requires reboot');")); // 81 Bytes oappend(SET_F("addInfo('Battery:min-voltage', 1, 'v');")); // 40 Bytes oappend(SET_F("addInfo('Battery:max-voltage', 1, 'v');")); // 40 Bytes - oappend(SET_F("addInfo('Battery:capacity', 1, 'mAh');")); // 39 Bytes oappend(SET_F("addInfo('Battery:interval', 1, 'ms');")); // 38 Bytes oappend(SET_F("addInfo('Battery:auto-off:threshold', 1, '%');")); // 47 Bytes oappend(SET_F("addInfo('Battery:indicator:threshold', 1, '%');")); // 48 Bytes @@ -503,9 +484,7 @@ class UsermodBattery : public Usermod // calculateTimeLeftEnabled = battery[F("time-left")] | calculateTimeLeftEnabled; setMinBatteryVoltage(battery[F("min-voltage")] | minBatteryVoltage); setMaxBatteryVoltage(battery[F("max-voltage")] | maxBatteryVoltage); - setTotalBatteryCapacity(battery[F("capacity")] | totalBatteryCapacity); setCalibration(battery[F("calibration")] | calibration); - setVoltageMultiplier(battery[F("voltage-multiplier")] | voltageMultiplier); setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); getUsermodConfigFromJsonObject(battery); @@ -655,22 +634,6 @@ class UsermodBattery : public Usermod } - /* - * Get the capacity of all cells in parralel sumed up - * unit: mAh - */ - unsigned int getTotalBatteryCapacity() - { - return totalBatteryCapacity; - } - - void setTotalBatteryCapacity(unsigned int capacity) - { - totalBatteryCapacity = capacity; - } - - - /* * Get the calculated voltage * formula: (adc pin value / adc precision * max voltage) + calibration @@ -707,24 +670,6 @@ class UsermodBattery : public Usermod calibration = offset; } - /* - * Set the voltage multiplier value - * A multiplier that may need adjusting for different voltage divider setups - */ - void setVoltageMultiplier(float multiplier) - { - voltageMultiplier = multiplier; - } - - /* - * Get the voltage multiplier value - * A multiplier that may need adjusting for different voltage divider setups - */ - float getVoltageMultiplier() - { - return voltageMultiplier; - } - /* * Get auto-off feature enabled status * is auto-off enabled, true/false From a9d6a1592412a6f901afecc1e9e4e8934ef46b13 Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Sat, 9 Sep 2023 21:50:30 +0200 Subject: [PATCH 11/66] Update Classes --- usermods/Battery/battery.h | 23 ++- usermods/Battery/battery_defaults.h | 25 +--- usermods/Battery/types/lion.h | 3 +- usermods/Battery/types/lipo.h | 3 +- usermods/Battery/types/unkown.h | 4 +- usermods/Battery/usermod_v2_Battery.h | 208 ++++++++++---------------- 6 files changed, 111 insertions(+), 155 deletions(-) diff --git a/usermods/Battery/battery.h b/usermods/Battery/battery.h index 8a8042ff3..4cdfb035f 100644 --- a/usermods/Battery/battery.h +++ b/usermods/Battery/battery.h @@ -17,6 +17,7 @@ class Battery float voltage; int8_t level = 100; float calibration; // offset or calibration value to fine tune the calculated voltage + float voltageMultiplier; // ratio for the voltage divider float linearMapping(float v, float min, float max, float oMin = 0.0f, float oMax = 100.0f) { @@ -26,7 +27,9 @@ class Battery public: Battery() { - + this->setVoltage(this->getVoltage()); + this->setVoltageMultiplier(USERMOD_BATTERY_VOLTAGE_MULTIPLIER); + this->setCalibration(USERMOD_BATTERY_CALIBRATION); } virtual void update(batteryConfig cfg) = 0; @@ -127,6 +130,24 @@ class Battery { calibration = offset; } + + /* + * Get the configured calibration value + * a value to set the voltage divider ratio + */ + virtual float getVoltageMultiplier() + { + return voltageMultiplier; + } + + /* + * Set the voltage multiplier value + * a value to set the voltage divider ratio. + */ + virtual void setVoltageMultiplier(float multiplier) + { + voltageMultiplier = voltageMultiplier; + } }; #endif \ No newline at end of file diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h index 199ee3432..6d0a95dc4 100644 --- a/usermods/Battery/battery_defaults.h +++ b/usermods/Battery/battery_defaults.h @@ -40,10 +40,7 @@ #ifndef USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE #define USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE 4.2f #endif -#ifndef USERMOD_BATTERY_UNKOWN_CALIBRATION - // offset or calibration value to fine tune the calculated voltage - #define USERMOD_BATTERY_UNKOWN_CALIBRATION 0 -#endif + /* * * Lithium polymer (Li-Po) defaults @@ -56,9 +53,7 @@ #ifndef USERMOD_BATTERY_LIPO_MAX_VOLTAGE #define USERMOD_BATTERY_LIPO_MAX_VOLTAGE 4.2f #endif -#ifndef USERMOD_BATTERY_LIPO_CALIBRATION - #define USERMOD_BATTERY_LIPO_CALIBRATION 0 -#endif + /* * * Lithium-ion (Li-Ion) defaults @@ -71,12 +66,8 @@ #ifndef USERMOD_BATTERY_LION_MAX_VOLTAGE #define USERMOD_BATTERY_LION_MAX_VOLTAGE 4.2f #endif -#ifndef USERMOD_BATTERY_LION_CALIBRATION - // offset or calibration value to fine tune the calculated voltage - #define USERMOD_BATTERY_LION_CALIBRATION 0 -#endif -//the default ratio for the voltage divider +// the default ratio for the voltage divider #ifndef USERMOD_BATTERY_VOLTAGE_MULTIPLIER #ifdef ARDUINO_ARCH_ESP32 #define USERMOD_BATTERY_VOLTAGE_MULTIPLIER 2.0f @@ -85,13 +76,8 @@ #endif #endif -#ifndef USERMOD_BATTERY_MAX_VOLTAGE - #define USERMOD_BATTERY_MAX_VOLTAGE 4.2f -#endif - -// a common capacity for single 18650 battery cells is between 2500 and 3600 mAh -#ifndef USERMOD_BATTERY_TOTAL_CAPACITY - #define USERMOD_BATTERY_TOTAL_CAPACITY 3100 +#ifndef USERMOD_BATTERY_AVERAGING_ALPHA + #define USERMOD_BATTERY_AVERAGING_ALPHA 0.1f #endif // offset or calibration value to fine tune the calculated voltage @@ -138,7 +124,6 @@ typedef struct bconfig_t batteryType type; float minVoltage; float maxVoltage; - unsigned int capacity; // current capacity float voltage; // current voltage int8_t level; // current level float calibration; // offset or calibration value to fine tune the calculated voltage diff --git a/usermods/Battery/types/lion.h b/usermods/Battery/types/lion.h index 2ff54a1ea..0d2325386 100644 --- a/usermods/Battery/types/lion.h +++ b/usermods/Battery/types/lion.h @@ -14,11 +14,10 @@ class Lion : public Battery public: Lion() + : Battery() { this->setMinVoltage(USERMOD_BATTERY_LION_MIN_VOLTAGE); this->setMaxVoltage(USERMOD_BATTERY_LION_MAX_VOLTAGE); - this->setVoltage(this->getVoltage()); - this->setCalibration(USERMOD_BATTERY_LION_CALIBRATION); } void update(batteryConfig cfg) diff --git a/usermods/Battery/types/lipo.h b/usermods/Battery/types/lipo.h index 264d3251e..f65ab12c5 100644 --- a/usermods/Battery/types/lipo.h +++ b/usermods/Battery/types/lipo.h @@ -14,11 +14,10 @@ class Lipo : public Battery public: Lipo() + : Battery() { this->setMinVoltage(USERMOD_BATTERY_LIPO_MIN_VOLTAGE); this->setMaxVoltage(USERMOD_BATTERY_LIPO_MAX_VOLTAGE); - this->setVoltage(this->getVoltage()); - this->setCalibration(USERMOD_BATTERY_LIPO_CALIBRATION); } void update(batteryConfig cfg) diff --git a/usermods/Battery/types/unkown.h b/usermods/Battery/types/unkown.h index 2b38da96c..edf220040 100644 --- a/usermods/Battery/types/unkown.h +++ b/usermods/Battery/types/unkown.h @@ -14,18 +14,16 @@ class Unkown : public Battery public: Unkown() + : Battery() { this->setMinVoltage(USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE); this->setMaxVoltage(USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE); - this->setVoltage(this->getVoltage()); - this->setCalibration(USERMOD_BATTERY_UNKOWN_CALIBRATION); } void update(batteryConfig cfg) { if(cfg.minVoltage) this->setMinVoltage(cfg.minVoltage); else this->setMinVoltage(USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE); if(cfg.maxVoltage) this->setMaxVoltage(cfg.maxVoltage); else this->setMaxVoltage(USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE); - if(cfg.calibration) this->setCalibration(cfg.calibration); else this->setCalibration(USERMOD_BATTERY_UNKOWN_CALIBRATION); } float mapVoltage(float v, float min, float max) override diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index a91331cb7..9b980d557 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -20,27 +20,15 @@ class UsermodBattery : public Usermod // battery pin can be defined in my_config.h int8_t batteryPin = USERMOD_BATTERY_MEASUREMENT_PIN; - Battery* bat = nullptr; - batteryConfig bcfg; + Battery* bat = new Unkown(); + batteryConfig cfg; // how often to read the battery voltage unsigned long readingInterval = USERMOD_BATTERY_MEASUREMENT_INTERVAL; unsigned long nextReadTime = 0; unsigned long lastReadTime = 0; - // battery min. voltage - float minBatteryVoltage = 3.3f; - // battery max. voltage - float maxBatteryVoltage = USERMOD_BATTERY_MAX_VOLTAGE; - // all battery cells summed up - unsigned int totalBatteryCapacity = USERMOD_BATTERY_TOTAL_CAPACITY; - // raw analog reading - float rawValue = 0.0f; - // calculated voltage - float voltage = maxBatteryVoltage; // between 0 and 1, to control strength of voltage smoothing filter - float alpha = 0.05f; - // mapped battery level based on voltage - int8_t batteryLevel = 100; + float alpha = USERMOD_BATTERY_AVERAGING_ALPHA; // offset or calibration value to fine tune the calculated voltage float calibration = USERMOD_BATTERY_CALIBRATION; @@ -70,13 +58,16 @@ class UsermodBattery : public Usermod static const char _duration[]; static const char _init[]; + /** + * Helper for rounding floating point values + */ float dot2round(float x) { float nx = (int)(x * 100 + .5); return (float)(nx / 100); } - /* + /** * Turn off all leds */ void turnOff() @@ -85,7 +76,7 @@ class UsermodBattery : public Usermod stateUpdated(CALL_MODE_DIRECT_CHANGE); } - /* + /** * Indicate low power by activating a configured preset for a given time and then switching back to the preset that was selected previously */ void lowPowerIndicator() @@ -108,25 +99,24 @@ class UsermodBattery : public Usermod } } - // float readVoltage() - // { - // #ifdef ARDUINO_ARCH_ESP32 - // // use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV default attentuation) and divide by 1000 to get from milivolts to volts and multiply by voltage multiplier and apply calibration value - // return (analogReadMilliVolts(batteryPin) / 1000.0f) * voltageMultiplier + calibration; - // #else - // // use analog read on esp8266 ( 0V ~ 1V no attenuation options) and divide by ADC precision 1023 and multiply by voltage multiplier and apply calibration value - // return (analogRead(batteryPin) / 1023.0f) * voltageMultiplier + calibration; - // #endif - // } + /** + * read the battery voltage in different ways depending on the architecture + */ + float readVoltage() + { + #ifdef ARDUINO_ARCH_ESP32 + // use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV default attentuation) and divide by 1000 to get from milivolts to volts and multiply by voltage multiplier and apply calibration value + return (analogReadMilliVolts(batteryPin) / 1000.0f) * bat->getVoltageMultiplier() + bat->getCalibration(); + #else + // use analog read on esp8266 ( 0V ~ 1V no attenuation options) and divide by ADC precision 1023 and multiply by voltage multiplier and apply calibration value + return (analogRead(batteryPin) / 1023.0f) * bat->getVoltageMultiplier() + bat->getCalibration(); + #endif + } public: - UsermodBattery() - { - bat = new Unkown(); - } //Functions called by WLED - /* + /** * setup() is called once at boot. WiFi is not yet connected at this point. * You can use it to initialize variables, sensors or similar. */ @@ -153,16 +143,15 @@ class UsermodBattery : public Usermod // voltage = readVoltage(); #endif - //this could also be handled with a factory class but for only 2 types it should be sufficient for now - if(bcfg.type == (batteryType)lipo) { + // plug in the right battery type + if(cfg.type == (batteryType)lipo) { bat = new Lipo(); - } else if(bcfg.type == (batteryType)lion) { + } else if(cfg.type == (batteryType)lion) { bat = new Lion(); - } else { - bat = new Unkown(); // nullObject pattern } - bat->update(bcfg); + // update the choosen battery type with configured values + bat->update(cfg); nextReadTime = millis() + readingInterval; lastReadTime = millis(); @@ -171,7 +160,7 @@ class UsermodBattery : public Usermod } - /* + /** * connected() is called every time the WiFi is (re)connected * Use it to initialize network interfaces */ @@ -199,28 +188,15 @@ class UsermodBattery : public Usermod if (batteryPin < 0) return; // nothing to read - initializing = false; - float voltage = -1.0f; - float rawValue = 0.0f; -#ifdef ARDUINO_ARCH_ESP32 - // use calibrated millivolts analogread on esp32 (150 mV ~ 2450 mV) - rawValue = analogReadMilliVolts(batteryPin); - // calculate the voltage - voltage = (rawValue / 1000.0f) + calibration; - // usually a voltage divider (50%) is used on ESP32, so we need to multiply by 2 - voltage *= 2.0f; -#else - // read battery raw input - rawValue = analogRead(batteryPin); - // calculate the voltage - voltage = ((rawValue / getAdcPrecision()) * bat->getMaxVoltage()) + bat->getCalibration(); -#endif - // filter with exponential smoothing because ADC in esp32 is fluctuating too much for a good single readout - voltage = voltage + alpha * (rawValue - voltage); + initializing = false; + float rawValue = readVoltage(); - bat->setVoltage(voltage); + // filter with exponential smoothing because ADC in esp32 is fluctuating too much for a good single readout + float filteredVoltage = bat->getVoltage() + alpha * (rawValue - bat->getVoltage()); + + bat->setVoltage(filteredVoltage); // translate battery voltage into percentage - bat->calculateAndSetLevel(voltage); + bat->calculateAndSetLevel(filteredVoltage); // Auto off -- Master power off if (autoOffEnabled && (autoOffThreshold >= bat->getLevel())) @@ -232,13 +208,13 @@ class UsermodBattery : public Usermod if (WLED_MQTT_CONNECTED) { char buf[64]; // buffer for snprintf() snprintf_P(buf, 63, PSTR("%s/voltage"), mqttDeviceTopic); - mqtt->publish(buf, 0, false, String(voltage).c_str()); + mqtt->publish(buf, 0, false, String(bat->getVoltage()).c_str()); } #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 @@ -286,7 +262,7 @@ class UsermodBattery : public Usermod void addBatteryToJsonObject(JsonObject& battery, bool forJsonState) { - if(forJsonState) { battery[F("type")] = bcfg.type; } else {battery[F("type")] = (String)bcfg.type; } // has to be a String otherwise it won't get converted to a Dropdown + if(forJsonState) { battery[F("type")] = cfg.type; } else {battery[F("type")] = (String)cfg.type; } // has to be a String otherwise it won't get converted to a Dropdown battery[F("min-voltage")] = bat->getMinVoltage(); battery[F("max-voltage")] = bat->getMaxVoltage(); battery[F("calibration")] = bat->getCalibration(); @@ -305,10 +281,10 @@ class UsermodBattery : public Usermod void getUsermodConfigFromJsonObject(JsonObject& battery) { - getJsonValue(battery[F("type")], bcfg.type); - getJsonValue(battery[F("min-voltage")], bcfg.minVoltage); - getJsonValue(battery[F("max-voltage")], bcfg.maxVoltage); - getJsonValue(battery[F("calibration")], bcfg.calibration); + getJsonValue(battery[F("type")], cfg.type); + getJsonValue(battery[F("min-voltage")], cfg.minVoltage); + getJsonValue(battery[F("max-voltage")], cfg.maxVoltage); + getJsonValue(battery[F("calibration")], cfg.calibration); setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); @@ -324,10 +300,10 @@ class UsermodBattery : public Usermod setLowPowerIndicatorDuration(lp[FPSTR(_duration)] | lowPowerIndicatorDuration); if(initDone) - bat->update(bcfg); + bat->update(cfg); } - /* + /** * 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 */ @@ -345,7 +321,7 @@ class UsermodBattery : public Usermod } - /* + /** * 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 */ @@ -365,7 +341,7 @@ class UsermodBattery : public Usermod */ - /* + /** * addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object. * It will be called by WLED when settings are actually saved (for example, LED settings are saved) * If you want to force saving the current state, use serializeConfig() in your loop(). @@ -449,7 +425,7 @@ class UsermodBattery : public Usermod } - /* + /** * readFromConfig() can be used to read back the custom settings you added with addToConfig(). * This is called by WLED when settings are loaded (currently this only happens immediately after boot, or after saving on the Usermod Settings page) * @@ -482,8 +458,8 @@ class UsermodBattery : public Usermod newBatteryPin = battery[F("pin")] | newBatteryPin; #endif // calculateTimeLeftEnabled = battery[F("time-left")] | calculateTimeLeftEnabled; - setMinBatteryVoltage(battery[F("min-voltage")] | minBatteryVoltage); - setMaxBatteryVoltage(battery[F("max-voltage")] | maxBatteryVoltage); + setMinBatteryVoltage(battery[F("min-voltage")] | bat->getMinVoltage()); + setMaxBatteryVoltage(battery[F("max-voltage")] | bat->getMaxVoltage()); setCalibration(battery[F("calibration")] | calibration); setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); @@ -515,7 +491,7 @@ class UsermodBattery : public Usermod return !battery[FPSTR(_readInterval)].isNull(); } - /* + /** * TBD: Generate a preset sample for low power indication * a button on the config page would be cool, currently not possible */ @@ -554,7 +530,7 @@ class UsermodBattery : public Usermod * */ - /* + /** * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. */ @@ -569,7 +545,7 @@ class UsermodBattery : public Usermod return readingInterval; } - /* + /** * minimum repetition is 3000ms (3s) */ void setReadingInterval(unsigned long newReadingInterval) @@ -577,100 +553,78 @@ class UsermodBattery : public Usermod readingInterval = max((unsigned long)3000, newReadingInterval); } - /* - * Get the choosen adc precision - * esp8266 = 10bit resolution = 1024.0f - * esp32 = 12bit resolution = 4095.0f - */ - float getAdcPrecision() - { - #ifdef ARDUINO_ARCH_ESP32 - // esp32 - return 4096.0f; - #else - // esp8266 - return 1024.0f; - #endif - } - - /* - - /* + /** * Get lowest configured battery voltage */ float getMinBatteryVoltage() { - return minBatteryVoltage; + return bat->getMinVoltage(); } - /* + /** * Set lowest battery voltage - * can't be below 0 volt + * cant be below 0 volt */ void setMinBatteryVoltage(float voltage) { - minBatteryVoltage = max(0.0f, voltage); + bat->setMinVoltage(voltage); } - /* + /** * Get highest configured battery voltage */ float getMaxBatteryVoltage() { - return maxBatteryVoltage; + return bat->getMaxVoltage(); } - /* + /** * Set highest battery voltage * can't be below minBatteryVoltage */ void setMaxBatteryVoltage(float voltage) { - #ifdef USERMOD_BATTERY_USE_LIPO - maxBatteryVoltage = max(getMinBatteryVoltage()+0.7f, voltage); - #else - maxBatteryVoltage = max(getMinBatteryVoltage()+1.0f, voltage); - #endif + bat->setMaxVoltage(voltage); } - /* + /** * Get the calculated voltage * formula: (adc pin value / adc precision * max voltage) + calibration */ float getVoltage() { - return voltage; + return bat->getVoltage(); } - /* + /** * Get the mapped battery level (0 - 100) based on voltage * important: voltage can drop when a load is applied, so its only an estimate */ int8_t getBatteryLevel() { - return batteryLevel; + return bat->getLevel(); } - /* + /** * Get the configured calibration value * a offset value to fine-tune the calculated voltage. */ float getCalibration() { - return calibration; + return bat->getCalibration(); } - /* + /** * Set the voltage calibration offset value * a offset value to fine-tune the calculated voltage. */ void setCalibration(float offset) { - calibration = offset; + bat->setCalibration(offset); } - /* + /** * Get auto-off feature enabled status * is auto-off enabled, true/false */ @@ -679,7 +633,7 @@ class UsermodBattery : public Usermod return autoOffEnabled; } - /* + /** * Set auto-off feature status */ void setAutoOffEnabled(bool enabled) @@ -687,7 +641,7 @@ class UsermodBattery : public Usermod autoOffEnabled = enabled; } - /* + /** * Get auto-off threshold in percent (0-100) */ int8_t getAutoOffThreshold() @@ -695,7 +649,7 @@ class UsermodBattery : public Usermod return autoOffThreshold; } - /* + /** * Set auto-off threshold in percent (0-100) */ void setAutoOffThreshold(int8_t threshold) @@ -705,7 +659,7 @@ class UsermodBattery : public Usermod autoOffThreshold = lowPowerIndicatorEnabled /*&& autoOffEnabled*/ ? min(lowPowerIndicatorThreshold-1, (int)autoOffThreshold) : autoOffThreshold; } - /* + /** * Get low-power-indicator feature enabled status * is the low-power-indicator enabled, true/false */ @@ -714,7 +668,7 @@ class UsermodBattery : public Usermod return lowPowerIndicatorEnabled; } - /* + /** * Set low-power-indicator feature status */ void setLowPowerIndicatorEnabled(bool enabled) @@ -722,7 +676,7 @@ class UsermodBattery : public Usermod lowPowerIndicatorEnabled = enabled; } - /* + /** * Get low-power-indicator preset to activate when low power is detected */ int8_t getLowPowerIndicatorPreset() @@ -730,7 +684,7 @@ class UsermodBattery : public Usermod return lowPowerIndicatorPreset; } - /* + /** * Set low-power-indicator preset to activate when low power is detected */ void setLowPowerIndicatorPreset(int8_t presetId) @@ -748,7 +702,7 @@ class UsermodBattery : public Usermod return lowPowerIndicatorThreshold; } - /* + /** * Set low-power-indicator threshold in percent (0-100) */ void setLowPowerIndicatorThreshold(int8_t threshold) @@ -758,7 +712,7 @@ class UsermodBattery : public Usermod lowPowerIndicatorThreshold = autoOffEnabled /*&& lowPowerIndicatorEnabled*/ ? max(autoOffThreshold+1, (int)lowPowerIndicatorThreshold) : max(5, (int)lowPowerIndicatorThreshold); } - /* + /** * Get low-power-indicator duration in seconds */ int8_t getLowPowerIndicatorDuration() @@ -766,7 +720,7 @@ class UsermodBattery : public Usermod return lowPowerIndicatorDuration; } - /* + /** * Set low-power-indicator duration in seconds */ void setLowPowerIndicatorDuration(int8_t duration) @@ -774,7 +728,7 @@ class UsermodBattery : public Usermod lowPowerIndicatorDuration = duration; } - /* + /** * Get low-power-indicator status when the indication is done thsi returns true */ bool getLowPowerIndicatorDone() From c3787af29d317e52cb2d9a3837f882c9412360c0 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 9 Apr 2024 20:00:00 +0200 Subject: [PATCH 12/66] Send ArtnetPollReply for Art-Net proxy universe --- wled00/e131.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/wled00/e131.cpp b/wled00/e131.cpp index a67a672c2..ee8fa3949 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -346,7 +346,6 @@ void handleArtnetPollReply(IPAddress ipAddress) { switch (DMXMode) { case DMX_MODE_DISABLED: - return; // nothing to do break; case DMX_MODE_SINGLE_RGB: @@ -391,9 +390,17 @@ void handleArtnetPollReply(IPAddress ipAddress) { break; } - for (uint16_t i = startUniverse; i <= endUniverse; ++i) { - sendArtnetPollReply(&artnetPollReply, ipAddress, i); + if (DMXMode != DMX_MODE_DISABLED) { + for (uint16_t i = startUniverse; i <= endUniverse; ++i) { + sendArtnetPollReply(&artnetPollReply, ipAddress, i); + } } + + #ifdef WLED_ENABLE_DMX + if (e131ProxyUniverse > 0 && (DMXMode == DMX_MODE_DISABLED || (e131ProxyUniverse < startUniverse || e131ProxyUniverse > endUniverse))) { + sendArtnetPollReply(&artnetPollReply, ipAddress, e131ProxyUniverse); + } + #endif } void prepareArtnetPollReply(ArtPollReply *reply) { From 7abfe68458daf62477621a9d9487470233045e47 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Mon, 15 Apr 2024 16:13:13 +0200 Subject: [PATCH 13/66] Add support for TM1914 chip --- wled00/bus_wrapper.h | 194 +++++++++++++++++++++++++++------- wled00/const.h | 1 + wled00/data/settings_leds.htm | 1 + 3 files changed, 158 insertions(+), 38 deletions(-) diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index ebbeca4ad..32a5c1aae 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -74,7 +74,7 @@ #define I_8266_U1_APA106_3 82 #define I_8266_DM_APA106_3 83 #define I_8266_BB_APA106_3 84 -//WS2805 +//WS2805 (RGBCW) #define I_8266_U0_2805_5 89 #define I_8266_U1_2805_5 90 #define I_8266_DM_2805_5 91 @@ -117,10 +117,14 @@ #define I_32_RN_APA106_3 85 #define I_32_I0_APA106_3 86 #define I_32_I1_APA106_3 87 -//WS2805 +//WS2805 (RGBCW) #define I_32_RN_2805_5 93 #define I_32_I0_2805_5 94 #define I_32_I1_2805_5 95 +//TM1914 (RGB) +#define I_32_RN_TM1914_3 96 +#define I_32_I0_TM1914_3 97 +#define I_32_I1_TM1914_3 98 //APA102 @@ -170,10 +174,10 @@ #define B_8266_DM_TM1_4 NeoPixelBusLg #define B_8266_BB_TM1_4 NeoPixelBusLg //TM1829 (RGB) -#define B_8266_U0_TM2_4 NeoPixelBusLg -#define B_8266_U1_TM2_4 NeoPixelBusLg -#define B_8266_DM_TM2_4 NeoPixelBusLg -#define B_8266_BB_TM2_4 NeoPixelBusLg +#define B_8266_U0_TM2_3 NeoPixelBusLg +#define B_8266_U1_TM2_3 NeoPixelBusLg +#define B_8266_DM_TM2_3 NeoPixelBusLg +#define B_8266_BB_TM2_3 NeoPixelBusLg //UCS8903 #define B_8266_U0_UCS_3 NeoPixelBusLg //3 chan, esp8266, gpio1 #define B_8266_U1_UCS_3 NeoPixelBusLg //3 chan, esp8266, gpio2 @@ -199,6 +203,11 @@ #define B_8266_U1_2805_5 NeoPixelBusLg //esp8266, gpio2 #define B_8266_DM_2805_5 NeoPixelBusLg //esp8266, gpio3 #define B_8266_BB_2805_5 NeoPixelBusLg //esp8266, bb +//TM1914 (RGB) +#define B_8266_U0_TM1914_3 NeoPixelBusLg +#define B_8266_U1_TM1914_3 NeoPixelBusLg +#define B_8266_DM_TM1914_3 NeoPixelBusLg +#define B_8266_BB_TM1914_3 NeoPixelBusLg #endif /*** ESP32 Neopixel methods ***/ @@ -302,6 +311,16 @@ #define B_32_I1_2805_5 NeoPixelBusLg //#define B_32_I1_2805_5 NeoPixelBusLg // parallel I2S #endif +//TM1914 (RGB) +#define B_32_RN_TM1914_3 NeoPixelBusLg +#ifndef WLED_NO_I2S0_PIXELBUS +#define B_32_I0_TM1914_3 NeoPixelBusLg +//#define B_32_I0_TM1914_3 NeoPixelBusLg +#endif +#ifndef WLED_NO_I2S1_PIXELBUS +#define B_32_I1_TM1914_3 NeoPixelBusLg +//#define B_32_I1_TM1914_3 NeoPixelBusLg +#endif #endif //APA102 @@ -363,6 +382,13 @@ class PolyBus { tm1814_strip->SetPixelSettings(NeoTm1814Settings(/*R*/225, /*G*/225, /*B*/225, /*W*/225)); } + template + static void beginTM1914(void* busPtr) { + T tm1914_strip = static_cast(busPtr); + tm1914_strip->Begin(); + tm1914_strip->SetPixelSettings(NeoTm1914Settings()); //NeoTm1914_Mode_DinFdinAutoSwitch, NeoTm1914_Mode_DinOnly, NeoTm1914_Mode_FdinOnly + } + static void begin(void* busPtr, uint8_t busType, uint8_t* pins, uint16_t clock_kHz = 0U) { switch (busType) { case I_NONE: break; @@ -383,10 +409,10 @@ class PolyBus { case I_8266_U1_TM1_4: beginTM1814(busPtr); break; case I_8266_DM_TM1_4: beginTM1814(busPtr); break; case I_8266_BB_TM1_4: beginTM1814(busPtr); break; - case I_8266_U0_TM2_3: (static_cast(busPtr))->Begin(); break; - case I_8266_U1_TM2_3: (static_cast(busPtr))->Begin(); break; - case I_8266_DM_TM2_3: (static_cast(busPtr))->Begin(); break; - case I_8266_BB_TM2_3: (static_cast(busPtr))->Begin(); break; + case I_8266_U0_TM2_3: (static_cast(busPtr))->Begin(); break; + case I_8266_U1_TM2_3: (static_cast(busPtr))->Begin(); break; + case I_8266_DM_TM2_3: (static_cast(busPtr))->Begin(); break; + case I_8266_BB_TM2_3: (static_cast(busPtr))->Begin(); break; case I_HS_DOT_3: beginDotStar(busPtr, -1, -1, -1, -1, clock_kHz); break; case I_HS_LPD_3: beginDotStar(busPtr, -1, -1, -1, -1, clock_kHz); break; case I_HS_LPO_3: beginDotStar(busPtr, -1, -1, -1, -1, clock_kHz); break; @@ -412,6 +438,10 @@ class PolyBus { case I_8266_U1_2805_5: (static_cast(busPtr))->Begin(); break; case I_8266_DM_2805_5: (static_cast(busPtr))->Begin(); break; case I_8266_BB_2805_5: (static_cast(busPtr))->Begin(); break; + case I_8266_U0_TM1914_3: beginTM1914(busPtr); break; + case I_8266_U1_TM1914_3: beginTM1914(busPtr); break; + case I_8266_DM_TM1914_3: beginTM1914(busPtr); break; + case I_8266_BB_TM1914_3: beginTM1914(busPtr); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: (static_cast(busPtr))->Begin(); break; @@ -480,6 +510,13 @@ class PolyBus { #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_2805_5: (static_cast(busPtr))->Begin(); break; #endif + case I_32_RN_TM1914_3: beginTM1914(busPtr); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_TM1914_3: beginTM1914(busPtr); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_TM1914_3: beginTM1914(busPtr); break; + #endif // ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin() case I_HS_DOT_3: beginDotStar(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break; case I_HS_LPD_3: beginDotStar(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break; @@ -516,10 +553,10 @@ class PolyBus { case I_8266_U1_TM1_4: busPtr = new B_8266_U1_TM1_4(len, pins[0]); break; case I_8266_DM_TM1_4: busPtr = new B_8266_DM_TM1_4(len, pins[0]); break; case I_8266_BB_TM1_4: busPtr = new B_8266_BB_TM1_4(len, pins[0]); break; - case I_8266_U0_TM2_3: busPtr = new B_8266_U0_TM2_4(len, pins[0]); break; - case I_8266_U1_TM2_3: busPtr = new B_8266_U1_TM2_4(len, pins[0]); break; - case I_8266_DM_TM2_3: busPtr = new B_8266_DM_TM2_4(len, pins[0]); break; - case I_8266_BB_TM2_3: busPtr = new B_8266_BB_TM2_4(len, pins[0]); break; + case I_8266_U0_TM2_3: busPtr = new B_8266_U0_TM2_3(len, pins[0]); break; + case I_8266_U1_TM2_3: busPtr = new B_8266_U1_TM2_3(len, pins[0]); break; + case I_8266_DM_TM2_3: busPtr = new B_8266_DM_TM2_3(len, pins[0]); break; + case I_8266_BB_TM2_3: busPtr = new B_8266_BB_TM2_3(len, pins[0]); break; case I_8266_U0_UCS_3: busPtr = new B_8266_U0_UCS_3(len, pins[0]); break; case I_8266_U1_UCS_3: busPtr = new B_8266_U1_UCS_3(len, pins[0]); break; case I_8266_DM_UCS_3: busPtr = new B_8266_DM_UCS_3(len, pins[0]); break; @@ -540,6 +577,10 @@ class PolyBus { case I_8266_U1_2805_5: busPtr = new B_8266_U1_2805_5(len, pins[0]); break; case I_8266_DM_2805_5: busPtr = new B_8266_DM_2805_5(len, pins[0]); break; case I_8266_BB_2805_5: busPtr = new B_8266_BB_2805_5(len, pins[0]); break; + case I_8266_U0_TM1914_3: busPtr = new B_8266_U0_TM1914_3(len, pins[0]); break; + case I_8266_U1_TM1914_3: busPtr = new B_8266_U1_TM1914_3(len, pins[0]); break; + case I_8266_DM_TM1914_3: busPtr = new B_8266_DM_TM1914_3(len, pins[0]); break; + case I_8266_BB_TM1914_3: busPtr = new B_8266_BB_TM1914_3(len, pins[0]); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: busPtr = new B_32_RN_NEO_3(len, pins[0], (NeoBusChannel)channel); break; @@ -608,6 +649,13 @@ class PolyBus { #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_2805_5: busPtr = new B_32_I1_2805_5(len, pins[0]); break; #endif + case I_32_RN_TM1914_3: busPtr = new B_32_RN_TM1914_3(len, pins[0], (NeoBusChannel)channel); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_TM1914_3: busPtr = new B_32_I0_TM1914_3(len, pins[0]); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_TM1914_3: busPtr = new B_32_I1_TM1914_3(len, pins[0]); break; + #endif #endif // for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat) case I_HS_DOT_3: busPtr = new B_HS_DOT_3(len, pins[1], pins[0]); break; @@ -645,10 +693,10 @@ class PolyBus { case I_8266_U1_TM1_4: (static_cast(busPtr))->Show(consistent); break; case I_8266_DM_TM1_4: (static_cast(busPtr))->Show(consistent); break; case I_8266_BB_TM1_4: (static_cast(busPtr))->Show(consistent); break; - case I_8266_U0_TM2_3: (static_cast(busPtr))->Show(consistent); break; - case I_8266_U1_TM2_3: (static_cast(busPtr))->Show(consistent); break; - case I_8266_DM_TM2_3: (static_cast(busPtr))->Show(consistent); break; - case I_8266_BB_TM2_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U0_TM2_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U1_TM2_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_DM_TM2_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_BB_TM2_3: (static_cast(busPtr))->Show(consistent); break; case I_8266_U0_UCS_3: (static_cast(busPtr))->Show(consistent); break; case I_8266_U1_UCS_3: (static_cast(busPtr))->Show(consistent); break; case I_8266_DM_UCS_3: (static_cast(busPtr))->Show(consistent); break; @@ -669,6 +717,10 @@ class PolyBus { case I_8266_U1_2805_5: (static_cast(busPtr))->Show(consistent); break; case I_8266_DM_2805_5: (static_cast(busPtr))->Show(consistent); break; case I_8266_BB_2805_5: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U0_TM1914_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U1_TM1914_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_DM_TM1914_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_BB_TM1914_3: (static_cast(busPtr))->Show(consistent); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: (static_cast(busPtr))->Show(consistent); break; @@ -737,6 +789,13 @@ class PolyBus { #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_2805_5: (static_cast(busPtr))->Show(consistent); break; #endif + case I_32_RN_TM1914_3: (static_cast(busPtr))->Show(consistent); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_TM1914_3: (static_cast(busPtr))->Show(consistent); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_TM1914_3: (static_cast(busPtr))->Show(consistent); break; + #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->Show(consistent); break; case I_SS_DOT_3: (static_cast(busPtr))->Show(consistent); break; @@ -771,10 +830,10 @@ class PolyBus { case I_8266_U1_TM1_4: return (static_cast(busPtr))->CanShow(); break; case I_8266_DM_TM1_4: return (static_cast(busPtr))->CanShow(); break; case I_8266_BB_TM1_4: return (static_cast(busPtr))->CanShow(); break; - case I_8266_U0_TM2_3: return (static_cast(busPtr))->CanShow(); break; - case I_8266_U1_TM2_3: return (static_cast(busPtr))->CanShow(); break; - case I_8266_DM_TM2_3: return (static_cast(busPtr))->CanShow(); break; - case I_8266_BB_TM2_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U0_TM2_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U1_TM2_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_DM_TM2_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_BB_TM2_3: return (static_cast(busPtr))->CanShow(); break; case I_8266_U0_UCS_3: return (static_cast(busPtr))->CanShow(); break; case I_8266_U1_UCS_3: return (static_cast(busPtr))->CanShow(); break; case I_8266_DM_UCS_3: return (static_cast(busPtr))->CanShow(); break; @@ -794,6 +853,10 @@ class PolyBus { case I_8266_U1_2805_5: return (static_cast(busPtr))->CanShow(); break; case I_8266_DM_2805_5: return (static_cast(busPtr))->CanShow(); break; case I_8266_BB_2805_5: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U0_TM1914_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U1_TM1914_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_DM_TM1914_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_BB_TM1914_3: return (static_cast(busPtr))->CanShow(); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: return (static_cast(busPtr))->CanShow(); break; @@ -862,6 +925,13 @@ class PolyBus { #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_2805_5: return (static_cast(busPtr))->CanShow(); break; #endif + case I_32_RN_TM1914_3: return (static_cast(busPtr))->CanShow(); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_TM1914_3: return (static_cast(busPtr))->CanShow(); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_TM1914_3: return (static_cast(busPtr))->CanShow(); break; + #endif #endif case I_HS_DOT_3: return (static_cast(busPtr))->CanShow(); break; case I_SS_DOT_3: return (static_cast(busPtr))->CanShow(); break; @@ -921,10 +991,10 @@ class PolyBus { case I_8266_U1_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; case I_8266_DM_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; case I_8266_BB_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_8266_U0_TM2_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_8266_U1_TM2_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_8266_DM_TM2_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_8266_BB_TM2_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_8266_U0_TM2_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_8266_U1_TM2_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_8266_DM_TM2_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_8266_BB_TM2_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_8266_U0_UCS_3: (static_cast(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; case I_8266_U1_UCS_3: (static_cast(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; case I_8266_DM_UCS_3: (static_cast(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; @@ -945,6 +1015,10 @@ class PolyBus { case I_8266_U1_2805_5: (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; case I_8266_DM_2805_5: (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; case I_8266_BB_2805_5: (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; + case I_8266_U0_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_8266_U1_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_8266_DM_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_8266_BB_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; @@ -1013,6 +1087,13 @@ class PolyBus { #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_2805_5: (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; #endif + case I_32_RN_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_SS_DOT_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; @@ -1047,10 +1128,10 @@ class PolyBus { case I_8266_U1_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; case I_8266_DM_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; case I_8266_BB_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; - case I_8266_U0_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_8266_U1_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_8266_DM_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_8266_BB_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U0_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U1_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_DM_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_BB_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; case I_8266_U0_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; case I_8266_U1_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; case I_8266_DM_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; @@ -1071,6 +1152,10 @@ class PolyBus { case I_8266_U1_2805_5: (static_cast(busPtr))->SetLuminance(b); break; case I_8266_DM_2805_5: (static_cast(busPtr))->SetLuminance(b); break; case I_8266_BB_2805_5: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U0_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U1_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_DM_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_BB_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: (static_cast(busPtr))->SetLuminance(b); break; @@ -1139,6 +1224,13 @@ class PolyBus { #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_2805_5: (static_cast(busPtr))->SetLuminance(b); break; #endif + case I_32_RN_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; + #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->SetLuminance(b); break; case I_SS_DOT_3: (static_cast(busPtr))->SetLuminance(b); break; @@ -1174,10 +1266,10 @@ class PolyBus { case I_8266_U1_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; case I_8266_DM_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; case I_8266_BB_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; - case I_8266_U0_TM2_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; - case I_8266_U1_TM2_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; - case I_8266_DM_TM2_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; - case I_8266_BB_TM2_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_U0_TM2_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_U1_TM2_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_DM_TM2_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_BB_TM2_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; case I_8266_U0_UCS_3: { Rgb48Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,0); } break; case I_8266_U1_UCS_3: { Rgb48Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,0); } break; case I_8266_DM_UCS_3: { Rgb48Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,0); } break; @@ -1198,6 +1290,10 @@ class PolyBus { case I_8266_U1_2805_5: { RgbwwColor c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W case I_8266_DM_2805_5: { RgbwwColor c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W case I_8266_BB_2805_5: { RgbwwColor c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W + case I_8266_U0_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_U1_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_DM_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_BB_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; @@ -1266,6 +1362,13 @@ class PolyBus { #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_2805_5: { RgbwwColor c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W #endif + case I_32_RN_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + #endif #endif case I_HS_DOT_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; case I_SS_DOT_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; @@ -1319,10 +1422,10 @@ class PolyBus { case I_8266_U1_TM1_4: delete (static_cast(busPtr)); break; case I_8266_DM_TM1_4: delete (static_cast(busPtr)); break; case I_8266_BB_TM1_4: delete (static_cast(busPtr)); break; - case I_8266_U0_TM2_3: delete (static_cast(busPtr)); break; - case I_8266_U1_TM2_3: delete (static_cast(busPtr)); break; - case I_8266_DM_TM2_3: delete (static_cast(busPtr)); break; - case I_8266_BB_TM2_3: delete (static_cast(busPtr)); break; + case I_8266_U0_TM2_3: delete (static_cast(busPtr)); break; + case I_8266_U1_TM2_3: delete (static_cast(busPtr)); break; + case I_8266_DM_TM2_3: delete (static_cast(busPtr)); break; + case I_8266_BB_TM2_3: delete (static_cast(busPtr)); break; case I_8266_U0_UCS_3: delete (static_cast(busPtr)); break; case I_8266_U1_UCS_3: delete (static_cast(busPtr)); break; case I_8266_DM_UCS_3: delete (static_cast(busPtr)); break; @@ -1343,6 +1446,10 @@ class PolyBus { case I_8266_U1_2805_5: delete (static_cast(busPtr)); break; case I_8266_DM_2805_5: delete (static_cast(busPtr)); break; case I_8266_BB_2805_5: delete (static_cast(busPtr)); break; + case I_8266_U0_TM1914_3: delete (static_cast(busPtr)); break; + case I_8266_U1_TM1914_3: delete (static_cast(busPtr)); break; + case I_8266_DM_TM1914_3: delete (static_cast(busPtr)); break; + case I_8266_BB_TM1914_3: delete (static_cast(busPtr)); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: delete (static_cast(busPtr)); break; @@ -1411,6 +1518,13 @@ class PolyBus { #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_2805_5: delete (static_cast(busPtr)); break; #endif + case I_32_RN_TM1914_3: delete (static_cast(busPtr)); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_TM1914_3: delete (static_cast(busPtr)); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_TM1914_3: delete (static_cast(busPtr)); break; + #endif #endif case I_HS_DOT_3: delete (static_cast(busPtr)); break; case I_SS_DOT_3: delete (static_cast(busPtr)); break; @@ -1476,6 +1590,8 @@ class PolyBus { return I_8266_U0_FW6_5 + offset; case TYPE_WS2805: return I_8266_U0_2805_5 + offset; + case TYPE_TM1914: + return I_8266_U0_TM1914_3 + offset; } #else //ESP32 uint8_t offset = 0; // 0 = RMT (num 1-8), 1 = I2S0 (used by Audioreactive), 2 = I2S1 @@ -1521,6 +1637,8 @@ class PolyBus { return I_32_RN_FW6_5 + offset; case TYPE_WS2805: return I_32_RN_2805_5 + offset; + case TYPE_TM1914: + return I_32_RN_TM1914_3 + offset; } #endif } diff --git a/wled00/const.h b/wled00/const.h index 0ce7b27d5..e0509824f 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -268,6 +268,7 @@ #define TYPE_SK6812_RGBW 30 #define TYPE_TM1814 31 #define TYPE_WS2805 32 //RGB + WW + CW +#define TYPE_TM1914 33 //RGB //"Analog" types (40-47) #define TYPE_ONOFF 40 //binary output (relays etc.; NOT PWM) #define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 4ad4cb16e..1ab3374a0 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -386,6 +386,7 @@ ${i+1}: \ \ \ +\ \ \ \ From 6d1410741d4c3f2d080b9ec12d7ffa7e0a2e4d8c Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 17 Apr 2024 19:00:16 +0200 Subject: [PATCH 14/66] Fix 8266 compile --- wled00/bus_wrapper.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 32a5c1aae..966a391c3 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -79,6 +79,11 @@ #define I_8266_U1_2805_5 90 #define I_8266_DM_2805_5 91 #define I_8266_BB_2805_5 92 +//TM1914 (RGB) +#define I_8266_U0_TM1914_3 99 +#define I_8266_U1_TM1914_3 100 +#define I_8266_DM_TM1914_3 101 +#define I_8266_BB_TM1914_3 102 /*** ESP32 Neopixel methods ***/ //RGB From 6276c2f1f5db493e2db47b85dfbeda018a1faa22 Mon Sep 17 00:00:00 2001 From: gaaat Date: Fri, 26 Apr 2024 16:39:32 +0200 Subject: [PATCH 15/66] improved brightness change via long button presses --- wled00/button.cpp | 26 +++++++++++++++++++++----- wled00/wled.h | 1 + 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/wled00/button.cpp b/wled00/button.cpp index 3b73df81d..296be8090 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -7,9 +7,10 @@ #define WLED_DEBOUNCE_THRESHOLD 50 // only consider button input of at least 50ms as valid (debouncing) #define WLED_LONG_PRESS 600 // long press if button is released after held for at least 600ms #define WLED_DOUBLE_PRESS 350 // double press if another press within 350ms after a short press -#define WLED_LONG_REPEATED_ACTION 300 // how often a repeated action (e.g. dimming) is fired on long press on button IDs >0 +#define WLED_LONG_REPEATED_ACTION 400 // how often a repeated action (e.g. dimming) is fired on long press on button IDs >0 #define WLED_LONG_AP 5000 // how long button 0 needs to be held to activate WLED-AP #define WLED_LONG_FACTORY_RESET 10000 // how long button 0 needs to be held to trigger a factory reset +#define WLED_LONG_BRI_STEPS 16 // how long to wait before increasing/decreasing brightness on long press static const char _mqtt_topic_button[] PROGMEM = "%s/button/%d"; // optimize flash usage @@ -39,7 +40,20 @@ void longPressAction(uint8_t b) if (!macroLongPress[b]) { switch (b) { case 0: setRandomColor(col); colorUpdated(CALL_MODE_BUTTON); break; - case 1: bri += 8; stateUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action + case 1: + // increase bri on true, decrease on false + if(buttonBriDirection) { + if (bri == 255) break; // avoid unnecessary updates to brightness + if (bri >= 255 - WLED_LONG_BRI_STEPS) bri = 255; + else bri += WLED_LONG_BRI_STEPS; + } else { + if (bri == 1) break; // avoid unnecessary updates to brightness + if (bri <= WLED_LONG_BRI_STEPS) bri = 1; + else bri -= WLED_LONG_BRI_STEPS; + } + stateUpdated(CALL_MODE_BUTTON); + buttonPressedTime[b] = millis(); + break; // repeatable action } } else { applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET); @@ -284,10 +298,12 @@ void handleButton() buttonPressedBefore[b] = true; if (now - buttonPressedTime[b] > WLED_LONG_PRESS) { //long press - if (!buttonLongPressed[b]) longPressAction(b); - else if (b) { //repeatable action (~3 times per s) on button > 0 + if (!buttonLongPressed[b]) { + buttonBriDirection = !buttonBriDirection; //toggle brightness direction on long press longPressAction(b); - buttonPressedTime[b] = now - WLED_LONG_REPEATED_ACTION; //333ms + } else if (b) { //repeatable action (~5 times per s) on button > 0 + longPressAction(b); + buttonPressedTime[b] = now - WLED_LONG_REPEATED_ACTION; //200ms } buttonLongPressed[b] = true; } diff --git a/wled00/wled.h b/wled00/wled.h index 139c451f8..18eb17b7c 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -594,6 +594,7 @@ WLED_GLOBAL bool buttonPressedBefore[WLED_MAX_BUTTONS] _INIT({false}); WLED_GLOBAL bool buttonLongPressed[WLED_MAX_BUTTONS] _INIT({false}); WLED_GLOBAL unsigned long buttonPressedTime[WLED_MAX_BUTTONS] _INIT({0}); WLED_GLOBAL unsigned long buttonWaitTime[WLED_MAX_BUTTONS] _INIT({0}); +WLED_GLOBAL bool buttonBriDirection _INIT(false); WLED_GLOBAL bool disablePullUp _INIT(false); WLED_GLOBAL byte touchThreshold _INIT(TOUCH_THRESHOLD); From bdd4d9f3ffd2db6d259d9ddb24cb7ad8b98ca1c3 Mon Sep 17 00:00:00 2001 From: gaaat98 <67930088+gaaat98@users.noreply.github.com> Date: Fri, 26 Apr 2024 18:23:34 +0200 Subject: [PATCH 16/66] set buttonBriDirection as local static --- wled00/button.cpp | 2 +- wled00/wled.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/wled00/button.cpp b/wled00/button.cpp index 296be8090..1cd8245c8 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -13,6 +13,7 @@ #define WLED_LONG_BRI_STEPS 16 // how long to wait before increasing/decreasing brightness on long press static const char _mqtt_topic_button[] PROGMEM = "%s/button/%d"; // optimize flash usage +static bool buttonBriDirection = false; // true: increase brightness, false: decrease brightness void shortPressAction(uint8_t b) { @@ -41,7 +42,6 @@ void longPressAction(uint8_t b) switch (b) { case 0: setRandomColor(col); colorUpdated(CALL_MODE_BUTTON); break; case 1: - // increase bri on true, decrease on false if(buttonBriDirection) { if (bri == 255) break; // avoid unnecessary updates to brightness if (bri >= 255 - WLED_LONG_BRI_STEPS) bri = 255; diff --git a/wled00/wled.h b/wled00/wled.h index 18eb17b7c..139c451f8 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -594,7 +594,6 @@ WLED_GLOBAL bool buttonPressedBefore[WLED_MAX_BUTTONS] _INIT({false}); WLED_GLOBAL bool buttonLongPressed[WLED_MAX_BUTTONS] _INIT({false}); WLED_GLOBAL unsigned long buttonPressedTime[WLED_MAX_BUTTONS] _INIT({0}); WLED_GLOBAL unsigned long buttonWaitTime[WLED_MAX_BUTTONS] _INIT({0}); -WLED_GLOBAL bool buttonBriDirection _INIT(false); WLED_GLOBAL bool disablePullUp _INIT(false); WLED_GLOBAL byte touchThreshold _INIT(TOUCH_THRESHOLD); From 25dd43b949176a99c19d43ca1bc7b53474754708 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 26 Apr 2024 23:49:34 +0200 Subject: [PATCH 17/66] Bugfix for bugfix - thanks @softhack007 --- wled00/bus_wrapper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index c48946eb8..efaad7c42 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -499,7 +499,7 @@ class PolyBus { #if defined(ARDUINO_ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)) // NOTE: "channel" is only used on ESP32 (and its variants) for RMT channel allocation // since 0.15.0-b3 I2S1 is favoured for classic ESP32 and moved to position 0 (channel 0) so we need to subtract 1 for correct RMT allocation - if (channel > 1) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32 + if (channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32 #endif void* busPtr = nullptr; switch (busType) { From d7e0b364d16b6474aed0d893d60e95f34a669fc0 Mon Sep 17 00:00:00 2001 From: gaaat98 <67930088+gaaat98@users.noreply.github.com> Date: Sat, 27 Apr 2024 12:25:34 +0200 Subject: [PATCH 18/66] fixed wrong comment --- wled00/button.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/button.cpp b/wled00/button.cpp index 1cd8245c8..6d69f15f8 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -10,7 +10,7 @@ #define WLED_LONG_REPEATED_ACTION 400 // how often a repeated action (e.g. dimming) is fired on long press on button IDs >0 #define WLED_LONG_AP 5000 // how long button 0 needs to be held to activate WLED-AP #define WLED_LONG_FACTORY_RESET 10000 // how long button 0 needs to be held to trigger a factory reset -#define WLED_LONG_BRI_STEPS 16 // how long to wait before increasing/decreasing brightness on long press +#define WLED_LONG_BRI_STEPS 16 // how much to increase/decrease the brightness with each long press repetition static const char _mqtt_topic_button[] PROGMEM = "%s/button/%d"; // optimize flash usage static bool buttonBriDirection = false; // true: increase brightness, false: decrease brightness From 1048bf993af9693c7b795f5e2ccb4db404636616 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sat, 27 Apr 2024 23:34:35 +0200 Subject: [PATCH 19/66] use lolin_s3_mini for esp32-S3 4MB buildenv --- platformio.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 8d9109c02..76c4c92d6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -471,8 +471,7 @@ monitor_filters = esp32_exception_decoder [env:esp32s3_4M_qspi] ;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi) -board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support -board_build.arduino.memory_type = qio_qspi ;; use with PSRAM: 2MB or 4MB +board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 From 9f99a1896df5e1439d328ab974d89f18bd5ac37e Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 29 Apr 2024 16:05:12 +0200 Subject: [PATCH 20/66] presets.json PSRAM caching: consider cacheInvalidate * trying to make the caching mechanism bulletproof. `cacheInvalidate` is changed when - autosave usermod updates presets - a file was upload * (coding style) fixed some unitialized variables --- wled00/file.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/wled00/file.cpp b/wled00/file.cpp index eae50ff1d..814aa77e6 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -381,11 +381,15 @@ void updateFSInfo() { // original idea by @akaricchi (https://github.com/Akaricchi) // returns a pointer to the PSRAM buffer, updates size parameter static const uint8_t *getPresetCache(size_t &size) { - static unsigned long presetsCachedTime; - static uint8_t *presetsCached; - static size_t presetsCachedSize; + static unsigned long presetsCachedTime = 0; + static uint8_t *presetsCached = nullptr; + static size_t presetsCachedSize = 0; + static byte presetsCachedValidate = 0; - if (presetsModifiedTime != presetsCachedTime) { + //if (presetsModifiedTime != presetsCachedTime) DEBUG_PRINTLN(F("getPresetCache(): presetsModifiedTime changed.")); + //if (presetsCachedValidate != cacheInvalidate) DEBUG_PRINTLN(F("getPresetCache(): cacheInvalidate changed.")); + + if ((presetsModifiedTime != presetsCachedTime) || (presetsCachedValidate != cacheInvalidate)) { if (presetsCached) { free(presetsCached); presetsCached = nullptr; @@ -396,6 +400,7 @@ static const uint8_t *getPresetCache(size_t &size) { File file = WLED_FS.open(FPSTR(getPresetsFileName()), "r"); if (file) { presetsCachedTime = presetsModifiedTime; + presetsCachedValidate = cacheInvalidate; presetsCachedSize = 0; presetsCached = (uint8_t*)ps_malloc(file.size() + 1); if (presetsCached) { From 74bc159a522a14f947e2b66288996a20a2e229e5 Mon Sep 17 00:00:00 2001 From: gaaat Date: Mon, 29 Apr 2024 20:19:10 +0200 Subject: [PATCH 21/66] enabled some audioreactive effects for single pixel strips/segments --- wled00/FX.cpp | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 5592f7ba8..3110ab910 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -6643,7 +6643,7 @@ static const char _data_FX_MODE_GRAVIMETER[] PROGMEM = "Gravimeter@Rate of fall, // * JUGGLES // ////////////////////// uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. - if (SEGLEN == 1) return mode_static(); + //if (SEGLEN == 1) return mode_static(); um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { // add support for no audio @@ -6655,12 +6655,13 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. uint16_t my_sampleAgc = fmax(fmin(volumeSmth, 255.0), 0); for (size_t i=0; i Date: Tue, 30 Apr 2024 14:09:12 +0200 Subject: [PATCH 22/66] using brightness in analog clock overlay --- wled00/overlay.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/wled00/overlay.cpp b/wled00/overlay.cpp index 19b26c224..92d8820e3 100644 --- a/wled00/overlay.cpp +++ b/wled00/overlay.cpp @@ -11,6 +11,7 @@ void _overlayAnalogClock() { _overlayAnalogCountdown(); return; } + uint8_t brightness = strip.getBrightness(); float hourP = ((float)(hour(localTime)%12))/12.0f; float minuteP = ((float)minute(localTime))/60.0f; hourP = hourP + minuteP/12.0f; @@ -25,11 +26,11 @@ void _overlayAnalogClock() { if (secondPixel < analogClock12pixel) { - strip.setRange(analogClock12pixel, overlayMax, 0xFF0000); - strip.setRange(overlayMin, secondPixel, 0xFF0000); + strip.setRange(analogClock12pixel, overlayMax, (uint32_t)brightness<<16); + strip.setRange(overlayMin, secondPixel, (uint32_t)brightness<<16); } else { - strip.setRange(analogClock12pixel, secondPixel, 0xFF0000); + strip.setRange(analogClock12pixel, secondPixel, (uint32_t)brightness<<16); } } if (analogClock5MinuteMarks) @@ -38,12 +39,12 @@ void _overlayAnalogClock() { unsigned pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i); if (pix > overlayMax) pix -= overlaySize; - strip.setPixelColor(pix, 0x00FFAA); + strip.setPixelColor(pix, ((uint32_t)brightness<<8)|((uint32_t)brightness*2/3)); } } - if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, 0xFF0000); - strip.setPixelColor(minutePixel, 0x00FF00); - strip.setPixelColor(hourPixel, 0x0000FF); + if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, (uint32_t)brightness<<16); + strip.setPixelColor(minutePixel, (uint32_t)brightness<<8); + strip.setPixelColor(hourPixel, (uint32_t)brightness); } From bd69c24231153912e97ff31be399dcedd34567a5 Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Tue, 30 Apr 2024 14:54:53 +0200 Subject: [PATCH 23/66] intermediate update --- usermods/Battery/battery_defaults.h | 1 + usermods/Battery/readme.md | 5 +++++ usermods/Battery/types/lion.h | 3 +-- usermods/Battery/types/lipo.h | 3 +-- usermods/Battery/types/unkown.h | 3 +-- usermods/Battery/usermod_v2_Battery.h | 6 ++---- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h index 6d0a95dc4..ea01e8620 100644 --- a/usermods/Battery/battery_defaults.h +++ b/usermods/Battery/battery_defaults.h @@ -111,6 +111,7 @@ #define USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION 5 #endif +// battery types typedef enum { unknown=0, diff --git a/usermods/Battery/readme.md b/usermods/Battery/readme.md index 1ca229763..e82378084 100644 --- a/usermods/Battery/readme.md +++ b/usermods/Battery/readme.md @@ -86,6 +86,11 @@ Specification from: [Molicel INR18650-M35A, 3500mAh 10A Lithium-ion battery, 3. ## 📝 Change Log +2024-04-30 + +- integrate factory pattern to make it easier to add other / custom battery types +- update readme + 2023-01-04 - basic support for LiPo rechargeable batteries ( `-D USERMOD_BATTERY_USE_LIPO`) diff --git a/usermods/Battery/types/lion.h b/usermods/Battery/types/lion.h index 0d2325386..b3641e263 100644 --- a/usermods/Battery/types/lion.h +++ b/usermods/Battery/types/lion.h @@ -13,8 +13,7 @@ class Lion : public Battery private: public: - Lion() - : Battery() + Lion() : Battery() { this->setMinVoltage(USERMOD_BATTERY_LION_MIN_VOLTAGE); this->setMaxVoltage(USERMOD_BATTERY_LION_MAX_VOLTAGE); diff --git a/usermods/Battery/types/lipo.h b/usermods/Battery/types/lipo.h index f65ab12c5..1deb6e7d3 100644 --- a/usermods/Battery/types/lipo.h +++ b/usermods/Battery/types/lipo.h @@ -13,8 +13,7 @@ class Lipo : public Battery private: public: - Lipo() - : Battery() + Lipo() : Battery() { this->setMinVoltage(USERMOD_BATTERY_LIPO_MIN_VOLTAGE); this->setMaxVoltage(USERMOD_BATTERY_LIPO_MAX_VOLTAGE); diff --git a/usermods/Battery/types/unkown.h b/usermods/Battery/types/unkown.h index edf220040..32a1bfe42 100644 --- a/usermods/Battery/types/unkown.h +++ b/usermods/Battery/types/unkown.h @@ -13,8 +13,7 @@ class Unkown : public Battery private: public: - Unkown() - : Battery() + Unkown() : Battery() { this->setMinVoltage(USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE); this->setMaxVoltage(USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE); diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index 9b980d557..a82a46667 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -9,9 +9,8 @@ /* * Usermod by Maximilian Mewes - * Mail: mewes.maximilian@gmx.de - * GitHub: itCarl - * Date: 25.12.2022 + * E-mail: mewes.maximilian@gmx.de + * Created at: 25.12.2022 * If you have any questions, please feel free to contact me. */ class UsermodBattery : public Usermod @@ -140,7 +139,6 @@ class UsermodBattery : public Usermod } #else //ESP8266 boards have only one analog input pin A0 pinMode(batteryPin, INPUT); - // voltage = readVoltage(); #endif // plug in the right battery type From a13f1a9bee52ad637cf6903546f1bac4ef3df3da Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Tue, 30 Apr 2024 15:24:02 +0200 Subject: [PATCH 24/66] bug fixes --- usermods/Battery/battery.h | 61 +++++++++++++++------------ usermods/Battery/types/lion.h | 8 ---- usermods/Battery/types/lipo.h | 8 ---- usermods/Battery/usermod_v2_Battery.h | 43 ++++++++++++++++++- 4 files changed, 75 insertions(+), 45 deletions(-) diff --git a/usermods/Battery/battery.h b/usermods/Battery/battery.h index 4cdfb035f..084e6c0aa 100644 --- a/usermods/Battery/battery.h +++ b/usermods/Battery/battery.h @@ -32,7 +32,14 @@ class Battery this->setCalibration(USERMOD_BATTERY_CALIBRATION); } - virtual void update(batteryConfig cfg) = 0; + virtual void update(batteryConfig cfg) + { + if(cfg.minVoltage) this->setMinVoltage(cfg.minVoltage); + if(cfg.maxVoltage) this->setMaxVoltage(cfg.maxVoltage); + if(cfg.level) this->setLevel(cfg.level); + if(cfg.calibration) this->setCalibration(cfg.calibration); + if(cfg.voltageMultiplier) this->setVoltageMultiplier(cfg.voltageMultiplier); + } /** * Corresponding battery curves @@ -49,10 +56,10 @@ class Battery /* - * - * Getter and Setter - * - */ + * + * Getter and Setter + * + */ /* * Get lowest configured battery voltage @@ -63,26 +70,26 @@ class Battery } /* - * Set lowest battery voltage - * can't be below 0 volt - */ + * Set lowest battery voltage + * can't be below 0 volt + */ virtual void setMinVoltage(float voltage) { this->minVoltage = max(0.0f, voltage); } /* - * Get highest configured battery voltage - */ + * Get highest configured battery voltage + */ virtual float getMaxVoltage() { return this->maxVoltage; } /* - * Set highest battery voltage - * can't be below minVoltage - */ + * Set highest battery voltage + * can't be below minVoltage + */ virtual void setMaxVoltage(float voltage) { this->maxVoltage = max(getMinVoltage()+.5f, voltage); @@ -110,43 +117,43 @@ class Battery void setLevel(float level) { - this->level = constrain(level, 0.0f, 110.0f);; + this->level = constrain(level, 0.0f, 110.0f); } /* - * Get the configured calibration value - * a offset value to fine-tune the calculated voltage. - */ + * Get the configured calibration value + * a offset value to fine-tune the calculated voltage. + */ virtual float getCalibration() { return calibration; } /* - * Set the voltage calibration offset value - * a offset value to fine-tune the calculated voltage. - */ + * Set the voltage calibration offset value + * a offset value to fine-tune the calculated voltage. + */ virtual void setCalibration(float offset) { calibration = offset; } /* - * Get the configured calibration value - * a value to set the voltage divider ratio - */ + * Get the configured calibration value + * a value to set the voltage divider ratio + */ virtual float getVoltageMultiplier() { return voltageMultiplier; } /* - * Set the voltage multiplier value - * a value to set the voltage divider ratio. - */ + * Set the voltage multiplier value + * a value to set the voltage divider ratio. + */ virtual void setVoltageMultiplier(float multiplier) { - voltageMultiplier = voltageMultiplier; + voltageMultiplier = multiplier; } }; diff --git a/usermods/Battery/types/lion.h b/usermods/Battery/types/lion.h index b3641e263..e77266164 100644 --- a/usermods/Battery/types/lion.h +++ b/usermods/Battery/types/lion.h @@ -19,14 +19,6 @@ class Lion : public Battery this->setMaxVoltage(USERMOD_BATTERY_LION_MAX_VOLTAGE); } - void update(batteryConfig cfg) - { - if(cfg.minVoltage) this->setMinVoltage(cfg.minVoltage); - if(cfg.maxVoltage) this->setMaxVoltage(cfg.maxVoltage); - if(cfg.level) this->setLevel(cfg.level); - if(cfg.calibration) this->setCalibration(cfg.calibration); - } - float mapVoltage(float v, float min, float max) override { return this->linearMapping(v, min, max); // basic mapping diff --git a/usermods/Battery/types/lipo.h b/usermods/Battery/types/lipo.h index 1deb6e7d3..d732cf4da 100644 --- a/usermods/Battery/types/lipo.h +++ b/usermods/Battery/types/lipo.h @@ -19,14 +19,6 @@ class Lipo : public Battery this->setMaxVoltage(USERMOD_BATTERY_LIPO_MAX_VOLTAGE); } - void update(batteryConfig cfg) - { - if(cfg.minVoltage) this->setMinVoltage(cfg.minVoltage); - if(cfg.maxVoltage) this->setMaxVoltage(cfg.maxVoltage); - if(cfg.level) this->setLevel(cfg.level); - if(cfg.calibration) this->setCalibration(cfg.calibration); - } - /** * LiPo batteries have a differnt discharge curve, see * https://blog.ampow.com/lipo-voltage-chart/ diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index a82a46667..b9631d6db 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -264,6 +264,7 @@ class UsermodBattery : public Usermod battery[F("min-voltage")] = bat->getMinVoltage(); battery[F("max-voltage")] = bat->getMaxVoltage(); battery[F("calibration")] = bat->getCalibration(); + battery[F("voltage-multiplier")] = bat->getVoltageMultiplier(); battery[FPSTR(_readInterval)] = readingInterval; JsonObject ao = battery.createNestedObject(F("auto-off")); // auto off section @@ -283,6 +284,7 @@ class UsermodBattery : public Usermod getJsonValue(battery[F("min-voltage")], cfg.minVoltage); getJsonValue(battery[F("max-voltage")], cfg.maxVoltage); getJsonValue(battery[F("calibration")], cfg.calibration); + getJsonValue(battery[F("voltage-multiplier")], cfg.voltageMultiplier); setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); @@ -459,6 +461,7 @@ class UsermodBattery : public Usermod setMinBatteryVoltage(battery[F("min-voltage")] | bat->getMinVoltage()); setMaxBatteryVoltage(battery[F("max-voltage")] | bat->getMaxVoltage()); setCalibration(battery[F("calibration")] | calibration); + setVoltageMultiplier(battery[F("voltage-multiplier")] | voltageMultiplier); setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); getUsermodConfigFromJsonObject(battery); @@ -537,7 +540,25 @@ class UsermodBattery : public Usermod return USERMOD_ID_BATTERY; } + /** + * get currently active battery type + */ + batteryType getBatteryType() + { + return cfg.type; + } + /** + * Set currently active battery type + */ + batteryType setBatteryType(batteryType type) + { + cfg.type = type; + } + + /** + * + */ unsigned long getReadingInterval() { return readingInterval; @@ -561,7 +582,7 @@ class UsermodBattery : public Usermod /** * Set lowest battery voltage - * cant be below 0 volt + * can't be below 0 volt */ void setMinBatteryVoltage(float voltage) { @@ -622,6 +643,24 @@ class UsermodBattery : public Usermod bat->setCalibration(offset); } + /** + * Set the voltage multiplier value + * A multiplier that may need adjusting for different voltage divider setups + */ + void setVoltageMultiplier(float multiplier) + { + bat->setVoltageMultiplier(multiplier); + } + + /* + * Get the voltage multiplier value + * A multiplier that may need adjusting for different voltage divider setups + */ + float getVoltageMultiplier() + { + return bat->getVoltageMultiplier(); + } + /** * Get auto-off feature enabled status * is auto-off enabled, true/false @@ -727,7 +766,7 @@ class UsermodBattery : public Usermod } /** - * Get low-power-indicator status when the indication is done thsi returns true + * Get low-power-indicator status when the indication is done this returns true */ bool getLowPowerIndicatorDone() { From ff10130176ff06a81ed09113b6669703583a3c71 Mon Sep 17 00:00:00 2001 From: Woody Date: Tue, 30 Apr 2024 16:53:47 +0200 Subject: [PATCH 25/66] Fix resizing bug The bug was that when resizing the window, it always jumped to the Colors tab instead of staying on the currently selected tab. --- wled00/data/index.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wled00/data/index.js b/wled00/data/index.js index bbf6bd109..9f8c579d0 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -304,7 +304,6 @@ function updateTablinks(tabI) { var tablinks = gEBCN("tablinks"); for (var i of tablinks) i.classList.remove('active'); - if (pcMode) return; tablinks[tabI].classList.add('active'); } @@ -3047,12 +3046,11 @@ function togglePcMode(fromB = false) if (fromB) { pcModeA = !pcModeA; localStorage.setItem('pcm', pcModeA); + openTab(0, true); } pcMode = (wW >= 1024) && pcModeA; if (cpick) cpick.resize(pcMode && wW>1023 && wW<1250 ? 230 : 260); // for tablet in landscape if (!fromB && ((wW < 1024 && lastw < 1024) || (wW >= 1024 && lastw >= 1024))) return; // no change in size and called from size() - openTab(0, true); - updateTablinks(0); gId('buttonPcm').className = (pcMode) ? "active":""; gId('bot').style.height = (pcMode && !cfg.comp.pcmbot) ? "0":"auto"; sCol('--bh', gId('bot').clientHeight + "px"); From 2245ee6fce23343cacfd6cd424a6339be0f1fada Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Tue, 30 Apr 2024 17:02:57 +0200 Subject: [PATCH 26/66] bugfixes --- usermods/Battery/battery.h | 9 +++++---- usermods/Battery/usermod_v2_Battery.h | 18 ++++-------------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/usermods/Battery/battery.h b/usermods/Battery/battery.h index 084e6c0aa..31e2e0755 100644 --- a/usermods/Battery/battery.h +++ b/usermods/Battery/battery.h @@ -27,7 +27,7 @@ class Battery public: Battery() { - this->setVoltage(this->getVoltage()); + this->setVoltage(USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE); this->setVoltageMultiplier(USERMOD_BATTERY_VOLTAGE_MULTIPLIER); this->setCalibration(USERMOD_BATTERY_CALIBRATION); } @@ -105,9 +105,10 @@ class Battery */ void setVoltage(float voltage) { - this->voltage = ( (voltage < this->getMinVoltage() * 0.85f) || (voltage > this->getMaxVoltage() * 1.1f) ) - ? -1.0f - : voltage; + // this->voltage = ( (voltage < this->getMinVoltage() * 0.85f) || (voltage > this->getMaxVoltage() * 1.1f) ) + // ? -1.0f + // : voltage; + this->voltage = voltage; } float getLevel() diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index b9631d6db..31c31f066 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -28,8 +28,6 @@ class UsermodBattery : public Usermod unsigned long lastReadTime = 0; // between 0 and 1, to control strength of voltage smoothing filter float alpha = USERMOD_BATTERY_AVERAGING_ALPHA; - // offset or calibration value to fine tune the calculated voltage - float calibration = USERMOD_BATTERY_CALIBRATION; // auto shutdown/shutoff/master off feature bool autoOffEnabled = USERMOD_BATTERY_AUTO_OFF_ENABLED; @@ -45,6 +43,7 @@ class UsermodBattery : public Usermod unsigned long lowPowerActivationTime = 0; // used temporary during active time uint8_t lastPreset = 0; + // bool initDone = false; bool initializing = true; @@ -311,9 +310,8 @@ class UsermodBattery : public Usermod { JsonObject battery = root.createNestedObject(FPSTR(_name)); - if (battery.isNull()) { + if (battery.isNull()) battery = root.createNestedObject(FPSTR(_name)); - } addBatteryToJsonObject(battery, true); @@ -460,8 +458,8 @@ class UsermodBattery : public Usermod // calculateTimeLeftEnabled = battery[F("time-left")] | calculateTimeLeftEnabled; setMinBatteryVoltage(battery[F("min-voltage")] | bat->getMinVoltage()); setMaxBatteryVoltage(battery[F("max-voltage")] | bat->getMaxVoltage()); - setCalibration(battery[F("calibration")] | calibration); - setVoltageMultiplier(battery[F("voltage-multiplier")] | voltageMultiplier); + setCalibration(battery[F("calibration")] | bat->getCalibration()); + setVoltageMultiplier(battery[F("voltage-multiplier")] | bat->getVoltageMultiplier()); setReadingInterval(battery[FPSTR(_readInterval)] | readingInterval); getUsermodConfigFromJsonObject(battery); @@ -548,14 +546,6 @@ class UsermodBattery : public Usermod return cfg.type; } - /** - * Set currently active battery type - */ - batteryType setBatteryType(batteryType type) - { - cfg.type = type; - } - /** * */ From fd9570e7826b53a0c59440179bd340f195d0bb6a Mon Sep 17 00:00:00 2001 From: Pasquale Pizzuti Date: Tue, 30 Apr 2024 17:52:35 +0200 Subject: [PATCH 27/66] using color_fade --- wled00/overlay.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/wled00/overlay.cpp b/wled00/overlay.cpp index 92d8820e3..cd0c04c04 100644 --- a/wled00/overlay.cpp +++ b/wled00/overlay.cpp @@ -26,11 +26,11 @@ void _overlayAnalogClock() { if (secondPixel < analogClock12pixel) { - strip.setRange(analogClock12pixel, overlayMax, (uint32_t)brightness<<16); - strip.setRange(overlayMin, secondPixel, (uint32_t)brightness<<16); + strip.setRange(analogClock12pixel, overlayMax, color_fade(0xFF0000, brightness)); + strip.setRange(overlayMin, secondPixel, color_fade(0xFF0000, brightness)); } else { - strip.setRange(analogClock12pixel, secondPixel, (uint32_t)brightness<<16); + strip.setRange(analogClock12pixel, secondPixel, color_fade(0xFF0000, brightness)); } } if (analogClock5MinuteMarks) @@ -39,12 +39,12 @@ void _overlayAnalogClock() { unsigned pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i); if (pix > overlayMax) pix -= overlaySize; - strip.setPixelColor(pix, ((uint32_t)brightness<<8)|((uint32_t)brightness*2/3)); + strip.setPixelColor(pix, color_fade(0x00FFAA, brightness)); } } - if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, (uint32_t)brightness<<16); - strip.setPixelColor(minutePixel, (uint32_t)brightness<<8); - strip.setPixelColor(hourPixel, (uint32_t)brightness); + if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, color_fade(0xFF0000, brightness)); + strip.setPixelColor(minutePixel, color_fade(0x00FF00, brightness)); + strip.setPixelColor(hourPixel, color_fade(0x0000FF, brightness)); } From 05a8c692f29f2439a96027433ee6440f71a84c7b Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Tue, 30 Apr 2024 18:11:18 +0200 Subject: [PATCH 28/66] read initial voltage correctly --- usermods/Battery/battery.h | 1 - usermods/Battery/usermod_v2_Battery.h | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/usermods/Battery/battery.h b/usermods/Battery/battery.h index 31e2e0755..2ddd84149 100644 --- a/usermods/Battery/battery.h +++ b/usermods/Battery/battery.h @@ -27,7 +27,6 @@ class Battery public: Battery() { - this->setVoltage(USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE); this->setVoltageMultiplier(USERMOD_BATTERY_VOLTAGE_MULTIPLIER); this->setCalibration(USERMOD_BATTERY_CALIBRATION); } diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index 31c31f066..7b6b038a6 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -150,6 +150,8 @@ class UsermodBattery : public Usermod // update the choosen battery type with configured values bat->update(cfg); + bat->setVoltage(readVoltage()); + nextReadTime = millis() + readingInterval; lastReadTime = millis(); @@ -389,7 +391,7 @@ class UsermodBattery : public Usermod addBatteryToJsonObject(battery, false); // read voltage in case calibration or voltage multiplier changed to see immediate effect - // voltage = readVoltage(); + bat->setVoltage(readVoltage()); DEBUG_PRINTLN(F("Battery config saved.")); } From d2984e9e160f649e0d900761d76240740201a4b6 Mon Sep 17 00:00:00 2001 From: Woody Date: Tue, 30 Apr 2024 18:57:53 +0200 Subject: [PATCH 29/66] add Webpage shortcuts, resolves #2362 --- wled00/data/index.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/wled00/data/index.js b/wled00/data/index.js index 9f8c579d0..8feec9789 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -272,6 +272,7 @@ function onLoad() selectSlot(0); updateTablinks(0); + handleLocationHash(); cpick.on("input:end", () => {setColor(1);}); cpick.on("color:change", () => {updatePSliders()}); pmtLS = localStorage.getItem('wledPmt'); @@ -314,6 +315,21 @@ function openTab(tabI, force = false) _C.classList.toggle('smooth', false); _C.style.setProperty('--i', iSlide); updateTablinks(tabI); + switch (tabI) { + case 0: window.location.hash = "Colors"; break; + case 1: window.location.hash = "Effects"; break; + case 2: window.location.hash = "Segments"; break; + case 3: window.location.hash = "Presets"; break; + } +} + +function handleLocationHash() { + switch (window.location.hash) { + case "#Colors": openTab(0); break; + case "#Effects": openTab(1); break; + case "#Segments": openTab(2); break; + case "#Presets": openTab(3); break; + } } var timeout; @@ -3212,6 +3228,7 @@ size(); _C.style.setProperty('--n', N); window.addEventListener('resize', size, true); +window.addEventListener('hashchange', handleLocationHash); _C.addEventListener('mousedown', lock, false); _C.addEventListener('touchstart', lock, false); From bed364d75e8ecc0f65c43bfb1db4d9a089072158 Mon Sep 17 00:00:00 2001 From: freakintoddles2 Date: Tue, 30 Apr 2024 16:21:40 -0700 Subject: [PATCH 30/66] Update playlist.cpp Updated to allow a user to optionally skip to the next preset in the playlist anytime they desire. --- wled00/playlist.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/playlist.cpp b/wled00/playlist.cpp index 67c4f6049..0f6f5745b 100644 --- a/wled00/playlist.cpp +++ b/wled00/playlist.cpp @@ -123,11 +123,11 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) { } -void handlePlaylist() { +void handlePlaylist(bool skipNext) { static unsigned long presetCycledTime = 0; if (currentPlaylist < 0 || playlistEntries == nullptr) return; - if (millis() - presetCycledTime > (100*playlistEntryDur)) { +if (millis() - presetCycledTime > (100 * playlistEntryDur) || skipNext) { presetCycledTime = millis(); if (bri == 0 || nightlightActive) return; From 071e0be445ed012ff9ab1f72347440684eed678f Mon Sep 17 00:00:00 2001 From: freakintoddles2 Date: Tue, 30 Apr 2024 16:23:43 -0700 Subject: [PATCH 31/66] Update fcn_declare.h Updated to add the optional skipNext bool to handlePlaylist() which allows people to skip to the next preset when desired --- wled00/fcn_declare.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 2461ebb28..d77bdd8f1 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -226,7 +226,7 @@ void _overlayAnalogClock(); void shufflePlaylist(); void unloadPlaylist(); int16_t loadPlaylist(JsonObject playlistObject, byte presetId = 0); -void handlePlaylist(); +void handlePlaylist(bool skipNext=false); void serializePlaylist(JsonObject obj); //presets.cpp From 3b89814b6935261d65f95059690591f51a0eab5f Mon Sep 17 00:00:00 2001 From: freakintoddles2 Date: Tue, 30 Apr 2024 16:33:30 -0700 Subject: [PATCH 32/66] Update set.cpp added new NP command to API to allow user to skip to next preset in a playlist. Example use is win&NP in a preset. --- wled00/set.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wled00/set.cpp b/wled00/set.cpp index d3382be18..8a00a9814 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -901,6 +901,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) applyPreset(presetCycCurr); } + pos = req.indexOf(F("NP")); //skips to next preset in a playlist + if (pos > 0) handlePlaylist(true); + //set brightness updateVal(req.c_str(), "&A=", &bri); From a1d6ffadad852449a825431ad0bb8bba2f7f448d Mon Sep 17 00:00:00 2001 From: freakintoddles2 Date: Tue, 30 Apr 2024 16:49:52 -0700 Subject: [PATCH 33/66] Update json.cpp adds support for np boolean parameter to skip to next preset --- wled00/json.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wled00/json.cpp b/wled00/json.cpp index ae8224ad3..866fa968f 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -486,7 +486,11 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) strip.loadCustomPalettes(); } } - + + if (root.containsKey(F("np")) && root[F("np")].as()) { //skip to next preset in a playlist + handlePlaylist(true); + } + JsonObject wifi = root[F("wifi")]; if (!wifi.isNull()) { bool apMode = getBoolVal(wifi[F("ap")], apActive); From 25fb878e5434dd47b888bd3e5a46176c369ff8c4 Mon Sep 17 00:00:00 2001 From: freakintoddles2 Date: Wed, 1 May 2024 10:01:30 -0700 Subject: [PATCH 34/66] Update fcn_declare.h reworked approach based on feedback --- wled00/fcn_declare.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index d77bdd8f1..2818ada30 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -226,7 +226,7 @@ void _overlayAnalogClock(); void shufflePlaylist(); void unloadPlaylist(); int16_t loadPlaylist(JsonObject playlistObject, byte presetId = 0); -void handlePlaylist(bool skipNext=false); +void handlePlaylist(bool doAdvancePlaylist = false); void serializePlaylist(JsonObject obj); //presets.cpp From caa4fe1ec4f814f89fa2c77ef7405b0935b846ec Mon Sep 17 00:00:00 2001 From: freakintoddles2 Date: Wed, 1 May 2024 10:02:27 -0700 Subject: [PATCH 35/66] Update json.cpp reworked approach based on feedback --- wled00/json.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/json.cpp b/wled00/json.cpp index 866fa968f..01cbeddb1 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -488,7 +488,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) } if (root.containsKey(F("np")) && root[F("np")].as()) { //skip to next preset in a playlist - handlePlaylist(true); + doAdvancePlaylist = true; } JsonObject wifi = root[F("wifi")]; From a2b9aed40df5bb55eb4f53db72c6871c72c9b30d Mon Sep 17 00:00:00 2001 From: freakintoddles2 Date: Wed, 1 May 2024 10:03:16 -0700 Subject: [PATCH 36/66] Update playlist.cpp reworked approach based on feedback --- wled00/playlist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/playlist.cpp b/wled00/playlist.cpp index 0f6f5745b..5665ef72f 100644 --- a/wled00/playlist.cpp +++ b/wled00/playlist.cpp @@ -123,7 +123,7 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) { } -void handlePlaylist(bool skipNext) { +void handlePlaylist(bool doAdvancePlaylist) { static unsigned long presetCycledTime = 0; if (currentPlaylist < 0 || playlistEntries == nullptr) return; From e88c81ad0d6a1ff8c18667facd2b7b326ede2b74 Mon Sep 17 00:00:00 2001 From: freakintoddles2 Date: Wed, 1 May 2024 10:04:02 -0700 Subject: [PATCH 37/66] Update set.cpp reworked based on feedback --- wled00/set.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/set.cpp b/wled00/set.cpp index 8a00a9814..0b4a0da3f 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -902,7 +902,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } pos = req.indexOf(F("NP")); //skips to next preset in a playlist - if (pos > 0) handlePlaylist(true); + if (pos > 0) doAdvancePlaylist = true; //set brightness updateVal(req.c_str(), "&A=", &bri); From 16086c09615d7e8c2e2050c650b9af00b875062c Mon Sep 17 00:00:00 2001 From: freakintoddles2 Date: Wed, 1 May 2024 10:05:26 -0700 Subject: [PATCH 38/66] Update wled.h reworked based on feedback from original PR --- wled00/wled.h | 1 + 1 file changed, 1 insertion(+) diff --git a/wled00/wled.h b/wled00/wled.h index 139c451f8..75f7c14c5 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -645,6 +645,7 @@ WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, WLED_GLOBAL byte timerMonth[] _INIT_N(({28,28,28,28,28,28,28,28})); WLED_GLOBAL byte timerDay[] _INIT_N(({1,1,1,1,1,1,1,1})); WLED_GLOBAL byte timerDayEnd[] _INIT_N(({31,31,31,31,31,31,31,31})); +WLED_GLOBAL bool doAdvancePlaylist _INIT(false); //improv WLED_GLOBAL byte improvActive _INIT(0); //0: no improv packet received, 1: improv active, 2: provisioning From 6daf7f6322eacdc0ff83756b4da735d02a269fa9 Mon Sep 17 00:00:00 2001 From: freakintoddles2 Date: Wed, 1 May 2024 10:07:52 -0700 Subject: [PATCH 39/66] Update wled.cpp reworked based on PR feedback --- wled00/wled.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wled00/wled.cpp b/wled00/wled.cpp index eb7860851..25cc0442c 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -209,6 +209,12 @@ void WLED::loop() toki.resetTick(); +// Advance to next playlist preset if the flag is set to true + if (doAdvancePlaylist) { + handlePlaylist(true); + doAdvancePlaylist = false; // Reset flag to false + } + #if WLED_WATCHDOG_TIMEOUT > 0 // we finished our mainloop, reset the watchdog timer static unsigned long lastWDTFeed = 0; From db475b69988567f19c3969d1808c96918924f55e Mon Sep 17 00:00:00 2001 From: freakintoddles2 Date: Wed, 1 May 2024 10:09:17 -0700 Subject: [PATCH 40/66] Update playlist.cpp --- wled00/playlist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/playlist.cpp b/wled00/playlist.cpp index 5665ef72f..fc39db42b 100644 --- a/wled00/playlist.cpp +++ b/wled00/playlist.cpp @@ -127,7 +127,7 @@ void handlePlaylist(bool doAdvancePlaylist) { static unsigned long presetCycledTime = 0; if (currentPlaylist < 0 || playlistEntries == nullptr) return; -if (millis() - presetCycledTime > (100 * playlistEntryDur) || skipNext) { +if (millis() - presetCycledTime > (100 * playlistEntryDur) || doAdvancePlaylist) { presetCycledTime = millis(); if (bri == 0 || nightlightActive) return; From 22f6128bc47c7ee7349b4f039758bf46962b0eba Mon Sep 17 00:00:00 2001 From: Pasquale Pizzuti Date: Thu, 2 May 2024 09:04:07 +0200 Subject: [PATCH 41/66] using global brightness --- wled00/overlay.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/wled00/overlay.cpp b/wled00/overlay.cpp index cd0c04c04..d6d8ba52a 100644 --- a/wled00/overlay.cpp +++ b/wled00/overlay.cpp @@ -11,7 +11,6 @@ void _overlayAnalogClock() { _overlayAnalogCountdown(); return; } - uint8_t brightness = strip.getBrightness(); float hourP = ((float)(hour(localTime)%12))/12.0f; float minuteP = ((float)minute(localTime))/60.0f; hourP = hourP + minuteP/12.0f; @@ -26,11 +25,11 @@ void _overlayAnalogClock() { if (secondPixel < analogClock12pixel) { - strip.setRange(analogClock12pixel, overlayMax, color_fade(0xFF0000, brightness)); - strip.setRange(overlayMin, secondPixel, color_fade(0xFF0000, brightness)); + strip.setRange(analogClock12pixel, overlayMax, color_fade(0xFF0000, bri)); + strip.setRange(overlayMin, secondPixel, color_fade(0xFF0000, bri)); } else { - strip.setRange(analogClock12pixel, secondPixel, color_fade(0xFF0000, brightness)); + strip.setRange(analogClock12pixel, secondPixel, color_fade(0xFF0000, bri)); } } if (analogClock5MinuteMarks) @@ -39,12 +38,12 @@ void _overlayAnalogClock() { unsigned pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i); if (pix > overlayMax) pix -= overlaySize; - strip.setPixelColor(pix, color_fade(0x00FFAA, brightness)); + strip.setPixelColor(pix, color_fade(0x00FFAA, bri)); } } - if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, color_fade(0xFF0000, brightness)); - strip.setPixelColor(minutePixel, color_fade(0x00FF00, brightness)); - strip.setPixelColor(hourPixel, color_fade(0x0000FF, brightness)); + if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, color_fade(0xFF0000, bri)); + strip.setPixelColor(minutePixel, color_fade(0x00FF00, bri)); + strip.setPixelColor(hourPixel, color_fade(0x0000FF, bri)); } From 736a8b1b80102d2f9b32b8cc88ce5f409eeca116 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Thu, 2 May 2024 10:31:50 +0200 Subject: [PATCH 42/66] Fix for rotating tablet into PC mode. --- wled00/data/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/data/index.js b/wled00/data/index.js index 8feec9789..d33fb63f7 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -3062,11 +3062,11 @@ function togglePcMode(fromB = false) if (fromB) { pcModeA = !pcModeA; localStorage.setItem('pcm', pcModeA); - openTab(0, true); } pcMode = (wW >= 1024) && pcModeA; if (cpick) cpick.resize(pcMode && wW>1023 && wW<1250 ? 230 : 260); // for tablet in landscape if (!fromB && ((wW < 1024 && lastw < 1024) || (wW >= 1024 && lastw >= 1024))) return; // no change in size and called from size() + if (pcMode) openTab(0, true); gId('buttonPcm').className = (pcMode) ? "active":""; gId('bot').style.height = (pcMode && !cfg.comp.pcmbot) ? "0":"auto"; sCol('--bh', gId('bot').clientHeight + "px"); From 4df936a437a2e643fca724885b336b6bb3034bbd Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Thu, 2 May 2024 10:33:10 +0200 Subject: [PATCH 43/66] Fix for unfortunate prior CRLF coversion. --- wled00/mqtt.cpp | 394 ++++++++++++++++++++++++------------------------ 1 file changed, 197 insertions(+), 197 deletions(-) diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index 810291094..2e2e4a6bd 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -1,197 +1,197 @@ -#include "wled.h" - -/* - * MQTT communication protocol for home automation - */ - -#ifdef WLED_ENABLE_MQTT -#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds - -void parseMQTTBriPayload(char* payload) -{ - if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);} - else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); stateUpdated(CALL_MODE_DIRECT_CHANGE);} - else { - uint8_t in = strtoul(payload, NULL, 10); - if (in == 0 && bri > 0) briLast = bri; - bri = in; - stateUpdated(CALL_MODE_DIRECT_CHANGE); - } -} - - -void onMqttConnect(bool sessionPresent) -{ - //(re)subscribe to required topics - char subuf[38]; - - if (mqttDeviceTopic[0] != 0) { - strlcpy(subuf, mqttDeviceTopic, 33); - mqtt->subscribe(subuf, 0); - strcat_P(subuf, PSTR("/col")); - mqtt->subscribe(subuf, 0); - strlcpy(subuf, mqttDeviceTopic, 33); - strcat_P(subuf, PSTR("/api")); - mqtt->subscribe(subuf, 0); - } - - if (mqttGroupTopic[0] != 0) { - strlcpy(subuf, mqttGroupTopic, 33); - mqtt->subscribe(subuf, 0); - strcat_P(subuf, PSTR("/col")); - mqtt->subscribe(subuf, 0); - strlcpy(subuf, mqttGroupTopic, 33); - strcat_P(subuf, PSTR("/api")); - mqtt->subscribe(subuf, 0); - } - - usermods.onMqttConnect(sessionPresent); - - DEBUG_PRINTLN(F("MQTT ready")); - publishMqtt(); -} - - -void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { - static char *payloadStr; - - DEBUG_PRINT(F("MQTT msg: ")); - DEBUG_PRINTLN(topic); - - // paranoia check to avoid npe if no payload - if (payload==nullptr) { - DEBUG_PRINTLN(F("no payload -> leave")); - return; - } - - if (index == 0) { // start (1st partial packet or the only packet) - if (payloadStr) delete[] payloadStr; // fail-safe: release buffer - payloadStr = new char[total+1]; // allocate new buffer - } - if (payloadStr == nullptr) return; // buffer not allocated - - // copy (partial) packet to buffer and 0-terminate it if it is last packet - char* buff = payloadStr + index; - memcpy(buff, payload, len); - if (index + len >= total) { // at end - payloadStr[total] = '\0'; // terminate c style string - } else { - DEBUG_PRINTLN(F("MQTT partial packet received.")); - return; // process next packet - } - DEBUG_PRINTLN(payloadStr); - - size_t topicPrefixLen = strlen(mqttDeviceTopic); - if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) { - topic += topicPrefixLen; - } else { - topicPrefixLen = strlen(mqttGroupTopic); - if (strncmp(topic, mqttGroupTopic, topicPrefixLen) == 0) { - topic += topicPrefixLen; - } else { - // Non-Wled Topic used here. Probably a usermod subscribed to this topic. - usermods.onMqttMessage(topic, payloadStr); - delete[] payloadStr; - payloadStr = nullptr; - return; - } - } - - //Prefix is stripped from the topic at this point - - if (strcmp_P(topic, PSTR("/col")) == 0) { - colorFromDecOrHexString(col, payloadStr); - colorUpdated(CALL_MODE_DIRECT_CHANGE); - } else if (strcmp_P(topic, PSTR("/api")) == 0) { - if (!requestJSONBufferLock(15)) { - delete[] payloadStr; - payloadStr = nullptr; - return; - } - if (payloadStr[0] == '{') { //JSON API - deserializeJson(*pDoc, payloadStr); - deserializeState(pDoc->as()); - } else { //HTTP API - String apireq = "win"; apireq += '&'; // reduce flash string usage - apireq += payloadStr; - handleSet(nullptr, apireq); - } - releaseJSONBufferLock(); - } else if (strlen(topic) != 0) { - // non standard topic, check with usermods - usermods.onMqttMessage(topic, payloadStr); - } else { - // topmost topic (just wled/MAC) - parseMQTTBriPayload(payloadStr); - } - delete[] payloadStr; - payloadStr = nullptr; -} - - -void publishMqtt() -{ - if (!WLED_MQTT_CONNECTED) return; - DEBUG_PRINTLN(F("Publish MQTT")); - - #ifndef USERMOD_SMARTNEST - char s[10]; - char subuf[48]; - - sprintf_P(s, PSTR("%u"), bri); - strlcpy(subuf, mqttDeviceTopic, 33); - strcat_P(subuf, PSTR("/g")); - mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) - - sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2])); - strlcpy(subuf, mqttDeviceTopic, 33); - strcat_P(subuf, PSTR("/c")); - mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) - - strlcpy(subuf, mqttDeviceTopic, 33); - strcat_P(subuf, PSTR("/status")); - mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT - - char apires[1024]; // allocating 1024 bytes from stack can be risky - XML_response(nullptr, apires); - strlcpy(subuf, mqttDeviceTopic, 33); - strcat_P(subuf, PSTR("/v")); - mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263) - #endif -} - - -//HA autodiscovery was removed in favor of the native integration in HA v0.102.0 - -bool initMqtt() -{ - if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false; - - if (mqtt == nullptr) { - mqtt = new AsyncMqttClient(); - mqtt->onMessage(onMqttMessage); - mqtt->onConnect(onMqttConnect); - } - if (mqtt->connected()) return true; - - DEBUG_PRINTLN(F("Reconnecting MQTT")); - IPAddress mqttIP; - if (mqttIP.fromString(mqttServer)) //see if server is IP or domain - { - mqtt->setServer(mqttIP, mqttPort); - } else { - mqtt->setServer(mqttServer, mqttPort); - } - mqtt->setClientId(mqttClientID); - if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass); - - #ifndef USERMOD_SMARTNEST - strlcpy(mqttStatusTopic, mqttDeviceTopic, 33); - strcat_P(mqttStatusTopic, PSTR("/status")); - mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message - #endif - mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME); - mqtt->connect(); - return true; -} -#endif +#include "wled.h" + +/* + * MQTT communication protocol for home automation + */ + +#ifdef WLED_ENABLE_MQTT +#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds + +void parseMQTTBriPayload(char* payload) +{ + if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);} + else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); stateUpdated(CALL_MODE_DIRECT_CHANGE);} + else { + uint8_t in = strtoul(payload, NULL, 10); + if (in == 0 && bri > 0) briLast = bri; + bri = in; + stateUpdated(CALL_MODE_DIRECT_CHANGE); + } +} + + +void onMqttConnect(bool sessionPresent) +{ + //(re)subscribe to required topics + char subuf[38]; + + if (mqttDeviceTopic[0] != 0) { + strlcpy(subuf, mqttDeviceTopic, 33); + mqtt->subscribe(subuf, 0); + strcat_P(subuf, PSTR("/col")); + mqtt->subscribe(subuf, 0); + strlcpy(subuf, mqttDeviceTopic, 33); + strcat_P(subuf, PSTR("/api")); + mqtt->subscribe(subuf, 0); + } + + if (mqttGroupTopic[0] != 0) { + strlcpy(subuf, mqttGroupTopic, 33); + mqtt->subscribe(subuf, 0); + strcat_P(subuf, PSTR("/col")); + mqtt->subscribe(subuf, 0); + strlcpy(subuf, mqttGroupTopic, 33); + strcat_P(subuf, PSTR("/api")); + mqtt->subscribe(subuf, 0); + } + + usermods.onMqttConnect(sessionPresent); + + DEBUG_PRINTLN(F("MQTT ready")); + publishMqtt(); +} + + +void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { + static char *payloadStr; + + DEBUG_PRINT(F("MQTT msg: ")); + DEBUG_PRINTLN(topic); + + // paranoia check to avoid npe if no payload + if (payload==nullptr) { + DEBUG_PRINTLN(F("no payload -> leave")); + return; + } + + if (index == 0) { // start (1st partial packet or the only packet) + if (payloadStr) delete[] payloadStr; // fail-safe: release buffer + payloadStr = new char[total+1]; // allocate new buffer + } + if (payloadStr == nullptr) return; // buffer not allocated + + // copy (partial) packet to buffer and 0-terminate it if it is last packet + char* buff = payloadStr + index; + memcpy(buff, payload, len); + if (index + len >= total) { // at end + payloadStr[total] = '\0'; // terminate c style string + } else { + DEBUG_PRINTLN(F("MQTT partial packet received.")); + return; // process next packet + } + DEBUG_PRINTLN(payloadStr); + + size_t topicPrefixLen = strlen(mqttDeviceTopic); + if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) { + topic += topicPrefixLen; + } else { + topicPrefixLen = strlen(mqttGroupTopic); + if (strncmp(topic, mqttGroupTopic, topicPrefixLen) == 0) { + topic += topicPrefixLen; + } else { + // Non-Wled Topic used here. Probably a usermod subscribed to this topic. + usermods.onMqttMessage(topic, payloadStr); + delete[] payloadStr; + payloadStr = nullptr; + return; + } + } + + //Prefix is stripped from the topic at this point + + if (strcmp_P(topic, PSTR("/col")) == 0) { + colorFromDecOrHexString(col, payloadStr); + colorUpdated(CALL_MODE_DIRECT_CHANGE); + } else if (strcmp_P(topic, PSTR("/api")) == 0) { + if (!requestJSONBufferLock(15)) { + delete[] payloadStr; + payloadStr = nullptr; + return; + } + if (payloadStr[0] == '{') { //JSON API + deserializeJson(*pDoc, payloadStr); + deserializeState(pDoc->as()); + } else { //HTTP API + String apireq = "win"; apireq += '&'; // reduce flash string usage + apireq += payloadStr; + handleSet(nullptr, apireq); + } + releaseJSONBufferLock(); + } else if (strlen(topic) != 0) { + // non standard topic, check with usermods + usermods.onMqttMessage(topic, payloadStr); + } else { + // topmost topic (just wled/MAC) + parseMQTTBriPayload(payloadStr); + } + delete[] payloadStr; + payloadStr = nullptr; +} + + +void publishMqtt() +{ + if (!WLED_MQTT_CONNECTED) return; + DEBUG_PRINTLN(F("Publish MQTT")); + + #ifndef USERMOD_SMARTNEST + char s[10]; + char subuf[48]; + + sprintf_P(s, PSTR("%u"), bri); + strlcpy(subuf, mqttDeviceTopic, 33); + strcat_P(subuf, PSTR("/g")); + mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) + + sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2])); + strlcpy(subuf, mqttDeviceTopic, 33); + strcat_P(subuf, PSTR("/c")); + mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) + + strlcpy(subuf, mqttDeviceTopic, 33); + strcat_P(subuf, PSTR("/status")); + mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT + + char apires[1024]; // allocating 1024 bytes from stack can be risky + XML_response(nullptr, apires); + strlcpy(subuf, mqttDeviceTopic, 33); + strcat_P(subuf, PSTR("/v")); + mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263) + #endif +} + + +//HA autodiscovery was removed in favor of the native integration in HA v0.102.0 + +bool initMqtt() +{ + if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false; + + if (mqtt == nullptr) { + mqtt = new AsyncMqttClient(); + mqtt->onMessage(onMqttMessage); + mqtt->onConnect(onMqttConnect); + } + if (mqtt->connected()) return true; + + DEBUG_PRINTLN(F("Reconnecting MQTT")); + IPAddress mqttIP; + if (mqttIP.fromString(mqttServer)) //see if server is IP or domain + { + mqtt->setServer(mqttIP, mqttPort); + } else { + mqtt->setServer(mqttServer, mqttPort); + } + mqtt->setClientId(mqttClientID); + if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass); + + #ifndef USERMOD_SMARTNEST + strlcpy(mqttStatusTopic, mqttDeviceTopic, 33); + strcat_P(mqttStatusTopic, PSTR("/status")); + mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message + #endif + mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME); + mqtt->connect(); + return true; +} +#endif From 5e38039c4dd630d7b4c6841deb5e0b04aa07f573 Mon Sep 17 00:00:00 2001 From: Todd Meyer Date: Thu, 2 May 2024 14:36:18 -0700 Subject: [PATCH 44/66] Updated based on more feedback --- wled00/fcn_declare.h | 2 +- wled00/json.cpp | 6 +++--- wled00/playlist.cpp | 3 ++- wled00/set.cpp | 4 ++-- wled00/wled.cpp | 6 ------ 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 2818ada30..2461ebb28 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -226,7 +226,7 @@ void _overlayAnalogClock(); void shufflePlaylist(); void unloadPlaylist(); int16_t loadPlaylist(JsonObject playlistObject, byte presetId = 0); -void handlePlaylist(bool doAdvancePlaylist = false); +void handlePlaylist(); void serializePlaylist(JsonObject obj); //presets.cpp diff --git a/wled00/json.cpp b/wled00/json.cpp index 01cbeddb1..d998a462b 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -486,9 +486,9 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) strip.loadCustomPalettes(); } } - - if (root.containsKey(F("np")) && root[F("np")].as()) { //skip to next preset in a playlist - doAdvancePlaylist = true; + + if (root.containsKey(F("np"))) { + doAdvancePlaylist = root[F("np")].as(); //advances to next preset in playlist when true } JsonObject wifi = root[F("wifi")]; diff --git a/wled00/playlist.cpp b/wled00/playlist.cpp index fc39db42b..36235ab9e 100644 --- a/wled00/playlist.cpp +++ b/wled00/playlist.cpp @@ -123,7 +123,7 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) { } -void handlePlaylist(bool doAdvancePlaylist) { +void handlePlaylist() { static unsigned long presetCycledTime = 0; if (currentPlaylist < 0 || playlistEntries == nullptr) return; @@ -149,6 +149,7 @@ if (millis() - presetCycledTime > (100 * playlistEntryDur) || doAdvancePlaylist) strip.setTransition(fadeTransition ? playlistEntries[playlistIndex].tr * 100 : 0); playlistEntryDur = playlistEntries[playlistIndex].dur; applyPresetFromPlaylist(playlistEntries[playlistIndex].preset); + doAdvancePlaylist = false; } } diff --git a/wled00/set.cpp b/wled00/set.cpp index 0b4a0da3f..efbc7b18b 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -901,8 +901,8 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) applyPreset(presetCycCurr); } - pos = req.indexOf(F("NP")); //skips to next preset in a playlist - if (pos > 0) doAdvancePlaylist = true; + pos = req.indexOf(F("NP")); //advances to next preset in a playlist + if (pos > 0) doAdvancePlaylist = true; //set brightness updateVal(req.c_str(), "&A=", &bri); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 25cc0442c..eb7860851 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -209,12 +209,6 @@ void WLED::loop() toki.resetTick(); -// Advance to next playlist preset if the flag is set to true - if (doAdvancePlaylist) { - handlePlaylist(true); - doAdvancePlaylist = false; // Reset flag to false - } - #if WLED_WATCHDOG_TIMEOUT > 0 // we finished our mainloop, reset the watchdog timer static unsigned long lastWDTFeed = 0; From 2ff49cf657a322d17ec4fab854d9834ae10a5566 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 3 May 2024 15:45:15 +0200 Subject: [PATCH 45/66] Fix for #3952 - included IR optimisations & code rearrangement --- wled00/fcn_declare.h | 14 +-- wled00/ir.cpp | 254 ++++++++++++++++++++----------------------- wled00/set.cpp | 4 +- wled00/wled.cpp | 7 ++ 4 files changed, 130 insertions(+), 149 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 2461ebb28..a6ff9d096 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -143,20 +143,8 @@ void handleImprovWifiScan(); void sendImprovIPRPCResult(ImprovRPCType type); //ir.cpp -void applyRepeatActions(); -byte relativeChange(byte property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF); -void decodeIR(uint32_t code); -void decodeIR24(uint32_t code); -void decodeIR24OLD(uint32_t code); -void decodeIR24CT(uint32_t code); -void decodeIR40(uint32_t code); -void decodeIR44(uint32_t code); -void decodeIR21(uint32_t code); -void decodeIR6(uint32_t code); -void decodeIR9(uint32_t code); -void decodeIRJson(uint32_t code); - void initIR(); +void deInitIR(); void handleIR(); //json.cpp diff --git a/wled00/ir.cpp b/wled00/ir.cpp index ba34aa526..e475198f6 100644 --- a/wled00/ir.cpp +++ b/wled00/ir.cpp @@ -1,20 +1,14 @@ #include "wled.h" +#ifndef WLED_DISABLE_INFRARED #include "ir_codes.h" /* - * Infrared sensor support for generic 24/40/44 key RGB remotes + * Infrared sensor support for several generic RGB remotes and custom JSON remote */ -#if defined(WLED_DISABLE_INFRARED) -void handleIR(){} -#else - IRrecv* irrecv; -//change pin in NpbWrapper.h - decode_results results; - unsigned long irCheckedTime = 0; uint32_t lastValidCode = 0; byte lastRepeatableAction = ACTION_NONE; @@ -35,16 +29,16 @@ uint8_t lastIR6ColourIdx = 0; // print("%d values: %s" % (len(result), result)) // // It would be hard to maintain repeatable steps if calculating this on the fly. -const byte brightnessSteps[] = { +const uint8_t brightnessSteps[] = { 5, 7, 9, 12, 16, 20, 26, 34, 43, 56, 72, 93, 119, 154, 198, 255 }; const size_t numBrightnessSteps = sizeof(brightnessSteps) / sizeof(uint8_t); // increment `bri` to the next `brightnessSteps` value -void incBrightness() +static void incBrightness() { // dumb incremental search is efficient enough for so few items - for (uint8_t index = 0; index < numBrightnessSteps; ++index) + for (unsigned index = 0; index < numBrightnessSteps; ++index) { if (brightnessSteps[index] > bri) { @@ -56,7 +50,7 @@ void incBrightness() } // decrement `bri` to the next `brightnessSteps` value -void decBrightness() +static void decBrightness() { // dumb incremental search is efficient enough for so few items for (int index = numBrightnessSteps - 1; index >= 0; --index) @@ -70,12 +64,12 @@ void decBrightness() } } -void presetFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID) +static void presetFallback(uint8_t presetID, uint8_t effectID, uint8_t paletteID) { applyPresetWithFallback(presetID, CALL_MODE_BUTTON_PRESET, effectID, paletteID); } -byte relativeChange(byte property, int8_t amount, byte lowerBoundary, byte higherBoundary) +static byte relativeChange(byte property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF) { int16_t new_val = (int16_t) property + amount; if (lowerBoundary >= higherBoundary) return property; @@ -84,10 +78,10 @@ byte relativeChange(byte property, int8_t amount, byte lowerBoundary, byte highe return (byte)constrain(new_val, 0, 255); } -void changeEffect(uint8_t fx) +static void changeEffect(uint8_t fx) { if (irApplyToAllSelected) { - for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) { + for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { Segment& seg = strip.getSegment(i); if (!seg.isActive() || !seg.isSelected()) continue; strip.setMode(i, fx); @@ -100,10 +94,10 @@ void changeEffect(uint8_t fx) stateChanged = true; } -void changePalette(uint8_t pal) +static void changePalette(uint8_t pal) { if (irApplyToAllSelected) { - for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) { + for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { Segment& seg = strip.getSegment(i); if (!seg.isActive() || !seg.isSelected()) continue; seg.setPalette(pal); @@ -116,13 +110,13 @@ void changePalette(uint8_t pal) stateChanged = true; } -void changeEffectSpeed(int8_t amount) +static void changeEffectSpeed(int8_t amount) { if (effectCurrent != 0) { int16_t new_val = (int16_t) effectSpeed + amount; effectSpeed = (byte)constrain(new_val,0,255); if (irApplyToAllSelected) { - for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) { + for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { Segment& seg = strip.getSegment(i); if (!seg.isActive() || !seg.isSelected()) continue; seg.speed = effectSpeed; @@ -134,10 +128,7 @@ void changeEffectSpeed(int8_t amount) } } else { // if Effect == "solid Color", change the hue of the primary color Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment(); - CRGB fastled_col; - fastled_col.red = R(sseg.colors[0]); - fastled_col.green = G(sseg.colors[0]); - fastled_col.blue = B(sseg.colors[0]); + CRGB fastled_col = CRGB(sseg.colors[0]); CHSV prim_hsv = rgb2hsv_approximate(fastled_col); int16_t new_val = (int16_t)prim_hsv.h + amount; if (new_val > 255) new_val -= 255; // roll-over if bigger than 255 @@ -145,7 +136,7 @@ void changeEffectSpeed(int8_t amount) prim_hsv.h = (byte)new_val; hsv2rgb_rainbow(prim_hsv, fastled_col); if (irApplyToAllSelected) { - for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) { + for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { Segment& seg = strip.getSegment(i); if (!seg.isActive() || !seg.isSelected()) continue; seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0])); @@ -163,13 +154,13 @@ void changeEffectSpeed(int8_t amount) lastRepeatableValue = amount; } -void changeEffectIntensity(int8_t amount) +static void changeEffectIntensity(int8_t amount) { if (effectCurrent != 0) { int16_t new_val = (int16_t) effectIntensity + amount; effectIntensity = (byte)constrain(new_val,0,255); if (irApplyToAllSelected) { - for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) { + for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { Segment& seg = strip.getSegment(i); if (!seg.isActive() || !seg.isSelected()) continue; seg.intensity = effectIntensity; @@ -181,16 +172,13 @@ void changeEffectIntensity(int8_t amount) } } else { // if Effect == "solid Color", change the saturation of the primary color Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment(); - CRGB fastled_col; - fastled_col.red = R(sseg.colors[0]); - fastled_col.green = G(sseg.colors[0]); - fastled_col.blue = B(sseg.colors[0]); + CRGB fastled_col = CRGB(sseg.colors[0]); CHSV prim_hsv = rgb2hsv_approximate(fastled_col); int16_t new_val = (int16_t) prim_hsv.s + amount; prim_hsv.s = (byte)constrain(new_val,0,255); // constrain to 0-255 hsv2rgb_rainbow(prim_hsv, fastled_col); if (irApplyToAllSelected) { - for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) { + for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { Segment& seg = strip.getSegment(i); if (!seg.isActive() || !seg.isSelected()) continue; seg.colors[0] = RGBW32(fastled_col.red, fastled_col.green, fastled_col.blue, W(sseg.colors[0])); @@ -208,11 +196,11 @@ void changeEffectIntensity(int8_t amount) lastRepeatableValue = amount; } -void changeColor(uint32_t c, int16_t cct=-1) +static void changeColor(uint32_t c, int16_t cct=-1) { if (irApplyToAllSelected) { // main segment may not be selected! - for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) { + for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { Segment& seg = strip.getSegment(i); if (!seg.isActive() || !seg.isSelected()) continue; byte capabilities = seg.getLightCapabilities(); @@ -249,7 +237,7 @@ void changeColor(uint32_t c, int16_t cct=-1) stateChanged = true; } -void changeWhite(int8_t amount, int16_t cct=-1) +static void changeWhite(int8_t amount, int16_t cct=-1) { Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment(); byte r = R(seg.colors[0]); @@ -259,72 +247,7 @@ void changeWhite(int8_t amount, int16_t cct=-1) changeColor(RGBW32(r, g, b, w), cct); } -void decodeIR(uint32_t code) -{ - if (code == 0xFFFFFFFF) { - //repeated code, continue brightness up/down - irTimesRepeated++; - applyRepeatActions(); - return; - } - lastValidCode = 0; irTimesRepeated = 0; - lastRepeatableAction = ACTION_NONE; - - if (irEnabled == 8) { // any remote configurable with ir.json file - decodeIRJson(code); - stateUpdated(CALL_MODE_BUTTON); - return; - } - if (code > 0xFFFFFF) return; //invalid code - - switch (irEnabled) { - case 1: - if (code > 0xF80000) decodeIR24OLD(code); // white 24-key remote (old) - it sends 0xFF0000 values - else decodeIR24(code); // 24-key remote - 0xF70000 to 0xF80000 - break; - case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys - case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys - case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys - case 5: decodeIR21(code); break; // white 21-key remote - case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness, - // "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE" - // sets bright plain white - case 7: decodeIR9(code); break; - //case 8: return; // ir.json file, handled above switch statement - } - - if (nightlightActive && bri == 0) nightlightActive = false; - stateUpdated(CALL_MODE_BUTTON); //for notifier, IR is considered a button input -} - -void applyRepeatActions() -{ - if (irEnabled == 8) { - decodeIRJson(lastValidCode); - return; - } else switch (lastRepeatableAction) { - case ACTION_BRIGHT_UP : incBrightness(); stateUpdated(CALL_MODE_BUTTON); return; - case ACTION_BRIGHT_DOWN : decBrightness(); stateUpdated(CALL_MODE_BUTTON); return; - case ACTION_SPEED_UP : changeEffectSpeed(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return; - case ACTION_SPEED_DOWN : changeEffectSpeed(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return; - case ACTION_INTENSITY_UP : changeEffectIntensity(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return; - case ACTION_INTENSITY_DOWN : changeEffectIntensity(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return; - default: break; - } - if (lastValidCode == IR40_WPLUS) { - changeWhite(10); - stateUpdated(CALL_MODE_BUTTON); - } else if (lastValidCode == IR40_WMINUS) { - changeWhite(-10); - stateUpdated(CALL_MODE_BUTTON); - } else if ((lastValidCode == IR24_ON || lastValidCode == IR40_ON) && irTimesRepeated > 7 ) { - nightlightActive = true; - nightlightStartTime = millis(); - stateUpdated(CALL_MODE_BUTTON); - } -} - -void decodeIR24(uint32_t code) +static void decodeIR24(uint32_t code) { switch (code) { case IR24_BRIGHTER : incBrightness(); break; @@ -356,7 +279,7 @@ void decodeIR24(uint32_t code) lastValidCode = code; } -void decodeIR24OLD(uint32_t code) +static void decodeIR24OLD(uint32_t code) { switch (code) { case IR24_OLD_BRIGHTER : incBrightness(); break; @@ -388,7 +311,7 @@ void decodeIR24OLD(uint32_t code) lastValidCode = code; } -void decodeIR24CT(uint32_t code) +static void decodeIR24CT(uint32_t code) { switch (code) { case IR24_CT_BRIGHTER : incBrightness(); break; @@ -420,7 +343,7 @@ void decodeIR24CT(uint32_t code) lastValidCode = code; } -void decodeIR40(uint32_t code) +static void decodeIR40(uint32_t code) { Segment& seg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment(); byte r = R(seg.colors[0]); @@ -473,7 +396,7 @@ void decodeIR40(uint32_t code) lastValidCode = code; } -void decodeIR44(uint32_t code) +static void decodeIR44(uint32_t code) { switch (code) { case IR44_BPLUS : incBrightness(); break; @@ -525,7 +448,7 @@ void decodeIR44(uint32_t code) lastValidCode = code; } -void decodeIR21(uint32_t code) +static void decodeIR21(uint32_t code) { switch (code) { case IR21_BRIGHTER: incBrightness(); break; @@ -554,7 +477,7 @@ void decodeIR21(uint32_t code) lastValidCode = code; } -void decodeIR6(uint32_t code) +static void decodeIR6(uint32_t code) { switch (code) { case IR6_POWER: toggleOnOff(); break; @@ -587,7 +510,7 @@ void decodeIR6(uint32_t code) lastValidCode = code; } -void decodeIR9(uint32_t code) +static void decodeIR9(uint32_t code) { switch (code) { case IR9_POWER : toggleOnOff(); break; @@ -628,7 +551,7 @@ Sample: "label": "Preset 1, fallback to Saw - Party if not found"}, } */ -void decodeIRJson(uint32_t code) +static void decodeIRJson(uint32_t code) { char objKey[10]; char fileName[16]; @@ -701,41 +624,102 @@ void decodeIRJson(uint32_t code) releaseJSONBufferLock(); } +static void applyRepeatActions() +{ + if (irEnabled == 8) { + decodeIRJson(lastValidCode); + return; + } else switch (lastRepeatableAction) { + case ACTION_BRIGHT_UP : incBrightness(); stateUpdated(CALL_MODE_BUTTON); return; + case ACTION_BRIGHT_DOWN : decBrightness(); stateUpdated(CALL_MODE_BUTTON); return; + case ACTION_SPEED_UP : changeEffectSpeed(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return; + case ACTION_SPEED_DOWN : changeEffectSpeed(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return; + case ACTION_INTENSITY_UP : changeEffectIntensity(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return; + case ACTION_INTENSITY_DOWN : changeEffectIntensity(lastRepeatableValue); stateUpdated(CALL_MODE_BUTTON); return; + default: break; + } + if (lastValidCode == IR40_WPLUS) { + changeWhite(10); + stateUpdated(CALL_MODE_BUTTON); + } else if (lastValidCode == IR40_WMINUS) { + changeWhite(-10); + stateUpdated(CALL_MODE_BUTTON); + } else if ((lastValidCode == IR24_ON || lastValidCode == IR40_ON) && irTimesRepeated > 7 ) { + nightlightActive = true; + nightlightStartTime = millis(); + stateUpdated(CALL_MODE_BUTTON); + } +} + +static void decodeIR(uint32_t code) +{ + if (code == 0xFFFFFFFF) { + //repeated code, continue brightness up/down + irTimesRepeated++; + applyRepeatActions(); + return; + } + lastValidCode = 0; irTimesRepeated = 0; + lastRepeatableAction = ACTION_NONE; + + if (irEnabled == 8) { // any remote configurable with ir.json file + decodeIRJson(code); + stateUpdated(CALL_MODE_BUTTON); + return; + } + if (code > 0xFFFFFF) return; //invalid code + + switch (irEnabled) { + case 1: + if (code > 0xF80000) decodeIR24OLD(code); // white 24-key remote (old) - it sends 0xFF0000 values + else decodeIR24(code); // 24-key remote - 0xF70000 to 0xF80000 + break; + case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys + case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys + case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys + case 5: decodeIR21(code); break; // white 21-key remote + case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness, + // "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE" + // sets bright plain white + case 7: decodeIR9(code); break; + //case 8: return; // ir.json file, handled above switch statement + } + + if (nightlightActive && bri == 0) nightlightActive = false; + stateUpdated(CALL_MODE_BUTTON); //for notifier, IR is considered a button input +} + void initIR() { - if (irEnabled > 0) - { + if (irEnabled > 0) { irrecv = new IRrecv(irPin); - irrecv->enableIRIn(); + if (irrecv) irrecv->enableIRIn(); + } else irrecv = nullptr; +} + +void deInitIR() +{ + if (irrecv) { + irrecv->disableIRIn(); + delete irrecv; } + irrecv = nullptr; } void handleIR() { - if (irEnabled > 0 && millis() - irCheckedTime > 120 && !strip.isUpdating()) - { - irCheckedTime = millis(); - if (irEnabled > 0) - { - if (irrecv == NULL) - { - initIR(); return; + unsigned long currentTime = millis(); + unsigned timeDiff = currentTime - irCheckedTime; + if (timeDiff > 120 && irEnabled > 0 && irrecv) { + if (strip.isUpdating() && timeDiff < 240) return; // be nice, but not too nice + irCheckedTime = currentTime; + if (irrecv->decode(&results)) { + if (results.value != 0) { // only print results if anything is received ( != 0 ) + if (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut) // Serial TX pin (GPIO 1 on ESP32 and ESP8266) + Serial.printf_P(PSTR("IR recv: 0x%lX\n"), (unsigned long)results.value); } - - if (irrecv->decode(&results)) - { - if (results.value != 0) // only print results if anything is received ( != 0 ) - { - if (!pinManager.isPinAllocated(hardwareTX) || pinManager.getPinOwner(hardwareTX) == PinOwner::DebugOut) // Serial TX pin (GPIO 1 on ESP32 and ESP8266) - Serial.printf_P(PSTR("IR recv: 0x%lX\n"), (unsigned long)results.value); - } - decodeIR(results.value); - irrecv->resume(); - } - } else if (irrecv != NULL) - { - irrecv->disableIRIn(); - delete irrecv; irrecv = NULL; + decodeIR(results.value); + irrecv->resume(); } } } diff --git a/wled00/set.cpp b/wled00/set.cpp index d3382be18..2e8ba69d0 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -104,7 +104,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) } #ifndef WLED_DISABLE_INFRARED if (irPin>=0 && pinManager.isPinAllocated(irPin, PinOwner::IR)) { - pinManager.deallocatePin(irPin, PinOwner::IR); + deInitIR(); + pinManager.deallocatePin(irPin, PinOwner::IR); } #endif for (uint8_t s=0; sarg(F("IT")).toInt(); + initIR(); #endif irApplyToAllSelected = !request->hasArg(F("MSO")); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index eb7860851..6251735c3 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -505,6 +505,13 @@ void WLED::setup() initServer(); DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); +#ifndef WLED_DISABLE_INFRARED + // init IR + DEBUG_PRINTLN(F("initIR")); + initIR(); + DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); +#endif + // Seed FastLED random functions with an esp random value, which already works properly at this point. #if defined(ARDUINO_ARCH_ESP32) const uint32_t seed32 = esp_random(); From 6504fb68b6ba3fc49d18594df78812c6e153e9bc Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 3 May 2024 15:46:16 +0200 Subject: [PATCH 46/66] Minor MQTT optimisation. --- wled00/mqtt.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index 2e2e4a6bd..5599824ef 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -103,20 +103,17 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties colorFromDecOrHexString(col, payloadStr); colorUpdated(CALL_MODE_DIRECT_CHANGE); } else if (strcmp_P(topic, PSTR("/api")) == 0) { - if (!requestJSONBufferLock(15)) { - delete[] payloadStr; - payloadStr = nullptr; - return; + if (requestJSONBufferLock(15)) { + if (payloadStr[0] == '{') { //JSON API + deserializeJson(*pDoc, payloadStr); + deserializeState(pDoc->as()); + } else { //HTTP API + String apireq = "win"; apireq += '&'; // reduce flash string usage + apireq += payloadStr; + handleSet(nullptr, apireq); + } + releaseJSONBufferLock(); } - if (payloadStr[0] == '{') { //JSON API - deserializeJson(*pDoc, payloadStr); - deserializeState(pDoc->as()); - } else { //HTTP API - String apireq = "win"; apireq += '&'; // reduce flash string usage - apireq += payloadStr; - handleSet(nullptr, apireq); - } - releaseJSONBufferLock(); } else if (strlen(topic) != 0) { // non standard topic, check with usermods usermods.onMqttMessage(topic, payloadStr); From fa76431dd673e5c1a24c75fe7d9348a93e3f22f5 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 3 May 2024 16:08:20 +0200 Subject: [PATCH 47/66] Changelog update --- CHANGELOG.md | 10 ++++++++++ wled00/wled.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59c58dfa3..e37b08b69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ ## WLED changelog +#### Build 240503 +- Using brightness in analog clock overlay (#3944 by @paspiz85) +- Add Webpage shortcuts (#3945 by @w00000dy) +- ArtNet Poll reply (#3892 by @askask) +- Improved brightness change via long button presses (#3933 by @gaaat98) +- Relay open drain output (#3920 by @Suxsem) +- NEW JSON API: release info (update page, `info.release`) +- update esp32 platform to arduino-esp32 v2.0.9 (#3902) +- various optimisations and bugfixes (#3952, #3922, #3878, #3926, #3919, #3904 @DedeHai) + #### Build 2404120 - v0.15.0-b3 - fix for #3896 & WS2815 current saving diff --git a/wled00/wled.h b/wled00/wled.h index 139c451f8..c2efa1612 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2404120 +#define VERSION 2405030 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG From 6df3b417a94899fd382708208ced9ab08845826c Mon Sep 17 00:00:00 2001 From: Todd Meyer Date: Fri, 3 May 2024 08:30:37 -0700 Subject: [PATCH 48/66] Updated based on more feedback --- wled00/json.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wled00/json.cpp b/wled00/json.cpp index d998a462b..82952f4c4 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -487,9 +487,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) } } - if (root.containsKey(F("np"))) { - doAdvancePlaylist = root[F("np")].as(); //advances to next preset in playlist when true - } + doAdvancePlaylist = root["np"].as() || doAdvancePlaylist; //advances to next preset in playlist when true JsonObject wifi = root[F("wifi")]; if (!wifi.isNull()) { From dd19aa63d0e15693f0666ea1e33a370677b88450 Mon Sep 17 00:00:00 2001 From: Todd Meyer Date: Fri, 3 May 2024 08:47:14 -0700 Subject: [PATCH 49/66] Forgot F[], added it --- wled00/json.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/json.cpp b/wled00/json.cpp index 82952f4c4..9342dc53c 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -487,7 +487,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) } } - doAdvancePlaylist = root["np"].as() || doAdvancePlaylist; //advances to next preset in playlist when true + doAdvancePlaylist = root[F("np")].as() || doAdvancePlaylist; //advances to next preset in playlist when true JsonObject wifi = root[F("wifi")]; if (!wifi.isNull()) { From 379f1813620a56bb0b3136315feb647fb0c3d45d Mon Sep 17 00:00:00 2001 From: Todd Meyer Date: Fri, 3 May 2024 11:51:47 -0700 Subject: [PATCH 50/66] Further simplification --- wled00/json.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/json.cpp b/wled00/json.cpp index 9342dc53c..f306eb323 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -487,7 +487,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) } } - doAdvancePlaylist = root[F("np")].as() || doAdvancePlaylist; //advances to next preset in playlist when true + doAdvancePlaylist = root[F("np")] | doAdvancePlaylist; //advances to next preset in playlist when true JsonObject wifi = root[F("wifi")]; if (!wifi.isNull()) { From cd5494fdd2040ba8d6858532b7348b082c345ebb Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 4 May 2024 13:36:56 +0200 Subject: [PATCH 51/66] AR pin config: SCK == 1 --> PDM microphone --- usermods/audioreactive/audio_reactive.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 61915170c..746617a35 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -1121,6 +1121,11 @@ class AudioReactive : public Usermod { delay(100); // Give that poor microphone some time to setup. useBandPassFilter = false; + + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) + if ((i2sckPin == I2S_PIN_NO_CHANGE) && (i2ssdPin >= 0) && (i2swsPin >= 0) && ((dmType == 1) || (dmType == 4)) ) dmType = 5; // dummy user support: SCK == -1 --means--> PDM microphone + #endif + switch (dmType) { #if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) // stub cases for not-yet-supported I2S modes on other ESP32 chips From 3f9a6cae53889898486dae727bbacebc680d6ee0 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 4 May 2024 14:34:23 +0200 Subject: [PATCH 52/66] AR: fix for arduinoFFT 2.x API in contrast to previous 'dev' versions, the storage for windowWeighingFactors is now managed internally by the arduinoFFT object. --- usermods/audioreactive/audio_reactive.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 746617a35..442a651ea 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -183,7 +183,6 @@ constexpr uint16_t samplesFFT_2 = 256; // meaningfull part of FFT resul // These are the input and output vectors. Input vectors receive computed results from FFT. static float vReal[samplesFFT] = {0.0f}; // FFT sample inputs / freq output - these are our raw result bins static float vImag[samplesFFT] = {0.0f}; // imaginary parts -static float windowWeighingFactors[samplesFFT] = {0.0f}; // Create FFT object // lib_deps += https://github.com/kosme/arduinoFFT#develop @ 1.9.2 @@ -196,7 +195,8 @@ static float windowWeighingFactors[samplesFFT] = {0.0f}; #include -static ArduinoFFT FFT = ArduinoFFT( vReal, vImag, samplesFFT, SAMPLE_RATE, windowWeighingFactors); +/* Create FFT object with weighing factor storage */ +static ArduinoFFT FFT = ArduinoFFT( vReal, vImag, samplesFFT, SAMPLE_RATE, true); // Helper functions From a6e536189c5bc0d3e18b026ff6fcd1682d1cdb8b Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 5 May 2024 21:56:01 +0200 Subject: [PATCH 53/66] output_bin.py : fix for mapfile copy The build script was not looking into the right place, so there was never a .map file dropped into build_output/map/ Builds with the newer arduino-esp32 v2.0.x framework actually generate a .map file that is placed directly next to firmware.bin --- pio-scripts/output_bins.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pio-scripts/output_bins.py b/pio-scripts/output_bins.py index c0e85dcbb..633654008 100644 --- a/pio-scripts/output_bins.py +++ b/pio-scripts/output_bins.py @@ -36,6 +36,8 @@ def create_release(source): def bin_rename_copy(source, target, env): _create_dirs() variant = env["PIOENV"] + builddir = os.path.join(env["PROJECT_BUILD_DIR"], variant) + source_map = os.path.join(builddir, env["PROGNAME"] + ".map") # create string with location and file names based on variant map_file = "{}map{}{}.map".format(OUTPUT_DIR, os.path.sep, variant) @@ -44,7 +46,11 @@ def bin_rename_copy(source, target, env): # copy firmware.map to map/.map if os.path.isfile("firmware.map"): - shutil.move("firmware.map", map_file) + print("Found linker mapfile firmware.map") + shutil.copy("firmware.map", map_file) + if os.path.isfile(source_map): + print(f"Found linker mapfile {source_map}") + shutil.copy(source_map, map_file) def bin_gzip(source, target): # only create gzip for esp8266 From 2607c44fbb577cc549a23a5e0dbaf858c1fd2d80 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 6 May 2024 11:00:41 +0200 Subject: [PATCH 54/66] make objdump work Script update based on latest version from Tasmota * add support for all esp32 variants * add "-C" : Decode (demangle) low-level symbol names into user-level C++ names. --- pio-scripts/obj-dump.py | 19 +++++++++++++++++-- platformio.ini | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/pio-scripts/obj-dump.py b/pio-scripts/obj-dump.py index 91bc3de58..174df509c 100644 --- a/pio-scripts/obj-dump.py +++ b/pio-scripts/obj-dump.py @@ -1,9 +1,24 @@ # Little convenience script to get an object dump +# You may add "-S" to the objdump commandline (i.e. replace "-D -C " with "-d -S -C ") +# to get source code intermixed with disassembly (SLOW !) Import('env') def obj_dump_after_elf(source, target, env): + platform = env.PioPlatform() + board = env.BoardConfig() + mcu = board.get("build.mcu", "esp32") + print("Create firmware.asm") - env.Execute("xtensa-lx106-elf-objdump "+ "-D " + str(target[0]) + " > "+ "${PROGNAME}.asm") - + if mcu == "esp8266": + env.Execute("xtensa-lx106-elf-objdump "+ "-D -C " + str(target[0]) + " > "+ "$BUILD_DIR/${PROGNAME}.asm") + if mcu == "esp32": + env.Execute("xtensa-esp32-elf-objdump "+ "-D -C " + str(target[0]) + " > "+ "$BUILD_DIR/${PROGNAME}.asm") + if mcu == "esp32s2": + env.Execute("xtensa-esp32s2-elf-objdump "+ "-D -C " + str(target[0]) + " > "+ "$BUILD_DIR/${PROGNAME}.asm") + if mcu == "esp32s3": + env.Execute("xtensa-esp32s3-elf-objdump "+ "-D -C " + str(target[0]) + " > "+ "$BUILD_DIR/${PROGNAME}.asm") + if mcu == "esp32c3": + env.Execute("riscv32-esp-elf-objdump "+ "-D -C " + str(target[0]) + " > "+ "$BUILD_DIR/${PROGNAME}.asm") + env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", [obj_dump_after_elf]) diff --git a/platformio.ini b/platformio.ini index 76c4c92d6..fe8b3a278 100644 --- a/platformio.ini +++ b/platformio.ini @@ -115,6 +115,7 @@ extra_scripts = post:pio-scripts/strip-floats.py pre:pio-scripts/user_config_copy.py pre:pio-scripts/build_ui.py + ; post:pio-scripts/obj-dump.py ;; convenience script to create a disassembly dump of the firmware (hardcore debugging) # ------------------------------------------------------------------------------ # COMMON SETTINGS: From 18e9f9c304482e3506e8982805b5df33a2bbf6c4 Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Mon, 6 May 2024 17:39:40 +0200 Subject: [PATCH 55/66] Rename Battery classes --- usermods/Battery/{battery.h => UMBattery.h} | 4 ++-- usermods/Battery/battery_defaults.h | 1 - usermods/Battery/types/{lion.h => LionUMBattery.h} | 8 ++++---- usermods/Battery/types/{lipo.h => LipoUMBattery.h} | 8 ++++---- .../Battery/types/{unkown.h => UnkownUMBattery.h} | 8 ++++---- usermods/Battery/usermod_v2_Battery.h | 14 +++++++------- 6 files changed, 21 insertions(+), 22 deletions(-) rename usermods/Battery/{battery.h => UMBattery.h} (99%) rename usermods/Battery/types/{lion.h => LionUMBattery.h} (86%) rename usermods/Battery/types/{lipo.h => LipoUMBattery.h} (92%) rename usermods/Battery/types/{unkown.h => UnkownUMBattery.h} (87%) diff --git a/usermods/Battery/battery.h b/usermods/Battery/UMBattery.h similarity index 99% rename from usermods/Battery/battery.h rename to usermods/Battery/UMBattery.h index 2ddd84149..8a8ad891e 100644 --- a/usermods/Battery/battery.h +++ b/usermods/Battery/UMBattery.h @@ -7,7 +7,7 @@ * Battery base class * all other battery classes should inherit from this */ -class Battery +class UMBattery { private: @@ -25,7 +25,7 @@ class Battery } public: - Battery() + UMBattery() { this->setVoltageMultiplier(USERMOD_BATTERY_VOLTAGE_MULTIPLIER); this->setCalibration(USERMOD_BATTERY_CALIBRATION); diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h index ea01e8620..8b56c6014 100644 --- a/usermods/Battery/battery_defaults.h +++ b/usermods/Battery/battery_defaults.h @@ -131,5 +131,4 @@ typedef struct bconfig_t float voltageMultiplier; } batteryConfig; - #endif \ No newline at end of file diff --git a/usermods/Battery/types/lion.h b/usermods/Battery/types/LionUMBattery.h similarity index 86% rename from usermods/Battery/types/lion.h rename to usermods/Battery/types/LionUMBattery.h index e77266164..801faee7c 100644 --- a/usermods/Battery/types/lion.h +++ b/usermods/Battery/types/LionUMBattery.h @@ -2,18 +2,18 @@ #define UMBLion_h #include "../battery_defaults.h" -#include "../battery.h" +#include "../UMBattery.h" /** - * Lion Battery + * LiOn Battery * */ -class Lion : public Battery +class LionUMBattery : public UMBattery { private: public: - Lion() : Battery() + LionUMBattery() : UMBattery() { this->setMinVoltage(USERMOD_BATTERY_LION_MIN_VOLTAGE); this->setMaxVoltage(USERMOD_BATTERY_LION_MAX_VOLTAGE); diff --git a/usermods/Battery/types/lipo.h b/usermods/Battery/types/LipoUMBattery.h similarity index 92% rename from usermods/Battery/types/lipo.h rename to usermods/Battery/types/LipoUMBattery.h index d732cf4da..bb6a6ef94 100644 --- a/usermods/Battery/types/lipo.h +++ b/usermods/Battery/types/LipoUMBattery.h @@ -2,18 +2,18 @@ #define UMBLipo_h #include "../battery_defaults.h" -#include "../battery.h" +#include "../UMBattery.h" /** - * Lipo Battery + * LiPo Battery * */ -class Lipo : public Battery +class LipoUMBattery : public UMBattery { private: public: - Lipo() : Battery() + LipoUMBattery() : UMBattery() { this->setMinVoltage(USERMOD_BATTERY_LIPO_MIN_VOLTAGE); this->setMaxVoltage(USERMOD_BATTERY_LIPO_MAX_VOLTAGE); diff --git a/usermods/Battery/types/unkown.h b/usermods/Battery/types/UnkownUMBattery.h similarity index 87% rename from usermods/Battery/types/unkown.h rename to usermods/Battery/types/UnkownUMBattery.h index 32a1bfe42..ede5ffd88 100644 --- a/usermods/Battery/types/unkown.h +++ b/usermods/Battery/types/UnkownUMBattery.h @@ -2,18 +2,18 @@ #define UMBUnkown_h #include "../battery_defaults.h" -#include "../battery.h" +#include "../UMBattery.h" /** - * Lion Battery + * Unkown / Default Battery * */ -class Unkown : public Battery +class UnkownUMBattery : public UMBattery { private: public: - Unkown() : Battery() + UnkownUMBattery() : UMBattery() { this->setMinVoltage(USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE); this->setMaxVoltage(USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE); diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index 7b6b038a6..c70babf53 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -2,10 +2,10 @@ #include "wled.h" #include "battery_defaults.h" -#include "battery.h" -#include "types/unkown.h" -#include "types/lion.h" -#include "types/lipo.h" +#include "UMBattery.h" +#include "types/UnkownUMBattery.h" +#include "types/LionUMBattery.h" +#include "types/LiPoUMBattery.h" /* * Usermod by Maximilian Mewes @@ -19,7 +19,7 @@ class UsermodBattery : public Usermod // battery pin can be defined in my_config.h int8_t batteryPin = USERMOD_BATTERY_MEASUREMENT_PIN; - Battery* bat = new Unkown(); + UMBattery* bat = new UnkownUMBattery(); batteryConfig cfg; // how often to read the battery voltage @@ -142,9 +142,9 @@ class UsermodBattery : public Usermod // plug in the right battery type if(cfg.type == (batteryType)lipo) { - bat = new Lipo(); + bat = new LipoUMBattery(); } else if(cfg.type == (batteryType)lion) { - bat = new Lion(); + bat = new LipoUMBattery(); } // update the choosen battery type with configured values From d33651c25bfdc3ab4457c6e95496914fb924bad1 Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Mon, 6 May 2024 17:45:02 +0200 Subject: [PATCH 56/66] Update setup method --- usermods/Battery/usermod_v2_Battery.h | 41 +++++++++++++-------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index c70babf53..09be3ccc6 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -120,26 +120,6 @@ class UsermodBattery : public Usermod */ void setup() { - #ifdef ARDUINO_ARCH_ESP32 - bool success = false; - DEBUG_PRINTLN(F("Allocating battery pin...")); - if (batteryPin >= 0 && digitalPinToAnalogChannel(batteryPin) >= 0) - if (pinManager.allocatePin(batteryPin, false, PinOwner::UM_Battery)) { - DEBUG_PRINTLN(F("Battery pin allocation succeeded.")); - success = true; - voltage = readVoltage(); - } - - if (!success) { - DEBUG_PRINTLN(F("Battery pin allocation failed.")); - batteryPin = -1; // allocation failed - } else { - pinMode(batteryPin, INPUT); - } - #else //ESP8266 boards have only one analog input pin A0 - pinMode(batteryPin, INPUT); - #endif - // plug in the right battery type if(cfg.type == (batteryType)lipo) { bat = new LipoUMBattery(); @@ -150,7 +130,26 @@ class UsermodBattery : public Usermod // update the choosen battery type with configured values bat->update(cfg); - bat->setVoltage(readVoltage()); + #ifdef ARDUINO_ARCH_ESP32 + bool success = false; + DEBUG_PRINTLN(F("Allocating battery pin...")); + if (batteryPin >= 0 && digitalPinToAnalogChannel(batteryPin) >= 0) + if (pinManager.allocatePin(batteryPin, false, PinOwner::UM_Battery)) { + DEBUG_PRINTLN(F("Battery pin allocation succeeded.")); + success = true; + bat->setVoltage(readVoltage()); + } + + if (!success) { + DEBUG_PRINTLN(F("Battery pin allocation failed.")); + batteryPin = -1; // allocation failed + } else { + pinMode(batteryPin, INPUT); + } + #else //ESP8266 boards have only one analog input pin A0 + pinMode(batteryPin, INPUT); + bat->setVoltage(readVoltage()); + #endif nextReadTime = millis() + readingInterval; lastReadTime = millis(); From 52020cbe269e39dae3493e387bacbd35eefdc92b Mon Sep 17 00:00:00 2001 From: Maximilian Mewes Date: Mon, 6 May 2024 17:46:26 +0200 Subject: [PATCH 57/66] CP fix --- usermods/Battery/usermod_v2_Battery.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index 09be3ccc6..88a879b72 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -124,7 +124,7 @@ class UsermodBattery : public Usermod if(cfg.type == (batteryType)lipo) { bat = new LipoUMBattery(); } else if(cfg.type == (batteryType)lion) { - bat = new LipoUMBattery(); + bat = new LionUMBattery(); } // update the choosen battery type with configured values From 5bccb5fc422f4f680b6d3720db47c6bac2f11c1e Mon Sep 17 00:00:00 2001 From: gaaat98 <67930088+gaaat98@users.noreply.github.com> Date: Tue, 7 May 2024 00:31:37 +0200 Subject: [PATCH 58/66] removed commented checks --- wled00/FX.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 3110ab910..3c499edad 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -6643,7 +6643,6 @@ static const char _data_FX_MODE_GRAVIMETER[] PROGMEM = "Gravimeter@Rate of fall, // * JUGGLES // ////////////////////// uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. - //if (SEGLEN == 1) return mode_static(); um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { // add support for no audio @@ -7027,7 +7026,6 @@ static const char _data_FX_MODE_BLURZ[] PROGMEM = "Blurz@Fade rate,Blur;!,Color // ** DJLight // ///////////////////////// uint16_t mode_DJLight(void) { // Written by ??? Adapted by Will Tatam. - //if (SEGLEN == 1) return mode_static(); // No need to prevent from executing on single led strips, only mid will be set (mid = 0) const int mid = SEGLEN / 2; @@ -7100,7 +7098,6 @@ static const char _data_FX_MODE_FREQMAP[] PROGMEM = "Freqmap@Fade rate,Starting // ** Freqmatrix // /////////////////////// uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Pleschung. - //if (SEGLEN == 1) return mode_static(); // No need to prevent from executing on single led strips, we simply change pixel 0 each time and avoid the shift um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { @@ -7207,7 +7204,6 @@ static const char _data_FX_MODE_FREQPIXELS[] PROGMEM = "Freqpixels@Fade rate,Sta // As a compromise between speed and accuracy we are currently sampling with 10240Hz, from which we can then determine with a 512bin FFT our max frequency is 5120Hz. // Depending on the music stream you have you might find it useful to change the frequency mapping. uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschung. - //if (SEGLEN == 1) return mode_static(); // As before, this effect can also work on single pixels, we just lose the shifting effect um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { @@ -7318,7 +7314,6 @@ static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq@Rate of fall,Sens // ** Noisemove // ////////////////////// uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuline - //if (SEGLEN == 1) return mode_static(); um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { // add support for no audio @@ -7346,7 +7341,6 @@ static const char _data_FX_MODE_NOISEMOVE[] PROGMEM = "Noisemove@Speed of perlin // ** Rocktaves // ////////////////////// uint16_t mode_rocktaves(void) { // Rocktaves. Same note from each octave is same colour. By: Andrew Tuline - //if (SEGLEN == 1) return mode_static(); um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { // add support for no audio @@ -7388,9 +7382,8 @@ static const char _data_FX_MODE_ROCKTAVES[] PROGMEM = "Rocktaves@;!,!;!;01f;m12= /////////////////////// // Combines peak detection with FFT_MajorPeak and FFT_Magnitude. uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tuline - //if (SEGLEN == 1) return mode_static(); // effect can work on single pixels, we just lose the shifting effect - + um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { // add support for no audio From 88372cd516f959db0033644479621f5221aef3b1 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Tue, 7 May 2024 16:34:15 +0200 Subject: [PATCH 59/66] Brighter peek (ignore strip brightness) --- wled00/ws.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/wled00/ws.cpp b/wled00/ws.cpp index 307a0959e..cf09d592e 100644 --- a/wled00/ws.cpp +++ b/wled00/ws.cpp @@ -206,9 +206,12 @@ bool sendLiveLedsWs(uint32_t wsClient) uint8_t g = G(c); uint8_t b = B(c); uint8_t w = W(c); - buffer[pos++] = scale8(qadd8(w, r), strip.getBrightness()); //R, add white channel to RGB channels as a simple RGBW -> RGB map - buffer[pos++] = scale8(qadd8(w, g), strip.getBrightness()); //G - buffer[pos++] = scale8(qadd8(w, b), strip.getBrightness()); //B + //buffer[pos++] = scale8(qadd8(w, r), strip.getBrightness()); //R, add white channel to RGB channels as a simple RGBW -> RGB map + //buffer[pos++] = scale8(qadd8(w, g), strip.getBrightness()); //G + //buffer[pos++] = scale8(qadd8(w, b), strip.getBrightness()); //B + buffer[pos++] = qadd8(w, r); //R, add white channel to RGB channels as a simple RGBW -> RGB map + buffer[pos++] = qadd8(w, g); //G + buffer[pos++] = qadd8(w, b); //B } wsc->binary(std::move(wsBuf)); From b88c300d0467bd65dd9e58b3ae99977434f70fab Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 18 Apr 2024 12:57:29 +0200 Subject: [PATCH 60/66] audioreactive: workaround for ArduinoFFT bug 93 This fix works around a problem that was solved in upstream ArduinoFFT 2.0.2 --- usermods/audioreactive/audio_reactive.h | 1 + 1 file changed, 1 insertion(+) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 442a651ea..8741eb14c 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -282,6 +282,7 @@ void FFTcode(void * parameter) //FFT.windowing(FFTWindow::Blackman_Harris, FFTDirection::Forward); // Weigh data using "Blackman- Harris" window - sharp peaks due to excellent sideband rejection FFT.compute( FFTDirection::Forward ); // Compute FFT FFT.complexToMagnitude(); // Compute magnitudes + vReal[0] = 0; // The remaining DC offset on the signal produces a strong spike on position 0 that should be eliminated to avoid issues. FFT.majorPeak(&FFT_MajorPeak, &FFT_Magnitude); // let the effects know which freq was most dominant FFT_MajorPeak = constrain(FFT_MajorPeak, 1.0f, 11025.0f); // restrict value to range expected by effects From a320f164045c53b4b8454c9b25e792f64fae57ca Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Thu, 9 May 2024 23:58:58 +0200 Subject: [PATCH 61/66] Real math fix --- wled00/fcn_declare.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index a6ff9d096..1b25c8926 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -409,14 +409,14 @@ void clearEEPROM(); float fmod_t(float num, float denom); #else #include - #define sin_t sin - #define cos_t cos - #define tan_t tan - #define asin_t asin - #define acos_t acos - #define atan_t atan - #define fmod_t fmod - #define floor_t floor + #define sin_t sinf + #define cos_t cosf + #define tan_t tanf + #define asin_t asinf + #define acos_t acosf + #define atan_t atanf + #define fmod_t fmodf + #define floor_t floorf #endif //wled_serial.cpp From 4dbe9a701596d130ff34157c111abf93f0c29846 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 10 May 2024 00:02:28 +0200 Subject: [PATCH 62/66] Antialiased line & circle --- wled00/FX.cpp | 4 +- wled00/FX.h | 27 ++++-- wled00/FX_2Dfcn.cpp | 211 ++++++++++++++++++++++++++------------------ 3 files changed, 147 insertions(+), 95 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 3c499edad..d4566976d 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2506,7 +2506,7 @@ uint16_t ripple_base() uint16_t cx = rippleorigin >> 8; uint16_t cy = rippleorigin & 0xFF; uint8_t mag = scale8(sin8((propF>>2)), amp); - if (propI > 0) SEGMENT.draw_circle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag)); + if (propI > 0) SEGMENT.drawCircle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag), true); } else #endif { @@ -6056,7 +6056,7 @@ uint16_t mode_2Dfloatingblobs(void) { } } uint32_t c = SEGMENT.color_from_palette(blob->color[i], false, false, 0); - if (blob->r[i] > 1.f) SEGMENT.fill_circle(roundf(blob->x[i]), roundf(blob->y[i]), roundf(blob->r[i]), c); + if (blob->r[i] > 1.f) SEGMENT.fillCircle(roundf(blob->x[i]), roundf(blob->y[i]), roundf(blob->r[i]), c); else SEGMENT.setPixelColorXY((int)roundf(blob->x[i]), (int)roundf(blob->y[i]), c); // move x if (blob->x[i] + blob->r[i] >= cols - 1) blob->x[i] += (blob->sX[i] * ((cols - 1 - blob->x[i]) / blob->r[i] + 0.005f)); diff --git a/wled00/FX.h b/wled00/FX.h index 106a6712c..6e458fcea 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -106,6 +106,10 @@ #define PURPLE (uint32_t)0x400080 #define ORANGE (uint32_t)0xFF3000 #define PINK (uint32_t)0xFF1493 +#define GREY (uint32_t)0x808080 +#define GRAY GREY +#define DARKGREY (uint32_t)0x333333 +#define DARKGRAY DARKGREY #define ULTRAWHITE (uint32_t)0xFFFFFFFF #define DARKSLATEGRAY (uint32_t)0x2F4F4F #define DARKSLATEGREY DARKSLATEGRAY @@ -605,6 +609,7 @@ typedef struct Segment { inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } + inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); } #ifdef WLED_USE_AA_PIXELS void setPixelColorXY(float x, float y, uint32_t c, bool aa = true); inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); } @@ -624,24 +629,25 @@ typedef struct Segment { void moveX(int8_t delta, bool wrap = false); void moveY(int8_t delta, bool wrap = false); void move(uint8_t dir, uint8_t delta, bool wrap = false); - void draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c); - void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c); - void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c); - inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline + void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); + inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); } + void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); + inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { fillCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); } + void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false); + inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0), soft); } // automatic inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, int8_t rotate = 0); inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate); } // automatic inline void wu_pixel(uint32_t x, uint32_t y, CRGB c); - void blur1d(fract8 blur_amount); // blur all rows in 1 dimension inline void blur2d(fract8 blur_amount) { blur(blur_amount); } inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } - void nscale8(uint8_t scale); #else inline uint16_t XY(uint16_t x, uint16_t y) { return x; } inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } + inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColor(int(x), RGBW32(c.r,c.g,c.b,0)); } #ifdef WLED_USE_AA_PIXELS inline void setPixelColorXY(float x, float y, uint32_t c, bool aa = true) { setPixelColor(x, c, aa); } inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColor(x, RGBW32(r,g,b,w), aa); } @@ -660,9 +666,12 @@ typedef struct Segment { inline void moveX(int8_t delta, bool wrap = false) {} inline void moveY(int8_t delta, bool wrap = false) {} inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {} - inline void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c) {} - inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) {} - inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) {} + inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {} + inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {} + inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {} + inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {} + inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false) {} + inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) {} inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t = 0, int8_t = 0) {} inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color) {} inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) {} diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index e14b68f4f..b262c157d 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -342,55 +342,36 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { // 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur]) void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) { if (!isActive() || blur_amount == 0) return; // not active - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); - const unsigned dim1 = vertical ? rows : cols; - const unsigned dim2 = vertical ? cols : rows; + const int cols = virtualWidth(); + const int rows = virtualHeight(); + const int dim1 = vertical ? rows : cols; + const int dim2 = vertical ? cols : rows; if (i >= dim2) return; const float seep = blur_amount/255.f; const float keep = 3.f - 2.f*seep; // 1D box blur - CRGB tmp[dim1]; - for (unsigned j = 0; j < dim1; j++) { - unsigned x = vertical ? i : j; - unsigned y = vertical ? j : i; - int xp = vertical ? x : x-1; // "signed" to prevent underflow - int yp = vertical ? y-1 : y; // "signed" to prevent underflow - unsigned xn = vertical ? x : x+1; - unsigned yn = vertical ? y+1 : y; - CRGB curr = getPixelColorXY(x,y); - CRGB prev = (xp<0 || yp<0) ? CRGB::Black : getPixelColorXY(xp,yp); - CRGB next = ((vertical && yn>=dim1) || (!vertical && xn>=dim1)) ? CRGB::Black : getPixelColorXY(xn,yn); - unsigned r, g, b; - r = (curr.r*keep + (prev.r + next.r)*seep) / 3; - g = (curr.g*keep + (prev.g + next.g)*seep) / 3; - b = (curr.b*keep + (prev.b + next.b)*seep) / 3; - tmp[j] = CRGB(r,g,b); + uint32_t out[dim1], in[dim1]; + for (int j = 0; j < dim1; j++) { + int x = vertical ? i : j; + int y = vertical ? j : i; + in[j] = getPixelColorXY(x, y); } - for (unsigned j = 0; j < dim1; j++) { - unsigned x = vertical ? i : j; - unsigned y = vertical ? j : i; - setPixelColorXY(x, y, tmp[j]); + for (int j = 0; j < dim1; j++) { + uint32_t curr = in[j]; + uint32_t prev = j > 0 ? in[j-1] : BLACK; + uint32_t next = j < dim1-1 ? in[j+1] : BLACK; + uint8_t r, g, b, w; + r = (R(curr)*keep + (R(prev) + R(next))*seep) / 3; + g = (G(curr)*keep + (G(prev) + G(next))*seep) / 3; + b = (B(curr)*keep + (B(prev) + B(next))*seep) / 3; + w = (W(curr)*keep + (W(prev) + W(next))*seep) / 3; + out[j] = RGBW32(r,g,b,w); + } + for (int j = 0; j < dim1; j++) { + int x = vertical ? i : j; + int y = vertical ? j : i; + setPixelColorXY(x, y, out[j]); } -} - -// blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors. -// blur2d: two-dimensional blur filter. Spreads light to 8 XY neighbors. -// -// 0 = no spread at all -// 64 = moderate spreading -// 172 = maximum smooth, even spreading -// -// 173..255 = wider spreading, but increasing flicker -// -// Total light is NOT entirely conserved, so many repeated -// calls to 'blur' will also result in the light fading, -// eventually all the way to black; this is by design so that -// it can be used to (slowly) clear the LEDs to black. - -void Segment::blur1d(fract8 blur_amount) { - const unsigned rows = virtualHeight(); - for (unsigned y = 0; y < rows; y++) blurRow(y, blur_amount); } void Segment::moveX(int8_t delta, bool wrap) { @@ -447,33 +428,67 @@ void Segment::move(uint8_t dir, uint8_t delta, bool wrap) { } } -void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { +void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) { if (!isActive() || radius == 0) return; // not active - // Bresenham’s Algorithm - int d = 3 - (2*radius); - int y = radius, x = 0; - while (y >= x) { - setPixelColorXY(cx+x, cy+y, col); - setPixelColorXY(cx-x, cy+y, col); - setPixelColorXY(cx+x, cy-y, col); - setPixelColorXY(cx-x, cy-y, col); - setPixelColorXY(cx+y, cy+x, col); - setPixelColorXY(cx-y, cy+x, col); - setPixelColorXY(cx+y, cy-x, col); - setPixelColorXY(cx-y, cy-x, col); - x++; - if (d > 0) { - y--; - d += 4 * (x - y) + 10; - } else { - d += 4 * x + 6; + if (soft) { + // Xiaolin Wu’s algorithm + int rsq = radius*radius; + int x = 0; + int y = radius; + unsigned oldFade = 0; + while (x < y) { + float yf = sqrtf(float(rsq - x*x)); // needs to be floating point + unsigned fade = float(0xFFFF) * (ceilf(yf) - yf); // how much color to keep + if (oldFade > fade) y--; + oldFade = fade; + setPixelColorXY(cx+x, cy+y, color_blend(col, getPixelColorXY(cx+x, cy+y), fade, true)); + setPixelColorXY(cx-x, cy+y, color_blend(col, getPixelColorXY(cx-x, cy+y), fade, true)); + setPixelColorXY(cx+x, cy-y, color_blend(col, getPixelColorXY(cx+x, cy-y), fade, true)); + setPixelColorXY(cx-x, cy-y, color_blend(col, getPixelColorXY(cx-x, cy-y), fade, true)); + setPixelColorXY(cx+y, cy+x, color_blend(col, getPixelColorXY(cx+y, cy+x), fade, true)); + setPixelColorXY(cx-y, cy+x, color_blend(col, getPixelColorXY(cx-y, cy+x), fade, true)); + setPixelColorXY(cx+y, cy-x, color_blend(col, getPixelColorXY(cx+y, cy-x), fade, true)); + setPixelColorXY(cx-y, cy-x, color_blend(col, getPixelColorXY(cx-y, cy-x), fade, true)); + setPixelColorXY(cx+x, cy+y-1, color_blend(getPixelColorXY(cx+x, cy+y-1), col, fade, true)); + setPixelColorXY(cx-x, cy+y-1, color_blend(getPixelColorXY(cx-x, cy+y-1), col, fade, true)); + setPixelColorXY(cx+x, cy-y+1, color_blend(getPixelColorXY(cx+x, cy-y+1), col, fade, true)); + setPixelColorXY(cx-x, cy-y+1, color_blend(getPixelColorXY(cx-x, cy-y+1), col, fade, true)); + setPixelColorXY(cx+y-1, cy+x, color_blend(getPixelColorXY(cx+y-1, cy+x), col, fade, true)); + setPixelColorXY(cx-y+1, cy+x, color_blend(getPixelColorXY(cx-y+1, cy+x), col, fade, true)); + setPixelColorXY(cx+y-1, cy-x, color_blend(getPixelColorXY(cx+y-1, cy-x), col, fade, true)); + setPixelColorXY(cx-y+1, cy-x, color_blend(getPixelColorXY(cx-y+1, cy-x), col, fade, true)); + x++; + } + } else { + // Bresenham’s Algorithm + int d = 3 - (2*radius); + int y = radius, x = 0; + while (y >= x) { + setPixelColorXY(cx+x, cy+y, col); + setPixelColorXY(cx-x, cy+y, col); + setPixelColorXY(cx+x, cy-y, col); + setPixelColorXY(cx-x, cy-y, col); + setPixelColorXY(cx+y, cy+x, col); + setPixelColorXY(cx-y, cy+x, col); + setPixelColorXY(cx+y, cy-x, col); + setPixelColorXY(cx-y, cy-x, col); + x++; + if (d > 0) { + y--; + d += 4 * (x - y) + 10; + } else { + d += 4 * x + 6; + } } } } // by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs -void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { +void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) { if (!isActive() || radius == 0) return; // not active + // draw soft bounding circle + if (soft) drawCircle(cx, cy, radius, col, soft); + // fill it const int cols = virtualWidth(); const int rows = virtualHeight(); for (int y = -radius; y <= radius; y++) { @@ -486,30 +501,58 @@ void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { } } -void Segment::nscale8(uint8_t scale) { - if (!isActive()) return; // not active - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); - for (unsigned y = 0; y < rows; y++) for (unsigned x = 0; x < cols; x++) { - setPixelColorXY(x, y, CRGB(getPixelColorXY(x, y)).nscale8(scale)); - } -} - //line function -void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) { +void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft) { if (!isActive()) return; // not active - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); + const int cols = virtualWidth(); + const int rows = virtualHeight(); if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return; - const int dx = abs(x1-x0), sx = x0dy ? dx : -dy)/2, e2; - for (;;) { - setPixelColorXY(x0,y0,c); - if (x0==x1 && y0==y1) break; - e2 = err; - if (e2 >-dx) { err -= dy; x0 += sx; } - if (e2 < dy) { err += dx; y0 += sy; } + + const int dx = abs(x1-x0), sx = x0 dx; + if (steep) { + // we need to go along longest dimension + std::swap(x0,y0); + std::swap(x1,y1); + } + if (x0 > x1) { + // we need to go in increasing fashion + std::swap(x0,x1); + std::swap(y0,y1); + } + float gradient = x1-x0 == 0 ? 1.0f : float(y1-y0) / float(x1-x0); + float intersectY = y0; + for (int x = x0; x <= x1; x++) { + unsigned keep = float(0xFFFF) * (intersectY-int(intersectY)); // how much color to keep + unsigned seep = 0xFFFF - keep; // how much background to keep + int y = int(intersectY); + if (steep) std::swap(x,y); // temporaryly swap if steep + // pixel coverage is determined by fractional part of y co-ordinate + setPixelColorXY(x, y, color_blend(c, getPixelColorXY(x, y), keep, true)); + setPixelColorXY(x+int(steep), y+int(!steep), color_blend(c, getPixelColorXY(x+int(steep), y+int(!steep)), seep, true)); + intersectY += gradient; + if (steep) std::swap(x,y); // restore if steep + } + } else { + // Bresenham's algorithm + int err = (dx>dy ? dx : -dy)/2; // error direction + for (;;) { + setPixelColorXY(x0, y0, c); + if (x0==x1 && y0==y1) break; + int e2 = err; + if (e2 >-dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } } } From bc5aadff7d73931f971b3d1ee534b7a2d4dc7f0a Mon Sep 17 00:00:00 2001 From: Adam Matthews Date: Thu, 9 May 2024 23:09:45 +0100 Subject: [PATCH 63/66] Update Usermod: Battery Issue: When taking the initial voltage reading after first powering on, voltage hasn't had chance to stabilize so the reading can be inaccurate, which in turn may incorrectly trigger the low-power preset. (Manifests when the user has selected a low read interval and/or is using a capacitor). Resolution: A non-blocking, fixed 10 second delay has been added to the initial voltage reading to give the voltage time to stabilize. This is a reworked version of the (now closed) PR here: https://github.com/Aircoookie/WLED/pull/3959 - Rebased the update for 0_15. - Added a constant so the delay can be modified via my_config.h. - Small adjustments to make the PR compatible again after the recent restructuring in this PR: (https://github.com/Aircoookie/WLED/pull/3003). Thankyou! --- usermods/Battery/battery_defaults.h | 6 ++++++ usermods/Battery/readme.md | 5 +++++ usermods/Battery/usermod_v2_Battery.h | 28 ++++++++++++++++++++++++--- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h index 8b56c6014..ddbd114e4 100644 --- a/usermods/Battery/battery_defaults.h +++ b/usermods/Battery/battery_defaults.h @@ -14,6 +14,12 @@ #endif #endif +// The initial delay before the first battery voltage reading after power-on. +// This allows the voltage to stabilize before readings are taken, improving accuracy of initial reading. +#ifndef USERMOD_BATTERY_INITIAL_DELAY + #define USERMOD_BATTERY_INITIAL_DELAY 10000 // (milliseconds) +#endif + // the frequency to check the battery, 30 sec #ifndef USERMOD_BATTERY_MEASUREMENT_INTERVAL #define USERMOD_BATTERY_MEASUREMENT_INTERVAL 30000 diff --git a/usermods/Battery/readme.md b/usermods/Battery/readme.md index b3607482a..efe25cc24 100644 --- a/usermods/Battery/readme.md +++ b/usermods/Battery/readme.md @@ -37,6 +37,7 @@ define `USERMOD_BATTERY` in `wled00/my_config.h` | ----------------------------------------------- | ----------- |-------------------------------------------------------------------------------------- | | `USERMOD_BATTERY` | | define this (in `my_config.h`) to have this usermod included wled00\usermods_list.cpp | | `USERMOD_BATTERY_MEASUREMENT_PIN` | | defaults to A0 on ESP8266 and GPIO35 on ESP32 | +| `USERMOD_BATTERY_INITIAL_DELAY` | ms | delay before initial reading. defaults to 10 seconds to allow voltage stabilization | `USERMOD_BATTERY_MEASUREMENT_INTERVAL` | ms | battery check interval. defaults to 30 seconds | | `USERMOD_BATTERY_{TYPE}_MIN_VOLTAGE` | v | minimum battery voltage. default is 2.6 (18650 battery standard) | | `USERMOD_BATTERY_{TYPE}_MAX_VOLTAGE` | v | maximum battery voltage. default is 4.2 (18650 battery standard) | @@ -88,6 +89,10 @@ Specification from: [Molicel INR18650-M35A, 3500mAh 10A Lithium-ion battery, 3. 2024-04-30 +- improved initial reading accuracy by delaying initial measurement to allow voltage to stabilize at power-on + +2024-04-30 + - integrate factory pattern to make it easier to add other / custom battery types - update readme diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index 88a879b72..35da337e1 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -22,6 +22,10 @@ class UsermodBattery : public Usermod UMBattery* bat = new UnkownUMBattery(); batteryConfig cfg; + // Initial delay before first reading to allow voltage stabilization + unsigned long initialDelay = USERMOD_BATTERY_INITIAL_DELAY; + bool initialDelayComplete = false; + bool isFirstVoltageReading = true; // how often to read the battery voltage unsigned long readingInterval = USERMOD_BATTERY_MEASUREMENT_INTERVAL; unsigned long nextReadTime = 0; @@ -137,7 +141,6 @@ class UsermodBattery : public Usermod if (pinManager.allocatePin(batteryPin, false, PinOwner::UM_Battery)) { DEBUG_PRINTLN(F("Battery pin allocation succeeded.")); success = true; - bat->setVoltage(readVoltage()); } if (!success) { @@ -148,10 +151,10 @@ class UsermodBattery : public Usermod } #else //ESP8266 boards have only one analog input pin A0 pinMode(batteryPin, INPUT); - bat->setVoltage(readVoltage()); #endif - nextReadTime = millis() + readingInterval; + // First voltage reading is delayed to allow voltage stabilization after powering up + nextReadTime = millis() + initialDelay; lastReadTime = millis(); initDone = true; @@ -178,6 +181,25 @@ class UsermodBattery : public Usermod lowPowerIndicator(); + // Handling the initial delay + if (!initialDelayComplete && millis() < nextReadTime) + return; // Continue to return until the initial delay is over + + // Once the initial delay is over, set it as complete + if (!initialDelayComplete) + { + initialDelayComplete = true; + // Set the regular interval after initial delay + nextReadTime = millis() + readingInterval; + } + + // Make the first voltage reading after the initial delay has elapsed + if (isFirstVoltageReading) + { + bat->setVoltage(readVoltage()); + isFirstVoltageReading = false; + } + // check the battery level every USERMOD_BATTERY_MEASUREMENT_INTERVAL (ms) if (millis() < nextReadTime) return; From 4afed48f58569394f1a71a74d2df26a0b8be7acd Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 10 May 2024 15:59:11 +0200 Subject: [PATCH 64/66] Use libc trigonometric functions on ESP32 by default - use custom (space saving) functions on ESP8266 --- platformio.ini | 4 ++-- wled00/fcn_declare.h | 2 +- wled00/ntp.cpp | 36 ++++++++++++------------------------ 3 files changed, 15 insertions(+), 27 deletions(-) diff --git a/platformio.ini b/platformio.ini index fe8b3a278..504a1f3f7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -339,14 +339,14 @@ platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_1m128k} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA - ; -D WLED_USE_UNREAL_MATH ;; may cause wrong sunset/sunrise times, but saves 7064 bytes FLASH and 975 bytes RAM + ; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM lib_deps = ${esp8266.lib_deps} [env:esp01_1m_full_160] extends = env:esp01_1m_full board_build.f_cpu = 160000000L build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP01_160 -D WLED_DISABLE_OTA - ; -D WLED_USE_UNREAL_MATH ;; may cause wrong sunset/sunrise times, but saves 7064 bytes FLASH and 975 bytes RAM + ; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM [env:esp32dev] board = esp32dev diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 1b25c8926..2a9d0bfcd 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -398,7 +398,7 @@ void clearEEPROM(); #endif //wled_math.cpp -#ifndef WLED_USE_REAL_MATH +#if defined(ESP8266) && !defined(WLED_USE_REAL_MATH) template T atan_t(T x); float cos_t(float phi); float sin_t(float x); diff --git a/wled00/ntp.cpp b/wled00/ntp.cpp index d473186ed..e2c99045a 100644 --- a/wled00/ntp.cpp +++ b/wled00/ntp.cpp @@ -2,20 +2,8 @@ #include "wled.h" #include "fcn_declare.h" -// on esp8266, building with `-D WLED_USE_UNREAL_MATH` saves around 7Kb flash and 1KB RAM -// warning: causes errors in sunset calculations, see #3400 -#if defined(WLED_USE_UNREAL_MATH) -#define sinf sin_t -#define asinf asin_t -#define cosf cos_t -#define acosf acos_t -#define tanf tan_t -#define atanf atan_t -#define fmodf fmod_t -#define floorf floor_t -#else -#include -#endif +// WARNING: may cause errors in sunset calculations on ESP8266, see #3400 +// building with `-D WLED_USE_REAL_MATH` will prevent those errors at the expense of flash and RAM /* * Acquires time from NTP server @@ -439,7 +427,7 @@ static int getSunriseUTC(int year, int month, int day, float lat, float lon, boo //1. first calculate the day of the year float N1 = 275 * month / 9; float N2 = (month + 9) / 12; - float N3 = (1.0f + floorf((year - 4 * floorf(year / 4) + 2.0f) / 3.0f)); + float N3 = (1.0f + floor_t((year - 4 * floor_t(year / 4) + 2.0f) / 3.0f)); float N = N1 - (N2 * N3) + day - 30.0f; //2. convert the longitude to hour value and calculate an approximate time @@ -450,37 +438,37 @@ static int getSunriseUTC(int year, int month, int day, float lat, float lon, boo float M = (0.9856f * t) - 3.289f; //4. calculate the Sun's true longitude - float L = fmodf(M + (1.916f * sinf(DEG_TO_RAD*M)) + (0.02f * sinf(2*DEG_TO_RAD*M)) + 282.634f, 360.0f); + float L = fmod_t(M + (1.916f * sin_t(DEG_TO_RAD*M)) + (0.02f * sin_t(2*DEG_TO_RAD*M)) + 282.634f, 360.0f); //5a. calculate the Sun's right ascension - float RA = fmodf(RAD_TO_DEG*atanf(0.91764f * tanf(DEG_TO_RAD*L)), 360.0f); + float RA = fmod_t(RAD_TO_DEG*atan_t(0.91764f * tan_t(DEG_TO_RAD*L)), 360.0f); //5b. right ascension value needs to be in the same quadrant as L - float Lquadrant = floorf( L/90) * 90; - float RAquadrant = floorf(RA/90) * 90; + float Lquadrant = floor_t( L/90) * 90; + float RAquadrant = floor_t(RA/90) * 90; RA = RA + (Lquadrant - RAquadrant); //5c. right ascension value needs to be converted into hours RA /= 15.0f; //6. calculate the Sun's declination - float sinDec = 0.39782f * sinf(DEG_TO_RAD*L); - float cosDec = cosf(asinf(sinDec)); + float sinDec = 0.39782f * sin_t(DEG_TO_RAD*L); + float cosDec = cos_t(asin_t(sinDec)); //7a. calculate the Sun's local hour angle - float cosH = (sinf(DEG_TO_RAD*ZENITH) - (sinDec * sinf(DEG_TO_RAD*lat))) / (cosDec * cosf(DEG_TO_RAD*lat)); + float cosH = (sin_t(DEG_TO_RAD*ZENITH) - (sinDec * sin_t(DEG_TO_RAD*lat))) / (cosDec * cos_t(DEG_TO_RAD*lat)); if ((cosH > 1.0f) && !sunset) return INT16_MAX; // the sun never rises on this location (on the specified date) if ((cosH < -1.0f) && sunset) return INT16_MAX; // the sun never sets on this location (on the specified date) //7b. finish calculating H and convert into hours - float H = sunset ? RAD_TO_DEG*acosf(cosH) : 360 - RAD_TO_DEG*acosf(cosH); + float H = sunset ? RAD_TO_DEG*acos_t(cosH) : 360 - RAD_TO_DEG*acos_t(cosH); H /= 15.0f; //8. calculate local mean time of rising/setting float T = H + RA - (0.06571f * t) - 6.622f; //9. adjust back to UTC - float UT = fmodf(T - lngHour, 24.0f); + float UT = fmod_t(T - lngHour, 24.0f); // return in minutes from midnight return UT*60; From b209b1e481715716825d6ad2b34f5abb924dee05 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 10 May 2024 16:01:47 +0200 Subject: [PATCH 65/66] Peek on/off fix --- wled00/ws.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/wled00/ws.cpp b/wled00/ws.cpp index cf09d592e..d0bac144d 100644 --- a/wled00/ws.cpp +++ b/wled00/ws.cpp @@ -206,12 +206,9 @@ bool sendLiveLedsWs(uint32_t wsClient) uint8_t g = G(c); uint8_t b = B(c); uint8_t w = W(c); - //buffer[pos++] = scale8(qadd8(w, r), strip.getBrightness()); //R, add white channel to RGB channels as a simple RGBW -> RGB map - //buffer[pos++] = scale8(qadd8(w, g), strip.getBrightness()); //G - //buffer[pos++] = scale8(qadd8(w, b), strip.getBrightness()); //B - buffer[pos++] = qadd8(w, r); //R, add white channel to RGB channels as a simple RGBW -> RGB map - buffer[pos++] = qadd8(w, g); //G - buffer[pos++] = qadd8(w, b); //B + buffer[pos++] = bri ? qadd8(w, r) : 0; //R, add white channel to RGB channels as a simple RGBW -> RGB map + buffer[pos++] = bri ? qadd8(w, g) : 0; //G + buffer[pos++] = bri ? qadd8(w, b) : 0; //B } wsc->binary(std::move(wsBuf)); From b9ca2cfe90f18b0d5ebfaa1361d281fb98d7f0dc Mon Sep 17 00:00:00 2001 From: Michael Bisbjerg Date: Fri, 10 May 2024 20:55:10 +0200 Subject: [PATCH 66/66] Fix missing conversions of bme280 values The BME280 usermod uses a multiply-round-divide approach to cap the temperature/humidity/pressure values to some number of decimals. But the divide-part was missing in a few instances. --- usermods/BME280_v2/usermod_bme280.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/usermods/BME280_v2/usermod_bme280.h b/usermods/BME280_v2/usermod_bme280.h index 38930da5a..ae6eba89d 100644 --- a/usermods/BME280_v2/usermod_bme280.h +++ b/usermods/BME280_v2/usermod_bme280.h @@ -368,9 +368,9 @@ public: JsonArray temperature_json = user.createNestedArray(F("Temperature")); JsonArray pressure_json = user.createNestedArray(F("Pressure")); - temperature_json.add(roundf(sensorTemperature * powf(10, TemperatureDecimals))); + temperature_json.add(roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals)); temperature_json.add(tempScale); - pressure_json.add(roundf(sensorPressure * powf(10, PressureDecimals))); + pressure_json.add(roundf(sensorPressure * powf(10, PressureDecimals)) / powf(10, PressureDecimals)); pressure_json.add(F("hPa")); } else if (sensorType==1) //BME280 @@ -382,9 +382,9 @@ public: JsonArray dewpoint_json = user.createNestedArray(F("Dew Point")); temperature_json.add(roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals)); temperature_json.add(tempScale); - humidity_json.add(roundf(sensorHumidity * powf(10, HumidityDecimals))); + humidity_json.add(roundf(sensorHumidity * powf(10, HumidityDecimals)) / powf(10, HumidityDecimals)); humidity_json.add(F("%")); - pressure_json.add(roundf(sensorPressure * powf(10, PressureDecimals))); + pressure_json.add(roundf(sensorPressure * powf(10, PressureDecimals)) / powf(10, PressureDecimals)); pressure_json.add(F("hPa")); heatindex_json.add(roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals)); heatindex_json.add(tempScale);