Skip to content

Commit

Permalink
- Resolve deprecation warnings with 2024.7.x: https://developers.home…
Browse files Browse the repository at this point in the history
  • Loading branch information
alexdelprete committed Jul 6, 2024
1 parent b7e33b6 commit e59f98f
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 60 deletions.
92 changes: 60 additions & 32 deletions custom_components/abb_powerone_pvi_sunspec/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,40 @@
https://github.com/alexdelprete/ha-abb-powerone-pvi-sunspec
"""

import asyncio
import logging
from collections.abc import Callable
from dataclasses import dataclass

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from .const import (
CONF_HOST,
CONF_NAME,
DATA,
DOMAIN,
PLATFORMS,
STARTUP_MESSAGE,
UPDATE_LISTENER,
)
from .coordinator import ABBPowerOneFimerCoordinator

_LOGGER = logging.getLogger(__name__)

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

# The type alias needs to be suffixed with 'ConfigEntry'
type ABBPowerOneFimerConfigEntry = ConfigEntry[RuntimeData]


@dataclass
class RuntimeData:
"""Class to hold your data."""

coordinator: DataUpdateCoordinator
update_listener: Callable


def get_instance_count(hass: HomeAssistant) -> int:
"""Return number of instances."""
Expand All @@ -35,47 +48,55 @@ def get_instance_count(hass: HomeAssistant) -> int:
return len(entries)


async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry):
async def async_setup_entry(
hass: HomeAssistant, config_entry: ABBPowerOneFimerConfigEntry
):
"""Set up this integration using UI."""
if hass.data.get(DOMAIN) is None:
hass.data.setdefault(DOMAIN, {})
_LOGGER.info(STARTUP_MESSAGE)

_LOGGER.debug(f"Setup config_entry for {DOMAIN}")

# Initialise the coordinator that manages data updates from your api.
# This is defined in coordinator.py
coordinator = ABBPowerOneFimerCoordinator(hass, config_entry)

# If the refresh fails, async_config_entry_first_refresh() will
# raise ConfigEntryNotReady and setup will try again later
# ref.: https://developers.home-assistant.io/docs/integration_setup_failures
await coordinator.async_config_entry_first_refresh()

# Test to see if api initialised correctly, else raise ConfigNotReady to make HA retry setup
# Change this to match how your api will know if connected or successful update
if not coordinator.api.data["comm_sernum"]:
raise ConfigEntryNotReady(
f"Timeout connecting to {config_entry.data.get(CONF_NAME)}"
)

# Update listener for config option changes
# Initialise a listener for config flow options changes.
# See config_flow for defining an options setting that shows up as configure on the integration.
update_listener = config_entry.add_update_listener(_async_update_listener)

# Add coordinator and update_listener to config_entry
hass.data[DOMAIN][config_entry.entry_id] = {
DATA: coordinator,
UPDATE_LISTENER: update_listener,
}
# Add the coordinator and update listener to hass data to make
# accessible throughout your integration
# Note: this will change on HA2024.6 to save on the config entry.
config_entry.runtime_data = RuntimeData(coordinator, update_listener)

# Setup platforms
for platform in PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, platform)
)
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)

# Regiser device
await async_update_device_registry(hass, config_entry)

# Return true to denote a successful setup.
return True


async def async_update_device_registry(hass: HomeAssistant, config_entry):
async def async_update_device_registry(
hass: HomeAssistant, config_entry: ABBPowerOneFimerConfigEntry
):
"""Manual device registration."""
coordinator = hass.data[DOMAIN][config_entry.entry_id][DATA]
coordinator: ABBPowerOneFimerCoordinator = config_entry.runtime_data.coordinator
device_registry = dr.async_get(hass)
device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
Expand Down Expand Up @@ -108,28 +129,35 @@ async def async_remove_config_entry_device(
return True


async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Handle removal of config_entry."""
async def async_unload_entry(
hass: HomeAssistant, config_entry: ABBPowerOneFimerConfigEntry
) -> bool:
"""Unload a config entry."""
# This is called when you remove your integration or shutdown HA.
# If you have created any custom services, they need to be removed here too.

_LOGGER.debug("Unload config_entry")

# This is called when you remove your integration or shutdown HA.
# If you have created any custom services, they need to be removed here too.

# Remove the config options update listener
_LOGGER.debug("Detach config update listener")
hass.data[DOMAIN][config_entry.entry_id].update_listener()

# Check if there are other instances
if get_instance_count(hass) == 0:
_LOGGER.debug("Unload config_entry: no more entries found")

_LOGGER.debug("Unload integration platforms")
# Unload a config entry
unloaded = all(
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_unload(config_entry, platform)
for platform in PLATFORMS
]
)
)

_LOGGER.debug("Detach config update listener")
hass.data[DOMAIN][config_entry.entry_id][UPDATE_LISTENER]()
# Unload platforms
unload_ok = await hass.config_entries.async_unload_platforms(
config_entry, PLATFORMS
)

if unloaded:
# Remove the config entry from the hass data object.
if unload_ok:
_LOGGER.debug("Unload integration")
hass.data[DOMAIN].pop(config_entry.entry_id)
return True # unloaded
Expand Down
9 changes: 0 additions & 9 deletions custom_components/abb_powerone_pvi_sunspec/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
# Base component constants
NAME = "ABB/Power-One/FIMER PVI SunSpec ModBus TCP"
DOMAIN = "abb_powerone_pvi_sunspec"
DOMAIN_DATA = f"{DOMAIN}_data"
VERSION = "3.0.0"
ATTRIBUTION = "by @alexdelprete"
ISSUE_URL = "https://github.com/alexdelprete/ha-abb-powerone-pvi-sunspec/issues"
Expand All @@ -27,14 +26,6 @@
# Device classes
BINARY_SENSOR_DEVICE_CLASS = "connectivity"

# Platforms
SENSOR = "sensor"
PLATFORMS = [
"sensor",
]
UPDATE_LISTENER = "update_listener"
DATA = "data"

# Configuration and options
CONF_NAME = "name"
CONF_HOST = "host"
Expand Down
8 changes: 5 additions & 3 deletions custom_components/abb_powerone_pvi_sunspec/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
import logging
from datetime import datetime, timedelta

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from . import ABBPowerOneFimerConfigEntry
from .api import ABBPowerOneFimerAPI
from .const import (
CONF_BASE_ADDR,
Expand All @@ -29,9 +29,11 @@
class ABBPowerOneFimerCoordinator(DataUpdateCoordinator):
"""Class to manage fetching data from the API."""

config_entry: ConfigEntry
config_entry: ABBPowerOneFimerConfigEntry

def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
def __init__(
self, hass: HomeAssistant, config_entry: ABBPowerOneFimerConfigEntry
) -> None:
"""Initialize data update coordinator."""

# get scan_interval from user config
Expand Down
40 changes: 25 additions & 15 deletions custom_components/abb_powerone_pvi_sunspec/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from . import ABBPowerOneFimerConfigEntry
from .const import (
CONF_NAME,
DATA,
DOMAIN,
INVERTER_TYPE,
SENSOR_TYPES_COMMON,
Expand All @@ -22,11 +22,17 @@
SENSOR_TYPES_SINGLE_PHASE,
SENSOR_TYPES_THREE_PHASE,
)
from .coordinator import ABBPowerOneFimerCoordinator

_LOGGER = logging.getLogger(__name__)


def add_sensor_defs(coordinator, config_entry, sensor_list, sensor_definitions):
def add_sensor_defs(
coordinator: ABBPowerOneFimerCoordinator,
config_entry: ABBPowerOneFimerConfigEntry,
sensor_list,
sensor_definitions,
):
"""Class Initializitation."""

for sensor_info in sensor_definitions.values():
Expand All @@ -43,11 +49,13 @@ def add_sensor_defs(coordinator, config_entry, sensor_list, sensor_definitions):
)


async def async_setup_entry(hass: HomeAssistant, config_entry, async_add_entities):
async def async_setup_entry(
hass: HomeAssistant, config_entry: ABBPowerOneFimerConfigEntry, async_add_entities
):
"""Sensor Platform setup."""

# Get handler to coordinator from config
coordinator = hass.data[DOMAIN][config_entry.entry_id][DATA]
coordinator: ABBPowerOneFimerCoordinator = config_entry.runtime_data.coordinator

_LOGGER.debug("(sensor) Name: %s", config_entry.data.get(CONF_NAME))
_LOGGER.debug("(sensor) Manufacturer: %s", coordinator.api.data["comm_manufact"])
Expand Down Expand Up @@ -93,25 +101,25 @@ class ABBPowerOneFimerSensor(CoordinatorEntity, SensorEntity):
def __init__(self, coordinator, config_entry, sensor_data):
"""Class Initializitation."""
super().__init__(coordinator)
self.coordinator = coordinator
self._coordinator = coordinator
self._name = sensor_data["name"]
self._key = sensor_data["key"]
self._unit_of_measurement = sensor_data["unit"]
self._icon = sensor_data["icon"]
self._device_class = sensor_data["device_class"]
self._state_class = sensor_data["state_class"]
self._device_name = self.coordinator.api.name
self._device_host = self.coordinator.api.host
self._device_model = self.coordinator.api.data["comm_model"]
self._device_manufact = self.coordinator.api.data["comm_manufact"]
self._device_sn = self.coordinator.api.data["comm_sernum"]
self._device_swver = self.coordinator.api.data["comm_version"]
self._device_hwver = self.coordinator.api.data["comm_options"]
self._device_name = self._coordinator.api.name
self._device_host = self._coordinator.api.host
self._device_model = self._coordinator.api.data["comm_model"]
self._device_manufact = self._coordinator.api.data["comm_manufact"]
self._device_sn = self._coordinator.api.data["comm_sernum"]
self._device_swver = self._coordinator.api.data["comm_version"]
self._device_hwver = self._coordinator.api.data["comm_options"]

@callback
def _handle_coordinator_update(self) -> None:
"""Fetch new state data for the sensor."""
self._state = self.coordinator.api.data[self._key]
self._state = self._coordinator.api.data[self._key]
self.async_write_ha_state()
# write debug log only on first sensor to avoid spamming the log
if self.name == "Manufacturer":
Expand Down Expand Up @@ -160,8 +168,10 @@ def entity_category(self):
@property
def native_value(self):
"""Return the state of the sensor."""
if self._key in self.coordinator.api.data:
return self.coordinator.api.data[self._key]
if self._key in self._coordinator.api.data:
return self._coordinator.api.data[self._key]
else:
return None

@property
def state_attributes(self) -> dict[str, Any] | None:
Expand Down
2 changes: 1 addition & 1 deletion hacs.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ABB Power-One PVI SunSpec",
"homeassistant": "2023.11.0",
"homeassistant": "2024.6.0",
"content_in_root": false,
"render_readme": true,
"zip_release": true,
Expand Down

0 comments on commit e59f98f

Please sign in to comment.