Hallo zusammen,
nachdem ein Freund mit seinem out-of-the-box internetsteuerbarem Heizthermostat angibt, war es an der Zeit, meine Hausautomatisierung zu erweitern
Auch wenn ich das Gesamtkonstrukt noch nicht vorgestellt habe, stelle ich diesen Teil mal online; ich hab nämlich im Vorfeld wenig dazu im Netz gefunden.
Ursprünglich wollte ich ja fertige Funk-Thermostate steuern, aber nachdem ich zu faul war, Funkprotokolle zu analysieren und im Internet nicht richtig fündig wurde, habe ich die quick&dirty-Lösung verfolgt.
-
Billig-Thermostat von Conrad. Nicht, weil er gut wäre, er leise wäre, er schnell regeln würde, oder ich ihn besonders empfehlen könnte, sondern einfach weil die potentiellen 10€ Verlust beim ersten Basteln verkraftbar sind.
-
An die Taster-Pins rückseitig angelötete Kabel, die zum Arduino gehen.
Nachteil beim verwendeten Thermostat: ein wenig friemelig, da SMD.
Vorteil beim verwendeten Thermostat: komplett aufschraubbar, relativ geräumig, Schaltplan nachverfolgbar (nicht nur ein einziger ASIC als Siliziumklecks).
Nachdem wir 90% der Wohnung über nur eine einzelne riesige Heizung wärmen, und diese 4m vom zentralen Arduino entfernt ist, ist der Nachteil der kabelgebundenen Lösung für mich akzeptabel (wenn auch nicht absolut befriedigend).
In meinem Szenario ist die Heizung jetzt u.a. übers Ethernet-Shield steuerbar, Schaltzeiten und Verläufe werden dabei von einem externen Server vorgegeben; daher ist die Logik auf dem Arduino eher schmal.
Anbei findet Ihr das Test-Programm mit der (trivialen) Hardware-Beschaltung.
Viele Grüße, Holger
/*
* Arduino-Steuerung Heizungsthermostat HSA9001A
*
* Funktion:
* Steuerung eines Heizungsthermostates mittels emulierter Tastendrücke per Kabel
* Typ: "Heizkörperregler mit Timer HSA9001A" von Conrad
*
* Hardware:
* Die Taster "Up" und "Down" des Heizungsthermostates werden mit
* Optokopplern versehen und an zwei Pins des Arduino gehängt.
*
*
* Jeweils für hoch und runter:
* _____HCPL-817-000E
* 330 Ohm |. |
* PORT_HEAT_UP--------|=====|------|1 3|---------- Thermostat Taster Hoch 'Signal'
* | |
* Masse----------------------------|2 4|---------- Thermostat Taster Hoch 'Masse'
* |_____|
*
* Optional, wem "galvanische Trennung", "50 mA Imax am 3.3V-Pin" und "3.3V statt 3V" egal ist:
* 3.3V ---------------------------------------------- Batteriefach Plus
* Masse---------------------------------------------- Batteriefach Masse
* (Bei mir tut das (noch), aber ohne jegliche Gewähr, dass der Arduino damit nicht bei euch in Flammen aufgeht!)
*/
//Hardware
#define PORT_HEAT_UP 12
#define PORT_HEAT_DOWN 13
//temperature memory
int heatSetTemperature = 0; //Current temperature set on the module times 10 (e.g. 200 means 20.0°C)
int heatWantedTemperature = 0; //Requested temperature times 10
//recalibration
boolean heatRecalibrationMode = 0; //Current mode of operation. Used for the recalibration sequence
byte heatRecalibrationCounter = 0; //Recalibration mode 1: Number of already finished "Down" presses
/* Aus dem Handbuch:
Betriebsart MANUELL (=Werkseinstellung) Symbol:
In dieser Betriebsart regelt der Heizungsstellantrieb die Temperatur auf einen vom Anwender einstellbaren Temperatur-Schwellwert.
Durch Betätigen der Taste „UP“ bzw. „DOWN“ kann der Temperatur-Schwellwert in 0,5 Schritten erhöht bzw. erniedrigt werden.
Max. Einstellwert = 30°C, anschließend erscheint die Anzeige ON, dies bedeutet, das Ventil wird vollständig geöffnet.
Min. Einstellwert = 8°C, darunter erscheint die Anzeige OFF, dies bedeutet, das Ventil wird vollständig geschlossen.
*/
#define HEAT_DOWN_PRESSES_FOR_CALIBRATION 50 // Max 22 degree * 2 steps per degree + 2 time for turning off --> 46 should be enough
//delays
unsigned long heatLastPressMillis = 0; //millis, when button is currently pressed
unsigned long heatLastReleaseMillis = 0; //millis for the delay after a button has been pressed and released
//Delays
#define MINIMAL_HEAT_BUTTON_PRESS_TIME 200 //minimal number of ms the heating system needs for a key press
#define MINIMAL_HEAT_BUTTON_RELEASE_TIME 200 //minimal number of ms the heating system needs between two key presses
template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
//TEST PROGRAM
void setup()
{
Serial.begin(9600); // start serial port at 9600 bps:
Serial << "Start heating thermostat example\n";
Serial << "Press 0 to 9 for temperatures 20 to 29 °C\n";
Serial << "Press r for recalibration test\n";
setUpHeating();
}
void loop()
{
if (Serial.available() > 0) {
byte inByte = Serial.read();
if (inByte=='r')
{
Serial << "Recalibrate\n";
heatRecalibrate();
}
else
{
byte temp = inByte - '0'; // --> 0=0, 1=1, ...
int wanted = 200+temp*10; // --> 0=200, 1=210, ...
Serial << "Setting " << (int)(wanted) << "C\n";
heatSetTemp(wanted);
}
}
heatingManager();
delay(1);
}
//ENDE TEST
//The setup function for the thermostat
void setUpHeating()
{
digitalWrite(PORT_HEAT_UP, LOW);
pinMode( PORT_HEAT_UP, OUTPUT);
digitalWrite(PORT_HEAT_DOWN, LOW);
pinMode( PORT_HEAT_DOWN, OUTPUT);
heatSetTemp(180);
heatRecalibrate();
}
//Loop function (non-Blocking) for all heating functions
void heatingManager()
{
if (heatLastPressMillis!=0 && (millis() - heatLastPressMillis < MINIMAL_HEAT_BUTTON_PRESS_TIME))
{ //Wait while pressing a button
return;
}
if (heatLastPressMillis!=0)
{ //Release button
heatLastPressMillis=0;
heatReleaseButtons(); //heatLastReleaseMillis will be set here
return;
}
if (heatLastReleaseMillis!=0 && (millis() - heatLastReleaseMillis <MINIMAL_HEAT_BUTTON_RELEASE_TIME))
{ //Wait after releasing a button
return;
}
if (heatLastReleaseMillis!=0)
{ //We waited enough after releasing ... Now we can continue ...
heatLastReleaseMillis=0;
}
if (heatRecalibrationMode == 0) //normal mode, check for changet temperature requirements
{
if (heatWantedTemperature==0)
return;
if (heatSetTemperature < heatWantedTemperature)
heatPressUp();
if (heatSetTemperature > heatWantedTemperature)
heatPressDown();
}
else if (heatRecalibrationMode == 1) //recalibration mode phase 1 - turn off the thermostat
{
heatRecalibrationCounter ++;
if (heatRecalibrationCounter < HEAT_DOWN_PRESSES_FOR_CALIBRATION)
heatPressDown();
else
heatRecalibrationMode = 2;
}
else if (heatRecalibrationMode == 2) //recalibration mode phase 2 - turn on again
{
heatPressUp();
heatSetTemperature = 80;
heatRecalibrationMode = 0;
}
return;
}
void heatSetTemp(int tempMal10)
{
Serial << "T Set " << tempMal10 << "\n";
heatWantedTemperature = tempMal10;
}
//At startup as well as after concurrent user input, heatSetTemperature might not reflect reality
//Here we have to make sure that heatSetTemperature is correct
void heatRecalibrate()
{
/* The following (blocking code) is implemented nonblocking in the heatingManager() operation
for (int i = 0; i<(2+22*2); i++) heatPressDown(); --> turn off --> recalibrationMode = 1
moveUp(); --> turn on --> recalibrationMode = 2
while (heatSetTemperature < heatWantedTemperature) heatPressUp(); --> Set again --> recalibrationMode = 0
*/
Serial << "T Calib.\n";
heatRecalibrationMode = 1;
heatRecalibrationCounter =0;
}
void heatReleaseButtons()
{
heatLastReleaseMillis = millis();
digitalWrite(PORT_HEAT_UP, LOW);
digitalWrite(PORT_HEAT_DOWN, LOW);
}
void heatPressUp()
{
heatSetTemperature+=5;
Serial << "T+\n";
heatLastPressMillis=millis();
digitalWrite(PORT_HEAT_UP, HIGH);
}
void heatPressDown()
{
heatSetTemperature-=5;
Serial << "T-\n";
heatLastPressMillis=millis();
digitalWrite(PORT_HEAT_DOWN, HIGH);
}