PyViCare 2.55.1__tar.gz → 2.57.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.55.1 → pyvicare-2.57.0}/PKG-INFO +1 -1
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCare.py +1 -1
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareAbstractOAuthManager.py +6 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareCachedService.py +13 -3
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareDeviceConfig.py +29 -4
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareFuelCell.py +16 -16
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareGateway.py +2 -2
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareHeatPump.py +83 -1
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareHeatingDevice.py +14 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareUtils.py +12 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareVentilationDevice.py +20 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/pyproject.toml +3 -2
- {pyvicare-2.55.1 → pyvicare-2.57.0}/LICENSE +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/Feature.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareBrowserOAuthManager.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareDevice.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareElectricalEnergySystem.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareFloorHeating.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareGazBoiler.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareHeatCurveCalculation.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareHybrid.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareOAuthManager.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareOilBoiler.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCarePelletsBoiler.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareRadiatorActuator.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareRepeater.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareRoomSensor.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/PyViCareService.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/PyViCare/__init__.py +0 -0
- {pyvicare-2.55.1 → pyvicare-2.57.0}/README.md +0 -0
|
@@ -61,7 +61,7 @@ class PyViCare:
|
|
|
61
61
|
|
|
62
62
|
logger.info("Device found: %s", device.modelId)
|
|
63
63
|
|
|
64
|
-
yield PyViCareDeviceConfig(service, device.id, device.modelId, device.status)
|
|
64
|
+
yield PyViCareDeviceConfig(service, device.id, device.modelId, device.status, device.deviceType, device.roles)
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
class DictWrap(object):
|
|
@@ -7,6 +7,7 @@ from authlib.integrations.requests_client import OAuth2Session
|
|
|
7
7
|
|
|
8
8
|
from PyViCare import Feature
|
|
9
9
|
from PyViCare.PyViCareUtils import (PyViCareCommandError,
|
|
10
|
+
PyViCareDeviceCommunicationError,
|
|
10
11
|
PyViCareInternalServerError,
|
|
11
12
|
PyViCareRateLimitError)
|
|
12
13
|
|
|
@@ -39,6 +40,7 @@ class AbstractViCareOAuthManager:
|
|
|
39
40
|
logger.debug("Response to get request: %s", response)
|
|
40
41
|
self.__handle_expired_token(response)
|
|
41
42
|
self.__handle_rate_limit(response)
|
|
43
|
+
self.__handle_device_communication_error(response)
|
|
42
44
|
self.__handle_server_error(response)
|
|
43
45
|
return response
|
|
44
46
|
except TokenExpiredError:
|
|
@@ -59,6 +61,10 @@ class AbstractViCareOAuthManager:
|
|
|
59
61
|
if ("statusCode" in response and response["statusCode"] == 429):
|
|
60
62
|
raise PyViCareRateLimitError(response)
|
|
61
63
|
|
|
64
|
+
def __handle_device_communication_error(self, response):
|
|
65
|
+
if ("errorType" in response and response["errorType"] == "DEVICE_COMMUNICATION_ERROR"):
|
|
66
|
+
raise PyViCareDeviceCommunicationError(response)
|
|
67
|
+
|
|
62
68
|
def __handle_server_error(self, response):
|
|
63
69
|
if ("statusCode" in response and response["statusCode"] >= 500):
|
|
64
70
|
raise PyViCareInternalServerError(response)
|
|
@@ -5,7 +5,10 @@ from typing import Any, List
|
|
|
5
5
|
from PyViCare.PyViCareAbstractOAuthManager import AbstractViCareOAuthManager
|
|
6
6
|
from PyViCare.PyViCareService import (ViCareDeviceAccessor, ViCareService,
|
|
7
7
|
readFeature)
|
|
8
|
-
from PyViCare.PyViCareUtils import
|
|
8
|
+
from PyViCare.PyViCareUtils import (PyViCareDeviceCommunicationError,
|
|
9
|
+
PyViCareInvalidDataError,
|
|
10
|
+
PyViCareInternalServerError,
|
|
11
|
+
ViCareTimer)
|
|
9
12
|
|
|
10
13
|
logger = logging.getLogger('ViCare')
|
|
11
14
|
logger.addHandler(logging.NullHandler())
|
|
@@ -33,13 +36,20 @@ class ViCareCachedService(ViCareService):
|
|
|
33
36
|
def __get_or_update_cache(self):
|
|
34
37
|
with self.__lock:
|
|
35
38
|
if self.is_cache_invalid():
|
|
36
|
-
# we always
|
|
39
|
+
# we always set the cache time before we fetch the data
|
|
37
40
|
# to avoid consuming all the api calls if the api is down
|
|
38
41
|
# see https://github.com/home-assistant/core/issues/67052
|
|
39
42
|
# we simply return the old cache in this case
|
|
40
43
|
self.__cacheTime = ViCareTimer().now()
|
|
41
44
|
|
|
42
|
-
|
|
45
|
+
try:
|
|
46
|
+
data = self.fetch_all_features()
|
|
47
|
+
except (PyViCareDeviceCommunicationError, PyViCareInternalServerError) as e:
|
|
48
|
+
if self.__cache is not None:
|
|
49
|
+
logger.warning("API error, returning stale cache: %s", e)
|
|
50
|
+
return self.__cache
|
|
51
|
+
raise
|
|
52
|
+
|
|
43
53
|
if "data" not in data:
|
|
44
54
|
logger.error("Missing 'data' property when fetching data.")
|
|
45
55
|
raise PyViCareInvalidDataError(data)
|
|
@@ -22,11 +22,14 @@ logger.addHandler(logging.NullHandler())
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class PyViCareDeviceConfig:
|
|
25
|
-
|
|
25
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
|
26
|
+
def __init__(self, service, device_id, device_model, status, device_type=None, roles=None):
|
|
26
27
|
self.service = service
|
|
27
28
|
self.device_id = device_id
|
|
28
29
|
self.device_model = device_model
|
|
29
30
|
self.status = status
|
|
31
|
+
self.device_type = device_type
|
|
32
|
+
self.roles = roles if roles is not None else []
|
|
30
33
|
|
|
31
34
|
def asGeneric(self):
|
|
32
35
|
return HeatingDevice(self.service)
|
|
@@ -85,6 +88,15 @@ class PyViCareDeviceConfig:
|
|
|
85
88
|
def isOnline(self):
|
|
86
89
|
return self.status == "Online"
|
|
87
90
|
|
|
91
|
+
def getDeviceType(self):
|
|
92
|
+
return self.device_type
|
|
93
|
+
|
|
94
|
+
def getRoles(self):
|
|
95
|
+
return self.roles
|
|
96
|
+
|
|
97
|
+
def isGateway(self):
|
|
98
|
+
return self.service._isGateway() # pylint: disable=protected-access
|
|
99
|
+
|
|
88
100
|
# see: https://vitodata300.viessmann.com/vd300/ApplicationHelp/VD300/1031_de_DE/Ger%C3%A4teliste.html
|
|
89
101
|
def asAutoDetectDevice(self):
|
|
90
102
|
device_types = [
|
|
@@ -122,12 +134,25 @@ class PyViCareDeviceConfig:
|
|
|
122
134
|
return self.service.fetch_all_features()
|
|
123
135
|
|
|
124
136
|
def dump_secure(self, flat=False):
|
|
137
|
+
raw_data = self.get_raw_json()
|
|
138
|
+
device_info = {
|
|
139
|
+
"id": self.device_id,
|
|
140
|
+
"modelId": self.device_model,
|
|
141
|
+
"type": self.device_type,
|
|
142
|
+
"status": self.status,
|
|
143
|
+
"roles": self.roles
|
|
144
|
+
}
|
|
145
|
+
output = {
|
|
146
|
+
"device": device_info,
|
|
147
|
+
"data": raw_data['data']
|
|
148
|
+
}
|
|
149
|
+
|
|
125
150
|
if flat:
|
|
126
|
-
inner = ',\n'.join([json.dumps(x, sort_keys=True) for x in
|
|
127
|
-
outer = json.dumps({'data': ['placeholder']}, indent=0)
|
|
151
|
+
inner = ',\n'.join([json.dumps(x, sort_keys=True) for x in output['data']])
|
|
152
|
+
outer = json.dumps({'device': output['device'], 'data': ['placeholder']}, indent=0, sort_keys=True)
|
|
128
153
|
dumpJSON = outer.replace('"placeholder"', inner)
|
|
129
154
|
else:
|
|
130
|
-
dumpJSON = json.dumps(
|
|
155
|
+
dumpJSON = json.dumps(output, indent=4, sort_keys=True)
|
|
131
156
|
|
|
132
157
|
def repl(m):
|
|
133
158
|
return m.group(1) + ('#' * len(m.group(2))) + m.group(3)
|
|
@@ -192,9 +192,9 @@ class FuelCell(HeatingDevice):
|
|
|
192
192
|
return self.getProperty("heating.fuelCell.power.production")["properties"]["year"]["value"][0]
|
|
193
193
|
|
|
194
194
|
@handleNotSupported
|
|
195
|
-
def getFuelCellOperatingPhase(self):
|
|
195
|
+
def getFuelCellOperatingPhase(self) -> str:
|
|
196
196
|
# Returns current operating phase as string, e.g. "standby" or "generation"
|
|
197
|
-
return self.getProperty("
|
|
197
|
+
return str(self.getProperty("fuelCell.operating.phase")["properties"]["value"]["value"])
|
|
198
198
|
|
|
199
199
|
@handleNotSupported
|
|
200
200
|
def getFuelCellPowerProductionCurrentUnit(self):
|
|
@@ -257,39 +257,39 @@ class FuelCell(HeatingDevice):
|
|
|
257
257
|
return self.getProperty("heating.power.sold.cumulative")["properties"]["value"]["value"]
|
|
258
258
|
|
|
259
259
|
@handleNotSupported
|
|
260
|
-
def getFuelCellFlowReturnTemperatureUnit(self):
|
|
260
|
+
def getFuelCellFlowReturnTemperatureUnit(self) -> str:
|
|
261
261
|
# Returns flow return temperature unit, e.g. "celsius"
|
|
262
|
-
return self.getProperty("
|
|
262
|
+
return str(self.getProperty("fuelCell.sensors.temperature.return")["properties"]["value"]["unit"])
|
|
263
263
|
|
|
264
264
|
@handleNotSupported
|
|
265
|
-
def getFuelCellFlowReturnTemperature(self):
|
|
265
|
+
def getFuelCellFlowReturnTemperature(self) -> float:
|
|
266
266
|
# Returns flow return temperature at the fuel cell as float
|
|
267
|
-
return self.getProperty("
|
|
267
|
+
return float(self.getProperty("fuelCell.sensors.temperature.return")["properties"]["value"]["value"])
|
|
268
268
|
|
|
269
269
|
@handleNotSupported
|
|
270
|
-
def getFuelCellFlowSupplyTemperatureUnit(self):
|
|
270
|
+
def getFuelCellFlowSupplyTemperatureUnit(self) -> str:
|
|
271
271
|
# Returns flow supply temperature unit, e.g. "celsius"
|
|
272
|
-
return self.getProperty("
|
|
272
|
+
return str(self.getProperty("fuelCell.sensors.temperature.supply")["properties"]["value"]["unit"])
|
|
273
273
|
|
|
274
274
|
@handleNotSupported
|
|
275
|
-
def getFuelCellFlowSupplyTemperature(self):
|
|
275
|
+
def getFuelCellFlowSupplyTemperature(self) -> float:
|
|
276
276
|
# Returns flow supply temperature at the fuel cell as float
|
|
277
|
-
return self.getProperty("
|
|
277
|
+
return float(self.getProperty("fuelCell.sensors.temperature.supply")["properties"]["value"]["value"])
|
|
278
278
|
|
|
279
279
|
@handleNotSupported
|
|
280
|
-
def getFuelCellOperationHours(self):
|
|
280
|
+
def getFuelCellOperationHours(self) -> int:
|
|
281
281
|
# Returns the operation hours of the fuel cell
|
|
282
|
-
return self.getProperty("
|
|
282
|
+
return int(self.getProperty("fuelCell.statistics")["properties"]["operationHours"]["value"])
|
|
283
283
|
|
|
284
284
|
@handleNotSupported
|
|
285
|
-
def getFuelCellProductionHours(self):
|
|
285
|
+
def getFuelCellProductionHours(self) -> int:
|
|
286
286
|
# Returns the production hours of the fuel cell
|
|
287
|
-
return self.getProperty("
|
|
287
|
+
return int(self.getProperty("fuelCell.statistics")["properties"]["productionHours"]["value"])
|
|
288
288
|
|
|
289
289
|
@handleNotSupported
|
|
290
|
-
def getFuelCellProductionStarts(self):
|
|
290
|
+
def getFuelCellProductionStarts(self) -> int:
|
|
291
291
|
# Returns the number of production starts of the fuel cell
|
|
292
|
-
return self.getProperty("
|
|
292
|
+
return int(self.getProperty("fuelCell.statistics")["properties"]["productionStarts"]["value"])
|
|
293
293
|
|
|
294
294
|
@handleNotSupported
|
|
295
295
|
def getFuelCellGasConsumptionUnit(self):
|
|
@@ -9,5 +9,5 @@ class Gateway(Device):
|
|
|
9
9
|
return self.getProperty("gateway.devices")["gatewayId"]
|
|
10
10
|
|
|
11
11
|
@handleNotSupported
|
|
12
|
-
def getWifiSignalStrength(self):
|
|
13
|
-
return self.getProperty("gateway.wifi")["properties"]["strength"]["value"]
|
|
12
|
+
def getWifiSignalStrength(self) -> int:
|
|
13
|
+
return int(self.getProperty("gateway.wifi")["properties"]["strength"]["value"])
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
from contextlib import suppress
|
|
2
3
|
from typing import Any, List
|
|
3
4
|
from deprecated import deprecated
|
|
4
5
|
|
|
5
6
|
from PyViCare.PyViCareHeatingDevice import HeatingDevice, HeatingDeviceWithComponent
|
|
6
|
-
from PyViCare.PyViCareUtils import
|
|
7
|
+
from PyViCare.PyViCareUtils import (PyViCareNotSupportedFeatureError,
|
|
8
|
+
handleAPICommandErrors, handleNotSupported)
|
|
7
9
|
from PyViCare.PyViCareVentilationDevice import VentilationDevice
|
|
8
10
|
|
|
9
11
|
|
|
@@ -34,6 +36,13 @@ class HeatPump(HeatingDevice, VentilationDevice):
|
|
|
34
36
|
def getEvaporator(self, evaporator) -> Evaporator:
|
|
35
37
|
return Evaporator(self, evaporator)
|
|
36
38
|
|
|
39
|
+
@property
|
|
40
|
+
def inverters(self) -> List[Inverter]:
|
|
41
|
+
return [self.getInverter(x) for x in self.getAvailableCompressors()]
|
|
42
|
+
|
|
43
|
+
def getInverter(self, inverter) -> Inverter:
|
|
44
|
+
return Inverter(self, inverter)
|
|
45
|
+
|
|
37
46
|
@handleNotSupported
|
|
38
47
|
def getBufferMainTemperature(self):
|
|
39
48
|
return self.getProperty("heating.bufferCylinder.sensors.temperature.main")["properties"]['value']['value']
|
|
@@ -313,6 +322,39 @@ class HeatPump(HeatingDevice, VentilationDevice):
|
|
|
313
322
|
def getHeatingRodPowerConsumptionTotalThisYear(self) -> float:
|
|
314
323
|
return float(self.getProperty("heating.heatingRod.power.consumption.total")["properties"]["year"]["value"][0])
|
|
315
324
|
|
|
325
|
+
# Cooling circuits
|
|
326
|
+
@property
|
|
327
|
+
def coolingCircuits(self) -> List[CoolingCircuit]:
|
|
328
|
+
return [self.getCoolingCircuit(x) for x in self.getAvailableCoolingCircuits()]
|
|
329
|
+
|
|
330
|
+
def getCoolingCircuit(self, circuit) -> CoolingCircuit:
|
|
331
|
+
return CoolingCircuit(self, circuit)
|
|
332
|
+
|
|
333
|
+
def getAvailableCoolingCircuits(self):
|
|
334
|
+
"""Detect available cooling circuits (0, 1, 2, etc.)."""
|
|
335
|
+
available = []
|
|
336
|
+
for circuit in ['0', '1', '2', '3']:
|
|
337
|
+
with suppress(KeyError, PyViCareNotSupportedFeatureError):
|
|
338
|
+
if self.getProperty(f"heating.coolingCircuits.{circuit}.type") is not None:
|
|
339
|
+
available.append(circuit)
|
|
340
|
+
return available
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
class CoolingCircuit(HeatingDeviceWithComponent):
|
|
344
|
+
"""Cooling circuit component for heat pumps with cooling capability."""
|
|
345
|
+
|
|
346
|
+
@property
|
|
347
|
+
def circuit(self) -> str:
|
|
348
|
+
return self.component
|
|
349
|
+
|
|
350
|
+
@handleNotSupported
|
|
351
|
+
def getType(self) -> str:
|
|
352
|
+
return str(self.getProperty(f"heating.coolingCircuits.{self.circuit}.type")["properties"]["value"]["value"])
|
|
353
|
+
|
|
354
|
+
@handleNotSupported
|
|
355
|
+
def getReverseActive(self) -> bool:
|
|
356
|
+
return bool(self.getProperty(f"heating.coolingCircuits.{self.circuit}.reverse")["properties"]["active"]["value"])
|
|
357
|
+
|
|
316
358
|
|
|
317
359
|
class Compressor(HeatingDeviceWithComponent):
|
|
318
360
|
|
|
@@ -356,6 +398,10 @@ class Compressor(HeatingDeviceWithComponent):
|
|
|
356
398
|
def getPhase(self):
|
|
357
399
|
return self.getProperty(f"heating.compressors.{self.compressor}")["properties"]["phase"]["value"]
|
|
358
400
|
|
|
401
|
+
@handleNotSupported
|
|
402
|
+
def getSpeed(self) -> int:
|
|
403
|
+
return int(self.getProperty(f"heating.compressors.{self.compressor}.speed.current")["properties"]["value"]["value"])
|
|
404
|
+
|
|
359
405
|
@handleNotSupported
|
|
360
406
|
def getHeatProductionCurrent(self) -> float:
|
|
361
407
|
return float(self.getProperty(f"heating.compressors.{self.compressor}.heat.production.current")["properties"]["value"]["value"])
|
|
@@ -480,6 +526,23 @@ class Compressor(HeatingDeviceWithComponent):
|
|
|
480
526
|
# Shows the inlet temperature of the compressor.
|
|
481
527
|
return float(self.getProperty(f"heating.compressors.{self.compressor}.sensors.temperature.inlet")["properties"]["value"]["value"])
|
|
482
528
|
|
|
529
|
+
@handleNotSupported
|
|
530
|
+
def getOilTemperature(self) -> float:
|
|
531
|
+
# Shows the oil temperature of the compressor.
|
|
532
|
+
return float(self.getProperty(f"heating.compressors.{self.compressor}.sensors.temperature.oil")["properties"]["value"]["value"])
|
|
533
|
+
|
|
534
|
+
def getMotorChamberTemperature(self) -> float:
|
|
535
|
+
# Shows the motor chamber temperature of the compressor.
|
|
536
|
+
return float(self.getProperty(f"heating.compressors.{self.compressor}.sensors.temperature.motorChamber")["properties"]["value"]["value"])
|
|
537
|
+
|
|
538
|
+
def getAmbientTemperature(self) -> float:
|
|
539
|
+
# Shows the ambient temperature of the compressor.
|
|
540
|
+
return float(self.getProperty(f"heating.compressors.{self.compressor}.sensors.temperature.ambient")["properties"]["value"]["value"])
|
|
541
|
+
|
|
542
|
+
def getOverheatTemperature(self) -> float:
|
|
543
|
+
# Shows the overheat temperature of the compressor.
|
|
544
|
+
return float(self.getProperty(f"heating.compressors.{self.compressor}.sensors.temperature.overheat")["properties"]["value"]["value"])
|
|
545
|
+
|
|
483
546
|
|
|
484
547
|
class Evaporator(HeatingDeviceWithComponent):
|
|
485
548
|
|
|
@@ -581,3 +644,22 @@ class Condensor(HeatingDeviceWithComponent):
|
|
|
581
644
|
def getLiquidTemperature(self) -> float:
|
|
582
645
|
# Shows the liquid temperature of the condenser.
|
|
583
646
|
return float(self.getProperty(f"heating.condensors.{self.condensor}.sensors.temperature.liquid")["properties"]["value"]["value"])
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
class Inverter(HeatingDeviceWithComponent):
|
|
650
|
+
|
|
651
|
+
@property
|
|
652
|
+
def inverter(self) -> str:
|
|
653
|
+
return self.component
|
|
654
|
+
|
|
655
|
+
@handleNotSupported
|
|
656
|
+
def getCurrent(self) -> float:
|
|
657
|
+
return float(self.getProperty(f"heating.inverters.{self.inverter}.sensors.power.current")["properties"]["value"]["value"])
|
|
658
|
+
|
|
659
|
+
@handleNotSupported
|
|
660
|
+
def getPower(self) -> float:
|
|
661
|
+
return float(self.getProperty(f"heating.inverters.{self.inverter}.sensors.power.output")["properties"]["value"]["value"])
|
|
662
|
+
|
|
663
|
+
@handleNotSupported
|
|
664
|
+
def getTemperature(self) -> float:
|
|
665
|
+
return float(self.getProperty(f"heating.inverters.{self.inverter}.sensors.temperature.powerModule")["properties"]["value"]["value"])
|
|
@@ -36,6 +36,10 @@ class HeatingDevice(Device):
|
|
|
36
36
|
Note that currently, a new token is generated for each run.
|
|
37
37
|
"""
|
|
38
38
|
|
|
39
|
+
@handleNotSupported
|
|
40
|
+
def getWifiSignalStrength(self) -> int:
|
|
41
|
+
return int(self.getProperty("tcu.wifi")["properties"]["strength"]["value"])
|
|
42
|
+
|
|
39
43
|
@property
|
|
40
44
|
def circuits(self) -> List[Any]:
|
|
41
45
|
return list([self.getCircuit(x) for x in self.getAvailableCircuits()])
|
|
@@ -194,6 +198,16 @@ class HeatingDevice(Device):
|
|
|
194
198
|
return self.setProperty("heating.dhw.temperature.temp2", "setTargetTemperature",
|
|
195
199
|
{"temperature": int(temperature)})
|
|
196
200
|
|
|
201
|
+
@handleNotSupported
|
|
202
|
+
def getDomesticHotWaterOperatingModes(self):
|
|
203
|
+
return self.getProperty("heating.dhw.operating.modes.active")[
|
|
204
|
+
"commands"]["setMode"]["params"]["mode"]["constraints"]["enum"]
|
|
205
|
+
|
|
206
|
+
@handleNotSupported
|
|
207
|
+
def getDomesticHotWaterActiveOperatingMode(self):
|
|
208
|
+
return self.getProperty("heating.dhw.operating.modes.active")[
|
|
209
|
+
"properties"]["value"]["value"]
|
|
210
|
+
|
|
197
211
|
@handleAPICommandErrors
|
|
198
212
|
def setDomesticHotWaterOperatingMode(self, mode):
|
|
199
213
|
return self.setProperty("heating.dhw.operating.modes.active", "setMode",
|
|
@@ -105,6 +105,18 @@ class PyViCareInvalidDataError(Exception):
|
|
|
105
105
|
pass
|
|
106
106
|
|
|
107
107
|
|
|
108
|
+
class PyViCareDeviceCommunicationError(Exception):
|
|
109
|
+
def __init__(self, response):
|
|
110
|
+
extended_payload = response.get("extendedPayload", {})
|
|
111
|
+
reason = extended_payload.get("reason", "Unknown")
|
|
112
|
+
|
|
113
|
+
msg = f'Device communication error. Reason: {reason}'
|
|
114
|
+
|
|
115
|
+
super().__init__(self, msg)
|
|
116
|
+
self.message = msg
|
|
117
|
+
self.reason = reason
|
|
118
|
+
|
|
119
|
+
|
|
108
120
|
class PyViCareRateLimitError(Exception):
|
|
109
121
|
|
|
110
122
|
def __init__(self, response):
|
|
@@ -12,6 +12,10 @@ class VentilationDevice(Device):
|
|
|
12
12
|
Note that currently, a new token is generated for each run.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
+
@handleNotSupported
|
|
16
|
+
def getWifiSignalStrength(self) -> int:
|
|
17
|
+
return int(self.getProperty("tcu.wifi")["properties"]["strength"]["value"])
|
|
18
|
+
|
|
15
19
|
@handleNotSupported
|
|
16
20
|
def getVentilationDemand(self) -> str:
|
|
17
21
|
return str(self.getProperty("ventilation.operating.state")["properties"]["demand"]["value"])
|
|
@@ -285,3 +289,19 @@ class VentilationDevice(Device):
|
|
|
285
289
|
@handleNotSupported
|
|
286
290
|
def getExhaustVolumeFlow(self) -> int:
|
|
287
291
|
return int(self.getProperty("ventilation.volumeFlow.current.output")["properties"]["value"]["value"])
|
|
292
|
+
|
|
293
|
+
@handleNotSupported
|
|
294
|
+
def getConfiguredLevelOneVolumeFlow(self) -> int:
|
|
295
|
+
return int(self.getProperty("ventilation.levels.levelOne")["properties"]["volumeFlow"]["value"])
|
|
296
|
+
|
|
297
|
+
@handleNotSupported
|
|
298
|
+
def getConfiguredLevelTwoVolumeFlow(self) -> int:
|
|
299
|
+
return int(self.getProperty("ventilation.levels.levelTwo")["properties"]["volumeFlow"]["value"])
|
|
300
|
+
|
|
301
|
+
@handleNotSupported
|
|
302
|
+
def getConfiguredLevelThreeVolumeFlow(self) -> int:
|
|
303
|
+
return int(self.getProperty("ventilation.levels.levelThree")["properties"]["volumeFlow"]["value"])
|
|
304
|
+
|
|
305
|
+
@handleNotSupported
|
|
306
|
+
def getConfiguredLevelFourVolumeFlow(self) -> int:
|
|
307
|
+
return int(self.getProperty("ventilation.levels.levelFour")["properties"]["volumeFlow"]["value"])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "PyViCare"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.57.0"
|
|
4
4
|
description = "Library to communicate with the Viessmann ViCare API."
|
|
5
5
|
authors = [
|
|
6
6
|
"Simon Gillet <mail+pyvicare@gillet.ninja>"
|
|
@@ -26,6 +26,7 @@ classifiers = [
|
|
|
26
26
|
"Programming Language :: Python :: 3.10",
|
|
27
27
|
"Programming Language :: Python :: 3.11",
|
|
28
28
|
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Programming Language :: Python :: 3.13",
|
|
29
30
|
"Programming Language :: Python :: 3",
|
|
30
31
|
"License :: OSI Approved :: Apache Software License",
|
|
31
32
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
@@ -51,7 +52,7 @@ mypy = "^1.11.2"
|
|
|
51
52
|
pylint = "^4.0.0"
|
|
52
53
|
pytest = "^9.0.0"
|
|
53
54
|
pytest-cov = "^7.0.0"
|
|
54
|
-
ruff = "^0.
|
|
55
|
+
ruff = "^0.15.0"
|
|
55
56
|
types-deprecated = "^1.2.15.20241117"
|
|
56
57
|
types-requests = ">=2.31"
|
|
57
58
|
|
|
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
|