Telegram Nachrichten flexibel wieder löschen

Begonnen von slor, 30 Januar 2018, 12:08:19

Vorheriges Thema - Nächstes Thema

slor

Hallo zusammen,

ich habe folgendes vor:

Nachrichten, die Fhem via Telegram Bot an eine Suppergruppe sendet automatisch wieder zu löschen.
a - die letzen 10 Nachrichten im Chat belassen und bei jeder neuen eine alte löschen
b - alle Nachrichten, die älter als 24 Stunden sind löschen.
c - bei Bedarf alle Nachrichten löschen. (Geht max 48h zurück)

Ich habe gesehen, dass man mit msgdelete einzelne Nachrichten löschen kann. Das klappt auch Prima.

Nur wie setze ich am besten das oben genannte um? Ist geplant so eine Funktion im das Telegram Modul zu integrieren?
Wenn nicht, wie speicher ich mir am besten die Message IDs ab und lösche die nach Anzahl oder Zeit? Vielleicht hat ja schon jemand so etwas gebaut? :-)
Fhem auf Raspberry Pi 4
CCU3 mit RaspberryMatic mit HMCCU an FHEM
HMCCU, Telegram, Conbee2 und Hue/Tradfri/Osram Lampen AQARA Sensoren, HomeConnect

viegener

Bisher ist nicht geplant eine solche Funktionalität in Telegram zu implementieren. Grund: das TelegramBot-Modul würde damit überladen werden, es wäre hier sicher besser das separat abzuhandeln.

Vielleicht braucht man dafür ein eigenes Modul, dass eine Art Channel in Telegram repräsentiert an dem solche Einstellungen gemacht werden könnten.

Mit jetzigen Bordmitteln würde ich vermutlich eine Kombination von

readingsHistory (um die alten msgIds und Nachrichten zu speichern).
Hier muss man schauen, wie man nur die Nachrichten speichert, die in die Supergruppe gegangene sind.

notify/DOIF (um alte Nachrichten, wenn mehr als 10 nachrichten enthalten sind zu löschen)

Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

slor

Ok, macht Sinn so ein Telegram Helper Modul.
Dann warte ich mal ab, ob jemand was in der Richtung baut, da das leider meine Fähigkeiten übersteigt.
Fhem auf Raspberry Pi 4
CCU3 mit RaspberryMatic mit HMCCU an FHEM
HMCCU, Telegram, Conbee2 und Hue/Tradfri/Osram Lampen AQARA Sensoren, HomeConnect

marvin78

Fähigkeiten kann man immer verbessern. Es gibt viele hier, die in ihrem Leben noch keine einzige Zeile Perl geschrieben haben und nun sehr komplexe eigene Module bauen. Mit irgendwas muss man ja anfangen. ;)

Vermutlich muss es kein eigenes Modul sein. Ein paar subs in Kombination mit notify, dummy oder eigenen Readings sollten auch ihren Dienst tun. Ein wenig reinfuchsen geht vermutlich schneller, als darauf warten, dass jemand, der die Fähigkeiten schon hat oder sich dafür aneignet, genau die gleichen, sehr speziellen Anforderungen hat.

viegener

Zitat von: slor am 30 Januar 2018, 15:04:10
Ok, macht Sinn so ein Telegram Helper Modul.
Dann warte ich mal ab, ob jemand was in der Richtung baut, da das leider meine Fähigkeiten übersteigt.

Ich weiss nicht ob jemand das bauen wird - aber meine Hinweise gingen ebenfalls in die Richtung mit existierenden Mitteln Readingshistory und notify das selber zu bauen - ob Du es hinbekommst ist doch erst nach dem Versuch klar
Kein Support über PM - Anfragen gerne im Forum - Damit auch andere profitieren und helfen können

Motivierte linke Hände

Da das das einzige Thema zu sein scheint, in dem sich bisher jemand mit der Frage des automatischen Löschens von Telegram-Nachrichten beschäftigt hat:

