weheat 2024.7.8__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.

Potentially problematic release.


This version of weheat might be problematic. Click here for more details.

weheat/__init__.py ADDED
@@ -0,0 +1,42 @@
1
+ # coding: utf-8
2
+
3
+ # flake8: noqa
4
+
5
+ """
6
+ Weheat Backend
7
+
8
+ This is the backend for the Weheat project
9
+
10
+ The version of the OpenAPI document: v1
11
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
12
+
13
+ Do not edit the class manually.
14
+ """ # noqa: E501
15
+
16
+
17
+ __version__ = "2024.07.08"
18
+
19
+ # import apis into sdk package
20
+ from weheat.api.energy_log_api import EnergyLogApi
21
+ from weheat.api.heat_pump_api import HeatPumpApi
22
+ from weheat.api.heat_pump_log_api import HeatPumpLogApi
23
+
24
+ # import ApiClient
25
+ from weheat.api_response import ApiResponse
26
+ from weheat.api_client import ApiClient
27
+ from weheat.configuration import Configuration
28
+ from weheat.exceptions import OpenApiException
29
+ from weheat.exceptions import ApiTypeError
30
+ from weheat.exceptions import ApiValueError
31
+ from weheat.exceptions import ApiKeyError
32
+ from weheat.exceptions import ApiAttributeError
33
+ from weheat.exceptions import ApiException
34
+
35
+ # import models into sdk package
36
+ from weheat.models.device_state import DeviceState
37
+ from weheat.models.energy_view_dto import EnergyViewDto
38
+ from weheat.models.heat_pump_log_view_dto import HeatPumpLogViewDto
39
+ from weheat.models.raw_heat_pump_log_dto import RawHeatPumpLogDto
40
+ from weheat.models.read_all_heat_pump_dto import ReadAllHeatPumpDto
41
+ from weheat.models.read_heat_pump_dto import ReadHeatPumpDto
42
+
@@ -0,0 +1,3 @@
1
+ from weheat.abstractions.auth import AbstractAuth
2
+ from weheat.abstractions.discovery import HeatPumpDiscovery
3
+ from weheat.abstractions.heat_pump import HeatPump
@@ -0,0 +1,34 @@
1
+ from abc import ABC, abstractmethod
2
+ from aiohttp import ClientSession, ClientResponse
3
+
4
+
5
+ class AbstractAuth(ABC):
6
+ """Abstract class to make authenticated requests."""
7
+
8
+ def __init__(self, websession: ClientSession, host: str) -> None:
9
+ """Initialize the auth."""
10
+ self.websession = websession
11
+ self.host = host
12
+
13
+ @abstractmethod
14
+ async def async_get_access_token(self) -> str:
15
+ """Return a valid access token."""
16
+
17
+ async def request(self, method, url, **kwargs) -> ClientResponse:
18
+ """Make a request."""
19
+ headers = kwargs.get("headers")
20
+
21
+ if headers is None:
22
+ headers = {}
23
+ else:
24
+ headers = dict(headers)
25
+
26
+ access_token = await self.async_get_access_token()
27
+ headers["authorization"] = f"Bearer {access_token}"
28
+
29
+ return await self.websession.request(
30
+ method,
31
+ f"{self.host}/{url}",
32
+ **kwargs,
33
+ headers=headers,
34
+ )
@@ -0,0 +1,47 @@
1
+ from dataclasses import dataclass
2
+
3
+ from weheat.configuration import Configuration
4
+ from weheat.api_client import ApiClient
5
+ from weheat.api.heat_pump_api import HeatPumpApi
6
+
7
+
8
+ class HeatPumpDiscovery:
9
+ @dataclass
10
+ class HeatPumpInfo:
11
+ uuid: str
12
+ name: str
13
+ model: str
14
+ sn : str
15
+ has_dhw: bool = False
16
+
17
+ @staticmethod
18
+ def discover(api_url: str, access_token: str) -> list[HeatPumpInfo]:
19
+ discovered_pumps = []
20
+
21
+ config = Configuration(host=api_url, access_token=access_token)
22
+
23
+ with ApiClient(configuration=config) as client:
24
+ # try:
25
+ response = HeatPumpApi(client).api_v1_heat_pumps_get_with_http_info()
26
+ if response.status_code == 200:
27
+ for pump in response.data:
28
+ model_string = "BlackBird P80 heat pump"
29
+ if pump.model == 1:
30
+ model_string = "BlackBird P60 heat pump"
31
+ elif pump.model == 2:
32
+ model_string = "Sparrow P60 heat pump"
33
+
34
+ dhw = False
35
+ if pump.dhw_type is not None and pump.dhw_type == 1:
36
+ dhw = True
37
+
38
+ discovered_pumps.append(
39
+ HeatPumpDiscovery.HeatPumpInfo(
40
+ uuid=pump.id,
41
+ name=pump.name,
42
+ model=model_string,
43
+ sn=pump.serial_number,
44
+ has_dhw=dhw,
45
+ )
46
+ )
47
+ return discovered_pumps
@@ -0,0 +1,150 @@
1
+ from enum import Enum, auto
2
+ from weheat.configuration import Configuration
3
+ from weheat.api_client import ApiClient
4
+ from weheat.api.heat_pump_log_api import HeatPumpLogApi
5
+
6
+
7
+ class HeatPump:
8
+ class State(Enum):
9
+ UNDEFINED = auto()
10
+ STANDBY = auto()
11
+ WATER_CHECK = auto()
12
+ HEATING = auto()
13
+ COOLING = auto()
14
+ DHW = auto()
15
+ LEGIONELLA_PREVENTION = auto()
16
+ DEFROSTING = auto()
17
+ SELF_TEST = auto()
18
+ MANUAL_CONTROL = auto()
19
+
20
+ def __init__(self, api_url: str, uuid: str) -> None:
21
+ self._api_url = api_url
22
+ self._uuid = uuid
23
+ self._last_log = None
24
+
25
+ def get_status(self, access_token: str):
26
+ try:
27
+ config = Configuration(host=self._api_url, access_token=access_token)
28
+
29
+ with ApiClient(configuration=config) as client:
30
+ response = HeatPumpLogApi(
31
+ client
32
+ ).api_v1_heat_pumps_heat_pump_id_logs_latest_get_with_http_info(
33
+ heat_pump_id=self._uuid
34
+ )
35
+ if response.status_code == 200:
36
+ self._last_log = response.data
37
+ except Exception as e:
38
+ self._last_log = None
39
+ raise e
40
+
41
+ def _update_properties(self):
42
+ pass
43
+
44
+ def _if_available(self, key):
45
+ if self._last_log is not None and hasattr(self._last_log, key):
46
+ return getattr(self._last_log, key)
47
+ return None
48
+
49
+ def __str__(self):
50
+ return f"WeheatHeatPump(uuid={self._uuid}, last update={self._if_available('timestamp')})"
51
+
52
+ def __repr__(self):
53
+ return self.__str__()
54
+
55
+ @property
56
+ def water_inlet_temperature(self):
57
+ return self._if_available("t_water_in")
58
+
59
+ @property
60
+ def water_outlet_temperature(self):
61
+ return self._if_available("t_water_out")
62
+
63
+ @property
64
+ def water_house_in_temperature(self):
65
+ return self._if_available("t_water_house_in")
66
+
67
+ @property
68
+ def air_inlet_temperature(self):
69
+ return self._if_available("t_air_in")
70
+
71
+ @property
72
+ def air_outlet_temperature(self):
73
+ return self._if_available("t_air_out")
74
+
75
+ @property
76
+ def thermostat_water_setpoint(self):
77
+ return self._if_available("t_thermostat_setpoint")
78
+
79
+ @property
80
+ def thermostat_room_temperature(self):
81
+ return self._if_available("t_room")
82
+
83
+ @property
84
+ def thermostat_room_temperature_setpoint(self):
85
+ return self._if_available("t_room_target")
86
+
87
+ @property
88
+ def thermostat_on_off_state(self):
89
+ return self._if_available("on_off_thermostat_state")
90
+
91
+ @property
92
+ def power_input(self):
93
+ return self._if_available("cm_mass_power_in")
94
+
95
+ @property
96
+ def power_output(self):
97
+ return self._if_available("cm_mass_power_out")
98
+
99
+ @property
100
+ def cop(self):
101
+ """
102
+ Returns the coefficient of performance of the heat pump.
103
+ Note that this is calculated from a singular log entry and might not be accurate when the
104
+ heat pump is changing its output power or switching states
105
+ """
106
+ input = self.power_input
107
+ output = self.power_output
108
+ if input is not None and output is not None and input != 0:
109
+ return output / input
110
+
111
+ @property
112
+ def inside_unit_water_pump_state(self):
113
+ return self._if_available("control_bridge_status_decoded_water_pump")
114
+
115
+ @property
116
+ def inside_unit_auxilary_pump_state(self):
117
+ return self._if_available("control_bridge_status_decoded_water_pump2")
118
+
119
+ @property
120
+ def inside_unit_dhw_valve_or_pump_state(self):
121
+ return self._if_available("control_bridge_status_decoded_dhw_valve")
122
+
123
+ @property
124
+ def inside_unit_gas_boiler_state(self):
125
+ return self._if_available("control_bridge_status_decoded_gas_boiler")
126
+
127
+ @property
128
+ def heat_pump_state(self) -> State:
129
+ numeric_state = self._if_available("state")
130
+ if numeric_state is None:
131
+ return self.State.UNDEFINED
132
+
133
+ if numeric_state == 40:
134
+ return self.State.STANDBY
135
+ elif numeric_state == 70:
136
+ return self.State.HEATING
137
+ elif numeric_state == 130:
138
+ return self.State.COOLING
139
+ elif numeric_state == 150:
140
+ return self.State.DHW
141
+ elif numeric_state == 160:
142
+ return self.State.LEGIONELLA_PREVENTION
143
+ elif numeric_state == 170:
144
+ return self.State.SELF_TEST
145
+ elif numeric_state == 180:
146
+ return self.State.MANUAL_CONTROL
147
+ elif numeric_state == 200:
148
+ return self.State.DEFROSTING
149
+ else:
150
+ return self.State.UNDEFINED
weheat/api/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ # flake8: noqa
2
+
3
+ # import apis into api package
4
+ from weheat.api.energy_log_api import EnergyLogApi
5
+ from weheat.api.heat_pump_api import HeatPumpApi
6
+ from weheat.api.heat_pump_log_api import HeatPumpLogApi
@@ -0,0 +1,228 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ Weheat Backend
5
+
6
+ This is the backend for the Weheat project
7
+
8
+ The version of the OpenAPI document: v1
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+
15
+ import re # noqa: F401
16
+ import io
17
+ import warnings
18
+
19
+ from pydantic import validate_arguments, ValidationError
20
+
21
+ from typing_extensions import Annotated
22
+ from datetime import datetime
23
+
24
+ from pydantic import Field, StrictStr
25
+
26
+ from typing import List, Optional
27
+
28
+ from weheat.models.energy_view_dto import EnergyViewDto
29
+
30
+ from weheat.api_client import ApiClient
31
+ from weheat.api_response import ApiResponse
32
+ from weheat.exceptions import ( # noqa: F401
33
+ ApiTypeError,
34
+ ApiValueError
35
+ )
36
+
37
+
38
+ class EnergyLogApi:
39
+ """NOTE: This class is auto generated by OpenAPI Generator
40
+ Ref: https://openapi-generator.tech
41
+
42
+ Do not edit the class manually.
43
+ """
44
+
45
+ def __init__(self, api_client=None) -> None:
46
+ if api_client is None:
47
+ api_client = ApiClient.get_default()
48
+ self.api_client = api_client
49
+
50
+ @validate_arguments
51
+ def api_v1_energy_logs_heat_pump_id_get(self, heat_pump_id : Annotated[StrictStr, Field(..., description="The id of the heat pump")], start_time : Annotated[Optional[datetime], Field(description="Start time of the interval as a DateTime object in UTC (format: yyyy-MM-dd HH:mm:ss)")] = None, end_time : Annotated[Optional[datetime], Field(description="End time of the interval as a DateTime object in UTC (format: yyyy-MM-dd HH:mm:ss)")] = None, interval : Annotated[Optional[StrictStr], Field(description="Interval granularity of the log data, allowed intervals: \"Hour\", \"Day\", \"Week\", \"Month\", \"Year\"")] = None, x_version : Annotated[Optional[StrictStr], Field(description="Optional version parameter for frontend applications to check if an update / refresh is needed")] = None, **kwargs) -> List[EnergyViewDto]: # noqa: E501
52
+ """Gets the energy logs of the heat pump in a from start time to end time for a given interval Correct Intervals include: Hour, Day, Week, Month, Year Hour logs are rounded to 3 decimals, other logs to 2 decimals # noqa: E501
53
+
54
+ This method makes a synchronous HTTP request by default. To make an
55
+ asynchronous HTTP request, please pass async_req=True
56
+
57
+ >>> thread = api.api_v1_energy_logs_heat_pump_id_get(heat_pump_id, start_time, end_time, interval, x_version, async_req=True)
58
+ >>> result = thread.get()
59
+
60
+ :param heat_pump_id: The id of the heat pump (required)
61
+ :type heat_pump_id: str
62
+ :param start_time: Start time of the interval as a DateTime object in UTC (format: yyyy-MM-dd HH:mm:ss)
63
+ :type start_time: datetime
64
+ :param end_time: End time of the interval as a DateTime object in UTC (format: yyyy-MM-dd HH:mm:ss)
65
+ :type end_time: datetime
66
+ :param interval: Interval granularity of the log data, allowed intervals: \"Hour\", \"Day\", \"Week\", \"Month\", \"Year\"
67
+ :type interval: str
68
+ :param x_version: Optional version parameter for frontend applications to check if an update / refresh is needed
69
+ :type x_version: str
70
+ :param async_req: Whether to execute the request asynchronously.
71
+ :type async_req: bool, optional
72
+ :param _request_timeout: timeout setting for this request.
73
+ If one number provided, it will be total request
74
+ timeout. It can also be a pair (tuple) of
75
+ (connection, read) timeouts.
76
+ :return: Returns the result object.
77
+ If the method is called asynchronously,
78
+ returns the request thread.
79
+ :rtype: List[EnergyViewDto]
80
+ """
81
+ kwargs['_return_http_data_only'] = True
82
+ if '_preload_content' in kwargs:
83
+ message = "Error! Please call the api_v1_energy_logs_heat_pump_id_get_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501
84
+ raise ValueError(message)
85
+ return self.api_v1_energy_logs_heat_pump_id_get_with_http_info(heat_pump_id, start_time, end_time, interval, x_version, **kwargs) # noqa: E501
86
+
87
+ @validate_arguments
88
+ def api_v1_energy_logs_heat_pump_id_get_with_http_info(self, heat_pump_id : Annotated[StrictStr, Field(..., description="The id of the heat pump")], start_time : Annotated[Optional[datetime], Field(description="Start time of the interval as a DateTime object in UTC (format: yyyy-MM-dd HH:mm:ss)")] = None, end_time : Annotated[Optional[datetime], Field(description="End time of the interval as a DateTime object in UTC (format: yyyy-MM-dd HH:mm:ss)")] = None, interval : Annotated[Optional[StrictStr], Field(description="Interval granularity of the log data, allowed intervals: \"Hour\", \"Day\", \"Week\", \"Month\", \"Year\"")] = None, x_version : Annotated[Optional[StrictStr], Field(description="Optional version parameter for frontend applications to check if an update / refresh is needed")] = None, **kwargs) -> ApiResponse: # noqa: E501
89
+ """Gets the energy logs of the heat pump in a from start time to end time for a given interval Correct Intervals include: Hour, Day, Week, Month, Year Hour logs are rounded to 3 decimals, other logs to 2 decimals # noqa: E501
90
+
91
+ This method makes a synchronous HTTP request by default. To make an
92
+ asynchronous HTTP request, please pass async_req=True
93
+
94
+ >>> thread = api.api_v1_energy_logs_heat_pump_id_get_with_http_info(heat_pump_id, start_time, end_time, interval, x_version, async_req=True)
95
+ >>> result = thread.get()
96
+
97
+ :param heat_pump_id: The id of the heat pump (required)
98
+ :type heat_pump_id: str
99
+ :param start_time: Start time of the interval as a DateTime object in UTC (format: yyyy-MM-dd HH:mm:ss)
100
+ :type start_time: datetime
101
+ :param end_time: End time of the interval as a DateTime object in UTC (format: yyyy-MM-dd HH:mm:ss)
102
+ :type end_time: datetime
103
+ :param interval: Interval granularity of the log data, allowed intervals: \"Hour\", \"Day\", \"Week\", \"Month\", \"Year\"
104
+ :type interval: str
105
+ :param x_version: Optional version parameter for frontend applications to check if an update / refresh is needed
106
+ :type x_version: str
107
+ :param async_req: Whether to execute the request asynchronously.
108
+ :type async_req: bool, optional
109
+ :param _preload_content: if False, the ApiResponse.data will
110
+ be set to none and raw_data will store the
111
+ HTTP response body without reading/decoding.
112
+ Default is True.
113
+ :type _preload_content: bool, optional
114
+ :param _return_http_data_only: response data instead of ApiResponse
115
+ object with status code, headers, etc
116
+ :type _return_http_data_only: bool, optional
117
+ :param _request_timeout: timeout setting for this request. If one
118
+ number provided, it will be total request
119
+ timeout. It can also be a pair (tuple) of
120
+ (connection, read) timeouts.
121
+ :param _request_auth: set to override the auth_settings for an a single
122
+ request; this effectively ignores the authentication
123
+ in the spec for a single request.
124
+ :type _request_auth: dict, optional
125
+ :type _content_type: string, optional: force content-type for the request
126
+ :return: Returns the result object.
127
+ If the method is called asynchronously,
128
+ returns the request thread.
129
+ :rtype: tuple(List[EnergyViewDto], status_code(int), headers(HTTPHeaderDict))
130
+ """
131
+
132
+ _params = locals()
133
+
134
+ _all_params = [
135
+ 'heat_pump_id',
136
+ 'start_time',
137
+ 'end_time',
138
+ 'interval',
139
+ 'x_version'
140
+ ]
141
+ _all_params.extend(
142
+ [
143
+ 'async_req',
144
+ '_return_http_data_only',
145
+ '_preload_content',
146
+ '_request_timeout',
147
+ '_request_auth',
148
+ '_content_type',
149
+ '_headers'
150
+ ]
151
+ )
152
+
153
+ # validate the arguments
154
+ for _key, _val in _params['kwargs'].items():
155
+ if _key not in _all_params:
156
+ raise ApiTypeError(
157
+ "Got an unexpected keyword argument '%s'"
158
+ " to method api_v1_energy_logs_heat_pump_id_get" % _key
159
+ )
160
+ _params[_key] = _val
161
+ del _params['kwargs']
162
+
163
+ _collection_formats = {}
164
+
165
+ # process the path parameters
166
+ _path_params = {}
167
+ if _params['heat_pump_id'] is not None:
168
+ _path_params['heatPumpId'] = _params['heat_pump_id']
169
+
170
+
171
+ # process the query parameters
172
+ _query_params = []
173
+ if _params.get('start_time') is not None: # noqa: E501
174
+ if isinstance(_params['start_time'], datetime):
175
+ _query_params.append(('startTime', _params['start_time'].strftime(self.api_client.configuration.datetime_format)))
176
+ else:
177
+ _query_params.append(('startTime', _params['start_time']))
178
+
179
+ if _params.get('end_time') is not None: # noqa: E501
180
+ if isinstance(_params['end_time'], datetime):
181
+ _query_params.append(('endTime', _params['end_time'].strftime(self.api_client.configuration.datetime_format)))
182
+ else:
183
+ _query_params.append(('endTime', _params['end_time']))
184
+
185
+ if _params.get('interval') is not None: # noqa: E501
186
+ _query_params.append(('interval', _params['interval']))
187
+
188
+ # process the header parameters
189
+ _header_params = dict(_params.get('_headers', {}))
190
+ if _params['x_version'] is not None:
191
+ _header_params['x-version'] = _params['x_version']
192
+
193
+ # process the form parameters
194
+ _form_params = []
195
+ _files = {}
196
+ # process the body parameter
197
+ _body_params = None
198
+ # set the HTTP header `Accept`
199
+ _header_params['Accept'] = self.api_client.select_header_accept(
200
+ ['text/plain', 'application/json', 'text/json']) # noqa: E501
201
+
202
+ # authentication setting
203
+ _auth_settings = ['oauth2'] # noqa: E501
204
+
205
+ _response_types_map = {
206
+ '403': "str",
207
+ '505': None,
208
+ '200': "List[EnergyViewDto]",
209
+ '400': None,
210
+ '500': None,
211
+ }
212
+
213
+ return self.api_client.call_api(
214
+ '/api/v1/energy-logs/{heatPumpId}', 'GET',
215
+ _path_params,
216
+ _query_params,
217
+ _header_params,
218
+ body=_body_params,
219
+ post_params=_form_params,
220
+ files=_files,
221
+ response_types_map=_response_types_map,
222
+ auth_settings=_auth_settings,
223
+ async_req=_params.get('async_req'),
224
+ _return_http_data_only=_params.get('_return_http_data_only'), # noqa: E501
225
+ _preload_content=_params.get('_preload_content', True),
226
+ _request_timeout=_params.get('_request_timeout'),
227
+ collection_formats=_collection_formats,
228
+ _request_auth=_params.get('_request_auth'))