TelegramBot: Ein einzelnes Reading via Handy abfragen?

Begonnen von curt, 17 September 2019, 02:17:33

Vorheriges Thema - Nächstes Thema

curt

Hallo TelegramBot-Nutzer,

Ich möchte:
* Am Handy in Telegram eine kurze Zeile schreiben.
* TelegramBot antwortet auf dem Kanal.

Genauer beschrieben: Ich habe in FHEM den Status aller Fenster als Summe: Ist da eins offen oder alle zu? Ich bin in Timbuktu und sende mit meinem Handy via Telegram "Fenster" - und der Bot antwortet "zu" oder "auf". Aber wir müssen uns jetzt nicht am Beispiel aufhalten, die Frage geht allgemein auf alles, was ein Reading hat: Wie geht das? Geht das überhaupt?

Ich möchte nicht:
Ich weiß theoretisch, dass man in FHEM der TelegramBot-Device mitgeben kann, dass sie ganz allgemein alle Kommandos vom Bot entgegennehmen soll: https://wiki.fhem.de/wiki/TelegramBot#Kommandos_ausl.C3.B6sen
Aus Sicherheitserwägungen möchte ich das nicht.

Mein Lernstand:
1) Ich kann von FHEM aus Messages an den Bot senden. Die kommen fein auf meinem Handy an.
2) Ich weiß von der Theorie her, dass es die Möglichkeit gibt, vom Handy aus Kommandos bei FHEM auszulösen.
3) Ich weiß, dass ich die commandref für telegrambot nicht verstanden habe.

Hmmm.
Ist meine Idee umsetzbar? Hat das jemand von euch schon umgesetzt?
RPI 4 - Jeelink HomeMatic Z-Wave

binford6000


curt

Danke für Deine schnelle Antwort.

Ich habe das ganz schnell überflogen und ... also ... so richtig schlau werde ich nicht.

Ich frage mal ganz keck:
Nutzt Du diesen Anwendungsfall? Magst Du mir das ganz konkret an einem Beispiel zeigen?

(Das wäre sehr schön, ich bin ein Typ, der am besten von Beispielen lernt.)
RPI 4 - Jeelink HomeMatic Z-Wave

binford6000

#3
Zitat von: curt am 17 September 2019, 03:02:47
Danke für Deine schnelle Antwort.

Ich habe das ganz schnell überflogen und ... also ... so richtig schlau werde ich nicht.

Ich frage mal ganz keck:
Nutzt Du diesen Anwendungsfall? Magst Du mir das ganz konkret an einem Beispiel zeigen?

(Das wäre sehr schön, ich bin ein Typ, der am besten von Beispielen lernt.)

Ich nutze nicht genau diesen Anwendungsfall. Aber Licht ein-/ausschalten oder Steckdosen ein-/ausschalten
geht ja in die Richtung. Hier mal ein Dialog für die Lampen (DEF):
{
"02.💡...Lampen....💡": {
"message": [
"(💡 Lampe einschalten) ",
"(💡 Lampe ausschalten) ",
    "(abbrechen|zurück:%me%) ",
"Bitte wählen:"
],
"💡 Lampe einschalten": {
"message": [
"{return(lightsOn())}"
],
"Einschalten": {
"match": ".*_licht",
"commands": [
"set $message on",
"set $SELF say @$recipient 02.💡...Lampen....💡|Lampe einschalten"
]
},
"Zurück": {
"commands": [
"set $SELF say @$recipient 02.💡...Lampen....💡"
]
}
},
"💡 Lampe ausschalten": {
"message": [
"{return(lightsOut())}"
],
"Ausschalten": {
"match": ".*_licht",
"commands": [
"set $message off",
"set $SELF say @$recipient 02.💡...Lampen....💡|Lampe ausschalten"
]
},
"Zurück": {
"commands": [
"set $SELF say @$recipient 02.💡...Lampen....💡"
]
}
}

}
}


