"""CircuitPython PCF85063 Real-Time Clock (RTC) driver. Synchronizes the hardware RTC with CircuitPython's native rtc.RTC() system clock. """ import rtc import time class PCF85063: ADDR = 0x51 TIME_REG_START = 0x04 def __init__(self, i2c): self.i2c = i2c self._init_rtc() def read_reg(self, reg, n=1): while not self.i2c.try_lock(): pass try: self.i2c.writeto(self.ADDR, bytes([reg])) buf = bytearray(n) self.i2c.readfrom_into(self.ADDR, buf) return buf except Exception as e: print(f"RTC read failed at reg 0x{reg:02X}: {e}") return None finally: self.i2c.unlock() def write_reg(self, reg, data): while not self.i2c.try_lock(): pass try: payload = bytearray([reg]) if isinstance(data, (bytes, bytearray, list)): payload.extend(data) else: payload.append(data) self.i2c.writeto(self.ADDR, payload) return True except Exception as e: print(f"RTC write failed at reg 0x{reg:02X}: {e}") return False finally: self.i2c.unlock() def _init_rtc(self): ctrl1 = self.read_reg(0x00, 1) if ctrl1 is not None and (ctrl1[0] & 0x20): print("RTC oscillator was stopped. Starting oscillator...") self.write_reg(0x00, 0x00) def _dec2bcd(self, val): return (val // 10 << 4) | (val % 10) def _bcd2dec(self, val): return ((val >> 4) * 10) + (val & 0x0F) def get_datetime(self): """Reads current time from hardware RTC. Returns: tuple: (year, month, day, weekday, hour, minute, second) or None on error. """ data = self.read_reg(self.TIME_REG_START, 7) if data is None: return None second = self._bcd2dec(data[0] & 0x7F) minute = self._bcd2dec(data[1] & 0x7F) hour = self._bcd2dec(data[2] & 0x3F) day = self._bcd2dec(data[3] & 0x3F) weekday = data[4] & 0x07 month = self._bcd2dec(data[5] & 0x1F) year = 2000 + self._bcd2dec(data[6]) return (year, month, day, weekday, hour, minute, second) def set_datetime(self, dt): """Sets the hardware RTC time. Args: dt (tuple): (year, month, day, weekday, hour, minute, second) """ try: year, month, day, weekday, hour, minute, second = dt reg_year = year % 100 data = bytearray(7) data[0] = self._dec2bcd(second) & 0x7F data[1] = self._dec2bcd(minute) data[2] = self._dec2bcd(hour) data[3] = self._dec2bcd(day) data[4] = weekday & 0x07 data[5] = self._dec2bcd(month) data[6] = self._dec2bcd(reg_year) return self.write_reg(self.TIME_REG_START, data) except Exception as e: print(f"Error setting PCF85063 RTC: {e}") return False def sync_to_system(self): """Synchronizes the CircuitPython system time from the hardware RTC.""" dt = self.get_datetime() if dt: year, month, day, weekday, hour, minute, second = dt r = rtc.RTC() r.datetime = time.struct_time((year, month, day, hour, minute, second, weekday, -1, -1)) print(f"System clock synced to RTC: {year:04d}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}:{second:02d}") return True return False def sync_from_system(self): """Synchronizes the hardware RTC time from the system clock.""" try: t = time.localtime() dt = (t.tm_year, t.tm_mon, t.tm_mday, t.tm_wday, t.tm_hour, t.tm_min, t.tm_sec) success = self.set_datetime(dt) if success: print(f"RTC synced from System: {t.tm_year:04d}-{t.tm_mon:02d}-{t.tm_mday:02d} {t.tm_hour:02d}:{t.tm_min:02d}:{t.tm_sec:02d}") return success except Exception as e: print(f"Error syncing RTC from system: {e}") return False def get_time_string(self): dt = self.get_datetime() if dt: return f"{dt[0]:04d}-{dt[1]:02d}-{dt[2]:02d} {dt[4]:02d}:{dt[5]:02d}:{dt[6]:02d}" return "0000-00-00 00:00:00"