From c547bd8cb9a6db5321c23f48eb88287b429676dd Mon Sep 17 00:00:00 2001 From: root Date: Wed, 27 Aug 2025 00:11:56 +1200 Subject: [PATCH] ESPHome new device, DIN power mon PMB --- esphome/esp-bedrm2fanswitch.yaml | 8 +- esphome/esp-dinpowermonitor-pmb.yaml | 755 +++++++++++++++++++++++++++ esphome/esp-mainbathfancombo.yaml | 12 +- esphome/esp-officeelvcontrol.yaml | 5 +- esphome/esp-officeusbhubpower.yaml | 5 +- packages/simulation_lights.yaml | 7 +- 6 files changed, 776 insertions(+), 16 deletions(-) create mode 100644 esphome/esp-dinpowermonitor-pmb.yaml diff --git a/esphome/esp-bedrm2fanswitch.yaml b/esphome/esp-bedrm2fanswitch.yaml index 135dfc5..cb15920 100644 --- a/esphome/esp-bedrm2fanswitch.yaml +++ b/esphome/esp-bedrm2fanswitch.yaml @@ -36,8 +36,8 @@ substitutions: api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names static_ip_address: !secret esp-bedrm2fanswitch_ip - mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic - mqtt_local_status_main_topic: !secret mqtt_local_status_main_topic + mqtt_command_main_topic: !secret mqtt_command_main_topic + mqtt_status_main_topic: !secret mqtt_status_main_topic # Device Settings #relay_icon: "mdi:heating-coil" @@ -51,11 +51,11 @@ substitutions: # MQTT REMOTE Controls mqtt_remote_device_name: "bedroom2-ceilingfan" - mqtt_remote_device_command_topic: "${mqtt_local_command_main_topic}/${mqtt_remote_device_name}/speed/set" + mqtt_remote_device_command_topic: "${mqtt_command_main_topic}/${mqtt_remote_device_name}/speed/set" mqtt_remote_device_command1: "+" mqtt_remote_device_command2: "-" mqtt_remote_device_command3: "0" - mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_remote_device_name}/speed/state" # Topic we will use to view status locally without HA + mqtt_local_status_topic: "${mqtt_status_main_topic}/${mqtt_remote_device_name}/speed/state" # Topic we will use to view status locally without HA # Button Naming & Icons diff --git a/esphome/esp-dinpowermonitor-pmb.yaml b/esphome/esp-dinpowermonitor-pmb.yaml new file mode 100644 index 0000000..44b76c7 --- /dev/null +++ b/esphome/esp-dinpowermonitor-pmb.yaml @@ -0,0 +1,755 @@ +########################################################################################## +########################################################################################## +# SMART DIN POWER MONITOR AND RELAY (Originally CBU) +# V1.0 2025-08-26 Initial Version +########################################################################################## +# Ex Tuya Smart Relay +# Uses this chip for power monitoring BL0942 +# Replacement https://templates.blakadder.com/ESP8685-WROOM-06.html +# +# NOTES +# - DIN rail power monitor and relay +# - Relay is a pulse to latch ON (GPIO04) and pulse to latch OFF (GPIO05) +# - Has an "is it running" template sensor with a minimum wattage value of ${min_power_to_state_running_default} +# - The relay opens on over-current at ${max_current_trip_default} (Trip Active sensor set). Trip is latched +# (relay stays OFF) until manually reset via the "Clear Trip" button or you toggle the relay ON again. +# - The status_led flashes with a speed depending on current (faster near limit). +# - The status_led is ON when the relay has tripped +# - Inrush debounce: current must remain above the trip threshold for ${overcurrent_debounce_ms} ms +# before the trip occurs (helps ignore short inrush spikes). +# - Energy totals calculated on-device: +# * Last Hour Energy (kWh) – snapshot of the previous completed hour +# * Today / Yesterday (kWh) – resets at local midnight, survives reboots +# * This Week / Last Week (kWh) – resets at Monday 00:00 local time, survives reboots +# * This Month / Last Month (kWh) – resets at 1st of month 00:00 local time, survives reboots +# - For rolling 24h Min/Max Power, use HA "Statistics" helper instead of on-device buffers. +# +########################################################################################## +########################################################################################## + +########################################################################################## +# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +# If NOT using a secrets file, just replace these with the passwords etc (in quotes) +########################################################################################## +substitutions: + # Device Naming + device_name: "dinpowermonitor-pmb" + friendly_name: "Din Power" + description_comment: "DIN Rail mounted current monitor and relay, with current based (software) trip" + device_area: "Hallway" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "Generic ESP32.ESP8685-WROOM-06" # Project details, a dot separates the HA columns + project_version: "v1.0" # Project version allows checking of deployed vs latest version + + # Passwords + api_key: !secret esp-api_key # unfortunately you cannot use substitutions inside secrets names + ota_pass: !secret esp-ota_pass + static_ip_address: !secret esp-dinpowermonitor-pmb_ip + + # Device General Settings + log_level: "ERROR" # NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + update_interval: "60s" # update time for general sensors etc + + # Device Specific Defaults (used to seed HA-tunable numbers) + relay_1_name: "Relay" + button_1_name: "Toggle Button" + status_led_name: "Power Active" + min_power_to_state_running_default: 4 # Watts, initial value only + max_current_trip_default: 6 # Amps, initial value only + led_flash_slow_ms: 1000 # slow flash period when just running + led_flash_fast_ms: 100 # very fast flash period near trip + overcurrent_debounce_ms: 300 # Over-current inrush debounce (ms) + +########################################################################################## +# PACKAGES: Included Common Packages +# https://esphome.io/components/packages.html +########################################################################################## +packages: + common_wifi: !include + file: common/network_common.yaml + vars: + local_device_name: "${device_name}" + local_static_ip_address: "${static_ip_address}" + local_ota_pass: "${ota_pass}" + common_api: !include + file: common/api_common.yaml + vars: + local_api_key: "${api_key}" + common_webportal: !include + file: common/webportal_common.yaml + common_mqtt: !include + file: common/mqtt_common.yaml + vars: + local_device_name: "${device_name}" + common_sntp: !include + file: common/sntp_common.yaml + common_general_sensors: !include + file: common/sensors_common.yaml + vars: + local_friendly_name: "${friendly_name}" + local_update_interval: "${update_interval}" + +########################################################################################## +# ESPHome +# https://esphome.io/components/esphome.html +########################################################################################## +esphome: + name: "${device_name}" + friendly_name: "${friendly_name}" + comment: "${description_comment}" # Appears on the ESPHome page in HA + area: "${device_area}" + project: + name: "${project_name}" + version: "${project_version}" + on_boot: + priority: -100 + then: + # Restore "Last Trip" text from persisted epoch (if any) + - lambda: |- + if (id(last_trip_epoch) > 0) { + auto t = time::ESPTime::from_epoch_local(id(last_trip_epoch)); + char buf[24]; + t.strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S"); + id(ts_last_trip).publish_state(buf); + } else { + id(ts_last_trip).publish_state("Never"); + } + # Apply Power Restore Mode selector (Always ON / Always OFF / Previous State) + - lambda: |- + std::string mode = id(sel_restore_mode).state; + if (mode == "Always ON") { + id(relay_virtual).turn_on(); + } else if (mode == "Always OFF") { + id(relay_virtual).turn_off(); + } else { + // "Previous State" -> do nothing (template switch will keep last or default OFF) + } + +########################################################################################## +# ESP Platform and Framework +# https://esphome.io/components/esp32.html +########################################################################################## +esp32: + board: esp32-c3-devkitm-1 + variant: esp32c3 + framework: + type: esp-idf + +########################################################################################## +# ESPHome Logging Enable +# https://esphome.io/components/logger.html +########################################################################################## +logger: + level: ${log_level} + +########################################################################################## +# STATUS LED (BLUE) - low = ON per mapping +# https://esphome.io/components/status_led.html +########################################################################################## +status_led: + pin: + number: GPIO8 + inverted: true + +########################################################################################## +# UART BUS +# https://esphome.io/components/uart/ +########################################################################################## +uart: + # for BL0942 + id: bl_uart + rx_pin: GPIO19 # BL0942 TXD -> MCU RX + tx_pin: GPIO18 # BL0942 RXD -> MCU TX + baud_rate: 4800 + parity: NONE + stop_bits: 1 + +########################################################################################## +# GLOBALS +# https://esphome.io/components/globals.html +########################################################################################## +globals: + # Used for LED blink period calculation (in milliseconds) + - id: _blink_period_ms + type: int + restore_value: no + initial_value: "500" + + # Last trip time, saved across reboots. + - id: last_trip_epoch + type: uint32_t + restore_value: yes + initial_value: "0" + + # Debounce start timestamp (ms since boot) for over-current detection + - id: _oc_start_ms + type: uint32_t + restore_value: no + initial_value: "0" + + # ---- ENERGY ACCUMULATION & PERIOD SNAPSHOTS ---- + - id: g_last_ms # millis() timestamp of last integration step + type: uint32_t + restore_value: no + initial_value: "0" + + # Current-period totals (persisted) + - id: g_hour_kwh + type: float + restore_value: yes + initial_value: "0.0" + - id: g_today_kwh + type: float + restore_value: yes + initial_value: "0.0" + - id: g_week_kwh + type: float + restore_value: yes + initial_value: "0.0" + - id: g_month_kwh + type: float + restore_value: yes + initial_value: "0.0" + + # Last-period snapshots (persisted) + - id: g_last_hour_kwh + type: float + restore_value: yes + initial_value: "0.0" + - id: g_yesterday_kwh + type: float + restore_value: yes + initial_value: "0.0" + - id: g_last_week_kwh + type: float + restore_value: yes + initial_value: "0.0" + - id: g_last_month_kwh + type: float + restore_value: yes + initial_value: "0.0" + + # Boundary trackers (don’t persist) + - id: g_last_hour_seen + type: int + restore_value: no + initial_value: "-1" + - id: g_last_doy_seen + type: int + restore_value: no + initial_value: "-1" + - id: g_last_wday_seen + type: int + restore_value: no + initial_value: "-1" + - id: g_last_month_seen + type: int + restore_value: no + initial_value: "-1" + +########################################################################################## +# SENSORS +# https://esphome.io/components/sensor/ +########################################################################################## +sensor: + - platform: bl0942 + uart_id: bl_uart + update_interval: 250ms + voltage: + name: "${friendly_name} Voltage" + id: pm_voltage + accuracy_decimals: 1 + unit_of_measurement: "V" + device_class: voltage + state_class: measurement + current: + name: "${friendly_name} Current" + id: pm_current + accuracy_decimals: 3 + unit_of_measurement: "A" + device_class: current + state_class: measurement + on_value: + then: + - lambda: |- + // OVER-CURRENT TRIP HANDLER with inrush debounce + // Trip when current > n_max_trip and relay is ON, but only if it stays above + // for ${overcurrent_debounce_ms} ms (to ignore short inrush spikes). + if (id(bs_tripped).state) { + // Already tripped: reset debounce tracker and do nothing + id(_oc_start_ms) = 0; + } else if (id(relay_virtual).state && x > id(n_max_trip).state) { + // Over threshold while relay is ON + if (id(_oc_start_ms) == 0) { + id(_oc_start_ms) = millis(); // start debounce window + } + uint32_t elapsed = millis() - id(_oc_start_ms); + if (elapsed >= ${overcurrent_debounce_ms}) { + ESP_LOGI("trip", + "Overcurrent trip: %.3f A > %.3f A for %u ms (>= %u ms), opening relay", + x, id(n_max_trip).state, (unsigned) elapsed, (unsigned) ${overcurrent_debounce_ms}); + + // Mark trip, stop blinker FIRST + id(bs_tripped).publish_state(true); + id(led_blinker).stop(); + + // Open latching relay (template handles OFF coil pulse) + id(relay_virtual).turn_off(); + + // Force LED solid ON to indicate trip + auto call = id(led).turn_on(); + call.perform(); + + // Time-stamp "Last Trip" using SNTP time (YYYY-MM-DD HH:MM:SS) and persist + auto now_clk = id(sntp_time).now(); + if (now_clk.is_valid()) { + char buf[24]; + now_clk.strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S"); + id(ts_last_trip).publish_state(buf); + id(last_trip_epoch) = (uint32_t) now_clk.timestamp; + } else { + id(ts_last_trip).publish_state("unknown"); + } + + // Reset debounce tracker + id(_oc_start_ms) = 0; + } + } else { + // Below threshold or relay OFF: reset debounce tracker + id(_oc_start_ms) = 0; + } + + // ------------------------------------------------------------------ + // ENERGY ACCUMULATION (kWh) + PERIOD ROLLOVERS (hour/day/week/month) + // ------------------------------------------------------------------ + // Integrate W over time using millis() -> kWh + uint32_t now_ms = millis(); + if (id(g_last_ms) == 0) { + id(g_last_ms) = now_ms; // first sample since boot + } else { + uint32_t dt_ms = now_ms - id(g_last_ms); + id(g_last_ms) = now_ms; + + float p_w = (isnan(x) || x < 0.0f) ? 0.0f : x; // sanitize power + float inc_kwh = p_w * (dt_ms / 3600000.0f); // W * hours -> kWh + + id(g_hour_kwh) += inc_kwh; + id(g_today_kwh) += inc_kwh; + id(g_week_kwh) += inc_kwh; // Week rolls at Monday 00:00 local time + id(g_month_kwh) += inc_kwh; + } + + // Use SNTP time for clean boundary changes + auto now = id(sntp_time).now(); + if (now.is_valid()) { + // Hour rollover: when hour changes + if (id(g_last_hour_seen) != now.hour) { + if (id(g_last_hour_seen) != -1) { + id(g_last_hour_kwh) = id(g_hour_kwh); + id(s_last_hour_kwh).publish_state(id(g_last_hour_kwh)); + } + id(g_hour_kwh) = 0.0f; + id(g_last_hour_seen) = now.hour; + } + + // Day rollover (midnight local) + if (id(g_last_doy_seen) != now.day_of_year) { + if (id(g_last_doy_seen) != -1) { + id(g_yesterday_kwh) = id(g_today_kwh); + id(s_yesterday_kwh).publish_state(id(g_yesterday_kwh)); + } + id(g_today_kwh) = 0.0f; + id(g_last_doy_seen) = now.day_of_year; + } + + // Week rollover: Monday 00:00 local time (i.e., after Sunday) + // ESPHome day_of_week: Monday=1 ... Sunday=7 + if (now.day_of_week == 1 && now.hour == 0 && id(g_last_wday_seen) != 1) { + id(g_last_week_kwh) = id(g_week_kwh); + id(s_last_week_kwh).publish_state(id(g_last_week_kwh)); + id(g_week_kwh) = 0.0f; + } + id(g_last_wday_seen) = now.day_of_week; + + // Month rollover: first day of month at 00:00 + if (id(g_last_month_seen) != now.month) { + if (id(g_last_month_seen) != -1 && now.day_of_month == 1 && now.hour == 0) { + id(g_last_month_kwh) = id(g_month_kwh); + id(s_last_month_kwh).publish_state(id(g_last_month_kwh)); + id(g_month_kwh) = 0.0f; + } + id(g_last_month_seen) = now.month; + } + } + power: + name: "${friendly_name} Power" + id: pm_power + accuracy_decimals: 1 + unit_of_measurement: "W" + device_class: power + state_class: measurement + energy: + name: "${friendly_name} Energy" + id: pm_energy + unit_of_measurement: "Wh" + device_class: energy + state_class: total_increasing + frequency: + name: "${friendly_name} Frequency" + id: pm_freq + unit_of_measurement: "Hz" + device_class: frequency + state_class: measurement + # Optional calibration references (uncomment and tune if needed) + # voltage_reference: 15968 + # current_reference: 124180 + # power_reference: 309.1 + # energy_reference: 2653 + + ########################################################################## + # ENERGY TOTALS (kWh) EXPOSED TO HA + # These read the persisted globals; they update periodically. + ########################################################################## + - platform: template + name: "${friendly_name} Last Hour Energy" + id: s_last_hour_kwh + unit_of_measurement: "kWh" + device_class: energy + state_class: total + accuracy_decimals: 3 + update_interval: 30s + lambda: |- + return id(g_last_hour_kwh); + + - platform: template + name: "${friendly_name} Today Energy" + id: s_today_kwh + unit_of_measurement: "kWh" + device_class: energy + state_class: total + accuracy_decimals: 3 + update_interval: 30s + lambda: |- + return id(g_today_kwh); + + - platform: template + name: "${friendly_name} Yesterday Energy" + id: s_yesterday_kwh + unit_of_measurement: "kWh" + device_class: energy + state_class: total + accuracy_decimals: 3 + update_interval: 30s + lambda: |- + return id(g_yesterday_kwh); + + - platform: template + name: "${friendly_name} This Week Energy" + id: s_week_kwh + unit_of_measurement: "kWh" + device_class: energy + state_class: total + accuracy_decimals: 3 + update_interval: 30s + lambda: |- + return id(g_week_kwh); + + - platform: template + name: "${friendly_name} Last Week Energy" + id: s_last_week_kwh + unit_of_measurement: "kWh" + device_class: energy + state_class: total + accuracy_decimals: 3 + update_interval: 30s + lambda: |- + return id(g_last_week_kwh); + + - platform: template + name: "${friendly_name} This Month Energy" + id: s_month_kwh + unit_of_measurement: "kWh" + device_class: energy + state_class: total + accuracy_decimals: 3 + update_interval: 30s + lambda: |- + return id(g_month_kwh); + + - platform: template + name: "${friendly_name} Last Month Energy" + id: s_last_month_kwh + unit_of_measurement: "kWh" + device_class: energy + state_class: total + accuracy_decimals: 3 + update_interval: 30s + lambda: |- + return id(g_last_month_kwh); + +########################################################################################## +# TEXT SENSOR COMPONENT +# https://esphome.io/components/text_sensor/ +########################################################################################## +text_sensor: + # Holds the date/time of last trip (string with seconds) + - platform: template + name: "${friendly_name} Last Trip" + id: ts_last_trip + icon: "mdi:clock-alert" + entity_category: diagnostic + +########################################################################################## +# BINARY SENSORS +# https://esphome.io/components/binary_sensor/ +# https://esphome.io/components/binary_sensor/template.html +########################################################################################## +binary_sensor: + # "Is Running" template sensor + - platform: template + id: bs_running + name: "${friendly_name} Running" + lambda: |- + if (isnan(id(pm_power).state)) { + return false; + } else if (id(pm_power).state > id(n_min_power).state) { + return true; + } else { + return false; + } + filters: + - delayed_off: 15s + on_press: + then: + - if: + condition: + and: + - switch.is_on: relay_virtual + - lambda: 'return !id(bs_tripped).state;' + then: + - script.execute: led_blinker + on_release: + then: + - script.stop: led_blinker + - if: + condition: + lambda: 'return !id(bs_tripped).state;' + then: + - light.turn_off: led + + # Trip flag exposed to HA; set true on over-current. Cleared when relay is turned ON or via Reset button. + - platform: template + id: bs_tripped + name: "${friendly_name} Trip Active" + device_class: problem + + # On-board button (P17 -> IO9) pulls low when pressed + - platform: gpio + pin: + number: GPIO9 + mode: INPUT_PULLUP + inverted: true + name: "${button_1_name}" + on_press: + - switch.toggle: relay_virtual + +########################################################################################## +# NUMBER COMPONENT +# https://esphome.io/components/number/ +########################################################################################## +# HA-TUNABLE THRESHOLDS (NUMBER ENTITIES) +# https://esphome.io/components/number/template.html +########################################################################################## +number: + - platform: template + name: "${friendly_name} Min Power Running" + id: n_min_power + optimistic: true + restore_value: true + initial_value: ${min_power_to_state_running_default} + min_value: 1 + max_value: 100 + step: 1 + unit_of_measurement: "W" + icon: "mdi:flash-outline" + + - platform: template + name: "${friendly_name} Max Current Trip" + id: n_max_trip + optimistic: true + restore_value: true + initial_value: ${max_current_trip_default} + min_value: 0 + max_value: 10 + step: 0.2 + unit_of_measurement: "A" + icon: "mdi:current-ac" + +########################################################################################## +# BUTTON COMPONENT +# Reset the trip latch from HA (does not close the relay automatically) +# https://esphome.io/components/button/ +########################################################################################## +button: + - platform: template + name: "${friendly_name} Clear Trip" + id: btn_clear_trip + icon: "mdi:alert-remove-outline" + on_press: + - logger.log: "Trip reset requested (clearing Trip Active and LED state)" + - binary_sensor.template.publish: + id: bs_tripped + state: false + - lambda: |- + // Clear any pending debounce + id(_oc_start_ms) = 0; + - if: + condition: + and: + - switch.is_on: relay_virtual + - binary_sensor.is_on: bs_running + then: + - script.execute: led_blinker + else: + - light.turn_off: led + +########################################################################################## +# SWITCH COMPONENT +# https://esphome.io/components/switch/ +########################################################################################## +# LATCHING RELAY CONTROL (two coils: ON and OFF) +# P24 -> IO5 (close), P26 -> IO4 (open) per mapping. +# Two hidden GPIO pulse switches to drive the coils. +# User-facing switch sends a short pulse to the appropriate coil. +########################################################################################## +switch: + # Hidden coil driver: ON pulse (GPIO5) + - platform: gpio + id: relay_on_coil + pin: + number: GPIO5 + inverted: false + restore_mode: ALWAYS_OFF + + # Hidden coil driver: OFF pulse (GPIO4) + - platform: gpio + id: relay_off_coil + pin: + number: GPIO4 + inverted: false + restore_mode: ALWAYS_OFF + + # User-facing virtual switch + - platform: template + id: relay_virtual + name: "${relay_1_name}" + optimistic: true + # Use default restore behavior; "Previous State" is honored by doing nothing in on_boot. + # Set a safe baseline here (default off if no previous state). + restore_mode: RESTORE_DEFAULT_OFF + turn_on_action: + - logger.log: "Relay ON: pulsing ON coil" + - binary_sensor.template.publish: + id: bs_tripped + state: false # clear trip on manual ON + - switch.turn_on: relay_on_coil + - delay: 200ms + - switch.turn_off: relay_on_coil + - if: + condition: + and: + - binary_sensor.is_on: bs_running + - lambda: 'return !id(bs_tripped).state;' + then: + - script.execute: led_blinker + turn_off_action: + - logger.log: "Relay OFF: pulsing OFF coil" + - switch.turn_on: relay_off_coil + - delay: 200ms + - switch.turn_off: relay_off_coil + - script.stop: led_blinker + - if: + condition: + lambda: 'return !id(bs_tripped).state;' + then: + - light.turn_off: led + +########################################################################################## +# OUTPUT COMPONENT +# https://esphome.io/components/output/ledc.html +########################################################################################## +# RED LED AS LIGHT (P9 -> IO10, low = ON) +########################################################################################## +output: + - platform: ledc + id: pow_red_led_pwm + pin: + number: GPIO10 + inverted: true + +########################################################################################## +# LIGHT COMPONENT +# https://esphome.io/components/light/monochromatic.html +########################################################################################## +# Hidden from HA; still used internally by scripts/logic +light: + - platform: monochromatic + id: led + output: pow_red_led_pwm + internal: true + +########################################################################################## +# SELECT COMPONENT +# Choose how the relay state should be restored after boot +# https://esphome.io/components/select/template.html +########################################################################################## +select: + - platform: template + name: "${friendly_name} Power Restore Mode" + id: sel_restore_mode + optimistic: true + restore_value: true + options: + - "Always ON" + - "Always OFF" + - "Previous State" + initial_option: "Previous State" + icon: "mdi:power-settings" + +########################################################################################## +# SCRIPTS +# https://esphome.io/components/script.html +########################################################################################## +script: + # LED blinker: variable-speed based on current vs n_max_trip; runs only when running, relay ON, not tripped + - id: led_blinker + mode: restart + then: + - while: + condition: + and: + - switch.is_on: relay_virtual + - binary_sensor.is_on: bs_running + - lambda: 'return !id(bs_tripped).state;' + then: + # Compute and store current-period ms in _blink_period_ms + - lambda: |- + float i = isnan(id(pm_current).state) ? 0.0f : id(pm_current).state; + float maxA = id(n_max_trip).state; + if (maxA < 0.1f) maxA = 0.1f; + float f = i / maxA; // 0.0 .. 1.0 + if (f < 0.0f) f = 0.0f; + if (f > 1.0f) f = 1.0f; + int slow_ms = ${led_flash_slow_ms}; + int fast_ms = ${led_flash_fast_ms}; + if (slow_ms < fast_ms) { int t = slow_ms; slow_ms = fast_ms; fast_ms = t; } # ensure slow >= fast + int period = slow_ms - (int)((slow_ms - fast_ms) * f); + id(_blink_period_ms) = period; + # Blink with 50% duty cycle at the computed period + - light.turn_on: + id: led + brightness: 100% + - delay: !lambda 'return (uint32_t)(id(_blink_period_ms) / 2);' + - light.turn_off: led + - delay: !lambda 'return (uint32_t)(id(_blink_period_ms) / 2);' diff --git a/esphome/esp-mainbathfancombo.yaml b/esphome/esp-mainbathfancombo.yaml index c4f09dd..d5b2bb9 100644 --- a/esphome/esp-mainbathfancombo.yaml +++ b/esphome/esp-mainbathfancombo.yaml @@ -1,6 +1,7 @@ ############################################# ############################################# # MAIN BATHROOM FAN/HEAT COMBO SWITCH +# V1.1 2025-08-26 Minor Changes (MQTT) # V1.0 2025-06-01 Initial Version ############################################# # Zemismart KS-811 Triple push button @@ -25,7 +26,7 @@ substitutions: # Project Naming project_name: "Zemismart Technologies.KS-811-2 (Double)" # Project Details - project_version: "v1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_version: "v1.1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version entity_prefix: "Main Bathroom" # Simple device name where we want to prefix a sensor or switch, eg "Load" Current. @@ -33,16 +34,17 @@ substitutions: api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names static_ip_address: !secret esp-mainbathfancombo_ip + mqtt_command_main_topic: !secret mqtt_command_main_topic + #mqtt_status_main_topic: !secret mqtt_status_main_topic # Device Settings #relay_icon: "mdi:heating-coil" log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE update_interval: "60s" # update time for for general sensors etc - # MQTT Controls - mqtt_main_command_topic: !secret mqtt_main_command_topic - #mqtt_main_status_topic: !secret mqtt_main_status_topic - mqtt_remote_device1_command_topic: "${mqtt_main_command_topic}/masterbath-towelrail/operation" + # MQTT REMOTE Controls + mqtt_remote_device1_name: "masterbath-towelrail" + mqtt_remote_device1_command_topic: "${mqtt_command_main_topic}/${mqtt_remote_device1_name}/operation" mqtt_remote_device1_command1: "BOOST" ########################################################################################## diff --git a/esphome/esp-officeelvcontrol.yaml b/esphome/esp-officeelvcontrol.yaml index 910089b..8d8751e 100644 --- a/esphome/esp-officeelvcontrol.yaml +++ b/esphome/esp-officeelvcontrol.yaml @@ -27,7 +27,8 @@ substitutions: api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names static_ip_address: !secret esp-officeelvcontrol_ip - mqtt_main_command_topic: !secret mqtt_main_command_topic + mqtt_command_main_topic: !secret mqtt_command_main_topic + #mqtt_status_main_topic: !secret mqtt_status_main_topic # Device Settings relay_icon: "mdi:generator-portable" @@ -40,7 +41,7 @@ substitutions: # MQTT Controls mqtt_device_name: "office-elv-control" - mqtt_main_topic: "${mqtt_main_command_topic}/${mqtt_device_name}" # Topic we will use to command stuff from external without HA + mqtt_main_topic: "${mqtt_command_main_topic}/${mqtt_device_name}" # Topic we will use to command stuff from external without HA ########################################################################################## # PACKAGES: Included Common Packages diff --git a/esphome/esp-officeusbhubpower.yaml b/esphome/esp-officeusbhubpower.yaml index 82201fe..ae97ba3 100644 --- a/esphome/esp-officeusbhubpower.yaml +++ b/esphome/esp-officeusbhubpower.yaml @@ -27,7 +27,8 @@ substitutions: api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names static_ip_address: !secret esp-officeusbhubpower_ip - mqtt_main_command_topic: !secret mqtt_main_command_topic + mqtt_command_main_topic: !secret mqtt_command_main_topic + mqtt_status_main_topic: !secret mqtt_status_main_topic # Device Settings relay_icon: "mdi:generator-portable" @@ -40,7 +41,7 @@ substitutions: # MQTT Controls mqtt_device_name: "office-usbhub-power" - mqtt_main_topic: "${mqtt_main_command_topic}/${mqtt_device_name}" # Topic we will use to command stuff from external without HA + mqtt_main_topic: "${mqtt_command_main_topic}/${mqtt_device_name}" # Topic we will use to command stuff from external without HA ########################################################################################## # PACKAGES: Included Common Packages diff --git a/packages/simulation_lights.yaml b/packages/simulation_lights.yaml index f482b2c..90e40ac 100644 --- a/packages/simulation_lights.yaml +++ b/packages/simulation_lights.yaml @@ -2,13 +2,14 @@ group: simulation_lights_all: name: Simulation Lights (All) entities: + - switch.esp_centralstairs_top_relay_2_stair_footer_lights + - switch.esp_centralstairs_bottom_relay_1_main_stair_lights_lower + - switch.esp_entrancebathrmlights_relay_1_main_lights + - group.downstairs_flat_lights # ← now valid here - switch.tasmo_ks811d_1242_entrance_a - switch.tasmo_ks811d_6110_kitchen_a - switch.tasmo_ks811d_6110_kitchen_b - switch.main_hallway_lightswitch_tasmo_ks811s_2940_hallway_1a - - switch.tasmo_ks811d_1701_stairs_2a - switch.tasmo_ks811t_0702_lounge_3a - switch.tasmo_ks811t_0702_lounge_3b - switch.tasmo_ks811t_0702_lounge_3c - - switch.esp_entrancebathrmlights_relay_1_main_lights - - group.downstairs_flat_lights # ← now valid here