implement some features of Venus OS
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-02-19 15:37:41 +11:00
parent d72e88ab7b
commit e8153e2953
21 changed files with 4143 additions and 90 deletions

View File

@@ -12,21 +12,32 @@ from homeassistant.helpers import config_validation as cv, discovery
from homeassistant.helpers.typing import ConfigType
from .const import (
ATTR_ESS_MAX_CHARGE_POWER,
ATTR_ESS_MAX_DISCHARGE_POWER,
ATTR_ESS_MODE,
ATTR_ESS_SETPOINT,
ATTR_CURRENT_LIMIT,
ATTR_MODE,
CONF_COMMAND_TOPIC,
CONF_STATE_TOPIC,
CONF_STATUS_TOPIC,
CONF_TOPIC_ROOT,
CONF_VENUS_GUIDE_COMPAT,
CONF_VENUS_PORTAL_ID,
CONF_VENUS_TOPIC_PREFIX,
DATA_BRIDGE,
DEFAULT_COMMAND_TOPIC,
DEFAULT_NAME,
DEFAULT_STATE_TOPIC,
DEFAULT_STATUS_TOPIC,
DEFAULT_TOPIC_ROOT,
DEFAULT_VENUS_GUIDE_COMPAT,
DEFAULT_VENUS_PORTAL_ID,
DEFAULT_VENUS_TOPIC_PREFIX,
DOMAIN,
PANEL_MODES,
PLATFORMS,
SERVICE_SET_ESS_CONTROL,
SERVICE_SET_REMOTE_PANEL_STATE,
)
from .coordinator import VictronMqttBridge
@@ -42,6 +53,9 @@ CONFIG_SCHEMA = vol.Schema(
): cv.string,
vol.Optional(CONF_STATUS_TOPIC, default=DEFAULT_STATUS_TOPIC): cv.string,
vol.Optional(CONF_TOPIC_ROOT): cv.string,
vol.Optional(CONF_VENUS_PORTAL_ID, default=DEFAULT_VENUS_PORTAL_ID): cv.string,
vol.Optional(CONF_VENUS_TOPIC_PREFIX, default=DEFAULT_VENUS_TOPIC_PREFIX): cv.string,
vol.Optional(CONF_VENUS_GUIDE_COMPAT, default=DEFAULT_VENUS_GUIDE_COMPAT): cv.boolean,
}
)
},
@@ -56,6 +70,16 @@ SERVICE_SET_REMOTE_PANEL_STATE_SCHEMA = vol.Schema(
extra=vol.PREVENT_EXTRA,
)
SERVICE_SET_ESS_CONTROL_SCHEMA = vol.Schema(
{
vol.Optional(ATTR_ESS_SETPOINT): vol.Coerce(float),
vol.Optional(ATTR_ESS_MAX_CHARGE_POWER): vol.Coerce(float),
vol.Optional(ATTR_ESS_MAX_DISCHARGE_POWER): vol.Coerce(float),
vol.Optional(ATTR_ESS_MODE): vol.Coerce(int),
},
extra=vol.PREVENT_EXTRA,
)
def mqtt_topic_root(topic: str) -> str:
"""Match invertergui MQTT root behavior."""
@@ -123,3 +147,40 @@ async def _register_services(hass: HomeAssistant, bridge: VictronMqttBridge) ->
handle_set_remote_panel_state,
schema=SERVICE_SET_REMOTE_PANEL_STATE_SCHEMA,
)
async def handle_set_ess_control(call: ServiceCall) -> None:
setpoint = call.data.get(ATTR_ESS_SETPOINT)
max_charge = call.data.get(ATTR_ESS_MAX_CHARGE_POWER)
max_discharge = call.data.get(ATTR_ESS_MAX_DISCHARGE_POWER)
ess_mode = call.data.get(ATTR_ESS_MODE)
if all(value is None for value in (setpoint, max_charge, max_discharge, ess_mode)):
raise HomeAssistantError(
"Provide at least one of ess_setpoint, ess_max_charge_power, ess_max_discharge_power, or ess_mode"
)
if max_charge is not None and max_charge < 0:
raise HomeAssistantError("ess_max_charge_power must be >= 0")
if max_discharge is not None and max_discharge < 0:
raise HomeAssistantError("ess_max_discharge_power must be >= 0")
if ess_mode is not None and ess_mode not in (9, 10):
raise HomeAssistantError("ess_mode must be 9 or 10")
commands: list[dict[str, Any]] = []
if setpoint is not None:
commands.append({"kind": "ess_setpoint", "value": float(setpoint)})
if max_charge is not None:
commands.append({"kind": "ess_max_charge_power", "value": float(max_charge)})
if max_discharge is not None:
commands.append({"kind": "ess_max_discharge_power", "value": float(max_discharge)})
if ess_mode is not None:
commands.append({"kind": "ess_mode", "value": int(ess_mode)})
for payload in commands:
await bridge.async_publish_command(payload)
hass.services.async_register(
DOMAIN,
SERVICE_SET_ESS_CONTROL,
handle_set_ess_control,
schema=SERVICE_SET_ESS_CONTROL_SCHEMA,
)