11import json
22import logging
3- from datetime import timedelta
3+ from datetime import timedelta , datetime
44from numbers import Number
55from re import sub
66from typing import Final , Iterable
2020 XEVPLUGCHARGER_STATE_DISCONNECTED , XEVPLUGCHARGER_STATE_CONNECTED ,
2121 XEVBATTERYCHARGEDISPLAY_STATE_IN_PROGRESS ,
2222 VEHICLE_LOCK_STATE_LOCKED , VEHICLE_LOCK_STATE_PARTLY , VEHICLE_LOCK_STATE_UNLOCKED ,
23- REMOTE_START_STATE_ACTIVE , REMOTE_START_STATE_INACTIVE , HONK_AND_FLASH
23+ REMOTE_START_STATE_ACTIVE , REMOTE_START_STATE_INACTIVE , HONK_AND_FLASH , DAYS_MAP
2424)
2525
2626_LOGGER = logging .getLogger (__name__ )
3737ROOT_UPDTIME : Final = "updateTime"
3838
3939UNSUPPORTED : Final = str ("Unsupported" )
40+ UNDEFINED : Final = str ("Undefined" )
4041
4142class FordpassDataHandler :
4243 # Helper functions to simplify the callable implementations
@@ -543,6 +544,9 @@ def get_elveh_attrs(data, units:UnitSystem):
543544 else :
544545 attrs ["motorkW" ] = 0
545546
547+ xev_next_departure_time_schedule_id = None
548+ xev_next_departure_time_location_id = None
549+
546550 if "customMetrics" in data_metrics :
547551 for key in data_metrics .get ("customMetrics" , {}):
548552 if "accumulated-vehicle-speed-cruising-coaching-score" in key :
@@ -562,8 +566,56 @@ def get_elveh_attrs(data, units:UnitSystem):
562566 attrs ["remoteDataResponseStatus" ] = data_metrics .get ("customMetrics" , {}).get (key , {}).get ("value" )
563567
564568 if ":custom:xev-" in key :
565- entryName = FordpassDataHandler .to_camel (key .split (":custom:xev-" )[1 ])
566- attrs [entryName ] = data_metrics .get ("customMetrics" , {}).get (key , {}).get ("value" )
569+ if "next-departure-time-schedule-id" in key :
570+ xev_next_departure_time_schedule_id = data_metrics .get ("customMetrics" , {}).get (key , {}).get ("value" )
571+ elif "next-departure-time-location-id" in key :
572+ xev_next_departure_time_location_id = data_metrics .get ("customMetrics" , {}).get (key , {}).get ("value" )
573+ else :
574+ entryName = FordpassDataHandler .to_camel (key .split (":custom:xev-" )[1 ])
575+ attrs [entryName ] = data_metrics .get ("customMetrics" , {}).get (key , {}).get ("value" )
576+
577+ if xev_next_departure_time_schedule_id is not None : #and xev_next_departure_time_location_id is not None:
578+ # IF there is a 'schedule_id' defined, then we set the attribute, in order to make the processing
579+ # of this data a bit easier - since you must not check for existence of both id's all the time
580+ attrs ["nextScheduledDepartureTime" ] = UNDEFINED
581+ xev_departure_locations = data_metrics .get ("configurations" , {}).get ("xevDepartureSchedulesSetting" ,{}).get ("value" , {}).get ("departureLocations" , {})
582+ for a_depart_location in xev_departure_locations :
583+ if "departureSchedules" in a_depart_location and (
584+ len (xev_departure_locations ) == 1 or
585+ a_depart_location .get ("locationId" , None ) == xev_next_departure_time_location_id
586+ ) :
587+ for a_schedule in a_depart_location ["departureSchedules" ]:
588+ if str (a_schedule .get ("scheduleId" , None )) == str (xev_next_departure_time_schedule_id ):
589+ if a_schedule .get ("scheduleStatus" , "OFF" ).upper () == "ON" :
590+ a_schedule_obj = a_schedule .get ("schedule" , {})
591+ if len (a_schedule_obj ) > 0 :
592+ _LOGGER .debug (f"{ a_schedule_obj } " )
593+ time_obj = a_schedule_obj .get ("weeklySchedule" , {})
594+ day_of_week = time_obj .get ("dayOfWeek" , UNSUPPORTED ).upper ()
595+ time_of_day = time_obj .get ("timeOfDay" , UNSUPPORTED )
596+ tz = a_schedule_obj .get ("timeZone" , UNSUPPORTED )
597+
598+ if "LOCAL_TIME" == tz :
599+ if day_of_week in DAYS_MAP and time_of_day != UNSUPPORTED :
600+ # Get the current date and time in local timezone
601+ now = datetime .now ()
602+
603+ # Get the weekday number for the specified day
604+ target_weekday = DAYS_MAP [day_of_week ]
605+ target_time = datetime .strptime (time_of_day , "%H:%M" ).time ()
606+
607+ # Calculate days until the next target day
608+ days_until = (target_weekday - now .weekday () + 7 ) % 7
609+ if days_until == 0 and now .time () >= target_time :
610+ days_until = 7 # If today is Friday but the time is past, go to next week
611+
612+ # Calculate the next date
613+ next_date = now + timedelta (days = days_until )
614+
615+ # Set the target time
616+ attrs ["nextScheduledDepartureTime" ] = next_date .replace (hour = target_time .hour , minute = target_time .minute , second = 0 , microsecond = 0 )
617+
618+ break
567619
568620 data_events = FordpassDataHandler .get_events (data )
569621 if "customEvents" in data_events :
0 commit comments