weheat 2024.11.1__py3-none-any.whl → 2025.11.24rc1__py3-none-any.whl

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.
Files changed (42) hide show
  1. weheat/__init__.py +6 -2
  2. weheat/abstractions/__init__.py +1 -1
  3. weheat/abstractions/discovery.py +11 -7
  4. weheat/abstractions/heat_pump.py +223 -81
  5. weheat/abstractions/user.py +16 -11
  6. weheat/api/__init__.py +1 -0
  7. weheat/api/energy_log_api.py +615 -127
  8. weheat/api/heat_pump_api.py +580 -374
  9. weheat/api/heat_pump_log_api.py +884 -360
  10. weheat/api/user_api.py +260 -115
  11. weheat/api_client.py +238 -265
  12. weheat/api_response.py +11 -15
  13. weheat/configuration.py +14 -9
  14. weheat/exceptions.py +59 -25
  15. weheat/models/__init__.py +8 -0
  16. weheat/models/boiler_type.py +8 -3
  17. weheat/models/device_state.py +9 -5
  18. weheat/models/dhw_type.py +8 -3
  19. weheat/models/energy_view_dto.py +87 -65
  20. weheat/models/heat_pump_log_view_dto.py +1394 -559
  21. weheat/models/heat_pump_model.py +8 -3
  22. weheat/models/heat_pump_status_enum.py +9 -4
  23. weheat/models/pagination_metadata.py +95 -0
  24. weheat/models/raw_heat_pump_log_dto.py +438 -375
  25. weheat/models/raw_heatpump_log_and_is_online_dto.py +578 -0
  26. weheat/models/read_all_heat_pump_dto.py +69 -53
  27. weheat/models/read_all_heat_pump_dto_paged_response.py +107 -0
  28. weheat/models/read_heat_pump_dto.py +64 -48
  29. weheat/models/read_user_dto.py +55 -37
  30. weheat/models/read_user_me_dto.py +124 -0
  31. weheat/models/role.py +10 -4
  32. weheat/models/total_energy_aggregate.py +111 -0
  33. weheat/rest.py +152 -259
  34. weheat-2025.11.24rc1.dist-info/METADATA +104 -0
  35. weheat-2025.11.24rc1.dist-info/RECORD +39 -0
  36. {weheat-2024.11.1.dist-info → weheat-2025.11.24rc1.dist-info}/WHEEL +1 -1
  37. weheat/abstractions/auth.py +0 -34
  38. weheat/models/heat_pump_type.py +0 -42
  39. weheat-2024.11.1.dist-info/METADATA +0 -107
  40. weheat-2024.11.1.dist-info/RECORD +0 -36
  41. {weheat-2024.11.1.dist-info → weheat-2025.11.24rc1.dist-info/licenses}/LICENSE +0 -0
  42. {weheat-2024.11.1.dist-info → weheat-2025.11.24rc1.dist-info}/top_level.txt +0 -0
