Montag, 2. Januar 2017
Haussteuerung - Backup/Restore der Log-Datenbank (MariaDB)
_________________________________________________________
BACKUP der Datenbank einrichten
_________________________________________________________

1. Script backup.sh anlegen

#!/bin/bash
#
# dieses Skript kann man beliebig oft ausführen
#
# Anzahl der Sicherungen die aufgehoben werden sollen
KEEP=3
BACKUPS=`find /volume1/Backup/DBBackup/backup -name "mysqldump-*.gz" | wc -l | sed 's/\ //g'`
while [ $BACKUPS -ge $KEEP ]
do
ls -tr1 /volume1/Backup/DBBackup/mysqldump-*.gz | head -n 1 | xargs rm -f
BACKUPS=`expr $BACKUPS - 1`
done
DATE=`date +%Y%m%d%H%M%S`
rm -f /volume1/Backup/DBBackup/.mysqldump-${DATE}.gz_INPROGRESS
/usr/syno/mysql/bin/mysqldump --opt -uroot -phomer_2009 --all-databases | gzip -c -9 > /volume1/Backup/DBBackup/.mysqldump-${DATE}.gz_INPROGRESS
mv -f /volume1/Backup/DBBackup/.mysqldump-${DATE}.gz_INPROGRESS /volume1/Backup/DBBackup/mysqldump-${DATE}.gz
exit 0

2. anpassen /etc/crontab

# Jeden Tag um 5:00 h ausführen
0 5 * * * root sh /volume1/Backup/DBBackup/backup.sh

3. restart cron

synoservicecfg --restart crond

_________________________________________________________
tägliches CLEANUP der Datenbank
________________________________________________________
Da es einige Aktoren/Sensoren gibt, die sehr gesprächig sind, wo ich es bis aber zeitlich nicht geschafft habe, das in FHEM mal anzupassen, war es notwendig dafür zu sorgen, dass die Datenbank nicht so schnell ins unermessliche wächst. Die einfachste Methode dafür - einfach einmal täglich unbenutze Logeinträge per SQL zu löschen.

1. Scheduler einschalten

Dazu in etc/mysql/my.cnf unter mysqld folgendes eintragen:

event_scheduler = on

Danach Restart der DB: /usr/share/mysql/mysql.server restart

2. über phpmyadmin ein cleanup Event erstellen

CREATE EVENT cleanup_fhem

ON SCHEDULE EVERY 1 DAY

DO

delete from history where device like 'iPhone%' or device like 'iphone%' or device like 'HK.Wasch%' or device like 'st_anwe%' or (device like '%Sauna%' and device not like '%Saunag%') or device like 'HMLAN%' or device like 'E_WS%' or device like 'WS1%' or device like 'Weihna%' or device like 'Action%' or device like 'FSB14%' or device like 'Fenster%' or device like 'HM_%' or device like 'HR%' or device like 'Lampe%' or device like 'Mac%' or device like 'Stehl%' or (device = 'Zisterne' and reading <> 'level') or device like 'DS18B20%' or device = 'CCU' or device = 'CUL1' or device = 'CUL_0' or device like 'TC_TWI%' or device = 'fronthem' or device like 'TCM%' or device like 'EnO%' or device like 'Stern%' or device like '%Wasch%' or (device like 'DS2423%' and event like 'counters.B%') or device like 'Auto_Raff%' or device like 'Securasp%' or device = 'global' or device = 'OWSERVER' or device like 'Raff%' or device like 'Rasen%' or device like '%Temp'

-> Das Script ist nicht sonderlich elegant, erfüllt aber seinen Zweck. Ihr müsst über phpadmin oder ein gescheites Analysetool einfach mal Eure Logtabelle mal analysieren und die nicht benötigten Einträge identifizieren.

________________________________________________________
MYSQL - Log File für cron jobs einrichten:
________________________________________________________

mysql -u root -p fhem
SHOW PROCESSLIST\G

Datei öffnen: /etc/syslog-ng/syslog-ng.conf
folgende Zeilen hinzufügen:

destination cron { file("/var/log/cron.log"); };
filter f_cron { facility(cron); };
log { source(src); filter(f_cron); destination(cron); };

________________________________________________________
Tuning der MariaDB
________________________________________________________

in etc/mysql/my.cnf unter mysqld folgendes eintragen:

query_cache_type = 1
query_cache_limit = 256K
query_cache_min_res_unit = 2k
query_cache_size = 20M

________________________________________________________
Backup/Restore
________________________________________________________

#backup all databases in one file (eventually add the option --add-locks):
mysqldump -u username -p -–all-databases > file.sql

#backup all databases in one gzipped file:
mysqldump -u username -p -–all-databases | gzip > file.sql.gz

#restore all databases:
mysql -u username -p < file.sql




Donnerstag, 29. Dezember 2016
Haussteuerung - FHEM und instabiler Eltako Bus
Während die Heizungssteuerung sehr stabil läuft, hatte ich mit dem Eltako Bus immer mal wieder Probleme. Merkbar wurde das meistens erst, wenn man versucht hat im OG irgendwo das Licht ein- oder auszuschalten. In diesen Fällen war die schnellste Lösung der Gang zum Schaltschrank und kurz die Sicherung des Eltako Busses ausgeschaltet. Für den WAF (Woman Acceptance Factor) natürlich nicht unbedingt hilfreich.
Aber zum Glück gibt es mit dem FHEM Forum eine schier unendliche Quelle hilfreichen Wissens. Auf der Suche nach meinem Problem bin ich auf einen ähnlichen Fall gestoßen, der die Instabilitäten auf die fehlende Fehlerbehandlung im 00_TCM.pm Modul zurückführte. Da das alles plausibel klang habe ich die Änderungen ebenfalls implementiert:

Im Write-Teil ganz am Ende:

...
Log3 $name, 5, "TCM $name sent ESP: $bstring";
DevIo_SimpleWrite($hash, $bstring, 1);
# next commands will be sent with a delay
usleep(int(AttrVal($name, "sendInterval", 100)) * 1000);

my $po = $hash->{USBDev};
my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status;
my $ClearedErrorFlags = $po->reset_error;
}


im Read-Teil ganz am Ende:

...
}
$hash->{PARTIAL} = $data;

my $po = $hash->{USBDev};
my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status;
my $ClearedErrorFlags = $po->reset_error;
}

Langzeiterfahrungen poste ist später vielleicht nochmal. Vorerst hatte ich seit den Änderungen keinen Ausfall mehr, was schon sehr positiv ist. Offen ist, wo überhaupt die Fehler herkommen und wie man sie ggf. verhindern/reduzieren kann.

Für alle zukünftigen FHEM Updates müsst Ihr jetzt daran denken, die Änderungen immer wieder im 00_TCM.pm nachzuziehen, falls die nicht irgendwann standardmässig sowieso schon implementiert werden.

Nachtrag vom 02.01.2017: Seit der Umsetzung, die jetzt eine reichliche Woche zurückliegt, läuft das System erfreulicherweise äußerst stabil - Null Aussetzer - der Haussegen ist gerettet ;)



Donnerstag, 22. Dezember 2016
Haussteuerung - Waschmaschine fertig
Hier kommen wir jetzt mal wieder zu einem weiteren Beispiel der Kategorie nicht nötig aber nützlich :)
Auf der Suche nach Dingen die man automatisieren kann, bin ich auch irgendwann mal auf die Waschmaschine gekommen. Auch hier wird sich der skeptische Leser sicher wieder fragen - was soll das? Um es kurz zu machen geht es nur darum, ein Feedback zu bekommen, wenn der Waschvorgang abgeschlossen ist. Jedem ist es sicher schonmal passiert, dass er vergessen hat, die Wäsche aufzuhängen, weil er einfach nicht mehr daran gedacht hat, dass er die Waschmaschine angestellt hatte.
Da meine Waschmaschine keinen Netzwerkanschluss oder irgendeine andere Schnittstelle hat (gibt es überhaupt Geräte?), musste ein anderer Ansatz her. Die einfachste Lösung ist den Stromverbrauch zu monitoren. Damit ich das auch kann, verwende ich einen Homematic Funk-Schaltaktor 1fach mit Leistungsmessung.
Die Funktionsweise der Lösung ist recht einfach:
- steigt der Verbrauch auf > 30 Watt, was sofort eintritt, wenn die Trommel losdreht, ist das ein Zeichen dafür, dass die Waschmaschine läuft
- sinkt der Verbrauch danach für wenigstens 5 min unter 9Watt, gehe ich davon aus, dass die Waschmaschine fertig ist und sende eine Pushnachricht ans Handy, sowie gebe auch aktustisch eine Rückmeldung
- 15 min nachdem die Fertigmeldung kam, wird dann auch der Aktor und somit die Waschmaschine komplett ausgeschaltet

Und damit Ihr das Ganze jetzt noch Programmtechnisch nachvollziehen könnt, ist hier der Code dazu:

define HK.Waschmaschine CUL_HM 38B715
attr HK.Waschmaschine IODev CUL1
attr HK.Waschmaschine IOgrp CCU:CUL1
attr HK.Waschmaschine actCycle 000:10
attr HK.Waschmaschine actStatus alive
attr HK.Waschmaschine autoReadReg 4_reqStatus
attr HK.Waschmaschine expert 2_full
attr HK.Waschmaschine firmware 1.6
attr HK.Waschmaschine group 2: Geräte
attr HK.Waschmaschine model HM-ES-PMSw1-Pl
attr HK.Waschmaschine room UG.Heizungskeller
attr HK.Waschmaschine serialNr MEQ0170626
attr HK.Waschmaschine subType powerMeter
attr HK.Waschmaschine webCmd getConfig:clear msgEvents

define HK.Waschmaschine_Sw CUL_HM 38B71501
attr HK.Waschmaschine_Sw devStateIcon on:black_Steckdose.on off:black_Steckdose.off
attr HK.Waschmaschine_Sw event-on-change-reading state
attr HK.Waschmaschine_Sw group 2: Geräte
attr HK.Waschmaschine_Sw model HM-ES-PMSw1-Pl
attr HK.Waschmaschine_Sw peerIDs 00000000,
attr HK.Waschmaschine_Sw room UG.Heizungskeller
attr HK.Waschmaschine_Sw subType switch
attr HK.Waschmaschine_Sw webCmd statusRequest:toggle:on:off
define HK.Waschmaschine_Pwr CUL_HM 38B71502
attr HK.Waschmaschine_Pwr event-on-change-reading current,power
attr HK.Waschmaschine_Pwr model HM-ES-PMSw1-Pl
define HK.Waschmaschine_SenPwr CUL_HM 38B71503
attr HK.Waschmaschine_SenPwr event-on-change-reading none
attr HK.Waschmaschine_SenPwr model HM-ES-PMSw1-Pl
attr HK.Waschmaschine_SenPwr peerIDs 00000000,
define HK.Waschmaschine_SenI CUL_HM 38B71504
attr HK.Waschmaschine_SenI event-on-change-reading none
attr HK.Waschmaschine_SenI model HM-ES-PMSw1-Pl
attr HK.Waschmaschine_SenI peerIDs 00000000,
define HK.Waschmaschine_SenU CUL_HM 38B71505
attr HK.Waschmaschine_SenU event-on-change-reading none
attr HK.Waschmaschine_SenU model HM-ES-PMSw1-Pl
attr HK.Waschmaschine_SenU peerIDs 00000000,
define HK.Waschmaschine_SenF CUL_HM 38B71506
attr HK.Waschmaschine_SenF event-on-change-reading none
attr HK.Waschmaschine_SenF model HM-ES-PMSw1-Pl
attr HK.Waschmaschine_SenF peerIDs 00000000,

-> Definition der Geräte

#Dummy WaschmaschineWatt für die Anzeige des aktuellen Watt-Verbrauchs definieren
define HK.WaschmaschineWatt dummy
attr HK.WaschmaschineWatt event-on-change-reading state
attr HK.WaschmaschineWatt group 1: Automatisierung Waschmaschine
attr HK.WaschmaschineWatt room UG.Heizungskeller

#Dummy HK.WaschmaschineWatt mit Werten versorgen
define HK.WaschmaschineWattSet notify HK.Waschmaschine_Pwr {my $power =ReadingsVal("HK.Waschmaschine_Pwr","power","");; fhem ("set HK.WaschmaschineWatt $power")}
attr HK.WaschmaschineWattSet group 1: Automatisierung Waschmaschine
attr HK.WaschmaschineWattSet room UG.Heizungskeller

define HK.WaschmaschineBetrieb dummy
attr HK.WaschmaschineBetrieb event-on-change-reading state
attr HK.WaschmaschineBetrieb group 1: Automatisierung Waschmaschine
attr HK.WaschmaschineBetrieb room UG.Heizungskeller

-> Definition der Dummies

define HK.WaschmaschineBetriebCheck DOIF ([HK.Waschmaschine_Pwr:power]>30) (set HK.WaschmaschineBetrieb on) \
DOELSEIF \
([HK.Waschmaschine_Pwr:power]<9) (set HK.WaschmaschineBetrieb off, set Pushover msg 'FHEM' 'Waschmaschine ist fertig', set HM_3674FE playTone 032, setstate HK.WaschmaschineAutoOff defined, trigger HK.WaschmaschineBetrieb off)
attr HK.WaschmaschineBetriebCheck event-on-change-reading state
attr HK.WaschmaschineBetriebCheck group 1: Automatisierung Waschmaschine
attr HK.WaschmaschineBetriebCheck room UG.Heizungskeller
attr HK.WaschmaschineBetriebCheck wait 60:300

define HK.WaschmaschineAutoOff watchdog HK.WaschmaschineBetrieb:off 00:15 HK.WaschmaschineBetrieb:on {fhem("set HK.Waschmaschine_Sw off");;;;fhem("set Pushover msg 'FHEM' 'Waschmaschine wurde ausgeschaltet'")}
attr HK.WaschmaschineAutoOff group 1: Automatisierung Waschmaschine
attr HK.WaschmaschineAutoOff regexp1WontReactivate 1
attr HK.WaschmaschineAutoOff room UG.Heizungskeller

-> die Logik



Dienstag, 6. Dezember 2016
Hauststeuerung - Benachrichtigungen und Feedback
Um für uns noch einiges an Comfort zu schaffen, wollte ich vom Haus bei gewissen Aktionen aktiv benachrichtigt werden. Folgende Szenarien sind das aktuell:

- Rückmeldung, dass die Waschmaschine fertig ist per akustischem Signal und Push Nachricht auf´s Smartphone
- Benachrichtigung sobald die Sauna die Soll-Temperatur erreicht hat
- morgentlicher Wetterservice
- Statusrückmeldungen bei kritischen Events

Für die Umsetzung der Push Nachrichten verwende ich Pushover. Pushover ist ein kostenfreier Dienst, mit dem man Push Nachrichten auf sein Handy schicken kann. Apps gibt es für iOS und Android, die allerdings einmalig bezahlt werden muss. Und natürlich gibt es auch mal wieder ein Modul: PUSHOVER, welches das Einbinden in FHEM vereinfacht. Auf das Setup geh ich nicht weiter ein, das ist im Wiki sehr gut beschrieben. Ich zeige Euch nur ein paar Beispiele zur Anregung:

define Weatherforecast OPENWEATHER meinProjekt meinOrt meinAPIkey
attr Weatherforecast INTERVAL 21600
attr Weatherforecast room Wetter

define DailyWeatherNotify at *06:45 {my $TETemperatur = ReadingsVal("WS1_TEMPERATURE","state", "");; my $TERain = ReadingsVal("WS1_ISRAINING","state", "");; my $TETempmax = ReadingsVal("Weatherforecast","fc0_tempMax11", "");; my $TEWeather = ReadingsVal("Weatherforecast","fc0_weather11", "");; my $TEUnit = "°C";; system ("curl -s -F 'token=aYA4DVYTVt77Dc93JsUZXWBtaBWVXm' -F 'user=u8QsBGPTr41B5H7GupYVD4qS6W8j5S' -F 'message=aktuelles Wetter\nTemperatur $TETemperatur°C\nRegen: $TERain\nHeute: $TETempmax$TEUnit / $TEWeather' https://api.pushover.net/1/messages.json")}
attr DailyWeatherNotify room Wetter

-> mein täglicher Wetterservice, für den Forecast verwende ich Openweather

define UG.SaunaBereit DOIF ([UG.Saunaofen] eq "on" and [UG.SaunatemperaturInnen] > 79) (set Pushover msg 'FHEM' 'Sauna bereit')
attr UG.SaunaBereit disable 0
attr UG.SaunaBereit group 1: Sauna
attr UG.SaunaBereit room UG.Sauna

-> Sauna bereit:)

Für die akustische Rückmeldung ist ein HomeMatic-Funk-Gongmodul MP3 im Einsatz. Auf einer SD Karte sind verschiende Sound Samples hinterlegt, die man einfach abrufen kann:

define HM_3674FE CUL_HM 3674FE
attr HM_3674FE IODev CUL1
attr HM_3674FE IOgrp CCU:CUL1
attr HM_3674FE autoReadReg 4_reqStatus
attr HM_3674FE devStateIcon .*:audio_volume_high
attr HM_3674FE expert 2_raw
attr HM_3674FE firmware 1.0
attr HM_3674FE group 2: Benachrichtigungen
attr HM_3674FE model HM-OU-CM-PCB
attr HM_3674FE peerIDs 00000000,
attr HM_3674FE room System
attr HM_3674FE serialNr MEQ0277871
attr HM_3674FE subType outputUnit

set HM_3674FE playTone 032

Ein paar Soundfiles für den Aktor könnt Ihr hier: soundfiles (zip, 6,066 KB) runterladen.



Montag, 5. Dezember 2016
Hauststeuerung - Heizungssteuerung
Und schon sind wir bei einem der brandaktuellsten Themen angekommen. Herz unser Heizung ist ein Pellet-Kessel von Viessmann, ein Vitolig 300 VL3A. Im EG + UG haben wir damals ganz klassisch Raumtemperaturregler (Busch Jäger 1095U) verbaut, die per Bimetall und Relais die Stellmotoren im Heizkreisregler steuern. Zusätzlich gibt es eine Fernbedienung, über die alle Soll-Temperaturen und Heizzeiten eingestellt werden können. Funktionierte soweit auch.
Im OG habe ich auf die Raumtemperaturregler verzichtet, da ich ja überall meine 1 Wire Temperatursensoren verteilt habe. Als Stellantriebe im Verteiler setze ich Alpha 5 mit einer Betriebsleistung von 1 Watt ein. Gesteuert werden die Antriebe elektrisch über ein HomeMatic 8Kanal Empfangsmodul HM-MOD-Re-8 eQ-3, welches per 8fach Relais dann die Motoren schaltet. Anders als bei herkömmlichen Thermostaten gibt es nur 2 Zustände - an und aus - was eine Steuerlogik sehr vereinfacht.
In Fhem habe ich jetzt pro Raum ein virtuelles Thermostat angelegt, welches anhand der Ist Temperatur, der Soll Temperatur und der eingestellten Hysterese (vereinfacht gesagt ist das einfach ein Toleranzbereich, der Über-/Unterschritten werden kann, bevor geschaltet wird), die Relais ein- und ausschaltet.

Benötigt wird dazu ein Dummy für die Soll Temperatur des Raumes:

define OG.SZ.TempDes dummy
attr OG.SZ.TempDes group 4: Heizung
attr OG.SZ.TempDes room OG.Schlafzimmer
attr OG.SZ.TempDes setList state:20,21,22,23,24
attr OG.SZ.TempDes webCmd state

Das Reading der Ist Temperatur und das Modul Threshold:

define OG.SZ.TH THRESHOLD OG.SZ.Temp:temperature:0.2:OG.SZ.TempDes:state HM_35F8F0_Sw_03
attr OG.SZ.TH group 4: Heizung
attr OG.SZ.TH number_format %.1f
attr OG.SZ.TH room OG.Schlafzimmer
attr OG.SZ.TH setOnDeactivated cmd1_gt
attr OG.SZ.TH state_cmd1_gt off
attr OG.SZ.TH state_cmd2_lt on
attr OG.SZ.TH state_format _m _dv _sc

So, dass funktioniert also schön. Temperatur nicht erreicht - Stellmotor auf, Temperatur erreicht - Stellmotor zu. Ganz einfach oder :)

Die Probleme fingen an, als unser Monteur den zweiten Heizkreis am Kessel in Betrieb genommen hat. Mal funktionierte die Pumpe, mal nicht. Nachdem das Steuermodul getauscht wurde und ich beim Aufheizen des Estrichs quasi nur im Handbetrieb halbwegs vernünftige Temperaturen erreichen konnte, hatte ich die Nase voll. Selbst der Viessmann Kundendienst konnte nicht mehr weiter helfen und wolle anfangen, auf Verdacht Steuerplatinen und Netzteile zu tauschen - natürlich auf unsere Kosten. Aber nicht mit mir 1000€ nur für Experimente auf meinem Rücken hab ich nicht eingesehen. Also was blieb mir anderes übrig, als mich noch weiter mit der Heizung auseinanderzusetzen. Größte Herausforderung ist der Heizkreismischer, der dafür sorgt, dass entsprechend der Außentemperatur und der eingestellten Heizkurve die richtige Vorlauftemperatur eingestellt wird. Zum Glück gibt es auch andere Anwender, die sich dazu schon Gedanken gemacht haben und u.a. dafür das Modul Stellmotor entwickelt haben. Softwareseitig also halbwegs gelöst. Die Hardware ist aber auch nicht wirklich dramatisch (Bitte ggf. aber einen Fachmann ran lassen, da 230V!).
Was müssen wir tun:
- Mischermotor steuern (bei mir ähnlich einem Rolladenmotor, gibt es eine Leitung für den Rechts- und eine für den Linkslauf)
- Umwälzpumpe bedarfsgerecht ein- und ausschalten

Für das physische Schalten verwende ich die GPIOs des Raspberries und schalte damit ein Relais. Ich setze hier keine zusätzlichen Aktoren ein, da ich keine Delays haben möchte und keine Komponenten, die ggf. nicht funktionieren. Achtet bei den Relais darauf, dass diese bereits eine Sperrdiode verfügen, um den durch die Spule induzierten Strom abzufangen, sonst müsst Ihr das in Eurer Schaltung berücksichtigen. Da das Relais mit 3,3V nicht zuverlässig schaltet, verwende ich 5V und schalte das Relais per Transistor. Den Transitor deshalb, da Ihr Euch sonst die GPIOs des Raspberry zerschießt.
Folgende Bauteile werden benötigt:
- Widerstand 10kΩ
- Widerstand 2KΩ
- NPN Transistor z.B. BC548

Und so habe ich alles miteinander verdrahtet:
->>>>>>>>> Bild einfügen

Zusätzlich zu den zu schaltenden Relais brauchen wir auch wieder ein paar 1 Wire Temperatursensoren. Für die softwareseitige Umsetzung werfen wir jetzt mal alles zusammen:

define Mischer.OG.zu RPI_GPIO 18
attr Mischer.OG.zu direction output
attr Mischer.OG.zu eventMap on:1 off:0
attr Mischer.OG.zu group GPIO
attr Mischer.OG.zu poll_interval 1
attr Mischer.OG.zu room Heizung,System

define Mischer.OG.auf RPI_GPIO 17
attr Mischer.OG.auf direction output
attr Mischer.OG.auf eventMap on:1 off:0
attr Mischer.OG.auf group GPIO
attr Mischer.OG.auf poll_interval 1
attr Mischer.OG.auf room Heizung,System

-> damit ist jetzt die GPIO Steuerung für den Mischer definiert

define Heizung.OG.Pumpe RPI_GPIO 2
attr Heizung.OG.Pumpe alias Heizung.OG.Pumpe
attr Heizung.OG.Pumpe comment Pin3
attr Heizung.OG.Pumpe direction output
attr Heizung.OG.Pumpe group GPIO
attr Heizung.OG.Pumpe poll_interval 1
attr Heizung.OG.Pumpe room Heizung,System

-> damit können wir das Relais für die Pumpe ansteuern

define Heizung.OG.Mischer STELLMOTOR FhemDev
attr Heizung.OG.Mischer STMcalibrateDirection L
attr Heizung.OG.Mischer STMdebugToLog3 0
attr Heizung.OG.Mischer STMfhemDevRL Mischer.OG.auf
attr Heizung.OG.Mischer STMfhemDevSTART Mischer.OG.zu
attr Heizung.OG.Mischer STMinvertOut 0
attr Heizung.OG.Mischer STMlastDiffMax 1
attr Heizung.OG.Mischer STMmapOffCmd 0
attr Heizung.OG.Mischer STMmapOnCmd 0
attr Heizung.OG.Mischer STMmaxDriveSeconds 118
attr Heizung.OG.Mischer STMmaxTics 100
attr Heizung.OG.Mischer STMpollInterval 0.1
attr Heizung.OG.Mischer STMresetOtherDeviceAtCalibrate 0
attr Heizung.OG.Mischer STMrlType einzel
attr Heizung.OG.Mischer STMtimeTolerance 0.01
attr Heizung.OG.Mischer group Steuerung
attr Heizung.OG.Mischer room Heizung

-> Steuerung Mischermotor

define Heizung.OG.MischerCommands DOIF ([Heizung.OG.VorlaufIst:temperature.avg] < 10)\
(set Heizung.OG.Mischer 1)\
DOELSEIF ([Heizung.OG.VorlaufIst:temperature.avg] > 49)\
(set Heizung.OG.Mischer 1)\
DOELSEIF ([Heizung.OG.VorlaufIst:temperature.avg] < ([Heizung.OG.VorlaufSollClone]-10) and [Heizung.OG.Mischer:position]<97 and [Heizung.OG.Pumpe] eq "on")\
(set Heizung.OG.Mischer {([Heizung.OG.Mischer:position]+3)}) ## Cmd 3: Schnell oeffnen\
DOELSEIF ([Heizung.OG.VorlaufIst:temperature.avg] < ([Heizung.OG.VorlaufSollClone]-6) and [Heizung.OG.Mischer:position]<98 and [Heizung.OG.Pumpe] eq "on")\
(set Heizung.OG.Mischer {([Heizung.OG.Mischer:position]+2)}) ## Cmd 4: Ganz langsam oeffnen\
DOELSEIF ([Heizung.OG.VorlaufIst:temperature.avg] < ([Heizung.OG.VorlaufSollClone]-2) and [Heizung.OG.Mischer:position]<98 and [Heizung.OG.Pumpe] eq "on")\
(set Heizung.OG.Mischer {([Heizung.OG.Mischer:position]+1)}) ## Cmd 5: Noch ein bisschen\
DOELSEIF ([Heizung.OG.VorlaufIst:temperature.avg] > ([Heizung.OG.VorlaufSollClone]+5) and [Heizung.OG.Mischer:position]>3)\
(set Heizung.OG.Mischer {([Heizung.OG.Mischer:position]-2)}) ## Cmd 6: Viel zu heiss, schnell zu\
DOELSEIF ([Heizung.OG.VorlaufIst:temperature.avg] > ([Heizung.OG.VorlaufSollClone]+3) and [Heizung.OG.Mischer:position]>2)\
(set Heizung.OG.Mischer {([Heizung.OG.Mischer:position]-1)}) ## Cmd 7: Zu heiss, schnell zu\
DOELSEIF ([Heizung.OG.VorlaufIst:temperature.avg] > ([Heizung.OG.VorlaufSollClone]+1) and [Heizung.OG.Mischer:position]>2)\
(set Heizung.OG.Mischer {([Heizung.OG.Mischer:position]-1)}) ## Cmd 8: Noch ein bisschen\
DOELSEIF ([03:50])\
(set Heizung.OG.Mischer calibrate) ## Cmd 9: Calibrieren fuer Tagprogramm\
DOELSE()
attr Heizung.OG.MischerCommands cmdpause 0:0:30:60:90:60:120:180:0:0
attr Heizung.OG.MischerCommands do always
attr Heizung.OG.MischerCommands group Steuerung
attr Heizung.OG.MischerCommands room Heizung
attr Heizung.OG.MischerCommands wait 0,0,90,120,150,180,240,480,0,0

-> Logik für das Mischen der Temperatur, die ersten 2 Kommandos schließen den Mischer zur Sicherheit, wenn aus irgendeinem Grund keine Vorlauftemperatur gelesen wird bzw. der Vorlauf wegen der Schwerkraft (Wärme zirkuliert auch wenn die Pume aus ist) oder wegen der Pufferladepumpe zu heiß ist

define FHEM FHEM2FHEM 192.168.1.39:7072 LOG:Heizung.*
attr FHEM room System

-> Verbindung zur Hauptinstanz herstellen

define Heizung.OG.VorlaufSollClone cloneDummy Heizung.OG.VorlaufSoll
attr Heizung.OG.VorlaufSollClone group Temperaturen
attr Heizung.OG.VorlaufSollClone room Heizung
attr Heizung.OG.VorlaufSollClone stateFormat {sprintf(ReadingsVal("Heizung.OG.VorlaufSollClone","temperature",30))}

define Heizung.OG.PumpenanforderungClone cloneDummy Heizung.OG.Pumpenanforderung
attr Heizung.OG.PumpenanforderungClone group Steuerung
attr Heizung.OG.PumpenanforderungClone room Heizung
attr Heizung.OG.PumpenanforderungClone stateFormat {sprintf(ReadingsVal("Heizung.OG.PumpenanforderungClone","status","off"))}

-> von der Haussteuerung bekomme ich jetzt das Soll der Vorlauftemperatur und die Info, ob die Pumpe laufen soll

define Sensorencheck DOIF ([Heizung.OG.VorlaufIst:temperature] == 0) (set Pushover msg 'FHEM' 'Heizungssensoren ausgefallen - Neustart notwendig!')
attr Sensorencheck group Benachrichtigungen
attr Sensorencheck room System

-> da es alle paar Wochen mal passiert, dass der 1 Wire ausfällt, lass ich mich für den Fall per Push Nachricht auf´s Handy informieren, ich hab keine Lust, noch einen Busmaster für 1 Wire zu kaufen, damit würde das nicht mehr passieren. Aber so lange das nur 1x alle 5-6 Wochen passiert, sitz ich das aus ;)

define Heizung.OG.VorlaufIst GPIO4 28-80000026e279
attr Heizung.OG.VorlaufIst group Temperaturen
attr Heizung.OG.VorlaufIst model DS18B20
attr Heizung.OG.VorlaufIst room Heizung
attr Heizung.OG.VorlaufIst stateFormat {sprintf (ReadingsVal("Heizung.OG.VorlaufIst","temperature",0))}
attr Heizung.OG.VorlaufIst userReadings temperature.avg {movingAverage("Heizung.OG.VorlaufIst","temperature",300)}

-> die Ist Temperatur des Vorlaufs, ich verwende hier den Gleitenden Mittelwert, um ein ständiges Gegensteuern des Mischers etwas abzumildern.

sub movingAverage($$$){
my ($name,$reading,$avtime) = @_;
my $hash = $defs{$name};
my @new = my ($val,$time) = ($hash->{READINGS}{$reading}{VAL},$hash->{READINGS}{$reading}{TIME});
my ($cyear, $cmonth, $cday, $chour, $cmin, $csec) = $time =~ /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)/;
my $ctime = $csec+60*$cmin+3600*$chour;
my $num;
my $arr;
#-- initialize if requested
if( ($avtime eq "-1") ){
$hash->{READINGS}{$reading}{"history"}=undef;
}
#-- test for existence
if( !$hash->{READINGS}{$reading}{"history"}){
#Log 1,"ARRAY CREATED";
push(@{$hash->{READINGS}{$reading}{"history"}},\@new);
$num = 1;
$arr=\@{$hash->{READINGS}{$reading}{"history"}};
} else {
$num = int(@{$hash->{READINGS}{$reading}{"history"}});
$arr=\@{$hash->{READINGS}{$reading}{"history"}};
my $starttime = $arr->[0][1];
my ($syear, $smonth, $sday, $shour, $smin, $ssec) = $starttime =~ /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)/;
my $stime = $ssec+60*$smin+3600*$shour;
#-- correct for daybreak
$stime-=86400
if( $stime > $ctime);
if( ($num < 25)&&( ($ctime-$stime)<$avtime) ){
#Log 1,"ARRAY has $num elements, adding another one";
push(@{$hash->{READINGS}{$reading}{"history"}},\@new);
}else{
shift(@{$hash->{READINGS}{$reading}{"history"}});
push(@{$hash->{READINGS}{$reading}{"history"}},\@new);
}
}
#-- output and average
my $average = 0;
for(my $i=0;$i<$num;$i++){
$average+=$arr->[$i][0];
Log 4,"[$name moving average] Value = ".$arr->[$i][0]." Time = ".$arr->[$i][1];
}
$average=sprintf( "%5.3f", $average/$num);
#--average
Log 4,"[$name moving average] calculated over $num values is $average";
return $average;
}

-> Den Code müsst Ihr in Eure "99_myUtils.pm" kopieren. Zu finden bei "edit files". Falls das File noch nicht existiert, öffnet Ihr die "myUtilsTemplate.pm" und speichert sie als "99_myUtils.pm" ab.

Jetzt noch das notwendige Setup auf dem Haupt-FHEM:

define Heizung.OG.Neigung dummy
attr Heizung.OG.Neigung group 4: Heizung
attr Heizung.OG.Neigung room UG.Heizungskeller
attr Heizung.OG.Neigung setList state:0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0
attr Heizung.OG.Neigung webCmd state

define Heizung.OG.Niveau dummy
attr Heizung.OG.Niveau group 4: Heizung
attr Heizung.OG.Niveau room UG.Heizungskeller
attr Heizung.OG.Niveau setList state:0,1,2,3,4,5,6
attr Heizung.OG.Niveau webCmd state

define Heizung.OG.Verstaerkung dummy
attr Heizung.OG.Verstaerkung group 4: Heizung
attr Heizung.OG.Verstaerkung room UG.Heizungskeller
attr Heizung.OG.Verstaerkung setList state:0.0,0.5,1.0,1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0
attr Heizung.OG.Verstaerkung webCmd state

define Heizung.OG.VorlaufMin dummy
attr Heizung.OG.VorlaufMin group 4: Heizung
attr Heizung.OG.VorlaufMin room UG.Heizungskeller
attr Heizung.OG.VorlaufMin setList state:25,26,27,28,29,30
attr Heizung.OG.VorlaufMin webCmd state

define Heizung.OG.VorlaufMax dummy
attr Heizung.OG.VorlaufMax group 4: Heizung
attr Heizung.OG.VorlaufMax room UG.Heizungskeller
attr Heizung.OG.VorlaufMax setList state:45,46,47,48,49,50
attr Heizung.OG.VorlaufMax webCmd state

