Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
custom_components/victron/__pycache__
.idea
26 changes: 21 additions & 5 deletions custom_components/victron/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""The victron integration."""

from __future__ import annotations

from homeassistant.config_entries import ConfigEntry
Expand All @@ -8,7 +9,14 @@
from .const import DOMAIN, CONF_HOST, CONF_PORT, SCAN_REGISTERS, CONF_INTERVAL
from .coordinator import victronEnergyDeviceUpdateCoordinator as Coordinator

PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.SWITCH, Platform.NUMBER, Platform.SELECT, Platform.BINARY_SENSOR, Platform.BUTTON]
PLATFORMS: list[Platform] = [
Platform.SENSOR,
Platform.SWITCH,
Platform.NUMBER,
Platform.SELECT,
Platform.BINARY_SENSOR,
Platform.BUTTON,
]


async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
Expand All @@ -20,8 +28,13 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
# TODO 3. Store an API object for your platforms to access
# hass.data[DOMAIN][entry.entry_id] = MyApi(...)

coordinator = Coordinator(hass, config_entry.options[CONF_HOST], config_entry.options[CONF_PORT],
config_entry.data[SCAN_REGISTERS], config_entry.options[CONF_INTERVAL])
coordinator = Coordinator(
hass,
config_entry.options[CONF_HOST],
config_entry.options[CONF_PORT],
config_entry.data[SCAN_REGISTERS],
config_entry.options[CONF_INTERVAL],
)
# try:
# await coordinator.async_config_entry_first_refresh()
# except ConfigEntryNotReady:
Expand All @@ -41,11 +54,14 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b

async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Unload a config entry."""
if unload_ok := await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS):
if unload_ok := await hass.config_entries.async_unload_platforms(
config_entry, PLATFORMS
):
hass.data[DOMAIN].pop(config_entry.entry_id)

return unload_ok


