M5-T11: add HA discovery and state publishing wired to polling
This commit is contained in:
+44
-19
@@ -91,9 +91,10 @@ class ExposableEntity:
|
||||
context, e.g. ``"SDM120 Voltage"``).
|
||||
|
||||
value_getter
|
||||
Optional callable ``() -> object | None`` that returns the current
|
||||
entity value. ``None`` means "not yet wired" (T11 will populate this).
|
||||
T11 calls this to obtain the current state before publishing.
|
||||
Optional callable ``(session) -> object | None`` that returns the current
|
||||
entity value given an open SQLAlchemy session. ``None`` means "not yet
|
||||
wired". T11 calls this to obtain the current state before publishing.
|
||||
Signature: ``Callable[[Session], Any]``.
|
||||
|
||||
state_class
|
||||
HA ``state_class`` string (e.g. ``"measurement"``, ``"total_increasing"``).
|
||||
@@ -106,7 +107,7 @@ class ExposableEntity:
|
||||
device_class: Optional[str]
|
||||
unit: str
|
||||
name: str
|
||||
value_getter: Optional[Callable[[], Any]] = field(default=None, repr=False)
|
||||
value_getter: Optional[Callable[["Session"], Any]] = field(default=None, repr=False)
|
||||
state_class: Optional[str] = None
|
||||
|
||||
|
||||
@@ -269,16 +270,29 @@ def _modbus_provider(session: Session) -> list[ExposableEntity]:
|
||||
for metric in profile.metrics:
|
||||
entity_key = f"modbus.{device.uuid}.{metric.key}"
|
||||
|
||||
# Capture metric and device for the value_getter closure.
|
||||
_device_uuid = device.uuid
|
||||
# Capture device id and metric key for the value_getter closure.
|
||||
# The getter queries the most recent ModbusReading for this device
|
||||
# and extracts the metric value from its payload.
|
||||
_device_id = device.id
|
||||
_metric_key = metric.key
|
||||
|
||||
def _make_value_getter(dev_uuid: str, m_key: str) -> Callable[[], Any]:
|
||||
"""Return a getter stub for this metric; T11 will wire real retrieval."""
|
||||
def _getter() -> Any:
|
||||
# Stub — T11 will call build_catalog with a live session
|
||||
# and replace this with a real value-fetch callable.
|
||||
return None
|
||||
def _make_value_getter(
|
||||
dev_id: int, m_key: str
|
||||
) -> Callable[["Session"], Any]:
|
||||
"""Return a getter that fetches the latest reading value from DB."""
|
||||
def _getter(sess: "Session") -> Any:
|
||||
from app.models.modbus import ModbusReading
|
||||
from sqlalchemy import desc
|
||||
|
||||
reading = (
|
||||
sess.query(ModbusReading)
|
||||
.filter(ModbusReading.device_id == dev_id)
|
||||
.order_by(desc(ModbusReading.recorded_at))
|
||||
.first()
|
||||
)
|
||||
if reading is None:
|
||||
return None
|
||||
return reading.payload.get(m_key)
|
||||
|
||||
return _getter
|
||||
|
||||
@@ -290,19 +304,30 @@ def _modbus_provider(session: Session) -> list[ExposableEntity]:
|
||||
device_class=metric.device_class or None,
|
||||
unit=metric.unit,
|
||||
name=f"{device.friendly_name} {metric.key.replace('_', ' ').title()}",
|
||||
value_getter=_make_value_getter(_device_uuid, _metric_key),
|
||||
value_getter=_make_value_getter(_device_id, _metric_key),
|
||||
state_class=metric.state_class,
|
||||
)
|
||||
)
|
||||
|
||||
# One binary_sensor entity for device "online" status.
|
||||
online_key = f"modbus.{device.uuid}.online"
|
||||
_dev_uuid_online = device.uuid
|
||||
_dev_id_online = device.id
|
||||
|
||||
def _make_online_getter(dev_id: int) -> Callable[["Session"], Any]:
|
||||
"""Return a getter that reports the device online status from DB."""
|
||||
def _getter(sess: "Session") -> Any:
|
||||
from app.models.modbus import ModbusDevice
|
||||
|
||||
dev = sess.query(ModbusDevice).filter(
|
||||
ModbusDevice.id == dev_id
|
||||
).first()
|
||||
if dev is None:
|
||||
return None
|
||||
# Map last_poll_ok to HA binary_sensor payload strings.
|
||||
if dev.last_poll_ok is True:
|
||||
return "ON"
|
||||
return "OFF"
|
||||
|
||||
def _make_online_getter(dev_uuid: str) -> Callable[[], Any]:
|
||||
def _getter() -> Any:
|
||||
# T11 will wire this to last_poll_ok.
|
||||
return None
|
||||
return _getter
|
||||
|
||||
entities.append(
|
||||
@@ -313,7 +338,7 @@ def _modbus_provider(session: Session) -> list[ExposableEntity]:
|
||||
device_class="connectivity",
|
||||
unit="",
|
||||
name=f"{device.friendly_name} Online",
|
||||
value_getter=_make_online_getter(_dev_uuid_online),
|
||||
value_getter=_make_online_getter(_dev_id_online),
|
||||
state_class=None,
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user