aioWiserHeatAPI 1.5.19__tar.gz → 1.6.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/PKG-INFO +15 -2
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/README.md +14 -1
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/__init__.py +1 -1
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/binary_sensor.py +40 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/const.py +3 -0
- aiowiserheatapi-1.6.1/aioWiserHeatAPI/devices.py +465 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/heating_actuator.py +18 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/device.py +10 -2
- aiowiserheatapi-1.6.1/aioWiserHeatAPI/helpers/threshold.py +93 -0
- aiowiserheatapi-1.6.1/aioWiserHeatAPI/helpers/uiconfiguration.py +73 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/hot_water.py +114 -35
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/light.py +24 -3
- aiowiserheatapi-1.6.1/aioWiserHeatAPI/ptc.py +192 -0
- aiowiserheatapi-1.6.1/aioWiserHeatAPI/temp_humidity.py +50 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI.egg-info/PKG-INFO +15 -2
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI.egg-info/SOURCES.txt +4 -0
- aiowiserheatapi-1.5.19/aioWiserHeatAPI/devices.py +0 -373
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/LICENSE +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/automation.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/boiler_interface.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/button_panel.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/cli.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/discovery.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/exceptions.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/heating.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/__init__.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/automations.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/battery.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/capabilities.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/cloud.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/equipment.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/extra_config.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/firmware.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/gps.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/misc.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/network.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/opentherm.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/signal.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/special_times.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/status.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/temp.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/version.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/helpers/zigbee.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/moments.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/pte.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/rest_controller.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/room.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/roomstat.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/schedule.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/shutter.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/smartplug.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/smartvalve.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/smokealarm.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/system.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/ufh.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI/wiserhub.py +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI.egg-info/dependency_links.txt +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI.egg-info/entry_points.txt +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI.egg-info/requires.txt +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/aioWiserHeatAPI.egg-info/top_level.txt +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/setup.cfg +0 -0
- {aiowiserheatapi-1.5.19 → aiowiserheatapi-1.6.1}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: aioWiserHeatAPI
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.1
|
|
4
4
|
Summary: An AsyncIO API for controlling the Drayton Wiser Heating system
|
|
5
5
|
Home-page: https://github.com/msp1974/aioWiserHeatAPI
|
|
6
6
|
Author: Mark Parker
|
|
@@ -18,7 +18,7 @@ Requires-Dist: aiohttp>=3.9.3
|
|
|
18
18
|
Requires-Dist: aiofiles>=23.2.1
|
|
19
19
|
Requires-Dist: pyyaml>=6.0.1
|
|
20
20
|
|
|
21
|
-
# Drayton Wiser Hub API Async v1.
|
|
21
|
+
# Drayton Wiser Hub API Async v1.6.1
|
|
22
22
|
|
|
23
23
|
This repository contains a simple API which queries the Drayton Wiser Heating sysystem used in the UK.
|
|
24
24
|
|
|
@@ -72,6 +72,19 @@ Documentation available in [info.md](https://github.com/msp1974/wiserHeatAPIv2/b
|
|
|
72
72
|
|
|
73
73
|
## Changelog
|
|
74
74
|
|
|
75
|
+
### v1.6.1
|
|
76
|
+
* Added: support for temperature and humidity sensors
|
|
77
|
+
|
|
78
|
+
### v1.6.0
|
|
79
|
+
* Refactored how devices are enumerated
|
|
80
|
+
* BREAKING CHANGE - threshold sensor is now a device attribute and not its own device
|
|
81
|
+
* Added: support for 2 gang light switches
|
|
82
|
+
* Added: support for threshold and UI configuration as device attributes
|
|
83
|
+
* Added: support for PTC devices
|
|
84
|
+
* Added: UUID now exists for all devices (for future use)
|
|
85
|
+
* Added: New attributes and stored extra config for Hot Water to support HW Climate automation in HA integration
|
|
86
|
+
* Added: Control of interacts with room climate for binary sensors
|
|
87
|
+
|
|
75
88
|
### v1.5.19
|
|
76
89
|
* Fixed error when BoilerInterface does not provide DeviceId field
|
|
77
90
|
* Fixed not supporting non ascii characters in schedule names
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Drayton Wiser Hub API Async v1.
|
|
1
|
+
# Drayton Wiser Hub API Async v1.6.1
|
|
2
2
|
|
|
3
3
|
This repository contains a simple API which queries the Drayton Wiser Heating sysystem used in the UK.
|
|
4
4
|
|
|
@@ -52,6 +52,19 @@ Documentation available in [info.md](https://github.com/msp1974/wiserHeatAPIv2/b
|
|
|
52
52
|
|
|
53
53
|
## Changelog
|
|
54
54
|
|
|
55
|
+
### v1.6.1
|
|
56
|
+
* Added: support for temperature and humidity sensors
|
|
57
|
+
|
|
58
|
+
### v1.6.0
|
|
59
|
+
* Refactored how devices are enumerated
|
|
60
|
+
* BREAKING CHANGE - threshold sensor is now a device attribute and not its own device
|
|
61
|
+
* Added: support for 2 gang light switches
|
|
62
|
+
* Added: support for threshold and UI configuration as device attributes
|
|
63
|
+
* Added: support for PTC devices
|
|
64
|
+
* Added: UUID now exists for all devices (for future use)
|
|
65
|
+
* Added: New attributes and stored extra config for Hot Water to support HW Climate automation in HA integration
|
|
66
|
+
* Added: Control of interacts with room climate for binary sensors
|
|
67
|
+
|
|
55
68
|
### v1.5.19
|
|
56
69
|
* Fixed error when BoilerInterface does not provide DeviceId field
|
|
57
70
|
* Fixed not supporting non ascii characters in schedule names
|
|
@@ -2,13 +2,43 @@
|
|
|
2
2
|
Handles binary_sensor devices
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
import inspect
|
|
6
|
+
|
|
7
|
+
from aioWiserHeatAPI import _LOGGER
|
|
8
|
+
|
|
5
9
|
from .helpers.battery import _WiserBattery
|
|
6
10
|
from .helpers.device import _WiserDevice
|
|
11
|
+
from .helpers.threshold import _WiserThresholdSensor
|
|
7
12
|
|
|
8
13
|
|
|
9
14
|
class _WiserBinarySensor(_WiserDevice):
|
|
10
15
|
"""Class representing a Wiser Binary Sensor"""
|
|
11
16
|
|
|
17
|
+
def __init__(self, *args):
|
|
18
|
+
"""Initialise."""
|
|
19
|
+
super().__init__(*args)
|
|
20
|
+
self._threshold_sensors: list[_WiserThresholdSensor] = []
|
|
21
|
+
|
|
22
|
+
async def _send_command(self, cmd: dict):
|
|
23
|
+
"""
|
|
24
|
+
Send control command to the Threshold sensor
|
|
25
|
+
param cmd: json command structure
|
|
26
|
+
return: boolen - true = success, false = failed
|
|
27
|
+
"""
|
|
28
|
+
result = await self._wiser_rest_controller._send_command(
|
|
29
|
+
self._endpoint.format(self.device_type_id), cmd
|
|
30
|
+
)
|
|
31
|
+
if result:
|
|
32
|
+
self._device_type_data = result
|
|
33
|
+
if result:
|
|
34
|
+
_LOGGER.debug(
|
|
35
|
+
"Wiser light - {} command successful".format(
|
|
36
|
+
inspect.stack()[1].function
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
return True
|
|
40
|
+
return False
|
|
41
|
+
|
|
12
42
|
@property
|
|
13
43
|
def active(self) -> bool:
|
|
14
44
|
"""Get if is active"""
|
|
@@ -19,6 +49,11 @@ class _WiserBinarySensor(_WiserDevice):
|
|
|
19
49
|
"""Get the if interacts with room climate"""
|
|
20
50
|
return self._device_type_data.get("InteractsWithRoomClimate")
|
|
21
51
|
|
|
52
|
+
async def set_interacts_with_room_climate(self, enabled: bool):
|
|
53
|
+
if await self._send_command({"InteractsWithRoomClimate": str(enabled).lower()}):
|
|
54
|
+
self._interacts_with_room_climate = enabled
|
|
55
|
+
return True
|
|
56
|
+
|
|
22
57
|
@property
|
|
23
58
|
def type(self) -> str:
|
|
24
59
|
"""Get the type of device"""
|
|
@@ -34,6 +69,11 @@ class _WiserBinarySensor(_WiserDevice):
|
|
|
34
69
|
"""Get the battery information for the smokealarm"""
|
|
35
70
|
return _WiserBattery(self._data)
|
|
36
71
|
|
|
72
|
+
@property
|
|
73
|
+
def threshold_sensors(self) -> list[_WiserThresholdSensor]:
|
|
74
|
+
"""Get threshold sensors."""
|
|
75
|
+
return self._threshold_sensors
|
|
76
|
+
|
|
37
77
|
|
|
38
78
|
class _WiserWindowDoorSensor(_WiserBinarySensor):
|
|
39
79
|
"""Class representing a Wiser WindowDoor Sensor"""
|
|
@@ -101,11 +101,14 @@ WISERHEATINGACTUATOR = "HeatingActuator/{}"
|
|
|
101
101
|
WISERUFHCONTROLLER = "UnderFloorHeating/{}"
|
|
102
102
|
WISERSHUTTER = "Shutter/{}"
|
|
103
103
|
WISERLIGHT = "Light/{}"
|
|
104
|
+
WISERPOWERTAGCONTROL = "PTC/{}"
|
|
104
105
|
WISERPOWERTAGENERGY = "PTE/{}"
|
|
105
106
|
WISERSMOKEALARM = "SmokeAlarmDevice/{}"
|
|
106
107
|
WISERBINARYSENSOR = "BinarySensor/{}"
|
|
107
108
|
WISERBOILERINTERFACE = "BoilerInterface/{}"
|
|
108
109
|
WISERBUTTONPANEL = "ButtonPanel/{}"
|
|
110
|
+
WISERTHRESHOLDSENSOR = "ThresholdSensor/{}"
|
|
111
|
+
WISERUICONFIGURATION = "UIConfiguration/{}"
|
|
109
112
|
|
|
110
113
|
|
|
111
114
|
# Enums
|
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module to manage all devices
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from .binary_sensor import (
|
|
9
|
+
_WiserBinarySensor,
|
|
10
|
+
_WiserBinarySensorCollection,
|
|
11
|
+
)
|
|
12
|
+
from .boiler_interface import _WiserBoilerInterface, _WiserBoilerInterfaceCollection
|
|
13
|
+
from .button_panel import _WiserButtonPanel, _WiserButtonPanelCollection
|
|
14
|
+
from .const import (
|
|
15
|
+
WISERBINARYSENSOR,
|
|
16
|
+
WISERBOILERINTERFACE,
|
|
17
|
+
WISERBUTTONPANEL,
|
|
18
|
+
WISERHEATINGACTUATOR,
|
|
19
|
+
WISERLIGHT,
|
|
20
|
+
WISERPOWERTAGCONTROL,
|
|
21
|
+
WISERPOWERTAGENERGY,
|
|
22
|
+
WISERROOMSTAT,
|
|
23
|
+
WISERSHUTTER,
|
|
24
|
+
WISERSMARTPLUG,
|
|
25
|
+
WISERSMARTVALVE,
|
|
26
|
+
WISERSMOKEALARM,
|
|
27
|
+
WISERTHRESHOLDSENSOR,
|
|
28
|
+
WISERUFHCONTROLLER,
|
|
29
|
+
WISERUICONFIGURATION,
|
|
30
|
+
)
|
|
31
|
+
from .heating_actuator import _WiserHeatingActuator, _WiserHeatingActuatorCollection
|
|
32
|
+
from .helpers.device import _WiserDevice
|
|
33
|
+
from .helpers.threshold import (
|
|
34
|
+
_WiserThresholdSensor,
|
|
35
|
+
)
|
|
36
|
+
from .helpers.uiconfiguration import _WiserUIConfigSensor
|
|
37
|
+
from .light import _WiserDimmableLight, _WiserLight, _WiserLightCollection
|
|
38
|
+
from .ptc import _WiserPowerTagControl, _WiserPowerTagControlCollection
|
|
39
|
+
from .pte import _WiserPowerTagEnergy, _WiserPowerTagEnergyCollection
|
|
40
|
+
from .rest_controller import _WiserRestController
|
|
41
|
+
from .roomstat import _WiserRoomStat, _WiserRoomStatCollection
|
|
42
|
+
from .schedule import WiserScheduleTypeEnum, _WiserScheduleCollection
|
|
43
|
+
from .shutter import _WiserShutter, _WiserShutterCollection
|
|
44
|
+
from .smartplug import _WiserSmartPlug, _WiserSmartPlugCollection
|
|
45
|
+
from .smartvalve import _WiserSmartValve, _WiserSmartValveCollection
|
|
46
|
+
from .smokealarm import _WiserSmokeAlarm, _WiserSmokeAlarmCollection
|
|
47
|
+
from .temp_humidity import _WiserTempHumidity, _WiserTempHumidityCollection
|
|
48
|
+
from .ufh import _WiserUFHController, _WiserUFHControllerCollection
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass(frozen=True, kw_only=True)
|
|
52
|
+
class DeviceConfig:
|
|
53
|
+
device_class: Any
|
|
54
|
+
collection: Any
|
|
55
|
+
endpoint: str = None
|
|
56
|
+
heating: bool = False
|
|
57
|
+
schedule_type: WiserScheduleTypeEnum | None = None
|
|
58
|
+
has_v2_equipment: bool = False
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass(frozen=True, kw_only=True)
|
|
62
|
+
class AncillaryDeviceConfig:
|
|
63
|
+
device_class: Any
|
|
64
|
+
attribute: str
|
|
65
|
+
endpoint: str = None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
PRODUCT_TYPE_CONFIG = {
|
|
69
|
+
"SmartValve": DeviceConfig(
|
|
70
|
+
device_class=_WiserSmartValve,
|
|
71
|
+
collection=_WiserSmartValveCollection,
|
|
72
|
+
endpoint=WISERSMARTVALVE,
|
|
73
|
+
heating=True,
|
|
74
|
+
),
|
|
75
|
+
"RoomStat": DeviceConfig(
|
|
76
|
+
device_class=_WiserRoomStat,
|
|
77
|
+
collection=_WiserRoomStatCollection,
|
|
78
|
+
endpoint=WISERROOMSTAT,
|
|
79
|
+
heating=True,
|
|
80
|
+
),
|
|
81
|
+
"SmartPlug": DeviceConfig(
|
|
82
|
+
device_class=_WiserSmartPlug,
|
|
83
|
+
collection=_WiserSmartPlugCollection,
|
|
84
|
+
endpoint=WISERSMARTPLUG,
|
|
85
|
+
schedule_type=WiserScheduleTypeEnum.onoff,
|
|
86
|
+
has_v2_equipment=True,
|
|
87
|
+
),
|
|
88
|
+
"HeatingActuator": DeviceConfig(
|
|
89
|
+
device_class=_WiserHeatingActuator,
|
|
90
|
+
collection=_WiserHeatingActuatorCollection,
|
|
91
|
+
endpoint=WISERHEATINGACTUATOR,
|
|
92
|
+
heating=True,
|
|
93
|
+
has_v2_equipment=True,
|
|
94
|
+
),
|
|
95
|
+
"UnderFloorHeating": DeviceConfig(
|
|
96
|
+
device_class=_WiserUFHController,
|
|
97
|
+
collection=_WiserUFHControllerCollection,
|
|
98
|
+
endpoint=WISERUFHCONTROLLER,
|
|
99
|
+
heating=True,
|
|
100
|
+
),
|
|
101
|
+
"Light": DeviceConfig(
|
|
102
|
+
device_class=_WiserLight,
|
|
103
|
+
collection=_WiserLightCollection,
|
|
104
|
+
endpoint=WISERLIGHT,
|
|
105
|
+
schedule_type=WiserScheduleTypeEnum.level,
|
|
106
|
+
),
|
|
107
|
+
"Shutter": DeviceConfig(
|
|
108
|
+
device_class=_WiserShutter,
|
|
109
|
+
collection=_WiserShutterCollection,
|
|
110
|
+
endpoint=WISERSHUTTER,
|
|
111
|
+
schedule_type=WiserScheduleTypeEnum.level,
|
|
112
|
+
),
|
|
113
|
+
"PTC": DeviceConfig(
|
|
114
|
+
device_class=_WiserPowerTagControl,
|
|
115
|
+
collection=_WiserPowerTagControlCollection,
|
|
116
|
+
endpoint=WISERPOWERTAGCONTROL,
|
|
117
|
+
has_v2_equipment=True,
|
|
118
|
+
),
|
|
119
|
+
"PTE": DeviceConfig(
|
|
120
|
+
device_class=_WiserPowerTagEnergy,
|
|
121
|
+
collection=_WiserPowerTagEnergyCollection,
|
|
122
|
+
endpoint=WISERPOWERTAGENERGY,
|
|
123
|
+
has_v2_equipment=True,
|
|
124
|
+
),
|
|
125
|
+
"SmokeAlarmDevice": DeviceConfig(
|
|
126
|
+
device_class=_WiserSmokeAlarm,
|
|
127
|
+
collection=_WiserSmokeAlarmCollection,
|
|
128
|
+
endpoint=WISERSMOKEALARM,
|
|
129
|
+
),
|
|
130
|
+
"BinarySensor": DeviceConfig(
|
|
131
|
+
device_class=_WiserBinarySensor,
|
|
132
|
+
collection=_WiserBinarySensorCollection,
|
|
133
|
+
endpoint=WISERBINARYSENSOR,
|
|
134
|
+
),
|
|
135
|
+
"BoilerInterface": DeviceConfig(
|
|
136
|
+
device_class=_WiserBoilerInterface,
|
|
137
|
+
collection=_WiserBoilerInterfaceCollection,
|
|
138
|
+
endpoint=WISERBOILERINTERFACE,
|
|
139
|
+
),
|
|
140
|
+
"ButtonPanel": DeviceConfig(
|
|
141
|
+
device_class=_WiserButtonPanel,
|
|
142
|
+
collection=_WiserButtonPanelCollection,
|
|
143
|
+
endpoint=WISERBUTTONPANEL,
|
|
144
|
+
),
|
|
145
|
+
"TempHumidity": DeviceConfig(
|
|
146
|
+
device_class=_WiserTempHumidity,
|
|
147
|
+
collection=_WiserTempHumidityCollection,
|
|
148
|
+
endpoint=None,
|
|
149
|
+
),
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
ANCILLARY_SENSOR_CONFIG = {
|
|
153
|
+
"ThresholdSensor": AncillaryDeviceConfig(
|
|
154
|
+
device_class=_WiserThresholdSensor,
|
|
155
|
+
attribute="_threshold_sensors",
|
|
156
|
+
endpoint=WISERTHRESHOLDSENSOR,
|
|
157
|
+
),
|
|
158
|
+
"UIConfiguration": AncillaryDeviceConfig(
|
|
159
|
+
device_class=_WiserUIConfigSensor,
|
|
160
|
+
attribute="_uiconfig_sensors",
|
|
161
|
+
endpoint=WISERUICONFIGURATION,
|
|
162
|
+
),
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class _WiserDeviceCollection:
|
|
167
|
+
"""Class holding all wiser devices"""
|
|
168
|
+
|
|
169
|
+
def __init__(
|
|
170
|
+
self,
|
|
171
|
+
wiser_rest_controller: _WiserRestController,
|
|
172
|
+
domain_data: dict,
|
|
173
|
+
schedules: _WiserScheduleCollection,
|
|
174
|
+
):
|
|
175
|
+
self._wiser_rest_controller = wiser_rest_controller
|
|
176
|
+
self._device_data = domain_data.get("Device", {})
|
|
177
|
+
self._domain_data = domain_data
|
|
178
|
+
self._equipment_data = domain_data.get("Equipment", {}) # Supported by v2 hub
|
|
179
|
+
self._schedules = schedules
|
|
180
|
+
self._device_collection = {}
|
|
181
|
+
|
|
182
|
+
self._build()
|
|
183
|
+
|
|
184
|
+
def _get_equipment_data(self, equipment_id: int) -> dict:
|
|
185
|
+
"""Get equipment data"""
|
|
186
|
+
equipment_data = [
|
|
187
|
+
equipment_data
|
|
188
|
+
for equipment_data in self._equipment_data
|
|
189
|
+
if equipment_data.get("id") == equipment_id
|
|
190
|
+
]
|
|
191
|
+
return equipment_data[0] if equipment_data else None
|
|
192
|
+
|
|
193
|
+
def _get_device_info_by_id(self, device_id: int) -> dict[str, Any] | None:
|
|
194
|
+
"""Get device entry by id."""
|
|
195
|
+
for device in self._domain_data.get("Device"):
|
|
196
|
+
if device.get("id") == device_id:
|
|
197
|
+
return device
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
def _build(self):
|
|
201
|
+
"""Updated builf collection of devices.
|
|
202
|
+
|
|
203
|
+
Starts with device type key first and then gets matching device data
|
|
204
|
+
"""
|
|
205
|
+
# TODO - limit checks based on DeviceCapabilityMatrix
|
|
206
|
+
for device_type in PRODUCT_TYPE_CONFIG:
|
|
207
|
+
# If not yet in the collection, add empty collection to device collections.
|
|
208
|
+
if device_type not in self._device_collection:
|
|
209
|
+
self._device_collection[device_type] = PRODUCT_TYPE_CONFIG[
|
|
210
|
+
device_type
|
|
211
|
+
].collection()
|
|
212
|
+
|
|
213
|
+
if device_type == "TempHumidity":
|
|
214
|
+
# This is a workaround for temp humidity device(s)
|
|
215
|
+
for device in self._domain_data.get("Device"):
|
|
216
|
+
if device.get("ProductType") == "TemperatureHumiditySensor":
|
|
217
|
+
device_config = PRODUCT_TYPE_CONFIG[device_type]
|
|
218
|
+
device_class = device_config.device_class
|
|
219
|
+
self._device_collection[device_type]._items.append(
|
|
220
|
+
device_class(
|
|
221
|
+
self._wiser_rest_controller,
|
|
222
|
+
device_config.endpoint,
|
|
223
|
+
device,
|
|
224
|
+
{},
|
|
225
|
+
None,
|
|
226
|
+
)
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
elif device_type_data := self._domain_data.get(device_type):
|
|
230
|
+
# We have this device type in data
|
|
231
|
+
device_config = PRODUCT_TYPE_CONFIG[device_type]
|
|
232
|
+
|
|
233
|
+
# Now build collection of devices
|
|
234
|
+
for device in device_type_data:
|
|
235
|
+
# Get class to create and collection to append for device
|
|
236
|
+
device_class = device_config.device_class
|
|
237
|
+
|
|
238
|
+
# TODO: Fix this so not fudged
|
|
239
|
+
if device_type == "Light" and device.get("IsDimmable"):
|
|
240
|
+
device_class = _WiserDimmableLight
|
|
241
|
+
|
|
242
|
+
# Device info id can be DeviceId or id depending on device type
|
|
243
|
+
device_info_id = device.get("DeviceId", device.get("id"))
|
|
244
|
+
|
|
245
|
+
# Get device info data
|
|
246
|
+
device_info_data = self._get_device_info_by_id(device_info_id)
|
|
247
|
+
|
|
248
|
+
# If heating device add room id
|
|
249
|
+
if device_config.heating:
|
|
250
|
+
if not device.get("RoomId", device_info_data.get("RoomId")):
|
|
251
|
+
device["RoomId"] = self._get_temp_device_room_id(
|
|
252
|
+
self._domain_data, device_info_id
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# If schedule device add schedule
|
|
256
|
+
if device_config.schedule_type:
|
|
257
|
+
device_schedule = self._schedules.get_by_id(
|
|
258
|
+
device_config.schedule_type, device.get("ScheduleId")
|
|
259
|
+
)
|
|
260
|
+
else:
|
|
261
|
+
device_schedule = None
|
|
262
|
+
|
|
263
|
+
# Add device to collection
|
|
264
|
+
self._device_collection[device_type]._items.append(
|
|
265
|
+
device_class(
|
|
266
|
+
self._wiser_rest_controller,
|
|
267
|
+
device_config.endpoint,
|
|
268
|
+
device_info_data,
|
|
269
|
+
device,
|
|
270
|
+
device_schedule,
|
|
271
|
+
)
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
# Add ancillary sensors to device
|
|
275
|
+
for anc_device_type, anc_device_type_info in ANCILLARY_SENSOR_CONFIG.items():
|
|
276
|
+
if anc_device_type_data := self._domain_data.get(anc_device_type):
|
|
277
|
+
for anc_device in anc_device_type_data:
|
|
278
|
+
device_id = anc_device.get("DeviceId", anc_device.get("id"))
|
|
279
|
+
if device := self.get_by_id(device_id):
|
|
280
|
+
if hasattr(device, anc_device_type_info.attribute):
|
|
281
|
+
getattr(device, anc_device_type_info.attribute).append(
|
|
282
|
+
anc_device_type_info.device_class(
|
|
283
|
+
self._wiser_rest_controller,
|
|
284
|
+
anc_device_type_info.endpoint,
|
|
285
|
+
anc_device,
|
|
286
|
+
)
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
def _get_temp_device_room_id(self, domain_data: dict, device_id: int) -> int:
|
|
290
|
+
rooms = domain_data.get("Room")
|
|
291
|
+
for room in rooms:
|
|
292
|
+
room_device_list = []
|
|
293
|
+
room_device_list.extend(room.get("SmartValveIds", []))
|
|
294
|
+
room_device_list.extend(room.get("HeatingActuatorIds", []))
|
|
295
|
+
room_device_list.append(room.get("RoomStatId"))
|
|
296
|
+
room_device_list.append(room.get("UnderFloorHeatingId"))
|
|
297
|
+
if device_id in room_device_list:
|
|
298
|
+
return room.get("id")
|
|
299
|
+
return 0
|
|
300
|
+
|
|
301
|
+
@property
|
|
302
|
+
def all(self) -> list[_WiserDevice]:
|
|
303
|
+
"""Return all devices"""
|
|
304
|
+
items = []
|
|
305
|
+
for key in self._device_collection:
|
|
306
|
+
items.extend(self._device_collection[key].all)
|
|
307
|
+
return items
|
|
308
|
+
|
|
309
|
+
@property
|
|
310
|
+
def count(self) -> int:
|
|
311
|
+
"""Return count of devices"""
|
|
312
|
+
return len(self.all)
|
|
313
|
+
|
|
314
|
+
@property
|
|
315
|
+
def heating_actuators(self) -> _WiserHeatingActuatorCollection:
|
|
316
|
+
"""Return all heating actuators"""
|
|
317
|
+
try:
|
|
318
|
+
return self._device_collection["HeatingActuator"]
|
|
319
|
+
except KeyError:
|
|
320
|
+
return None
|
|
321
|
+
|
|
322
|
+
@property
|
|
323
|
+
def lights(self) -> _WiserLightCollection:
|
|
324
|
+
"""Return all lights"""
|
|
325
|
+
try:
|
|
326
|
+
return self._device_collection["Light"]
|
|
327
|
+
except KeyError:
|
|
328
|
+
return None
|
|
329
|
+
|
|
330
|
+
@property
|
|
331
|
+
def power_tags_c(self) -> _WiserPowerTagControlCollection:
|
|
332
|
+
"""Return all power tag Cs"""
|
|
333
|
+
try:
|
|
334
|
+
return self._device_collection["PTC"]
|
|
335
|
+
except KeyError:
|
|
336
|
+
return None
|
|
337
|
+
|
|
338
|
+
@property
|
|
339
|
+
def power_tags(self) -> _WiserPowerTagEnergyCollection:
|
|
340
|
+
"""Return all power tags"""
|
|
341
|
+
try:
|
|
342
|
+
return self._device_collection["PTE"]
|
|
343
|
+
except KeyError:
|
|
344
|
+
return None
|
|
345
|
+
|
|
346
|
+
@property
|
|
347
|
+
def roomstats(self) -> _WiserRoomStatCollection:
|
|
348
|
+
"""Return all roomstats"""
|
|
349
|
+
try:
|
|
350
|
+
return self._device_collection["RoomStat"]
|
|
351
|
+
except KeyError:
|
|
352
|
+
return None
|
|
353
|
+
|
|
354
|
+
@property
|
|
355
|
+
def shutters(self) -> _WiserShutterCollection:
|
|
356
|
+
"""Return all shutters"""
|
|
357
|
+
try:
|
|
358
|
+
return self._device_collection["Shutter"]
|
|
359
|
+
except KeyError:
|
|
360
|
+
return None
|
|
361
|
+
|
|
362
|
+
@property
|
|
363
|
+
def smartplugs(self) -> _WiserSmartPlugCollection:
|
|
364
|
+
"""Return all smart plugs"""
|
|
365
|
+
try:
|
|
366
|
+
return self._device_collection["SmartPlug"]
|
|
367
|
+
except KeyError:
|
|
368
|
+
return None
|
|
369
|
+
|
|
370
|
+
@property
|
|
371
|
+
def smartvalves(self) -> _WiserSmartValveCollection:
|
|
372
|
+
"""Return all smart valves (iTRVs)"""
|
|
373
|
+
try:
|
|
374
|
+
return self._device_collection["SmartValve"]
|
|
375
|
+
except KeyError:
|
|
376
|
+
return None
|
|
377
|
+
|
|
378
|
+
@property
|
|
379
|
+
def smokealarms(self) -> _WiserSmokeAlarmCollection:
|
|
380
|
+
"""Return all smoke alarms"""
|
|
381
|
+
try:
|
|
382
|
+
return self._device_collection["SmokeAlarmDevice"]
|
|
383
|
+
except KeyError:
|
|
384
|
+
return None
|
|
385
|
+
|
|
386
|
+
@property
|
|
387
|
+
def ufh_controllers(self) -> _WiserUFHControllerCollection:
|
|
388
|
+
"""Return all UFH controllers"""
|
|
389
|
+
try:
|
|
390
|
+
return self._device_collection["UnderFloorHeating"]
|
|
391
|
+
except KeyError:
|
|
392
|
+
return None
|
|
393
|
+
|
|
394
|
+
@property
|
|
395
|
+
def binary_sensor(self):
|
|
396
|
+
"""Return all binary sensors"""
|
|
397
|
+
try:
|
|
398
|
+
return self._device_collection["BinarySensor"]
|
|
399
|
+
except KeyError:
|
|
400
|
+
return None
|
|
401
|
+
|
|
402
|
+
@property
|
|
403
|
+
def temp_humidity_sensors(self):
|
|
404
|
+
"""Return all temp humidity sensors"""
|
|
405
|
+
try:
|
|
406
|
+
return self._device_collection["TempHumidity"]
|
|
407
|
+
except KeyError:
|
|
408
|
+
return None
|
|
409
|
+
|
|
410
|
+
def get_by_id(self, device_id: int) -> _WiserDevice:
|
|
411
|
+
"""
|
|
412
|
+
Gets a device object from the devices id
|
|
413
|
+
param id: id of device
|
|
414
|
+
return: Device type class
|
|
415
|
+
"""
|
|
416
|
+
try:
|
|
417
|
+
return [device for device in self.all if device.id == device_id][0]
|
|
418
|
+
except IndexError:
|
|
419
|
+
return None
|
|
420
|
+
|
|
421
|
+
def get_by_room_id(self, room_id: int) -> list[_WiserDevice]:
|
|
422
|
+
"""
|
|
423
|
+
Gets a list of devices belonging to the room id
|
|
424
|
+
param room_id: the id of the room
|
|
425
|
+
return: Device type class
|
|
426
|
+
"""
|
|
427
|
+
try:
|
|
428
|
+
return [device for device in self.all if device.room_id == room_id]
|
|
429
|
+
except IndexError:
|
|
430
|
+
return None
|
|
431
|
+
|
|
432
|
+
def get_by_node_id(self, node_id: int) -> _WiserDevice:
|
|
433
|
+
"""
|
|
434
|
+
Gets a device object from the devices zigbee node id
|
|
435
|
+
param node_id: zigbee node id of device
|
|
436
|
+
return: Device type class
|
|
437
|
+
"""
|
|
438
|
+
try:
|
|
439
|
+
return [device for device in self.all if device.node_id == node_id][0]
|
|
440
|
+
except IndexError:
|
|
441
|
+
return None
|
|
442
|
+
|
|
443
|
+
def get_by_serial_number(self, serial_number: str) -> _WiserDevice:
|
|
444
|
+
"""
|
|
445
|
+
Gets a device object from the devices serial number
|
|
446
|
+
param node_id: serial number of device
|
|
447
|
+
return: Device type class
|
|
448
|
+
"""
|
|
449
|
+
try:
|
|
450
|
+
return [
|
|
451
|
+
device for device in self.all if device.serial_number == serial_number
|
|
452
|
+
][0]
|
|
453
|
+
except IndexError:
|
|
454
|
+
return None
|
|
455
|
+
|
|
456
|
+
def get_by_parent_node_id(self, node_id: int) -> list[_WiserDevice]:
|
|
457
|
+
"""
|
|
458
|
+
Gets a list of device from the devices zigbee parent node id
|
|
459
|
+
param node_id: zigbee parent node id of device
|
|
460
|
+
return: Device type class
|
|
461
|
+
"""
|
|
462
|
+
try:
|
|
463
|
+
return [device for device in self.all if device.parent_node_id == node_id]
|
|
464
|
+
except IndexError:
|
|
465
|
+
return None
|
|
@@ -2,6 +2,8 @@ from .const import TEMP_OFF, TEXT_UNKNOWN, WISERHEATINGACTUATOR, WiserTempLimits
|
|
|
2
2
|
from .helpers.device import _WiserDevice
|
|
3
3
|
from .helpers.equipment import _WiserEquipment
|
|
4
4
|
from .helpers.temp import _WiserTemperatureFunctions as tf
|
|
5
|
+
from .helpers.threshold import _WiserThresholdSensor
|
|
6
|
+
from .helpers.uiconfiguration import _WiserUIConfigSensor
|
|
5
7
|
from .rest_controller import _WiserRestController
|
|
6
8
|
|
|
7
9
|
|
|
@@ -107,6 +109,12 @@ class _WiserTemperatureSensor:
|
|
|
107
109
|
class _WiserHeatingActuator(_WiserDevice):
|
|
108
110
|
"""Class representing a Wiser Heating Actuator device"""
|
|
109
111
|
|
|
112
|
+
def __init__(self, *args):
|
|
113
|
+
"""Initialise."""
|
|
114
|
+
super().__init__(*args)
|
|
115
|
+
self._threshold_sensors: list[_WiserThresholdSensor] = []
|
|
116
|
+
self._uiconfig_sensors: list[_WiserUIConfigSensor] = []
|
|
117
|
+
|
|
110
118
|
@property
|
|
111
119
|
def current_target_temperature(self) -> float:
|
|
112
120
|
"""Get the current target temperature setting"""
|
|
@@ -161,6 +169,16 @@ class _WiserHeatingActuator(_WiserDevice):
|
|
|
161
169
|
"""Get output type"""
|
|
162
170
|
return self._device_type_data.get("OutputType", TEXT_UNKNOWN)
|
|
163
171
|
|
|
172
|
+
@property
|
|
173
|
+
def threshold_sensors(self) -> list[_WiserThresholdSensor]:
|
|
174
|
+
"""Get threshold sensors."""
|
|
175
|
+
return self._threshold_sensors
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def uiconfig_sensors(self) -> list[_WiserUIConfigSensor]:
|
|
179
|
+
"""Get ui configuration sensors."""
|
|
180
|
+
return self._uiconfig_sensors
|
|
181
|
+
|
|
164
182
|
|
|
165
183
|
class _WiserHeatingActuatorCollection(object):
|
|
166
184
|
"""Class holding all wiser heating actuators"""
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import hashlib
|
|
1
2
|
import inspect
|
|
2
3
|
from typing import Union
|
|
4
|
+
from uuid import UUID
|
|
3
5
|
|
|
4
6
|
from .. import _LOGGER
|
|
5
7
|
from ..const import (
|
|
@@ -76,7 +78,7 @@ class _WiserDevice(object):
|
|
|
76
78
|
@property
|
|
77
79
|
def device_type_id(self) -> int:
|
|
78
80
|
"""Get the device id for the specific device type"""
|
|
79
|
-
return self.
|
|
81
|
+
return self._device_type_data.get("id")
|
|
80
82
|
|
|
81
83
|
@property
|
|
82
84
|
def identify(self) -> bool:
|
|
@@ -188,7 +190,13 @@ class _WiserDevice(object):
|
|
|
188
190
|
@property
|
|
189
191
|
def uuid(self) -> str:
|
|
190
192
|
"""Get UUID zigbee"""
|
|
191
|
-
|
|
193
|
+
if uuid := self._device_type_data.get("UUID"):
|
|
194
|
+
return uuid
|
|
195
|
+
uname = (
|
|
196
|
+
f"{self.product_type}_{self.serial_number}_{self.id}_{self.device_type_id}"
|
|
197
|
+
)
|
|
198
|
+
hexstr = hashlib.md5(uname.encode("UTF-8")).hexdigest()
|
|
199
|
+
return UUID(hex=hexstr)
|
|
192
200
|
|
|
193
201
|
# END Added by LGO
|
|
194
202
|
|