📬 NTFY.sh: Push Nachrichten an iOS, Android, PC, Command-Line, E-Mail & Telefon

Begonnen von Torxgewinde, 09 Februar 2024, 15:35:12

Vorheriges Thema - Nächstes Thema

Torxgewinde

Hallo,
NTFY.sh bietet Push-Dienste auf iOS, Android, Console, E-Mail, ja sogar als Anruf auf ein Telefon an. Es ist damit ähnlich zu dem was man mit PushOver, PushBullet oder auch Gotify anstellen kann, wobei NTFY auch Kriterien wie "Self-hosted" und echte "iOS-Pushnachrichten" erfüllt. Man kann damit von FHEM aus alle diese Kanäle mit einer Push-Nachricht erreichen. Die Nutzung ist extrem einfach, man setzt einen HTTP-Aufruf ab um eine Push-Nachricht zu versenden. NTFY.sh betreibt sogar einen Gratis-Server, den man nutzen darf. Man kann den Server auch selber hosten wenn man will.

Öffnet testweise diesen Link, dort tauchen die Nachrichten auch in der PWA (Webapp) auf: https://ntfy.sh/FreundlichenGruesseAnAlleFHEMNutzer

Hier ein Codeschnipsel, der so direkt mit dem Gratis-Server funktioniert:
defmod NTFY HTTPMOD none 0
attr NTFY userattr NtfyServer password username
attr NTFY NtfyServer ntfy.sh
attr NTFY comment # for HTTP Basic authentication use this as "setUrl":\
# https://[$name:username]:[$name:password]@[$name:NtfyServer]/%%path%%
attr NTFY replacement01Mode text
attr NTFY replacement01Regex %%path%%
attr NTFY replacement02Mode expression
attr NTFY replacement02Regex \[([^:]+):([^\]]+)\]
attr NTFY replacement02Value my $device = $name if ($1 eq "\$name") // $1;;\
ReadingsVal($device, $2, undef) or AttrVal($device, $2, "???");;
attr NTFY room Global
attr NTFY set1Data $val
attr NTFY set1Method POST
attr NTFY set1Name sendToTopicFreundlichenGruesseAnAlleFHEMNutzer
attr NTFY set1Replacement01Value FreundlichenGruesseAnAlleFHEMNutzer
attr NTFY set1TextArg 1
attr NTFY setURL https://[$name:NtfyServer]/%%path%%

Temporär kann man es auch bei CoolTux auf dem Testserver ausprobieren: https://demo-fhem.cooltux.net/fhem?detail=NTFY&fw_id=

Senden kann man die Testnachricht mit: set NTFY sendToTopicFreundlichenGruesseAnAlleFHEMNutzer Hallo Allerseits

Torxgewinde

Hier noch eine leicht erweitertes Snippet um bequem "Markdown", "Priorität" und "Titel" setzen zu können. Da FHEM mit UTF-8 und damit mit Emojis gut klarkommt, braucht man den Header für "Tags" nicht.

Der Befehl zum Senden ist hier leicht abgewandelt: set NTFY message und hier kommt der Text

defmod NTFY HTTPMOD none 0
attr NTFY userattr Markdown NtfyServer Priority Title Topic password username
attr NTFY Markdown false
attr NTFY NtfyServer ntfy.sh
attr NTFY Priority min
attr NTFY Title Titel aus UserAttr heraus
attr NTFY Topic FreundlichenGruesseAnAlleFHEMNutzer
attr NTFY comment # for HTTP Basic authentication use this as "setUrl":\
# https://[$name:username]:[$name:password]@[$name:NtfyServer]/%%path%%
attr NTFY replacement01Mode text
attr NTFY replacement01Regex %%path%%
attr NTFY replacement02Mode expression
attr NTFY replacement02Regex \[([^:]+):([^\]]+)\]
attr NTFY replacement02Value my $device = $name if ($1 eq "\$name") // $1;;\
ReadingsVal($device, $2, undef) or AttrVal($device, $2, "???");;
attr NTFY room Global
attr NTFY set1Data $val
attr NTFY set1HeaderMarkdown Markdown: [$name:Markdown]
attr NTFY set1HeaderPrio Priority: [$name:Priority]
attr NTFY set1HeaderTitle Title: [$name:Title]
attr NTFY set1Method POST
attr NTFY set1Name message
attr NTFY set1Replacement01Value [$name:Topic]
attr NTFY set1TextArg 1
attr NTFY setURL https://[$name:NtfyServer]/%%path%%
attr NTFY widgetOverride Priority:select,max,high,default,low,min Markdown:select,true,false

marvin78

Ich habe vor kurzem auch ein FHEM Modul für ntfy gefunden. Leider hat das einige Bugs und es hält sich nicht an gängige Vorgaben für die FHEM Entwicklung.

Torxgewinde

@marvin78: Kann man sich ja mal angucken, wo kann man das Modul denn finden?

marvin78


Torxgewinde

Ah, danke, jetzt habe ich es gefunden: https://gitea.federationhq.de/byterazor/FHEM-NTFY

Vom reinen Durchlesen her sieht das doch ganz sinnig aus.

Was klappt bei dem Modul denn nicht und weiß der Autor bereits davon? Die Liste der "Issues" ist leer: https://gitea.federationhq.de/byterazor/FHEM-NTFY/issues

Gisbert

Hallo Torxgewinde,

das klingt ja recht interessant und funktioniert auf Anhieb.
Wie kann ich denn das Attribute Title flexibel gestalten?
Kann man sowas in der Art umsetzen?
set NTFY message <Titel> und hier kommt der TextAnsonsten müsste man ja bei jeder Meldung mit anderem Titel das Attribut Title neu setzen.

Viele Grüße
Gisbert
Aktuelles FHEM | PROXMOX | Fujitsu Futro S740 | Debian 12 | UniFi | Homematic, VCCU, HMUART | ESP8266 | ATtiny85 | Wasser-, Stromzähler | tuya local | Wlan-Kamera | SIGNALduino, Flamingo Rauchmelder FA21/22RF | RHASSPY | DEYE | JK-BMS | ESPHome

marvin78

Zitat von: Torxgewinde am 10 Februar 2024, 11:46:01Ah, danke, jetzt habe ich es gefunden: https://gitea.federationhq.de/byterazor/FHEM-NTFY

Vom reinen Durchlesen her sieht das doch ganz sinnig aus.

Was klappt bei dem Modul denn nicht und weiß der Autor bereits davon? Die Liste der "Issues" ist leer: https://gitea.federationhq.de/byterazor/FHEM-NTFY/issues

Ich kann mich da nicht anmelden. Ich weiß auch nicht, wer der Autor ist.

Was mir direkt aufgefallen ist:

- STATE wird direkt gesetzt  ::)
- es fehlt die ATTR-sub, FHEM hängt sich auf, versucht man ein Attribut zu setzen
- keine Doku im Modul - wenn man sich den Code nicht anschaut und ihn versteht, kann man es gar nicht definieren
- ich verstehe die Struktur nicht: warum ein Device, das offline bleibt und eines, das versteckt wird?
- sicher noch weiteres



Torxgewinde

#8
Zitat von: Gisbert am 10 Februar 2024, 14:56:49Wie kann ich denn das Attribute Title flexibel gestalten?
Kann man sowas in der Art umsetzen?
set NTFY message <Titel> und hier kommt der Text

