Angespornt von der wunderbaren DOIF-Diskussion bin ich auch gerade dabei, etwas fitter in DOIF zu werden und habe momentan ein Problem. Ich hab gelesen, dass DOIF mittlerweile auch Eigenschaften eines Dummies übernehmen kann (setList, readingList), so dass ich gerne mein presence-Dummy und mein presence-DOIF zusammenführen wollte.
Das Problem ist, dass das DOIF-Device z.B. den Befehle "set env_presence home" nicht akzeptiert, obwohl "home" Teil von setList ist.
defmod env_presence DOIF ([env_presence:transition] eq "leaving") (set $SELF away) \
DOELSEIF ([env_presence:transition] eq "arriving") (set $SELF home, set env_f_justCameHome on-for-timer 300)
attr env_presence alias Anwesenheit
attr env_presence devStateIcon home:status_available away:status_away_1 sleep:scene_sleeping
attr env_presence event-on-change-reading (state|transition|statHomeDuration.*)
attr env_presence group Zustände
attr env_presence icon status_away_1
attr env_presence readingList transition
attr env_presence room Wohnung
attr env_presence setList away home sleep
attr env_presence userReadings homeDuration integral { (Value("env_presence") ne "away") /60.0 }
attr env_presence wait 300
attr env_presence webCmd home:away:sleep
Wenn ich dann aber "set env_presence home" aufrufe, kommt:
unknown argument home for env_presence, choose one of disable initialize enable cmd away home sleep
Zitat von: vbs am 15 Februar 2017, 09:05:27set $SELF home
Du kannst nicht den umbenannten Status aufrufen. Du könntest ja diesen Status auch mehrfach oder für eine Sub-Cmd verwenden.
Deshalb:
set $SELF cmd_1
wäre richtig.
Sorry, werde aus der Antwort leider nicht so richtig schlau. Soviel ich weiß ist $SELF einfach der Name des DOIF-Devices. Was meinst du mit "umbenannten Status aufrufen"? Bin jetzt verwirrt ^^
Abgesehen davon will ich ja einfach nur "set env_presence home" aufrufen können. Will also das DOIF-Device einfach nur wie einen Dummy verwenden können. Hat mMn also erstmal nichts mit den DOIF-Bedingungen zu tun.
Du kannst bei set nur Befehle setzen, die DOIF auch kennt. Im GGsatz zum Dummy, der erstmal jedes set akzeptiert hat.
Und bekannt sind neben den alten wie initialize jetzt neu cmd_1, cmd_2 usw. (so sie auch existieren). home kennt DOIF nicht.
Ein Lichtschalter kennt auch nur on und off, nicht aber home oder hgdskjas.
Genau aus dem Grund gibt es ja das Attribut "setList", was ich ja auch gesetzt habe. Damit dann dem Device die Werte bekannt sind, die man zu setzen gedenkt. Klappt bei einem Dummy auch wunderbar.
Wenn ich nochmal mich selbst mit der ursprünglichen Fehlermeldung zitieren darf, da sieht manm dass DOIF ja sogar von sich aus sagt, dass er nun "home", "away" und "sleep" kennt:
Zitatunknown argument home for env_presence, choose one of disable initialize enable cmd away home sleep
Entweder du nutzt setList und die alte (https://forum.fhem.de/index.php/topic,64939.0.html) set-Variante oder cmd_X und die neue (https://forum.fhem.de/index.php/topic,66153.0.html). Mischen impossible.
Das set-Kommando home usw. wird ja abgesetzt, allerdings weiß DOIF nicht, was er damit machen soll. Wenn du einen bestimmten Befehlszweig damit ausführen willst, dann musst du noch die Zuordnung zu den Kommandos definieren. Das kannst du über eventMap machen, z. B.
attr di_tt eventMap /cmd_1:home/cmd_2:sleep/cmd_3:away/
Du kannst auch Zustände definieren, die es nicht gibt, die dann auch keine Kommandos ausführen, aber den Zustand des Moduls verändern:
attr di_tt eventMap /cmd_4:home/cmd_5:sleep/cmd_6:away/
Die kannst du dann über das Attribut cmdState auf andere Namen umbiegen.
Mit dem Attribut devStateIcon kannst du wiederum weiter z. B. Icons definieren
Ich wollte eigentlich gar keine Logik dahinter haben bzw. wollte auch gar keine Zweige o.ä. ausführen. Ich wollte wirklich nur (wie bei einem dummy), dass der Wert als state übernommen wird und entsprechend ein Event generiert wird.
Geh ich recht in der Annahme, dass ich damit einfach etwas auf dem Holzweg bin? Vermutlich sollte ich das wieder trennen in ein DOIF + ein separaten Dummy.
Zitat von: vbs am 15 Februar 2017, 16:53:07
Ich wollte eigentlich gar keine Logik dahinter haben bzw. wollte auch gar keine Zweige o.ä. ausführen. Ich wollte wirklich nur (wie bei einem dummy), dass der Wert als state übernommen wird und entsprechend ein Event generiert wird.
Geh ich recht in der Annahme, dass ich damit einfach etwas auf dem Holzweg bin? Vermutlich sollte ich das wieder trennen in ein DOIF + ein separaten Dummy.
Das Problem ist, dass Dummy keine interne Zustandsverwaltung hat. DOIF aber schon. D.h. intern wird der Zustand nicht über den Status, sondern über bestimmte Readings: cmd, cmd_nr, verwaltet. home hat aber keine Nummer, deswegen muss man beim DOIF das über eventMap abbilden. Das ist zumindest der aktuelle Stand des Moduls. Man könnte ggf. automatisch weitere Zustandsnummern vergeben, aber das ist bisher nicht programmiert.
Ok, danke euch trotzdem. Vielleicht ist die Idee auch sowieso nicht so gut, den Zustands-Dummy und seine Logik in ein Gerät zu packen, keine Ahnung. Andererseits wirds auch nicht übersichtlicher, wenn man für eine Logik 3 Geräte + Perl-Code braucht...
Mir stellt sich die Frage, was der Dummy für eine Aufgabe hatte bevor er ins DOIF gewandert ist.
Das Reading state kann einen beliebigen Wert annehmen mit setreading state env_presence <wert>, dazu benötigst Du die setList nicht. Der Wert wird allerdings bei jedem Schaltvorgang überschrieben.
Wenn Dir aber wichtig ist übers Frontend state zusetzen geht es mit einem zusätzlichen DOELSEIF-Zweig und cmdState
([env_presence:transition] eq "leaving" or [$SELF:dummy] eq "away")
DOELSEIF ([env_presence:transition] eq "arriving" or [$SELF:dummy] eq "home") (set env_f_justCameHome on-for-timer 300)
DOELSEIF ([$SELF:dummy] eq "sleep")
und die Attribute
readingList transition dummy
setList dummy:away,home,sleep
webCmd dummy
cmdState away|home|sleep
Der Dummy ist wirklich ganz plump der Anwesenheitsstatus, also ein Dummy, das einfach den Wert home, sleep oder away annimmt (noch etwas Transistionslogik drumrum). Klar, ich kann mit setreading u.ä. beliebig irgendwo "reingreifen", aber das ist mir schon etwas zu "low-levelig". Ich möchte schon gerne straightforward auf das Device zugreifen mit Value("") und co, sonst wird mir das zu kryptisch.
Werde dann einfach bei einem normalen Dummy bleiben, danke!
So wie ich es in Dein DOIF eingebaut habe wird state gesetzt und Du könntest auch mit Value darauf zugreifen, wenns aber schon läuft besteht ja auch keine Notwendigkeit es zu ändern.
Verstehe es erst jetzt richtig, ehrlich gesagt. Das cmdState ist ja sehr genial, denk ich! Allein damit wird ja aus dem DOIF schon ein kleiner Dummy. Das setList ist dann eigentlich nur wichtig, damit Frontends die möglichen Befehle auslesen könne, oder?
Danke für den nochmaligen Hinweis! Habe gerade sehr viele Idee, wo ich das einsetzen kann!
Die ursächliche Idee war, die benutzereigenen Readings im DOIF direkt im Frontend zusetzen, ohne zwischen geschalteten Dummy.
Man könnte programmieren, dass ein set <DOIF> irgendetwas, das irgendetwas als Status schreibt und den Zustand cmd auf 0 setzt. Allerdings möchte man das vermutlich nicht, wenn setlist in Verbindung mit einem Reading eingesetzt wird.
Auf der anderen Seite, wenn man gar keinen Bezug auf das irgendetwas im DOIF haben möchte, warum sollte es dann in dem DOIF sein?
Ich habe mal spaßeshalber eine Version gebastelt, die alle set Befehle erlaubt ohne etwas zu tun, damit funktioniert so etwas dann:
defmod di_dd DOIF ([$SELF:"home"])\
DOELSEIF([$SELF:"away"])\
DOELSE\
attr di_dd cmdState home|away|sonstwas
attr di_dd setList away home
hier mal zum ausprobieren:
Also das klappt erstmal wie beschrieben.
Nochmal ein einfaches (anderes) Real-Life-Beispiel dazu:
Ich hab ein Dummy bei dem ich Heizpausen und Frostschutz für die Heizung einstellen kann:
1. Einen dummy "heatingMode", der hat setList "heatPause frostProtection normal"
2. Ein notify mit "heatingMode:.* { updateHeating($NAME, $EVENT) }", das die Funktion "updateHeating" aufruft, wenn sich heatingMode ändert
So wie ich dich verstanden habe, könnte man das jetzt als ein DOIF ungefähr so bauen:
di_dd DOIF ([$SELF:"heatPause"]) { updateHeating($DEVIE, $EVENT) }
DOELSEIF([$SELF:"frostProtection"]) { updateHeating($DEVIE, $EVENT) }
DOELSEIF([$SELF:"normal"]) { updateHeating($DEVIE, $EVENT) }
attr di_dd cmdState heatPause|frostProtection|normal
attr di_dd setList heatPause frostProtection normal
Bin im Moment unsicher, ob ich das eleganter finde als die Variante mit zwei Devices. Mindestens etwas unschön ist mMn, dass man für jeden state einen eigenen DOIF-Zweig aufmachen muss. Vielleicht geht es ja aber auch einfacher, bin da nicht so fit mit DOIF.
Ich spinn mal etwas rum mit einer anderen Idee: das cmdState und die verschiedenen Zweige braucht man ja nur, weil das DOIF bei jedem Befehl in den state schreibt, richtig?. Was wäre denn, wenn das DOIF den state nie anfassen würde (evtl. steuerbar durch ein Attribut in der Art "dontTouchState") und man aber von außen durch die normalen set-Aufrufe auch den state setzen könnte.
Dann könnte das DOIF ungefähr so aussehen:
di_dd DOIF ([$SELF]) { updateHeating($DEVIE, $EVENT) }
attr di_dd setList heatPause frostProtection normal
attr di_dd dontTouchState 1
Wie gesagt: ist kein Feature-Request oder so, einfach ein bisschen Spinnerei. Ich kann auch gut mit der bisherigen Variante leben. :)
Die SetList Sachen sind relativ neu im DOIF-Modul. Ellert hat es ja schon geschrieben, zunächst war die Lösung für Reading im DOIF angedacht und nicht für Stati. Wir dürfen das Konzept des Moduls nicht auf den Kopf stellen. Es arbeitet mit Zuständen und die entsprechen dem Status, daher möchte ich das Konzept an der Stelle nicht ändern.
Was ich aber noch zum Ausprobieren einbauen wollte ist folgendes Features:
di_dd DOIF (1)
({updateHeating($DEVICE, $EVENT)})
DOELSEIF(1)
({updateHeating($DEVICE, $EVENT)})
DOELSEIF(1)
({updateHeating($DEVICE, $EVENT)})
attr di_dd cmdState heatPause|frostProtection|normal
SetList wäre in diesem Fall überflüssig, weil durch die Definition cmdState heatPause cmd_1 entspricht, frostProtection cmd_2 usw.
Zitat von: vbs am 16 Februar 2017, 10:55:52
Also das klappt erstmal wie beschrieben.
Nochmal ein einfaches (anderes) Real-Life-Beispiel dazu:
Ich hab ein Dummy bei dem ich Heizpausen und Frostschutz für die Heizung einstellen kann:
1. Einen dummy "heatingMode", der hat setList "heatPause frostProtection normal"
2. Ein notify mit "heatingMode:.* { updateHeating($NAME, $EVENT) }", das die Funktion "updateHeating" aufruft, wenn sich heatingMode ändert
So wie ich dich verstanden habe, könnte man das jetzt als ein DOIF ungefähr so bauen:
di_dd DOIF ([$SELF:"heatPause"]) { updateHeating($DEVIE, $EVENT) }
DOELSEIF([$SELF:"frostProtection"]) { updateHeating($DEVIE, $EVENT) }
DOELSEIF([$SELF:"normal"]) { updateHeating($DEVIE, $EVENT) }
attr di_dd cmdState heatPause|frostProtection|normal
attr di_dd setList heatPause frostProtection normal
Bin im Moment unsicher, ob ich das eleganter finde als die Variante mit zwei Devices. Mindestens etwas unschön ist mMn, dass man für jeden state einen eigenen DOIF-Zweig aufmachen muss. Vielleicht geht es ja aber auch einfacher, bin da nicht so fit mit DOIF.
Ich spinn mal etwas rum mit einer anderen Idee: das cmdState und die verschiedenen Zweige braucht man ja nur, weil das DOIF bei jedem Befehl in den state schreibt, richtig?. Was wäre denn, wenn das DOIF den state nie anfassen würde (evtl. steuerbar durch ein Attribut in der Art "dontTouchState") und man aber von außen durch die normalen set-Aufrufe auch den state setzen könnte.
Dann könnte das DOIF ungefähr so aussehen:
di_dd DOIF ([$SELF]) { updateHeating($DEVIE, $EVENT) }
attr di_dd setList heatPause frostProtection normal
attr di_dd dontTouchState 1
Wie gesagt: ist kein Feature-Request oder so, einfach ein bisschen Spinnerei. Ich kann auch gut mit der bisherigen Variante leben. :)
Das DOIF könnte auch so aussehen
di_dd DOIF ([$SELF:heatingMode]) { updateHeating($DEVICE, [$SELF:heatingMode])
und die Attribute
do always
readingList heatingMode
setList heatingMode:heatPause,frostProtection,normal
webCmd heatingMode
cmdState [$SELF:heatingMode]
Das Reading
heatingMode dient als Frontendelement.
state nimmt den aktuellen Status aus dem Reading
heatingMode.
Das würde in Dein Konzept nur passen, wenn der dummy "heatingMode" als Frontend-Element genutzt wurde.
Wenn der Dummy aber über eine Logik gesetzt wird (mit set), dann müsste die Logik statt set jetzt setreading verwenden. Die Attribute setList, redingsList und webCmd wären dann nicht erforderlich.
cmdState [$SELF:heatingMode]
Hm, das ist ja auch interessant... ich komm aus dem Staunen gar nicht mehr raus :)
Ich glaub, ich würde aber gerne das normale "set" nutzen können. Das hab ich sonst vermutlich in 3 Monaten wieder vergessen, dass ich bei dem speziellen Device nur setreading verwenden darf...