Und hier der dazugehörige Code in myUtils:
sub lightsOut
{
  my @lights = devspec2array('.*_licht:FILTER=STATE!=off');
  my $msg = '';
  if (@lights > 0 and defined($defs{$lights[0]})) {
    foreach (@lights) {
      $msg .= '('.AttrVal($_,'alexaName','alexaName').-AttrVal($_,'alexaRoom','alexaRoom').' :'.$_.') ';
}
$msg .= '(🔄Aktualisieren) (Zurück) (⬆️Hauptmenü:Q) Folgende Lampen sind an:';
  }
  else {
    $msg = '(🔄Aktualisieren) (Zurück) (⬆️Hauptmenü:Q) Alle Lampen sind aus.';
  }
  return $msg;
}

sub lightsOn
{
  my @lights = devspec2array('.*_licht:FILTER=STATE=off');
  my $msg;
  if (@lights > 0 and defined($defs{$lights[0]})) {
    foreach (@lights){
      $msg .= '('.AttrVal($_,'alexaName','alexaName').-AttrVal($_,'alexaRoom','alexaRoom').' :'.$_.') ';
    }
    $msg .= '(🔄Aktualisieren) (Zurück) (⬆️Hauptmenü:Q) Folgende Lampen sind aus:';
  }
  else {
    $msg = '(🔄Aktualisieren) (Zurück) (⬆️Hauptmenü:Q) Alle Lampen sind an.';
  }
  return $msg;
}


Ich denke der Code ist auch ohne Kommentare lesbar. Entscheidend ist hier eigentlich nur
my @lights = devspec2array('.*_licht:FILTER=STATE!=off');

Damit kannst du zB. auch alle offenen Fenster abholen. Oder was auch immer offen/zu/an/aus ist  ;)

Ich nutze msgDialog für alles mögliche:
Wecker, Lampen, Steckdosen, Bewohner, Dienste, Staus, Blitzer,...

VG Sebastian

binford6000

Das ganze sieht dann so aus:

  • Hauptmenü
  • Lampen einschalten
  • Liste der ausgeschalteten Lampen anzeigen
  • Lampen einschalten/Liste der eingeschalteten Lampen

VG Sebastian

Wzut

Man kann auch fürs Zigaretten holen einen 40 Tonner mit Anhänger benutzen ....
Gegeben sei ein Telebot mit Namen TeleBot und eingetragenem Attribut defaultPeer und ein Device mit Namen "offene_Fenster" das in einem Reading mit Namen "of_Fe" den Status der Fenster hat.
defmod TeleBot_notify_Test notify TeleBot:msgText:.Fenster { \
  fhem("set TeleBot message Status aller Fenster ".ReadingsVal("offene_Fenster","of_Fe","unbekannt"));;\
}

Aber Achtung : Anfragen kann in dem Beispiel jeder, die Antwort geht allerdings immer an defaultPeer und es gibt nur eine Antwort wenn man exakt "Fenster" schreibt.
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

binford6000

ZitatMan kann auch fürs Zigaretten holen einen 40 Tonner mit Anhänger benutzen ....
Ja kann man...

Dafür ist msgDialog eine extrem flexible, schicke und sichere Art mit seinem Smarthome zu reden.
Vom WAF mal ganz abgesehen...  ;)

VG Sebastian

Wzut

maybe, aber das war nicht curts Frage ..
Zitatdie Frage geht allgemein auf alles, was ein Reading hat: Wie geht das? Geht das überhaupt?

Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

binford6000

Zitatmaybe, aber das war nicht curts Frage ..
Aber klar doch! Es ist EINE MÖGLICHE LÖSUNG unter vielen...

flummy1978

#9
Hallo Sebastian,

Zitat von: binford6000 am 17 September 2019, 11:09:47
Ja kann man...

Dafür ist msgDialog eine extrem flexible, schicke und sichere Art mit seinem Smarthome zu reden.
Vom WAF mal ganz abgesehen...  ;)

Genauso sehe ich das auch. Denn ich habe genau nach sowas gesucht. Das "Rückgabemenu" das ich von Fhem bekomme, hätte ich gern wie Du anhand der Screenshots gezeigt hast und nicht wie es bei mir derzeit ist, als reines TextMenue.

Kannst Du dafür mal zeigen, wie Deine Senderoutine aussieht?

Der Hintergrund meiner Frage ist:
- Pur aus dem Telegram Device, bekomme ich den Befehl geschickt, so dass es als "Button" auftaucht  ABER:

