gelöst: JSON zu MQTT Device senden aus Fhem

Begonnen von matze1999, 01 April 2023, 15:24:37

Vorheriges Thema - Nächstes Thema

matze1999

#30
Hallo, ich wollte das nicht vorenthalten: ich habe jetzt für die Ulanzi Clock awtrix-light ausprobiert und finde das besser und auch leichter in fhem einzubinden, u.a. wird hier der Batterieladezustand als Reading zur Verfügung gestellt.

Es gibt mit awtrix auf dem Device voreingestellte apps, wie z.B. Uhr und Datum, die immer abwechselnd angezeigt werden, einzelne apps kann man abschalten und custom apps hinzufügen. diese werden dann immer in der eingestellten Reihenfolge auf dem Display angezeigt.

Das Device:

defmod MQTT2_awtrix_d66fe0 MQTT2_DEVICE awtrix_d66fe0
attr MQTT2_awtrix_d66fe0 readingList awtrix_d66fe0:awtrix_d66fe0/stats:.* { json2nameValue($EVENT) }\
awtrix_d66fe0:awtrix_d66fe0/stats/buttonSelect:.* buttonSelect\
awtrix_d66fe0:awtrix_d66fe0/stats/buttonRight:.* buttonRight\
awtrix_d66fe0:awtrix_d66fe0/stats/buttonLeft:.* buttonLeft
attr MQTT2_awtrix_d66fe0 room MQTT2_DEVICE
attr MQTT2_awtrix_d66fe0 setList on:noArg {awtrixon}\
off:noArg {awtrixoff}\
update:noArg {awtrixupdate}\
Text {awtrixtext ("$EVTPART1")}\
letzterAnruf:noArg {awtrixnummer}
attr MQTT2_awtrix_d66fe0 stateFormat bat %

Dazu die sub's aus der 99_myUtils:

Aufruf einer custom App zur Anzeige der Temperatur, der Text und das icon farblich der Temperatur angepasst. 

sub awtrixupdate {
my $temp = ReadingsVal("MQTT2_DVES_6CA8FD","Global_Temperature",0)."°C";
# kalt = blau
if (ReadingsVal("MQTT2_DVES_6CA8FD","Global_Temperature",0) < 10)
{fhem( qq(set myBroker publish awtrix_d66fe0/custom/1 {"text":"$temp","icon":"10977","color":"#8585FF"}))}
# warm = gelb
elsif ((ReadingsVal("MQTT2_DVES_6CA8FD","Global_Temperature",0) >= 10) && (ReadingsVal("MQTT2_DVES_6CA8FD","Global_Temperature",0) <= 20))
{fhem( qq(set myBroker publish awtrix_d66fe0/custom/1 {"text":"$temp","icon":"12144","color":"#FFFF00"}))}
# heiss = rot
elsif (ReadingsVal("MQTT2_DVES_6CA8FD","Global_Temperature",0) > 20)
{fhem( qq(set myBroker publish awtrix_d66fe0/custom/1 {"text":"$temp","icon":"12144","color":"#FF0000"}))}
}


[s]sub awtrixon {
{fhem( qq(set awtrixState on))};
{fhem( qq(set myBroker publish awtrix_d66fe0/apps [
    {
      "name":"date",
      "show":true,
      "pos":0
     },
{
      "name":"time",
      "show":true,
      "pos":1
     },
{
      "name":"1",
      "show":true,
      "pos":3
     }
]
))};
{awtrixupdate}

}



sub awtrixoff {
{fhem( qq(set awtrixState off))};
{fhem( qq(set myBroker publish awtrix_d66fe0/apps [
    {
      "name":"date",
      "show":false
     },
{
      "name":"time",
      "show":false
     },
{
      "name":"1",
      "show":false
     }
]
))}
}[/s]

sub awtrixtext {
    my $text = shift // q{Kein Text!!!};
    my $farbe = shift // 'FF0000';
    my $durchlauf = shift // 10;

    fhem( qq(set myBroker publish awtrix_d66fe0/notify {"text":"$text", "color": "#$farbe","duration":$durchlauf}))
}

sub awtrixnummer {
    my $nummer = ReadingsVal("Fritzbox_Callmonitor","external_name","unknown")."-".ReadingsVal("Fritzbox_Callmonitor","external_number","unknown");
    fhem( qq(set myBroker publish awtrix_d66fe0/notify {"text":"$nummer", "color": "#FF0000","duration":30}))
}

