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
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
import time
|
|
3
|
+
import threading
|
|
4
|
+
import logging
|
|
5
|
+
import struct
|
|
6
|
+
import datetime
|
|
7
|
+
import getmac
|
|
8
|
+
import os
|
|
9
|
+
from queue import Queue
|
|
10
|
+
import config
|
|
11
|
+
from scipy.interpolate import interp1d
|
|
12
|
+
from numpy import where, logical_and, empty, append, array, delete, floor
|
|
13
|
+
try:
|
|
14
|
+
from . import queues
|
|
15
|
+
except ImportError:
|
|
16
|
+
import queues
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# CONFIGURATION
|
|
20
|
+
rawFileLength_sec = config.rawFileLength_sec
|
|
21
|
+
port = config.port
|
|
22
|
+
target_dir = config.target_dir
|
|
23
|
+
from model import packet_size, ChannelType, CmdType
|
|
24
|
+
|
|
25
|
+
npackets = 63
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
class Esp_Mesh():
|
|
30
|
+
|
|
31
|
+
def __init__(self, model):
|
|
32
|
+
|
|
33
|
+
self.model = model
|
|
34
|
+
self.sockets = {}
|
|
35
|
+
|
|
36
|
+
thread = threading.Thread(target = self.mesh_svr_begin)
|
|
37
|
+
thread.start()
|
|
38
|
+
logger.info("mesh_server started.")
|
|
39
|
+
|
|
40
|
+
def get_ip_address(self):
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
# This will get the local IP address of your machine
|
|
44
|
+
host_name = socket.gethostname()
|
|
45
|
+
ip_address = socket.gethostbyname(host_name)
|
|
46
|
+
return ip_address
|
|
47
|
+
except socket.error as e:
|
|
48
|
+
print(f"Error: {e}")
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
def handle_client(self, client_socket, ip_address):
|
|
52
|
+
|
|
53
|
+
logger.info("handle_client called...")
|
|
54
|
+
data = bytearray()
|
|
55
|
+
nodeID = 0
|
|
56
|
+
# client_socket.settimeout(0)
|
|
57
|
+
is_socket_stored = False
|
|
58
|
+
|
|
59
|
+
while True:
|
|
60
|
+
try:
|
|
61
|
+
# Managing Sockets: store the handle for access from outside
|
|
62
|
+
if True:
|
|
63
|
+
data += client_socket.recv(packet_size * npackets)
|
|
64
|
+
else:
|
|
65
|
+
data += client_socket.recv(packet_size * 1)
|
|
66
|
+
# Storing socket handler for access from outside
|
|
67
|
+
if not is_socket_stored and len(data) >= packet_size:
|
|
68
|
+
packet = data[:packet_size]
|
|
69
|
+
rec = struct.unpack('>H', packet[:2]) # B = unsigned char (1byte),
|
|
70
|
+
# H = unsigned short integer (2byte),
|
|
71
|
+
nodeID = rec[0] # consisting of nodeType (uint8_t) + nodeNUmber (uint8_t)
|
|
72
|
+
logger.info('nodeID={}'.format(nodeID))
|
|
73
|
+
self.sockets[nodeID] = client_socket
|
|
74
|
+
is_socket_stored = True
|
|
75
|
+
# forward the data to parser
|
|
76
|
+
if is_socket_stored:
|
|
77
|
+
self.model.data_push(nodeID, data)
|
|
78
|
+
logger.debug('data_pushed {} bytes'.format(len(data)))
|
|
79
|
+
data.clear()
|
|
80
|
+
#time.sleep(0.5)
|
|
81
|
+
|
|
82
|
+
# except BlockingIOError:
|
|
83
|
+
# time.sleep(0.1)
|
|
84
|
+
# except socket.timeout:
|
|
85
|
+
# time.sleep(0.1)
|
|
86
|
+
except Exception as e:
|
|
87
|
+
errnum = e.args[0]
|
|
88
|
+
if errnum in [104, 113, 110] :
|
|
89
|
+
# 110: connection tiemout
|
|
90
|
+
# peer closed the connection, then svr closes it as well
|
|
91
|
+
break
|
|
92
|
+
else:
|
|
93
|
+
raise
|
|
94
|
+
# delete socket handle if disconnected
|
|
95
|
+
del self.sockets[nodeID]
|
|
96
|
+
logger.info("close()...")
|
|
97
|
+
client_socket.close()
|
|
98
|
+
# queues.Mesh2GUI.put({'updateType': 1, 'nodeID': nodeID, 'connection': False})
|
|
99
|
+
|
|
100
|
+
def mesh_svr_begin(self):
|
|
101
|
+
|
|
102
|
+
# Create a socket object
|
|
103
|
+
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
104
|
+
# print("recv buffer size = {}".format(server_socket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)))
|
|
105
|
+
hostname = socket.gethostname()
|
|
106
|
+
# if hostname in ['wing1a', 'wing3.lan']:
|
|
107
|
+
# host = self.get_ip_address()
|
|
108
|
+
# else:
|
|
109
|
+
# host = '192.168.1.104'
|
|
110
|
+
host = '192.168.1.202'
|
|
111
|
+
logger.info(f"ip address= {host}")
|
|
112
|
+
|
|
113
|
+
while(True):
|
|
114
|
+
try:
|
|
115
|
+
server_socket.bind((host, port)) # Bind the socket to the host and port
|
|
116
|
+
break
|
|
117
|
+
except:
|
|
118
|
+
print(".")
|
|
119
|
+
time.sleep(1)
|
|
120
|
+
server_socket.listen(20) # Listen for incoming connections; The argument is the maximum number of queued connections
|
|
121
|
+
logger.info(f"Server is listening on {host}:{port}")
|
|
122
|
+
while True:
|
|
123
|
+
logger.info("Waiting for a connection...")
|
|
124
|
+
client_socket, client_address = server_socket.accept()
|
|
125
|
+
logger.info(f"Accepted connection from {client_address}")
|
|
126
|
+
# Start a new thread to handle the client
|
|
127
|
+
client_handler = threading.Thread(target=self.handle_client, args=(client_socket, client_address,))
|
|
128
|
+
client_handler.start()
|
|
129
|
+
|
|
130
|
+
def send_cmd(self, nodeID, cmd, data0 = 0, data1 = 0):
|
|
131
|
+
|
|
132
|
+
msg = struct.pack('=BBBBB', cmd, data0, data1, 0, 0)
|
|
133
|
+
logger.info('msg={}'.format(msg))
|
|
134
|
+
self.sockets[nodeID].send(msg)
|
|
135
|
+
|
|
136
|
+
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
# Form implementation generated from reading ui file 'gui_v2.ui'
|
|
4
|
+
#
|
|
5
|
+
# Created by: PyQt5 UI code generator 5.15.9
|
|
6
|
+
#
|
|
7
|
+
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
|
8
|
+
# run again. Do not edit this file unless you know what you are doing.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Ui_MainWindow(object):
|
|
15
|
+
def setupUi(self, MainWindow):
|
|
16
|
+
MainWindow.setObjectName("MainWindow")
|
|
17
|
+
MainWindow.resize(860, 596)
|
|
18
|
+
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
|
19
|
+
self.centralwidget.setObjectName("centralwidget")
|
|
20
|
+
self.widget = QtWidgets.QWidget(self.centralwidget)
|
|
21
|
+
# self.widget.setGeometry(QtCore.QRect(10, 10, 831, 531))
|
|
22
|
+
self.widget.setObjectName("widget")
|
|
23
|
+
|
|
24
|
+
#
|
|
25
|
+
# LAYOUTS
|
|
26
|
+
#
|
|
27
|
+
|
|
28
|
+
# Vertical layout
|
|
29
|
+
self.verticalLayout = QtWidgets.QVBoxLayout(self.widget)
|
|
30
|
+
# self.verticalLayout.setContentsMargins(0, 0, 0, 0)
|
|
31
|
+
self.verticalLayout.setObjectName("verticalLayout")
|
|
32
|
+
|
|
33
|
+
# Horizontal layout 1
|
|
34
|
+
self.horizontalLayout1 = QtWidgets.QHBoxLayout()
|
|
35
|
+
self.horizontalLayout1.setObjectName("horizontalLayout1")
|
|
36
|
+
|
|
37
|
+
# Horizontal layout 2
|
|
38
|
+
self.horizontalLayout2 = QtWidgets.QHBoxLayout()
|
|
39
|
+
self.horizontalLayout2.setObjectName("horizontalLayout2")
|
|
40
|
+
|
|
41
|
+
self.verticalLayout.addLayout(self.horizontalLayout1)
|
|
42
|
+
self.verticalLayout.addLayout(self.horizontalLayout2)
|
|
43
|
+
|
|
44
|
+
# add Widgets for Horizontal layout1
|
|
45
|
+
self.label = QtWidgets.QLabel(self.widget)
|
|
46
|
+
font = QtGui.QFont()
|
|
47
|
+
font.setFamily("Arial")
|
|
48
|
+
font.setBold(True)
|
|
49
|
+
font.setWeight(75)
|
|
50
|
+
self.label.setFont(font)
|
|
51
|
+
self.label.setObjectName("label")
|
|
52
|
+
self.label.setText("Number of Nodes")
|
|
53
|
+
self.horizontalLayout1.addWidget(self.label)
|
|
54
|
+
|
|
55
|
+
self.spinBox = QtWidgets.QSpinBox(self.widget)
|
|
56
|
+
self.spinBox.setMaximum(16)
|
|
57
|
+
self.spinBox.setProperty("value", 14)
|
|
58
|
+
self.spinBox.setObjectName("spinBox")
|
|
59
|
+
self.spinBox.valueChanged.connect(self.update_nnodes)
|
|
60
|
+
self.horizontalLayout1.addWidget(self.spinBox)
|
|
61
|
+
|
|
62
|
+
self.pushButton = QtWidgets.QPushButton(self.widget)
|
|
63
|
+
self.pushButton.setObjectName("pushButton")
|
|
64
|
+
self.horizontalLayout1.addWidget(self.pushButton)
|
|
65
|
+
self.pushButton_2 = QtWidgets.QPushButton(self.widget)
|
|
66
|
+
self.pushButton_2.setObjectName("pushButton_2")
|
|
67
|
+
self.horizontalLayout1.addWidget(self.pushButton_2)
|
|
68
|
+
|
|
69
|
+
# Add widgets for Horizontal layout2
|
|
70
|
+
self.tableView = QtWidgets.QTableView(self.widget)
|
|
71
|
+
self.tableView.setObjectName("tableView")
|
|
72
|
+
self.horizontalLayout2.addWidget(self.tableView, stretch = 1)
|
|
73
|
+
|
|
74
|
+
self.listView = []
|
|
75
|
+
# self.listView = QtWidgets.QListView(self.widget)
|
|
76
|
+
# self.listView.setObjectName("listView")
|
|
77
|
+
# self.verticalLayout.addWidget(self.listView, stretch=3)
|
|
78
|
+
|
|
79
|
+
self.centralwidget.setLayout(self.verticalLayout)
|
|
80
|
+
MainWindow.setCentralWidget(self.centralwidget)
|
|
81
|
+
|
|
82
|
+
# self.menubar = QtWidgets.QMenuBar(MainWindow)
|
|
83
|
+
# self.menubar.setGeometry(QtCore.QRect(0, 0, 860, 20))
|
|
84
|
+
# self.menubar.setObjectName("menubar")
|
|
85
|
+
# self.menu_File = QtWidgets.QMenu(self.menubar)
|
|
86
|
+
# self.menu_File.setObjectName("menu_File")
|
|
87
|
+
# MainWindow.setMenuBar(self.menubar)
|
|
88
|
+
# self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
|
89
|
+
# self.statusbar.setObjectName("statusbar")
|
|
90
|
+
# MainWindow.setStatusBar(self.statusbar)
|
|
91
|
+
# self.action_Open = QtWidgets.QAction(MainWindow)
|
|
92
|
+
# self.action_Open.setObjectName("action_Open")
|
|
93
|
+
# self.action_Action1 = QtWidgets.QAction(MainWindow)
|
|
94
|
+
# self.action_Action1.setObjectName("action_Action1")
|
|
95
|
+
# self.menu_File.addAction(self.action_Open)
|
|
96
|
+
# self.menubar.addAction(self.menu_File.menuAction())
|
|
97
|
+
|
|
98
|
+
self.retranslateUi(MainWindow)
|
|
99
|
+
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
|
100
|
+
|
|
101
|
+
def retranslateUi(self, MainWindow):
|
|
102
|
+
pass
|
|
103
|
+
_translate = QtCore.QCoreApplication.translate
|
|
104
|
+
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
|
|
105
|
+
self.label.setText(_translate("MainWindow", "Number of Nodes"))
|
|
106
|
+
self.pushButton.setText(_translate("MainWindow", "Start DAQ All"))
|
|
107
|
+
self.pushButton_2.setText(_translate("MainWindow", "Reboot All"))
|
|
108
|
+
# self.menu_File.setTitle(_translate("MainWindow", "&File"))
|
|
109
|
+
# self.action_Open.setText(_translate("MainWindow", "&Quit"))
|
|
110
|
+
# self.action_Action1.setText(_translate("MainWindow", "&Action1"))
|
|
111
|
+
|
|
112
|
+
def update_nnodes(self, value):
|
|
113
|
+
print("nnode={}".format(value))
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/local/bin/python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
###########################################################################
|
|
5
|
+
## Python code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
|
|
6
|
+
## http://www.wxformbuilder.org/
|
|
7
|
+
##
|
|
8
|
+
## PLEASE DO *NOT* EDIT THIS FILE!
|
|
9
|
+
###########################################################################
|
|
10
|
+
|
|
11
|
+
import wx
|
|
12
|
+
import wx.xrc
|
|
13
|
+
import wx.grid
|
|
14
|
+
|
|
15
|
+
import gettext
|
|
16
|
+
_ = gettext.gettext
|
|
17
|
+
|
|
18
|
+
###########################################################################
|
|
19
|
+
## Class MyFrame1
|
|
20
|
+
###########################################################################
|
|
21
|
+
|
|
22
|
+
class MyFrame1 ( wx.Frame ):
|
|
23
|
+
|
|
24
|
+
def __init__( self, parent ):
|
|
25
|
+
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = _(u"Wireless Sensor DAQ"), pos = wx.DefaultPosition, size = wx.Size( 1024,600 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
|
|
26
|
+
|
|
27
|
+
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
|
|
28
|
+
|
|
29
|
+
bSizer1 = wx.BoxSizer( wx.VERTICAL )
|
|
30
|
+
|
|
31
|
+
bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
|
|
32
|
+
|
|
33
|
+
self.m_staticText2 = wx.StaticText( self, wx.ID_ANY, _(u"Sensor Nodes:"), wx.DefaultPosition, wx.DefaultSize, 0 )
|
|
34
|
+
self.m_staticText2.Wrap( -1 )
|
|
35
|
+
|
|
36
|
+
bSizer2.Add( self.m_staticText2, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 )
|
|
37
|
+
|
|
38
|
+
self.m_textCtrl2 = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
|
|
39
|
+
bSizer2.Add( self.m_textCtrl2, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 )
|
|
40
|
+
|
|
41
|
+
self.m_staticText3 = wx.StaticText( self, wx.ID_ANY, _(u"Fs="), wx.DefaultPosition, wx.DefaultSize, 0 )
|
|
42
|
+
self.m_staticText3.Wrap( -1 )
|
|
43
|
+
|
|
44
|
+
bSizer2.Add( self.m_staticText3, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 )
|
|
45
|
+
|
|
46
|
+
m_choice1Choices = [ _(u"62.5"), _(u"125") ]
|
|
47
|
+
self.m_choice1 = wx.Choice( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, m_choice1Choices, 0 )
|
|
48
|
+
self.m_choice1.SetSelection( 0 )
|
|
49
|
+
bSizer2.Add( self.m_choice1, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 )
|
|
50
|
+
|
|
51
|
+
self.m_staticText4 = wx.StaticText( self, wx.ID_ANY, _(u"Hz"), wx.DefaultPosition, wx.DefaultSize, 0 )
|
|
52
|
+
self.m_staticText4.Wrap( -1 )
|
|
53
|
+
|
|
54
|
+
bSizer2.Add( self.m_staticText4, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 )
|
|
55
|
+
|
|
56
|
+
self.m_button1 = wx.Button( self, wx.ID_ANY, _(u"Start DAQ"), wx.DefaultPosition, wx.DefaultSize, 0 )
|
|
57
|
+
bSizer2.Add( self.m_button1, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 )
|
|
58
|
+
|
|
59
|
+
self.m_button2 = wx.Button( self, wx.ID_ANY, _(u"Stop DAQ"), wx.DefaultPosition, wx.DefaultSize, 0 )
|
|
60
|
+
bSizer2.Add( self.m_button2, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 )
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
bSizer1.Add( bSizer2, 0, wx.EXPAND, 5 )
|
|
64
|
+
|
|
65
|
+
bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
|
|
66
|
+
|
|
67
|
+
bSizer4 = wx.BoxSizer( wx.VERTICAL )
|
|
68
|
+
|
|
69
|
+
self.m_staticText21 = wx.StaticText( self, wx.ID_ANY, _(u"WiFi Mesh Status"), wx.DefaultPosition, wx.DefaultSize, 0 )
|
|
70
|
+
self.m_staticText21.Wrap( -1 )
|
|
71
|
+
|
|
72
|
+
bSizer4.Add( self.m_staticText21, 0, wx.ALL, 5 )
|
|
73
|
+
|
|
74
|
+
self.m_grid2 = wx.grid.Grid( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 )
|
|
75
|
+
|
|
76
|
+
# Grid
|
|
77
|
+
self.m_grid2.CreateGrid( 5, 6 )
|
|
78
|
+
self.m_grid2.EnableEditing( True )
|
|
79
|
+
self.m_grid2.EnableGridLines( True )
|
|
80
|
+
self.m_grid2.EnableDragGridSize( True )
|
|
81
|
+
self.m_grid2.SetMargins( 0, 0 )
|
|
82
|
+
|
|
83
|
+
# Columns
|
|
84
|
+
self.m_grid2.SetColSize( 0, 70 )
|
|
85
|
+
self.m_grid2.SetColSize( 1, 100 )
|
|
86
|
+
self.m_grid2.SetColSize( 2, 20 )
|
|
87
|
+
self.m_grid2.SetColSize( 3, 40 )
|
|
88
|
+
self.m_grid2.SetColSize( 4, 40 )
|
|
89
|
+
self.m_grid2.SetColSize( 5, 45 )
|
|
90
|
+
self.m_grid2.EnableDragColMove( False )
|
|
91
|
+
self.m_grid2.EnableDragColSize( True )
|
|
92
|
+
self.m_grid2.SetColLabelValue( 0, _(u"Node ID") )
|
|
93
|
+
self.m_grid2.SetColLabelValue( 1, _(u"Status") )
|
|
94
|
+
self.m_grid2.SetColLabelValue( 2, _(u"L") )
|
|
95
|
+
self.m_grid2.SetColLabelValue( 3, _(u"RSSI") )
|
|
96
|
+
self.m_grid2.SetColLabelValue( 4, _(u"PPS") )
|
|
97
|
+
self.m_grid2.SetColLabelValue( 5, _(u"Data") )
|
|
98
|
+
self.m_grid2.SetColLabelSize( wx.grid.GRID_AUTOSIZE )
|
|
99
|
+
self.m_grid2.SetColLabelAlignment( wx.ALIGN_CENTER, wx.ALIGN_CENTER )
|
|
100
|
+
|
|
101
|
+
# Rows
|
|
102
|
+
self.m_grid2.EnableDragRowSize( True )
|
|
103
|
+
self.m_grid2.SetRowLabelSize( wx.grid.GRID_AUTOSIZE )
|
|
104
|
+
self.m_grid2.SetRowLabelAlignment( wx.ALIGN_CENTER, wx.ALIGN_CENTER )
|
|
105
|
+
|
|
106
|
+
# Label Appearance
|
|
107
|
+
|
|
108
|
+
# Cell Defaults
|
|
109
|
+
self.m_grid2.SetDefaultCellAlignment( wx.ALIGN_LEFT, wx.ALIGN_TOP )
|
|
110
|
+
bSizer4.Add( self.m_grid2, 1, wx.ALL|wx.EXPAND, 5 )
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
bSizer3.Add( bSizer4, 0, wx.EXPAND, 5 )
|
|
114
|
+
|
|
115
|
+
self.m_notebook2 = wx.Notebook( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 )
|
|
116
|
+
self.m_panel1 = wx.Panel( self.m_notebook2, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
|
|
117
|
+
self.m_notebook2.AddPage( self.m_panel1, _(u"Time history plot"), True )
|
|
118
|
+
self.m_panel2 = wx.Panel( self.m_notebook2, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
|
|
119
|
+
self.m_notebook2.AddPage( self.m_panel2, _(u"PSD plot"), False )
|
|
120
|
+
|
|
121
|
+
bSizer3.Add( self.m_notebook2, 1, wx.ALL|wx.EXPAND, 5 )
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
bSizer1.Add( bSizer3, 1, wx.EXPAND, 5 )
|
|
125
|
+
|
|
126
|
+
self.m_textCtrl21 = wx.TextCtrl( self, wx.ID_ANY, _(u"\"test line 1\ntest2 line|\""), wx.DefaultPosition, wx.Size( -1,100 ), 0 )
|
|
127
|
+
bSizer1.Add( self.m_textCtrl21, 0, wx.ALL|wx.EXPAND, 5 )
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
self.SetSizer( bSizer1 )
|
|
131
|
+
self.Layout()
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# MENU
|
|
135
|
+
self.m_statusBar1 = self.CreateStatusBar(1, wx.STB_SIZEGRIP, wx.ID_ANY)
|
|
136
|
+
self.m_menubar = wx.MenuBar(0)
|
|
137
|
+
self.m_menu_file = wx.Menu()
|
|
138
|
+
self.m_menu_file_open = wx.MenuItem(self.m_menu_file, wx.ID_ANY, _(u"&Open"), wx.EmptyString, wx.ITEM_NORMAL)
|
|
139
|
+
self.m_menu_file_save = wx.MenuItem(self.m_menu_file, wx.ID_ANY, _(u"&Save"), wx.EmptyString, wx.ITEM_NORMAL)
|
|
140
|
+
self.m_menu_file_quit = wx.MenuItem(self.m_menu_file, wx.ID_ANY, _(u"&Quit"), wx.EmptyString, wx.ITEM_NORMAL)
|
|
141
|
+
self.m_menu_file.Append(self.m_menu_file_open)
|
|
142
|
+
self.m_menu_file.Append(self.m_menu_file_save)
|
|
143
|
+
self.m_menu_file.AppendSeparator()
|
|
144
|
+
self.m_menu_file.Append(self.m_menu_file_quit)
|
|
145
|
+
self.m_menubar.Append(self.m_menu_file, _(u"&File"))
|
|
146
|
+
|
|
147
|
+
self.m_menu_help = wx.Menu()
|
|
148
|
+
self.m_menu_help_about = wx.MenuItem(self.m_menu_help, wx.ID_ANY, _(u"&Help"), wx.EmptyString, wx.ITEM_NORMAL)
|
|
149
|
+
self.m_menu_help.Append(self.m_menu_help_about)
|
|
150
|
+
self.m_menubar.Append(self.m_menu_help, _(u"&Help"))
|
|
151
|
+
|
|
152
|
+
self.SetMenuBar(self.m_menubar)
|
|
153
|
+
|
|
154
|
+
self.Centre( wx.BOTH )
|
|
155
|
+
|
|
156
|
+
# Connect Events
|
|
157
|
+
self.m_textCtrl2.Bind( wx.EVT_TEXT, self.test )
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def __del__( self ):
|
|
162
|
+
pass
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
# Virtual event handlers, override them in your derived class
|
|
166
|
+
def test( self, event ):
|
|
167
|
+
event.Skip()
|
|
168
|
+
|
|
169
|
+
import wx
|
|
170
|
+
import wx.lib.agw.aui as aui
|
|
171
|
+
import wx.lib.mixins.inspection as wit
|
|
172
|
+
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
|
|
173
|
+
from matplotlib.backends.backend_wxagg import \
|
|
174
|
+
NavigationToolbar2WxAgg as NavigationToolbar
|
|
175
|
+
from matplotlib.figure import Figure
|
|
176
|
+
|
|
177
|
+
class Plot(wx.Panel):
|
|
178
|
+
def __init__(self, parent, id=-1, dpi=None, **kwargs):
|
|
179
|
+
super().__init__(parent, id=id, **kwargs)
|
|
180
|
+
self.figure = Figure(dpi=dpi, figsize=(2, 2))
|
|
181
|
+
self.canvas = FigureCanvas(self, -1, self.figure)
|
|
182
|
+
self.toolbar = NavigationToolbar(self.canvas)
|
|
183
|
+
self.toolbar.Realize()
|
|
184
|
+
|
|
185
|
+
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
186
|
+
sizer.Add(self.canvas, 1, wx.EXPAND)
|
|
187
|
+
sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
|
|
188
|
+
self.SetSizer(sizer)
|
|
189
|
+
|
|
190
|
+
class PlotNotebook(wx.Panel):
|
|
191
|
+
def __init__(self, parent, id=-1):
|
|
192
|
+
super().__init__(parent, id=id)
|
|
193
|
+
self.nb = aui.AuiNotebook(self)
|
|
194
|
+
sizer = wx.BoxSizer()
|
|
195
|
+
sizer.Add(self.nb, 1, wx.EXPAND)
|
|
196
|
+
self.SetSizer(sizer)
|
|
197
|
+
|
|
198
|
+
def add(self, name="plot"):
|
|
199
|
+
page = Plot(self.nb)
|
|
200
|
+
self.nb.AddPage(page, name)
|
|
201
|
+
return page.figure
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
import wx.grid as gridlib
|
|
205
|
+
import configparser
|
|
206
|
+
import os
|
|
207
|
+
|
|
208
|
+
CONFIG_FILE = 'config.ini'
|
|
209
|
+
|
|
210
|
+
def save_config(options):
|
|
211
|
+
config = configparser.ConfigParser()
|
|
212
|
+
|
|
213
|
+
config['Settings'] = {
|
|
214
|
+
'option1': options['option1'],
|
|
215
|
+
'option2': options['option2']
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
with open(CONFIG_FILE, 'w') as configfile:
|
|
219
|
+
config.write(configfile)
|
|
220
|
+
|
|
221
|
+
def load_config():
|
|
222
|
+
config = configparser.ConfigParser()
|
|
223
|
+
|
|
224
|
+
if not os.path.exists(CONFIG_FILE):
|
|
225
|
+
# Return default options if config file doesn't exist
|
|
226
|
+
return {
|
|
227
|
+
'option1': 'default_value1',
|
|
228
|
+
'option2': 'default_value2'
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
config.read(CONFIG_FILE)
|
|
232
|
+
options = {
|
|
233
|
+
'option1': config.get('Settings', 'option1', fallback='default_value1'),
|
|
234
|
+
'option2': config.get('Settings', 'option2', fallback='default_value2')
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return options
|
|
238
|
+
|
|
239
|
+
def MainWindow():
|
|
240
|
+
# window = wx.Frame(None, title = "wxPython Frame", size = (300,200))
|
|
241
|
+
frame1 = MyFrame1(None)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
fig1 = Plot(frame1.m_panel1)
|
|
245
|
+
# plotter = PlotNotebook(frame1.m_notebook2)
|
|
246
|
+
axes1 = fig1.figure.add_subplot()
|
|
247
|
+
axes1.plot([1, 2, 3], [2, 1, 4])
|
|
248
|
+
fig2 = Plot(frame1.m_panel2)
|
|
249
|
+
axes2 = fig2.figure.add_subplot()
|
|
250
|
+
axes2.plot([1, 2, 3, 4, 5], [2, 1, 4, 2, 3])
|
|
251
|
+
|
|
252
|
+
canvas = FigureCanvas(frame1.m_panel1, -1, fig1.figure)
|
|
253
|
+
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
254
|
+
sizer.Add(canvas, 1, wx.EXPAND)
|
|
255
|
+
|
|
256
|
+
# Set the sizer for the panel
|
|
257
|
+
frame1.m_panel1.SetSizer(sizer)
|
|
258
|
+
|
|
259
|
+
# Change the background color of cell (1, 1)
|
|
260
|
+
attr = gridlib.GridCellAttr()
|
|
261
|
+
attr.SetBackgroundColour(wx.Colour(255, 255, 0)) # Yellow
|
|
262
|
+
frame1.m_grid2.SetAttr(1, 1, attr)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
frame1.Show(True)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
return frame1
|
|
270
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from numpy import *
|
|
2
|
+
import struct
|
|
3
|
+
import datetime
|
|
4
|
+
import os
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def load_adxl355_file(filename):
|
|
9
|
+
t, y = [], []
|
|
10
|
+
with open(filename, 'rb') as file:
|
|
11
|
+
while True:
|
|
12
|
+
chunk = file.read(24)
|
|
13
|
+
if not chunk:
|
|
14
|
+
break
|
|
15
|
+
data = struct.unpack('<QIfff', chunk)
|
|
16
|
+
|
|
17
|
+
t_ = datetime.datetime.fromtimestamp(data[0])
|
|
18
|
+
t_ = t_.replace(microsecond = data[1])
|
|
19
|
+
t.append(t_)
|
|
20
|
+
y.append(data[2:])
|
|
21
|
+
t = array(t)
|
|
22
|
+
y = array(y)
|
|
23
|
+
df = pd.DataFrame({'timestamps': t, "X": y[:, 0], "Y": y[:, 1], "Z": y[:, 2]})
|
|
24
|
+
df.set_index(df['timestamps'], inplace = True)
|
|
25
|
+
del df['timestamps']
|
|
26
|
+
return df
|
|
27
|
+
|
|
File without changes
|
|
File without changes
|
enode_host/backup/s.py
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/local/bin/python3
|
|
2
|
+
|
|
3
|
+
#----------------------------------------------
|
|
4
|
+
# HOW TO USE THE SYSTEM
|
|
5
|
+
#
|
|
6
|
+
# 1. please execute this file first, so that the server is ready to receive data from ndoes
|
|
7
|
+
# 2. turn on the node(s)
|
|
8
|
+
# - the PPS LED on the display can be believed
|
|
9
|
+
# - please don't believe RSSI, Lv, BAT %, as they are not completed yet.
|
|
10
|
+
# 3. Files are saved under data2 folder in HDF
|
|
11
|
+
# 4. Please read example.ipynb for how to load data file and display it
|
|
12
|
+
# - Please notice the time is in UTC to avoid any issues regarding British Summer Time
|
|
13
|
+
# 5. For time-sync, never reset the acc node, but power-cycle it.
|
|
14
|
+
# - there are two buttons on the sensor node:
|
|
15
|
+
# - one for power next to the USB-c port
|
|
16
|
+
# - the other for reset next to the SD slot
|
|
17
|
+
# - pressing the pwr button for 5 sec will shutdown the node, and pressing it for 1 sec will start the node
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
import logging
|
|
21
|
+
import gui
|
|
22
|
+
import mesh
|
|
23
|
+
import sys
|
|
24
|
+
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
25
|
+
from PyQt5.QtGui import QColor
|
|
26
|
+
import threading
|
|
27
|
+
import queues
|
|
28
|
+
from numpy import array
|
|
29
|
+
import shm_sigproc
|
|
30
|
+
import glob
|
|
31
|
+
import os
|
|
32
|
+
|
|
33
|
+
from matplotlib.pyplot import *
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
os.makedirs("log", exist_ok = True)
|
|
38
|
+
os.makedirs("data", exist_ok = True)
|
|
39
|
+
os.makedirs("data2", exist_ok = True)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
logging.basicConfig(level=logging.INFO, # Set the minimum log level
|
|
43
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
44
|
+
handlers=[logging.FileHandler('log/my_log_file.log'), logging.StreamHandler()])
|
|
45
|
+
logger = logging.getLogger(__name__)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
df = []
|
|
49
|
+
psd = []
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def begin():
|
|
53
|
+
|
|
54
|
+
mesh.begin()
|
|
55
|
+
shm_sigproc.begin()
|
|
56
|
+
|
|
57
|
+
app = QtWidgets.QApplication(sys.argv)
|
|
58
|
+
window = gui.MainWindow()
|
|
59
|
+
app.exec_()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def export():
|
|
64
|
+
|
|
65
|
+
global df
|
|
66
|
+
|
|
67
|
+
raw_data_dir = 'data2'
|
|
68
|
+
|
|
69
|
+
node_IDs = []
|
|
70
|
+
|
|
71
|
+
import os
|
|
72
|
+
import pandas as pd
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
entries = os.listdir(raw_data_dir)
|
|
76
|
+
files = [f for f in entries if f.endswith('.hd5')]
|
|
77
|
+
|
|
78
|
+
# IDENTIFY NODE IDs
|
|
79
|
+
for file in files:
|
|
80
|
+
node_IDs.append(file.split('-')[0])
|
|
81
|
+
node_IDs = sorted(set(node_IDs))
|
|
82
|
+
|
|
83
|
+
# READ AND MERGE ALL RAW DATA FILES
|
|
84
|
+
dfs = []
|
|
85
|
+
for node_ID in node_IDs:
|
|
86
|
+
dfs_ = []
|
|
87
|
+
files_ = [f for f in entries if f.endswith('.hd5') and f.startswith(node_ID)]
|
|
88
|
+
for file_ in files_:
|
|
89
|
+
dfs_.append(pd.read_hdf(os.path.join(raw_data_dir, file_)))
|
|
90
|
+
df_ = pd.concat(dfs_, axis = 0)
|
|
91
|
+
df_ = df_.rename(columns={
|
|
92
|
+
'X': '{}-X'.format(node_ID),
|
|
93
|
+
'Y': '{}-Y'.format(node_ID),
|
|
94
|
+
'Z': '{}-Z'.format(node_ID)
|
|
95
|
+
})
|
|
96
|
+
dfs.append(df_)
|
|
97
|
+
|
|
98
|
+
df = pd.concat(dfs, axis = 1)
|
|
99
|
+
df = df.dropna()
|
|
100
|
+
df.plot(figsize=(24, 6))
|
|
101
|
+
show()
|
|
102
|
+
|
|
103
|
+
filename = "data/daq-{}".format(df.index[0].strftime("%Y_%m%d_%H%M"))
|
|
104
|
+
df.to_hdf(filename, key="df")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def clear():
|
|
109
|
+
# DELETE TEMPORARIL FILES
|
|
110
|
+
for file in glob.glob("data2/*.hd5"):
|
|
111
|
+
try:
|
|
112
|
+
os.remove(file)
|
|
113
|
+
except Exception as e:
|
|
114
|
+
logger.error(f"Error deleting file {file}: {e}")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
if __name__ == '__main__':
|
|
119
|
+
begin()
|
|
120
|
+
|
|
121
|
+
# thread = threading.Thread(target = main)
|
|
122
|
+
# thread.start()
|
|
123
|
+
# logger.info("mesh_server started.")
|
|
124
|
+
|
|
125
|
+
# grid_time = int(datetime.datetime.now().timestamp()/config.TIME_WINDOW_LENGTH_SEC) * config.TIME_WINDOW_LENGTH_SEC
|
|
126
|
+
|
|
127
|
+
# timeWindow = [datetime.datetime.fromtimestamp(grid_time),
|
|
128
|
+
# datetime.datetime.fromtimestamp(grid_time + config.TIME_WINDOW_LENGTH_SEC)]
|
|
129
|
+
# tdata = thp_lines[nodeID-1].get_xdata()
|
|
130
|
+
# ydata = thp_lines[nodeID-1].get_ydata()
|
|
131
|
+
# idx = where(array(tdata) < timeWindow[0])
|
|
132
|
+
# tdata = delete(tdata, idx[0])
|
|
133
|
+
# ydata = delete(ydata, idx[0], 0)
|
|
134
|
+
# tdata = append(tdata, t)
|
|
135
|
+
# ydata = append(ydata, y)
|
|
136
|
+
# thp_lines[nodeID - 1].set_xdata(tdata)
|
|
137
|
+
# thp_lines[nodeID - 1].set_ydata(ydata)
|
|
138
|
+
# sc = window.m_ui.listView
|
|
139
|
+
# sc.axes[0].set_xlim(timeWindow[0], timeWindow[1])
|
|
140
|
+
# sc.axes[0].xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))
|
|
141
|
+
# draw()
|
|
142
|
+
# # pause(0.05)
|
|
143
|
+
# # show(block = False)
|
|
144
|
+
# logger.info("len(tdata) = {}".format(len(tdata)))
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# for t, y_ in zip(t, y):
|
|
148
|
+
# logger.info("{}, {}, {}, {}".format(t, y_[0], y_[1], y_[2]))
|
|
149
|
+
|
|
150
|
+
# time.sleep(0.1)
|
|
151
|
+
|