- Der Button taucht in der Tastatureingabezeile auf (nicht wie bei Dir in den "empfangenen Nachrichten" oben)
- Aus der 99_myUtils heraus, bekomme ich ein mehrreihiges Menu gar nicht erst gesandt ;(

Vielen Dank im Voraus
Andreas

# Edith sagt: https://wiki.fhem.de/wiki/MsgDialog den hab ich ursprünglich übersehen. Aber ist das denn zwingend dafür nötig? Ich meine, man muss doch dem Telegram Bot auch so irgendwie näherbringen können, dass er Buttons aus den Nachrichten machen soll ( wie in Einzelnachrichten durch die () geschehen .... )

binford6000

#10
Zitat von: flummy1978 am 18 September 2019, 14:40:24
# Edith sagt: https://wiki.fhem.de/wiki/MsgDialog den hab ich ursprünglich übersehen. Aber ist das denn zwingend dafür nötig? Ich meine, man muss doch dem Telegram Bot auch so irgendwie näherbringen können, dass er Buttons aus den Nachrichten machen soll ( wie in Einzelnachrichten durch die () geschehen .... )

Nichts anderes macht ja auch msgDialog (set Befehle TelegramBot):
queryInline [ @<peer1> ... @<peerN> ] (<keyrow1>) ... (<keyrowN>) <text>
Sends the given message to the recipient(s) with an inline keyboard allowing direct response
IMPORTANT: The response coming from the keyboard will be provided in readings and a corresponding answer command with the query id is required, sicne the client is frozen otherwise waiting for the response from the bot! REMARK: inline queries are only accepted from contacts/peers that are authorized (i.e. as for executing commands, see cmdKeyword and cmdRestrictedPeer !)

queryEditInline <msgid> [ @<peer> ] (<keyrow1>) ... (<keyrowN>) <text>
Updates the original message specified with msgId with the given message to the recipient(s) with an inline keyboard allowing direct response
With this method interactive inline dialogs are possible, since the edit of message or inline keyboard can be done multiple times.

queryAnswer <queryid> [ <text> ]
Sends the response to the inline query button press. The message is optional, the query id can be collected from the reading "callbackID". This call is mandatory on reception of an inline query from the inline command above


Mit msgDialog bekommst du halt auch Menüs und Untermenüs hin  ;)
Dafür ist msgDialog leider nicht so trivial.  :o

VG Sebastian

flummy1978

Zitat von: binford6000 am 18 September 2019, 15:32:41
Nichts anderes macht ja auch msgDialog (set Befehle TelegramBot):

Mit msgDialog bekommst du halt auch Menüs und Untermenüs hin  ;)
Dafür ist msgDialog leider nicht so trivial.  :o

Genau hier scheint ja doch etwas anders zu sein....

Wenn man mit "set BOT-device @Empfänger (Button1) (Button1) text" etwas abschickt, kommt bei Telegram eben Buttons (1+2) anstelle der Tastatur und der text als Text oben in der Empfängerzeile. Bei Deinen Screenshots meine ich zu sehen dass alles an Button / text usw.  oben in der Empfängerspalte geschieht. So dass Du die eigentliche Tastatur bei Deinem Bot nicht mehr brauchst.

Das mit den Untermenues kann man dann ggf manuell machen. Ich würde ungern wieder ein seperates Modul aktivieren für etwas das generell alles unübersichtlicher macht, nicht nötig ist, wenn ich NUR die Syntax brauche, damit das oben im Menue angezeigt wird..... Mit ( ) wird ja schon mal ein Button angezeigt ;)

Grüße
Andreas

flummy1978

Hallo Curt,

zunächst einmal sorry, dass ich Deinen Beitrag für meine Frage genutzt habe, aber das Beispiel das binford6000 gebracht hat, hat mich einfach sehr interessiert.

Zitat von: curt am 17 September 2019, 02:17:33
Genauer beschrieben: Ich habe in FHEM den Status aller Fenster als Summe: Ist da eins offen oder alle zu? Ich bin in Timbuktu und sende mit meinem Handy via Telegram "Fenster" - und der Bot antwortet "zu" oder "auf". Aber wir müssen uns jetzt nicht am Beispiel aufhalten, die Frage geht allgemein auf alles, was ein Reading hat: Wie geht das? Geht das überhaupt?

Jupp das geht wunderbar sogar und ist eigentlich auch mit dem o.g. Beispiel gut umsetzbar.... Die Frage ist wie sehen die Nachrichten aus, die Du Dir auf das Handy geschickt hast ? Hast Du schon mal eine gewisse dynamische Benachrichtigung hinbekommen ? -> Wenn das passiert, dann sende das, sonst sende das oder mach mal dies..... ?

Ich frage deshalb, weil ich Deinen sonstigen FHEM (Perl) Kenntnissstand nicht weiß und sich somit vielleicht mehr Fragen als Antworten auftun, wenn ich Dir mein Beispiel zeige. Aber ich schieß da trotzdem einfach mal rein, wenn was unverständlich ist - Nur zu -

( Für alle anderen, die sicher mehr Erfahrung haben und es bestimmt schon mal (besser) gemacht haben -> Auch ich bin danbar für jeden noch so kleinen Tipp, denn nur so kann man lernen ;) )

Zunächst die Struktur:
Mich interessieren geschlossene Fenster und Türen nicht, sondern nur die offenen. Daher ist die Abfrage nur für nicht geschlossene Kontakte. Alle Geräte die bei mir einen Fenster oder Türstatus durchgeben können heißen TK.....irgendwas, damit lässt sich auch das folgende list erklären. Mit solchen Versuchen innerhalb FHEM teste ich erstmal, ob ich die Filter / Einschränkungen etc richtig hab, bevor ich an Perl unterroutinen und Notifys gehe ...

list TK_.*:FILTER=contact=false:FILTER=state=open alias

Damit werden nur Geräte gefunden die TK.....irgendwas heißen das Reading contact mit dem Zustand false haben und das reading state den Zustand open  hat. Zusätzlich wird das Alias des Gerätes angezeigt nicht nur der Devicename. (Dass contact und state abgefragt wird, liegt bei mir daran, dass ich in einigen Kontakten eine Zeitverzögerung eingebaut habe, die dann eben auch mal den Zustand "delayed" haben könnten)

Nun sende ich den Abfrage Befehl an Fhem(Telegram) und fange diesen mit dem notify ab:
/fenstertuer


telegramdevice:msgText:.* {
my $msgText = ReadingsVal("telegramdevice","msgText","");
my $msgPeerId = ReadingsVal("telegramdevice","msgPeerId","");
if(($msgPeerId eq "111222333") || ($msgPeerId eq "444555666")){ chatbot($msgPeerId,$msgText); }
}
}

Erklräung:
1112222333 und 44445555666 sind die IDs die meinem Telegrambot was schicken dürfen. Man sollte zwar noch mehr Sperren einbauen, wer die Befehle ausführen darf, aber das ist schon mal eine erste und imho zwingend notwendige Sache.
if $msgPeerId prüft diese
$msgPeerId = ReadingsVal("telegramdevice","msgPeerId","") - übernimmnt den Inhalt der Nachricht und übergibt diese über die Variable in das Unterprogramm.

chatbot($msgPeerId,$msgText);  Damit rufe ich die sub routine auf, die sich in 99_myUtils.pm (oder ähnlichem) befinden muss:

sub chatbot($$){
1 my ($msgPeerId, $msgText) = @_;
2 $msgText = lc $msgText;
3
4 if($msgText eq "/fenstertuer"){
5 # Suche nach Geräten mit contact reading und zustand "open"
6
7 my $temp = fhem "list TK.*:FILTER=contact=false:FILTER=state=open alias";
8 my $txt = " ist offen.";
9 $temp =~ s/(\S+\s)(.*)(\n)/$2$txt\n/mg;
10 fhem "set telegramdevice message \@$msgPeerId $temp";
11 }
12
13 }


Zeilennummern musst Du entfernen:
1. Übernahme der Variablen aus dem o.g. Notify
2. umschreiben der Nachricht auf kleinbuchstaben (falls Autokorrektur schon mal dazwischen greift)
4. Abfrage ob Nachricht /fenstertuer beinhaltet
7. das oben erwähnte List in eine Variable schieben (mit dem Schönheitszusatz, dass der Alias Name genommen wird und nicht der Device Name)
8. Schönheitstext hinter dem Gerätealias - "ist offen"
9. Schneidet aus der Variablen den Gerätenamen ab und hinterlässt nur noch den Text "Alias ist offen" ... Also z.B "Fenster Schlafzimmer ist offen"
10 sendet das Telegram mit dem Inhalt an die ID die oben mit übernommen wurde