Ich habe daran auch Bedarf gehabt und mir sowas gebastelt. Meine Bastelei funktioniert nach folgendem System:


  • Eine Nachricht, die versendet und dann gelöscht werden soll, wird über eine eigene sub routine versendet, die die Nachricht über das Telegram-Modul versendet und gleichzeitig ein Warte-Reading erzeugt.
  • Kommt dann eine neue sentMsgId in Telegram (notify reagiert darauf), wird das Warte-Reading ersetzt durch ein Reading mit der sentMsgId (die braucht man zum Löschen), der zu wartenden Zeit, und dem Zeitstempel, an dem die Nachricht ursprünglich abgeschickt wurde.
  • Wird eine Nachricht erhalten, die gelöscht werden soll, wird ein Reading mit der msgId, der zu wartenden Zeit und dem Zeitstempel des Erhalts erstellt.
  • Die so erstellten Readings werden regelmäßig daraufhin geprüft, ob Nachrichten zu löschen sind. Wenn ja, werden die Löschbefehle abgesetzt und die Readings gelöscht.

Solllte das jemals jemand brauchen, kann ich den (nicht kommentierten/dokumentierten) Code gerne zur Verfügung stellen.
FHEM 6 in einer KVM VM mit Ubuntu
HM-CFG-USB2, 2xHM-CFG-HMLAN, HM-HMUARTLGW mit 100+ HomeMatic Devices, Geofencing, Fritzbox, Unifi, HUE, Harmony-Hub, Denon-Receiver-Modul, Calendar, GardenaSmartDevice, Shelly, MQTT (zigbee2mqtt, Tasmota und Shelly) und ein wenig 1Wire.

jkriegl

#6
Auch um etwas Perl zu üben, ein userreading das nur 3 Nachrichten behält und ältere löscht.
stack:sentMsgId:.* {\
my @words=split/ /, ReadingsVal($name,"stack","");; \
\
if (my $l=length(ReadingsVal($name,"sentMsgId",""))<=0) {return("@words");;} # Ausnahme wegen Doppeltrigger\
\
push(@words,ReadingsVal($name,"sentMsgId",""));;\
if (my $i=@words>3) {\
  my $first = shift @words;;\
  fhem("set TeleBot msgDelete $first");;} \
return("@words");;\
}

Natürlich ist dies sehr einfach und es sind viele Sonderegelungen zu beachten. (z.B. Dialoge, Menue nicht löschen, also bestimmte Nachrichten; was macht man, wenn per Hand Nachrichten gelöscht werden - Stack zurücksetzen usw. zu einer bestimmetn Zeit löschen; im stack nur sammeln und per notify löschen)
Ist als Anstoß gemeint
Das Modul löscht sentMsgId und daher wird noch einmal getriggert, habe keine passende Lösung gefunden.
Rpi 3, Fhem, Cul 868, HM-CC-RT-DN, HM-Sec-Sco, HM-ES-PMSw1-Pl, ebus (Vaillant), ECMD, Telegram, HTTPMOD, Xiaomi, Shelly

slor

Zitat von: Motivierte linke Hände am 04 Februar 2020, 11:50:12

Solllte das jemals jemand brauchen, kann ich den (nicht kommentierten/dokumentierten) Code gerne zur Verfügung stellen.
Interesse! Kannst du deinen Code hier bitte mal teilen?
Fhem auf Raspberry Pi 4
CCU3 mit RaspberryMatic mit HMCCU an FHEM
HMCCU, Telegram, Conbee2 und Hue/Tradfri/Osram Lampen AQARA Sensoren, HomeConnect

Motivierte linke Hände

Bin mal gespannt, ob Du damit was anfangen kannst...  ;)