Ja, das wäre dann (mit leicht abgewandelter Idee) möglich mit solch einem Snippet:
define NTFY HTTPMOD none 0
attr NTFY userattr Markdown NtfyServer Priority Title Topic password username
attr NTFY Markdown false
attr NTFY NtfyServer ntfy.sh
attr NTFY Priority min
attr NTFY Title Titel aus UserAttr heraus
attr NTFY Topic FreundlichenGruesseAnAlleFHEMNutzer
attr NTFY comment # for HTTP Basic authentication use this as "setUrl":\
# https://[$name:username]:[$name:password]@[$name:NtfyServer]/%%path%%
attr NTFY replacement01Mode text
attr NTFY replacement01Regex %%path%%
attr NTFY replacement02Mode expression
attr NTFY replacement02Regex \[([^:]+):([^\]]+)\]
attr NTFY replacement02Value my $device = $name if ($1 eq "\$name") // $1;;\
ReadingsVal($device, $2, undef) or AttrVal($device, $2, "???");;
attr NTFY replacement03Mode expression
attr NTFY replacement03Regex %%title%%
attr NTFY replacement04Mode expression
attr NTFY replacement04Regex %%message%%
attr NTFY room Global
attr NTFY set1Data %%message%%
attr NTFY set1HeaderMarkdown Markdown: [$name:Markdown]
attr NTFY set1HeaderPrio Priority: [$name:Priority]
attr NTFY set1HeaderTitle Title: %%title%%
attr NTFY set1Method POST
attr NTFY set1Name message
attr NTFY set1Replacement01Value [$name:Topic]
attr NTFY set1Replacement03Value # get the value as passed to the set command:\
my $value = InternalVal($name, "value", "???");;\
\
# find first occurence of pattern Title=".*" and use that as result:\
my ($result) = $value =~ /Title="(.*?)"/;;\
\
# assign value from userAttr if $result is emtpy:\
$result //= AttrVal($name, "Title", "???");;\
\
return $result;;
attr NTFY set1Replacement04Value # get the value as passed to the set command:\
my $value = InternalVal($name, "value", "???");;\
\
# remove everything matching pattern Title=".*"\
$value =~ s/Title=".*?"//;;\
\
return $value;;
attr NTFY set1TextArg 1
attr NTFY setURL https://[$name:NtfyServer]/%%path%%
attr NTFY widgetOverride Priority:select,max,high,default,low,min Markdown:select,true,false

Einen Titel kann man dann mitgeben mit:
  • set NTFY message Title="mein Titel aus dem Set heraus" Meine Nachricht
  • set NTFY message Title="" Meine Nachricht ohne Titel
  • set NTFY message Title="✅ Emojis 🚀" 📝 Meine Nachricht mit Emojis 👾
  • oder man hat nur den Titel im User-Attribut "Title" falls das Muster Title="irgendwas" nicht im Parameter der set Nachricht auftaucht: set NTFY message Meine kurze Nachricht, Titel aus UserAttr Title genutzt

Bei dem CoolTux Testserver habe ich es aktualisiert um es zu testen und zu demonstrieren: https://demo-fhem.cooltux.net/fhem?detail=NTFY&fw_id=

Torxgewinde

Zitat von: marvin78 am 10 Februar 2024, 15:36:34Ich kann mich da nicht anmelden. Ich weiß auch nicht, wer der Autor ist.

Ich habe dem Autor eine E-Mail geschrieben und auf diesen Thread hingewiesen, mal schauen...

Gisbert

Hallo Torxgewinde,

top, funktioniert:
set NTFY message Title="mein Titel aus dem Set heraus" Meine Nachricht
Vielen Dank und viele Grüße
Gisbert
Aktuelles FHEM | PROXMOX | Fujitsu Futro S740 | Debian 12 | UniFi | Homematic, VCCU, HMUART | ESP8266 | ATtiny85 | Wasser-, Stromzähler | tuya local | Wlan-Kamera | SIGNALduino, Flamingo Rauchmelder FA21/22RF | RHASSPY | DEYE | JK-BMS | ESPHome

Gisbert

Hallo zusammen,

ein kleiner Hinweis von meiner Seite.
Falls NTFY in einem Fhem notify genutzt werden soll und man auf der Perl-Ebene arbeitet, dann müssen die Anführungszeichen escaped werden (statt " dann \"), also so (im raw-Format):
defmod Wasseralarm.notify notify Wassermelder:wet|dry\
{if (ReadingsVal("Wassermelder","state","") eq "wet" \
and ReadingsVal("Wasseralarm.dum","state","") eq "off") \
{fhem "set Wasseralarm.dum on-for-timer 600;; \
set Pushover.Nachricht msg 'Wasserschaden Heizung' 'Es wurde ein Wasseraustritt an der Heizung registriert !!!';; \
set NTFY message Title=\"Wasserschaden Heizung\" Es wurde ein Wasseraustritt an der Heizung registriert !!!;; \
set PushNotifier.Nachricht message Es wurde ein Wasseraustritt an der Heizung registriert !!!"} \
elsif (ReadingsVal("Wassermelder","state","") eq "dry") \
{fhem "set Pushover.Nachricht msg 'Heizung' 'Anscheinend ist es (wieder) trocken !';; \
set NTFY message Title=\"Heizung\" Anscheinend ist es (wieder) trocken !;; \
set PushNotifier.Nachricht message Anscheinend ist es (wieder) trocken !"}}

Viele Grüße Gisbert
Aktuelles FHEM | PROXMOX | Fujitsu Futro S740 | Debian 12 | UniFi | Homematic, VCCU, HMUART | ESP8266 | ATtiny85 | Wasser-, Stromzähler | tuya local | Wlan-Kamera | SIGNALduino, Flamingo Rauchmelder FA21/22RF | RHASSPY | DEYE | JK-BMS | ESPHome

Torxgewinde

Wenn man den NTFY Server selbst hosten möchte, habe ich ggf. eine hilfreiche HAProxy Konfiguration anzubieten: https://forum.fhem.de/index.php?topic=134798.msg1303380#msg1303380

isy

Moin zusammen,
das defmod klappt gut - super, vielen Dank.

Ich versuche gerade, als Message den Status eines Devices zu senden (mit DebianMail geht das), scheitere leider am Syntax.
Hat jemand eine Idee?

(set NTFY message ReadingsVal("az_SW_Fenster_l","state","--"))
VG Helmut
Ein Weg wird erst zu einem Weg, wenn man ihn geht

isy

Der erste Schritt ist gefunden. Mit:
set NTFY message Büro links: [az_SW_Fenster_l:state], Büro rechts: [az_SW_Fenster_r:state], Badezimmer Dach: [bz_SW_Fenster_Dach:state]
lassen sich die jeweiligen state Infos senden.

Einen Zeilenumbruch kriege ich nicht hin. ⁄n geht nicht, auch nicht mit ⁄⁄n oder <br>

Eine Idee?
Ein Weg wird erst zu einem Weg, wenn man ihn geht

Torxgewinde

Genau, im ersten Post hattest du falsch geklammert, im zweiten nutzt du die Set Magic was IMHO schön übersichtlich ist.

Zeilenumbrüche gehen grundsätzlich mit einer kleinen Ergänzung, es bietet sich modifizierte Definition an:
defmod NTFY HTTPMOD none 0
attr NTFY userattr Markdown NtfyServer Priority Title Topic password username
attr NTFY Markdown true
attr NTFY NtfyServer ntfy.sh
attr NTFY Priority default
attr NTFY Title Titel aus UserAttr heraus
attr NTFY Topic FreundlichenGruesseAnAlleFHEMNutzer
attr NTFY comment # for HTTP Basic authentication use this as "setUrl":\
# https://[$name:username]:[$name:password]@[$name:NtfyServer]/%%path%%
attr NTFY replacement01Mode text
attr NTFY replacement01Regex %%path%%
attr NTFY replacement02Mode expression
attr NTFY replacement02Regex \[([^:]+):([^\]]+)\]
attr NTFY replacement02Value my $device = $name if ($1 eq "\$name") // $1;;\
ReadingsVal($device, $2, undef) or AttrVal($device, $2, "???");;
attr NTFY replacement03Mode expression
attr NTFY replacement03Regex %%title%%
attr NTFY replacement04Mode expression
attr NTFY replacement04Regex %%message%%
attr NTFY room Global
attr NTFY set1Data %%message%%
attr NTFY set1HeaderIcon Icon: https://fhem.de/www/images/default/fhemicon.png
attr NTFY set1HeaderMarkdown Markdown: [$name:Markdown]
attr NTFY set1HeaderPrio Priority: [$name:Priority]
attr NTFY set1HeaderTitle Title: %%title%%
attr NTFY set1Method POST
attr NTFY set1Name message
attr NTFY set1Replacement01Value [$name:Topic]
attr NTFY set1Replacement03Value # get the value as passed to the set command:\
my $value = InternalVal($name, "value", "???");;\
\
# find first occurence of pattern Title=".*" and use that as result:\
my ($result) = $value =~ /Title="(.*?)"/;;\
\
# assign value from userAttr if $result is emtpy:\
$result //= AttrVal($name, "Title", "???");;\
\
return $result;;
attr NTFY set1Replacement04Value # get the value as passed to the set command:\
my $value = InternalVal($name, "value", "???");;\
\
# remove everything matching pattern Title=".*"\
$value =~ s/Title=".*?"//;;\
\
#replace the literal character sequence\
# \n with a real linefeed\
$value =~ s/\\n/\n/g;;\
\
return $value;;
attr NTFY set1TextArg 1
attr NTFY setURL https://[$name:NtfyServer]/%%path%%
attr NTFY widgetOverride Priority:select,max,high,default,low,min Markdown:select,true,false

