FHEM Forum

FHEM => Anfängerfragen => Thema gestartet von: Nogga am 12 Februar 2018, 12:52:37

Titel: Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: Nogga am 12 Februar 2018, 12:52:37
Hallo zusammen,

meine Pflanzen möchte ich (noch) nicht mit Sensoren ausstatten. Als notorischer Gieß-Vergesser möchte ich aber trotzdem das Gießen in FHEM nachhalten.

Meine Idee:

1. Jede Pflanze bekommt ein Dummy
2. Der Dummy hat das letzte Gießdatum ("LetztesGiessen")
3. Zusätzlich auch ein Gießintervall in Tagen ("GiessIntervall")

Jetzt möchte ich:
FHEM regelmäßig checkt, ob das Intervall erreicht ist, wenn ja ein (state) Reading von "OK" auf "Gießen" stellt.
Per webcmd möchte ich dann wiederum das Gießen "abschließen", d.h. das Datums-Reading wieder auf jetzt stellen bei Auslösen.

Ich glaube, das ist ziemlich simpel. Aber irgendwie stehe ich auf dem Schlauch. Insbesondere das Datum, bzw. die Fälligkeit  zu kalkulieren...

Der Vollständigkeit halber, was ich dann noch vorhabe:
Über alle Pflanzen-Dummies ziehe ich eine Readingsgroup. In meinem Tablet UI zähle ich zunächst die überfälligen Pflanzen und zeige dies mit einem Icon + Counter an (vgl. Fenster-Offen-Counter). Über ein Popup zeige ich dann alle fälligen Pflanzen an, die ich dann per Touch "als gegossen" zurücksetzen kann).
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: rabehd am 12 Februar 2018, 13:24:33
Ich habe ähnliche Fragen per Forensuche und Google lösen können. U.a. mir Hilfe des Blogs von Otto (glaube ich).

Zuerst würde ich Das stückweise verwirklichen.

ZitatFHEM regelmäßig checkt, ob das Intervall erreicht ist, wenn ja ein (state) Reading von "OK" auf "Gießen" stellt.
Wie wäre es mit einem at?

ZitatPer webcmd möchte ich dann wiederum das Gießen "abschließen", d.h. das Datums-Reading wieder auf jetzt stellen bei Auslösen.
http://heinz-otto.blogspot.de/2017/01/ein-remote-taster-in-fhem-mit.html (http://heinz-otto.blogspot.de/2017/01/ein-remote-taster-in-fhem-mit.html)
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: Nogga am 12 Februar 2018, 13:29:25
Ich glaube auch, dass ich das alleine hinbekomme. Das at ist mir klar.
Das einzige, was evtl. zur Selbsthilfe fehlt ist das spezifische Intervall berechnen.

Sowas in der Art (Pseudocode):

if ((JetztTimestamp - IntervallAusReading) > LetztesGiessenAusReading) set Dummy.state = 'Giessen'

Wie mache ich das in Perl?
Idealerweise als wiederverwendbares Stück Code, das ich in jedes Dummy einpflanzen kann, bzw. 1x generisch per at aufrufen kann und alle Dummies abklopft...
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: rabehd am 12 Februar 2018, 15:38:43
Im Dummy wird Dir der Code nichts nutzen. Du musst die Berechnung doch auslösen.

Ich würde eine Funktion für 99_myUtils.pm bauen, welche ein Datum und ein Intervall übergeben bekommt und damit das Zieldatum errechnet.
(Gibt es bestimmt schon zum Koiieren)

Im at gehtst Du die einzelnen Dummys ab. Rufst mit deren Werten die Funktion auf. Wertest das Ergebnis aus und setzt ggf. den Wert für den Dummy.

Lässt sich natürlich noch optimieren.
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: CoolTux am 12 Februar 2018, 18:58:19
Gab es da nicht mal so ein Modul für Erinnerungen? Mir fällt da leider gerade nicht ein wie das heißt.
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: Nogga am 12 Februar 2018, 22:23:15
Meine letzten Perl-Ausflüge sind ungefähr 15 Jahre her... ziemlich eingerostet.

In der Theorie sollte alles klappen, nur das Auslesen der Timestamps über ReadingsVal funktioniert nicht. Kann da jemand helfen?
Und zuletzt: wie bekomme ich das at und notify generisch hin, dass ich im Zweifel alle "Pflanze_.*" oder noch besser alle Dummies mit dem Attribut Pflanze = 1 selektiere.

Folgende Logik:
- Ein Dummy repräsentiert eine Pflanze.
- Das letzte Giessen steckt in letztesGiessenTimestamp
- giessenIntervall ist in Sekunden
- das notify aktualisiert das letzte Giessen (kann man das auch direkt im Dummy einbauen?!)
- das at (nur zum Test alle 10 Sekunden) checkt ob das (Letzte Giessen + Interval) schon in der Vergangenheit liegt, wenn ja, dann muss gegossen werden und der Status des Dummies wird gesetzt


Folgendes habe ich zusammen:

defmod Pflanze_1 dummy
attr Pflanze_1 userattr letztesGiessenTimestamp giessenIntervall Pflanze
attr Pflanze_1 Pflanze 1
attr Pflanze_1 giessenIntervall 120
attr Pflanze_1 letztesGiessenTimestamp 1518469613
attr Pflanze_1 room Tablet-UI
attr Pflanze_1 setList state:ok,giessen
attr Pflanze_1 webCmd update


defmod notify_Pflanze_1 notify Pflanze_1 {\
if ("$EVENT" eq "update")\
{\
fhem('attr Pflanze_1 letztesGiessenTimestamp '.time());;\
}\
}\

attr notify_Pflanze_1 room Tablet-UI


defmod At_Pflanzen_Check at +*00:00:10 {\
Debug(ReadingsVal('Pflanze_1', 'letztesGiessenTimestamp', 0));;\
Debug(ReadingsVal('Pflanze_1', 'giessenIntervall', 0));;\
Debug(time());;\
if (ReadingsVal('Pflanze_1', 'letztesGiessenTimestamp', 0) + ReadingsVal('Pflanze_1', 'giessenIntervall', 0) > time())\
{\
# alles ok - Zeit noch nicht abgelaufen\
fhem("set Pflanze_1 ok");;\
Debug('Pflanze 1 ist ok');;\
}\
else\
{\
# nicht ok - Zeit ist abgelaufen!\
fhem("set Pflanze_1 giessen");;\
Debug('Pflanze 1 ist nicht ok - giessen!');;\
}\
}
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: Amenophis86 am 12 Februar 2018, 22:31:29
Zitat von: CoolTux am 12 Februar 2018, 18:58:19
Gab es da nicht mal so ein Modul für Erinnerungen? Mir fällt da leider gerade nicht ein wie das heißt.

Denke du meinst https://fhem.de/commandref_DE.html#monitoring
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: CoolTux am 13 Februar 2018, 07:43:40
Zitat von: Amenophis86 am 12 Februar 2018, 22:31:29
Denke du meinst https://fhem.de/commandref_DE.html#monitoring

Jepp. Würde dann wohl unter regelmäßige Wartungsarbeiten (z.B. Tischwasserfilter wechseln oder Räume putzen) fallen.
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: CoolTux am 13 Februar 2018, 07:46:28
Zitat von: Nogga am 12 Februar 2018, 22:23:15
Meine letzten Perl-Ausflüge sind ungefähr 15 Jahre her... ziemlich eingerostet.

In der Theorie sollte alles klappen, nur das Auslesen der Timestamps über ReadingsVal funktioniert nicht. Kann da jemand helfen?
Und zuletzt: wie bekomme ich das at und notify generisch hin, dass ich im Zweifel alle "Pflanze_.*" oder noch besser alle Dummies mit dem Attribut Pflanze = 1 selektiere.

Folgende Logik:
- Ein Dummy repräsentiert eine Pflanze.
- Das letzte Giessen steckt in letztesGiessenTimestamp
- giessenIntervall ist in Sekunden
- das notify aktualisiert das letzte Giessen (kann man das auch direkt im Dummy einbauen?!)
- das at (nur zum Test alle 10 Sekunden) checkt ob das (Letzte Giessen + Interval) schon in der Vergangenheit liegt, wenn ja, dann muss gegossen werden und der Status des Dummies wird gesetzt


Folgendes habe ich zusammen:

defmod Pflanze_1 dummy
attr Pflanze_1 userattr letztesGiessenTimestamp giessenIntervall Pflanze
attr Pflanze_1 Pflanze 1
attr Pflanze_1 giessenIntervall 120
attr Pflanze_1 letztesGiessenTimestamp 1518469613
attr Pflanze_1 room Tablet-UI
attr Pflanze_1 setList state:ok,giessen
attr Pflanze_1 webCmd update


defmod notify_Pflanze_1 notify Pflanze_1 {\
if ("$EVENT" eq "update")\
{\
fhem('attr Pflanze_1 letztesGiessenTimestamp '.time());;\
}\
}\

