1+ # https://github.com/gwvsol/ESP8266-RTC-PCF8563
2+
3+ from micropython import const
4+ from time import localtime , mktime
5+ from gc import collect
6+
7+ #Registers overview
8+ _SECONDS = const (0x02 )
9+ _MINUTES = const (0x03 )
10+ _HOURS = const (0x04 )
11+ _DATE = const (0x05 )
12+ _WDAY = const (0x06 )
13+ _MONTH = const (0x07 )
14+ _YEAR = const (0x08 )
15+
16+ class PCF8563 (object ):
17+ def __init__ (self , i2c , i2c_addr , zone = 0 , dht = True ):
18+ self .i2c = i2c
19+ self .i2c_addr = i2c_addr
20+ self .timebuf = None
21+ self .zone = zone
22+ self .block = False
23+ self .dht = dht
24+ if self .i2c_addr in self .i2c .scan ():
25+ print ('RTC: PCF8563 find at address: 0x%x ' % (self .i2c_addr ))
26+ else :
27+ print ('RTC: PCF8563 not found at address: 0x%x ' % (self .i2c_addr ))
28+ collect () #Очищаем RAM
29+
30+ #Преобразование двоично-десятичного формата
31+ def _bcd2dec (self , bcd ):
32+ """Convert binary coded decimal (BCD) format to decimal"""
33+ return (((bcd & 0xf0 ) >> 4 ) * 10 + (bcd & 0x0f ))
34+
35+ #Преобразование в двоично-десятичный формат
36+ def _dec2bcd (self , dec ):
37+ """Convert decimal to binary coded decimal (BCD) format"""
38+ tens , units = divmod (dec , 10 )
39+ return (tens << 4 ) + units
40+
41+ def _tobytes (self , num ):
42+ return num .to_bytes (1 , 'little' )
43+
44+ #Чтение времени или запись нового знвчения и преобразование в формат ESP8266
45+ #Возвращает кортеж в формате localtime() (в ESP8266 0 - понедельник, а 6 - воскресенье)
46+ def datetime (self , datetime = None ):
47+ """Reading RTC time and convert to ESP8266 and Direct write un-none value.
48+ Range: seconds [0,59], minutes [0,59], hours [0,23],
49+ day [0,7], date [1-31], month [1-12], year [0-99]."""
50+ if datetime == None :
51+ """Reading RTC time and convert to ESP8266"""
52+ data = self .i2c .readfrom_mem (self .i2c_addr , _SECONDS , 7 )
53+ ss = self ._bcd2dec (data [0 ] & 0x7F )
54+ mm = self ._bcd2dec (data [1 ] & 0x7F )
55+ hh = self ._bcd2dec (data [2 ] & 0x3F )
56+ dd = self ._bcd2dec (data [3 ] & 0x3F )
57+ wday = data [4 ] & 0x07
58+ MM = self ._bcd2dec (data [5 ] & 0x1F )
59+ yy = self ._bcd2dec (data [6 ]) + 2000
60+ return yy , MM , dd , hh , mm , ss , wday , 0 # wday in esp8266 0 == Monday, 6 == Sunday
61+ elif datetime != None :
62+ """Direct write un-none value"""
63+ if datetime == 'reset' : #Если datetime = 'reset', сброс времени на 2000-01-01 00:00:00
64+ (yy , MM , mday , hh , mm , ss , wday , yday ) = (0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 )
65+ else :
66+ (yy , MM , mday , hh , mm , ss , wday , yday ) = datetime
67+ if ss < 0 or ss > 59 : #Записывем новое значение секунд
68+ raise ValueError ('RTC: Seconds is out of range [0,59].' )
69+ self .i2c .writeto_mem (self .i2c_addr , _SECONDS , self ._tobytes (self ._dec2bcd (ss )))
70+ if mm < 0 or mm > 59 : #Записываем новое значение минут
71+ raise ValueError ('RTC: Minutes is out of range [0,59].' )
72+ self .i2c .writeto_mem (self .i2c_addr , _MINUTES , self ._tobytes (self ._dec2bcd (mm )))
73+ if hh < 0 or hh > 23 : #Записываем новое значение часов
74+ raise ValueError ('RTC: Hours is out of range [0,23].' )
75+ self .i2c .writeto_mem (self .i2c_addr , _HOURS , self ._tobytes (self ._dec2bcd (hh ))) #Sets to 24hr mode
76+ if mday < 1 or mday > 31 : #Записываем новое значение дней
77+ raise ValueError ('RTC: Date is out of range [1,31].' )
78+ self .i2c .writeto_mem (self .i2c_addr , _DATE , self ._tobytes (self ._dec2bcd (mday ))) #Day of month
79+ if wday < 0 or wday > 6 : #Записываем новое значение дней недели
80+ raise ValueError ('RTC: Day is out of range [0,6].' )
81+ self .i2c .writeto_mem (self .i2c_addr , _WDAY , self ._tobytes (self ._dec2bcd (wday )))
82+ if MM < 1 or MM > 12 : #Записываем новое значение месяцев
83+ raise ValueError ('RTC: Month is out of range [1,12].' )
84+ self .i2c .writeto_mem (self .i2c_addr , _MONTH , self ._tobytes (self ._dec2bcd (MM )))
85+ if yy < 0 or yy > 99 : #Записываем новое значение лет
86+ raise ValueError ('RTC: Years is out of range [0,99].' )
87+ self .i2c .writeto_mem (self .i2c_addr , _YEAR , self ._tobytes (self ._dec2bcd (yy )))
88+ (yy , MM , mday , hh , mm , ss , wday , yday ) = self .datetime () #Cчитываем записанное новое значение времени с PCF8563
89+ print ('RTC: New Time: {:0>2d}-{:0>2d}-{:0>2d} {:0>2d}:{:0>2d}:{:0>2d}' .format (yy , MM , mday , hh , mm , ss )) #Выводим новое время PCF8563
90+
91+ def settime (self , source = 'esp' ):
92+ utc = self .datetime ()
93+ if source == 'esp' : #Устанавливаем время с часов ESP8266
94+ utc = localtime ()
95+ rtc = self .datetime () #Cчитываем значение времени с PCF8563
96+ #Блокировка перевода времени. Если октябрь, блокировка на 1час 3минуты
97+ if self .block and rtc [1 ] == 10 :
98+ if rtc [3 ] == 2 : #Если 2 часа, блокировка не снимается
99+ pass
100+ elif rtc [3 ] == 3 and rtc [4 ] <= 2 : #Если 3 часа и меньше 2 минут, бликировка не снимается
101+ pass
102+ else : #Во всех остальных случаях блокировка снимается
103+ self .block = False
104+ #Если март, бликировка включена для следующего вызова метода
105+ elif self .block and rtc [1 ] == 3 :
106+ if rtc [3 ] == 3 : #Блокировка действует пока не измениться rtc[3] = 3
107+ pass
108+ else : #Во всех остальных случаях блокировка снимается
109+ self .block = False
110+ else : #Во всех остальных случаях блокировка снимается
111+ self .block = False
112+ (yy , MM , mday , hh , mm , ss , wday , yday ) = utc
113+ #Если существует разница во времени, применяем изменения
114+ if source == 'dht' and rtc [3 ] != hh :
115+ print ('RTC: Old Time: {:0>2d}-{:0>2d}-{:0>2d} {:0>2d}:{:0>2d}:{:0>2d}' \
116+ .format (rtc [0 ], rtc [1 ], rtc [2 ], rtc [3 ], rtc [4 ], rtc [5 ]))
117+ self .datetime ((yy - 2000 , MM , mday , hh , mm , ss , wday , yday ))
118+ elif source == 'esp' or source == 'ntp' or rtc [3 ] != hh or rtc [4 ] != mm or rtc [5 ] != ss :
119+ print ('RTC: Old Time: {:0>2d}-{:0>2d}-{:0>2d} {:0>2d}:{:0>2d}:{:0>2d}' \
120+ .format (rtc [0 ], rtc [1 ], rtc [2 ], rtc [3 ], rtc [4 ], rtc [5 ]))
121+ self .datetime ((yy - 2000 , MM , mday , hh , mm , ss , wday , yday ))
122+ #else: #Если разница во времени не обнаружена, выводим время с PCF8563
123+ # print('RTC: No time change: {:0>2d}-{:0>2d}-{:0>2d} {:0>2d}:{:0>2d}:{:0>2d}'\
124+ # .format(yy, MM, mday, hh, mm, ss))
125+
126+ if __name__ == "__main__" :
127+
128+ from machine import I2C , Pin
129+ i2c = I2C (scl = Pin (22 ), sda = Pin (21 ), freq = 400000 )
130+ rtc = PCF8563 (i2c , 0x51 , zone = 3 )
131+ print (rtc .datetime ())
132+
0 commit comments