Hallo liebe Freunde der Hausautomatisierung,
für lange eingeschaltete und Lasten bei 2kW bietet sich ein 16A Stromstoßrelais an, sowie weil man dieses auch zur Not manuell im Verteilerschank schalten kann. Den Nachteil, dass das Relais mit einem Impuls ein- sowie ausgeschalten wird und FHEM damit den Zustand wechseln kann, aber den aktuellen Schaltzustand nicht kennt, habe ich durch ein zweikanaliges Finder Stromstroßrelais gelöst, sodass am ersten Kanal über einen Input der Zustand abgefragt wird und am zweiten Kanal die eigentliche Last geschalten wird.
Gesteuern/Ausgelesen wird über 1-wire und zweier DS2408. Dh. mit dem ersten DS2408 (Sensor) frage ich den Zustand des Relais mit sensed.0 ab und am zweiten DS2408 (Relais) sende ich einen Schaltimpuls auf PIO.0 zum Wechsel von on auf off und umgekehrt.
Und jetzt stehe ich an. Mit welchen Elemente (zB. readingsProxy, dummy) kann man jetzt die beiden Einzelkanäle elegant zu einem schaltbaren Element zusammenfassen.
Folgendes habe ich mittels eines readingsProxy versucht:
DEF Sensor:sensed.0
attr setFn {
my $cur = ReadingsVal("Sensor","sensed.0",0);
if ((($CMD eq "on") && ($cur == 1)) || (($CMD eq "off") && ($cur == 0))) {
fhem("set Relais PIO.0 11");
sleep 1 ;
fhem("set Relais PIO.0 10"); }
}
..funktioniert aber leider nicht.
Zitat von: vallant am 19 Februar 2017, 14:33:08
..funktioniert aber leider nicht.
Kannst Du uns erhellen, was nicht funktioniert?
Ich bekomme die Fehlermeldung:
"Unknown argument on, choose one of interval LCD_H/clear LCD_H/home LCD_H/message LCD_H/onoff LCD_H/screen LCD_H/screenyc LCD_M/clear LCD_M/home LCD_M/message LCD_M/onoff LCD_M/screen LCD_M/screenyc PIO.0 PIO.1 PIO.2 PIO.3 PIO.4 PIO.5 PIO.6 PIO.7 PIO.ALL PIO.BYTE latch.0 latch.1 latch.2 latch.3 latch.4 latch.5 latch.6 latch.7 latch.ALL latch.BYTE por set_alarm strobe"
Danke viegener für deine Unterstützung!
Es scheint das grundsätzliche Problem zu sein, dass der Steuerkanal eben nicht on oder off ist, sondern ständig off, bis auf die eine Sekunde on des Zustandswechsels. Gibt es ein verwendbares Element/Modul welches diese T-Flipflop-Charakteristik abbildet? Im Ergebnis wäre ein Element, welches on:off verstehen würde optimal.
Annahme 1 - ich nehme an setList hast Du gesetzt? - Korrekt?
Generell müsste ja das Ergebnis Deiner setFn ein Ausdruck sein, der an das target device (also Sensor) weitergeleitet wird. Das passiert in Deiner setFn schonmal nicht. Dann wird wahrscheinlich der Originalwert weitergeleitet (Vermutung !).
Annahme 2: Du hast zwei 1-Wire devices einer heisst Sensor (gibt den Schlatzustand wieder) und einer heisst Rellais (mit dem wird das Relais geschaltet) - so entnehme ich das den verschiedenen Codes hier. - Korrekt ?
Weitere Annahme (3) - Du hast die Befehle set Relais PIO.0 11 etc ausprobiert und sie schalten das Relais? - Korrekt?
Anmerkung - Deinn Sleep hält das gesamte FHEm an (der ist blocking) und damit ein grundsätzliches Probelm
Problem 2 - Du musst in der setFn ja einen Befehl an Dein One-wire-Sensor-Device weitergeben, der braucht aber eigentlich gar keinen set-Befehl?
Was passiert denn wenn Du folgendes machst:
attr setFn {
my $cur = ReadingsVal("Sensor","sensed.0",0);
if ((($CMD eq "on") && ($cur == 1)) || (($CMD eq "off") && ($cur == 0))) {
fhem("set Relais PIO.0 11; sleep 1; set Relais PIO.0 10");
}
}
return "interval 10"
ad A1: setList = "on off"
ad A2/3: ja genau so
ad Anmerkung) Gibt es da eine Alternative? Ist die Funktion "on-for-time 1" blocking
ad P2) Würde der notwendige set-Befehl mit einem (Device-unabhängigen) Dummy-Element entfallen? Kann man sonst irgendwie geräteunabhängig ein on,sleep,off absetzen?
ad Code) Liefert leider die idente Meldung:
"Unknown argument on, choose one of interval LCD_H/clear LCD_H/home LCD_H/message LCD_H/onoff LCD_H/screen LCD_H/screenyc LCD_M/clear LCD_M/home LCD_M/message LCD_M/onoff LCD_M/screen LCD_M/screenyc PIO.0 PIO.1 PIO.2 PIO.3 PIO.4 PIO.5 PIO.6 PIO.7 PIO.ALL PIO.BYTE latch.0 latch.1 latch.2 latch.3 latch.4 latch.5 latch.6 latch.7 latch.ALL latch.BYTE por set_alarm strobe"
Hi,
mir ist das hier alles etwas kompliziert. Kann man denn nicht einfach das Device "Relais" zum Schalten nehmen und an das Device "Sensor" ein notify hängen, dass mit setreading ein neues Reading ins Device "Relais" setzt, das den tatsächlichen Schaltzustand anzeigt?
Also in etwa so:
define blabla notify Sensor:sensed.* setreading Relais schaltzustand $EVENT
Gruß,
Thorsten
Zitat von: vallant am 19 Februar 2017, 17:09:13
ad A1: setList = "on off"
ad A2/3: ja genau so
ad Anmerkung) Gibt es da eine Alternative? Ist die Funktion "on-for-time 1" blocking
ad P2) Würde der notwendige set-Befehl mit einem (Device-unabhängigen) Dummy-Element entfallen? Kann man sonst irgendwie geräteunabhängig ein on,sleep,off absetzen?
ad Code) Liefert leider die idente Meldung:
"Unknown argument on, choose one of interval LCD_H/clear LCD_H/home LCD_H/message LCD_H/onoff LCD_H/screen LCD_H/screenyc LCD_M/clear LCD_M/home LCD_M/message LCD_M/onoff LCD_M/screen LCD_M/screenyc PIO.0 PIO.1 PIO.2 PIO.3 PIO.4 PIO.5 PIO.6 PIO.7 PIO.ALL PIO.BYTE latch.0 latch.1 latch.2 latch.3 latch.4 latch.5 latch.6 latch.7 latch.ALL latch.BYTE por set_alarm strobe"
Irgendwas ist mit Deinen settings so nicht in Ordnung. Generell sollte der Ansatz so ja funktionieren, denn Dein Readingsproxy sollte ja korrekt den Schaltzustand wiedergeben und die Befehle sollten nur an das Relais durchgereicht werden.
kannst Du mal einen "list" von Deinem Readingsproxy machen und das Ergebnis in code tags hier posten.
Ausserdem wäre es vielleicht mal interessant zu schauen, ob da noch was anderes im log auftaucht, wenn die am Readingsproxy und an den anderen beiden Devices mal verbose auf 5 setzt.
Zitat von: Thorsten Pferdekaemper am 19 Februar 2017, 17:28:48
Hi,
mir ist das hier alles etwas kompliziert. Kann man denn nicht einfach das Device "Relais" zum Schalten nehmen und an das Device "Sensor" ein notify hängen, dass mit setreading ein neues Reading ins Device "Relais" setzt, das den tatsächlichen Schaltzustand anzeigt?
Also in etwa so:
define blabla notify Sensor:sensed.* setreading Relais schaltzustand $EVENT
Gruß,
Thorsten
Das Problem ist ja nicht den Schaltzustand zu erkennen das erfolgt ja im Sensor, sondern dass Einschalten des Stroms heisst das Relais erst auf on und dann sofort wieder auf off zu setzen (also sozusagen einen Taster zu simulieren). Das ginge auch mit einem Befehl "on-for-timer" aber das eigentliche Problem ist ja, dass hier die setFn nicht richtig läuft..
Ach so...
Ja dann dürfte das ursprüngliche Problem daran liegen, dass die setFn einen Rückgabewert haben muss, der ein erlaubtes "set"-Kommando ergibt.
Müsste es dann nicht in etwa so gehen (unter der Annahme, dass das readingsProxy zum Relais gehört):
attr setFn {
my $cur = ReadingsVal("Sensor","sensed.0",0);
if ((($CMD eq "on") && ($cur == 1)) || (($CMD eq "off") && ($cur == 0))) {
fhem("set Relais PIO.0 11; sleep 1");
}
}
return "PIO.0 10";
...oder aber ein notify auf Relais.PIO.0 (wenn das geht), das ein at erzeugt, dass das Ding nach 1 Sekunde oder so wieder abschaltet.
Gruß,
Thorsten
@Thorsten: Ja so ähnlich, deshalb hatte ich den zweiten Ansatz gepostet, der am Ende:
return "interval 10"
sendet.
Allerdings kommt danach immer noch "Unknown argument on... das passt nicht, denn es wird ja eigentlich kein "on" mehr weitergeleitet, deshalb hatte ich vermutet, dass etwas anderes gerade nicht passt
Hallo viegener,
Klammerfehler, das "return()" war bereits außerhalb des "}"-Blocks, ich bekomme jetzt: "new interval is equal to old interval.", dh das Kommando wird an das Device darunter durchgereicht. Habe jetzt eines gefunden - hoffentlich ohne Auswirkungen: por (power on reset) ist true bei Neustart und meldet sich dann bei einem full-bus-scan und sollte dann auf false gehen und bleiben. Weist du noch eine Lösung für das blocking beim sleep? Habe einfach den Impuls mal auf ein min reduziert auf 300ms, ist aber keine Lösung des Problems.
Gesamtlösung funktioniert jetzt wie folgt:
Erster DS2408 "Relais" für 12V Relais-Output:
Internals:
DEF 29.D61909000000 1
IODev iBUS
NAME Relais
STATE sensed.0: 1 sensed.1: 1 sensed.2: 1 sensed.3: 1 sensed.4: 1 sensed.5: 1 sensed.6: 1 sensed.7: 1 alarm: 0
TYPE OWDevice
Fhem:
address 29.D61909000000
alerting 1
bus bus.0
interfaces state
interval 1
Attributes:
IODev iBUS
group Relais
model DS2408
polls sensed.0,sensed.1,sensed.2,sensed.3,sensed.4,sensed.5,sensed.6,sensed.7
Zweiter DS2408 "Sensor" für Rückkanal am Stromstoßrelais:
Internals:
DEF 29.B73009000000 1
IODev iBUS
NAME Sensor
STATE sensed.0: 1 sensed.1: 0 sensed.2: n/a sensed.3: n/a sensed.4: n/a sensed.5: n/a sensed.6: n/a sensed.7: n/a alarm: 0
TYPE OWDevice
Fhem:
address 29.B73009000000
alerting 1
bus bus.0
interfaces state
interval 1
Attributes:
IODev iBUS
group Relais
model DS2408
polls latch.4,sensed.0,sensed.1
Device für das Stromstoßrelais am PIO.0:
Internals:
DEF Sensor:sensed.0
DEVICE Sensor
NAME Licht0
READING sensed.0
STATE on
TYPE readingsProxy
Content:
Sensor 1
Attributes:
setFn {
my $cur = ReadingsVal("Sensor","sensed.0",0);
if ((($CMD eq "on") && ($cur == 0)) || (($CMD eq "off") && ($cur == 1)) || ($CMD eq "toggle") ) {
fhem("set Relais PIO.0 11");
sleep 0.3 ;
fhem("set Relais PIO.0 10");
}
return "por 0"
}
setList on off toggle
valueFn {($VALUE == 1)?"on":"off"}
webCmd on:off:toggle
Damit ist das SSRelais mit on, off und toggle bedienbar.
Will man es mit einem Taster an der Wand (ebenfalls am Sensor Kanal 4) toggeln fügt man folgendes hinzu:
Device für den Taster "White" am Kanal 4 des Sensor:
Das Gerät muss latch.4 abfragen und nicht sensed.4, da der Taster nur wenige ms am DS2408 durch das Drücken des Tasters das sensed.4 auf high gibt. Hierfür hat DalSemi das Alarming für die einzelnen Kanäle einführt und durch kurzes high-tasten geht latch.4 high und bleibt bis zum bewussten low-setzen (set senWhite reset) dort, dh. wenn das Stromstoßrelais fertig geschalten hat.
Internals:
DEF Sensor:latch.4
DEVICE Sensor
NAME senWhite
NR 42
NTFY_ORDER 50-senWhite
READING latch.4
STATE off
TYPE readingsProxy
Attributes:
group Sensors
room Büro
setFn { if ($CMD eq "reset") { "latch.4 10" } }
setList reset
valueFn {($VALUE == 0)?"off":"on"}
webCmd reset
Notify verbindet senWhite mit Licht0:
Wird der Taster gedrückt geht Sensor:latch.0 auf 1, löst das Notify aus, dieses toggelt das SSRelais und resetet das Sensor:latch.4 auf 0. Auch wenn viele Taster im Haus gleichzeitig gedrückt werden, wird damit kein Event "vergessen".
Internals:
CFGFN
DEF senWhite.on set Licht0 toggle ; set senWhite reset
NAME onWhite
REGEXP senWhite.on
TYPE notify
Attributes:
group Sensors
Bleibt nur zu hoffen, dass meine 80 Stk. DS2408 (für Taster) im Haus vom darunter liegenden OWFS in unter 1sek ausgelesen werden können. Länger warten auf das Licht bei betreten eines Raumes wäre mau.
Danke nochmals viegener!
@Thorsten:
readingProxy Licht0 hängt auf Sensor um den Status des Rückkanals abfragen zu können. Aber das return("PIO.0 10") ist die saubere Lösung statt por, da am Sensor der Steuerausgang bei Beschaltung als Eingang naturgemäß ohnedies 0 sein muss. Das mit "at" schaue ich mir genauer an, ob es etwas 300ms schalten kann. Das SSRelais nimmt etwa 90mA vom Bus wenn der Magnet anzieht, die Zeit ist demnach bei vielen Geräten schon relevant - ist aber die Lösung für das Blocking des sleep().
Hi,
das at kann wahrscheinlich nur minimal 1 Sekunde. Es gibt aber noch die Funktion InternalTimer, die Du vielleicht verwenden kannst. Die kann auch Millisekunden.
Gruß,
Thorsten
@vallant: Die Lösung beim sleep ist eigentlich ganz einfach, wie oben bereits im ersten Vorschlag:
Zitatfhem("set Relais PIO.0 11; sleep 1; set Relais PIO.0 10");
Wenn der sleep in einer FHEM-Befehlssequenz auftaucht, wird er das System nicht blockieren.
Dann ist es ein FHEM-Sleep und kein perl-sleep -> das findest Du auch in der commandref
...außerdem geht mit sleep auch 300ms:
Zitat
The unit is seconds, with millisecond accuracy, as you can specify decimal places.
Ich glaube, dass am Ende "return undef" das richtige wäre. Die setFn handelt ja schon alles ab und laut Commandref scheint mir das zu sagen "tue (ansonsten) nichts".
Gruß,
Thorsten
Zitat von: Thorsten Pferdekaemper am 20 Februar 2017, 07:39:09
...außerdem geht mit sleep auch 300ms:Ich glaube, dass am Ende "return undef" das richtige wäre. Die setFn handelt ja schon alles ab und laut Commandref scheint mir das zu sagen "tue (ansonsten) nichts".
Gruß,
Thorsten
Ja das ist auch im Modulcode so implementiert, mich hatte nur verwundert, dass es ohne return nicht funktioniert. Ich hätte angenommen, dass das einem "return undef" entspricht.
Also soillte die setfn eigentlich so aussehen
setFn {
my $cur = ReadingsVal("Sensor","sensed.0",0);
if ((($CMD eq "on") && ($cur == 0)) || (($CMD eq "off") && ($cur == 1)) || ($CMD eq "toggle") ) {
fhem("set Relais PIO.0 11; sleep 1; set Relais PIO.0 10");
}
return undef;
}
Hi,
aus http://perldoc.perl.org/functions/return.html:
Zitat
(In the absence of an explicit return, a subroutine, eval, or do FILE automatically returns the value of the last expression evaluated.)
Gruß,
Thorsten
Zitat von: Thorsten Pferdekaemper am 20 Februar 2017, 09:35:16
Hi,
aus http://perldoc.perl.org/functions/return.html:Gruß,
Thorsten
Danke! Ich sags ja ich werde nie ein perl-Experte :D
Hallo viegener und Thorsten,
mit "return undef" funktioniert's perfekt. Ich werde den eigentlichen Umschaltimpuls noch in eine Schleife packen, falls die Stromstoßrelais beim ersten Impuls nicht umsetzen (kann sein, wenn länger nicht benutzt kleben diese leicht fest).
Gibt es eine Möglichkeit in fhem den Code in eine Funktion zu abstrahieren, sodass bei einem weiteren Gerät nur mehr der Sensor-Kanal und Relais-Kanal angegeben werden muss, sowie bei Änderungen am Code, diese für alle Geräte durchschlagen?
Vielen vielen Dank für eure Hilfe!!
LG Oliver
Zitat von: Oliver Vallant am 20 Februar 2017, 14:10:09
Hallo viegener und Thorsten,
mit "return undef" funktioniert's perfekt. Ich werde den eigentlichen Umschaltimpuls noch in eine Schleife packen, falls die Stromstoßrelais beim ersten Impuls nicht umsetzen (kann sein, wenn länger nicht benutzt kleben diese leicht fest).
Gibt es eine Möglichkeit in fhem den Code in eine Funktion zu abstrahieren, sodass bei einem weiteren Gerät nur mehr der Sensor-Kanal und Relais-Kanal angegeben werden muss, sowie bei Änderungen am Code, diese für alle Geräte durchschlagen?
Vielen vielen Dank für eure Hilfe!!
LG Oliver
Schön das es geht.
Um den Code wiederverwendbar zu machen setze ich meist Subroutinen in 99_myUtils.pm ein (https://wiki.fhem.de/wiki/99_myUtils_anlegen (https://wiki.fhem.de/wiki/99_myUtils_anlegen)) und dann kannst Du eine sub definieren, die als Parameter den Wert von $CMD, etc annimmt.
Zitat von: Oliver Vallant am 20 Februar 2017, 14:10:09Ich werde den eigentlichen Umschaltimpuls noch in eine Schleife packen, falls die Stromstoßrelais beim ersten Impuls nicht umsetzen
Das ist aber u.U. gar nicht so einfach. Das Konstrukt fhem("tuwas;sleep 1;tuwasanderes") kommt ja zurück, bevor es ganz abgearbeitet ist. Da wirst Du Dir was einfallen lassen müssen.
Zitat
Gibt es eine Möglichkeit in fhem den Code in eine Funktion zu abstrahieren, sodass bei einem weiteren Gerät nur mehr der Sensor-Kanal und Relais-Kanal angegeben werden muss, sowie bei Änderungen am Code, diese für alle Geräte durchschlagen?
Klar, Unterprogramm (Funktion) schreiben und in die 99_myUtils.pm packen.
Gruß,
Thorsten
Falls jemand die Funktionen benötigt:
Für normale Spulen/Thyrister/MosFET-Relais:
DEF=<Relais DS2408>:sensed.<Channel 0..7>
TYPE=readingsProxy
setFn={switchRelais($CMD, $READING)}
Funktion in der 99:myUtils.pm
sub switchRelais($$) {
my ($cmd, $relCh) = @_;
$relCh = (split(/\./, $relCh))[1];
$cmd = ($cmd eq "on")?owON:owOFF;
return ("PIO." . $relCh . " " . $cmd);
}
Für 2-Kanal-Stromstoß-Relais (1xRückmeldung,1xLast):
Zusätzliches globales userattr angelegt: "relaisDevCh"
DEF=<Sensor DS2408>:sensed.<Channel 0..7>
TYPE=readingsProxy
setFn={switchSSRelais($CMD, $DEVICE, $READING, AttrVal($name,"relaisDevCh",undef) )}
relaisDevCh=<Relais DS2408> PIO.<Channel 0..7>
Funktion in der 99:myUtils.pm
sub switchSSRelais($$$$) {
my ($CMD, $senDev, $senCh, $relDevCh) = @_;
my $cur = ReadingsVal($senDev,$senCh,0);
if ((($CMD eq "on") && ($cur == 1)) || (($CMD eq "off") && ($cur == 0)) || ($CMD eq "toggle") ) {
fhem("set " . $relDevCh . " " . owON . "; sleep 0.2; set " . $relDevCh . " " . owOFF); }
return undef
}
Taster am Sensor:
DEF=<Sensor DS2408>:latch.<channel 0..7>
TYPE=readingsProxy
setFn={ if ($CMD eq "reset") { "$READING 10" } }
setList=reset
Das Notify für den Taster, sowie rücksetzen des Alarming:
DEF=<TasterDevice>.on set <Relais oder SSRelais> toggle ; set <TasterDevice> reset
TYPE=notify
@Thorsten: Dein Bedenken ist korrekt. Das wird dann wohl ohne "at" nicht funktionieren.