Skip to content

Commit

Permalink
Allow setting zone temperature if device supports it (#4)
Browse files Browse the repository at this point in the history
* Bump aioaquarea dependency

* Allow setting temperature of the zone if device supports it

* Code clean up
  • Loading branch information
cjaliaga authored Sep 4, 2022
1 parent 4c4aff2 commit c3aaae4
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 37 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,17 @@ This integration is currently in beta. Please report any issues you find and any
**⚠️ Make sure to read the 'Remarks' and 'Warning' sections**

## Features
* Climate entity per device zone that allows you to control the operation mode and read the current temperature of the device/zone.
* Climate entity per device zone that allows you to control the operation mode, read the current temperature of the water in the device/zone and (if the zone supports it), change the target temperature.
* Sensor entity for the outdoor temperature.
* Water heater entity for the hot water tank (if the device has one).
* Water heater entity for the hot water tank (if the device has one), that allows you to control the operation mode (enabled/disabled) and read the current temperature of the water in the tank.
* Diagnostic sensor to indicate if the device has any problem (such not enough water flow).

## Features in the works
* Consumption sensors.
* Weekly schedule.
* Set the device in eco mode/quiet mode/holiday mode (if the device supports it).
* Set the device in away mode (if the device supports it).
* Investigate if it's possible to set target temperature for the zone on devices that support it.

* Additional sensors/switches for the device.

## Remarks
Panasonic only allows one connection per account at the same time. This means that if you open the session from the Panasonic Confort Cloud app or the Panasonic Confort Cloud website, the session will be closed and you will be disconnected from Home Assistant. The integration will try to reconnect automatically, clossing the session from the app or the website. If you want to use the app or the website, you will have to temporarily disable the integration.
Expand Down
2 changes: 2 additions & 0 deletions custom_components/aquarea/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import Any

import aioaquarea

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
from homeassistant.core import HomeAssistant
Expand Down Expand Up @@ -48,6 +49,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data[DOMAIN][entry.entry_id][CLIENT] = client

try:
await client.login()
# Get all the devices, we will filter the disabled ones later
devices = await client.get_devices(include_long_id=True)

Expand Down
17 changes: 9 additions & 8 deletions custom_components/aquarea/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
"""Diagnostics sensor that indicates if the Panasonic Aquarea Device is on error"""
import logging

from homeassistant.components.binary_sensor import (BinarySensorDeviceClass,
BinarySensorEntity)
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
BinarySensorEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import EntityCategory
Expand All @@ -25,15 +28,13 @@ async def async_setup_entry(
config_entry.entry_id
][DEVICES]

entities: list[StatusBinarySensor] = []

entities.extend([StatusBinarySensor(coordinator) for coordinator in data.values()])

async_add_entities(entities)
async_add_entities(
[StatusBinarySensor(coordinator) for coordinator in data.values()]
)


class StatusBinarySensor(AquareaBaseEntity, BinarySensorEntity):
"""Representation of a Aquarea sensor."""
"""Representation of a Aquarea sensor that indicates if the device is on error"""

_attr_has_entity_name = True

Expand Down
68 changes: 51 additions & 17 deletions custom_components/aquarea/climate.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
"""Climate entity to control a zone for a Panasonic Aquarea Device"""
import logging

from aioaquarea import DeviceAction, ExtendedOperationMode, UpdateOperationMode

from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
ClimateEntityFeature,
HVACAction,
HVACMode,
)
from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import TEMP_CELSIUS
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback

Expand All @@ -31,18 +32,14 @@ async def async_setup_entry(
config_entry.entry_id
][DEVICES]

entities: list[HeatPumpClimate] = []

