"""Home Assistant integration for invertergui MQTT topics.""" from __future__ import annotations from typing import Any import voluptuous as vol from homeassistant.const import CONF_NAME from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import config_validation as cv, discovery from homeassistant.helpers.typing import ConfigType from .const import ( ATTR_CURRENT_LIMIT, ATTR_MODE, CONF_COMMAND_TOPIC, CONF_STATE_TOPIC, CONF_STATUS_TOPIC, CONF_TOPIC_ROOT, DATA_BRIDGE, DEFAULT_COMMAND_TOPIC, DEFAULT_NAME, DEFAULT_STATE_TOPIC, DEFAULT_STATUS_TOPIC, DEFAULT_TOPIC_ROOT, DOMAIN, PANEL_MODES, PLATFORMS, SERVICE_SET_REMOTE_PANEL_STATE, ) from .coordinator import VictronMqttBridge CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.Schema( { vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_STATE_TOPIC, default=DEFAULT_STATE_TOPIC): cv.string, vol.Optional( CONF_COMMAND_TOPIC, default=DEFAULT_COMMAND_TOPIC ): cv.string, vol.Optional(CONF_STATUS_TOPIC, default=DEFAULT_STATUS_TOPIC): cv.string, vol.Optional(CONF_TOPIC_ROOT): cv.string, } ) }, extra=vol.ALLOW_EXTRA, ) SERVICE_SET_REMOTE_PANEL_STATE_SCHEMA = vol.Schema( { vol.Optional(ATTR_MODE): vol.In(PANEL_MODES), vol.Optional(ATTR_CURRENT_LIMIT): vol.Coerce(float), }, extra=vol.PREVENT_EXTRA, ) def mqtt_topic_root(topic: str) -> str: """Match invertergui MQTT root behavior.""" cleaned = topic.strip().strip("/") if not cleaned: return DEFAULT_TOPIC_ROOT if cleaned.endswith("/updates"): root = cleaned[: -len("/updates")] if root: return root return cleaned async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up Victron MK2 MQTT integration from YAML.""" conf = config.get(DOMAIN) if conf is None: return True setup_conf: dict[str, Any] = dict(conf) if not setup_conf.get(CONF_TOPIC_ROOT): setup_conf[CONF_TOPIC_ROOT] = mqtt_topic_root(setup_conf[CONF_STATE_TOPIC]) bridge = VictronMqttBridge(hass, setup_conf) await bridge.async_setup() hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][DATA_BRIDGE] = bridge await _register_services(hass, bridge) for platform in PLATFORMS: hass.async_create_task( discovery.async_load_platform(hass, platform, DOMAIN, {}, config) ) return True async def _register_services(hass: HomeAssistant, bridge: VictronMqttBridge) -> None: """Register integration services.""" if hass.services.has_service(DOMAIN, SERVICE_SET_REMOTE_PANEL_STATE): return async def handle_set_remote_panel_state(call: ServiceCall) -> None: mode = call.data.get(ATTR_MODE) current_limit = call.data.get(ATTR_CURRENT_LIMIT) if mode is None and current_limit is None: raise HomeAssistantError("Provide at least one of mode or current_limit") if current_limit is not None and current_limit < 0: raise HomeAssistantError("current_limit must be >= 0") payload: dict[str, Any] = {"kind": "panel_state"} if mode is not None: payload["switch"] = mode if current_limit is not None: payload["current_limit"] = float(current_limit) await bridge.async_publish_command(payload) hass.services.async_register( DOMAIN, SERVICE_SET_REMOTE_PANEL_STATE, handle_set_remote_panel_state, schema=SERVICE_SET_REMOTE_PANEL_STATE_SCHEMA, )