define Heizung.OG.VorlaufSoll dummy
attr Heizung.OG.VorlaufSoll group 4: Heizung
attr Heizung.OG.VorlaufSoll room UG.Heizungskeller
attr Heizung.OG.VorlaufSoll userReadings temperature { ReadingsVal ("Heizung.OG.VorlaufSoll", "state",30);;;;}

define Heizung.OG.VorlaufSollRefresh at +*00:10:00 { prg_Vorlauf_OG() }
attr Heizung.OG.VorlaufSollRefresh group 4: Heizung
attr Heizung.OG.VorlaufSollRefresh room UG.Heizungskeller

-> Das sind die Paramter, die ich auch am Kessel einstellen könnte. Ggf. müsst Ihr mit den Parametern etwas rumprobieren.

sub
prg_Vorlauf_OG()
{
my $steil = ReadingsVal("Heizung.OG.Neigung","state","0.4");
my $kh = ReadingsVal("Heizung.OG.Niveau","state","1");
my $verst = ReadingsVal("Heizung.OG.Verstaerkung","state","1");
my $minvl = ReadingsVal("Heizung.OG.VorlaufMin","state","25");
my $maxvl = ReadingsVal("Heizung.OG.VorlaufMax","state","50");
my $sw = ReadingsVal("OG.KZ.TempDes","state","22");
my $iw = ReadingsVal("OG.KZ.Temp","temperature","20");
my $at = ReadingsVal("E_WS1","temperature","10");

my $t1 = ($at/(320-$at*4));
my $t2 = pow($sw,$t1);
my $maxabw = $sw-$iw;

my $swhk = (((0.55)*$steil*($t2)*((-$at+20)*2)+$sw+$kh)+($maxabw*$verst));
if ($swhk < $minvl) {$swhk=$minvl};
if ($swhk > $maxvl) {$swhk=$maxvl};
$swhk = int(100*$swhk+0.5)/100;
fhem ("set Heizung.OG.VorlaufSoll $swhk");
}

-> Das ist der Code zur Berechnung der Innen- und Außentemperaturabhängigen Vorlauf Soll Temperatur.

define OG.Heizung.Sommerbetrieb dummy
attr OG.Heizung.Sommerbetrieb devStateIcon on:weather_sun off:weather_frost
attr OG.Heizung.Sommerbetrieb group 4: Heizung
attr OG.Heizung.Sommerbetrieb room UG.Heizungskeller
attr OG.Heizung.Sommerbetrieb setList on off

define Heizung.OG.Pumpenanforderung dummy
attr Heizung.OG.Pumpenanforderung group 4: Heizung
attr Heizung.OG.Pumpenanforderung room UG.Heizungskeller
attr Heizung.OG.Pumpenanforderung userReadings status { ReadingsVal ("Heizung.OG.Pumpenanforderung", "state","off");;;;}

define Heizung.OG.PumpenanforderungCommands DOIF ([+0:01] and [OG.Heizung.Sommerbetrieb] eq "off" and \
([?HM_35F8F0_Sw_06] eq "on" or \
[?HM_35F8F0_Sw_03] eq "on" or\
[?HM_35F8F0_Sw_02] eq "on"))\
(set Heizung.OG.Pumpenanforderung on) ## 6 KZ, 3 SZ, 2 Bad\
DOELSE\
(set Heizung.OG.Pumpenanforderung off)
attr Heizung.OG.PumpenanforderungCommands group 4: Heizung
attr Heizung.OG.PumpenanforderungCommands room UG.Heizungskeller

-> Mit dem dummy Sommerbetrieb, kann ich sowohl die Ansteuerung der Stellmotoren deaktivieren, als auch die Umwälzpumpe (indirekt, da die Pumpenanforderung in dem Fall nie auf "on" schaltet).

Da das Setup im Obergeschoss sehr stabil lief, habe ich kurzerhand dem Kessel auch die Kontrolle über den Heizkreis im EG/UG entzogen. Mangels 1 Wire im "Altbau" musste ich auf einen STM 330 Temperatursensor zurückgreifen. Bisher habe ich erstmal nur einen im Wohnzimmer (ca. 50€ pro Stück ist schon ziemlich heftig), aber auch damit funktioniert das Setup hervorragend. Letztendlich richtet sich somit alles nach dem Wohnzimmer. Da ich im EG/UG aber immer noch die ganz am Anfang genannten analogen Raumtemperaturregler verwende, hab ich die in den anderen Räumen etwas höher gedreht und im Wohnzimmer etwas runter. Läuft...
Die Steuerung im Kessel ist jetzt nur noch dafür verantwortlich, dass der Puffer geladen wird und Warmwasser bereit steht - sollte er ja wohl noch hinbekommen ;)

Irgendwann werd ich in den restlichen Zimmern auch noch Temperatursensoren nachrüsten. Sobald das erledigt ist, kann ich auch die Stellmotoren im EG/UG in die Haussteuerung einbinden.



Sonntag, 4. Dezember 2016
Hauststeuerung - FHEM als Basis
Für alle Komponenten, die ich einsetze brauchte ich natürlich auch eine gescheite Softwarelösung, die das alles zusammenführen und steuern kann. Nachdem ich mich mit den verschiedenen Opensource Möglichkeiten beschäftigt hatte, ist meine Wahl schlußendlich auf FHEM (Freundliche Hausautomation und Energie-Messung) gefallen. Auf den allgemeinen Teil möchte ich hier auch gar nicht weiter eingehen, den findet Ihr ausführlich im Wiki erläutert: http://fhemwiki.de
Wichtige Anlaufstelle für Support ist das Forum, dort findet Ihr jede Menge Hilfe und Beispiele, also unbedingt bookmarken: https://forum.fhem.de
Aktuell habe ich 2 Raspberry Pi mit FHEM im Einsatz. Auf dem Haupt Pi läuft die Haussteuerung, der 2. Pi ist mit dem ersten Pi per FHEM2FHEM verbunden und steuert die Mischer der Heizkreise, sowie die Heizkreispumpen.



