Taster (FT55): notify für "Taste lange gedrückt" und "Doppelklick"

Begonnen von 50watt, 07 April 2014, 21:19:43

Vorheriges Thema - Nächstes Thema

krikan

Halte Deine Lösung für besser. Meine hat in der derzeitige Form die "Nebenwirkung", dass Sie B0 und BI-Events nicht unterscheidet. Hierzu müsste das notify weiter mit Abfragen für BO und BI ausgebaut werden, dann wird es mMn zu kompliziert...

Für Einfach- versus Doppelklick finde ich Andre´s (justme1968) Ansatz hier http://forum.fhem.de/index.php/topic,12965.msg186119.html#msg186119 umsetzbar.

krikan

"Doppelklick"

Habe Andre´s Vorschlag zur Unterscheidung von Einfach- und Doppelklick einmal umgesetzt. Folgenden Code für eine Tasterseite (B0) hat bei mir ohne erkennbare Nebenwirkungen funktioniert:

define sDoppelklickB0 sequence Taster2:channelB:.B0 1 Taster2:channelB:.B0
define nDoppelklickB0 notify DoppelklickB0:trigger { fhem "set Lampe off" }
define wEinfachklickB0 watchdog Taster2:channelB:.B0 00:00:01 SAME set Lampe on;; trigger wEinfachklickB0 .
attr wEinfachklickB0 regexp1WontReactivate 1

"Taste lange gedrückt"


Für die Unterscheidung von Kurz- und Langklick auf Timestamp-Basis habe ich meinen Code überarbeitet/korrigiert. Beide Tasterseiten (B0/BI) unterscheiden hiermit die Tastdauer:

define nklickdauer notify Taster:buttons:.released {\
my $start=time_str2num(ReadingsTimestamp("$NAME", "channelB", 0));;\
my $stop=time_str2num(ReadingsTimestamp("$NAME", "buttons", 0));;\
if (ReadingsVal("$NAME","channelB",0) eq "B0"){\
if ($stop-$start<=1) {fhem "set Raffstore 50"} else {fhem "set Raffstore 100"}}\
else {if ($stop-$start<=1) {fhem "set Raffstore 20"} else {fhem "set Raffstore 80"}}\
}