So kann man dann auch Zeilenumbrüche senden:
set NTFY message Title="mein Titel"Zeile #1\nZeile #2\nZeile #3

Gisbert

15.2.2024, Ergänzung:
Ich hab's jetzt erneut versucht und diesmal geht das Escapen mit "\.
Korrektur nach dem Kommentar von Torxgewinde (Beitrag #18): Es muss richtig so heißen: \"
Auch der Zeilenumbruch funktioniert in Kombination mit dem Ecapen.

Hallo Torxgewinde,

leider geht mit der neuen Definition mit dem Zeilenumbruch das escapen von " mit "\ leider nicht mehr. Das wird dann benötigt, wenn man in einem Fhem-notify mit " arbeiten muss, um den Titel in der Nachricht situationsbedingt zu erhalten.
Hast du eine Idee, was zu ändern ist?
Es müsste vermutlich an dieser Einstellung liegen:
#replace the literal character sequence\
# \n with a real linefeed\
$value =~ s/\\n/\n/g;;\

Viele Grüße Gisbert
Aktuelles FHEM | PROXMOX | Fujitsu Futro S740 | Debian 12 | UniFi | Homematic, VCCU, HMUART | ESP8266 | ATtiny85 | Wasser-, Stromzähler | tuya local | Wlan-Kamera | SIGNALduino, Flamingo Rauchmelder FA21/22RF | RHASSPY | DEYE | JK-BMS | ESPHome

isy

Ein Weg wird erst zu einem Weg, wenn man ihn geht

Torxgewinde

Hallo Gisbert,
⚠️ Die Reihenfolge beim Escapen ist verdreht. Es müsste \" sein, der Backslash bei dem ß auf einer deutschen Tastatur leitet das ein und dann kommt das Zeichen was "escaped" sein soll. Andersherum die Zeichen anzuordnen ist vermutlich nicht das was du willst.

Zitat von: Gisbert am 14 Februar 2024, 20:47:0915.2.2024, Ergänzung:
Ich hab's jetzt erneut versucht und diesmal geht das Escapen mit "\.
Auch der Zeilenumbruch funktioniert in Kombination mit dem Ecapen.


... das escapen von " mit "\ leider nicht mehr. ...
Es müsste vermutlich an dieser Einstellung liegen:
#replace the literal character sequence\
# \n with a real linefeed\
$value =~ s/\\n/\n/g;;\
Das klingt gut, tut also alles.

Testweise habe ich es auch auf Cool-Tux Demoseite verifiziert. Du wechselst in deinem notify ja auf die Perl Ebene mit der geschweiften Klammer, nutzt dann die Perl-Funktion fhem() und übergibst der Perl-Funktion fhem() einen String. Der String ist mit " und " begrenzt, damit kann man Variablen in dem String nutzen, aber muss eben auch enthaltene Doppelte-Anführungszeichen escapen. Testweise sieht das dann bei mir so aus:
{ fhem("set NTFY message Title=\"Mein Titel\"Meine Zeile Nummer 1\nMeine Zeile Nummer 2") }Ist das gleiche wie der FHEM Befehl:
set NTFY message Title="Mein Titel"Meine Zeile Nummer 1\nMeine Zeile Nummer 2
Besonderheit bei Perl ist, dass man bei Funktionen die runden Klammern einfach weglassen kann. Es ist also gleichwertig für Perl ob man fhem("set bla blubb") oder fhem "set bla blubb" schreibt. Das fanden die Entwickler von Perl scheinbar toll, das kann auch mal verwirren finde ich.

Scheint ja jetzt zu klappen, wie ich deiner Ergänzung entnehmen kann 👍

isy

Zitat von: Torxgewinde am 14 Februar 2024, 18:55:28Zeilenumbrüche gehen grundsätzlich mit einer kleinen Ergänzung, es bietet sich modifizierte Definition an:

Moin - super, der neue Code funktioniert!
Schön auch mit dem Logo!

VG Helmut
Ein Weg wird erst zu einem Weg, wenn man ihn geht

TomLee

Moin,

Zitat... aber muss eben auch enthaltene Doppelte-Anführungszeichen escapen.

Oder man verwendet qq() und spart sich das escapen:
{ fhem(qq(set NTFY message Title="Mein Titel " Meine Zeile Nummer 1\nMeine Zeile Nummer 2)) }

byterazor

Hallo,

ich bin der Autor vom NTFY_CLIENT. @Torxgewinde hat mich darauf aufmerksam gemacht, dass ich offensichtlich
mein Repository für den Client nicht privat geschaltet hatte. Da der Code nun raus ist und, wie üblich in diesem Forum, gleich für schlecht befunden wurde, habe ich einige Verbesserungen eingepflegt. Die aktuellste Version ist immer unter https://gitea.federationhq.de/byterazor/FHEM-NTFY zu finden. Der Issue Tracker befindet sich unter https://rm.byterazor.de/projects/fhem-ntfy.

Konstruktive Kritik und Verbesserungsvorschläge sind herzlich willkommen. Zu bedenken sollte aber immer sein, dass ich, wie viele Modulautoren hier, einen Job und eine Familie besitze.

bis denn
byterazor


marvin78

Tatsächlich war meine Kritik konstruktiv und niemand hat geschrieben, dass der Code schlecht ist, wenn du mal genau hinschaust. Da reagierst du etwas zu empfindlich. Die Punkte sind alle valide und tatsächlich (bis auf den STATE - da kräuseln sich mir die Fußnägel) komplett neutral. Es war mir nicht klar, dass der Code privat bleiben sollte. Hätte ich das gewusst, hätte ich gar nichts geschrieben. Ich bin jedoch der Meinung, wenn er denn nicht privat bleibt, sollte man gewisse Dinge beachten. Die Guidelines sind schon sinnvoll. Das hat dann auch nichts damit zu tun, dass man Job und Familie hat. Es ist nichts zeitaufwändiges oder kompliziertes dabei. Mein Perl ist alles andere als gut, ich hasse Perl. Trotzdem, trotz Familie, trotz 60 Stunden-Woche, versuche ich mich bei den öffentlichen Modulen weitgehend an gewisse Dinge zu halten. Nicht, weil es jemand so möchte, sondern weil es sinnvoll ist.

Danke für's verbessern. Ich werde es testen, sobald ich Zeit habe.

Torxgewinde

@byterazor: Ein großes Dankeschön dafür, dass die Doku ergänzt wurde. 🎉

Der Riesen-Vorteil deines NTFY_CLIENT ist, dass es nicht nur Nachrichten sendet, sondern dass man auch Nachrichten empfangen kann. Damit sollte der HTTPMOD aus diesem Codeschnipsel-Thread schnell obsolet werden, was IMHO völlig Ok ist - also: DANKE!

marvin78

Zitat von: Torxgewinde am 24 Februar 2024, 08:48:18Der Riesen-Vorteil deines NTFY_CLIENT ist, dass es nicht nur Nachrichten sendet, sondern dass man auch Nachrichten empfangen kann. Damit sollte der HTTPMOD aus diesem Codeschnipsel-Thread schnell obsolet werden, was IMHO völlig Ok ist - also: DANKE!

Ich glaube tatsächlich, das mit dem Lauschen funktioniert in dieser Version nicht. Das Topic bleibt im Hash leer, da es im Define nicht mehr angegeben wird. Das Attribut defaultTopic hingegen wird bei der Subscription offenbar nicht ausgewertet. Es gibt auch eine Inkonsistenz zwischen $hash->{helper}->{topics} (was immer leer zu sein scheint) und $hash->{TOPIC} (was wohl bei der Subscription ausgewertet wird). Ich habe aber nur grob über den Code geschaut und kann etwas übersehen haben.

Eine Bitte hätte ich noch: STATE bitte über das Readings state setzen damit man als USER stateFormat zuverlässig nutzen kann (siehe Guidelines). 

byterazor

Das subscriben zu topics kommt wieder. Kann man dann auf mehrere Topics mittels set festlegen.

STATE wird bis auf das erste Mal im define als Readings gesetzt. Seit der ersten Version.

Torxgewinde

Stimmt, schade - ich habe es jetzt gerade ausprobiert:

Im Terminal den Quelltext holen, verrechten:
cd /opt/fhem/FHEM
wget https://gitea.federationhq.de/byterazor/FHEM-NTFY/raw/branch/main/FHEM/98_NTFY_CLIENT.pm
chown fhem:dialout 98_NTFY_CLIENT.pm

In FHEM:
update
shutdown restart
...warten bis FHEM wieder da ist, dann:
define NTFY0 NTFY_CLIENT https://ntfy.sh

Nachricht senden mit:
set NTFY0 publish @FreundlichenGruesseAnAlleFHEMNutzer Meine Nachricht
Empfang ist dann noch etwas das sowohl bei dem HTTPMOD als auch @byterazors Modul vorerst nicht geht. Das Wichtigste ist ja erstmal signalisieren von Nachrichten und das klappt bei beiden Lösungen. Ich finde es trotzdem gut hier auch ein Modul zu haben...

marvin78

Zitat von: byterazor am 24 Februar 2024, 09:24:23Das subscriben zu topics kommt wieder. Kann man dann auf mehrere Topics mittels set festlegen.

STATE wird bis auf das erste Mal im define als Readings gesetzt. Seit der ersten Version.

Warum im Define nicht auch? Das Ding ist, das ein stateFormat somit bei jedem Neustart oder Define überschrieben wird. Das ist nicht schön.

Zum Rest: Ich bin gespannt :)

