From 03a98d3e69ee8e30854b0978b70b2960d199858b Mon Sep 17 00:00:00 2001 From: Rodriguez Date: Tue, 14 Nov 2023 10:15:40 +0100 Subject: [PATCH] start restoring tenma 72-2710 --- .../connectors/olds/serial_base.py | 14 --- .../connectors/olds/serial_tty.py | 82 -------------- .../connectors/serial_base.py | 2 +- .../panduza_platform/connectors/serial_tty.py | 33 +++--- .../panduza_platform/core/platform_device.py | 6 ++ .../core/platform_device_factory.py | 3 + .../devices/korad/ka3005/dev_ka3005.py | 4 +- .../korad/ka3005/itf_korad_ka3005p_ammeter.py | 4 +- .../korad/ka3005/itf_korad_ka3005p_bpc.py | 4 +- .../ka3005/itf_korad_ka3005p_voltmeter.py | 4 +- .../devices/tenma/__init__.py | 2 +- .../devices/tenma/t722710/__init__.py | 0 .../devices/tenma/t722710/dev_t722710.py | 102 ++++++++++++++++++ .../tenma/t722710/drv_tenma_722710_bpc.py | 40 +++---- .../devices/tenma/t722710/t722710.py | 53 --------- .../tests/manual/{start_hunt.py => hunt.py} | 2 +- platform/tests/manual/load_config.py | 26 +++++ platform/tests/manual/platform_basics.py | 1 - 18 files changed, 180 insertions(+), 202 deletions(-) delete mode 100644 platform/panduza_platform/connectors/olds/serial_base.py delete mode 100644 platform/panduza_platform/connectors/olds/serial_tty.py create mode 100644 platform/panduza_platform/devices/tenma/t722710/__init__.py create mode 100644 platform/panduza_platform/devices/tenma/t722710/dev_t722710.py delete mode 100644 platform/panduza_platform/devices/tenma/t722710/t722710.py rename platform/tests/manual/{start_hunt.py => hunt.py} (95%) create mode 100644 platform/tests/manual/load_config.py diff --git a/platform/panduza_platform/connectors/olds/serial_base.py b/platform/panduza_platform/connectors/olds/serial_base.py deleted file mode 100644 index 31cf88b0..00000000 --- a/platform/panduza_platform/connectors/olds/serial_base.py +++ /dev/null @@ -1,14 +0,0 @@ -import abc - - -class ConnectorSerialBase(metaclass=abc.ABCMeta): - """ - """ - - @abc.abstractmethod - def read(self): - pass - - @abc.abstractmethod - def write(self, data): - pass diff --git a/platform/panduza_platform/connectors/olds/serial_tty.py b/platform/panduza_platform/connectors/olds/serial_tty.py deleted file mode 100644 index 4bafa84f..00000000 --- a/platform/panduza_platform/connectors/olds/serial_tty.py +++ /dev/null @@ -1,82 +0,0 @@ -import serial -import logging -from .serial_base import ConnectorSerialBase -from .udev_tty import SerialPortFromUsbSetting - -class ConnectorSerialTty(ConnectorSerialBase): - """ - """ - - - # Contains instances - __instances = {} - - ########################################################################### - ########################################################################### - - @staticmethod - def Get(**kwargs): - """Singleton main getter - """ - # Get the serial port name - port_name = None - if "port_name" in kwargs: - port_name = kwargs["port_name"] - elif "vendor" in kwargs: - port_name = SerialPortFromUsbSetting(**kwargs) - kwargs["port_name"] = port_name - else: - raise Exception("no way to identify the serial port") - - - # Create the new connector - if not (port_name in ConnectorSerialTty.__instances): - ConnectorSerialTty.__instances[port_name] = None - # try: - new_instance = ConnectorSerialTty(**kwargs) - ConnectorSerialTty.__instances[port_name] = new_instance - # except Exception as e: - # ConnectorSerialTty.__instances.pop(port_name) - # raise Exception('Error during initialization').with_traceback(e.__traceback__) - - # Return the previously created - return ConnectorSerialTty.__instances[port_name] - - - ########################################################################### - ########################################################################### - - def __init__(self, **kwargs): - """Constructor - """ - - port_name = kwargs["port_name"] - if not (port_name in ConnectorSerialTty.__instances): - raise Exception("You need to pass through Get method to create an instance") - else: - self.log = logging.getLogger(port_name) - self.log.info(f"attached to the Serial TTY Connector") - - self.__internal_driver = serial.serial_for_url(port_name, do_not_open=True) - self.__internal_driver.baudrate = 19200 if "baudrate" not in kwargs else kwargs["baudrate"] - self.__internal_driver.bytesize = serial.EIGHTBITS - self.__internal_driver.parity = serial.PARITY_NONE - self.__internal_driver.stopbits = serial.STOPBITS_ONE - self.__internal_driver.rtscts = False - self.__internal_driver.timeout = 10 - self.__internal_driver.write_timeout = 10 - - # Open - self.__internal_driver.open() - - - def read(self): - pass - - def write(self, data): - pass - - - def get_internal_driver(self): - return self.__internal_driver - diff --git a/platform/panduza_platform/connectors/serial_base.py b/platform/panduza_platform/connectors/serial_base.py index d26b3fad..32629aba 100644 --- a/platform/panduza_platform/connectors/serial_base.py +++ b/platform/panduza_platform/connectors/serial_base.py @@ -1,6 +1,6 @@ import abc -class SerialBase(metaclass=abc.ABCMeta): +class ConnectorSerialBase(metaclass=abc.ABCMeta): """Base class for modbus client connectors It defines method to interact with the modbus client diff --git a/platform/panduza_platform/connectors/serial_tty.py b/platform/panduza_platform/connectors/serial_tty.py index b6d33c19..2a4ba292 100644 --- a/platform/panduza_platform/connectors/serial_tty.py +++ b/platform/panduza_platform/connectors/serial_tty.py @@ -4,26 +4,23 @@ import aioserial # import serial_asyncio -from .serial_base import SerialBase +from .serial_base import ConnectorSerialBase from log.driver import driver_logger from .udev_tty import SerialPortFromUsbSetting -class SerialTty(SerialBase): +class ConnectorSerialTty(ConnectorSerialBase): """ """ # Hold instances mutex __MUTEX = asyncio.Lock() - # Hold instances mutex - __MUTEX = asyncio.Lock() - # Contains instances __INSTANCES = {} # Local logs - log = driver_logger("SerialTty") + log = driver_logger("ConnectorSerialTty") ########################################################################### ########################################################################### @@ -46,12 +43,12 @@ async def Get(**kwargs): ID_MODEL_ID """ # Log - SerialTty.log.debug(f"Get connector for {kwargs}") + ConnectorSerialTty.log.debug(f"Get connector for {kwargs}") - async with SerialTty.__MUTEX: + async with ConnectorSerialTty.__MUTEX: # Log - SerialTty.log.debug(f"Lock acquired !") + ConnectorSerialTty.log.debug(f"Lock acquired !") # Get the serial port name @@ -67,22 +64,22 @@ async def Get(**kwargs): raise Exception("no way to identify the serial port") # Create the new connector - if not (serial_port_name in SerialTty.__INSTANCES): - SerialTty.__INSTANCES[serial_port_name] = None + if not (serial_port_name in ConnectorSerialTty.__INSTANCES): + ConnectorSerialTty.__INSTANCES[serial_port_name] = None try: - new_instance = SerialTty(**kwargs) + new_instance = ConnectorSerialTty(**kwargs) await new_instance.connect() - SerialTty.__INSTANCES[serial_port_name] = new_instance - SerialTty.log.info("connector created") + ConnectorSerialTty.__INSTANCES[serial_port_name] = new_instance + ConnectorSerialTty.log.info("connector created") except Exception as e: - SerialTty.__INSTANCES.pop(serial_port_name) + ConnectorSerialTty.__INSTANCES.pop(serial_port_name) raise Exception('Error during initialization').with_traceback(e.__traceback__) else: - SerialTty.log.info("connector already created, use existing instance") + ConnectorSerialTty.log.info("connector already created, use existing instance") # Return the previously created - return SerialTty.__INSTANCES[serial_port_name] + return ConnectorSerialTty.__INSTANCES[serial_port_name] ########################################################################### ########################################################################### @@ -104,7 +101,7 @@ def __init__(self, **kwargs): key = kwargs["serial_port_name"] - if not (key in SerialTty.__INSTANCES): + if not (key in ConnectorSerialTty.__INSTANCES): raise Exception("You need to pass through Get method to create an instance") else: self.log = driver_logger(key) diff --git a/platform/panduza_platform/core/platform_device.py b/platform/panduza_platform/core/platform_device.py index 7f8a65e3..ddbd243d 100644 --- a/platform/panduza_platform/core/platform_device.py +++ b/platform/panduza_platform/core/platform_device.py @@ -1,4 +1,5 @@ import abc +import copy from .platform_errors import InitializationError from .itf_device import InterfacePanduzaDevice @@ -123,6 +124,11 @@ def get_manufacturer(self): # --- + def get_settings(self): + return copy.deepcopy(self.settings) + + # --- + def get_settings_props(self): return self.get_config_field("settings_props", []) diff --git a/platform/panduza_platform/core/platform_device_factory.py b/platform/panduza_platform/core/platform_device_factory.py index bcf0cffe..85d2b7e0 100644 --- a/platform/panduza_platform/core/platform_device_factory.py +++ b/platform/panduza_platform/core/platform_device_factory.py @@ -94,6 +94,9 @@ async def hunt_next(self): d = next(self.__hunt_iter) device_builder = self.__device_templates[d]() + + self.__log.info(f"HUNT FOR >> {device_builder.get_ref()}") + instances = await device_builder.get_hunted_instances() self.__device_store[d]['instances'] = instances diff --git a/platform/panduza_platform/devices/korad/ka3005/dev_ka3005.py b/platform/panduza_platform/devices/korad/ka3005/dev_ka3005.py index 8940ea48..a58b0cbb 100644 --- a/platform/panduza_platform/devices/korad/ka3005/dev_ka3005.py +++ b/platform/panduza_platform/devices/korad/ka3005/dev_ka3005.py @@ -8,7 +8,7 @@ from connectors.udev_tty import HuntUsbDevs -from connectors.serial_tty import SerialTty +from connectors.serial_tty import ConnectorSerialTty class DeviceKoradKA3005P(PlatformDevice): """Power Supply From Korad @@ -37,7 +37,7 @@ async def _PZA_DEV_hunt(self): """ print( HuntUsbDevs('0416', '5011', 'tty') ) - # connector = await SerialTty.Get(serial_port_name='/dev/ttyACM0') + # connector = await ConnectorSerialTty.Get(serial_port_name='/dev/ttyACM0') # status = await connector.write_and_read_until("*IDN?", time_lock_s=0.5) # print(">>> ", status) diff --git a/platform/panduza_platform/devices/korad/ka3005/itf_korad_ka3005p_ammeter.py b/platform/panduza_platform/devices/korad/ka3005/itf_korad_ka3005p_ammeter.py index 796540b6..01b517f0 100644 --- a/platform/panduza_platform/devices/korad/ka3005/itf_korad_ka3005p_ammeter.py +++ b/platform/panduza_platform/devices/korad/ka3005/itf_korad_ka3005p_ammeter.py @@ -1,7 +1,7 @@ from hamcrest import assert_that, has_key, instance_of import asyncio from meta_drivers.ammeter import MetaDriverAmmeter -from connectors.serial_tty import SerialTty +from connectors.serial_tty import ConnectorSerialTty COMMAND_TIME_LOCK=0.1 @@ -31,7 +31,7 @@ async def _PZA_DRV_loop_init(self): # Checks assert_that(settings, has_key("serial_baudrate")) - self.serial_connector = await SerialTty.Get(loop,**settings) + self.serial_connector = await ConnectorSerialTty.Get(loop,**settings) # Call meta class BPC ini await super()._PZA_DRV_loop_init() diff --git a/platform/panduza_platform/devices/korad/ka3005/itf_korad_ka3005p_bpc.py b/platform/panduza_platform/devices/korad/ka3005/itf_korad_ka3005p_bpc.py index b506da16..fb0168e3 100644 --- a/platform/panduza_platform/devices/korad/ka3005/itf_korad_ka3005p_bpc.py +++ b/platform/panduza_platform/devices/korad/ka3005/itf_korad_ka3005p_bpc.py @@ -1,7 +1,7 @@ from hamcrest import assert_that, has_key, instance_of import asyncio from meta_drivers.bpc import MetaDriverBpc -from connectors.serial_tty import SerialTty +from connectors.serial_tty import ConnectorSerialTty VOLTAGE_BOUNDS = { "min": 0, "max": 30 } CURRENT_BOUNDS = { "min": 0, "max": 5 } @@ -36,7 +36,7 @@ async def _PZA_DRV_loop_init(self): # Checks assert_that(settings, has_key("serial_baudrate")) - self.serial_connector = await SerialTty.Get(loop,**settings) + self.serial_connector = await ConnectorSerialTty.Get(loop,**settings) # Call meta class BPC ini await super()._PZA_DRV_loop_init() diff --git a/platform/panduza_platform/devices/korad/ka3005/itf_korad_ka3005p_voltmeter.py b/platform/panduza_platform/devices/korad/ka3005/itf_korad_ka3005p_voltmeter.py index bdb37041..60c3732a 100644 --- a/platform/panduza_platform/devices/korad/ka3005/itf_korad_ka3005p_voltmeter.py +++ b/platform/panduza_platform/devices/korad/ka3005/itf_korad_ka3005p_voltmeter.py @@ -1,7 +1,7 @@ from hamcrest import assert_that, has_key, instance_of import asyncio from meta_drivers.voltmeter import MetaDriverVoltmeter -from connectors.serial_tty import SerialTty +from connectors.serial_tty import ConnectorSerialTty COMMAND_TIME_LOCK=0.1 @@ -31,7 +31,7 @@ async def _PZA_DRV_loop_init(self): # Checks assert_that(settings, has_key("serial_baudrate")) - self.serial_connector = await SerialTty.Get(loop,**settings) + self.serial_connector = await ConnectorSerialTty.Get(loop,**settings) # Call meta class BPC ini await super()._PZA_DRV_loop_init() diff --git a/platform/panduza_platform/devices/tenma/__init__.py b/platform/panduza_platform/devices/tenma/__init__.py index c5f9e316..41dc786f 100644 --- a/platform/panduza_platform/devices/tenma/__init__.py +++ b/platform/panduza_platform/devices/tenma/__init__.py @@ -1,4 +1,4 @@ -from .t722710.t722710 import DeviceTenma722710 +from .t722710.dev_t722710 import DeviceTenma722710 PZA_DEVICES_LIST= [ DeviceTenma722710 diff --git a/platform/panduza_platform/devices/tenma/t722710/__init__.py b/platform/panduza_platform/devices/tenma/t722710/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/platform/panduza_platform/devices/tenma/t722710/dev_t722710.py b/platform/panduza_platform/devices/tenma/t722710/dev_t722710.py new file mode 100644 index 00000000..fe92638f --- /dev/null +++ b/platform/panduza_platform/devices/tenma/t722710/dev_t722710.py @@ -0,0 +1,102 @@ +import asyncio + +from hamcrest import has_key + +from core.platform_device import PlatformDevice + +from connectors.udev_tty import HuntUsbDevs +from connectors.serial_tty import ConnectorSerialTty + +from .drv_tenma_722710_bpc import InterfaceTenma722710Bpc + +USBID_VENDOR="0416" +USBID_MODEL="5011" +TTY_BASE="/dev/ttyACM0" + +class DeviceTenma722710(PlatformDevice): + """Power Supply From Tenma + """ + + def _PZA_DEV_config(self): + """ + """ + return { + "family": "bps", + "model": "72-2710", + "manufacturer": "Tenma", + "settings_props": [ + { + 'name': 'usb_serial_short', + 'type': 'string', + 'description': 'USB serial number of the device', + 'default': '' + }, + { + 'name': 'serial_port_name', + 'type': 'string', + 'description': 'Serial port name, better use the usb_serial_short', + 'default': '' + } + ] + } + + # --- + + async def _PZA_DEV_hunt(self): + """ + """ + bag = [] + + matches = HuntUsbDevs(USBID_VENDOR, USBID_MODEL, 'tty') + for match in matches: + # print('------', match) + devname = match.get('DEVNAME', None) + if devname: + try: + # self.log.info(devname) + connector = await ConnectorSerialTty.Get( + serial_port_name=devname, + serial_baudrate=9600 + ) + IDN = await connector.write_and_read_until("*IDN?", time_lock_s=0.5) + # self.log.info(IDN) + + if IDN.decode().startswith("TENMA 72-2710"): + ma = self._PZA_DEV_config()["manufacturer"] + mo = self._PZA_DEV_config()["model"] + ref = f"{ma}.{mo}" + bag.append({ + "ref": ref, + "settings": { + "usb_serial_short": match.get('ID_SERIAL_SHORT', None) + } + }) + + except asyncio.exceptions.TimeoutError: + print("tiemout") + + return bag + + # --- + + async def _PZA_DEV_mount_interfaces(self): + """ + """ + + settings = self.get_settings() + + if ('usb_serial_short' not in settings) and ('serial_port_name' not in settings): + raise Exception("At least one settings must be set") + + const_settings = { + "usb_vendor": USBID_VENDOR, + "usb_model": USBID_MODEL, + "serial_baudrate": 9600 + } + + settings.update(const_settings) + + self.mount_interface( + InterfaceTenma722710Bpc(name=f":channel_0:_ctrl", settings=settings) + ) + diff --git a/platform/panduza_platform/devices/tenma/t722710/drv_tenma_722710_bpc.py b/platform/panduza_platform/devices/tenma/t722710/drv_tenma_722710_bpc.py index 08ac82f9..6245a8e5 100644 --- a/platform/panduza_platform/devices/tenma/t722710/drv_tenma_722710_bpc.py +++ b/platform/panduza_platform/devices/tenma/t722710/drv_tenma_722710_bpc.py @@ -1,6 +1,6 @@ from hamcrest import assert_that, has_key, instance_of from meta_drivers.bpc import MetaDriverBpc -from connectors.serial_tty import SerialTty +from connectors.serial_tty import ConnectorSerialTty STATE_VALUE_ENUM = { True : 1, False: 0 } VOLTAGE_BOUNDS = { "min": 0, "max": 30 } @@ -16,10 +16,20 @@ def int_to_state_string(v_int): position = val_list.index(v_int) return key_list[position] -class DrvTenma722710Bpc(MetaDriverBpc): +class InterfaceTenma722710Bpc(MetaDriverBpc): """ Driver to manage the Tenma power supply """ + # --- + + def __init__(self, name=None, settings={}) -> None: + """Constructor + """ + self.settings = settings + super().__init__(name=name) + + # --- + # ============================================================================= # FROM MetaDriverBpc @@ -39,21 +49,10 @@ async def _PZA_DRV_loop_init(self): """Driver initialization """ - # Load settings - assert_that(tree, has_key("settings")) - settings = tree["settings"] - assert_that(settings, instance_of(dict)) - - # Checks - assert_that(settings, has_key("usb_vendor")) - assert_that(settings, has_key("usb_model")) - assert_that(settings, has_key("serial_baudrate")) - # Get the Serial Connector - self.serial_connector = await SerialTty.Get(loop,**settings) + self.serial_connector = await ConnectorSerialTty.Get(**self.settings) # - #self.modbus_unit = 1 self.channel = 1 # Call meta class BPC ini @@ -67,10 +66,8 @@ async def _PZA_DRV_loop_init(self): async def _PZA_DRV_BPC_read_enable_value(self): # Send "STATUS?" to get back the output state - await self.serial_connector.beg_cmd() - await self.serial_connector.write(f"STATUS?\n", time_lock_s=COMMAND_TIME_LOCK) - statusBytes = await self.serial_connector.read() - await self.serial_connector.end_cmd() + + statusBytes = await self.serial_connector.write_and_read_until("STATUS?\n", time_lock_s=COMMAND_TIME_LOCK) self.log.debug(f"{statusBytes.strip()}") status = ord(statusBytes.strip()) @@ -93,8 +90,7 @@ async def _PZA_DRV_BPC_write_enable_value(self, v): async def _PZA_DRV_BPC_read_voltage_value(self): # Send "VSET1?" to get the voltage value - await self.serial_connector.write(f"VSET{self.channel}?\n", time_lock_s=COMMAND_TIME_LOCK) - voltage = await self.serial_connector.read() + voltage = await self.serial_connector.write_and_read_until(f"VSET{self.channel}?\n", time_lock_s=COMMAND_TIME_LOCK) return float(voltage) # --- @@ -116,9 +112,7 @@ async def _PZA_DRV_BPC_read_voltage_decimals(self): # CURRENT # async def _PZA_DRV_BPC_read_current_value(self): - # Send "ISET1?" to get the Current value - await self.serial_connector.write(f"ISET{self.channel}?\n", time_lock_s=COMMAND_TIME_LOCK) - current = await self.serial_connector.read() + current = await self.serial_connector.write_and_read_until(f"ISET{self.channel}?\n", time_lock_s=COMMAND_TIME_LOCK) return float(current) # --- diff --git a/platform/panduza_platform/devices/tenma/t722710/t722710.py b/platform/panduza_platform/devices/tenma/t722710/t722710.py deleted file mode 100644 index db41c921..00000000 --- a/platform/panduza_platform/devices/tenma/t722710/t722710.py +++ /dev/null @@ -1,53 +0,0 @@ - -from core.platform_device import PlatformDevice - -USBID_VENDOR="0416" -USBID_MODEL="5011" -TTY_BASE="/dev/ttyACM0" - -class DeviceTenma722710(PlatformDevice): - """Power Supply From Tenma - """ - - def _PZA_DEV_config(self): - """ - """ - return { - "family": "bps", - "model": "722710", - "manufacturer": "Tenma" - } - - def _PZA_DEV_interfaces_generator(self): - """ - """ - interfaces = [] - - fake_mode = self.get_settings().get("fake_mode", False) - - - if fake_mode: - pass - else: - interfaces.append({ - "name": f":channel_{0}:_ctrl", - "driver": "tenma.722710.bpc", - "settings": { - "usb_vendor": USBID_VENDOR, - "usb_model": USBID_MODEL, - "serial_baudrate": 9600 - } - }) - ''' - interfaces.append({ - "name": f"am", - "driver": "tenma.722710.ammeter", - "settings": { - "usb_vendor": USBID_VENDOR, - "usb_model": USBID_MODEL, - "serial_baudrate": 9600 - } - }) - ''' - return interfaces - diff --git a/platform/tests/manual/start_hunt.py b/platform/tests/manual/hunt.py similarity index 95% rename from platform/tests/manual/start_hunt.py rename to platform/tests/manual/hunt.py index 27f25d62..0a2cceb4 100644 --- a/platform/tests/manual/start_hunt.py +++ b/platform/tests/manual/hunt.py @@ -6,7 +6,7 @@ ADDR="localhost" PORT=1883 -Core.EnableLogging() +# Core.EnableLogging() diff --git a/platform/tests/manual/load_config.py b/platform/tests/manual/load_config.py new file mode 100644 index 00000000..1a6bf123 --- /dev/null +++ b/platform/tests/manual/load_config.py @@ -0,0 +1,26 @@ +import time +import numpy as np +from panduza import Client, Core, Platform + +ADDR="localhost" +PORT=1883 + +Core.EnableLogging() + +c = Client(url=ADDR, port=PORT) +c.connect() +platforms = c.scan_all_platform_interfaces() + +platform_topic = next(iter(platforms.keys())) +print(platform_topic) + +plat = Platform(addr=ADDR, port=PORT, topic=platform_topic) + + +plat.dtree.content.set({ + "devices": [ + {'ref': 'Tenma.72-2710', 'settings': {'usb_serial_short': '00321FCC0454'}} + ] +}) + + diff --git a/platform/tests/manual/platform_basics.py b/platform/tests/manual/platform_basics.py index e23e4efc..8eb28563 100644 --- a/platform/tests/manual/platform_basics.py +++ b/platform/tests/manual/platform_basics.py @@ -28,4 +28,3 @@ ] }) -