attr notify_Pflanze_1 room Tablet-UI


defmod At_Pflanzen_Check at +*00:00:10 {\
Debug(ReadingsVal('Pflanze_1', 'letztesGiessenTimestamp', 0));;\
Debug(ReadingsVal('Pflanze_1', 'giessenIntervall', 0));;\
Debug(time());;\
if (ReadingsVal('Pflanze_1', 'letztesGiessenTimestamp', 0) + ReadingsVal('Pflanze_1', 'giessenIntervall', 0) > time())\
{\
# alles ok - Zeit noch nicht abgelaufen\
fhem("set Pflanze_1 ok");;\
Debug('Pflanze 1 ist ok');;\
}\
else\
{\
# nicht ok - Zeit ist abgelaufen!\
fhem("set Pflanze_1 giessen");;\
Debug('Pflanze 1 ist nicht ok - giessen!');;\
}\
}


Da Du Deinen Code aus der Config Datei hast kann ich da nicht helfen. Keine Lust irgendein Backslash zu über sehen. So was ist unnötig. Alles kann man in der Detailansicht mit DEF editieren, sogar mit Syntaxprüfung. Ansonsten ein list vom Device/Notify passt gut damit wir alles sehen können.
Timestamp mact man mit ReadingsTimestamp. Da ich das auch nicht altäglich mache musste ich auch danach suchen, und was soll ich sagen mit der suche findet man das sogar.
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: Nogga am 13 Februar 2018, 08:07:38
Ich habe meinen Code nicht aus der Config genommen, da ich die ConfigDB nutze. Offensichtlich hat er die Escapes beim Kopieren eingefügt. Ich habe alle Definitionen aus den DEF bzw RawDefinition Feldern. Aber ichbwerde mir ReadingsTimestamp nochmal genauer ansehen. Danke.
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: Nogga am 13 Februar 2018, 08:15:31
Ich habe gerade gesehen, dass ich wohl alles aus den RawDefinitions genommen habe statt aus den DEF Feldern, deswegen die Escapes... aber ich werde es heute Abend auch gerne nochmal sauber als copy aus den DEF Feldern Posten...
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: Nogga am 13 Februar 2018, 22:15:10
So, ich glaube ich habe es jetzt geschafft. Das at checkt wann zuletzt gegossen wird und wenn das Intervall überschritten wird, dann wird die Pflanze auf giessen (=pour) gesetzt.

Jetzt fehlt nur noch ein Detail: das notify reagiert momentan auf ein bestimmtes Dummy (Pflanze_1), wie bekomme ich das generisch hin, dass auf alle Dummies mit dem Attribut model=Pflanze reagiert wird?

(Dummy aus dem Raw Definition, notify und at aus dem DEF-Editor kopiert...)


defmod Pflanze_1 dummy
attr Pflanze_1 userattr pourInterval model
attr Pflanze_1 model Pflanze
attr Pflanze_1 pourInterval 20
attr Pflanze_1 room Tablet-UI
attr Pflanze_1 setList state:ok,giessen
attr Pflanze_1 webCmd update


At_Pflanzen_Check:
+*00:00:10 {
if (time_str2num(ReadingsTimestamp('Pflanze_1', 'lastPouringTimestamp', 0)) + AttrVal('Pflanze_1', 'pourInterval', 0) > time())
{
# alles ok - Zeit noch nicht abgelaufen
fhem("set Pflanze_1 ok");
Debug('Pflanze 1 ist ok');
}
else
{
# nicht ok - Zeit ist abgelaufen!
fhem("set Pflanze_1 giessen");
Debug('Pflanze 1 ist nicht ok - giessen!');
}
}


Notify:
Pflanze_1 {
if ("$EVENT" eq "update")
{
fhem('setreading $NAME lastPouringTimestamp '.localtime());
fhem('set $NAME ok');
}
}
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: CoolTux am 14 Februar 2018, 05:51:15
Dein Notify sieht seltsam aus und sollte so eigentlich nicht gehen. Ausser es fehlt hier in der Anzeige was.

Notify arbeitet mit RegEx. Mach also aus Dein Pflanze_1 ein Pflanze.* als Trigger und überall wo Du im Code Pflanze_1 hast machst Du $NAME
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: Nogga am 14 Februar 2018, 09:31:03
Naja eine Regex muss nicht immer wildcards haben /Pflanze_1/ funktioniert genau so. Halt exakt auf den Namen.
Die Variante mit .* auf den Namen kenne ich. Ich wollte aber nicht auf Namen filtern, sondern auf Attribute.. ich habe das schon gesehen, finde es aber nicht mehr.
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: CoolTux am 14 Februar 2018, 10:12:04
Du kannst ein Notify RegEx nur auf NAME triggern lassen.
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: maci am 14 Februar 2018, 15:24:35
Wenn bereits das Kalendermodul aktiv ist, dann würde ich den benutzen
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: Nogga am 14 Februar 2018, 16:02:20
Das ist grundsätzlich schon in Betrieb und hatte ich mir auch überlegt. Ich wollte aber bewusst diese Funktionalität, da ich ähnlich einer Ablaufgestützten Todo Liste immer wieder bestätigen muss. Schlussendlich bestimmt sich ja das nächste mal nicht zwingend auf ein Datum, sondern vielmehr auf das letzte Mal...
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: Nogga am 15 Februar 2018, 21:27:21
Tut mir Leid, aber ich komm jetzt wieder nicht weiter.
Das at klappt jetzt auf einem spezifischen Device. Aber wie bekomme ich es hin, dass er alle Devices "Pflanze_.*" berücksichtigt?
Titel: Antw:Tage-Counter mit Dummy (Pflanzen Gießen Erinnerung)
Beitrag von: Nogga am 19 Februar 2018, 22:34:55
Ich habe jetzt meine uralten Perl-Kenntnisse nochmal ausgegraben und habe tatsächlich eine Routine gebaut, die auch funktioniert.
Das ganze ist jetzt so flexibel, dass man grundsätzlich alles damit prüfen kann (z.B. das letzte Mal Pflanzen gießen, Fenster putzen, usw). Klar man könnte das über einen Kalender machen, aber wenn es auf die Zeitdifferenz ankommt, nicht auf den eigentlichen Zeitpunkt, dann ist meine Variante glaube ich sinnvoller?! Bitte entschuldigt, wenn ich ggf. etwas umständlich umgesetzt habe... Das einzige das noch fehlt ist ein generisches notify, bzw. ggf. ein DOIF mit dem ich alle Dummies mit dem Attribut "periodicCheck = 1" filtern kann... Aber vielleicht sehe ich auch vor lauter Bäumen den Wald nicht mehr.

Jetzt aber die Code-Schnipsel:

Dummy:
defmod Pflanze_1 dummy
attr Pflanze_1 userattr periodicCheck periodicInterval periodicStates
attr Pflanze_1 periodicCheck 1
attr Pflanze_1 periodicInterval 60
attr Pflanze_1 periodicStates ok:giessen
attr Pflanze_1 room Tablet-UI
attr Pflanze_1 setList state:ok,giessen
attr Pflanze_1 webCmd update


Notify um den Timestamp (z.B. das effektive Gießen) zu aktualisieren:
Pflanze_.*
{
if ("$EVENT" eq "update")
{
my @states = split(/\:/, AttrVal($NAME, 'periodicStates', 'ok:not ok'));

fhem("set $NAME " . $states[0]);
fhem("setreading $NAME lastPeriodicTimestamp " . localtime());
}
}


At um periodisch den Check laufen zu lassen:
+*00:01:00 { periodicCheck(); }

Und jetzt die "Magie" in der myUtils:
# BEGIN - sub periodicCheck()
# Check all dummies, if the last update has exceeded the defined interval (e.g. last pouring of a plant)
# Attributes of dummy:
#   periodicCheck = 1 (only check these)
#   periodicInterval = interval in seconds before that
#   periodicStates = "ok:not ok" (colon to split)
sub periodicCheck()
{
#Debug('Periodic Check started...');
    #Debug(devspec2array("TYPE=dummy:FILTER=periodicCheck=1"));

# filter for periodicCheck dummies
my @filtered_devs = devspec2array("TYPE=dummy:FILTER=periodicCheck=1");
my $dev = '';

# loop through all found devices
foreach $dev (@filtered_devs) {

# check if this is an existing device
    if ($defs{$dev})
{
# get the defined states
my @states = split(/\:/, AttrVal($dev, 'periodicStates', 'ok:not ok'));

# check if the the timestamp expired
if (time_str2num(ReadingsTimestamp($dev, 'lastPeriodicTimestamp', 0)) + AttrVal($dev, 'periodicInterval', 0) > time())
{
# all ok, not expired
fhem("set $dev " . $states[0]);
}
else
{
# not ok - time expired!
fhem("set $dev " . $states[1]);
}
}

}

}
# END - sub periodicCheck