Skip to content

Commit

Permalink
Merge pull request #448 from asantaga/dev
Browse files Browse the repository at this point in the history
V3.4.4
  • Loading branch information
msp1974 authored Mar 4, 2024
2 parents 0289282 + 02ee9f0 commit 6d27d21
Show file tree
Hide file tree
Showing 14 changed files with 147 additions and 35 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Wiser Home Assistant Integration v3.4.3
# Wiser Home Assistant Integration v3.4.4

[![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg?style=for-the-badge)](https://github.com/hacs/integration)
[![downloads](https://shields.io/github/downloads/asantaga/wiserHomeAssistantPlatform/latest/total?style=for-the-badge)](https://github.com/asantaga/wiserHomeAssistantPlatform)
Expand All @@ -24,6 +24,17 @@ For more information checkout the AMAZING community thread available on

## Change log

- v3.4.4
- Bump api to v1.5.11
- Improved api retry handling for inconsitant errors coming from the hub causing errors in the log and entities to go unavailable (issues [#434](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/434), #436, #439)
- Fixed Validation of translation placeholders error for German language (issue [#434](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/434)
- Fixed diagnostic download failure (issue [#444](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/444))
- Fixed error with wall plugs not providing power data (issue [#446](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/446))
- Set state of target temp sensors to Unavailable when the climate HVAC mode is off (issue [#447](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/447), #378)
- Added ability to set a different IP port for hub - PR#430 - thanks @simick
- Enabled statistics on batteries - PR#445 - thanks @msalway
- Added number_of_trvs, number_of_trvs_locked and is_roomstat_locked attributes to climate entities (issue [#374](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/374))

- v3.4.3
- Fixed Warning error in logs caused by new HA2024.2 requirement to explicity support Turn On/Off for climate entities (issue [#435](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/435))
- Bump api to v1.5.7 to fix issue setting lower target temp when in passive mode
Expand Down
2 changes: 1 addition & 1 deletion custom_components/wiser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry):

await coordinator.async_config_entry_first_refresh()

if not coordinator.wiserhub.system:
if not coordinator.last_update_success:
raise ConfigEntryNotReady

# Update listener for config option changes
Expand Down
29 changes: 29 additions & 0 deletions custom_components/wiser/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from homeassistant.helpers import entity_platform
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from aioWiserHeatAPI.wiserhub import TEMP_MINIMUM, TEMP_MAXIMUM, TEMP_OFF
from aioWiserHeatAPI.devices import _WiserRoomStat, _WiserSmartValve
from .const import (
DATA,
DOMAIN,
Expand Down Expand Up @@ -276,6 +277,7 @@ class WiserRoom(CoordinatorEntity, ClimateEntity, WiserScheduleEntity):
"""WiserRoom ClientEntity Object."""

_enable_turn_on_off_backwards_compatibility = False
_attr_translation_key = "wiser"

def __init__(self, hass: HomeAssistant, coordinator, room_id) -> None:
"""Initialize the sensor."""
Expand Down Expand Up @@ -524,6 +526,33 @@ def extra_state_attributes(self):
if self._room.is_passive_mode:
attrs["passive_mode_temp_increment"] = self.passive_temperature_increment

# Climate devices (iTRVs and Roomstats)
attrs["number_of_trvs"] = len(
[
device
for device in self._room.devices
if isinstance(device, (_WiserSmartValve))
]
)
attrs["number_of_trvs_locked"] = len(
[
device
for device in self._room.devices
if isinstance(device, (_WiserSmartValve)) and device.device_lock_enabled
]
)
attrs["is_roomstat_locked"] = (
len(
[
device
for device in self._room.devices
if isinstance(device, (_WiserRoomStat))
and device.device_lock_enabled
]
)
> 0
)

return attrs

@property
Expand Down
26 changes: 24 additions & 2 deletions custom_components/wiser/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@

from homeassistant import config_entries, exceptions
from homeassistant.components import zeroconf
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_SCAN_INTERVAL
from homeassistant.const import (
CONF_HOST,
CONF_PORT,
CONF_NAME,
CONF_PASSWORD,
CONF_SCAN_INTERVAL,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.selector import selector, SelectSelectorMode
Expand Down Expand Up @@ -46,7 +52,11 @@
_LOGGER = logging.getLogger(__name__)

DATA_SCHEMA = vol.Schema(
{vol.Required(CONF_HOST): str, vol.Required(CONF_PASSWORD): str}
{
vol.Required(CONF_HOST): str,
vol.Optional(CONF_PORT, default=80): int,
vol.Required(CONF_PASSWORD): str,
}
)


Expand All @@ -57,6 +67,7 @@ async def validate_input(hass: HomeAssistant, data):
"""
wiserhub = WiserAPI(
host=data[CONF_HOST],
port=data[CONF_PORT],
secret=data[CONF_PASSWORD],
session=async_get_clientsession(hass),
extra_config_file=hass.config.config_dir + CUSTOM_DATA_STORE,
Expand Down Expand Up @@ -140,6 +151,7 @@ async def async_step_zeroconf(
if not discovery_info.name.startswith("WiserHeat"):
return self.async_abort(reason="not_wiser_hub")
host = discovery_info.host
port = discovery_info.port
zctype = discovery_info.type
name = discovery_info.name.replace(f".{zctype}", "")

Expand All @@ -151,6 +163,7 @@ async def async_step_zeroconf(
self.discovery_info.update(
{
CONF_HOST: host,
CONF_PORT: port,
CONF_HOSTNAME: discovery_info.hostname.replace(".local.", ".local"),
CONF_NAME: name,
}
Expand Down Expand Up @@ -192,12 +205,16 @@ async def async_step_zeroconf_confirm(
"name": self.discovery_info[CONF_NAME],
"hostname": self.discovery_info[CONF_HOSTNAME],
"ip_address": self.discovery_info[CONF_HOST],
"port": self.discovery_info[CONF_PORT],
},
data_schema=vol.Schema(
{
vol.Required(
CONF_HOST, default=self.discovery_info[CONF_HOST]
): str,
vol.Optional(
CONF_PORT, default=self.discovery_info[CONF_PORT]
): int,
vol.Required(CONF_PASSWORD): str,
}
),
Expand Down Expand Up @@ -250,10 +267,12 @@ async def async_step_main_params(self, user_input=None):
if user_input[CONF_HOST]:
data = {
CONF_HOST: user_input[CONF_HOST],
CONF_PORT: user_input[CONF_PORT],
CONF_PASSWORD: self.config_entry.data[CONF_PASSWORD],
CONF_NAME: self.config_entry.data[CONF_NAME],
}
user_input.pop(CONF_HOST)
user_input.pop(CONF_PORT)
self.hass.config_entries.async_update_entry(
self.config_entry, data=data
)
Expand All @@ -262,6 +281,9 @@ async def async_step_main_params(self, user_input=None):

data_schema = {
vol.Required(CONF_HOST, default=self.config_entry.data[CONF_HOST]): str,
vol.Optional(
CONF_PORT, default=self.config_entry.data.get(CONF_PORT, 80)
): str,
vol.Optional(
CONF_SCAN_INTERVAL,
default=self.config_entry.options.get(
Expand Down
2 changes: 1 addition & 1 deletion custom_components/wiser/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[email protected]
"""
VERSION = "3.4.3"
VERSION = "3.4.4"
DOMAIN = "wiser"
DATA_WISER_CONFIG = "wiser_config"
URL_BASE = "/wiser"
Expand Down
36 changes: 22 additions & 14 deletions custom_components/wiser/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Wiser Data Update Coordinator."""

from dataclasses import dataclass
from datetime import datetime, timedelta
import logging
Expand All @@ -12,10 +14,10 @@
)

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_SCAN_INTERVAL
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_SCAN_INTERVAL
from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import (
CONF_AUTOMATIONS_PASSIVE,
Expand All @@ -40,6 +42,8 @@

@dataclass
class WiserSettings:
"""Class to hold settings."""

minimum_temp: float
maximum_temp: float
boost_temp: float
Expand All @@ -53,11 +57,15 @@ class WiserSettings:

@dataclass
class WiserData:
"""Class to hold Wiser data."""

# settings: WiserSettings = field(init=False, default_factory=dict)
data: dict


class WiserUpdateCoordinator(DataUpdateCoordinator):
"""Wiser hub data update coordinator."""

config_entry: ConfigEntry

def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
Expand Down Expand Up @@ -111,6 +119,7 @@ def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:

self.wiserhub = WiserAPI(
host=config_entry.data[CONF_HOST],
port=config_entry.data.get(CONF_PORT, 80),
secret=str(config_entry.data[CONF_PASSWORD]).strip(),
extra_config_file=hass.config.config_dir + CUSTOM_DATA_STORE,
enable_automations=self.enable_automations_passive_mode,
Expand All @@ -125,27 +134,26 @@ def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
)

async def async_update_data(self) -> WiserData:
"""Update data from hub."""
try:
self.last_update_status = "Failed"
await self.wiserhub.read_hub_data()
self.hub_version = self.wiserhub.system.hardware_generation
self.last_update_time = datetime.now()
self.last_update_status = "Success"

_LOGGER.info(f"Hub update completed for {self.wiserhub.system.name}")
_LOGGER.info("Hub update completed for %s", self.wiserhub.system.name)

# Send event to websockets to notify hub update
async_dispatcher_send(
self.hass, "wiser_update_received", self.wiserhub.system.name
)
return True
except (
WiserHubConnectionError,
WiserHubAuthenticationError,
WiserHubRESTError,
) as ex:
self.last_update_status = "Failed"
_LOGGER.warning(ex)
except Exception as ex:
self.last_update_status = "Failed"
_LOGGER.error(ex)
raise ex
except WiserHubConnectionError as ex:
raise TimeoutError(ex) from ex
except WiserHubAuthenticationError as ex:
raise UpdateFailed(ex) from ex
except WiserHubRESTError as ex:
raise UpdateFailed(ex) from ex
except Exception as ex: # pylint: disable=broad-except
raise UpdateFailed(ex) from ex
2 changes: 1 addition & 1 deletion custom_components/wiser/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ def _async_get_diagnostics(
) -> dict[str, Any]:
data = hass.data[DOMAIN][entry.entry_id]["data"]

return anonymise_data(data.wiserhub._raw_hub_data)
return anonymise_data(data.wiserhub.raw_hub_data)
30 changes: 30 additions & 0 deletions custom_components/wiser/icons.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"entity": {
"climate": {
"wiser": {
"state_attributes": {
"preset_mode": {
"default": "mdi:home-thermometer",
"state": {
"Advance Schedule": "mdi:calendar-arrow-right",
"Cancel Overrides": "mdi:close-circle",
"Boost 30m": "mdi:fraction-one-half",
"Boost 1h": "mdi:numeric-1",
"Boost 2h": "mdi:numeric-2",
"Boost 3h": "mdi:numeric-3"
}
}
}
}
}
},
"services": {
"get_schedule": "mdi:calendar-export",
"set_schedule": "mdi:calendar-import",
"assign_schedule": "mdi:calendar-check",
"copy_schedule": "mdi:calendar-blank-multiple",
"set_device_mode": "mdi:home-switch-outline",
"boost_heating": "mdi:thermometer-chevron-up",
"set_opentherm_parameter": "mdi:application-cog-outline"
}
}
2 changes: 1 addition & 1 deletion custom_components/wiser/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"iot_class": "local_polling",
"issue_tracker": "https://github.com/asantaga/wiserHomeAssistantPlatform/issues",
"requirements": [
"aioWiserHeatAPI==1.5.7"
"aioWiserHeatAPI==1.5.11"
],
"version": "3.4.3",
"zeroconf": [
Expand Down
23 changes: 15 additions & 8 deletions custom_components/wiser/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
)
from homeassistant.const import (
ATTR_BATTERY_LEVEL,
STATE_UNAVAILABLE,
UnitOfTemperature,
UnitOfElectricCurrent,
UnitOfElectricPotential,
Expand Down Expand Up @@ -286,6 +287,10 @@ def device_class(self):
"""Return the class of the sensor."""
return SensorDeviceClass.BATTERY

@property
def state_class(self):
return SensorStateClass.MEASUREMENT

@property
def native_unit_of_measurement(self):
"""Return the unit of measurement of this entity."""
Expand Down Expand Up @@ -832,7 +837,7 @@ def _handle_coordinator_update(self) -> None:
).current_target_temperature
== TEMP_OFF
):
self._state = "Off"
self._state = STATE_UNAVAILABLE
else:
self._state = self._data.wiserhub.rooms.get_by_id(
self._device_id
Expand Down Expand Up @@ -883,8 +888,6 @@ def native_value(self):

@property
def native_unit_of_measurement(self):
if self._state == "Off":
return None
return UnitOfTemperature.CELSIUS


Expand Down Expand Up @@ -1190,18 +1193,22 @@ def _handle_coordinator_update(self) -> None:
"""Fetch new state data for the sensor."""
super()._handle_coordinator_update()
if self._lts_sensor_type == "Power":
self._state = self._data.wiserhub.devices.get_by_id(
self._device_id
).instantaneous_power
self._state = self._data.wiserhub.devices.get_by_id(self._device_id).get(
"instantaneous_power", 0
)
elif self._lts_sensor_type == "Energy":
self._state = round(
self._data.wiserhub.devices.get_by_id(self._device_id).delivered_power
self._data.wiserhub.devices.get_by_id(self._device_id).get(
"delivered_power", 0
)
/ 1000,
2,
)
elif self._lts_sensor_type == "EnergyReceived":
self._state = round(
self._data.wiserhub.devices.get_by_id(self._device_id).received_power
self._data.wiserhub.devices.get_by_id(self._device_id).get(
"received_power", 0
)
/ 1000,
2,
)
Expand Down
Loading

0 comments on commit 6d27d21

Please sign in to comment.