on und off muss man selbst definieren, je nachdem, welche apps man nutzt, da werden nur die genutzten apps auf der clock ein- bzw. ausgeschaltet, also nichts angezeigt, sonst bleibt das Gerät aber an. awtrixtext dient zum Anzeigen eines beliebigen Textes per notify.

awtrixnummer habe ich angelegt, weil ich das per DOIF nicht hinbekomme  ::)

und hier noch die Button notifys dazu:

Button zum an- und ausschalten, über ein dummyDevice, was den State speichert.
defmod MQTT2_awtrix_d66fe0_DOIF_1 DOIF ([MQTT2_awtrix_d66fe0:"^buttonSelect:.1$"] and [?awtrixState] eq "on") (\
set MQTT2_awtrix_d66fe0 off\
)\
DOELSEIF (\
[MQTT2_awtrix_d66fe0:"^buttonSelect:.1$"] and [?awtrixState] eq "off") (\
set MQTT2_awtrix_d66fe0 on\
)

Beispielhaft die Belegung der Vor- und Zurück-Taste:

defmod MQTT2_awtrix_d66fe0_DOIF_2 DOIF ([MQTT2_awtrix_d66fe0:"^buttonRight:.1$"]) (\
set myBroker publish awtrix_d66fe0/nextapp\
)\
DOELSEIF\
([MQTT2_awtrix_d66fe0:"^buttonLeft:.1$"]) (\
set myBroker publish awtrix_d66fe0/previousapp\
)\

Und noch eine Anwendung, zum triggern der Wertänderung der Temperatur in der Anzeige, hier muss der state des Dummy Devices ausgewertet werden, weil sonst im "off-Modus" die Temperatur trotzdem angezeigt wird:

defmod MQTT2_awtrix_d66fe0_DOIF_3 DOIF ([MQTT2_DVES_6CA8FD:"^BME280_Temperature:.*$"] and [awtrixState] eq "on") (\
set MQTT2_awtrix_d66fe0 update)

Das geht alles evtl. auch eleganter oder mit anderen Mitteln, so läuft es aber für mich erst mal gut.

matze1999

matze1999

#31
Nachtrag: mi t der Version 0.49 awtrix ist jetzt on/off des Displays per MQTT möglich, damit entfällt die o.g. Konstruktion für on/off (awtrixon/awtrixoff)

matze1999

Smart_Homer

Super Danke für die Info, werd mir mal welche bestellen, wenn es mit FHEM jetzt geht....

Smart_Homer

#33
Hallo,

ich lass mir jetzt einige CustomApps minütlich aktualisieren:

z.B.
#   Aussentemperatur   _______________________________________________________________________________________________________________________________________
my $CA_Temp_outside = sprintf('%.0f', ReadingsVal("IP.Wetterstation","ACTUAL_TEMPERATURE", ""));;
if ($CA_Temp_outside < 5) {
fhem(qq(set MQTT2_FHEM_SERVER publish Ulanzi_BUERO/custom/CA__Temp_outside {"text":"$CA_Temp_outside °C", "color": [0,0,255],"duration":5,"icon":2422}));;
};;
if ($CA_Temp_outside >= 5 && $CA_Temp_outside < 15) {
fhem(qq(set MQTT2_FHEM_SERVER publish Ulanzi_BUERO/custom/CA__Temp_outside {"text":"$CA_Temp_outside °C", "color": [255,255,255],"duration":5,"icon":2422}));;
};;
if ($CA_Temp_outside >= 15 && $CA_Temp_outside < 23) {
fhem(qq(set MQTT2_FHEM_SERVER publish Ulanzi_BUERO/custom/CA__Temp_outside {"text":"$CA_Temp_outside °C", "color": [0,255,0],"duration":5,"icon":2422}));;
};;
if ($CA_Temp_outside >= 23) {
fhem(qq(set MQTT2_FHEM_SERVER publish Ulanzi_BUERO/custom/CA__Temp_outside {"text":"$CA_Temp_outside °C", "color": [255,0,0],"duration":5,"icon":2422}));;
};;

Allerdings habe ich 3 von den Ulanzi Pixel Clocks mit Awtrix.
Deswegen würde ich gern den gleichen Satz an Befehlen immer an alle 3 Geräte senden.
Was ist den die eleganteste Art das zu lösen?
Mit einem Loop/ForEach/schleifenbefehöl würde ich spontan sagen und dann den Gerätenamen über eine Variable austauschen.
Allerdings habe ich keine Loop Befehlmöglichkeit in FHEM gefunden.

