Status LEDs on control rod number plate added
This commit is contained in:
BIN
3d_model/Box for one.stl
Normal file
BIN
3d_model/Box for one.stl
Normal file
Binary file not shown.
BIN
3d_model/case_test.stl
Normal file
BIN
3d_model/case_test.stl
Normal file
Binary file not shown.
@@ -20,7 +20,9 @@
|
|||||||
"unit": "W",
|
"unit": "W",
|
||||||
"leds": {
|
"leds": {
|
||||||
"red_pin": 33,
|
"red_pin": 33,
|
||||||
"green_pin": 32
|
"green_pin": 32,
|
||||||
|
"ws2812_red": [255, 0, 0],
|
||||||
|
"ws2812_green": [0, 255, 0]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -34,14 +36,17 @@
|
|||||||
"unit": "C",
|
"unit": "C",
|
||||||
"leds": {
|
"leds": {
|
||||||
"red_pin": 21,
|
"red_pin": 21,
|
||||||
"green_pin": 20
|
"green_pin": 20,
|
||||||
|
"ws2812_red": [255, 0, 0],
|
||||||
|
"ws2812_green": [0, 255, 0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
"backlight": {
|
"backlight": {
|
||||||
"pin": 23,
|
"pin": 23,
|
||||||
"num_leds_per_gauge": 3
|
"num_leds_per_gauge": 3,
|
||||||
|
"num_status_leds_per_gauge": 2
|
||||||
},
|
},
|
||||||
|
|
||||||
"device": {
|
"device": {
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ REZERO_INTERVAL_MS = int(_cfg.get("rezero_interval_ms", 3600000))
|
|||||||
backlight_cfg = _cfg.get("backlight", {})
|
backlight_cfg = _cfg.get("backlight", {})
|
||||||
BACKLIGHT_PIN = int(backlight_cfg.get("pin", _cfg.get("led_bl_pin", 23)))
|
BACKLIGHT_PIN = int(backlight_cfg.get("pin", _cfg.get("led_bl_pin", 23)))
|
||||||
BACKLIGHT_LEDS_PER_GAUGE = int(backlight_cfg.get("num_leds_per_gauge", 3))
|
BACKLIGHT_LEDS_PER_GAUGE = int(backlight_cfg.get("num_leds_per_gauge", 3))
|
||||||
|
STATUS_LEDS_PER_GAUGE = int(backlight_cfg.get("num_status_leds_per_gauge", 2))
|
||||||
|
|
||||||
device_cfg = _cfg.get("device", {})
|
device_cfg = _cfg.get("device", {})
|
||||||
DEVICE_NAME = device_cfg.get("name", _cfg.get("device_name", "Selsyn Multi"))
|
DEVICE_NAME = device_cfg.get("name", _cfg.get("device_name", "Selsyn Multi"))
|
||||||
@@ -126,6 +127,8 @@ if "gauges" in _cfg:
|
|||||||
"unit": g.get("unit", ""),
|
"unit": g.get("unit", ""),
|
||||||
"red_pin": int(led_cfg.get("red_pin", 33)),
|
"red_pin": int(led_cfg.get("red_pin", 33)),
|
||||||
"green_pin": int(led_cfg.get("green_pin", 32)),
|
"green_pin": int(led_cfg.get("green_pin", 32)),
|
||||||
|
"ws2812_red": tuple(led_cfg.get("ws2812_red", [255, 0, 0])),
|
||||||
|
"ws2812_green": tuple(led_cfg.get("ws2812_green", [0, 255, 0])),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@@ -142,6 +145,8 @@ else:
|
|||||||
"unit": _cfg.get("gauge_unit", "W"),
|
"unit": _cfg.get("gauge_unit", "W"),
|
||||||
"red_pin": int(_cfg.get("led_red_pin", 33)),
|
"red_pin": int(_cfg.get("led_red_pin", 33)),
|
||||||
"green_pin": int(_cfg.get("led_green_pin", 32)),
|
"green_pin": int(_cfg.get("led_green_pin", 32)),
|
||||||
|
"ws2812_red": tuple(_cfg.get("ws2812_red", [255, 0, 0])),
|
||||||
|
"ws2812_green": tuple(_cfg.get("ws2812_green", [0, 255, 0])),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
BL_UNIT = _cfg.get("backlight_unit", "%")
|
BL_UNIT = _cfg.get("backlight_unit", "%")
|
||||||
@@ -229,6 +234,12 @@ def make_gauge_topics(prefix, gauge_id):
|
|||||||
"led_red_disc": f"homeassistant/switch/{MQTT_CLIENT_ID}_g{gauge_id}_red/config",
|
"led_red_disc": f"homeassistant/switch/{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/switch/{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_green": f"{prefix}/gauge{gauge_id}/status_led/green/set",
|
||||||
|
"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_red_disc": f"homeassistant/switch/{MQTT_CLIENT_ID}_g{gauge_id}_status_red/config",
|
||||||
|
"status_green_disc": f"homeassistant/switch/{MQTT_CLIENT_ID}_g{gauge_id}_status_green/config",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -317,12 +328,16 @@ for g in gauges:
|
|||||||
leds_red.append(Pin(g["red_pin"], Pin.OUT, value=0))
|
leds_red.append(Pin(g["red_pin"], Pin.OUT, value=0))
|
||||||
leds_green.append(Pin(g["green_pin"], Pin.OUT, value=0))
|
leds_green.append(Pin(g["green_pin"], Pin.OUT, value=0))
|
||||||
|
|
||||||
total_backlight_leds = num_gauges * BACKLIGHT_LEDS_PER_GAUGE
|
total_backlight_leds = num_gauges * (BACKLIGHT_LEDS_PER_GAUGE + STATUS_LEDS_PER_GAUGE)
|
||||||
leds_bl = NeoPixel(Pin(BACKLIGHT_PIN), total_backlight_leds)
|
leds_bl = NeoPixel(Pin(BACKLIGHT_PIN), total_backlight_leds)
|
||||||
|
|
||||||
_backlight_color = (0, 0, 0)
|
backlight_color = [(0, 0, 0) for _ in range(num_gauges)]
|
||||||
_backlight_brightness = 100
|
backlight_brightness = [100 for _ in range(num_gauges)]
|
||||||
_backlight_on = False
|
backlight_on = [False for _ in range(num_gauges)]
|
||||||
|
|
||||||
|
status_led_red = [False for _ in range(num_gauges)]
|
||||||
|
status_led_green = [False for _ in range(num_gauges)]
|
||||||
|
|
||||||
_bl_dirty_since = None
|
_bl_dirty_since = None
|
||||||
_BL_SAVE_DELAY_MS = 5000
|
_BL_SAVE_DELAY_MS = 5000
|
||||||
|
|
||||||
@@ -379,9 +394,11 @@ def set_backlight_color(gauge_idx, r, g, b, brightness=None):
|
|||||||
backlight_on[gauge_idx] = new_on
|
backlight_on[gauge_idx] = new_on
|
||||||
|
|
||||||
scale = brightness / 100
|
scale = brightness / 100
|
||||||
base_idx = gauge_idx * BACKLIGHT_LEDS_PER_GAUGE
|
leds_per_gauge = BACKLIGHT_LEDS_PER_GAUGE + STATUS_LEDS_PER_GAUGE
|
||||||
|
base_idx = gauge_idx * leds_per_gauge
|
||||||
for j in range(BACKLIGHT_LEDS_PER_GAUGE):
|
for j in range(BACKLIGHT_LEDS_PER_GAUGE):
|
||||||
leds_bl[base_idx + j] = (int(g * scale), int(r * scale), int(b * scale))
|
leds_bl[base_idx + j] = (int(g * scale), int(r * scale), int(b * scale))
|
||||||
|
_update_status_leds(gauge_idx)
|
||||||
leds_bl.write()
|
leds_bl.write()
|
||||||
_mark_bl_dirty()
|
_mark_bl_dirty()
|
||||||
|
|
||||||
@@ -397,13 +414,44 @@ def set_backlight_brightness(gauge_idx, brightness):
|
|||||||
backlight_on[gauge_idx] = new_on
|
backlight_on[gauge_idx] = new_on
|
||||||
r, g, b = backlight_color[gauge_idx]
|
r, g, b = backlight_color[gauge_idx]
|
||||||
scale = clamped / 100
|
scale = clamped / 100
|
||||||
base_idx = gauge_idx * BACKLIGHT_LEDS_PER_GAUGE
|
leds_per_gauge = BACKLIGHT_LEDS_PER_GAUGE + STATUS_LEDS_PER_GAUGE
|
||||||
|
base_idx = gauge_idx * leds_per_gauge
|
||||||
for j in range(BACKLIGHT_LEDS_PER_GAUGE):
|
for j in range(BACKLIGHT_LEDS_PER_GAUGE):
|
||||||
leds_bl[base_idx + j] = (int(g * scale), int(r * scale), int(b * scale))
|
leds_bl[base_idx + j] = (int(g * scale), int(r * scale), int(b * scale))
|
||||||
|
_update_status_leds(gauge_idx)
|
||||||
leds_bl.write()
|
leds_bl.write()
|
||||||
_mark_bl_dirty()
|
_mark_bl_dirty()
|
||||||
|
|
||||||
|
|
||||||
|
def _update_status_leds(gauge_idx):
|
||||||
|
leds_per_gauge = BACKLIGHT_LEDS_PER_GAUGE + STATUS_LEDS_PER_GAUGE
|
||||||
|
base_idx = gauge_idx * leds_per_gauge + BACKLIGHT_LEDS_PER_GAUGE
|
||||||
|
|
||||||
|
g_cfg = gauges[gauge_idx]
|
||||||
|
red_color = g_cfg["ws2812_red"]
|
||||||
|
green_color = g_cfg["ws2812_green"]
|
||||||
|
|
||||||
|
if status_led_red[gauge_idx]:
|
||||||
|
leds_bl[base_idx] = (red_color[1], red_color[0], red_color[2])
|
||||||
|
else:
|
||||||
|
leds_bl[base_idx] = (0, 0, 0)
|
||||||
|
|
||||||
|
if status_led_green[gauge_idx]:
|
||||||
|
leds_bl[base_idx + 1] = (green_color[1], green_color[0], green_color[2])
|
||||||
|
else:
|
||||||
|
leds_bl[base_idx + 1] = (0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def set_status_led(gauge_idx, led_type, state):
|
||||||
|
global status_led_red, status_led_green
|
||||||
|
if led_type == "red":
|
||||||
|
status_led_red[gauge_idx] = state
|
||||||
|
elif led_type == "green":
|
||||||
|
status_led_green[gauge_idx] = state
|
||||||
|
_update_status_leds(gauge_idx)
|
||||||
|
leds_bl.write()
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# State
|
# State
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -513,6 +561,20 @@ def on_message(topic, payload):
|
|||||||
info(f"Gauge {i} backlight → #{r:02x}{g:02x}{b:02x} @ {brightness}%")
|
info(f"Gauge {i} backlight → #{r:02x}{g:02x}{b:02x} @ {brightness}%")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if topic == gt["status_red"]:
|
||||||
|
state = payload.upper() == "ON"
|
||||||
|
set_status_led(i, "red", state)
|
||||||
|
_publish(gt["status_red_state"], "ON" if state else "OFF", retain=True)
|
||||||
|
info(f"Gauge {i} status red → {'ON' if state else 'OFF'}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if topic == gt["status_green"]:
|
||||||
|
state = payload.upper() == "ON"
|
||||||
|
set_status_led(i, "green", state)
|
||||||
|
_publish(gt["status_green_state"], "ON" if state else "OFF", retain=True)
|
||||||
|
info(f"Gauge {i} status green → {'ON' if state else 'OFF'}")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# MQTT connect + discovery
|
# MQTT connect + discovery
|
||||||
@@ -542,6 +604,8 @@ def connect_mqtt():
|
|||||||
client.subscribe(gt["led_red"])
|
client.subscribe(gt["led_red"])
|
||||||
client.subscribe(gt["led_green"])
|
client.subscribe(gt["led_green"])
|
||||||
client.subscribe(gt["led_bl"])
|
client.subscribe(gt["led_bl"])
|
||||||
|
client.subscribe(gt["status_red"])
|
||||||
|
client.subscribe(gt["status_green"])
|
||||||
_mqtt_connected = True
|
_mqtt_connected = True
|
||||||
info(f"MQTT connected client_id={MQTT_CLIENT_ID}")
|
info(f"MQTT connected client_id={MQTT_CLIENT_ID}")
|
||||||
return client
|
return client
|
||||||
@@ -592,6 +656,8 @@ def check_mqtt():
|
|||||||
client_ref.subscribe(gt["led_red"])
|
client_ref.subscribe(gt["led_red"])
|
||||||
client_ref.subscribe(gt["led_green"])
|
client_ref.subscribe(gt["led_green"])
|
||||||
client_ref.subscribe(gt["led_bl"])
|
client_ref.subscribe(gt["led_bl"])
|
||||||
|
client_ref.subscribe(gt["status_red"])
|
||||||
|
client_ref.subscribe(gt["status_green"])
|
||||||
_mqtt_connected = True
|
_mqtt_connected = True
|
||||||
info("MQTT reconnected!")
|
info("MQTT reconnected!")
|
||||||
publish_discovery(client_ref)
|
publish_discovery(client_ref)
|
||||||
@@ -696,6 +762,44 @@ def publish_discovery(client):
|
|||||||
)
|
)
|
||||||
info(f"Discovery: gauge {i} backlight")
|
info(f"Discovery: gauge {i} backlight")
|
||||||
|
|
||||||
|
client.publish(
|
||||||
|
gt["status_red_disc"],
|
||||||
|
ujson.dumps(
|
||||||
|
{
|
||||||
|
"name": f"{g['name']} Status Red",
|
||||||
|
"uniq_id": f"{MQTT_CLIENT_ID}_g{i}_status_red",
|
||||||
|
"cmd_t": gt["status_red"],
|
||||||
|
"stat_t": gt["status_red_state"],
|
||||||
|
"pl_on": "ON",
|
||||||
|
"pl_off": "OFF",
|
||||||
|
"icon": "mdi:led-on",
|
||||||
|
"dev": _dev_ref,
|
||||||
|
"ret": True,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
retain=True,
|
||||||
|
)
|
||||||
|
info(f"Discovery: gauge {i} status red")
|
||||||
|
|
||||||
|
client.publish(
|
||||||
|
gt["status_green_disc"],
|
||||||
|
ujson.dumps(
|
||||||
|
{
|
||||||
|
"name": f"{g['name']} Status Green",
|
||||||
|
"uniq_id": f"{MQTT_CLIENT_ID}_g{i}_status_green",
|
||||||
|
"cmd_t": gt["status_green"],
|
||||||
|
"stat_t": gt["status_green_state"],
|
||||||
|
"pl_on": "ON",
|
||||||
|
"pl_off": "OFF",
|
||||||
|
"icon": "mdi:led-on",
|
||||||
|
"dev": _dev_ref,
|
||||||
|
"ret": True,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
retain=True,
|
||||||
|
)
|
||||||
|
info(f"Discovery: gauge {i} status green")
|
||||||
|
|
||||||
|
|
||||||
def publish_state(client):
|
def publish_state(client):
|
||||||
for i, g in enumerate(gauge_objects):
|
for i, g in enumerate(gauge_objects):
|
||||||
|
|||||||
Reference in New Issue
Block a user