Umsetzung der Funktionalität MAX Wandthermostaten

Begonnen von mickym, 11 März 2013, 00:59:24

Vorheriges Thema - Nächstes Thema

mickym

Hallo an das Forum, ich habe hier schon ein bisschen gestöbert und möchte mich mit obigem Thema kurz vorstellen.
Ich bin bzgl. Hausautomation noch ein rechter Neuling und seit ca. 1 Monat im Besitz eines MAX - System mit 3 Wandthermostaten und 5 Thermostaten, 1 Cube und 5 Fensterkontakten.
Nachdem mit der neuesten MAX Software (1.37) nun alles ganz gut funktioniert und ich von der Idee von FHEM begeistert bin, herstellerunabhängig verschiedene Systeme kombinieren zu können, wollte ich erst mal meine Konfiguration nun auch in FHEM abbilden.
Nachdem ich kein LINUX Freak bin und eher mit Windows Systemen vertraut bin, gingen erst mal ein paar Tage drauf, bis der FHEM Server nun stabil auf einer FB7170 läuft. Nun nachdem ich die Basiszusammenhänge so einigermassen verstanden habe - habe versucht ich mich mit der PERL Programmierung vertraut zu machen und nachdem die jetzige Implementierung nun funktioniert (wenn auch mit viel Probieren) glaube ich die Basisdinge verstanden zu haben.
Da ich derzeit noch keinen CUL besitze steuere ich das ganze MAX System über den Cube (MAXLAN) und werde einen CUL nur benutzen, wenn ich ihn brauche. Ausserdem sollte das MAX System nicht ausschliesslich über FHEM, sondern auch noch über die MAX Software/Portal steuerbar bleiben.
Nachdem alle Devices durch die autocreate Funktion alle problemlos definiert wurden und ich die Basisdinge konfiguriert hatte - hatte ich jedoch einige Probleme, für die ich bis jetzt keine Beschreibung fand und deshalb selbst implemtiert habe.

Folgende Probleme hatte ich zu Beginn bei Steuerung des Wandthermostaten mit FHEM:


1. Bei Ansteuerung der Wandthermostaten erfolgt die Synchronisation mit den Heizkörperthermostaten nicht korrekt - bzw. unzureichend.
Es wird anscheinend nicht die groupid verwendet, um sämtliche Befehle von FHEM korrekt mit allen Geräten in einem Zimmer zu synchronisieren. Der Cube sendet zwar etwas später die Temperatur an die Heizkörperthermostate, wenn man die Befehle an den Wandthermostaten schickt, aber der Mode funktioniert nicht korrekt.
Das heisst weder boost, noch manual oder auto funktionieren. Das heisst die gesendeten Wunschtemperaturen schalten den Wandthermostaten auf z.Bsp. manual 23.0, die Heizkörper schalten dann auf 23.0 bleiben aber auf auto. Boost wird gar nicht übertragen.
Ein "associate" zwischen Wandthermostaten und Heizkörperthermostaten funktioniert nicht. Das mag mit einem CUL gehen, ich weiss es nicht, aber sobald man das mit dem Wandthermostaten macht, kann man diesen aus der Konfig in der MAX Software schmeissen und nach einem Werksreset neu einbinden.
Ohne FHEM arbeit die Synchronisation über den Cube auch zufriedenstellend. Das heisst Änderung an Heizkörperthermostat oder Wandthermostat wird an dem CUBE übertragen, der kurz darauf die anderen Devices synchronisiert. Die Fensterkontakte sind sowieso schon direkt mit den Heizkörper und Wandthermostaten gekoppelt.
Eventuell wird das Fehler der Synchronisation mit der groupid ja noch von den Entwickler des MAXLAN Modules behoben oder angepasst, ich habe es jetzt über eine FHEM Structure gelöst, in dem zugehörige Heizkörperthermostaten und Wandthermostat zusammengefasst sind.
Das funktioniert in der Regel nun ganz gut, allerdings sollte man warten erneut Befehle zu schicken, bevor der Zustand der in der Structure zusammengefassten Geräte keinen einheitlichen Status aufweist. Das prüft nun eine Subroutine in MyUtils.
Das Verwenden der Stuctures macht natürlich die Verwendung von dummy Switches erforderlich. Dazu später noch.
Insgesamt funktioniert das Ganze nun so, dass der aktuelle Status des Raums (nicht direkt durch Definition aller Readings in der Struktur) durch Auslesen der Wandthermostats des Raums ermittelt wird und dieser den Zustand an die Dummy Switches übermittelt. Befehle weder dann an die Structure geschickt - also: Wandthermostat => Dummy Switch => Structure =>alle Geräte und somit über Wandthermostat wieder Rückmeldung and den Switch, ob Änderungen auch erfolgreich waren.
Diese Zusammenhänge habe ich unter Einhaltung bestimmter Zusammenhänge nun auch weitgehenst in dem Modul MyUtils reaisiert.
Ich habe nun pro Raum 2 Dummy Schalter definiert - obwohl über den Hauptschalter nun auch fast alle Wandthermostatfunktionen enthalten sind - ausser der Urlaubsfunktion. Das steht dann wohl als nächstes an.

