1- from datetime import datetime
1+ from datetime import datetime , time
22import logging
33
4- from weconnect .addressable import AddressableAttribute , AddressableList
4+ from weconnect .addressable import AddressableAttribute , AddressableDict , AddressableObject
5+ from weconnect .elements .enums import UnlockPlugState
56from weconnect .elements .generic_settings import GenericSettings
7+ from weconnect .elements .timer import Timer
68
79LOG = logging .getLogger ("weconnect" )
810
@@ -16,7 +18,7 @@ def __init__(
1618 fromDict = None ,
1719 fixAPI = True ,
1820 ):
19- self .profiles = AddressableList (localAddress = 'profiles' , parent = self )
21+ self .profiles = AddressableDict (localAddress = 'profiles' , parent = self )
2022 self .timeInCar = AddressableAttribute (localAddress = 'timeInCar' , parent = self , value = None , valueType = datetime )
2123 super ().__init__ (vehicle = vehicle , parent = parent , statusId = statusId , fromDict = fromDict , fixAPI = fixAPI )
2224
@@ -26,8 +28,15 @@ def update(self, fromDict, ignoreAttributes=None):
2628
2729 if 'value' in fromDict :
2830 if 'profiles' in fromDict ['value' ] and fromDict ['value' ]['profiles' ] is not None :
29- for profile in fromDict ['value' ]['profiles' ]:
30- LOG .warning ('Charging profiles are not yet implemented %s' , profile )
31+ for profileDict in fromDict ['value' ]['profiles' ]:
32+ if 'id' in profileDict :
33+ if profileDict ['id' ] in self .profiles :
34+ self .profiles [profileDict ['id' ]].update (fromDict = profileDict )
35+ else :
36+ self .profiles [profileDict ['id' ]] = ChargingProfiles .ChargingProfile (fromDict = profileDict , parent = self .profiles )
37+ for profileId in [profileId for profileId in self .profiles .keys ()
38+ if profileId not in [profile ['id' ] for profile in fromDict ['value' ]['profiles' ] if 'id' in profile ]]:
39+ del self .profiles [profileId ]
3140 else :
3241 self .profiles .clear ()
3342 self .profiles .enabled = False
@@ -45,7 +54,170 @@ def __str__(self):
4554 if self .timeInCar .enabled :
4655 string += f'\n \t Time in Car: { self .timeInCar .value .isoformat ()} ' # pylint: disable=no-member
4756 string += f' (captured at { self .carCapturedTimestamp .value .isoformat ()} )' # pylint: disable=no-member
48- string += f'\n \t Profiles: { len (self .profiles )} items'
49- for profile in self .profiles :
50- string += f '\n \t \t { profile } '
57+ string += f'\n \t \ t Profiles: { len (self .profiles )} items'
58+ for profile in self .profiles . values () :
59+ string += '\n ' + '' . join ([ ' \t \t \t ' + line for line in str ( profile ). splitlines ( True )])
5160 return string
61+
62+ class ChargingProfile (AddressableObject ):
63+ def __init__ (
64+ self ,
65+ parent ,
66+ fromDict = None
67+ ):
68+ self .id = AddressableAttribute (localAddress = 'id' , parent = self , value = None , valueType = int )
69+ self .name = AddressableAttribute (localAddress = 'name' , parent = self , value = None , valueType = str )
70+ self .maxChargingCurrent = AddressableAttribute (localAddress = 'maxChargingCurrent' , parent = self , value = None , valueType = str )
71+ self .minSOC_pct = AddressableAttribute (localAddress = 'minSOC_pct' , parent = self , value = None , valueType = int )
72+ self .targetSOC_pct = AddressableAttribute (localAddress = 'targetSOC_pct' , parent = self , value = None , valueType = int )
73+ self .timers = AddressableDict (localAddress = 'timers' , parent = self )
74+ self .preferredChargingTimes = AddressableDict (localAddress = 'preferredChargingTimes' , parent = self )
75+ self .options = None
76+ super ().__init__ (localAddress = None , parent = parent )
77+
78+ if fromDict is not None :
79+ self .update (fromDict )
80+
81+ def update (self , fromDict ): # noqa: C901
82+ LOG .debug ('Update charging profile from dict' )
83+
84+ if 'id' in fromDict :
85+ self .id .fromDict (fromDict , 'id' )
86+ self .localAddress = str (self .id .value )
87+ else :
88+ LOG .error ('Charging Proile is missing id attribute' )
89+
90+ self .name .fromDict (fromDict , 'name' )
91+ self .maxChargingCurrent .fromDict (fromDict , 'maxChargingCurrent' )
92+ self .minSOC_pct .fromDict (fromDict , 'minSOC_pct' )
93+ self .targetSOC_pct .fromDict (fromDict , 'targetSOC_pct' )
94+
95+ if 'options' in fromDict and fromDict ['options' ] is not None :
96+ if self .options is not None and self .options .enabled :
97+ self .options .update (fromDict = fromDict ['options' ])
98+ else :
99+ self .options = ChargingProfiles .ChargingProfile .Options (fromDict = fromDict ['options' ], parent = self )
100+
101+ if 'timers' in fromDict and fromDict ['timers' ] is not None :
102+ for chargingProfileTimerDict in fromDict ['timers' ]:
103+ if 'id' in chargingProfileTimerDict :
104+ if chargingProfileTimerDict ['id' ] in self .timers :
105+ self .timers [chargingProfileTimerDict ['id' ]].update (fromDict = chargingProfileTimerDict )
106+ else :
107+ self .timers [chargingProfileTimerDict ['id' ]] = Timer (
108+ fromDict = chargingProfileTimerDict , parent = self .timers )
109+ for timerId in [timerId for timerId in self .timers .keys ()
110+ if timerId not in [timer ['id' ]
111+ for timer in fromDict ['timers' ] if 'id' in timer ]]:
112+ del self .timers [timerId ]
113+ else :
114+ self .timers .clear ()
115+ self .timers .enabled = False
116+
117+ if 'preferredChargingTimes' in fromDict and fromDict ['preferredChargingTimes' ] is not None :
118+ for preferredChargingTimesDict in fromDict ['preferredChargingTimes' ]:
119+ if 'id' in preferredChargingTimesDict :
120+ if preferredChargingTimesDict ['id' ] in self .preferredChargingTimes :
121+ self .preferredChargingTimes [preferredChargingTimesDict ['id' ]].update (fromDict = preferredChargingTimesDict )
122+ else :
123+ self .preferredChargingTimes [preferredChargingTimesDict ['id' ]] = ChargingProfiles .ChargingProfile .PreferredTime (
124+ fromDict = preferredChargingTimesDict , parent = self .preferredChargingTimes )
125+ for timeId in [timeId for timeId in self .preferredChargingTimes .keys ()
126+ if timeId not in [timer ['id' ]
127+ for timer in fromDict ['timers' ] if 'id' in timer ]]:
128+ del self .preferredChargingTimes [timeId ]
129+ else :
130+ self .preferredChargingTimes .clear ()
131+ self .preferredChargingTimes .enabled = False
132+
133+ for key , value in {key : value for key , value in fromDict .items () if key not in ['id' , 'name' , 'maxChargingCurrent' , 'minSOC_pct' , 'targetSOC_pct' ,
134+ 'timers' , 'preferredChargingTimes' , 'options' ]}.items ():
135+ LOG .warning ('%s: Unknown attribute %s with value %s' , self .getGlobalAddress (), key , value )
136+
137+ def __str__ (self ):
138+ string = ''
139+ if self .id .enabled :
140+ string += f'Profile: { self .id .value } '
141+ if self .name .enabled :
142+ string += f' - { self .name .value } '
143+ if self .options is not None and self .options .enabled :
144+ string += f'\n Options: { self .options } '
145+ if self .timers .enabled :
146+ string += f'\n Timers: { len (self .timers )} items'
147+ for timer in self .timers .values ():
148+ string += '' .join (['\n \t ' + line for line in str (timer ).splitlines (True )])
149+ if self .preferredChargingTimes .enabled :
150+ string += f'\n Preferred Times: { len (self .preferredChargingTimes )} items'
151+ for preferredTime in self .preferredChargingTimes .values ():
152+ string += '' .join (['\n \t ' + line for line in str (preferredTime ).splitlines (True )])
153+ return string
154+
155+ class PreferredTime (AddressableObject ):
156+ def __init__ (
157+ self ,
158+ parent ,
159+ fromDict = None ,
160+ ):
161+ super ().__init__ (localAddress = None , parent = parent )
162+ self .id = AddressableAttribute (localAddress = 'id' , parent = self , value = None , valueType = int )
163+ self .preferredTimeEnabled = AddressableAttribute (localAddress = 'enabled' , parent = self , value = None , valueType = bool )
164+ self .startTime = AddressableAttribute (localAddress = 'startTime' , parent = self , value = None , valueType = time )
165+ self .endTime = AddressableAttribute (localAddress = 'endTime' , parent = self , value = None , valueType = time )
166+ if fromDict is not None :
167+ self .update (fromDict )
168+
169+ def update (self , fromDict ):
170+ LOG .debug ('Update preferred time from dict' )
171+
172+ if 'id' in fromDict :
173+ self .id .fromDict (fromDict , 'id' )
174+ self .localAddress = str (self .id .value )
175+ else :
176+ LOG .error ('Preferred time is missing id attribute' )
177+
178+ self .preferredTimeEnabled .fromDict (fromDict , 'enabled' )
179+ self .startTime .fromDict (fromDict , 'startTime' )
180+ self .endTime .fromDict (fromDict , 'endTime' )
181+
182+ for key , value in {key : value for key , value in fromDict .items ()
183+ if key not in ['id' , 'enabled' , 'startTime' , 'endTime' ]}.items ():
184+ LOG .warning ('%s: Unknown attribute %s with value %s' , self .getGlobalAddress (), key , value )
185+
186+ def __str__ (self ):
187+ string = ''
188+ if self .id .enabled :
189+ string += f'{ self .id .value } :'
190+ if self .preferredTimeEnabled .enabled :
191+ string += f' Enabled: { self .preferredTimeEnabled .value } '
192+ if self .startTime .enabled :
193+ string += f' Start: { self .startTime .value } '
194+ if self .endTime .enabled :
195+ string += f' End: { self .endTime .value } '
196+ return string
197+
198+ class Options (AddressableObject ):
199+ def __init__ (
200+ self ,
201+ parent ,
202+ fromDict = None ,
203+ ):
204+ super ().__init__ (localAddress = 'options' , parent = parent )
205+ self .id = AddressableAttribute (localAddress = 'id' , parent = self , value = None , valueType = int )
206+ self .autoUnlockPlugWhenCharged = AddressableAttribute (localAddress = 'autoUnlockPlugWhenCharged' , value = None , parent = self ,
207+ valueType = UnlockPlugState )
208+ if fromDict is not None :
209+ self .update (fromDict )
210+
211+ def update (self , fromDict ):
212+ LOG .debug ('Update preferred time from dict' )
213+
214+ self .autoUnlockPlugWhenCharged .fromDict (fromDict , 'autoUnlockPlugWhenCharged' )
215+
216+ for key , value in {key : value for key , value in fromDict .items () if key not in ['autoUnlockPlugWhenCharged' ]}.items ():
217+ LOG .warning ('%s: Unknown attribute %s with value %s' , self .getGlobalAddress (), key , value )
218+
219+ def __str__ (self ):
220+ string = ''
221+ if self .autoUnlockPlugWhenCharged .enabled :
222+ string += f'\n \t Auto Unlock When Charged: { self .autoUnlockPlugWhenCharged .value .value } '
223+ return string
0 commit comments