Skip to content
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Ongoing

- Code optimizations via PR [#837](https://github.com/plugwise/python-plugwise/pull/837)

## v1.11.0

- Extend feature: support pumping group, add group sensors
Expand Down
4 changes: 2 additions & 2 deletions plugwise/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def _reorder_devices(self) -> None:
break
self.gw_entities = {**reordered, **self.gw_entities}

def _entity_switching_group(self, entity: GwEntityData, data: GwEntityData) -> None:
def _entity_switching_group(self, entity: GwEntityData) -> None:
"""Helper-function for _get_device_zone_data().

Determine switching group device data.
Expand All @@ -185,7 +185,7 @@ def _entity_switching_group(self, entity: GwEntityData, data: GwEntityData) -> N
for member in entity["members"]:
if self.gw_entities[member]["switches"].get("relay"):
counter += 1
data["switches"]["relay"] = counter != 0
entity["switches"]["relay"] = counter != 0
self._count += 1

def _get_groups(self) -> dict[str, GwEntityData]:
Expand Down
112 changes: 52 additions & 60 deletions plugwise/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ def _update_zones(self) -> None:
Collect data for each zone/location and add to self._zones.
"""
for location_id, zone in self._zones.items():
data = self._get_location_data(location_id)
zone.update(data)
self._get_location_data(location_id, zone)

def _update_gw_entities(self) -> None:
"""Helper-function for _all_entities_data() and async_update().
Expand All @@ -55,12 +54,11 @@ def _update_gw_entities(self) -> None:
"""
mac_list: list[str] = []
for entity_id, entity in self.gw_entities.items():
data = self._get_entity_data(entity_id)
self._get_entity_data(entity_id, entity)
if entity_id == self._gateway_id:
mac_list = self._detect_low_batteries()
self._add_or_update_notifications(entity_id, entity, data)
self._add_or_update_notifications(entity_id, entity)

entity.update(data)
is_battery_low = (
mac_list
and "low_battery" in entity["binary_sensors"]
Expand Down Expand Up @@ -106,7 +104,7 @@ def _detect_low_batteries(self) -> list[str]:
return mac_address_list

def _add_or_update_notifications(
self, entity_id: str, entity: GwEntityData, data: GwEntityData
self, entity_id: str, entity: GwEntityData
) -> None:
"""Helper-function adding or updating the Plugwise notifications."""
if (
Expand All @@ -116,8 +114,10 @@ def _add_or_update_notifications(
"binary_sensors" in entity
and "plugwise_notification" in entity["binary_sensors"]
):
data["binary_sensors"]["plugwise_notification"] = bool(self._notifications)
data["notifications"] = self._notifications
entity["binary_sensors"]["plugwise_notification"] = bool(
self._notifications
)
entity["notifications"] = self._notifications
self._count += 2

def _update_for_cooling(self, entity: GwEntityData) -> None:
Expand Down Expand Up @@ -154,82 +154,76 @@ def _update_for_cooling(self, entity: GwEntityData) -> None:
3 # add 4 total, remove 1, count the conditional remove separately
)

def _get_location_data(self, loc_id: str) -> GwEntityData:
def _get_location_data(self, loc_id: str, zone: GwEntityData) -> None:
"""Helper-function for _all_entity_data() and async_update().

Provide entity-data, based on Location ID (= loc_id).
"""
zone = self._zones[loc_id]
data = self._get_zone_data(loc_id)
self._regulation_control(data)
self._get_zone_data(loc_id, zone)
self._regulation_control(zone)

data["control_state"] = "idle"
zone["control_state"] = "idle"
self._count += 1
if (ctrl_state := self._control_state(data)) and ctrl_state in (
if (ctrl_state := self._control_state(zone)) and ctrl_state in (
"cooling",
"heating",
"preheating",
):
data["control_state"] = str(ctrl_state)
zone["control_state"] = str(ctrl_state)

if "setpoint" in data["sensors"]:
data["sensors"].pop("setpoint") # remove, only used in _control_state()
if "setpoint" in zone["sensors"]:
zone["sensors"].pop("setpoint") # remove, only used in _control_state()
self._count -= 1

# Thermostat data (presets, temperatures etc)
self._climate_data(loc_id, zone, data)

return data
self._climate_data(loc_id, zone)

def _get_entity_data(self, entity_id: str) -> GwEntityData:
def _get_entity_data(self, entity_id: str, entity: GwEntityData) -> None:
"""Helper-function for _update_gw_entities() and async_update().

Provide entity-data, based on appliance_id (= entity_id).
"""
entity = self.gw_entities[entity_id]
data = self._get_measurement_data(entity_id)
self._get_measurement_data(entity_id, entity)

# Check availability of wired-connected entities
# Smartmeter
self._check_availability(
entity, "smartmeter", data, "P1 does not seem to be connected"
entity, "smartmeter", "P1 does not seem to be connected"
)
# OpenTherm entity
if entity["name"] != "OnOff":
self._check_availability(
entity, "heater_central", data, "no OpenTherm communication"
entity, "heater_central", "no OpenTherm communication"
)

# Switching groups data
self._entity_switching_group(entity, data)
self._entity_switching_group(entity)
# Adam data
if self.check_name(ADAM):
self._get_adam_data(entity, data)
self._get_adam_data(entity)

# Thermostat data for Anna (presets, temperatures etc)
if self.check_name(ANNA) and entity["dev_class"] == "thermostat":
self._climate_data(entity_id, entity, data)
self._get_anna_control_state(data)

return data
self._climate_data(entity_id, entity)
self._get_anna_control_state(entity)

def _check_availability(
self, entity: GwEntityData, dev_class: str, data: GwEntityData, message: str
self, entity: GwEntityData, dev_class: str, message: str
) -> None:
"""Helper-function for _get_entity_data().

Provide availability status for the wired-connected devices.
"""
if entity["dev_class"] == dev_class:
data["available"] = True
entity["available"] = True
self._count += 1
for item in self._notifications.values():
for msg in item.values():
if message in msg:
data["available"] = False
entity["available"] = False
break

def _get_adam_data(self, entity: GwEntityData, data: GwEntityData) -> None:
def _get_adam_data(self, entity: GwEntityData) -> None:
"""Helper-function for _get_entity_data().

Determine Adam heating-status for on-off heating via valves,
Expand All @@ -239,28 +233,26 @@ def _get_adam_data(self, entity: GwEntityData, data: GwEntityData) -> None:
if entity["dev_class"] == "heater_central":
# Indicate heating_state based on valves being open in case of city-provided heating
if self._on_off_device and isinstance(self._heating_valves(), int):
data["binary_sensors"]["heating_state"] = self._heating_valves() != 0
entity["binary_sensors"]["heating_state"] = self._heating_valves() != 0
# Add cooling_enabled binary_sensor
if (
"binary_sensors" in data
and "cooling_enabled" not in data["binary_sensors"]
"binary_sensors" in entity
and "cooling_enabled" not in entity["binary_sensors"]
and self._cooling_present
):
data["binary_sensors"]["cooling_enabled"] = self._cooling_enabled
entity["binary_sensors"]["cooling_enabled"] = self._cooling_enabled
self._count += 1

# Show the allowed regulation_modes and gateway_modes
if entity["dev_class"] == "gateway":
if self._reg_allowed_modes:
data["regulation_modes"] = self._reg_allowed_modes
entity["regulation_modes"] = self._reg_allowed_modes
self._count += 1
if self._gw_allowed_modes:
data["gateway_modes"] = self._gw_allowed_modes
entity["gateway_modes"] = self._gw_allowed_modes
self._count += 1

def _climate_data(
self, location_id: str, entity: GwEntityData, data: GwEntityData
) -> None:
def _climate_data(self, location_id: str, entity: GwEntityData) -> None:
"""Helper-function for _get_entity_data().

Determine climate-control entity data.
Expand All @@ -270,38 +262,38 @@ def _climate_data(
loc_id = entity["location"]

# Presets
data["preset_modes"] = None
data["active_preset"] = None
entity["preset_modes"] = None
entity["active_preset"] = None
self._count += 2
if presets := self._presets(loc_id):
data["preset_modes"] = list(presets)
data["active_preset"] = self._preset(loc_id)
entity["preset_modes"] = list(presets)
entity["active_preset"] = self._preset(loc_id)

# Schedule
data["available_schedules"] = []
data["select_schedule"] = None
entity["available_schedules"] = []
entity["select_schedule"] = None
self._count += 2
avail_schedules, sel_schedule = self._schedules(loc_id)
if avail_schedules != [NONE]:
data["available_schedules"] = avail_schedules
data["select_schedule"] = sel_schedule
entity["available_schedules"] = avail_schedules
entity["select_schedule"] = sel_schedule

# Set HA climate HVACMode: auto, heat, heat_cool, cool and off
data["climate_mode"] = "auto"
entity["climate_mode"] = "auto"
self._count += 1
if sel_schedule in (NONE, OFF):
data["climate_mode"] = "heat"
entity["climate_mode"] = "heat"
if self._cooling_present:
data["climate_mode"] = (
entity["climate_mode"] = (
"cool" if self.check_reg_mode("cooling") else "heat_cool"
)

if self.check_reg_mode("off"):
data["climate_mode"] = "off"
entity["climate_mode"] = "off"

if NONE not in avail_schedules:
self._get_schedule_states_with_off(
loc_id, avail_schedules, sel_schedule, data
loc_id, avail_schedules, sel_schedule, entity
)

def check_reg_mode(self, mode: str) -> bool:
Expand All @@ -326,7 +318,7 @@ def _get_anna_control_state(self, data: GwEntityData) -> None:
data["control_state"] = "cooling"

def _get_schedule_states_with_off(
self, location: str, schedules: list[str], selected: str, data: GwEntityData
self, location: str, schedules: list[str], selected: str, entity: GwEntityData
) -> None:
"""Collect schedules with states for each thermostat.

Expand All @@ -335,11 +327,11 @@ def _get_schedule_states_with_off(
all_off = True
self._schedule_old_states[location] = {}
for schedule in schedules:
active: bool = schedule == selected and data["climate_mode"] == "auto"
active: bool = schedule == selected and entity["climate_mode"] == "auto"
self._schedule_old_states[location][schedule] = "off"
if active:
self._schedule_old_states[location][schedule] = "on"
all_off = False

if all_off:
data["select_schedule"] = OFF
entity["select_schedule"] = OFF
20 changes: 9 additions & 11 deletions plugwise/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,39 +305,37 @@ def _get_appliances_with_offset_functionality(self) -> list[str]:

return therm_list

def _get_zone_data(self, loc_id: str) -> GwEntityData:
def _get_zone_data(self, loc_id: str, zone: GwEntityData) -> None:
"""Helper-function for smile.py: _get_entity_data().

Collect the location-data based on location id.
Collect the location/zone-data based on location id.
"""
data: GwEntityData = {"sensors": {}}
zone = self._zones[loc_id]
measurements = ZONE_MEASUREMENTS
if (
location := self._domain_objects.find(f'./location[@id="{loc_id}"]')
) is not None:
self._appliance_measurements(location, data, measurements)
self._get_actuator_functionalities(location, zone, data)

return data
zone.update(data)

def _get_measurement_data(self, entity_id: str) -> GwEntityData:
def _get_measurement_data(self, entity_id: str, entity: GwEntityData) -> None:
"""Helper-function for smile.py: _get_entity_data().

Collect the appliance-data based on entity_id.
"""
data: GwEntityData = {"binary_sensors": {}, "sensors": {}, "switches": {}}
entity = self.gw_entities[entity_id]

# Get P1 smartmeter data from LOCATIONS
is_smartmeter = entity.get("dev_class") == "smartmeter"
smile_is_power = self.smile.type == "power"
if (smile_is_power or self.smile.anna_p1) and entity.get(
"dev_class"
) == "smartmeter":
if is_smartmeter and (smile_is_power or self.smile.anna_p1):
data.update(self._power_data_from_location())

if smile_is_power and not self.smile.anna_p1:
return data
entity.update(data)
return

# Get group data
if "members" in entity:
Expand Down Expand Up @@ -372,7 +370,7 @@ def _get_measurement_data(self, entity_id: str) -> GwEntityData:

self._cleanup_data(data)

return data
entity.update(data)

def _collect_group_sensors(
self,
Expand Down
Loading