UDP-socket communication based integration – how-to

First of all – I’m not even a rookie Python developer. But I wrote an integration that communicates HA with a gateway via UDP protocol. Yet my UDP connector that I wrote is quite… unstable – it lacks reconnections and generally error handling.

Can you point me anywhere where I cant find a good example of how to run UDP socket connection that can communicate two ways?

This is what I wrote, can you point me what can I do better? How can I assure reconnections after gateway restarted or my WiFi connection was lost?

This is a snippet of what I’ve made (I’ve skipped imports):

def setup(hass, config):
    gateway = XiaomiGw(hass, config[DOMAIN][CONF_HOST], config[DOMAIN][CONF_PORT])
    gateway.create_socket()
    gateway.listen_socket()

class XiaomiGw:
    def __init__(self, hass, host, port):
        self.hass = hass
        self._host = host
        self._port = port
        self._socket = None
        self._thread = None
        self._listening = False
        self._send_queue = Queue(maxsize=25)

    def create_socket(self):
        _LOGGER.info("Creating socket...")
        self._socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
        self._socket.settimeout(0.1)

    def listen_socket(self):
        self._listening = True
        self._thread = Thread(target=self._run_socket_thread, args=())
        self._thread.daemon = True
        self._thread.start()

    def send_to_hub(self, data, callback=None):
        if callback is not None:
            _LOGGER.info("Adding callback for call ID: " + data.id)
            self._result_callbacks[data.id] = callback
        self._send_queue.put(data)

    def _run_socket_thread(self):
        _LOGGER.info("Starting listener thread...")
        while self._listening:
            if self._socket is None:
                continue
            while not self._send_queue.empty():
                data = self._send_queue.get();
                _LOGGER.debug("Sending data:")
                _LOGGER.debug(data)
                self._socket.sendto(data, (self._host, self._port))

            try:
                data = self._socket.recvfrom(1480)[0]
                _LOGGER.debug("Received data:")
                _LOGGER.debug(data)

                # Gateway available = true
                self._set_available()

                # Parse all messages in response
                self._parse_received_data(data)

            except socket.timeout:
                pass

Full code can be found here: https://github.com/cadavre/miio_gateway/blob/6e439f490785caf628d521155a0878e5dd28e109/init.py

As you can see it revolves around deamonized Thread with while loop that uses Socket to send data (in Queue) and then try to receive data from socket.

Additionally in background theres a thread that tries to send pings and receive any data that updates state of the component.

I quite feel that using threads with while loops and queues is not the right way to do it. Even if it is – how to “bulletproof” it more?

Thank for any tips or pointing out an examples inside HASS.

@Seweryn_Zeman

Hey! Did you ever get this going? I have a solar inverter that uses UDP. It is very basic. You send it a specific datagram and it returns the current KWhr generated … and some other stuff that is not particularly useful.

I am not even up to the level of experience with HA to even write a simple script, though I have added a Tasmota device, a Z-Wave device and four different sensors controlled by an Arduino through the MySensors MQTT gateway. Bottom line, I won’t be of much help here other than a tester.

OSD