@ -58,7 +58,7 @@ import threading
from abc import ABC , abstractmethod
from abc import ABC , abstractmethod
from dataclasses import dataclass
from dataclasses import dataclass
from enum import Enum , auto
from enum import Enum , auto
from typing import Callable, Optional , final
from typing import Any, Callable, Optional , final
from paho . mqtt . client import (
from paho . mqtt . client import (
MQTT_ERR_SUCCESS ,
MQTT_ERR_SUCCESS ,
@ -173,9 +173,9 @@ class MipsCmdType(Enum):
class MipsCmd :
class MipsCmd :
""" MIoT Pub/Sub command. """
""" MIoT Pub/Sub command. """
type_ : MipsCmdType
type_ : MipsCmdType
data : a ny
data : A ny
def __init__ ( self , type_ : MipsCmdType , data : a ny) - > None :
def __init__ ( self , type_ : MipsCmdType , data : A ny) - > None :
self . type_ = type_
self . type_ = type_
self . data = data
self . data = data
@ -184,8 +184,8 @@ class MipsCmd:
class MipsRequest :
class MipsRequest :
""" MIoT Pub/Sub request. """
""" MIoT Pub/Sub request. """
mid : int = None
mid : int = None
on_reply : Callable [ [ str , a ny] , None ] = None
on_reply : Callable [ [ str , A ny] , None ] = None
on_reply_ctx : a ny = None
on_reply_ctx : A ny = None
timer : TimeoutHandle = None
timer : TimeoutHandle = None
@ -194,8 +194,8 @@ class MipsRequestData:
""" MIoT Pub/Sub request data. """
""" MIoT Pub/Sub request data. """
topic : str = None
topic : str = None
payload : str = None
payload : str = None
on_reply : Callable [ [ str , a ny] , None ] = None
on_reply : Callable [ [ str , A ny] , None ] = None
on_reply_ctx : a ny = None
on_reply_ctx : A ny = None
timeout_ms : int = None
timeout_ms : int = None
@ -223,8 +223,8 @@ class MipsApi:
param2 : payload
param2 : payload
param3 : handler_ctx
param3 : handler_ctx
"""
"""
handler : Callable [ [ MipsIncomingApiCall , str , a ny] , None ] = None
handler : Callable [ [ MipsIncomingApiCall , str , A ny] , None ] = None
handler_ctx : a ny = None
handler_ctx : A ny = None
class MipsRegApi ( MipsApi ) :
class MipsRegApi ( MipsApi ) :
@ -247,8 +247,8 @@ class MipsBroadcast:
param 2 : msg payload
param 2 : msg payload
param 3 : handle_ctx
param 3 : handle_ctx
"""
"""
handler : Callable [ [ str , str , a ny] , None ] = None
handler : Callable [ [ str , str , A ny] , None ] = None
handler_ctx : a ny = None
handler_ctx : A ny = None
def __str__ ( self ) - > str :
def __str__ ( self ) - > str :
return f ' { self . topic } , { id ( self . handler ) } , { id ( self . handler_ctx ) } '
return f ' { self . topic } , { id ( self . handler ) } , { id ( self . handler_ctx ) } '
@ -265,7 +265,6 @@ class MipsState:
"""
"""
str : key
str : key
bool : mips connect state
bool : mips connect state
any : ctx
"""
"""
handler : Callable [ [ str , bool ] , asyncio . Future ] = None
handler : Callable [ [ str , bool ] , asyncio . Future ] = None
@ -288,10 +287,10 @@ class MipsDeviceState:
""" handler
""" handler
str : did
str : did
MIoTDeviceState : online / offline / disable
MIoTDeviceState : online / offline / disable
a ny: ctx
A ny: ctx
"""
"""
handler : Callable [ [ str , MIoTDeviceState , a ny] , None ] = None
handler : Callable [ [ str , MIoTDeviceState , A ny] , None ] = None
handler_ctx : a ny = None
handler_ctx : A ny = None
class MipsRegDeviceState ( MipsDeviceState ) :
class MipsRegDeviceState ( MipsDeviceState ) :
@ -512,8 +511,8 @@ class MipsClient(ABC):
@final
@final
def mev_set_timeout (
def mev_set_timeout (
self , timeout_ms : int , handler : Callable [ [ a ny] , None ] ,
self , timeout_ms : int , handler : Callable [ [ A ny] , None ] ,
handler_ctx : a ny = None
handler_ctx : A ny = None
) - > Optional [ TimeoutHandle ] :
) - > Optional [ TimeoutHandle ] :
""" set timeout.
""" set timeout.
NOTICE : Internal function , only mips threads are allowed to call
NOTICE : Internal function , only mips threads are allowed to call
@ -534,7 +533,7 @@ class MipsClient(ABC):
@final
@final
def mev_set_read_handler (
def mev_set_read_handler (
self , fd : int , handler : Callable [ [ any ] , None ] , handler_ctx : a ny
self , fd : int , handler : Callable [ [ Any ] , None ] , handler_ctx : A ny
) - > bool :
) - > bool :
""" set read handler.
""" set read handler.
NOTICE : Internal function , only mips threads are allowed to call
NOTICE : Internal function , only mips threads are allowed to call
@ -546,7 +545,7 @@ class MipsClient(ABC):
@final
@final
def mev_set_write_handler (
def mev_set_write_handler (
self , fd : int , handler : Callable [ [ any ] , None ] , handler_ctx : a ny
self , fd : int , handler : Callable [ [ Any ] , None ] , handler_ctx : A ny
) - > bool :
) - > bool :
""" set write handler.
""" set write handler.
NOTICE : Internal function , only mips threads are allowed to call
NOTICE : Internal function , only mips threads are allowed to call
@ -604,8 +603,8 @@ class MipsClient(ABC):
@abstractmethod
@abstractmethod
def sub_prop (
def sub_prop (
self , did : str , handler : Callable [ [ dict , a ny] , None ] ,
self , did : str , handler : Callable [ [ dict , A ny] , None ] ,
siid : int = None , piid : int = None , handler_ctx : a ny = None
siid : int = None , piid : int = None , handler_ctx : A ny = None
) - > bool : . . .
) - > bool : . . .
@abstractmethod
@abstractmethod
@ -615,8 +614,8 @@ class MipsClient(ABC):
@abstractmethod
@abstractmethod
def sub_event (
def sub_event (
self , did : str , handler : Callable [ [ dict , a ny] , None ] ,
self , did : str , handler : Callable [ [ dict , A ny] , None ] ,
siid : int = None , eiid : int = None , handler_ctx : a ny = None
siid : int = None , eiid : int = None , handler_ctx : A ny = None
) - > bool : . . .
) - > bool : . . .
@abstractmethod
@abstractmethod
@ -632,11 +631,11 @@ class MipsClient(ABC):
@abstractmethod
@abstractmethod
async def get_prop_async (
async def get_prop_async (
self , did : str , siid : int , piid : int , timeout_ms : int = 10000
self , did : str , siid : int , piid : int , timeout_ms : int = 10000
) - > a ny: . . .
) - > A ny: . . .
@abstractmethod
@abstractmethod
async def set_prop_async (
async def set_prop_async (
self , did : str , siid : int , piid : int , value : a ny,
self , did : str , siid : int , piid : int , value : A ny,
timeout_ms : int = 10000
timeout_ms : int = 10000
) - > bool : . . .
) - > bool : . . .
@ -709,7 +708,7 @@ class MipsClient(ABC):
return False
return False
@final
@final
def _mips_send_cmd ( self , type_ : MipsCmdType , data : a ny) - > bool :
def _mips_send_cmd ( self , type_ : MipsCmdType , data : A ny) - > bool :
if self . _mips_queue is None or self . _cmd_event_fd is None :
if self . _mips_queue is None or self . _cmd_event_fd is None :
raise MIoTMipsError ( ' send mips cmd disable ' )
raise MIoTMipsError ( ' send mips cmd disable ' )
# Put data to queue
# Put data to queue
@ -723,7 +722,7 @@ class MipsClient(ABC):
if threading . current_thread ( ) is not self . _mips_thread :
if threading . current_thread ( ) is not self . _mips_thread :
raise MIoTMipsError ( ' illegal call ' )
raise MIoTMipsError ( ' illegal call ' )
def __mips_cmd_read_handler ( self , ctx : a ny) - > None :
def __mips_cmd_read_handler ( self , ctx : A ny) - > None :
fd_value = os . eventfd_read ( self . _cmd_event_fd )
fd_value = os . eventfd_read ( self . _cmd_event_fd )
if fd_value == 0 :
if fd_value == 0 :
return
return
@ -763,20 +762,20 @@ class MipsClient(ABC):
if self . _on_mips_cmd :
if self . _on_mips_cmd :
self . _on_mips_cmd ( mips_cmd = mips_cmd )
self . _on_mips_cmd ( mips_cmd = mips_cmd )
def __mqtt_read_handler ( self , ctx : a ny) - > None :
def __mqtt_read_handler ( self , ctx : A ny) - > None :
self . __mqtt_loop_handler ( ctx = ctx )
self . __mqtt_loop_handler ( ctx = ctx )
def __mqtt_write_handler ( self , ctx : a ny) - > None :
def __mqtt_write_handler ( self , ctx : A ny) - > None :
self . mev_set_write_handler ( self . _mqtt_fd , None , None )
self . mev_set_write_handler ( self . _mqtt_fd , None , None )
self . __mqtt_loop_handler ( ctx = ctx )
self . __mqtt_loop_handler ( ctx = ctx )
def __mqtt_timer_handler ( self , ctx : a ny) - > None :
def __mqtt_timer_handler ( self , ctx : A ny) - > None :
self . __mqtt_loop_handler ( ctx = ctx )
self . __mqtt_loop_handler ( ctx = ctx )
if self . _mqtt :
if self . _mqtt :
self . _mqtt_timer = self . mev_set_timeout (
self . _mqtt_timer = self . mev_set_timeout (
self . MQTT_INTERVAL_MS , self . __mqtt_timer_handler , None )
self . MQTT_INTERVAL_MS , self . __mqtt_timer_handler , None )
def __mqtt_loop_handler ( self , ctx : a ny) - > None :
def __mqtt_loop_handler ( self , ctx : A ny) - > None :
try :
try :
if self . _mqtt :
if self . _mqtt :
self . _mqtt . loop_read ( )
self . _mqtt . loop_read ( )
@ -896,7 +895,7 @@ class MipsClient(ABC):
self . _mips_reconnect_timer = self . mev_set_timeout (
self . _mips_reconnect_timer = self . mev_set_timeout (
interval , self . __mips_connect , None )
interval , self . __mips_connect , None )
def __mips_sub_internal_pending_handler ( self , ctx : a ny) - > None :
def __mips_sub_internal_pending_handler ( self , ctx : A ny) - > None :
subbed_count = 1
subbed_count = 1
for topic in list ( self . _mips_sub_pending_map . keys ( ) ) :
for topic in list ( self . _mips_sub_pending_map . keys ( ) ) :
if subbed_count > self . MIPS_SUB_PATCH :
if subbed_count > self . MIPS_SUB_PATCH :
@ -923,7 +922,7 @@ class MipsClient(ABC):
else :
else :
self . _mips_sub_pending_timer = None
self . _mips_sub_pending_timer = None
def __mips_connect ( self , ctx : a ny = None ) - > None :
def __mips_connect ( self , ctx : A ny = None ) - > None :
result = MQTT_ERR_UNKNOWN
result = MQTT_ERR_UNKNOWN
if self . _mips_reconnect_timer :
if self . _mips_reconnect_timer :
self . mev_clear_timeout ( self . _mips_reconnect_timer )
self . mev_clear_timeout ( self . _mips_reconnect_timer )
@ -1034,8 +1033,8 @@ class MipsCloudClient(MipsClient):
@final
@final
def sub_prop (
def sub_prop (
self , did : str , handler : Callable [ [ dict , a ny] , None ] ,
self , did : str , handler : Callable [ [ dict , A ny] , None ] ,
siid : int = None , piid : int = None , handler_ctx : a ny = None
siid : int = None , piid : int = None , handler_ctx : A ny = None
) - > bool :
) - > bool :
if not isinstance ( did , str ) or handler is None :
if not isinstance ( did , str ) or handler is None :
raise MIoTMipsError ( ' invalid params ' )
raise MIoTMipsError ( ' invalid params ' )
@ -1044,7 +1043,7 @@ class MipsCloudClient(MipsClient):
f ' device/ { did } /up/properties_changed/ '
f ' device/ { did } /up/properties_changed/ '
f ' { " # " if siid is None or piid is None else f " { siid } / { piid } " } ' )
f ' { " # " if siid is None or piid is None else f " { siid } / { piid } " } ' )
def on_prop_msg ( topic : str , payload : str , ctx : a ny) - > bool :
def on_prop_msg ( topic : str , payload : str , ctx : A ny) - > bool :
try :
try :
msg : dict = json . loads ( payload )
msg : dict = json . loads ( payload )
except json . JSONDecodeError :
except json . JSONDecodeError :
@ -1077,8 +1076,8 @@ class MipsCloudClient(MipsClient):
@final
@final
def sub_event (
def sub_event (
self , did : str , handler : Callable [ [ dict , a ny] , None ] ,
self , did : str , handler : Callable [ [ dict , A ny] , None ] ,
siid : int = None , eiid : int = None , handler_ctx : a ny = None
siid : int = None , eiid : int = None , handler_ctx : A ny = None
) - > bool :
) - > bool :
if not isinstance ( did , str ) or handler is None :
if not isinstance ( did , str ) or handler is None :
raise MIoTMipsError ( ' invalid params ' )
raise MIoTMipsError ( ' invalid params ' )
@ -1087,7 +1086,7 @@ class MipsCloudClient(MipsClient):
f ' device/ { did } /up/event_occured/ '
f ' device/ { did } /up/event_occured/ '
f ' { " # " if siid is None or eiid is None else f " { siid } / { eiid } " } ' )
f ' { " # " if siid is None or eiid is None else f " { siid } / { eiid } " } ' )
def on_event_msg ( topic : str , payload : str , ctx : a ny) - > bool :
def on_event_msg ( topic : str , payload : str , ctx : A ny) - > bool :
try :
try :
msg : dict = json . loads ( payload )
msg : dict = json . loads ( payload )
except json . JSONDecodeError :
except json . JSONDecodeError :
@ -1122,15 +1121,15 @@ class MipsCloudClient(MipsClient):
@final
@final
def sub_device_state (
def sub_device_state (
self , did : str , handler : Callable [ [ str , MIoTDeviceState , a ny] , None ] ,
self , did : str , handler : Callable [ [ str , MIoTDeviceState , A ny] , None ] ,
handler_ctx : a ny = None
handler_ctx : A ny = None
) - > bool :
) - > bool :
""" subscribe online state. """
""" subscribe online state. """
if not isinstance ( did , str ) or handler is None :
if not isinstance ( did , str ) or handler is None :
raise MIoTMipsError ( ' invalid params ' )
raise MIoTMipsError ( ' invalid params ' )
topic : str = f ' device/ { did } /state/# '
topic : str = f ' device/ { did } /state/# '
def on_state_msg ( topic : str , payload : str , ctx : a ny) - > None :
def on_state_msg ( topic : str , payload : str , ctx : A ny) - > None :
msg : dict = json . loads ( payload )
msg : dict = json . loads ( payload )
# {"device_id":"xxxx","device_name":"米家智能插座3 ","event":"online",
# {"device_id":"xxxx","device_name":"米家智能插座3 ","event":"online",
# "model": "cuco.plug.v3","timestamp":1709001070828,"uid":xxxx}
# "model": "cuco.plug.v3","timestamp":1709001070828,"uid":xxxx}
@ -1163,11 +1162,11 @@ class MipsCloudClient(MipsClient):
async def get_prop_async (
async def get_prop_async (
self , did : str , siid : int , piid : int , timeout_ms : int = 10000
self , did : str , siid : int , piid : int , timeout_ms : int = 10000
) - > a ny:
) - > A ny:
raise NotImplementedError ( ' please call in http client ' )
raise NotImplementedError ( ' please call in http client ' )
async def set_prop_async (
async def set_prop_async (
self , did : str , siid : int , piid : int , value : a ny,
self , did : str , siid : int , piid : int , value : A ny,
timeout_ms : int = 10000
timeout_ms : int = 10000
) - > bool :
) - > bool :
raise NotImplementedError ( ' please call in http client ' )
raise NotImplementedError ( ' please call in http client ' )
@ -1199,8 +1198,8 @@ class MipsCloudClient(MipsClient):
self . _mips_unsub_internal ( topic = unreg_bc . topic )
self . _mips_unsub_internal ( topic = unreg_bc . topic )
def __reg_broadcast (
def __reg_broadcast (
self , topic : str , handler : Callable [ [ str , str , a ny] , None ] ,
self , topic : str , handler : Callable [ [ str , str , A ny] , None ] ,
handler_ctx : a ny = None
handler_ctx : A ny = None
) - > bool :
) - > bool :
return self . _mips_send_cmd (
return self . _mips_send_cmd (
type_ = MipsCmdType . REG_BROADCAST ,
type_ = MipsCmdType . REG_BROADCAST ,
@ -1259,7 +1258,7 @@ class MipsLocalClient(MipsClient):
_device_state_sub_map : dict [ str , MipsDeviceState ]
_device_state_sub_map : dict [ str , MipsDeviceState ]
_get_prop_queue : dict [ str , list ]
_get_prop_queue : dict [ str , list ]
_get_prop_timer : asyncio . TimerHandle
_get_prop_timer : asyncio . TimerHandle
_on_dev_list_changed : Callable [ [ a ny, list [ str ] ] , asyncio . Future ]
_on_dev_list_changed : Callable [ [ A ny, list [ str ] ] , asyncio . Future ]
def __init__ (
def __init__ (
self , did : str , host : str , group_id : str ,
self , did : str , host : str , group_id : str ,
@ -1347,14 +1346,14 @@ class MipsLocalClient(MipsClient):
@final
@final
def sub_prop (
def sub_prop (
self , did : str , handler : Callable [ [ dict , a ny] , None ] ,
self , did : str , handler : Callable [ [ dict , A ny] , None ] ,
siid : int = None , piid : int = None , handler_ctx : a ny = None
siid : int = None , piid : int = None , handler_ctx : A ny = None
) - > bool :
) - > bool :
topic : str = (
topic : str = (
f ' appMsg/notify/iot/ { did } /property/ '
f ' appMsg/notify/iot/ { did } /property/ '
f ' { " # " if siid is None or piid is None else f " { siid } . { piid } " } ' )
f ' { " # " if siid is None or piid is None else f " { siid } . { piid } " } ' )
def on_prop_msg ( topic : str , payload : str , ctx : a ny) :
def on_prop_msg ( topic : str , payload : str , ctx : A ny) :
msg : dict = json . loads ( payload )
msg : dict = json . loads ( payload )
if (
if (
msg is None
msg is None
@ -1380,14 +1379,14 @@ class MipsLocalClient(MipsClient):
@final
@final
def sub_event (
def sub_event (
self , did : str , handler : Callable [ [ dict , a ny] , None ] ,
self , did : str , handler : Callable [ [ dict , A ny] , None ] ,
siid : int = None , eiid : int = None , handler_ctx : a ny = None
siid : int = None , eiid : int = None , handler_ctx : A ny = None
) - > bool :
) - > bool :
topic : str = (
topic : str = (
f ' appMsg/notify/iot/ { did } /event/ '
f ' appMsg/notify/iot/ { did } /event/ '
f ' { " # " if siid is None or eiid is None else f " { siid } . { eiid } " } ' )
f ' { " # " if siid is None or eiid is None else f " { siid } . { eiid } " } ' )
def on_event_msg ( topic : str , payload : str , ctx : a ny) :
def on_event_msg ( topic : str , payload : str , ctx : A ny) :
msg : dict = json . loads ( payload )
msg : dict = json . loads ( payload )
if (
if (
msg is None
msg is None
@ -1414,7 +1413,7 @@ class MipsLocalClient(MipsClient):
@final
@final
async def get_prop_safe_async (
async def get_prop_safe_async (
self , did : str , siid : int , piid : int , timeout_ms : int = 10000
self , did : str , siid : int , piid : int , timeout_ms : int = 10000
) - > a ny:
) - > A ny:
self . _get_prop_queue . setdefault ( did , [ ] )
self . _get_prop_queue . setdefault ( did , [ ] )
fut : asyncio . Future = self . main_loop . create_future ( )
fut : asyncio . Future = self . main_loop . create_future ( )
self . _get_prop_queue [ did ] . append ( {
self . _get_prop_queue [ did ] . append ( {
@ -1434,7 +1433,7 @@ class MipsLocalClient(MipsClient):
@final
@final
async def get_prop_async (
async def get_prop_async (
self , did : str , siid : int , piid : int , timeout_ms : int = 10000
self , did : str , siid : int , piid : int , timeout_ms : int = 10000
) - > a ny:
) - > A ny:
result_obj = await self . __request_async (
result_obj = await self . __request_async (
topic = ' proxy/get ' ,
topic = ' proxy/get ' ,
payload = json . dumps ( {
payload = json . dumps ( {
@ -1449,7 +1448,7 @@ class MipsLocalClient(MipsClient):
@final
@final
async def set_prop_async (
async def set_prop_async (
self , did : str , siid : int , piid : int , value : a ny,
self , did : str , siid : int , piid : int , value : A ny,
timeout_ms : int = 10000
timeout_ms : int = 10000
) - > dict :
) - > dict :
payload_obj : dict = {
payload_obj : dict = {
@ -1580,13 +1579,13 @@ class MipsLocalClient(MipsClient):
@final
@final
@property
@property
def on_dev_list_changed ( self ) - > Callable [ [ a ny, list [ str ] ] , asyncio . Future ] :
def on_dev_list_changed ( self ) - > Callable [ [ A ny, list [ str ] ] , asyncio . Future ] :
return self . _on_dev_list_changed
return self . _on_dev_list_changed
@final
@final
@on_dev_list_changed.setter
@on_dev_list_changed.setter
def on_dev_list_changed (
def on_dev_list_changed (
self , func : Callable [ [ a ny, list [ str ] ] , asyncio . Future ]
self , func : Callable [ [ A ny, list [ str ] ] , asyncio . Future ]
) - > None :
) - > None :
""" run in main loop. """
""" run in main loop. """
self . _on_dev_list_changed = func
self . _on_dev_list_changed = func
@ -1731,8 +1730,8 @@ class MipsLocalClient(MipsClient):
def __request (
def __request (
self , topic : str , payload : str ,
self , topic : str , payload : str ,
on_reply : Callable [ [ str , a ny] , None ] ,
on_reply : Callable [ [ str , A ny] , None ] ,
on_reply_ctx : a ny = None , timeout_ms : int = 10000
on_reply_ctx : A ny = None , timeout_ms : int = 10000
) - > bool :
) - > bool :
if topic is None or payload is None or on_reply is None :
if topic is None or payload is None or on_reply is None :
raise MIoTMipsError ( ' invalid params ' )
raise MIoTMipsError ( ' invalid params ' )
@ -1745,8 +1744,8 @@ class MipsLocalClient(MipsClient):
return self . _mips_send_cmd ( type_ = MipsCmdType . CALL_API , data = req_data )
return self . _mips_send_cmd ( type_ = MipsCmdType . CALL_API , data = req_data )
def __reg_broadcast (
def __reg_broadcast (
self , topic : str , handler : Callable [ [ str , str , a ny] , None ] ,
self , topic : str , handler : Callable [ [ str , str , A ny] , None ] ,
handler_ctx : a ny
handler_ctx : A ny
) - > bool :
) - > bool :
return self . _mips_send_cmd (
return self . _mips_send_cmd (
type_ = MipsCmdType . REG_BROADCAST ,
type_ = MipsCmdType . REG_BROADCAST ,
@ -1764,7 +1763,7 @@ class MipsLocalClient(MipsClient):
) - > dict :
) - > dict :
fut_handler : asyncio . Future = self . main_loop . create_future ( )
fut_handler : asyncio . Future = self . main_loop . create_future ( )
def on_msg_reply ( payload : str , ctx : a ny) :
def on_msg_reply ( payload : str , ctx : A ny) :
fut : asyncio . Future = ctx
fut : asyncio . Future = ctx
if fut :
if fut :
self . main_loop . call_soon_threadsafe ( fut . set_result , payload )
self . main_loop . call_soon_threadsafe ( fut . set_result , payload )