byterazor


Torxgewinde

Hi,
Das klingt super.

Ich komme gerade erst dazu es auszuprobieren, habe aber noch keinen Erfolg. Es wird wohl das Device angelegt, aber wenn ich mich auf das Topic "FreundlichenGruesseAnAlleFHEMNutzer" subscribe, wird ein Device "NTFY0_FreundlichenGruesseAnAlleFHEMNutzer" angelegt. Das Internal DeviceName ist allerdings komisch mit einem doppeltem Slash "wss:ntfy.sh:443//ws?auth=FreundlichenGruesseAnAlleFHEMNutzer".

Ich habe testweise in 98_NTFY_TOPIC.pm eine kleine Änderung vorgenommen um doppelten Slashes zu entfernen:
my $dev = $hash->{SERVER} . ":" . $port . "/" . $hash->{TOPIC} . "/ws";
#$dev =~ s#/{2}#/#g;
my $dev = $hash->{SERVER} . ":" . $port . $hash->{TOPIC} . "/ws";

Das Device NTFY0_FreundlichenGruesseAnAlleFHEMNutzer gelöscht und mich wieder neu über das Device NTFY0 subscribed. Dann ist das Internal DeviceName "wss:ntfy.sh:443/ws?auth=FreundlichenGruesseAnAlleFHEMNutzer". Trotzdem ist es komisch, dass das Topic als Token angehängt wird. Auch meldet das Log:
2024.02.25 08:33:20 1: NTFY-CLIENT:password required for NFTY_Calc_Auth_Token
2024.02.25 08:33:20 1: PERL WARNING: Use of uninitialized value in concatenation (.) or string at ./FHEM/98_NTFY_TOPIC.pm line 129.
2024.02.25 08:33:20 3: Opening NTFY0_FreundlichenGruesseAnAlleFHEMNutzer device wss:ntfy.sh:443/ws?auth=FreundlichenGruesseAnAlleFHEMNutzer
2024.02.25 08:33:25 1: NTFY0_FreundlichenGruesseAnAlleFHEMNutzer: Can't connect to wss:ntfy.sh:443/ws?auth=FreundlichenGruesseAnAlleFHEMNutzer: HTTP CODE 200
2024.02.25 08:33:25 1: NTFY-TOPIC:error while connecting to websocket: HTTP CODE 200

Testweise habe ich dann die DEF geändert in:
https://ntfy.sh "" FreundlichenGruesseAnAlleFHEMNutzerLeider auch ohne Erfolg. Es wird zwar das Topic dann korrekt verwendet, aber Nachrichten kann ich so noch nicht empfangen.

Ich glaube da muss auch noch was mit dem AuthToken nicht stimmen, der ist hier noch nicht optional glaube ich...

byterazor

hi,

sorry ich benutze eine eigene Instanz mit Authentifizierung. Habe nicht daran gedacht, dass das ja bei ntfy.sh anders ist ...
Sollte gefixt sein.
Fehlermeldungen wären mir aber über ein Issue lieber, geht auch anonym ohne Anmeldung. Hab das hier nur deshalb mitbekommen weil die Seite noch auf meinem Tablet offen war ....

bis denn

Torxgewinde


Gisbert

Hallo,

ich nutze die Definition aus dem Anfangspost. Es funktioniert auch soweit alles bis auf die Tatsache, dass Meldungen mit einer Verzögerung von 2~3 Stunden eintreffen.

Woran könnte es liegen?

Viele Grüße Gisbert
Aktuelles FHEM | PROXMOX | Fujitsu Futro S740 | Debian 12 | UniFi | Homematic, VCCU, HMUART | ESP8266 | ATtiny85 | Wasser-, Stromzähler | tuya local | Wlan-Kamera | SIGNALduino, Flamingo Rauchmelder FA21/22RF | RHASSPY | DEYE | JK-BMS | ESPHome

isy

Hallo Gisbert,
ich habe den Client auf iOS 17.3.1 und auf Android 9 und 13 Geräten installiert.
Auf allen kommt die Meldung sofort oder nur wenige Sekunden (Apple) verzögert.

Priorität im FHEM ist "high" eingestellt.

VG Helmut
Ein Weg wird erst zu einem Weg, wenn man ihn geht

Gisbert

Hallo Helmut,

ich hatte priority auf max stehen. Mit high oder max kommen Testnachrichten im Bruchteil einer Sekunde aufs Handy. Daran liegt es vermutlich eher nicht.
Vielleicht liegt es an der Definition (notify), mit der ich Nachrichten versende. Ich schau mir die logs dazu an, am besten verbose vorher auf 5 stellen.

Viele Grüße Gisbert
Aktuelles FHEM | PROXMOX | Fujitsu Futro S740 | Debian 12 | UniFi | Homematic, VCCU, HMUART | ESP8266 | ATtiny85 | Wasser-, Stromzähler | tuya local | Wlan-Kamera | SIGNALduino, Flamingo Rauchmelder FA21/22RF | RHASSPY | DEYE | JK-BMS | ESPHome


byterazor


mähschaf

Guten Abend,

erst einmal vielen Dank für die tolle Arbeit!

Was mich interessieren würde: Gibt es beim Senden der Nachricht die Möglichkeit - ähnlich wie mit @TOPIC das defaultTopic - auch die defaultPriority zu überschreiben? Ich habe dazu nichts gefunden...

Vielen Dank und schöne Ostertage,
Martin

habl

Zitat von: mähschaf am 28 März 2024, 21:32:24Gibt es beim Senden der Nachricht die Möglichkeit - ähnlich wie mit @TOPIC das defaultTopic - auch die defaultPriority zu überschreiben?

wenn Du das  Modul von byterazor nutzt:

attr NTFY defaultPriority default
VG
  habl

mähschaf

Hallo,

ich habe mir den gut verständlichen Code auf GitHub angesehen. Die defaultPriority kann über ein vorangestelltes Ausrufezeichen mitgegeben werden.

Also z. B. ... publish @TOPIC !low blabla

Frohe Ostern!
Martin

Torxgewinde

Ich hatte nun endlich mal einen Anlass Dominik Meyers Device zu testen und vielleicht ist diese Zusammenfassung hier auch gut aufgehoben:

Um NTFY.sh einzurichten:
update add https://rm.byterazor.de/upd-fhem-ntfy/controls_byterazor-fhem-ntfy.txt
update
shutdown restart
Ein Device anlegen mit:
defmod NTFY0 NTFY_CLIENT https://ntfy.sh
attr NTFY0 defaultPriority default
attr NTFY0 defaultTopic FreundlichenGruesseAnAlleFHEMNutzer
attr NTFY0 room Experimente

