diff --git a/local/platform-aio-monitor.sh b/local/platform-aio-monitor.sh new file mode 100755 index 00000000..13a3f3a6 --- /dev/null +++ b/local/platform-aio-monitor.sh @@ -0,0 +1,9 @@ + +# =================================================================== +# PARAMETERS +PYTHON_VENV_PATH=/usr/local/bin/panduza/venv + +# =================================================================== + +${PYTHON_VENV_PATH}/bin/python3 -m aiomonitor.cli + diff --git a/platform/panduza_platform/core/mqtt_async_client.py b/platform/panduza_platform/core/mqtt_async_client.py new file mode 100644 index 00000000..413f7ad3 --- /dev/null +++ b/platform/panduza_platform/core/mqtt_async_client.py @@ -0,0 +1,422 @@ +import abc +import sys +import time +import json +import socket +import asyncio +import traceback +import threading +import paho.mqtt.client as mqtt +import logging + +from fnmatch import fnmatch +from log.client import client_logger +from .platform_worker import PlatformWorker + +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= + +class TopicListener: + + def __init__(self, wildcard, topic) -> None: + """Constructor + """ + self.subscribed = False + self.topic = topic + self.wildcard = wildcard + self.callbacks = [] + + def append_callback(self, callback, **kwargs): + """Append a new callback + """ + # Check that callback is not already registered, and register + if callback in self.callbacks: + raise Exception( + f"callback {callback} already registered for topic {self.wildcard}") + + # Append callback + self.callbacks.append(callback) + +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= + +class TopicListeners: + + def __init__(self) -> None: + """Constructor + """ + self.entries = [] + + def register_entry_from_topic(self, topic): + """Get entry associated to this topic + """ + # Compose the wildcard from the topic + wildcard = topic.replace("/+", "/*").replace("/#", "/*") + + # Check that the new wildcard is not already in the store + for tl in self.entries: + if tl.wildcard == wildcard: + return tl + + # Append a new topic listeners + entry = TopicListener(wildcard, topic) + self.entries.append(entry) + + # return + return entry + + def trigger_callbacks(self, topic, payload): + """ + """ + # Check that the new wildcard is not already in the store + for entry in self.entries: + if fnmatch(topic, entry.wildcard): + for cb in entry.callbacks: + cb(topic, payload) + + +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= +# ============================================================================= + +class MqttAsyncClient(PlatformWorker): + """Mqtt Client used by the platform and compatible with PlatformThreads + """ + + # --- + + def __init__(self, addr, port) -> None: + """Constructor + """ + # Build parent + super().__init__() + + # Save address and port + self.addr = addr + self.port = port + + # Create the logger + self.log = client_logger(str(addr) + ":" + str(port)) + self.worker_name = f"CLIENT>{str(addr)}:{str(port)}" + + # Mqtt connection + self.mqtt_client = None + + # Initialize state machine + self.__state = "init" + self.__state_prev = None + + # States + self.__states = { + 'init': self.__state_init, + 'connecting': self.__state_connecting, + 'running': self.__state_running, + 'error': self.__state_error, + 'disconnecting': self.__state_disconnecting + } + + # Topic listeners will store callbacks that must be triggered when + # a message for a given topic arrive. + self.__listeners = TopicListeners() + + # ============================================================================= + # PUBLIC FUNCTIONS + + # --- + + def subscribe(self, topic: str, callback, **kwargs): + """Registers a listener + """ + # Debug log + self.log.debug(f"Register listener for topic '{topic}'") + + # Create set if not existing for topics + entry = self.__listeners.register_entry_from_topic(topic) + + # Append callback to the listener + entry.append_callback(callback, **kwargs) + + # --- + + async def publish(self, topic, payload: bytes, qos=0, retain=False): + """Helper to publish raw messages + """ + # Debug + self.log.debug(f"MSG_OUT %{topic}% {payload} QOS={qos}") + + # Publish the message and wait for it to be complete + request = self.mqtt_client.publish(topic, payload, qos=qos, retain=retain) + + # Wait for publish but async way + while(not request.is_published): + await asyncio.sleep(0.01) + + # Debug + # self.log.debug(f"MSG_OUT OK") + + # --- + + async def publish_json(self, topic, req: dict, qos=0, retain=False): + """Helper to publish json messages + """ + await self.publish( + topic=topic, + payload=json.dumps(req).encode("utf-8"), + qos=qos, + retain=retain + ) + + # ============================================================================= + # WORKER FUNCTIONS + + def stop(self): + self.mqtt_client.disconnect() + super().stop() + + # --- + + def PZA_WORKER_name(self): + """From Worker + """ + return self.worker_name + + # --- + + def PZA_WORKER_log(self): + """From Worker + """ + return self.log + + # --- + + def PZA_WORKER_status(self): + """From Worker + """ + status = {} + status["name"] = self.PZA_WORKER_name() + status["final_state"] = f'{self.__state}' + return status + + # --- + + async def PZA_WORKER_task(self): + """ + """ + # Log state transition + if self.__state != self.__state_prev: + + # Managed message + self._state_started_time = time.time() + self.log.debug(f"STATE CHANGE ::: {self.__state_prev} => {self.__state}") + self.__state_prev = self.__state + + # Execute the correct callback + if not (self.__state in self.__states): + # error critique ! + pass + await self.__states[self.__state]() + + # ============================================================================= + # STATES FUNCTIONS + + async def __state_init(self): + """Initialization state + """ + + # Start connection + self.mqtt_client = mqtt.Client() + # self.mqtt_client.socket().setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2048) + + # self.mqtt_client.keep_alive = 45 + + + self.mqtt_client.on_message = self.__on_message + + self.mqtt_client.on_connect = self.__on_connect + + # self.mqtt_client.on_disconnect = self.__on_disconnect + # self.mqtt_client.on_subscribe = self.__on_subscribe + # self.mqtt_client.on_unsubscribe = self.__on_unsubscribe + # self.mqtt_client.on_publish = self.__on_publish + # self.mqtt_client.on_log = self.__on_log + + self.mqtt_client.on_socket_open = self.__on_socket_open + self.mqtt_client.on_socket_close = self.__on_socket_close + self.mqtt_client.on_socket_register_write = self.__on_socket_register_write + self.mqtt_client.on_socket_unregister_write = self.__on_socket_unregister_write + self.mqtt_client.connect(self.addr, self.port, keepalive=60) + + # Go connecting state + self.__state = 'connecting' + self.log.info("Connecting...") + + # --- + + async def __state_connecting(self): + """Running state + """ + await asyncio.sleep(0.5) + + # --- + + async def __state_running(self): + """Running state + """ + # Make sure subscribes are done after the connection + for entry in self.__listeners.entries: + if not entry.subscribed: + self.log.debug(f"subscribe topic '{entry.topic}'") + self.mqtt_client.subscribe(entry.topic) + entry.subscribed = True + + # --- + + async def __state_error(self): + """ + """ + await asyncio.sleep(1) + + # --- + + async def __state_disconnecting(self): + """ + """ + await asyncio.sleep(1) + + # ============================================================================= + # CLIENT CALLBACKS + + # --- + + def __on_connect(self, client, userdata, flags, rc): + """On connect callback + """ + if self.__state == 'connecting': + self.__state = 'running' + self.log.info(f"Connected ! ({str(rc)})") + else: + self.log.warning(f"Wierd connection status ? ({str(rc)})") + + # --- + + def __on_disconnect(self, client, userdata, flags, rc): + self.log.warning(f"Disconnected !") + + # --- + + def __on_subscribe(self, client, userdata, mid, granted_qos): + self.log.warning(f"__on_subscribe") + + # --- + + def __on_unsubscribe(self, userdata, mid): + self.log.warning(f"__on_unsubscribe") + + # --- + + def __on_publish(self, client, userdata, result): + self.log.warning(f"__on_publish({result})") + + # --- + + def __on_log(self, client, userdata, level, buff): + self.log.warning(f"__on_log({level}, {buff})") + + # --- + + def __on_message(self, client, userdata, msg): + """Callback to manage incomming mqtt messages + + Args: + - client: from paho.mqtt.client + - userdata: from paho.mqtt.client + - msg: from paho.mqtt.client + """ + # Get the topix string + topic_string = str(msg.topic) + + # Debug purpose + self.log.info(f"MSG_IN < %{topic_string}% {msg.payload}") + + self.__listeners.trigger_callbacks(topic_string, msg.payload) + + # --- + + async def misc_loop(self): + self.log.debug("misc_loop started") + while self.client.loop_misc() == mqtt.MQTT_ERR_SUCCESS: + try: + await asyncio.sleep(1) + except asyncio.CancelledError: + break + self.log.debug("misc_loop finished") + + # --- + + def __on_socket_open(self, client, userdata, sock): + self.log.debug("Socket opened") + + def cb(): + # Debug + # self.log.debug("Socket is readable, calling loop_read") + client.loop_read() + + asyncio.get_event_loop().add_reader(sock, cb) + self.misc = asyncio.get_event_loop().create_task(self.misc_loop()) + + # --- + + def __on_socket_close(self, client, userdata, sock): + asyncio.get_event_loop().remove_reader(sock) + self.misc.cancel() + + self.log.warning("Socket closed") + + # self.__state = "error" + self.worker_panic() + + + # --- + + def __on_socket_register_write(self, client, userdata, sock): + # Debug + # self.log.debug("Watching socket for writability.") + + def cb(): + # Debug + # self.log.debug("Socket is writable, calling loop_write") + client.loop_write() + + asyncio.get_event_loop().add_writer(sock, cb) + + # --- + + def __on_socket_unregister_write(self, client, userdata, sock): + # Debug + # self.log.debug("Stop watching socket for writability.") + asyncio.get_event_loop().remove_writer(sock) + + # --- diff --git a/platform/panduza_platform/core/platform.py b/platform/panduza_platform/core/platform.py index 177e9e2e..92f4e55c 100644 --- a/platform/panduza_platform/core/platform.py +++ b/platform/panduza_platform/core/platform.py @@ -19,11 +19,13 @@ from .conf import PLATFORM_VERSION from log.platform import platform_logger -from .platform_thread import PlatformThread -from .platform_client import PlatformClient + +# from .platform_client import PlatformClient from .platform_errors import InitializationError -from .platform_driver_factory import PlatformDriverFactory +from .mqtt_async_client import MqttAsyncClient + +# from .platform_driver_factory import PlatformDriverFactory from .platform_device_factory import PlatformDeviceFactory @@ -52,7 +54,6 @@ def __init__(self, run_dir="/etc"): self.log.info("==========================================") # Create Factories - self.driver_factory = PlatformDriverFactory(self) self.device_factory = PlatformDeviceFactory(self) # Threads @@ -78,19 +79,28 @@ def __init__(self, run_dir="/etc"): # If true, it means that the platform event loop can continue to run and work self.alive = True + # Event loop object holder + self.event_loop = None + # To enable or disable event loop monitoring # Should be false for release self.event_loop_debug = True + # self.workers = [] + # self.workers_mutex = threading.Lock() + + + # Mqtt Clients + self.clients = {} + + # --- def run(self): """Starting point of the platform """ - # First go into factories initialization try: - self.driver_factory.discover() self.device_factory.discover() except InitializationError as e: self.log.critical(f"Error during platform initialization: {e}") @@ -104,23 +114,55 @@ def run(self): # --- - def mount_device(self, device_cfg): + async def load_worker(self, worker): + """Load worker into the event loop + """ + await self.event_loop.create_task( worker.task(), name=worker.name() ) + + # --- + + # unload_worker + + # --- + + async def mount_client(self, name, host_addr, host_port): + """Mount a mqtt client + """ + mqtt_client = MqttAsyncClient(host_addr, host_port) + self.clients[name] = mqtt_client + await self.load_worker(mqtt_client) + + # --- + + def unmount_client(self): pass - # device.attach_pclient(client) + # --- - # _PZA_DEV_mount_interfaces - # self.threads[0].attach_worker(interface) + async def mount_device(self, client_name, group_name, device_cfg): + """Mount a device + """ + # Debug log + self.log.info(f"Mount device {device_cfg}") + + # Produce the device instance + device_instance = self.device_factory.produce_device(self.clients[client_name], group_name, device_cfg) + # Mount interfaces + await device_instance.mount_interfaces() # --- def unmount_device(self): pass + # --- + + + + - # --- @@ -240,14 +282,27 @@ def get_interface_instance(self, bench, device, name): return None + # ============================================================================= # PRIVATE FUNCTIONS # --- async def __idle_task(self): + """Idle Task of the platform + """ + # Start idle task + self.log.info(f"Idle task start") + # Connect to primary broker + await self.mount_client("primary", "localhost", 1883) + # Mount the device interfaces of the server + await self.mount_device("primary", "server", { + "name": socket.gethostname(), + "ref": "Panduza.Server", + } + ) # Wait for ever while(self.alive): @@ -262,6 +317,9 @@ def __oper_mode(self): """ try: + # Manage the status file (file to indicate the admin interface logs of the crash) + if os.path.isfile(STATUS_FILE_PATH): + os.remove(STATUS_FILE_PATH) # Start the loop and monitor activity # If the debug flag is enabled, start monitored event loop @@ -278,8 +336,6 @@ def __oper_mode(self): # try: - # if os.path.isfile(STATUS_FILE_PATH): - # os.remove(STATUS_FILE_PATH) # self.__load_tree() @@ -317,7 +373,7 @@ def __oper_mode(self): # for interface in self.interfaces: - # interface.attach_pclient(client) + # interface.attach_client(client) # # Prepare interface internal data # for interface in self.interfaces: diff --git a/platform/panduza_platform/core/platform_device.py b/platform/panduza_platform/core/platform_device.py index 7534047a..de3daad3 100644 --- a/platform/panduza_platform/core/platform_device.py +++ b/platform/panduza_platform/core/platform_device.py @@ -1,11 +1,13 @@ import abc from .platform_errors import InitializationError +from log.device import device_logger + class PlatformDevice: """Represent a Device """ - def __init__(self, platform=None, name=None, settings = {}) -> None: + def __init__(self, platform=None, client=None, group_name=None, name=None, settings = {}) -> None: """Constructor It can be instanciated with empty settings to provide only the _PZA_DEV_config @@ -13,9 +15,15 @@ def __init__(self, platform=None, name=None, settings = {}) -> None: # Custom name of the device self.__name = name + self.log = device_logger("device_" + str(self.__name)) + # Settings json provided by the user with the tree.json self.__platform = platform + + self.__client = client + self.__group_name = group_name + # Settings json provided by the user with the tree.json self.__settings = settings @@ -31,6 +39,21 @@ def initialize(self): # --- + async def mount_interfaces(self): + """Request to mount all the interfaces of the device + """ + await self._PZA_DEV_mount_interfaces() + + # --- + + async def mount_interface(self, itf): + """ + """ + itf.attach_client(self.__client) + await self.__platform.load_worker(itf) + + # --- + def register_interface(self, interface): self.__interfaces.append(interface) @@ -114,7 +137,7 @@ def _PZA_DEV_config(self): # --- @abc.abstractmethod - def _PZA_DEV_mount_interfaces(self): + async def _PZA_DEV_mount_interfaces(self): """ """ pass diff --git a/platform/panduza_platform/core/platform_device_factory.py b/platform/panduza_platform/core/platform_device_factory.py index 24da4f6a..f933d7d5 100644 --- a/platform/panduza_platform/core/platform_device_factory.py +++ b/platform/panduza_platform/core/platform_device_factory.py @@ -19,7 +19,7 @@ def __init__(self, parent_platform): # --- - def produce_device(self, config): + def produce_device(self, client, group_name, config): """Try to produce the device corresponding the ref """ # Get ref and control it exists in the config provided by the user @@ -36,7 +36,7 @@ def produce_device(self, config): # Produce the device try: - producted_device = self.__device_templates[ref](platform=self.__platform, name=name, settings=config.get("settings", {})) + producted_device = self.__device_templates[ref](platform=self.__platform, client=client, group_name=group_name, name=name, settings=config.get("settings", {})) producted_device.initialize() return producted_device except Exception as e: diff --git a/platform/panduza_platform/core/platform_driver.py b/platform/panduza_platform/core/platform_driver.py index da5c7c77..d32d3f97 100644 --- a/platform/panduza_platform/core/platform_driver.py +++ b/platform/panduza_platform/core/platform_driver.py @@ -67,7 +67,7 @@ def set_tree(self, tree): # --- - def attach_pclient(self, pclient): + def attach_client(self, pclient): self._pclient = pclient # --- @@ -203,18 +203,18 @@ def PZA_WORKER_status(self): # --- - async def PZA_WORKER_task(self, loop): + async def PZA_WORKER_task(self): """ """ try: # Process Scan Events - await self.__process_scan_events(loop) + await self.__process_scan_events() if not self._events_cmds.empty(): event = self._events_cmds.get() - await self._PZA_DRV_cmds_set(loop, event["payload"]) + await self._PZA_DRV_cmds_set(event["payload"]) # Log state transition if self.__drv_state != self.__drv_state_prev: @@ -239,7 +239,7 @@ async def PZA_WORKER_task(self, loop): if not (self.__drv_state in self.__states): # error critique ! pass - await self.__states[self.__drv_state](loop) + await self.__states[self.__drv_state]() except Exception as e: self._PZA_DRV_error_detected(str(e) + " " + traceback.format_exc()) diff --git a/platform/panduza_platform/core/platform_worker.py b/platform/panduza_platform/core/platform_worker.py index a3c7576a..cc94b7c8 100644 --- a/platform/panduza_platform/core/platform_worker.py +++ b/platform/panduza_platform/core/platform_worker.py @@ -7,27 +7,30 @@ class PlatformWorker(metaclass=abc.ABCMeta): def __init__(self) -> None: self.__alive = True - self.__thread = None self.reset_work_time() - def set_thread(self, thread): - self.__thread = thread - def reset_work_time(self): self.work_time = 0 - def worker_panic(self): - self.__thread.handle_worker_panic(self.PZA_WORKER_name()) + # def worker_panic(self): + # self.__thread.handle_worker_panic(self.PZA_WORKER_name()) + + # --- + + def name(self): + return self.PZA_WORKER_name() + + # --- def stop(self): self.__alive = False - async def task(self, loop): + async def task(self): """ """ while(self.__alive): await asyncio.sleep(0.1) - await self.PZA_WORKER_task(loop) + await self.PZA_WORKER_task() self.PZA_WORKER_log().info("stopped") @@ -62,7 +65,7 @@ def PZA_WORKER_status(self): # --- @abc.abstractmethod - async def PZA_WORKER_task(self, loop): + async def PZA_WORKER_task(self): """ """ pass diff --git a/platform/panduza_platform/devices/panduza/__init__.py b/platform/panduza_platform/devices/panduza/__init__.py index 10eedeff..fa3a698d 100644 --- a/platform/panduza_platform/devices/panduza/__init__.py +++ b/platform/panduza_platform/devices/panduza/__init__.py @@ -1,12 +1,12 @@ from .fake_dio_controller import DevicePanduzaFakeDioController from .fake_bps.fake_bps import DevicePanduzaFakeBps from .fake_relay_controller import DevicePanduzaFakeRelayController -from .machine import DevicePanduzaMachine +from .server.server import DevicePanduzaServer PZA_DEVICES_LIST= [ DevicePanduzaFakeDioController, DevicePanduzaFakeBps, DevicePanduzaFakeRelayController, - DevicePanduzaMachine + DevicePanduzaServer ] diff --git a/platform/panduza_platform/devices/panduza/machine.py b/platform/panduza_platform/devices/panduza/machine.py deleted file mode 100644 index babb4a02..00000000 --- a/platform/panduza_platform/devices/panduza/machine.py +++ /dev/null @@ -1,34 +0,0 @@ -from core.platform_device import PlatformDevice - -class DevicePanduzaMachine(PlatformDevice): - """Represent the machine on which the platform is running - """ - - def _PZA_DEV_config(self): - """ - """ - return { - "family": "TBD", - "model": "Machine", - "manufacturer": "Panduza" - } - - def _PZA_DEV_interfaces_generator(self): - """ - """ - - # number_of_channel = int( self.get_settings().get("number_of_channel", 1) ) - - interfaces = [] - # for chan in range(0, number_of_channel): - # interfaces.append( - # { - # "name": f"channel_{chan}", - # "driver": "panduza.fake.relay" - # } - # ) - - return interfaces - - - diff --git a/platform/panduza_platform/devices/panduza/server/__init__.py b/platform/panduza_platform/devices/panduza/server/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/platform/panduza_platform/drivers/platform/drv_platform.py b/platform/panduza_platform/devices/panduza/server/itf_platform.py similarity index 91% rename from platform/panduza_platform/drivers/platform/drv_platform.py rename to platform/panduza_platform/devices/panduza/server/itf_platform.py index ad8d2354..795977af 100644 --- a/platform/panduza_platform/drivers/platform/drv_platform.py +++ b/platform/panduza_platform/devices/panduza/server/itf_platform.py @@ -1,7 +1,7 @@ -import time + from core.platform_driver import PlatformDriver -class DriverPlatform(PlatformDriver): +class InterfacePanduzaPlatform(PlatformDriver): """ """ @@ -23,7 +23,7 @@ def _PZA_DRV_config(self): ########################################################################### ########################################################################### - async def _PZA_DRV_loop_init(self, loop, tree): + async def _PZA_DRV_loop_init(self): """From PlatformDriver """ # Update the number of managed interface diff --git a/platform/panduza_platform/devices/panduza/server/server.py b/platform/panduza_platform/devices/panduza/server/server.py new file mode 100644 index 00000000..87d8c8c3 --- /dev/null +++ b/platform/panduza_platform/devices/panduza/server/server.py @@ -0,0 +1,36 @@ +from core.platform_device import PlatformDevice + +from .itf_platform import InterfacePanduzaPlatform + +class DevicePanduzaServer(PlatformDevice): + """Represent the machine on which the platform is running + """ + + # --- + + def _PZA_DEV_config(self): + """ + """ + return { + "family": "server", + "model": "Server", + "manufacturer": "Panduza" + } + + # --- + + async def _PZA_DEV_mount_interfaces(self): + """ + """ + + self.log.info("mount !!!!!!!!!!!!!!!!!!!") + + itf_platform = InterfacePanduzaPlatform() + await self.mount_interface(itf_platform) + + # itf_platform.attach_client() + # load_worker() + + + + diff --git a/platform/panduza_platform/drivers/__init__.py b/platform/panduza_platform/drivers/__init__.py index 9f9e4b35..e69de29b 100644 --- a/platform/panduza_platform/drivers/__init__.py +++ b/platform/panduza_platform/drivers/__init__.py @@ -1,15 +0,0 @@ - -from .ammeter import PZA_DRIVERS_LIST as AMMETERS_DRIVERS -from .dio import PZA_DRIVERS_LIST as DIO_DRIVERS -from .platform import PZA_DRIVERS_LIST as PLATFORM_DRIVERS -from .bpc import PZA_DRIVERS_LIST as BPC_DRIVERS -from .relay import PZA_DRIVERS_LIST as RELAY_DRIVERS -from .voltmeter import PZA_DRIVERS_LIST as VOLTMETERS_DRIVERS - -PZA_DRIVERS_LIST= [] \ - + AMMETERS_DRIVERS \ - + DIO_DRIVERS \ - + PLATFORM_DRIVERS \ - + BPC_DRIVERS \ - + RELAY_DRIVERS \ - + VOLTMETERS_DRIVERS diff --git a/platform/panduza_platform/drivers/platform/__init__.py b/platform/panduza_platform/drivers/platform/__init__.py index 9b6bb3d6..e97128ed 100644 --- a/platform/panduza_platform/drivers/platform/__init__.py +++ b/platform/panduza_platform/drivers/platform/__init__.py @@ -1,5 +1,5 @@ -from .drv_platform import DriverPlatform +from ...devices.panduza.server.itf_platform import DriverPlatform from .drv_device import DriverDevice PZA_DRIVERS_LIST= [DriverPlatform, DriverDevice] diff --git a/platform/panduza_platform/log/thread.py b/platform/panduza_platform/log/device.py similarity index 98% rename from platform/panduza_platform/log/thread.py rename to platform/panduza_platform/log/device.py index b81dfc34..7c6793e6 100644 --- a/platform/panduza_platform/log/thread.py +++ b/platform/panduza_platform/log/device.py @@ -77,7 +77,7 @@ def formatMessage(self, record): # ============================================================================= -def thread_logger(driver_name): +def device_logger(driver_name): """Logger for platform drivers """