11""" Aqara Gateway """
2+ import asyncio
23# pylint: disable=broad-except
34import logging
45import socket
56import time
67import json
78import re
8- from threading import Thread
99from typing import Optional
1010from random import randint
1111from paho .mqtt .client import Client , MQTTMessage
1212
13- from homeassistant .core import Event
14- from homeassistant .const import CONF_NAME , CONF_PASSWORD
13+ from homeassistant .config_entries import ConfigEntry
14+ from homeassistant .core import Event , HomeAssistant
15+ from homeassistant .const import CONF_NAME , CONF_PASSWORD , MAJOR_VERSION , MINOR_VERSION
1516from homeassistant .components .light import ATTR_HS_COLOR , ATTR_RGB_COLOR , ATTR_BRIGHTNESS
1617
1718from .shell import (
3435MD5_MOSQUITTO_G2HPRO_ARMV7L = '9cd591ec76f85c4d96b744eb99943eb3'
3536MD5_MOSQUITTO_MIPSEL = 'e0ce4757cfcccb079d89134381fd11b0'
3637
37- class Gateway ( Thread ) :
38+ class Gateway :
3839 # pylint: disable=too-many-instance-attributes, unused-argument
3940 """ Aqara Gateway """
4041
41- def __init__ (self , hass , host : str , config : dict , ** options ):
42+ main_task : asyncio .Task | None = None # for HA < 2023.3
43+
44+ def __init__ (self , hass : HomeAssistant , host : str , config : dict , ** options ):
4245 """Initialize the Xiaomi/Aqara device."""
43- super ().__init__ (daemon = True )
4446 self .hass = hass
4547 self .host = host
4648 self .options = options
@@ -94,9 +96,12 @@ def stop(self):
9496 """ stop function """
9597 self .enabled = False
9698
97- async def async_connect (self ) -> str :
99+ if self .main_task : # HA < 2023.3
100+ self .main_task .cancel ()
101+
102+ async def async_connect (self ):
98103 """Connect to the host. Does not process messages yet."""
99- result : int = None
104+ result : int | None = None
100105 try :
101106 result = await self .hass .async_add_executor_job (
102107 self ._mqttc .connect ,
@@ -125,7 +130,13 @@ def stop():
125130
126131 await self .hass .async_add_executor_job (stop )
127132
128- def run (self ):
133+ def start (self , hass : HomeAssistant , config_entry : ConfigEntry ):
134+ if (MAJOR_VERSION , MINOR_VERSION ) >= (2023 , 3 ):
135+ config_entry .async_create_background_task (hass , self .run (), f"{ DOMAIN } gateway.run" )
136+ else :
137+ self .main_task = hass .loop .create_task (self .run ())
138+
139+ async def run (self ):
129140 """ Main thread loop. """
130141 telnetshell = False
131142 if "telnet" not in self .hass .data [DOMAIN ]:
@@ -136,14 +147,14 @@ def run(self):
136147 if not self ._check_port (23 ):
137148 if self .host in self .hass .data [DOMAIN ]["telnet" ]:
138149 self .hass .data [DOMAIN ]["telnet" ].remove (self .host )
139- time .sleep (30 )
150+ await asyncio .sleep (30 )
140151 continue
141152
142153 telnetshell = True
143154 devices = self ._prepare_gateway (get_devices = True )
144155 if isinstance (devices , list ):
145156 self ._gw_topic = "gw/{}/" .format (devices [0 ]['mac' ][2 :].upper ())
146- self .setup_devices (devices )
157+ await self .setup_devices (devices )
147158 break
148159
149160 if telnetshell :
@@ -154,7 +165,7 @@ def run(self):
154165 if not self ._mqtt_connect () or not self ._prepare_gateway ():
155166 if self .host in self .hass .data [DOMAIN ]["mqtt" ]:
156167 self .hass .data [DOMAIN ]["mqtt" ].remove (self .host )
157- time .sleep (60 )
168+ await asyncio .sleep (60 )
158169 continue
159170
160171 self ._mqttc .loop_start ()
@@ -319,7 +330,7 @@ def _get_devices(self, shell):
319330
320331 return devices
321332
322- def setup_devices (self , devices : list ):
333+ async def setup_devices (self , devices : list ):
323334 """Add devices to hass."""
324335 for device in devices :
325336 timeout = 300
@@ -349,7 +360,7 @@ def setup_devices(self, devices: list):
349360
350361 # wait domain init
351362 while domain not in self .setups and timeout > 0 :
352- time .sleep (1 )
363+ await asyncio .sleep (1 )
353364 timeout = timeout - 1
354365 attr = param [2 ]
355366 if (attr in ('illuminance' , 'light' ) and
@@ -360,7 +371,7 @@ def setup_devices(self, devices: list):
360371
361372 if self .options .get ('stats' ):
362373 while 'sensor' not in self .setups :
363- time .sleep (1 )
374+ await asyncio .sleep (1 )
364375 self .setups ['sensor' ](self , device , device ['type' ])
365376
366377 def add_stats (self , ieee : str , handler ):
@@ -467,7 +478,7 @@ def on_disconnect(self, client, userdata, ret):
467478 self .hass .data [DOMAIN ]["mqtt" ].remove (self .host )
468479 self .available = False
469480# self.process_gateway_stats()
470- self .run ()
481+ self .hass . create_task ( self . run () )
471482
472483 def on_message (self , client : Client , userdata , msg : MQTTMessage ):
473484 # pylint: disable=unused-argument
@@ -575,7 +586,7 @@ def _process_devices_info(self, prop, value):
575586 'model_ver' : dev ['model_ver' ],
576587 'status' : dev ['status' ]
577588 }
578- self .setup_devices ([device ])
589+ self .hass . create_task ( self . setup_devices ([device ]) )
579590 break
580591
581592 def _process_message (self , data : dict ):
@@ -739,7 +750,7 @@ def _process_message(self, data: dict):
739750 device ['mac' ] = '0x' + device ['mac' ]
740751 device ['type' ] = 'zigbee'
741752 device ['init' ] = payload
742- self .setup_devices ([device ])
753+ self .hass . create_task ( self . setup_devices ([device ]) )
743754
744755 async def _handle_device_remove (self , payload : dict ):
745756 """Remove device from Hass. """
0 commit comments