@@ -95,6 +95,8 @@ def __init__( # noqa: PLR0913
9595 name : str | None = None ,
9696 model : str | None = None ,
9797 identifier : str | None = None ,
98+ alignment_date : datetime | None = None ,
99+ alignment_index : int | None = None ,
98100 ) -> None :
99101 """
100102 Initialize a FindMyAccessory. These values are usually obtained during pairing.
@@ -116,6 +118,14 @@ def __init__( # noqa: PLR0913
116118 self ._name = name
117119 self ._model = model
118120 self ._identifier = identifier
121+ self ._alignment_date = alignment_date if alignment_date is not None else paired_at
122+ self ._alignment_index = alignment_index if alignment_index is not None else 0
123+ if self ._alignment_date .tzinfo is None :
124+ self ._alignment_date = self ._alignment_date .astimezone ()
125+ logger .warning (
126+ "Alignment datetime is timezone-naive. Assuming system tz: %s." ,
127+ self ._alignment_date .tzname (),
128+ )
119129
120130 @property
121131 def master_key (self ) -> bytes :
@@ -173,25 +183,27 @@ def keys_at(self, ind: int | datetime) -> set[KeyPair]:
173183 secondary_offset = 0
174184
175185 if isinstance (ind , datetime ):
176- # number of 15-minute slots since pairing time
177- ind = (
186+ # number of 15-minute slots since alignment
187+ slots_since_alignment = (
178188 int (
179- (ind - self ._paired_at ).total_seconds () / (15 * 60 ),
189+ (ind - self ._alignment_date ).total_seconds () / (15 * 60 ),
180190 )
181191 + 1
182192 )
193+ ind = self ._alignment_index + slots_since_alignment
194+
183195 # number of slots until first 4 am
184- first_rollover = self ._paired_at .astimezone ().replace (
196+ first_rollover = self ._alignment_date .astimezone ().replace (
185197 hour = 4 ,
186198 minute = 0 ,
187199 second = 0 ,
188200 microsecond = 0 ,
189201 )
190- if first_rollover < self ._paired_at : # we rolled backwards, so increment the day
202+ if first_rollover < self ._alignment_date : # we rolled backwards, so increment the day
191203 first_rollover += timedelta (days = 1 )
192204 secondary_offset = (
193205 int (
194- (first_rollover - self ._paired_at ).total_seconds () / (15 * 60 ),
206+ (first_rollover - self ._alignment_date ).total_seconds () / (15 * 60 ),
195207 )
196208 + 1
197209 )
@@ -213,6 +225,7 @@ def keys_at(self, ind: int | datetime) -> set[KeyPair]:
213225 def from_plist (
214226 cls ,
215227 plist : str | Path | dict | bytes | IO [bytes ],
228+ key_alignment_plist : IO [bytes ] | None = None ,
216229 * ,
217230 name : str | None = None ,
218231 ) -> FindMyAccessory :
@@ -247,6 +260,16 @@ def from_plist(
247260 model = device_data ["model" ]
248261 identifier = device_data ["identifier" ]
249262
263+ alignment_date = None
264+ index = None
265+ if key_alignment_plist :
266+ alignment_data = plistlib .load (key_alignment_plist )
267+
268+ alignment_date = alignment_data ["lastIndexObservationDate" ].replace (
269+ tzinfo = timezone .utc ,
270+ )
271+ index = alignment_data ["lastIndexObserved" ]
272+
250273 return cls (
251274 master_key = master_key ,
252275 skn = skn ,
@@ -255,6 +278,8 @@ def from_plist(
255278 name = name ,
256279 model = model ,
257280 identifier = identifier ,
281+ alignment_date = alignment_date ,
282+ alignment_index = index ,
258283 )
259284
260285 @override
0 commit comments