sub TelegramGetNextIndex ($) {
  my ($Bot) = @_;
  my $i = 0;
  my $MaxIndex = 256;
  my $Timestamp = '';
  my $Value = '';
 
  for ($i = 0; $i <= $MaxIndex; $i++) {
    $i = sprintf('%03d', $i);
    $Value = ReadingsVal($Bot, $i.'_DelLater', 'empty');
    last if ($Value eq 'empty');
    if (index($Value, 'Wait_') != -1) {
      if (age_in_seconds(ReadingsTimestamp($Bot, $i.'_DelLater', 0)) > 120) {
        Log 1, ("TelegramGetNextIndex($i): Index wartet seit mehr als 120 Sekunden (".ReadingsTimestamp($Bot, $i.'_DelLater', 0).") auf eine msgID, wird wiederverwendet.");
        Log 1, ("TelegramGetNextIndex($i): Nicht gelöschte Nachricht: >".ReadingsVal($Bot, $i.'_DelContent', 'err').'<');
        last;
      }
    }
  }

  return $i if ($i < $MaxIndex);
  return -1;
}

sub TelegramGetPeer ($) {
  my ($Kommando) = @_;
  my $start = index($Kommando, '@');
  my $end = index($Kommando, ' ', $start);
  my $Peer = substr($Kommando, $start + 1, $end - $start - 1);
  # Log 1, ("TelegramGetPeer($Kommando): Peer ist >$Peer<");
  return $Peer;
}

sub TelegramSend ($$) {
  my ($Hours, $Kommando) = @_;

  if ($Hours == -1) {
    fhem($Kommando);
  } else {
    TelegramSendAndDeleteLater($Hours, $Kommando);
  }
}

sub TelegramSendAndDeleteLater ($$) {
  my ($Hours, $Kommando) = @_;
  my $Bot = 'Telegram';
  my $NewIndex = TelegramGetNextIndex($Bot);
  my $Peer = TelegramGetPeer($Kommando);
 
  Log 1, ("TelegramSendAndDeleteLater($Kommando): Löschanforderung gesetzt, Index >$NewIndex<, Peer >$Peer<");
  if ($NewIndex != -1) {
    fhem("setreading $Bot ".$NewIndex."_DelLater Wait_$Hours", 1);
    fhem("setreading $Bot ".$NewIndex."_DelPeer $Peer", 1);
    fhem("setreading $Bot ".$NewIndex."_DelContent $Kommando", 1)
  # } else {
  #   Log 1, ("TelegramSendAndDeleteLater($Kommando): Keine freien Warteplätze, Nachricht wird nicht gelöscht.");
  }
  fhem($Kommando);
}

sub TelegramFindWaitingIndex ($) {
  my ($Bot) = @_;
  my $Hash = $defs{$Bot};
  my $Readings = $Hash->{READINGS};
  my $Reading = '';
  my $FoundIndex = -1;
  my @ReadingComponents = undef;
  my $Value = '';
 
  foreach $Reading (keys %{$Readings}) {
    if (index($Reading, 'DelLater') != -1) {
      $Value = ReadingsVal($Bot, $Reading, 'err');
      if (index($Value, 'Wait_') != -1) {
        @ReadingComponents = split(/_/, $Reading);
        $FoundIndex = $ReadingComponents[0];
        last;
      }
    }
  }
  return $FoundIndex;
}

sub TelegramGetWaitHours ($$) {
  my ($Bot, $Index) = @_;
  my $Value = ReadingsVal($Bot, $Index.'_DelLater', 'Wait_24');
  my @ValueComponents = split(/_/, $Value);
  return $ValueComponents[1];
}

sub TelegramNewMsgIdRcvd ($) {
  my ($msgID) = @_;
  my $Bot = 'Telegram';
  my $WaitingIndex = TelegramFindWaitingIndex($Bot);
  my $Reading = $WaitingIndex.'_DelLater';
  my $Hours = TelegramGetWaitHours($Bot, $WaitingIndex);
  my $Value = $Hours.'_'.$msgID.'_'.ReadingsTimestamp($Bot, $Reading, 0);

  if ($WaitingIndex != -1) {
    Log 1, ("TelegramNewMsgIdRcvd: Waiting Index >$WaitingIndex< erhält ID >$msgID<");
    fhem("setreading $Bot $Reading $Value", 1);
    fhem("deletereading $Bot ".$WaitingIndex."_DelContent", 1);
  } else {
    Log 1, ("TelegramNewMsgIdRcvd: MSG-ID >$msgID< erhalten, ohne dass eine Nachricht darauf wartet...?");
  }
}

