@@ -69,7 +69,7 @@ class Option():
69
69
max :Optional [int ] = None
70
70
stepsize :Optional [int ] = None
71
71
allowedvalues :Optional [list [str ]] = None
72
- displayallowedvalues :Optional [list [str ]] = None
72
+ allowedvaluesdisplay :Optional [list [str ]] = None
73
73
execution :Optional [str ] = None
74
74
liveupdate :Optional [bool ] = None
75
75
default :Optional [str ] = None
@@ -92,7 +92,7 @@ def create(cls, data:dict):
92
92
option .max = constraints .get ('max' )
93
93
option .stepsize = constraints .get ('stepsize' )
94
94
option .allowedvalues = constraints .get ('allowedvalues' )
95
- option .displayallowedvalues = constraints .get ('displayvalues' )
95
+ option .allowedvaluesdisplay = constraints .get ('displayvalues' )
96
96
option .execution = constraints .get ('execution' )
97
97
option .liveupdate = constraints .get ('liveupdate' )
98
98
option .default = constraints .get ('default' )
@@ -485,46 +485,9 @@ async def async_update_data(self, data:dict) -> None:
485
485
await self .async_fetch_data ()
486
486
await self ._callbacks .async_broadcast_event (self , Events .PAIRED )
487
487
await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
488
- else :
489
- # update options, statuses and settings in the data model
490
- if self .selected_program and self .selected_program .options and key in self .selected_program .options :
491
- self .selected_program .options [key ].value = value
492
- self .selected_program .options [key ].name = data .get ("name" )
493
- self .selected_program .options [key ].displayvalue = data .get ("displayvalue" )
494
- elif "programs/selected" in uri :
495
- _LOGGER .debug ("Got event for unknown property: %s" , data )
496
- self .active_program = await self ._async_fetch_programs ("selected" )
497
- await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
498
-
499
- if self .active_program and self .active_program .options and key in self .active_program .options :
500
- self .active_program .options [key ].value = value
501
- self .active_program .options [key ].name = data .get ("name" )
502
- self .active_program .options [key ].displayvalue = data .get ("displayvalue" )
503
- elif "programs/active" in uri :
504
- _LOGGER .debug ("Got event for unknown property: %s" , data )
505
- self .active_program = await self ._async_fetch_programs ("active" )
506
- await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
507
-
508
- if key in self .status :
509
- self .status [key ].value = value
510
- self .status [key ].name = data .get ("name" )
511
- self .status [key ].displayvalue = data .get ("displayvalue" )
512
- elif "/status/" in uri :
513
- _LOGGER .debug ("Got event for unknown property: %s" , data )
514
- self .status = await self ._async_fetch_status ()
515
- await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
516
-
517
- if key in self .settings :
518
- self .settings [key ].value = value
519
- self .settings [key ].name = data .get ("name" )
520
- self .settings [key ].displayvalue = data .get ("displayvalue" )
521
- elif "/settings/" in uri :
522
- _LOGGER .debug ("Got event for unknown property: %s" , data )
523
- self .settings = await self ._async_fetch_settings ()
524
- await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
525
488
526
489
# Fetch data from the API on major events
527
- if key == "BSH.Common.Root.SelectedProgram" and (not self .selected_program or self .selected_program .key != value ):
490
+ elif key == "BSH.Common.Root.SelectedProgram" and (not self .selected_program or self .selected_program .key != value ):
528
491
# handle selected program
529
492
async with Synchronization .selected_program_lock :
530
493
# Have to check again after aquiring the lock
@@ -551,7 +514,7 @@ async def async_update_data(self, data:dict) -> None:
551
514
# apparently it is possible to get progress notifications without getting the ActiveProgram event first so we handle that
552
515
(key in ["BSH.Common.Option.ProgramProgress" , "BSH.Common.Option.RemainingProgramTime" ]) or
553
516
# it is also possible to get operation state Run without getting the ActiveProgram event
554
- (key == "BSH.Common.Status.OperationState" and value == "BSH.Common.EnumType.OperationState.Run" )
517
+ (key == "BSH.Common.Status.OperationState" and value in [ "BSH.Common.EnumType.OperationState.Run" , "BSH.Common.EnumType.OperationState.DelayedStart" ] )
555
518
) and \
556
519
(not self .active_program or (key == "BSH.Common.Root.ActiveProgram" and self .active_program .key != value ) ) and \
557
520
self ._active_program_fail_count < 3 :
@@ -560,53 +523,120 @@ async def async_update_data(self, data:dict) -> None:
560
523
if self .active_program :
561
524
self ._active_program_fail_count = 0
562
525
else :
563
- # This is a workaround to prevent rate limiting when receiving progress events but avaialable_programs returns 404
526
+ # This is a workaround to prevent rate limiting when receiving progress events but active_program returns 404
564
527
self ._active_program_fail_count += 1
565
528
self .available_programs = await self ._async_fetch_programs ("available" )
566
- self .settings = await self ._async_fetch_settings ()
529
+ if not self .settings :
530
+ self .settings = await self ._async_fetch_settings ()
567
531
self .commands = await self ._async_fetch_commands ()
568
532
await self ._callbacks .async_broadcast_event (self , Events .PROGRAM_STARTED , value )
569
533
await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
570
534
571
535
elif ( (key == "BSH.Common.Root.ActiveProgram" and not value ) or
572
- (key == "BSH.Common.Status.OperationState" and value in [ "BSH.Common.EnumType.OperationState.Ready" , "BSH.Common.EnumType.OperationState. Finished"] ) or
536
+ (key == "BSH.Common.Status.OperationState" and value == "BSH.Common.EnumType.OperationState.Finished" ) or
573
537
(key == "BSH.Common.Event.ProgramFinished" )
574
538
) and self .active_program :
575
539
# handle program end
540
+
541
+ # NOTE: Depending on the received event there may still be an active program provided by the API
542
+ # This creates an inconsistency of HA is restarted while the appliance is in this state
543
+ # however, it still seems bettert than relying on the order of received events which is very inconsistent
544
+
576
545
prev_prog = self .active_program .key if self .active_program else None
577
546
self .active_program = None
578
547
self ._active_program_fail_count = 0
579
- self .settings = await self ._async_fetch_settings ()
580
548
self .commands = await self ._async_fetch_commands ()
581
- self .available_programs = await self . _async_fetch_programs ( "available" )
549
+ # TODO: should self.available_programs = None ????
582
550
await self ._callbacks .async_broadcast_event (self , Events .PROGRAM_FINISHED , prev_prog )
583
551
await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
584
552
585
- elif key == "BSH.Common.Status.OperationState" and \
586
- value != "BSH.Common.EnumType.OperationState.Run" and \
587
- self .status .get ("BSH.Common.Status.OperationState" ) != value : # ignore repeat notifiations of the same state
588
- self .active_program = await self ._async_fetch_programs ("active" )
553
+ elif key == "BSH.Common.Status.OperationState" and value == "BSH.Common.EnumType.OperationState.Ready" \
554
+ and self .status .get ("BSH.Common.Status.OperationState" , {"value" : None }).value != value : # ignore repeating events
555
+ prev_prog = self .active_program .key if self .active_program else None
556
+ self .active_program = None
557
+ self ._active_program_fail_count = 0
589
558
self .selected_program = await self ._async_fetch_programs ("selected" )
590
559
self .available_programs = await self ._async_fetch_programs ("available" )
591
- self .settings = await self ._async_fetch_settings ()
592
560
self .commands = await self ._async_fetch_commands ()
561
+ if not self .settings :
562
+ self .settings = await self ._async_fetch_settings ()
563
+ await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
564
+ if prev_prog :
565
+ await self ._callbacks .async_broadcast_event (self , Events .PROGRAM_FINISHED , prev_prog )
566
+
567
+ elif key == "BSH.Common.Status.OperationState" and value == "BSH.Common.EnumType.OperationState.Inactive" \
568
+ and self .status .get ("BSH.Common.Status.OperationState" , {"value" : None }).value != value :
569
+ self .active_program = None
570
+ self ._active_program_fail_count = 0
571
+ self .selected_program = None
572
+ self .available_programs = None
573
+ self .commands = {}
593
574
await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
594
575
576
+ elif key == "BSH.Common.Status.OperationState" and value == "BSH.Common.EnumType.OperationState.Pause" \
577
+ and self .status .get ("BSH.Common.Status.OperationState" , {"value" : None }).value != value :
578
+ self .commands = await self ._async_fetch_commands ()
579
+
580
+ elif key == "BSH.Common.Status.OperationState" \
581
+ and value in [ "BSH.Common.EnumType.OperationState.ActionRequired" , "BSH.Common.EnumType.OperationState.Error" , "BSH.Common.EnumType.OperationState.Aborting" ] \
582
+ and self .status .get ("BSH.Common.Status.OperationState" , {"value" : None }).value != value :
583
+ _LOGGER .debug ("The appliance entered and error operation state: %s" , data )
584
+
595
585
elif key == "BSH.Common.Status.RemoteControlStartAllowed" :
596
586
self .available_programs = await self ._async_fetch_programs ("available" )
587
+ self .commands = await self ._async_fetch_commands ()
597
588
await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
598
589
599
- elif ( not self .available_programs or len (self .available_programs ) < 2 ) and \
600
- ( key in ["BSH.Common.Status.OperationState" , "BSH.Common.Status.RemoteControlActive" ] ) and \
601
- ( "BSH.Common.Status.OperationState" not in self .status or self .status ["BSH.Common.Status.OperationState" ].value == "BSH.Common.EnumType.OperationState.Ready" ) and \
602
- ( "BSH.Common.Status.RemoteControlActive" not in self .status or self .status ["BSH.Common.Status.RemoteControlActive" ].value ):
603
- # Handle cases were the appliance data was loaded without getting all the programs (for example when HA is restarted while a program is active)
604
- # If the state is Ready and remote control is possible and we didn't load the available programs before then load them now
605
- available_programs = await self ._async_fetch_programs ("available" )
606
- self .available_programs = available_programs
607
- await self ._callbacks .async_broadcast_event (self , Events .PAIRED )
590
+ # elif ( not self.available_programs or len(self.available_programs) < 2) and \
591
+ # ( key in ["BSH.Common.Status.OperationState", "BSH.Common.Status.RemoteControlActive"] ) and \
592
+ # ( "BSH.Common.Status.OperationState" not in self.status or self.status["BSH.Common.Status.OperationState"].value == "BSH.Common.EnumType.OperationState.Ready" ) and \
593
+ # ( "BSH.Common.Status.RemoteControlActive" not in self.status or self.status["BSH.Common.Status.RemoteControlActive"].value):
594
+ # # Handle cases were the appliance data was loaded without getting all the programs (for example when HA is restarted while a program is active)
595
+ # # If the state is Ready and remote control is possible and we didn't load the available programs before then load them now
596
+ # available_programs = await self._async_fetch_programs("available")
597
+ # self.available_programs = available_programs
598
+ # await self._callbacks.async_broadcast_event(self, Events.PAIRED)
599
+ # await self._callbacks.async_broadcast_event(self, Events.DATA_CHANGED)
600
+
601
+ if self .selected_program and self .selected_program .options and key in self .selected_program .options :
602
+ self .selected_program .options [key ].value = value
603
+ self .selected_program .options [key ].name = data .get ("name" )
604
+ self .selected_program .options [key ].displayvalue = data .get ("displayvalue" )
605
+ elif "programs/selected" in uri and key != "BSH.Common.Root.SelectedProgram" :
606
+ _LOGGER .debug ("Got event for unknown property: %s" , data )
607
+ self .active_program = await self ._async_fetch_programs ("selected" )
608
608
await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
609
609
610
+ if self .active_program and self .active_program .options and key in self .active_program .options :
611
+ self .active_program .options [key ].value = value
612
+ self .active_program .options [key ].name = data .get ("name" )
613
+ self .active_program .options [key ].displayvalue = data .get ("displayvalue" )
614
+ elif ( "programs/active" in uri and key != "BSH.Common.Root.ActiveProgram"
615
+ # ignore late active program events coming after the program has finished
616
+ # this implies that an unknown event will not triger the first active program fetch, which should be fine
617
+ and self .active_program
618
+ ):
619
+ _LOGGER .debug ("Got event for unknown property: %s" , data )
620
+ self .active_program = await self ._async_fetch_programs ("active" )
621
+ await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
622
+
623
+ if key in self .status :
624
+ self .status [key ].value = value
625
+ self .status [key ].name = data .get ("name" )
626
+ self .status [key ].displayvalue = data .get ("displayvalue" )
627
+ elif "/status/" in uri :
628
+ _LOGGER .debug ("Got event for unknown property: %s" , data )
629
+ self .status = await self ._async_fetch_status ()
630
+ await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
631
+
632
+ if key in self .settings :
633
+ self .settings [key ].value = value
634
+ self .settings [key ].name = data .get ("name" )
635
+ self .settings [key ].displayvalue = data .get ("displayvalue" )
636
+ elif "/settings/" in uri :
637
+ _LOGGER .debug ("Got event for unknown property: %s" , data )
638
+ self .settings = await self ._async_fetch_settings ()
639
+ await self ._callbacks .async_broadcast_event (self , Events .DATA_CHANGED )
610
640
# broadcast the specific event that was received
611
641
await self ._callbacks .async_broadcast_event (self , key , value )
612
642
0 commit comments