time_t
umzustellen.
Um time_t
setzen zu können, braucht es tmElements_t
.
Und diese Datenstruktur dreht völlig frei, wenn der -1970 bei der
Jahreszahl fehlt. Da wird dann nicht etwa nur ein falsches Jahr
geliefert, sondern sämtliche Werte haben nix mehr mit den
Eingangswerten zu tun. Wenn man dann den Fehler zuerst in der setRTC()
statt in getRTC()
sucht und aus GPIO14 als
zusätzliches Problem nicht schnell genug Saft rauskommt, um damit
das RTC-Modul mit +3.3V zu versorgen, dann geht praktisch nix und
die grauen Haare sprießen nur so...#include "rtc_eeprom.h"
#include "globals.h"
/* -------------------------------------------------------------------
* Initialisiert den ESP8266-12E zum Betrieb des RTC/EEPROM-Moduls.
*/
void RTC_EEPROM_init(void) {
pinMode(RTC_EEPROM_POWER_PIN, OUTPUT);
Wire.begin(RTC_EEPROM_SDA_PIN, RTC_EEPROM_SCL_PIN);
digitalWrite(RTC_EEPROM_POWER_PIN, LOW); // RTC aus
}
/* -------------------------------------------------------------------
* Kleine Helferchen für RTC-Funktionen.
*/
byte dec2bcd(byte val) { return((val/10*16)+(val%10)); }
byte bcd2dec(byte val) { return((val/16*10)+(val%16)); }
/* -------------------------------------------------------------------
* Liefert Datum und Uhrzeit von der RTC als time_t.
*/
time_t getRTC(void) {
tmElements_t tm;
time_t t;
digitalWrite(RTC_EEPROM_POWER_PIN, HIGH); delay(1);
Wire.beginTransmission(DS3231_ADR);
Wire.write(0); // Register(0) (Seconds)
Wire.endTransmission();
Wire.requestFrom(DS3231_ADR, 7); // 7 Byte holen
tm.Second=bcd2dec(Wire.read())&0x3F; // Seconds
tm.Minute=bcd2dec(Wire.read())&0x3F; // Minutes
tm.Hour =bcd2dec(Wire.read())&0x1F; // Hours
Wire.read(); // Day weglesen
tm.Day =bcd2dec(Wire.read())&0x1F; // Date
tm.Month =bcd2dec(Wire.read())&0x0F; // Month
tm.Year =bcd2dec(Wire.read())&0x3F; // Year
tm.Year +=2000-1970;
digitalWrite(RTC_EEPROM_POWER_PIN, LOW);
t=makeTime(tm); // time_t setzen
return(t);
}
/* -------------------------------------------------------------------
* Debug-Print der Zeit "t".
*/
void printRTC(time_t t) {
Serial.print(year(t)); Serial.print("."); Serial.print(month(t)); Serial.print("."); Serial.print(day(t)); Serial.print(" ");
Serial.print(hour(t)); Serial.print(":"); Serial.print(minute(t)); Serial.print(":"); Serial.print(second(t));
}
/* -------------------------------------------------------------------
* Stellt die RTC gemäß Parameter ein.
*/
void setRTC(byte YY, byte MM, byte DD, byte hh, byte mm, byte ss) {
digitalWrite(RTC_EEPROM_POWER_PIN, HIGH); delay(1);
Wire.beginTransmission(DS3231_ADR);
Wire.write(0);
Wire.write(dec2bcd(ss));
Wire.write(dec2bcd(mm));
Wire.write(dec2bcd(hh));
Wire.write(0);
Wire.write(dec2bcd(DD));
Wire.write(dec2bcd(MM));
Wire.write(dec2bcd(YY));
Wire.endTransmission();
digitalWrite(RTC_EEPROM_POWER_PIN, LOW);
}
/* -------------------------------------------------------------------
* Schreibt einen time_t in die RTC.
*/
void setRTC(time_t tm) {
setRTC(year(tm)-2000, month(tm), day(tm), hour(tm), minute(tm), second(tm));
}
/* -------------------------------------------------------------------
* Schreibt einen String mit Datum+Zeit in die RTC.
* Der String muss folgendes Format haben: YYYY.MM.DD hh:mm:ss
*/
void setRTC(char *datetime_str) {
// Einzelstrings aus Timestamp bauen
// 2015.10.20 19:48:08
// 01234567890123456789
// X X X X X
*(datetime_str+4)='\0';
*(datetime_str+7)='\0';
*(datetime_str+10)='\0';
*(datetime_str+13)='\0';
*(datetime_str+16)='\0';
setRTC(atoi(datetime_str)-2000, atoi(datetime_str+5), atoi(datetime_str+8),
atoi(datetime_str+11), atoi(datetime_str+14), atoi(datetime_str+17));
}
Die blau markierten Stellen waren es, die mich so aus dem Zeitplan gebracht haben.....damit sehe ich jetzt schwarz für meine Idee, die Schaltung heute noch im Heizungsraum installieren zu können.
So viel Ärger für etwas, das nur nach einem Stromausfall gebraucht wird. Und dann auch nur, wenn zusätzlich keine WLAN-Verbindung aufgebaut werden kann.
Immerhin ist die Hardware nun endgültig fertig. Das RTC-Modul sitzt auf der CPU-Platine (Vcc=GPIO14, SDA=GPIO4, SCL=GPIO5), die zwei LEDs stecken in der Gehäuse-Vorderseite, die Gehäuse-Hinterseite hat zwei Löcher zwecks Wand-Befestigung und sogar die Basis-Platine habe ich bereits am Gehäuse-Boden festgeschraubt. Es fehlen somit nur noch zwei Dübel samt Schrauben in der Wand im Heizungsraum, an denen das Gehäuse letztendlich hängen soll.
TODO: ich muss noch daran denken, bei Gelegenheit diese unsägliche Akku-Ladeschaltung vom RTC-Modul lahmzulegen.
a0 | a1 | a2 | a3 | a4 | a5 | a6 | a7 | b0 | b1 | b2 | b3 |
00:00 | 00:05 | 00:10 | 00:15 | 00:20 | 00:25 | 00:30 | 00:35 | 00:40 | 00:45 | 00:50 | 00:55 |
b4 | b5 | b6 | b7 | c0 | c1 | c2 | c3 | c4 | c5 | c6 | c7 |
01:00 | 01:05 | 01:10 | 01:15 | 01:20 | 01:25 | 01:30 | 01:35 | 01:40 | 01:45 | 01:50 | 01:55 |
Stunde | Byte |
00:XX | 00 + 01 |
01:XX | 01 + 02 |
02:XX | 03 + 04 |
03:XX | 04 + 05 |
.... | |
20:XX | 30 + 31 |
21:XX | 31 + 32 |
22:XX | 33 + 34 |
23:XX | 34 + 35 |
hour | byte_adr | bit_offset |
00 | 0 | 0 |
01 | 1 | 4 |
02 | 3 | 0 |
03 | 4 | 4 |
.... | ||
20 | 30 | 0 |
21 | 31 | 4 |
22 | 33 | 0 |
23 | 34 | 4 |
for h in range(24): for m in range(0, 59, 5): bit_full_day=h*12+(m-m%5)/5 byte_adr=bit_full_day/8 bit_num=bit_full_day-byte_adr*8 print "%02d:%02d - %03d, %02d.%d"%(h, m, bit_full_day, byte_adr, bit_num) |
00:00 - 000, 00.0 00:05 - 001, 00.1 00:10 - 002, 00.2 00:15 - 003, 00.3 00:20 - 004, 00.4 00:25 - 005, 00.5 00:30 - 006, 00.6 00:35 - 007, 00.7 00:40 - 008, 01.0 00:45 - 009, 01.1 00:50 - 010, 01.2 00:55 - 011, 01.3 01:00 - 012, 01.4 01:05 - 013, 01.5 [.....] 22:50 - 274, 34.2 22:55 - 275, 34.3 23:00 - 276, 34.4 23:05 - 277, 34.5 23:10 - 278, 34.6 23:15 - 279, 34.7 23:20 - 280, 35.0 23:25 - 281, 35.1 23:30 - 282, 35.2 23:35 - 283, 35.3 23:40 - 284, 35.4 23:45 - 285, 35.5 23:50 - 286, 35.6 23:55 - 287, 35.7 |
int getPowerOnStateForTime(time_t t) { int bit_full_day, byte_adr, bit_num; bit_full_day=hour(t)*12+(minute(t)-minute(t)%5)/5; byte_adr=bit_full_day/8; bit_num=bit_full_day-byte_adr*8; return((power_on_times_g[weekday(t)-1][byte_adr]>>bit_num)&1); } |
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import datetime
import sys
class PowerOnBitmap():
def __init__(self):
# self.power_on_times[7][36] anlegen und mit 0/AUS füllen
self.power_on_times=[[0 for x in range(36)] for y in range(7)]
# ###########################################################
# Python-Weekday kompatibel zum C-Weekday machen.
#
# datetime.weekday(): Monday is 0 and Sunday is 6
# Time.h : Day of the week (1-7), Sunday is day 1
# Py C
# Mo 0 -> 2
# Di 1 -> 3
# Mi 2 -> 4
# Do 3 -> 5
# Fr 4 -> 6
# Sa 5 -> 7
# So 6 -> 1
def __weekday_c(self, dt):
if dt.weekday()==6:
return(1)
return(dt.weekday()+2)
# ###########################################################
# bit_nr [0, ..., 7]
def __getBit(self, byte, bit_nr):
return((byte>>bit_nr)&1)
# ###########################################################
#
def getPowerOnStateForTime(self, dt):
bit_full_day=dt.hour*12+(dt.minute-dt.minute%5)/5
byte_adr=bit_full_day/8
bit_num=bit_full_day-byte_adr*8
return(self.__getBit(self.power_on_times[self.__weekday_c(dt)-1][byte_adr], bit_num))
# ###########################################################
#
def setPowerOnStateForDatetime(self, dt, state):
bit_full_day=dt.hour*12+(dt.minute-dt.minute%5)/5
byte_adr=bit_full_day/8
bit_num=bit_full_day-byte_adr*8
if state==0:
self.power_on_times[self.__weekday_c(dt)-1][byte_adr]&=((1<<bit_num)^0xff)
elif state==1:
self.power_on_times[self.__weekday_c(dt)-1][byte_adr]|=(1<<bit_num)
# ###########################################################
#
def setPowerOnStateForTime(self, weekday, hour, minute, state):
bit_full_day=hour*12+(minute-minute%5)/5
byte_adr=bit_full_day/8
bit_num=bit_full_day-byte_adr*8
if state==0:
self.power_on_times[weekday-1][byte_adr]&=((1<<bit_num)^0xff)
elif state==1:
self.power_on_times[weekday-1][byte_adr]|=(1<<bit_num)
# ###########################################################
#
def printBitmap(self):
print " ",
for i in range(0, 23, 2):
print "%02d:00 "%(i,),
print
for i in range(len(self.power_on_times)):
print "day=%d :"%(i,),
for j in range(len(self.power_on_times[i])):
print "%02x"%(self.power_on_times[i][j],),
print
# ###########################################################
#
def initDefault(self):
for wd in [2, 3, 4, 5, 6]: # Montag - Freitag
self.setPowerOnStateForTime(wd, 5, 45, 1)
self.setPowerOnStateForTime(wd, 5, 50, 1)
self.setPowerOnStateForTime(wd, 5, 55, 1)
self.setPowerOnStateForTime(wd, 6, 0, 1)
self.setPowerOnStateForTime(wd, 7, 0, 1)
self.setPowerOnStateForTime(wd, 8, 0, 1)
self.setPowerOnStateForTime(wd, 10, 0, 1)
self.setPowerOnStateForTime(wd, 13, 0, 1)
self.setPowerOnStateForTime(wd, 14, 0, 1)
self.setPowerOnStateForTime(wd, 18, 0, 1)
self.setPowerOnStateForTime(wd, 20, 0, 1)
self.setPowerOnStateForTime(wd, 21, 0, 1)
self.setPowerOnStateForTime(wd, 22, 0, 1)
self.setPowerOnStateForTime(wd, 22, 30, 1)
for wd in [1, 7]: # Sonntag, Samstag
self.setPowerOnStateForTime(wd, 6, 0, 1)
self.setPowerOnStateForTime(wd, 7, 0, 1)
self.setPowerOnStateForTime(wd, 8, 0, 1)
self.setPowerOnStateForTime(wd, 10, 0, 1)
self.setPowerOnStateForTime(wd, 13, 0, 1)
self.setPowerOnStateForTime(wd, 14, 0, 1)
self.setPowerOnStateForTime(wd, 18, 0, 1)
self.setPowerOnStateForTime(wd, 20, 0, 1)
self.setPowerOnStateForTime(wd, 21, 0, 1)
self.setPowerOnStateForTime(wd, 22, 0, 1)
self.setPowerOnStateForTime(wd, 22, 30, 1)
# ###########################################################
#
def getAsString(self):
ret_str=""
for wd in range(7):
for bp in range(36):
ret_str+=chr(self.power_on_times[wd][bp])
return(ret_str)
# ###########################################################
# Gibt einen Hexdump von "buf" in der Länge "lng" aus.
def hexdump(buf, lng):
p=0
while p<lng:
sys.stdout.write("%04X "%(p))
for i in range(min(16, (lng-p))):
sys.stdout.write("%02x "%ord(buf[p+i]))
sys.stdout.write(" ")
if (lng-p)<16:
sys.stdout.write(" "*(3*(16-(lng-p))))
for i in range(min(16, (lng-p))):
c=ord(buf[p+i])
if c>31 and c<128:
sys.stdout.write(chr(c))
else:
sys.stdout.write('.')
p+=16
print
if __name__=='__main__':
pob=PowerOnBitmap()
pob.initDefault()
pob.printBitmap()
print pob.getPowerOnStateForTime(datetime.datetime(2017, 10, 2, 6, 0))
print pob.getPowerOnStateForTime(datetime.datetime(2017, 10, 2, 12, 0))
print "---"
#for m in range(40, 60):
# print "%02d, %d"%(m, pob.getPowerOnStateForTime(datetime.datetime(2017, 10, 2, 5, m)))
bm=pob.getAsString()
hexdump(bm, len(bm))
00:00 02:00 04:00 06:00 08:00 10:00 12:00 14:00 16:00 18:00 20:00 22:00 day=0 : 00 00 00 00 00 00 00 00 00 01 10 00 01 00 00 01 00 00 00 10 00 01 00 00 00 00 00 01 00 00 01 10 00 41 00 00 day=1 : 00 00 00 00 00 00 00 00 e0 01 10 00 01 00 00 01 00 00 00 10 00 01 00 00 00 00 00 01 00 00 01 10 00 41 00 00 day=2 : 00 00 00 00 00 00 00 00 e0 01 10 00 01 00 00 01 00 00 00 10 00 01 00 00 00 00 00 01 00 00 01 10 00 41 00 00 day=3 : 00 00 00 00 00 00 00 00 e0 01 10 00 01 00 00 01 00 00 00 10 00 01 00 00 00 00 00 01 00 00 01 10 00 41 00 00 day=4 : 00 00 00 00 00 00 00 00 e0 01 10 00 01 00 00 01 00 00 00 10 00 01 00 00 00 00 00 01 00 00 01 10 00 41 00 00 day=5 : 00 00 00 00 00 00 00 00 e0 01 10 00 01 00 00 01 00 00 00 10 00 01 00 00 00 00 00 01 00 00 01 10 00 41 00 00 day=6 : 00 00 00 00 00 00 00 00 00 01 10 00 01 00 00 01 00 00 00 10 00 01 00 00 00 00 00 01 00 00 01 10 00 41 00 00 1 0 --- 0000 00 00 00 00 00 00 00 00 00 01 10 00 01 00 00 01 ................ 0010 00 00 00 10 00 01 00 00 00 00 00 01 00 00 01 10 ................ 0020 00 41 00 00 00 00 00 00 00 00 00 00 e0 01 10 00 .A.............. 0030 01 00 00 01 00 00 00 10 00 01 00 00 00 00 00 01 ................ 0040 00 00 01 10 00 41 00 00 00 00 00 00 00 00 00 00 .....A.......... 0050 e0 01 10 00 01 00 00 01 00 00 00 10 00 01 00 00 ................ 0060 00 00 00 01 00 00 01 10 00 41 00 00 00 00 00 00 .........A...... 0070 00 00 00 00 e0 01 10 00 01 00 00 01 00 00 00 10 ................ 0080 00 01 00 00 00 00 00 01 00 00 01 10 00 41 00 00 .............A.. 0090 00 00 00 00 00 00 00 00 e0 01 10 00 01 00 00 01 ................ 00A0 00 00 00 10 00 01 00 00 00 00 00 01 00 00 01 10 ................ 00B0 00 41 00 00 00 00 00 00 00 00 00 00 e0 01 10 00 .A.............. 00C0 01 00 00 01 00 00 00 10 00 01 00 00 00 00 00 01 ................ 00D0 00 00 01 10 00 41 00 00 00 00 00 00 00 00 00 00 .....A.......... 00E0 00 01 10 00 01 00 00 01 00 00 00 10 00 01 00 00 ................ 00F0 00 00 00 01 00 00 01 10 00 41 00 00 .........A.. |