Senden einer Nachricht mit einem curl-Befehl:
curl -d "Your message content here" \
     -H "Title: Bla" \
     https://ntfy.sh/FreundlichenGruesseAnAlleFHEMNutzer
Das Gleiche nur mit WGET:
wget --method=POST \
     --body-data="Your message content here" \
     --header="Title: Bla" \
     https://ntfy.sh/FreundlichenGruesseAnAlleFHEMNutzer -q -O -
Oder, wenn es ein reines HTTP-GET als Webhook sein soll:
https://ntfy.sh/FreundlichenGruesseAnAlleFHEMNutzer/publish?message=Your%20message%20content%20here&title=Bla

Oder, aus FHEM an den Server eine Nachricht senden mit:
set NTFY0 publish @FreundlichenGruesseAnAlleFHEMNutzer Testnachricht!

Im Event-Log taucht dann folgendes auf, darauf kann man mit notify oder DOIF reagieren:
2024-10-29 19:01:16.714 NTFY_TOPIC NTFY0_FreundlichenGruesseAnAlleFHEMNutzer nrReceivedMessages: 7
2024-10-29 19:01:16.715 NTFY_CLIENT NTFY0 subscriptions: FreundlichenGruesseAnAlleFHEMNutzer
2024-10-29 19:01:16.715 NTFY_CLIENT NTFY0 nrReceivedMessages: 7
2024-10-29 19:01:16.715 NTFY_CLIENT NTFY0 lastReceivedTitle: Bla
2024-10-29 19:01:16.715 NTFY_CLIENT NTFY0 lastReceivedData: Your message content here
2024-10-29 19:01:16.715 NTFY_CLIENT NTFY0 lastReceivedRawMessage: {"id":"oU5iqrdSFoeY","time":1730224876,"expires":1730268076,"event":"message","topic":"FreundlichenGruesseAnAlleFHEMNutzer","title":"Bla","message":"Your message content here"}

Testen kannst man hier:
https://ntfy.sh/FreundlichenGruesseAnAlleFHEMNutzer
https://demo-fhem.cooltux.net/fhem?detail=NTFY0 <-- Begrenzt gültiger Link
https://ntfy.sh/FreundlichenGruesseAnAlleFHEMNutzer/publish?message=Blubb&title=Bla

ReneR1986

Nach ein paar Tagen wird nicht mehr auf die Subscriptions reagiert.
Nur ein neu anlegen des Moduls hat bisher das Problem immer lösen können.

Internals:
   CFGFN     
   DEF        https://ntfy.sh password=XX user=XX
   FUUID      67717943-f33f-db0c-a5db-0b141b4f528e6772
   LASTInputDev NotifyClient_iyiDRZLk4Jks34Sa
   MSGCNT     1
   NAME       NotifyClient
   NR         437
   NotifyClient_iyiDRZLk4Jks34Sa_MSGCNT 1
   NotifyClient_iyiDRZLk4Jks34Sa_TIME 2024-12-29 17:31:45
   SERVER     https://ntfy.sh
   STATE      passive
   TYPE       NTFY_CLIENT
   USERNAME   XX
   VERSION    0.0.1
   eventCount 3
   READINGS:
     2024-12-29 17:31:45   Titel           Test123
     2024-12-29 17:31:45   lastReceivedData Hoftor
     2024-12-29 17:31:45   lastReceivedRawMessage {"id":"eA2G3dpAW6ji","time":1735489905,"expires":1735533105,"event":"message","topic":"XX","title":"Test123","message":"Hoftor"}
     2024-12-29 17:31:45   lastReceivedTitle Test123
     2024-12-29 17:31:45   lastReceivedTopic XXX
     2024-12-29 17:31:45   nrReceivedMessages 1
     2024-12-29 17:30:59   state           passive
     2024-12-29 17:31:45   subscriptions   XXX
   helper:
     PASSWORD   XXX
Attributes:
   defaultPriority default
   defaultTopic XXX
   group      Push Nachrichten
   userReadings Titel:lastReceivedRawMessage:.* { my $VAR=ReadingsVal("NotifyClient","lastReceivedRawMessage",0);$VAR =~ /"title":"(.*?)"/;return "$1";}

Torxgewinde