Jeder Tip ist willkommen.

Gruß und Dank..

Beta-User

Das sieht aber umständlich aus...

Eher erst mal alles Variable ermitteln, und dann halt die publishes am Ende passend zusammenbasteln?
Der Spur nach so:

my $CA_Temp_outside = sprintf('%.0f', ReadingsNum('IP.Wetterstation','ACTUAL_TEMPERATURE', 0.000));;
my $col = $CA_Temp_outside >= 23 ? '[255,0,0]' :
          $CA_Temp_outside >= 15 ? '[0,255,0]' :
          $CA_Temp_outside >=  5 ? '[255,255,255]' :
                                   '[0,0,255]';;
my $payl = qq({"text":"$CA_Temp_outside °C", "color": $col,"duration":5,"icon":2422});;

fhem(qq(set MQTT2_FHEM_SERVER publish Ulanzi_BUERO/custom/CA__Temp_outside $payl;set MQTT2_FHEM_SERVER publish Ulanzi_WERKSTATT/custom/CA__Temp_outside $payl));;
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

Smart_Homer

Zitat von: Beta-User am 06 Mai 2023, 16:23:00Das sieht aber umständlich aus...

Eher erst mal alles Variable ermitteln, und dann halt die publishes am Ende passend zusammenbasteln?
Der Spur nach so:

my $CA_Temp_outside = sprintf('%.0f', ReadingsNum('IP.Wetterstation','ACTUAL_TEMPERATURE', 0.000));;
my $col = $CA_Temp_outside >= 23 ? '[255,0,0]' :
          $CA_Temp_outside >= 15 ? '[0,255,0]' :
          $CA_Temp_outside >=  5 ? '[255,255,255]' :
                                   '[0,0,255]';;
my $payl = qq({"text":"$CA_Temp_outside °C", "color": $col,"duration":5,"icon":2422});;

fhem(qq(set MQTT2_FHEM_SERVER publish Ulanzi_BUERO/custom/CA__Temp_outside $payl;set MQTT2_FHEM_SERVER publish Ulanzi_WERKSTATT/custom/CA__Temp_outside $payl));;


Super, Danke, das ist schon mal stark entschlackt und vereinfacht das 3malige versenden.

Smart_Homer

Jetzt bräuchte ich aber doch nochmal eine Loop Option, was nimmt man am besten für einen 3er Loop?

Danke.

Beta-User

