2121 ATTR_NAME ,
2222 ATTR_UNIT_OF_MEASUREMENT ,
2323 BINARY_SENSORS ,
24- DAYS ,
2524 DEVICE_MEASUREMENTS ,
2625 ENERGY_KILO_WATT_HOUR ,
2726 ENERGY_WATT_HOUR ,
5352 PlugwiseException ,
5453 ResponseError ,
5554)
56- from .util import (
57- escape_illegal_xml_characters ,
58- format_measure ,
59- in_between ,
60- version_to_model ,
61- )
55+ from .util import escape_illegal_xml_characters , format_measure , version_to_model
6256
6357
6458def update_helper (
@@ -93,40 +87,6 @@ def check_model(name: str | None, vendor_name: str | None) -> str | None:
9387 return name
9488
9589
96- def schedules_schedule_temp (
97- schedules : dict [str , dict [str , float ]], name : str
98- ) -> float | None :
99- """Helper-function for schedules().
100- Obtain the schedule temperature of the schedule.
101- """
102- if name == NONE :
103- return None # pragma: no cover
104-
105- schedule_list : list [tuple [int , dt .time , float ]] = []
106- for period , temp in schedules [name ].items ():
107- moment , dummy = period .split ("," )
108- moment_cleaned = moment .replace ("[" , "" ).split (" " )
109- day_nr = DAYS [moment_cleaned [0 ]]
110- start_time = dt .datetime .strptime (moment_cleaned [1 ], "%H:%M" ).time ()
111- tmp_list : tuple [int , dt .time , float ] = (day_nr , start_time , temp )
112- schedule_list .append (tmp_list )
113-
114- length = len (schedule_list )
115- schedule_list = sorted (schedule_list )
116- for i in range (length ):
117- j = (i + 1 ) % (length - 1 )
118- now = dt .datetime .now ().time ()
119- today = dt .datetime .now ().weekday ()
120- day_0 = schedule_list [i ][0 ]
121- day_1 = schedule_list [j ][0 ]
122- time_0 = schedule_list [i ][1 ]
123- time_1 = schedule_list [j ][1 ]
124- if today in [day_0 , day_1 ] and in_between (now , time_0 , time_1 ):
125- return schedule_list [i ][2 ]
126-
127- return None
128-
129-
13090def power_data_local_format (
13191 attrs : dict [str , str ], key_string : str , val : str
13292) -> float | int | bool :
@@ -688,16 +648,16 @@ def _control_state(self, loc_id: str) -> str | bool:
688648
689649 def _presets_legacy (self ) -> dict [str , list [float ]]:
690650 """Helper-function for presets() - collect Presets for a legacy Anna."""
691- preset_dictionary : dict [str , list [float ]] = {}
651+ presets : dict [str , list [float ]] = {}
692652 for directive in self ._domain_objects .findall ("rule/directives/when/then" ):
693653 if directive is not None and "icon" in directive .keys ():
694654 # Ensure list of heating_setpoint, cooling_setpoint
695- preset_dictionary [directive .attrib ["icon" ]] = [
655+ presets [directive .attrib ["icon" ]] = [
696656 float (directive .attrib ["temperature" ]),
697657 0 ,
698658 ]
699659
700- return preset_dictionary
660+ return presets
701661
702662 def _presets (self , loc_id : str ) -> dict [str , list [float ]]:
703663 """Collect Presets for a Thermostat based on location_id."""
@@ -731,35 +691,39 @@ def _presets(self, loc_id: str) -> dict[str, list[float]]:
731691 float (preset .get ("cooling_setpoint" )),
732692 ]
733693
694+ # Adam does not show vacation preset anymore, issue #185
695+ if self .smile_name == "Adam" :
696+ presets .pop ("vacation" )
697+
734698 return presets
735699
736- def _rule_ids_by_name (self , name : str , loc_id : str ) -> dict [str , str | None ]:
700+ def _rule_ids_by_name (self , name : str , loc_id : str ) -> dict [str , str ]:
737701 """Helper-function for _presets().
738702 Obtain the rule_id from the given name and and provide the location_id, when present.
739703 """
740- schedule_ids : dict [str , str | None ] = {}
704+ schedule_ids : dict [str , str ] = {}
741705 locator = f'./contexts/context/zone/location[@id="{ loc_id } "]'
742706 for rule in self ._domain_objects .findall (f'./rule[name="{ name } "]' ):
743707 if rule .find (locator ) is not None :
744708 schedule_ids [rule .attrib ["id" ]] = loc_id
745709 else :
746- schedule_ids [rule .attrib ["id" ]] = None
710+ schedule_ids [rule .attrib ["id" ]] = NONE
747711
748712 return schedule_ids
749713
750- def _rule_ids_by_tag (self , tag : str , loc_id : str ) -> dict [str , str | None ]:
714+ def _rule_ids_by_tag (self , tag : str , loc_id : str ) -> dict [str , str ]:
751715 """Helper-function for _presets(), _schedules() and _last_active_schedule().
752716 Obtain the rule_id from the given template_tag and provide the location_id, when present.
753717 """
754- schedule_ids : dict [str , str | None ] = {}
718+ schedule_ids : dict [str , str ] = {}
755719 locator1 = f'./template[@tag="{ tag } "]'
756720 locator2 = f'./contexts/context/zone/location[@id="{ loc_id } "]'
757721 for rule in self ._domain_objects .findall ("./rule" ):
758722 if rule .find (locator1 ) is not None :
759723 if rule .find (locator2 ) is not None :
760724 schedule_ids [rule .attrib ["id" ]] = loc_id
761725 else :
762- schedule_ids [rule .attrib ["id" ]] = None
726+ schedule_ids [rule .attrib ["id" ]] = NONE
763727
764728 return schedule_ids
765729
@@ -1072,8 +1036,8 @@ def _preset(self, loc_id: str) -> str | None:
10721036 return str (active_rule .attrib ["icon" ])
10731037
10741038 def _schedules_legacy (
1075- self , avail : list [str ], sched_temp : float | None , sel : str
1076- ) -> tuple [list [str ], str , float | None , None ]:
1039+ self , avail : list [str ], sel : str
1040+ ) -> tuple [list [str ], str , None ]:
10771041 """Helper-function for _schedules().
10781042 Collect available schedules/schedules for the legacy thermostat.
10791043 """
@@ -1096,25 +1060,21 @@ def _schedules_legacy(
10961060 if active :
10971061 sel = name
10981062
1099- return avail , sel , sched_temp , None
1063+ return avail , sel , None
11001064
1101- def _schedules (
1102- self , location : str
1103- ) -> tuple [list [str ], str , float | None , str | None ]:
1065+ def _schedules (self , location : str ) -> tuple [list [str ], str , str | None ]:
11041066 """Helper-function for smile.py: _device_data_climate().
11051067 Obtain the available schedules/schedules. Adam: a schedule can be connected to more than one location.
11061068 NEW: when a location_id is present then the schedule is active. Valid for both Adam and non-legacy Anna.
11071069 """
11081070 available : list [str ] = [NONE ]
11091071 last_used : str | None = None
1110- rule_ids : dict [str , str | None ] = {}
1111- schedule_temperature : float | None = None
1072+ rule_ids : dict [str , str ] = {}
11121073 selected = NONE
1113- tmp_last_used : str | None = None
11141074
11151075 # Legacy Anna schedule, only one schedule allowed
11161076 if self ._smile_legacy :
1117- return self ._schedules_legacy (available , schedule_temperature , selected )
1077+ return self ._schedules_legacy (available , selected )
11181078
11191079 # Adam schedules, one schedule can be linked to various locations
11201080 # self._last_active contains the locations and the active schedule name per location, or None
@@ -1123,68 +1083,24 @@ def _schedules(
11231083
11241084 tag = "zone_preset_based_on_time_and_presence_with_override"
11251085 if not (rule_ids := self ._rule_ids_by_tag (tag , location )):
1126- return available , selected , schedule_temperature , None
1086+ return available , selected , None
11271087
1128- schedules : dict [str , dict [ str , float ]] = {}
1088+ schedules : list [str ] = []
11291089 for rule_id , loc_id in rule_ids .items ():
11301090 name = self ._domain_objects .find (f'./rule[@id="{ rule_id } "]/name' ).text
1131- schedule : dict [str , float ] = {}
1132- temp : dict [str , float ] = {}
1133- locator = f'./rule[@id="{ rule_id } "]/directives'
1134- directives = self ._domain_objects .find (locator )
1135- count = 0
1136- for directive in directives :
1137- entry = directive .find ("then" ).attrib
1138- keys , dummy = zip (* entry .items ())
1139- if str (keys [0 ]) == "preset" :
1140- if loc_id is None : # set to 0 when the schedule is not active
1141- temp [directive .attrib ["time" ]] = float (0 )
1142- else :
1143- temp [directive .attrib ["time" ]] = float (
1144- self ._presets (loc_id )[entry ["preset" ]][0 ]
1145- )
1146- if self .cooling_active :
1147- temp [directive .attrib ["time" ]] = float (
1148- self ._presets (loc_id )[entry ["preset" ]][1 ]
1149- )
1150- else :
1151- if "heating_setpoint" in entry :
1152- temp [directive .attrib ["time" ]] = float (
1153- entry ["heating_setpoint" ]
1154- )
1155- if self .cooling_active :
1156- temp [directive .attrib ["time" ]] = float (
1157- entry ["cooling_setpoint" ]
1158- )
1159- else :
1160- temp [directive .attrib ["time" ]] = float (entry ["setpoint" ])
1161- count += 1
1162-
1163- if count > 1 :
1164- schedule = temp
1165- else :
1166- # Schedule with less than 2 items
1167- LOGGER .debug ("Invalid schedule, only one entry, ignoring." )
1168-
1169- if schedule :
1170- available .append (name )
1171- if location == loc_id :
1172- selected = name
1173- self ._last_active [location ] = selected
1174- schedules [name ] = schedule
1091+ available .append (name )
1092+ if location == loc_id :
1093+ selected = name
1094+ self ._last_active [location ] = selected
1095+ schedules .append (name )
11751096
11761097 if schedules :
11771098 available .remove (NONE )
1178- tmp_last_used = self ._last_used_schedule (location , rule_ids )
1179- if tmp_last_used in schedules :
1180- last_used = tmp_last_used
1181- schedule_temperature = schedules_schedule_temp (schedules , last_used )
1099+ last_used = self ._last_used_schedule (location , schedules )
11821100
1183- return available , selected , schedule_temperature , last_used
1101+ return available , selected , last_used
11841102
1185- def _last_used_schedule (
1186- self , loc_id : str , rule_ids : dict [str , str | None ]
1187- ) -> str | None :
1103+ def _last_used_schedule (self , loc_id : str , schedules : list [str ]) -> str | None :
11881104 """Helper-function for smile.py: _device_data_climate().
11891105 Determine the last-used schedule based on the location or the modified date.
11901106 """
@@ -1194,24 +1110,21 @@ def _last_used_schedule(
11941110 return last_used
11951111
11961112 # Alternatively, find last_used by finding the most recent modified_date
1197- if not rule_ids :
1198- return None # pragma: no cover
1113+ last_used = None
1114+ if not schedules :
1115+ return last_used # pragma: no cover
11991116
12001117 epoch = dt .datetime (1970 , 1 , 1 , tzinfo = pytz .utc )
1201- schedules : dict [str , float ] = {}
1118+ schedules_dates : dict [str , float ] = {}
12021119
1203- for rule_id in rule_ids :
1204- schedule_name = self ._domain_objects .find (
1205- f'./rule[@id="{ rule_id } "]/name'
1206- ).text
1207- schedule_date = self ._domain_objects .find (
1208- f'./rule[@id="{ rule_id } "]/modified_date'
1209- ).text
1120+ for name in schedules :
1121+ result = self ._domain_objects .find (f'./rule[name="{ name } "]' )
1122+ schedule_date = result .find ("modified_date" ).text
12101123 schedule_time = parse (schedule_date )
1211- schedules [ schedule_name ] = (schedule_time - epoch ).total_seconds ()
1124+ schedules_dates [ name ] = (schedule_time - epoch ).total_seconds ()
12121125
12131126 if schedules :
1214- last_used = sorted (schedules .items (), key = lambda kv : kv [1 ])[- 1 ][0 ]
1127+ last_used = sorted (schedules_dates .items (), key = lambda kv : kv [1 ])[- 1 ][0 ]
12151128
12161129 return last_used
12171130
0 commit comments