Hier kommt der neue Code für die Heizungssteuerung.
Es steuert zwei WW-Boiler, die je nach Temperatur mit einem Dreiwege-Ventil umgeswitcht werden.
Nun ist bei 40°C und mehr der Wechsel eingerichtet, damit das Wasser nicht zu lange stehen bleibt.
#include <LiquidCrystal.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Ethernet.h>
#include <EthernetUdp.h> // für die NTP-Abfrage
#include <LCD.h>
#include <Keypad.h>
#include <Keypad_I2C.h>
#include <SPI.h>
#include <SD.h> // für die SD-Kartennutzung
#include <avr/wdt.h> // für den Watchdog vgl. (http://tushev.org/articles/arduino/item/46-arduino-and-watchdog-timer)
#include <Time.h>
// fuer das LCD
#define I2C_ADDR 0x27 // Define I2C Address where the PCF8574A is
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
// LCD Sonderzeichen definieren
uint8_t boilerwand[8] = {
0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x4};
uint8_t arrow_left[8] = {
0x4,0x4,0xc,0x1f,0xc,0x4,0x4,0x4};
uint8_t arrow_right[8] = {
0x4,0x4,0x6,0x1f,0x6,0x4,0x4,0x4};
uint8_t ecke_re[8] = {
0x0,0x0,0x0,0x7,0x4,0x4,0x4,0x4};
uint8_t ecke_li[8] = {
0x0,0x0,0x0,0x1c,0x4,0x4,0x4,0x4};
uint8_t linie[8] = {
0x0,0x0,0x0,0x1f,0x0,0x0,0x0,0x0};
uint8_t arrow_up[8] = {
0x4,0xe,0x1f,0x4,0x4,0x4,0x4};
uint8_t arrow_down[8] = {
0x4,0x4,0x4,0x4,0x1f,0xa,0x4};
uint8_t clock[8] = {
0x0,0xe,0x15,0x17,0x11,0xe,0x0};
uint8_t check[8] = {
0x0,0x1,0x3,0x16,0x1c,0x8,0x0};
uint8_t retarrow[8] = {
0x1,0x1,0x5,0x9,0x1f,0x8,0x4};
uint8_t bell[8] = {
0x4,0xe,0xe,0xe,0x1f,0x0,0x4};
// LCD Instanz
LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);
// für die SD Karte
File SD_Datei;
// für NTP
unsigned int localPort = 8888; // local port to listen for UDP packets
IPAddress timeServer(192, 168, 178, 1); // ntp nun über die eigene Fritzbox, die als Zeitserver eingestellt ist
// IPAddress timeServer(192, 53, 103, 108); // ntp1 ptb.de 192.53.103.108 Physikalisch-Technische Bundesanstalt (PTB), Braunschweig
const int timeZone = 1; // Central European Time
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
EthernetUDP Udp; // A UDP instance to let us send and receive packets over UDP
boolean zeitpaket_angefordert=false;
boolean zeitpaket_geliefert=false;
unsigned long epoch=0;
int stunde=0;
int minuten=0;
int sekunden=0;
// assign a MAC address for the ethernet controller.
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // 0xED zum Schluss ist für die Produktivversion gedacht
byte gateway[] = { 192,168,178,1};
byte subnet[] = { 255, 255, 255, 0};
IPAddress ip(192,168,178,44);// assign an IP address for the controller: // die 47 am Ende für die Produktivversion!
EthernetClient client;// initialize the library instance:
char server[] = "api.cosm.com"; //IPAddress server(216,52,233,121);
// fuer COSM - Testversion
/*#define APIKEY "XXXXXXXXXXXXXXXXX" // your cosm api key
#define FEEDID XXXX // your feed ID - Arduino Testversion 2
#define USERAGENT "Cosm Arduino Example (XXXX)" // user agent is the project name
*/
#define APIKEY "XXXXXXXXXXXXXXXXXXX" // your cosm api key
#define FEEDID XXXX // your feed ID- Arduino Testversion 1
#define USERAGENT "Heizduino (XXXX)" // user agent is the project name
unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
boolean lastConnected = false; // state of the connection last time through the main loop
const int postingInterval = 10000; //delay between updates to Pachube.com, in ms
/* Ende der Angaben für Pachube */
// für das Keypad
#define ROWS 4
#define COLS 4 // sollte 4 sein!
#define PCF8574_ADDR 0x23 // Keypad Adresse
byte rowPins[4] = {0,1,2,3}; //connect to the row pinouts of the keypad
byte colPins[4] = {4,5,6,7}; //connect to the column pinouts of the keypad
char keys[4][4]=
{
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
char key;
byte key2;
byte key_i;
// Keypad Instanz
Keypad_I2C kpd = Keypad_I2C(makeKeymap(keys),rowPins,colPins,ROWS,COLS,PCF8574_ADDR); // für das Keypad
// I2C-Adressen der angeschlossenen Geräte
#define expander_keypad 0x23 //EXPANDER address, hier mit A0 und A1 auf HIGH, Adresse des Keypads
#define expander_relais 0x20 //EXPANDER address with 3 address pins grounded, Adresse der Relaiskarte
/*
// Der PCF8574 hat die Adresse 0x20
// einer ist für das Keyboard (Adresse: 0x20)
// einer ist für das Relaismodul (Adresse: 0x21, dazu A0 kurzschliessem; INT steht die Interrupts)
// Pins 0-5 sind an die Temp-Fühler (Erdungsfarbe) angeschlossen, braun an +, blau an -
// Update: Pin 0 und 1 sind beim Ethernet-Shield für die Nutzung von SD Card gedacht und liefern daher falsche Werte, daher Umlegung auf 8-13
// 8 = 300l-Boiler oben
// 9 = 300l-Boiler unten
// 10 = 500l-Boiler oben
// 11 = 500l-Boiler unten
// 12 = Vorlauf
// 13 = Rücklauf
*/
/*
// Relaisbyte
// ACHTUNG: Relais mit +/- nicht über Arduino versorgen, sondern ext. Stromquelle anzapfen!
// Achtung: Das Relaisboard ist so konstruiert, dass die einzelnen Relais imer unter Strom sind,
// Wird das Kanal auf LOW geschaltet (GND), dann fließt Strom und das Relais schließt.
// Folge: bei 11111110 schaltet das erste Relais, die anderen bleiben aus.
//
// Bit 0 - Zusatzpumpe für die Heizungsunterstützung, falls der Vorlauf z.B. über 95 Grad steigt
// Bit 1 - Pumpe UND Zwangsventil für die Aufheizung der Warmwasser-Boiler durch die Heizung ("befüllen")
// Bit 2 - 3-Wege-Ventil für die Aufheizung: in kleinen Boiler
// Bit 3 - 3-Wege-Ventil für die Aufheizung: in großen Boiler
// Bit 4 - Umwälzpumpe UND Ventil für die Umwälzung der Wärme vom 500l-Solarboiler in den kleinen 300l-Boiler ("umwälzen")
// Bit 5 - für später
// Bit 6 - 3-Wege-Ventil für das Brauchwasser: 300l-Boiler
// Bit 7 - 3-Wege-Ventil für das Brauchwasser: 500l-Boiler
// dementsprechend werden die Relais zugeordnet!
*/
byte relais_befehls_byte; // Dieses Byte ist das Ergebnis der Überprüfung des Relais-Bytes dar. Es ist um evtl. Konflikte bereinigt
// Es ist das Ergebnis der Schaltung des Relais und das Endergebnis
byte relais_byte; // darüber werden die Methoden gesteuert,
// dieses Byte wird nach einer Kontrolle der Konsistenz an den Relaiskontroller PCF8574 als relais_befehls_byte geschickt
// Im Konfliktfall wird DIESES um das Ergebnis der Kontrollprüfung korrigert
// Es ist der SOLL-Zustand des Relais, insofern ein Zwischenergebnis
byte relais_vorschlag_byte; // Dieses Byte ist das Ergebnis der Temperaturvergleiche, ein erstes SOLL_Byte
char test[4];
char tmp[10];
char tmpp[20];
boolean arbeitsmodus=0; // Setzen des Arbeitsmodus: entweder Manuell (=1) oder Autopilot (=0)
boolean neue_temp_da=0;
const unsigned long max_millis=4294967295;
unsigned long time; // wird nach ca. X Tagen wieder auf Null gestezt
unsigned long time_letzte_temp_messung=0; // Zwischenstand für temp_erfassung_ausgabe()
unsigned long time_letzte_lcd_ausgabe=0; //
unsigned long time_letzter_lcd_reset=0; // Zwischenstände für regelmäßigen lcd_reset
unsigned long time_letzte_zeit_ausgabe=0; // Zwischenstände für regelmäßigen Zeit-Ausgabe
unsigned long time_letzte_zeitanforderung; // Zwischenstände, gebraucht für die Zeitabfrage
unsigned long letzte_zeit; // Zwischenstände, gebraucht für die Zeitabfrage
unsigned long time_d; // Zwischenstände, Arbeitsvariable
const unsigned long time_abstand_lcd_reset=600000; // 10 Minuten
const unsigned long time_abstand_lcd_ausgabe=60000; // 60 Sekunden
const unsigned long time_abstand_zeit_ausgabe=1000; // 1 Sekunde
const unsigned long time_abstand_temp_messung=10000; // 10 Sekunden
const unsigned long time_abstand_zeit_abfrage=600000; // 10 Minuten
const unsigned long time_abstand_3WV_schaltung=300000; // 5 Minuten
const unsigned long time_abstand_pumpen_schaltung=150000; // 150 Sekunden
const unsigned long time_vorgabe_3WV_abschaltung=30000; // 30 Sekunden
const unsigned long time_vorgabe_pumpen_abschaltung=3600000; // 1 Stunde
const unsigned long time_abstand_WW_boiler_wechsel=25200000; // 7 Stunden
// boolean relais3WV_switch=0;
unsigned long time_letzter_relaiswechsel[8]={
0,
0,
0,
0,
(max_millis-time_abstand_pumpen_schaltung+30000),
0,
(max_millis-time_abstand_3WV_schaltung+30000),
(max_millis-time_abstand_3WV_schaltung+30000)
}; // Zeitpunkt der letzten Schaltung der sieben Relais, gleich auf Null initiieren
const unsigned int TEMP_SENSOR_PIN[6]={8, 9, 10, 11, 12, 13}; // Pinnummern zu Temp-Sensoren zuweisen, s.o.
// unsigned int temp_3_alt=0; // Zwischenspeicher für die untere Boilertemperatur für die Feststellung des Sommers
const int Anzahl_Temp_Messungen=25; // Zahl der pro Durchgang gemachten Messungen an den Fühlern, je mehr, desto besser
// const int large_archiv_groesse=10; // Zahl der gespeicherten alten Temp-Werte, kommt später!
float TEMP_SENSOR[6]={0,1,2,3,4,5};
int TEMP_SENSOR_Reading[6][Anzahl_Temp_Messungen];
//float TEMP_SENSOR_L[6][large_archiv_groesse];
// und gleich die sechs passenden Zeiger
// int temp_pointer[6]; , kommt päter
const float max_B_temp=60; // Temperatur, die ein Boiler maximal erreichen darf, um keine Kalkablagerungen abzukriegen 60 Grad??
const float max_temp_vorlauf=85; // ab hier schaltet die Zusatzpumpe
const float hysteresis_3WV=6000;
const float zusatzpumpen_hysteresis=5; // unterschreitet die temp die max_temp_vorlauf-Temp um diesen Wert, schaltet die Zusatzpumpe aus
const float sommer_temp_solarboiler=50; // angenommene Temp im gr. Boiler unten, wenn Sommer ist
const float SUPPLY_VOLTAGE = 1.1; // Voltage für die interne Vergleichsspannung, nur beim MEGA 1,1!
const unsigned int BOUD_RATE = 38400; // Übetragungsrate zum ser. Monitor, warum nicht 9600 ... oder mehr?
// Beschreibung der String-Lib: http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html
// und http://www.robotc.net/wiki/ARDUINO_328_Functions_Strings
char temp_string[200];
char temp_a_string[200];
/* alt:
//The link:http://www.dfrobot.com/image/data/DFR0154/LiquidCrystal_I2Cv1-1.rar
//DFRobot.com
//Compatible with the Arduino IDE 1.0
//Library version:1.1
neu:
https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home
*/
#if defined(ARDUINO) && ARDUINO >= 100 // // keine Ahnung wofür
#define printByte(args) write(args);
#else
#define printByte(args) print(args,BYTE);
#endif;
void get_temperature()
{
long vol=0;
for (int i=0; i<Anzahl_Temp_Messungen; i++)
{
for (int j=0; j<=5; j++)
{
TEMP_SENSOR_Reading[j][i]=analogRead(TEMP_SENSOR_PIN[(j)]);
}
}
// nun die Mittelwert-Berechnung!
for (int i=0; i<=5; i++)
{
vol=0;
for (int j=0; j<Anzahl_Temp_Messungen; j++)
{
vol=vol+TEMP_SENSOR_Reading[i][j];
}
TEMP_SENSOR[i]=SUPPLY_VOLTAGE*vol/10.24/Anzahl_Temp_Messungen;
if (TEMP_SENSOR[i]>=99)
TEMP_SENSOR[i]=99; // Absicherung gegen unerwünschte und unrealistische Readings
if (TEMP_SENSOR[i]<=0)
TEMP_SENSOR[i]=0; // Absicherung gegen unerwünschte und unrealistische Readings, für den Fall späterer Minustemperaturen
}
}
void zeit_lcd_ausgabe()
{
if (zeitabstand_bestimmen_zum(time_letzte_zeit_ausgabe)>time_abstand_zeit_ausgabe) // erst nach Ablauf einere Sek Zeit neu ausgeben
{
unixtime_umrechnen_aktualisieren();
if(zeitpaket_angefordert==false&&zeitpaket_geliefert==true)
{
lcd.setCursor(4, 1);
//lcd.print(F("*"));
lcd.printByte(5);
}
else
{ lcd.setCursor(4, 1);
//lcd.print(F("O"));
lcd.print(F(" "));
}
lcd.setCursor(5, 1);
lcd.print(stunde);
lcd.print(F(":"));
if ( minuten < 10 )
{
// In the first 10 minutes of each hour, we'll want a leading '0'
lcd.print(F("0"));
}
lcd.print(minuten);
lcd.print(F(":"));
if ( sekunden < 10 )
{
// In the first 10 seconds of each minute, we'll want a leading '0'
lcd.print(F("0"));
}
lcd.print(sekunden);
time_letzte_zeit_ausgabe=millis();
}
}
void lcd_ausgabe()
{
// if (zeitabstand_bestimmen_zum(time_letzte_lcd_ausgabe)>time_abstand_lcd_ausgabe)
{
Serial.println(F("lcd_ausgabe!"));
//lcd.clear();
//ZEICHNUNG Boiler
for (int i=0;i<=3;i++)
{
lcd.setCursor(2, i);
//lcd.print(F("I"));
lcd.write(uint8_t(0));
}
for (int i=0;i<=3;i++)
{
lcd.setCursor(15, i);
//lcd.print(F("I"));
lcd.write(uint8_t(0));
}
// kleiner Boiler-Temperatur
lcd.setCursor(0, 0);
lcd.print(TEMP_SENSOR[0],0);
lcd.setCursor(0, 3);
lcd.print(TEMP_SENSOR[1],0);
// großer Boiler-Temperatur
lcd.setCursor(16, 0);
lcd.print(TEMP_SENSOR[2],1);
lcd.setCursor(16, 3);
lcd.print(TEMP_SENSOR[3],1);
// Vorlauf- und Rücklauf-Temperatur
lcd.setCursor(3, 3);
lcd.print(F("v"));
lcd.print(TEMP_SENSOR[4],1);
lcd.setCursor(10, 3);
lcd.print(F("r"));
lcd.print(TEMP_SENSOR[5],1);
// Relaisfunktionen: vgl. byte relais_byte
if (byte_bit_abfragen(relais_byte,0)==1)
{
lcd.setCursor(8, 3);
lcd.print(F("+"));
}
else
{
lcd.setCursor(8, 3);
lcd.print(F(" "));
}
// Umwälzung zwischen den beiden Boilern
// Umwälzen und Aufheizen findet niemals zusammen statt, daher diese Abfrage zuerst
if (byte_bit_abfragen(relais_byte,4)==1)
{
lcd.setCursor(2, 2);
//lcd.print(F("<"));
lcd.printByte(1);
for (int i=0;i<=11;i++)
{
//lcd.print(F("-"));
lcd.printByte(6);
}
//lcd.print(F(">"));
lcd.printByte(2);
}
else
{
lcd.setCursor(2, 2);
//lcd.print(F("I"));
lcd.write(uint8_t(0));
lcd.print(F(" "));
//lcd.print(F("I"));
lcd.write(uint8_t(0));
}
// Aufheizung der Boiler
if (byte_bit_abfragen(relais_byte,1)==1)
{
//Aufheizung des kl. (0) o. gr. (1) Boilers
if (byte_bit_abfragen(relais_byte,2)==1) // Aufheizung des kleinen Boilers
{
lcd.setCursor(2, 2);
//lcd.print(F("<"));
lcd.printByte(1);
for (int i=0;i<=5;i++)
{
//lcd.print(F("-"));
lcd.printByte(6);
}
//lcd.print(F("+"));
lcd.printByte(4);
lcd.print(F(" "));
//lcd.print(F("I"));
lcd.write(uint8_t(0));
}
if (byte_bit_abfragen(relais_byte,3)==1) // Aufheizung des kleinen Boilers
{
lcd.setCursor(2, 2);
//lcd.print(F("I"));
lcd.write(uint8_t(0));
lcd.print(F(" "));
//lcd.print(F("+"));
lcd.printByte(3);
for (int i=0;i<=4;i++)
{
//lcd.print(F("-"));
lcd.printByte(6);
}
//lcd.print(F(">"));
lcd.printByte(2);
}
}
else
{
}
// WW-Entnahme aus den Boilern
if (byte_bit_abfragen(relais_byte,6)==1) // Entnahme aus dem kleinen Boiler
{
lcd.setCursor(2, 0);
//lcd.print(F(">"));
lcd.printByte(2);
lcd.print(F("WW"));
lcd.setCursor(13, 0);
lcd.print(F(" "));
//lcd.print(F("I"));
lcd.write(uint8_t(0));
}
if (byte_bit_abfragen(relais_byte,7)==1) // Entnahme aus dem großen Boiler
{
lcd.setCursor(2, 0);
//lcd.print(F("I"));
lcd.write(uint8_t(0));
lcd.print(F(" "));
lcd.setCursor(13, 0);
lcd.print(F("WW"));
//lcd.print(F("<"));
lcd.printByte(1);
}
// und zum Schluss das Relais der Auffüllung zeigen, falls es auf 300 zeigt und damit umsonst arbeitet
//Entnahme aus kleinen (1) bzw. großen Boiler (0)
if (byte_bit_abfragen(relais_byte,3)==1)
{
lcd.setCursor(9, 2);
//lcd.print(F(">"));
lcd.printByte(3);
}
if (byte_bit_abfragen(relais_byte,2)==1)
{
lcd.setCursor(9, 2);
//lcd.print(F("<"));
lcd.printByte(4);
}
if (arbeitsmodus == 0)
{
lcd.setCursor(7, 0);
lcd.print(F("Auto"));
}
else
{
lcd.setCursor(7, 0);
lcd.print(F("Man "));
}
time_letzte_lcd_ausgabe=millis();
}
}
void expanderWrite(byte data)
{ // Ansteuerung der Expander-Karte
Wire.beginTransmission(expander_relais);
Wire.write(data);
Wire.endTransmission();
// lcd_init(); // um das Kaulderwelsch zu beseitigen, nicht mehr nötig
}
byte expanderRead(int i2caddr)
{
int _data = -1; // Returnwert bei Fehlern ist "-1"!! // wäre abzufangen!
Wire.requestFrom(i2caddr, 1);
if (Wire.available())
{
_data = Wire.read();
}
return _data;
}
int byte_bit_abfragen(byte by, int stelle)
{
// by=beliebiges byte, z.B. das zu sendende oder vorgeschlagene byte
// stelle startet mit 0 und geht bis 7
int bitmaske = 1 << stelle;
if ((bitmaske&by)>0)
return 1;
else
return 0;
}
byte relais_bit_setzen(byte rel_byte, unsigned int Position, boolean wert)
{
unsigned int bitmaske = 1 << Position;
byte vb=0;
if (wert==0)
{
vb=((~bitmaske)&rel_byte);
}
else
{
vb=(rel_byte|bitmaske);
}
return vb;
}
byte relais_bit_wechseln(byte vb, byte pos)
{
// Serial.println("relais_bit_wechseln!");
byte bitmask2=1<<pos;
vb=vb^bitmask2;
return vb;
}
unsigned long zeitabstand_bestimmen_zum(unsigned long zeit_var)
{
unsigned long time_diff=0;
time=millis();
if (time>=zeit_var)
{
time_diff=time-zeit_var;
}
else
{
time_diff=4294967295-zeit_var+time;
}
return time_diff;
}
void relais_byte_senden (byte vb)
{
// vb=~vb; // Das Relaisbyte muss bei den blauen vor dem Senden invertiert werden, da nur bei bit=low das Relais schaltet! (nicht so bei den SDD)
expanderWrite(vb); //... und rüberschieben zur Relaiskarte
}
void temp_archivieren(int fuehler, float temp)
{
/*Serial.println("temp_archivieren!");
TEMP_SENSOR_L[fuehler][temp_pointer[fuehler]]=temp;
if ((temp_pointer[fuehler]+1)==large_archiv_groesse)
{
temp_pointer[fuehler]=0;
}
else
{
temp_pointer[fuehler]=temp_pointer[fuehler]+1;
}
*/
}
void temp_erfassung_ausgabe()
{
if (zeitabstand_bestimmen_zum(time_letzte_temp_messung)>time_abstand_temp_messung) // wurde vor mehr als x Sek gemessen? Dann führe erneute Messung durch!
{
get_temperature();
//temp_archivieren(k,TEMP_SENSOR[k]);
time_letzte_temp_messung=millis();
// lcd_ausgabe();
neue_temp_da=1;
daten_ablegen_versenden(); // zusammenstoepseln passiert in derdem unterprg.; Daten zu Cosm schaffen
}
else
{
neue_temp_da=0;
}
}
float mittelwert_L_berechnen(int fuehler)
{
/* Serial.println("mittelwert_berechnen!");
float mittelwert=0;
for (int a=0;a<large_archiv_groesse; a++)
{
mittelwert=mittelwert+TEMP_SENSOR_L[fuehler][a];
}
return (mittelwert/large_archiv_groesse);
*/
}
char keypad_ergebnis() // Abfrage des Keypads; evtl. unnötig, wird z.Z. nicht benutzt
{
char k = kpd.getKey();
if (k != 0)
return k;
}
void temp_ausgabe_serial()
{
for (int i=0; i<=5; i++)
{
Serial.print(TEMP_SENSOR[i],1);
Serial.print(F(" ("));
// Serial.print(mittelwert_L_berechnen(i),2);
Serial.print(F(")"));
Serial.print(F(" - "));
}
Serial.print(F(" --- "));
Serial.write(itoa(relais_byte,test,10));
Serial.print(F(" --- "));
Serial.write(itoa(relais_vorschlag_byte,test,10));
Serial.println();
}
boolean sommer_feststellen()
{
if (TEMP_SENSOR[3]>sommer_temp_solarboiler)
return 1;
if (TEMP_SENSOR[3]<45)
return 0;
}
void sendData() // zu COSM
{
// this method makes a HTTP connection to the server:
// if there's a successful connection:
if (client.connect(server, 80))
{
Serial.println(F("connecting..."));
// send the HTTP PUT request:
client.print(F("PUT /v2/feeds/"));
client.print(FEEDID);
client.println(F(".csv HTTP/1.1"));
client.println(F("Host: api.pachube.com"));
client.print(F("X-PachubeApiKey: "));
client.println(APIKEY);
client.print(F("User-Agent: "));
client.println(USERAGENT);
client.print(F("Content-Length: "));
client.println(strlen(temp_string), DEC);
// last pieces of the HTTP PUT request:
client.print(F("Content-Type: text/csv\n"));
client.println(F("Connection: close\n"));
// Serial.print(F("Laenge des Strings: ")); // was kommt bei der Laenge des Contents heraus??
// Serial.println(strlen(temp_string), DEC);
// here's the actual content of the PUT request:
Serial.println(temp_string);
client.println(temp_string);
Serial.print(F("Nun der SD-Archiv-String: "));
Serial.println(temp_a_string);
// note the time that the connection was made:
lastConnectionTime = millis();
}
else
{
// if you couldn't make a connection:
Serial.println(F("connection failed"));
Serial.println();
Serial.println(F("disconnecting."));
client.stop();
}
}
void daten_ablegen_versenden()
{
// if there's incoming data from the net connection, send it out the serial port.
// This is for debugging purposes only:
while (client.available())
{
char c = client.read();
Serial.print(c);
}
// if there's no net connection, but there was one last time then stop the client:
if (!client.connected() && lastConnected)
{
Serial.println();
Serial.println(F("disconnecting.."));
client.stop();
}
// if you're not connected, and ten seconds have passed since
// your last connection, then connect again and send data:
// war: if (!client.connected() && (millis() - lastConnectionTime > postingInterval)) // soll ich das !client.connected() herausnehmen????
if (millis() - lastConnectionTime > postingInterval) // soll ich das !client.connected() herausnehmen????
{
cosm_daten_zusammenstoepseln();
sendData(); // temp_string wird verschickt
sd_karte_archivieren();
}
// store the state of the connection for next time through the loop:
lastConnected = client.connected();
}
void cosm_daten_zusammenstoepseln()
{
// Serial.println("daten_zusammenstoepseln!");
strcpy (temp_string,"sensor0"); strcat(temp_string,",");
strcat(temp_string,(dtostrf(TEMP_SENSOR[0],3,2,tmp)));
strcat(temp_string,"\n");
strcat (temp_string,"sensor1"); strcat(temp_string,",");
strcat(temp_string,(dtostrf(TEMP_SENSOR[1],3,2,tmp)));
strcat(temp_string,"\n");
strcat (temp_string,"sensor2"); strcat(temp_string,",");
strcat(temp_string,(dtostrf(TEMP_SENSOR[2],3,2,tmp)));
strcat(temp_string,"\n");
strcat (temp_string,"sensor3"); strcat(temp_string,",");
strcat(temp_string,(dtostrf(TEMP_SENSOR[3],3,2,tmp)));
strcat(temp_string,"\n");
strcat (temp_string,"sensor4"); strcat(temp_string,",");
strcat(temp_string,(dtostrf(TEMP_SENSOR[4],3,2,tmp)));
strcat(temp_string,"\n");
strcat (temp_string,"sensor5"); strcat(temp_string,",");
strcat(temp_string,(dtostrf(TEMP_SENSOR[5],3,2,tmp)));
strcat(temp_string,"\n");
strcat(temp_string,"relais0"); strcat(temp_string,",");
strcat(temp_string,(itoa(byte_bit_abfragen(relais_byte,0),test,10)));
strcat(temp_string,"\n");
strcat(temp_string,"relais1"); strcat(temp_string,",");
strcat(temp_string,(itoa(byte_bit_abfragen(relais_byte,1),test,10)));
strcat(temp_string,"\n");
strcat(temp_string,"relais2"); strcat(temp_string,",");
strcat(temp_string,(itoa(byte_bit_abfragen(relais_byte,2),test,10)));
strcat(temp_string,"\n");
strcat(temp_string,"relais3"); strcat(temp_string,",");
strcat(temp_string,(itoa(byte_bit_abfragen(relais_byte,3),test,10)));
strcat(temp_string,"\n");
strcat(temp_string,"relais4"); strcat(temp_string,",");
strcat(temp_string,(itoa(byte_bit_abfragen(relais_byte,4),test,10)));
strcat(temp_string,"\n");
strcat(temp_string,"relais6"); strcat(temp_string,",");
strcat(temp_string,(itoa(byte_bit_abfragen(relais_byte,6),test,10)));
strcat(temp_string,"\n");
strcat(temp_string,"relais7"); strcat(temp_string,",");
strcat(temp_string,(itoa(byte_bit_abfragen(relais_byte,7),test,10)));
strcat(temp_string,"\n");
strcat(temp_string,"manuell"); strcat(temp_string,",");
strcat(temp_string,(itoa(arbeitsmodus,test,10)));
strcat(temp_string,"\n");
// nun Archiv_string zusammenstoepseln
// unsigned long epoch2 = 1363644467; // ja, es geht :-)
unsigned long epoch2 = now() + (millis()-letzte_zeit) / 1000;
// war unsigned long epoch2 = epoch + (millis()-letzte_zeit) / 1000;
strcpy(temp_a_string," "); strcat(temp_a_string,(ltoa(epoch2,tmpp,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(dtostrf(TEMP_SENSOR[0],3,2,tmp)));
strcat(temp_a_string,","); strcat(temp_a_string,(dtostrf(TEMP_SENSOR[1],3,2,tmp)));
strcat(temp_a_string,","); strcat(temp_a_string,(dtostrf(TEMP_SENSOR[2],3,2,tmp)));
strcat(temp_a_string,","); strcat(temp_a_string,(dtostrf(TEMP_SENSOR[3],3,2,tmp)));
strcat(temp_a_string,","); strcat(temp_a_string,(dtostrf(TEMP_SENSOR[4],3,2,tmp)));
strcat(temp_a_string,","); strcat(temp_a_string,(dtostrf(TEMP_SENSOR[5],3,2,tmp)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(byte_bit_abfragen(relais_byte,0),test,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(byte_bit_abfragen(relais_byte,1),test,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(byte_bit_abfragen(relais_byte,2),test,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(byte_bit_abfragen(relais_byte,3),test,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(byte_bit_abfragen(relais_byte,4),test,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(byte_bit_abfragen(relais_byte,6),test,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(byte_bit_abfragen(relais_byte,7),test,10)));
strcat(temp_a_string,","); strcat(temp_a_string,(itoa(arbeitsmodus,test,10)));
}
void lcd_neuausgabe()
{
lcd_reset();
lcd_ausgabe(); // vorläufig; hier detailliertere Infos ausgeben
zeit_lcd_ausgabe();
// relais_byte_senden(relais_byte);
lcd.setCursor(3,2);
lcd.print(F("M"));
lcd.print(freeRam());
lcd.print(F("T"));
lcd.print(int(millis()/3600000));lcd.print(F(":")); lcd.print(int((millis()%3600000)/60000));
}
void lcd_reset()
{ // jede 600 Sek. = 10 Min
if (zeitabstand_bestimmen_zum(time_letzter_lcd_reset)>time_abstand_lcd_reset) // wurde vor mehr als X Min. gemessen? Dann führe erneute Messung durch!
{
lcd_hardreset();
}
}
void lcd_hardreset()
{ // jede 600 Sek. = 10 Min
lcd_init();
lcd.clear();
lcd_ausgabe();
zeit_lcd_ausgabe();
time_letzter_lcd_reset=millis();
}
void lcd_init()
{
lcd.begin(20, 4);
// lcd.init(); // initialize the lcd
// lcd.backlight();
lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
lcd.setBacklight(HIGH);
lcd.home (); // go home
lcd.createChar(0, boilerwand);
lcd.createChar(1, arrow_left);
lcd.createChar(2, arrow_right);
lcd.createChar(3, ecke_re);
lcd.createChar(4, ecke_li);
lcd.createChar(5, clock);
lcd.createChar(6, linie);
lcd.createChar(7, retarrow);
}
int freeRam()
{
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
void sd_karte_archivieren()
{
digitalWrite(10, HIGH); // deaktiviere Ethernet
digitalWrite(4, LOW); // aktiviere SD-Card
SD_Datei = SD.open("heizung.csv", FILE_WRITE); // hier ist der name der Datei auf der SD-Karte abgespeichert
if (SD_Datei)
{
Serial.print(F("Writing to FILE..."));
SD_Datei.println(temp_a_string);
// close the file:
SD_Datei.close();
Serial.println(F("done."));
}
else
{
// if the file didn't open, print an error:
Serial.println(F("error opening file on SD-card"));
}
digitalWrite(4, HIGH); // deaktiviere SD-Karte
digitalWrite(10, LOW); // aktiviere Ethernet
// vgl. http://macherzin.net/article27-Arduino-Kommunikation-Ethernet
// hier aber mit dem PIN 8, und nicht 4 - noch zu klären
}
unsigned long sendNTPpacket(IPAddress &address)
{
//send an NTP request to the time server at the given address
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer,NTP_PACKET_SIZE);
Udp.endPacket();
Serial.println(F("NTP-Paket gesendet" ));
}
void unixtime_umrechnen_aktualisieren()
{
stunde=hour()+(int)summertime_EU(year(),month(),day(),hour(),1);
minuten=minute();
sekunden=second();
}
boolean summertime_EU(int year, byte month, byte day, byte hour, byte tzHours)
// Quelle: http://forum.arduino.cc/index.php?topic=172044.msg1278536#msg1278536
// European Daylight Savings Time calculation by "jurs" for German Arduino Forum
// input parameters: "normal time" for year, month, day, hour and tzHours (0=UTC, 1=MEZ)
// return value: returns true during Daylight Saving Time, false otherwise
{
if (month<3 || month>10) return false; // keine Sommerzeit in Jan, Feb, Nov, Dez
if (month>3 && month<10) return true; // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep
if (month==3 && (hour + 24 * day)>=(1 + tzHours + 24*(31 - (5 * year /4 + 4) % 7)) || month==10 && (hour + 24 * day)<(1 + tzHours + 24*(31 - (5 * year /4 + 1) % 7)))
return true;
else
return false;
}
void zeitabfrage_ausgabe()
{
// Quelle: Sketch-Beispiel für die Zeit
if((millis()-time_letzte_zeitanforderung>100)&&(zeitpaket_angefordert==true))
{
zeitpaket_angefordert=false; // gleich den Schalter zurücksetzen
letzte_zeit=millis();
setSyncProvider(getNtpTime);
zeitpaket_geliefert=true;
}
if((zeitpaket_angefordert==false)&&(millis()-letzte_zeit>time_abstand_zeit_abfrage))
{
while (Udp.parsePacket() > 0) ; // discard any previously received packets
Serial.println(F("Transmit NTP Request"));
sendNTPpacket(timeServer);
time_letzte_zeitanforderung=millis();
zeitpaket_angefordert=true;
lcd.clear(); // regelmaessig den screen säubern
lcd_ausgabe();
zeit_lcd_ausgabe();
}
}
time_t getNtpTime()
{
uint32_t beginWait = millis();
while (millis() - beginWait < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Serial.println(F("Receive NTP Response"));
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
unsigned long secsSince1900;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
}
}
Serial.println(F("No NTP Response :-("));
return 0; // return 0 if unable to get the time
}
void relais_vorschlagsbyte_kontrollieren()
{
// Konflikte klären
if (byte_bit_abfragen(relais_vorschlag_byte,1)==1 && byte_bit_abfragen(relais_vorschlag_byte,4)==1) // Kollision zwischen Auffüllen und Umwälzen abfangen, dann nichts machen!
{
relais_vorschlag_byte=relais_byte; // das manipulierte Vorschlag-Byte auf den Ursprungswert zurücksetzen
Serial.println(F("Achtung: KOLLISION 1"));
}
if (byte_bit_abfragen(relais_vorschlag_byte,6)==1 && byte_bit_abfragen(relais_vorschlag_byte,7)==1) // Kollision
{
relais_vorschlag_byte=relais_byte; // das manipulierte Vorschlag-Byte auf den Ursprungswert zurücksetzen
Serial.println(F("Achtung: KOLLISION 2"));
}
if (byte_bit_abfragen(relais_vorschlag_byte,2)==1 && byte_bit_abfragen(relais_vorschlag_byte,3)==1) // Kollision
{
relais_vorschlag_byte=relais_byte; // das manipulierte Vorschlag-Byte auf den Ursprungswert zurücksetzen
Serial.println(F("Achtung: KOLLISION 3"));
}
/*
// Übermäßige Laufzeit beenden
if (byte_bit_abfragen(relais_vorschlag_byte,0)==1 && zeitabstand_bestimmen_zum(time_letzter_relaiswechsel[0])>time_vorgabe_pumpen_abschaltung)
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,0,0);
Serial.println("Zusatz-Pumpe nach einer Stunde ausschalten!");
}
// Die Boileraufwärmung kann mehr als eine Stunde dauern
if (byte_bit_abfragen(relais_vorschlag_byte,1)==1 && zeitabstand_bestimmen_zum(time_letzter_relaiswechsel[1])>time_vorgabe_pumpen_abschaltung)
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,0);
Serial.println("Boileraufladung nach einer Stunde ausschalten!");
}
if (byte_bit_abfragen(relais_vorschlag_byte,4)==1 && zeitabstand_bestimmen_zum(time_letzter_relaiswechsel[4])>time_vorgabe_pumpen_abschaltung)
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,4,0);
Serial.println("Boilertausch nach einer Stunde ausschalten!");
}*/
}
void relaiswechsel_zeit_ablegen()
{
for (int i=0; i<8; i++)
{
if (byte_bit_abfragen(relais_byte,i)!=byte_bit_abfragen(relais_vorschlag_byte,i))
{
time_letzter_relaiswechsel[i]=millis();
// Serial.print("Relaiswechsel: ");Serial.println(i);
}
}
}
void relaiswechsel_umsetzungsbyte_kontrollieren()
{
byte altes_relais_befehls_byte=relais_befehls_byte;
relais_befehls_byte=relais_vorschlag_byte;
/* if (byte_bit_abfragen(relais_befehls_byte,6)==1 && zeitabstand_bestimmen_zum(time_letzter_relaiswechsel[6])>time_vorgabe_3WV_abschaltung)
{
relais_befehls_byte=relais_bit_setzen(relais_befehls_byte,2,0);
}
// if (byte_bit_abfragen(altes_relais_befehls_byte,2)==0 && byte_bit_abfragen(relais_befehls_byte,2)==1 && zeitabstand_bestimmen_zum(time_letzter_relaiswechsel[2])<time_abstand_3WV_schaltung)
// {
// relais_befehls_byte=relais_bit_setzen(relais_befehls_byte,2,0);
// }
if (byte_bit_abfragen(altes_relais_befehls_byte,3)==1 && byte_bit_abfragen(relais_befehls_byte,3)==1 && zeitabstand_bestimmen_zum(time_letzter_relaiswechsel[3])>time_vorgabe_3WV_abschaltung)
{
relais_befehls_byte=relais_bit_setzen(relais_befehls_byte,3,0);
}
if (byte_bit_abfragen(altes_relais_befehls_byte,6)==1 && byte_bit_abfragen(relais_befehls_byte,6)==1 && zeitabstand_bestimmen_zum(time_letzter_relaiswechsel[6])>time_vorgabe_3WV_abschaltung)
{
relais_befehls_byte=relais_bit_setzen(relais_befehls_byte,6,0);
}
if (byte_bit_abfragen(altes_relais_befehls_byte,7)==1 && byte_bit_abfragen(relais_befehls_byte,7)==1 && zeitabstand_bestimmen_zum([7])>time_vorgabe_3WV_abschaltung)
{
relais_befehls_byte=relais_bit_setzen(relais_befehls_byte,7,0);
}
// relais_vorschlags_byte -> relais_befehls_byte
if (byte_bit_abfragen(altes_relais_befehls_byte,6)==0 && byte_bit_abfragen(relais_befehls_byte,6)==1
&& byte_bit_abfragen(altes_relais_befehls_byte,7)==1 && byte_bit_abfragen(relais_befehls_byte,7)==0)
{
relais_befehls_byte=relais_bit_setzen(relais_befehls_byte,6,0);
// relais3WV_switch=1;
}
if (byte_bit_abfragen(altes_relais_befehls_byte,6)==1 && byte_bit_abfragen(relais_befehls_byte,6)==0
&& byte_bit_abfragen(altes_relais_befehls_byte,7)==0 && byte_bit_abfragen(relais_befehls_byte,7)==1)
{
relais_befehls_byte=relais_bit_setzen(relais_befehls_byte,7,0);
// relais3WV_switch=1;
}
*/
/* relais_byte_senden(relais_befehls_byte);
if (// relais3WV_switch==1)
{
delay(1000);
// relais3WV_switch=0;
}
// Serial.print("Relaisvorschlag: "); Serial.println(relais_vorschlag_byte);
// Serial.print("Relaisstand: "); Serial.println(relais_byte);
*/
}
void setup()
{
// zum Abschalten der unbenutzten Pins
for (uint8_t pin=0; pin<69; ++pin)
{
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
}
// für die Eingänge der Temperatursensoren
pinMode(62, INPUT);
pinMode(63, INPUT);
pinMode(64, INPUT);
pinMode(65, INPUT);
pinMode(66, INPUT);
pinMode(67, INPUT);
analogReference(INTERNAL1V1); // für die 1,1V Vergleichsspannung des Mega
// Open serial communications and wait for port to open:
Serial.begin(BOUD_RATE);
delay(500);
Serial.println(F("Setup SD beginnt 1"));
// disable w5100 SPI while setting up SD
pinMode(4,OUTPUT);
// pinMode(8,OUTPUT);
pinMode(10,OUTPUT);
pinMode(53, OUTPUT); // Nur MEGA: Pin 53 fuer SD-Card
Serial.println(F("Regulaeres Setup beginnt 2"));
digitalWrite(4, LOW); // aktiviere SD-Karte
digitalWrite(10,HIGH); // deaktiviere Ethernet
if(SD.begin(4) == 0)
Serial.println(F("SD failed"));
else
Serial.println(F("SD ok"));
digitalWrite(4, HIGH); // deaktiviere SD-Karte - oder doch die 6?
digitalWrite(10, LOW); // aktiviere Ethernet
Serial.println(F("SD-Card Setup beendet"));
time_letzte_temp_messung=
time_letzter_lcd_reset=
time_letzte_zeitanforderung=
time_d=
time=
letzte_zeit=
millis(); // alle Zwischenstände beim Start auf praktisch Null setzen
// -----------------------------------------
Wire.begin(); // für den Anschluss der Expander-Karte
delay(500);
Serial.println(F("setup1 erfolgreich"));
kpd.begin(); // Keypad initialisieren
delay(500);
Serial.println(F("setup2 erfolgreich"));
//Ansteuerungs-Byte der Relaiskarte auf null setzen
relais_byte=0;
relais_byte_senden(byte(0)); // für ein Reset alles auf 0!
relais_befehls_byte=0;
//time_d=millis();
//for (int i=0; i<8;i++) time_letzter_relaiswechsel[i]=time_d;
//Serial.println(F("setup3 erfolgreich"));
lcd_init(); // initialize the lcd
lcd.clear();
lcd_ausgabe();
zeit_lcd_ausgabe();
Serial.println(F("setup4 erfolgreich"));
// start the Ethernet connection:
if (Ethernet.begin(mac) == 0)
// Ethernet.begin(mac, ip, gateway, subnet); // starte Ethernet! verbaucht weniger platz
// delay(1000); // warten auf Ethernet
{
delay(1500);
Serial.println(F("Failed to configure Ethernet using DHCP"));
// DHCP failed, so use a fixed IP address:
Ethernet.begin(mac, ip, gateway, subnet);
delay(1500);
}
Serial.println(F("Success to configure Ethernet using DHCP"));
Udp.begin(localPort);// für UDP
delay(250);
Serial.println(F("setup5 erfolgreich"));
Serial.println(F("Success with whole setup"));
// zum Schluss den Watchdog aktivieren! Totzeitraum max. 8 Sek zum Reset
wdt_enable(WDTO_8S);
}
void loop()
{
wdt_reset(); // Reset des Watchdogs
lcd_reset(); // gegen die ewigen LCD-Probleme :-)
relais_vorschlag_byte=relais_byte;
temp_erfassung_ausgabe(); // wird nur jede X Sek wirklich durchgeführt
zeitabfrage_ausgabe();
zeit_lcd_ausgabe();
key=0;
key=kpd.getKey(); // neu, war: key=keypad_ergebnis();
if (key!=0 || neue_temp_da==1)
{
if (key=='A') { arbeitsmodus=0; lcd_reset(); lcd_ausgabe(); }
if (key=='B') { arbeitsmodus=1; lcd_reset(); lcd_ausgabe(); }
if (key=='C') { lcd_hardreset(); }
if (key=='D') { lcd_neuausgabe(); } // RESET des LCD und der Relaiskarte
if (arbeitsmodus==1) // MANUELL
{
if (key=='0' || key=='1' || key=='2' || key=='3' || key=='4' || key=='6' || key=='7')
{
key2=key-48; // den ASCII-Key umrechnen
relais_vorschlag_byte=relais_bit_wechseln(relais_vorschlag_byte, key2);
}
else
{
if (key=='A' || key=='B' || key=='C' || key=='D' || key==0 )
{
// zulässige Eingaben ausschliessen
}
else
{
lcd.clear(); // Fehlermeldung("Falsche Taste")
lcd.setCursor(0, 1); lcd.print(F(" NUR 0,1,2, "));
lcd.setCursor(0, 2); lcd.print(F("3,4,6,7,A,B,C,D"));
delay(1000); // obwohl es ein Delay ist, ist es gerade hier richtig
lcd.clear();
lcd_ausgabe(); // aktuellen Zustand am LCD erneut anzeigen
zeit_lcd_ausgabe();
}
}
}
if (arbeitsmodus==0) // AUTOPILOT
{
// Serial.print("gesetzt auf autopilot\n"); // gesetzt auf manuell
// Ausgabe des Displays
/*if (key=='D') // Reset des LCD und der Relaiskarte
{
lcd_neuausgabe();
}*/
// Prüfung der Vorlauftemperatur, um evtl. die Zusatzpumpe anzuwerfen
if (TEMP_SENSOR[4]>=max_temp_vorlauf) // falls Temp Vorlauf zu hoch, die Zusatzpumpe einschalten!
{
// Serial.print("Temp Vorlauf >= Temp B o !!");
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,0,1);
}
else
{
// Serial.print("Temp Vorlauf <= Temp B o !!");
if (TEMP_SENSOR[4]<=(max_temp_vorlauf-zusatzpumpen_hysteresis))
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,0,0);
}
}
// Boilerauswahl Warmwasser
if (zeitabstand_bestimmen_zum(time_letzter_relaiswechsel[6]) > time_abstand_3WV_schaltung
&& zeitabstand_bestimmen_zum(time_letzter_relaiswechsel[7]) > time_abstand_3WV_schaltung)
{
if (byte_bit_abfragen(relais_byte,6)==0 && byte_bit_abfragen(relais_byte,7)==0) // für den Start, wenn alle Bits auf 0 gesetzt sind
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,6,0); // ... grossen Boiler als WW-Quelle auswählen
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,7,1); // ... grossen Boiler als WW-Quelle auswählen
}
if (TEMP_SENSOR[0]>40)
{
if (zeitabstand_bestimmen_zum(time_letzter_relaiswechsel[6]) > time_abstand_WW_boiler_wechsel)
{
if(byte_bit_abfragen(relais_byte,6)==1) // Prüfung, ob WW gerade vom kleiner Boiler kommt
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,6,0); // ... grossen Boiler als WW-Quelle auswählen
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,7,1); // ... grossen Boiler als WW-Quelle auswählen
}
else
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,6,1); // ... kleinen Boiler als WW-Quelle auswählen
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,7,0); // ... kleinen Boiler als WW-Quelle auswählen
}
}
else
{
// braucht man nicht, da keine Veränderung des Vorschlagbytes
// relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,6,byte_bit_abfragen(relais_byte,6)); // auf bisherige Werte setzen
// relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,7,byte_bit_abfragen(relais_byte,7)); // auf bisherige Werte setzen
}
}
else
{
if (TEMP_SENSOR[2]>TEMP_SENSOR[0]) // Großer Boiler wärmer als der kleine ...
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,6,0); //... kleinen Boiler als WW-Quelle abwählen
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,7,1); //... großen Boiler als WW-Quelle auswählen
}
else // ... nein, der kleine Boiler ist wärmer
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,6,1); // ... kleinen Boiler als WW-Quelle auswählen
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,7,0); // ... kleinen Boiler als WW-Quelle auswählen
}
}
}
// Umwälzung der Boiler im Sommer
if (zeitabstand_bestimmen_zum(time_letzter_relaiswechsel[4]) > time_abstand_pumpen_schaltung)
{
if (byte_bit_abfragen(relais_byte,4)==0) // falls Boileraustausch nicht stattfindet (==0)
{
if ((sommer_feststellen()==1) && //Festlegung, wann es zur Umwälzung kommen soll: Falls Sommer und ...
((TEMP_SENSOR[2]-TEMP_SENSOR[1])>10) && //Temp.Differenz zwischen großen und kleinen Boiler >10 Grad und ...
(TEMP_SENSOR[2]>max_B_temp) && //Temp-Gr-Boiler > max. zulässige Temp und ...
(TEMP_SENSOR[0]<=60)) //Temp-Kl-Boiler <= max. zulässige Temp und ...
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,0); // Befüllung stoppen (falls sowoeso nicht gestoppt!)
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,4,1); // Umwälzung zw den Boilern beginnen
}
}
if (byte_bit_abfragen(relais_byte,4)==1) // falls Boileraustausch stattfindet (==0)
{
if ((sommer_feststellen()==0) ||
((TEMP_SENSOR[2]-TEMP_SENSOR[1])<5) || // falls Temp-Differenz zw. Gr-Boiler und Kl-Boiler unter 5 Grad fällt oder...
(TEMP_SENSOR[2]<=50)) // || // falls Temp Gr-Boiler unter 45 Grad fällt oder ...
//TEMP_SENSOR[0]>max_B_temp) // falls Temp Kl-Boiler größer als max zulässige Boiler-Temp
// Festlegung, wann die Umwälzung aufhören soll! Sommer_feststellen wohl nicht erforderlich :-)
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,4,0); // Umwälzung zw den Boilern stoppen
}
}
}
// Aufheizung der Boiler im Winter
if(byte_bit_abfragen(relais_byte,1)==1) // Prüfung, ob der Boiler gerade aufgeladen wird
{
// Serial.print("Die Aufheizung des Boilers laeuft.\n"); // Eine Meldung ausgeben
if (key=='#') // wenn Heizung manuell als Ziel ausgewählt wird
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,0); // Auffüllen des Boilers beenden, Relais schließen
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,2,0); // dazu das Aufladungsrelais in den Ruhezustand schalten
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,3,0); // dazu das Aufladungsrelais in den Ruhezustand schalten
}
if (byte_bit_abfragen(relais_byte,2)==1 && TEMP_SENSOR[0]>max_B_temp) // falls die Temp des gerade befüllten kleinen Boilers oben größer als erlaubte Temp ...
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,0); // ... die Befüllung des Boilers beenden
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,2,0); // auch das 3WV-Relais in den Ruhezustand schalten
// Serial.print("Aufheizung des Boilers wird gleich unterbrochen werden, da die Temperatur des Boilers inzwischen groesser als erlaubt ist!\n");Serial.print(TEMP_SENSOR[(2-Heizung_3WV*2),2]);
// evtl. später eine entsprechende LCD-Meldung einbauen
// temp_ausgabe_serial();
}
if (byte_bit_abfragen(relais_byte,3)==1 && TEMP_SENSOR[2]>max_B_temp) // falls die Temp des gerade befüllten großen Boilers oben größer als erlaubte Temp ...
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,0); // ... die Befüllung des Boilers beenden
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,3,0); // auch das 3WV-Relais in den Ruhezustand schalten
}
if (byte_bit_abfragen(relais_byte,2)==1 && TEMP_SENSOR[4]<(TEMP_SENSOR[0]+3)) // Vorlauf um 3 Grad kleiner als Temperatur des geschalteten Boilers oben?
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,0); // ... die Befüllung des Boilers beenden
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,2,0); // auch das 3WV-Relais in den Ruhezustand schalten
}
if (byte_bit_abfragen(relais_byte,3)==1 && TEMP_SENSOR[4]<(TEMP_SENSOR[2]+3)) // Vorlauf um 3 Grad kleiner als Temperatur des geschalteten Boilers oben?
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,0); // ... die Befüllung des Boilers beenden
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,3,0); // auch das 3WV-Relais in den Ruhezustand schalten
}
}
else // falls der Boiler gerade nicht aufgeladen wird
{
// Serial.print("Die Aufheizung des Boilers findet nicht statt\n"); // Eine Meldung ausgeben
if (key=='#') // wenn Heizung als Ziel ausgewählt wird
{
// Serial.print("Sie haben # ausgewaehlt, Heizung ist jedoch bereits als Ziel ausgewaehlt\n"); // Eine Meldung ausgeben
// temp_ausgabe_serial();
}
if (key=='*') // wenn Boiler als Ziel ausgewählt wird
{
if ((TEMP_SENSOR[2]<=max_B_temp)&&((TEMP_SENSOR[2]+2)<TEMP_SENSOR[4])) // 500l-Boiler-Temp kleiner als max.Temp und kleiner als Vorlauf-Temp
{
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,2,0); // das 3WV in 300l-Boiler-Richtung aus!
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,3,1); // auch das 3WV-Relais in 500l-Richtung schalten
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,1); // ... die Befüllung des Boilers beginnen
// Serial.print("Sie haben * ausgewaehlt, max. Temp des gr. Boilers ist noch nicht erreicht und der Vorlauf ist fuer den gr. Boiler warm genug, also wird der gr. Boiler aufgeladen\n"); // Eine Meldung ausgeben
// temp_ausgabe_serial();
}
else // falls Boiler befüllt werden soll und Gr-Boiler warm genug ODER der Vorlauf reicht zum Erwärmen des großen Boilers nicht aus
{
// Serial.print("Sie haben * ausgewaehlt, max. Temp des gr. Boilers ist bereits erreicht oder der Vorlauf ist fuer den gr. Boiler nicht warm genug (evtl. aber fuer den 300l-Boiler)\n"); // Eine Meldung ausgeben
if ((TEMP_SENSOR[0]<=max_B_temp)&&((TEMP_SENSOR[0]+2)<TEMP_SENSOR[4])) // 300l-Boiler-Temp kleiner als max.Temp und kleiner als Vorlauf-Temp
{
// Serial.print("Sie haben * ausgewaehlt, max. Temp des kl. Boilers ist noch nicht erreicht und der Vorlauf ist fuer den kl. Boiler warm genug, also wird der kl. Boiler aufgeladen\n"); // Eine Meldung ausgeben
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,2,1); // das Relais zum 300l-Boiler schalten
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,3,0); // das Relais in 500l-Richtung ausschalten
relais_vorschlag_byte=relais_bit_setzen(relais_vorschlag_byte,1,1); // ... die Befüllung des (kleinen) Boilers beginnen
// temp_ausgabe_serial();
}
else
{
// Serial.print("Sie haben * ausgewaehlt, max. Temp auch des kl. Boilers ist bereits erreicht oder der Vorlauf ist fuer den kl. Boiler nicht warm genug, also wird auch er nicht aufgeladen\n"); // Eine Meldung ausgeben
// temp_ausgabe_serial();
}
}
}
}
} // Hier endet der Anweisungsblock für den Arbeitsmodus = 0 (autopilot)
} // Ende der Verarbeitungsschleife, wenn key != 0
relais_vorschlagsbyte_kontrollieren();
if (relais_byte!=relais_vorschlag_byte)
{
relaiswechsel_zeit_ablegen();
relais_byte=relais_vorschlag_byte;
lcd_ausgabe();
}
if (neue_temp_da==1)
{
lcd_ausgabe();
}
relais_byte_senden(relais_byte);
} // Ende der loop-Funktion
Keine Kommentare:
Kommentar veröffentlichen