Zitat von: Smart_Homer am 12 Mai 2023, 15:30:06Jetzt bräuchte ich aber doch nochmal eine Loop Option, was nimmt man am besten für einen 3er Loop?
... for (...) {

Aber die Frage ist nicht exakt genug, um eine brauchbarere Antwort zu geben.

Im Zweifel ist der Aufwand für eine Schleife hier höher wie die "zu Fuß"-Lösung...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

Smart_Homer

Ich habs mal soweit vorbereitet:

#  Fenster offen  _______________________________________________________________________________________________________________________________________
my $FT_NAME  = "xxx";;
my $FT_ALIAS = "xxx";;
my $FT_STATE = "xxx";;

my $PART_ICON_OFFEN = 2364;;  # Fehler
my $PART_PAYLOAD_OFFEN = qq({"text":"FEHLER" , "color": [255,0,0] , "duration":4 , "icon":"$PART_ICON_OFFEN"});;

my $PART_PAYLOAD_GESCHLOSSEN = qq({});;

my $FT_Custom = "";;



# $FT_NAME = "HM.FENSTERKONTAKT_1";;
# $FT_NAME = "IP.TUERKONTAKT_2";;
# $FT_NAME = "HM.TUERKONTAKT_3";;

# Block pro Fenster__________________________________________________________
 $FT_NAME = "HM.FENSTERKONTAKT_4";;
$FT_STATE = ReadingsVal($FT_NAME,"state", "");;
$FT_ALIAS = AttrVal($FT_NAME,"alias",$FT_NAME);;

    $FT_Custom = qq(Ulanzi_WZ/custom/CA__FT__$FT_ALIAS);;

if ($FT_STATE eq "open") {

 $PART_ICON_OFFEN = 34970;;
 $PART_PAYLOAD_OFFEN = qq({"text":"$FT_ALIAS ist OFFEN" , "color": [255,0,0] , "duration":4 , "icon":"$PART_ICON_OFFEN"});;

fhem(qq( set MQTT2_FHEM_SERVER publish $FT_Custom $PART_PAYLOAD_OFFEN ));;
}


elsif ($FT_STATE eq "closed") {

 $PART_PAYLOAD_GESCHLOSSEN = qq({});;

fhem(qq( set MQTT2_FHEM_SERVER publish $FT_Custom $PART_PAYLOAD_GESCHLOSSEN ));;
}

Das würde ich gern in eine Schleife packen, in der sich nur immer $FT_NAME ändert, der Rest wird dynamisch zugewiesen.
Kann ich da einfach eine While Schleife drumpacken:

while($i <= 4)
{

if ($i = 1)  {
 $FT_NAME = "HM.FENSTERKONTAKT_1";;
}
if ($i = 2)  {
 $FT_NAME = "HM.TUERKONTAKT_2";;
}
if ($i = 3)  {
 $FT_NAME = "IP.TUERKONTAKT_3";;
}
if ($i = 4)  {
 $FT_NAME = "HM.TUERKONTAKT_4";;
}

Danke.....

Beta-User

Zitat von: Smart_Homer am 14 Mai 2023, 23:44:08Ich habs mal soweit vorbereitet:

#  Fenster offen  _______________________________________________________________________________________________________________________________________
my $FT_NAME  = "xxx";;
my $FT_ALIAS = "xxx";;
my $FT_STATE = "xxx";;

my $PART_ICON_OFFEN = 2364;;  # Fehler
my $PART_PAYLOAD_OFFEN = qq({"text":"FEHLER" , "color": [255,0,0] , "duration":4 , "icon":"$PART_ICON_OFFEN"});;

my $PART_PAYLOAD_GESCHLOSSEN = qq({});;

my $FT_Custom = "";;



# $FT_NAME = "HM.FENSTERKONTAKT_1";;
# $FT_NAME = "IP.TUERKONTAKT_2";;
# $FT_NAME = "HM.TUERKONTAKT_3";;

# Block pro Fenster__________________________________________________________
 $FT_NAME = "HM.FENSTERKONTAKT_4";;
$FT_STATE = ReadingsVal($FT_NAME,"state", "");;
$FT_ALIAS = AttrVal($FT_NAME,"alias",$FT_NAME);;

    $FT_Custom = qq(Ulanzi_WZ/custom/CA__FT__$FT_ALIAS);;

if ($FT_STATE eq "open") {

 $PART_ICON_OFFEN = 34970;;
 $PART_PAYLOAD_OFFEN = qq({"text":"$FT_ALIAS ist OFFEN" , "color": [255,0,0] , "duration":4 , "icon":"$PART_ICON_OFFEN"});;

fhem(qq( set MQTT2_FHEM_SERVER publish $FT_Custom $PART_PAYLOAD_OFFEN ));;
}


elsif ($FT_STATE eq "closed") {

 $PART_PAYLOAD_GESCHLOSSEN = qq({});;

fhem(qq( set MQTT2_FHEM_SERVER publish $FT_Custom $PART_PAYLOAD_GESCHLOSSEN ));;
}

Das würde ich gern in eine Schleife packen, in der sich nur immer $FT_NAME ändert, der Rest wird dynamisch zugewiesen.
Kann ich da einfach eine While Schleife drumpacken:

while($i <= 4)
{

if ($i = 1)  {
 $FT_NAME = "HM.FENSTERKONTAKT_1";;
}
if ($i = 2)  {
 $FT_NAME = "HM.TUERKONTAKT_2";;
}
if ($i = 3)  {
 $FT_NAME = "IP.TUERKONTAKT_3";;
}
if ($i = 4)  {
 $FT_NAME = "HM.TUERKONTAKT_4";;
}

Danke.....


Puh, eigentlich ist das Grundlagenwissen, und in Automatisierung/Perl für FHEM-User gibt's auch etwas mehr zum Thema Schleifen. Vielleicht schaust du dir das bei Gelegenheit an.

Da du dir aber immerhin die Mühe gemacht hast, das halbwegs sauber vorzubereiten, ein paar Hinweise:

Zur eigentlichen direkten Frage: Ja, man kann man das natürlich mit einer "while"-Schleife lösen, muss dann aber zum einen den Zähler vorher initialisieren und den dann zum anderen auch innerhalb der Schleife erhöhen. Ist also umständlich...

Einfacher: Ein Array mit den Schlüsselworten definieren und dann darüber loopen. Hier ein entsprechendes Schnippselchen aus WeekdayTimer:
my @tempSet = qw(desired-temp desiredTemperature desired thermostatSetpointSet);
my $allSets = getAllSets($dName);
for my $ts (@tempSet) {
  if ($allSets =~ m{$ts}xms) {
     Log3( $hash, 4, "[$name] device type heating recognized, setModifier:$ts" );

Man kann das zusammenfassen:
for my $sensor ( qw(HM.FENSTERKONTAKT_1 HM.TUERKONTAKT_2 IP.TUERKONTAKT_3 HM.TUERKONTAKT_4) ) {
 <Schleife>
}

oder noch kürzer:
for (qw (HM.FENSTERKONTAKT_1 HM.TUERKONTAKT_2 IP.TUERKONTAKT_3 HM.TUERKONTAKT_4) ) {
 <Schleife, einzelner Kontakt ist dann  als Umlaufvariable "$_" zu schreiben>
}

Ich würde dann empfehlen, erst zu ermitteln, ob der Kontakt offen oder zu ist, und dann anhand dieser Unterscheidung erst die Symbole und Texte definieren, das ist m.E. am Ende einfach lesbarer...
Dieses ganze "Vorab-Variablen-definieren" braucht man in der Regel bei Perl nicht, also verzichte ich meistens auch weitgehend darauf

Vielleicht versuchst du erst mal dein Glück mit diesen Hinweisen und zeigst dann wieder, wie weit du gekommen bist?
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

Smart_Homer

Super, läuft. Vielen Dank für die Hilfe. Der Array Tip war Super. Ich hab tatsächlich nicht wirklich viel zu Schleifen in FHEM gefunden.

Was hat es mit der Umgebungsvariablen $_ eigentlich auf sich? MIt der hat es nicht funktioniert.

foreach my $LOOP_Device (@DeviceSet) {

$FT_NAME = $LOOP_Device;;

# Variablenzuweisung in der Schleife
    $FT_STATE = ReadingsVal($FT_NAME,"state", "");;
    $FT_ALIAS = AttrVal($FT_NAME,"alias",$FT_NAME);;


Beta-User

Zitat von: Smart_Homer am 18 Mai 2023, 16:01:11Super, läuft. Vielen Dank für die Hilfe. Der Array Tip war Super. Ich hab tatsächlich nicht wirklich viel zu Schleifen in FHEM gefunden.

Was hat es mit der Umgebungsvariablen $_ eigentlich auf sich? MIt der hat es nicht funktioniert.

foreach my $LOOP_Device (@DeviceSet) {

    $FT_NAME = $LOOP_Device;;

# Variablenzuweisung in der Schleife
    $FT_STATE = ReadingsVal($FT_NAME,"state", "");;
    $FT_ALIAS = AttrVal($FT_NAME,"alias",$FT_NAME);;


Kann nicht nachvollziehen, warum
- das nicht geklappt haben soll (Fehlermeldung?!?)
- irgendwelche weiteren Variablennamen erforderlich sind (oder welchen Mehrwert hat "$FT_NAME = $LOOP_Device;;"?)
- es erforderlich sein soll, die Variablennamen "vorab" zu reservieren.
- wo das unnütze "each" herkommt...

Also kürzer:
for my $FT_NAME (@DeviceSet) {

# Variablenzuweisung in der Schleife
    $FT_STATE = ReadingsVal($FT_NAME,"state", "");;
    $FT_ALIAS = AttrVal($FT_NAME,"alias",$FT_NAME);;
(Achtung: $FT_NAME entspricht hier dann nicht dem, was "außen" definiert war!)

...oder noch kürzer (ohne vorherige "Leerdefinition" von $FT_STATE/$FT_STATE und unter Umgehung von unnötigen Interpolationen und mit einfachen ;, da das direkt aus der DEF zu kommen scheint, müßte es auch so gehen):
for (@DeviceSet) {

# Variablenzuweisung in der Schleife
  my $FT_STATE = ReadingsVal($_,'state', '');
  my $FT_ALIAS = AttrVal($_, 'alias', $_);
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors