Blinking added with Light-Effects in Home Assistant
This commit is contained in:
244
gauge.py
244
gauge.py
@@ -223,6 +223,15 @@ def set_status_led(gauge_idx, led_type, on):
|
|||||||
_set_led(gauge_idx, _LED_STATUS_GREEN, r, g, b)
|
_set_led(gauge_idx, _LED_STATUS_GREEN, r, g, b)
|
||||||
|
|
||||||
|
|
||||||
|
def _apply_blink_or_led(gauge_idx, led_idx, color, effect):
|
||||||
|
"""Set LED to color; if effect is a known blink preset, start blinking."""
|
||||||
|
r, g, b = color
|
||||||
|
arduino_send(f"LED {gauge_idx} {led_idx} {r} {g} {b}")
|
||||||
|
if effect in _BLINK_PRESETS:
|
||||||
|
on_ms, off_ms = _BLINK_PRESETS[effect]
|
||||||
|
arduino_send(f"BLINK {gauge_idx} {led_idx} {on_ms} {off_ms}")
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# State tracking (for MQTT state publishing)
|
# State tracking (for MQTT state publishing)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -240,6 +249,19 @@ _BL_SAVE_DELAY_MS = 5000
|
|||||||
client_ref = None
|
client_ref = None
|
||||||
_mqtt_connected = False
|
_mqtt_connected = False
|
||||||
|
|
||||||
|
_BLINK_PRESETS = {
|
||||||
|
"Blink Slow": (800, 800),
|
||||||
|
"Blink Fast": (150, 150),
|
||||||
|
"Blink Alert": (100, 400),
|
||||||
|
}
|
||||||
|
_EFFECT_LIST = list(_BLINK_PRESETS.keys())
|
||||||
|
|
||||||
|
_red_effect = [None] * num_gauges
|
||||||
|
_green_effect = [None] * num_gauges
|
||||||
|
_status_red_effect = [None] * num_gauges
|
||||||
|
_status_green_effect= [None] * num_gauges
|
||||||
|
_bl_effect = [None] * num_gauges
|
||||||
|
|
||||||
|
|
||||||
def _backlight_changed(gauge_idx, new_color, new_on, new_brightness):
|
def _backlight_changed(gauge_idx, new_color, new_on, new_brightness):
|
||||||
return (
|
return (
|
||||||
@@ -295,6 +317,8 @@ def publish_backlight_states(client):
|
|||||||
"brightness": int(brightness * 2.55),
|
"brightness": int(brightness * 2.55),
|
||||||
"color": {"r": r, "g": g, "b": b},
|
"color": {"r": r, "g": g, "b": b},
|
||||||
}
|
}
|
||||||
|
if _bl_effect[i]:
|
||||||
|
state["effect"] = _bl_effect[i]
|
||||||
try:
|
try:
|
||||||
client.publish(gt["led_bl_state"], ujson.dumps(state), retain=True)
|
client.publish(gt["led_bl_state"], ujson.dumps(state), retain=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -344,15 +368,15 @@ def make_gauge_topics(prefix, gauge_id):
|
|||||||
"led_red_state": f"{prefix}/gauge{gauge_id}/led/red/state",
|
"led_red_state": f"{prefix}/gauge{gauge_id}/led/red/state",
|
||||||
"led_green_state": f"{prefix}/gauge{gauge_id}/led/green/state",
|
"led_green_state": f"{prefix}/gauge{gauge_id}/led/green/state",
|
||||||
"led_bl_state": f"{prefix}/gauge{gauge_id}/led/backlight/state",
|
"led_bl_state": f"{prefix}/gauge{gauge_id}/led/backlight/state",
|
||||||
"led_red_disc": f"homeassistant/switch/{MQTT_CLIENT_ID}_g{gauge_id}_red/config",
|
"led_red_disc": f"homeassistant/light/{MQTT_CLIENT_ID}_g{gauge_id}_red/config",
|
||||||
"led_green_disc": f"homeassistant/switch/{MQTT_CLIENT_ID}_g{gauge_id}_green/config",
|
"led_green_disc": f"homeassistant/light/{MQTT_CLIENT_ID}_g{gauge_id}_green/config",
|
||||||
"led_bl_disc": f"homeassistant/light/{MQTT_CLIENT_ID}_g{gauge_id}_bl/config",
|
"led_bl_disc": f"homeassistant/light/{MQTT_CLIENT_ID}_g{gauge_id}_bl/config",
|
||||||
"status_red": f"{prefix}/gauge{gauge_id}/status_led/red/set",
|
"status_red": f"{prefix}/gauge{gauge_id}/status_led/red/set",
|
||||||
"status_green": f"{prefix}/gauge{gauge_id}/status_led/green/set",
|
"status_green": f"{prefix}/gauge{gauge_id}/status_led/green/set",
|
||||||
"status_red_state": f"{prefix}/gauge{gauge_id}/status_led/red/state",
|
"status_red_state": f"{prefix}/gauge{gauge_id}/status_led/red/state",
|
||||||
"status_green_state": f"{prefix}/gauge{gauge_id}/status_led/green/state",
|
"status_green_state": f"{prefix}/gauge{gauge_id}/status_led/green/state",
|
||||||
"status_red_disc": f"homeassistant/switch/{MQTT_CLIENT_ID}_g{gauge_id}_status_red/config",
|
"status_red_disc": f"homeassistant/light/{MQTT_CLIENT_ID}_g{gauge_id}_status_red/config",
|
||||||
"status_green_disc": f"homeassistant/switch/{MQTT_CLIENT_ID}_g{gauge_id}_status_green/config",
|
"status_green_disc": f"homeassistant/light/{MQTT_CLIENT_ID}_g{gauge_id}_status_green/config",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -464,27 +488,50 @@ def on_message(topic, payload):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if topic == gt["led_red"]:
|
if topic == gt["led_red"]:
|
||||||
state = payload.upper() == "ON"
|
try:
|
||||||
set_red_led(i, state)
|
data = ujson.loads(payload)
|
||||||
_publish(gt["led_red_state"], "ON" if state else "OFF", retain=True)
|
except:
|
||||||
info(f"Gauge {i} red LED → {'ON' if state else 'OFF'}")
|
data = {"state": payload}
|
||||||
|
state_on = data.get("state", "ON").upper() != "OFF"
|
||||||
|
effect = data.get("effect") if state_on else None
|
||||||
|
if effect not in _BLINK_PRESETS:
|
||||||
|
effect = None
|
||||||
|
_red_effect[i] = effect
|
||||||
|
color = gauges[i]["ws2812_red"] if state_on else (0, 0, 0)
|
||||||
|
_apply_blink_or_led(i, _LED_RED, color, effect)
|
||||||
|
pub = {"state": "ON" if state_on else "OFF"}
|
||||||
|
if effect:
|
||||||
|
pub["effect"] = effect
|
||||||
|
_publish(gt["led_red_state"], ujson.dumps(pub), retain=True)
|
||||||
|
info(f"Gauge {i} red LED → {'ON' if state_on else 'OFF'}{' [' + effect + ']' if effect else ''}")
|
||||||
return
|
return
|
||||||
|
|
||||||
if topic == gt["led_green"]:
|
if topic == gt["led_green"]:
|
||||||
state = payload.upper() == "ON"
|
try:
|
||||||
set_green_led(i, state)
|
data = ujson.loads(payload)
|
||||||
_publish(gt["led_green_state"], "ON" if state else "OFF", retain=True)
|
except:
|
||||||
info(f"Gauge {i} green LED → {'ON' if state else 'OFF'}")
|
data = {"state": payload}
|
||||||
|
state_on = data.get("state", "ON").upper() != "OFF"
|
||||||
|
effect = data.get("effect") if state_on else None
|
||||||
|
if effect not in _BLINK_PRESETS:
|
||||||
|
effect = None
|
||||||
|
_green_effect[i] = effect
|
||||||
|
color = gauges[i]["ws2812_green"] if state_on else (0, 0, 0)
|
||||||
|
_apply_blink_or_led(i, _LED_GREEN, color, effect)
|
||||||
|
pub = {"state": "ON" if state_on else "OFF"}
|
||||||
|
if effect:
|
||||||
|
pub["effect"] = effect
|
||||||
|
_publish(gt["led_green_state"], ujson.dumps(pub), retain=True)
|
||||||
|
info(f"Gauge {i} green LED → {'ON' if state_on else 'OFF'}{' [' + effect + ']' if effect else ''}")
|
||||||
return
|
return
|
||||||
|
|
||||||
if topic == gt["led_bl"]:
|
if topic == gt["led_bl"]:
|
||||||
try:
|
try:
|
||||||
data = ujson.loads(payload)
|
data = ujson.loads(payload)
|
||||||
if data.get("state", "ON").upper() == "OFF":
|
if data.get("state", "ON").upper() == "OFF":
|
||||||
|
_bl_effect[i] = None
|
||||||
set_backlight_brightness(i, 0)
|
set_backlight_brightness(i, 0)
|
||||||
_publish(
|
_publish(gt["led_bl_state"], ujson.dumps({"state": "OFF"}), retain=True)
|
||||||
gt["led_bl_state"], ujson.dumps({"state": "OFF"}), retain=True
|
|
||||||
)
|
|
||||||
info(f"Gauge {i} backlight → OFF")
|
info(f"Gauge {i} backlight → OFF")
|
||||||
return
|
return
|
||||||
color = data.get("color", {})
|
color = data.get("color", {})
|
||||||
@@ -498,32 +545,71 @@ def on_message(topic, payload):
|
|||||||
brightness = backlight_brightness[i]
|
brightness = backlight_brightness[i]
|
||||||
else:
|
else:
|
||||||
brightness = 100
|
brightness = 100
|
||||||
|
effect = data.get("effect")
|
||||||
|
if effect not in _BLINK_PRESETS:
|
||||||
|
effect = None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
warn(f"Invalid backlight payload for gauge {i}: '{payload}' ({e})")
|
warn(f"Invalid backlight payload for gauge {i}: '{payload}' ({e})")
|
||||||
return
|
return
|
||||||
set_backlight_color(i, r, g, b, brightness)
|
_bl_effect[i] = effect
|
||||||
|
if effect:
|
||||||
|
set_backlight(i, r, g, b, brightness)
|
||||||
|
backlight_color[i] = (r, g, b)
|
||||||
|
backlight_brightness[i] = brightness
|
||||||
|
backlight_on[i] = True
|
||||||
|
on_ms, off_ms = _BLINK_PRESETS[effect]
|
||||||
|
arduino_send(f"BLINK {i} {_LED_BACKLIGHT_RANGE} {on_ms} {off_ms}")
|
||||||
|
_mark_bl_dirty()
|
||||||
|
else:
|
||||||
|
set_backlight_color(i, r, g, b, brightness)
|
||||||
state = {
|
state = {
|
||||||
"state": "ON",
|
"state": "ON",
|
||||||
"color_mode": "rgb",
|
"color_mode": "rgb",
|
||||||
"brightness": int(brightness * 2.55),
|
"brightness": int(brightness * 2.55),
|
||||||
"color": {"r": r, "g": g, "b": b},
|
"color": {"r": r, "g": g, "b": b},
|
||||||
}
|
}
|
||||||
|
if effect:
|
||||||
|
state["effect"] = effect
|
||||||
_publish(gt["led_bl_state"], ujson.dumps(state), retain=True)
|
_publish(gt["led_bl_state"], ujson.dumps(state), retain=True)
|
||||||
info(f"Gauge {i} backlight → #{r:02x}{g:02x}{b:02x} @ {brightness}%")
|
info(f"Gauge {i} backlight → #{r:02x}{g:02x}{b:02x} @ {brightness}%{' [' + effect + ']' if effect else ''}")
|
||||||
return
|
return
|
||||||
|
|
||||||
if topic == gt["status_red"]:
|
if topic == gt["status_red"]:
|
||||||
state = payload.upper() == "ON"
|
try:
|
||||||
set_status_led(i, "red", state)
|
data = ujson.loads(payload)
|
||||||
_publish(gt["status_red_state"], "ON" if state else "OFF", retain=True)
|
except:
|
||||||
info(f"Gauge {i} status red → {'ON' if state else 'OFF'}")
|
data = {"state": payload}
|
||||||
|
state_on = data.get("state", "ON").upper() != "OFF"
|
||||||
|
effect = data.get("effect") if state_on else None
|
||||||
|
if effect not in _BLINK_PRESETS:
|
||||||
|
effect = None
|
||||||
|
_status_red_effect[i] = effect
|
||||||
|
color = gauges[i]["ws2812_red"] if state_on else (0, 0, 0)
|
||||||
|
_apply_blink_or_led(i, _LED_STATUS_RED, color, effect)
|
||||||
|
pub = {"state": "ON" if state_on else "OFF"}
|
||||||
|
if effect:
|
||||||
|
pub["effect"] = effect
|
||||||
|
_publish(gt["status_red_state"], ujson.dumps(pub), retain=True)
|
||||||
|
info(f"Gauge {i} status red → {'ON' if state_on else 'OFF'}{' [' + effect + ']' if effect else ''}")
|
||||||
return
|
return
|
||||||
|
|
||||||
if topic == gt["status_green"]:
|
if topic == gt["status_green"]:
|
||||||
state = payload.upper() == "ON"
|
try:
|
||||||
set_status_led(i, "green", state)
|
data = ujson.loads(payload)
|
||||||
_publish(gt["status_green_state"], "ON" if state else "OFF", retain=True)
|
except:
|
||||||
info(f"Gauge {i} status green → {'ON' if state else 'OFF'}")
|
data = {"state": payload}
|
||||||
|
state_on = data.get("state", "ON").upper() != "OFF"
|
||||||
|
effect = data.get("effect") if state_on else None
|
||||||
|
if effect not in _BLINK_PRESETS:
|
||||||
|
effect = None
|
||||||
|
_status_green_effect[i] = effect
|
||||||
|
color = gauges[i]["ws2812_green"] if state_on else (0, 0, 0)
|
||||||
|
_apply_blink_or_led(i, _LED_STATUS_GREEN, color, effect)
|
||||||
|
pub = {"state": "ON" if state_on else "OFF"}
|
||||||
|
if effect:
|
||||||
|
pub["effect"] = effect
|
||||||
|
_publish(gt["status_green_state"], ujson.dumps(pub), retain=True)
|
||||||
|
info(f"Gauge {i} status green → {'ON' if state_on else 'OFF'}{' [' + effect + ']' if effect else ''}")
|
||||||
return
|
return
|
||||||
|
|
||||||
if topic == T_ZERO:
|
if topic == T_ZERO:
|
||||||
@@ -658,6 +744,24 @@ def publish_discovery(client):
|
|||||||
"""Publish all HA MQTT discovery payloads for gauges and LEDs."""
|
"""Publish all HA MQTT discovery payloads for gauges and LEDs."""
|
||||||
_dev_ref = _DEVICE
|
_dev_ref = _DEVICE
|
||||||
|
|
||||||
|
# Clear any previously registered switch entities (migration to light).
|
||||||
|
for i in range(num_gauges):
|
||||||
|
for old_t in [
|
||||||
|
f"homeassistant/switch/{MQTT_CLIENT_ID}_g{i}_red/config",
|
||||||
|
f"homeassistant/switch/{MQTT_CLIENT_ID}_g{i}_green/config",
|
||||||
|
f"homeassistant/switch/{MQTT_CLIENT_ID}_g{i}_status_red/config",
|
||||||
|
f"homeassistant/switch/{MQTT_CLIENT_ID}_g{i}_status_green/config",
|
||||||
|
]:
|
||||||
|
client.publish(old_t, b"", retain=True)
|
||||||
|
|
||||||
|
_indicator_light = {
|
||||||
|
"schema": "json",
|
||||||
|
"supported_color_modes": ["onoff"],
|
||||||
|
"effect": True,
|
||||||
|
"effect_list": _EFFECT_LIST,
|
||||||
|
"ret": True,
|
||||||
|
}
|
||||||
|
|
||||||
for i, g in enumerate(gauges):
|
for i, g in enumerate(gauges):
|
||||||
gt = gauge_topics[i]
|
gt = gauge_topics[i]
|
||||||
|
|
||||||
@@ -688,38 +792,30 @@ def publish_discovery(client):
|
|||||||
|
|
||||||
client.publish(
|
client.publish(
|
||||||
gt["led_red_disc"],
|
gt["led_red_disc"],
|
||||||
ujson.dumps(
|
ujson.dumps({
|
||||||
{
|
"name": f"{g['name']} Red LED",
|
||||||
"name": f"{g['name']} Red LED",
|
"uniq_id": f"{MQTT_CLIENT_ID}_g{i}_red",
|
||||||
"uniq_id": f"{MQTT_CLIENT_ID}_g{i}_red",
|
"cmd_t": gt["led_red"],
|
||||||
"cmd_t": gt["led_red"],
|
"stat_t": gt["led_red_state"],
|
||||||
"stat_t": gt["led_red_state"],
|
"icon": "mdi:led-on",
|
||||||
"pl_on": "ON",
|
"dev": _dev_ref,
|
||||||
"pl_off": "OFF",
|
**_indicator_light,
|
||||||
"icon": "mdi:led-on",
|
}),
|
||||||
"dev": _dev_ref,
|
|
||||||
"ret": True,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
retain=True,
|
retain=True,
|
||||||
)
|
)
|
||||||
info(f"Discovery: gauge {i} red LED")
|
info(f"Discovery: gauge {i} red LED")
|
||||||
|
|
||||||
client.publish(
|
client.publish(
|
||||||
gt["led_green_disc"],
|
gt["led_green_disc"],
|
||||||
ujson.dumps(
|
ujson.dumps({
|
||||||
{
|
"name": f"{g['name']} Green LED",
|
||||||
"name": f"{g['name']} Green LED",
|
"uniq_id": f"{MQTT_CLIENT_ID}_g{i}_green",
|
||||||
"uniq_id": f"{MQTT_CLIENT_ID}_g{i}_green",
|
"cmd_t": gt["led_green"],
|
||||||
"cmd_t": gt["led_green"],
|
"stat_t": gt["led_green_state"],
|
||||||
"stat_t": gt["led_green_state"],
|
"icon": "mdi:led-on",
|
||||||
"pl_on": "ON",
|
"dev": _dev_ref,
|
||||||
"pl_off": "OFF",
|
**_indicator_light,
|
||||||
"icon": "mdi:led-on",
|
}),
|
||||||
"dev": _dev_ref,
|
|
||||||
"ret": True,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
retain=True,
|
retain=True,
|
||||||
)
|
)
|
||||||
info(f"Discovery: gauge {i} green LED")
|
info(f"Discovery: gauge {i} green LED")
|
||||||
@@ -738,6 +834,8 @@ def publish_discovery(client):
|
|||||||
"stat_t": gt["led_bl_state"],
|
"stat_t": gt["led_bl_state"],
|
||||||
"schema": "json",
|
"schema": "json",
|
||||||
"supported_color_modes": ["rgb"],
|
"supported_color_modes": ["rgb"],
|
||||||
|
"effect": True,
|
||||||
|
"effect_list": _EFFECT_LIST,
|
||||||
"icon": "mdi:led-strip",
|
"icon": "mdi:led-strip",
|
||||||
"dev": _dev_ref,
|
"dev": _dev_ref,
|
||||||
"ret": True,
|
"ret": True,
|
||||||
@@ -749,38 +847,30 @@ def publish_discovery(client):
|
|||||||
|
|
||||||
client.publish(
|
client.publish(
|
||||||
gt["status_red_disc"],
|
gt["status_red_disc"],
|
||||||
ujson.dumps(
|
ujson.dumps({
|
||||||
{
|
"name": f"{g['name']} Status Red",
|
||||||
"name": f"{g['name']} Status Red",
|
"uniq_id": f"{MQTT_CLIENT_ID}_g{i}_status_red",
|
||||||
"uniq_id": f"{MQTT_CLIENT_ID}_g{i}_status_red",
|
"cmd_t": gt["status_red"],
|
||||||
"cmd_t": gt["status_red"],
|
"stat_t": gt["status_red_state"],
|
||||||
"stat_t": gt["status_red_state"],
|
"icon": "mdi:led-on",
|
||||||
"pl_on": "ON",
|
"dev": _dev_ref,
|
||||||
"pl_off": "OFF",
|
**_indicator_light,
|
||||||
"icon": "mdi:led-on",
|
}),
|
||||||
"dev": _dev_ref,
|
|
||||||
"ret": True,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
retain=True,
|
retain=True,
|
||||||
)
|
)
|
||||||
info(f"Discovery: gauge {i} status red")
|
info(f"Discovery: gauge {i} status red")
|
||||||
|
|
||||||
client.publish(
|
client.publish(
|
||||||
gt["status_green_disc"],
|
gt["status_green_disc"],
|
||||||
ujson.dumps(
|
ujson.dumps({
|
||||||
{
|
"name": f"{g['name']} Status Green",
|
||||||
"name": f"{g['name']} Status Green",
|
"uniq_id": f"{MQTT_CLIENT_ID}_g{i}_status_green",
|
||||||
"uniq_id": f"{MQTT_CLIENT_ID}_g{i}_status_green",
|
"cmd_t": gt["status_green"],
|
||||||
"cmd_t": gt["status_green"],
|
"stat_t": gt["status_green_state"],
|
||||||
"stat_t": gt["status_green_state"],
|
"icon": "mdi:led-on",
|
||||||
"pl_on": "ON",
|
"dev": _dev_ref,
|
||||||
"pl_off": "OFF",
|
**_indicator_light,
|
||||||
"icon": "mdi:led-on",
|
}),
|
||||||
"dev": _dev_ref,
|
|
||||||
"ret": True,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
retain=True,
|
retain=True,
|
||||||
)
|
)
|
||||||
info(f"Discovery: gauge {i} status green")
|
info(f"Discovery: gauge {i} status green")
|
||||||
|
|||||||
Reference in New Issue
Block a user