Hi @ReneR:
Das hatte ich auch mal (https://forum.fhem.de/index.php?topic=139621.msg1323988#msg1323988), allerdings hatte @ByteRazor das in seinem GIT bereits gefixt. Hast du die neuste Version von ihm? Magst du sonst ggf. dort ein Ticket anfragen?

Alternativ hatte ich mir mit einem zusammengezimmerten Dummy mit Websocket geholfen, vielleicht gefällt dir das ja auch (siehe auch oben verlinkter Post). Wenn du kannst, solltest du ByteRazors Lösung bevorzugen, die ist weniger "hacky" und mehr im Sinne von FHEM.

ReneR1986


Torxgewinde

Super, und falls das wieder Stress macht mal meinen Snippet ausprobieren und ggf. auch Byterazor bitten da nochmal nach zu schauen. Er ist NICHT hier im Forum aktiv, deswegen am besten direkt kontaktieren über seine Webseite - der ist IMHO ganz offen für sowas.

Torxgewinde

Ich hatte auch nochmal an meinem Snippet einen weiteren Watchdog zu dem einfachen Wiederverbinden eingefügt, doppelt hält besser... Das sollte damit recht hartnäckig die Verbindung halten und neu aufbauen, außer man gibt den stop-Befehl.

Weiterhin: Erste Wahl ist IMHO der Code von ByteRazor, falls das nicht klappt alternativ den Snippet von mir nehmen.

defmod NTFY_RECEIVE dummy
attr NTFY_RECEIVE userattr URL last_seen_max_age
attr NTFY_RECEIVE URL wss:ntfy.sh:443/FreundlichenGruesseAnAlleFHEMNutzer/ws
attr NTFY_RECEIVE alias NTFY_RECEIVE
attr NTFY_RECEIVE devStateIcon opened:general_ok@green:stop disconnected:rc_STOP@red:start
attr NTFY_RECEIVE eventMap /cmd connect:start/cmd disconnect:stop/
attr NTFY_RECEIVE group Experimente
attr NTFY_RECEIVE icon hue_filled_plug
attr NTFY_RECEIVE last_seen_max_age 600
attr NTFY_RECEIVE readingList cmd
attr NTFY_RECEIVE setList cmd
attr NTFY_RECEIVE userReadings connect:cmd:.connect {\
my $hash = $defs{$name};;\
my $devState = DevIo_IsOpen($hash);;\
return "Device already open" if (defined($devState));;\
\
$hash->{DeviceName} = AttrVal($name, "URL", "wss:ntfy.sh:443/FreundlichenGruesseAnAlleFHEMNutzer/ws");;\
$hash->{header}{'Host'} = 'ntfy.sh';;\
$hash->{header}{'User-Agent'} = 'FHEM';;\
\
$hash->{directReadFn} = sub () {\
my $hash = $defs{$name};;\
readingsBeginUpdate($hash);;\
my $buf = DevIo_SimpleRead($hash);;\
\
# track activity, emtpy buffer normally is from ping/pongs\
readingsBulkUpdate($hash, "last_seen", int(time()*1000));;\
RemoveInternalTimer($name.'Timeout');;\
my $timeoutFunction = sub() {\
my ($arg) = @_;;\
my $hash = $defs{$name};;\
my $myCmd = ReadingsVal($name, "cmd", "disconnect");;\
return if ($myCmd =~ /disconnect|stop/);;\
\
Log3($name, 3, "$name: Timeout occured, restarting websocket...");;\
DevIo_CloseDev($hash);;\
readingsBeginUpdate($hash);;\
readingsBulkUpdate($hash, "state", "disconnected");;\
readingsBulkUpdate($hash, "cmd", "connect", 1);;\
readingsEndUpdate($hash, 1);;\
};;\
InternalTimer(gettimeofday() + 120, $timeoutFunction, $name.'Timeout');;\
\
if(!defined($buf)) {\
DevIo_CloseDev($hash);;\
#readingsBulkUpdate($hash, "last_seen", 0);;\
$buf = "not_connected";;\
}\
\
# only update our reading if buffer is not empty and looks like it contains a message\
if ($buf ne "" && \
    $buf =~ /^{.*"event":"message".*}$/) { ## check if buffer looks like JSON with msg\
\
# delete all our readings that begin with "ntfy_"\
foreach my $reading (grep { $_ =~ /^ntfy_.*/ } keys %{$hash->{READINGS}}) {\
readingsDelete($hash, $reading);;\
}\
\
# parse as JSON, do not trust the input fully, thus sanitize buffer\
my %res = %{json2nameValue($buf)};; #(https://wiki.fhem.de/wiki/MQTT2_DEVICE_-_Schritt_f%C3%BCr_Schritt#json2nameValue.28.29)\
foreach my $k (sort keys %res) {\
# only keep ASCII and a German Characters like Umlaute, sharp-S...\
my $sanitizedValue = $res{$k} =~ s/[^[:ascii:]äöüÖÄÜß]/_/rg;; # 'r' flag prevents modifying the input string\
readingsBulkUpdate($hash, "ntfy_".makeReadingName($k), $sanitizedValue);;\
}\
}\
#readingsBulkUpdate($hash, "websocketData", "$buf") if ($buf ne "");;\
Log3($name, 3, "$name: Rx: >>>$buf<<<") if ($buf ne "");;\
\
readingsEndUpdate($hash, 1);;\
};;\
\
DevIo_OpenDev($hash,\
0,      ## reopen flag\
undef,  ## initFn, on success\
sub() { ## callbackFn, on verdict, req. to make it a non-blocking call\
my ($hash, $error) = @_;;\
if ($error) {\
Log(3, "$name: DevIo_OpenDev Callback: connection failed: $error");;\
\
my $timerFunction = sub() {\
my ($arg) = @_;;\
my $hash = $defs{$name};;\
my $devState = DevIo_IsOpen($hash);;\
readingsSingleUpdate($hash, "cmd", "connect", 1) if (!defined($devState));;\
};;\
\
RemoveInternalTimer($name.'Timer');;\
my $rwait = int(rand(20)) + 10;;\
InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.'Timer');;\
readingsSingleUpdate($hash, "cmd", "reconnect attempt in $rwait seconds", 1);;\
}\
}\
);;\
\
readingsBulkUpdate($hash, "state", "connecting...");;\
return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
disconnect:cmd:.(disconnect|reconnect) {\
my $hash = $defs{$name};;\
my $myCmd = ReadingsVal($name, "cmd", "???");;\
\
RemoveInternalTimer($name.'Timer');;\
RemoveInternalTimer($name.'Timeout');;\
DevIo_CloseDev($hash);;\
readingsBulkUpdate($hash, "state", "disconnected") if (!defined(DevIo_IsOpen($hash)));;\
\
if ($myCmd =~ /reconnect/) {\
my $timerFunction = sub() {\
my $hash = $defs{$name};;\
readingsSingleUpdate($hash, "cmd", "connect", 1);;\
};;\
\
RemoveInternalTimer("${name}_${reading}_timer");;\
InternalTimer(gettimeofday()+1, $timerFunction, "${name}_${reading}_timer");;\
} else {\
RemoveInternalTimer("${name}_watchdog_timer");;\
}\
\
return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
onDisconnect { ## check on each update if the connection is unintentionally broken...\
my $myState = ReadingsVal($name, "state", "???");;\
my $myData = ReadingsVal($name, "websocketData", "???");;\
my $myCmd = ReadingsVal($name, "cmd", "disconnect");;\
return if ($myState ne "disconnected" and $myData ne "not_connected");;\
return if ($myCmd =~ /disconnect|stop/);;\
\
my $timerFunction = sub() {\
my ($arg) = @_;;\
my $hash = $defs{$name};;\
my $devState = DevIo_IsOpen($hash);;\
readingsSingleUpdate($hash, "cmd", "connect", 1) if (!defined($devState));;\
};;\
\
RemoveInternalTimer($name.'Timer');;\
my $rwait = int(rand(20)) + 10;;\
InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.'Timer');;\
readingsBulkUpdate($hash, "cmd", "reconnect attempt in $rwait seconds");;\
\
return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
watchdog:last_seen:.* {\
my $ls = ReadingsVal($name, "last_seen", 0);;\
\
my $timerFunction = sub() {\
##fhem("set FHEMMeldung.ntfy message $name $reading wurde ausgelöst (last_seen: $ls)");;\
readingsSingleUpdate($hash, "cmd", "reconnect", 1);;\
readingsSingleUpdate($hash, "last_seen", 0, 1);;\
};;\
\
RemoveInternalTimer("${name}_${reading}_timer");;\
InternalTimer(gettimeofday()+240, $timerFunction, "${name}_${reading}_timer");;\
\
return POSIX::strftime("%H:%M:%S", localtime(time()));;\
}
attr NTFY_RECEIVE verbose 1
attr NTFY_RECEIVE webCmd start:stop

Torxgewinde

Kleines Update, falls mit meinem Snippet auch Nutzername und Passwort (als Attribute "username" und "password") genutzt werden sollen:

defmod NTFY_RECEIVE dummy
attr NTFY_RECEIVE userattr URL last_seen_max_age password username
attr NTFY_RECEIVE URL wss:ntfy.sh:443/FreundlichenGruesseAnAlleFHEMNutzer/ws
attr NTFY_RECEIVE alias NTFY_RECEIVE
attr NTFY_RECEIVE devStateIcon opened:general_ok@green:stop disconnected:rc_STOP@red:start
attr NTFY_RECEIVE eventMap /cmd connect:start/cmd disconnect:stop/
attr NTFY_RECEIVE group Experimente
attr NTFY_RECEIVE icon hue_filled_plug

attr NTFY_RECEIVE password superGeheimesPasswort
attr NTFY_RECEIVE readingList cmd

attr NTFY_RECEIVE setList cmd
attr NTFY_RECEIVE userReadings connect:cmd:.connect {\
    my $hash = $defs{$name};;\
    my $devState = DevIo_IsOpen($hash);;\
    return "Device already open" if (defined($devState));;\
    \
    $hash->{DeviceName} = AttrVal($name, "URL", "wss:ntfy.sh:443/FreundlichenGruesseAnAlleFHEMNutzer/ws");;\
    $hash->{DeviceName} =~ m,^(ws:|wss:)?([^/:]+):([0-9]+)(.*?)$,;;\
    $hash->{header}{'Host'} = $2;;\
    $hash->{header}{'User-Agent'} = 'FHEM';;\
    \
    my $user = AttrVal($name, "username", "???");;\
    my $pwd  = AttrVal($name, "password", "???");;\
    if ($user ne "???" && $pwd ne "???") {\
        my $encoded_auth = MIME::Base64::encode_base64("$user:$pwd", "");;\
        $hash->{header}{'Authorization'} = "Basic $encoded_auth";;\
    }\
    \
    $hash->{directReadFn} = sub () {\
        my $hash = $defs{$name};;\
        readingsBeginUpdate($hash);;\
        my $buf = DevIo_SimpleRead($hash);;\
        \
        # track activity, emtpy buffer normally is from ping/pongs\
        readingsBulkUpdate($hash, "last_seen", int(time()*1000));;\
        RemoveInternalTimer($name.'Timeout');;\
        my $timeoutFunction = sub() {\
            my ($arg) = @_;;\
            my $hash = $defs{$name};;\
            my $myCmd = ReadingsVal($name, "cmd", "disconnect");;\
            return if ($myCmd =~ /disconnect|stop/);;\
            \
            Log3($name, 3, "$name: Timeout occured, restarting websocket...");;\
            DevIo_CloseDev($hash);;\
            readingsBeginUpdate($hash);;\
            readingsBulkUpdate($hash, "state", "disconnected");;\
            readingsBulkUpdate($hash, "cmd", "connect", 1);;\
            readingsEndUpdate($hash, 1);;\
        };;\
        InternalTimer(gettimeofday() + 120, $timeoutFunction, $name.'Timeout');;\
        \
        if(!defined($buf)) {\
            DevIo_CloseDev($hash);;\
            #readingsBulkUpdate($hash, "last_seen", 0);;\
            $buf = "not_connected";;\
        }\
        \
        # only update our reading if buffer is not empty and looks like it contains a message\
        if ($buf ne "" && \
            $buf =~ /^{.*"event":"message".*}$/) { ## check if buffer looks like JSON with msg\
            \
            # delete all our readings that begin with "ntfy_"\
            foreach my $reading (grep { $_ =~ /^ntfy_.*/ } keys %{$hash->{READINGS}}) {\
                readingsDelete($hash, $reading);;\
            }\
            \
            # parse as JSON, do not trust the input fully, thus sanitize buffer\
            my %res = %{json2nameValue($buf)};; #(https://wiki.fhem.de/wiki/MQTT2_DEVICE_-_Schritt_f%C3%BCr_Schritt#json2nameValue.28.29)\
            foreach my $k (sort keys %res) {\
                # only keep ASCII and a German Characters like Umlaute, sharp-S...\
                my $sanitizedValue = $res{$k} =~ s/[^[:ascii:]äöüÖÄÜß]/_/rg;; # 'r' flag prevents modifying the input string\
                readingsBulkUpdate($hash, "ntfy_".makeReadingName($k), $sanitizedValue);;\
            }\
        }\
        #readingsBulkUpdate($hash, "websocketData", "$buf") if ($buf ne "");;\
        Log3($name, 3, "$name: Rx: >>>$buf<<<") if ($buf ne "");;\
        \
        readingsEndUpdate($hash, 1);;\
    };;\
    \
    DevIo_OpenDev($hash,\
        0,      ## reopen flag\
        undef,  ## initFn, on success\
        sub() { ## callbackFn, on verdict, req. to make it a non-blocking call\
            my ($hash, $error) = @_;;\
            if ($error) {\
                Log(3, "$name: DevIo_OpenDev Callback: connection failed: $error");;\
                \
                my $timerFunction = sub() {\
                    my ($arg) = @_;;\
                    my $hash = $defs{$name};;\
                    my $devState = DevIo_IsOpen($hash);;\
                    readingsSingleUpdate($hash, "cmd", "connect", 1) if (!defined($devState));;\
                };;\
                \
                RemoveInternalTimer($name.'Timer');;\
                my $rwait = int(rand(20)) + 10;;\
                InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.'Timer');;\
                readingsSingleUpdate($hash, "cmd", "reconnect attempt in $rwait seconds", 1);;\
            }\
        }\
    );;\
    \
    readingsBulkUpdate($hash, "state", "connecting...");;\
    return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
disconnect:cmd:.(disconnect|reconnect) {\
    my $hash = $defs{$name};;\
    my $myCmd = ReadingsVal($name, "cmd", "???");;\
    \
    RemoveInternalTimer($name.'Timer');;\
    RemoveInternalTimer($name.'Timeout');;\
    DevIo_CloseDev($hash);;\
    readingsBulkUpdate($hash, "state", "disconnected") if (!defined(DevIo_IsOpen($hash)));;\
    \
    if ($myCmd =~ /reconnect/) {\
        my $timerFunction = sub() {\
            my $hash = $defs{$name};;\
            readingsSingleUpdate($hash, "cmd", "connect", 1);;\
        };;\
    \
        RemoveInternalTimer("${name}_${reading}_timer");;\
        InternalTimer(gettimeofday()+1, $timerFunction, "${name}_${reading}_timer");;\
    } else {\
        RemoveInternalTimer("${name}_watchdog_timer");;\
    }\
    \
    return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
onDisconnect { ## check on each update if the connection is unintentionally broken...\
    my $myState = ReadingsVal($name, "state", "???");;\
    my $myData = ReadingsVal($name, "websocketData", "???");;\
    my $myCmd = ReadingsVal($name, "cmd", "disconnect");;\
    return if ($myState ne "disconnected" and $myData ne "not_connected");;\
    return if ($myCmd =~ /disconnect|stop/);;\
    \
    my $timerFunction = sub() {\
        my ($arg) = @_;;\
        my $hash = $defs{$name};;\
        my $devState = DevIo_IsOpen($hash);;\
        readingsSingleUpdate($hash, "cmd", "connect", 1) if (!defined($devState));;\
    };;\
    \
    RemoveInternalTimer($name.'Timer');;\
    my $rwait = int(rand(20)) + 10;;\
    InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.'Timer');;\
    readingsBulkUpdate($hash, "cmd", "reconnect attempt in $rwait seconds");;\
    \
    return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
watchdog:last_seen:.* {\
    my $ls = ReadingsVal($name, "last_seen", 0);;\
        \
    my $timerFunction = sub() {\
        ##fhem("set FHEMMeldung.ntfy message $name $reading wurde ausgelöst (last_seen: $ls)");;\
        readingsSingleUpdate($hash, "cmd", "reconnect", 1);;\
        readingsSingleUpdate($hash, "last_seen", 0, 1);;\
    };;\
    \
    RemoveInternalTimer("${name}_${reading}_timer");;\
    InternalTimer(gettimeofday()+240, $timerFunction, "${name}_${reading}_timer");;\
    \
    return POSIX::strftime("%H:%M:%S", localtime(time()));;\
}
attr NTFY_RECEIVE username Torxgewinde
attr NTFY_RECEIVE verbose 1
attr NTFY_RECEIVE webCmd start:stop

isy

Moin zusammen,
kann man mit dem Snippet (oder dem Modul?) auch Bilder versenden?
Ähnlich wie mit dem Telegram Modul?

VG Helmut
Ein Weg wird erst zu einem Weg, wenn man ihn geht

Torxgewinde

Stand bis jetzt erstmal nicht (Weder in meinem Snippet, noch in ByteRazors: https://rm.byterazor.de/issues/27)

Es gibt zwei Methoden die NTFY für Bilder annehmen kann:

In welchem Format läge dein Bild denn vor?
  • Hast du Bilddaten und keine öffentlich erreichbare URL für die Empfänger, dann wäre die HTTP-PUT Methode sinnvoller.
  • Wäre es von einer externen URL aus erreichbar? Dann wäre die Methode mit der URL in dem Header sinnvoll.

isy

Es handelt sich um jpg Files vom PI eigenen Directory /opt/fhem usw. Also per put wäre die Option.

Ich habe mir aber gedacht, dass die Funktion zumindest aktuell nicht geht und sende das Bild per debianmail. Dauert halt bei iOS Endgeräten immer recht lange, da Push-Mail nicht funktioniert.
Ein Weg wird erst zu einem Weg, wenn man ihn geht

Torxgewinde

Ok, ich behalt es mal im Kopf. Sollte sich eigentlich auch mit FHEM machen lassen, spricht ja nix dagegen, außer dass ich Zeit finde.

Ich hatte was ähnliches mit NTFY gemacht um mir die Bilder meiner Carport-Kamera in NTFY zu senden. Da sendet die Kamera die E-Mails und die poppen in NTFY dann ziemlich direkt auf: https://forum.fhem.de/index.php?topic=139868.msg1325988
Da du per Mail versendest ist das vielleicht bereits jetzt OK genug, auch wenn es ein weniger hin- und hergeht mit den Daten.

isy

Spannend deine Lösung im verlinkten Thread.
Für mich wäre das etwas zu aufwändig.

Gerade noch gefunden:
https://ntfy.geraffel.org/docs/publish/#__tabbed_24_1
Ein Weg wird erst zu einem Weg, wenn man ihn geht

Torxgewinde

Probier es mal aus:

defmod NTFY HTTPMOD none 0
attr NTFY userattr Filename Markdown NtfyServer Priority Title Topic password username
attr NTFY Filename test.png
attr NTFY Markdown true
attr NTFY NtfyServer ntfy.sh
attr NTFY Priority high
attr NTFY Title Titel aus UserAttr heraus
attr NTFY Topic FreundlichenGruesseAnAlleFHEMNutzer
attr NTFY comment # for HTTP Basic authentication use this as "setUrl":\
# https://[$name:username]:[$name:password]@[$name:NtfyServer]/%%path%%
attr NTFY replacement01Mode text
attr NTFY replacement01Regex %%path%%
attr NTFY replacement02Mode expression
attr NTFY replacement02Regex \[([^:]+):([^\]]+)\]
attr NTFY replacement02Value my $device = $name if ($1 eq "\$name") // $1;;\
ReadingsVal($device, $2, undef) or AttrVal($device, $2, "???");;
attr NTFY replacement03Mode expression
attr NTFY replacement03Regex %%title%%
attr NTFY replacement04Mode expression
attr NTFY replacement04Regex %%message%%
attr NTFY replacement05Mode expression
attr NTFY replacement05Regex %%file%%
attr NTFY room Global
attr NTFY set1Data %%message%%
attr NTFY set1HeaderIcon Icon: https://fhem.de/www/images/default/fhemicon.png
attr NTFY set1HeaderMarkdown Markdown: [$name:Markdown]
attr NTFY set1HeaderPrio Priority: [$name:Priority]
attr NTFY set1HeaderTitle Title: %%title%%
attr NTFY set1Method POST
attr NTFY set1Name message
attr NTFY set1Replacement01Value [$name:Topic]
attr NTFY set1Replacement03Value # get the value as passed to the set command:\
my $value = InternalVal($name, "value", "???");;\
\
# find first occurence of pattern Title=".*" and use that as result:\
my ($result) = $value =~ /Title="(.*?)"/;;\
\
# assign value from userAttr if $result is emtpy:\
$result //= AttrVal($name, "Title", "???");;\
\
return $result;;
attr NTFY set1Replacement04Value # get the value as passed to the set command:\
my $value = InternalVal($name, "value", "???");;\
\
# remove everything matching pattern Title=".*"\
$value =~ s/Title=".*?"//;;\
\
#replace the literal character sequence\
# \n with a real linefeed\
$value =~ s/\\n/\n/g;;\
\
return $value;;
attr NTFY set1TextArg 1
attr NTFY set2Data %%file%%
attr NTFY set2HeaderFilename Filename: [$name:Filename]
attr NTFY set2HeaderPrio Priority: [$name:Priority]
attr NTFY set2HeaderTitle Title: [$name:Title]
attr NTFY set2Method PUT
attr NTFY set2Name attach
attr NTFY set2Replacement01Value [$name:Topic]
attr NTFY set2Replacement05Value my $value = InternalVal($name, "value", "???");;\
\
open(my $fh, '<', $value) or return "ERROR: Cannot open file";;\
binmode($fh);; \
my $result = do { local $/;; <$fh> };; \
close($fh);; \
\
return $result;;
attr NTFY set2TextArg 1
attr NTFY setURL https://[$name:NtfyServer]/%%path%%
attr NTFY widgetOverride Priority:select,max,high,default,low,min Markdown:select,true,false

Senden einer Datei geht wie in diesem Beispiel:
set NTFY attach /opt/fhem/www/images/default/fhemicon.png

Wie die Datei beim Empfänger heißen soll, bestimmt der Parameter "Filename". Dies kann man als Reading oder Attribut setzen, das Reading hat Vorrang:
  • setreading NTFY Filename meinDateiName.jpg
  • attr NTFY Filename meinDateiName.jpg

Eine Demo ist kurzzeitig auf: https://demo-fhem.cooltux.net/fhem?detail=NTFY

So sieht es dann aus:
Du darfst diesen Dateianhang nicht ansehen.

Edit #1: Habe die Formatierung verbessert und ein weniger deutlicher beschrieben wie man den Dateinamen setzt.

isy

Hallo Torxgewinde,
das funktioniert. Toll!
Getestet habe ich mit einem jpg Bild und einem mp4 Video.


Vielen, vielen Dank!
Sehr schön, auch den Dateinamen, den ich als Ursprung verstehe, per attr variabel setzen zu können.

Ich hatte mir vor ein paar Tagen Blink Kameras zugelegt und habe bislang Videos und Bilder per Mail versandt.
Das kann ich nun zumindest für die Bilder umbauen, denn bei den Videos habe ich wegen der Dateigröße etwas Bedenken wegen der Nutzung des Gratis-Servers. Wenn die Bilder schnell ankommen, können die Videos ja warten oder wir rufen die Mail selbst ab. Das klappt dann schon mit dem nötigen WAF.

Beste Grüße,
Helmut
Ein Weg wird erst zu einem Weg, wenn man ihn geht

isy

Ich habe noch ein paar Zeilen im Log gefunden, evtl. fehlt mir noch eine Eingabe?

2025.02.14 13:45:40 3: NTFY: URL is none, periodic updates will be limited to explicit GetXXPoll attribues (if defined)
2025.02.14 13:45:40 3: NTFY: interval is 0, no periodic updates will done.
2025.02.14 13:45:40 3: NTFY: Defined without URL featurelevel 6.3
Ein Weg wird erst zu einem Weg, wenn man ihn geht

isy

Die Meldungen kamen 2* und aktuell nicht mehr.
Getestet mit Text, Bild und Video Anhang.
Ein Weg wird erst zu einem Weg, wenn man ihn geht

Torxgewinde

Zitat von: isy am 14 Februar 2025, 14:13:06Ich habe noch ein paar Zeilen im Log gefunden, evtl. fehlt mir noch eine Eingabe?

2025.02.14 13:45:40 3: NTFY: URL is none, periodic updates will be limited to explicit GetXXPoll attribues (if defined)
2025.02.14 13:45:40 3: NTFY: interval is 0, no periodic updates will done.
2025.02.14 13:45:40 3: NTFY: Defined without URL featurelevel 6.3

Das ist OK und kann ignoriert werden. HTTPMOD kann ja auch Webseiten abrufen und auswerten, das macht der Snippet aber nicht. Es gibt keine URL zum Abrufen --> "URL is none" und es soll auch nicht zyklisch probiert werden "interval is 0".

Torxgewinde


isy

Ein Weg wird erst zu einem Weg, wenn man ihn geht

isy

Ich habe soeben bemerkt, dass die iOS App (auf einem iPhone mit 18.3.1) und die iPadOS App (auf einem M2 MAC mit MacOS 15.3.1) beide kein Bild anzeigen.
Soll ich mal den Entwickler anschreiben?
Ein Weg wird erst zu einem Weg, wenn man ihn geht

isy

Laut git hat die iOS Version keine Möglichkeit, Anhänge zu empfangen.
Info vom Dez. 2024.
Siehe https://github.com/binwiederhier/ntfy/issues/1226

Nachtrag: Ich habe dort mal nachgefragt. Ein Grund sei, dass "PWA" auf iOS keine Attachments erlaubt.
Siehe auch:
https://www.heise.de/news/Apple-bestaetigt-Keine-Progressive-Web-Apps-mehr-fuer-iOS-in-der-EU-9630089.html
Ein Weg wird erst zu einem Weg, wenn man ihn geht

Torxgewinde

Uuuh, das ist ja hart. Ich nutze selbst nur noch Android/GrapheneOS und habe das Problem in iOS nicht mitbekommen.

Am produktivsten und zukunftsgerichtet ist sicherlich dem Entwickler ein Ticket da zu lassen, oder sich dem vorhandenem Ticket anzuschließen. Ich glaube dies hier bezieht sich dann genau auf die richtig iOS-App: https://github.com/binwiederhier/ntfy-ios/pull/8

Unter iOS habe ich früher sehr gerne PushOver genutzt, das war ausgereift, aber eben nicht selbstgehostet. Vielleicht ist das für iOS-Empfänger dann die bessere Wahl. In FHEM kann man beide Dienste (NTFY, PushOver ...) gleichzeitig nutzen und die jeweiligen Nachrichten über die verschiedenen Kanäle raussenden.

isy

Ein Weg wird erst zu einem Weg, wenn man ihn geht

isy

Soll ich das Wiki Update schreiben?
Ein Weg wird erst zu einem Weg, wenn man ihn geht

isy

Die Web App auf MacOS und iOS zeigt die Attachments an.
Beide OS erlauben die Anzeige auf dem Home Bildschirm (sieht aus, wie eine App).
Benachrichtigungen funktionieren

OK, geht also
Ein Weg wird erst zu einem Weg, wenn man ihn geht

Torxgewinde

Zitat von: isy am 15 Februar 2025, 13:47:19Soll ich das Wiki Update?
Sehr gerne, am besten auch mit dem Hinweis, dass/wie die WebApp installiert/gebookmarked werden sollte.

isy

Update ist eingetragen, ich hoffe die Info passt an die Stelle.
Ein Weg wird erst zu einem Weg, wenn man ihn geht

Torxgewinde

Passt, ich habe deinen Link zum GitHub Issue auch noch mit aufgenommen. Danke!