entities.extend(
async_add_entities(
[
HeatPumpClimate(coordinator, zone_id)
for coordinator in data.values()
for zone_id in coordinator.device.zones
]
)

async_add_entities(entities)


def get_hvac_mode_from_ext_op_mode(mode: ExtendedOperationMode) -> HVACMode:
"""Convert extended operation mode to HVAC mode."""
Expand Down Expand Up @@ -117,25 +114,62 @@ def _handle_coordinator_update(self) -> None:

self._attr_hvac_mode = get_hvac_mode_from_ext_op_mode(device.mode)
self._attr_hvac_action = get_hvac_action_from_ext_action(device.current_action)
self._attr_icon = (
"mdi:hvac-off" if device.mode == ExtendedOperationMode.OFF else "mdi:hvac"
)

# The device doesn't allow to set the temperature directly
zone = device.zones.get(self._zone_id)
self._attr_current_temperature = zone.temperature

# If the device doesn't allow to set the temperature directly
# So we set the max and min to the current temperature.
# This is a workaround to make the UI work
# We need to study if other devices allow to set the temperature and detect that
# programatelly to make this work for all devices.
# https://github.com/cjaliaga/aioaquarea/issues/7
current_temperature = device.zones.get(self._zone_id).temperature
self._attr_current_temperature = current_temperature
self._attr_max_temp = current_temperature
self._attr_min_temp = current_temperature
# This is a workaround to make the UI work.
self._attr_max_temp = zone.temperature
self._attr_min_temp = zone.temperature

if zone.supports_set_temperature and device.mode != ExtendedOperationMode.OFF:
self._attr_max_temp = (
zone.cool_max
if device.mode
in (ExtendedOperationMode.COOL, ExtendedOperationMode.AUTO_COOL)
else zone.heat_max
)
self._attr_min_temp = (
zone.cool_min
if device.mode
in (ExtendedOperationMode.COOL, ExtendedOperationMode.AUTO_COOL)
else zone.heat_min
)
self._attr_target_temperature_step = 1

super()._handle_coordinator_update()

async def async_set_hvac_mode(self, hvac_mode):
"""Set new target hvac mode."""
if hvac_mode not in self.hvac_modes:
raise ValueError(f"Unsupported HVAC mode: {hvac_mode}")

_LOGGER.debug(
"Setting operation mode of %s to %s",
self.coordinator.device.device_id,
hvac_mode,
)

await self.coordinator.device.set_mode(
get_update_operation_mode_from_hvac_mode(hvac_mode), self._zone_id
)

async def async_set_temperature(self, **kwargs) -> None:
"""The device doesn't allow to set the temperature directly."""
"""Set new target temperature if supported by the zone"""
zone = self.coordinator.device.zones.get(self._zone_id)
temperature = kwargs.get(ATTR_TEMPERATURE, None)

if temperature and zone.supports_set_temperature:
_LOGGER.debug(
"Setting temperature of device:zone == %s:%s to %s",
self.coordinator.device.device_id,
zone.name,
str(temperature),
)

await self.coordinator.device.set_temperature(temperature, zone.zone_id)
3 changes: 2 additions & 1 deletion custom_components/aquarea/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
"""Config flow for Aquarea Smart Cloud integration."""
from __future__ import annotations

import logging
from collections.abc import Mapping
import logging
from typing import Any

import aioaquarea
import aiohttp
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.data_entry_flow import FlowResult
Expand Down
3 changes: 2 additions & 1 deletion custom_components/aquarea/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""Coordinator for Aquarea."""
from __future__ import annotations

import logging
from datetime import timedelta
import logging

import aioaquarea

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_USERNAME
from homeassistant.core import HomeAssistant
Expand Down
4 changes: 2 additions & 2 deletions custom_components/aquarea/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"documentation": "https://github.com/cjaliaga/home-assistant-aquarea",
"issue_tracker": "https://github.com/cjaliaga/home-assistant-aquarea/issues",
"requirements": [
"aioaquarea==0.2.0"
"aioaquarea==0.3.0"
],
"ssdp": [],
"zeroconf": [],
Expand All @@ -20,5 +20,5 @@
"@cjaliaga"
],
"iot_class": "cloud_polling",
"version": "0.1.0a1"
"version": "0.1.0"
}
7 changes: 5 additions & 2 deletions custom_components/aquarea/sensor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import logging

from homeassistant.components.sensor import (SensorDeviceClass, SensorEntity,
SensorStateClass)
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
Expand Down
27 changes: 25 additions & 2 deletions custom_components/aquarea/water_heater.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
"""Defines the water heater entity to control the Aquarea water tank."""
from __future__ import annotations

import logging

from aioaquarea.data import DeviceAction, OperationStatus

from homeassistant.components.water_heater import (
STATE_HEAT_PUMP,
WaterHeaterEntity,
WaterHeaterEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import PRECISION_WHOLE, STATE_OFF, TEMP_CELSIUS
from homeassistant.const import (
ATTR_TEMPERATURE,
PRECISION_WHOLE,
STATE_OFF,
TEMP_CELSIUS,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback

Expand Down Expand Up @@ -82,7 +89,13 @@ def _update_operation_state(self) -> None:
if self.coordinator.device.tank.operation_status == OperationStatus.OFF:
self._attr_state = STATE_OFF
self._attr_current_operation = STATE_OFF
self._attr_icon = (
"mdi:water-boiler-alert"
if self.coordinator.device.is_on_error
else "mdi:water-boiler-off"
)
else:
self._attr_icon = "mdi:water-boiler"
self._attr_state = STATE_HEAT_PUMP
self._attr_current_operation = (
HEATING
Expand All @@ -98,10 +111,20 @@ def _update_temperature(self) -> None:

async def async_set_temperature(self, **kwargs):
"""Set new target temperature."""
if temperature := kwargs.get("temperature"):
if temperature := kwargs.get(ATTR_TEMPERATURE):
_LOGGER.debug(
"Setting %s water tank temperature to %s",
self.coordinator.device.device_id,
str(temperature),
)
await self.coordinator.device.tank.set_target_temperature(int(temperature))

async def async_set_operation_mode(self, operation_mode):
_LOGGER.debug(
"Turning %s water tank %s",
self.coordinator.device.device_id,
operation_mode,
)
if operation_mode == HEATING:
await self.coordinator.device.tank.turn_on()
elif operation_mode == STATE_OFF:
Expand Down

0 comments on commit c3aaae4

Please sign in to comment.