2. Problem war, dass die Autofunktion nicht standardmässig implementiert ist.
Der Code zum Automodus - also desiredTemperature auto 20.0 - ist dokumentiert, aber der auto Modus sollte ja nur dann genutzt werden, wenn der auto Modus aktiv ist. Also mussten die dummy Switches entsprechend, nach aktuellem Mode Zustand des Wandthermostaten bei Temperaturänderungen diese entweder im auto oder manuellen Modus durchführen.
Aufpasen muss man hier bei Implementierung von on, off - das hier in den manuelle Modus umgeschaltet wird und das man die Ermittlung der Comfort un Eco Temperatur selbst auslesen muss, um diese einzustellen, wenn man beide Temperaturen im auto Modus einstellen möchte.
Diese ganzen Zustandsabfragen kosteten etwas Zeit, aber wurden nun ebenfalls über die Subroutine in MyUtils gelöst.


3. Problem war, dass Dummy Switches nicht so wie in der Standardimplementierung verhielten.
Die Standardimplementierung, dass der Status die IST Tempeatur - das DropDown Feld aber die aktuell eingestellte Temperatur anzeigt, finde ich sehr praktisch, hat mir aber erst Kopfzerbrechen bereitet. Nach einigem Recherchieren bin ich auch dahinter gekommen, wie das nun funktioniert und teile es kurz mit, da so nicht in der Dokumentation beschrieben.
Insgesamt ist das Verhalten aber von den Entwicklern ganz genial gelöst. ;)
Man definiert in dem DummySwitch ein Reading für temperature und desiredTemperature.
Anstelle von setList state:...........  definiert man setList desiredTemperature:......... und in webCmd desiredTemperature und schon hat man das gwünschte Ergebnis. Wird der Dummy Switch mit der Temperatur aktualisiert und das Listenfeld ist vorselektiert mit dem Wert in state.
Ähnlich funktioniert das auch mit meinem Mode Schalter.
Genial ist nun - das die Statevariable als state immer den aktuellen mode oder desiredTemperatur erhält. Nur bei Betätigung des Schalters ändern sich dann der State in desiredMode 20.0-

So ich hoffe, ich habe niemand gelangweilt. Wenn weiteres Interesse besteht, kann ich ja gerne die Detaillösung vorstellen. Bevor ich mir jedoch hier einen Wolf schreibe und es interessiert niemand, belasse ich es erst mal dabei.

Gruss Mic :)  
 

 
 




 

mickym

So nachdem gestern das Problem mit der Synchronisation über die groupid behoben wurde, benhemen sich die Thermostate schon ganz gut. Wobei ich heute wieder an mein Sendelimit gekommen bin.

Gibt es eigentlich ein Möglichkeit - wenn diese 1% Regel greift und man nichts mehr Senden kann, sich dies im Interface irgendwie anzeigen zu lassen - ohne dass man das LOG analysiert? ;)

