pqopen-lib 0.8.4__py3-none-any.whl → 0.8.5__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.
- pqopen/powersystem.py +23 -0
- pqopen/storagecontroller.py +48 -5
- {pqopen_lib-0.8.4.dist-info → pqopen_lib-0.8.5.dist-info}/METADATA +1 -1
- {pqopen_lib-0.8.4.dist-info → pqopen_lib-0.8.5.dist-info}/RECORD +6 -6
- {pqopen_lib-0.8.4.dist-info → pqopen_lib-0.8.5.dist-info}/WHEEL +0 -0
- {pqopen_lib-0.8.4.dist-info → pqopen_lib-0.8.5.dist-info}/licenses/LICENSE +0 -0
pqopen/powersystem.py
CHANGED
|
@@ -676,6 +676,14 @@ class PowerSystem(object):
|
|
|
676
676
|
self._last_known_freq = self.nominal_frequency
|
|
677
677
|
self._calculation_mode = "FALLBACK"
|
|
678
678
|
elif self._calculation_mode == "FALLBACK":
|
|
679
|
+
remaining_virtual_zc = []
|
|
680
|
+
last_rel_zc = self._zero_crossings[-1] - start_acq_sidx
|
|
681
|
+
zc_gap = zero_crossings[0] - last_rel_zc
|
|
682
|
+
num_zc_to_fill = int(zc_gap / (self._samplerate/self._last_known_freq)) + 1
|
|
683
|
+
virtual_zc_interval = int(zc_gap / num_zc_to_fill)
|
|
684
|
+
remaining_virtual_zc = [last_rel_zc + i*virtual_zc_interval for i in range(1,num_zc_to_fill)]
|
|
685
|
+
logger.debug("Finishing Fallback: Added virtual zero crossing: idx=" + ",".join([f"{virtual_zc:.1f}" for virtual_zc in remaining_virtual_zc]))
|
|
686
|
+
zero_crossings = remaining_virtual_zc + zero_crossings
|
|
679
687
|
self._calculation_mode = "NORMAL"
|
|
680
688
|
else:
|
|
681
689
|
self._calculation_mode = "NORMAL"
|
|
@@ -698,6 +706,21 @@ class PowerSystem(object):
|
|
|
698
706
|
output_values[ch_name] = ch_data
|
|
699
707
|
return output_values
|
|
700
708
|
|
|
709
|
+
def get_channel_info(self) -> dict:
|
|
710
|
+
channel_info = {}
|
|
711
|
+
for phase in self._phases:
|
|
712
|
+
for calc_interval, interval_group in phase._calc_channels.items():
|
|
713
|
+
for derived_type, phys_group in interval_group.items():
|
|
714
|
+
for phys_type, channel in phys_group.items():
|
|
715
|
+
channel_info[channel.name] = {
|
|
716
|
+
"unit": channel.unit,
|
|
717
|
+
"phys_type": phys_type,
|
|
718
|
+
"derived_type": derived_type,
|
|
719
|
+
"calc_interval": calc_interval,
|
|
720
|
+
"phase": phase.name
|
|
721
|
+
}
|
|
722
|
+
return channel_info
|
|
723
|
+
|
|
701
724
|
def __del__(self):
|
|
702
725
|
if self._features["energy_channels"]:
|
|
703
726
|
w_pos_value = float(self._calc_channels["multi_period"]["energy"]["w_pos"].last_sample_value)
|
pqopen/storagecontroller.py
CHANGED
|
@@ -57,11 +57,13 @@ import numpy as np
|
|
|
57
57
|
from pqopen.helper import floor_timestamp, JsonDecimalLimiter
|
|
58
58
|
from pqopen.eventdetector import Event
|
|
59
59
|
from daqopen.channelbuffer import DataChannelBuffer, AcqBuffer
|
|
60
|
+
from daqopen.daqinfo import DaqInfo
|
|
60
61
|
from pathlib import Path
|
|
61
62
|
from typing import List, Dict
|
|
62
63
|
import logging
|
|
63
64
|
import json
|
|
64
65
|
import gzip
|
|
66
|
+
import time
|
|
65
67
|
import paho.mqtt.client as mqtt
|
|
66
68
|
|
|
67
69
|
|
|
@@ -91,7 +93,7 @@ class StorageEndpoint(object):
|
|
|
91
93
|
"""
|
|
92
94
|
Writes aggregated data to the storage endpoint.
|
|
93
95
|
|
|
94
|
-
|
|
96
|
+
Parameters:
|
|
95
97
|
data: The aggregated data to store.
|
|
96
98
|
timestamp_us: The timestamp in microseconds for the aggregated data.
|
|
97
99
|
interval_seconds: The aggregation interval in seconds.
|
|
@@ -101,6 +103,17 @@ class StorageEndpoint(object):
|
|
|
101
103
|
def write_event(self, event: Event):
|
|
102
104
|
pass
|
|
103
105
|
|
|
106
|
+
def write_measurement_config(self, m_config: dict, daq_info: DaqInfo, channe_info: dict, **kwargs):
|
|
107
|
+
"""
|
|
108
|
+
Writes measurement config to the storage endpoint.
|
|
109
|
+
|
|
110
|
+
Parameters:
|
|
111
|
+
m_config: The measurement config to store.
|
|
112
|
+
daq_info: The daq info to store.
|
|
113
|
+
channel_info: The channel's specific infos
|
|
114
|
+
"""
|
|
115
|
+
pass
|
|
116
|
+
|
|
104
117
|
class StoragePlan(object):
|
|
105
118
|
"""Defines a plan for storing data with specified intervals and channels."""
|
|
106
119
|
|
|
@@ -190,6 +203,9 @@ class StoragePlan(object):
|
|
|
190
203
|
if self._store_events_enabled:
|
|
191
204
|
self.storage_endpoint.write_event(event, **self._additional_config)
|
|
192
205
|
|
|
206
|
+
def store_measurement_config(self, m_config: dict, daq_info: DaqInfo, channel_info: dict):
|
|
207
|
+
self.storage_endpoint.write_measurement_config(m_config, daq_info, channel_info, **self._additional_config)
|
|
208
|
+
|
|
193
209
|
class StorageController(object):
|
|
194
210
|
"""Manages multiple storage plans and processes data for storage."""
|
|
195
211
|
|
|
@@ -304,7 +320,10 @@ class StorageController(object):
|
|
|
304
320
|
available_channels: dict,
|
|
305
321
|
measurement_id: str,
|
|
306
322
|
device_id: str,
|
|
307
|
-
start_timestamp_us: int
|
|
323
|
+
start_timestamp_us: int,
|
|
324
|
+
m_config: dict | None = None,
|
|
325
|
+
daq_info: DaqInfo | None = None,
|
|
326
|
+
channel_info: dict| None = None):
|
|
308
327
|
"""
|
|
309
328
|
Setup endpoints and storage plans from config
|
|
310
329
|
|
|
@@ -319,7 +338,7 @@ class StorageController(object):
|
|
|
319
338
|
Raises:
|
|
320
339
|
NotImplementedError: If a not implemented endpoint will be configured
|
|
321
340
|
"""
|
|
322
|
-
self._configured_eps = {}
|
|
341
|
+
self._configured_eps: dict[str, StorageEndpoint] = {}
|
|
323
342
|
for ep_type, ep_config in endpoints.items():
|
|
324
343
|
if ep_type == "csv":
|
|
325
344
|
csv_storage_endpoint = CsvStorageEndpoint("csv", measurement_id, ep_config.get("data_dir", "/tmp/"))
|
|
@@ -375,8 +394,11 @@ class StorageController(object):
|
|
|
375
394
|
else:
|
|
376
395
|
logger.warning(f"Channel {channel} not available for storing")
|
|
377
396
|
self.add_storage_plan(storage_plan)
|
|
378
|
-
|
|
379
|
-
|
|
397
|
+
# Initially store the measurement config if configured
|
|
398
|
+
if sp_config.get("store_config", False) and m_config and daq_info and channel_info:
|
|
399
|
+
storage_plan.store_measurement_config(m_config=m_config,
|
|
400
|
+
daq_info=daq_info,
|
|
401
|
+
channel_info=channel_info)
|
|
380
402
|
|
|
381
403
|
class TestStorageEndpoint(StorageEndpoint):
|
|
382
404
|
"""A implementation of StorageEndpoint for testing purposes."""
|
|
@@ -499,6 +521,27 @@ class MqttStorageEndpoint(StorageEndpoint):
|
|
|
499
521
|
self._client.publish(topic_prefix + f"/{self._device_id:s}/event/json",
|
|
500
522
|
json_item.encode('utf-8'), qos=2)
|
|
501
523
|
|
|
524
|
+
def write_measurement_config(self, m_config: dict, daq_info: DaqInfo, channel_info: dict, **kwargs):
|
|
525
|
+
"""
|
|
526
|
+
Write measurement config
|
|
527
|
+
"""
|
|
528
|
+
m_config_object = {
|
|
529
|
+
"type": "m_config",
|
|
530
|
+
"measurement_uuid": self.measurement_id,
|
|
531
|
+
"timestamp": time.time(),
|
|
532
|
+
"m_config": m_config,
|
|
533
|
+
"daq_info": daq_info.to_dict(),
|
|
534
|
+
"channel_info": channel_info
|
|
535
|
+
}
|
|
536
|
+
json_item = json.dumps(m_config_object)
|
|
537
|
+
topic_prefix = kwargs.get("mqtt_topic_prefix", self._topic_prefix)
|
|
538
|
+
if self._compression:
|
|
539
|
+
self._client.publish(topic_prefix + f"/{self._device_id:s}/m_config/gjson",
|
|
540
|
+
gzip.compress(json_item.encode('utf-8')), qos=2)
|
|
541
|
+
else:
|
|
542
|
+
self._client.publish(topic_prefix + f"/{self._device_id:s}/m_config/json",
|
|
543
|
+
json_item.encode('utf-8'), qos=2)
|
|
544
|
+
|
|
502
545
|
class HomeAssistantStorageEndpoint(StorageEndpoint):
|
|
503
546
|
"""Represents a MQTT endpoint (MQTT) for HomeAssistant."""
|
|
504
547
|
def __init__(self,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pqopen-lib
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.5
|
|
4
4
|
Summary: A power quality processing library for calculating parameters from waveform data
|
|
5
5
|
Project-URL: Homepage, https://github.com/DaqOpen/pqopen-lib
|
|
6
6
|
Project-URL: Issues, https://github.com/DaqOpen/pqopen-lib/issues
|
|
@@ -3,10 +3,10 @@ pqopen/auxcalc.py,sha256=P11Nu9pgJRoPYZDjLk-mXI6Ha02LoTH5bS9FdFTvC9M,2733
|
|
|
3
3
|
pqopen/eventdetector.py,sha256=NKZU7GbeorZdkYu3ET4lhMaeynw70GhIGO2p1xH4aTA,11962
|
|
4
4
|
pqopen/helper.py,sha256=0msrm6i1v8jj2Z5X8F7wDEW0KD5i91RBNZwPJC05YrA,2533
|
|
5
5
|
pqopen/powerquality.py,sha256=dRVCedWa1QJKHgdiYoIIdvhH_p40cwpgeUePO5u1j28,15953
|
|
6
|
-
pqopen/powersystem.py,sha256=
|
|
7
|
-
pqopen/storagecontroller.py,sha256=
|
|
6
|
+
pqopen/powersystem.py,sha256=1Dux78f20rN8qeu0qqSjzr_hK6lP01O6zOW-h9Udk-8,50595
|
|
7
|
+
pqopen/storagecontroller.py,sha256=8JkeRX3HDWGFR40wO1ejxctQp53eMgEtsJMbOl7ea1Y,33468
|
|
8
8
|
pqopen/zcd.py,sha256=olJZsHRd1CjU65vysc2emR5wFGMkayIWdUEDNE8jfIc,6253
|
|
9
|
-
pqopen_lib-0.8.
|
|
10
|
-
pqopen_lib-0.8.
|
|
11
|
-
pqopen_lib-0.8.
|
|
12
|
-
pqopen_lib-0.8.
|
|
9
|
+
pqopen_lib-0.8.5.dist-info/METADATA,sha256=rhdRRPk0xDqkCyWg5YBICo6CmZWruJVm5mJDh8rgry4,4787
|
|
10
|
+
pqopen_lib-0.8.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
11
|
+
pqopen_lib-0.8.5.dist-info/licenses/LICENSE,sha256=yhYwu9dioytbAvNQa0UBwaBVcALqiOoBViEs4HLW6aU,1064
|
|
12
|
+
pqopen_lib-0.8.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|