enode-host 0.1.0__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.
- enode_host/__init__.py +1 -0
- enode_host/async_socket.py +165 -0
- enode_host/backup/c-wing3.py +226 -0
- enode_host/backup/c.py +226 -0
- enode_host/backup/esp_mesh.py +136 -0
- enode_host/backup/gui_comps.py +113 -0
- enode_host/backup/gui_wx_bk.py +270 -0
- enode_host/backup/load_file.py +27 -0
- enode_host/backup/mesh.py +0 -0
- enode_host/backup/mesh_bk.py +0 -0
- enode_host/backup/s.py +151 -0
- enode_host/backup/sandbox.py +93 -0
- enode_host/backup/shm.py +262 -0
- enode_host/backup/shmtools.py +70 -0
- enode_host/backup/smarts.py +243 -0
- enode_host/backup/test_wxpython_choice.py +49 -0
- enode_host/backup/view-wing3.py +494 -0
- enode_host/backup/wx_example.py +55 -0
- enode_host/backup/wx_test01.py +43 -0
- enode_host/cli.py +192 -0
- enode_host/config.py +8 -0
- enode_host/constants.py +25 -0
- enode_host/framed_mesh.py +237 -0
- enode_host/gui_framed.py +207 -0
- enode_host/model.py +1415 -0
- enode_host/protocol.py +311 -0
- enode_host/psd_recursive.py +139 -0
- enode_host/queues.py +11 -0
- enode_host/resampling.py +206 -0
- enode_host/shm_sigproc.py +47 -0
- enode_host/storage.py +93 -0
- enode_host/timestamping.py +79 -0
- enode_host/types.py +38 -0
- enode_host/view.py +1233 -0
- enode_host-0.1.0.dist-info/METADATA +81 -0
- enode_host-0.1.0.dist-info/RECORD +39 -0
- enode_host-0.1.0.dist-info/WHEEL +5 -0
- enode_host-0.1.0.dist-info/entry_points.txt +2 -0
- enode_host-0.1.0.dist-info/top_level.txt +1 -0
enode_host/storage.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from numpy import floor
|
|
2
|
+
import datetime
|
|
3
|
+
from pandas import DataFrame, to_datetime
|
|
4
|
+
import time
|
|
5
|
+
import copy
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
try:
|
|
9
|
+
from .constants import RT_STREAM_HD5_DIR
|
|
10
|
+
except ImportError:
|
|
11
|
+
from constants import RT_STREAM_HD5_DIR
|
|
12
|
+
import re
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
class Storage:
|
|
17
|
+
|
|
18
|
+
def __init__(self, file_length_in_sec):
|
|
19
|
+
self.file_buf = {}
|
|
20
|
+
# the buffer for file outputs
|
|
21
|
+
# {
|
|
22
|
+
# 'acc1':{'t':[], 'y':[], 'last_gridTime':-1},
|
|
23
|
+
# 'acc2':{'t':[], 'y':[], 'last_gridTime':-1},
|
|
24
|
+
# }
|
|
25
|
+
self.file_length_in_sec = file_length_in_sec
|
|
26
|
+
self.tmp_length_in_sec = 24 * 60 * 60
|
|
27
|
+
os.makedirs(RT_STREAM_HD5_DIR, exist_ok=True)
|
|
28
|
+
|
|
29
|
+
def _length_for_node(self, nodeID):
|
|
30
|
+
if isinstance(nodeID, int):
|
|
31
|
+
return self.file_length_in_sec
|
|
32
|
+
match = re.match(r"([A-Za-z]+)", str(nodeID))
|
|
33
|
+
if match and match.group(1).upper() == "TMP":
|
|
34
|
+
return self.tmp_length_in_sec
|
|
35
|
+
return self.file_length_in_sec
|
|
36
|
+
|
|
37
|
+
def get_gridTime(self, t, nodeID):
|
|
38
|
+
length = self._length_for_node(nodeID)
|
|
39
|
+
return floor(t / length) * length
|
|
40
|
+
|
|
41
|
+
def get_filepath(self, nodeID, t):
|
|
42
|
+
timestamp = datetime.datetime.fromtimestamp(t).strftime('%Y_%m%d_%H%M')
|
|
43
|
+
label = None
|
|
44
|
+
if isinstance(nodeID, int):
|
|
45
|
+
label = f"acc{nodeID:02d}"
|
|
46
|
+
else:
|
|
47
|
+
match = re.match(r"([A-Za-z]+)(\\d+)$", str(nodeID))
|
|
48
|
+
if match:
|
|
49
|
+
node_type = match.group(1).lower()
|
|
50
|
+
node_num = int(match.group(2))
|
|
51
|
+
label = f"{node_type}{node_num:02d}"
|
|
52
|
+
else:
|
|
53
|
+
label = str(nodeID).lower()
|
|
54
|
+
return os.path.join(RT_STREAM_HD5_DIR, f"{timestamp}-{label}.hd5")
|
|
55
|
+
|
|
56
|
+
def push(self, nodeID, t, y):
|
|
57
|
+
if not nodeID in self.file_buf.keys():
|
|
58
|
+
self.file_buf[nodeID] = {'last_gridTime': -1, 't':[], 'y':[]}
|
|
59
|
+
|
|
60
|
+
for t_, y_ in zip(t, y):
|
|
61
|
+
current_gridTime = self.get_gridTime(t_.timestamp(), nodeID)
|
|
62
|
+
if self.file_buf[nodeID]['last_gridTime'] == -1:
|
|
63
|
+
self.file_buf[nodeID]['last_gridTime'] = current_gridTime
|
|
64
|
+
elif self.file_buf[nodeID]['last_gridTime'] != current_gridTime:
|
|
65
|
+
# Save to disk in HDF
|
|
66
|
+
df = DataFrame(self.file_buf[nodeID]['y'], columns = ['X', 'Y', 'Z'])
|
|
67
|
+
df.index = to_datetime(self.file_buf[nodeID]['t'])
|
|
68
|
+
filepath = self.get_filepath(nodeID, self.file_buf[nodeID]['last_gridTime'])
|
|
69
|
+
df.to_hdf(filepath, key='df', mode='w')
|
|
70
|
+
logger.info("file saved: {}".format(filepath))
|
|
71
|
+
# Reinitialise
|
|
72
|
+
self.file_buf[nodeID]['last_gridTime'] = copy.copy(current_gridTime)
|
|
73
|
+
self.file_buf[nodeID]['t'] = []
|
|
74
|
+
self.file_buf[nodeID]['y'] = []
|
|
75
|
+
|
|
76
|
+
self.file_buf[nodeID]['t'].append(t_)
|
|
77
|
+
self.file_buf[nodeID]['y'].append(y_)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if __name__ == '__main__':
|
|
82
|
+
import pandas as pd
|
|
83
|
+
|
|
84
|
+
t = [datetime.datetime(2024,1,1,0,i,j) for i in range(3) for j in range(60)]
|
|
85
|
+
y = [[i,2*i,3*i] for i in range(180)]
|
|
86
|
+
storage = Storage(60)
|
|
87
|
+
i = 0
|
|
88
|
+
# t[60*i:60*(i+1)]
|
|
89
|
+
# y[60*i:60*(i+1)]
|
|
90
|
+
for i in range(3):
|
|
91
|
+
storage.push(1, t[60*i:60*(i+1)], y[60*i:60*(i+1)])
|
|
92
|
+
|
|
93
|
+
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from numpy import empty, append, array, where, logical_and, delete
|
|
2
|
+
from scipy.interpolate import interp1d
|
|
3
|
+
try:
|
|
4
|
+
from . import config
|
|
5
|
+
except ImportError:
|
|
6
|
+
import config
|
|
7
|
+
import struct
|
|
8
|
+
import datetime
|
|
9
|
+
|
|
10
|
+
class Timestamping():
|
|
11
|
+
|
|
12
|
+
def __init__(self):
|
|
13
|
+
|
|
14
|
+
self.CC_ppsEpoch = empty((0, 2), dtype = float) # array( [[cc0, epoch_PPS0], [cc1, epoch_PPS1]] )
|
|
15
|
+
self.CC_ACC = empty((0, 4), dtype = float) # array( [[cc, acc_x, acc_y, acc_z], ...])
|
|
16
|
+
|
|
17
|
+
def push_cc_acc(self, cc_acc):
|
|
18
|
+
|
|
19
|
+
# only add when it is a new data
|
|
20
|
+
if self.CC_ppsEpoch.shape[0] > 1 and cc_acc[0] > self.CC_ppsEpoch[1, 0]:
|
|
21
|
+
self.CC_ACC = append(self.CC_ACC, array([cc_acc]), axis=0) # CC, acc_x, acc_y, acc_z
|
|
22
|
+
|
|
23
|
+
def push_cc_pps(self, CC, epoch_time):
|
|
24
|
+
|
|
25
|
+
# Populating CC_ppsEpoch Table
|
|
26
|
+
self.CC_ppsEpoch = append(self.CC_ppsEpoch, array([[CC, epoch_time]]), axis = 0)
|
|
27
|
+
if len(self.CC_ppsEpoch) == 1:
|
|
28
|
+
return [], []
|
|
29
|
+
elif len(self.CC_ppsEpoch) == 3:
|
|
30
|
+
self.CC_ppsEpoch = self.CC_ppsEpoch[1:, :] # shifting CC_ppsEpoch
|
|
31
|
+
|
|
32
|
+
# timestamping
|
|
33
|
+
cc0 = self.CC_ppsEpoch[0, 0]
|
|
34
|
+
cc1 = self.CC_ppsEpoch[1, 0]
|
|
35
|
+
idx = where(logical_and(self.CC_ACC[:,0] >= cc0, self.CC_ACC[:,0] < cc1))
|
|
36
|
+
if len(idx[0]) > 0:
|
|
37
|
+
cc_acc = self.CC_ACC[idx[0], :]
|
|
38
|
+
linear_interp = interp1d(self.CC_ppsEpoch[:2, 0], self.CC_ppsEpoch[:2, 1], kind = 'linear')
|
|
39
|
+
x_interp = cc_acc[:, 0]
|
|
40
|
+
y_interp = linear_interp(x_interp)
|
|
41
|
+
t = []
|
|
42
|
+
for i in range(cc_acc.shape[0]):
|
|
43
|
+
epoch = int(y_interp[i])
|
|
44
|
+
suseconds = int((y_interp[i] - epoch) * 1e6)
|
|
45
|
+
t_ = datetime.datetime.fromtimestamp(epoch, tz=datetime.timezone.utc)
|
|
46
|
+
t_ = t_.replace(microsecond = suseconds)
|
|
47
|
+
t.append(t_)
|
|
48
|
+
y = cc_acc[:, 1:4]
|
|
49
|
+
# Delete already timestamped points
|
|
50
|
+
mask = self.CC_ACC[:, 0] >= cc1
|
|
51
|
+
self.CC_ACC = self.CC_ACC[mask,...]
|
|
52
|
+
return t, y
|
|
53
|
+
|
|
54
|
+
return [], []
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# rawFileLength_sec = config.rawFileLength_sec
|
|
59
|
+
# def getGridTime(self, epoch):
|
|
60
|
+
# return int(epoch / rawFileLength_sec) * rawFileLength_sec
|
|
61
|
+
# # FILE SAVING
|
|
62
|
+
# if 0:
|
|
63
|
+
# if epoch_time > 0:
|
|
64
|
+
# if fid == -1:
|
|
65
|
+
# latest_fileName = self.getFileName(streamID, epoch_time)
|
|
66
|
+
# fid = open(latest_fileName, "wb")
|
|
67
|
+
# elif self.getFileName(streamID, epoch_time) != latest_fileName:
|
|
68
|
+
# fid.close()
|
|
69
|
+
# latest_fileName = self.getFileName(streamID, epoch_time)
|
|
70
|
+
# fid = open(latest_fileName, "wb")
|
|
71
|
+
# if fid != -1:
|
|
72
|
+
# fid.write(packet[2:])
|
|
73
|
+
# data = data[packet_size:]
|
|
74
|
+
|
|
75
|
+
# def getFileName(self, streamID, epoch_time):
|
|
76
|
+
# nodeNumber = (streamID & 0x0FF0) >> 4
|
|
77
|
+
# streamID_str = 'ACC{}-ACC'.format(nodeNumber)
|
|
78
|
+
# t = datetime.datetime.fromtimestamp(epoch_time)
|
|
79
|
+
# return os.path.join(target_dir, '{}-{}'.format(datetime.datetime.strftime(t, '%Y_%m%d_%H%M'), streamID_str))
|
enode_host/types.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Dict, List, Optional
|
|
5
|
+
import datetime
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class NodeStatus:
|
|
10
|
+
node_id: int
|
|
11
|
+
node_label: str
|
|
12
|
+
connection: str = "waiting"
|
|
13
|
+
speed_kb_s: float = 0.0
|
|
14
|
+
level: Optional[int] = None
|
|
15
|
+
parent: str = ""
|
|
16
|
+
rssi_db: Optional[int] = None
|
|
17
|
+
children: str = ""
|
|
18
|
+
pps_age: str = ""
|
|
19
|
+
cmd: str = ""
|
|
20
|
+
pps_time: Optional[datetime.datetime] = None
|
|
21
|
+
pps_flash_time: Optional[datetime.datetime] = None
|
|
22
|
+
daq_time: Optional[datetime.datetime] = None
|
|
23
|
+
parent_mac: Optional[str] = None
|
|
24
|
+
self_mac: Optional[str] = None
|
|
25
|
+
conn_rpt_time: Optional[datetime.datetime] = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class PpsFlashState:
|
|
30
|
+
flash_until: Optional[datetime.datetime] = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class PlotBuffers:
|
|
35
|
+
timehistory_xdata: List[datetime.datetime] = field(default_factory=list)
|
|
36
|
+
timehistory_ydata: List[List[float]] = field(default_factory=list)
|
|
37
|
+
psd_xdata: List[float] = field(default_factory=list)
|
|
38
|
+
psd_ydata: Dict[int, List[List[float]]] = field(default_factory=dict)
|