juham-automation 0.0.16__tar.gz → 0.0.19__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.
- {juham_automation-0.0.16/juham_automation.egg-info → juham_automation-0.0.19}/PKG-INFO +1 -1
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/automation/hotwateroptimizer.py +84 -37
- {juham_automation-0.0.16 → juham_automation-0.0.19/juham_automation.egg-info}/PKG-INFO +1 -1
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation.egg-info/SOURCES.txt +1 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/pyproject.toml +1 -1
- juham_automation-0.0.19/tests/__pycache__/__init__.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/__pycache__/test_hotwateroptimizer.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/test_hotwateroptimizer.py +44 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/LICENSE.rst +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/MANIFEST.in +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/README.rst +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/docs/source/CHANGELOG.rst +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/docs/source/CONTRIBUTING.rst +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/docs/source/LICENSE.rst +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/docs/source/README.rst +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/examples/myapp.log +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/examples/myapp.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/__init__.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/automation/__init__.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/automation/energycostcalculator.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/automation/powermeter_simulator.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/automation/spothintafi.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/automation/watercirculator.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/japp.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/py.typed +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/ts/__init__.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/ts/electricityprice_ts.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/ts/energycostcalculator_ts.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/ts/forecast_ts.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/ts/log_ts.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/ts/power_ts.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/ts/powermeter_ts.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/ts/powerplan_ts.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation.egg-info/dependency_links.txt +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation.egg-info/entry_points.txt +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation.egg-info/requires.txt +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation.egg-info/top_level.txt +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/setup.cfg +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/__init__.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/__pycache__/test_japp.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/__init__.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/__pycache__/__init__.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/__pycache__/test_energycostcalculator.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/__pycache__/test_juham.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/__pycache__/test_powermeter_simulator.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/__pycache__/test_spothintafi.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/test_energycostcalculator.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/test_juham.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/test_spothintafi.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/test_japp.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/__init__.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/__pycache__/__init__.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/__pycache__/test_energycostcalculator_ts.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/__pycache__/test_forecast_ts.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/__pycache__/test_log_ts.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/__pycache__/test_power_ts.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/__pycache__/test_powermeter_ts.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/__pycache__/test_powerplan_ts.cpython-312.pyc +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/test_energycostcalculator_ts.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/test_forecast_ts.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/test_log_ts.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/test_power_ts.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/test_powermeter_ts.py +0 -0
- {juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/test_powerplan_ts.py +0 -0
{juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/automation/hotwateroptimizer.py
RENAMED
@@ -16,13 +16,17 @@ from juham_core.timeutils import (
|
|
16
16
|
|
17
17
|
class HotWaterOptimizer(Juham):
|
18
18
|
"""Automation class for optimized control of temperature driven home energy consumers e.g hot
|
19
|
-
water radiators. Reads spot prices, electricity forecast and temperatures to minimize electricity bill.
|
20
|
-
Additional control over heating is provided by the following attributes
|
19
|
+
water radiators. Reads spot prices, electricity forecast, power meter and temperatures to minimize electricity bill.
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
Represents a heating system that knows the power rating of its radiator (e.g., 3kW).
|
22
|
+
The system subscribes to the 'power' topic to track the current power balance. If the solar panels
|
23
|
+
generate more energy than is being consumed, the optimizer activates a relay to ensure that all excess energy
|
24
|
+
produced within that hour is used for heating. The goal is to achieve a net zero energy balance for each hour,
|
25
|
+
ensuring that any surplus energy from the solar panels is fully utilized.
|
25
26
|
|
27
|
+
Computes also UOI - optimization utilization index for each hour, based on the spot price and the solar power forecast.
|
28
|
+
For negative energy balance this determines when energy is consumed. Value of 0 means the hour is expensive, value of 1 means
|
29
|
+
the hour is free. The UOI threshold determines the slots that are allowed to be consumed.
|
26
30
|
|
27
31
|
"""
|
28
32
|
|
@@ -172,41 +176,64 @@ class HotWaterOptimizer(Juham):
|
|
172
176
|
self.debug(f"Forecast sorted for the next {str(len(ranked_hours))} hours")
|
173
177
|
return ranked_hours
|
174
178
|
|
179
|
+
def on_spot(self, m: list[dict[str, Any]], ts_quantized: float) -> None:
|
180
|
+
"""Handle the spot prices.
|
181
|
+
|
182
|
+
Args:
|
183
|
+
list[dict[str, Any]]: list of spot prices
|
184
|
+
ts_quantized (float): current time
|
185
|
+
"""
|
186
|
+
self.ranked_spot_prices = self.sort_by_rank(m, ts_quantized)
|
187
|
+
|
188
|
+
def on_forecast(
|
189
|
+
self, forecast: list[dict[str, Any]], ts_utc_quantized: float
|
190
|
+
) -> None:
|
191
|
+
"""Handle the solar forecast.
|
192
|
+
|
193
|
+
Args:
|
194
|
+
m (list[dict[str, Any]]): list of forecast prices
|
195
|
+
ts_quantized (float): current time
|
196
|
+
"""
|
197
|
+
# reject forecasts that don't have solarenergy key
|
198
|
+
for f in forecast:
|
199
|
+
if not "solarenergy" in f:
|
200
|
+
return
|
201
|
+
|
202
|
+
self.ranked_solarpower = self.sort_by_power(forecast, ts_utc_quantized)
|
203
|
+
self.debug(
|
204
|
+
f"Solar energy forecast received and ranked for {len(self.ranked_solarpower)} hours"
|
205
|
+
)
|
206
|
+
self.power_plan = [] # reset power plan, it depends on forecast
|
207
|
+
|
208
|
+
def on_power(self, m: dict[str, Any], ts: float) -> None:
|
209
|
+
"""Handle the power consumption. Read the current power balance and accumulate
|
210
|
+
to the net energy balance to reflect the energy produced (or consumed) within the
|
211
|
+
current time slot.
|
212
|
+
Args:
|
213
|
+
m (dict[str, Any]): power consumption message
|
214
|
+
ts (float): current time
|
215
|
+
"""
|
216
|
+
self.net_energy_power = m["power"]
|
217
|
+
balance: float = (ts - self.net_energy_balance_ts) * self.net_energy_power
|
218
|
+
self.net_energy_balance = self.net_energy_balance + balance
|
219
|
+
self.net_energy_balance_ts = ts
|
220
|
+
|
175
221
|
@override
|
176
222
|
def on_message(self, client: object, userdata: Any, msg: MqttMsg) -> None:
|
177
223
|
m = None
|
178
224
|
ts: float = timestamp()
|
179
225
|
ts_utc_quantized: float = quantize(3600, ts - 3600)
|
180
226
|
if msg.topic == self.topic_spot:
|
181
|
-
self.
|
182
|
-
json.loads(msg.payload.decode()), ts_utc_quantized
|
183
|
-
)
|
184
|
-
self.debug(
|
185
|
-
f"Spot prices received and ranked for {len(self.ranked_spot_prices)} hours"
|
186
|
-
)
|
187
|
-
self.power_plan = [] # reset power plan, it depends on spot prices
|
227
|
+
self.on_spot(json.loads(msg.payload.decode()), ts_utc_quantized)
|
188
228
|
return
|
189
229
|
elif msg.topic == self.topic_forecast:
|
190
|
-
|
191
|
-
# reject messages that don't have solarenergy forecast
|
192
|
-
|
193
|
-
for f in forecast:
|
194
|
-
if not "solarenergy" in f:
|
195
|
-
return
|
196
|
-
|
197
|
-
self.ranked_solarpower = self.sort_by_power(forecast, ts_utc_quantized)
|
198
|
-
self.debug(
|
199
|
-
f"Solar energy forecast received and ranked for {len(self.ranked_solarpower)} hours"
|
200
|
-
)
|
201
|
-
self.power_plan = [] # reset power plan, it depends on forecast
|
230
|
+
self.on_forecast(json.loads(msg.payload.decode()), ts_utc_quantized)
|
202
231
|
return
|
203
232
|
elif msg.topic == self.topic_temperature:
|
204
233
|
m = json.loads(msg.payload.decode())
|
205
234
|
self.current_temperature = m["temperature"]
|
206
235
|
elif msg.topic == self.topic_in_net_energy_balance:
|
207
|
-
|
208
|
-
self.net_energy_balance = m["energy"]
|
209
|
-
self.net_energy_power = m["power"]
|
236
|
+
self.on_power(json.loads(msg.payload.decode()), ts)
|
210
237
|
elif msg.topic == self.topic_in_powerconsumption:
|
211
238
|
m = json.loads(msg.payload.decode())
|
212
239
|
self.current_power = m["real_total"]
|
@@ -216,7 +243,10 @@ class HotWaterOptimizer(Juham):
|
|
216
243
|
self.on_powerplan(ts)
|
217
244
|
|
218
245
|
def on_powerplan(self, ts_utc_now: float) -> None:
|
219
|
-
"""Apply power plan.
|
246
|
+
"""Apply the power plan. Check if the relay needs to be switched on or off.
|
247
|
+
The relay is switched on if the current temperature is below the maximum
|
248
|
+
temperature and the current time is within the heating plan. The relay is switched off
|
249
|
+
if the current temperature is above the maximum temperature or the current time is outside.
|
220
250
|
|
221
251
|
Args:
|
222
252
|
ts_utc_now (float): utc time
|
@@ -299,28 +329,43 @@ class HotWaterOptimizer(Juham):
|
|
299
329
|
bool: true if production exceeds the consumption
|
300
330
|
"""
|
301
331
|
|
332
|
+
# if net energy balance is negative, then we are not in balancing mode
|
333
|
+
if self.net_energy_balance < 0:
|
334
|
+
return False
|
335
|
+
|
302
336
|
# elapsed and remaining time within the current balancing slot
|
303
337
|
elapsed_ts = ts - quantize(self.energy_balancing_interval, ts)
|
304
338
|
remaining_ts = self.energy_balancing_interval - elapsed_ts
|
305
339
|
|
306
340
|
# don't bother to switch the relay on for small intervals, to avoid
|
307
341
|
# wearing contactors out
|
308
|
-
if
|
342
|
+
if (
|
343
|
+
not self.net_energy_balancing_mode
|
344
|
+
and remaining_ts < self.operation_threshold
|
345
|
+
):
|
309
346
|
print(
|
310
347
|
f"Skipping balance, remaining time {remaining_ts}s < {self.operation_threshold}s"
|
311
348
|
)
|
312
349
|
return False
|
350
|
+
elif remaining_ts <= 0:
|
351
|
+
self.net_energy_balancing_rc = False # heating off
|
352
|
+
self.info(
|
353
|
+
f"End of the balancing interval reached, disabled with {self.net_energy_balance/3600}kWh left"
|
354
|
+
)
|
355
|
+
self.net_energy_balance = 0.0
|
356
|
+
self.net_energy_balance_ts = ts
|
357
|
+
return False
|
313
358
|
|
314
|
-
# check if the balance is sufficient for heating the
|
315
|
-
# if yes then switch heating on
|
316
|
-
needed_energy =
|
359
|
+
# check if the balance is sufficient for heating the remainin interval
|
360
|
+
# if yes then switch heating on
|
361
|
+
needed_energy = self.radiator_power * remaining_ts
|
317
362
|
elapsed_interval = ts - self.net_energy_balance_ts
|
318
363
|
print(
|
319
|
-
f"Needed energy {needed_energy}
|
364
|
+
f"Needed energy {int(needed_energy)/3600}kWh, current balance {int(self.net_energy_balance/3600)}kWh"
|
320
365
|
)
|
321
366
|
|
322
367
|
if (
|
323
|
-
self.net_energy_balance
|
368
|
+
self.net_energy_balance >= needed_energy
|
324
369
|
) and not self.net_energy_balancing_rc:
|
325
370
|
self.net_energy_balance_ts = ts
|
326
371
|
self.net_energy_balancing_rc = True # heat
|
@@ -330,7 +375,7 @@ class HotWaterOptimizer(Juham):
|
|
330
375
|
# check if we have reach the end of the interval, or consumed all the energy
|
331
376
|
# of the current slot. If so switch the energy balancer mode off
|
332
377
|
if (
|
333
|
-
elapsed_interval > self.energy_balancing_interval
|
378
|
+
elapsed_interval > self.energy_balancing_interval
|
334
379
|
or self.net_energy_balance < 0
|
335
380
|
):
|
336
381
|
self.net_energy_balancing_rc = False # heating off
|
@@ -338,7 +383,9 @@ class HotWaterOptimizer(Juham):
|
|
338
383
|
return self.net_energy_balancing_rc
|
339
384
|
|
340
385
|
def consider_heating(self, ts: float) -> int:
|
341
|
-
"""Consider whether the target boiler needs heating.
|
386
|
+
"""Consider whether the target boiler needs heating. Check first if the solar
|
387
|
+
energy is enough to heat the water the remaining time in the current slot.
|
388
|
+
If not, follow the predefined heating plan computed earlier based on the cheapest spot prices.
|
342
389
|
|
343
390
|
Args:
|
344
391
|
ts (float): current UTC time
|
@@ -349,7 +396,7 @@ class HotWaterOptimizer(Juham):
|
|
349
396
|
|
350
397
|
# check if we have energy to consume, if so return 1
|
351
398
|
if self.consider_net_energy_balance(ts):
|
352
|
-
self.
|
399
|
+
self.info("Net energy balance positive")
|
353
400
|
return 1
|
354
401
|
elif self.net_energy_balancing_mode:
|
355
402
|
balancing_slot_start_ts = quantize(self.energy_balancing_interval, ts)
|
@@ -33,6 +33,7 @@ juham_automation/ts/powermeter_ts.py
|
|
33
33
|
juham_automation/ts/powerplan_ts.py
|
34
34
|
tests/__init__.py
|
35
35
|
tests/test_japp.py
|
36
|
+
tests/__pycache__/__init__.cpython-312.pyc
|
36
37
|
tests/__pycache__/test_japp.cpython-312.pyc
|
37
38
|
tests/automation/__init__.py
|
38
39
|
tests/automation/test_energycostcalculator.py
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
5
5
|
|
6
6
|
[project]
|
7
7
|
name = "juham-automation"
|
8
|
-
version = "0.0.
|
8
|
+
version = "0.0.19"
|
9
9
|
description = "Juha's Ultimate Home Automation Masterpiece"
|
10
10
|
readme = {file = "README.rst", content-type = "text/markdown"}
|
11
11
|
requires-python = ">=3.8"
|
Binary file
|
Binary file
|
{juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/test_hotwateroptimizer.py
RENAMED
@@ -104,6 +104,50 @@ class TestHotWaterOptimizer(unittest.TestCase):
|
|
104
104
|
self.optimizer.on_message(None, None, mock_msg)
|
105
105
|
self.assertEqual(self.optimizer.current_temperature, 55)
|
106
106
|
|
107
|
+
def test_consider_net_energy_balance(self):
|
108
|
+
# Test: Simulate passing time and accumulate energy
|
109
|
+
time_steps = [
|
110
|
+
0,
|
111
|
+
600,
|
112
|
+
1200,
|
113
|
+
1800,
|
114
|
+
2400,
|
115
|
+
3000,
|
116
|
+
3300,
|
117
|
+
3500,
|
118
|
+
3600,
|
119
|
+
] # Time steps in seconds
|
120
|
+
accumulated_power = 0
|
121
|
+
|
122
|
+
# Loop through the time steps and accumulate power
|
123
|
+
for ts in time_steps:
|
124
|
+
accumulated_power += 500000
|
125
|
+
self.optimizer.net_energy_balance = accumulated_power
|
126
|
+
|
127
|
+
# Call the method to check if balancing mode should be activated
|
128
|
+
heating_on = self.optimizer.consider_net_energy_balance(ts)
|
129
|
+
|
130
|
+
# Calculate the remaining energy needed to power the radiator for the rest of the time slot
|
131
|
+
remaining_time = self.optimizer.energy_balancing_interval - ts
|
132
|
+
required_energy = self.optimizer.radiator_power * remaining_time
|
133
|
+
|
134
|
+
# Check if heating was enabled or not based on energy balance
|
135
|
+
if accumulated_power >= required_energy:
|
136
|
+
self.assertTrue(heating_on, f"At time {ts}, heating should be ON")
|
137
|
+
else:
|
138
|
+
self.assertFalse(heating_on, f"At time {ts}, heating should be OFF")
|
139
|
+
|
140
|
+
# Ensure heating state is correct
|
141
|
+
if accumulated_power >= required_energy:
|
142
|
+
self.assertTrue(self.optimizer.net_energy_balancing_rc)
|
143
|
+
else:
|
144
|
+
self.assertFalse(self.optimizer.net_energy_balancing_rc)
|
145
|
+
|
146
|
+
# Check if the correct state transitions happen during the process
|
147
|
+
self.assertTrue(
|
148
|
+
self.optimizer.net_energy_balancing_rc
|
149
|
+
) # At the end of the test, it should be on
|
150
|
+
|
107
151
|
|
108
152
|
if __name__ == "__main__":
|
109
153
|
unittest.main()
|
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
|
{juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/automation/spothintafi.py
RENAMED
File without changes
|
{juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/automation/watercirculator.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/ts/electricityprice_ts.py
RENAMED
File without changes
|
{juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation/ts/energycostcalculator_ts.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation.egg-info/dependency_links.txt
RENAMED
File without changes
|
{juham_automation-0.0.16 → juham_automation-0.0.19}/juham_automation.egg-info/entry_points.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{juham_automation-0.0.16 → juham_automation-0.0.19}/tests/__pycache__/test_japp.cpython-312.pyc
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{juham_automation-0.0.16 → juham_automation-0.0.19}/tests/automation/test_energycostcalculator.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/__pycache__/__init__.cpython-312.pyc
RENAMED
File without changes
|
File without changes
|
File without changes
|
{juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/__pycache__/test_log_ts.cpython-312.pyc
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{juham_automation-0.0.16 → juham_automation-0.0.19}/tests/ts/test_energycostcalculator_ts.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|