GELÖST: Status und Status-Icon eines Gerätes ändern, OHNE die Aktion auszulösen?

Begonnen von Uli Zappe, 06 Juli 2016, 05:00:12

Vorheriges Thema - Nächstes Thema

Uli Zappe

Hallo allerseits,

ich stehe vor einem Problem, das ich so nicht erwartet hatte: Ich finde keinen Weg, den Status eines FHEM-Gerätes einschließlich des Icons auf der Web-Oberfläche verändern, ohne die zugehörige Aktion auszulösen.

Im Detail:

Ich habe etliche elektronische Geräte (HiFI-Anlage, Computer, Projektor, ...), die ich in FHEM integrieren will, d.h. ich will sehen können, ob sie an oder aus (= in Bereitschaft/im Schlafmodus) sind und sie schlafen legen bzw. aufwecken können.

All diesen Geräten ist gemein, dass sie auch völlig unabhängig von FHEM an- oder ausgeschaltet werden können, so dass ich eine Statusabfrage brauche, die unabhängig von den Ein-/Ausschaltvorgängen funktioniert. Das sind in meinem Fall bisher PRESENCE-Module mit Ping-Abfrage oder Shellskripten, die spezielle Binaries aufrufen, oder FS20-Stromverbrauchsmesser, die Statussignale (Strom/kein Strom) an FHEM senden.

Ebenso gibt es unterschiedliche Methoden zum An- und Ausschalten, die funktionieren aber alle prima und sind hier nicht das Thema.

Da das Problem, auf das ich stoße, immer dasselbe ist, beschränke ich mich im Folgenden beispielhaft auf die Ping-Abfrage mit PRESENCE.

Die Idee ist, dass PRESENCE über notify mit einer Aktion verknüpft ist, die überprüft, ob der Status, den PRESENCE meldet, dem gespeicherten Gerätestatus entspricht, und falls nicht, diesen ändert.

Als Beispiel für den Rechner woodstock (vereinfacht, nur die hier wichtigen Parameter):

define woodstock_STATE PRESENCE lan-ping woodstock 1 1
define woodstock_PAIRon notify woodstock_STATE:present { if(Value("woodstock") eq "off") { fhem("set woodstock on") } }
define woodstock_PAIRoff notify woodstock_STATE:absent { if(Value("woodstock") eq "on") { fhem("set woodstock off") } }


Diese Implementation hätte aber das Problem, dass eine Aktion ausgelöst wird, statt nur der gespeicherte Zustand geändert. Wenn woodstock z.B. durch einen Tastendruck an seiner Tastatur aufgeweckt wird, würde unsinnigerweise eine nochmalige Aktion ausgelöst, ihn aufzuwecken. Im besten Fall ist das harmloser Overhead, es kann aber leider auch zu diversen Problemen führen (spielt hier keine Rolle, welche genau). So geht es also definitiv nicht, das war von Beginn an klar.

Nur dachte ich, dass dies super-einfach zu lösen wäre, denn genau dafür – so meine Vermutung – gibt es ja den Befehl setstate in FHEM, der gerade keine Aktion beim Setzen des Status auslöst:

define woodstock_STATE PRESENCE lan-ping woodstock 1 1
define woodstock_PAIRon notify woodstock_STATE:present { if(Value("woodstock") eq "off") { fhem("setstate woodstock on") } }
define woodstock_PAIRoff notify woodstock_STATE:absent { if(Value("woodstock") eq "on") { fhem("setstate woodstock off") } }


In der Tat wird nun keine Aktion ausgelöst, zu meiner Überraschung wird aber das Status-Icon auf der Web-Oberfläche ebensowenig verändert, womit diese Lösung unbrauchbar ist.

Abhilfe schafft hier trigger:

define woodstock_STATE PRESENCE lan-ping woodstock 1 1
define woodstock_PAIRon notify woodstock_STATE:present { if(Value("woodstock") eq "off") { fhem("setstate woodstock on;; trigger woodstock on") } }
define woodstock_PAIRoff notify woodstock_STATE:absent { if(Value("woodstock") eq "on") { fhem("setstate woodstock off;; trigger woodstock off") } }


Jetzt wird das Icon wieder aktualisiert, aber jetzt werden auch die Aktionen wieder gesendet, d.h. ich bin wieder am Anfang. (Ich vermute mal, dass de facto set nichts anderes ist als setstate plus trigger.)

Mein Problem also: Wie kann ich den Status eines FHEM-Gerätes einschließlich des Icons auf der Web-Oberfläche verändern, ohne die zugehörige Aktion auszulösen?

Danke im Voraus für alle Antworten!

Starkstrombastler

Probiere mal folgendes:
definiere vier Stati:  on, off, ON, OFF
Presence setzt Status auf ON oder OFF
attr devStateIcon  device on:icon-on:off ON:icon-on:off off:icon-off:on OFF:icon-off:on
Das notify auf device schaltet nur bei 'on' oder 'off' das Zielgerät
IPC\Ubuntu + Fhem, 1wire, Shellies, Siemens Logo!, Z-Wave, PhilipsTV, Vu+duo2, KM200

justme1968

der longpoll update für das frontend hängt an genau dem gleichen event wie dein notify und das bei der bei änderung der readings und mit dem trigger erzeugt wird. so lange es das gleiche event ist geht das eine nicht ohne das andere. d.h. du musst unterschiedliche events verwenden.

z.b. mit dem vorschlag von oben.

genau für deine anwendung gib es in PRESENCE aber auch schon das powerCmd attribut und das power kommando.

