gazpar2haws 0.3.0b23__tar.gz → 0.3.0b25__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/CHANGELOG.md +5 -1
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/PKG-INFO +4 -4
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/gazpar2haws/__main__.py +3 -0
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/gazpar2haws/date_array.py +20 -18
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/gazpar2haws/gazpar.py +5 -5
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/gazpar2haws/model.py +2 -1
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/gazpar2haws/pricer.py +9 -1
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/pyproject.toml +4 -4
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/LICENSE +0 -0
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/README.md +0 -0
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/gazpar2haws/__init__.py +0 -0
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/gazpar2haws/bridge.py +0 -0
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/gazpar2haws/config_utils.py +0 -0
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/gazpar2haws/configuration.py +0 -0
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/gazpar2haws/haws.py +0 -0
- {gazpar2haws-0.3.0b23 → gazpar2haws-0.3.0b25}/gazpar2haws/version.py +0 -0
@@ -5,12 +5,16 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
-
## [0.3.0] - 2025-02-
|
8
|
+
## [0.3.0] - 2025-02-15
|
9
9
|
|
10
10
|
### Added
|
11
11
|
|
12
12
|
[#31](https://github.com/ssenart/gazpar2haws/issues/31): Cost integration.
|
13
13
|
|
14
|
+
### Changed
|
15
|
+
|
16
|
+
[#60](https://github.com/ssenart/gazpar2haws/issues/60): Upgrade PyGazpar library version to 1.3.0.
|
17
|
+
|
14
18
|
## [0.2.1] - 2025-01-24
|
15
19
|
|
16
20
|
### Fixed
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: gazpar2haws
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.0b25
|
4
4
|
Summary: Gazpar2HAWS is a gateway that reads data history from the GrDF (French gas provider) meter and send it to Home Assistant using WebSocket interface
|
5
5
|
License: MIT License
|
6
6
|
|
@@ -24,14 +24,14 @@ License: MIT License
|
|
24
24
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
25
25
|
SOFTWARE.
|
26
26
|
Author: Stéphane Senart
|
27
|
-
Requires-Python: >=3.
|
28
|
-
Classifier: Programming Language :: Python :: 3.9
|
27
|
+
Requires-Python: >=3.10
|
29
28
|
Classifier: Programming Language :: Python :: 3.10
|
30
29
|
Classifier: Programming Language :: Python :: 3.11
|
31
30
|
Classifier: Programming Language :: Python :: 3.12
|
31
|
+
Classifier: Programming Language :: Python :: 3.13
|
32
32
|
Requires-Dist: pydantic-extra-types (>=2.10.2,<3.0.0)
|
33
33
|
Requires-Dist: pydantic[email] (>=2.10.6,<3.0.0)
|
34
|
-
Requires-Dist: pygazpar (>=1.
|
34
|
+
Requires-Dist: pygazpar (>=1.3.0b4)
|
35
35
|
Requires-Dist: pyyaml (>=6.0.2)
|
36
36
|
Requires-Dist: websockets (>=14.1)
|
37
37
|
Description-Content-Type: text/markdown
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import argparse
|
2
2
|
import asyncio
|
3
3
|
import logging
|
4
|
+
import sys
|
4
5
|
import traceback
|
5
6
|
|
6
7
|
from gazpar2haws import __version__
|
@@ -40,6 +41,7 @@ async def main():
|
|
40
41
|
config = Configuration.load(args.config, args.secrets)
|
41
42
|
|
42
43
|
print(f"Gazpar2HAWS version: {__version__}")
|
44
|
+
print(f"Running on Python version: {sys.version}")
|
43
45
|
|
44
46
|
# Set up logging
|
45
47
|
logging_file = config.logging.file
|
@@ -73,6 +75,7 @@ async def main():
|
|
73
75
|
logging.getLogger().addHandler(console_handler)
|
74
76
|
|
75
77
|
Logger.info(f"Starting Gazpar2HAWS version {__version__}")
|
78
|
+
Logger.info(f"Running on Python version: {sys.version}")
|
76
79
|
|
77
80
|
# Log configuration
|
78
81
|
Logger.info(f"Configuration:\n{config.dumps()}")
|
@@ -11,6 +11,7 @@ from pydantic import BaseModel, ConfigDict, model_validator
|
|
11
11
|
class DateArray(BaseModel): # pylint: disable=too-few-public-methods
|
12
12
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
13
13
|
|
14
|
+
name: Optional[str] = None
|
14
15
|
start_date: dt.date
|
15
16
|
end_date: dt.date
|
16
17
|
array: Optional[np.ndarray] = None
|
@@ -39,7 +40,7 @@ class DateArray(BaseModel): # pylint: disable=too-few-public-methods
|
|
39
40
|
if self.array is None:
|
40
41
|
raise ValueError("Array is not initialized")
|
41
42
|
|
42
|
-
result = DateArray(start_date=self.start_date, end_date=self.end_date)
|
43
|
+
result = DateArray(name=f"cumsum_{self.name}", start_date=self.start_date, end_date=self.end_date)
|
43
44
|
result.array = np.cumsum(self.array)
|
44
45
|
return result
|
45
46
|
|
@@ -77,7 +78,10 @@ class DateArray(BaseModel): # pylint: disable=too-few-public-methods
|
|
77
78
|
f"Date slice [{start_date}:{end_date}] is out of range [{self.start_date}:{self.end_date}]"
|
78
79
|
)
|
79
80
|
return DateArray(
|
80
|
-
|
81
|
+
name=self.name,
|
82
|
+
start_date=start_date,
|
83
|
+
end_date=end_date + timedelta(-1),
|
84
|
+
array=self.array[start_index:end_index],
|
81
85
|
)
|
82
86
|
raise TypeError("Key must be a date or a slice of dates")
|
83
87
|
|
@@ -110,8 +114,6 @@ class DateArray(BaseModel): # pylint: disable=too-few-public-methods
|
|
110
114
|
raise ValueError(
|
111
115
|
f"Date slice [{start_date}:{end_date}] is out of range [{self.start_date}:{self.end_date}]"
|
112
116
|
)
|
113
|
-
self.start_date = start_date
|
114
|
-
self.end_date = end_date + timedelta(-1)
|
115
117
|
if isinstance(value, float):
|
116
118
|
self.array[start_index:end_index] = value
|
117
119
|
elif isinstance(value, DateArray):
|
@@ -156,15 +158,15 @@ class DateArray(BaseModel): # pylint: disable=too-few-public-methods
|
|
156
158
|
raise ValueError("Array is not initialized")
|
157
159
|
|
158
160
|
if isinstance(other, (int, float)):
|
159
|
-
result = DateArray(start_date=self.start_date, end_date=self.end_date)
|
161
|
+
result = DateArray(name=self.name, start_date=self.start_date, end_date=self.end_date)
|
160
162
|
result.array = self.array + other
|
161
163
|
return result
|
162
164
|
if isinstance(other, DateArray):
|
163
165
|
if other.array is None:
|
164
166
|
raise ValueError("Array is not initialized")
|
165
167
|
if not self.is_aligned_with(other):
|
166
|
-
raise ValueError("Date arrays are not aligned")
|
167
|
-
result = DateArray(start_date=self.start_date, end_date=self.end_date)
|
168
|
+
raise ValueError(f"Date arrays {self} and {other} are not aligned")
|
169
|
+
result = DateArray(name=self.name, start_date=self.start_date, end_date=self.end_date)
|
168
170
|
result.array = self.array + other.array # pylint: disable=protected-access
|
169
171
|
return result
|
170
172
|
|
@@ -183,15 +185,15 @@ class DateArray(BaseModel): # pylint: disable=too-few-public-methods
|
|
183
185
|
raise ValueError("Array is not initialized")
|
184
186
|
|
185
187
|
if isinstance(other, (int, float)):
|
186
|
-
result = DateArray(start_date=self.start_date, end_date=self.end_date)
|
188
|
+
result = DateArray(name=self.name, start_date=self.start_date, end_date=self.end_date)
|
187
189
|
result.array = self.array - other
|
188
190
|
return result
|
189
191
|
if isinstance(other, DateArray):
|
190
192
|
if other.array is None:
|
191
193
|
raise ValueError("Array is not initialized")
|
192
194
|
if not self.is_aligned_with(other):
|
193
|
-
raise ValueError("Date arrays are not aligned")
|
194
|
-
result = DateArray(start_date=self.start_date, end_date=self.end_date)
|
195
|
+
raise ValueError(f"Date arrays {self} and {other} are not aligned")
|
196
|
+
result = DateArray(name=self.name, start_date=self.start_date, end_date=self.end_date)
|
195
197
|
result.array = self.array - other.array # pylint: disable=protected-access
|
196
198
|
return result
|
197
199
|
|
@@ -210,15 +212,15 @@ class DateArray(BaseModel): # pylint: disable=too-few-public-methods
|
|
210
212
|
raise ValueError("Array is not initialized")
|
211
213
|
|
212
214
|
if isinstance(other, (int, float)):
|
213
|
-
result = DateArray(start_date=self.start_date, end_date=self.end_date)
|
215
|
+
result = DateArray(name=self.name, start_date=self.start_date, end_date=self.end_date)
|
214
216
|
result.array = self.array * other
|
215
217
|
return result
|
216
218
|
if isinstance(other, DateArray):
|
217
219
|
if other.array is None:
|
218
220
|
raise ValueError("Array is not initialized")
|
219
221
|
if not self.is_aligned_with(other):
|
220
|
-
raise ValueError("Date arrays are not aligned")
|
221
|
-
result = DateArray(start_date=self.start_date, end_date=self.end_date)
|
222
|
+
raise ValueError(f"Date arrays {self} and {other} are not aligned")
|
223
|
+
result = DateArray(name=self.name, start_date=self.start_date, end_date=self.end_date)
|
222
224
|
result.array = self.array * other.array # pylint: disable=protected-access
|
223
225
|
return result
|
224
226
|
|
@@ -237,21 +239,21 @@ class DateArray(BaseModel): # pylint: disable=too-few-public-methods
|
|
237
239
|
raise ValueError("Array is not initialized")
|
238
240
|
|
239
241
|
if isinstance(other, (int, float)):
|
240
|
-
result = DateArray(start_date=self.start_date, end_date=self.end_date)
|
242
|
+
result = DateArray(name=self.name, start_date=self.start_date, end_date=self.end_date)
|
241
243
|
result.array = self.array / other
|
242
244
|
return result
|
243
245
|
if isinstance(other, DateArray):
|
244
246
|
if other.array is None:
|
245
247
|
raise ValueError("Array is not initialized")
|
246
248
|
if not self.is_aligned_with(other):
|
247
|
-
raise ValueError("Date arrays are not aligned")
|
248
|
-
result = DateArray(start_date=self.start_date, end_date=self.end_date)
|
249
|
+
raise ValueError(f"Date arrays {self} and {other} are not aligned")
|
250
|
+
result = DateArray(name=self.name, start_date=self.start_date, end_date=self.end_date)
|
249
251
|
result.array = self.array / other.array # pylint: disable=protected-access
|
250
252
|
return result
|
251
253
|
|
252
254
|
raise TypeError("Other must be a date array or a number")
|
253
255
|
|
254
256
|
# ----------------------------------
|
255
|
-
def
|
257
|
+
def __str__(self) -> str:
|
256
258
|
|
257
|
-
return f"DateArray(start_date={self.start_date}, end_date={self.end_date}, array={self.array})"
|
259
|
+
return f"DateArray(name={self.name}, start_date={self.start_date}, end_date={self.end_date}, array={self.array}, slots={(self.end_date - self.start_date).days + 1}, length={len(self)})"
|
@@ -209,10 +209,10 @@ class Gazpar:
|
|
209
209
|
client = pygazpar.Client(data_source)
|
210
210
|
|
211
211
|
try:
|
212
|
-
history = client.
|
213
|
-
|
214
|
-
|
215
|
-
|
212
|
+
history = client.load_date_range(
|
213
|
+
pce_identifier=self._pce_identifier,
|
214
|
+
start_date=start_date,
|
215
|
+
end_date=end_date,
|
216
216
|
frequencies=[pygazpar.Frequency.DAILY],
|
217
217
|
)
|
218
218
|
|
@@ -260,7 +260,7 @@ class Gazpar:
|
|
260
260
|
# Fill the quantity array.
|
261
261
|
if reading[property_name] is not None:
|
262
262
|
if res is None:
|
263
|
-
res = DateArray(start_date=start_date, end_date=end_date)
|
263
|
+
res = DateArray(name=property_name, start_date=start_date, end_date=end_date)
|
264
264
|
res[reading_date] = reading[property_name]
|
265
265
|
|
266
266
|
return res
|
@@ -104,13 +104,14 @@ class Value(Period):
|
|
104
104
|
|
105
105
|
# ----------------------------------
|
106
106
|
class ValueArray(Period):
|
107
|
+
name: Optional[str] = None
|
107
108
|
value_array: Optional[DateArray] = None
|
108
109
|
|
109
110
|
@model_validator(mode="after")
|
110
111
|
def set_value_array(self):
|
111
112
|
if self.value_array is None:
|
112
113
|
self.value_array = DateArray(
|
113
|
-
start_date=self.start_date, end_date=self.end_date
|
114
|
+
name=self.name, start_date=self.start_date, end_date=self.end_date
|
114
115
|
) # pylint: disable=attribute-defined-outside-init
|
115
116
|
return self
|
116
117
|
|
@@ -105,6 +105,7 @@ class Pricer:
|
|
105
105
|
)
|
106
106
|
else:
|
107
107
|
subscription_price_array = SubscriptionPriceArray(
|
108
|
+
name="subscription_prices",
|
108
109
|
start_date=start_date,
|
109
110
|
end_date=end_date,
|
110
111
|
value_unit=price_unit,
|
@@ -121,6 +122,7 @@ class Pricer:
|
|
121
122
|
)
|
122
123
|
else:
|
123
124
|
transport_price_array = TransportPriceArray(
|
125
|
+
name="transport_prices",
|
124
126
|
start_date=start_date,
|
125
127
|
end_date=end_date,
|
126
128
|
value_unit=price_unit,
|
@@ -137,6 +139,7 @@ class Pricer:
|
|
137
139
|
)
|
138
140
|
else:
|
139
141
|
energy_taxes_price_array = EnergyTaxesPriceArray(
|
142
|
+
name="energy_taxes",
|
140
143
|
start_date=start_date,
|
141
144
|
end_date=end_date,
|
142
145
|
value_unit=price_unit,
|
@@ -144,6 +147,7 @@ class Pricer:
|
|
144
147
|
)
|
145
148
|
|
146
149
|
res = CostArray(
|
150
|
+
name="costs",
|
147
151
|
start_date=start_date,
|
148
152
|
end_date=end_date,
|
149
153
|
value_unit=price_unit,
|
@@ -167,7 +171,7 @@ class Pricer:
|
|
167
171
|
res = dict[str, VatRateArray]()
|
168
172
|
vat_rate_by_id = dict[str, list[VatRate]]()
|
169
173
|
for vat_rate in vat_rates:
|
170
|
-
res[vat_rate.id] = VatRateArray(id=vat_rate.id, start_date=start_date, end_date=end_date)
|
174
|
+
res[vat_rate.id] = VatRateArray(name="vats", id=vat_rate.id, start_date=start_date, end_date=end_date)
|
171
175
|
if vat_rate.id not in vat_rate_by_id:
|
172
176
|
vat_rate_by_id[vat_rate.id] = list[VatRate]()
|
173
177
|
vat_rate_by_id[vat_rate.id].append(vat_rate)
|
@@ -193,6 +197,7 @@ class Pricer:
|
|
193
197
|
first_consumption_price = consumption_prices[0]
|
194
198
|
|
195
199
|
res = ConsumptionPriceArray(
|
200
|
+
name="consumption_prices",
|
196
201
|
start_date=start_date,
|
197
202
|
end_date=end_date,
|
198
203
|
value_unit=first_consumption_price.value_unit,
|
@@ -220,6 +225,7 @@ class Pricer:
|
|
220
225
|
first_subscription_price = subscription_prices[0]
|
221
226
|
|
222
227
|
res = SubscriptionPriceArray(
|
228
|
+
name="subscription_prices",
|
223
229
|
start_date=start_date,
|
224
230
|
end_date=end_date,
|
225
231
|
value_unit=first_subscription_price.value_unit,
|
@@ -247,6 +253,7 @@ class Pricer:
|
|
247
253
|
first_transport_price = transport_prices[0]
|
248
254
|
|
249
255
|
res = TransportPriceArray(
|
256
|
+
name="transport_prices",
|
250
257
|
start_date=start_date,
|
251
258
|
end_date=end_date,
|
252
259
|
value_unit=first_transport_price.value_unit,
|
@@ -274,6 +281,7 @@ class Pricer:
|
|
274
281
|
first_energy_taxes_price = energy_taxes_prices[0]
|
275
282
|
|
276
283
|
res = EnergyTaxesPriceArray(
|
284
|
+
name="energy_taxes",
|
277
285
|
start_date=start_date,
|
278
286
|
end_date=end_date,
|
279
287
|
value_unit=first_energy_taxes_price.value_unit,
|
@@ -1,21 +1,21 @@
|
|
1
1
|
[project]
|
2
2
|
name = "gazpar2haws"
|
3
|
-
version = "0.3.
|
3
|
+
version = "0.3.0b25"
|
4
4
|
description = "Gazpar2HAWS is a gateway that reads data history from the GrDF (French gas provider) meter and send it to Home Assistant using WebSocket interface"
|
5
5
|
license = { file = "LICENSE" }
|
6
6
|
readme = "README.md"
|
7
|
-
requires-python = ">=3.
|
7
|
+
requires-python = ">=3.10"
|
8
8
|
authors = [
|
9
9
|
{ name = "Stéphane Senart" }
|
10
10
|
]
|
11
11
|
classifiers = [
|
12
|
-
"Programming Language :: Python :: 3.9",
|
13
12
|
"Programming Language :: Python :: 3.10",
|
14
13
|
"Programming Language :: Python :: 3.11",
|
15
14
|
"Programming Language :: Python :: 3.12",
|
15
|
+
"Programming Language :: Python :: 3.13",
|
16
16
|
]
|
17
17
|
dependencies = [
|
18
|
-
"pygazpar>=1.
|
18
|
+
"pygazpar>=1.3.0b4",
|
19
19
|
"websockets>=14.1",
|
20
20
|
"pyyaml>=6.0.2",
|
21
21
|
"pydantic[email] (>=2.10.6,<3.0.0)",
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|