4141from pyshark .capture .live_capture import LiveCapture , UnknownInterfaceException # type: ignore
4242from pyshark .packet .packet import Packet # type: ignore
4343
44- from roborock import SHORT_MODEL_TO_ENUM , RoborockCommand
45- from roborock .data import DeviceData , RoborockBase , UserData
44+ from roborock import RoborockCommand
45+ from roborock .data import RoborockBase , UserData
46+ from roborock .data .b01_q10 .b01_q10_code_mappings import B01_Q10_DP
4647from roborock .device_features import DeviceFeatures
4748from roborock .devices .cache import Cache , CacheData
4849from roborock .devices .device import RoborockDevice
5354from roborock .devices .traits .v1 .map_content import MapContentTrait
5455from roborock .exceptions import RoborockException , RoborockUnsupportedFeature
5556from roborock .protocol import MessageParser
56- from roborock .version_1_apis .roborock_mqtt_client_v1 import RoborockMqttClientV1
5757from roborock .web_api import RoborockApiClient
5858
5959_LOGGER = logging .getLogger (__name__ )
@@ -91,7 +91,14 @@ def wrapper(*args, **kwargs):
9191 context : RoborockContext = ctx .obj
9292
9393 async def run ():
94- return await func (* args , ** kwargs )
94+ try :
95+ await func (* args , ** kwargs )
96+ except Exception as err :
97+ _LOGGER .exception ("Uncaught exception in command" )
98+ click .echo (f"Error: { err } " , err = True )
99+ finally :
100+ if not context .is_session_mode ():
101+ await context .cleanup ()
95102
96103 if context .is_session_mode ():
97104 # Session mode - run in the persistent loop
@@ -739,6 +746,21 @@ async def network_info(ctx, device_id: str):
739746 await _display_v1_trait (context , device_id , lambda v1 : v1 .network_info )
740747
741748
749+ def _parse_b01_q10_command (cmd : str ) -> B01_Q10_DP :
750+ """Parse B01_Q10 command from either enum name or value."""
751+ try :
752+ return B01_Q10_DP (int (cmd ))
753+ except ValueError :
754+ try :
755+ return B01_Q10_DP .from_name (cmd )
756+ except ValueError :
757+ try :
758+ return B01_Q10_DP .from_value (cmd )
759+ except ValueError :
760+ pass
761+ raise RoborockException (f"Invalid command { cmd } for B01_Q10 device" )
762+
763+
742764@click .command ()
743765@click .option ("--device_id" , required = True )
744766@click .option ("--cmd" , required = True )
@@ -749,12 +771,18 @@ async def command(ctx, cmd, device_id, params):
749771 context : RoborockContext = ctx .obj
750772 device_manager = await context .get_device_manager ()
751773 device = await device_manager .get_device (device_id )
752- if device .v1_properties is None :
753- raise RoborockException (f"Device { device .name } does not support V1 protocol" )
754- command_trait : Trait = device .v1_properties .command
755- result = await command_trait .send (cmd , json .loads (params ) if params is not None else None )
756- if result :
757- click .echo (dump_json (result ))
774+ if device .v1_properties is not None :
775+ command_trait : Trait = device .v1_properties .command
776+ result = await command_trait .send (cmd , json .loads (params ) if params is not None else None )
777+ if result :
778+ click .echo (dump_json (result ))
779+ elif device .b01_q10_properties is not None :
780+ cmd_value = _parse_b01_q10_command (cmd )
781+ command_trait : Trait = device .b01_q10_properties .command
782+ await command_trait .send (cmd_value , json .loads (params ) if params is not None else None )
783+ click .echo ("Command sent successfully; Enable debug logging (-d) to see responses." )
784+ # Q10 commands don't have a specific time to respond, so wait a bit and log
785+ await asyncio .sleep (5 )
758786
759787
760788@click .command ()
@@ -815,44 +843,46 @@ async def get_device_info(ctx: click.Context):
815843 """
816844 click .echo ("Discovering devices..." )
817845 context : RoborockContext = ctx .obj
818- connection_cache = await context .get_devices ()
819-
820- home_data = connection_cache .cache_data .home_data
821-
822- all_devices = home_data .get_all_devices ()
823- if not all_devices :
846+ device_connection_manager = await context .get_device_manager ()
847+ device_manager = await device_connection_manager .ensure_device_manager ()
848+ devices = await device_manager .get_devices ()
849+ if not devices :
824850 click .echo ("No devices found." )
825851 return
826852
827- click .echo (f"Found { len (all_devices )} devices. Fetching data..." )
853+ click .echo (f"Found { len (devices )} devices. Fetching data..." )
828854
829855 all_products_data = {}
830856
831- for device in all_devices :
857+ for device in devices :
832858 click .echo (f" - Processing { device .name } ({ device .duid } )" )
833- product_info = home_data .product_map [device .product_id ]
834- device_data = DeviceData (device , product_info .model )
835- mqtt_client = RoborockMqttClientV1 (connection_cache .user_data , device_data )
836859
837- try :
838- init_status_result = await mqtt_client .send_command (
839- RoborockCommand .APP_GET_INIT_STATUS ,
840- )
841- product_nickname = SHORT_MODEL_TO_ENUM .get (product_info .model .split ("." )[- 1 ]).name
842- current_product_data = {
843- "Protocol Version" : device .pv ,
844- "Product Nickname" : product_nickname ,
845- "New Feature Info" : init_status_result .get ("new_feature_info" ),
846- "New Feature Info Str" : init_status_result .get ("new_feature_info_str" ),
847- "Feature Info" : init_status_result .get ("feature_info" ),
848- }
860+ if device .product .model in all_products_data :
861+ click .echo (f" - Skipping duplicate model { device .product .model } " )
862+ continue
849863
850- all_products_data [product_info .model ] = current_product_data
864+ current_product_data = {
865+ "Protocol Version" : device .device_info .pv ,
866+ "Product Nickname" : device .product .product_nickname .name ,
867+ }
868+ if device .v1_properties is not None :
869+ try :
870+ result : list [dict [str , Any ]] = await device .v1_properties .command .send (
871+ RoborockCommand .APP_GET_INIT_STATUS
872+ )
873+ except Exception as e :
874+ click .echo (f" - Error processing device { device .name } : { e } " , err = True )
875+ continue
876+ init_status_result = result [0 ] if result else {}
877+ current_product_data .update (
878+ {
879+ "New Feature Info" : init_status_result .get ("new_feature_info" ),
880+ "New Feature Info Str" : init_status_result .get ("new_feature_info_str" ),
881+ "Feature Info" : init_status_result .get ("feature_info" ),
882+ }
883+ )
851884
852- except Exception as e :
853- click .echo (f" - Error processing device { device .name } : { e } " , err = True )
854- finally :
855- await mqtt_client .async_release ()
885+ all_products_data [device .product .model ] = current_product_data
856886
857887 if all_products_data :
858888 click .echo ("\n --- Device Information (copy to your YAML file) ---\n " )
0 commit comments