@@ -142,6 +142,13 @@ class MammotionErrorSensorEntityDescription(SensorEntityDescription):
142142 value_fn : Callable [[MammotionDeviceErrorUpdateCoordinator , MowingDevice ], StateType ]
143143
144144
145+ @dataclass (frozen = True , kw_only = True )
146+ class MammotionSpinoErrorSensorEntityDescription (SensorEntityDescription ):
147+ """Describes a Spino error-log sensor entity."""
148+
149+ value_fn : Callable [[MammotionSpinoCoordinator ], StateType ]
150+
151+
145152LUBA_SENSOR_ONLY_TYPES : tuple [MammotionSensorEntityDescription , ...] = (
146153 MammotionSensorEntityDescription (
147154 key = "blade_height" ,
@@ -326,21 +333,19 @@ class MammotionErrorSensorEntityDescription(SensorEntityDescription):
326333 entity_category = EntityCategory .DIAGNOSTIC ,
327334 ),
328335 MammotionSensorEntityDescription (
329- key = "l1_satellites " ,
336+ key = "pos_level " ,
330337 state_class = SensorStateClass .MEASUREMENT ,
331338 device_class = None ,
332339 native_unit_of_measurement = None ,
333- value_fn = lambda mower_data : (mower_data .report_data .rtk .co_view_stars >> 0 )
334- & 255 ,
340+ value_fn = lambda mower_data : mower_data .report_data .rtk .pos_level ,
335341 entity_category = EntityCategory .DIAGNOSTIC ,
336342 ),
337343 MammotionSensorEntityDescription (
338- key = "l2_satellites " ,
344+ key = "age " ,
339345 state_class = SensorStateClass .MEASUREMENT ,
340- device_class = None ,
341- native_unit_of_measurement = None ,
342- value_fn = lambda mower_data : (mower_data .report_data .rtk .co_view_stars >> 8 )
343- & 255 ,
346+ device_class = SensorDeviceClass .DURATION ,
347+ native_unit_of_measurement = UnitOfTime .SECONDS ,
348+ value_fn = lambda mower_data : mower_data .report_data .rtk .age ,
344349 entity_category = EntityCategory .DIAGNOSTIC ,
345350 ),
346351 # MammotionSensorEntityDescription(
@@ -441,6 +446,73 @@ class MammotionErrorSensorEntityDescription(SensorEntityDescription):
441446 ),
442447)
443448
449+ # Luba 2 / Yuka (non-RTK) only — APK refreshNonRtkDeviceUI shows these;
450+ # Luba 1 and standard RTK devices do not display them.
451+ LUBA_2_YUKA_SIGNAL_TYPES : tuple [MammotionSensorEntityDescription , ...] = (
452+ MammotionSensorEntityDescription (
453+ key = "l1_satellites" ,
454+ state_class = SensorStateClass .MEASUREMENT ,
455+ device_class = None ,
456+ native_unit_of_measurement = None ,
457+ value_fn = lambda mower_data : (mower_data .report_data .rtk .dis_status >> 16 ) & 255 ,
458+ entity_category = EntityCategory .DIAGNOSTIC ,
459+ ),
460+ MammotionSensorEntityDescription (
461+ key = "l2_satellites" ,
462+ state_class = SensorStateClass .MEASUREMENT ,
463+ device_class = None ,
464+ native_unit_of_measurement = None ,
465+ value_fn = lambda mower_data : (mower_data .report_data .rtk .dis_status >> 24 ) & 255 ,
466+ entity_category = EntityCategory .DIAGNOSTIC ,
467+ ),
468+ MammotionSensorEntityDescription (
469+ key = "co_view_l1" ,
470+ state_class = SensorStateClass .MEASUREMENT ,
471+ device_class = None ,
472+ native_unit_of_measurement = None ,
473+ value_fn = lambda mower_data : mower_data .report_data .rtk .co_view_stars & 255 ,
474+ entity_category = EntityCategory .DIAGNOSTIC ,
475+ ),
476+ MammotionSensorEntityDescription (
477+ key = "co_view_l2" ,
478+ state_class = SensorStateClass .MEASUREMENT ,
479+ device_class = None ,
480+ native_unit_of_measurement = None ,
481+ value_fn = lambda mower_data : (mower_data .report_data .rtk .co_view_stars >> 8 )
482+ & 255 ,
483+ entity_category = EntityCategory .DIAGNOSTIC ,
484+ ),
485+ MammotionSensorEntityDescription (
486+ key = "rtk_signal" ,
487+ state_class = SensorStateClass .MEASUREMENT ,
488+ device_class = None ,
489+ native_unit_of_measurement = None ,
490+ value_fn = lambda mower_data : (mower_data .report_data .rtk .dis_status >> 40 ) & 255 ,
491+ entity_category = EntityCategory .DIAGNOSTIC ,
492+ ),
493+ MammotionSensorEntityDescription (
494+ key = "device_signal" ,
495+ state_class = None ,
496+ device_class = SensorDeviceClass .ENUM ,
497+ native_unit_of_measurement = None ,
498+ value_fn = lambda mower_data : (mower_data .report_data .rtk .dis_status >> 32 ) & 255 ,
499+ entity_category = EntityCategory .DIAGNOSTIC ,
500+ ),
501+ )
502+
503+ # Luba 1 only — APK refreshLuba1ModeUI shows base_link_status (connection_to_ref);
504+ # Luba 2 / Yuka and RTK devices hide it.
505+ LUBA_1_SIGNAL_TYPES : tuple [MammotionSensorEntityDescription , ...] = (
506+ MammotionSensorEntityDescription (
507+ key = "base_link_status" ,
508+ state_class = SensorStateClass .MEASUREMENT ,
509+ device_class = None ,
510+ native_unit_of_measurement = None ,
511+ value_fn = lambda mower_data : (mower_data .report_data .rtk .dis_status >> 48 ) & 255 ,
512+ entity_category = EntityCategory .DIAGNOSTIC ,
513+ ),
514+ )
515+
444516WORK_SENSOR_TYPES : tuple [MammotionWorkSensorEntityDescription , ...] = (
445517 MammotionWorkSensorEntityDescription (
446518 key = "work_area" ,
@@ -548,6 +620,44 @@ class MammotionErrorSensorEntityDescription(SensorEntityDescription):
548620 ),
549621)
550622
623+ SPINO_ERROR_SENSOR_TYPES : tuple [MammotionSpinoErrorSensorEntityDescription , ...] = (
624+ MammotionSpinoErrorSensorEntityDescription (
625+ key = "spino_error_time" ,
626+ device_class = SensorDeviceClass .TIMESTAMP ,
627+ value_fn = lambda coordinator : coordinator .get_error_time (),
628+ entity_category = EntityCategory .DIAGNOSTIC ,
629+ ),
630+ MammotionSpinoErrorSensorEntityDescription (
631+ key = "spino_error_message" ,
632+ state_class = None ,
633+ native_unit_of_measurement = None ,
634+ device_class = None ,
635+ value_fn = lambda coordinator : (
636+ msg [:255 ] if (msg := coordinator .get_error_message ()) is not None else None
637+ ),
638+ entity_category = EntityCategory .DIAGNOSTIC ,
639+ ),
640+ MammotionSpinoErrorSensorEntityDescription (
641+ key = "spino_error_code" ,
642+ state_class = None ,
643+ native_unit_of_measurement = None ,
644+ device_class = None ,
645+ value_fn = lambda coordinator : coordinator .get_error_code (),
646+ entity_category = EntityCategory .DIAGNOSTIC ,
647+ ),
648+ MammotionSpinoErrorSensorEntityDescription (
649+ key = "spino_mqtt_status" ,
650+ state_class = None ,
651+ native_unit_of_measurement = None ,
652+ device_class = SensorDeviceClass .ENUM ,
653+ options = ["online" , "offline" ],
654+ value_fn = lambda coordinator : "online"
655+ if coordinator .mqtt_device_online
656+ else "offline" ,
657+ entity_category = EntityCategory .DIAGNOSTIC ,
658+ ),
659+ )
660+
551661
552662async def async_setup_entry (
553663 hass : HomeAssistant ,
@@ -570,12 +680,25 @@ async def async_setup_entry(
570680 MammotionSensorEntity (mower .reporting_coordinator , description )
571681 for description in LUBA_2_YUKA_ONLY_TYPES
572682 )
573- if not DeviceType .is_yuka_mini (mower .device .device_name ):
683+ entities .extend (
684+ MammotionSensorEntity (mower .reporting_coordinator , description )
685+ for description in LUBA_2_YUKA_SIGNAL_TYPES
686+ )
687+ device_type = DeviceType .value_of_str (
688+ mower .device .device_name , mower .device .product_key
689+ )
690+ if device_type .supports_battery_cycle_count ():
574691 entities .extend (
575692 MammotionSensorEntity (mower .reporting_coordinator , description )
576693 for description in MINI_SERIES_EXCLUDED_TYPES
577694 )
578695
696+ if DeviceType .is_luba1 (mower .device .device_name , mower .device .product_key ):
697+ entities .extend (
698+ MammotionSensorEntity (mower .reporting_coordinator , description )
699+ for description in LUBA_1_SIGNAL_TYPES
700+ )
701+
579702 entities .extend (
580703 MammotionSensorEntity (mower .reporting_coordinator , description )
581704 for description in SENSOR_TYPES
@@ -619,6 +742,10 @@ async def async_setup_entry(
619742 MammotionSpinoSensorEntity (spino .coordinator , description )
620743 for description in SPINO_SENSOR_TYPES
621744 )
745+ entities .extend (
746+ MammotionSpinoErrorSensorEntity (spino .coordinator , description )
747+ for description in SPINO_ERROR_SENSOR_TYPES
748+ )
622749
623750 async_add_entities (entities )
624751
@@ -687,6 +814,28 @@ def native_value(self) -> StateType:
687814 return self .entity_description .value_fn (self .coordinator .data )
688815
689816
817+ class MammotionSpinoErrorSensorEntity (MammotionBaseSpinoEntity , SensorEntity ):
818+ """Sensor entity for a single Spino error-log field (code, time, or message)."""
819+
820+ entity_description : MammotionSpinoErrorSensorEntityDescription
821+ _attr_has_entity_name = True
822+
823+ def __init__ (
824+ self ,
825+ coordinator : MammotionSpinoCoordinator ,
826+ entity_description : MammotionSpinoErrorSensorEntityDescription ,
827+ ) -> None :
828+ """Set up MammotionSpinoErrorSensorEntity."""
829+ super ().__init__ (coordinator , entity_description .key )
830+ self .entity_description = entity_description
831+ self ._attr_translation_key = entity_description .key
832+
833+ @property
834+ def native_value (self ) -> StateType :
835+ """Return the state of the sensor."""
836+ return self .entity_description .value_fn (self .coordinator )
837+
838+
690839class MammotionErrorSensorEntity (MammotionBaseEntity , SensorEntity ):
691840 """Defining the Mammotion Error Sensor."""
692841
0 commit comments