Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e197d7808 |
@@ -1028,7 +1028,7 @@ def _m8_energy_provider(session: Session) -> list[ExposableEntity]:
|
||||
elif meter.commodity == "heating":
|
||||
unit, device_class = "GJ", "energy"
|
||||
else:
|
||||
unit, device_class = "m³", "volume"
|
||||
unit, device_class = "m³", "water"
|
||||
for suffix, getter in (
|
||||
("total", _meter_total_getter(binding.id, source.id, channel.id)),
|
||||
("today", _meter_today_getter(binding.id, source.id, channel.id)),
|
||||
|
||||
@@ -1214,6 +1214,12 @@ M8 收尾的前置条件。agent 不得执行、记录为已执行,或以 mock
|
||||
|
||||
## 14. Post-M8 lifecycle repair(M8-R08~R10)
|
||||
|
||||
### M8-R16 — HA Water Energy Discovery metadata
|
||||
|
||||
active `hot_water` Meter 的 total/today MQTT Discovery metadata 从通用 `volume` 修正为 Home
|
||||
Assistant Energy Water 所要求的 `water`;保留 `m³` 与 `total_increasing`。区域供暖继续使用合法的
|
||||
`energy + GJ` 组合,thermal EUR 成本实体以及既有 key、identity、unique_id 和 topic 均不变。
|
||||
|
||||
### M8-R15 — HA Discovery identity/topic repair
|
||||
|
||||
修复 HA 将多值 `device.identifiers` 任一匹配合并的风险:Source、Meter、Modbus 与成本 epoch 均使用单一完整 namespaced identifier,内部 MQTT identity 独立保存。thermal 的既有点号 identity/key 保持兼容,node/object topic segment 单独规范化;仅对 v1.6.1 实际发布过的 dot topic 做可重试、成功后抑制的精确 retained cleanup。新增默认关闭的 `Thermal Hot Water Total/Today`,金额为 `hot_water_heating + hot_water`,不含 `hot_water_tax`。
|
||||
|
||||
@@ -2788,7 +2788,11 @@ def test_m8_catalog_has_source_meter_and_thermal_entities_disabled(energy_db) ->
|
||||
assert entries[f"meter.{heating.uuid}.total"].entity.unit == "GJ"
|
||||
assert entries[f"meter.{heating.uuid}.total"].entity.device_class == "energy"
|
||||
assert entries[f"meter.{water.uuid}.total"].entity.unit == "m³"
|
||||
assert entries[f"meter.{water.uuid}.total"].entity.device_class == "volume"
|
||||
for suffix in ("total", "today"):
|
||||
water_entity = entries[f"meter.{water.uuid}.{suffix}"].entity
|
||||
assert water_entity.device_class == "water"
|
||||
assert water_entity.unit == "m³"
|
||||
assert water_entity.state_class == "total_increasing"
|
||||
assert entries[f"meter.{electricity.uuid}.total"].entity.unit == "kWh"
|
||||
assert entries[f"meter.{electricity.uuid}.total"].entity.device_class == "energy"
|
||||
assert entries[f"meter.{electricity.uuid}.today"].entity.state_class == "total_increasing"
|
||||
@@ -2812,6 +2816,31 @@ def test_m8_catalog_has_source_meter_and_thermal_entities_disabled(energy_db) ->
|
||||
assert all(entry.entity.unit == "EUR" and entry.entity.device_class == "monetary" for entry in thermal)
|
||||
|
||||
|
||||
def test_m8_hot_water_discovery_payload_is_ha_energy_compatible(energy_db) -> None:
|
||||
"""Hot-water Meter discovery exposes the exact HA Energy Water metadata."""
|
||||
from app.integrations.expose import build_catalog
|
||||
from app.services.ha_discovery import build_discovery_payload
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
with Session(energy_db) as session:
|
||||
_source, _channel, meter = _make_thermal_source_and_meter(session, "hot_water", now)
|
||||
session.commit()
|
||||
entries = {item.entity.key: item.entity for item in build_catalog(session)}
|
||||
|
||||
for suffix in ("total", "today"):
|
||||
entity = entries[f"meter.{meter.uuid}.{suffix}"]
|
||||
topic, payload = build_discovery_payload(entity, "homeassistant")
|
||||
assert payload["device_class"] == "water"
|
||||
assert payload["unit_of_measurement"] == "m³"
|
||||
assert payload["state_class"] == "total_increasing"
|
||||
assert payload["unique_id"] == f"{meter.uuid}_meter_{meter.uuid}_{suffix}"
|
||||
assert payload["device"]["identifiers"] == [f"home-automation:meter:{meter.uuid}"]
|
||||
assert topic == (
|
||||
f"homeassistant/sensor/{meter.uuid.replace('-', '_')}/"
|
||||
f"meter_{meter.uuid.replace('-', '_')}_{suffix}/config"
|
||||
)
|
||||
|
||||
|
||||
def test_m8_meter_getter_hides_stale_or_offline_source(energy_db) -> None:
|
||||
from app.integrations.expose import build_catalog
|
||||
|
||||
|
||||
Reference in New Issue
Block a user