Merge remote-tracking branch 'origin/master'

# Conflicts:
#	config/machine_settings/defaults.ini
#	src/components/galaxy_camera.py
This commit is contained in:
neo-dl 2022-07-06 11:09:23 +02:00
commit f5865b6f28
12 changed files with 234 additions and 143 deletions

View File

@ -1,12 +1,14 @@
[galaxy_camera]
horizontal_resolution: 2448
vertical_resolution: 2048
; frame_time_ms: 300
exposure_time: 10000
; horizontal_crop_offset: 0
; horizontal_crop_resolution: 2448
; vertical_crop_offset: 0
; vertical_crop_resolution: 2048
; rotate_90_clockwise times: 0
; auto_white_balance: off
; balance_red: 1.0
; balance_green: 1.0
; balance_blue: 1.0

View File

@ -6,7 +6,7 @@ cd "$here"
echo "---------- initialize venv ----------"
lsof "./venv/bin/python" | awk 'NR > 1 {print $2}' | xargs kill || :
lsof "./venv/Scripts/activate" | awk 'NR > 1 {print $2}' | xargs kill || :
python="python3.9"
python="python"
"${python}" -m pip install --upgrade pip
"${python}" -m venv venv
source "./venv/bin/activate" || source "./venv/Scripts/activate" || :

View File

@ -29,11 +29,11 @@ class GalaxyCamera(Component):
self._last_frame = None
def config_changed(self):
self._period = int(self.config[self.name].get("frame time ms", 300)) / 1000
self.resolution = {
"w": int(self.round_4(self.config[self.name]["horizontal_resolution"])),
"h": int(self.round_4(self.config[self.name]["vertical_resolution"])),
}
self._period = int(self.config[self.name].get("frame_time_ms", 300)) / 1000
self.exposure_time = int(self.config[self.name]["exposure_time"])
self.roi = {
"x": int(self.round_4(self.config[self.name].get("horizontal_crop_offset", 0))),
@ -42,7 +42,7 @@ class GalaxyCamera(Component):
"h": int(self.round_4(self.config[self.name].get("vertical_crop_resolution", self.resolution["h"]))),
"r": int(self.config[self.name].get("rotate_90_clockwise_times", 0)),
}
self.auto_white_balance = bool(self.config[self.name].get("auto white balance", False))
self.auto_white_balance = self.config[self.name].get("auto_white_balance", "").lower() in {"on", "1", "y", "yes", "true", "enable", "enabled", }
self.balance = {
"r": float(self.config[self.name].get("balance_red", 1)),
"g": float(self.config[self.name].get("balance_green", 1)),

View File

@ -14,12 +14,6 @@ else:
from .component import Component
# from pymodbus.client.sync import ModbusSerialClient as ModbusClient
# import serial
# client = ModbusClient(method="rtu", port="COM3", stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, baudrate=115200, timeout=1, strict=False)
# client.connect()
# client.read_holding_registers(1, count=1)
class ModbusComponent(Component):
def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True, registers=None):
@ -64,7 +58,7 @@ class ModbusComponent(Component):
def _write(self, register, value):
self.lock.lock()
wrote = self.client.write_register(register, value)
wrote = self.client.write_registers(register, value, skip_encode=True)
self.lock.unlock()
if wrote.isError():
self.log.exception(traceback.format_exception(wrote))

View File

@ -16,6 +16,7 @@ class TecnaMarpossProvasetT3(ModbusComponent):
super().config_changed()
# self.set_measure_units()
self.units = self.get_measure_units()
self.log.info(f"units: {self.units}")
_pressure_units = {"mH2O": 0, "mbar": 1, "kPa": 2, "mmHg": 3, "inH2O": 4, "psi": 5, "mmH2O": 6, } # (se fondoscala <=6 bar)
_leak_units = {"mmH2O": 0, "mbar": 1, "Pa": 2, "mmHg": 3, "inH2O": 4, "psi": 5, }
@ -32,11 +33,11 @@ class TecnaMarpossProvasetT3(ModbusComponent):
def set_measure_units(self):
return [
self.write("MEASURE UNITS: pressure measure units", self._pressure_units["mbar"]),
self.write("MEASURE UNITS: Leak measure units", self._leak_units["mbar"]),
self.write("MEASURE UNITS: leak flow rate measure units", self._leak_flow_units["cm3/min"]),
self.write("MEASURE UNITS: Volume", self._volume_units["litri"]),
self.write("MEASURE UNITS: Flow rate measure units", self._flow_units["liters/min"]),
self.write("MEASURE UNITS: pressure measure units", self._pressure_units["mbar"]), # red, ?purple?
self.write("MEASURE UNITS: Leak measure units", self._leak_units["mbar"]), # yellow
self.write("MEASURE UNITS: leak flow rate measure units", self._leak_flow_units["cm3/min"]), # blue
self.write("MEASURE UNITS: Volume", self._volume_units["litri"]), # green
self.write("MEASURE UNITS: Flow rate measure units", self._flow_units["liters/min"]), # orange
]
def get_measure_units(self):
@ -56,38 +57,43 @@ class TecnaMarpossProvasetT3(ModbusComponent):
units[unit_name] = unit
return units
def _convert_from_format(self, data, format=None):
if format is None:
return data
# units = self.units[format]
# return [data * units[0], units[1]]
return data * self.units[format][0]
def _convert_from_format(self, data, formatting=None, decoding_map=None):
if decoding_map is not None:
data = decoding_map[data]
if formatting is not None:
# units = self.units[formatting]
# data = [data * units[0], units[1]]
data = data * self.units[formatting][0]
return data
def _convert_to_format(self, data, format=None):
if format is None:
return data
return int(data / self.units[format][0])
def _convert_to_format(self, data, formatting=None, encoding_map=None):
if formatting is not None:
data = int(data / self.units[formatting][0])
if encoding_map is not None:
data = encoding_map[data]
return data
def read(self, register, *args, format=None, **kwargs):
def read(self, register, *args, formatting=None, decoding_map=None, **kwargs):
if type(register) is str:
_, s = self.registers[register]
if format is None:
format = s.get("f")
return self._convert_from_format(super().read(register, *args, **kwargs), format=format)
if formatting is None:
formatting = s.get("f", None)
if decoding_map is None:
decoding_map = s.get("decoding", None)
return self._convert_from_format(super().read(register, *args, **kwargs), formatting=formatting, decoding_map=decoding_map)
def write(self, register, data, *args, format=None, **kwargs):
def write(self, register, data, *args, formatting=None, encoding_map=None, **kwargs):
if type(register) is str:
_, s = self.registers[register]
if format is None:
format = s.get("f")
return super().write(register, self._convert_to_format(data, format=format), *args, **kwargs)
if formatting is None:
formatting = s.get("f", None)
if encoding_map is None:
encoding_map = s.get("encoding", None)
return super().write(register, self._convert_to_format(data, formatting=formatting, encoding_map=encoding_map), *args, **kwargs)
def _get(self):
# print("TECNA", str(int(QThread.currentThreadId())), flush=True)
# READ INFO
if self.units is None:
self.set_measure_units()
self.units = self.get_measure_units()
info = {r: self.read(r) for r in [
"Instrument status: active phase",
"Test circuit pressure, in real time",
@ -97,8 +103,20 @@ class TecnaMarpossProvasetT3(ModbusComponent):
"Running test: type of test",
"Testing in progress: progressive sequence index",
]}
if info["Running test: type of test"] is None:
info.update(self.get_test_results())
self.start_test()
print(info, flush=True)
super()._get([info])
def start_test(self):
self.log.info("starting test")
self.write("Start testing", 1)
def stop_test(self):
self.log.warining("stopping test")
self.write("Stop the test in progress", 0)
def get_test_results(self):
return {r: self.read(r) for r in [
"Running test: measured leak",

View File

@ -16,30 +16,31 @@ registers = {
"Format of time variables": [26, {"dt": "16bit_uint", }],
"Format of variables related to flow measurements": [27, {"dt": "16bit_uint", }],
"Instrument status: table of parameters in use": [31, {"dt": "16bit_uint", }],
"Instrument status: active phase": [32, {"dt": "16bit_uint", }],
# 0 = NO TEST EXECUTED: WAITING START NEW TEST
# 10 = TEST IN PROGRESS: CHECK BARCODE CODE (if enabled)
# 20 = TEST IN PROGRESS: WAITING READING BARCODE CODE (if enabled)
# 30 = TEST IN PROGRESS: TEST INITIALIZATION
# 40 = TEST IN PROGRESS: AUTOMATIC CLOSING 1 (CAGE)
# 50 = TEST IN PROGRESS: AUTOMATIC CLOSING 2 (PLUG)
# 60 = TEST IN PROGRESS: ACTIVE TEST PROGRAM INITIALIZATION
# 70 = TEST IN PROGRESS: WAITING ACKNOWLEDGE WITH BI-START COMMAND (if used)
# 80 = TEST IN PROGRESS: WAITING DELAY (PSDEL parameter)
# 90 = TEST IN PROGRESS: WAITING CONSENT SIGNAL (PSIN parameter)
# 100 = TEST IN PROGRESS: PHASE T0 - PRE-FILLING
# 110 = TEST IN PROGRESS: PHASE T1 - FILLING
# 120 = TEST IN PROGRESS: PHASE T2 - ASSESTMENT
# 130 = TEST IN PROGRESS: PHASE T3- SIZE
# 140 = TEST IN PROGRESS: WAITING CONFIRMATION EXAMINED BY OPERATOR (if used)
# 150 = TEST IN PROGRESS: TEST RESULT PRESENT
# 160 = TEST IN PROGRESS: MARKING (only if last table of a sequence or not in sequence mode)
# 170 = TEST IN PROGRESS: PRESSURE DISCHARGE
# 180 = TEST IN PROGRESS: END OF TESTING TABLE - IF IN SEQUENCE MODE THE CYCLE STARTS FROM
# PHASE 60 WITH THE NEXT TABLE OF THE SEQUENCE
# 190 = TEST IN PROGRESS: AUTOMATIC OPENING 2 (BUFFER)
# 200 = TEST IN PROGRESS: AUTOMATIC OPENING 1 (CAGE)
# 210 = TEST TERMINATED: WAITING THE START OF A NEW TEST
"Instrument status: active phase": [32, {"dt": "16bit_uint", "decoding": {
0: "NO TEST EXECUTED: WAITING START NEW TEST",
10: "TEST IN PROGRESS: CHECK BARCODE CODE (if enabled)",
20: "TEST IN PROGRESS: WAITING READING BARCODE CODE (if enabled)",
30: "TEST IN PROGRESS: TEST INITIALIZATION",
40: "TEST IN PROGRESS: AUTOMATIC CLOSING 1 (CAGE)",
50: "TEST IN PROGRESS: AUTOMATIC CLOSING 2 (PLUG)",
60: "TEST IN PROGRESS: ACTIVE TEST PROGRAM INITIALIZATION",
70: "TEST IN PROGRESS: WAITING ACKNOWLEDGE WITH BI-START COMMAND (if used)",
80: "TEST IN PROGRESS: WAITING DELAY (PSDEL parameter)",
90: "TEST IN PROGRESS: WAITING CONSENT SIGNAL (PSIN parameter)",
100: "TEST IN PROGRESS: PHASE T0 - PRE-FILLING",
110: "TEST IN PROGRESS: PHASE T1 - FILLING",
120: "TEST IN PROGRESS: PHASE T2 - ASSESTMENT",
130: "TEST IN PROGRESS: PHASE T3- SIZE",
140: "TEST IN PROGRESS: WAITING CONFIRMATION EXAMINED BY OPERATOR (if used)",
150: "TEST IN PROGRESS: TEST RESULT PRESENT",
160: "TEST IN PROGRESS: MARKING (only if last table of a sequence or not in sequence mode)",
170: "TEST IN PROGRESS: PRESSURE DISCHARGE",
180: "TEST IN PROGRESS: END OF TESTING TABLE - IF IN SEQUENCE MODE THE CYCLE STARTS FROM",
# PHASE 60 WITH THE NEXT TABLE OF THE SEQUENCE
190: "TEST IN PROGRESS: AUTOMATIC OPENING 2 (BUFFER)",
200: "TEST IN PROGRESS: AUTOMATIC OPENING 1 (CAGE)",
210: "TEST TERMINATED: WAITING THE START OF A NEW TEST",
}, }],
"Running test: active phase backwards time": [33, {"dt": "16bit_uint", "f": 26, }],
"Running test: T1 phase end pressure": [34, {"dt": "32bit_int", "f": 21, }],
"Running test: T2 phase end pressure": [36, {"dt": "32bit_int", "f": 21, }],
@ -47,39 +48,58 @@ registers = {
"Running test: measured leak": [40, {"dt": "32bit_int", "f": 22, }],
"Running test: calculated leak flow rate": [42, {"dt": "32bit_int", "f": 24, }],
"Running test: calculate RVP%": [44, {"dt": "32bit_int", }],
"Running test: result": [46, {"dt": "16bit_uint", }],
# 1 = LEAK TEST PASSED
# 2 = BURST TEST PASSED WITH BURST
# 3 = BURST TEST PASSED WITHOUT BURST
# 4 = not used
# 5 = BLOCKAGE TEST PASSED
# 100 = LEAK TEST FAILED - UPPER LIMIT
# 101 = LEAK TEST – FAILED ANOMALY
# 102 = LEAK TEST - MAXIMUM LEAK FAILED
# 103 = BURST - BREAKAGE PRESSURE DEFLECTION
# 104 = VOLUMETRIC CONTROL - RVP% FAILED
# 105 = not used
# 106 = not used
# 107 = BLOCKAGE - MAX PRESSURE FAILED
# 108 = BLOCKAGE - MIN PRESSURE FAILED
# 109 = BURST - MINIMUM PRESSURE FAILED
# 200 = LEAK TEST FAILED – PR% PRESSURE MINUM
# 201 = LEAK TEST FAILED - PR% PRESSURE MAX
# 202 = LEAK TEST FAILED – P0% PRESSURE MINUM
# 203 = LEAK TEST FAILED - P0% PRESSURE MAX
# 204 = ERROR - INTERNAL ALARMS
# 205 = ERROR - RELATIVE PRESSURE OUT OF RANGE
# 206 = ERROR - DIFFERENTIAL PRESSURE OUT OF RANGE
# 207 = ERROR – PRE-FILLING VALVE NOT OPENED
# 250 = TEST ABORTED
"Running test: type of test": [47, {"dt": "16bit_uint", }],
# 1 = LEAK TEST
# 2 = BLOCKAGE TEST
# 3 = LEAK TEST WITH VOLUME CHECK
# 4 = BURST TEST
"Running test: result": [46, {"dt": "16bit_uint", "decoding": {
0: None,
1: "LEAK TEST PASSED",
2: "BURST TEST PASSED WITH BURST",
3: "BURST TEST PASSED WITHOUT BURST",
4: "not used",
5: "BLOCKAGE TEST PASSED",
100: "LEAK TEST FAILED - UPPER LIMIT",
101: "LEAK TEST – FAILED ANOMALY",
102: "LEAK TEST - MAXIMUM LEAK FAILED",
103: "BURST - BREAKAGE PRESSURE DEFLECTION",
104: "VOLUMETRIC CONTROL - RVP% FAILED",
105: "not used",
106: "not used",
107: "BLOCKAGE - MAX PRESSURE FAILED",
108: "BLOCKAGE - MIN PRESSURE FAILED",
109: "BURST - MINIMUM PRESSURE FAILED",
200: "LEAK TEST FAILED – PR% PRESSURE MINUM",
201: "LEAK TEST FAILED - PR% PRESSURE MAX",
202: "LEAK TEST FAILED – P0% PRESSURE MINUM",
203: "LEAK TEST FAILED - P0% PRESSURE MAX",
204: "ERROR - INTERNAL ALARMS",
205: "ERROR - RELATIVE PRESSURE OUT OF RANGE",
206: "ERROR - DIFFERENTIAL PRESSURE OUT OF RANGE",
207: "ERROR – PRE-FILLING VALVE NOT OPENED",
250: "TEST ABORTED",
}, }],
"Running test: type of test": [47, {"dt": "16bit_uint", "decoding": {
0: None,
1: "LEAK TEST",
2: "BLOCKAGE TEST",
3: "LEAK TEST WITH VOLUME CHECK",
4: "BURST TEST",
}, }],
"Testing in progress: progressive sequence index": [48, {"dt": "16bit_uint", }],
"Testing in progress: graphical sampling rate": [49, {"dt": "16bit_uint", }],
"Testing in progress: number of samples of the graph": [50, {"dt": "16bit_uint", }],
# ------------------------- COMMANDS -------------------------
"Start testing": [101, {"dt": "16bit_uint", }],
# Write a value of 0 to use the selected test table.
# Write a value from 1 to 100 to start testing with the desired table.
"Stop the test in progress": [102, {"dt": "16bit_uint", }],
"Activate digital output": [103, {"dt": "16bit_uint", }],
# Write a number from 1 to 16 to activate the corresponding digital output (the output must be set as "Free")
"Reset specific digital output": [104, {"dt": "16bit_uint", }],
# Write a number from 1 to 16 to disable the relative digital output (the output must be set as "Free")
"Activate digital output (mask)": [105, {"dt": "16bit_uint", }],
# Write 1 in the bit corresponding to the output to be activated
"Reset digital output (mask)": [106, {"dt": "16bit_uint", }],
# Write 1 in the bit corresponding to the output to be deactivated
"Reset test counter": [107, {"dt": "16bit_uint", }],
# ------------------------------------------------------------
"DISLPAY and SOUND: Language": [601, {"dt": "16bit_uint", }],
# 0=ITALIANO
# 1=ENGLISH
@ -166,4 +186,11 @@ registers = {
# VOLUME+LEAK: Format x.xx (from 0.00 to 649.99)
"RVP%: max tolerance": [751, {"dt": "16bit_uint", }],
# VOLUME+LEAK: Format: x.xx
# 1001-1060 Table of the last test performed X The order of the parameters is always the same, as indicated for register from 701 to 759.
# 10001-10060 Direct access to test program table number 1 X X The order of the parameters is always the same, as indicated for register from 701 to 759.
# 10101-10160 Direct access to test program table number 2 X X The order of the parameters is always the same, as indicated for register from 701 to 759.
# 10201-19960 Direct access to test program table number 2 thru 100 X X The order of the parameters is always the same, as indicated for register from 701 to 759.
# 501-510 U16 Model name X 20 ASCII characters divided into 10 registers
# 511-520 U16 Serial number X 10 ASCII characters divided into 5 registers
# 2001-8000 S32 Pressure values with sign X Register 49 indicates the sampling rate in tenths of a second Register 50 indicates the number of valid values In the leak tests, the values referred to the phases T0, T1 and T2 are under absolute pressure, while the values referred to phase T3 represent the detected loss.
}

View File

@ -18,15 +18,22 @@ from .component import Component
from .consumer import Consumer
if "--no-edgetpu" not in sys.argv:
if "--no-tflite" not in sys.argv:
try:
from pycoral.utils.edgetpu import make_interpreter
except (ImportError, ModuleNotFoundError) as e:
def make_interpreter(*args, **kwargs):
raise ValueError(f"{e!r}")
else:
def make_interpreter(*args, **kwargs):
raise ValueError("\"--no-edgetpu\" in sys.argv")
if "--no-tflite" not in sys.argv:
from pycoral.adapters import detect
from tflite_runtime.interpreter import Interpreter
try:
from pycoral.adapters import detect
from tflite_runtime.interpreter import Interpreter
except (ImportError, ModuleNotFoundError) as e:
def Interpreter(*args, **kwargs):
raise ValueError(f"{e!r}")
else:
def Interpreter(*args, **kwargs):
raise ValueError("\"--no-tflite\" in sys.argv")

View File

@ -11,11 +11,12 @@ class Crud_DB:
self.table_fields = list(self.table_model._meta.fields.keys())
self.pagination = pagination
self.default_filters = {}
self.sorting = {}
self.filters = {}
if filters is None:
filters = {}
for column_name, filter in filters.items():
self.filter(column_name, filter, filter_storage=self.default_filters)
self.revert()
def commit(self, data, deleted_rows=None):
with db.atomic() as trx:
@ -37,8 +38,8 @@ class Crud_DB:
raise e
def revert(self):
self.sorting = {}
self.filters = {}
self.sorting.clear()
self.filters.clear()
def get(self, page=0):
if self.table_model._meta.composite_key:

View File

@ -6,14 +6,18 @@ import os
import signal
import sys
import traceback
import weakref
from datetime import datetime
from pathlib import Path
app = None
def quit_app(signalnum=None, handler=None):
logging.info(f"quitting app. signal: {signalnum!r}, handler: {handler!r}")
global app
app.quit()
if app is not None:
app.quit()
quit()
@ -34,7 +38,7 @@ logging.basicConfig(
handlers=[
logging.StreamHandler(stream=sys.stderr),
logging.FileHandler(
logs_dir / f"{datetime.now().isoformat()}.log",
logs_dir / f"{datetime.now().isoformat().replace(':', ';')}.log",
mode="a",
encoding="utf-8",
delay=False,
@ -46,10 +50,9 @@ logging.basicConfig(
try:
# IMPORT PROJECT ONLY AFTER SETTING UP SIGNAL, FAULTHANDLER AND LOGGHING
from components import (ArchiveSynchronizer, GalaxyCamera, NeoPixels,
Os_Label_Printer, RemoteAPI,
TecnaMarpossProvasetT3, TestComponent, Vision,
VisionSaver)
from components import (ArchiveSynchronizer, NeoPixels, Os_Label_Printer,
RemoteAPI, TecnaMarpossProvasetT3, TestComponent,
Vision, VisionSaver)
from lib.db import Users
from lib.helpers import ConfigReader
from PyQt5.QtCore import QObject, QThread, pyqtSignal
@ -110,18 +113,18 @@ try:
# self.main_window = Main_Window(self.bench)
self.main_window = Main_Window()
# CONNECT MAIN WINDOW ACTIONS
self.main_window.archive_a.triggered.connect(self.open_archive)
self.main_window.archive_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Archive()))
if "--archive" in sys.argv:
self.main_window.archive_a.trigger()
self.main_window.autotests_archive_a.triggered.connect(self.open_autotests_archive)
self.main_window.autotests_archive_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Autotests_Archive()))
if "--autotests-archive" in sys.argv:
self.main_window.autotests_archive_a.trigger()
self.main_window.about_a.triggered.connect(self.open_about)
self.main_window.about_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(About()))
if "--about" in sys.argv:
self.main_window.about_a.trigger()
self.main_window.admin_m.menuAction().setVisible(False) # admin menu should not be visible before an admin logs in
self.main_window.quit_a.triggered.connect(quit_app)
self.main_window.users_management_a.triggered.connect(self.open_users_management)
self.main_window.users_management_a.triggered.connect(lambda checked, self=weakref.ref(self): self().main_window.open_dialog(Users_Management()))
if "--users-management" in sys.argv:
self.main_window.users_management_a.trigger()
# OPEN LOGIN TAB
@ -136,19 +139,6 @@ try:
else:
self.main_window.showFullScreen()
def open_archive(self):
self.main_window.open_dialog(Archive())
def open_autotests_archive(self):
self.main_window.open_dialog(Autotests_Archive())
def open_users_management(self):
self.main_window.open_dialog(Users_Management())
def open_about(self):
about_widget = About()
self.main_window.open_dialog(about_widget)
def open_login(self):
tab = Login()
tab.successful_login.connect(self.logghed_in)
@ -161,13 +151,8 @@ try:
self.main_window.admin_m.menuAction().setVisible(True)
else:
self.main_window.admin_m.menuAction().setVisible(False)
self.open_test()
def open_test(self):
self.main_window.open_tab(Test(self.config.machine_id, self.components))
def open_test(self):
self.main_window.open_tab(Test(self.config.machine_id, self.components))
# open test
self.main_window.open_tab(Test(self.config.machine_id, self.components))
if __name__ == "__main__":
app = QApplication(sys.argv)

56
src/test/chart_memory_usage.py Executable file
View File

@ -0,0 +1,56 @@
#!/usr/bin/env python3
import sys
import traceback
from time import perf_counter
import pyqtgraph as pg
from pyqtgraph.Qt.QtCore import QTimer
from pyqtgraph.Qt.QtWidgets import QApplication, QGridLayout, QWidget
interval_ms = 250
statm_index = 0 # use 5 to limit showing size of data + stack
class App(QWidget):
def __init__(self):
super().__init__()
# GUI SETUP
self.layout = QGridLayout()
self.setLayout(self.layout)
# CHART SETUP
self.plot_widget = pg.PlotWidget()
self.plot_widget.enableAutoRange()
self.layout.addWidget(self.plot_widget)
self.plot_data = {"time": [], "size": []}
self.plot = self.plot_widget.plot(*self.plot_data.values())
# print(self.plot)
# self.plot_widget.addItem(self.plot)
# DATA SETUP
self.pid = sys.argv[1]
self.statm_file = f"/proc/{self.pid}/statm"
# PERIODIC SETUP
self.timer = QTimer()
# self.timer.setSingleShot(True)
self.timer.setInterval(interval_ms)
self.timer.timeout.connect(self.add_data)
self.start = perf_counter()
self.timer.start()
def add_data(self):
try:
with open(self.statm_file, "r") as f:
statm = f.read()
self.plot_data["time"].append(perf_counter() - self.start)
statm = statm.split()
self.plot_data["size"].append(int(statm[statm_index]))
self.plot.setData(*self.plot_data.values())
except Exception:
traceback.print_exc()
self.timer.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = App()
window.show()
sys.exit(app.exec_())

View File

@ -6,8 +6,8 @@ client = ModbusClient(method="rtu", port="COM3", stopbits=serial.STOPBITS_ONE, b
status = client.connect()
read_data = client.read_holding_registers(1, count=1)
if type(read_data) is not pymodbus.exceptions.ModbusIOException:
for i, v in enumerate(read_data):
print(f"READ DATA at {i}:{v}")
for i, v in enumerate(read_data.registers):
print(f"READ DATA at {i}: {v}")
pass
else:
print("READ ERROR")

View File

@ -1,6 +1,7 @@
import ast
import json
import traceback
import weakref
from datetime import datetime
from lib.db import Crud_DB
@ -198,7 +199,7 @@ class Crud(Widget):
self.filters = {}
self.db_tw.crud = self
self.refresh("init")
self.db_tw.horizontalHeader().sectionClicked.connect(self.toggleSort)
self.db_tw.horizontalHeader().sectionClicked.connect(self.toggle_sort)
# self.db_tw.horizontalHeader().setStretchLastSection(True)
self.db_tw.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
# self.db_tw.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
@ -208,13 +209,13 @@ class Crud(Widget):
else:
self.db_tw.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.db_tw.itemSelectionChanged.connect(self.show_selection)
self.revert_b.clicked.connect(lambda: self.refresh("revert"))
self.revert_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("revert"))
if self.pagination is not False:
self.start_b.clicked.connect(lambda: self.refresh("pagination", page=0))
self.previous_b.clicked.connect(lambda: self.refresh("pagination", page=max(self.page - 1, 0)))
self.page_n_sb.valueChanged.connect(lambda page: self.refresh("pagination", page=page - 1))
self.next_b.clicked.connect(lambda: self.refresh("pagination", page=self.page + 1))
self.end_b.clicked.connect(lambda: self.refresh("pagination", page=-1))
self.start_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("pagination", page=0))
self.previous_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("pagination", page=max(self().page - 1, 0)))
self.page_n_sb.valueChanged.connect(lambda page, self=weakref.ref(self): self().refresh("pagination", page=page - 1))
self.next_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("pagination", page=self().page + 1))
self.end_b.clicked.connect(lambda checked, self=weakref.ref(self): self().refresh("pagination", page=-1))
else:
self.next_b.setHidden(True)
self.previous_b.setHidden(True)
@ -239,7 +240,7 @@ class Crud(Widget):
sort_cycle = [True, False, None]
sort_symbol = [u" \u25B4", u" \u25BE", u""]
def toggleSort(self, cn=None):
def toggle_sort(self, cn=None, refresh=True):
if cn is not None:
fn = self.select[cn]
if fn not in self.db.table_fields:
@ -257,7 +258,8 @@ class Crud(Widget):
self.db_tw.setHorizontalHeaderLabels(self.fields_aliases.values())
self.sorting.clear() # for single column sorting
self.db.sort(None) # for single column sorting
self.refresh()
if refresh:
self.refresh()
def filter_edited(self, cn):
text = self.db_tw.cellWidget(0, cn).text()
@ -303,10 +305,9 @@ class Crud(Widget):
pass
elif action == "revert":
# REVERT SORTING AND FILTERS
self.sorting = {}
for cn, fn in enumerate(self.select):
self.toggleSort(None)
self.filters.clear()
self.sorting.clear()
self.toggle_sort(None, refresh=False)
self.filters.clear()
self.db.revert()
elif action == "commit" and not (self.readonly is None or self.readonly is True):
# COMMIT CHANGES
@ -358,7 +359,7 @@ class Crud(Widget):
if fn in self.db.table_fields:
w.setPlaceholderText("Filtro")
w.setText(self.filters.get(fn, None))
w.editingFinished.connect(lambda cn=cn: self.filter_edited(cn))
w.editingFinished.connect(lambda cn=cn, self=weakref.ref(self): self().filter_edited(cn))
else:
w.setPlaceholderText("Non filtrabile")
w.setEnabled(False)
@ -373,7 +374,7 @@ class Crud(Widget):
if fn in r:
w._render(data=r[fn], row_number=rn, crud=self)
self.db_tw.setCellWidget(rn, cn, w)
# REENABLEEVENTS AFTER UPDATE
# REENABLE EVENTS AFTER UPDATE
self.db_tw.blockSignals(False)
return True