sub TelegramDeleteOldMsgs () {
  my $Bot = 'Telegram';
  my $Hash = $defs{$Bot};
  my $Readings = $Hash->{READINGS};

  my $FoundIndex = -1;
  my $Hours = '';
  my $Index = '';
  my $msgID = '';
  my $Peer = '';
  my $Reading = '';
  my @ReadingComponents = undef;
  my $TimeStamp = '';
  my $Value = '';
  my @ValueComponents = undef;
 
  foreach $Reading (keys %{$Readings}) {
    if (index($Reading, 'DelLater') != -1) {
      @ReadingComponents = split(/_/, $Reading);
      $Index = $ReadingComponents[0];
      $Value = ReadingsVal($Bot, $Reading, 'err');
      if (index($Value, 'Wait') == -1) {
        @ValueComponents = split(/_/, $Value);
        $Hours = $ValueComponents[0];
        $msgID = $ValueComponents[1];
        $TimeStamp = $ValueComponents[2];
        $Peer = ReadingsVal($Bot, $Index.'_DelPeer', '#Hausmeldungen');
        # Log 1, ("TelegramDeleteOldMsgs: Zu löschen: Stunden >$Hours<, ID >$msgID<, Timestamp >$TimeStamp<, Peer >$Peer<");
        if (age_in_minutes($TimeStamp) > ($Hours * 60)) {
          Log 1, ("TelegramDeleteOldMsgs: Jetzt löschen: Stunden >$Hours<, ID >$msgID<, Timestamp >$TimeStamp<, Peer >$Peer<");
          fhem("set $Bot msgDelete $msgID @".$Peer, 1);
          fhem("deletereading $Bot ".$Index."_Del.*", 1);
        # } else {
        #   Log 1, ("TelegramDeleteOldMsgs: >$msgID< noch nicht alt genug (".age_in_minutes($TimeStamp)." Minuten)");
        }
      } else {
        $TimeStamp = ReadingsTimestamp($Bot, $Reading, 0);
        if (age_in_seconds($TimeStamp) > 120) {
          Log 1, ("TelegramDeleteOldMsgs($Reading): Eintrag wartet seit mehr als 120s auf msgID, wird gelöscht.");
          Log 1, ("TelegramDeleteOldMsgs($Reading): Nicht gelöschte Nachricht: >".ReadingsVal($Bot, $Index.'_DelContent', 'err')."<");
          fhem("deletereading $Bot ".$Index."_Del.*", 1);
        }
      }
    }
  }
}


Noch ein paar Hinweise:


  • TelegramSend($$) wird aufgerufen, um Nachrichten per Telegram zu versenden. Der erste Parameter gibt an, nach wie vielen Stunden die Nachricht wieder gelöscht werden soll. Ein -1 bedeutet, nie automatisch löschen. Der zweite Parameter ist der (komplette) fhem-Befehl zum versenden.
  • TelegramNewMsgIdRcvd muss aufgerufen werden über ein notify auf das Reading sentMsgId
  • TelegramDeleteOldMsgs muss regelmäßig (wie oft auch immer...) aufgerufen werden, um zu löschenden Nachrichten dann tatsächlich zu löschen.
  • Die Subs können die Kommunikation auf unterschiedlichen Kanälen/mit unterschiedlichen Peers verwalten.
  • Die benötigten Daten speichere ich in Readings des TelegramBots selbst. Aber die kann man (sollte man?) natürlich auch in ein Dummy oder so auslagern. Der Code oben verfolgt maximal 256 zu löschende Telegram-Nachrichten.

Man kann auch eingehende Nachrichten automatisch löschen. Dafür musst Du nur erhaltene Msg-IDs ebenfalls in die Readings einspeisen:


(...)
    Log 1, ("TelegramDialog: Lösche erhaltene Nachricht in $Hours Stunden.");
    $NewIndex = TelegramGetNextIndex('Telegram');
    $Reading = $NewIndex.'_DelLater';
    $ReadingPeer = $NewIndex.'_DelPeer';
    fhem("setreading Telegram $ReadingPeer $Channel", 1);
    fhem("setreading Telegram $Reading $Hours".'_'.$msgIDrcvd.'_'.ReadingsTimestamp('Telegram', 'msgId', 0), 1);
(...)


Und zum Abschluss: Ich bin von der Ausbildung her Geisteswissenschaftler, also eigentlich recht weit weg von Informatik. Das geht sicher (viel) besser als oben, aber es funktioniert für mich.

Grüße!
FHEM 6 in einer KVM VM mit Ubuntu
HM-CFG-USB2, 2xHM-CFG-HMLAN, HM-HMUARTLGW mit 100+ HomeMatic Devices, Geofencing, Fritzbox, Unifi, HUE, Harmony-Hub, Denon-Receiver-Modul, Calendar, GardenaSmartDevice, Shelly, MQTT (zigbee2mqtt, Tasmota und Shelly) und ein wenig 1Wire.

Dalle

Hi,

ich möchte gerne auch realisieren das Telegram Nachrichten, die älter sind als 3 Stunden löschen.
Ich möchte das gerne in Python machen.

Gruß Dalle

P.S. bin Anfänger in programmieren

jhohmann

Ich wollte auch zumindest die meisten Nachrichten wieder löschen und ich wollte bestimmen, wie lange eine Nachricht auf Löschung warten soll.
Deshalb habe ich mir folgende Lösunge gebastelt.
Meine Lösung geht davon aus, dass der Telegram Bot mit dem Namen teleBot definiert ist.

Zuerst wird eine neue Funktion in der 99_myUtils.pm gebraucht.
sub TelegramSendAndDeleteLater($$) {
  my ($slp, $Kommando) = @_;
  fhem("setreading teleBot deleteOffset ".$slp);
  fhem($Kommando);
}

Dann wird noch ein notify auf das Event sentMsgId gebraucht (hier als mehrzeilige RAW-Definition):
defmod ntTeleBot_sentMsgId notify teleBot.sentMsgId:.* {\
my $offset = ReadingsVal("teleBot", "deleteOffset", "");;\
my $msgId = ReadingsVal("teleBot", "sentMsgId", "");;\
if ($offset ne "" && $msgId ne "") {\
  fhem("define atTeleBotDeleteMsg_".$msgId." at +".$offset." set teleBot msgDelete ".$msgId);;\
  fhem("deletereading teleBot deleteOffset");;\
}\
}

Ausgelöst wird das als Perl-Aufruf wie im folgenden Beispiel:
ArbeitszimmerFenster:1.STATE.*open 00:12:00 ArbeitszimmerFenster:1.STATE.*closed {
TelegramSendAndDeleteLater("36:00:00","set teleBot message ".telegramEmpfaenger()." Das Fenster im Arbeitszimmer ist seit 12 min offen!");
fhem("trigger wdArbeitszimmerFensterOpen .");
}

Wenn man eine Nachricht als Alt-Väter-Sitte abschickt, bleibt diese einfach bestehen.
Ansonsten bei Nutzung der neuen Perl-Funktion wird dort an einem Reading am teleBot die Zeit zwischengespeichert, zu der die Nachricht wieder gelöscht werden soll.
Dann wird die Nachricht an den Bot übergeben und damit versendet.
Jetzt reagiert das notify und stellt fest: Nachricht ist geschickt und das Lösch-Offset ist vorhanden. Also lege ein temporäres at an, dass die Nachricht löschen soll. Das Lösch-Offset wird wieder entfernt.
Wenn später mal eine Nachricht normal gesendet wird, wird im notify erkannt, dass kein Lösch-Offset existiert und damit entfällt auch die Generierung des at.
Raspberry Pi 4 - bookworm / EnOcean - Rollo+Licht, deCONZ - Licht+Sensoren, ZWave - CO Messung, HMCCU mit piVCCU - Heizung+Rollo
plus dovecot, minidlna