async def update_listener(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
"""Update listener."""
await hass.config_entries.async_reload(config_entry.entry_id)
await hass.config_entries.async_reload(config_entry.entry_id)
12 changes: 8 additions & 4 deletions custom_components/victron/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
from dataclasses import dataclass
from homeassistant.helpers.entity import EntityDescription


@dataclass
class VictronBaseEntityDescription(EntityDescription):
slave: int = None
value_fn: Callable[[dict], StateType] = lambda data, slave, key: data["data"][str(slave) + "." + str(key)]
slave: int = None
value_fn: Callable[[dict], StateType] = lambda data, slave, key: data["data"][
str(slave) + "." + str(key)
]


@dataclass
@dataclass
class VictronWriteBaseEntityDescription(VictronBaseEntityDescription):
address: int = None
address: int = None
72 changes: 43 additions & 29 deletions custom_components/victron/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,65 @@
"""Support for Victron Energy binary sensors."""

from __future__ import annotations

from contextlib import suppress
from typing import cast

from homeassistant.core import HomeAssistant, HassJob

from collections.abc import Callable
from homeassistant.helpers.typing import StateType

from dataclasses import dataclass

from homeassistant.helpers.update_coordinator import CoordinatorEntity

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers import event, entity
from homeassistant.helpers import entity

from homeassistant.components.binary_sensor import BinarySensorEntityDescription, BinarySensorEntity, DOMAIN as BINARY_SENSOR_DOMAIN
from homeassistant.components.binary_sensor import (
BinarySensorEntityDescription,
BinarySensorEntity,
DOMAIN as BINARY_SENSOR_DOMAIN,
)

from .coordinator import victronEnergyDeviceUpdateCoordinator
from .base import VictronBaseEntityDescription
from .const import DOMAIN, CONF_ADVANCED_OPTIONS, register_info_dict, BoolReadEntityType
from .const import DOMAIN, register_info_dict, BoolReadEntityType

import logging

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Victron energy binary sensor entries."""
_LOGGER.debug("attempting to setup binary sensor entities")
victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][
config_entry.entry_id
]
_LOGGER.debug(victron_coordinator.processed_data()["register_set"])
_LOGGER.debug(victron_coordinator.processed_data()["data"])
descriptions = []
#TODO cleanup
# TODO cleanup
register_set = victron_coordinator.processed_data()["register_set"]
for slave, registerLedger in register_set.items():
for name in registerLedger:
for register_name, registerInfo in register_info_dict[name].items():
_LOGGER.debug("unit == " + str(slave) + " registerLedger == " + str(registerLedger) + " registerInfo ")
_LOGGER.debug(
"unit == "
+ str(slave)
+ " registerLedger == "
+ str(registerLedger)
+ " registerInfo "
)

if isinstance(registerInfo.entityType, BoolReadEntityType):
description = VictronEntityDescription(
key=register_name,
name=register_name.replace('_', ' '),
name=register_name.replace("_", " "),
slave=slave,
)
_LOGGER.debug("composed description == " + str(description))
Expand All @@ -58,28 +69,29 @@ async def async_setup_entry(
entity = {}
for description in descriptions:
entity = description
entities.append(
VictronBinarySensor(
victron_coordinator,
entity
))
entities.append(VictronBinarySensor(victron_coordinator, entity))

async_add_entities(
entities, True
)
async_add_entities(entities, True)


@dataclass
class VictronEntityDescription(BinarySensorEntityDescription, VictronBaseEntityDescription):
class VictronEntityDescription(
BinarySensorEntityDescription, VictronBaseEntityDescription
):
"""Describes victron sensor entity."""


class VictronBinarySensor(CoordinatorEntity, BinarySensorEntity):
"""A binary sensor implementation for Victron energy device."""

def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription) -> None:
def __init__(
self,
coordinator: victronEnergyDeviceUpdateCoordinator,
description: VictronEntityDescription,
) -> None:
"""Initialize the binary sensor."""
self.description: VictronEntityDescription = description
#this needs to be changed to allow multiple of the same type
# this needs to be changed to allow multiple of the same type
self._attr_device_class = description.device_class
self._attr_name = f"{description.name}"

Expand All @@ -97,7 +109,11 @@ def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, descriptio
@property
def is_on(self) -> bool:
"""Return True if the binary sensor is on."""
data = self.description.value_fn(self.coordinator.processed_data(), self.description.slave, self.description.key)
data = self.description.value_fn(
self.coordinator.processed_data(),
self.description.slave,
self.description.key,
)
return cast(bool, data)

@property
Expand All @@ -109,10 +125,8 @@ def available(self) -> bool:
def device_info(self) -> entity.DeviceInfo:
"""Return the device info."""
return entity.DeviceInfo(
identifiers={
(DOMAIN, self.unique_id.split('_')[0])
},
name=self.unique_id.split('_')[1],
model=self.unique_id.split('_')[0],
identifiers={(DOMAIN, self.unique_id.split("_")[0])},
name=self.unique_id.split("_")[1],
model=self.unique_id.split("_")[0],
manufacturer="victron",
)
)
66 changes: 41 additions & 25 deletions custom_components/victron/button.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Support for Victron energy button sensors."""

from __future__ import annotations

from homeassistant.core import HomeAssistant, HassJob
Expand All @@ -8,41 +9,55 @@
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers import entity

from homeassistant.components.button import ButtonEntityDescription, ButtonDeviceClass, ButtonEntity, DOMAIN as BUTTON_DOMAIN
from homeassistant.components.button import (
ButtonEntityDescription,
ButtonDeviceClass,
ButtonEntity,
DOMAIN as BUTTON_DOMAIN,
)

from .base import VictronWriteBaseEntityDescription
from .coordinator import victronEnergyDeviceUpdateCoordinator
from .const import DOMAIN, CONF_ADVANCED_OPTIONS, register_info_dict, ButtonWriteType

import logging

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Victron energy binary sensor entries."""
_LOGGER.debug("attempting to setup button entities")
victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][
config_entry.entry_id
]
descriptions = []
#TODO cleanup
# TODO cleanup
register_set = victron_coordinator.processed_data()["register_set"]
for slave, registerLedger in register_set.items():
for name in registerLedger:
for register_name, registerInfo in register_info_dict[name].items():
_LOGGER.debug("unit == " + str(slave) + " registerLedger == " + str(registerLedger) + " registerInfo ")
_LOGGER.debug(
"unit == "
+ str(slave)
+ " registerLedger == "
+ str(registerLedger)
+ " registerInfo "
)
if not config_entry.options[CONF_ADVANCED_OPTIONS]:
continue
continue

if isinstance(registerInfo.entityType, ButtonWriteType):
description = VictronEntityDescription(
key=register_name,
name=register_name.replace('_', ' '),
name=register_name.replace("_", " "),
slave=slave,
device_class=ButtonDeviceClass.RESTART,
address=registerInfo.register,
Expand All @@ -54,25 +69,26 @@ async def async_setup_entry(
entity = {}
for description in descriptions:
entity = description
entities.append(
VictronBinarySensor(
victron_coordinator,
entity
))
entities.append(VictronBinarySensor(victron_coordinator, entity))

async_add_entities(entities, True)

async_add_entities(
entities, True
)

@dataclass
class VictronEntityDescription(ButtonEntityDescription, VictronWriteBaseEntityDescription):
class VictronEntityDescription(
ButtonEntityDescription, VictronWriteBaseEntityDescription
):
"""Describes victron sensor entity."""


class VictronBinarySensor(CoordinatorEntity, ButtonEntity):
"""A button implementation for Victron energy device."""

def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription) -> None:
def __init__(
self,
coordinator: victronEnergyDeviceUpdateCoordinator,
description: VictronEntityDescription,
) -> None:
"""Initialize the sensor."""
self.description: VictronEntityDescription = description
self._attr_device_class = description.device_class
Expand All @@ -91,7 +107,9 @@ def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, descriptio

async def async_press(self) -> None:
"""Handle the button press."""
self.coordinator.write_register(unit=self.description.slave, address=self.description.address, value=1)
self.coordinator.write_register(
unit=self.description.slave, address=self.description.address, value=1
)

@property
def available(self) -> bool:
Expand All @@ -102,10 +120,8 @@ def available(self) -> bool:
def device_info(self) -> entity.DeviceInfo:
"""Return the device info."""
return entity.DeviceInfo(
identifiers={
(DOMAIN, self.unique_id.split('_')[0])
},
name=self.unique_id.split('_')[1],
model=self.unique_id.split('_')[0],
manufacturer="victron",
)
identifiers={(DOMAIN, self.unique_id.split("_")[0])},
name=self.unique_id.split("_")[1],
model=self.unique_id.split("_")[0],
manufacturer="victron",
)
Loading