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

Implement limited access to gateway modes for Adam #486

Merged
merged 13 commits into from
Dec 27, 2023
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Changelog

## Ongoing
## v0.36.0

- New Feature: For Adam, implement limited access to the gateway-modes.
- Refresh adam_plus_anna_new userdata and adapt.
- Bump actions and requirements to Python 3.12.
- Ruff as per #470 (defaulting black and isort to ruff).
Expand Down
4 changes: 3 additions & 1 deletion fixtures/adam_heatpump_cooling/all_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@
},
"dev_class": "gateway",
"firmware": "3.2.8",
"gateway_modes": ["away", "full", "vacation"],
"hardware": "AME Smile 2.0 board",
"location": "eedadcb297564f1483faa509179aebed",
"mac_address": "012345670001",
Expand All @@ -228,6 +229,7 @@
"bleeding_hot",
"cooling"
],
"select_gateway_mode": "full",
"select_regulation_mode": "cooling",
"sensors": {
"outdoor_temperature": 13.4
Expand Down Expand Up @@ -630,7 +632,7 @@
"cooling_present": true,
"gateway_id": "7d97fc3117784cfdafe347bcedcbbbcb",
"heater_id": "0ca13e8176204ca7bf6f09de59f81c83",
"item_count": 413,
"item_count": 415,
"notifications": {},
"smile_name": "Adam"
}
Expand Down
4 changes: 3 additions & 1 deletion fixtures/adam_jip/all_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,14 @@
},
"dev_class": "gateway",
"firmware": "3.2.8",
"gateway_modes": ["away", "full", "vacation"],
"hardware": "AME Smile 2.0 board",
"location": "9e4433a9d69f40b3aefd15e74395eaec",
"mac_address": "012345670001",
"model": "Gateway",
"name": "Adam",
"regulation_modes": ["heating", "off", "bleeding_cold", "bleeding_hot"],
"select_gateway_mode": "full",
"select_regulation_mode": "heating",
"sensors": {
"outdoor_temperature": 24.9
Expand Down Expand Up @@ -304,7 +306,7 @@
"cooling_present": false,
"gateway_id": "b5c2386c6f6342669e50fe49dd05b188",
"heater_id": "e4684553153b44afbef2200885f379dc",
"item_count": 219,
"item_count": 221,
"notifications": {},
"smile_name": "Adam"
}
Expand Down
4 changes: 3 additions & 1 deletion fixtures/adam_onoff_cooling_fake_firmware/all_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
},
"dev_class": "gateway",
"firmware": "3.2.8",
"gateway_modes": ["away", "full", "vacation"],
"hardware": "AME Smile 2.0 board",
"location": "eedadcb297564f1483faa509179aebed",
"mac_address": "012345670001",
Expand All @@ -54,6 +55,7 @@
"bleeding_hot",
"cooling"
],
"select_gateway_mode": "full",
"select_regulation_mode": "cooling",
"sensors": {
"outdoor_temperature": 13.4
Expand Down Expand Up @@ -94,7 +96,7 @@
"cooling_present": true,
"gateway_id": "7d97fc3117784cfdafe347bcedcbbbcb",
"heater_id": "0ca13e8176204ca7bf6f09de59f81c83",
"item_count": 54,
"item_count": 56,
"notifications": {},
"smile_name": "Adam"
}
Expand Down
4 changes: 3 additions & 1 deletion fixtures/adam_plus_anna_new/all_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,14 @@
},
"dev_class": "gateway",
"firmware": "3.7.8",
"gateway_modes": ["away", "full", "vacation"],
"hardware": "AME Smile 2.0 board",
"location": "bc93488efab249e5bc54fd7e175a6f91",
"mac_address": "012345679891",
"model": "Gateway",
"name": "Adam",
"regulation_modes": ["bleeding_hot", "bleeding_cold", "off", "heating"],
"select_gateway_mode": "full",
"select_regulation_mode": "heating",
"sensors": {
"outdoor_temperature": 9.19
Expand Down Expand Up @@ -229,7 +231,7 @@
"cooling_present": false,
"gateway_id": "da224107914542988a88561b4452b0f6",
"heater_id": "056ee145a816487eaa69243c3280f8bf",
"item_count": 145,
"item_count": 147,
"notifications": {},
"smile_name": "Adam"
}
Expand Down
4 changes: 3 additions & 1 deletion fixtures/m_adam_cooling/all_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
},
"dev_class": "gateway",
"firmware": "3.7.8",
"gateway_modes": ["away", "full", "vacation"],
"hardware": "AME Smile 2.0 board",
"location": "bc93488efab249e5bc54fd7e175a6f91",
"mac_address": "012345679891",
Expand All @@ -98,6 +99,7 @@
"heating",
"cooling"
],
"select_gateway_mode": "full",
"select_regulation_mode": "cooling",
"sensors": {
"outdoor_temperature": 29.65
Expand Down Expand Up @@ -162,7 +164,7 @@
"cooling_present": true,
"gateway_id": "da224107914542988a88561b4452b0f6",
"heater_id": "056ee145a816487eaa69243c3280f8bf",
"item_count": 145,
"item_count": 147,
"notifications": {},
"smile_name": "Adam"
}
Expand Down
4 changes: 3 additions & 1 deletion fixtures/m_adam_heating/all_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,14 @@
},
"dev_class": "gateway",
"firmware": "3.7.8",
"gateway_modes": ["away", "full", "vacation"],
"hardware": "AME Smile 2.0 board",
"location": "bc93488efab249e5bc54fd7e175a6f91",
"mac_address": "012345679891",
"model": "Gateway",
"name": "Adam",
"regulation_modes": ["bleeding_hot", "bleeding_cold", "off", "heating"],
"select_gateway_mode": "full",
"select_regulation_mode": "heating",
"sensors": {
"outdoor_temperature": -1.25
Expand Down Expand Up @@ -184,7 +186,7 @@
"cooling_present": false,
"gateway_id": "da224107914542988a88561b4452b0f6",
"heater_id": "056ee145a816487eaa69243c3280f8bf",
"item_count": 145,
"item_count": 147,
"notifications": {},
"smile_name": "Adam"
}
Expand Down
4 changes: 3 additions & 1 deletion fixtures/m_adam_jip/all_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,14 @@
},
"dev_class": "gateway",
"firmware": "3.2.8",
"gateway_modes": ["away", "full", "vacation"],
"hardware": "AME Smile 2.0 board",
"location": "9e4433a9d69f40b3aefd15e74395eaec",
"mac_address": "012345670001",
"model": "Gateway",
"name": "Adam",
"regulation_modes": ["heating", "off", "bleeding_cold", "bleeding_hot"],
"select_gateway_mode": "full",
"select_regulation_mode": "heating",
"sensors": {
"outdoor_temperature": 24.9
Expand Down Expand Up @@ -304,7 +306,7 @@
"cooling_present": false,
"gateway_id": "b5c2386c6f6342669e50fe49dd05b188",
"heater_id": "e4684553153b44afbef2200885f379dc",
"item_count": 219,
"item_count": 221,
"notifications": {},
"smile_name": "Adam"
}
Expand Down
35 changes: 31 additions & 4 deletions plugwise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,14 @@ def _device_data_adam(self, device: DeviceData, data: DeviceData) -> None:
):
data["binary_sensors"]["heating_state"] = self._heating_valves() != 0

# Show the allowed regulation modes for Adam
if device["dev_class"] == "gateway" and self._reg_allowed_modes:
data["regulation_modes"] = self._reg_allowed_modes
self._count += 1
# Show the allowed regulation modes and gateway_modes
if device["dev_class"] == "gateway":
if self._reg_allowed_modes:
data["regulation_modes"] = self._reg_allowed_modes
self._count += 1
if self._gw_allowed_modes:
data["gateway_modes"] = self._gw_allowed_modes
self._count += 1

# Control_state, only for Adam master thermostats
if device["dev_class"] in ZONE_THERMOSTATS:
Expand Down Expand Up @@ -862,6 +866,29 @@ async def set_switch_state(

await self._request(uri, method="put", data=data)

async def set_gateway_mode(self, mode: str) -> None:
"""Set the gateway mode."""
if mode not in self._gw_allowed_modes:
raise PlugwiseError("Plugwise: invalid gateway mode.")

time_1 = dt.datetime.now(dt.UTC)
away_time = time_1.isoformat(timespec="milliseconds") + "Z"
time_2 = str(dt.date.today() - dt.timedelta(1))
vacation_time = time_2 + "T23:00:00.000Z"
end_time = "2037-04-21T08:00:53.000Z"
valid = ""
if mode == "away":
bouwew marked this conversation as resolved.
Show resolved Hide resolved
valid = (
f"<valid_from>{away_time}</valid_from><valid_to>{end_time}</valid_to>"
)
if mode == "vacation":
valid = f"<valid_from>{vacation_time}</valid_from><valid_to>{end_time}</valid_to>"

uri = f"{APPLIANCES};type=gateway/gateway_mode_control"
data = f"<gateway_mode_control_functionality><mode>{mode}</mode>{valid}</gateway_mode_control_functionality>"

await self._request(uri, method="put", data=data)

async def set_regulation_mode(self, mode: str) -> None:
"""Set the heating regulation mode."""
if mode not in self._reg_allowed_modes:
Expand Down
4 changes: 3 additions & 1 deletion plugwise/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,8 +519,10 @@ class DeviceData(TypedDict, total=False):
dhw_modes: list[str]

# Gateway
select_regulation_mode: str
gateway_modes: list[str]
regulation_modes: list[str]
select_gateway_mode: str
select_regulation_mode: str

# Master Thermostats
# Presets:
Expand Down
25 changes: 22 additions & 3 deletions plugwise/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ def __init__(self) -> None:
self._dhw_allowed_modes: list[str] = []
self._domain_objects: etree
self._elga = False
self._gw_allowed_modes: list[str] = []
self._heater_id: str
self._home_location: str
self._is_thermostat = False
Expand Down Expand Up @@ -423,7 +424,7 @@ def _appliance_info_finder(self, appliance: etree, appl: Munch) -> Munch:
):
appl.zigbee_mac = found.find("mac_address").text

# Adam: collect modes and check for cooling, indicating cooling-mode is present
# Adam: collect regulation_modes and check for cooling, indicating cooling-mode is present
reg_mode_list: list[str] = []
locator = "./actuator_functionalities/regulation_mode_control_functionality"
if (search := appliance.find(locator)) is not None:
Expand All @@ -434,6 +435,13 @@ def _appliance_info_finder(self, appliance: etree, appl: Munch) -> Munch:
self._cooling_present = True
self._reg_allowed_modes = reg_mode_list

# Adam: check for presence of gateway_modes
self._gw_allowed_modes = []
locator = "./actuator_functionalities/gateway_mode_control_functionality[type='gateway_mode']/allowed_modes"
if appliance.find(locator) is not None:
# Limit the possible gateway-modes
self._gw_allowed_modes = ["away", "full", "vacation"]

return appl

# Collect thermostat device info
Expand Down Expand Up @@ -971,6 +979,16 @@ def _get_regulation_mode(self, appliance: etree, data: DeviceData) -> None:
self._count += 1
self._cooling_enabled = data["select_regulation_mode"] == "cooling"

def _get_gateway_mode(self, appliance: etree, data: DeviceData) -> None:
"""Helper-function for _get_measurement_data().

Collect the gateway mode.
"""
locator = "./actuator_functionalities/gateway_mode_control_functionality"
if (search := appliance.find(locator)) is not None:
data["select_gateway_mode"] = search.find("mode").text
self._count += 1

def _cleanup_data(self, data: DeviceData) -> None:
"""Helper-function for _get_measurement_data().

Expand Down Expand Up @@ -1059,8 +1077,9 @@ def _get_measurement_data(self, dev_id: str) -> DeviceData:
# Collect availability-status for wireless connected devices to Adam
self._wireless_availablity(appliance, data)

if dev_id == self.gateway_id and self.smile(ADAM):
self._get_regulation_mode(appliance, data)
if dev_id == self.gateway_id and self.smile(ADAM):
self._get_regulation_mode(appliance, data)
self._get_gateway_mode(appliance, data)

# Adam & Anna: the Smile outdoor_temperature is present in DOMAIN_OBJECTS and LOCATIONS - under Home
# The outdoor_temperature present in APPLIANCES is a local sensor connected to the active device
Expand Down
2 changes: 2 additions & 0 deletions tests/data/adam/adam_heatpump_cooling.json
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,13 @@
},
"dev_class": "gateway",
"firmware": "3.2.8",
"gateway_modes": ["away", "full", "vacation"],
"hardware": "AME Smile 2.0 board",
"location": "eedadcb297564f1483faa509179aebed",
"mac_address": "012345670001",
"model": "Gateway",
"name": "Adam",
"select_gateway_mode": "full",
"select_regulation_mode": "cooling",
"regulation_modes": [
"heating",
Expand Down
2 changes: 2 additions & 0 deletions tests/data/adam/adam_jip.json
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,15 @@
"b5c2386c6f6342669e50fe49dd05b188": {
"dev_class": "gateway",
"firmware": "3.2.8",
"gateway_modes": ["away", "full", "vacation"],
"hardware": "AME Smile 2.0 board",
"location": "9e4433a9d69f40b3aefd15e74395eaec",
"mac_address": "012345670001",
"model": "Gateway",
"name": "Adam",
"zigbee_mac_address": "ABCD012345670101",
"vendor": "Plugwise",
"select_gateway_mode": "full",
"select_regulation_mode": "heating",
"regulation_modes": ["heating", "off", "bleeding_cold", "bleeding_hot"],
"binary_sensors": {
Expand Down
4 changes: 3 additions & 1 deletion tests/data/adam/adam_plus_anna_new.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
"outdoor_temperature": 9.19
},
"select_regulation_mode": "heating",
"regulation_modes": ["bleeding_hot", "bleeding_cold", "off", "heating"]
"regulation_modes": ["bleeding_hot", "bleeding_cold", "off", "heating"],
"gateway_modes": ["away", "full", "vacation"],
"select_gateway_mode": "full"
},
"056ee145a816487eaa69243c3280f8bf": {
"dev_class": "heater_central",
Expand Down
10 changes: 5 additions & 5 deletions tests/test_adam.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ async def test_adam_heatpump_cooling(self):
assert smile._last_active["a562019b0b1f47a4bde8ebe3dbe3e8a9"] == WERKDAG_SCHEMA
assert smile._last_active["8cf650a4c10c44819e426bed406aec34"] == WERKDAG_SCHEMA
assert smile._last_active["5cc21042f87f4b4c94ccb5537c47a53f"] == WERKDAG_SCHEMA
assert smile.device_items == 413
assert smile.device_items == 415

await smile.close_connection()
await self.disconnect(server, client)
Expand All @@ -167,7 +167,7 @@ async def test_connect_adam_onoff_cooling_fake_firmware(self):
)

await self.device_test(smile, "2022-01-02 00:00:01", testdata)
assert smile.device_items == 54
assert smile.device_items == 56
assert smile._cooling_present
assert smile._cooling_enabled

Expand Down Expand Up @@ -270,7 +270,7 @@ async def test_connect_adam_plus_anna_new(self):
assert smile.gateway_id == "da224107914542988a88561b4452b0f6"
assert smile._last_active["f2bf9048bef64cc5b6d5110154e33c81"] == "Weekschema"
assert smile._last_active["f871b8c4d63549319221e294e4f88074"] == "Badkamer"
assert smile.device_items == 145
assert smile.device_items == 147
assert smile.device_list == [
"da224107914542988a88561b4452b0f6",
"056ee145a816487eaa69243c3280f8bf",
Expand Down Expand Up @@ -345,8 +345,8 @@ async def test_connect_adam_plus_anna_new(self):
)
assert not switch_change

await self.tinker_gateway_mode(smile)
await self.tinker_regulation_mode(smile)

await self.tinker_max_boiler_temp(smile)

# Now change some data and change directory reading xml from
Expand Down Expand Up @@ -376,7 +376,7 @@ async def test_adam_plus_jip(self):
assert smile._last_active["06aecb3d00354375924f50c47af36bd2"] is None
assert smile._last_active["d27aede973b54be484f6842d1b2802ad"] is None
assert smile._last_active["13228dab8ce04617af318a2888b3c548"] is None
assert smile.device_items == 219
assert smile.device_items == 221

# Negative test
result = await self.tinker_thermostat(
Expand Down
Loading
Loading