weheat/__init__.py CHANGED
@@ -14,7 +14,7 @@
14
14
  """ # noqa: E501
15
15
 
16
16
 
17
- __version__ = "2024.07.08"
17
+ __version__ = "2025.11.24"
18
18
 
19
19
  # import apis into sdk package
20
20
  from weheat.api.energy_log_api import EnergyLogApi
@@ -34,12 +34,16 @@ from weheat.exceptions import ApiAttributeError
34
34
  from weheat.exceptions import ApiException
35
35
 
36
36
  # import models into sdk package
37
+ from weheat.models.boiler_type import BoilerType
37
38
  from weheat.models.device_state import DeviceState
39
+ from weheat.models.dhw_type import DhwType
38
40
  from weheat.models.energy_view_dto import EnergyViewDto
39
41
  from weheat.models.heat_pump_log_view_dto import HeatPumpLogViewDto
42
+ from weheat.models.heat_pump_model import HeatPumpModel
43
+ from weheat.models.heat_pump_status_enum import HeatPumpStatusEnum
40
44
  from weheat.models.raw_heat_pump_log_dto import RawHeatPumpLogDto
41
45
  from weheat.models.read_all_heat_pump_dto import ReadAllHeatPumpDto
42
46
  from weheat.models.read_heat_pump_dto import ReadHeatPumpDto
43
47
  from weheat.models.read_user_dto import ReadUserDto
48
+ from weheat.models.read_user_me_dto import ReadUserMeDto
44
49
  from weheat.models.role import Role
45
-
@@ -1,3 +1,3 @@
1
- from weheat.abstractions.auth import AbstractAuth
2
1
  from weheat.abstractions.discovery import HeatPumpDiscovery
3
2
  from weheat.abstractions.heat_pump import HeatPump
3
+ from weheat.abstractions.user import async_get_user_id_from_token
@@ -1,5 +1,8 @@
1
+ import asyncio
1
2
  from dataclasses import dataclass
2
3
 
4
+ import aiohttp
5
+
3
6
  from weheat import DeviceState
4
7
  from weheat.configuration import Configuration
5
8
  from weheat.api_client import ApiClient
@@ -10,22 +13,23 @@ class HeatPumpDiscovery:
10
13
  @dataclass
11
14
  class HeatPumpInfo:
12
15
  uuid: str
13
- name: str
16
+ device_name: str
14
17
  model: str
15
18
  sn : str
16
19
  has_dhw: bool = False
17
20
 
18
21
  @staticmethod
19
- async def discover_active(api_url: str, access_token: str) -> list[HeatPumpInfo]:
22
+ async def async_discover_active(api_url: str, access_token: str, client_session:aiohttp.ClientSession|None = None) -> list[HeatPumpInfo]:
20
23
  discovered_pumps = []
21
24
 
22
- config = Configuration(host=api_url, access_token=access_token)
25
+ config = Configuration(host=api_url, access_token=access_token, client_session=client_session)
26
+
27
+ async with ApiClient(configuration=config) as client:
23
28
 
24
- with ApiClient(configuration=config) as client:
29
+ response = await HeatPumpApi(client).api_v1_heat_pumps_get_with_http_info(1, 1000, state=DeviceState.NUMBER_3)
25
30
 
26
- response = HeatPumpApi(client).api_v1_heat_pumps_get_with_http_info('', 0, 1000, DeviceState.NUMBER_3 ,async_req=True).get()
27
31
  if response.status_code == 200:
28
- for pump in response.data:
32
+ for pump in response.data.data:
29
33
  # Model of the heat pump
30
34
  # - BlackBirdP80: BlackBird P80 heat pump (0)
31
35
  # - BlackBirdP60: BlackBird P60 heat pump (1)
@@ -49,7 +53,7 @@ class HeatPumpDiscovery:
49
53
  discovered_pumps.append(
50
54
  HeatPumpDiscovery.HeatPumpInfo(
51
55
  uuid=pump.id,
52
- name=pump.name,
56
+ device_name=pump.name,
53
57
  model=model_string,
54
58
  sn=pump.serial_number,
55
59
  has_dhw=dhw,
@@ -1,19 +1,28 @@
1
1
  """Weheat heat pump abstraction from the API."""
2
+ import asyncio
2
3
  from enum import Enum, auto
3
4
 
5
+ import aiohttp
6
+
4
7
  from weheat import HeatPumpApi
5
8
  from weheat.configuration import Configuration
6
9
  from weheat.api_client import ApiClient
7
10
  from weheat.api.heat_pump_log_api import HeatPumpLogApi
8
11
  from weheat.api.energy_log_api import EnergyLogApi
9
12
  from datetime import datetime, timedelta
13
+ from typing import TypeVar, Union, Optional
14
+
15
+ from weheat.models import TotalEnergyAggregate
10
16
 
11
17
  # before this date no energy logs are available, so start from this point onwards
12
18
  START_DATE = datetime(2023, 1, 1, 0, 0, 0)
13
19
 
20
+ T = TypeVar("T", bool, int, float)
21
+
14
22
 
15
23
  class HeatPump:
16
24
  """Heat pump class representing a heat pump."""
25
+
17
26
  class State(Enum):
18
27
  STANDBY = auto()
19
28
  WATER_CHECK = auto()
@@ -25,162 +34,172 @@ class HeatPump:
25
34
  SELF_TEST = auto()
26
35
  MANUAL_CONTROL = auto()
27
36
 
28
- def __init__(self, api_url: str, uuid: str) -> None:
37
+ def __init__(self, api_url: str, uuid: str, client_session: aiohttp.ClientSession | None = None) -> None:
29
38
  self._api_url = api_url
30
39
  self._uuid = uuid
31
40
  self._last_log = None
32
- self._energy_consumption = None
33
- self._energy_output = None
34
- self._nominal_max_power = None
41
+ self._energy_total: Union[TotalEnergyAggregate, None] = None
42
+ self._nominal_max_power: Union[float, None] = None
43
+ self._client = client_session
35
44
 
36
- def get_status(self, access_token: str):
45
+ async def async_get_status(self, access_token: str) -> None:
46
+ """Updates the heat pump instance with data from the API."""
47
+ await self.async_get_logs(access_token)
48
+ await self.async_get_energy(access_token)
49
+
50
+
51
+ async def async_get_logs(self, access_token: str) -> None:
37
52
  """Updates the heat pump instance with data from the API."""
38
53
  try:
39
- config = Configuration(host=self._api_url, access_token=access_token)
54
+ config = Configuration(host=self._api_url, access_token=access_token, client_session=self._client)
40
55
 
41
- with ApiClient(configuration=config) as client:
56
+ async with ApiClient(configuration=config) as client:
42
57
  # Set the max power once
43
58
  if self._nominal_max_power is None:
44
- repsonse = HeatPumpApi(client).api_v1_heat_pumps_heat_pump_id_get_with_http_info(heat_pump_id=self._uuid)
59
+ response = await HeatPumpApi(client).api_v1_heat_pumps_heat_pump_id_get_with_http_info(
60
+ heat_pump_id=self._uuid)
45
61
 
46
- if repsonse.status_code == 200:
47
- self._set_nominal_max_power_for_model(repsonse.data.model)
62
+ if response.status_code == 200:
63
+ self._set_nominal_max_power_for_model(response.data.model)
48
64
 
49
-
50
- response = HeatPumpLogApi(
65
+ response = await HeatPumpLogApi(
51
66
  client
52
67
  ).api_v1_heat_pumps_heat_pump_id_logs_latest_get_with_http_info(
53
- heat_pump_id=self._uuid
54
- )
68
+ heat_pump_id=self._uuid)
69
+
55
70
  if response.status_code == 200:
56
71
  self._last_log = response.data
57
72
 
58
- # Also get all energy totals form past years and add them together
59
- # As end time pick today + 1 day to avoid issues with timezones
60
- response = EnergyLogApi(client).api_v1_energy_logs_heat_pump_id_get_with_http_info(heat_pump_id=self._uuid,
61
- start_time=START_DATE,
62
- end_time=datetime.now() + timedelta(days=1),
63
- interval='Year')
64
73
 
65
- if response.status_code == 200:
66
- # aggregate the energy consumption
67
- self._energy_consumption = 0
68
- self._energy_output = 0
69
- for year in response.data:
70
- self._energy_consumption += year.total_ein_cooling
71
- self._energy_consumption += year.total_ein_heating
72
- self._energy_consumption += year.total_ein_heating_defrost
73
- self._energy_consumption += year.total_ein_dhw
74
- self._energy_consumption += year.total_ein_dhw_defrost
75
- self._energy_output += year.total_e_out_cooling
76
- self._energy_output += year.total_e_out_heating
77
- self._energy_output += year.total_e_out_heating_defrost
78
- self._energy_output += year.total_e_out_dhw
79
- self._energy_output += year.total_e_out_dhw_defrost
74
+ except Exception as e:
75
+ self._last_log = None
76
+ raise e
77
+
80
78
 
79
+ async def async_get_energy(self, access_token: str) -> None:
80
+ """Updates the heat pump instance with data from the API."""
81
+ try:
82
+ config = Configuration(host=self._api_url, access_token=access_token, client_session=self._client)
81
83
 
84
+ async with ApiClient(configuration=config) as client:
85
+ response = await EnergyLogApi(client).total_heat_pump_id_get_with_http_info(heat_pump_id=self._uuid)
86
+
87
+ if response.status_code == 200:
88
+ # aggregate the energy consumption
89
+ self._energy_total = response.data
82
90
 
83
91
  except Exception as e:
84
- self._last_log = None
85
- self._energy_consumption = None
86
- raise e
92
+ self._energy_total = None
93
+
94
+ def _if_available_and_valid(self, key:str) -> Optional[T]:
95
+ """Return the value from the last logged value if available and not -1. None otherwise."""
96
+ value = self._if_available(key)
97
+ if value is not None and value != -1:
98
+ return value
99
+ return None
87
100
 
88
- def _if_available(self, key):
101
+ def _if_available(self, key: str) -> Optional[T]:
89
102
  """Returns the value from the last logged value if available. None otherwise."""
90
103
  if self._last_log is not None and hasattr(self._last_log, key):
91
104
  return getattr(self._last_log, key)
92
105
  return None
93
106
 
94
- def _set_nominal_max_power_for_model(self, model_id:int):
107
+ def _set_nominal_max_power_for_model(self, model_id: int) -> None:
95
108
  # These numbers are the rpm at 100% power in the portal
96
109
  # RPM can go above 100% if the limit is increased in the portal.
97
110
  # except for the Flint, that cannot go above 100%.
98
111
  if model_id == 1:
99
- #BB60
100
- self._nominal_max_power = 5280
112
+ # BB60
113
+ self._nominal_max_power = 5520
101
114
  elif 2 <= model_id <= 4:
102
- #SP60
103
- self._nominal_max_power = 5280
115
+ # SP60
116
+ self._nominal_max_power = 5520
104
117
  elif model_id == 5:
105
118
  # Flint
106
119
  self._nominal_max_power = 5400
107
120
  else:
108
- #BB80
121
+ # BB80
109
122
  self._nominal_max_power = 4500
110
123
 
111
- def __str__(self):
124
+ def __str__(self) -> str:
112
125
  return f"WeheatHeatPump(uuid={self._uuid}, last update={self._if_available('timestamp')})"
113
126
 
114
- def __repr__(self):
127
+ def __repr__(self) -> str:
115
128
  return self.__str__()
116
129
 
117
130
  @property
118
- def water_inlet_temperature(self):
131
+ def raw_content(self) -> Optional[dict]:
132
+ if self._last_log is not None:
133
+ return vars(self._last_log) # type: ignore[unreachable]
134
+ return None
135
+
136
+ @property
137
+ def water_inlet_temperature(self) -> Union[float, None]:
119
138
  """The heat pump water inlet temperature."""
120
139
  return self._if_available("t_water_in")
121
140
 
122
141
  @property
123
- def water_outlet_temperature(self):
142
+ def water_outlet_temperature(self) -> Union[float, None]:
124
143
  """The heat pump water outlet temperature."""
125
144
  return self._if_available("t_water_out")
126
145
 
127
146
  @property
128
- def water_house_in_temperature(self):
147
+ def water_house_in_temperature(self) -> Union[float, None]:
129
148
  """The water house in temperature."""
130
149
  return self._if_available("t_water_house_in")
131
150
 
132
151
  @property
133
- def air_inlet_temperature(self):
152
+ def air_inlet_temperature(self) -> Union[float, None]:
134
153
  """The heat pump air inlet temperature."""
135
154
  return self._if_available("t_air_in")
136
155
 
137
156
  @property
138
- def air_outlet_temperature(self):
157
+ def air_outlet_temperature(self) -> Union[float, None]:
139
158
  """The heat pump air outlet temperature."""
140
159
  return self._if_available("t_air_out")
141
160
 
142
161
  @property
143
- def thermostat_water_setpoint(self):
162
+ def thermostat_water_setpoint(self) -> Union[float, None]:
144
163
  """The thermostat water setpoint."""
145
164
  return self._if_available("t_thermostat_setpoint")
146
165
 
147
166
  @property
148
- def thermostat_room_temperature(self):
167
+ def thermostat_room_temperature(self) -> Union[float, None]:
149
168
  """The thermostat current room temperature."""
150
- return self._if_available("t_room")
169
+ return self._if_available_and_valid("t_room")
151
170
 
152
171
  @property
153
- def thermostat_room_temperature_setpoint(self):
172
+ def thermostat_room_temperature_setpoint(self) -> Union[float, None]:
154
173
  """The thermostat room temperature setpoint."""
155
- return self._if_available("t_room_target")
174
+ return self._if_available_and_valid("t_room_target")
156
175
 
157
176
  @property
158
- def thermostat_on_off_state(self):
177
+ def thermostat_on_off_state(self) -> Union[bool, None]:
159
178
  """The thermostat on/off state."""
160
179
  return self._if_available("on_off_thermostat_state")
161
180
 
162
181
  @property
163
- def power_input(self):
182
+ def power_input(self) -> Union[float, None]:
164
183
  """The heat pumps power input."""
165
184
  return self._if_available("cm_mass_power_in")
166
185
 
167
186
  @property
168
- def power_output(self):
187
+ def power_output(self) -> Union[float, None]:
169
188
  """The heat pumps hydraulic output power."""
170
189
  return self._if_available("cm_mass_power_out")
171
190
 
172
191
  @property
173
- def dhw_top_temperature(self):
192
+ def dhw_top_temperature(self) -> Union[float, None]:
174
193
  """The DHW vessel top temperature."""
175
194
  return self._if_available("t1")
176
195
 
177
196
  @property
178
- def dhw_bottom_temperature(self):
197
+ def dhw_bottom_temperature(self) -> Union[float, None]:
179
198
  """The DHW vessel bottom temperature."""
180
199
  return self._if_available("t2")
181
200
 
182
201
  @property
183
- def cop(self):
202
+ def cop(self) -> Union[float, None]:
184
203
  """
