PyViCare 2.61.0__tar.gz → 2.62.0__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.
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PKG-INFO +2 -2
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareCachedServiceBase.py +5 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareCachedServiceViaGateway.py +0 -4
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareDeviceConfig.py +5 -0
- pyvicare-2.62.0/PyViCare/PyViCareWaterTreatment.py +141 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/pyproject.toml +6 -6
- {pyvicare-2.61.0 → pyvicare-2.62.0}/LICENSE +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/Feature.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCare.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareAbstractOAuthManager.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareBrowserOAuthManager.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareCachedService.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareDevice.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareElectricalEnergySystem.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareFloorHeating.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareFuelCell.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareGateway.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareGazBoiler.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareHeatCurveCalculation.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareHeatPump.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareHeatingDevice.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareHybrid.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareOAuthManager.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareOilBoiler.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCarePelletsBoiler.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareRadiatorActuator.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareRepeater.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareRoomControl.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareRoomSensor.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareService.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareServiceViaGateway.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareUtils.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/PyViCareVentilationDevice.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/PyViCare/__init__.py +0 -0
- {pyvicare-2.61.0 → pyvicare-2.62.0}/README.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyViCare
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.62.0
|
|
4
4
|
Summary: Library to communicate with the Viessmann ViCare API.
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -22,7 +22,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.14
|
|
23
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
24
|
Requires-Dist: authlib (>1.2.0)
|
|
25
|
-
Requires-Dist: deprecated (>=1.
|
|
25
|
+
Requires-Dist: deprecated (>=1.3.0,<2.0.0)
|
|
26
26
|
Requires-Dist: requests (>=2.31.0)
|
|
27
27
|
Project-URL: Bug Tracker, https://github.com/openviess/PyViCare/issues
|
|
28
28
|
Project-URL: Changelog, https://github.com/openviess/PyViCare/releases
|
|
@@ -34,6 +34,11 @@ class ViCareCachedServiceBase(ViCareService):
|
|
|
34
34
|
entities = self._extract_entities(data, accessor)
|
|
35
35
|
return readFeature(entities, property_name)
|
|
36
36
|
|
|
37
|
+
def fetch_all_features(self, accessor: ViCareDeviceAccessor) -> Any:
|
|
38
|
+
# cached, so a caller refreshing with fetch_all_features() warms the
|
|
39
|
+
# cache the following getProperty calls read from
|
|
40
|
+
return self._get_or_update_cache(accessor)
|
|
41
|
+
|
|
37
42
|
def setProperty(self, accessor: ViCareDeviceAccessor, property_name: str, action: str, data: Any) -> Any:
|
|
38
43
|
response = super().setProperty(accessor, property_name, action, data)
|
|
39
44
|
self.clear_cache()
|
|
@@ -28,7 +28,3 @@ class ViCareCachedServiceViaGateway(ViCareCachedServiceBase, ViCareServiceViaGat
|
|
|
28
28
|
|
|
29
29
|
def _extract_entities(self, data: dict, accessor: ViCareDeviceAccessor) -> list[dict[str, Any]]:
|
|
30
30
|
return filter_features_for_device(data["data"], accessor.device_id)
|
|
31
|
-
|
|
32
|
-
def fetch_all_features(self, accessor: ViCareDeviceAccessor) -> Any:
|
|
33
|
-
# cached too, so per-device coordinators share one bulk fetch
|
|
34
|
-
return self._get_or_update_cache(accessor)
|
|
@@ -20,6 +20,7 @@ from PyViCare.PyViCareService import (ViCareDeviceAccessor, ViCareService,
|
|
|
20
20
|
hasRoles, is_gateway_role)
|
|
21
21
|
from PyViCare.PyViCareUtils import PyViCareNotPaidForError
|
|
22
22
|
from PyViCare.PyViCareVentilationDevice import VentilationDevice
|
|
23
|
+
from PyViCare.PyViCareWaterTreatment import WaterTreatment
|
|
23
24
|
|
|
24
25
|
logger = logging.getLogger(__name__)
|
|
25
26
|
logger.addHandler(logging.NullHandler())
|
|
@@ -84,6 +85,9 @@ class PyViCareDeviceConfig:
|
|
|
84
85
|
def asVentilation(self):
|
|
85
86
|
return VentilationDevice(self.accessor, self.service, self.roles)
|
|
86
87
|
|
|
88
|
+
def asWaterTreatment(self):
|
|
89
|
+
return WaterTreatment(self.accessor, self.service, self.roles)
|
|
90
|
+
|
|
87
91
|
def getConfig(self):
|
|
88
92
|
return self.accessor
|
|
89
93
|
|
|
@@ -127,6 +131,7 @@ class PyViCareDeviceConfig:
|
|
|
127
131
|
(self.asRoomControl, r"E3_RoomControl|Smart_RoomControl", ["type:virtual;smartRoomControl"]),
|
|
128
132
|
(self.asRoomSensor, r"E3_RoomSensor", ["type:climateSensor"]),
|
|
129
133
|
(self.asRepeater, r"E3_Repeater", ["type:repeater"]),
|
|
134
|
+
(self.asWaterTreatment, r"VitosetAqua", ["type:waterTreatment"]),
|
|
130
135
|
(self.asGateway, r"E3_TCU41_x04", ["type:gateway;TCU100"]),
|
|
131
136
|
(self.asGateway, r"E3_TCU19_x05", ["type:gateway;TCU200"]),
|
|
132
137
|
(self.asGateway, r"E3_TCU10_x07", ["type:gateway;TCU300"]),
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from contextlib import suppress
|
|
2
|
+
from typing import Any, List, Optional
|
|
3
|
+
|
|
4
|
+
from PyViCare.PyViCareDevice import Device
|
|
5
|
+
from PyViCare.PyViCareUtils import PyViCareNotSupportedFeatureError, handleNotSupported
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
_LEAK_SENSOR_SLOTS = 5
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class WaterTreatment(Device):
|
|
12
|
+
"""Viessmann Vitoset Aqua water treatment station.
|
|
13
|
+
|
|
14
|
+
Combines water softener, leak detection (up to 5 sensors), consumption metering
|
|
15
|
+
and main shutoff valve in one device.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
# --- Softener ---
|
|
19
|
+
|
|
20
|
+
@handleNotSupported
|
|
21
|
+
def getSaltDaysRemaining(self) -> int:
|
|
22
|
+
return int(self.getProperty("water.softener.salt.level.days")["properties"]["remaining"]["value"])
|
|
23
|
+
|
|
24
|
+
@handleNotSupported
|
|
25
|
+
def getLowSaltAlertDays(self) -> int:
|
|
26
|
+
return int(self.getProperty("water.softener.configuration.lowSaltAlert")["properties"]["lowLevelAlertDays"]["value"])
|
|
27
|
+
|
|
28
|
+
# --- Consumption ---
|
|
29
|
+
|
|
30
|
+
@handleNotSupported
|
|
31
|
+
def getCurrentFlow(self) -> float:
|
|
32
|
+
return float(self.getProperty("water.consumption.flow.current")["properties"]["value"]["value"])
|
|
33
|
+
|
|
34
|
+
@handleNotSupported
|
|
35
|
+
def getMaxFlow(self) -> float:
|
|
36
|
+
return float(self.getProperty("water.consumption.flow.max")["properties"]["value"]["value"])
|
|
37
|
+
|
|
38
|
+
@handleNotSupported
|
|
39
|
+
def getTotalConsumption(self) -> int:
|
|
40
|
+
return int(self.getProperty("water.consumption.summary")["properties"]["total"]["value"])
|
|
41
|
+
|
|
42
|
+
# --- Leak Detection ---
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def leakSensors(self) -> List["LeakSensor"]:
|
|
46
|
+
return [LeakSensor(self, slot) for slot in self.getAvailableLeakSensorSlots()]
|
|
47
|
+
|
|
48
|
+
def getAvailableLeakSensorSlots(self) -> List[int]:
|
|
49
|
+
available: List[int] = []
|
|
50
|
+
for slot in range(_LEAK_SENSOR_SLOTS):
|
|
51
|
+
with suppress(PyViCareNotSupportedFeatureError):
|
|
52
|
+
feature = self.getProperty(f"water.leakDetection.sensors.leakage.{slot}")
|
|
53
|
+
if feature.get("isEnabled"):
|
|
54
|
+
available.append(slot)
|
|
55
|
+
return available
|
|
56
|
+
|
|
57
|
+
@handleNotSupported
|
|
58
|
+
def getFlowAlertMaxDuration(self) -> int:
|
|
59
|
+
return int(self.getProperty("water.leakDetection.configuration.flowAlert")["properties"]["maxDuration"]["value"])
|
|
60
|
+
|
|
61
|
+
@handleNotSupported
|
|
62
|
+
def getFlowAlertMaxFlow(self) -> float:
|
|
63
|
+
return float(self.getProperty("water.leakDetection.configuration.flowAlert")["properties"]["maxFlow"]["value"])
|
|
64
|
+
|
|
65
|
+
# --- Shutoff Valve ---
|
|
66
|
+
|
|
67
|
+
@handleNotSupported
|
|
68
|
+
def getShutoffPosition(self) -> str:
|
|
69
|
+
return str(self.getProperty("water.valves.shutoff.position")["properties"]["value"]["value"])
|
|
70
|
+
|
|
71
|
+
@handleNotSupported
|
|
72
|
+
def getShutoffMotorState(self) -> str:
|
|
73
|
+
return str(self.getProperty("water.valves.shutoff.motor")["properties"]["state"]["value"])
|
|
74
|
+
|
|
75
|
+
@handleNotSupported
|
|
76
|
+
def getHolidayModeActive(self) -> bool:
|
|
77
|
+
return bool(self.getProperty("water.valves.shutoff.holiday")["properties"]["active"]["value"])
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class LeakSensor:
|
|
81
|
+
"""Single wireless leakage sensor connected to a Vitoset Aqua."""
|
|
82
|
+
|
|
83
|
+
def __init__(self, device: WaterTreatment, slot: int) -> None:
|
|
84
|
+
self.service = device.service
|
|
85
|
+
self.slot = slot
|
|
86
|
+
self.device = device
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def id(self) -> int:
|
|
90
|
+
return self.slot
|
|
91
|
+
|
|
92
|
+
def getProperty(self, property_name: str) -> Any:
|
|
93
|
+
return self.device.getProperty(property_name)
|
|
94
|
+
|
|
95
|
+
@handleNotSupported
|
|
96
|
+
def getStatus(self) -> str:
|
|
97
|
+
return str(self.getProperty(f"water.leakDetection.sensors.leakage.{self.slot}")["properties"]["status"]["value"])
|
|
98
|
+
|
|
99
|
+
@handleNotSupported
|
|
100
|
+
def getLeakDetected(self) -> bool:
|
|
101
|
+
return bool(self.getProperty(f"water.leakDetection.sensors.leakage.{self.slot}")["properties"]["value"]["value"])
|
|
102
|
+
|
|
103
|
+
@handleNotSupported
|
|
104
|
+
def getSensorId(self) -> str:
|
|
105
|
+
return str(self.getProperty(f"water.leakDetection.sensors.leakage.{self.slot}.id")["properties"]["value"]["value"])
|
|
106
|
+
|
|
107
|
+
@handleNotSupported
|
|
108
|
+
def getName(self) -> str:
|
|
109
|
+
return str(self.getProperty(f"water.leakDetection.sensors.leakage.{self.slot}.name")["properties"]["name"]["value"])
|
|
110
|
+
|
|
111
|
+
@handleNotSupported
|
|
112
|
+
def getBatteryPercent(self) -> int:
|
|
113
|
+
return int(self.getProperty(f"water.leakDetection.sensors.leakage.{self.slot}.battery")["properties"]["level"]["value"])
|
|
114
|
+
|
|
115
|
+
@handleNotSupported
|
|
116
|
+
def getRssi(self) -> int:
|
|
117
|
+
return int(self.getProperty(f"water.leakDetection.sensors.leakage.{self.slot}.rssi")["properties"]["value"]["value"])
|
|
118
|
+
|
|
119
|
+
def getHardwareVersion(self) -> Optional[dict[str, int]]:
|
|
120
|
+
try:
|
|
121
|
+
feature = self.getProperty(f"water.leakDetection.sensors.leakage.{self.slot}.version.hardware")
|
|
122
|
+
except PyViCareNotSupportedFeatureError:
|
|
123
|
+
return None
|
|
124
|
+
return self._versionFields(feature.get("properties") or {})
|
|
125
|
+
|
|
126
|
+
def getSoftwareVersion(self) -> Optional[dict[str, int]]:
|
|
127
|
+
try:
|
|
128
|
+
feature = self.getProperty(f"water.leakDetection.sensors.leakage.{self.slot}.version.software")
|
|
129
|
+
except PyViCareNotSupportedFeatureError:
|
|
130
|
+
return None
|
|
131
|
+
return self._versionFields(feature.get("properties") or {})
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def _versionFields(props: dict[str, Any]) -> Optional[dict[str, int]]:
|
|
135
|
+
if not props:
|
|
136
|
+
return None
|
|
137
|
+
return {
|
|
138
|
+
field: int(props[field]["value"])
|
|
139
|
+
for field in ("build", "family", "revision", "version")
|
|
140
|
+
if field in props
|
|
141
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "PyViCare"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.62.0"
|
|
4
4
|
description = "Library to communicate with the Viessmann ViCare API."
|
|
5
5
|
authors = [
|
|
6
6
|
"Simon Gillet <mail+pyvicare@gillet.ninja>"
|
|
@@ -45,15 +45,15 @@ Changelog = "https://github.com/openviess/PyViCare/releases"
|
|
|
45
45
|
authlib = ">1.2.0"
|
|
46
46
|
python = "^3.10"
|
|
47
47
|
requests = ">=2.31.0"
|
|
48
|
-
deprecated = "^1.
|
|
48
|
+
deprecated = "^1.3.0"
|
|
49
49
|
|
|
50
50
|
[tool.poetry.group.dev.dependencies]
|
|
51
|
-
codespell = "2.4.
|
|
52
|
-
mypy = "2.3.
|
|
53
|
-
pylint = "4.0.
|
|
51
|
+
codespell = "2.4.3"
|
|
52
|
+
mypy = "2.3.1"
|
|
53
|
+
pylint = "4.0.7"
|
|
54
54
|
pytest = "9.1.1"
|
|
55
55
|
pytest-cov = "7.1.0"
|
|
56
|
-
ruff = "0.15.
|
|
56
|
+
ruff = "0.15.22"
|
|
57
57
|
types-deprecated = "^1.2.15.20241117"
|
|
58
58
|
types-requests = ">=2.31"
|
|
59
59
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|