From bffcf62cae85bbb592768733e8042a49adc6519c Mon Sep 17 00:00:00 2001 From: "Adrian A. Baumann" Date: Mon, 27 Apr 2026 19:20:30 +0200 Subject: [PATCH] Timing changed on Arduino script, latest version of ESP-Home script added --- Gaugecontroller/Gaugecontroller.ino | 225 ++++---- changes.md | 46 ++ esp-home-rewrite.yaml | 823 +++++++++++++--------------- 3 files changed, 559 insertions(+), 535 deletions(-) create mode 100644 changes.md diff --git a/Gaugecontroller/Gaugecontroller.ino b/Gaugecontroller/Gaugecontroller.ino index e84be18..8ff7d50 100644 --- a/Gaugecontroller/Gaugecontroller.ino +++ b/Gaugecontroller/Gaugecontroller.ino @@ -36,6 +36,8 @@ char displayBuffer[kDigitCount] = {' ', ' ', ' ', ' '}; bool pointEnabled = false; bool bellEnabled = false; uint8_t currentPhase = 0; +unsigned long phaseStartMicros = 0; +bool phaseActive = false; uint8_t encodeCharacter(char c) { switch (c) { @@ -110,12 +112,12 @@ void clear() { bellEnabled = false; } -bool parseCommand(const String& command) { +bool parseCommand(const char* command) { char displayText[16]; size_t inputIndex = 0; size_t displayIndex = 0; - if (command.length() == 0) { + if (command[0] == '\0') { return false; } @@ -127,7 +129,7 @@ bool parseCommand(const String& command) { } const size_t digitStart = inputIndex; - while (inputIndex < static_cast(command.length()) && + while (command[inputIndex] != '\0' && isxdigit(static_cast(command[inputIndex]))) { if (displayIndex + 1 >= sizeof(displayText)) { return false; @@ -142,7 +144,7 @@ bool parseCommand(const String& command) { bool newPointEnabled = false; bool newBellEnabled = false; - while (inputIndex < static_cast(command.length())) { + while (command[inputIndex] != '\0') { if (command[inputIndex] == '.') { newPointEnabled = true; } else if (command[inputIndex] == '!') { @@ -201,8 +203,19 @@ void begin() { shiftDriverWord(0); } +// Non-blocking. Returns immediately while the current digit is still being held; +// only does work when the hold time has elapsed and it is time to advance phases. void refresh() { + unsigned long now = micros(); + if (phaseActive && (now - phaseStartMicros) < kDigitHoldMicros) { + return; + } + setBlanked(true); + if (phaseActive) { + currentPhase = (currentPhase + 1) % (kDigitCount + 1); + } + if (currentPhase < kDigitCount) { renderDigit(currentPhase); } else if (pointEnabled || bellEnabled) { @@ -211,10 +224,9 @@ void refresh() { shiftDriverWord(0); } setBlanked(false); - delayMicroseconds(kDigitHoldMicros); - setBlanked(true); - currentPhase = (currentPhase + 1) % (kDigitCount + 1); + phaseStartMicros = micros(); + phaseActive = true; } } // namespace vfd @@ -280,6 +292,10 @@ struct Gauge { bool sweepEnabled = false; bool sweepTowardMax = true; + + // Cached direction-pin state. 0 = uninitialised, 1 = forward, -1 = reverse. + // Lets setDir() skip redundant digitalWrites when the direction hasn't flipped. + int8_t lastDir = 0; }; enum LedFx : uint8_t { FX_BLINK = 0, FX_BREATHE = 1, FX_DFLASH = 2 }; @@ -298,29 +314,26 @@ struct BlinkState { }; Gauge gauges[GAUGE_COUNT]; -String rxLine; + +// Fixed receive buffer — Arduino String would heap-fragment on the Mega over time. +// kRxBufSize - 1 is the max payload (one byte reserved for the null terminator). +static const uint8_t kRxBufSize = 128; +char rxBuf[kRxBufSize]; +uint8_t rxLen = 0; CRGB leds[TOTAL_LEDS]; uint8_t gaugeLedOffset[GAUGE_COUNT]; uint8_t gaugeLedCount[GAUGE_COUNT]; BlinkState blinkState[TOTAL_LEDS]; +// Precomputed in setup() from gaugePins[].ledOrder so per-LED writes don't +// have to walk the gauge table on every call. +bool ledNeedsSwap[TOTAL_LEDS]; bool ledsDirty = false; // FastLED drives the shared strip as RGB. Each gauge's ledOrder string marks per-LED // type ('R' = RGB, 'G' = GRB); writes to GRB-ordered LEDs pre-swap R and G to compensate. -inline bool ledNeedsRgSwap(uint8_t globalIdx) { - for (uint8_t i = 0; i < GAUGE_COUNT; i++) { - uint8_t off = gaugeLedOffset[i]; - if (globalIdx >= off && globalIdx < off + gaugeLedCount[i]) { - char c = gaugePins[i].ledOrder[globalIdx - off]; - return c == 'G' || c == 'g'; - } - } - return false; -} - inline CRGB encodeForStrip(uint8_t globalIdx, CRGB color) { - if (ledNeedsRgSwap(globalIdx)) { + if (ledNeedsSwap[globalIdx]) { uint8_t tmp = color.r; color.r = color.g; color.g = tmp; @@ -338,6 +351,9 @@ inline CRGB readLed(uint8_t globalIdx) { // Sends one-line command replies back over the control port. // +// All parse* functions take a null-terminated char* (no Arduino String) so the +// command pipeline never touches the heap. +// // Serial protocol summary. // // Host -> controller commands (newline-terminated ASCII): @@ -354,7 +370,7 @@ inline CRGB readLed(uint8_t globalIdx) { // LED // BLINK [ ] // BREATHE -// DFLASH +// DFLASH // VFD // PING // @@ -388,15 +404,10 @@ inline CRGB readLed(uint8_t globalIdx) { // Emitted once per configured LED before the trailing OK reply to LED?. // HOMED // Debug event printed on DEBUG_PORT when a homing sequence settles successfully. -void sendReply(const String& s) { +void sendReply(const char* s) { CMD_PORT.println(s); } -// Tiny float absolute-value helper to avoid dragging more machinery into the sketch. -float absf(float x) { - return (x < 0.0f) ? -x : x; -} - // Updates the cached enable state and toggles the hardware pin if one exists. void setEnable(uint8_t id, bool en) { if (id >= GAUGE_COUNT) return; @@ -410,9 +421,19 @@ void setEnable(uint8_t id, bool en) { } // Applies the logical direction after accounting for per-gauge inversion. +// digitalWrite is skipped when the direction is already correct, which is the +// common case (a step run almost always reuses the previous direction). void setDir(uint8_t id, bool forward) { + Gauge& g = gauges[id]; + int8_t want = forward ? 1 : -1; + if (g.lastDir == want) return; + g.lastDir = want; + bool level = gaugePins[id].dirInverted ? !forward : forward; digitalWrite(gaugePins[id].dirPin, level ? HIGH : LOW); + // DIR-to-STEP setup time. Most A4988/DRV8825-class drivers want at least + // ~200 ns; 1 us is cheap insurance and only paid when the direction flips. + delayMicroseconds(1); } // Emits one step pulse with the polarity expected by the driver. @@ -521,13 +542,13 @@ void updateSweepTarget(uint8_t id) { if (g.sweepTowardMax) { g.targetPos = g.maxPos; - if (g.currentPos >= g.maxPos && absf(g.velocity) < 1.0f) { + if (g.currentPos >= g.maxPos && fabsf(g.velocity) < 1.0f) { g.sweepTowardMax = false; g.targetPos = g.minPos; } } else { g.targetPos = g.minPos; - if (g.currentPos <= g.minPos && absf(g.velocity) < 1.0f) { + if (g.currentPos <= g.minPos && fabsf(g.velocity) < 1.0f) { g.sweepTowardMax = true; g.targetPos = g.maxPos; } @@ -562,7 +583,7 @@ void updateGauge(uint8_t id) { long error = g.targetPos - g.currentPos; - if (error == 0 && absf(g.velocity) < 0.01f) { + if (error == 0 && fabsf(g.velocity) < 0.01f) { g.velocity = 0.0f; g.stepAccumulator = 0.0f; return; @@ -570,7 +591,8 @@ void updateGauge(uint8_t id) { float dir = (error > 0) ? 1.0f : (error < 0 ? -1.0f : 0.0f); // Basic trapezoidal profile: brake if the remaining travel is shorter than the stop distance. - float brakingDistance = (g.velocity * g.velocity) / (2.0f * g.accel + 0.0001f); + // parseAccel rejects accel <= 0, so the divisor is always positive. + float brakingDistance = (g.velocity * g.velocity) / (2.0f * g.accel); if ((float)labs(error) <= brakingDistance) { if (g.velocity > 0.0f) { @@ -634,10 +656,10 @@ void updateGauge(uint8_t id) { // Parses `SET ` and updates the target position. // Replies: `OK`, `ERR BAD_ID`. -bool parseSet(const String& line) { +bool parseSet(const char* line) { int id; long pos; - if (sscanf(line.c_str(), "SET %d %ld", &id, &pos) == 2) { + if (sscanf(line, "SET %d %ld", &id, &pos) == 2) { if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); return true; @@ -655,14 +677,15 @@ bool parseSet(const String& line) { // Parses `SPEED ` and updates the max step rate. // Replies: `OK`, `ERR BAD_ID`, `ERR BAD_SPEED`. -bool parseSpeed(const String& line) { - int firstSpace = line.indexOf(' '); - int secondSpace = line.indexOf(' ', firstSpace + 1); - if (firstSpace < 0 || secondSpace < 0) return false; - if (line.substring(0, firstSpace) != "SPEED") return false; +// AVR libc sscanf doesn't support %f by default, so we hand-split with strchr/atof. +bool parseSpeed(const char* line) { + if (strncmp(line, "SPEED ", 6) != 0) return false; + const char* p = line + 6; + const char* sp = strchr(p, ' '); + if (!sp) return false; - int id = line.substring(firstSpace + 1, secondSpace).toInt(); - float speed = line.substring(secondSpace + 1).toFloat(); + int id = atoi(p); + float speed = atof(sp + 1); if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); @@ -680,14 +703,14 @@ bool parseSpeed(const String& line) { // Parses `ACCEL ` and updates the acceleration limit. // Replies: `OK`, `ERR BAD_ID`, `ERR BAD_ACCEL`. -bool parseAccel(const String& line) { - int firstSpace = line.indexOf(' '); - int secondSpace = line.indexOf(' ', firstSpace + 1); - if (firstSpace < 0 || secondSpace < 0) return false; - if (line.substring(0, firstSpace) != "ACCEL") return false; +bool parseAccel(const char* line) { + if (strncmp(line, "ACCEL ", 6) != 0) return false; + const char* p = line + 6; + const char* sp = strchr(p, ' '); + if (!sp) return false; - int id = line.substring(firstSpace + 1, secondSpace).toInt(); - float accel = line.substring(secondSpace + 1).toFloat(); + int id = atoi(p); + float accel = atof(sp + 1); if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); @@ -705,9 +728,9 @@ bool parseAccel(const String& line) { // Parses `ENABLE <0|1>` and toggles the selected driver. // Replies: `OK`, `ERR BAD_ID`. -bool parseEnable(const String& line) { +bool parseEnable(const char* line) { int id, en; - if (sscanf(line.c_str(), "ENABLE %d %d", &id, &en) == 2) { + if (sscanf(line, "ENABLE %d %d", &id, &en) == 2) { if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); return true; @@ -722,9 +745,9 @@ bool parseEnable(const String& line) { // Parses `ZERO ` and declares the current position to be home. // Replies: `OK`, `ERR BAD_ID`. -bool parseZero(const String& line) { +bool parseZero(const char* line) { int id; - if (sscanf(line.c_str(), "ZERO %d", &id) == 1) { + if (sscanf(line, "ZERO %d", &id) == 1) { if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); return true; @@ -745,9 +768,9 @@ bool parseZero(const String& line) { // Parses `HOME ` or `HOMEALL` and kicks off the homing sequence. // Replies: `OK`, `ERR BAD_ID`. Successful completion later emits debug line `HOMED `. -bool parseHome(const String& line) { +bool parseHome(const char* line) { int id; - if (sscanf(line.c_str(), "HOME %d", &id) == 1) { + if (sscanf(line, "HOME %d", &id) == 1) { if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); return true; @@ -758,7 +781,7 @@ bool parseHome(const String& line) { return true; } - if (line == "HOMEALL") { + if (strcmp(line, "HOMEALL") == 0) { requestHomeAll(); sendReply("OK"); return true; @@ -769,17 +792,17 @@ bool parseHome(const String& line) { // Parses `SWEEP ` and enables or disables end-to-end motion. // Replies: `OK`, `ERR BAD_ID`. -bool parseSweep(const String& line) { - int firstSpace = line.indexOf(' '); - int secondSpace = line.indexOf(' ', firstSpace + 1); - int thirdSpace = line.indexOf(' ', secondSpace + 1); +bool parseSweep(const char* line) { + if (strncmp(line, "SWEEP ", 6) != 0) return false; + const char* p = line + 6; + const char* sp1 = strchr(p, ' '); + if (!sp1) return false; + const char* sp2 = strchr(sp1 + 1, ' '); + if (!sp2) return false; - if (firstSpace < 0 || secondSpace < 0 || thirdSpace < 0) return false; - if (line.substring(0, firstSpace) != "SWEEP") return false; - - int id = line.substring(firstSpace + 1, secondSpace).toInt(); - float accel = line.substring(secondSpace + 1, thirdSpace).toFloat(); - float speed = line.substring(thirdSpace + 1).toFloat(); + int id = atoi(p); + float accel = atof(sp1 + 1); + float speed = atof(sp2 + 1); if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); @@ -808,8 +831,8 @@ bool parseSweep(const String& line) { // Answers `POS?` with current motion state for every gauge. // Emits one `POS ` line per gauge, // then replies `OK`. -bool parsePosQuery(const String& line) { - if (line == "POS?") { +bool parsePosQuery(const char* line) { + if (strcmp(line, "POS?") == 0) { for (uint8_t i = 0; i < GAUGE_COUNT; i++) { CMD_PORT.print("POS "); CMD_PORT.print(i); @@ -832,8 +855,8 @@ bool parsePosQuery(const String& line) { // Answers `CFG?` with speed and acceleration for every gauge. // Emits one `CFG ` line per gauge, then replies `OK`. -bool parseCfgQuery(const String& line) { - if (line == "CFG?") { +bool parseCfgQuery(const char* line) { + if (strcmp(line, "CFG?") == 0) { for (uint8_t i = 0; i < GAUGE_COUNT; i++) { CMD_PORT.print("CFG "); CMD_PORT.print(i); @@ -850,8 +873,8 @@ bool parseCfgQuery(const String& line) { // Answers the mandatory life question: are you there? // Reply: `PONG`. -bool parsePing(const String& line) { - if (line == "PING") { +bool parsePing(const char* line) { + if (strcmp(line, "PING") == 0) { sendReply("PONG"); return true; } @@ -860,17 +883,17 @@ bool parsePing(const String& line) { // Parses `VFD ` where is up to four hex characters with optional `.` and `!` suffixes. // Replies: `OK`, `ERR BAD_VFD`. -bool parseVfd(const String& line) { - if (line == "VFD") { +bool parseVfd(const char* line) { + if (strcmp(line, "VFD") == 0) { vfd::clear(); sendReply("OK"); return true; } - if (!line.startsWith("VFD ")) return false; + if (strncmp(line, "VFD ", 4) != 0) return false; - const String payload = line.substring(4); - if (payload.length() == 0) { + const char* payload = line + 4; + if (*payload == '\0') { vfd::clear(); sendReply("OK"); return true; @@ -886,8 +909,8 @@ bool parseVfd(const String& line) { // Answers `LED?` with the current RGB values for every configured LED. // Emits one `LED ` line per configured LED, then replies `OK`. -bool parseLedQuery(const String& line) { - if (line == "LED?") { +bool parseLedQuery(const char* line) { + if (strcmp(line, "LED?") == 0) { for (uint8_t i = 0; i < GAUGE_COUNT; i++) { for (uint8_t j = 0; j < gaugeLedCount[i]; j++) { CRGB c = readLed(gaugeLedOffset[i] + j); @@ -911,10 +934,10 @@ bool parseLedQuery(const String& line) { // Parses `LED ` and writes static colours. // Replies: `OK`, `ERR BAD_ID`, `ERR BAD_IDX`. -bool parseLed(const String& line) { +bool parseLed(const char* line) { int id, r, g, b; char idxToken[16]; - if (sscanf(line.c_str(), "LED %d %15s %d %d %d", &id, idxToken, &r, &g, &b) == 5) { + if (sscanf(line, "LED %d %15s %d %d %d", &id, idxToken, &r, &g, &b) == 5) { if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); return true; } char* dash = strchr(idxToken, '-'); int idxFirst = atoi(idxToken); @@ -936,11 +959,11 @@ bool parseLed(const String& line) { // Parses `BLINK ...` and assigns a simple on/off effect to one LED or a range. // Replies: `OK`, `ERR BAD_ID`, `ERR BAD_IDX`, `ERR BAD_TIME`. -bool parseBlink(const String& line) { +bool parseBlink(const char* line) { int id, onMs, offMs, r, g, b; char idxToken[16]; // Optional RGB values let BLINK either reuse or replace the current colour. - int count = sscanf(line.c_str(), "BLINK %d %15s %d %d %d %d %d", + int count = sscanf(line, "BLINK %d %15s %d %d %d %d %d", &id, idxToken, &onMs, &offMs, &r, &g, &b); if (count != 4 && count != 7) return false; @@ -984,10 +1007,10 @@ bool parseBlink(const String& line) { // Parses `BREATHE ...` and assigns a triangle-wave fade effect. // Replies: `OK`, `ERR BAD_ID`, `ERR BAD_IDX`, `ERR BAD_TIME`. -bool parseBreathe(const String& line) { +bool parseBreathe(const char* line) { int id, periodMs, r, g, b; char idxToken[16]; - if (sscanf(line.c_str(), "BREATHE %d %15s %d %d %d %d", + if (sscanf(line, "BREATHE %d %15s %d %d %d %d", &id, idxToken, &periodMs, &r, &g, &b) != 6) return false; if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); return true; } char* dash = strchr(idxToken, '-'); @@ -1017,10 +1040,10 @@ bool parseBreathe(const String& line) { // Parses `DFLASH ...` and assigns the double-flash pattern. // Replies: `OK`, `ERR BAD_ID`, `ERR BAD_IDX`. -bool parseDflash(const String& line) { +bool parseDflash(const char* line) { int id, r, g, b; char idxToken[16]; - if (sscanf(line.c_str(), "DFLASH %d %15s %d %d %d", + if (sscanf(line, "DFLASH %d %15s %d %d %d", &id, idxToken, &r, &g, &b) != 5) return false; if (id < 0 || id >= GAUGE_COUNT) { sendReply("ERR BAD_ID"); return true; } char* dash = strchr(idxToken, '-'); @@ -1104,7 +1127,7 @@ void updateBlink() { // Runs the command parsers in order until one claims the line. // Reply: `ERR BAD_CMD` when no parser accepts the line. -void processLine(const String& line) { +void processLine(const char* line) { if (parseSet(line)) return; if (parseSpeed(line)) return; if (parseAccel(line)) return; @@ -1132,16 +1155,24 @@ void readCommands() { char c = (char)CMD_PORT.read(); if (c == '\n') { - rxLine.trim(); - if (rxLine.length() > 0) { - processLine(rxLine); + // Trim trailing whitespace. + while (rxLen > 0 && (rxBuf[rxLen - 1] == ' ' || rxBuf[rxLen - 1] == '\t')) { + rxLen--; } - rxLine = ""; + rxBuf[rxLen] = '\0'; + // Skip leading whitespace. + char* start = rxBuf; + while (*start == ' ' || *start == '\t') start++; + if (*start) { + processLine(start); + } + rxLen = 0; } else if (c != '\r') { - rxLine += c; - if (rxLine.length() > 120) { - rxLine = ""; + if (rxLen >= kRxBufSize - 1) { + rxLen = 0; sendReply("ERR TOO_LONG"); + } else { + rxBuf[rxLen++] = c; } } } @@ -1168,11 +1199,17 @@ void setup() { gauges[i].lastUpdateMicros = micros(); } - // Flatten the per-gauge LED counts into offsets on the shared strip. + // Flatten the per-gauge LED counts into offsets on the shared strip, + // and precompute the GRB-vs-RGB swap flag so writeLed/readLed don't have + // to walk the gauge table on every call. uint8_t ledOff = 0; for (uint8_t i = 0; i < GAUGE_COUNT; i++) { gaugeLedCount[i] = cstrLen(gaugePins[i].ledOrder); gaugeLedOffset[i] = ledOff; + for (uint8_t j = 0; j < gaugeLedCount[i]; j++) { + char c = gaugePins[i].ledOrder[j]; + ledNeedsSwap[ledOff + j] = (c == 'G' || c == 'g'); + } ledOff += gaugeLedCount[i]; } FastLED.addLeds(leds, TOTAL_LEDS); diff --git a/changes.md b/changes.md new file mode 100644 index 0000000..fac39c9 --- /dev/null +++ b/changes.md @@ -0,0 +1,46 @@ +# Changes + +## 2026-04-27 — Arduino firmware refactor (`Gaugecontroller/Gaugecontroller.ino`) + +### Non-blocking VFD multiplexer +`vfd::refresh()` previously held each digit for 2000 µs via `delayMicroseconds`, +which capped the effective stepper pulse rate at roughly 500 Hz regardless of +`maxSpeed`. It now tracks `phaseStartMicros`/`phaseActive` and returns +immediately while the digit is still being held; the main loop runs at +microsecond cadence again and the configured `maxSpeed = 4000.0f` steps/s is +actually achievable. + +### Fixed-buffer command parser (no more `String` heap churn) +Replaced `String rxLine` with `char rxBuf[128]` and converted the entire +command pipeline to take `const char*`: + +- `processLine`, `sendReply`, `vfd::parseCommand` +- All `parse*` functions: `parseSet`, `parseSpeed`, `parseAccel`, `parseEnable`, + `parseZero`, `parseHome`, `parseSweep`, `parsePosQuery`, `parseCfgQuery`, + `parseLedQuery`, `parseLed`, `parseBlink`, `parseBreathe`, `parseDflash`, + `parseVfd`, `parsePing`. + +`parseSpeed` / `parseAccel` / `parseSweep` use `strncmp` + `atof` because the +default AVR-libc `sscanf` doesn't support `%f`. No allocations on the command +path; the Mega's heap no longer fragments over time. + +### Cached `ledNeedsSwap[TOTAL_LEDS]` +Per-LED RGB-vs-GRB swap flag is now precomputed once in `setup()` from +`gaugePins[].ledOrder`. `encodeForStrip` is a single array index instead of +walking the gauge table on every LED read/write. + +### Cached step direction per gauge +Added `Gauge.lastDir`. `setDir()` skips the DIR-pin `digitalWrite` when the +direction hasn't flipped (the common case during a step run) and adds a 1 µs +DIR-to-STEP setup delay only when it actually flips. + +### Cleanups +- Removed the `absf` helper; use `fabsf` consistently. +- Removed the `+ 0.0001f` epsilon in the trapezoidal braking-distance divisor. + `parseAccel` already rejects `accel <= 0`, so the divisor is always positive. +- Fixed the ` ` typo to ` ` in the protocol comment for + `DFLASH`. + +### Build verification +`arduino-cli compile --fqbn arduino:avr:mega Gaugecontroller`: +17758 B flash (6%), 1845 B SRAM (22%). diff --git a/esp-home-rewrite.yaml b/esp-home-rewrite.yaml index ddeafb5..8a3ccab 100644 --- a/esp-home-rewrite.yaml +++ b/esp-home-rewrite.yaml @@ -1,36 +1,38 @@ substitutions: # --- Device identity --- - device_name: gauge_controller + device_name: gaugecontroller device_friendly_name: Selsyn Multi device_area: Control Panels # --- WiFi --- - wifi_ssid: MyNetwork - wifi_password: MyPassword + wifi_ssid: !secret wifi_ssid + wifi_password: !secret wifi_password # --- Arduino UART bridge --- - arduino_tx_pin: GPIO17 - arduino_rx_pin: GPIO16 + arduino_tx_pin: GPIO4 + arduino_rx_pin: GPIO5 arduino_baud: "38400" # --- Gauge 1 --- + gauge0_name: Selsyn 1 gauge0_entity_name: Selsyn 1 Power gauge0_min: "0.0" - gauge0_max: "7300.0" - gauge0_max_steps: "4000" + gauge0_max: "7612.0" + gauge0_max_steps: "3780" gauge0_unit: W gauge0_step: "1.0" - gauge0_speed_step: "100" - gauge0_accel_step: "100" + gauge0_speed_step: "1" + gauge0_accel_step: "1" gauge0_default_speed: "5000" gauge0_default_accel: "6000" # --- Gauge 2 --- - gauge1_entity_name: Selsyn 2 Power + gauge1_name: Selsyn 2 + gauge1_entity_name: Selsyn 2 Temperature gauge1_min: "0.0" - gauge1_max: "7300.0" - gauge1_max_steps: "4000" - gauge1_unit: W + gauge1_max: "76.0" + gauge1_max_steps: "3780" + gauge1_unit: Deg gauge1_step: "1.0" gauge1_speed_step: "100" gauge1_accel_step: "100" @@ -38,10 +40,11 @@ substitutions: gauge1_default_accel: "6000" # --- Gauge 3 --- + gauge2_name: Selsyn 3 gauge2_entity_name: Selsyn 3 Power gauge2_min: "0.0" - gauge2_max: "7300.0" - gauge2_max_steps: "4000" + gauge2_max: "7612.0" + gauge2_max_steps: "3780" gauge2_unit: W gauge2_step: "1.0" gauge2_speed_step: "100" @@ -50,10 +53,11 @@ substitutions: gauge2_default_accel: "6000" # --- Gauge 4 --- + gauge3_name: Selsyn 4 gauge3_entity_name: Selsyn 4 Power gauge3_min: "0.0" - gauge3_max: "7300.0" - gauge3_max_steps: "4000" + gauge3_max: "7612.0" + gauge3_max_steps: "3780" gauge3_unit: W gauge3_step: "1.0" gauge3_speed_step: "100" @@ -79,18 +83,29 @@ esphome: id: arduino_uart data: "HOMEALL\n" - logger.log: "Boot: HOMEALL sent to Arduino" + - delay: 15s + - uart.write: + id: arduino_uart + data: "POS?\n" + - logger.log: "Boot: POS? sent to Arduino" + - uart.write: + id: arduino_uart + data: "CFG?\n" + - logger.log: "Boot: CFG? sent to Arduino" esp32: - board: esp32dev + board: esp32-c3-devkitm-1 + variant: ESP32C3 framework: - type: arduino + type: esp-idf + version: recommended # --------------------------------------------------------------------------- # Logging (set level: NONE in production) # --------------------------------------------------------------------------- logger: - level: INFO + level: DEBUG # --------------------------------------------------------------------------- # Native HA API — handles all entity registration, state sync, and commands. @@ -113,12 +128,13 @@ ota: wifi: ssid: ${wifi_ssid} password: ${wifi_password} + output_power: 15 ap: ssid: "${device_name} Fallback" - password: "esphomefb" + password: !secret fallbackpassword captive_portal: - + # --------------------------------------------------------------------------- # Arduino UART bridge # --------------------------------------------------------------------------- @@ -131,20 +147,6 @@ uart: # Uncomment to log raw Arduino traffic: # debug: # direction: BOTH - on_data: - - lambda: |- - for (uint8_t b : x) { - if (b == '\n') { - std::string &buf = id(uart_rx_buf); - if (!buf.empty() && buf.back() == '\r') buf.pop_back(); - if (!buf.empty() && buf != "OK" && buf != "PONG") { - id(arduino_last_message).publish_state(buf); - } - buf.clear(); - } else if (id(uart_rx_buf).size() < 128) { - id(uart_rx_buf) += static_cast(b); - } - } # --------------------------------------------------------------------------- # Connectivity diagnostics @@ -161,7 +163,7 @@ sensor: entity_category: diagnostic - platform: template - name: "${gauge0_entity_name} Target" + name: "${gauge0_name} Target" lambda: |- return id(gauge0_target_value); unit_of_measurement: "${gauge0_unit}" @@ -169,7 +171,7 @@ sensor: update_interval: 5s - platform: template - name: "${gauge1_entity_name} Target" + name: "${gauge1_name} Target" lambda: |- return id(gauge1_target_value); unit_of_measurement: "${gauge1_unit}" @@ -177,7 +179,7 @@ sensor: update_interval: 5s - platform: template - name: "${gauge2_entity_name} Target" + name: "${gauge2_name} Target" lambda: |- return id(gauge2_target_value); unit_of_measurement: "${gauge2_unit}" @@ -185,84 +187,14 @@ sensor: update_interval: 5s - platform: template - name: "${gauge3_entity_name} Target" + name: "${gauge3_name} Target" lambda: |- return id(gauge3_target_value); unit_of_measurement: "${gauge3_unit}" accuracy_decimals: 1 update_interval: 5s - - platform: template - name: "${gauge0_entity_name} Speed" - lambda: |- - return id(gauge0_speed_value); - unit_of_measurement: "steps/s" - accuracy_decimals: 0 - update_interval: 5s - entity_category: config - - - platform: template - name: "${gauge0_entity_name} Acceleration" - lambda: |- - return id(gauge0_accel_value); - unit_of_measurement: "steps/s^2" - accuracy_decimals: 0 - update_interval: 5s - entity_category: config - - - platform: template - name: "${gauge1_entity_name} Speed" - lambda: |- - return id(gauge1_speed_value); - unit_of_measurement: "steps/s" - accuracy_decimals: 0 - update_interval: 5s - entity_category: config - - - platform: template - name: "${gauge1_entity_name} Acceleration" - lambda: |- - return id(gauge1_accel_value); - unit_of_measurement: "steps/s^2" - accuracy_decimals: 0 - update_interval: 5s - entity_category: config - - - platform: template - name: "${gauge2_entity_name} Speed" - lambda: |- - return id(gauge2_speed_value); - unit_of_measurement: "steps/s" - accuracy_decimals: 0 - update_interval: 5s - entity_category: config - - - platform: template - name: "${gauge2_entity_name} Acceleration" - lambda: |- - return id(gauge2_accel_value); - unit_of_measurement: "steps/s^2" - accuracy_decimals: 0 - update_interval: 5s - entity_category: config - - - platform: template - name: "${gauge3_entity_name} Speed" - lambda: |- - return id(gauge3_speed_value); - unit_of_measurement: "steps/s" - accuracy_decimals: 0 - update_interval: 5s - entity_category: config - - - platform: template - name: "${gauge3_entity_name} Acceleration" - lambda: |- - return id(gauge3_accel_value); - unit_of_measurement: "steps/s^2" - accuracy_decimals: 0 - update_interval: 5s - entity_category: config + entity_category: diagnostic text_sensor: - platform: wifi_info @@ -290,7 +222,7 @@ number: min_value: ${gauge0_min} max_value: ${gauge0_max} step: ${gauge0_step} - mode: box + mode: slider optimistic: true restore_value: false initial_value: ${gauge0_min} @@ -308,6 +240,7 @@ number: id(gauge0_target_value) = clamped; char cmd[24]; snprintf(cmd, sizeof(cmd), "SET 0 %d\n", steps); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: template @@ -317,7 +250,7 @@ number: min_value: ${gauge1_min} max_value: ${gauge1_max} step: ${gauge1_step} - mode: box + mode: slider optimistic: true restore_value: false initial_value: ${gauge1_min} @@ -335,6 +268,7 @@ number: id(gauge1_target_value) = clamped; char cmd[24]; snprintf(cmd, sizeof(cmd), "SET 1 %d\n", steps); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: template @@ -344,7 +278,7 @@ number: min_value: ${gauge2_min} max_value: ${gauge2_max} step: ${gauge2_step} - mode: box + mode: slider optimistic: true restore_value: false initial_value: ${gauge2_min} @@ -362,6 +296,7 @@ number: id(gauge2_target_value) = clamped; char cmd[24]; snprintf(cmd, sizeof(cmd), "SET 2 %d\n", steps); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: template @@ -371,7 +306,7 @@ number: min_value: ${gauge3_min} max_value: ${gauge3_max} step: ${gauge3_step} - mode: box + mode: slider optimistic: true restore_value: false initial_value: ${gauge3_min} @@ -389,12 +324,13 @@ number: id(gauge3_target_value) = clamped; char cmd[24]; snprintf(cmd, sizeof(cmd), "SET 3 %d\n", steps); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: template id: gauge0_speed_number - name: "${gauge0_entity_name} Speed" - entity_category: config + name: "${gauge0_name} Speed" + entity_category: diagnostic unit_of_measurement: "steps/s" min_value: 1 max_value: 20000 @@ -409,12 +345,13 @@ number: id(gauge0_speed_value) = clamped; char cmd[24]; snprintf(cmd, sizeof(cmd), "SPEED 0 %d\n", clamped); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: template id: gauge0_accel_number - name: "${gauge0_entity_name} Acceleration" - entity_category: config + name: "${gauge0_name} Acceleration" + entity_category: diagnostic unit_of_measurement: "steps/s^2" min_value: 1 max_value: 50000 @@ -429,12 +366,13 @@ number: id(gauge0_accel_value) = clamped; char cmd[24]; snprintf(cmd, sizeof(cmd), "ACCEL 0 %d\n", clamped); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: template id: gauge1_speed_number - name: "${gauge1_entity_name} Speed" - entity_category: config + name: "${gauge1_name} Speed" + entity_category: diagnostic unit_of_measurement: "steps/s" min_value: 1 max_value: 20000 @@ -449,12 +387,13 @@ number: id(gauge1_speed_value) = clamped; char cmd[24]; snprintf(cmd, sizeof(cmd), "SPEED 1 %d\n", clamped); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: template id: gauge1_accel_number - name: "${gauge1_entity_name} Acceleration" - entity_category: config + name: "${gauge1_name} Acceleration" + entity_category: diagnostic unit_of_measurement: "steps/s^2" min_value: 1 max_value: 50000 @@ -469,12 +408,13 @@ number: id(gauge1_accel_value) = clamped; char cmd[24]; snprintf(cmd, sizeof(cmd), "ACCEL 1 %d\n", clamped); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: template id: gauge2_speed_number - name: "${gauge2_entity_name} Speed" - entity_category: config + name: "${gauge2_name} Speed" + entity_category: diagnostic unit_of_measurement: "steps/s" min_value: 1 max_value: 20000 @@ -489,12 +429,13 @@ number: id(gauge2_speed_value) = clamped; char cmd[24]; snprintf(cmd, sizeof(cmd), "SPEED 2 %d\n", clamped); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: template id: gauge2_accel_number - name: "${gauge2_entity_name} Acceleration" - entity_category: config + name: "${gauge2_name} Acceleration" + entity_category: diagnostic unit_of_measurement: "steps/s^2" min_value: 1 max_value: 50000 @@ -509,12 +450,13 @@ number: id(gauge2_accel_value) = clamped; char cmd[24]; snprintf(cmd, sizeof(cmd), "ACCEL 2 %d\n", clamped); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: template id: gauge3_speed_number - name: "${gauge3_entity_name} Speed" - entity_category: config + name: "${gauge3_name} Speed" + entity_category: diagnostic unit_of_measurement: "steps/s" min_value: 1 max_value: 20000 @@ -529,12 +471,13 @@ number: id(gauge3_speed_value) = clamped; char cmd[24]; snprintf(cmd, sizeof(cmd), "SPEED 3 %d\n", clamped); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: template id: gauge3_accel_number - name: "${gauge3_entity_name} Acceleration" - entity_category: config + name: "${gauge3_name} Acceleration" + entity_category: diagnostic unit_of_measurement: "steps/s^2" min_value: 1 max_value: 50000 @@ -549,6 +492,7 @@ number: id(gauge3_accel_value) = clamped; char cmd[24]; snprintf(cmd, sizeof(cmd), "ACCEL 3 %d\n", clamped); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); # --------------------------------------------------------------------------- @@ -596,7 +540,8 @@ text: cmd += " 0" + suffix; } cmd += "\n"; - id(arduino_uart).write_str(cmd); + ESP_LOGI("uart_tx", "TX: %s", cmd.c_str()); + id(arduino_uart).write_str(cmd.c_str()); switch: - platform: template @@ -620,7 +565,8 @@ switch: cmd += " 0" + suffix; } cmd += "\n"; - id(arduino_uart).write_str(cmd); + ESP_LOGI("uart_tx", "TX: %s", cmd.c_str()); + id(arduino_uart).write_str(cmd.c_str()); turn_off_action: - lambda: |- id(vfd_decimal_point_on) = false; @@ -635,7 +581,8 @@ switch: cmd += " 0" + suffix; } cmd += "\n"; - id(arduino_uart).write_str(cmd); + ESP_LOGI("uart_tx", "TX: %s", cmd.c_str()); + id(arduino_uart).write_str(cmd.c_str()); - platform: template id: vfd_alarm @@ -659,7 +606,8 @@ switch: cmd += " 0" + suffix; } cmd += "\n"; - id(arduino_uart).write_str(cmd); + ESP_LOGI("uart_tx", "TX: %s", cmd.c_str()); + id(arduino_uart).write_str(cmd.c_str()); turn_off_action: - lambda: |- id(vfd_alarm_on) = false; @@ -674,7 +622,8 @@ switch: cmd += " 0" + suffix; } cmd += "\n"; - id(arduino_uart).write_str(cmd); + ESP_LOGI("uart_tx", "TX: %s", cmd.c_str()); + id(arduino_uart).write_str(cmd.c_str()); # --------------------------------------------------------------------------- # Gauge homing buttons @@ -682,32 +631,32 @@ switch: button: - platform: template - name: "${gauge0_entity_name} Rezero" - entity_category: config + name: "${gauge0_name} Rezero" + entity_category: diagnostic on_press: - uart.write: id: arduino_uart data: "HOME 0\n" - platform: template - name: "${gauge1_entity_name} Rezero" - entity_category: config + name: "${gauge1_name} Rezero" + entity_category: diagnostic on_press: - uart.write: id: arduino_uart data: "HOME 1\n" - platform: template - name: "${gauge2_entity_name} Rezero" - entity_category: config + name: "${gauge2_name} Rezero" + entity_category: diagnostic on_press: - uart.write: id: arduino_uart data: "HOME 2\n" - platform: template - name: "${gauge3_entity_name} Rezero" - entity_category: config + name: "${gauge3_name} Rezero" + entity_category: diagnostic on_press: - uart.write: id: arduino_uart @@ -715,7 +664,7 @@ button: - platform: template name: Rezero All Gauges - entity_category: config + entity_category: diagnostic on_press: - uart.write: id: arduino_uart @@ -726,6 +675,82 @@ button: # --------------------------------------------------------------------------- interval: + - interval: 10ms + then: + - lambda: |- + while (id(arduino_uart).available()) { + uint8_t b; + id(arduino_uart).read_byte(&b); + if (b == '\n') { + std::string &buf = id(uart_rx_buf); + if (!buf.empty() && buf.back() == '\r') buf.pop_back(); + if (!buf.empty()) ESP_LOGI("uart_rx", "RX: %s", buf.c_str()); + if (!buf.empty() && buf != "OK" && buf != "PONG") { + if (buf.rfind("POS ", 0) == 0) { + int gid, cur, tgt, homed, hstate, sweep; + if (sscanf(buf.c_str(), "POS %d %d %d %d %d %d", + &gid, &cur, &tgt, &homed, &hstate, &sweep) == 6) { + float value = 0.0f; + if (gid == 0) { + value = ${gauge0_min} + (tgt / (float)${gauge0_max_steps}) * (${gauge0_max} - ${gauge0_min}); + id(gauge0_target_value) = value; + id(gauge0_target_number).publish_state(value); + } else if (gid == 1) { + value = ${gauge1_min} + (tgt / (float)${gauge1_max_steps}) * (${gauge1_max} - ${gauge1_min}); + id(gauge1_target_value) = value; + id(gauge1_target_number).publish_state(value); + } else if (gid == 2) { + value = ${gauge2_min} + (tgt / (float)${gauge2_max_steps}) * (${gauge2_max} - ${gauge2_min}); + id(gauge2_target_value) = value; + id(gauge2_target_number).publish_state(value); + } else if (gid == 3) { + value = ${gauge3_min} + (tgt / (float)${gauge3_max_steps}) * (${gauge3_max} - ${gauge3_min}); + id(gauge3_target_value) = value; + id(gauge3_target_number).publish_state(value); + } + } + } else if (buf.rfind("CFG ", 0) == 0) { + int gid, spd, acc; + if (sscanf(buf.c_str(), "CFG %d %d %d", &gid, &spd, &acc) == 3) { + if (gid == 0) { + id(gauge0_speed_value) = spd; + id(gauge0_accel_value) = acc; + id(gauge0_speed_number).publish_state(spd); + id(gauge0_accel_number).publish_state(acc); + } else if (gid == 1) { + id(gauge1_speed_value) = spd; + id(gauge1_accel_value) = acc; + id(gauge1_speed_number).publish_state(spd); + id(gauge1_accel_number).publish_state(acc); + } else if (gid == 2) { + id(gauge2_speed_value) = spd; + id(gauge2_accel_value) = acc; + id(gauge2_speed_number).publish_state(spd); + id(gauge2_accel_number).publish_state(acc); + } else if (gid == 3) { + id(gauge3_speed_value) = spd; + id(gauge3_accel_value) = acc; + id(gauge3_speed_number).publish_state(spd); + id(gauge3_accel_number).publish_state(acc); + } + } + } else { + id(arduino_last_message).publish_state(buf); + } + } + buf.clear(); + } else if (id(uart_rx_buf).size() < 128) { + id(uart_rx_buf) += static_cast(b); + } + } + - interval: 30s + then: + - uart.write: + id: arduino_uart + data: "POS?\n" + - uart.write: + id: arduino_uart + data: "CFG?\n" - interval: ${rezero_interval} then: - uart.write: @@ -925,10 +950,6 @@ output: write_action: - lambda: |- id(gauge0_bl_r) = static_cast(state * 255.0f + 0.5f); - char cmd[32]; - snprintf(cmd, sizeof(cmd), "LED 0 0-2 %d %d %d\n", - id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); - id(arduino_uart).write_str(cmd); - platform: template id: gauge0_backlight_green_output @@ -936,10 +957,6 @@ output: write_action: - lambda: |- id(gauge0_bl_g) = static_cast(state * 255.0f + 0.5f); - char cmd[32]; - snprintf(cmd, sizeof(cmd), "LED 0 0-2 %d %d %d\n", - id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); - id(arduino_uart).write_str(cmd); - platform: template id: gauge0_backlight_blue_output @@ -947,10 +964,6 @@ output: write_action: - lambda: |- id(gauge0_bl_b) = static_cast(state * 255.0f + 0.5f); - char cmd[32]; - snprintf(cmd, sizeof(cmd), "LED 0 0-2 %d %d %d\n", - id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); - id(arduino_uart).write_str(cmd); - platform: template id: gauge1_backlight_red_output @@ -958,10 +971,6 @@ output: write_action: - lambda: |- id(gauge1_bl_r) = static_cast(state * 255.0f + 0.5f); - char cmd[32]; - snprintf(cmd, sizeof(cmd), "LED 1 0-2 %d %d %d\n", - id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); - id(arduino_uart).write_str(cmd); - platform: template id: gauge1_backlight_green_output @@ -969,10 +978,6 @@ output: write_action: - lambda: |- id(gauge1_bl_g) = static_cast(state * 255.0f + 0.5f); - char cmd[32]; - snprintf(cmd, sizeof(cmd), "LED 1 0-2 %d %d %d\n", - id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); - id(arduino_uart).write_str(cmd); - platform: template id: gauge1_backlight_blue_output @@ -980,10 +985,6 @@ output: write_action: - lambda: |- id(gauge1_bl_b) = static_cast(state * 255.0f + 0.5f); - char cmd[32]; - snprintf(cmd, sizeof(cmd), "LED 1 0-2 %d %d %d\n", - id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); - id(arduino_uart).write_str(cmd); - platform: template id: gauge2_backlight_red_output @@ -991,10 +992,6 @@ output: write_action: - lambda: |- id(gauge2_bl_r) = static_cast(state * 255.0f + 0.5f); - char cmd[32]; - snprintf(cmd, sizeof(cmd), "LED 2 0-2 %d %d %d\n", - id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); - id(arduino_uart).write_str(cmd); - platform: template id: gauge2_backlight_green_output @@ -1002,10 +999,6 @@ output: write_action: - lambda: |- id(gauge2_bl_g) = static_cast(state * 255.0f + 0.5f); - char cmd[32]; - snprintf(cmd, sizeof(cmd), "LED 2 0-2 %d %d %d\n", - id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); - id(arduino_uart).write_str(cmd); - platform: template id: gauge2_backlight_blue_output @@ -1013,10 +1006,6 @@ output: write_action: - lambda: |- id(gauge2_bl_b) = static_cast(state * 255.0f + 0.5f); - char cmd[32]; - snprintf(cmd, sizeof(cmd), "LED 2 0-2 %d %d %d\n", - id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); - id(arduino_uart).write_str(cmd); - platform: template id: gauge3_backlight_red_output @@ -1024,10 +1013,6 @@ output: write_action: - lambda: |- id(gauge3_bl_r) = static_cast(state * 255.0f + 0.5f); - char cmd[32]; - snprintf(cmd, sizeof(cmd), "LED 3 0-2 %d %d %d\n", - id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); - id(arduino_uart).write_str(cmd); - platform: template id: gauge3_backlight_green_output @@ -1035,10 +1020,6 @@ output: write_action: - lambda: |- id(gauge3_bl_g) = static_cast(state * 255.0f + 0.5f); - char cmd[32]; - snprintf(cmd, sizeof(cmd), "LED 3 0-2 %d %d %d\n", - id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); - id(arduino_uart).write_str(cmd); - platform: template id: gauge3_backlight_blue_output @@ -1046,10 +1027,6 @@ output: write_action: - lambda: |- id(gauge3_bl_b) = static_cast(state * 255.0f + 0.5f); - char cmd[32]; - snprintf(cmd, sizeof(cmd), "LED 3 0-2 %d %d %d\n", - id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); - id(arduino_uart).write_str(cmd); - platform: template id: gauge0_red_indicator_output @@ -1057,7 +1034,7 @@ output: write_action: - lambda: |- id(gauge0_red_on) = state; - id(arduino_uart).write_str(state ? "LED 0 3 255 0 0\n" : "LED 0 3 0 0 0\n"); + { const char* _s = state ? "LED 0 3 255 0 0\n" : "LED 0 3 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge0_green_indicator_output @@ -1065,7 +1042,7 @@ output: write_action: - lambda: |- id(gauge0_green_on) = state; - id(arduino_uart).write_str(state ? "LED 0 4 0 255 0\n" : "LED 0 4 0 0 0\n"); + { const char* _s = state ? "LED 0 4 0 255 0\n" : "LED 0 4 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge0_status_red_output @@ -1073,7 +1050,7 @@ output: write_action: - lambda: |- id(gauge0_status_red_on) = state; - id(arduino_uart).write_str(state ? "LED 0 5 255 0 0\n" : "LED 0 5 0 0 0\n"); + { const char* _s = state ? "LED 0 5 255 0 0\n" : "LED 0 5 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge0_status_green_output @@ -1081,7 +1058,7 @@ output: write_action: - lambda: |- id(gauge0_status_green_on) = state; - id(arduino_uart).write_str(state ? "LED 0 6 0 255 0\n" : "LED 0 6 0 0 0\n"); + { const char* _s = state ? "LED 0 6 0 255 0\n" : "LED 0 6 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge1_red_indicator_output @@ -1089,7 +1066,7 @@ output: write_action: - lambda: |- id(gauge1_red_on) = state; - id(arduino_uart).write_str(state ? "LED 1 3 255 0 0\n" : "LED 1 3 0 0 0\n"); + { const char* _s = state ? "LED 1 3 255 0 0\n" : "LED 1 3 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge1_green_indicator_output @@ -1097,7 +1074,7 @@ output: write_action: - lambda: |- id(gauge1_green_on) = state; - id(arduino_uart).write_str(state ? "LED 1 4 0 255 0\n" : "LED 1 4 0 0 0\n"); + { const char* _s = state ? "LED 1 4 0 255 0\n" : "LED 1 4 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge1_status_red_output @@ -1105,7 +1082,7 @@ output: write_action: - lambda: |- id(gauge1_status_red_on) = state; - id(arduino_uart).write_str(state ? "LED 1 5 255 0 0\n" : "LED 1 5 0 0 0\n"); + { const char* _s = state ? "LED 1 5 255 0 0\n" : "LED 1 5 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge1_status_green_output @@ -1113,7 +1090,7 @@ output: write_action: - lambda: |- id(gauge1_status_green_on) = state; - id(arduino_uart).write_str(state ? "LED 1 6 0 255 0\n" : "LED 1 6 0 0 0\n"); + { const char* _s = state ? "LED 1 6 0 255 0\n" : "LED 1 6 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge2_red_indicator_output @@ -1121,7 +1098,7 @@ output: write_action: - lambda: |- id(gauge2_red_on) = state; - id(arduino_uart).write_str(state ? "LED 2 3 255 0 0\n" : "LED 2 3 0 0 0\n"); + { const char* _s = state ? "LED 2 3 255 0 0\n" : "LED 2 3 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge2_green_indicator_output @@ -1129,7 +1106,7 @@ output: write_action: - lambda: |- id(gauge2_green_on) = state; - id(arduino_uart).write_str(state ? "LED 2 4 0 255 0\n" : "LED 2 4 0 0 0\n"); + { const char* _s = state ? "LED 2 4 0 255 0\n" : "LED 2 4 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge2_status_red_output @@ -1137,7 +1114,7 @@ output: write_action: - lambda: |- id(gauge2_status_red_on) = state; - id(arduino_uart).write_str(state ? "LED 2 5 255 0 0\n" : "LED 2 5 0 0 0\n"); + { const char* _s = state ? "LED 2 5 255 0 0\n" : "LED 2 5 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge2_status_green_output @@ -1145,7 +1122,7 @@ output: write_action: - lambda: |- id(gauge2_status_green_on) = state; - id(arduino_uart).write_str(state ? "LED 2 6 0 255 0\n" : "LED 2 6 0 0 0\n"); + { const char* _s = state ? "LED 2 6 0 255 0\n" : "LED 2 6 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge3_red_indicator_output @@ -1153,7 +1130,7 @@ output: write_action: - lambda: |- id(gauge3_red_on) = state; - id(arduino_uart).write_str(state ? "LED 3 3 255 0 0\n" : "LED 3 3 0 0 0\n"); + { const char* _s = state ? "LED 3 3 255 0 0\n" : "LED 3 3 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge3_green_indicator_output @@ -1161,7 +1138,7 @@ output: write_action: - lambda: |- id(gauge3_green_on) = state; - id(arduino_uart).write_str(state ? "LED 3 4 0 255 0\n" : "LED 3 4 0 0 0\n"); + { const char* _s = state ? "LED 3 4 0 255 0\n" : "LED 3 4 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge3_status_red_output @@ -1169,7 +1146,7 @@ output: write_action: - lambda: |- id(gauge3_status_red_on) = state; - id(arduino_uart).write_str(state ? "LED 3 5 255 0 0\n" : "LED 3 5 0 0 0\n"); + { const char* _s = state ? "LED 3 5 255 0 0\n" : "LED 3 5 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } - platform: template id: gauge3_status_green_output @@ -1177,7 +1154,7 @@ output: write_action: - lambda: |- id(gauge3_status_green_on) = state; - id(arduino_uart).write_str(state ? "LED 3 6 0 255 0\n" : "LED 3 6 0 0 0\n"); + { const char* _s = state ? "LED 3 6 0 255 0\n" : "LED 3 6 0 0 0\n"; ESP_LOGI("uart_tx", "TX: %s", _s); id(arduino_uart).write_str(_s); } # --------------------------------------------------------------------------- # Native HA lights @@ -1186,7 +1163,7 @@ output: light: - platform: rgb id: gauge0_backlight - name: "${gauge0_entity_name} Backlight" + name: "${gauge0_name} Backlight" red: gauge0_backlight_red_output green: gauge0_backlight_green_output blue: gauge0_backlight_blue_output @@ -1195,114 +1172,105 @@ light: effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[36]; snprintf(cmd, sizeof(cmd), "BLINK 0 0-2 800 800 %d %d %d\n", id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[36]; snprintf(cmd, sizeof(cmd), "BLINK 0 0-2 150 150 %d %d %d\n", id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[36]; snprintf(cmd, sizeof(cmd), "BLINK 0 0-2 100 400 %d %d %d\n", id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[34]; snprintf(cmd, sizeof(cmd), "BREATHE 0 0-2 3000 %d %d %d\n", id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[34]; snprintf(cmd, sizeof(cmd), "BREATHE 0 0-2 1200 %d %d %d\n", id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[32]; snprintf(cmd, sizeof(cmd), "DFLASH 0 0-2 %d %d %d\n", id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); on_state: - lambda: |- auto effect = id(gauge0_backlight).get_effect_name(); - char cmd[36]; - if (effect == "Blink Slow") { - snprintf(cmd, sizeof(cmd), "BLINK 0 0-2 800 800 %d %d %d\n", - id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); - } else if (effect == "Blink Fast") { - snprintf(cmd, sizeof(cmd), "BLINK 0 0-2 150 150 %d %d %d\n", - id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); - } else if (effect == "Blink Alert") { - snprintf(cmd, sizeof(cmd), "BLINK 0 0-2 100 400 %d %d %d\n", - id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); - } else if (effect == "Breathe Slow") { - snprintf(cmd, sizeof(cmd), "BREATHE 0 0-2 3000 %d %d %d\n", - id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); - } else if (effect == "Breathe Fast") { - snprintf(cmd, sizeof(cmd), "BREATHE 0 0-2 1200 %d %d %d\n", - id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); - } else if (effect == "Double Flash") { - snprintf(cmd, sizeof(cmd), "DFLASH 0 0-2 %d %d %d\n", - id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); - } else { - snprintf(cmd, sizeof(cmd), "LED 0 0-2 %d %d %d\n", - id(gauge0_bl_r), id(gauge0_bl_g), id(gauge0_bl_b)); - } + if (effect != "None" && !effect.empty()) return; + auto& rv = id(gauge0_backlight).remote_values; + char cmd[32]; + snprintf(cmd, sizeof(cmd), "LED 0 0-2 %d %d %d\n", + rv.is_on() ? static_cast(rv.get_red() * rv.get_brightness() * 255.0f + 0.5f) : 0, + rv.is_on() ? static_cast(rv.get_green() * rv.get_brightness() * 255.0f + 0.5f) : 0, + rv.is_on() ? static_cast(rv.get_blue() * rv.get_brightness() * 255.0f + 0.5f) : 0); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: binary id: gauge0_red_indicator - name: "${gauge0_entity_name} Red Indicator" + name: "${gauge0_name} Red Indicator" output: gauge0_red_indicator_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 0 3 800 800 255 0 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 0 3 150 150 255 0 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 0 3 100 400 255 0 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 0 3 3000 255 0 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 0 3 1200 255 0 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 0 3 255 0 0\n"); on_state: @@ -1330,38 +1298,38 @@ light: - platform: binary id: gauge0_green_indicator - name: "${gauge0_entity_name} Green Indicator" + name: "${gauge0_name} Green Indicator" output: gauge0_green_indicator_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 0 4 800 800 0 255 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 0 4 150 150 0 255 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 0 4 100 400 0 255 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 0 4 3000 0 255 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 0 4 1200 0 255 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 0 4 0 255 0\n"); on_state: @@ -1389,38 +1357,38 @@ light: - platform: binary id: gauge0_status_red - name: "${gauge0_entity_name} Status Red" + name: "${gauge0_name} Status Red" output: gauge0_status_red_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 0 5 800 800 255 0 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 0 5 150 150 255 0 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 0 5 100 400 255 0 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 0 5 3000 255 0 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 0 5 1200 255 0 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 0 5 255 0 0\n"); on_state: @@ -1448,38 +1416,38 @@ light: - platform: binary id: gauge0_status_green - name: "${gauge0_entity_name} Status Green" + name: "${gauge0_name} Status Green" output: gauge0_status_green_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 0 6 800 800 0 255 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 0 6 150 150 0 255 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 0 6 100 400 0 255 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 0 6 3000 0 255 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 0 6 1200 0 255 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 0 6 0 255 0\n"); on_state: @@ -1507,7 +1475,7 @@ light: - platform: rgb id: gauge1_backlight - name: "${gauge1_entity_name} Backlight" + name: "${gauge1_name} Backlight" red: gauge1_backlight_red_output green: gauge1_backlight_green_output blue: gauge1_backlight_blue_output @@ -1516,114 +1484,105 @@ light: effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[36]; snprintf(cmd, sizeof(cmd), "BLINK 1 0-2 800 800 %d %d %d\n", id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[36]; snprintf(cmd, sizeof(cmd), "BLINK 1 0-2 150 150 %d %d %d\n", id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[36]; snprintf(cmd, sizeof(cmd), "BLINK 1 0-2 100 400 %d %d %d\n", id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[34]; snprintf(cmd, sizeof(cmd), "BREATHE 1 0-2 3000 %d %d %d\n", id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[34]; snprintf(cmd, sizeof(cmd), "BREATHE 1 0-2 1200 %d %d %d\n", id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[32]; snprintf(cmd, sizeof(cmd), "DFLASH 1 0-2 %d %d %d\n", id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); on_state: - lambda: |- auto effect = id(gauge1_backlight).get_effect_name(); - char cmd[36]; - if (effect == "Blink Slow") { - snprintf(cmd, sizeof(cmd), "BLINK 1 0-2 800 800 %d %d %d\n", - id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); - } else if (effect == "Blink Fast") { - snprintf(cmd, sizeof(cmd), "BLINK 1 0-2 150 150 %d %d %d\n", - id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); - } else if (effect == "Blink Alert") { - snprintf(cmd, sizeof(cmd), "BLINK 1 0-2 100 400 %d %d %d\n", - id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); - } else if (effect == "Breathe Slow") { - snprintf(cmd, sizeof(cmd), "BREATHE 1 0-2 3000 %d %d %d\n", - id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); - } else if (effect == "Breathe Fast") { - snprintf(cmd, sizeof(cmd), "BREATHE 1 0-2 1200 %d %d %d\n", - id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); - } else if (effect == "Double Flash") { - snprintf(cmd, sizeof(cmd), "DFLASH 1 0-2 %d %d %d\n", - id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); - } else { - snprintf(cmd, sizeof(cmd), "LED 1 0-2 %d %d %d\n", - id(gauge1_bl_r), id(gauge1_bl_g), id(gauge1_bl_b)); - } + if (effect != "None" && !effect.empty()) return; + auto& rv = id(gauge1_backlight).remote_values; + char cmd[32]; + snprintf(cmd, sizeof(cmd), "LED 1 0-2 %d %d %d\n", + rv.is_on() ? static_cast(rv.get_red() * rv.get_brightness() * 255.0f + 0.5f) : 0, + rv.is_on() ? static_cast(rv.get_green() * rv.get_brightness() * 255.0f + 0.5f) : 0, + rv.is_on() ? static_cast(rv.get_blue() * rv.get_brightness() * 255.0f + 0.5f) : 0); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: binary id: gauge1_red_indicator - name: "${gauge1_entity_name} Red Indicator" + name: "${gauge1_name} Red Indicator" output: gauge1_red_indicator_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 1 3 800 800 255 0 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 1 3 150 150 255 0 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 1 3 100 400 255 0 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 1 3 3000 255 0 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 1 3 1200 255 0 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 1 3 255 0 0\n"); on_state: @@ -1651,38 +1610,38 @@ light: - platform: binary id: gauge1_green_indicator - name: "${gauge1_entity_name} Green Indicator" + name: "${gauge1_name} Green Indicator" output: gauge1_green_indicator_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 1 4 800 800 0 255 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 1 4 150 150 0 255 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 1 4 100 400 0 255 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 1 4 3000 0 255 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 1 4 1200 0 255 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 1 4 0 255 0\n"); on_state: @@ -1710,38 +1669,38 @@ light: - platform: binary id: gauge1_status_red - name: "${gauge1_entity_name} Status Red" + name: "${gauge1_name} Status Red" output: gauge1_status_red_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 1 5 800 800 255 0 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 1 5 150 150 255 0 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 1 5 100 400 255 0 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 1 5 3000 255 0 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 1 5 1200 255 0 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 1 5 255 0 0\n"); on_state: @@ -1769,38 +1728,38 @@ light: - platform: binary id: gauge1_status_green - name: "${gauge1_entity_name} Status Green" + name: "${gauge1_name} Status Green" output: gauge1_status_green_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 1 6 800 800 0 255 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 1 6 150 150 0 255 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 1 6 100 400 0 255 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 1 6 3000 0 255 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 1 6 1200 0 255 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 1 6 0 255 0\n"); on_state: @@ -1828,7 +1787,7 @@ light: - platform: rgb id: gauge2_backlight - name: "${gauge2_entity_name} Backlight" + name: "${gauge2_name} Backlight" red: gauge2_backlight_red_output green: gauge2_backlight_green_output blue: gauge2_backlight_blue_output @@ -1837,114 +1796,105 @@ light: effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[36]; snprintf(cmd, sizeof(cmd), "BLINK 2 0-2 800 800 %d %d %d\n", id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[36]; snprintf(cmd, sizeof(cmd), "BLINK 2 0-2 150 150 %d %d %d\n", id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[36]; snprintf(cmd, sizeof(cmd), "BLINK 2 0-2 100 400 %d %d %d\n", id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[34]; snprintf(cmd, sizeof(cmd), "BREATHE 2 0-2 3000 %d %d %d\n", id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[34]; snprintf(cmd, sizeof(cmd), "BREATHE 2 0-2 1200 %d %d %d\n", id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[32]; snprintf(cmd, sizeof(cmd), "DFLASH 2 0-2 %d %d %d\n", id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); on_state: - lambda: |- auto effect = id(gauge2_backlight).get_effect_name(); - char cmd[36]; - if (effect == "Blink Slow") { - snprintf(cmd, sizeof(cmd), "BLINK 2 0-2 800 800 %d %d %d\n", - id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); - } else if (effect == "Blink Fast") { - snprintf(cmd, sizeof(cmd), "BLINK 2 0-2 150 150 %d %d %d\n", - id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); - } else if (effect == "Blink Alert") { - snprintf(cmd, sizeof(cmd), "BLINK 2 0-2 100 400 %d %d %d\n", - id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); - } else if (effect == "Breathe Slow") { - snprintf(cmd, sizeof(cmd), "BREATHE 2 0-2 3000 %d %d %d\n", - id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); - } else if (effect == "Breathe Fast") { - snprintf(cmd, sizeof(cmd), "BREATHE 2 0-2 1200 %d %d %d\n", - id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); - } else if (effect == "Double Flash") { - snprintf(cmd, sizeof(cmd), "DFLASH 2 0-2 %d %d %d\n", - id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); - } else { - snprintf(cmd, sizeof(cmd), "LED 2 0-2 %d %d %d\n", - id(gauge2_bl_r), id(gauge2_bl_g), id(gauge2_bl_b)); - } + if (effect != "None" && !effect.empty()) return; + auto& rv = id(gauge2_backlight).remote_values; + char cmd[32]; + snprintf(cmd, sizeof(cmd), "LED 2 0-2 %d %d %d\n", + rv.is_on() ? static_cast(rv.get_red() * rv.get_brightness() * 255.0f + 0.5f) : 0, + rv.is_on() ? static_cast(rv.get_green() * rv.get_brightness() * 255.0f + 0.5f) : 0, + rv.is_on() ? static_cast(rv.get_blue() * rv.get_brightness() * 255.0f + 0.5f) : 0); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: binary id: gauge2_red_indicator - name: "${gauge2_entity_name} Red Indicator" + name: "${gauge2_name} Red Indicator" output: gauge2_red_indicator_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 2 3 800 800 255 0 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 2 3 150 150 255 0 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 2 3 100 400 255 0 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 2 3 3000 255 0 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 2 3 1200 255 0 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 2 3 255 0 0\n"); on_state: @@ -1972,38 +1922,38 @@ light: - platform: binary id: gauge2_green_indicator - name: "${gauge2_entity_name} Green Indicator" + name: "${gauge2_name} Green Indicator" output: gauge2_green_indicator_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 2 4 800 800 0 255 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 2 4 150 150 0 255 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 2 4 100 400 0 255 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 2 4 3000 0 255 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 2 4 1200 0 255 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 2 4 0 255 0\n"); on_state: @@ -2031,38 +1981,38 @@ light: - platform: binary id: gauge2_status_red - name: "${gauge2_entity_name} Status Red" + name: "${gauge2_name} Status Red" output: gauge2_status_red_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 2 5 800 800 255 0 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 2 5 150 150 255 0 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 2 5 100 400 255 0 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 2 5 3000 255 0 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 2 5 1200 255 0 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 2 5 255 0 0\n"); on_state: @@ -2090,38 +2040,38 @@ light: - platform: binary id: gauge2_status_green - name: "${gauge2_entity_name} Status Green" + name: "${gauge2_name} Status Green" output: gauge2_status_green_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 2 6 800 800 0 255 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 2 6 150 150 0 255 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 2 6 100 400 0 255 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 2 6 3000 0 255 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 2 6 1200 0 255 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 2 6 0 255 0\n"); on_state: @@ -2149,7 +2099,7 @@ light: - platform: rgb id: gauge3_backlight - name: "${gauge3_entity_name} Backlight" + name: "${gauge3_name} Backlight" red: gauge3_backlight_red_output green: gauge3_backlight_green_output blue: gauge3_backlight_blue_output @@ -2158,114 +2108,105 @@ light: effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[36]; snprintf(cmd, sizeof(cmd), "BLINK 3 0-2 800 800 %d %d %d\n", id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[36]; snprintf(cmd, sizeof(cmd), "BLINK 3 0-2 150 150 %d %d %d\n", id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[36]; snprintf(cmd, sizeof(cmd), "BLINK 3 0-2 100 400 %d %d %d\n", id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[34]; snprintf(cmd, sizeof(cmd), "BREATHE 3 0-2 3000 %d %d %d\n", id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[34]; snprintf(cmd, sizeof(cmd), "BREATHE 3 0-2 1200 %d %d %d\n", id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- char cmd[32]; snprintf(cmd, sizeof(cmd), "DFLASH 3 0-2 %d %d %d\n", id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); on_state: - lambda: |- auto effect = id(gauge3_backlight).get_effect_name(); - char cmd[36]; - if (effect == "Blink Slow") { - snprintf(cmd, sizeof(cmd), "BLINK 3 0-2 800 800 %d %d %d\n", - id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); - } else if (effect == "Blink Fast") { - snprintf(cmd, sizeof(cmd), "BLINK 3 0-2 150 150 %d %d %d\n", - id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); - } else if (effect == "Blink Alert") { - snprintf(cmd, sizeof(cmd), "BLINK 3 0-2 100 400 %d %d %d\n", - id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); - } else if (effect == "Breathe Slow") { - snprintf(cmd, sizeof(cmd), "BREATHE 3 0-2 3000 %d %d %d\n", - id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); - } else if (effect == "Breathe Fast") { - snprintf(cmd, sizeof(cmd), "BREATHE 3 0-2 1200 %d %d %d\n", - id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); - } else if (effect == "Double Flash") { - snprintf(cmd, sizeof(cmd), "DFLASH 3 0-2 %d %d %d\n", - id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); - } else { - snprintf(cmd, sizeof(cmd), "LED 3 0-2 %d %d %d\n", - id(gauge3_bl_r), id(gauge3_bl_g), id(gauge3_bl_b)); - } + if (effect != "None" && !effect.empty()) return; + auto& rv = id(gauge3_backlight).remote_values; + char cmd[32]; + snprintf(cmd, sizeof(cmd), "LED 3 0-2 %d %d %d\n", + rv.is_on() ? static_cast(rv.get_red() * rv.get_brightness() * 255.0f + 0.5f) : 0, + rv.is_on() ? static_cast(rv.get_green() * rv.get_brightness() * 255.0f + 0.5f) : 0, + rv.is_on() ? static_cast(rv.get_blue() * rv.get_brightness() * 255.0f + 0.5f) : 0); + ESP_LOGI("uart_tx", "TX: %s", cmd); id(arduino_uart).write_str(cmd); - platform: binary id: gauge3_red_indicator - name: "${gauge3_entity_name} Red Indicator" + name: "${gauge3_name} Red Indicator" output: gauge3_red_indicator_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 3 3 800 800 255 0 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 3 3 150 150 255 0 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 3 3 100 400 255 0 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 3 3 3000 255 0 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 3 3 1200 255 0 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 3 3 255 0 0\n"); on_state: @@ -2293,38 +2234,38 @@ light: - platform: binary id: gauge3_green_indicator - name: "${gauge3_entity_name} Green Indicator" + name: "${gauge3_name} Green Indicator" output: gauge3_green_indicator_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 3 4 800 800 0 255 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 3 4 150 150 0 255 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 3 4 100 400 0 255 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 3 4 3000 0 255 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 3 4 1200 0 255 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 3 4 0 255 0\n"); on_state: @@ -2352,38 +2293,38 @@ light: - platform: binary id: gauge3_status_red - name: "${gauge3_entity_name} Status Red" + name: "${gauge3_name} Status Red" output: gauge3_status_red_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 3 5 800 800 255 0 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 3 5 150 150 255 0 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 3 5 100 400 255 0 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 3 5 3000 255 0 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 3 5 1200 255 0 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 3 5 255 0 0\n"); on_state: @@ -2411,38 +2352,38 @@ light: - platform: binary id: gauge3_status_green - name: "${gauge3_entity_name} Status Green" + name: "${gauge3_name} Status Green" output: gauge3_status_green_output restore_mode: ALWAYS_OFF effects: - lambda: name: Blink Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 3 6 800 800 0 255 0\n"); - lambda: name: Blink Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 3 6 150 150 0 255 0\n"); - lambda: name: Blink Alert - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BLINK 3 6 100 400 0 255 0\n"); - lambda: name: Breathe Slow - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 3 6 3000 0 255 0\n"); - lambda: name: Breathe Fast - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("BREATHE 3 6 1200 0 255 0\n"); - lambda: name: Double Flash - update_interval: 750ms + update_interval: 3600s lambda: |- id(arduino_uart).write_str("DFLASH 3 6 0 255 0\n"); on_state: