From dcf2e9a33fde26b6c9d90a1b5f4c9d58f386f610 Mon Sep 17 00:00:00 2001 From: Philipp Grimm Date: Thu, 23 May 2024 13:42:27 +0200 Subject: [PATCH] added support for mgw lan --- custom_components/eltako/esp3_tcp_com.py | 134 +++++++++++++++++++++++ custom_components/eltako/gateway.py | 2 +- 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 custom_components/eltako/esp3_tcp_com.py diff --git a/custom_components/eltako/esp3_tcp_com.py b/custom_components/eltako/esp3_tcp_com.py new file mode 100644 index 00000000..3159f7fe --- /dev/null +++ b/custom_components/eltako/esp3_tcp_com.py @@ -0,0 +1,134 @@ +import socket +import time +import logging + +# from zeroconf import ServiceBrowser, Zeroconf, ServiceStateChange + +from esp2_gateway_adapter.esp3_serial_com import ESP3SerialCommunicator + + +# def detect_lan_gateways() -> list[str]: +# result = [] + +# zeroconf = Zeroconf() + +# def on_service_state_change(zeroconf, service_type, name, state_change): +# if state_change is ServiceStateChange.Added: +# zeroconf.get_service_info(service_type, name) + +# name = '_bsc-sc-socket._tcp.local.' +# ServiceBrowser(zeroconf, name, handlers=[on_service_state_change]) + +# time.sleep(2) + +# alias = zeroconf.cache.entries_with_name('_bsc-sc-socket._tcp.local.')[0].alias +# service_name = alias.split('.')[0] + '.local.' + +# for e in zeroconf.cache.entries_with_name(service_name): +# if 'record[a' in str(e): +# ip_adr = str(e).split('=')[1].split(',')[1] +# if ip_adr not in result: +# result.append(ip_adr) + +# zeroconf.close() + +# return result + + +class TCP2SerialCommunicator(ESP3SerialCommunicator): + + def __init__(self, + host, + port, + log=None, + callback=None, + reconnection_timeout:float=10, + esp2_translation_enabled:bool=False, + auto_reconnect=True): + + self.__recon_time = reconnection_timeout + self.esp2_translation_enabled = esp2_translation_enabled + self._outside_callback = callback + self._auto_reconnect = auto_reconnect + + super(TCP2SerialCommunicator, self).__init__(None, log, callback, None, reconnection_timeout, esp2_translation_enabled, auto_reconnect) + + self._host = host + self._port = port + + self.log = log or logging.getLogger('eltakobus.tcp2serial') + + self.__ser = None + + + def _test_connection(self): + sent = self.__ser.send(b'\xff\x00\xff' * 5) + if sent == 0: + raise Exception("Data was not sent.") + try: + self.__ser.recv(1024) + except socket.timeout as e: + pass + + def run(self): + timeout_count = 0 + self.logger.info('TCP2SerialCommunicator started') + self._fire_status_change_handler(connected=False) + while not self._stop_flag.is_set(): + try: + # Initialize serial port + if self.__ser is None: + self.__ser = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.__ser.connect((self._host, self._port)) + self.__ser.settimeout(1) + + # Test connection + self._test_connection() + + self.log.info("Established TCP connection to %s:%s", self._host, self._port) + + self.is_serial_connected.set() + self._fire_status_change_handler(connected=True) + + # If there's messages in transmit queue + # send them + while True: + packet = self._get_from_send_queue() + if not packet: + break + self.log.debug("send msg: %s", packet) + self.__ser.sendall( bytearray(packet.build()) ) + + # Read chars from serial port as hex numbers + try: + data = self.__ser.recv(1024) + # print(hex(int.from_bytes(data, "big"))) + if data != b'IM2M': + self._buffer = data + self.parse() + timeout_count = 0 + timeout_count += 1 + except socket.timeout as e: + pass + if timeout_count > self.__recon_time: + timeout_count = 0 + self._test_connection() + time.sleep(0) + + except Exception as e: + self._fire_status_change_handler(connected=False) + self.is_serial_connected.clear() + self.log.error(e) + self.__ser = None + if self._auto_reconnect: + self.log.info("TCP2Serial communication crashed. Wait %s seconds for reconnection.", self.__recon_time) + time.sleep(self.__recon_time) + else: + self._stop_flag.set() + + if self.__ser is not None: + self.__ser.close() + self.__ser = None + self.is_serial_connected.clear() + self._fire_status_change_handler(connected=False) + self.logger.info('TCP2SerialCommunicator stopped') diff --git a/custom_components/eltako/gateway.py b/custom_components/eltako/gateway.py index 09454f6c..85d8b31f 100644 --- a/custom_components/eltako/gateway.py +++ b/custom_components/eltako/gateway.py @@ -132,7 +132,7 @@ def _init_bus(self): self._bus = TCP2SerialCommunicator(host=self.serial_path, port=5100, callback=self._callback_receive_message_from_serial_bus, esp2_translation_enabled=True) else: # lazy import to avoid preloading library - from esp2_gateway_adapter.esp3_serial_com import ESP3SerialCommunicator + from .esp3_tcp_com import ESP3SerialCommunicator self._bus = ESP3SerialCommunicator(filename=self.serial_path, callback=self._callback_receive_message_from_serial_bus, esp2_translation_enabled=True) self._bus.set_status_changed_handler(self._fire_connection_state_changed_event)