185
204
  Returns the coefficient of performance of the heat pump.
186
205
  Note that this is calculated from a singular log entry and might not be accurate when the
@@ -188,36 +207,42 @@ class HeatPump:
188
207
  """
189
208
  input = self.power_input
190
209
  output = self.power_output
191
- if input is not None and output is not None and input != 0:
210
+ # When either is not available, the calculation cannot be made.
211
+ if input is None or output is None:
212
+ return None
213
+
214
+ if input > 0:
192
215
  return output / input
193
216
 
217
+ return 0
218
+
194
219
  @property
195
- def inside_unit_water_pump_state(self):
220
+ def indoor_unit_water_pump_state(self) -> Union[bool, None]:
196
221
  """Decoded water pump state."""
197
222
  return self._if_available("control_bridge_status_decoded_water_pump")
198
223
 
199
224
  @property
200
- def inside_unit_auxilary_pump_state(self):
201
- """Decoded auxilary pump state."""
225
+ def indoor_unit_auxiliary_pump_state(self) -> Union[bool, None]:
226
+ """Decoded auxiliary pump state."""
202
227
  return self._if_available("control_bridge_status_decoded_water_pump2")
203
228
 
204
229
  @property
205
- def inside_unit_dhw_valve_or_pump_state(self):
230
+ def indoor_unit_dhw_valve_or_pump_state(self) -> Union[bool, None]:
206
231
  """Decoded DHW valve or pump state."""
207
232
  return self._if_available("control_bridge_status_decoded_dhw_valve")
208
233
 
209
234
  @property
210
- def inside_unit_gas_boiler_state(self):
235
+ def indoor_unit_gas_boiler_state(self) -> Union[bool, None]:
211
236
  """Decoded gas boiler state."""
212
237
  return self._if_available("control_bridge_status_decoded_gas_boiler")
213
238
 
214
239
  @property
215
- def inside_unit_gas_electric_heater(self):
240
+ def indoor_unit_electric_heater_state(self) -> Union[bool, None]:
216
241
  """Decoded electric heater state."""
217
242
  return self._if_available("control_bridge_status_decoded_electric_heater")
218
243
 
219
244
  @property
220
- def compressor_percentage(self):
245
+ def compressor_percentage(self) -> Union[int, None]:
221
246
  current_rpm = self._if_available("rpm")
222
247
  if self._nominal_max_power is not None and current_rpm is not None:
223
248
  # calculate percentage of rpm
@@ -225,12 +250,12 @@ class HeatPump:
225
250
  return None
226
251
 
227
252
  @property
228
- def compressor_rpm(self):
253
+ def compressor_rpm(self) -> Union[float, None]:
229
254
  """Compressor RPM."""
230
255
  return self._if_available("rpm")
231
256
 
232
257
  @property
233
- def heat_pump_state(self) -> State | None:
258
+ def heat_pump_state(self) -> Union[State, None]:
234
259
  """The heat pump state."""
235
260
  numeric_state = self._if_available("state")
236
261
  if numeric_state is None:
@@ -240,7 +265,7 @@ class HeatPump:
240
265
  return self.State.STANDBY
241
266
  elif numeric_state == 70:
242
267
  return self.State.HEATING
243
- elif numeric_state == 130:
268
+ elif numeric_state >= 130 and numeric_state < 140:
244
269
  return self.State.COOLING
245
270
  elif numeric_state == 150:
246
271
  return self.State.DHW
@@ -250,16 +275,133 @@ class HeatPump:
250
275
  return self.State.SELF_TEST
251
276
  elif numeric_state == 180:
252
277
  return self.State.MANUAL_CONTROL
253
- elif numeric_state == 200:
278
+ elif numeric_state >= 200 and numeric_state <= 240:
254
279
  return self.State.DEFROSTING
255
280
  return None
256
281
 
282
+ @staticmethod
283
+ def _pwm_to_volume(pwm: float, max: float) -> Union[float, None]:
284
+ """Calculate PWM to Volume in m3/h based on the max available volume"""
285
+
286
+ # 0 or > 75 are abnormal states. 255 = Off
287
+ if pwm < 1 or pwm > 75:
288
+ return None
289
+
290
+ # 2 = standby
291
+ if pwm <= 5:
292
+ return 0
293
+
294
+ # 5-75 is linear from 0 to max
295
+ return ((pwm - 5) / 70) * max
296
+
257
297
  @property
258
- def energy_total(self):
259
- """The total used energy in kWh from 2023 to now."""
260
- return self._energy_consumption
298
+ def dhw_flow_volume(self) -> Union[float, None]:
299
+ """The DHW Flow in m3/h."""
300
+ pwm = pwm=self._if_available("dhw_flow")
301
+ if pwm is None:
302
+ return None
303
+
304
+ return self._pwm_to_volume(pwm, max=2.1)
305
+
306
+ @property
307
+ def central_heating_flow_volume(self) -> Union[float, None]:
308
+ """The Central Heating Flow in m3/h."""
309
+ pwm = pwm=self._if_available("central_heating_flow")
310
+ if pwm is None:
311
+ return None
312
+
313
+ return self._pwm_to_volume(pwm, max=2.1)
314
+
315
+ @property
316
+ def energy_in_heating(self) -> Union[float, None]:
317
+ """The total used energy in heating mode."""
318
+ if self._energy_total is None:
319
+ return None
320
+ return float(self._energy_total.total_ein_heating)
261
321
 
262
322
  @property
263
- def energy_output(self):
264
- """The total energy output in kWh from 2023 to now."""
265
- return self._energy_output
323
+ def energy_in_dhw(self) -> Union[float, None]:
324
+ """The total used energy in DHW mode."""
325
+ if self._energy_total is None:
326
+ return None
327
+ return float(self._energy_total.total_ein_dhw)
328
+
329
+ @property
330
+ def energy_in_defrost(self) -> Union[float, None]:
331
+ """The total used energy in defrost modes."""
332
+ if self._energy_total is None:
333
+ return None
334
+ return float(self._energy_total.total_ein_heating_defrost + self._energy_total.total_ein_dhw_defrost)
335
+
336
+ @property
337
+ def energy_in_defrost_dhw(self) -> Union[float, None]:
338
+ """The total used energy in defrost from DHW mode."""
339
+ if self._energy_total is None:
340
+ return None
341
+ return float(self._energy_total.total_ein_dhw_defrost)
342
+
343
+ @property
344
+ def energy_in_defrost_ch(self) -> Union[float, None]:
345
+ """The total used energy in defrost from CH mode."""
346
+ if self._energy_total is None:
347
+ return None
348
+ return float(self._energy_total.total_ein_heating_defrost)
349
+
350
+ @property
351
+ def energy_in_cooling(self) -> Union[float, None]:
352
+ """The total used energy in cooling mode."""
353
+ if self._energy_total is None:
354
+ return None
355
+ return float(self._energy_total.total_ein_cooling)
356
+
357
+ @property
358
+ def energy_out_heating(self) -> Union[float, None]:
359
+ """The total supplied energy in heating mode."""
360
+ if self._energy_total is None:
361
+ return None
362
+ return float(self._energy_total.total_e_out_heating)
363
+
364
+
365
+ @property
366
+ def energy_out_dhw(self) -> Union[float, None]:
367
+ """The total supplied energy in DHW mode."""
368
+ if self._energy_total is None:
369
+ return None
370
+ return float(self._energy_total.total_e_out_dhw)
371
+
372
+ @property
373
+ def energy_out_defrost(self) -> Union[float, None]:
374
+ """The total supplied energy in defrost modes.
375
+ Note that this energy value is negative as energy is removed from the water.
376
+ """
377
+ if self._energy_total is None:
378
+ return None
379
+ return float(self._energy_total.total_e_out_dhw_defrost + self._energy_total.total_e_out_heating_defrost)
380
+
381
+ @property
382
+ def energy_out_defrost_dhw(self) -> Union[float, None]:
383
+ """The total supplied energy in defrost DHW mode.
384
+ Note that this energy value is negative as energy is removed from the water.
385
+ """
386
+ if self._energy_total is None:
387
+ return None
388
+ return float(self._energy_total.total_e_out_dhw_defrost)
389
+
390
+
391
+ @property
392
+ def energy_out_defrost_ch(self) -> Union[float, None]:
393
+ """The total supplied energy in defrost CH mode.
394
+ Note that this energy value is negative as energy is removed from the water.
395
+ """
396
+ if self._energy_total is None:
397
+ return None
398
+ return float(self._energy_total.total_e_out_heating_defrost)
399
+
400
+ @property
401
+ def energy_out_cooling(self) -> Union[float, None]:
402
+ """The total supplied energy in cooling mode.
403
+ Note that this energy value is negative as energy is removed from the water.
404
+ """
405
+ if self._energy_total is None:
406
+ return None
407
+ return float(self._energy_total.total_e_out_cooling)
@@ -1,18 +1,23 @@
1
+ import asyncio
2
+ from typing import Union
3
+
4
+ import aiohttp
5
+
1
6
  from weheat.configuration import Configuration
2
7
  from weheat.api_client import ApiClient
3
8
  from weheat.api.user_api import UserApi
4
9
 
5
10
 
6
- async def get_user_id_from_token(api_url: str, access_token: str):
11
+ async def async_get_user_id_from_token(api_url: str, access_token: str, client_session:aiohttp.ClientSession|None = None) -> Union[str,None]:
7
12
  """ Get the user id from the current logged-in user. """
8
- try:
9
- config = Configuration(host=api_url, access_token=access_token)
13
+ config = Configuration(host=api_url, access_token=access_token, client_session=client_session)
14
+
15
+ async with ApiClient(configuration=config) as client:
16
+ response = await UserApi(
17
+ client
18
+ ).api_v1_users_me_get_with_http_info()
19
+
20
+ if response.status_code == 200:
21
+ return response.data.id # type: ignore[no-any-return]
22
+ return None
10
23
 
11
- with ApiClient(configuration=config) as client:
12
- response = UserApi(
13
- client
14
- ).api_v1_users_me_get_with_http_info(async_req=True).get()
15
- if response.status_code == 200:
16
- return response.data.id
17
- except Exception as e:
18
- raise e
weheat/api/__init__.py CHANGED
@@ -5,3 +5,4 @@ from weheat.api.energy_log_api import EnergyLogApi
5
5
  from weheat.api.heat_pump_api import HeatPumpApi
6
6
  from weheat.api.heat_pump_log_api import HeatPumpLogApi
7
7
  from weheat.api.user_api import UserApi
8
+