parent
b9abb725e7
commit
0826f7b897
|
|
@ -35,7 +35,7 @@ Elektroměr posílá DLMS/COSEM PUSH zprávy každých **60 sekund**. Integrace
|
|||
## Instalace přes HACS
|
||||
|
||||
1. Otevři HACS → **Integrace** → tři tečky vpravo nahoře → **Vlastní repozitáře**
|
||||
2. Přidej URL tohoto repozitáře, kategorie: **Integration** (https://github.com/nero150/CEZ_rele_box)
|
||||
2. Přidej URL tohoto repozitáře, kategorie: **Integration**
|
||||
3. Najdi „XT211 HAN" a nainstaluj
|
||||
4. Restartuj Home Assistant
|
||||
5. **Nastavení → Zařízení a služby → Přidat integraci → XT211 HAN**
|
||||
|
|
|
|||
|
|
@ -12,11 +12,27 @@ from homeassistant import config_entries
|
|||
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_NAME
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
|
||||
from .const import DOMAIN, DEFAULT_PORT, DEFAULT_NAME
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
DEFAULT_PORT,
|
||||
DEFAULT_NAME,
|
||||
CONF_PHASES,
|
||||
CONF_HAS_FVE,
|
||||
CONF_TARIFFS,
|
||||
CONF_RELAY_COUNT,
|
||||
PHASES_1,
|
||||
PHASES_3,
|
||||
TARIFFS_1,
|
||||
TARIFFS_2,
|
||||
TARIFFS_4,
|
||||
RELAYS_0,
|
||||
RELAYS_4,
|
||||
RELAYS_6,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
STEP_USER_DATA_SCHEMA = vol.Schema(
|
||||
STEP_CONNECTION_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_HOST): str,
|
||||
vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
|
||||
|
|
@ -24,6 +40,29 @@ STEP_USER_DATA_SCHEMA = vol.Schema(
|
|||
}
|
||||
)
|
||||
|
||||
STEP_METER_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_PHASES, default=PHASES_3): vol.In(
|
||||
{PHASES_1: "Jednofázový", PHASES_3: "Třífázový"}
|
||||
),
|
||||
vol.Required(CONF_HAS_FVE, default=False): bool,
|
||||
vol.Required(CONF_TARIFFS, default=TARIFFS_2): vol.In(
|
||||
{
|
||||
TARIFFS_1: "Jeden tarif (pouze T1)",
|
||||
TARIFFS_2: "Dva tarify (T1 + T2)",
|
||||
TARIFFS_4: "Čtyři tarify (T1 – T4)",
|
||||
}
|
||||
),
|
||||
vol.Required(CONF_RELAY_COUNT, default=RELAYS_4): vol.In(
|
||||
{
|
||||
RELAYS_0: "Žádné relé",
|
||||
RELAYS_4: "WM-RelayBox (R1 – R4)",
|
||||
RELAYS_6: "WM-RelayBox rozšířený (R1 – R6)",
|
||||
}
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def _test_connection(host: str, port: int) -> str | None:
|
||||
"""Try to open a TCP connection. Returns error string or None on success."""
|
||||
|
|
@ -44,10 +83,17 @@ async def _test_connection(host: str, port: int) -> str | None:
|
|||
|
||||
|
||||
class XT211HANConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle the config flow for XT211 HAN."""
|
||||
"""Handle the config flow for XT211 HAN – two steps."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._connection_data: dict[str, Any] = {}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 1 – connection (host / port / name)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
|
|
@ -56,9 +102,7 @@ class XT211HANConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
if user_input is not None:
|
||||
host = user_input[CONF_HOST]
|
||||
port = user_input[CONF_PORT]
|
||||
name = user_input.get(CONF_NAME, DEFAULT_NAME)
|
||||
|
||||
# Prevent duplicate entries
|
||||
await self.async_set_unique_id(f"{host}:{port}")
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
|
|
@ -66,20 +110,33 @@ class XT211HANConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
if error:
|
||||
errors["base"] = error
|
||||
else:
|
||||
return self.async_create_entry(
|
||||
title=f"{name} ({host}:{port})",
|
||||
data={
|
||||
CONF_HOST: host,
|
||||
CONF_PORT: port,
|
||||
CONF_NAME: name,
|
||||
},
|
||||
)
|
||||
self._connection_data = user_input
|
||||
return await self.async_step_meter()
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=STEP_USER_DATA_SCHEMA,
|
||||
data_schema=STEP_CONNECTION_SCHEMA,
|
||||
errors=errors,
|
||||
description_placeholders={
|
||||
"default_port": str(DEFAULT_PORT),
|
||||
},
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 2 – meter configuration
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
async def async_step_meter(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
if user_input is not None:
|
||||
data = {**self._connection_data, **user_input}
|
||||
name = data.get(CONF_NAME, DEFAULT_NAME)
|
||||
host = data[CONF_HOST]
|
||||
port = data[CONF_PORT]
|
||||
return self.async_create_entry(
|
||||
title=f"{name} ({host}:{port})",
|
||||
data=data,
|
||||
)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="meter",
|
||||
data_schema=STEP_METER_SCHEMA,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,24 @@ DOMAIN = "xt211_han"
|
|||
CONF_HOST = "host"
|
||||
CONF_PORT = "port"
|
||||
CONF_NAME = "name"
|
||||
CONF_PHASES = "phases"
|
||||
CONF_HAS_FVE = "has_fve"
|
||||
CONF_TARIFFS = "tariffs"
|
||||
CONF_RELAY_COUNT = "relay_count"
|
||||
|
||||
DEFAULT_PORT = 8899
|
||||
DEFAULT_NAME = "XT211 HAN"
|
||||
|
||||
# Phases
|
||||
PHASES_1 = "1"
|
||||
PHASES_3 = "3"
|
||||
|
||||
# Tariff counts
|
||||
TARIFFS_1 = 1
|
||||
TARIFFS_2 = 2
|
||||
TARIFFS_4 = 4
|
||||
|
||||
# Relay counts
|
||||
RELAYS_0 = 0
|
||||
RELAYS_4 = 4
|
||||
RELAYS_6 = 6
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"domain": "xt211_han",
|
||||
"name": "XT211 HAN (RS485 via Ethernet)",
|
||||
"version": "0.5.1",
|
||||
"version": "0.6.0",
|
||||
"documentation": "https://github.com/nero150/xt211-han-ha",
|
||||
"issue_tracker": "https://github.com/nero150/xt211-han-ha/issues",
|
||||
"dependencies": [],
|
||||
|
|
|
|||
|
|
@ -32,7 +32,16 @@ from homeassistant.helpers.device_registry import DeviceInfo
|
|||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from .const import DOMAIN
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
CONF_PHASES,
|
||||
CONF_HAS_FVE,
|
||||
CONF_TARIFFS,
|
||||
CONF_RELAY_COUNT,
|
||||
PHASES_3,
|
||||
TARIFFS_2,
|
||||
RELAYS_4,
|
||||
)
|
||||
from .coordinator import XT211Coordinator
|
||||
from .dlms_parser import OBIS_DESCRIPTIONS
|
||||
|
||||
|
|
@ -91,13 +100,70 @@ async def async_setup_entry(
|
|||
entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up all XT211 HAN entities from a config entry."""
|
||||
"""Set up all XT211 HAN entities from a config entry, filtered by meter config."""
|
||||
coordinator: XT211Coordinator = hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
phases = entry.data.get(CONF_PHASES, PHASES_3)
|
||||
has_fve = entry.data.get(CONF_HAS_FVE, True)
|
||||
tariffs = int(entry.data.get(CONF_TARIFFS, TARIFFS_2))
|
||||
relay_count = int(entry.data.get(CONF_RELAY_COUNT, RELAYS_4))
|
||||
|
||||
# Build set of OBIS codes to include based on user config
|
||||
enabled_obis: set[str] = set()
|
||||
|
||||
# Always include: device name, serial, tariff, consumer message, disconnector, limiter
|
||||
enabled_obis.update({
|
||||
"0-0:42.0.0.255",
|
||||
"0-0:96.1.0.255",
|
||||
"0-0:96.14.0.255",
|
||||
"0-0:96.13.0.255",
|
||||
"0-0:96.3.10.255",
|
||||
"0-0:17.0.0.255",
|
||||
})
|
||||
|
||||
# Relays – according to relay_count
|
||||
relay_obis = {
|
||||
1: "0-1:96.3.10.255",
|
||||
2: "0-2:96.3.10.255",
|
||||
3: "0-3:96.3.10.255",
|
||||
4: "0-4:96.3.10.255",
|
||||
5: "0-5:96.3.10.255",
|
||||
6: "0-6:96.3.10.255",
|
||||
}
|
||||
for i in range(1, relay_count + 1):
|
||||
enabled_obis.add(relay_obis[i])
|
||||
|
||||
# Instant power import – total always included
|
||||
enabled_obis.add("1-0:1.7.0.255")
|
||||
if phases == PHASES_3:
|
||||
enabled_obis.update({"1-0:21.7.0.255", "1-0:41.7.0.255", "1-0:61.7.0.255"})
|
||||
|
||||
# Instant power export – only with FVE
|
||||
if has_fve:
|
||||
enabled_obis.add("1-0:2.7.0.255")
|
||||
if phases == PHASES_3:
|
||||
enabled_obis.update({"1-0:22.7.0.255", "1-0:42.7.0.255", "1-0:62.7.0.255"})
|
||||
|
||||
# Cumulative energy import – total + tariffs
|
||||
enabled_obis.add("1-0:1.8.0.255")
|
||||
for t in range(1, tariffs + 1):
|
||||
enabled_obis.add(f"1-0:1.8.{t}.255")
|
||||
|
||||
# Cumulative energy export – only with FVE
|
||||
if has_fve:
|
||||
enabled_obis.add("1-0:2.8.0.255")
|
||||
|
||||
_LOGGER.debug(
|
||||
"XT211 config: phases=%s fve=%s tariffs=%d relays=%d → %d entities",
|
||||
phases, has_fve, tariffs, relay_count, len(enabled_obis),
|
||||
)
|
||||
|
||||
entities: list = []
|
||||
registered_obis: set[str] = set()
|
||||
|
||||
for obis, meta in OBIS_DESCRIPTIONS.items():
|
||||
if obis not in enabled_obis:
|
||||
continue
|
||||
registered_obis.add(obis)
|
||||
if obis in BINARY_OBIS:
|
||||
entities.append(XT211BinarySensorEntity(coordinator, entry, obis, meta))
|
||||
|
|
@ -115,7 +181,7 @@ async def async_setup_entry(
|
|||
return
|
||||
new: list = []
|
||||
for obis, data in coordinator.data.items():
|
||||
if obis in registered_obis:
|
||||
if obis in registered_obis or obis not in enabled_obis:
|
||||
continue
|
||||
registered_obis.add(obis)
|
||||
_LOGGER.info("XT211: discovered new OBIS code %s – adding entity", obis)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,23 @@
|
|||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Nastavení XT211 HAN adaptéru",
|
||||
"title": "Nastavení připojení",
|
||||
"description": "Zadej IP adresu a port RS485-to-Ethernet adaptéru (např. PUSR USR-DR134). Výchozí port pro TCP server mód je 8899.",
|
||||
"data": {
|
||||
"host": "IP adresa adaptéru",
|
||||
"port": "TCP port",
|
||||
"name": "Název zařízení"
|
||||
}
|
||||
},
|
||||
"meter": {
|
||||
"title": "Konfigurace elektroměru",
|
||||
"description": "Upřesni parametry tvého elektroměru. Podle toho se zobrazí jen relevantní entity.",
|
||||
"data": {
|
||||
"phases": "Typ elektroměru",
|
||||
"has_fve": "Mám fotovoltaiku (FVE) / export energie",
|
||||
"tariffs": "Počet tarifů",
|
||||
"relay_count": "Relé boxy (WM-RelayBox)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
|
|
|
|||
|
|
@ -2,13 +2,23 @@
|
|||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Nastavení XT211 HAN adaptéru",
|
||||
"title": "Nastavení připojení",
|
||||
"description": "Zadej IP adresu a port RS485-to-Ethernet adaptéru (např. PUSR USR-DR134). Výchozí port pro TCP server mód je 8899.",
|
||||
"data": {
|
||||
"host": "IP adresa adaptéru",
|
||||
"port": "TCP port",
|
||||
"name": "Název zařízení"
|
||||
}
|
||||
},
|
||||
"meter": {
|
||||
"title": "Konfigurace elektroměru",
|
||||
"description": "Upřesni parametry tvého elektroměru. Podle toho se zobrazí jen relevantní entity.",
|
||||
"data": {
|
||||
"phases": "Typ elektroměru",
|
||||
"has_fve": "Mám fotovoltaiku (FVE) / export energie",
|
||||
"tariffs": "Počet tarifů",
|
||||
"relay_count": "Relé boxy (WM-RelayBox)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
|
|
|
|||
|
|
@ -2,13 +2,23 @@
|
|||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "XT211 HAN Adapter Setup",
|
||||
"title": "Connection Setup",
|
||||
"description": "Enter the IP address and port of your RS485-to-Ethernet adapter (e.g. PUSR USR-DR134). The default TCP server port is 8899.",
|
||||
"data": {
|
||||
"host": "Adapter IP address",
|
||||
"port": "TCP port",
|
||||
"name": "Device name"
|
||||
}
|
||||
},
|
||||
"meter": {
|
||||
"title": "Meter Configuration",
|
||||
"description": "Specify your meter parameters. Only relevant entities will be shown.",
|
||||
"data": {
|
||||
"phases": "Meter type",
|
||||
"has_fve": "I have solar panels (FVE) / energy export",
|
||||
"tariffs": "Number of tariffs",
|
||||
"relay_count": "Relay boxes (WM-RelayBox)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue