Skip to content
Open
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
85 changes: 55 additions & 30 deletions custom_components/panasonic_cc/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Platform for the Panasonic Comfort Cloud."""

import logging
from typing import Dict

Expand All @@ -8,8 +9,7 @@

from homeassistant.core import HomeAssistant
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_USERNAME, CONF_PASSWORD)
from homeassistant.const import CONF_USERNAME, CONF_PASSWORD
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.loader import async_get_integration
Expand All @@ -30,10 +30,14 @@
STARTUP,
DATA_COORDINATORS,
ENERGY_COORDINATORS,
AQUAREA_COORDINATORS)

from .coordinator import PanasonicDeviceCoordinator, PanasonicDeviceEnergyCoordinator, AquareaDeviceCoordinator
AQUAREA_COORDINATORS,
)

from .coordinator import (
PanasonicDeviceCoordinator,
PanasonicDeviceEnergyCoordinator,
AquareaDeviceCoordinator,
)

_LOGGER = logging.getLogger(__name__)

Expand All @@ -45,7 +49,10 @@
{
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_ENABLE_DAILY_ENERGY_SENSOR, default=DEFAULT_ENABLE_DAILY_ENERGY_SENSOR): cv.boolean,
vol.Optional(
CONF_ENABLE_DAILY_ENERGY_SENSOR,
default=DEFAULT_ENABLE_DAILY_ENERGY_SENSOR,
): cv.boolean,
# noqa: E501
}
)
Expand All @@ -55,6 +62,7 @@

AQUAREA_DEMO = False


def setup(hass, config):
pass

Expand All @@ -70,34 +78,47 @@ async def async_setup(hass: HomeAssistant, config: Dict) -> bool:

async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Establish connection with Comfort Cloud."""


conf = entry.data
if PANASONIC_DEVICES not in hass.data:
hass.data[PANASONIC_DEVICES] = []

username = conf[CONF_USERNAME]
password = conf[CONF_PASSWORD]
enable_daily_energy_sensor = entry.options.get(CONF_ENABLE_DAILY_ENERGY_SENSOR, DEFAULT_ENABLE_DAILY_ENERGY_SENSOR)

enable_daily_energy_sensor = entry.options.get(
CONF_ENABLE_DAILY_ENERGY_SENSOR, DEFAULT_ENABLE_DAILY_ENERGY_SENSOR
)

client = async_get_clientsession(hass)
api = ApiClient(username, password, client)
await api.start_session()
devices = api.get_devices()

if CONF_UPDATE_INTERVAL_VERSION not in conf or conf[CONF_UPDATE_INTERVAL_VERSION] < 2:

if (
CONF_UPDATE_INTERVAL_VERSION not in conf
or conf[CONF_UPDATE_INTERVAL_VERSION] < 2
):
_LOGGER.info("Updating configuration")
updated_config = dict(entry.data)
updated_config[CONF_UPDATE_INTERVAL_VERSION] = 2
if CONF_DEVICE_FETCH_INTERVAL not in conf or conf[CONF_DEVICE_FETCH_INTERVAL] <= 31:
if (
CONF_DEVICE_FETCH_INTERVAL not in conf
or conf[CONF_DEVICE_FETCH_INTERVAL] <= 31
):
updated_config[CONF_DEVICE_FETCH_INTERVAL] = DEFAULT_DEVICE_FETCH_INTERVAL
_LOGGER.info(f"Setting default fetch interval to {DEFAULT_DEVICE_FETCH_INTERVAL}")
if CONF_ENERGY_FETCH_INTERVAL not in conf or conf[CONF_ENERGY_FETCH_INTERVAL] <= 61:
_LOGGER.info(
f"Setting default fetch interval to {DEFAULT_DEVICE_FETCH_INTERVAL}"
)
if (
CONF_ENERGY_FETCH_INTERVAL not in conf
or conf[CONF_ENERGY_FETCH_INTERVAL] <= 61
):
updated_config[CONF_ENERGY_FETCH_INTERVAL] = DEFAULT_ENERGY_FETCH_INTERVAL
_LOGGER.info(f"Setting default energy fetch interval to {DEFAULT_ENERGY_FETCH_INTERVAL}")
_LOGGER.info(
f"Setting default energy fetch interval to {DEFAULT_ENERGY_FETCH_INTERVAL}"
)
hass.config_entries.async_update_entry(entry, data=updated_config)


if len(devices) == 0 and not api.has_unknown_devices:
_LOGGER.error("Could not find any Panasonic Comfort Cloud Heat Pumps")
return False
Expand All @@ -107,48 +128,52 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
energy_coordinators: list[PanasonicDeviceEnergyCoordinator] = []
aquarea_coordinators: list[AquareaDeviceCoordinator] = []


for device in devices:
try:
device_coordinator = PanasonicDeviceCoordinator(hass, conf, api, device)
await device_coordinator.async_config_entry_first_refresh()
data_coordinators.append(device_coordinator)
if enable_daily_energy_sensor:
energy_coordinators.append(PanasonicDeviceEnergyCoordinator(hass, conf, api, device))
energy_coordinators.append(
PanasonicDeviceEnergyCoordinator(hass, conf, api, device)
)
except Exception as e:
_LOGGER.warning(f"Failed to setup device: {device.name} ({e})", exc_info=e)

if api.has_unknown_devices or AQUAREA_DEMO:
try:

if not AQUAREA_DEMO:
aquarea_api_client = AquareaApiClient(client, username, password)
await aquarea_api_client.login()
else:
aquarea_api_client = AquareaApiClient(client, environment=AquareaEnvironment.DEMO)
aquarea_api_client._access_token = 'dummy'
aquarea_api_client = AquareaApiClient(
client, environment=AquareaEnvironment.DEMO
)
aquarea_api_client._access_token = "dummy"
aquarea_api_client._token_expiration = None
aquarea_devices = await aquarea_api_client.get_devices(include_long_id=True)
aquarea_devices = await aquarea_api_client.get_devices()
for aquarea_device in aquarea_devices:
try:
aquarea_device_coordinator = AquareaDeviceCoordinator(hass, conf, aquarea_api_client, aquarea_device)
aquarea_device_coordinator = AquareaDeviceCoordinator(
hass, conf, aquarea_api_client, aquarea_device
)
await aquarea_device_coordinator.async_config_entry_first_refresh()
aquarea_coordinators.append(aquarea_device_coordinator)
except Exception as e:
_LOGGER.warning(f"Failed to setup Aquarea device: {aquarea_device.name} ({e})", exc_info=e)
_LOGGER.warning(
f"Failed to setup Aquarea device: {aquarea_device.name} ({e})",
exc_info=e,
)
except Exception as e:
_LOGGER.warning(f"Failed to setup Aquarea: {e}", exc_info=e)


hass.data[DOMAIN][DATA_COORDINATORS] = data_coordinators
hass.data[DOMAIN][ENERGY_COORDINATORS] = energy_coordinators
hass.data[DOMAIN][AQUAREA_COORDINATORS] = aquarea_coordinators
await asyncio.gather(
*(
data.async_config_entry_first_refresh()
for data in energy_coordinators
),
return_exceptions=True
*(data.async_config_entry_first_refresh() for data in energy_coordinators),
return_exceptions=True,
)

await hass.config_entries.async_forward_entry_setups(entry, COMPONENT_TYPES)
Expand Down
14 changes: 9 additions & 5 deletions custom_components/panasonic_cc/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@

from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .coordinator import PanasonicDeviceCoordinator, PanasonicDeviceEnergyCoordinator, AquareaDeviceCoordinator
from .coordinator import (
PanasonicDeviceCoordinator,
PanasonicDeviceEnergyCoordinator,
AquareaDeviceCoordinator,
)


class PanasonicDataEntity(CoordinatorEntity[PanasonicDeviceCoordinator]):

Expand All @@ -16,7 +21,6 @@ def __init__(self, coordinator: PanasonicDeviceCoordinator, key: str) -> None:
self._attr_device_info = self.coordinator.device_info
self._async_update_attrs()


def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._async_update_attrs()
Expand All @@ -26,6 +30,7 @@ def _handle_coordinator_update(self) -> None:
def _async_update_attrs(self) -> None:
"""Update the attributes of the entity."""


class PanasonicEnergyEntity(CoordinatorEntity[PanasonicDeviceEnergyCoordinator]):

_attr_has_entity_name = True
Expand All @@ -37,7 +42,6 @@ def __init__(self, coordinator: PanasonicDeviceEnergyCoordinator, key: str) -> N
self._attr_device_info = self.coordinator.device_info
self._async_update_attrs()


def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._async_update_attrs()
Expand All @@ -47,6 +51,7 @@ def _handle_coordinator_update(self) -> None:
def _async_update_attrs(self) -> None:
"""Update the attributes of the entity."""


class AquareaDataEntity(CoordinatorEntity[AquareaDeviceCoordinator]):

_attr_has_entity_name = True
Expand All @@ -58,12 +63,11 @@ def __init__(self, coordinator: AquareaDeviceCoordinator, key: str) -> None:
self._attr_device_info = self.coordinator.device_info
self._async_update_attrs()


def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._async_update_attrs()
self.async_write_ha_state()

@abstractmethod
def _async_update_attrs(self) -> None:
"""Update the attributes of the entity."""
"""Update the attributes of the entity."""
48 changes: 32 additions & 16 deletions custom_components/panasonic_cc/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@

_LOGGER = logging.getLogger(__name__)


@dataclass(frozen=True, kw_only=True)
class PanasonicButtonEntityDescription(ButtonEntityDescription):
"""Describes a Panasonic Button entity."""

func: Callable[[PanasonicDeviceCoordinator], Awaitable[Any]] | None = None


Expand All @@ -23,44 +25,57 @@ class PanasonicButtonEntityDescription(ButtonEntityDescription):
name="Fetch latest app version",
icon="mdi:refresh",
entity_category=EntityCategory.DIAGNOSTIC,
func = lambda coordinator: coordinator.api_client.update_app_version()
func=lambda coordinator: coordinator.api_client.update_app_version(),
)

UPDATE_DATA_DESCRIPTION = ButtonEntityDescription(
key="update_data",
name="Fetch latest data",
icon="mdi:update",
entity_category=EntityCategory.DIAGNOSTIC
entity_category=EntityCategory.DIAGNOSTIC,
)
UPDATE_ENERGY_DESCRIPTION = ButtonEntityDescription(
key="update_energy",
name="Fetch latest energy data",
icon="mdi:update",
entity_category=EntityCategory.DIAGNOSTIC
entity_category=EntityCategory.DIAGNOSTIC,
)


async def async_setup_entry(hass: HomeAssistant, config, async_add_entities):
entities = []
data_coordinators: list[PanasonicDeviceCoordinator] = hass.data[DOMAIN][DATA_COORDINATORS]
energy_coordinators: list[PanasonicDeviceEnergyCoordinator] = hass.data[DOMAIN][ENERGY_COORDINATORS]
data_coordinators: list[PanasonicDeviceCoordinator] = hass.data[DOMAIN][
DATA_COORDINATORS
]
energy_coordinators: list[PanasonicDeviceEnergyCoordinator] = hass.data[DOMAIN][
ENERGY_COORDINATORS
]

for coordinator in data_coordinators:
entities.append(PanasonicButtonEntity(coordinator, APP_VERSION_DESCRIPTION))
entities.append(CoordinatorUpdateButtonEntity(coordinator, UPDATE_DATA_DESCRIPTION))
entities.append(
CoordinatorUpdateButtonEntity(coordinator, UPDATE_DATA_DESCRIPTION)
)
for coordinator in energy_coordinators:
entities.append(CoordinatorUpdateButtonEntity(coordinator, UPDATE_ENERGY_DESCRIPTION))

entities.append(
CoordinatorUpdateButtonEntity(coordinator, UPDATE_ENERGY_DESCRIPTION)
)

async_add_entities(entities)



class PanasonicButtonEntity(PanasonicDataEntity, ButtonEntity):
"""Representation of a Panasonic Button."""

entity_description: PanasonicButtonEntityDescription

def __init__(self, coordinator: PanasonicDeviceCoordinator, description: PanasonicButtonEntityDescription) -> None:
def __init__(
self,
coordinator: PanasonicDeviceCoordinator,
description: PanasonicButtonEntityDescription,
) -> None:
self.entity_description = description
super().__init__(coordinator, description.key)


def _async_update_attrs(self) -> None:
"""Update the attributes of the entity."""
Expand All @@ -70,18 +85,19 @@ async def async_press(self) -> None:
if self.entity_description.func:
await self.entity_description.func(self.coordinator)


class CoordinatorUpdateButtonEntity(PanasonicDataEntity, ButtonEntity):
"""Representation of a Coordinator Update Button."""

def __init__(self, coordinator: DataUpdateCoordinator, description: ButtonEntityDescription) -> None:

def __init__(
self, coordinator: DataUpdateCoordinator, description: ButtonEntityDescription
) -> None:
self.entity_description = description
super().__init__(coordinator, description.key)


def _async_update_attrs(self) -> None:
"""Update the attributes of the entity."""

async def async_press(self) -> None:
"""Press the button."""
await self.coordinator.async_request_refresh()

Loading