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..504a1f3f7 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:
@@ -338,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/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);
diff --git a/usermods/Battery/UMBattery.h b/usermods/Battery/UMBattery.h
new file mode 100644
index 000000000..8a8ad891e
--- /dev/null
+++ b/usermods/Battery/UMBattery.h
@@ -0,0 +1,160 @@
+#ifndef UMBBattery_h
+#define UMBBattery_h
+
+#include "battery_defaults.h"
+
+/**
+ * Battery base class
+ * all other battery classes should inherit from this
+ */
+class UMBattery
+{
+ private:
+
+ protected:
+ float minVoltage;
+ float maxVoltage;
+ 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)
+ {
+ return (v-min) * (oMax-oMin) / (max-min) + oMin;
+ }
+
+ public:
+ UMBattery()
+ {
+ this->setVoltageMultiplier(USERMOD_BATTERY_VOLTAGE_MULTIPLIER);
+ this->setCalibration(USERMOD_BATTERY_CALIBRATION);
+ }
+
+ 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
+ * calculates the level 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)
+ {
+ this->maxVoltage = max(getMinVoltage()+.5f, voltage);
+ }
+
+ 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;
+ this->voltage = 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;
+ }
+
+ /*
+ * 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 = multiplier;
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h
index 958bfe526..ddbd114e4 100644
--- a/usermods/Battery/battery_defaults.h
+++ b/usermods/Battery/battery_defaults.h
@@ -1,3 +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
@@ -9,24 +14,66 @@
#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
#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
- #ifdef USERMOD_BATTERY_USE_LIPO
- // 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
+
+/* Default Battery Type
+ * 0 = unkown
+ * 1 = Lipo
+ * 2 = Lion
+ */
+#ifndef USERMOD_BATTERY_DEFAULT_TYPE
+ #define USERMOD_BATTERY_DEFAULT_TYPE 0
+#endif
+/*
+ *
+ * Unkown 'Battery' defaults
+ *
+ */
+#ifndef USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE
+ // Extra save defaults
+ #define USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE 3.3f
+#endif
+#ifndef USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE
+ #define USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE 4.2f
#endif
-//the default ratio for the voltage divider
+/*
+ *
+ * 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
+
+/*
+ *
+ * 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
+
+// the default ratio for the voltage divider
#ifndef USERMOD_BATTERY_VOLTAGE_MULTIPLIER
#ifdef ARDUINO_ARCH_ESP32
#define USERMOD_BATTERY_VOLTAGE_MULTIPLIER 2.0f
@@ -35,13 +82,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
@@ -49,11 +91,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
@@ -78,4 +115,26 @@
#ifndef USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION
#define USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION 5
+#endif
+
+// battery types
+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;
+ float voltage; // current voltage
+ int8_t level; // current level
+ float calibration; // offset or calibration value to fine tune the calculated voltage
+ float voltageMultiplier;
+} batteryConfig;
+
#endif
\ No newline at end of file
diff --git a/usermods/Battery/readme.md b/usermods/Battery/readme.md
index 999c0a541..efe25cc24 100644
--- a/usermods/Battery/readme.md
+++ b/usermods/Battery/readme.md
@@ -36,13 +36,13 @@ 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_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_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 parallel summed 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 parallel summed 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 +54,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!
@@ -80,6 +87,15 @@ Specification from: [Molicel INR18650-M35A, 3500mAh 10A Lithium-ion battery, 3.
## 📝 Change Log
+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
+
2023-01-04
- basic support for LiPo rechargeable batteries ( `-D USERMOD_BATTERY_USE_LIPO`)
diff --git a/usermods/Battery/types/LionUMBattery.h b/usermods/Battery/types/LionUMBattery.h
new file mode 100644
index 000000000..801faee7c
--- /dev/null
+++ b/usermods/Battery/types/LionUMBattery.h
@@ -0,0 +1,38 @@
+#ifndef UMBLion_h
+#define UMBLion_h
+
+#include "../battery_defaults.h"
+#include "../UMBattery.h"
+
+/**
+ * LiOn Battery
+ *
+ */
+class LionUMBattery : public UMBattery
+{
+ private:
+
+ public:
+ LionUMBattery() : UMBattery()
+ {
+ this->setMinVoltage(USERMOD_BATTERY_LION_MIN_VOLTAGE);
+ this->setMaxVoltage(USERMOD_BATTERY_LION_MAX_VOLTAGE);
+ }
+
+ 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()));
+ };
+
+ 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/types/LipoUMBattery.h b/usermods/Battery/types/LipoUMBattery.h
new file mode 100644
index 000000000..bb6a6ef94
--- /dev/null
+++ b/usermods/Battery/types/LipoUMBattery.h
@@ -0,0 +1,54 @@
+#ifndef UMBLipo_h
+#define UMBLipo_h
+
+#include "../battery_defaults.h"
+#include "../UMBattery.h"
+
+/**
+ * LiPo Battery
+ *
+ */
+class LipoUMBattery : public UMBattery
+{
+ private:
+
+ public:
+ LipoUMBattery() : UMBattery()
+ {
+ this->setMinVoltage(USERMOD_BATTERY_LIPO_MIN_VOLTAGE);
+ this->setMaxVoltage(USERMOD_BATTERY_LIPO_MAX_VOLTAGE);
+ }
+
+ /**
+ * LiPo batteries have a differnt discharge 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
+ }
+
+ return lvl;
+ };
+
+ 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/types/UnkownUMBattery.h b/usermods/Battery/types/UnkownUMBattery.h
new file mode 100644
index 000000000..ede5ffd88
--- /dev/null
+++ b/usermods/Battery/types/UnkownUMBattery.h
@@ -0,0 +1,39 @@
+#ifndef UMBUnkown_h
+#define UMBUnkown_h
+
+#include "../battery_defaults.h"
+#include "../UMBattery.h"
+
+/**
+ * Unkown / Default Battery
+ *
+ */
+class UnkownUMBattery : public UMBattery
+{
+ private:
+
+ public:
+ UnkownUMBattery() : UMBattery()
+ {
+ this->setMinVoltage(USERMOD_BATTERY_UNKOWN_MIN_VOLTAGE);
+ this->setMaxVoltage(USERMOD_BATTERY_UNKOWN_MAX_VOLTAGE);
+ }
+
+ 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);
+ }
+
+ 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 be3d8748b..35da337e1 100644
--- a/usermods/Battery/usermod_v2_Battery.h
+++ b/usermods/Battery/usermod_v2_Battery.h
@@ -2,12 +2,15 @@
#include "wled.h"
#include "battery_defaults.h"
+#include "UMBattery.h"
+#include "types/UnkownUMBattery.h"
+#include "types/LionUMBattery.h"
+#include "types/LiPoUMBattery.h"
/*
* 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
@@ -15,47 +18,36 @@ class UsermodBattery : public Usermod
private:
// battery pin can be defined in my_config.h
int8_t batteryPin = USERMOD_BATTERY_MEASUREMENT_PIN;
+
+ 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;
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;
// 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;
+ float alpha = USERMOD_BATTERY_AVERAGING_ALPHA;
// 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;
@@ -67,22 +59,17 @@ 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;
- }
+ /**
+ * 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()
@@ -91,15 +78,15 @@ 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()
{
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();
@@ -114,26 +101,39 @@ class UsermodBattery : public Usermod
}
}
+ /**
+ * 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) * voltageMultiplier + calibration;
+ 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) * voltageMultiplier + calibration;
+ return (analogRead(batteryPin) / 1023.0f) * bat->getVoltageMultiplier() + bat->getCalibration();
#endif
}
public:
//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.
*/
void setup()
{
+ // plug in the right battery type
+ if(cfg.type == (batteryType)lipo) {
+ bat = new LipoUMBattery();
+ } else if(cfg.type == (batteryType)lion) {
+ bat = new LionUMBattery();
+ }
+
+ // update the choosen battery type with configured values
+ bat->update(cfg);
+
#ifdef ARDUINO_ARCH_ESP32
bool success = false;
DEBUG_PRINTLN(F("Allocating battery pin..."));
@@ -141,7 +141,6 @@ class UsermodBattery : public Usermod
if (pinManager.allocatePin(batteryPin, false, PinOwner::UM_Battery)) {
DEBUG_PRINTLN(F("Battery pin allocation succeeded."));
success = true;
- voltage = readVoltage();
}
if (!success) {
@@ -152,17 +151,17 @@ class UsermodBattery : public Usermod
}
#else //ESP8266 boards have only one analog input pin A0
pinMode(batteryPin, INPUT);
- voltage = readVoltage();
#endif
- nextReadTime = millis() + readingInterval;
+ // First voltage reading is delayed to allow voltage stabilization after powering up
+ nextReadTime = millis() + initialDelay;
lastReadTime = millis();
initDone = true;
}
- /*
+ /**
* connected() is called every time the WiFi is (re)connected
* Use it to initialize network interfaces
*/
@@ -182,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;
@@ -191,43 +209,17 @@ class UsermodBattery : public Usermod
if (batteryPin < 0) return; // nothing to read
initializing = false;
+ float rawValue = readVoltage();
- 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;
+ float filteredVoltage = bat->getVoltage() + alpha * (rawValue - bat->getVoltage());
+ bat->setVoltage(filteredVoltage);
// 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(filteredVoltage);
// Auto off -- Master power off
- if (autoOffEnabled && (autoOffThreshold >= batteryLevel))
+ if (autoOffEnabled && (autoOffThreshold >= bat->getLevel()))
turnOff();
#ifndef WLED_DISABLE_MQTT
@@ -236,13 +228,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
@@ -262,16 +254,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);
@@ -283,46 +265,104 @@ 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"));
}
+ void addBatteryToJsonObject(JsonObject& battery, bool forJsonState)
+ {
+ 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();
+ battery[F("voltage-multiplier")] = bat->getVoltageMultiplier();
+ 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;
+ }
+
+ void getUsermodConfigFromJsonObject(JsonObject& battery)
+ {
+ 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);
+ getJsonValue(battery[F("voltage-multiplier")], cfg.voltageMultiplier);
+
+ 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(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
*/
- /*
void addToJsonState(JsonObject& root)
{
+ 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."));
}
- */
- /*
+ /**
* 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
*/
/*
void readFromJsonState(JsonObject& root)
{
+ 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."));
+ }
}
*/
- /*
+ /**
* 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().
@@ -359,47 +399,41 @@ 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("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;
- 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);
// read voltage in case calibration or voltage multiplier changed to see immediate effect
- voltage = readVoltage();
+ bat->setVoltage(readVoltage());
DEBUG_PRINTLN(F("Battery config saved."));
}
void appendConfigData()
{
- 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: 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
+ 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: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++) {
@@ -412,7 +446,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)
*
@@ -445,25 +479,13 @@ 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);
- setTotalBatteryCapacity(battery[F("capacity")] | totalBatteryCapacity);
- setCalibration(battery[F("calibration")] | calibration);
- setVoltageMultiplier(battery[F("voltage-multiplier")] | voltageMultiplier);
+ setMinBatteryVoltage(battery[F("min-voltage")] | bat->getMinVoltage());
+ setMaxBatteryVoltage(battery[F("max-voltage")] | bat->getMaxVoltage());
+ setCalibration(battery[F("calibration")] | bat->getCalibration());
+ setVoltageMultiplier(battery[F("voltage-multiplier")] | bat->getVoltageMultiplier());
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)
@@ -491,8 +513,9 @@ class UsermodBattery : public Usermod
return !battery[FPSTR(_readInterval)].isNull();
}
- /*
- * 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()
{
@@ -529,7 +552,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.
*/
@@ -538,13 +561,23 @@ class UsermodBattery : public Usermod
return USERMOD_ID_BATTERY;
}
+ /**
+ * get currently active battery type
+ */
+ batteryType getBatteryType()
+ {
+ return cfg.type;
+ }
+ /**
+ *
+ */
unsigned long getReadingInterval()
{
return readingInterval;
}
- /*
+ /**
* minimum repetition is 3000ms (3s)
*/
void setReadingInterval(unsigned long newReadingInterval)
@@ -552,105 +585,84 @@ class UsermodBattery : public Usermod
readingInterval = max((unsigned long)3000, newReadingInterval);
}
-
- /*
+ /**
* Get lowest configured battery voltage
*/
float getMinBatteryVoltage()
{
- return minBatteryVoltage;
+ return bat->getMinVoltage();
}
- /*
+ /**
* Set lowest battery voltage
* can't 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 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
*/
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);
}
- /*
+ /**
* Set the voltage multiplier value
* A multiplier that may need adjusting for different voltage divider setups
*/
void setVoltageMultiplier(float multiplier)
{
- voltageMultiplier = multiplier;
+ bat->setVoltageMultiplier(multiplier);
}
/*
@@ -659,10 +671,10 @@ class UsermodBattery : public Usermod
*/
float getVoltageMultiplier()
{
- return voltageMultiplier;
+ return bat->getVoltageMultiplier();
}
- /*
+ /**
* Get auto-off feature enabled status
* is auto-off enabled, true/false
*/
@@ -671,7 +683,7 @@ class UsermodBattery : public Usermod
return autoOffEnabled;
}
- /*
+ /**
* Set auto-off feature status
*/
void setAutoOffEnabled(bool enabled)
@@ -679,7 +691,7 @@ class UsermodBattery : public Usermod
autoOffEnabled = enabled;
}
- /*
+ /**
* Get auto-off threshold in percent (0-100)
*/
int8_t getAutoOffThreshold()
@@ -687,7 +699,7 @@ class UsermodBattery : public Usermod
return autoOffThreshold;
}
- /*
+ /**
* Set auto-off threshold in percent (0-100)
*/
void setAutoOffThreshold(int8_t threshold)
@@ -697,8 +709,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
*/
@@ -707,7 +718,7 @@ class UsermodBattery : public Usermod
return lowPowerIndicatorEnabled;
}
- /*
+ /**
* Set low-power-indicator feature status
*/
void setLowPowerIndicatorEnabled(bool enabled)
@@ -715,7 +726,7 @@ class UsermodBattery : public Usermod
lowPowerIndicatorEnabled = enabled;
}
- /*
+ /**
* Get low-power-indicator preset to activate when low power is detected
*/
int8_t getLowPowerIndicatorPreset()
@@ -723,7 +734,7 @@ class UsermodBattery : public Usermod
return lowPowerIndicatorPreset;
}
- /*
+ /**
* Set low-power-indicator preset to activate when low power is detected
*/
void setLowPowerIndicatorPreset(int8_t presetId)
@@ -741,7 +752,7 @@ class UsermodBattery : public Usermod
return lowPowerIndicatorThreshold;
}
- /*
+ /**
* Set low-power-indicator threshold in percent (0-100)
*/
void setLowPowerIndicatorThreshold(int8_t threshold)
@@ -751,7 +762,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()
@@ -759,7 +770,7 @@ class UsermodBattery : public Usermod
return lowPowerIndicatorDuration;
}
- /*
+ /**
* Set low-power-indicator duration in seconds
*/
void setLowPowerIndicatorDuration(int8_t duration)
@@ -767,9 +778,8 @@ class UsermodBattery : public Usermod
lowPowerIndicatorDuration = duration;
}
-
- /*
- * 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()
{
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
diff --git a/wled00/FX.cpp b/wled00/FX.cpp
index 5592f7ba8..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));
@@ -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
@@ -6655,12 +6654,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= 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; }
+ }
}
}
diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h
index efaad7c42..57e98467e 100644
--- a/wled00/bus_wrapper.h
+++ b/wled00/bus_wrapper.h
@@ -74,11 +74,16 @@
#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
#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
@@ -117,10 +122,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 +179,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 +208,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 ***/
@@ -210,8 +224,11 @@
//#define B_32_I0_NEO_3 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_NEO_3 NeoPixelBusLg
-//#define B_32_I1_NEO_3 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_NEO_3 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//RGBW
#define B_32_RN_NEO_4 NeoPixelBusLg
@@ -220,8 +237,11 @@
//#define B_32_I0_NEO_4 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_NEO_4 NeoPixelBusLg
-//#define B_32_I1_NEO_4 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_NEO_4 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//400Kbps
#define B_32_RN_400_3 NeoPixelBusLg
@@ -230,8 +250,11 @@
//#define B_32_I0_400_3 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_400_3 NeoPixelBusLg
-//#define B_32_I1_400_3 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_400_3 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//TM1814 (RGBW)
#define B_32_RN_TM1_4 NeoPixelBusLg
@@ -240,8 +263,11 @@
//#define B_32_I0_TM1_4 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_TM1_4 NeoPixelBusLg
-//#define B_32_I1_TM1_4 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_TM1_4 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//TM1829 (RGB)
#define B_32_RN_TM2_3 NeoPixelBusLg
@@ -250,8 +276,11 @@
//#define B_32_I0_TM2_3 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_TM2_3 NeoPixelBusLg
-//#define B_32_I1_TM2_3 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_TM2_3 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//UCS8903
#define B_32_RN_UCS_3 NeoPixelBusLg
@@ -260,8 +289,11 @@
//#define B_32_I0_UCS_3 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_UCS_3 NeoPixelBusLg
-//#define B_32_I1_UCS_3 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_UCS_3 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//UCS8904
#define B_32_RN_UCS_4 NeoPixelBusLg
@@ -270,8 +302,11 @@
//#define B_32_I0_UCS_4 NeoPixelBusLg// parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_UCS_4 NeoPixelBusLg
-//#define B_32_I1_UCS_4 NeoPixelBusLg// parallel I2S
+ #else
+#define B_32_I1_UCS_4 NeoPixelBusLg// parallel I2S
+ #endif
#endif
#define B_32_RN_APA106_3 NeoPixelBusLg
#ifndef WLED_NO_I2S0_PIXELBUS
@@ -279,8 +314,11 @@
//#define B_32_I0_APA106_3 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_APA106_3 NeoPixelBusLg
-//#define B_32_I1_APA106_3 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_APA106_3 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//FW1906 GRBCW
#define B_32_RN_FW6_5 NeoPixelBusLg
@@ -289,8 +327,11 @@
//#define B_32_I0_FW6_5 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_FW6_5 NeoPixelBusLg
-//#define B_32_I1_FW6_5 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_FW6_5 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//WS2805 RGBWC
#define B_32_RN_2805_5 NeoPixelBusLg
@@ -299,8 +340,24 @@
//#define B_32_I0_2805_5 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_2805_5 NeoPixelBusLg
-//#define B_32_I1_2805_5 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_2805_5 NeoPixelBusLg // parallel I2S
+ #endif
+#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
+ #ifndef WLED_USE_PARALLEL_I2S
+#define B_32_I1_TM1914_3 NeoPixelBusLg
+ #else
+#define B_32_I1_TM1914_3 NeoPixelBusLg
+ #endif
#endif
#endif
@@ -363,6 +420,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 +447,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 +476,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 +548,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;
@@ -499,7 +574,11 @@ 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
+ #ifdef WLED_USE_PARALLEL_I2S
+ if (channel > 7) channel -= 8; // accommodate parallel I2S1 which is used 1st on classic ESP32
+ #else
if (channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32
+ #endif
#endif
void* busPtr = nullptr;
switch (busType) {
@@ -521,10 +600,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;
@@ -545,6 +624,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;
@@ -613,6 +696,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;
@@ -650,10 +740,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;
@@ -674,6 +764,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;
@@ -742,6 +836,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;
@@ -776,10 +877,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;
@@ -799,6 +900,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;
@@ -867,6 +972,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;
@@ -926,10 +1038,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;
@@ -950,6 +1062,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;
@@ -1018,6 +1134,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;
@@ -1052,10 +1175,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;
@@ -1076,6 +1199,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;
@@ -1144,6 +1271,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;
@@ -1179,10 +1313,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;
@@ -1203,6 +1337,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;
@@ -1271,6 +1409,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;
@@ -1324,10 +1469,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