From c9aa08e7aa598c6e0bc11be307250af0707db10b Mon Sep 17 00:00:00 2001 From: KrX3D Date: Fri, 28 Mar 2025 16:46:51 +0100 Subject: [PATCH 01/14] Update ReadMe --- .../seven_segment_display_reloaded/readme.md | 298 +++++++++++++----- 1 file changed, 219 insertions(+), 79 deletions(-) diff --git a/usermods/seven_segment_display_reloaded/readme.md b/usermods/seven_segment_display_reloaded/readme.md index 94788df7e4..53f94cb321 100644 --- a/usermods/seven_segment_display_reloaded/readme.md +++ b/usermods/seven_segment_display_reloaded/readme.md @@ -1,132 +1,272 @@ # Seven Segment Display Reloaded Uses the overlay feature to create a configurable seven segment display. -Optimized for maximum configurability and use with seven segment clocks by parallyze (https://www.instructables.com/member/parallyze/instructables/) +Optimized for maximum configurability and use with seven segment clocks by [parallyze](https://www.instructables.com/member/parallyze/instructables/). Very loosely based on the existing usermod "seven segment display". - ## Installation Add the compile-time option `-D USERMOD_SSDR` to your `platformio.ini` (or `platformio_override.ini`) or use `#define USERMOD_SSDR` in `my_config.h`. -For the auto brightness option, the usermod SN_Photoresistor or BH1750_V2 has to be installed as well. See SN_Photoresistor/readme.md or BH1750_V2/readme.md for instructions. +For the auto brightness option, the usermod **SN_Photoresistor** or **BH1750_V2** has to be installed as well. See [SN_Photoresistor/readme.md](SN_Photoresistor/readme.md) or [BH1750_V2/readme.md](BH1750_V2/readme.md) for instructions. + +## Available Compile-Time Parameters + +These parameters can be configured at compile time using `#define` statements in `my_config.h`. The following table summarizes the available options: + +| Parameter | Default Value | Description | +|-----------------------------------|---------------|-------------| +| SSDR_ENABLED | true | Enable SSDR usermod | +| SSDR_ENABLE_AUTO_BRIGHTNESS | false | Enable auto brightness (requires USERMOD_SN_PHOTORESISTOR) | +| SSDR_BRIGHTNESS_MIN | 0 | Minimum brightness value for auto brightness mapping | +| SSDR_BRIGHTNESS_MAX | 128 | Maximum brightness value for auto brightness mapping | +| SSDR_INVERTED | false | Inverted display (background on, digits off) | +| SSDR_COLONBLINK | true | Enable blinking colon(s) | +| SSDR_LEADING_ZERO | false | Show leading zero for hours (e.g., "07" instead of "7") | +| SSDR_DISPLAY_MASK | "H:m" | Display mask for time format (see below) | +| SSDR_HOURS | (see example) | LED definition for hours digits | +| SSDR_MINUTES | (see example) | LED definition for minutes digits | +| SSDR_SECONDS | "" | Reserved for seconds if needed | +| SSDR_COLONS | "266-275" | Segment range for colon separators | +| SSDR_LIGHT | "252-265" | Segment range for light indicator | +| SSDR_DAYS | "" | Reserved for day display if needed | +| SSDR_MONTHS | "" | Reserved for month display if needed | +| SSDR_YEARS | "" | Reserved for year display if needed | +| umSSDR_INVERT_AUTO_BRIGHTNESS | false | Invert brightness mapping (maps lux min to brightness max) | +| umSSDR_LUX_MIN | 0 | Minimum lux level for brightness mapping | +| umSSDR_LUX_MAX | 1000 | Maximum lux level for brightness mapping | + +Additionally, the usermod allows overriding the internal LED segment number mapping with the optional macro: +- umSSDR_NUMBERS ## Settings + All settings can be controlled via the usermod settings page. -Part of the settings can be controlled through MQTT with a raw payload or through a json request to /json/state. +Some settings can also be controlled through MQTT with a raw payload or via a JSON request to `/json/state`. + +### Parameters Controlled in the Settings Page + +- **enabled** + Enables/disables this usermod. -### enabled -Enables/disables this usermod +- **inverted** + Enables the inverted mode in which the background is lit and the digits are off (black). -### inverted -Enables the inverted mode in which the background should be enabled and the digits should be black (LEDs off) +- **Colon-blinking** + Enables the blinking colon(s) if they are defined. -### Colon-blinking -Enables the blinking colon(s) if they are defined +- **Leading-Zero** + Shows a leading zero for hours when applicable (e.g., "07" instead of "7"). -### Leading-Zero -Shows the leading zero of the hour if it exists (i.e. shows `07` instead of `7`) +- **enable-auto-brightness** + Enables the auto brightness feature. This works only when the usermod **SN_Photoresistor** or **BH1750_V2** is installed. -### enable-auto-brightness -Enables the auto brightness feature. Can be used only when the usermods SN_Photoresistor or BH1750_V2 are installed. +- **auto-brightness-min / auto-brightness-max** + Maps the lux value from the SN_Photoresistor or BH1750_V2 to brightness values. + The mapping (default: 0–1000 lux) is mapped to the defined auto brightness limits. Note that WLED current protection might override the calculated value if it is too high. -### auto-brightness-min / auto-brightness-max -The lux value calculated from usermod SN_Photoresistor or BH1750_V2 will be mapped to the values defined here. -The mapping, 0 - 1000 lux, will be mapped to auto-brightness-min and auto-brightness-max +- **lux-min** + Defines the minimum lux level for brightness mapping. When the lux value is at or below this level, the display brightness is set to the minimum brightness. Default is `0` lux. -WLED current protection will override the calculated value if it is too high. +- **lux-max** + Defines the maximum lux level for brightness mapping. When the lux value is at or above this level, the display brightness is set to the maximum brightness. Default is `1000` lux. -### Display-Mask -Defines the type of the time/date display. -For example "H:m" (default) -- H - 00-23 hours -- h - 01-12 hours -- k - 01-24 hours -- m - 00-59 minutes -- s - 00-59 seconds -- d - 01-31 day of month -- M - 01-12 month -- y - 21 last two positions of year -- Y - 2021 year -- : for a colon +- **invert-auto-brightness** + Inverts the mapping logic for brightness. When enabled (`true`), `lux-min` maps to the maximum brightness and `lux-max` maps to the minimum brightness. When disabled (`false`), `lux-min` maps to the minimum brightness and `lux-max` to the maximum brightness. -### LED-Numbers -- LED-Numbers-Hours -- LED-Numbers-Minutes -- LED-Numbers-Seconds -- LED-Numbers-Colons -- LED-Numbers-Day -- LED-Numbers-Month -- LED-Numbers-Year +- **Display-Mask** + Defines the layout for the time/date display. For example, `"H:m"` is the default. The mask characters include: + - **H** - 00–23 hours + - **h** - 01–12 hours + - **k** - 01–24 hours + - **m** - 00–59 minutes + - **s** - 00–59 seconds + - **d** - 01–31 day of month + - **M** - 01–12 month + - **y** - Last two digits of year + - **Y** - Full year (e.g., 2021) + - **L** - Light LED indicator + - **:** - Colon separator -See following example for usage. +- **LED-Numbers** + LED segment definitions for various parts of the display: + - LED-Numbers-Hours + - LED-Numbers-Minutes + - LED-Numbers-Seconds + - LED-Numbers-Colons + - LED-Numbers-Light + - LED-Numbers-Day + - LED-Numbers-Month + - LED-Numbers-Year +## Example LED Definitions -## Example +The following is an example of an LED layout for a seven segment display. The diagram below shows the segment positions: -Example of an LED definition: ``` < A > /\ /\ -F B +F B \/ \/ < G > /\ /\ -E C +E C \/ \/ < D > ``` -LEDs or Range of LEDs are separated by a comma "," +A digit segment can consist of single LED numbers and LED ranges, separated by commas (,) +An example would be 1,3,6-8,23,30-32. In this example the LEDs with the numbers 1,3,6,7,8,23,30,31 and 32 would make up a Segment. +Segments for each digit are separated by semicolons (;) and digits are separated by a colon (:). -Segments are separated by a semicolon ";" and are read as A;B;C;D;E;F;G +### Example for a Clock Display -Digits are separated by colon ":" -> A;B;C;D;E;F;G:A;B;C;D;E;F;G +- **Hour Definition Example:** + + 59,46;47-48;50-51;52-53;54-55;57-58;49,56:0,13;1-2;4-5;6-7;8-9;11-12;3,10 + + The definition above represents two digits (separated by ":"): + + **First digit (of the hour):** + - Segment A: 59, 46 + - Segment B: 47, 48 + - Segment C: 50, 51 + - Segment D: 52, 53 + - Segment E: 54, 55 + - Segment F: 57, 58 + - Segment G: 49, 56 -Ranges are defined as lower to higher (lower first) + **Second digit (of the hour):** + - Segment A: 0, 13 + - Segment B: 1, 2 + - Segment C: 4, 5 + - Segment D: 6, 7 + - Segment E: 8, 9 + - Segment F: 11, 12 + - Segment G: 3, 10 -For example, a clock definition for the following clock (https://www.instructables.com/Lazy-7-Quick-Build-Edition/) is +- **Minute Definition Example:** + + 37-38;39-40;42-43;44,31;32-33;35-36;34,41:21-22;23-24;26-27;28,15;16-17;19-20;18,25 + + (Definitions can be adjusted according to the physical orientation of your LEDs.) -- hour "59,46;47-48;50-51;52-53;54-55;57-58;49,56:0,13;1-2;4-5;6-7;8-9;11-12;3,10" +## Additional Notes -- minute "37-38;39-40;42-43;44,31;32-33;35-36;34,41:21-22;23-24;26-27;28,15;16-17;19-20;18,25" +- **Dynamic Brightness Control:** +Auto brightness is computed using sensor readings from either the SN_Photoresistor or BH1750. The value is mapped between the defined brightness and lux limits, with an option to invert the mapping. -or +- **Disabling LED Output:** +A public function `disableOutputFunction(bool state)` is provided to externally disable or enable the LED output. -- hour "6,7;8,9;11,12;13,0;1,2;4,5;3,10:52,53;54,55;57,58;59,46;47,48;50,51;49,56" +## Additional Projects -- minute "15,28;16,17;19,20;21,22;23,24;26,27;18,25:31,44;32,33;35,36;37,38;39,40;42,43;34,41" +### 1. Giant Hidden Shelf Edge Clock + +This project, available on [Thingiverse](https://www.thingiverse.com/thing:4207524), uses a large hidden shelf edge as the display for a clock. If you build the modified clock that also shows 24 hours, use the following settings in your configuration: + +my_config.h Settings: +-------------------------------- + +``` +#define USERMOD_SSDR + +#define umSSDR_ENABLED true // Enable SSDR usermod +#define umSSDR_ENABLE_AUTO_BRIGHTNESS false // Enable auto brightness (requires USERMOD_SN_PHOTORESISTOR) +#define umSSDR_INVERTED false // Inverted display +#define umSSDR_COLONBLINK true // Colon blink enabled +#define umSSDR_LEADING_ZERO false // Leading zero disabled +#define umSSDR_DISPLAY_MASK "H:mL" // Display mask for time format + +// Segment definitions for hours, minutes, seconds, colons, light, days, months, and years +#define umSSDR_HOURS "135-143;126-134;162-170;171-179;180-188;144-152;153-161:198-206;189-197;225-233;234-242;243-251;207-215;216-224" +#define umSSDR_MINUTES "9-17;0-8;36-44;45-53;54-62;18-26;27-35:72-80;63-71;99-107;108-116;117-125;81-89;90-98" +#define umSSDR_SECONDS "" +#define umSSDR_COLONS "266-275" // Segment range for colons +#define umSSDR_LIGHT "252-265" // Segment range for light indicator (added for this project) +#define umSSDR_DAYS "" // Reserved for days if needed +#define umSSDR_MONTHS "" // Reserved for months if needed +#define umSSDR_YEARS "" // Reserved for years if needed + +#define umSSDR_INVERT_AUTO_BRIGHTNESS true +#define umSSDR_LUX_MIN 50 +#define umSSDR_LUX_MAX 1000 + +// Brightness limits +#define umSSDR_BRIGHTNESS_MIN 0 // Minimum brightness +#define umSSDR_BRIGHTNESS_MAX 128 // Maximum brightness +``` -depending on the orientation. +-------------------------------- -# Example details: -hour "59,46;47-48;50-51;52-53;54-55;57-58;49,56:0,13;1-2;4-5;6-7;8-9;11-12;3,10" +*Note:* For this project, the `umSSDR_LIGHT` parameter was added to provide a dedicated segment for a light indicator. -there are two digits separated by ":" +--- -- 59,46;47-48;50-51;52-53;54-55;57-58;49,56 -- 0,13;1-2;4-5;6-7;8-9;11-12;3,10 +### 2. EleksTube Retro Glows Analog Nixie Tube Clock (Non-IPS Version) -In the first digit, -the **segment A** consists of the LEDs number **59 and 46**., **segment B** consists of the LEDs number **47, 48** and so on +The EleksTube project, available at [EleksTube Retro Glows Analog Nixie Tube Clock](https://elekstube.com/products/elekstube-r2-6-bit-electronic-led-luminous-retro-glows-analog-nixie-tube-clock). With the following settings, the SSDR usermod becomes more versatile and can be used with this clock as well: -The second digit starts again with **segment A** and LEDs **0 and 13**, **segment B** consists of the LEDs number **1 and 2** and so on +my_config.h Settings: +-------------------------------- + +``` +#define umSSDR_ENABLED true // Enable SSDR usermod +#define umSSDR_ENABLE_AUTO_BRIGHTNESS false // Enable auto brightness (requires USERMOD_SN_PHOTORESISTOR) +#define umSSDR_INVERTED false // Inverted display +#define umSSDR_COLONBLINK false // Colon blink disabled +#define umSSDR_LEADING_ZERO true // Leading zero enabled +#define umSSDR_DISPLAY_MASK "H:m:s" // Display mask for time format + +// Segment definitions for hours, minutes, seconds, colons, light, days, months, and years +#define umSSDR_HOURS "20,30;21,31;22,32;23,33;24,34;25,35;26,36;27,37;28,38;29,39:0,10;1,11;2,12;3,13;4,14;5,15;6,16;7,17;8,18;9,19" +#define umSSDR_MINUTES "60,70;61,71;62,72;63,73;64,74;65,75;66,76;67,77;68,78;69,79:40,50;41,51;42,52;43,53;44,54;45,55;46,56;47,57;48,58;49,59" +#define umSSDR_SECONDS "100,110;101,111;102,112;103,113;104,114;105,115;106,116;107,117;108,118;109,119:80,90;81,91;82,92;83,93;84,94;85,95;86,96;87,97;88,98;89,99" +#define umSSDR_COLONS "" // No colon segment mapping needed +#define umSSDR_LIGHT "" // No light indicator defined +#define umSSDR_DAYS "" // Reserved for days if needed +#define umSSDR_MONTHS "" // Reserved for months if needed +#define umSSDR_YEARS "" // Reserved for years if needed + +#define umSSDR_INVERT_AUTO_BRIGHTNESS true +#define umSSDR_LUX_MIN 50 +#define umSSDR_LUX_MAX 1000 + +// Brightness limits +#define umSSDR_BRIGHTNESS_MIN 0 // Minimum brightness +#define umSSDR_BRIGHTNESS_MAX 128 // Maximum brightness + +#define umSSDR_NUMBERS { \ + { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }, /* 0 */ \ + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 1 */ \ + { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, /* 2 */ \ + { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 3 */ \ + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* 4 */ \ + { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, /* 5 */ \ + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, /* 6 */ \ + { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, /* 7 */ \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, /* 8 */ \ + { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, /* 9 */ \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } /* Blank */ \ +} +``` + +### 3. Lazy Clock(s) by paralyze +[Lazy 7 Quick build edition](https://www.instructables.com/Lazy-7-Quick-Build-Edition/). The SSDR usermod can be used to drive this and other clock designs by [paralyze](https://www.instructables.com/member/parallyze/) +For example the Lazy 7 Quick build edition has the following settings - depending on the orientation. + +- hour "59,46;47-48;50-51;52-53;54-55;57-58;49,56:0,13;1-2;4-5;6-7;8-9;11-12;3,10" + +- minute "37-38;39-40;42-43;44,31;32-33;35-36;34,41:21-22;23-24;26-27;28,15;16-17;19-20;18,25" + +or + +- hour "6,7;8,9;11,12;13,0;1,2;4,5;3,10:52,53;54,55;57,58;59,46;47,48;50,51;49,56" + +- minute "15,28;16,17;19,20;21,22;23,24;26,27;18,25:31,44;32,33;35,36;37,38;39,40;42,43;34,41" -### first digit of the hour -- Segment A: 59, 46 -- Segment B: 47, 48 -- Segment C: 50, 51 -- Segment D: 52, 53 -- Segment E: 54, 55 -- Segment F: 57, 58 -- Segment G: 49, 56 +-------------------------------- -### second digit of the hour +With these modifications, the SSDR usermod becomes even more versatile, allowing it to be used on a wide variety of segment clocks and projects. -- Segment A: 0, 13 -- Segment B: 1, 2 -- Segment C: 4, 5 -- Segment D: 6, 7 -- Segment E: 8, 9 -- Segment F: 11, 12 -- Segment G: 3, 10 +*Note:* The ability to override the LED segment mapping via `umSSDR_NUMBERS` provides additional flexibility for adapting to different physical displays. \ No newline at end of file From 3849385f915fb16d4d78339c56577f59ff5470a5 Mon Sep 17 00:00:00 2001 From: KrX3D Date: Fri, 28 Mar 2025 16:53:17 +0100 Subject: [PATCH 02/14] Update SSDR --- .../seven_segment_display_reloaded.cpp | 453 ++++++++++++------ 1 file changed, 311 insertions(+), 142 deletions(-) diff --git a/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp b/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp index 971a80c8d7..7f5c1c562c 100644 --- a/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp +++ b/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp @@ -1,6 +1,6 @@ #include "wled.h" -#ifdef WLED_DISABLE_MQTT +#ifndef WLED_ENABLE_MQTT #error "This user mod requires MQTT to be enabled." #endif @@ -12,24 +12,51 @@ class UsermodSSDR : public Usermod { //Runtime variables. unsigned long umSSDRLastRefresh = 0; unsigned long umSSDRResfreshTime = 3000; - bool umSSDRDisplayTime = false; - bool umSSDRInverted = false; - bool umSSDRColonblink = true; - bool umSSDRLeadingZero = false; - bool umSSDREnableLDR = false; - String umSSDRHours = ""; - String umSSDRMinutes = ""; - String umSSDRSeconds = ""; - String umSSDRColons = ""; - String umSSDRDays = ""; - String umSSDRMonths = ""; - String umSSDRYears = ""; uint16_t umSSDRLength = 0; - uint16_t umSSDRBrightnessMin = 0; - uint16_t umSSDRBrightnessMax = 255; - bool* umSSDRMask = 0; + // Configurable settings for the SSDR Usermod + // Enabled usermod + #ifndef umSSDR_ENABLED + #define umSSDR_ENABLED false + #endif + + #ifndef umSSDR_ENABLE_AUTO_BRIGHTNESS + #define umSSDR_ENABLE_AUTO_BRIGHTNESS false + #endif + + #ifndef umSSDR_BRIGHTNESS_MIN + #define umSSDR_BRIGHTNESS_MIN 0 + #endif + + #ifndef umSSDR_BRIGHTNESS_MAX + #define umSSDR_BRIGHTNESS_MAX 255 + #endif + + #ifndef umSSDR_INVERT_AUTO_BRIGHTNESS + #define umSSDR_INVERT_AUTO_BRIGHTNESS false + #endif + + #ifndef umSSDR_LUX_MIN + #define umSSDR_LUX_MIN 0 + #endif + #ifndef umSSDR_LUX_MAX + #define umSSDR_LUX_MAX 1000 + #endif + + #ifndef umSSDR_INVERTED + #define umSSDR_INVERTED false + #endif + + #ifndef umSSDR_COLONBLINK + #define umSSDR_COLONBLINK true + #endif + + #ifndef umSSDR_LEADING_ZERO + #define umSSDR_LEADING_ZERO false + #endif + + // Display mask for physical layout /*// H - 00-23 hours // h - 01-12 hours // k - 01-24 hours @@ -39,43 +66,112 @@ class UsermodSSDR : public Usermod { // M - 01-12 month // y - 21 last two positions of year // Y - 2021 year + // L - Light LED + // This option defines a separate LED (or set of LEDs) that can be controlled independently + // from the other clock display LEDs. It can be switched on or off to provide additional + // lighting for the display or serve as an ambient light source, without affecting the + // clock's visual display of time and date. // : for a colon */ - String umSSDRDisplayMask = "H:m"; //This should reflect physical equipment. + + #ifndef umSSDR_DISPLAY_MASK + #define umSSDR_DISPLAY_MASK "H:m" + #endif - /* Segment order, seen from the front: + #ifndef umSSDR_HOURS + #define umSSDR_HOURS "" + #endif - < A > - /\ /\ - F B - \/ \/ - < G > - /\ /\ - E C - \/ \/ - < D > + #ifndef umSSDR_MINUTES + #define umSSDR_MINUTES "" + #endif - */ + #ifndef umSSDR_SECONDS + #define umSSDR_SECONDS "" + #endif - uint8_t umSSDRNumbers[11][7] = { - // A B C D E F G - { 1, 1, 1, 1, 1, 1, 0 }, // 0 - { 0, 1, 1, 0, 0, 0, 0 }, // 1 - { 1, 1, 0, 1, 1, 0, 1 }, // 2 - { 1, 1, 1, 1, 0, 0, 1 }, // 3 - { 0, 1, 1, 0, 0, 1, 1 }, // 4 - { 1, 0, 1, 1, 0, 1, 1 }, // 5 - { 1, 0, 1, 1, 1, 1, 1 }, // 6 - { 1, 1, 1, 0, 0, 0, 0 }, // 7 - { 1, 1, 1, 1, 1, 1, 1 }, // 8 - { 1, 1, 1, 1, 0, 1, 1 }, // 9 - { 0, 0, 0, 0, 0, 0, 0 } // blank - }; + #ifndef umSSDR_COLONS + #define umSSDR_COLONS "" + #endif + #ifndef umSSDR_LIGHT + #define umSSDR_LIGHT "" + #endif + + #ifndef umSSDR_DAYS + #define umSSDR_DAYS "" + #endif + + #ifndef umSSDR_MONTHS + #define umSSDR_MONTHS "" + #endif + + #ifndef umSSDR_YEARS + #define umSSDR_YEARS "" + #endif + + #ifndef umSSDR_NUMBERS + /* Segment order, seen from the front: + < A > + /\ /\ + F B + \/ \/ + < G > + /\ /\ + E C + \/ \/ + < D > + */ + uint8_t umSSDRNumbers[11][7] = { + // A B C D E F G + { 1, 1, 1, 1, 1, 1, 0 }, // 0 + { 0, 1, 1, 0, 0, 0, 0 }, // 1 + { 1, 1, 0, 1, 1, 0, 1 }, // 2 + { 1, 1, 1, 1, 0, 0, 1 }, // 3 + { 0, 1, 1, 0, 0, 1, 1 }, // 4 + { 1, 0, 1, 1, 0, 1, 1 }, // 5 + { 1, 0, 1, 1, 1, 1, 1 }, // 6 + { 1, 1, 1, 0, 0, 0, 0 }, // 7 + { 1, 1, 1, 1, 1, 1, 1 }, // 8 + { 1, 1, 1, 1, 0, 1, 1 }, // 9 + { 0, 0, 0, 0, 0, 0, 0 } // blank + }; + #else + uint8_t umSSDRNumbers[11][10] = umSSDR_NUMBERS; + #endif + + bool umSSDRDisplayTime = umSSDR_ENABLED; + bool umSSDREnableLDR = umSSDR_ENABLE_AUTO_BRIGHTNESS; + uint16_t umSSDRBrightnessMin = umSSDR_BRIGHTNESS_MIN; + uint16_t umSSDRBrightnessMax = umSSDR_BRIGHTNESS_MAX; + bool umSSDRInvertAutoBrightness = umSSDR_INVERT_AUTO_BRIGHTNESS; + uint16_t umSSDRLuxMin = umSSDR_LUX_MIN; + uint16_t umSSDRLuxMax = umSSDR_LUX_MAX; + bool umSSDRInverted = umSSDR_INVERTED; + bool umSSDRColonblink = umSSDR_COLONBLINK; + bool umSSDRLeadingZero = umSSDR_LEADING_ZERO; + String umSSDRDisplayMask = umSSDR_DISPLAY_MASK; + String umSSDRHours = umSSDR_HOURS; + String umSSDRMinutes = umSSDR_MINUTES; + String umSSDRSeconds = umSSDR_SECONDS; + String umSSDRColons = umSSDR_COLONS; + String umSSDRLight = umSSDR_LIGHT; + String umSSDRDays = umSSDR_DAYS; + String umSSDRMonths = umSSDR_MONTHS; + String umSSDRYears = umSSDR_YEARS; + + bool* umSSDRMask = 0; + bool disableUmLedControl = false; + //String to reduce flash memory usage static const char _str_name[]; - static const char _str_ldrEnabled[]; static const char _str_timeEnabled[]; + static const char _str_ldrEnabled[]; + static const char _str_minBrightness[]; + static const char _str_maxBrightness[]; + static const char _str_luxMin[]; + static const char _str_luxMax[]; + static const char _str_invertAutoBrightness[]; static const char _str_inverted[]; static const char _str_colonblink[]; static const char _str_leadingZero[]; @@ -84,11 +180,10 @@ class UsermodSSDR : public Usermod { static const char _str_minutes[]; static const char _str_seconds[]; static const char _str_colons[]; + static const char _str_light[]; static const char _str_days[]; static const char _str_months[]; static const char _str_years[]; - static const char _str_minBrightness[]; - static const char _str_maxBrightness[]; #ifdef USERMOD_SN_PHOTORESISTOR Usermod_SN_Photoresistor *ptr; @@ -104,6 +199,7 @@ class UsermodSSDR : public Usermod { void _overlaySevenSegmentDraw() { int displayMaskLen = static_cast(umSSDRDisplayMask.length()); bool colonsDone = false; + bool lightDone = false; _setAllFalse(); for (int index = 0; index < displayMaskLen; index++) { int timeVar = 0; @@ -150,6 +246,12 @@ class UsermodSSDR : public Usermod { colonsDone = true; } break; + case 'L': + if (!lightDone) { // only call _showElements once + _showElements(&umSSDRLight, 0, 1, 0); + lightDone = true; + } + break; } } _setMaskToLeds(); @@ -165,9 +267,7 @@ class UsermodSSDR : public Usermod { } } - void _showElements(String *map, int timevar, bool isColon, bool removeZero - -) { + void _showElements(String *map, int timevar, bool isColon, bool removeZero) { if ((map != nullptr) && (*map != nullptr) && !(*map).equals("")) { int length = String(timevar).length(); bool addZero = false; @@ -179,13 +279,13 @@ class UsermodSSDR : public Usermod { if(addZero) { if(removeZero) { - timeArr[1] = 10; timeArr[0] = timevar; + timeArr[1] = 10; } else { - timeArr[1] = 0; timeArr[0] = timevar; + timeArr[1] = 0; } } else { int count = 0; @@ -196,7 +296,6 @@ class UsermodSSDR : public Usermod { }; } - int colonsLen = static_cast((*map).length()); int count = 0; int countSegments = 0; @@ -275,21 +374,29 @@ class UsermodSSDR : public Usermod { void _publishMQTTint_P(const char *subTopic, int value) { - if(mqtt == NULL) return; - - char buffer[64]; - char valBuffer[12]; - sprintf_P(buffer, PSTR("%s/%S/%S"), mqttDeviceTopic, _str_name, subTopic); - sprintf_P(valBuffer, PSTR("%d"), value); - mqtt->publish(buffer, 2, true, valBuffer); + #ifndef WLED_DISABLE_MQTT + if (WLED_MQTT_CONNECTED) { + if(mqtt == NULL) return; + + char buffer[64]; + char valBuffer[12]; + sprintf_P(buffer, PSTR("%s/%S/%S"), mqttDeviceTopic, _str_name, subTopic); + sprintf_P(valBuffer, PSTR("%d"), value); + mqtt->publish(buffer, 2, true, valBuffer); + } + #endif } void _publishMQTTstr_P(const char *subTopic, String Value) { - if(mqtt == NULL) return; - char buffer[64]; - sprintf_P(buffer, PSTR("%s/%S/%S"), mqttDeviceTopic, _str_name, subTopic); - mqtt->publish(buffer, 2, true, Value.c_str(), Value.length()); + #ifndef WLED_DISABLE_MQTT + if (WLED_MQTT_CONNECTED) { + if(mqtt == NULL) return; + char buffer[64]; + sprintf_P(buffer, PSTR("%s/%S/%S"), mqttDeviceTopic, _str_name, subTopic); + mqtt->publish(buffer, 2, true, Value.c_str(), Value.length()); + } + #endif } bool _cmpIntSetting_P(char *topic, char *payload, const char *setting, void *value) @@ -331,6 +438,11 @@ class UsermodSSDR : public Usermod { { _publishMQTTint_P(_str_timeEnabled, umSSDRDisplayTime); _publishMQTTint_P(_str_ldrEnabled, umSSDREnableLDR); + _publishMQTTint_P(_str_minBrightness, umSSDRBrightnessMin); + _publishMQTTint_P(_str_maxBrightness, umSSDRBrightnessMax); + _publishMQTTint_P(_str_luxMin, umSSDRLuxMin); + _publishMQTTint_P(_str_luxMax, umSSDRLuxMax); + _publishMQTTint_P(_str_invertAutoBrightness, umSSDRInvertAutoBrightness); _publishMQTTint_P(_str_inverted, umSSDRInverted); _publishMQTTint_P(_str_colonblink, umSSDRColonblink); _publishMQTTint_P(_str_leadingZero, umSSDRLeadingZero); @@ -339,13 +451,11 @@ class UsermodSSDR : public Usermod { _publishMQTTstr_P(_str_minutes, umSSDRMinutes); _publishMQTTstr_P(_str_seconds, umSSDRSeconds); _publishMQTTstr_P(_str_colons, umSSDRColons); + _publishMQTTstr_P(_str_light, umSSDRLight); _publishMQTTstr_P(_str_days, umSSDRDays); _publishMQTTstr_P(_str_months, umSSDRMonths); _publishMQTTstr_P(_str_years, umSSDRYears); _publishMQTTstr_P(_str_displayMask, umSSDRDisplayMask); - - _publishMQTTint_P(_str_minBrightness, umSSDRBrightnessMin); - _publishMQTTint_P(_str_maxBrightness, umSSDRBrightnessMax); } void _addJSONObject(JsonObject& root) { @@ -356,6 +466,11 @@ class UsermodSSDR : public Usermod { ssdrObj[FPSTR(_str_timeEnabled)] = umSSDRDisplayTime; ssdrObj[FPSTR(_str_ldrEnabled)] = umSSDREnableLDR; + ssdrObj[FPSTR(_str_minBrightness)] = umSSDRBrightnessMin; + ssdrObj[FPSTR(_str_maxBrightness)] = umSSDRBrightnessMax; + ssdrObj[FPSTR(_str_luxMin)] = umSSDRLuxMin; + ssdrObj[FPSTR(_str_luxMax)] = umSSDRLuxMax; + ssdrObj[FPSTR(_str_invertAutoBrightness)] = umSSDRInvertAutoBrightness; ssdrObj[FPSTR(_str_inverted)] = umSSDRInverted; ssdrObj[FPSTR(_str_colonblink)] = umSSDRColonblink; ssdrObj[FPSTR(_str_leadingZero)] = umSSDRLeadingZero; @@ -364,11 +479,10 @@ class UsermodSSDR : public Usermod { ssdrObj[FPSTR(_str_minutes)] = umSSDRMinutes; ssdrObj[FPSTR(_str_seconds)] = umSSDRSeconds; ssdrObj[FPSTR(_str_colons)] = umSSDRColons; + ssdrObj[FPSTR(_str_light)] = umSSDRLight; ssdrObj[FPSTR(_str_days)] = umSSDRDays; ssdrObj[FPSTR(_str_months)] = umSSDRMonths; ssdrObj[FPSTR(_str_years)] = umSSDRYears; - ssdrObj[FPSTR(_str_minBrightness)] = umSSDRBrightnessMin; - ssdrObj[FPSTR(_str_maxBrightness)] = umSSDRBrightnessMax; } public: @@ -403,24 +517,30 @@ class UsermodSSDR : public Usermod { if (!umSSDRDisplayTime || strip.isUpdating()) { return; } - #ifdef USERMOD_SN_PHOTORESISTOR - if(bri != 0 && umSSDREnableLDR && (millis() - umSSDRLastRefresh > umSSDRResfreshTime)) { + #if defined(USERMOD_SN_PHOTORESISTOR) || defined(USERMOD_BH1750) + if(bri != 0 && umSSDREnableLDR && (millis() - umSSDRLastRefresh > umSSDRResfreshTime) && !disableUmLedControl) { + float lux = -1; // Initialize lux with an invalid value + + #ifdef USERMOD_SN_PHOTORESISTOR if (ptr != nullptr) { - uint16_t lux = ptr->getLastLDRValue(); - uint16_t brightness = map(lux, 0, 1000, umSSDRBrightnessMin, umSSDRBrightnessMax); - if (bri != brightness) { - bri = brightness; - stateUpdated(1); - } + lux = ptr->getLastLDRValue(); } - umSSDRLastRefresh = millis(); - } - #endif - #ifdef USERMOD_BH1750 - if(bri != 0 && umSSDREnableLDR && (millis() - umSSDRLastRefresh > umSSDRResfreshTime)) { + #endif + + #ifdef USERMOD_BH1750 if (bh1750 != nullptr) { - float lux = bh1750->getIlluminance(); - uint16_t brightness = map(lux, 0, 1000, umSSDRBrightnessMin, umSSDRBrightnessMax); + lux = bh1750->getIlluminance(); + } + #endif + + if (lux >= 0) { // Ensure we got a valid lux value + uint16_t brightness; + if (!umSSDRInvertAutoBrightness) { + brightness = map(lux, umSSDRLuxMin, umSSDRLuxMax, umSSDRBrightnessMin, umSSDRBrightnessMax); + } else { + brightness = map(lux, umSSDRLuxMin, umSSDRLuxMax, umSSDRBrightnessMax, umSSDRBrightnessMin); + } + if (bri != brightness) { DEBUG_PRINTF("Adjusting brightness based on lux value: %.2f lx, new brightness: %d\n", lux, brightness); bri = brightness; @@ -433,11 +553,16 @@ class UsermodSSDR : public Usermod { } void handleOverlayDraw() { - if (umSSDRDisplayTime) { + if (umSSDRDisplayTime && !disableUmLedControl) { _overlaySevenSegmentDraw(); } } + //Can be used outside of this usermod + void disableOutputFunction(bool state) { + this->disableUmLedControl = state; + } + /* * 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. @@ -448,17 +573,30 @@ class UsermodSSDR : public Usermod { if (user.isNull()) { user = root.createNestedObject(F("u")); } - JsonArray enabled = user.createNestedArray("Time enabled"); - enabled.add(umSSDRDisplayTime); - JsonArray invert = user.createNestedArray("Time inverted"); - invert.add(umSSDRInverted); - JsonArray blink = user.createNestedArray("Blinking colon"); - blink.add(umSSDRColonblink); - JsonArray zero = user.createNestedArray("Show the hour leading zero"); - zero.add(umSSDRLeadingZero); - JsonArray ldrEnable = user.createNestedArray("Auto Brightness enabled"); - ldrEnable.add(umSSDREnableLDR); - + + // Create a nested array for energy data + JsonArray ssr_json_seperator = user.createNestedArray(F("-----------------------------------")); + + JsonArray ssr_json = user.createNestedArray(F("Seven segment reloaded:")); + + if (!umSSDRDisplayTime) { + ssr_json.add(F("disabled")); // Indicate that the module is disabled + } else { + JsonArray invert = user.createNestedArray("Time inverted"); + invert.add(umSSDRInverted); + + JsonArray blink = user.createNestedArray("Blinking colon"); + blink.add(umSSDRColonblink); + + JsonArray zero = user.createNestedArray("Show hour leading zero"); + zero.add(umSSDRLeadingZero); + + JsonArray ldrEnable = user.createNestedArray(F("Auto Brightness enabled")); + ldrEnable.add(umSSDREnableLDR); + + JsonArray ldrInvert = user.createNestedArray(F("Auto Brightness inverted")); + ldrInvert.add(umSSDRInvertAutoBrightness); + } } /* @@ -483,56 +621,82 @@ class UsermodSSDR : public Usermod { JsonObject ssdrObj = user[FPSTR(_str_name)]; umSSDRDisplayTime = ssdrObj[FPSTR(_str_timeEnabled)] | umSSDRDisplayTime; umSSDREnableLDR = ssdrObj[FPSTR(_str_ldrEnabled)] | umSSDREnableLDR; + umSSDRBrightnessMin = ssdrObj[FPSTR(_str_minBrightness)] | umSSDRBrightnessMin; + umSSDRBrightnessMax = ssdrObj[FPSTR(_str_maxBrightness)] | umSSDRBrightnessMax; + umSSDRLuxMin = ssdrObj[FPSTR(_str_luxMin)] | umSSDRLuxMin; + umSSDRLuxMax = ssdrObj[FPSTR(_str_luxMax)] | umSSDRLuxMax; + umSSDRInvertAutoBrightness = ssdrObj[FPSTR(_str_invertAutoBrightness)] | umSSDRInvertAutoBrightness; umSSDRInverted = ssdrObj[FPSTR(_str_inverted)] | umSSDRInverted; umSSDRColonblink = ssdrObj[FPSTR(_str_colonblink)] | umSSDRColonblink; umSSDRLeadingZero = ssdrObj[FPSTR(_str_leadingZero)] | umSSDRLeadingZero; umSSDRDisplayMask = ssdrObj[FPSTR(_str_displayMask)] | umSSDRDisplayMask; + umSSDRHours = ssdrObj[FPSTR(_str_hours)] | umSSDRHours; + umSSDRMinutes = ssdrObj[FPSTR(_str_minutes)] | umSSDRMinutes; + umSSDRSeconds = ssdrObj[FPSTR(_str_seconds)] | umSSDRSeconds; + umSSDRColons = ssdrObj[FPSTR(_str_colons)] | umSSDRColons; + umSSDRLight = ssdrObj[FPSTR(_str_light)] | umSSDRLight; + umSSDRDays = ssdrObj[FPSTR(_str_days)] | umSSDRDays; + umSSDRMonths = ssdrObj[FPSTR(_str_months)] | umSSDRMonths; + umSSDRYears = ssdrObj[FPSTR(_str_years)] | umSSDRYears; } } void onMqttConnect(bool sessionPresent) { - char subBuffer[48]; - if (mqttDeviceTopic[0] != 0) - { - _updateMQTT(); - //subscribe for sevenseg messages on the device topic - sprintf_P(subBuffer, PSTR("%s/%S/+/set"), mqttDeviceTopic, _str_name); - mqtt->subscribe(subBuffer, 2); + if (!umSSDRDisplayTime) { + return; } + #ifndef WLED_DISABLE_MQTT + if (WLED_MQTT_CONNECTED) { + char subBuffer[48]; + if (mqttDeviceTopic[0] != 0) + { + _updateMQTT(); + //subscribe for sevenseg messages on the device topic + sprintf_P(subBuffer, PSTR("%s/%S/+/set"), mqttDeviceTopic, _str_name); + mqtt->subscribe(subBuffer, 2); + } - if (mqttGroupTopic[0] != 0) - { - //subscribe for sevenseg messages on the group topic - sprintf_P(subBuffer, PSTR("%s/%S/+/set"), mqttGroupTopic, _str_name); - mqtt->subscribe(subBuffer, 2); + if (mqttGroupTopic[0] != 0) + { + //subscribe for sevenseg messages on the group topic + sprintf_P(subBuffer, PSTR("%s/%S/+/set"), mqttGroupTopic, _str_name); + mqtt->subscribe(subBuffer, 2); + } } + #endif } bool onMqttMessage(char *topic, char *payload) { - //If topic begins with sevenSeg cut it off, otherwise not our message. - size_t topicPrefixLen = strlen_P(PSTR("/wledSS/")); - if (strncmp_P(topic, PSTR("/wledSS/"), topicPrefixLen) == 0) { - topic += topicPrefixLen; - } else { - return false; - } - //We only care if the topic ends with /set - size_t topicLen = strlen(topic); - if (topicLen > 4 && - topic[topicLen - 4] == '/' && - topic[topicLen - 3] == 's' && - topic[topicLen - 2] == 'e' && - topic[topicLen - 1] == 't') - { - //Trim /set and handle it - topic[topicLen - 4] = '\0'; - _handleSetting(topic, payload); + #ifndef WLED_DISABLE_MQTT + if (umSSDRDisplayTime) { + //If topic begins with sevenSeg cut it off, otherwise not our message. + size_t topicPrefixLen = strlen_P(PSTR("/wledSS/")); + if (strncmp_P(topic, PSTR("/wledSS/"), topicPrefixLen) == 0) { + topic += topicPrefixLen; + } else { + return false; + } + //We only care if the topic ends with /set + size_t topicLen = strlen(topic); + if (topicLen > 4 && + topic[topicLen - 4] == '/' && + topic[topicLen - 3] == 's' && + topic[topicLen - 2] == 'e' && + topic[topicLen - 1] == 't') + { + //Trim /set and handle it + topic[topicLen - 4] = '\0'; + _handleSetting(topic, payload); + } } return true; + #endif } void addToConfig(JsonObject &root) { _addJSONObject(root); + + _updateMQTT(); } bool readFromConfig(JsonObject &root) { @@ -543,23 +707,25 @@ class UsermodSSDR : public Usermod { DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); return false; } - - umSSDRDisplayTime = (top[FPSTR(_str_timeEnabled)] | umSSDRDisplayTime); - umSSDREnableLDR = (top[FPSTR(_str_ldrEnabled)] | umSSDREnableLDR); - umSSDRInverted = (top[FPSTR(_str_inverted)] | umSSDRInverted); - umSSDRColonblink = (top[FPSTR(_str_colonblink)] | umSSDRColonblink); - umSSDRLeadingZero = (top[FPSTR(_str_leadingZero)] | umSSDRLeadingZero); - - umSSDRDisplayMask = top[FPSTR(_str_displayMask)] | umSSDRDisplayMask; - umSSDRHours = top[FPSTR(_str_hours)] | umSSDRHours; - umSSDRMinutes = top[FPSTR(_str_minutes)] | umSSDRMinutes; - umSSDRSeconds = top[FPSTR(_str_seconds)] | umSSDRSeconds; - umSSDRColons = top[FPSTR(_str_colons)] | umSSDRColons; - umSSDRDays = top[FPSTR(_str_days)] | umSSDRDays; - umSSDRMonths = top[FPSTR(_str_months)] | umSSDRMonths; - umSSDRYears = top[FPSTR(_str_years)] | umSSDRYears; - umSSDRBrightnessMin = top[FPSTR(_str_minBrightness)] | umSSDRBrightnessMin; - umSSDRBrightnessMax = top[FPSTR(_str_maxBrightness)] | umSSDRBrightnessMax; + umSSDRDisplayTime = (top[FPSTR(_str_timeEnabled)] | umSSDRDisplayTime); + umSSDREnableLDR = (top[FPSTR(_str_ldrEnabled)] | umSSDREnableLDR); + umSSDRInverted = (top[FPSTR(_str_inverted)] | umSSDRInverted); + umSSDRColonblink = (top[FPSTR(_str_colonblink)] | umSSDRColonblink); + umSSDRLeadingZero = (top[FPSTR(_str_leadingZero)] | umSSDRLeadingZero); + umSSDRDisplayMask = top[FPSTR(_str_displayMask)] | umSSDRDisplayMask; + umSSDRHours = top[FPSTR(_str_hours)] | umSSDRHours; + umSSDRMinutes = top[FPSTR(_str_minutes)] | umSSDRMinutes; + umSSDRSeconds = top[FPSTR(_str_seconds)] | umSSDRSeconds; + umSSDRColons = top[FPSTR(_str_colons)] | umSSDRColons; + umSSDRLight = top[FPSTR(_str_light)] | umSSDRLight; + umSSDRDays = top[FPSTR(_str_days)] | umSSDRDays; + umSSDRMonths = top[FPSTR(_str_months)] | umSSDRMonths; + umSSDRYears = top[FPSTR(_str_years)] | umSSDRYears; + umSSDRBrightnessMin = top[FPSTR(_str_minBrightness)] | umSSDRBrightnessMin; + umSSDRBrightnessMax = top[FPSTR(_str_maxBrightness)] | umSSDRBrightnessMax; + umSSDRLuxMin = top[FPSTR(_str_luxMin)] | umSSDRLuxMin; + umSSDRLuxMax = top[FPSTR(_str_luxMax)] | umSSDRLuxMax; + umSSDRInvertAutoBrightness = top[FPSTR(_str_invertAutoBrightness)] | umSSDRInvertAutoBrightness; DEBUG_PRINT(FPSTR(_str_name)); DEBUG_PRINTLN(F(" config (re)loaded.")); @@ -585,13 +751,16 @@ const char UsermodSSDR::_str_hours[] PROGMEM = "LED-Numbers-Hours"; const char UsermodSSDR::_str_minutes[] PROGMEM = "LED-Numbers-Minutes"; const char UsermodSSDR::_str_seconds[] PROGMEM = "LED-Numbers-Seconds"; const char UsermodSSDR::_str_colons[] PROGMEM = "LED-Numbers-Colons"; +const char UsermodSSDR::_str_light[] PROGMEM = "LED-Numbers-Light"; const char UsermodSSDR::_str_days[] PROGMEM = "LED-Numbers-Day"; const char UsermodSSDR::_str_months[] PROGMEM = "LED-Numbers-Month"; const char UsermodSSDR::_str_years[] PROGMEM = "LED-Numbers-Year"; const char UsermodSSDR::_str_ldrEnabled[] PROGMEM = "enable-auto-brightness"; const char UsermodSSDR::_str_minBrightness[] PROGMEM = "auto-brightness-min"; const char UsermodSSDR::_str_maxBrightness[] PROGMEM = "auto-brightness-max"; - +const char UsermodSSDR::_str_luxMin[] PROGMEM = "lux-min"; +const char UsermodSSDR::_str_luxMax[] PROGMEM = "lux-max"; +const char UsermodSSDR::_str_invertAutoBrightness[] PROGMEM = "invert-auto-brightness"; static UsermodSSDR seven_segment_display_reloaded; REGISTER_USERMOD(seven_segment_display_reloaded); \ No newline at end of file From 50d54e2df66d282bb16146c48c7a89f1867e057d Mon Sep 17 00:00:00 2001 From: KrX3D Date: Sat, 12 Apr 2025 13:31:05 +0200 Subject: [PATCH 03/14] usermod v2 --- .../library.json | 3 -- .../library.json | 3 ++ .../readme.md | 0 .../seven_segment_display_reloaded_v2.cpp} | 36 +++++++++---------- wled00/const.h | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) delete mode 100644 usermods/seven_segment_display_reloaded/library.json create mode 100644 usermods/seven_segment_display_reloaded_v2/library.json rename usermods/{seven_segment_display_reloaded => seven_segment_display_reloaded_v2}/readme.md (100%) rename usermods/{seven_segment_display_reloaded/seven_segment_display_reloaded.cpp => seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp} (94%) diff --git a/usermods/seven_segment_display_reloaded/library.json b/usermods/seven_segment_display_reloaded/library.json deleted file mode 100644 index fdce8b5360..0000000000 --- a/usermods/seven_segment_display_reloaded/library.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name:": "seven_segment_display_reloaded" -} \ No newline at end of file diff --git a/usermods/seven_segment_display_reloaded_v2/library.json b/usermods/seven_segment_display_reloaded_v2/library.json new file mode 100644 index 0000000000..9b8e4a4b50 --- /dev/null +++ b/usermods/seven_segment_display_reloaded_v2/library.json @@ -0,0 +1,3 @@ +{ + "name:": "seven_segment_display_reloaded_v2" +} \ No newline at end of file diff --git a/usermods/seven_segment_display_reloaded/readme.md b/usermods/seven_segment_display_reloaded_v2/readme.md similarity index 100% rename from usermods/seven_segment_display_reloaded/readme.md rename to usermods/seven_segment_display_reloaded_v2/readme.md diff --git a/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp similarity index 94% rename from usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp rename to usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp index 7f5c1c562c..6a67b3a32d 100644 --- a/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp @@ -1,6 +1,6 @@ #include "wled.h" -#ifndef WLED_ENABLE_MQTT +#ifdef WLED_DISABLE_MQTT #error "This user mod requires MQTT to be enabled." #endif @@ -707,23 +707,23 @@ class UsermodSSDR : public Usermod { DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); return false; } - umSSDRDisplayTime = (top[FPSTR(_str_timeEnabled)] | umSSDRDisplayTime); - umSSDREnableLDR = (top[FPSTR(_str_ldrEnabled)] | umSSDREnableLDR); - umSSDRInverted = (top[FPSTR(_str_inverted)] | umSSDRInverted); - umSSDRColonblink = (top[FPSTR(_str_colonblink)] | umSSDRColonblink); - umSSDRLeadingZero = (top[FPSTR(_str_leadingZero)] | umSSDRLeadingZero); - umSSDRDisplayMask = top[FPSTR(_str_displayMask)] | umSSDRDisplayMask; - umSSDRHours = top[FPSTR(_str_hours)] | umSSDRHours; - umSSDRMinutes = top[FPSTR(_str_minutes)] | umSSDRMinutes; - umSSDRSeconds = top[FPSTR(_str_seconds)] | umSSDRSeconds; - umSSDRColons = top[FPSTR(_str_colons)] | umSSDRColons; - umSSDRLight = top[FPSTR(_str_light)] | umSSDRLight; - umSSDRDays = top[FPSTR(_str_days)] | umSSDRDays; - umSSDRMonths = top[FPSTR(_str_months)] | umSSDRMonths; - umSSDRYears = top[FPSTR(_str_years)] | umSSDRYears; - umSSDRBrightnessMin = top[FPSTR(_str_minBrightness)] | umSSDRBrightnessMin; - umSSDRBrightnessMax = top[FPSTR(_str_maxBrightness)] | umSSDRBrightnessMax; - umSSDRLuxMin = top[FPSTR(_str_luxMin)] | umSSDRLuxMin; + umSSDRDisplayTime = (top[FPSTR(_str_timeEnabled)] | umSSDRDisplayTime); + umSSDREnableLDR = (top[FPSTR(_str_ldrEnabled)] | umSSDREnableLDR); + umSSDRInverted = (top[FPSTR(_str_inverted)] | umSSDRInverted); + umSSDRColonblink = (top[FPSTR(_str_colonblink)] | umSSDRColonblink); + umSSDRLeadingZero = (top[FPSTR(_str_leadingZero)] | umSSDRLeadingZero); + umSSDRDisplayMask = top[FPSTR(_str_displayMask)] | umSSDRDisplayMask; + umSSDRHours = top[FPSTR(_str_hours)] | umSSDRHours; + umSSDRMinutes = top[FPSTR(_str_minutes)] | umSSDRMinutes; + umSSDRSeconds = top[FPSTR(_str_seconds)] | umSSDRSeconds; + umSSDRColons = top[FPSTR(_str_colons)] | umSSDRColons; + umSSDRLight = top[FPSTR(_str_light)] | umSSDRLight; + umSSDRDays = top[FPSTR(_str_days)] | umSSDRDays; + umSSDRMonths = top[FPSTR(_str_months)] | umSSDRMonths; + umSSDRYears = top[FPSTR(_str_years)] | umSSDRYears; + umSSDRBrightnessMin = top[FPSTR(_str_minBrightness)] | umSSDRBrightnessMin; + umSSDRBrightnessMax = top[FPSTR(_str_maxBrightness)] | umSSDRBrightnessMax; + umSSDRLuxMin = top[FPSTR(_str_luxMin)] | umSSDRLuxMin; umSSDRLuxMax = top[FPSTR(_str_luxMax)] | umSSDRLuxMax; umSSDRInvertAutoBrightness = top[FPSTR(_str_invertAutoBrightness)] | umSSDRInvertAutoBrightness; diff --git a/wled00/const.h b/wled00/const.h index 2b460f3f18..584f47b743 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -176,7 +176,7 @@ #define USERMOD_ID_SEVEN_SEGMENT_DISPLAY 21 //Usermod "usermod_v2_seven_segment_display.h" #define USERMOD_RGB_ROTARY_ENCODER 22 //Usermod "rgb-rotary-encoder.h" #define USERMOD_ID_QUINLED_AN_PENTA 23 //Usermod "quinled-an-penta.h" -#define USERMOD_ID_SSDR 24 //Usermod "usermod_v2_seven_segment_display_reloaded.h" +#define USERMOD_ID_SSDR 24 //Usermod "seven_segment_display_reloaded_v2.cpp" #define USERMOD_ID_CRONIXIE 25 //Usermod "usermod_cronixie.h" #define USERMOD_ID_WIZLIGHTS 26 //Usermod "wizlights.h" #define USERMOD_ID_WORDCLOCK 27 //Usermod "usermod_v2_word_clock.h" From afcc54f14e4d5f887fd530a393e3d9d3ff0fc4c2 Mon Sep 17 00:00:00 2001 From: KrX3D Date: Sat, 12 Apr 2025 13:34:50 +0200 Subject: [PATCH 04/14] Update readme.md --- usermods/seven_segment_display_reloaded_v2/readme.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/usermods/seven_segment_display_reloaded_v2/readme.md b/usermods/seven_segment_display_reloaded_v2/readme.md index 53f94cb321..642e182ed0 100644 --- a/usermods/seven_segment_display_reloaded_v2/readme.md +++ b/usermods/seven_segment_display_reloaded_v2/readme.md @@ -8,6 +8,10 @@ Very loosely based on the existing usermod "seven segment display". Add the compile-time option `-D USERMOD_SSDR` to your `platformio.ini` (or `platformio_override.ini`) or use `#define USERMOD_SSDR` in `my_config.h`. +In your `platformio.ini` you also need to add this to your env: + +- custom_usermods = seven_segment_display_reloaded_v2 + For the auto brightness option, the usermod **SN_Photoresistor** or **BH1750_V2** has to be installed as well. See [SN_Photoresistor/readme.md](SN_Photoresistor/readme.md) or [BH1750_V2/readme.md](BH1750_V2/readme.md) for instructions. ## Available Compile-Time Parameters @@ -269,4 +273,4 @@ or With these modifications, the SSDR usermod becomes even more versatile, allowing it to be used on a wide variety of segment clocks and projects. -*Note:* The ability to override the LED segment mapping via `umSSDR_NUMBERS` provides additional flexibility for adapting to different physical displays. \ No newline at end of file +*Note:* The ability to override the LED segment mapping via `umSSDR_NUMBERS` provides additional flexibility for adapting to different physical displays. From ae785864dc8cf4b57542e85f437dd880eb8a0ce7 Mon Sep 17 00:00:00 2001 From: KrX3D Date: Sat, 12 Apr 2025 13:36:23 +0200 Subject: [PATCH 05/14] Update readme.md --- usermods/seven_segment_display_reloaded_v2/readme.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/usermods/seven_segment_display_reloaded_v2/readme.md b/usermods/seven_segment_display_reloaded_v2/readme.md index 642e182ed0..c36965c2cf 100644 --- a/usermods/seven_segment_display_reloaded_v2/readme.md +++ b/usermods/seven_segment_display_reloaded_v2/readme.md @@ -8,9 +8,14 @@ Very loosely based on the existing usermod "seven segment display". Add the compile-time option `-D USERMOD_SSDR` to your `platformio.ini` (or `platformio_override.ini`) or use `#define USERMOD_SSDR` in `my_config.h`. -In your `platformio.ini` you also need to add this to your env: +# Compiling -- custom_usermods = seven_segment_display_reloaded_v2 +To enable, add `seven_segment_display_reloaded_v2` to your `custom_usermods` (e.g. in `platformio_override.ini`) +```ini +[env:usermod_ssdr_d1_mini] +extends = env:d1_mini +custom_usermods = ${env:d1_mini.custom_usermods} seven_segment_display_reloaded_v2 +``` For the auto brightness option, the usermod **SN_Photoresistor** or **BH1750_V2** has to be installed as well. See [SN_Photoresistor/readme.md](SN_Photoresistor/readme.md) or [BH1750_V2/readme.md](BH1750_V2/readme.md) for instructions. From 55b032640882bfc68da7a443168ab34b210a36a6 Mon Sep 17 00:00:00 2001 From: KrX3D Date: Sun, 27 Apr 2025 01:37:21 +0200 Subject: [PATCH 06/14] if "SN_Photoresistor" in usermods: fixed some problems, made and BH1750_v2 work again from this --- .../library.json | 5 +- .../setup_deps.py | 8 + .../seven_segment_display_reloaded_v2.cpp | 387 +++++------------- .../seven_segment_display_reloaded_v2.h | 234 +++++++++++ 4 files changed, 359 insertions(+), 275 deletions(-) create mode 100644 usermods/seven_segment_display_reloaded_v2/setup_deps.py create mode 100644 usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h diff --git a/usermods/seven_segment_display_reloaded_v2/library.json b/usermods/seven_segment_display_reloaded_v2/library.json index 9b8e4a4b50..86a3171e12 100644 --- a/usermods/seven_segment_display_reloaded_v2/library.json +++ b/usermods/seven_segment_display_reloaded_v2/library.json @@ -1,3 +1,6 @@ { - "name:": "seven_segment_display_reloaded_v2" + "name": "seven_segment_display_reloaded_v2", + "build": { + "extraScript": "setup_deps.py" + } } \ No newline at end of file diff --git a/usermods/seven_segment_display_reloaded_v2/setup_deps.py b/usermods/seven_segment_display_reloaded_v2/setup_deps.py new file mode 100644 index 0000000000..e784aa3a36 --- /dev/null +++ b/usermods/seven_segment_display_reloaded_v2/setup_deps.py @@ -0,0 +1,8 @@ +Import('env') + +usermods = env.GetProjectOption("custom_usermods","").split() +# Check for partner usermods +if "SN_Photoresistor" in usermods: + env.Append(CPPDEFINES=[("USERMOD_SN_PHOTORESISTOR")]) +if any(mod in ("BH1750_v2", "BH1750") for mod in usermods): + env.Append(CPPDEFINES=[("USERMOD_BH1750")]) diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp index 6a67b3a32d..82ba34383e 100644 --- a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp @@ -1,206 +1,22 @@ -#include "wled.h" - -#ifdef WLED_DISABLE_MQTT -#error "This user mod requires MQTT to be enabled." -#endif - -class UsermodSSDR : public Usermod { - -//#define REFRESHTIME 497 - -private: - //Runtime variables. - unsigned long umSSDRLastRefresh = 0; - unsigned long umSSDRResfreshTime = 3000; - uint16_t umSSDRLength = 0; - - // Configurable settings for the SSDR Usermod - // Enabled usermod - #ifndef umSSDR_ENABLED - #define umSSDR_ENABLED false - #endif - - #ifndef umSSDR_ENABLE_AUTO_BRIGHTNESS - #define umSSDR_ENABLE_AUTO_BRIGHTNESS false - #endif - - #ifndef umSSDR_BRIGHTNESS_MIN - #define umSSDR_BRIGHTNESS_MIN 0 - #endif - - #ifndef umSSDR_BRIGHTNESS_MAX - #define umSSDR_BRIGHTNESS_MAX 255 - #endif - - #ifndef umSSDR_INVERT_AUTO_BRIGHTNESS - #define umSSDR_INVERT_AUTO_BRIGHTNESS false - #endif - - #ifndef umSSDR_LUX_MIN - #define umSSDR_LUX_MIN 0 - #endif - - #ifndef umSSDR_LUX_MAX - #define umSSDR_LUX_MAX 1000 - #endif - - #ifndef umSSDR_INVERTED - #define umSSDR_INVERTED false - #endif - - #ifndef umSSDR_COLONBLINK - #define umSSDR_COLONBLINK true - #endif - - #ifndef umSSDR_LEADING_ZERO - #define umSSDR_LEADING_ZERO false - #endif - - // Display mask for physical layout - /*// H - 00-23 hours - // h - 01-12 hours - // k - 01-24 hours - // m - 00-59 minutes - // s - 00-59 seconds - // d - 01-31 day of month - // M - 01-12 month - // y - 21 last two positions of year - // Y - 2021 year - // L - Light LED - // This option defines a separate LED (or set of LEDs) that can be controlled independently - // from the other clock display LEDs. It can be switched on or off to provide additional - // lighting for the display or serve as an ambient light source, without affecting the - // clock's visual display of time and date. - // : for a colon - */ - - #ifndef umSSDR_DISPLAY_MASK - #define umSSDR_DISPLAY_MASK "H:m" - #endif - - #ifndef umSSDR_HOURS - #define umSSDR_HOURS "" - #endif - - #ifndef umSSDR_MINUTES - #define umSSDR_MINUTES "" - #endif - - #ifndef umSSDR_SECONDS - #define umSSDR_SECONDS "" - #endif - - #ifndef umSSDR_COLONS - #define umSSDR_COLONS "" - #endif - - #ifndef umSSDR_LIGHT - #define umSSDR_LIGHT "" - #endif - - #ifndef umSSDR_DAYS - #define umSSDR_DAYS "" - #endif - - #ifndef umSSDR_MONTHS - #define umSSDR_MONTHS "" - #endif - - #ifndef umSSDR_YEARS - #define umSSDR_YEARS "" - #endif - - #ifndef umSSDR_NUMBERS - /* Segment order, seen from the front: - < A > - /\ /\ - F B - \/ \/ - < G > - /\ /\ - E C - \/ \/ - < D > - */ - uint8_t umSSDRNumbers[11][7] = { - // A B C D E F G - { 1, 1, 1, 1, 1, 1, 0 }, // 0 - { 0, 1, 1, 0, 0, 0, 0 }, // 1 - { 1, 1, 0, 1, 1, 0, 1 }, // 2 - { 1, 1, 1, 1, 0, 0, 1 }, // 3 - { 0, 1, 1, 0, 0, 1, 1 }, // 4 - { 1, 0, 1, 1, 0, 1, 1 }, // 5 - { 1, 0, 1, 1, 1, 1, 1 }, // 6 - { 1, 1, 1, 0, 0, 0, 0 }, // 7 - { 1, 1, 1, 1, 1, 1, 1 }, // 8 - { 1, 1, 1, 1, 0, 1, 1 }, // 9 - { 0, 0, 0, 0, 0, 0, 0 } // blank - }; - #else - uint8_t umSSDRNumbers[11][10] = umSSDR_NUMBERS; - #endif - - bool umSSDRDisplayTime = umSSDR_ENABLED; - bool umSSDREnableLDR = umSSDR_ENABLE_AUTO_BRIGHTNESS; - uint16_t umSSDRBrightnessMin = umSSDR_BRIGHTNESS_MIN; - uint16_t umSSDRBrightnessMax = umSSDR_BRIGHTNESS_MAX; - bool umSSDRInvertAutoBrightness = umSSDR_INVERT_AUTO_BRIGHTNESS; - uint16_t umSSDRLuxMin = umSSDR_LUX_MIN; - uint16_t umSSDRLuxMax = umSSDR_LUX_MAX; - bool umSSDRInverted = umSSDR_INVERTED; - bool umSSDRColonblink = umSSDR_COLONBLINK; - bool umSSDRLeadingZero = umSSDR_LEADING_ZERO; - String umSSDRDisplayMask = umSSDR_DISPLAY_MASK; - String umSSDRHours = umSSDR_HOURS; - String umSSDRMinutes = umSSDR_MINUTES; - String umSSDRSeconds = umSSDR_SECONDS; - String umSSDRColons = umSSDR_COLONS; - String umSSDRLight = umSSDR_LIGHT; - String umSSDRDays = umSSDR_DAYS; - String umSSDRMonths = umSSDR_MONTHS; - String umSSDRYears = umSSDR_YEARS; - - bool* umSSDRMask = 0; - bool disableUmLedControl = false; - - //String to reduce flash memory usage - static const char _str_name[]; - static const char _str_timeEnabled[]; - static const char _str_ldrEnabled[]; - static const char _str_minBrightness[]; - static const char _str_maxBrightness[]; - static const char _str_luxMin[]; - static const char _str_luxMax[]; - static const char _str_invertAutoBrightness[]; - static const char _str_inverted[]; - static const char _str_colonblink[]; - static const char _str_leadingZero[]; - static const char _str_displayMask[]; - static const char _str_hours[]; - static const char _str_minutes[]; - static const char _str_seconds[]; - static const char _str_colons[]; - static const char _str_light[]; - static const char _str_days[]; - static const char _str_months[]; - static const char _str_years[]; - #ifdef USERMOD_SN_PHOTORESISTOR - Usermod_SN_Photoresistor *ptr; -#else - void* ptr = nullptr; + #include "SN_Photoresistor.h" #endif #ifdef USERMOD_BH1750 - Usermod_BH1750* bh1750 = nullptr; -#else - void* bh1750 = nullptr; + #include "BH1750_v2.h" #endif - void _overlaySevenSegmentDraw() { +#include "seven_segment_display_reloaded_v2.h" + +#ifdef WLED_DISABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + + void UsermodSSDR::_overlaySevenSegmentDraw() { int displayMaskLen = static_cast(umSSDRDisplayMask.length()); bool colonsDone = false; bool lightDone = false; _setAllFalse(); + for (int index = 0; index < displayMaskLen; index++) { int timeVar = 0; switch (umSSDRDisplayMask[index]) { @@ -233,7 +49,7 @@ class UsermodSSDR : public Usermod { _showElements(&umSSDRMonths, timeVar, 0, 0); break; case 'y': - timeVar = second(localTime); + timeVar = year(localTime) % 100; // Fix: Get last two digits of year _showElements(&umSSDRYears, timeVar, 0, 0); break; case 'Y': @@ -257,7 +73,7 @@ class UsermodSSDR : public Usermod { _setMaskToLeds(); } - void _setColons() { + void UsermodSSDR::_setColons() { if ( umSSDRColonblink ) { if ( second(localTime) % 2 == 0 ) { _showElements(&umSSDRColons, 0, 1, 0); @@ -267,33 +83,31 @@ class UsermodSSDR : public Usermod { } } - void _showElements(String *map, int timevar, bool isColon, bool removeZero) { + void UsermodSSDR::_showElements(String *map, int timevar, bool isColon, bool removeZero) { if ((map != nullptr) && (*map != nullptr) && !(*map).equals("")) { - int length = String(timevar).length(); + int length = (timevar == 0) ? 1 : log10(timevar) + 1; bool addZero = false; if (length == 1) { length = 2; addZero = true; } int timeArr[length]; - if(addZero) { - if(removeZero) - { - timeArr[0] = timevar; - timeArr[1] = 10; - } - else - { + + if (addZero) { + if (removeZero) { + timeArr[0] = timevar; + timeArr[1] = 10; // blank digit + } else { timeArr[0] = timevar; timeArr[1] = 0; } } else { - int count = 0; - while (timevar) { - timeArr[count] = timevar%10; - timevar /= 10; - count++; - }; + int count = 0; + while (timevar) { + timeArr[count] = timevar % 10; + timevar /= 10; + count++; + } } int colonsLen = static_cast((*map).length()); @@ -311,20 +125,26 @@ class UsermodSSDR : public Usermod { range = true; break; case ':': - _setLeds(_checkForNumber(count, index, map), lastSeenLedNr, range, countSegments, timeArr[countDigit], isColon); + if (countDigit < length) { // Prevent array out of bounds + _setLeds(_checkForNumber(count, index, map), lastSeenLedNr, range, countSegments, timeArr[countDigit], isColon); + } count = 0; range = false; countDigit++; countSegments = 0; break; case ';': - _setLeds(_checkForNumber(count, index, map), lastSeenLedNr, range, countSegments, timeArr[countDigit], isColon); + if (countDigit < length) { // Prevent array out of bounds + _setLeds(_checkForNumber(count, index, map), lastSeenLedNr, range, countSegments, timeArr[countDigit], isColon); + } count = 0; range = false; countSegments++; break; case ',': - _setLeds(_checkForNumber(count, index, map), lastSeenLedNr, range, countSegments, timeArr[countDigit], isColon); + if (countDigit < length) { // Prevent array out of bounds + _setLeds(_checkForNumber(count, index, map), lastSeenLedNr, range, countSegments, timeArr[countDigit], isColon); + } count = 0; range = false; break; @@ -333,16 +153,20 @@ class UsermodSSDR : public Usermod { break; } } - _setLeds(_checkForNumber(count, colonsLen, map), lastSeenLedNr, range, countSegments, timeArr[countDigit], isColon); + + // Process final segment if any + if (count > 0 && countDigit < length) { + _setLeds(_checkForNumber(count, colonsLen, map), lastSeenLedNr, range, countSegments, timeArr[countDigit], isColon); + } } } - void _setLeds(int lednr, int lastSeenLedNr, bool range, int countSegments, int number, bool colon) { - if ((lednr < 0) || (lednr >= umSSDRLength)) return; // prevent array bounds violation + void UsermodSSDR::_setLeds(int lednr, int lastSeenLedNr, bool range, int countSegments, int number, bool colon) { + if (!umSSDRMask || (lednr < 0) || (lednr >= umSSDRLength)) return; // prevent array bounds violation if (!(colon && umSSDRColonblink) && ((number < 0) || (countSegments < 0))) return; + if ((colon && umSSDRColonblink) || umSSDRNumbers[number][countSegments]) { - if (range) { for(int i = max(0, lastSeenLedNr); i <= lednr; i++) { umSSDRMask[i] = true; @@ -353,26 +177,32 @@ class UsermodSSDR : public Usermod { } } - void _setMaskToLeds() { - for(int i = 0; i <= umSSDRLength; i++) { + void UsermodSSDR::_setMaskToLeds() { + if (!umSSDRMask) return; // Safety check + + for(int i = 0; i < umSSDRLength; i++) { // Changed <= to < to prevent buffer overflow if ((!umSSDRInverted && !umSSDRMask[i]) || (umSSDRInverted && umSSDRMask[i])) { strip.setPixelColor(i, 0x000000); } } } - void _setAllFalse() { - for(int i = 0; i <= umSSDRLength; i++) { + void UsermodSSDR::_setAllFalse() { + if (!umSSDRMask) return; // Safety check + + for(int i = 0; i < umSSDRLength; i++) { // Changed <= to < to prevent buffer overflow umSSDRMask[i] = false; } } - int _checkForNumber(int count, int index, String *map) { + int UsermodSSDR::_checkForNumber(int count, int index, String *map) { + if (count <= 0 || map == nullptr || index < count) return 0; // Added safety checks + String number = (*map).substring(index - count, index); return number.toInt(); } - void _publishMQTTint_P(const char *subTopic, int value) + void UsermodSSDR::_publishMQTTint_P(const char *subTopic, int value) { #ifndef WLED_DISABLE_MQTT if (WLED_MQTT_CONNECTED) { @@ -380,37 +210,41 @@ class UsermodSSDR : public Usermod { char buffer[64]; char valBuffer[12]; - sprintf_P(buffer, PSTR("%s/%S/%S"), mqttDeviceTopic, _str_name, subTopic); - sprintf_P(valBuffer, PSTR("%d"), value); + int result = snprintf_P(buffer, sizeof(buffer), PSTR("%s/%S/%S"), mqttDeviceTopic, _str_name, subTopic); + if (result < 0 || result >= sizeof(buffer)) return; // Buffer overflow check + + snprintf_P(valBuffer, sizeof(valBuffer), PSTR("%d"), value); mqtt->publish(buffer, 2, true, valBuffer); } #endif } - void _publishMQTTstr_P(const char *subTopic, String Value) + void UsermodSSDR::_publishMQTTstr_P(const char *subTopic, String Value) { #ifndef WLED_DISABLE_MQTT if (WLED_MQTT_CONNECTED) { if(mqtt == NULL) return; char buffer[64]; - sprintf_P(buffer, PSTR("%s/%S/%S"), mqttDeviceTopic, _str_name, subTopic); + int result = snprintf_P(buffer, sizeof(buffer), PSTR("%s/%S/%S"), mqttDeviceTopic, _str_name, subTopic); + if (result < 0 || result >= sizeof(buffer)) return; // Buffer overflow check + mqtt->publish(buffer, 2, true, Value.c_str(), Value.length()); } #endif } - bool _cmpIntSetting_P(char *topic, char *payload, const char *setting, void *value) + bool UsermodSSDR::_cmpIntSetting_P(char *topic, char *payload, const char *setting, void *value) { if (strcmp_P(topic, setting) == 0) { - *((int *)value) = strtol(payload, NULL, 10); + *((int *)value) = strtol(payload, nullptr, 10); // Changed NULL to nullptr _publishMQTTint_P(setting, *((int *)value)); return true; } return false; } - bool _handleSetting(char *topic, char *payload) { + bool UsermodSSDR::_handleSetting(char *topic, char *payload) { if (_cmpIntSetting_P(topic, payload, _str_timeEnabled, &umSSDRDisplayTime)) { return true; } @@ -434,7 +268,7 @@ class UsermodSSDR : public Usermod { return false; } - void _updateMQTT() + void UsermodSSDR::_updateMQTT() { _publishMQTTint_P(_str_timeEnabled, umSSDRDisplayTime); _publishMQTTint_P(_str_ldrEnabled, umSSDREnableLDR); @@ -458,7 +292,7 @@ class UsermodSSDR : public Usermod { _publishMQTTstr_P(_str_displayMask, umSSDRDisplayMask); } - void _addJSONObject(JsonObject& root) { + void UsermodSSDR::_addJSONObject(JsonObject& root) { JsonObject ssdrObj = root[FPSTR(_str_name)]; if (ssdrObj.isNull()) { ssdrObj = root.createNestedObject(FPSTR(_str_name)); @@ -485,19 +319,18 @@ class UsermodSSDR : public Usermod { ssdrObj[FPSTR(_str_years)] = umSSDRYears; } -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() { + void UsermodSSDR::setup() { umSSDRLength = strip.getLengthTotal(); - if (umSSDRMask != 0) { - umSSDRMask = (bool*) realloc(umSSDRMask, umSSDRLength * sizeof(bool)); - } else { - umSSDRMask = (bool*) malloc(umSSDRLength * sizeof(bool)); + + // Fixed memory allocation to prevent leaks + if (umSSDRMask != nullptr) { + free(umSSDRMask); // Free previous allocation if exists + } + umSSDRMask = (bool*) calloc(umSSDRLength, sizeof(bool)); // Use calloc to initialize to 0 + + if (umSSDRMask == nullptr) { + DEBUG_PRINTLN(F("Failed to allocate memory for SSDR mask")); + return; // Early return on memory allocation failure } _setAllFalse(); @@ -507,16 +340,25 @@ class UsermodSSDR : public Usermod { #ifdef USERMOD_BH1750 bh1750 = (Usermod_BH1750*) UsermodManager::lookup(USERMOD_ID_BH1750); #endif - DEBUG_PRINTLN(F("Setup done")); + DEBUG_PRINTLN(F("SSDR setup done")); + } + + // Clean up any allocated memory in the destructor + UsermodSSDR::~UsermodSSDR() { + if (umSSDRMask != nullptr) { + free(umSSDRMask); + umSSDRMask = nullptr; + } } /* - * loop() is called continuously. Here you can check for events, read sensors, etc. - */ - void loop() { - if (!umSSDRDisplayTime || strip.isUpdating()) { + * loop() is called continuously. Here you can check for events, read sensors, etc. + */ + void UsermodSSDR::loop() { + if (!umSSDRDisplayTime || strip.isUpdating() || umSSDRMask == nullptr) { return; } + #if defined(USERMOD_SN_PHOTORESISTOR) || defined(USERMOD_BH1750) if(bri != 0 && umSSDREnableLDR && (millis() - umSSDRLastRefresh > umSSDRResfreshTime) && !disableUmLedControl) { float lux = -1; // Initialize lux with an invalid value @@ -535,10 +377,13 @@ class UsermodSSDR : public Usermod { if (lux >= 0) { // Ensure we got a valid lux value uint16_t brightness; - if (!umSSDRInvertAutoBrightness) { - brightness = map(lux, umSSDRLuxMin, umSSDRLuxMax, umSSDRBrightnessMin, umSSDRBrightnessMax); + // Constrain lux values within defined range + float constrainedLux = constrain(lux, umSSDRLuxMin, umSSDRLuxMax); + + if (!umSSDRInvertAutoBrightness) { + brightness = map(constrainedLux, umSSDRLuxMin, umSSDRLuxMax, umSSDRBrightnessMin, umSSDRBrightnessMax); } else { - brightness = map(lux, umSSDRLuxMin, umSSDRLuxMax, umSSDRBrightnessMax, umSSDRBrightnessMin); + brightness = map(constrainedLux, umSSDRLuxMin, umSSDRLuxMax, umSSDRBrightnessMax, umSSDRBrightnessMin); } if (bri != brightness) { @@ -552,23 +397,18 @@ class UsermodSSDR : public Usermod { #endif } - void handleOverlayDraw() { - if (umSSDRDisplayTime && !disableUmLedControl) { + void UsermodSSDR::handleOverlayDraw() { + if (umSSDRDisplayTime && !disableUmLedControl && umSSDRMask != nullptr) { _overlaySevenSegmentDraw(); } } - //Can be used outside of this usermod - void disableOutputFunction(bool state) { - this->disableUmLedControl = state; - } - -/* + /* * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. * Below it is shown how this could be used for e.g. a light sensor */ - void addToJsonInfo(JsonObject& root) { + void UsermodSSDR::addToJsonInfo(JsonObject& root) { JsonObject user = root[F("u")]; if (user.isNull()) { user = root.createNestedObject(F("u")); @@ -603,7 +443,7 @@ class UsermodSSDR : public Usermod { * 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) { + void UsermodSSDR::addToJsonState(JsonObject& root) { JsonObject user = root[F("u")]; if (user.isNull()) { user = root.createNestedObject(F("u")); @@ -615,7 +455,7 @@ class UsermodSSDR : 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 */ - void readFromJsonState(JsonObject& root) { + void UsermodSSDR::readFromJsonState(JsonObject& root) { JsonObject user = root[F("u")]; if (!user.isNull()) { JsonObject ssdrObj = user[FPSTR(_str_name)]; @@ -641,7 +481,7 @@ class UsermodSSDR : public Usermod { } } - void onMqttConnect(bool sessionPresent) { + void UsermodSSDR::onMqttConnect(bool sessionPresent) { if (!umSSDRDisplayTime) { return; } @@ -666,7 +506,7 @@ class UsermodSSDR : public Usermod { #endif } - bool onMqttMessage(char *topic, char *payload) { + bool UsermodSSDR::onMqttMessage(char *topic, char *payload) { #ifndef WLED_DISABLE_MQTT if (umSSDRDisplayTime) { //If topic begins with sevenSeg cut it off, otherwise not our message. @@ -693,13 +533,13 @@ class UsermodSSDR : public Usermod { #endif } - void addToConfig(JsonObject &root) { + void UsermodSSDR::addToConfig(JsonObject &root) { _addJSONObject(root); _updateMQTT(); } - bool readFromConfig(JsonObject &root) { + bool UsermodSSDR::readFromConfig(JsonObject &root) { JsonObject top = root[FPSTR(_str_name)]; if (top.isNull()) { @@ -733,13 +573,12 @@ class UsermodSSDR : public Usermod { return true; } /* - * 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. - */ - uint16_t getId() { + * 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. + */ + uint16_t UsermodSSDR::getId() { return USERMOD_ID_SSDR; } -}; const char UsermodSSDR::_str_name[] PROGMEM = "UsermodSSDR"; const char UsermodSSDR::_str_timeEnabled[] PROGMEM = "enabled"; diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h new file mode 100644 index 0000000000..d786b77985 --- /dev/null +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h @@ -0,0 +1,234 @@ +#pragma once +#include "wled.h" + +//#define REFRESHTIME 497 + +class UsermodSSDR : public Usermod { + private: + //Runtime variables. + unsigned long umSSDRLastRefresh = 0; + unsigned long umSSDRResfreshTime = 3000; + uint16_t umSSDRLength = 0; + + // Configurable settings for the SSDR Usermod + // Enabled usermod + #ifndef umSSDR_ENABLED + #define umSSDR_ENABLED false + #endif + + #ifndef umSSDR_ENABLE_AUTO_BRIGHTNESS + #define umSSDR_ENABLE_AUTO_BRIGHTNESS false + #endif + + #ifndef umSSDR_BRIGHTNESS_MIN + #define umSSDR_BRIGHTNESS_MIN 0 + #endif + + #ifndef umSSDR_BRIGHTNESS_MAX + #define umSSDR_BRIGHTNESS_MAX 255 + #endif + + #ifndef umSSDR_INVERT_AUTO_BRIGHTNESS + #define umSSDR_INVERT_AUTO_BRIGHTNESS false + #endif + + #ifndef umSSDR_LUX_MIN + #define umSSDR_LUX_MIN 0 + #endif + + #ifndef umSSDR_LUX_MAX + #define umSSDR_LUX_MAX 1000 + #endif + + #ifndef umSSDR_INVERTED + #define umSSDR_INVERTED false + #endif + + #ifndef umSSDR_COLONBLINK + #define umSSDR_COLONBLINK true + #endif + + #ifndef umSSDR_LEADING_ZERO + #define umSSDR_LEADING_ZERO false + #endif + + // Display mask for physical layout + /*// H - 00-23 hours + // h - 01-12 hours + // k - 01-24 hours + // m - 00-59 minutes + // s - 00-59 seconds + // d - 01-31 day of month + // M - 01-12 month + // y - 21 last two positions of year + // Y - 2021 year + // L - Light LED + // This option defines a separate LED (or set of LEDs) that can be controlled independently + // from the other clock display LEDs. It can be switched on or off to provide additional + // lighting for the display or serve as an ambient light source, without affecting the + // clock's visual display of time and date. + // : for a colon + */ + + #ifndef umSSDR_DISPLAY_MASK + #define umSSDR_DISPLAY_MASK "H:m" + #endif + + #ifndef umSSDR_HOURS + #define umSSDR_HOURS "" + #endif + + #ifndef umSSDR_MINUTES + #define umSSDR_MINUTES "" + #endif + + #ifndef umSSDR_SECONDS + #define umSSDR_SECONDS "" + #endif + + #ifndef umSSDR_COLONS + #define umSSDR_COLONS "" + #endif + + #ifndef umSSDR_LIGHT + #define umSSDR_LIGHT "" + #endif + + #ifndef umSSDR_DAYS + #define umSSDR_DAYS "" + #endif + + #ifndef umSSDR_MONTHS + #define umSSDR_MONTHS "" + #endif + + #ifndef umSSDR_YEARS + #define umSSDR_YEARS "" + #endif + + #ifndef umSSDR_NUMBERS + /* Segment order, seen from the front: + < A > + /\ /\ + F B + \/ \/ + < G > + /\ /\ + E C + \/ \/ + < D > + */ + uint8_t umSSDRNumbers[11][7] = { + // A B C D E F G + { 1, 1, 1, 1, 1, 1, 0 }, // 0 + { 0, 1, 1, 0, 0, 0, 0 }, // 1 + { 1, 1, 0, 1, 1, 0, 1 }, // 2 + { 1, 1, 1, 1, 0, 0, 1 }, // 3 + { 0, 1, 1, 0, 0, 1, 1 }, // 4 + { 1, 0, 1, 1, 0, 1, 1 }, // 5 + { 1, 0, 1, 1, 1, 1, 1 }, // 6 + { 1, 1, 1, 0, 0, 0, 0 }, // 7 + { 1, 1, 1, 1, 1, 1, 1 }, // 8 + { 1, 1, 1, 1, 0, 1, 1 }, // 9 + { 0, 0, 0, 0, 0, 0, 0 } // blank + }; + #else + uint8_t umSSDRNumbers[11][10] = umSSDR_NUMBERS; + #endif + + bool umSSDRDisplayTime = umSSDR_ENABLED; + bool umSSDREnableLDR = umSSDR_ENABLE_AUTO_BRIGHTNESS; + uint16_t umSSDRBrightnessMin = umSSDR_BRIGHTNESS_MIN; + uint16_t umSSDRBrightnessMax = umSSDR_BRIGHTNESS_MAX; + bool umSSDRInvertAutoBrightness = umSSDR_INVERT_AUTO_BRIGHTNESS; + uint16_t umSSDRLuxMin = umSSDR_LUX_MIN; + uint16_t umSSDRLuxMax = umSSDR_LUX_MAX; + bool umSSDRInverted = umSSDR_INVERTED; + bool umSSDRColonblink = umSSDR_COLONBLINK; + bool umSSDRLeadingZero = umSSDR_LEADING_ZERO; + String umSSDRDisplayMask = umSSDR_DISPLAY_MASK; + String umSSDRHours = umSSDR_HOURS; + String umSSDRMinutes = umSSDR_MINUTES; + String umSSDRSeconds = umSSDR_SECONDS; + String umSSDRColons = umSSDR_COLONS; + String umSSDRLight = umSSDR_LIGHT; + String umSSDRDays = umSSDR_DAYS; + String umSSDRMonths = umSSDR_MONTHS; + String umSSDRYears = umSSDR_YEARS; + + bool* umSSDRMask = nullptr; + bool disableUmLedControl = false; + + // Forward declarations of private methods + void _overlaySevenSegmentDraw(); + void _setColons(); + void _showElements(String *map, int timevar, bool isColon, bool removeZero); + void _setLeds(int lednr, int lastSeenLedNr, bool range, int countSegments, int number, bool colon); + void _setMaskToLeds(); + void _setAllFalse(); + int _checkForNumber(int count, int index, String *map); + void _publishMQTTint_P(const char *subTopic, int value); + void _publishMQTTstr_P(const char *subTopic, String Value); + bool _cmpIntSetting_P(char *topic, char *payload, const char *setting, void *value); + bool _handleSetting(char *topic, char *payload); + void _updateMQTT(); + void _addJSONObject(JsonObject& root); + + // String constants + static const char _str_name[]; + static const char _str_timeEnabled[]; + static const char _str_ldrEnabled[]; + static const char _str_minBrightness[]; + static const char _str_maxBrightness[]; + static const char _str_luxMin[]; + static const char _str_luxMax[]; + static const char _str_invertAutoBrightness[]; + static const char _str_inverted[]; + static const char _str_colonblink[]; + static const char _str_leadingZero[]; + static const char _str_displayMask[]; + static const char _str_hours[]; + static const char _str_minutes[]; + static const char _str_seconds[]; + static const char _str_colons[]; + static const char _str_light[]; + static const char _str_days[]; + static const char _str_months[]; + static const char _str_years[]; + + // Optional usermod dependencies + #ifdef USERMOD_SN_PHOTORESISTOR + Usermod_SN_Photoresistor *ptr = nullptr; + #else + void* ptr = nullptr; + #endif + + #ifdef USERMOD_BH1750 + Usermod_BH1750* bh1750 = nullptr; + #else + void* bh1750 = nullptr; + #endif + + public: + // Core usermod functions + void setup() override; + void loop() override; + void handleOverlayDraw(); + void addToJsonInfo(JsonObject& root) override; + void addToJsonState(JsonObject& root) override; + void readFromJsonState(JsonObject& root) override; + void onMqttConnect(bool sessionPresent) override; + bool onMqttMessage(char *topic, char *payload) override; + void addToConfig(JsonObject &root) override; + bool readFromConfig(JsonObject &root) override; + uint16_t getId() override; + + // Public function that can be called from other usermods + void disableOutputFunction(bool state) { + disableUmLedControl = state; + DEBUG_PRINTF("disableOutputFunction was triggered by an external Usermod: %s\n", disableUmLedControl ? "true" : "false"); + } + + // Destructor to clean up memory + ~UsermodSSDR(); +}; \ No newline at end of file From 291012b6eddcdc860bde4d211beec28a6256a10b Mon Sep 17 00:00:00 2001 From: KrX3D Date: Sun, 27 Apr 2025 12:01:27 +0200 Subject: [PATCH 07/14] coderabbitai improvments --- .../seven_segment_display_reloaded_v2.cpp | 8 ++--- .../seven_segment_display_reloaded_v2.h | 36 ++++++++++--------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp index 82ba34383e..ced8d66295 100644 --- a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp @@ -335,7 +335,7 @@ _setAllFalse(); #ifdef USERMOD_SN_PHOTORESISTOR - ptr = (Usermod_SN_Photoresistor*) UsermodManager::lookup(USERMOD_ID_SN_PHOTORESISTOR); + photoResistor = (Usermod_SN_Photoresistor*) UsermodManager::lookup(USERMOD_ID_SN_PHOTORESISTOR); #endif #ifdef USERMOD_BH1750 bh1750 = (Usermod_BH1750*) UsermodManager::lookup(USERMOD_ID_BH1750); @@ -360,12 +360,12 @@ } #if defined(USERMOD_SN_PHOTORESISTOR) || defined(USERMOD_BH1750) - if(bri != 0 && umSSDREnableLDR && (millis() - umSSDRLastRefresh > umSSDRResfreshTime) && !disableUmLedControl) { + if(bri != 0 && umSSDREnableLDR && (millis() - umSSDRLastRefresh > umSSDRRefreshTime) && !disableUmLedControl) { float lux = -1; // Initialize lux with an invalid value #ifdef USERMOD_SN_PHOTORESISTOR - if (ptr != nullptr) { - lux = ptr->getLastLDRValue(); + if (photoResistor != nullptr) { + lux = photoResistor->getLastLDRValue(); } #endif diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h index d786b77985..93db5acfc1 100644 --- a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h @@ -7,7 +7,7 @@ class UsermodSSDR : public Usermod { private: //Runtime variables. unsigned long umSSDRLastRefresh = 0; - unsigned long umSSDRResfreshTime = 3000; + unsigned long umSSDRRefreshTime = 3000; uint16_t umSSDRLength = 0; // Configurable settings for the SSDR Usermod @@ -71,43 +71,43 @@ class UsermodSSDR : public Usermod { */ #ifndef umSSDR_DISPLAY_MASK - #define umSSDR_DISPLAY_MASK "H:m" + #define umSSDR_DISPLAY_MASK "H:m" #endif #ifndef umSSDR_HOURS - #define umSSDR_HOURS "" + #define umSSDR_HOURS "" #endif #ifndef umSSDR_MINUTES - #define umSSDR_MINUTES "" + #define umSSDR_MINUTES "" #endif #ifndef umSSDR_SECONDS - #define umSSDR_SECONDS "" + #define umSSDR_SECONDS "" #endif #ifndef umSSDR_COLONS - #define umSSDR_COLONS "" + #define umSSDR_COLONS "" #endif #ifndef umSSDR_LIGHT - #define umSSDR_LIGHT "" + #define umSSDR_LIGHT "" #endif #ifndef umSSDR_DAYS - #define umSSDR_DAYS "" + #define umSSDR_DAYS "" #endif #ifndef umSSDR_MONTHS - #define umSSDR_MONTHS "" + #define umSSDR_MONTHS "" #endif #ifndef umSSDR_YEARS - #define umSSDR_YEARS "" + #define umSSDR_YEARS "" #endif #ifndef umSSDR_NUMBERS - /* Segment order, seen from the front: + /* Segment order, seen from the front: < A > /\ /\ F B @@ -117,8 +117,8 @@ class UsermodSSDR : public Usermod { E C \/ \/ < D > - */ - uint8_t umSSDRNumbers[11][7] = { + */ + uint8_t umSSDRNumbers[11][7] = { // A B C D E F G { 1, 1, 1, 1, 1, 1, 0 }, // 0 { 0, 1, 1, 0, 0, 0, 0 }, // 1 @@ -198,15 +198,15 @@ class UsermodSSDR : public Usermod { // Optional usermod dependencies #ifdef USERMOD_SN_PHOTORESISTOR - Usermod_SN_Photoresistor *ptr = nullptr; + Usermod_SN_Photoresistor *photoResistor = nullptr; #else - void* ptr = nullptr; + #define photoResistor nullptr; #endif #ifdef USERMOD_BH1750 Usermod_BH1750* bh1750 = nullptr; #else - void* bh1750 = nullptr; + #define bh1750 nullptr; #endif public: @@ -226,7 +226,9 @@ class UsermodSSDR : public Usermod { // Public function that can be called from other usermods void disableOutputFunction(bool state) { disableUmLedControl = state; - DEBUG_PRINTF("disableOutputFunction was triggered by an external Usermod: %s\n", disableUmLedControl ? "true" : "false"); + #ifdef DEBUG_PRINTF + DEBUG_PRINTF("disableOutputFunction was triggered by an external Usermod: %s\n", disableUmLedControl ? "true" : "false"); + #endif } // Destructor to clean up memory From aeb430d8e74c415c5a45deed9443bfeaac8e6eab Mon Sep 17 00:00:00 2001 From: KrX3D Date: Sun, 27 Apr 2025 12:06:42 +0200 Subject: [PATCH 08/14] fix --- .../seven_segment_display_reloaded_v2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h index 93db5acfc1..e4e57674bd 100644 --- a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h @@ -200,13 +200,13 @@ class UsermodSSDR : public Usermod { #ifdef USERMOD_SN_PHOTORESISTOR Usermod_SN_Photoresistor *photoResistor = nullptr; #else - #define photoResistor nullptr; + #define photoResistor nullptr #endif #ifdef USERMOD_BH1750 Usermod_BH1750* bh1750 = nullptr; #else - #define bh1750 nullptr; + #define bh1750 nullptr #endif public: From b753069c27dd1b69cf01b848702d5c5daac02be5 Mon Sep 17 00:00:00 2001 From: KrX3D Date: Sun, 27 Apr 2025 21:33:21 +0200 Subject: [PATCH 09/14] fixed wrong topic, added more logging with identifier [SSDR] --- .../seven_segment_display_reloaded_v2.cpp | 116 ++++++++++++++---- .../seven_segment_display_reloaded_v2.h | 15 ++- 2 files changed, 101 insertions(+), 30 deletions(-) diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp index ced8d66295..b54def95d9 100644 --- a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp @@ -16,10 +16,11 @@ bool colonsDone = false; bool lightDone = false; _setAllFalse(); - + for (int index = 0; index < displayMaskLen; index++) { int timeVar = 0; - switch (umSSDRDisplayMask[index]) { + char c = umSSDRDisplayMask[index]; + switch (c) { case 'h': timeVar = hourFormat12(localTime); _showElements(&umSSDRHours, timeVar, 0, !umSSDRLeadingZero); @@ -68,6 +69,7 @@ lightDone = true; } break; + _logWithPrefix("Unknown mask char '%c'", c); } } _setMaskToLeds(); @@ -205,15 +207,27 @@ void UsermodSSDR::_publishMQTTint_P(const char *subTopic, int value) { #ifndef WLED_DISABLE_MQTT + _logWithPrefix("Entering _publishMQTTint_P topic='%s' value=%d", subTopic, value); if (WLED_MQTT_CONNECTED) { - if(mqtt == NULL) return; + if(mqtt == NULL){ + _logWithPrefix("MQTT pointer NULL"); + return; + } - char buffer[64]; - char valBuffer[12]; - int result = snprintf_P(buffer, sizeof(buffer), PSTR("%s/%S/%S"), mqttDeviceTopic, _str_name, subTopic); - if (result < 0 || result >= sizeof(buffer)) return; // Buffer overflow check - + char buffer[64], nameBuffer[30], topicBuffer[30], valBuffer[12]; + + // Copy PROGMEM strings to local buffers + strlcpy(nameBuffer, reinterpret_cast(_str_name), sizeof(nameBuffer)); + strlcpy(topicBuffer, reinterpret_cast(subTopic), sizeof(topicBuffer)); + + int result = snprintf(buffer, sizeof(buffer), "%s/%s/%s", mqttDeviceTopic, nameBuffer, topicBuffer); + if (result < 0 || result >= sizeof(buffer)) { + _logWithPrefix("Buffer overflow in _publishMQTTint_P"); + return; // Buffer overflow check + } snprintf_P(valBuffer, sizeof(valBuffer), PSTR("%d"), value); + + _logWithPrefix("Publishing INT to: '%s', value: '%s'", buffer, valBuffer); mqtt->publish(buffer, 2, true, valBuffer); } #endif @@ -222,12 +236,25 @@ void UsermodSSDR::_publishMQTTstr_P(const char *subTopic, String Value) { #ifndef WLED_DISABLE_MQTT + _logWithPrefix("Entering _publishMQTTstr_P topic='%s' value='%s'", subTopic, Value.c_str()); if (WLED_MQTT_CONNECTED) { - if(mqtt == NULL) return; - char buffer[64]; - int result = snprintf_P(buffer, sizeof(buffer), PSTR("%s/%S/%S"), mqttDeviceTopic, _str_name, subTopic); - if (result < 0 || result >= sizeof(buffer)) return; // Buffer overflow check - + if(mqtt == NULL){ + _logWithPrefix("MQTT pointer NULL"); + return; + } + + char buffer[64], nameBuffer[30], topicBuffer[30]; + + strlcpy(nameBuffer, reinterpret_cast(_str_name), sizeof(nameBuffer)); + strlcpy(topicBuffer, reinterpret_cast(subTopic), sizeof(topicBuffer)); + + int result = snprintf(buffer, sizeof(buffer), "%s/%s/%s", mqttDeviceTopic, nameBuffer, topicBuffer); + if (result < 0 || result >= sizeof(buffer)) { + _logWithPrefix("Buffer overflow in _publishMQTTstr_P"); + return; // Buffer overflow check + } + + _logWithPrefix("Publishing STR to: '%s', value: '%s'", buffer, Value.c_str()); mqtt->publish(buffer, 2, true, Value.c_str(), Value.length()); } #endif @@ -235,9 +262,15 @@ bool UsermodSSDR::_cmpIntSetting_P(char *topic, char *payload, const char *setting, void *value) { - if (strcmp_P(topic, setting) == 0) + _logWithPrefix("._cmpIntSetting topic='%s' payload='%s' setting='%s'", topic, payload, reinterpret_cast(setting)); + char settingBuffer[30]; + strlcpy(settingBuffer, reinterpret_cast(setting), sizeof(settingBuffer)); + + if (strcmp_P(topic, settingBuffer) == 0) { + int oldValue = *((int *)value); *((int *)value) = strtol(payload, nullptr, 10); // Changed NULL to nullptr + _logWithPrefix("Setting updated from %d to %d", oldValue, *((int *)value)); _publishMQTTint_P(setting, *((int *)value)); return true; } @@ -245,26 +278,42 @@ } bool UsermodSSDR::_handleSetting(char *topic, char *payload) { + _logWithPrefix("Handling setting. Topic='%s', Payload='%s'", topic, payload); + if (_cmpIntSetting_P(topic, payload, _str_timeEnabled, &umSSDRDisplayTime)) { + _logWithPrefix("Updated timeEnabled"); return true; } if (_cmpIntSetting_P(topic, payload, _str_ldrEnabled, &umSSDREnableLDR)) { + _logWithPrefix("Updated ldrEnabled"); return true; } if (_cmpIntSetting_P(topic, payload, _str_inverted, &umSSDRInverted)) { + _logWithPrefix("Updated inverted"); return true; } if (_cmpIntSetting_P(topic, payload, _str_colonblink, &umSSDRColonblink)) { + _logWithPrefix("Updated colonblink"); return true; } if (_cmpIntSetting_P(topic, payload, _str_leadingZero, &umSSDRLeadingZero)) { + _logWithPrefix("Updated leadingZero"); return true; } + + char displayMaskBuffer[30]; + strlcpy(displayMaskBuffer, reinterpret_cast(_str_displayMask), sizeof(displayMaskBuffer)); + + _logWithPrefix("Comparing '%s' with '%s'", topic, displayMaskBuffer); + if (strcmp_P(topic, _str_displayMask) == 0) { umSSDRDisplayMask = String(payload); + + _logWithPrefix("Updated displayMask to '%s'", umSSDRDisplayMask.c_str()); _publishMQTTstr_P(_str_displayMask, umSSDRDisplayMask); return true; } + _logWithPrefix("No matching setting found"); return false; } @@ -329,7 +378,7 @@ umSSDRMask = (bool*) calloc(umSSDRLength, sizeof(bool)); // Use calloc to initialize to 0 if (umSSDRMask == nullptr) { - DEBUG_PRINTLN(F("Failed to allocate memory for SSDR mask")); + _logWithPrefix("Failed to allocate memory for SSDR mask"); return; // Early return on memory allocation failure } _setAllFalse(); @@ -340,7 +389,7 @@ #ifdef USERMOD_BH1750 bh1750 = (Usermod_BH1750*) UsermodManager::lookup(USERMOD_ID_BH1750); #endif - DEBUG_PRINTLN(F("SSDR setup done")); + _logWithPrefix("Setup done"); } // Clean up any allocated memory in the destructor @@ -360,7 +409,7 @@ } #if defined(USERMOD_SN_PHOTORESISTOR) || defined(USERMOD_BH1750) - if(bri != 0 && umSSDREnableLDR && (millis() - umSSDRLastRefresh > umSSDRRefreshTime) && !disableUmLedControl) { + if(bri != 0 && umSSDREnableLDR && (millis() - umSSDRLastRefresh > umSSDRRefreshTime) && !externalLedOutputDisabled) { float lux = -1; // Initialize lux with an invalid value #ifdef USERMOD_SN_PHOTORESISTOR @@ -385,9 +434,10 @@ } else { brightness = map(constrainedLux, umSSDRLuxMin, umSSDRLuxMax, umSSDRBrightnessMax, umSSDRBrightnessMin); } + _logWithPrefix("Lux=%.2f?brightness=%d",lux,br); if (bri != brightness) { - DEBUG_PRINTF("Adjusting brightness based on lux value: %.2f lx, new brightness: %d\n", lux, brightness); + _logWithPrefix("Adjusting brightness based on lux value: %.2f lx, new brightness: %d", lux, brightness); bri = brightness; stateUpdated(1); } @@ -398,7 +448,7 @@ } void UsermodSSDR::handleOverlayDraw() { - if (umSSDRDisplayTime && !disableUmLedControl && umSSDRMask != nullptr) { + if (umSSDRDisplayTime && !externalLedOutputDisabled && umSSDRMask != nullptr) { _overlaySevenSegmentDraw(); } } @@ -482,24 +532,34 @@ } void UsermodSSDR::onMqttConnect(bool sessionPresent) { + _logWithPrefix("onMqttConnect sessionPresent=%d", sessionPresent); if (!umSSDRDisplayTime) { + _logWithPrefix("DisplayTime disabled, skipping subscribe"); return; } #ifndef WLED_DISABLE_MQTT if (WLED_MQTT_CONNECTED) { - char subBuffer[48]; + char subBuffer[48], nameBuffer[30]; + + // Copy PROGMEM string to local buffer + strlcpy(nameBuffer, reinterpret_cast(_str_name), sizeof(nameBuffer)); + + _logWithPrefix("Connected. DeviceTopic='%s', GroupTopic='%s'", mqttDeviceTopic, mqttGroupTopic); + if (mqttDeviceTopic[0] != 0) { _updateMQTT(); //subscribe for sevenseg messages on the device topic - sprintf_P(subBuffer, PSTR("%s/%S/+/set"), mqttDeviceTopic, _str_name); + sprintf(subBuffer, "%s/%s/+/set", mqttDeviceTopic, nameBuffer); + _logWithPrefix("Subscribing to device topic: '%s'", subBuffer); mqtt->subscribe(subBuffer, 2); } if (mqttGroupTopic[0] != 0) { //subscribe for sevenseg messages on the group topic - sprintf_P(subBuffer, PSTR("%s/%S/+/set"), mqttGroupTopic, _str_name); + sprintf(subBuffer, "%s/%s/+/set", mqttGroupTopic, nameBuffer); + _logWithPrefix("Subscribing to group topic: '%s'", subBuffer); mqtt->subscribe(subBuffer, 2); } } @@ -512,7 +572,9 @@ //If topic begins with sevenSeg cut it off, otherwise not our message. size_t topicPrefixLen = strlen_P(PSTR("/wledSS/")); if (strncmp_P(topic, PSTR("/wledSS/"), topicPrefixLen) == 0) { + _logWithPrefix("onMqttMessage topic='%s' payload='%s'", topic, payload); topic += topicPrefixLen; + _logWithPrefix("Topic starts with /wledSS/, modified topic: '%s'", topic); } else { return false; } @@ -526,7 +588,9 @@ { //Trim /set and handle it topic[topicLen - 4] = '\0'; - _handleSetting(topic, payload); + _logWithPrefix("Processing setting. Setting='%s', Value='%s'", topic, payload); + bool result = _handleSetting(topic, payload); + _logWithPrefix("Handling result: %s", result ? "success" : "failure"); } } return true; @@ -543,8 +607,7 @@ JsonObject top = root[FPSTR(_str_name)]; if (top.isNull()) { - DEBUG_PRINT(FPSTR(_str_name)); - DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + _logWithPrefix("%s: No config found. (Using defaults.)", reinterpret_cast(_str_name)); return false; } umSSDRDisplayTime = (top[FPSTR(_str_timeEnabled)] | umSSDRDisplayTime); @@ -567,8 +630,7 @@ umSSDRLuxMax = top[FPSTR(_str_luxMax)] | umSSDRLuxMax; umSSDRInvertAutoBrightness = top[FPSTR(_str_invertAutoBrightness)] | umSSDRInvertAutoBrightness; - DEBUG_PRINT(FPSTR(_str_name)); - DEBUG_PRINTLN(F(" config (re)loaded.")); + _logWithPrefix("%s: config (re)loaded.)", reinterpret_cast(_str_name)); return true; } diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h index e4e57674bd..93bad9e6b9 100644 --- a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h @@ -1,6 +1,10 @@ #pragma once #include "wled.h" +// logging macro: +#define _logWithPrefix(fmt, ...) \ + DEBUG_PRINTF("[SSDR] " fmt "\n", ##__VA_ARGS__) + //#define REFRESHTIME 497 class UsermodSSDR : public Usermod { @@ -157,7 +161,7 @@ class UsermodSSDR : public Usermod { String umSSDRYears = umSSDR_YEARS; bool* umSSDRMask = nullptr; - bool disableUmLedControl = false; + bool externalLedOutputDisabled = false; // Forward declarations of private methods void _overlaySevenSegmentDraw(); @@ -224,10 +228,15 @@ class UsermodSSDR : public Usermod { uint16_t getId() override; // Public function that can be called from other usermods + /** + * Allows external usermods to temporarily disable the LED output of this usermod. + * This is useful when multiple usermods might be trying to control the same LEDs. + * @param state true to disable LED output, false to enable + */ void disableOutputFunction(bool state) { - disableUmLedControl = state; + externalLedOutputDisabled = state; #ifdef DEBUG_PRINTF - DEBUG_PRINTF("disableOutputFunction was triggered by an external Usermod: %s\n", disableUmLedControl ? "true" : "false"); + _logWithPrefix("disableOutputFunction was triggered by an external Usermod: %s\n", externalLedOutputDisabled ? "true" : "false"); #endif } From 114dd934f7f264d8084f767342d319921f36b013 Mon Sep 17 00:00:00 2001 From: KrX3D Date: Mon, 28 Apr 2025 22:44:55 +0200 Subject: [PATCH 10/14] log function -> unique name --- .../seven_segment_display_reloaded_v2.cpp | 77 +++++++++---------- .../seven_segment_display_reloaded_v2.h | 11 ++- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp index b54def95d9..e33eb4c437 100644 --- a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp @@ -1,10 +1,3 @@ -#ifdef USERMOD_SN_PHOTORESISTOR - #include "SN_Photoresistor.h" -#endif -#ifdef USERMOD_BH1750 - #include "BH1750_v2.h" -#endif - #include "seven_segment_display_reloaded_v2.h" #ifdef WLED_DISABLE_MQTT @@ -69,7 +62,7 @@ lightDone = true; } break; - _logWithPrefix("Unknown mask char '%c'", c); + _logUsermodSSDR("Unknown mask char '%c'", c); } } _setMaskToLeds(); @@ -207,10 +200,10 @@ void UsermodSSDR::_publishMQTTint_P(const char *subTopic, int value) { #ifndef WLED_DISABLE_MQTT - _logWithPrefix("Entering _publishMQTTint_P topic='%s' value=%d", subTopic, value); + _logUsermodSSDR("Entering _publishMQTTint_P topic='%s' value=%d", subTopic, value); if (WLED_MQTT_CONNECTED) { if(mqtt == NULL){ - _logWithPrefix("MQTT pointer NULL"); + _logUsermodSSDR("MQTT pointer NULL"); return; } @@ -222,12 +215,12 @@ int result = snprintf(buffer, sizeof(buffer), "%s/%s/%s", mqttDeviceTopic, nameBuffer, topicBuffer); if (result < 0 || result >= sizeof(buffer)) { - _logWithPrefix("Buffer overflow in _publishMQTTint_P"); + _logUsermodSSDR("Buffer overflow in _publishMQTTint_P"); return; // Buffer overflow check } snprintf_P(valBuffer, sizeof(valBuffer), PSTR("%d"), value); - _logWithPrefix("Publishing INT to: '%s', value: '%s'", buffer, valBuffer); + _logUsermodSSDR("Publishing INT to: '%s', value: '%s'", buffer, valBuffer); mqtt->publish(buffer, 2, true, valBuffer); } #endif @@ -236,10 +229,10 @@ void UsermodSSDR::_publishMQTTstr_P(const char *subTopic, String Value) { #ifndef WLED_DISABLE_MQTT - _logWithPrefix("Entering _publishMQTTstr_P topic='%s' value='%s'", subTopic, Value.c_str()); + _logUsermodSSDR("Entering _publishMQTTstr_P topic='%s' value='%s'", subTopic, Value.c_str()); if (WLED_MQTT_CONNECTED) { if(mqtt == NULL){ - _logWithPrefix("MQTT pointer NULL"); + _logUsermodSSDR("MQTT pointer NULL"); return; } @@ -250,11 +243,11 @@ int result = snprintf(buffer, sizeof(buffer), "%s/%s/%s", mqttDeviceTopic, nameBuffer, topicBuffer); if (result < 0 || result >= sizeof(buffer)) { - _logWithPrefix("Buffer overflow in _publishMQTTstr_P"); + _logUsermodSSDR("Buffer overflow in _publishMQTTstr_P"); return; // Buffer overflow check } - _logWithPrefix("Publishing STR to: '%s', value: '%s'", buffer, Value.c_str()); + _logUsermodSSDR("Publishing STR to: '%s', value: '%s'", buffer, Value.c_str()); mqtt->publish(buffer, 2, true, Value.c_str(), Value.length()); } #endif @@ -262,7 +255,7 @@ bool UsermodSSDR::_cmpIntSetting_P(char *topic, char *payload, const char *setting, void *value) { - _logWithPrefix("._cmpIntSetting topic='%s' payload='%s' setting='%s'", topic, payload, reinterpret_cast(setting)); + _logUsermodSSDR("._cmpIntSetting topic='%s' payload='%s' setting='%s'", topic, payload, reinterpret_cast(setting)); char settingBuffer[30]; strlcpy(settingBuffer, reinterpret_cast(setting), sizeof(settingBuffer)); @@ -270,7 +263,7 @@ { int oldValue = *((int *)value); *((int *)value) = strtol(payload, nullptr, 10); // Changed NULL to nullptr - _logWithPrefix("Setting updated from %d to %d", oldValue, *((int *)value)); + _logUsermodSSDR("Setting updated from %d to %d", oldValue, *((int *)value)); _publishMQTTint_P(setting, *((int *)value)); return true; } @@ -278,42 +271,42 @@ } bool UsermodSSDR::_handleSetting(char *topic, char *payload) { - _logWithPrefix("Handling setting. Topic='%s', Payload='%s'", topic, payload); + _logUsermodSSDR("Handling setting. Topic='%s', Payload='%s'", topic, payload); if (_cmpIntSetting_P(topic, payload, _str_timeEnabled, &umSSDRDisplayTime)) { - _logWithPrefix("Updated timeEnabled"); + _logUsermodSSDR("Updated timeEnabled"); return true; } if (_cmpIntSetting_P(topic, payload, _str_ldrEnabled, &umSSDREnableLDR)) { - _logWithPrefix("Updated ldrEnabled"); + _logUsermodSSDR("Updated ldrEnabled"); return true; } if (_cmpIntSetting_P(topic, payload, _str_inverted, &umSSDRInverted)) { - _logWithPrefix("Updated inverted"); + _logUsermodSSDR("Updated inverted"); return true; } if (_cmpIntSetting_P(topic, payload, _str_colonblink, &umSSDRColonblink)) { - _logWithPrefix("Updated colonblink"); + _logUsermodSSDR("Updated colonblink"); return true; } if (_cmpIntSetting_P(topic, payload, _str_leadingZero, &umSSDRLeadingZero)) { - _logWithPrefix("Updated leadingZero"); + _logUsermodSSDR("Updated leadingZero"); return true; } char displayMaskBuffer[30]; strlcpy(displayMaskBuffer, reinterpret_cast(_str_displayMask), sizeof(displayMaskBuffer)); - _logWithPrefix("Comparing '%s' with '%s'", topic, displayMaskBuffer); + _logUsermodSSDR("Comparing '%s' with '%s'", topic, displayMaskBuffer); if (strcmp_P(topic, _str_displayMask) == 0) { umSSDRDisplayMask = String(payload); - _logWithPrefix("Updated displayMask to '%s'", umSSDRDisplayMask.c_str()); + _logUsermodSSDR("Updated displayMask to '%s'", umSSDRDisplayMask.c_str()); _publishMQTTstr_P(_str_displayMask, umSSDRDisplayMask); return true; } - _logWithPrefix("No matching setting found"); + _logUsermodSSDR("No matching setting found"); return false; } @@ -378,7 +371,7 @@ umSSDRMask = (bool*) calloc(umSSDRLength, sizeof(bool)); // Use calloc to initialize to 0 if (umSSDRMask == nullptr) { - _logWithPrefix("Failed to allocate memory for SSDR mask"); + _logUsermodSSDR("Failed to allocate memory for SSDR mask"); return; // Early return on memory allocation failure } _setAllFalse(); @@ -389,7 +382,7 @@ #ifdef USERMOD_BH1750 bh1750 = (Usermod_BH1750*) UsermodManager::lookup(USERMOD_ID_BH1750); #endif - _logWithPrefix("Setup done"); + _logUsermodSSDR("Setup done"); } // Clean up any allocated memory in the destructor @@ -434,10 +427,10 @@ } else { brightness = map(constrainedLux, umSSDRLuxMin, umSSDRLuxMax, umSSDRBrightnessMax, umSSDRBrightnessMin); } - _logWithPrefix("Lux=%.2f?brightness=%d",lux,br); + _logUsermodSSDR("Lux=%.2f?brightness=%d",lux,br); if (bri != brightness) { - _logWithPrefix("Adjusting brightness based on lux value: %.2f lx, new brightness: %d", lux, brightness); + _logUsermodSSDR("Adjusting brightness based on lux value: %.2f lx, new brightness: %d", lux, brightness); bri = brightness; stateUpdated(1); } @@ -532,9 +525,9 @@ } void UsermodSSDR::onMqttConnect(bool sessionPresent) { - _logWithPrefix("onMqttConnect sessionPresent=%d", sessionPresent); + _logUsermodSSDR("onMqttConnect sessionPresent=%d", sessionPresent); if (!umSSDRDisplayTime) { - _logWithPrefix("DisplayTime disabled, skipping subscribe"); + _logUsermodSSDR("DisplayTime disabled, skipping subscribe"); return; } #ifndef WLED_DISABLE_MQTT @@ -544,14 +537,14 @@ // Copy PROGMEM string to local buffer strlcpy(nameBuffer, reinterpret_cast(_str_name), sizeof(nameBuffer)); - _logWithPrefix("Connected. DeviceTopic='%s', GroupTopic='%s'", mqttDeviceTopic, mqttGroupTopic); + _logUsermodSSDR("Connected. DeviceTopic='%s', GroupTopic='%s'", mqttDeviceTopic, mqttGroupTopic); if (mqttDeviceTopic[0] != 0) { _updateMQTT(); //subscribe for sevenseg messages on the device topic sprintf(subBuffer, "%s/%s/+/set", mqttDeviceTopic, nameBuffer); - _logWithPrefix("Subscribing to device topic: '%s'", subBuffer); + _logUsermodSSDR("Subscribing to device topic: '%s'", subBuffer); mqtt->subscribe(subBuffer, 2); } @@ -559,7 +552,7 @@ { //subscribe for sevenseg messages on the group topic sprintf(subBuffer, "%s/%s/+/set", mqttGroupTopic, nameBuffer); - _logWithPrefix("Subscribing to group topic: '%s'", subBuffer); + _logUsermodSSDR("Subscribing to group topic: '%s'", subBuffer); mqtt->subscribe(subBuffer, 2); } } @@ -572,9 +565,9 @@ //If topic begins with sevenSeg cut it off, otherwise not our message. size_t topicPrefixLen = strlen_P(PSTR("/wledSS/")); if (strncmp_P(topic, PSTR("/wledSS/"), topicPrefixLen) == 0) { - _logWithPrefix("onMqttMessage topic='%s' payload='%s'", topic, payload); + _logUsermodSSDR("onMqttMessage topic='%s' payload='%s'", topic, payload); topic += topicPrefixLen; - _logWithPrefix("Topic starts with /wledSS/, modified topic: '%s'", topic); + _logUsermodSSDR("Topic starts with /wledSS/, modified topic: '%s'", topic); } else { return false; } @@ -588,9 +581,9 @@ { //Trim /set and handle it topic[topicLen - 4] = '\0'; - _logWithPrefix("Processing setting. Setting='%s', Value='%s'", topic, payload); + _logUsermodSSDR("Processing setting. Setting='%s', Value='%s'", topic, payload); bool result = _handleSetting(topic, payload); - _logWithPrefix("Handling result: %s", result ? "success" : "failure"); + _logUsermodSSDR("Handling result: %s", result ? "success" : "failure"); } } return true; @@ -607,7 +600,7 @@ JsonObject top = root[FPSTR(_str_name)]; if (top.isNull()) { - _logWithPrefix("%s: No config found. (Using defaults.)", reinterpret_cast(_str_name)); + _logUsermodSSDR("%s: No config found. (Using defaults.)", reinterpret_cast(_str_name)); return false; } umSSDRDisplayTime = (top[FPSTR(_str_timeEnabled)] | umSSDRDisplayTime); @@ -630,7 +623,7 @@ umSSDRLuxMax = top[FPSTR(_str_luxMax)] | umSSDRLuxMax; umSSDRInvertAutoBrightness = top[FPSTR(_str_invertAutoBrightness)] | umSSDRInvertAutoBrightness; - _logWithPrefix("%s: config (re)loaded.)", reinterpret_cast(_str_name)); + _logUsermodSSDR("%s: config (re)loaded.)", reinterpret_cast(_str_name)); return true; } diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h index 93bad9e6b9..c1bf6f899f 100644 --- a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h @@ -2,9 +2,16 @@ #include "wled.h" // logging macro: -#define _logWithPrefix(fmt, ...) \ +#define _logUsermodSSDR(fmt, ...) \ DEBUG_PRINTF("[SSDR] " fmt "\n", ##__VA_ARGS__) +#ifdef USERMOD_SN_PHOTORESISTOR + #include "SN_Photoresistor.h" +#endif +#ifdef USERMOD_BH1750 + #include "BH1750_v2.h" +#endif + //#define REFRESHTIME 497 class UsermodSSDR : public Usermod { @@ -236,7 +243,7 @@ class UsermodSSDR : public Usermod { void disableOutputFunction(bool state) { externalLedOutputDisabled = state; #ifdef DEBUG_PRINTF - _logWithPrefix("disableOutputFunction was triggered by an external Usermod: %s\n", externalLedOutputDisabled ? "true" : "false"); + _logUsermodSSDR("disableOutputFunction was triggered by an external Usermod: %s", externalLedOutputDisabled ? "true" : "false"); #endif } From 3736242af4e176383f767264d46e66ae844abd0a Mon Sep 17 00:00:00 2001 From: KrX3D Date: Mon, 28 Apr 2025 23:18:00 +0200 Subject: [PATCH 11/14] coderabbitai improvments --- .../seven_segment_display_reloaded_v2.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp index e33eb4c437..71829e7584 100644 --- a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp @@ -79,14 +79,17 @@ } void UsermodSSDR::_showElements(String *map, int timevar, bool isColon, bool removeZero) { - if ((map != nullptr) && (*map != nullptr) && !(*map).equals("")) { - int length = (timevar == 0) ? 1 : log10(timevar) + 1; + if (map && map->length() > 0) { + uint8_t length = (timevar == 0) ? 1 + : static_cast(log10(static_cast(timevar))) + 1; + bool addZero = false; if (length == 1) { length = 2; addZero = true; } - int timeArr[length]; + uint8_t timeArr[4] = {10,10,10,10}; // supports up to 4 digits (0000-9999) + if (length > 4) length = 4; // safety clamp if (addZero) { if (removeZero) { @@ -259,7 +262,7 @@ char settingBuffer[30]; strlcpy(settingBuffer, reinterpret_cast(setting), sizeof(settingBuffer)); - if (strcmp_P(topic, settingBuffer) == 0) + if (strcmp(topic, settingBuffer) == 0) { int oldValue = *((int *)value); *((int *)value) = strtol(payload, nullptr, 10); // Changed NULL to nullptr @@ -299,7 +302,7 @@ _logUsermodSSDR("Comparing '%s' with '%s'", topic, displayMaskBuffer); - if (strcmp_P(topic, _str_displayMask) == 0) { + if (strcmp(topic, _str_displayMask) == 0) { umSSDRDisplayMask = String(payload); _logUsermodSSDR("Updated displayMask to '%s'", umSSDRDisplayMask.c_str()); From c304d9c5934c6365faa1c52efd5b13ec4d8eacbb Mon Sep 17 00:00:00 2001 From: KrX3D Date: Mon, 5 May 2025 20:15:42 +0200 Subject: [PATCH 12/14] skip function if usermod disabled, GUI Info - UM elements now better seperated from other UM --- .../setup_deps.py | 9 --------- .../seven_segment_display_reloaded_v2.cpp | 17 ++++++++--------- 2 files changed, 8 insertions(+), 18 deletions(-) delete mode 100644 usermods/seven_segment_display_reloaded/setup_deps.py diff --git a/usermods/seven_segment_display_reloaded/setup_deps.py b/usermods/seven_segment_display_reloaded/setup_deps.py deleted file mode 100644 index dd28f5fe9c..0000000000 --- a/usermods/seven_segment_display_reloaded/setup_deps.py +++ /dev/null @@ -1,9 +0,0 @@ -Import('env') - - -usermods = env.GetProjectOption("custom_usermods","").split() -# Check for partner usermods -if "SN_Photoresistor" in usermods: - env.Append(CPPDEFINES=[("USERMOD_SN_PHOTORESISTOR")]) -if any(mod in ("BH1750_v2", "BH1750") for mod in usermods): - env.Append(CPPDEFINES=[("USERMOD_BH1750")]) diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp index 71829e7584..325b3b49c6 100644 --- a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp @@ -461,26 +461,25 @@ } // Create a nested array for energy data - JsonArray ssr_json_seperator = user.createNestedArray(F("-----------------------------------")); - JsonArray ssr_json = user.createNestedArray(F("Seven segment reloaded:")); if (!umSSDRDisplayTime) { ssr_json.add(F("disabled")); // Indicate that the module is disabled } else { - JsonArray invert = user.createNestedArray("Time inverted"); + // File needs to be UTF-8 to show an arrow that points down and right instead of an question mark + JsonArray invert = user.createNestedArray("⤷ Time inverted"); invert.add(umSSDRInverted); - JsonArray blink = user.createNestedArray("Blinking colon"); + JsonArray blink = user.createNestedArray("⤷ Blinking colon"); blink.add(umSSDRColonblink); - JsonArray zero = user.createNestedArray("Show hour leading zero"); + JsonArray zero = user.createNestedArray("⤷ Show hour leading zero"); zero.add(umSSDRLeadingZero); - JsonArray ldrEnable = user.createNestedArray(F("Auto Brightness enabled")); + JsonArray ldrEnable = user.createNestedArray(F("⤷ Auto Brightness enabled")); ldrEnable.add(umSSDREnableLDR); - JsonArray ldrInvert = user.createNestedArray(F("Auto Brightness inverted")); + JsonArray ldrInvert = user.createNestedArray(F("⤷ Auto Brightness inverted")); ldrInvert.add(umSSDRInvertAutoBrightness); } } @@ -528,7 +527,6 @@ } void UsermodSSDR::onMqttConnect(bool sessionPresent) { - _logUsermodSSDR("onMqttConnect sessionPresent=%d", sessionPresent); if (!umSSDRDisplayTime) { _logUsermodSSDR("DisplayTime disabled, skipping subscribe"); return; @@ -595,7 +593,8 @@ void UsermodSSDR::addToConfig(JsonObject &root) { _addJSONObject(root); - + + if (!umSSDRDisplayTime) return; _updateMQTT(); } From 2fabc06bcf97ba8306233aea8111c5f604ab6581 Mon Sep 17 00:00:00 2001 From: KrX3D Date: Mon, 5 May 2025 21:28:29 +0200 Subject: [PATCH 13/14] coderabbitai improvements --- .../seven_segment_display_reloaded_v2.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp index 325b3b49c6..8a224d0159 100644 --- a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp @@ -62,7 +62,9 @@ lightDone = true; } break; - _logUsermodSSDR("Unknown mask char '%c'", c); + default: + _logUsermodSSDR("Unknown mask char '%c'", c); + break; } } _setMaskToLeds(); @@ -80,8 +82,8 @@ void UsermodSSDR::_showElements(String *map, int timevar, bool isColon, bool removeZero) { if (map && map->length() > 0) { - uint8_t length = (timevar == 0) ? 1 - : static_cast(log10(static_cast(timevar))) + 1; + uint8_t length = 1; + for (int tmp = timevar; tmp >= 10; tmp /= 10) ++length; bool addZero = false; if (length == 1) { @@ -164,7 +166,7 @@ if (!(colon && umSSDRColonblink) && ((number < 0) || (countSegments < 0))) return; - if ((colon && umSSDRColonblink) || umSSDRNumbers[number][countSegments]) { + if ((colon && umSSDRColonblink) || (number < 10 && umSSDRNumbers[number][countSegments])) { if (range) { for(int i = max(0, lastSeenLedNr); i <= lednr; i++) { umSSDRMask[i] = true; @@ -210,7 +212,7 @@ return; } - char buffer[64], nameBuffer[30], topicBuffer[30], valBuffer[12]; + char buffer[128], nameBuffer[30], topicBuffer[30], valBuffer[12]; // Copy PROGMEM strings to local buffers strlcpy(nameBuffer, reinterpret_cast(_str_name), sizeof(nameBuffer)); @@ -239,7 +241,7 @@ return; } - char buffer[64], nameBuffer[30], topicBuffer[30]; + char buffer[128], nameBuffer[30], topicBuffer[30]; strlcpy(nameBuffer, reinterpret_cast(_str_name), sizeof(nameBuffer)); strlcpy(topicBuffer, reinterpret_cast(subTopic), sizeof(topicBuffer)); From 90229e3b78e8683281d8dc12e709bec6ea5c5023 Mon Sep 17 00:00:00 2001 From: KrX3D Date: Mon, 5 May 2025 22:28:56 +0200 Subject: [PATCH 14/14] coderabbitai improvments --- .../seven_segment_display_reloaded_v2.cpp | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp index 8a224d0159..3bfa831d82 100644 --- a/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp +++ b/usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.cpp @@ -258,23 +258,6 @@ #endif } - bool UsermodSSDR::_cmpIntSetting_P(char *topic, char *payload, const char *setting, void *value) - { - _logUsermodSSDR("._cmpIntSetting topic='%s' payload='%s' setting='%s'", topic, payload, reinterpret_cast(setting)); - char settingBuffer[30]; - strlcpy(settingBuffer, reinterpret_cast(setting), sizeof(settingBuffer)); - - if (strcmp(topic, settingBuffer) == 0) - { - int oldValue = *((int *)value); - *((int *)value) = strtol(payload, nullptr, 10); // Changed NULL to nullptr - _logUsermodSSDR("Setting updated from %d to %d", oldValue, *((int *)value)); - _publishMQTTint_P(setting, *((int *)value)); - return true; - } - return false; - } - bool UsermodSSDR::_handleSetting(char *topic, char *payload) { _logUsermodSSDR("Handling setting. Topic='%s', Payload='%s'", topic, payload); @@ -304,7 +287,7 @@ _logUsermodSSDR("Comparing '%s' with '%s'", topic, displayMaskBuffer); - if (strcmp(topic, _str_displayMask) == 0) { + if (strcmp(topic, displayMaskBuffer) == 0) { umSSDRDisplayMask = String(payload); _logUsermodSSDR("Updated displayMask to '%s'", umSSDRDisplayMask.c_str()); @@ -424,13 +407,15 @@ if (lux >= 0) { // Ensure we got a valid lux value uint16_t brightness; - // Constrain lux values within defined range - float constrainedLux = constrain(lux, umSSDRLuxMin, umSSDRLuxMax); + // float linear interpolation to preserve full 0–255 resolution + float spanLux = umSSDRLuxMax - umSSDRLuxMin; + float spanBright = umSSDRBrightnessMax - umSSDRBrightnessMin; + float ratio = (constrainedLux - umSSDRLuxMin) / spanLux; if (!umSSDRInvertAutoBrightness) { - brightness = map(constrainedLux, umSSDRLuxMin, umSSDRLuxMax, umSSDRBrightnessMin, umSSDRBrightnessMax); + brightness = static_cast(ratio * spanBright + umSSDRBrightnessMin); } else { - brightness = map(constrainedLux, umSSDRLuxMin, umSSDRLuxMax, umSSDRBrightnessMax, umSSDRBrightnessMin); + brightness = static_cast((1.0f - ratio) * spanBright + umSSDRBrightnessMin); } _logUsermodSSDR("Lux=%.2f?brightness=%d",lux,br); @@ -535,6 +520,7 @@ } #ifndef WLED_DISABLE_MQTT if (WLED_MQTT_CONNECTED) { + int written; char subBuffer[48], nameBuffer[30]; // Copy PROGMEM string to local buffer @@ -546,7 +532,11 @@ { _updateMQTT(); //subscribe for sevenseg messages on the device topic - sprintf(subBuffer, "%s/%s/+/set", mqttDeviceTopic, nameBuffer); + written = snprintf(subBuffer, sizeof(subBuffer), "%s/%s/+/set", mqttDeviceTopic, nameBuffer); + if (written < 0 || written >= int(sizeof(subBuffer))) { + _logUsermodSSDR("subBuffer overflow – device topic too long"); + return; + } _logUsermodSSDR("Subscribing to device topic: '%s'", subBuffer); mqtt->subscribe(subBuffer, 2); } @@ -554,7 +544,11 @@ if (mqttGroupTopic[0] != 0) { //subscribe for sevenseg messages on the group topic - sprintf(subBuffer, "%s/%s/+/set", mqttGroupTopic, nameBuffer); + written = snprintf(subBuffer, sizeof(subBuffer), "%s/%s/+/set", mqttGroupTopic, nameBuffer); + if (written < 0 || written >= int(sizeof(subBuffer))) { + _logUsermodSSDR("subBuffer overflow – group topic too long"); + return; + } _logUsermodSSDR("Subscribing to group topic: '%s'", subBuffer); mqtt->subscribe(subBuffer, 2); }