Nachdem die Standardimplementierung der "set- Schalter" bei den Thermostaten jedoch in der Regel immer noch immer in den manuellen Modus schalten - habe ich weiter meine Dummy Schalter im Einsatz.
Ich habe noch einen 2. Dummy Schalter um nur den Mode umzuschalten - aber letzlich kann man auch alles in einem realisieren.

Die Wandthermostate - Events nehme ich zur Synchronsiation der Dummy Schalter.

Bei den SetListen - haben ich nun bei den Dummies noch die Temperaturen 4.5 und 30.5 aufgenommen - damit man bei on und off auch die richtig eingestellte Temperatur sieht und der Regeler nicht auf dem ersten Eintrag steht - da der Temperaturwert in der Liste nicht verfügbar ist.
Wie gesagt verhalten sich die dummy Schalter nun so, wie der Wandthermostat - das heisst wenn auto Modus eingestellt ist, dann kann man Temperaturen nun verstellen und werden dann bei nächsten Zeitevent wieder auf den neuen Wert automatisch gestellt. Das finde ich sehr sinnvoll, wenn man nur gerade eben mal die Temperatur anpassen will und dann evtl. vergisst, wieder auf "suto" zu schalten.
Der immer manuelle Modus ist halt dann sinnvoll, wenn man mal länger weg ist und die Zeitprogrammierung ignorieren will.
Die Temperaturen eco und comfort muss man selber auslesen vorher - da letztlich immer nur die Temperatur gesetzt wird. Will man also temporär auch eco schalten - langt nicht "desiredTemperature eco" - was dann z. Bsp in "desiredTemperature 17.0 umgesetzt wird - sondern man muss ja dann desiredTemperature auto 17.0 setzen.
Umgekehrt ist wichtig - dass man beim Setzen von 4.5 und 30.5 immer den manuellen Modus setzt und zwar rrichtig mit "desiredTemperature off oder on" und nicht die Temperaturwerte.


Ansonsten funktioniert die aktuelle Anzeige und die gesetzte Temperatur, wie in der Standardimpelemntierung, wenn man statt state - desiredTemperatur nimmt.

Alle Dummies rufen, dann eine Routine in MyUtils auf - wo dann durch Aktualisierung der Readings - der jeweilig zugehörige Master Wandthermostat ermittelt wird.

Das wars eigentlich schon.

Hier noch die Definition des Dummy Schalters:

event-on-change-reading desiredTemperature
setList desiredTemperature:auto,manual,comfort,eco,off,4.5,5.0,5.5,6.0,6.5,7.0,7.5,8.0,8.5,9.0,9.5,10.0,10.5,11.0,11.5,12.0,12.5,13.0,13.5,14.0,
14.5,15.0,15.5,16.0,16.5,17.0,17.5,18.0,18.5,19.0,19.5,20.0,20.5,21.0,21.5,22.0,22.5,23.0,23.5,24.0,24.5,25.0,25.5,26.0,26.5,27.0,27.5,28.0,28.5,29.0,29.5,30.0,30.5,on,boost

userReadings temperature {ReadingsVal("wz.Wandthermostat","temperature","n/a")},desiredTemperature {ReadingsVal("wz.Wandthermostat","desiredTemperature","n/a")}

webCmd desiredTemperature


hier mein notify Aufruf der Routine:

\w+.sw.*(mode|desiredTemperature).* {
TempControl("%NAME","%EVENT");
}


und hier die Routine selbst (Perl-Experten bitte ich um Nachsicht da Anfänger ;) - das sind so meine ersten Gehversuchen nach viel Probieren - man siehts an den LOG Einträgen ):