Hauststeuerung - was funktioniert bisher
So, bevor ich mich in die Details ergehe, schreib ich Euch mal kurz auf, was ich bisher realisiert habe. Dann könnt Ihr die Seite gleich wieder schließen, wenn nix für Euch dabei ist oder Ihr lest dann gespannt weiter :)
Der Einfachheit zähle ich die Sachen einfach auf, mehr dann jeweils später:

- Steuerung aller Raffstores per Taster oder App + wettergeführte Automatik (Temperatur, Wind, Sonnenuntergang)
- Steuerung der Lichtkuppel zum Stoßlüften
- Ein-/Ausschalten der Sauna mit Rückmeldung per App, wenn die Sauna die Solltemperatur erreicht hat
- Überwachung der Waschmaschine und Rückmeldung per Audio Signal und App bei Fertigstellung des Waschgangs
- morgentliche Benachrichtigung zum aktuellen Wetter + Forcast für den Tag
- Überwachung des Wasserstands der Zisterne
- Zeit-/Lichtgesteuertes Ein-/Ausschalten der Weihnachtsbeleuchtung
- Steuerung der Stellmotoren im Heizkreisverteiler
- komplette Steuerung der Mischer für die Heizkreise und der Umwälzpumpen
- Steuerung eines Numan One Radios per Haussteuerung
- Auslesen der 1 Wire Sensoren

Noch in Planung:
- Steuerung per Siri


to be updated...



Samstag, 3. Dezember 2016
Hauststeuerung - Die Planung
Oben sollte alles besser werden, doch wo fängt man an? Ich wollte wenigstens unsere neuen Raffstores steuern, das Licht in den Räumen und ein paar Steckdosen. Eins war klar, es sollte möglichst alles per Kabel angebunden werden. Da ich bis dato nur KNX kannte, was aber sehr teuer ist, machte ich mich auf die Suche nach Alternativen.
Dabei landete ich schnell beim RS485 Bus mit Aktoren von Eltako.
Das sollte es also werden. Da ich aber gern rumspiele, wollte ich auch eine Lösung, die ich über Smartphone oder Tablet bedienen kann. Out of the Box habe ich nichts gefunden, was meinen Ansprüchen genügte, deshalb bin ich nach einiger Recherche und Tests bei FHEM gelandet, welches also zukünftig mein Haus steuern sollte.
Zusätzlich zu den Aktoren wollte ich noch einige Temperatursensoren (als 1 Wire Bus), sowie eine Wetterstation (ebenfalls Eltako) verbauen.
Nach einem Gespräch mit einem bekannten Elektriker, der mich bei dem Projekt hauptsächlich am Schaltschrank unterstützen sollte, war aber ziemlich schnell klar, dass der darauf keinen Bock hat, weil ich viel selbst machen wollte und er deshalb nicht viel verdienen würde. Naja die Enttäuschung darüber war nicht wirklich groß, mach ich halt noch mehr selbst...



Freitag, 2. Dezember 2016
Hauststeuerung - Der Anfang
Beginn meiner Passion für die Hausautomatisierung war die bevorstehende Aufstockung unseres Hauses. 2005 haben wir unser Haus gekauft, einen Flachbau über 2 Etagen, der in einen Hang gebaut wurde. Die ursprünglichen Grundmauern stammen von ca. 1840. Im Laufe der Zeit wurde das Haus mehrfach umgebaut, so dass heute nur noch ein Tonnengewölbe das wahre Alter erahnen lässt. 2006 haben wir das zum damaligen Zeitpunkt bereits komplett entkernte Haus umgebaut und saniert. Bereits da hatte ich mir Gedanken über eine Busverkabelung gemacht, diese allerdings dann aus Kostengründen und mangels Alternativen verworfen. Mit dem Wissen von heute muss ich sagen - leider. Weil soviel Mehraufwand ist das gar nicht. Aber so ist das halt. Man ist jung, unerfahren und allein das Thema Hauskauf/Hausbau bringt so viele Dinge mit sich, mit denen man sich befassen muss, dass der Teil einfach zu kurz kam.
Damit Ihr eine Vorstellung bekommt, wie es so bei uns aussieht, beschreibe ich einfach mal den Stand von damals:
Man kommt im EG in Haus rein und kann dann (durch den Hang bedingt) noch eine Etage nach unten gehen. Im EG befanden sich das Wohnzimmer mit offener Küche, das Elternschlafzimmer, ein Kinderzimmer und das Bad. Im UG haben wir einen großen Mehrzweck-/Partyraum, eine Sauna, das Arbeits-/Carrerazimmer (dazu später mehr), den Wasch- und Heizungsraum, sowie eine separates WC.

Da bedingt durch die Bauweise unser Dach über die Jahre ebenfalls sanierungsbedürftig geworden ist und wir eigentlich noch ein zusätzliches Kinderzimmer brauchten (Sauna und Carrerazimmer wollte ich nicht aufgeben ;) ), haben wir uns dazu entschlossen, unser Haus um eine weitere Etage zu erweitern.
Da mittlerweile die Technik weiter fortgeschritten war und ich berufsbedingt sowieso gern mit Technik rumspiele, wusste ich sofort - im Neubau muss alles besser werden und so begann ich mich intensiv mit dem Thema Hausautomatisierung zu beschäftigen...

Die Planung für den Neubau sah folgendes vor:

Das Elternschlafzimmer sollte nach oben verlegt werden, mit einem direkt angrenzenden offenen Badebereich, einem separaten WC, einer Dampfsauna und einem Ankleidezimmer. Zusätzlich war ein Kinderzimmer vorgesehen, sowie eine Abstellkammer/Technikraum.

Nachdem wir mit der Planung und einigen Schwierigkeiten bei der Genehmigung über fast 2 Jahre zu kämpfen hatten, konnten wir 2015 im Mai endlich mit dem Umbau beginnen. Der Rohbau (Holzständerbauweise) inkl. Fenster war im Juli dann auch soweit durch, so dass ich mit der Technik beginnen konnte...