im attribut konfigurierst du die kommandos die zum ein- und ausschalten verwendet und. in devState icon und anderswo verwendest du das power kommando. damit hast du die events zum schalten und für den status getrennt und beides kommt sich nicht mehr in die quere.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Uli Zappe

Danke für Eure Tipps!  :D

Ich hoffe, ich werde heute Abend Zeit haben, das auszuprobieren (und dann natürlich hier berichten).

Uli Zappe

Zitat von: justme1968 am 06 Juli 2016, 08:28:57
genau für deine anwendung gib es in PRESENCE aber auch schon das powerCmd attribut und das power kommando.

im attribut konfigurierst du die kommandos die zum ein- und ausschalten verwendet und. in devState icon und anderswo verwendest du das power kommando. damit hast du die events zum schalten und für den status getrennt und beides kommt sich nicht mehr in die quere.
Ich habe jetzt versucht, das auszuprobieren, aber ich befürchte, ich bin zu blöd dafür. Dein Vorschlag klang so simpel, aber ich kriege es einfach nicht hin, und es scheint in realiter auch deutlich komplizierter zu sein.

Also Schritt für Schritt:

Zum Aufwecken und Schlafenlegen des Computers woodstock verwende ich zwei völlig getrennte Kommandozeilenprogramme. Der power-Befehl von PRESENCE kann aber nur ein einen Befehl mit zwei Attributen für ein und aus auslösen, folglich brauche ich zur Übersetzung erstmal einen dummy mit zwei notifys:

define woodstock_SWITCH dummy
attr woodstock_SWITCH setList on off
define woodstock_SWITCHon notify woodstock_SWITCH:on "/usr/local/bin/wake woodstock"
define woodstock_SWITCHoff notify woodstock_SWITCH:off "/usr/local/bin/sleepmac woodstock"

OK?

Dann kann ich problemlos den power-Befehl in PRESENCE definieren:

define woodstock_STATE PRESENCE lan-ping woodstock 1 1
attr woodstock_STATE powerCmd set woodstock_SWITCH $ARGUMENT

OK?

PRESENCE selbst bietet aber keine Möglichkeit, Schalter auf der Weboberfläche darzustellen. Folglich brauche ich dazu einen weiteren dummy samt dazugehörigem notify:

define woodstock dummy
attr woodstock setList on off
define woodstockOnOff notify woodstock set woodstock_STATE power $EVENT

OK?

So, und jetzt stehe ich komplett auf dem Schlauch. Wie sorge ich jetzt dafür, dass der vom dummy woodstock auf der Weboberfläche erzeugte Schalter jederzeit den aktuellen Status der PRESENCE-Instanz woodstock_STATE darstellt und beim Klick auf den Schalter entsprechend toggelt (also set woodstock_STATE power on sendet, wenn der Status off ist und umgekehrt)? Ich verstehe nicht, wie das mit devStateIcon funktionieren soll. Und ein notify von woodstock_STATE an woodstock zum Statusupdate kann ich genauso wenig senden, weil ich ja dann wieder in die Situation käme, dass dadurch ungewollt die entsprechende Aktion ausgelöst wird ...

Kannst Du mir sagen, mit welchem Code genau das gehen soll? Alles, was ich probiert habe, hat nicht funktioniert ...  ::)

Danke!

marvin78

Lagere den Aufruf der Skripte einfach in eine sub der myUtils aus, dann benötigst du weder dummys noch sonst irgendwelche weiteren Hilfen. Im powerCmd des PRESENCE Devices rufst du dann nur diese sub mit den entsprechenden Argumenten auf (siehe Doku zu PRESENCE). Die sub entscheidet dann anhand der Argumente, welches Skript es aufruft. Ein wenig Perl ist hier natürlich nötig.

Uli Zappe

Zitat von: marvin78 am 07 Juli 2016, 07:39:36
Lagere den Aufruf der Skripte einfach in eine sub der myUtils aus, dann benötigst du weder dummys noch sonst irgendwelche weiteren Hilfen. Im powerCmd des PRESENCE Devices rufst du dann nur diese sub mit den entsprechenden Argumenten auf (siehe Doku zu PRESENCE). Die sub entscheidet dann anhand der Argumente, welches Skript es aufruft. Ein wenig Perl ist hier natürlich nötig.
Aber das Problem ist doch nicht die Entscheidung, welches Skript aufzurufen ist – das geht ja prima mit dem dummy, auch wenn es mit einer eigenen sub natürlich kompakter zu lösen wäre.

Das Problem ist die Statusanzeige im Schalter auf der Weboberfläche, und da hilft mir auch keine sub weiter, jedenfalls nicht, wenn ich ganz grundsätzlich nicht kapiere, wie ich die Statusanzeige auf dem Schalter ändern kann, ohne gleichzeitig ungewollt den Schaltvorgang erneut auszulösen.

marvin78

Warum möchtest du, dass dein Device einen Status anzeigt, den es noch gar nicht hat? Das erschließt sich mir nicht. Die PRESENCE Lösung sorgt dafür dass du schalten kannst und in dem Moment, in dem Das Gerät an (oder aus) ist, liefert PRESENCE auch den richtigen Status (-> richtiges Icon).

Du benötigst hier keine weiteren notifys, setstate oder ähnliches. Es lässt sich alles in PRESENCE lösen.

Uli Zappe

Zitat von: marvin78 am 07 Juli 2016, 08:33:57
Es lässt sich alles in PRESENCE lösen.
Aber wie?

Sorry, es hilft mir nix, dass jemand sagt, dass etwas geht, wenn ich eben nicht weiß, wie es geht.

PRESENCE kann doch (auch bei definiertem power-Befehl) keine Schalter auf der Weboberfläche erzeugen, oder sehe ich das falsch?

Wenn es das aber nicht kann, benötige ich dafür mindestens einen dummy, den ich irgendwie mit PRESENCE koppeln muss – und da gehen die Probleme dann los.

Wo liegt mein Denkfehler?


justme1968

der schalter ist das icon des PRESENCE device. und da legst du mit devStateIcon das power kommando drauf.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

marvin78

Doch. Das kann es. Du brauchst keinen dummy (was dir hier ja schon beschrieben wurde). Der Schalter ist das ICON des PRESENCE Devices (über devStateIcon einstellbar). Wenn man die Doku oder eben viele viele Beispiele hier im Forum dazu liest, kommt man auch schnell drauf, wie das geht. Aber ich verstehe schon, du willst ein komplettes Kochrezept und nicht selbst was machen.

Hier ein komplettes Beispiel:

List vom PRESENCE Device:
Internals:
   ADDRESS    192.168.178.31
   CHANGED
   DEF        lan-ping 192.168.178.31 80 90
   MODE       lan-ping
   NAME       OG.sr.XX.ServerOnline.pres
   NOTIFYDEV  global
   NR         475
   NTFY_ORDER 50-OG.sr.XX.ServerOnline.pres
   STATE      present
   TIMEOUT_NORMAL 80
   TIMEOUT_PRESENT 90
   TYPE       PRESENCE
   Helper:
     Dblog:
       State:
         Logdb:
           TIME       1467858083.05397
           VALUE      statusRequest
   Readings:
     2016-05-02 17:03:10   powerCmd        executed
     2016-07-07 08:42:41   presence        present
     2016-07-07 08:42:41   state           present
   Helper:
Attributes:
   DbLogExclude powerCmd
   alias      Server
   devStateIcon present:rc_GREEN:off absent:rc_RED:on set_on:rc_YELLOW set_off:rc_STOP
   event-on-change-reading state
   eventMap   /power on:on/ /power off:off/ /power reboot:reboot/
   group      IT
   icon       it_nas
   powerCmd   {StartStopServer("$ARGUMENT","$NAME")}
   room       Serverschrank
   sortby     B04


sub in der myUtils:


sub StartStopServer($$) {
    my ($action,$dev) = @_;
    system('wakeonlan 00:11:32:29:5B:FF') if ($action eq "on" && Value($dev) ne "present");
  system('/opt/fhem/scripts/poweroff_mediaserver.sh &') if ($action eq "off" && Value($dev) eq "present");
  if ($action eq "reboot" && Value($dev) eq "present") {
      system('/opt/fhem/scripts/reboot_mediaserver.sh &');
  }
  Log 4, "MediaServer: power".$action;
  return undef;
}

Uli Zappe

Zitat von: marvin78 am 07 Juli 2016, 08:46:15
Doch. Das kann es.
OK, das war mir halt nicht klar.

ZitatDu brauchst keinen dummy (was dir hier ja schon beschrieben wurde).
Von Dir vor ein paar Minuten, ja. Vorher nicht.

ZitatDer Schalter ist das ICON des PRESENCE Devices
Nur dass meine PRESENCE-Geräte dummerweise keine Icons haben ...

Zitat(über devStateIcon einstellbar)
Ahaaa! Das ist die entscheidende Information. Das war mir nicht klar.

ZitatWenn man die Doku oder eben viele viele Beispiele hier im Forum dazu liest, kommt man auch schnell drauf, wie das geht.
Vielleicht, wenn man so clever ist wie Du. Ich hatte jetzt geschlagene 11 Stunden damit zugebracht, das herauszufinden, und war keinen Schritt weitergekommen.

Denn sorry, in der Dokumentation steht das einfach nicht. Ich habe aufgrund der vorangegangenen Hinweise wirklich alles, was in der Doku zu devStateIcon steht, mehrfach gelesen. Aus nichts lässt sich entnehmen, dass devStateIcon Geräten, die von Haus aus überhaupt keine Schalter abbilden, welche erzeugt. Wenn man schon weiß, dass das so ist, lassen die Texte sich so verstehen, das habe ich mir gerade noch einmal angesehen, ja. Wenn man das aber nicht weiß, kommt man durch die Infos in der Dokumentation absolut nicht drauf. Ich war mir sicher, dass devStateIcon nur genau dann weiterhilft, wenn bereits ein klickbarer Statustext da ist, man aber stattdessen ein Icon möchte (das suggeriert ja auch der Name). Einen klickbaren Text gibt es per Default in PRESENCE aber nicht.

Und im Forum habe ich etliche Suchbegriffe ausprobiert, ohne etwas für mich Einschlägiges zu finden. Das ist das Problem, wenn einem die Sache so unklar ist, dass man gar nicht weiß, wie man die Suche eingrenzen soll. Und alle 3740 Treffer auf fhem.de zu devStateIcon zu lesen – sorry, das schaffe ich nicht.

ZitatAber ich verstehe schon, du willst ein komplettes Kochrezept und nicht selbst was machen.
Ich habe bestimmt insgesamt 30, 40 Stunden versucht, das selbst zu machen. Ich habe es halt nicht geschafft. Deshalb habe ich jetzt um Hilfe gebeten. Ist das denn so verwerflich?

ZitatHier ein komplettes Beispiel:
Danke!

marvin78

Dass devStateIcon auf ALLE Devices angewendet kann, steht schon implizit in der Doku und ist natürlich Grundlagenwissen. Auch der Name "devStateIcon" impliziert eigentlich nicht, dass man es nur bei klickbaren Devices anwenden kann. Es impliziert, dass es ein Icon für den STATE einrichtet.

Ich mache dir gar keinen Vorwurf aber mir persönlich wäre deine Vorgehensweise zu anstrengend. Man sollte sich von den Grundlagen zu "höheren" Dingen durcharbeiten. Beispiele für devStateIcon finden man so viele, dass es einen erschlägt, ja, aber man muss sich ja nur wenige anschauen, um es zu kapieren.

Die Doku zu PRESENCE ist im Übrigen auch eindeutig.

Kleiner Tipp: Nicht die fhem.cfg direkt editieren, sondern Attribute über das Frontend (Detailansicht) setzen. Dann weißt du ganz genau, welche Attribute dir für das entsprechende Device zur Verfügung stehen.

Uli Zappe

Zitat von: marvin78 am 07 Juli 2016, 09:28:07
Dass devStateIcon auf ALLE Devices angewendet kann, steht schon implizit in der Doku
Naja, es steht implizit da ist letztlich eine nette Umschreibung für es steht nicht da ...  ;)

Zitatund ist natürlich Grundlagenwissen.
Was heißt ,,natürlich"? Woher soll dieses Wissen denn kommen? Wenn es Grundlagenwissen wäre, würde ich erwarten, dass etwas darüber in der PDF-Einführung steht, da taucht devStateIcon nicht einmal auf ... Und die Beschreibung in commandref ist sehr knapp und äußerst kryptisch; es werden sofort zwei Fälle unterschieden, statt erstmal in einem Satz zu klären, wofür das Attribut überhaupt gut ist.

ZitatMan sollte sich von den Grundlagen zu "höheren" Dingen durcharbeiten.
Ja, aber irgendwann sollte man auch fertig werden mit seiner Haussteuerung ...  :P

Ich bin ja nun kein komplettes Greenhorn, ich nutze FHEM seit 4 Jahren, habe mittlerweile eine ziemlich komplexe Konfiguration, die ansonsten wunderbar funktioniert, und übrigens mit zahllosen definierten devStateIcon-Attributen – halt immer in Geräten, die schon von Haus aus Schalter hatten. Ein ganz klein bisschen Code von mir hat es sogar in die FHEM-Distribution geschafft.

Nur das Problem, das ich jetzt hatte, hatte ich eben noch nie, und es wurde Zeit, es zu lösen.

ZitatBeispiele für devStateIcon finden man so viele, dass es einen erschlägt
Forumsbeiträge, ja. Instruktive Code-Beispiele habe ich in all den Forums-Fundstellen, die ich mir angesehen habe, keine gefunden.

Zitatja, aber man muss sich ja nur wenige anschauen, um es zu kapieren.
Nein, wenn man felsenfest davon überzeugt ist, dass sich devStateIcon nur bei Geräten anwenden lässt, die schon Schalter besitzen, dann kann man schauen, solange man will, und kommt nicht auf diese Idee.

ZitatDie Doku zu PRESENCE ist im Übrigen auch eindeutig.
?? In der Dokumentation zu PRESENCE taucht devStateIcon überhaupt nicht auf ...

Wie auch immer, ich werde mich jetzt mal dransetzen, beide vorgeschlagenen Varianten zu implementieren und dann berichten.

marvin78

Ich bin raus. Beiträge zerpflücken ist nicht der Stil, in dem ich mich unterhalte. Im Zusammenhang lesen ist mein Rat an dich.

Uli Zappe

So, ich habe jetzt beide vorgeschlagenen Lösungsansätze getestet und will wie versprochen des Ergebnis berichten.

Kurz gefasst ist das Ergebnis erfreulicherweise: Beide Ansätze funktionieren gleich gut; es ist also mehr oder weniger Geschmacksache, welchen Ansatz man bevorzugt. :) Einen kleinen Unterschied gibt es; den erläutere ich im abschließenden Abschnitt Zusammenfassung.

Im Folgenden der jeweilige Code, der sich auf die für die Problemstellung entscheidenden Konfigurationseinträge beschränkt. Ebenso habe ich auf kompliziertere Dinge wie Perl-Subroutinen verzichtet und der Anschaulichkeit halber alles in fhem.cfg konfiguriert.

Zur Erinnerung: Die Problemstellung war exemplarisch, dass der aktuelle Status (wach/schlafengelegt) des Computers woodstock mit Hilfe einer sekündlichen ping-Abfrage des Moduls PRESENCE angezeigt wird und sich auch ändern lässt (also woodstock aufwecken oder schlafenlegen lässt), ohne dass eine bloße Änderung der Statusanzeige (weil woodstock von anderer Seite aufgeweckt oder schlafengelegt wurde) unnötig (und möglicherweise Komplikationen verursachend) die Weck- und Schlafenleg-Aktionen auslöst.

Im Beispiel gibt es zwei Kommandozeilenprogramme, mit denen Computer geweckt und schlafengelegt werden kann: wake und sleepmac, die sich beide in /usr/local/bin/ befinden und 1 Argument benötigen, den Hostnamen des Computers (also eben woodstock im Beispiel).

Lösung 1: Der power-Befehl in PRESENCE

Das Modul PRESENCE lässt sich nicht nur zum Feststellen des aktuellen Status von woodstock mittels ping verwenden, sondern kann auch gleich selbst zum Aufwecken und Schlafenlegen verwendet werden, indem man für das Attribut powerCmd einen entsprechenden Befehl festlegt. Die PRESENCE-Instanz sollte also gleichzeitig das auf der Web-Oberfläche sichtbare Gerät sein.

Der Code sieht so aus:


define woodstock_SWITCH dummy
attr woodstock_SWITCH setList on off
define woodstock_SWITCHon notify woodstock_SWITCH:on "/usr/local/bin/wake woodstock"
define woodstock_SWITCHoff notify woodstock_SWITCH:off "/usr/local/bin/sleepmac woodstock"

define woodstock_STATE PRESENCE lan-ping woodstock 1 1
attr woodstock_STATE ping_count 1
attr woodstock_STATE devStateIcon present:on:off absent:off:on
attr woodstock_STATE eventMap /power on:on/power off:off/
attr woodstock_STATE powerCmd set woodstock_SWITCH $ARGUMENT
attr woodstock_STATE event-on-change-reading state


Mit Erläuterungen:

# Da wir für on (aufwecken) und off (schlafenlegen) zwei ganz unterschiedliche Kommandozeilenprogramme auslösen
# müssen, benötigen wir einen dummy und zwei notify-Befehle, um diese Zuordnung vorzunehmen

define woodstock_SWITCH dummy
attr woodstock_SWITCH setList on off
define woodstock_SWITCHon notify woodstock_SWITCH:on "/usr/local/bin/wake woodstock"
define woodstock_SWITCHoff notify woodstock_SWITCH:off "/usr/local/bin/sleepmac woodstock"


# Definition der PRESENCE-Instanz für ping-Abfragen im Sekundenabstand
define woodstock_STATE PRESENCE lan-ping woodstock 1 1
# Bei sekündlichen Abfragen können wir nur einen ping pro Abfrage nutzen; sollte der einmal nicht funktionieren, ist das
# angesichts der sekündlichen Abfragen kein Problem

attr woodstock_STATE ping_count 1
# Das folgende Attribut legt fest, dass auf der Web-Oberfläche für den Status present ein on-Icon und für den Status absent
# ein off-Icon angezeigt wird und ein Klicken auf das Icon den jeweils entgegengesetzten Befehl (on > off, off > on) auslöst

attr woodstock_STATE devStateIcon present:on:off absent:off:on
# Das folgende Attribut legt fest, dass "set woodstock_STATE on|off" "set woodstock_STATE power on|off" auslöst
attr woodstock_STATE eventMap /power on:on/power off:off/
# Das folgende Attribut legt fest, dass "set woodstock_STATE power on|off" "set woodstock_SWITCH on|off" auslöst
attr woodstock_STATE powerCmd set woodstock_SWITCH $ARGUMENT
# Das folgende Attribut verhindert Updates der Weboberfläche im Sekundenabstand, wenn der Status unverändert bleibt.
# Ohne dieses Attribut würde das Status-Icon auf der Weboberfläche im Sekundenabstand flackern.

attr woodstock_STATE event-on-change-reading state


Lösung 2: Verdopplung der Status im Geräte-dummy

Wenn man im auf der Web-Oberfläche sichtbaren Geräte-dummy, der den Computer repräsentiert, die Status von on off auf on ON off OFF verdoppelt, das Status-Icon allen Status zuweist, die Aktionen aber nur für on und off auslöst, kann man Status-Anzeige und Aktionen entkoppeln:

define woodstock dummy
attr woodstock setList on off ON OFF
attr woodstock devStateIcon on:on:off ON:on:off off:off:on OFF:off:on
define woodstockOn notify woodstock:on "/usr/local/bin/wake woodstock"
define woodstockOff notify woodstock:off "/usr/local/bin/sleepmac woodstock"

define woodstock_STATE PRESENCE lan-ping woodstock 1 1
attr woodstock_STATE ping_count 1
define woodstock_PAIRon notify woodstock_STATE:present { if(Value("woodstock") eq "OFF" || Value("woodstock") eq "off") { fhem("set woodstock ON") } }
define woodstock_PAIRoff notify woodstock_STATE:absent { if(Value("woodstock") eq "ON" || Value("woodstock") eq "on") { fhem("set woodstock OFF") } }


Mit Erläuterungen:

# dummy, der den Computer auf der Web-Oberfläche repräsentiert
define woodstock dummy
# verdoppelte Status
attr woodstock setList on off ON OFF
# Das Status-Icon reagiert jeweils gleich auf on und ON sowie auf off und OFF;
# die bei Klick auf das Icon gesendeten Befehle sind aber immer on und off

attr woodstock devStateIcon on:on:off ON:on:off off:off:on OFF:off:on

# Kopplung von on und off des dummys an die entsprechenden Kommandozeilenprogramme
define woodstockOn notify woodstock:on "/usr/local/bin/wake woodstock"
define woodstockOff notify woodstock:off "/usr/local/bin/sleepmac woodstock"


# Definition der PRESENCE-Instanz für ping-Abfragen im Sekundenabstand
define woodstock_STATE PRESENCE lan-ping woodstock 1 1
# Bei sekündlichen Abfragen können wir nur einen ping pro Abfrage nutzen; sollte der einmal nicht funktionieren, ist das
# angesichts der sekündlichen Abfragen kein Problem

attr woodstock_STATE ping_count 1

# Kopplung des Status von woodstock_STATE an den dummy woodstock (Updates werden nur bei verändertem Status gesendet)
define woodstock_PAIRon notify woodstock_STATE:present { if(Value("woodstock") eq "OFF" || Value("woodstock") eq "off") { fhem("set woodstock ON") } }
define woodstock_PAIRoff notify woodstock_STATE:absent { if(Value("woodstock") eq "ON" || Value("woodstock") eq "on") { fhem("set woodstock OFF") } }



Zusammenfassung

Die Lösungen scheinen ziemlich gleichwertig zu sein; sie arbeiten, so weit ich sehen kann, gleich stabil, und sie haben etwa die gleiche Anzahl von Zeilen in fhem.cfg (die 2. Lösung ist eine Zeile kürzer).

Einen kleinen Unterschied im Verhalten gibt es aber, der sich nur dann bemerkbar macht, wenn zwischen einem Klick auf das Status-Icon und dem Zeitpunkt, wo der erstrebte Status erreicht wird, einige Zeit (ein paar Sekunden) vergehen. Typischerweise ist das beim Aufwecken eines Computers der Fall; bis er wieder auf pings reagiert, können einige Sekunden verstreichen (der Ruhezustand hingegen tritt zumindest bei Macs ohne Zeitverzögerung ein).

Das PRESENCE-Modul ist nun so programmiert, dass sich das Status-Icon erst ändert, wenn der Zielzustand erreicht ist. Klicke ich also, wenn der Computer auf off steht, auf on, so bleibt das Status-Icon zunächst unverändert auf off. Erst wenn der Computer wirklich vollständig aufgewacht ist (= auf pings reagiert), wechselt das Status-Icon auf on.

Die 2. Lösung verhält sich hier anders. Ein Klick auf on im dummy setzt dessen Status-Icon sofort auf on; macht woodstock_STATE sein nächstes Statusupdate, wird das Status-Icon zunächst wieder auf off gesetzt, bis es schließlich erneut auf on springt, wenn der Computer vollständig aufgewacht ist.

Mit anderen Worten: Die 1. Lösung verhält sich ,,gelassener"; das Status-Icon ändert sich erst, wenn der Zielstatus erreicht ist. Dafür erhält man keinerlei Feedback, ob man tatsächlich geklickt hat. Die 2. Lösung bietet dieses Feedback, weil das Status-Icon kurzzeitig auf on springt, bevor es zunächst wieder auf off zurückfällt; dafür wirkt dieses Verhalten unruhiger. Letztlich ist das eine Geschmacksfrage; und man kann sich anhand ihrer ja die genehme Lösung aussuchen.

marvin78

Die beste Lösung ist jedoch Möglichkeit 3: ein einziges PRESENCE Device, das, wie beschrieben, ohne zusätzlichen dummy und notify auskommt.

Uli Zappe

Zitat von: marvin78 am 08 Juli 2016, 07:35:22
Die beste Lösung ist jedoch Möglichkeit 3: ein einziges PRESENCE Device, das, wie beschrieben, ohne zusätzlichen dummy und notify auskommt.

Nein, unter den eingangs explizit aufgelisteten Vorraussetzungen für die geschilderten Lösungen ...
Zitat von: Uli Zappe am 08 Juli 2016, 05:13:35
Ebenso habe ich auf kompliziertere Dinge wie Perl-Subroutinen verzichtet
... gibt es diese dritte Möglichkeit nicht.

Warum sie besser sein sollte als die 1. Lösung, wird auch Dein Geheimnis bleiben. Ob man nun einen Dummy oder eine Perl-Subroutine bevorzugt, ist wohl eher Geschmackssache. Und da sich so ein detailliert geschilderter Lösungsvorschlag eher an Einsteiger richtet, fand ich die Lösung ohne Perl-Subroutine die geeignetere. Wer mit Perl-Subroutinen umgehen kann, wird kein Problem damit haben, meinen Dummy durch die von Dir ja zuvor geschilderte Lösung zu ersetzen.

marvin78

Lösungen, die auf weniger Devices setzen (die ggf. gepflegt werden müssen) sind als effektiver und einfacher wartbar zu bezeichen. Das besagt schon die Logik. Zu erwähnen ist die "Ein-Device-Lösung" hier in jedem Fall.

Benni

Außerdem ist jedes zusätzliche notify auch eine zusätzliche (Performance-)Belastung für das System.

justme1968

schön das du deine beiden varianten so ausführlich vorstellst.

zu ein device ist besser:
es gibt in fhem einige stellen an denen die komplette device liste durchgegangen werden muss um bestimmte dinge zu tun. sehr viele davon sind zwar inzwischen optimiert. und es macht tatsächlich auf fast keiner platform mehr einen unterschied ob man ein device mehr hat oder nicht. du darfst aber nicht vergessen das auch notifys als device zählen. in deinem beispiel wird also nicht nur ein zusätzlicher dummy verwendet sondern insgesamt sind es pro presence drei zusätzliche devices bzw. insgesamt vier mal so viele. wenn man das überall macht summiert es sich sehr schnell.

für jeden (auch für dich) wird es in ein paar tagen oder wochen einfacher sein ein einziges device anzuschauen und nachzuvollziehen als vier die miteinander verknüpft sind.

es sind übrigens keine komplizierten perl subroutinen nötig. du kannst entweder der perl code direkt im powerCmd attribut angeben oder du kannst deine beiden wake und sleep programme (z.b. per shellscript) zu einem zusammen fassen und beim aufruf den aktuellen zustand mit übergeben.

spätestens wenn du mehr als ein gerät auf diese art einbinden willst und die ein device variante den beiden eben vorstellten gegenüber stellst sollte ersichtlich sein wie viel weniger zeilen implementierung und weniger duplizierten code du damit hast.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Uli Zappe

Zitat von: justme1968 am 08 Juli 2016, 10:40:46
zu ein device ist besser:
[... gute Argumente pro 1 device ...]
Das ist historisch ganz witzig:

Die Lösung, die ich jetzt endlich endgültig angegangen bin, schwebte mir schon seit 2012 vor, als ich mit FHEM begann. Damals gab es PRESENCE noch nicht, und ich habe daher im Forum zur Diskussion gestellt, ob es in FHEM ein Modul für Geräte wie Computer etc. geben sollte, die besondere Ein-/Ausschaltkommandos haben und deren Status durch sowas wie pings regelmäßig überprüft werden muss.

Rudis Antwort war damals sinngemäß, ich würde zu monolithisch denken. FHEM sei aber ein modulares System, und viel besser als ein solch ,,großes", zu spezialisiertes Device seien mehrere kleinere, die durch notify verbunden werden. Das habe ich seitdem zu beherzigen versucht.  ;)

Generell finde ich, bei der heute verfügbaren Rechenleistung spielt der Anspruch an Systemressourcen eine untergeordnete Rolle. Wobei ja sogar auf meinem 400-MHz-ARM-FHEM-Rechnerchen mit gerade mal 64 (!) MB RAM jetzt 5 PRESENCE-Instanzen mit Abfragen im Sekundentakt samt notifys und dummys völlig problemlos laufen. Da sind Fragen wie Code-Verständlichkeit IMHO wichtiger, und was man verständlicher findet, ist zu einem gewissen Grad dann wieder subjektiv.

Wie auch immer, für mich selbst stellt sich diese Frage jetzt ohnehin nicht, da ich mich nach einem Tag ausgiebiger Tests jetzt für Lösung 2 entschieden habe, da mir das unmittelbare visuelle Feedback, dass der Befehl getriggert wurde, wichtiger ist, als ich vermutet hätte. Aber wenn man mehrere Sekunden warten muss, bis das Status-Icon umspringt, und man bis dahin einfach nicht weiß, ob man mit seinem Wurstfinger auf dem Smartphone überhaupt den Schalter getroffen hat, kann das ziemlich irritieren.

justme1968

nur der vollständigkeit halber: auch das geht mit einem einzigen device :)

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Uli Zappe


Uli Zappe

Nachdem sich hier mehrere Forumsteilnehmer für eine Lösung mit nur einem FHEM-Gerät stärkt gemacht haben und bei einer vollumfänglichen Implementierung auch noch Logging-Probleme auftauchen, die am besten in einer Perl-Subroutine zu behandeln sind, möchte ich abschließend noch eine etwas ausgefeiltere Lösung vorstellen, die an Lösung 1 anknüpft, aber mit solch einer Perl-Subroutine arbeitet. Sie löst das Logging-Problem und erlaubt auch, ein GUI-Feedback einzuschalten, wie es oben nur Lösung 2 bot.

Zunächst zu dem
Logging-Problem:

Anders als etwa das Ein- und Ausschalten einer Lampe ist das Aufwecken und Schlafenlegen z.B. eines Computers keine ganz triviale Angelegenheit, weswegen ich gerne auch die erfolgreiche Befehlsausführung in der globalen FHEM-Logdatei protokolliert haben wollte.

Nun gibt es in FHEM aber leider einen seltsamen Bug oder jedenfalls ein ungelöstes Problem: Der Rückgabewert von Shell- bzw. Kommandozeilenbefehlen lässt sich in Perl nicht ermitteln; sowohl system() als auch Backquotes geben in Kontrast zu korrektem Verhalten immer den Wert -1 zurück, ganz egal, wie der tatsächliche Rückgabewert lautete.

Zudem sind Fehlermeldungen der Kommandozeile nur dann in Perl verfügbar, wenn sie auf stdout geschrieben wurden; d.h. stderr muss stets auf stdout umgeleitet werden. Die einzige Möglichkeit, dann noch Erfolgs- von Fehlermeldungen zu unterscheiden, ist, Erfolgsmeldungen zu unterdrücken (= Umleitung von stdout auf /dev/null), so dass ein leerer String als Rückgabewert mit Erfolg gleichzusetzen ist; in Perl muss die Erfolgsmeldung dann neu erzeugt werden.

Das ist die Methode, die die folgende Perl-Subroutine mit

Kommandozeilenbefehl 2>&1 1>/dev/null

anwendet.


Die Perl-Subroutine powerCommand()

Ich habe versucht, eine – jedenfalls im Rahmen meines Anwendungsspektrums – möglichst universell einsetzbare Subroutine zu stricken. Einige Voraussetzungen in Bezug auf die Shellskripte oder Kommandozeilenbefehle, die die eigentlichen Aktionen auslösen, gibt es aber:

  • Die Befehle reagieren entweder auf die Parameter on und off, oder es gibt zu Aufwecken und Schlafenlegen zwei getrennte Befehle.
  • Die Befehle benötigen als Parameter entweder den (auflösbaren) Hostnamen bzw. die IP-Adresse des zu kontrollierenden Gerätes im Netzwerk, oder sie benötigen gar keinen solchen Parameter (weil es nur ein entsprechendes Gerät gibt, dessen IP-Adresse fest in den Befehl eincodiert ist)
  • Werden sowohl Hostname als auch Ein-/Aus-Parameter benötigt, ist die Parameter-Reihenfolge befehl hostname on|off
  • Die Befehle liegen, wie für nutzerspezifische Befehle üblich, in /usr/local/bin/. Wird zum Aufwecken z.B. /usr/bin/wakeonlan verwendet, so hilft ein Link nach /usr/local/bin/.

Die Subroutine hat die folgenden 7 Parameter:

presenceName, hostname, action, command, onCommand, offCommand, guiFeedback

  • presenceName Der Name der PRESENCE-Instanz, als deren powerCmd die Subroutine gesetzt wird. Steht in PRESENCE als Variable $NAME zur Verfügung. Wenn der Name der PRESENCE-Instanz identisch ist mit dem Hostnamen des zu kontrollierenden Gerätes, kann auch ein leerer String übergeben werden.
  • hostname Der (auflösbare) Hostname bzw. die IP-Adresse des zu kontrollierenden Gerätes, oder ein leerer String, falls der/die Kommandozeilenbefehl(e) diese Angabe nicht benötigen
  • action on oder off. Steht in PRESENCE als Variable $ARGUMENT zur Verfügung.
  • command Der Kommandozeilenbefehl (ohne Pfad), der unter Auswertung der Parameter on oder off das zu kontrollierende Gerät aufweckt oder schlafenlegt, oder ein leerer String, falls für Aufwecken und Schlafenlegen zwei unterschiedliche Befehle benötigt werden.
  • onCommand Der Kommandozeilenbefehl (ohne Pfad), der das zu kontrollierende Gerät aufweckt, oder ein leerer String, falls hierfür ein kombinierter Befehl mit den Parametern on und off verwendet wird
  • offCommand Der Kommandozeilenbefehl (ohne Pfad), der das zu kontrollierende Gerät schlafenlegt, oder ein leerer String, falls hierfür ein kombinierter Befehl mit den Parametern on und off verwendet wird
  • guiFeedback Schaltet das GUI-Feedback aus (0) oder ein (jeder andere Wert). Ist das GUI-Feedback eingeschaltet, wechselt das Schaltflächen-Icon bei Betätigung kurz in den Zielzustand, um die Auslösung de Befehls zu signalisieren, bevor das Icon wieder den Ist-Zustand anzeigt, bis der Zielzustand tatsächlich erreicht ist

Die oben immer als Beispiel verwendete Ansteuerung des Computers woodstock sähe (mit GUI-Feedback) nun so aus:

define woodstock_STATE PRESENCE lan-ping woodstock 1 1
attr woodstock_STATE ping_count 1
attr woodstock_STATE devStateIcon present:on:off absent:off:on
attr woodstock_STATE eventMap /power on:on/power off:off/
attr woodstock powerCmd {powerCommand("", $NAME, $ARGUMENT, "", "wake", "sleepmac", 1)}
attr woodstock_STATE event-on-change-reading state


Ein anderes Beispiel: Ich habe einen Video-Projektor, der mit projector on|off gesteuert wird (da ich nur einen Video-Projektor habe, ist der Hostname fest codiert und muss nicht angegeben werden). Hier sähe die Definition wie folgt aus:

define Projektor PRESENCE shellscript '/usr/local/bin/projector numstate' 1 1
attr Projektor ping_count 1
attr Projektor devStateIcon present:on:off absent:off:on
attr Projektor eventMap /power on:on/power off:off/
attr Projektor powerCmd {powerCommand($NAME, "", $ARGUMENT, "projector", "", "", 1)}
attr Projektor event-on-change-reading state



Und hier schließlich der Code für die Perl-Subroutine, der nach 99_myUtils.pm kopiert werden muss. Ich hoffe, das hilft einigen, die ein ähnliches Einsatzszenario wie ich haben.

sub powerCommand($$$$$$$)
{
# arguments
my ($presenceName, $hostname, $action, $command, $onCommand, $offCommand, $guiFeedback) = @_;

# variables for building and executing the command
my $onCommandString;
my $offCommandString;
my $presenceState;
my $returnValue = "Internal error";

# variables for builing the success log message
my $successMessageOnCommandName;
my $successMessageOffCommandName;
my $successMessageDeviceName;
my $successMessage;

# sanity check
return "Configuration error: Either \$presenceName or \$hostname must be specified" if $presenceName eq "" && $hostname eq "";
return "Configuration error: Either \$command or \$onCommand and \$offCommand must be specified" if $command eq "" && ($onCommand eq "" || $offCommand eq "");

# initialize variables
$presenceName = $hostname if $presenceName eq "";
$presenceState = Value($presenceName);
$successMessageDeviceName = ($hostname eq "")? $presenceName : $hostname;

# build command strings and log message command names
# to be able to tell success from failure, stdout is ignored (= redirected to /dev/null), i.e. an empty return means success
# stderr is redirected to stdout so that error messages can be logged
if ($command eq "") # different commands for on and off
{
$successMessageOnCommandName = $onCommand;
$successMessageOffCommandName = $offCommand;
$onCommandString = "/usr/local/bin/$onCommand $hostname 2>&1 1>/dev/null";
$offCommandString = "/usr/local/bin/$offCommand $hostname 2>&1 1>/dev/null";
}
else # command with on|off argument for on and off
{
$successMessageOnCommandName = $successMessageOffCommandName = $command;
$onCommandString = "/usr/local/bin/$command $hostname on 2>&1 1>/dev/null";
$offCommandString = "/usr/local/bin/$command $hostname off 2>&1 1>/dev/null";
}

# depending on $action argument, build log message success string and execute command
if ("$action" eq "on" && $presenceState eq "absent")
{
$successMessage = "$successMessageOnCommandName: Waking \"$successMessageDeviceName\"";
fhem("setreading $presenceName state on") if $guiFeedback;
$returnValue = `$onCommandString`;
}
elsif ("$action" eq "off" && $presenceState eq "present")
{
$successMessage = "$successMessageOffCommandName: Putting \"$successMessageDeviceName\" to sleep";
fhem("setreading $presenceName state off") if $guiFeedback;
$returnValue = `$offCommandString`;
}
else {return 0;} # do nothing

# in case of success (= empty result string), log success message
Log 3, "PRESENCE ($presenceName) - $successMessage" if $returnValue eq "";

# return 0 (= success) or error message
return $returnValue;
}