From 514964d7c62285b36d5eb01ea1bf8a16f6baec50 Mon Sep 17 00:00:00 2001 From: matteo porta Date: Wed, 29 Jun 2022 13:12:09 +0200 Subject: [PATCH 1/4] camera config --- config/machine_settings/defaults.ini | 22 +++++++++++++--------- src/components/galaxy_camera.py | 28 ++++++++++++++++------------ 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/config/machine_settings/defaults.ini b/config/machine_settings/defaults.ini index b663ba3..a66eab0 100644 --- a/config/machine_settings/defaults.ini +++ b/config/machine_settings/defaults.ini @@ -1,13 +1,17 @@ [galaxy_camera] -exposure time: 10000 -horizontal crop offset: 0 -horizontal crop resolution: 2448 -vertical crop offset: 724 -vertical crop resolution: 800 -rotate 90 clockwise times: 0 -balance red: 1.0 -balance green: 1.0 -balance blue: 1.0 +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 [vision_saver] time_format: %Y-%m-%d_%H-%M-%S diff --git a/src/components/galaxy_camera.py b/src/components/galaxy_camera.py index afce9a5..2fe5fe9 100644 --- a/src/components/galaxy_camera.py +++ b/src/components/galaxy_camera.py @@ -29,20 +29,24 @@ 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.exposure_time = int(self.config[self.name]["exposure time"]) - self.roi = { - "x": int(self.round_4(self.config[self.name]["horizontal crop offset"])), - "w": int(self.round_4(self.config[self.name]["horizontal crop resolution"])), - "y": int(self.round_4(self.config[self.name]["vertical crop offset"])), - "h": int(self.round_4(self.config[self.name]["vertical crop resolution"])), - "r": int(self.config[self.name]["rotate 90 clockwise times"]), + 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.auto_white_balance = bool(self.config[self.name].get("auto white balance", False)) + 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))), + "w": int(self.round_4(self.config[self.name].get("horizontal_crop_resolution", self.resolution["w"]))), + "y": int(self.round_4(self.config[self.name].get("vertical_crop_offset", 0))), + "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 = 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)), - "b": float(self.config[self.name].get("balance blue", 1)), + "r": float(self.config[self.name].get("balance_red", 1)), + "g": float(self.config[self.name].get("balance_green", 1)), + "b": float(self.config[self.name].get("balance_blue", 1)), } self.lock.lock() self.camera.stream_off() From c36f95301227c3267f56d97fbaf39ad7eb4232a6 Mon Sep 17 00:00:00 2001 From: ST-TEN-1 Date: Mon, 4 Jul 2022 12:36:51 +0200 Subject: [PATCH 2/4] tecna wip --- init.sh | 2 +- src/components/modbus_component.py | 2 +- src/components/tecna_marposs_provaset_t3.py | 70 +++++---- .../tecna_marposs_provaset_t3_registers.py | 135 +++++++++++------- src/components/vision.py | 13 +- src/main.py | 8 +- src/test/tecna.py | 4 +- 7 files changed, 144 insertions(+), 90 deletions(-) diff --git a/init.sh b/init.sh index 3e34218..1e2c7f6 100755 --- a/init.sh +++ b/init.sh @@ -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" || : diff --git a/src/components/modbus_component.py b/src/components/modbus_component.py index d50e4af..20618f3 100644 --- a/src/components/modbus_component.py +++ b/src/components/modbus_component.py @@ -64,7 +64,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)) diff --git a/src/components/tecna_marposs_provaset_t3.py b/src/components/tecna_marposs_provaset_t3.py index 8944a15..330727a 100644 --- a/src/components/tecna_marposs_provaset_t3.py +++ b/src/components/tecna_marposs_provaset_t3.py @@ -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", diff --git a/src/components/tecna_marposs_provaset_t3_registers.py b/src/components/tecna_marposs_provaset_t3_registers.py index c5a85c6..3b66ed3 100644 --- a/src/components/tecna_marposs_provaset_t3_registers.py +++ b/src/components/tecna_marposs_provaset_t3_registers.py @@ -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. } diff --git a/src/components/vision.py b/src/components/vision.py index 27ce783..866ded6 100644 --- a/src/components/vision.py +++ b/src/components/vision.py @@ -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") diff --git a/src/main.py b/src/main.py index 3dc159a..ddd8ff8 100644 --- a/src/main.py +++ b/src/main.py @@ -9,11 +9,13 @@ import traceback 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 +36,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, @@ -48,7 +50,7 @@ logging.basicConfig( try: # IMPORT PROJECT ONLY AFTER SETTING UP SIGNAL, FAULTHANDLER AND LOGGHING - from components import (ArchiveSynchronizer, GalaxyCamera, NeoPixels, + from components import (ArchiveSynchronizer, NeoPixels, Os_Label_Printer, RemoteAPI, TecnaMarpossProvasetT3, TestComponent, Vision, VisionSaver) diff --git a/src/test/tecna.py b/src/test/tecna.py index 98cccff..4092ddf 100644 --- a/src/test/tecna.py +++ b/src/test/tecna.py @@ -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") From a3b38a63d39b0cc7d78058bd9d60d67a8e789fe3 Mon Sep 17 00:00:00 2001 From: matteo porta Date: Tue, 5 Jul 2022 18:16:22 +0200 Subject: [PATCH 3/4] fixes --- src/lib/db/crud_db.py | 7 ++++--- src/main.py | 31 +++++++------------------------ src/ui/crud/crud.py | 31 ++++++++++++++++--------------- 3 files changed, 27 insertions(+), 42 deletions(-) diff --git a/src/lib/db/crud_db.py b/src/lib/db/crud_db.py index 6ae47e5..f883bed 100755 --- a/src/lib/db/crud_db.py +++ b/src/lib/db/crud_db.py @@ -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: diff --git a/src/main.py b/src/main.py index 3dc159a..44b0173 100644 --- a/src/main.py +++ b/src/main.py @@ -6,6 +6,7 @@ import os import signal import sys import traceback +import weakref from datetime import datetime from pathlib import Path @@ -112,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 @@ -138,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) @@ -163,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) diff --git a/src/ui/crud/crud.py b/src/ui/crud/crud.py index 124b470..139d124 100755 --- a/src/ui/crud/crud.py +++ b/src/ui/crud/crud.py @@ -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 From ddda7357adc88e2826a77dd0abbd5006ac799e00 Mon Sep 17 00:00:00 2001 From: matteo porta Date: Tue, 5 Jul 2022 18:23:25 +0200 Subject: [PATCH 4/4] fixes --- src/components/modbus_component.py | 6 -- .../tecna_marposs_provaset_t3_registers.py | 2 +- src/main.py | 8 +-- src/test/chart_memory_usage.py | 56 +++++++++++++++++++ 4 files changed, 61 insertions(+), 11 deletions(-) create mode 100755 src/test/chart_memory_usage.py diff --git a/src/components/modbus_component.py b/src/components/modbus_component.py index 20618f3..55b89fe 100644 --- a/src/components/modbus_component.py +++ b/src/components/modbus_component.py @@ -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): diff --git a/src/components/tecna_marposs_provaset_t3_registers.py b/src/components/tecna_marposs_provaset_t3_registers.py index 3b66ed3..08d22f5 100644 --- a/src/components/tecna_marposs_provaset_t3_registers.py +++ b/src/components/tecna_marposs_provaset_t3_registers.py @@ -81,7 +81,7 @@ registers = { 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", }], diff --git a/src/main.py b/src/main.py index d2efd41..4fec119 100644 --- a/src/main.py +++ b/src/main.py @@ -12,6 +12,7 @@ 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 @@ -51,10 +52,9 @@ logging.basicConfig( try: # IMPORT PROJECT ONLY AFTER SETTING UP SIGNAL, FAULTHANDLER AND LOGGHING - from components import (ArchiveSynchronizer, 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 diff --git a/src/test/chart_memory_usage.py b/src/test/chart_memory_usage.py new file mode 100755 index 0000000..1d53d92 --- /dev/null +++ b/src/test/chart_memory_usage.py @@ -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_())