Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize and rearrange typing-related constants, implement and cleanup. #380

Merged
merged 7 commits into from
Sep 3, 2023
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Ongoing

- Extend p1v4_442_triple userdata to include a Plugwise notification, extending the related fixture which is used in PW-beta and Core Plugwise.
- Optimize and rearrange typing-related constants, implement and cleanup.

## v0.32.1 Improve typing, bugfix

Expand Down
13 changes: 5 additions & 8 deletions plugwise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
"""
from __future__ import annotations

from typing import cast

import aiohttp
from defusedxml import ElementTree as etree

Expand Down Expand Up @@ -34,7 +32,6 @@
SYSTEM,
ZONE_THERMOSTATS,
ActuatorData,
ApplianceData,
DeviceData,
PlugwiseData,
)
Expand Down Expand Up @@ -93,7 +90,7 @@ def _all_device_data(self) -> None:
Collect initial data for each device and add to self.gw_data and self.gw_devices.
"""
for device_id, device in self._appl_data.items():
self.gw_devices.update({device_id: cast(DeviceData, device)})
self.gw_devices.update({device_id: device})

data = self._get_device_data(device_id)
# Add plugwise notification binary_sensor to the relevant gateway
Expand Down Expand Up @@ -160,7 +157,7 @@ def get_all_devices(self) -> None:
self._all_device_data()

def _device_data_switching_group(
self, details: ApplianceData, device_data: DeviceData
self, details: DeviceData, device_data: DeviceData
) -> DeviceData:
"""Helper-function for _get_device_data().

Expand All @@ -178,7 +175,7 @@ def _device_data_switching_group(
return device_data

def _device_data_adam(
self, details: ApplianceData, device_data: DeviceData
self, details: DeviceData, device_data: DeviceData
) -> DeviceData:
"""Helper-function for _get_device_data().