sub TempControl{

my ($source,$event) = @_; # as parameter only 'source' (switch) and 'event' expected - all other ignored
#source - something ends with .Temperature - means dummy switch to set desiredTemperature, containing UserReadings 'desiredTemperature'

{Log 5,"DEBUG: TempControl: Source: $source"};
{Log 5,"DEBUG: TempControl: Event: $event"};

my $masterDevice = GetMasterDEF($source); #'Call Sub to retrieve master definition

if (!defined($masterDevice)){
{Log 1,"ERROR: TempControl: No MasterDevice found!"};
return;
}

my $mode =  ReadingsVal("$masterDevice","mode","n/a");
my $desiredTemperature =  ReadingsVal("$masterDevice","desiredTemperature","n/a");

my $eventChange;
my $eventChangeTo;
if ($event =~ /(.+?)\s(.*)/){
{Log 5,"DEBUG: TempControl: eventChange $1"};
$eventChange = $1;
{Log 5,"DEBUG: TempControl: eventChangeTo $2"};
$eventChangeTo = $2;
}
else {
{Log 5,"DEBUG: TempControl: No change event found!"};
return;
}

my $cmd = "set $masterDevice desiredTemperature "; #set always desiredTemperature of masterDevice
my $minTemp = ReadingsVal($masterDevice,"minimumTemperature","4.5");
my $maxTemp = ReadingsVal($masterDevice,"maximumTemperature","30.5");

SWITCH: for($eventChange){
if (/desiredTemperature/){ #desiredTemperature should be changed
{Log 5,"DEBUG: TempControl: Testing, if desiredTemperature should be changed"};
if ($mode ne "auto") {$mode='';} else {$mode .= " ";}
for($eventChangeTo){
if(/$desiredTemperature/) {{Log 5,"DEBUG: TempControl: desiredTemperature needs not to be changed ==> No Action"};return;}
if(/boost/) {$cmd .= "boost";last SWITCH;}
if(/manual/) {$cmd .= $desiredTemperature;last SWITCH;}
if(/auto/) {$cmd .= "auto";last SWITCH;}
if(/on/) {$cmd .= "on";last SWITCH;} #always manual
if(/off/) {$cmd .= "off";last SWITCH;} #always manual
if(/eco/) {$cmd .= $mode.ReadingsVal($masterDevice,"ecoTemperature","20.0");last SWITCH;} #translation for auto eco
if(/comfort/) {$cmd .= $mode.ReadingsVal($masterDevice,"comfortTemperature","20.0");last SWITCH;} #translation for auto comfort
if(/^$minTemp/) {$cmd .= "off";last SWITCH;} #in dummy switch min temperature selectable to display correct state
if(/^$maxTemp/) {$cmd .= "on";last SWITCH;} #in dummy switch max temperature selectable to display correct state
if(/\d+.\d/) {$cmd .= $mode.$eventChangeTo;last SWITCH;}
{Log 1,"ERROR: TempControl: Unknown setting for desiredTemperature ==> No Action"};
return;
}
last SWITCH;
}

}

{Log 5,"INFO: TempControl: Sending ==>$cmd"};
fhem($cmd); #Finally send the command
}

sub GetMasterDEF{
my ($source) = @_; # as parameter only 'source' (switch) expected - all other ignored
#source - something ends with .Temperature - means dummy switch to set desiredTemperature, containing UserReadings 'desiredTemperature'

my $masterDevice;
SWITCH: for($source){ #Get real MasterDevice the Dummy Switch reads its state from
if (/Temperature/){ #Source is Dummy Temperature Switch
my $userReadings=AttrVal($source,"userReadings","n/a");
$userReadings =~ /desiredTemperature \{ReadingsVal\("(.+?)"/;
{Log 5,"DEBUG: GetMasterDEF: UserReadings: $userReadings"};
if (defined($1)){
{Log 5,"DEBUG: GetMasterDEF: Match - 1:$1\tMatch - 2:$2"};
$masterDevice = $1;
}
else {
{Log 1,"ERROR: GetMasterDEF:Masterdevice not found - check defintion of 'desiredTemperature {ReadingsVal(...!'"};
return undef;
}
last SWITCH;
}
{Log 1,"ERROR: GetMasterDEF: Unknown type of Dummy Switch!"};
return undef;
}

return $masterDevice;
}


Ich hoffe für den einen oder anderen hilfreich - weil für mich trotzdem einige Recherchearbeit drin steckte. ;)

Gruss Mic :)