Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CODEOWNERS

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions homeassistant/components/victronvenus/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""The victronvenus integration."""

from __future__ import annotations

import logging

from homeassistant.const import Platform
from homeassistant.core import HomeAssistant

from ._hubcontrol import _async_setup_hub, _async_unload_hub
from .const import DOMAIN
from .victronvenus_base import VictronVenusConfigEntry as _VictronVenusConfigEntry

_LOGGER = logging.getLogger(__name__)

PLATFORMS: list[Platform] = [Platform.SENSOR]

__all__ = ["async_setup_entry", "async_unload_entry", "DOMAIN"]


async def async_setup_entry(
hass: HomeAssistant, entry: _VictronVenusConfigEntry
) -> bool:
"""Set up victronvenus from a config entry."""
return await _async_setup_hub(hass, entry, PLATFORMS)


async def async_unload_entry(
hass: HomeAssistant, entry: _VictronVenusConfigEntry
) -> bool:
"""Unload a config entry."""

return await _async_unload_hub(hass, entry, PLATFORMS)
58 changes: 58 additions & 0 deletions homeassistant/components/victronvenus/_hubcontrol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from __future__ import annotations

from homeassistant.const import (
CONF_HOST,
CONF_PASSWORD,
CONF_PORT,
CONF_SSL,
CONF_USERNAME,
Platform,
)
from homeassistant.core import HomeAssistant

from .const import CONF_INSTALLATION_ID, CONF_MODEL, CONF_SERIAL
from .victronvenus_base import VictronVenusConfigEntry
from .victronvenus_hub import VictronVenusHub


async def _async_setup_hub(
hass: HomeAssistant, entry: VictronVenusConfigEntry, platforms: list[Platform]
) -> bool:
"""Set up victronvenus from a config entry."""

config = entry.data
hub = VictronVenusHub(
hass,
config.get(CONF_HOST),
config.get(CONF_PORT, 1883),
config.get(CONF_USERNAME),
config.get(CONF_PASSWORD),
config.get(CONF_SERIAL),
config.get(CONF_SSL, False),
config.get(CONF_INSTALLATION_ID),
config.get(CONF_MODEL),
)

await hub.connect()

await hub.setup_subscriptions()
await hub.initiate_keep_alive()
await hub.wait_for_first_refresh()

entry.runtime_data = hub

await hass.config_entries.async_forward_entry_setups(entry, platforms)

return True


async def _async_unload_hub(
hass: HomeAssistant, entry: VictronVenusConfigEntry, platforms: list[Platform]
) -> bool:
"""Unload a config entry."""

hub = entry.runtime_data
if hub is not None:
if isinstance(hub, VictronVenusHub):
await hub.disconnect()
return await hass.config_entries.async_unload_platforms(entry, platforms)
277 changes: 277 additions & 0 deletions homeassistant/components/victronvenus/_topicmap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
from homeassistant.components.sensor.const import SensorDeviceClass, SensorStateClass

from ._unwrappers import unwrap_float, unwrap_int, unwrap_int_default_0, unwrap_string
from .const import DEVICE_MESSAGE, SENSOR_MESSAGE
from .data_classes import TopicDescriptor

topic_map = {
# generic device attributes
"N/+/+/+/ProductName": TopicDescriptor(
message_type=DEVICE_MESSAGE,
short_id="model",
unit_of_measurement=None,
device_class=None,
state_class=None,
precision=None,
unwrapper=unwrap_string,
),
"N/+/+/+/Serial": TopicDescriptor(
message_type=DEVICE_MESSAGE,
short_id="serial_number",
unit_of_measurement=None,
device_class=None,
state_class=None,
precision=None,
unwrapper=unwrap_string,
),
"N/+/+/+/Manufacturer": TopicDescriptor(
message_type=DEVICE_MESSAGE,
short_id="manufacturer",
unit_of_measurement=None,
device_class=None,
state_class=None,
precision=None,
unwrapper=unwrap_string,
),
"N/+/+/+/ProductId": TopicDescriptor(
message_type=DEVICE_MESSAGE,
short_id="victron_productid",
unit_of_measurement=None,
device_class=None,
state_class=None,
precision=0,
unwrapper=unwrap_int,
),
# grid
"N/+/system/+/Ac/Grid/NumberOfPhases": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="grid_phases",
unit_of_measurement=None,
device_class=None,
state_class=SensorStateClass.TOTAL,
precision=0,
unwrapper=unwrap_int_default_0,
),
# individual grid phases
"N/+/grid/+/Ac/+/Voltage": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="grid_voltage_{phase}",
unit_of_measurement="V",
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/grid/+/Ac/+/Current": TopicDescriptor(
message_type="sensor",
short_id="grid_current_{phase}",
unit_of_measurement="A",
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/grid/+/Ac/+/Power": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="grid_power_{phase}",
unit_of_measurement="W",
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
# total grid
"N/+/grid/+/Ac/Voltage": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="grid_voltage",
unit_of_measurement="V",
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/grid/+/Ac/Current": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="grid_current",
unit_of_measurement="A",
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/grid/+/Ac/Power": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="grid_power",
unit_of_measurement="W",
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/grid/+/Ac/Energy/Forward": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="grid_energy_forward",
unit_of_measurement="kWh",
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
precision=1,
unwrapper=unwrap_float,
),
"N/+/grid/+/Ac/Energy/Reverse": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="grid_energy_reverse",
unit_of_measurement="kWh",
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
precision=1,
unwrapper=unwrap_float,
),
# solar / MPPT
"N/+/solarcharger/+/Dc/0/Voltage": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="solar_voltage",
unit_of_measurement="V",
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/solarcharger/+/Dc/0/Current": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="solar_current",
unit_of_measurement="A",
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/solarcharger/+/Yield/Power": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="solar_power",
unit_of_measurement="W",
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/solarcharger/+/Yield/User": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="solar_yield",
unit_of_measurement="kWh",
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
precision=1,
unwrapper=unwrap_float,
),
"N/+/solarcharger/+/History/Daily/0/MaxPower": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="solar_max_power",
unit_of_measurement="W",
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
# batteries
"N/+/battery/+/Dc/0/Voltage": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="battery_voltage",
unit_of_measurement="V",
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/battery/+/Dc/0/Current": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="battery_current",
unit_of_measurement="A",
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/battery/+/Dc/0/Power": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="battery_power",
unit_of_measurement="W",
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/battery/+/Dc/0/Temperature": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="battery_temperature",
unit_of_measurement="°C",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/battery/+/History/DischargedEnergy": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="battery_discharged_energy",
unit_of_measurement="kWh",
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
precision=1,
unwrapper=unwrap_float,
),
"N/+/battery/+/History/ChargedEnergy": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="battery_charged_energy",
unit_of_measurement="kWh",
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
precision=1,
unwrapper=unwrap_float,
),
"N/+/battery/+/Capacity": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="battery_capacity",
unit_of_measurement="Ah",
device_class=None,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/battery/+/InstalledCapacity": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="battery_installed_capacity",
unit_of_measurement="Ah",
device_class=None,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/battery/+/Soc": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="battery_soc",
unit_of_measurement="%",
device_class=SensorDeviceClass.BATTERY,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
# integrated system. Note that this might not be currently accurate for all systems as there are different physical configurations
# and don't have access to any other for testing or feedback.
"N/+/system/+/Ac/ConsumptionOnOutput/+/Power": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="critical_loads_{phase}",
unit_of_measurement="W",
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
"N/+/system/+/Ac/ConsumptionOnInput/+/Power": TopicDescriptor(
message_type=SENSOR_MESSAGE,
short_id="ac_loads_{phase}",
unit_of_measurement="W",
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
precision=1,
unwrapper=unwrap_float,
),
}
Loading