@@ -126,10 +126,14 @@ def normalize_aws_state(device_state: dict[str, Any]) -> dict[str, Any]:
126126 # V02 wave_state actual values: 0=OFF, 40=MEDIUM, 100=HIGH
127127 # Map to V01 Airjet format (0/50/100) for AIRJET_V01_BUBBLES_MAP compatibility
128128 # Note: Hydrojet uses 40 for MEDIUM, so no mapping needed there
129+ _LOGGER .debug ("🔵 normalize_aws_state: INPUT wave_state=%s" , wave_state )
129130 if wave_state == 40 :
130131 wave_normalized = 50 # Map V02 MEDIUM (40) → V01 Airjet MEDIUM (50)
131132 else :
132133 wave_normalized = wave_state # 0 and 100 are same in both
134+ _LOGGER .debug (
135+ "🔵 normalize_aws_state: OUTPUT wave_normalized=%s" , wave_normalized
136+ )
133137
134138 # Build normalized dict, only including fields with actual values
135139 # This prevents None values from overwriting existing data during merges
@@ -848,6 +852,8 @@ async def airjet_v01_spa_set_bubbles(
848852 Physical button cycles: OFF → HIGH → MEDIUM → OFF
849853 Try sending absolute values first (simplest approach).
850854 """
855+ _LOGGER .debug ("🔵 airjet_v01_spa_set_bubbles: input level=%s" , level )
856+
851857 # Map BubblesLevel enum to V02 wave_state values
852858 value_map = {
853859 BubblesLevel .OFF : 0 ,
@@ -856,9 +862,45 @@ async def airjet_v01_spa_set_bubbles(
856862 }
857863
858864 target_value = value_map .get (level )
859- if target_value is not None :
860- await self .set_device_state (device_id , {"wave_state" : target_value })
861- _LOGGER .debug ("Set bubbles to %s (wave_state=%d)" , level .name , target_value )
865+ _LOGGER .debug ("🔵 airjet_v01_spa_set_bubbles: target_value=%s" , target_value )
866+
867+ if target_value is None :
868+ return
869+
870+ # Some V02 Hydrojet devices ignore a direct MEDIUM (40) command when currently OFF.
871+ # Physical button cycles: OFF -> HIGH -> MEDIUM -> OFF. To reliably reach MEDIUM
872+ # from OFF, send a HIGH (100) toggle first, wait briefly, then send MEDIUM (40).
873+ try :
874+ cached = self ._state_cache .get (device_id )
875+ current_wave = None
876+ if cached and isinstance (cached .attrs , dict ):
877+ current_wave = cached .attrs .get ("wave" )
878+ except Exception :
879+ current_wave = None
880+
881+ # If requesting MEDIUM but currently OFF, perform a toggle sequence
882+ if target_value == 40 and (current_wave is None or int (current_wave ) == 0 ):
883+ _LOGGER .debug (
884+ "🔵 airjet_v01_spa_set_bubbles: current_wave=%s, sending toggle sequence HIGH->MEDIUM" ,
885+ current_wave ,
886+ )
887+ # Send HIGH first
888+ await self .set_device_state (device_id , {"wave_state" : 100 })
889+ # Give device a short moment to apply
890+ try :
891+ await asyncio .sleep (1 )
892+ except Exception :
893+ pass
894+ # Now send MEDIUM
895+ await self .set_device_state (device_id , {"wave_state" : 40 })
896+ _LOGGER .debug (
897+ "🔵 Set bubbles to %s (wave_state=%d after toggle)" , level .name , 40
898+ )
899+ return
900+
901+ # Default: send the requested absolute value
902+ await self .set_device_state (device_id , {"wave_state" : target_value })
903+ _LOGGER .debug ("🔵 Set bubbles to %s (wave_state=%d)" , level .name , target_value )
862904
863905 async def hydrojet_spa_set_bubbles (
864906 self , device_id : str , level : BubblesLevel
@@ -867,6 +909,10 @@ async def hydrojet_spa_set_bubbles(
867909
868910 V02 uses same toggle approach as Airjet V02.
869911 """
912+ _LOGGER .debug (
913+ "🔵 hydrojet_spa_set_bubbles: delegating to airjet_v01_spa_set_bubbles with level=%s" ,
914+ level ,
915+ )
870916 # V02 uses toggle approach (same as Airjet V02)
871917 await self .airjet_v01_spa_set_bubbles (device_id , level )
872918
0 commit comments