diff --git a/usermods/usermod_v2_word_clock/de_DE_s1.svg b/usermods/usermod_v2_word_clock/de_DE_s1.svg
new file mode 100644
index 0000000000..d87b970ef5
--- /dev/null
+++ b/usermods/usermod_v2_word_clock/de_DE_s1.svg
@@ -0,0 +1,137 @@
+
+
diff --git a/usermods/usermod_v2_word_clock/readme.md b/usermods/usermod_v2_word_clock/readme.md
index b81cebcea9..4693043e8b 100644
--- a/usermods/usermod_v2_word_clock/readme.md
+++ b/usermods/usermod_v2_word_clock/readme.md
@@ -1,12 +1,13 @@
# Word Clock Usermod V2
-This usermod drives an 11x10 pixel matrix wordclock with WLED. There are 4 additional dots for the minutes.
+This usermod drives an 11x10 or a 11x11 pixel matrix wordclock with WLED. There are 4 additional dots for the minutes.
The visualisation is described by 4 masks with LED numbers (single dots for minutes, minutes, hours and "clock"). The index of the LEDs in the masks always starts at 0, even if the ledOffset is not 0.
There are 3 parameters that control behavior:
active: enable/disable usermod
-diplayItIs: enable/disable display of "Es ist" on the clock
+displayItIs: enable/disable display of "Es ist" on the clock
ledOffset: number of LEDs before the wordclock LEDs
+meanderwiring: on/off
## Update for alternative wiring pattern
@@ -16,7 +17,10 @@ The original used a long wire to connect DO to DI, from one line to the next lin
I wired my clock in meander style. So the first LED in the second line is on the right.
With this method, every other line was inverted and showed the wrong letter.
-I added a switch in usermod called "meander wiring?" to enable/disable the alternate wiring pattern.
+I added a switch in usermod called "meanderwiring" to enable/disable the alternate wiring pattern and a switch for the 11x11 grid.
+
+## 11x11 Grid
+I integrated the grafics from https://github.com/panbachi/wordclock/blob/master/graphics/plate/de_DE_s1.svg
## Installation
@@ -37,3 +41,72 @@ No special requirements.
2022/08/18 added meander wiring pattern.
2022/03/30 initial commit
+
+## Home Assistant Configuration
+Now, we will create the necessary entities in Home Assistant to display the switch and send commands to WLED.
+
+Step 2.1: Edit configuration.yaml
+
+Add the following complete code block to your configuration.yaml file.
+
+YAML
+
+`configuration.yaml`
+```
+# 1. REST command to send on/off commands to the WLED usermod
+rest_command:
+ wled_wordclock_set:
+ # REPLACE: Enter the IP address of your WLED device here
+ url: "http://YOUR_WLED_IP_ADDRESS/json/state"
+ method: "POST"
+ headers:
+ Content-Type: "application/json"
+ # Forces 'true'/'false' to be lowercase to generate valid JSON
+ payload: '{"WordClockUsermod":{"active":{{ active | string | lower }}}}'
+
+# 2. REST sensor to read the current state of the usermod
+rest:
+ - resource: "http://YOUR_WLED_IP_ADDRESS/json/state"
+ scan_interval: 30
+ sensor:
+ - name: "WLED Wordclock Status"
+ unique_id: wled_wordclock_status_sensor
+ value_template: "{{ value_json.WordClockUsermod.active }}"
+
+# 3. Template switch that combines the commands and the sensor into a UI element
+template:
+ - switch:
+ - name: "WLED Word Clock Active"
+ unique_id: wled_wordclock_active_switch
+ # Action on turning on
+ turn_on:
+ service: rest_command.wled_wordclock_set
+ data:
+ active: true
+ # Action on turning off
+ turn_off:
+ service: rest_command.wled_wordclock_set
+ data:
+ active: false
+ # Uses the state of the sensor to display the switch state (on/off)
+ state: >
+ {{ is_state('sensor.wled_wordclock_status', 'True') }}
+ # Changes the icon depending on the state
+ icon: >-
+ {% if this.state == 'on' %}
+ mdi:clock-digital
+ {% else %}
+ mdi:clock-outline
+ {% endif %}
+```
+Step 2.2: Adjust the IP Address
+
+In the YAML code, replace the placeholder YOUR_WLED_IP_ADDRESS in both places with the actual IP address of your WLED controller.
+
+Step 2.3: Restart Home Assistant
+
+Save the `configuration.yaml` file.
+
+Check the configuration under Settings > System > Restart > Check Configuration.
+
+If the configuration is valid, restart Home Assistant.
diff --git a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp
index 5100da180d..418a8cbd86 100644
--- a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp
+++ b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp
@@ -24,13 +24,18 @@ class WordClockUsermod : public Usermod
int ledOffset = 100;
bool meander = false;
bool nord = false;
+ bool eleven = false;
// defines for mask sizes
- #define maskSizeLeds 114
+ #define maskSizeLeds 121
#define maskSizeMinutes 12
#define maskSizeMinutesMea 12
+ #define maskSizeMinutes11 12
+ #define maskSizeMinutes11Mea 12
#define maskSizeHours 6
#define maskSizeHoursMea 6
+ #define maskSizeHours11 6
+ #define maskSizeHours11Mea 6
#define maskSizeItIs 5
#define maskSizeMinuteDots 4
@@ -39,10 +44,10 @@ class WordClockUsermod : public Usermod
const int maskMinutes[14][maskSizeMinutes] =
{
{107, 108, 109, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 0 - 00
- { 7, 8, 9, 10, 40, 41, 42, 43, -1, -1, -1, -1}, // 1 - 05 fünf nach
+ { 7, 8, 9, 10, 38, 39, 42, 43, -1, -1, -1, -1}, // 1 - 05 fünf nach
{ 11, 12, 13, 14, 40, 41, 42, 43, -1, -1, -1, -1}, // 2 - 10 zehn nach
{ 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1}, // 3 - 15 viertel
- { 15, 16, 17, 18, 19, 20, 21, 40, 41, 42, 43, -1}, // 4 - 20 zwanzig nach
+ { 11, 12, 13, 14, 15, 16, 17, 40, 41, 42, 43, -1}, // 4 - 20 zwanzig nach
{ 7, 8, 9, 10, 33, 34, 35, 44, 45, 46, 47, -1}, // 5 - 25 fünf vor halb
{ 44, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, -1}, // 6 - 30 halb
{ 7, 8, 9, 10, 40, 41, 42, 43, 44, 45, 46, 47}, // 7 - 35 fünf nach halb
@@ -72,7 +77,42 @@ class WordClockUsermod : public Usermod
{ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1}, // 12 - 15 alternative viertel nach
{ 26, 27, 28, 29, 30, 31, 32, 41, 42, 43, -1, -1} // 13 - 45 alternative viertel vor
};
-
+ // 11x11 wiring
+ const int maskMinutes11[14][maskSizeMinutes11] =
+ {
+ { 99, 100, 101, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 0 - 00
+ { 7, 8, 9, 10, 38, 39, 40, 41, -1, -1, -1, -1}, // 1 - 05 fünf nach
+ { 18, 19, 20, 21, 38, 39, 40, 41, -1, -1, -1, -1}, // 2 - 10 zehn nach
+ { 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1}, // 3 - 15 viertel
+ { 11, 12, 13, 14, 15, 16, 17, 38, 39, 40, 41, -1}, // 4 - 20 zwanzig nach
+ { 7, 8, 9, 10, 35, 36, 37, 44, 45, 46, 47, -1}, // 5 - 25 fünf vor halb
+ { 44, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, -1}, // 6 - 30 halb
+ { 7, 8, 9, 10, 38, 39, 40, 41, 44, 45, 46, 47}, // 7 - 35 fünf nach halb
+ { 11, 12, 13, 14, 15, 16, 17, 35, 36, 37, -1, -1}, // 8 - 40 zwanzig vor
+ { 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1}, // 9 - 45 dreiviertel
+ { 18, 19, 20, 21, 35, 36, 37, -1, -1, -1, -1, -1}, // 10 - 50 zehn vor
+ { 7, 8, 9, 10, 35, 36, 37, -1, -1, -1, -1, -1}, // 11 - 55 fünf vor
+ { 26, 27, 28, 29, 30, 31, 32, 38, 39, 40, 41, -1}, // 12 - 15 alternative viertel nach
+ { 26, 27, 28, 29, 30, 31, 32, 35, 36, 37, -1, -1} // 13 - 45 alternative viertel vor
+ };
+// 11x11 meander wiring ANPASSUNG HIER
+ const int maskMinutes11Mea[14][maskSizeMinutes11Mea] =
+ {
+ {107, 108, 109, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 0 - 00
+ { 7, 8, 9, 10, 35, 36, 37, 38, -1, -1, -1, -1}, // 1 - 05 fünf nach
+ { 11, 12, 13, 14, 35, 36, 37, 38, -1, -1, -1, -1}, // 2 - 10 zehn nach
+ { 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1}, // 3 - 15 viertel
+ { 15, 16, 17, 18, 19, 20, 21, 35, 36, 37, 38, -1}, // 4 - 20 zwanzig nach
+ { 7, 8, 9, 10, 39, 40, 41, 44, 45, 46, 47, -1}, // 5 - 25 fünf vor halb
+ { 44, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, -1}, // 6 - 30 halb
+ { 7, 8, 9, 10, 35, 36, 37, 38, 44, 45, 46, 47}, // 7 - 35 fünf nach halb
+ { 15, 16, 17, 18, 19, 20, 21, 39, 40, 41, -1, -1}, // 8 - 40 zwanzig vor
+ { 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1}, // 9 - 45 dreiviertel
+ { 11, 12, 13, 14, 39, 40, 41, -1, -1, -1, -1, -1}, // 10 - 50 zehn vor
+ { 7, 8, 9, 10, 39, 40, 41, -1, -1, -1, -1, -1}, // 11 - 55 fünf vor
+ { 26, 27, 28, 29, 30, 31, 32, 35, 36, 37, 38, -1}, // 12 - 15 alternative viertel nach
+ { 26, 27, 28, 29, 30, 31, 32, 39, 40, 41, -1, -1} // 13 - 45 alternative viertel vor
+ };
// hour masks
// Normal wiring
@@ -92,7 +132,8 @@ class WordClockUsermod : public Usermod
{ 49, 50, 51, -1, -1, -1}, // 11: elf
{ 94, 95, 96, 97, 98, -1} // 12: zwölf and 00: null
};
- // Meander wiring
+
+ // Meander wiring
const int maskHoursMea[13][maskSizeHoursMea] =
{
{ 63, 64, 65, -1, -1, -1}, // 01: ein
@@ -109,12 +150,45 @@ class WordClockUsermod : public Usermod
{ 49, 50, 51, -1, -1, -1}, // 11: elf
{ 94, 95, 96, 97, 98, -1} // 12: zwölf and 00: null
};
-
+ // 11x11
+ const int maskHours11[13][maskSizeHours11] =
+ {
+ { 61, 62, 63, -1, -1, -1}, // 01: ein
+ { 60, 61, 62, 63, -1, -1}, // 01: eins
+ { 62, 63, 64, 65, -1, -1}, // 02: zwei
+ { 67, 68, 69, 70, -1, -1}, // 03: drei
+ { 77, 78, 79, 80, -1, -1}, // 04: vier
+ { 73, 74, 75, 76, -1, -1}, // 05: fünf
+ {104, 105, 106, 107, 108, -1}, // 06: sechs
+ { 55, 56, 57, 58, 59, 60}, // 07: sieben
+ { 89, 90, 91, 92, -1, -1}, // 08: acht
+ { 81, 82, 83, 84, -1, -1}, // 09: neun
+ { 93, 94, 95, 96, -1, -1}, // 10: zehn
+ { 85, 86, 87, -1, -1, -1}, // 11: elf
+ { 49, 50, 51, 52, 53, -1} // 12: zwölf and 00: null
+ };
+ // 11x11 Meander wiring
+ const int maskHours11Mea[13][maskSizeHours11Mea] =
+ {
+ { 57, 58, 59, -1, -1, -1}, // 01: ein
+ { 57, 58, 59, 60, -1, -1}, // 01: eins
+ { 62, 63, 64, 65, -1, -1}, // 02: zwei
+ { 67, 68, 69, 70, -1, -1}, // 03: drei
+ { 84, 85, 86, 87, -1, -1}, // 04: vier
+ { 73, 74, 75, 76, -1, -1}, // 05: fünf
+ {100, 101, 102, 103, 104, -1}, // 06: sechs
+ { 60, 61, 62, 63, 64, 65}, // 07: sieben
+ { 89, 90, 91, 92, -1, -1}, // 08: acht
+ { 80, 81, 82, 83, -1, -1}, // 09: neun
+ { 93, 94, 95, 96, -1, -1}, // 10: zehn
+ { 77, 78, 79, -1, -1, -1}, // 11: elf
+ { 49, 50, 51, 52, 53, -1} // 12: zwölf and 00: null
+ };
// mask "it is"
const int maskItIs[maskSizeItIs] = {0, 1, 3, 4, 5};
// mask minute dots
- const int maskMinuteDots[maskSizeMinuteDots] = {110, 111, 112, 113};
+ const int maskMinuteDots[maskSizeMinuteDots] = {112, 114, 116, 118};
// overall mask to define which LEDs are on
int maskLedsOn[maskSizeLeds] =
@@ -129,7 +203,7 @@ class WordClockUsermod : public Usermod
0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0
+ 0,0,0,0,0,0,0,0,0,0,0
};
// update led mask
@@ -171,21 +245,29 @@ class WordClockUsermod : public Usermod
}
// update led mask
- if (meander)
- {
+ if (meander && !eleven) {
updateLedMask(maskHoursMea[index], maskSizeHoursMea);
+ } else if (eleven && !meander) {
+ updateLedMask(maskHours11[index], maskSizeHours11);
+ } else if (eleven && meander) {
+ updateLedMask(maskHours11Mea[index], maskSizeHours11Mea);
} else {
- updateLedMask(maskHours[index], maskSizeHours);
+ updateLedMask(maskHours[index], maskSizeHours);
}
+
+
}
// set minutes
void setMinutes(int index)
{
// update led mask
- if (meander)
- {
- updateLedMask(maskMinutesMea[index], maskSizeMinutesMea);
+ if (meander && !eleven) {
+ updateLedMask(maskMinutesMea[index], maskSizeMinutesMea);
+ } else if (eleven && !meander) {
+ updateLedMask(maskMinutes11[index], maskSizeMinutes11);
+ } else if (eleven && meander) {
+ updateLedMask(maskMinutes11Mea[index], maskSizeMinutes11Mea);
} else {
updateLedMask(maskMinutes[index], maskSizeMinutes);
}
@@ -212,7 +294,7 @@ class WordClockUsermod : public Usermod
// update the display
void updateDisplay(uint8_t hours, uint8_t minutes)
{
- // disable complete matrix at the bigging
+ // disable complete matrix at the beginning
for (int x = 0; x < maskSizeLeds; x++)
{
maskLedsOn[x] = 0;
@@ -374,6 +456,10 @@ class WordClockUsermod : public Usermod
*/
void addToJsonState(JsonObject& root)
{
+ // Create a nested object for the usermod
+ JsonObject usermodJson = root.createNestedObject("WordClockUsermod");
+ // Add the current state of the 'usermodActive' variable
+ usermodJson["active"] = usermodActive;
}
/*
@@ -382,6 +468,13 @@ class WordClockUsermod : public Usermod
*/
void readFromJsonState(JsonObject& root)
{
+ JsonObject usermodJson = root["WordClockUsermod"];
+ if (!usermodJson.isNull()) {
+ // Check if the 'active' key is present and update the variable
+ if (usermodJson.containsKey("active")) {
+ usermodActive = usermodJson["active"].as();
+ }
+ }
}
/*
@@ -425,7 +518,8 @@ class WordClockUsermod : public Usermod
top[F("active")] = usermodActive;
top[F("displayItIs")] = displayItIs;
top[F("ledOffset")] = ledOffset;
- top[F("Meander wiring?")] = meander;
+ top[F("meanderWiring")] = meander;
+ top[F("wiring11x11")] = eleven;
top[F("Norddeutsch")] = nord;
}
@@ -462,7 +556,11 @@ class WordClockUsermod : public Usermod
configComplete &= getJsonValue(top[F("active")], usermodActive);
configComplete &= getJsonValue(top[F("displayItIs")], displayItIs);
configComplete &= getJsonValue(top[F("ledOffset")], ledOffset);
- configComplete &= getJsonValue(top[F("Meander wiring?")], meander);
+ if (!getJsonValue(top[F("meanderWiring")], meander)) {
+ getJsonValue(top[F("meander")], meander); // backward compatibility
+ configComplete = false;
+ }
+ configComplete &= getJsonValue(top[F("wiring11x11")], eleven);
configComplete &= getJsonValue(top[F("Norddeutsch")], nord);
return configComplete;
@@ -505,4 +603,4 @@ class WordClockUsermod : public Usermod
};
static WordClockUsermod usermod_v2_word_clock;
-REGISTER_USERMOD(usermod_v2_word_clock);
\ No newline at end of file
+REGISTER_USERMOD(usermod_v2_word_clock);