Expand All @@ -196,7 +193,7 @@ def _device_data_adam(
return device_data

def _device_data_climate(
self, details: ApplianceData, device_data: DeviceData
self, details: DeviceData, device_data: DeviceData
) -> DeviceData:
"""Helper-function for _get_device_data().

Expand Down Expand Up @@ -249,7 +246,7 @@ def _device_data_climate(
return device_data

def _check_availability(
self, details: ApplianceData, device_data: DeviceData
self, details: DeviceData, device_data: DeviceData
) -> DeviceData:
"""Helper-function for _get_device_data().

Expand Down
188 changes: 95 additions & 93 deletions plugwise/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,29 +31,6 @@
VOLUME_CUBIC_METERS: Final = "m³"
VOLUME_CUBIC_METERS_PER_HOUR: Final = "m³/h"

ACTUATOR_CLASSES: Final[tuple[str, ...]] = (
"heater_central",
"thermostat",
"thermostatic_radiator_valve",
"zone_thermometer",
"zone_thermostat",
)
ActuatorType = Literal[
"domestic_hot_water_setpoint",
"max_dhw_temperature",
"maximum_boiler_temperature",
"temperature_offset",
"thermostat",
]
ACTIVE_ACTUATORS: Final[tuple[str, ...]] = get_args(ActuatorType)
ActuatorDataType = Literal[
"lower_bound",
"resolution",
"setpoint",
"setpoint_high",
"setpoint_low",
"upper_bound",
]
DAYS: Final[dict[str, int]] = {
"mo": 0,
"tu": 1,
Expand Down Expand Up @@ -108,36 +85,10 @@
"070051": "Switch",
"080029": "Switch",
}
LIMITS: Final[tuple[str, ...]] = (
"offset",
"setpoint",
"resolution",
"lower_bound",
"upper_bound",
)

MAX_SETPOINT: Final[float] = 30.0
MIN_SETPOINT: Final[float] = 4.0
NONE: Final = "None"
SPECIAL_FORMAT: Final[tuple[str, ...]] = (ENERGY_KILO_WATT_HOUR, VOLUME_CUBIC_METERS)
SWITCH_GROUP_TYPES: Final[tuple[str, ...]] = ("switching", "report")
ZONE_THERMOSTATS: Final[tuple[str, ...]] = (
"thermostat",
"thermostatic_radiator_valve",
"zone_thermometer",
"zone_thermostat",
)
THERMOSTAT_CLASSES: Final[tuple[str, ...]] = (
"thermostat",
"thermo_sensor",
"zone_thermometer",
"zone_thermostat",
"thermostatic_radiator_valve",
)
SPECIAL_PLUG_TYPES: Final[tuple[str, ...]] = (
"central_heating_pump",
"valve_actuator",
"heater_electric",
)

# XML data paths
APPLIANCES: Final = "/core/appliances"
Expand All @@ -151,6 +102,7 @@

UOM = namedtuple("UOM", "unit_of_measurement")
DATA = namedtuple("DATA", "name unit_of_measurement")

# P1 related measurements:
P1_MEASUREMENTS: Final[dict[str, UOM]] = {
"electricity_consumed": UOM(POWER_WATT),
Expand Down Expand Up @@ -234,15 +186,6 @@
"outdoor_temperature": DATA("outdoor_air_temperature", TEMP_CELSIUS),
}

ToggleNameType = Literal[
"cooling_ena_switch",
"dhw_cm_switch",
]
TOGGLES: Final[dict[str, ToggleNameType]] = {
"cooling_enabled": "cooling_ena_switch",
"domestic_hot_water_comfort_mode": "dhw_cm_switch",
}

# Known types of Smiles and Stretches
SMILE = namedtuple("SMILE", "smile_type smile_name")
SMILES: Final[dict[str, SMILE]] = {
Expand All @@ -258,7 +201,32 @@
"stretch_v3": SMILE("stretch", "Stretch"),
}

# All available Binary Sensor, Sensor, and Switch Types
# Class, Literal and related tuple-definitions

ACTUATOR_CLASSES: Final[tuple[str, ...]] = (
"heater_central",
"thermostat",
"thermostatic_radiator_valve",
"zone_thermometer",
"zone_thermostat",
)
ActuatorType = Literal[
"domestic_hot_water_setpoint",
"max_dhw_temperature",
"maximum_boiler_temperature",
"temperature_offset",
"thermostat",
]
ACTIVE_ACTUATORS: Final[tuple[str, ...]] = get_args(ActuatorType)

ActuatorDataType = Literal[
"lower_bound",
"resolution",
"setpoint",
"setpoint_high",
"setpoint_low",
"upper_bound",
]

ApplianceType = Literal[
"dev_class",
Expand Down Expand Up @@ -291,6 +259,14 @@
"temperature_offset",
]

LIMITS: Final[tuple[str, ...]] = (
"offset",
"setpoint",
"resolution",
"lower_bound",
"upper_bound",
)

SelectType = Literal[
"select_dhw_mode",
"select_regulation_mode",
Expand Down Expand Up @@ -357,6 +333,14 @@
]
SENSORS: Final[tuple[str, ...]] = get_args(SensorType)

SPECIAL_PLUG_TYPES: Final[tuple[str, ...]] = (
"central_heating_pump",
"valve_actuator",
"heater_electric",
)

SPECIAL_FORMAT: Final[tuple[str, ...]] = (ENERGY_KILO_WATT_HOUR, VOLUME_CUBIC_METERS)

SwitchType = Literal[
"cooling_ena_switch",
"dhw_cm_switch",
Expand All @@ -365,20 +349,31 @@
]
SWITCHES: Final[tuple[str, ...]] = get_args(SwitchType)

SWITCH_GROUP_TYPES: Final[tuple[str, ...]] = ("switching", "report")

class ApplianceData(TypedDict, total=False):
"""The Appliance Data class."""
THERMOSTAT_CLASSES: Final[tuple[str, ...]] = (
"thermostat",
"thermo_sensor",
"zone_thermometer",
"zone_thermostat",
"thermostatic_radiator_valve",
)

dev_class: str
firmware: str | None
hardware: str
location: str
mac_address: str | None
members: list[str]
model: str
name: str
vendor: str
zigbee_mac_address: str | None
ToggleNameType = Literal[
"cooling_ena_switch",
"dhw_cm_switch",
]
TOGGLES: Final[dict[str, ToggleNameType]] = {
"cooling_enabled": "cooling_ena_switch",
"domestic_hot_water_comfort_mode": "dhw_cm_switch",
}

ZONE_THERMOSTATS: Final[tuple[str, ...]] = (
"thermostat",
"thermostatic_radiator_valve",
"zone_thermometer",
"zone_thermostat",
)


class GatewayData(TypedDict, total=False):
Expand Down Expand Up @@ -449,7 +444,6 @@ class SmileSensors(TypedDict, total=False):
electricity_produced_peak_interval: int
electricity_produced_peak_point: int
electricity_produced_point: float
elga_status_code: int
gas_consumed_cumulative: float
gas_consumed_interval: float
humidity: float
Expand Down Expand Up @@ -502,16 +496,30 @@ class ActuatorData(TypedDict, total=False):
upper_bound: float


class DeviceData(
ApplianceData,
SmileBinarySensors,
SmileSensors,
SmileSwitches,
TypedDict,
total=False,
):
class DeviceData(TypedDict, total=False):
"""The Device Data class, covering the collected and ordered output-data per device."""

# Appliance base data
dev_class: str
firmware: str | None
hardware: str
location: str
mac_address: str | None
members: list[str]
model: str
name: str
vendor: str
zigbee_mac_address: str | None

# For temporary use
cooling_enabled: bool
domestic_hot_water_setpoint: float
elga_status_code: int
c_heating_state: bool

# Device availability
available: bool | None

# Loria
select_dhw_mode: str
dhw_modes: list[str]
Expand All @@ -521,31 +529,25 @@ class DeviceData(
regulation_modes: list[str]

# Master Thermostats
preset_modes: list[str] | None
# Presets:
active_preset: str | None

preset_modes: list[str] | None
# Schedules:
available_schedules: list[str]
select_schedule: str
last_used: str | None
select_schedule: str

mode: str

# Extra for Adam Master Thermostats
control_state: str | bool

# For temporary use
c_heating_state: bool
modified: str

# Device availability
available: bool | None

# Dict-types
binary_sensors: SmileBinarySensors
max_dhw_temperature: ActuatorData
maximum_boiler_temperature: ActuatorData
temperature_offset: ActuatorData
sensors: SmileSensors
switches: SmileSwitches
temperature_offset: ActuatorData
thermostat: ActuatorData


Expand Down
9 changes: 4 additions & 5 deletions plugwise/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
ActuatorData,
ActuatorDataType,
ActuatorType,
ApplianceData,
ApplianceType,
BinarySensorType,
DeviceData,
Expand Down Expand Up @@ -309,7 +308,7 @@ class SmileHelper:
def __init__(self) -> None:
"""Set the constructor for this class."""
self._appliances: etree
self._appl_data: dict[str, ApplianceData] = {}
self._appl_data: dict[str, DeviceData] = {}
self._cooling_activation_outdoor_temp: float
self._cooling_deactivation_threshold: float
self._cooling_present = False
Expand Down Expand Up @@ -1101,7 +1100,7 @@ def _rank_thermostat(
thermo_matching: dict[str, int],
loc_id: str,
appliance_id: str,
appliance_details: ApplianceData,
appliance_details: DeviceData,
) -> None:
"""Helper-function for _scan_thermostats().

Expand Down Expand Up @@ -1176,12 +1175,12 @@ def _thermostat_uri(self, loc_id: str) -> str:

return f"{LOCATIONS};id={loc_id}/thermostat;id={thermostat_functionality_id}"

def _group_switches(self) -> dict[str, ApplianceData]:
def _group_switches(self) -> dict[str, DeviceData]:
"""Helper-function for smile.py: get_all_devices().

Collect switching- or pump-group info.
"""
switch_groups: dict[str, ApplianceData] = {}
switch_groups: dict[str, DeviceData] = {}
# P1 and Anna don't have switchgroups
if self.smile_type == "power" or self.smile_name == "Smile Anna":
return switch_groups
Expand Down
Loading