Gleichen Zweck erfüllt auch der Code von zfranz für eine Tasterseite (BI) (http://forum.fhem.de/index.php/topic,22289.msg186089.html#msg186089):

define Schalter1BIlongclick notify Schalter1:BI { fhem "define Test at +00:00:01 set Alles off" }
define sSchalter1BIlongclick sequence Schalter1:BI 1 Schalter1:buttons:.*released
define nSchalter1BIlongclick notify sSchalter1BIlongclick:trigger { fhem "delete Test" }


Wenn noch jemand Verbesserungsvorschläge/andere Ideen hat, dann bitte anführen.

crispinus

Zitat von: krikan am 25 Juli 2014, 21:38:15
Für die Unterscheidung von Kurz- und Langklick auf Timestamp-Basis habe ich meinen Code überarbeitet/korrigiert. Beide Tasterseiten (B0/BI) unterscheiden hiermit die Tastdauer:

define nklickdauer notify Taster:buttons:.released {\
my $start=time_str2num(ReadingsTimestamp("$NAME", "channelB", 0));;\
my $stop=time_str2num(ReadingsTimestamp("$NAME", "buttons", 0));;\
if (ReadingsVal("$NAME","channelB",0) eq "B0"){\
if ($stop-$start<=1) {fhem "set Raffstore 50"} else {fhem "set Raffstore 100"}}\
else {if ($stop-$start<=1) {fhem "set Raffstore 20"} else {fhem "set Raffstore 80"}}\
}


Ich habe das heute mal mit meinem FT55 ausprobiert und stieß dabei auf das Problem, dass die auch noch vorhandene A-Seite vergessen wurde (also A0/AI), das führt nämlich dazu, dass das notify auch reagiert, wenn die A-Seite und nicht die B-Seite gedrückt wurde und dann eben einen langen Tastendruck annimmt (das abgefragte released-Event wird ja auch beim Drücken der A-Hälfte des Tasters erzeugt). Ich habe den Code nun wie folgt verändert und damit eine Tasterfunktion nach meinen Wünschen erhalten, bei denen sich alle vier möglichen Tasteraktionen eines FT55 je noch einmal nach lang und kurz unterscheiden und sich damit je Taster somit de facto acht Schaltaufträge unterscheiden lassen:

define nklickdauer notify Taster:buttons:.released {\
my $startA=time_str2num(ReadingsTimestamp("$NAME", "channelA", 0));;\
my $startB=time_str2num(ReadingsTimestamp("$NAME", "channelB", 0));;\
my $stop=time_str2num(ReadingsTimestamp("$NAME", "buttons", 0));;\
if($startB>$startA) { \
if (ReadingsVal("$NAME","channelB",0) eq "B0"){\
if ($stop-$start<=1) {fhem "set Raffstore 50"} else {fhem "set Raffstore 100"}}\
else {if ($stop-$start<=1) {fhem "set Raffstore 20"} else {fhem "set Raffstore 80"}}\
} else { \
if (ReadingsVal("$NAME","channelA",0) eq "A0"){\
if ($stop-$start<=1) {fhem "set AktionA0 kurz"} else {fhem "set AktionA0 lang"}}\
else {if ($stop-$start<=1) {fhem "set AktionAI kurz"} else {fhem "set AktionAI lang"}}\
} \
}


Einziger Schönheitsfehler ist nun aus meiner Sicht die geringe zeitliche Auflösung von ReadingsTimestamp (laut Commandref wohl nur sekundengenau - stimmt das?). Wünschenswert wäre für mich eine zumindest millisekundengenaue Auflösung, sodass bspw. auch ein halbsekündiger Tastendruck bereits als lang interpretiert werden kann, bei der aktuellen if-Abfrage muss man eher zwei Sekunden drücken, um wirklich sicher zu sein, dass die Aktion für langen Tastendruck ausgeführt wird. Gibt es eventuell eine Möglichkeit, die Genauigkeit von ReadingsTimestamp in den Millisekundenbereich zu erhöhen? Als Alternative wäre auch vorstellbar, dass die Aktion für langen Tastendruck nicht vom released-Event abhängt, sondern bereits ausgeführt wird, wenn die Taste nur lang genug gehalten wurde. Ich denke, das könnte man dann mit einer Kombination aus einem notify, welches ein at einrichtet (+00:00:01) sowie einer Modifikation des obigen Codes erreichen, der dann nur noch die durchzuführenden Aktionen für kurze Tastendrücke mit einem delete des zuvor angelegten ats enthält. Auch hierfür wäre aber eine größere Präzision als eine Sekunde wünschenswert.

VG
crispinus

krikan

Nun aber mal halblang.  ;)  Das haben wir nicht vergessen. Es entsprach nicht den Anforderungen. Wenn man das mit einem Einfachtaster macht ist, ist dass vollkommen korrekt so. Wenn Du natürlich das auf einem Doppeltaster haben willst, dann muss man es -wie von Dir getan- anpassen. Danke für Deinen Code.

Zu Deiner zeitlichen Auflösung kann ich nicht wirklich etwas beitragen.

Frage mich nur, ob man das nicht auch über triggerPartial irgendwie hinbekommen könnte.
http://forum.fhem.de/index.php/topic,26772.msg198050.html#msg198050

Gruß, Christian

crispinus

Zitat von: krikan am 12 September 2014, 23:51:14
Nun aber mal halblang.  ;)  Das haben wir nicht vergessen. Es entsprach nicht den Anforderungen. Wenn man das mit einem Einfachtaster macht ist, ist dass vollkommen korrekt so. Wenn Du natürlich das auf einem Doppeltaster haben willst, dann muss man es -wie von Dir getan- anpassen. Danke für Deinen Code.

Also am Anfang des Threads war aber auch nicht davon die Rede, dass der FT55 mit der Einfachwippe betrieben wird ;). Aber ist ja auch egal - jetzt steht hier für Leute wie mich, die erst beim Ausprobieren drauf kommen, warum auf einmal alles so komisch reagiert, hier noch die Lösung für alle, die den FT55 mit Doppelwippe benutzen.

Zitat von: krikan am 12 September 2014, 23:51:14
Zu Deiner zeitlichen Auflösung kann ich nicht wirklich etwas beitragen.

das hab ich im Code zwischenzeitlich mal nachgeschaut und dabei verifiziert, dass die Timestamps tatsächlich nur Sekunden und nichts kleineres halten, eine Modifikation wäre extrem aufwändig und sicherlich auch mit zahlreichen Inkompatibilitäten in anderen Modulen verbunden. Wenn man das WIRKLICH möchte, könnte man wahrscheinlich readingsBeginUpdate so verändern, dass neben TIME auch noch MILLITIME (o.ä.) gespeichert wird, worin dann eine um Millisekunden erweiterte Zeit enthalten ist. Entsprechend würde man dann ein ReadingsTimestampMillis ergänzen. So könnte man das zumindest für neuen Code, der die Präzision benötigt, recht einfach verwenden.

Zitat von: krikan am 12 September 2014, 23:51:14
Frage mich nur, ob man das nicht auch über triggerPartial irgendwie hinbekommen könnte.
http://forum.fhem.de/index.php/topic,26772.msg198050.html#msg198050

Das sieht im Prinzip gar nicht schlecht aus, zumal hier ja auch eine bessere zeitliche Auflösung geboten wird. Als zusätzlichen Benefit hätte man hier die von mir eigentlich favorisierte Lösung, dass bei langem Tastendruck schon geschaltet wird, bevor der Button losgelassen wird (nämlich bei Ablauf des "Timeouts" für einen langen Tastendruck), das entspricht der von mir als sehr intuitiv empfundenen Funktionsweise meiner HomeMatic-Funkschalter. Ein Codebeispiel würde sich dann wohl so lesen:


define sKurzerLangerDruck sequence Taster:A0 0.5 Taster:buttons:.released
attr sKurzerLangerDruck triggerPartial
define nKurzerDruck notify sKurzerLangerDruck:trigger set Lampe an
define nLangerDruck notify sKurzerLangerDruck:partial_1 set Lampe aus


Hier müsste nach meinem Verständnis (werde das morgen dann auch mal testen) bei kurzem Druck (also A0-Event und binnen 500ms released-Event) die Lampe eingeschaltet werden (im Moment des Loslassens des Tasters) und bei langem Druck (A0-Event und released-Event jenseits des Timeouts) die Lampe ausgeschaltet werden - aber eben schon in dem Moment, wenn das Timeout erreicht ist, und nicht erst, wenn ich den Taster los lasse. Ich als Benutzer bekomme also signalisiert, wann ich lange genug für einen langen Tastendruck gedrückt habe und musst nicht im Kopf die Sekunden zählen ^^.

VG
crispinus

crispinus

Zitat von: crispinus am 13 September 2014, 00:27:12
das hab ich im Code zwischenzeitlich mal nachgeschaut und dabei verifiziert, dass die Timestamps tatsächlich nur Sekunden und nichts kleineres halten, eine Modifikation wäre extrem aufwändig und sicherlich auch mit zahlreichen Inkompatibilitäten in anderen Modulen verbunden. Wenn man das WIRKLICH möchte, könnte man wahrscheinlich readingsBeginUpdate so verändern, dass neben TIME auch noch MILLITIME (o.ä.) gespeichert wird, worin dann eine um Millisekunden erweiterte Zeit enthalten ist. Entsprechend würde man dann ein ReadingsTimestampMillis ergänzen. So könnte man das zumindest für neuen Code, der die Präzision benötigt, recht einfach verwenden.