Wenn Du sonst noch nie was mit Perl gemacht hast, wird es schwierig sowas umzusetzen. Aber soweit es in meiner Macht steht, habe ich versucht nach bestem Wissen  und Gewissen hiermit zu helfen und jeder hat mal angefangen.  Wenn Du noch Fragen hast... nur zu :)  ::)


@binford6000:

Ich habs komplett ohne msgDialog hinbekommen. QueryInline ist hier das Zauberwort. Aber nun kann ich mich vom Hauptmenu durch diverseste Untermenus schlengeln, wenn ich das möchte und alles ohne eine einzige Antwort per Text zu schreiben oder die Buttons auf der Tastatur zu haben.
Danke für den Hinweis in die richtige Richtung  8)

Viele Grüße
Andreas

curt

Zitat von: flummy1978 am 20 September 2019, 02:27:35
Hallo Curt,
zunächst einmal sorry, dass ich Deinen Beitrag für meine Frage genutzt habe, aber das Beispiel das binford6000 gebracht hat, hat mich einfach sehr interessiert.

Absolut kein Problem.

Ich habe im Moment den Vorschlag von @Wzut im Auge, aber noch nicht umgesetzt. Andererseits wäre es natürlich schön, wenn es in der Handy-Telegram-App ein Knöpfchen "Fenster" gäbe und ich nicht erst "Fenster" eintippen muss. Klar.

Zitat von: flummy1978 am 20 September 2019, 02:27:35
Jupp das geht wunderbar sogar und ist eigentlich auch mit dem o.g. Beispiel gut umsetzbar.... Die Frage ist wie sehen die Nachrichten aus, die Du Dir auf das Handy geschickt hast ? Hast Du schon mal eine gewisse dynamische Benachrichtigung hinbekommen ? -> Wenn das passiert, dann sende das, sonst sende das oder mach mal dies..... ?

Mit wem redest Du gerade?

Falls ich gemeint bin: Nur einfachste Dinge via msg, Haustüre auf, Rasenmäher bockt, es regnet.

Zitat von: flummy1978 am 20 September 2019, 02:27:35
Ich frage deshalb, weil ich Deinen sonstigen FHEM (Perl) Kenntnissstand nicht weiß und sich somit vielleicht mehr Fragen als Antworten auftun, wenn ich Dir mein Beispiel zeige. Aber ich schieß da trotzdem einfach mal rein, wenn was unverständlich ist - Nur zu -

Falls ich gemeint bin:
Perl ist Hausgebrauch. Beispiele erstmal nicht angesehen - danke trotzdem.

Zitat von: flummy1978 am 20 September 2019, 02:27:35
Zunächst die Struktur:
Mich interessieren geschlossene Fenster und Türen nicht, sondern nur die offenen.

Das ist hier anders gelöst:
Alle Türen und Fenster sind in einer structure zusammengefasst. Und die ist halt open oder closed (wenn nur eins offen ist, ist in der structure alles offen) - habe ich mir mal irgendwann aus dem Forum geklaut. So sieht das hier aus:


define structure_Fenster structure Fenster_Status <Auflistung aller Devices>
attr structure_Fenster alias Fenster: Status
attr structure_Fenster clientstate_behavior relative
attr structure_Fenster clientstate_priority open closed
attr structure_Fenster devStateIcon open:fts_window_1w_tilt@red closed:fts_window_1w@green


Ich kann gern das list nachliefern, müsste dann aber aufwändig die Namen der Devices rauslöschen. Das Ergebnis der Veranstaltung steht jedenfalls in "state".

Den weiteren Teil übergehe ich im Moment, wir müssen erstmal gleiche Sprache finden - denke ich.

BTW: Danke für eure Mühe!
RPI 4 - Jeelink HomeMatic Z-Wave

flummy1978

Hallo Nachteule, Curt,

Mit wem ich rede.... lach....  War komplett alles für Dich. Komplette Anleitung / Erklärung wie ich es gemacht habe, war ausschließlich für Deine Fragestellung gedacht :)

Erst beim letzten Abschnitt  @binford6000.... Ist der angesprochene ein anderer ;)

Grüße
Andreas