Habe gerade nochmal nachgesehen und muss mich korrigieren, es wird von readingsEndUpdate mit dem Key "t" auch der direkte, unformatierte Wert von gettimeofday() hinterlegt (dieser enthält auch Millisekunden), es scheint nur noch keine einfache Zugriffsfunktion wie das ReadingsTimestamp für den Key "TIME" zu geben. Gerade für solche Zeitrechnungen wie im obigen Code wäre das aber wohl ganz praktisch. Es scheint auch nicht so richtig schwer zu ergänzen - eigentlich muss man ja nur ReadingsTimestamp kopieren und stattdessen den Inhalt von "t" zurückgeben. Ein passender Name wäre dann analog zu den im Quelltext gewählten assoziativen Arraykeys ReadingsTime.


sub
ReadingsTime($$$)
{
  my ($d,$n,$default) = @_;
  if(defined($defs{$d}) &&
     defined($defs{$d}{READINGS}) &&
     defined($defs{$d}{READINGS}{$n}) &&
     defined($defs{$d}{READINGS}{$n}{t})) {
     return $defs{$d}{READINGS}{$n}{t};
  }
  return $default;
}


damit sollte man dann auch problemlos im Millisekundenbereich rechnen können, und der Umweg über time_str2num entfällt auch.

rudolfkoenig

Der Haken an ReadingsTime ist, dass {t} nur fuer userReadings existiert.
Da die meisten kein Handbuch lesen, wuerde das zu Verwirrung fuehren.

krikan

Habe den Code für die Tastendruckdauer-Unterscheidung über sequence von crispinus mal probiert. Das funktioniert bei mir ohne erkennbare Probleme. Finde ich persönlich bisher die beste Lösung für Druckdauerunterscheidung.

@crispinus: Wenn Du es auch noch testet, gib bitte eine kurze Rückmeldung. Danke.

@Rudi: Danke für die Erweiterung von sequence um triggerPartial

crispinus

Zitat von: rudolfkoenig am 13 September 2014, 08:41:39
Der Haken an ReadingsTime ist, dass {t} nur fuer userReadings existiert.
Da die meisten kein Handbuch lesen, wuerde das zu Verwirrung fuehren.

Stimmt. Wobei man das doch eigentlich problemlos auf alle Readings erweitern könnte, ohne die Kompatibilität zu gefährden. Es wäre dann entsprechend eine Modifikation von setReadingsVal erforderlich, sowie die Übergabe eines zusätzlichen Argumentes in Form der unformatierten gettimeofday()-Ausgabe. Da setReadingsVal nur intern in fhem.pl genutzt wird sowie in drei anderen Modulen (10_SOMFY, 00_KM271 sowie 58_GPIO4 in contrib) sollte sich das mit überschaubarem Aufwand einbauen lassen. Von readingsBeginUpdate wird ja immer eine time in .updateTime gespeichert, unabhängig davon, ob userReadings oder andere geupdatet werden, das müsste man dann in readingsBulkUpdate bloß entsprechend zusätzlich verwerten, etwa so:

sub
setReadingsVal($$$$$)
{
  my ($hash,$rname,$val,$ts,$numtime) = @_;
  $hash->{READINGS}{$rname}{VAL} = $val;
  $hash->{READINGS}{$rname}{TIME} = $ts;
  $hash->{READINGS}{$rname}{t} = $numtime;
}

# Call in readingsBulkUpdate()
setReadingsVal($hash, $reading, $value, $hash->{".updateTimestamp"}, $hash->{".updateTime"});


Oder gibt es da irgendeinen Haken, den ich gerade übersehe?

rudolfkoenig

Ja, alle Module, die READINGS direkt aendern. Und abspeichern muss man auch, also setstate anpassen. Und der Uebergang von alten Statefile auf Neu muss auch irgendwie geloest werden.

Abgesehen davon halte ich den Nutzen dieser Feature fuer marginal. Und wenn der Benutzer anfangen muss, mit solchen Werten rumzurechnen, dann ist was grundsaetzlich kaputt, und sollte es an der richtigen Stelle gefixed werden.

crispinus

Zitat von: krikan am 13 September 2014, 12:11:21
Habe den Code für die Tastendruckdauer-Unterscheidung über sequence von crispinus mal probiert. Das funktioniert bei mir ohne erkennbare Probleme. Finde ich persönlich bisher die beste Lösung für Druckdauerunterscheidung.

@crispinus: Wenn Du es auch noch testet, gib bitte eine kurze Rückmeldung. Danke.

Bei mir funktionierts auch genau so wie gewünscht :).

krikan

Danke für Deine Rückmeldung. Code ist dort gelandet: http://www.fhemwiki.de/wiki/EnOcean-PTM-210-Taster#.22Taste_lange_gedr.C3.BCckt.22_und_.22Taste_kurz_gedr.C3.BCckt.22_unterscheiden
Natürlich auch der Hinweis, das es für Doppeltaster hier im Thread auch etwas gibt  :).
Gruß, Christian

phil1283

Hallo liebe FHEMler,

ich habe nach dem Post von krikan eine Taster-Doppelklick-Steuerung realisiert (steht auch so in der Wiki). Diese funktionierte auch bis vor kurzem.
Bevor ich jetzt den ganzen Code poste wollte ich eine Frage vorab abklären.
Wie wird das erkennen eines Einzelklicks beim zweiten Klick des Doppelklicks verhindert?
Das passiert seit kurzem bei meiner Konfig.
Danke.

krikan

Hallo!
Kannst Du bitte den betroffenen Code posten und die Ausgabe "list <device>" des zugehörigen Tasters. Ich würde mir das lieber anhand des betroffenen Codes anschauen, bevor ich in die falsche Richtung renne.
Gruß, Christian

phil1283

Hallo und schon mal vielen Dank Christian,

hier der Code:
define doppelclick_Taster_Schlafzimmer_2 sequence Taster_Schlafzimmer_2:channelB:.B0 1 Taster_Schlafzimmer_2:channelB:.B0
define a_doppelclick_Taster_Schlafzimmer_2 notify doppelclick_Taster_Schlafzimmer_2:trigger set Rollladen_Schlafzimmer up
define a_einfachclick_Taster_Schlafzimmer_2 watchdog Taster_Schlafzimmer_2:channelB:.B0 00:00:02 SAME set

Wandleuchte_Schlafzimmer_Jessica 25;;set Rollladen_Schlafzimmer down;; trigger a_einfachclick_Taster_Schlafzimmer_2 .
attr a_einfachclick_Taster_Schlafzimmer_2 regexp1WontReactivate 1


und hier die Devicelist:
Internals:
   DEF        00001041
   IODev      TCM_ESP2_0
   LASTInputDev TCM_ESP2_0
   MSGCNT     60
   NAME       Taster_Schlafzimmer_2
   NR         113
   NTFY_ORDER 50-Taster_Schlafzimmer_2
   STATE      B0
   TCM_ESP2_0_MSGCNT 60
   TCM_ESP2_0_TIME 2016-11-18 13:12:32
   TYPE       EnOcean
   Readings:
     2016-11-18 13:12:32   buttons         released
     2016-11-18 13:12:31   channelB        B0
     2016-11-18 13:12:31   state           B0
     2016-07-26 19:00:34   teach           RPS teach-in accepted EEP F6-02-01 Manufacturer: no ID
   Helper:
Attributes:
   IODev      TCM_ESP2_0
   eep        F6-02-01
   manufID    7FF
   room       EnOcean
   subType    switch
   teachMethod RPS