[gelöst] Wie kann ich mehrere "MQTT publish" Befehle einem set Befehl zuordnen?

Begonnen von supernova1963, 24 März 2020, 18:34:05

Vorheriges Thema - Nächstes Thema

supernova1963

Zitat von: 87insane am 25 März 2020, 19:15:28
Die Lösung und warum du diesen Weg gewählt hast, darfst du gern mitteilen :)

Na dann mal los:

Ich baue gerade eine Dusche im KG (siehe Anhang Dusch.png).
Wie man vielleicht erkennen kann möchte ich rundherum LED Stripes einsetzen. Ich habe mich für
4 von LTRGBW Super Hell 5M 5050 SMD 24V 600LEDs Dual White 2800K-7000K LED Streifen Warmweiß Kaltweiß Farbtemperatur Bicolor-LED-Stripe Wasserdicht IP67 entschieden, u.A. da kein Fenster möglich ist, und, meine Regierung warmweiss im Normalfall bevorzugt, in einigen Ausnahmefällen es aber "klinisch" hell benötigt.
Es kommen 3 LED Stripes zum Einsatz (2 für die "Rundum-Beleuchtung" und 1 für die Dusche, die separat schaltbar sein soll).
Da ich eh eine Bestellung von Shellies zum Testen bei ALLTERCO ROBOTICS machen habe ich die Shelly RGBW2 mit bestellt.
Die werden in LED Aluminium Fliesenprofile eingelegt und werden von 2 240 W 24V Netzteilen versorgt.

Da ich noch auf die Fliesen (aus Italien) warten muss, mache ich mir derzeit Gedanken um die Steuerung. 

Wenn ich fertig bin sende ich gerne auf pm-Anfrage Bilder....

lg

Gernot

supernova1963

Was habe ich mir dabei gedacht?
set - Befehle Aufbau:

       
  • A|B = LED-Streifen 1 oder 2
  • WW|CW = Kanäle: WarmWhite oder ColdWhite
  • on|off = ein oder ausschalten
  • pct = Dimmwert in Prozent festlegen ohne einschalten
  • pct_on =Dimmwert in Prozent festlegen und und diesen Kanal mit diesem Dimmwert einschalten
Der Shelly RGBW2 hat im "white" mode 4 Kanäle. 2 Kanäle werden für den jeweiligen Streifen benötigt (siehe Anhang Schema_Anschluss).
Beispiele:

       
  • set <devicename> A_WW_on
    = Schaltet den 2. Kanal = WarmWhite des 1. LED Streifens (mit dem zuletzt festgelegten Dimmwert) ein
  • set <devicename> B_CW_pct <0..100>
    = Setzt den Wert des 1. Kanal (3. des RGBW2) = ColdWhite des 2. LED Streifens auf den angebegeben % - Wert
  • set <devicename> A_on
    = Schaltet den 1. LED Streifen ein (beide Kanäle mit den zuletzt eingegebenen Dimmwerten)
  • set <devicename> B_on
    = Schaltet den 2. LED Streifen ein (beide Kanäle mit den zuletzt eingegebenen Dimmwerten)
  • set <devicename> WW_pct <0..100>
    = Setzt den Dimmwert beider WarmWhite Kanäle der LED Streifen auf den angegebenen Wert
  • set <devicename> on
    = Schaltet beide LED Streifen (alle 4 Kanäle) mit dem zuletzt eingegebenen Dimmwert ein

Die Anzeige im fhemweb beschränkt sich auch das Ein-/Ausschalten beider LED Streifen und das setzen der % - Werte beider Streifen auf den ausgewählten Wert für WarmWhite und ColdWhite.
Der Rest ist "Spielerei" zu einheitlichen Anzeige (DevStateIcon: StatusText, Hinweis auf Firmware-Update mit Update Funktion, An/Aus Symbol, Online Status Symbol mit Verlinkung auf die Web Oberfläche und webCMD zur Steuerung der WW-/CW- Kanäle)

raw Definition:
defmod 26_WandStripes MQTT2_DEVICE shellyrgbw2_6EAB2B
attr 26_WandStripes IODev MQTT2
attr 26_WandStripes alias Stripes Wand
attr 26_WandStripes devStateIcon devStateIcon A_WW_on:hue_filled_lightstrip@orangered:A_WW_off \
A_WW_off:hue_filled_lightstrip@navajowhite:A_WW_on \
A_CW_on:hue_filled_lightstrip@midnightblue:A_CW_off \
A_CW_off:hue_filled_lightstrip@lightblue:A_CW_on \
A_on:on@OrangeRed:A_off \
A_off:off:A_off\
B_WW_on:hue_filled_lightstrip@orangered:B_WW_off \
B_WW_off:hue_filled_lightstrip@navajowhite:B_WW_on \
B_CW_on:hue_filled_lightstrip@midnightblue:B_CW_off \
B_CW_off:hue_filled_lightstrip@lightblue:B_CW_on \
B_on:on@OrangeRed:B_off \
B_off:off:B_off\
WW_on:hue_filled_lightstrip@orangered:A_WW_off \
WW_off:hue_filled_lightstrip@navajowhite:A_WW_on \
CW_on:hue_filled_lightstrip@midnightblue:A_CW_off \
CW_off:hue_filled_lightstrip@lightblue:A_CW_on \
on:on@OrangeRed:off \
off:off:off \
info:rc_INFO@Darkblue \
true:10px-kreis-gruen \
false:10px-kreis-rot \
veraltet:refresh@OrangeRed:Upgrade \
aktuell:rc_BLANK\

attr 26_WandStripes devStateStyle style="text-align:right"
attr 26_WandStripes icon light_led_stripe
attr 26_WandStripes jsonMap brightness:pct
attr 26_WandStripes readingList shellyrgbw2_6EAB2B:shellies/26_shellyrgbw2-6EAB2B_AB/white/0:.* A_CW\
shellyrgbw2_6EAB2B:shellies/26_shellyrgbw2-6EAB2B_AB/white/0/status:.* { json2nameValue($EVENT, 'A_CW_', $JSONMAP) }\
shellyrgbw2_6EAB2B:shellies/26_shellyrgbw2-6EAB2B_AB/white/1:.* A_WW\
shellyrgbw2_6EAB2B:shellies/26_shellyrgbw2-6EAB2B_AB/white/1/status:.* { json2nameValue($EVENT, 'A_WW_', $JSONMAP) }\
shellyrgbw2_6EAB2B:shellies/26_shellyrgbw2-6EAB2B_AB/white/2:.* B_CW\
shellyrgbw2_6EAB2B:shellies/26_shellyrgbw2-6EAB2B_AB/white/2/status:.* { json2nameValue($EVENT, 'B_CW_', $JSONMAP) }\
shellyrgbw2_6EAB2B:shellies/26_shellyrgbw2-6EAB2B_AB/white/3:.* B_WW\
shellyrgbw2_6EAB2B:shellies/26_shellyrgbw2-6EAB2B_AB/white/3/status:.* { json2nameValue($EVENT, 'B_WW_', $JSONMAP) }\
shellyrgbw2_6EAB2B:shellies/26_shellyrgbw2-6EAB2B_AB/online:.* online\
shellyrgbw2_6EAB2B:shellies/26_shellyrgbw2-6EAB2B_AB/announce:.* { json2nameValue($EVENT, '', $JSONMAP) } \
shellies/announce:.* { $EVENT =~ m,..id...26_shellyrgbw2-6EAB2B_AB...mac.*, ? json2nameValue($EVENT) : undef }\

attr 26_WandStripes room temp,99_MQTT2_DEVICE
attr 26_WandStripes setList A_CW_off:noArg shellies/26_shellyrgbw2-6EAB2B_AB/white/0/command off \
  A_CW_on:noArg shellies/26_shellyrgbw2-6EAB2B_AB/white/0/command on \
  A_CW_pct:colorpicker,BRI,0,1,100 shellies/26_shellyrgbw2-6EAB2B_AB/white/0/set {"mode":"white","brightness":"$EVTPART1"} \
  A_CW_pct_on:colorpicker,BRI,0,1,100 shellies/26_shellyrgbw2-6EAB2B_AB/white/0/set {"turn":"on","brightness":"$EVTPART1"} \
  A_WW_off:noArg shellies/26_shellyrgbw2-6EAB2B_AB/white/1/command off \
  A_WW_on:noArg shellies/26_shellyrgbw2-6EAB2B_AB/white/1/command on \
  A_WW_pct:colorpicker,CT,0,1,100 shellies/26_shellyrgbw2-6EAB2B_AB/white/1/set {"mode":"white","brightness":"$EVTPART1"} \
  A_WW_pct_on:colorpicker,CT,0,1,100 shellies/26_shellyrgbw2-6EAB2B_AB/white/1/set {"turn":"on","brightness":"$EVTPART1"} \
  B_CW_off:noArg shellies/26_shellyrgbw2-6EAB2B_AB/white/2/command off \
  B_CW_on:noArg shellies/26_shellyrgbw2-6EAB2B_AB/white/2/command on \
  B_CW_pct:colorpicker,BRI,0,1,100 shellies/26_shellyrgbw2-6EAB2B_AB/white/2/set {"mode":"white","brightness":"$EVTPART1"}  \
  B_CW_pct_on:colorpicker,BRI,0,1,100 shellies/26_shellyrgbw2-6EAB2B_AB/white/2/set {"turn":"on","brightness":"$EVTPART1"} \
  B_WW_off:noArg shellies/26_shellyrgbw2-6EAB2B_AB/white/3/command off \
  B_WW_on:noArg shellies/26_shellyrgbw2-6EAB2B_AB/white/3/command on \
  B_WW_pct:colorpicker,CT,0,1,100 shellies/26_shellyrgbw2-6EAB2B_AB/white/3/set {"mode":"white","brightness":"$EVTPART1"} \
  B_WW_pct_on:colorpicker,CT,0,1,100 shellies/26_shellyrgbw2-6EAB2B_AB/white/3/set {"turn":"on","brightness":"$EVTPART1"} \
  A_on:noArg {fhem "set $NAME A_CW_on;;set $NAME A_WW_on;;";;} \
  A_off:noArg {fhem "set $NAME A_CW_off;;set $NAME A_WW_off;;";;} \
  B_on:noArg {fhem "set $NAME B_CW_on;;set $NAME B_WW_on;;";;} \
  B_off:noArg {fhem "set $NAME B_CW_off;;set $NAME B_WW_off;;";;} \
  on:noArg {fhem "set $NAME A_CW_on;;set $NAME A_WW_on;;set $NAME B_CW_on;;set $NAME B_WW_on;;";;} \
  off:noArg {fhem "set $NAME A_CW_off;;set $NAME A_WW_off;;set $NAME B_CW_off;;set $NAME B_WW_off;;";;} \
  WW_pct:colorpicker,CT,0,1,100 {fhem "set $NAME A_WW_pct $EVTPART1;;set $NAME B_WW_pct $EVTPART1;;";;} \
  WW_pct_on:colorpicker,CT,0,1,100 {fhem "set $NAME A_WW_pct_on $EVTPART1;;set $NAME B_WW_pct_on $EVTPART1;;";;} \
  CW_pct:colorpicker,BRI,0,1,100 {fhem "set $NAME A_CW_pct $EVTPART1;;set $NAME B_CW_pct $EVTPART1;;";;} \
  CW_pct_on:colorpicker,BRI,0,1,100 {fhem "set $NAME A_CW_pct_on $EVTPART1;;set $NAME B_CW_pct_on $EVTPART1;;";;} \
  x_mqttcom shellies/26_shellyrgbw2-6EAB2B_AB/command $EVTPART1 \
  x_httpcom { X_PerformShellyHttpRequest($NAME,ReadingsVal($NAME,"ip","").",".$EVTPART1.",".ReadPassword($defs{$NAME})) } \
  x_httpcom_login {StorePassword($defs{$NAME},$EVTPART1) } \
  x_update:noArg shellies/26_shellyrgbw2-6EAB2B_AB/command update_fw \
  reboot:noArg { X_PerformShellyHttpRequest($NAME,ReadingsVal($NAME,"ip","").",".$EVENT.",".ReadPassword($defs{$NAME})) }\
  status:noArg { X_PerformShellyHttpRequest($NAME,ReadingsVal($NAME,"ip","").",".$EVENT.",".ReadPassword($defs{$NAME})) }\
  settings:noArg { X_PerformShellyHttpRequest($NAME,ReadingsVal($NAME,"ip","").",".$EVENT.",".ReadPassword($defs{$NAME})) }\
  shelly:noArg { X_PerformShellyHttpRequest($NAME,ReadingsVal($NAME,"ip","").",".$EVENT.",".ReadPassword($defs{$NAME})) }\

attr 26_WandStripes stateFormat StatusText\
SystemState\
state\
connection
attr 26_WandStripes userReadings consumption\
{ \
return (ReadingsNum($NAME,"A_WW_power",0) + ReadingsNum($NAME,"A_CW_power",0) + ReadingsNum($NAME,"B_WW_power",0) + ReadingsNum($NAME,"B_CW_power",0)) \
},\
state\
{\
if (ReadingsVal($NAME,"A_CW","off") eq "off") {\
if (ReadingsVal($NAME,"A_WW","off") eq "off") {\
if (ReadingsVal($NAME,"B_CW","off") eq "off") {\
if (ReadingsVal($NAME,"B_WW","off") eq "off") {\
return "off";;\
}\
}\
}\
}\
return "on";; \
},\
WW_pct\
{\
if (ReadingsVal($NAME,"A_WW_pct","A") eq ReadingsVal($NAME,"B_WW_pct","B")) {\
return ReadingsVal($NAME,"A_WW_pct","A");;\
}\
return "0";;\
},\
CW_pct\
{\
if (ReadingsVal($NAME,"A_CW_pct","A") eq ReadingsVal($NAME,"B_CW_pct","B")) {\
return ReadingsVal($NAME,"A_CW_pct","0");;\
}\
return "0";;\
},\
StatusText \
{\
my $result = "";;\
if (uc(ReadingsVal($NAME,"state","")) eq "OFF") {\
$result = 'ist aus';;\
}\
else {\
$result = ' ist an (ACW='.ReadingsVal($NAME,"A_CW","").'/AWW='.ReadingsVal($NAME,"A_WW","").'/BCW='.ReadingsVal($NAME,"B_CW","").'/BWW='.ReadingsVal($NAME,"B_WW","").")";;\
}\
return AttrVal($NAME,"alias","")." ".$result."!";;\
},\
SystemState \
{\
if ( ReadingsVal($NAME,"new_fw","false") ne "false") {\
return "veraltet";;\
}\
else {\
return "aktuell";;\
}\
},\
connection \
{\
if ( ReadingsVal($NAME,"online","") eq "true") {\
return "<a href='http://".ReadingsVal($NAME,"ip","")."' target='_blank'>".FW_makeImage("10px-kreis-gruen","true")."</a>";;\
}\
else {\
return "<a href='http://".ReadingsVal($NAME,"ip","")."' target='_blank'>".FW_makeImage("10px-kreis-rot","false")."</a>";;\
}\
\
}
attr 26_WandStripes webCmd WW_pct:CW_pct


99_myShellyUtils.pm:
##############################################
# $Id: myShellyUtils.pm supernova1963 $
#
# myUtils für shellies:
# http commnands an Shelly senden und Rückgabe json - string als sub topic /<httpCMND> des
# Shelly topics zu publizieren
# Bitte am "shelly MQTT2_DEVICE" das Attribut setList um folgende Zeile eränzen:
# x_httpCMND { X_PerformShellyHttpRequest($hash,<IP des Shelly>,$EVTPART1[,<username:password>]}
# für den Aufruf und der Auswertung des http commnads erweitern

package main;

use strict;
use warnings;
use POSIX;
use HttpUtils;
use JSON;
use Data::Dumper;

sub
mySHELLYUtils_Initialize($$)
{
  my ($hash) = @_;
}

# Enter you functions below _this_ line.

sub X_Switch2Channels($)
{
my ($name,$chn1,$chn2,$state) = @_;
fhem "set $name $chn1 $state";
fhem "set $name $chn2 $state";
}

sub X_PerformShellyHttpRequest($$)
{
    my ($name, $shelly) = @_;
    my $hash = $defs{$name};
    my ($IP, $httpCMND, $httpCMND_Login) = split(/\,/,$shelly);
    my $shellyURL = "";
    if ($IP eq "" || !defined($IP))
    {
      Log3 $hash, 3, $hash->{NAME}.": Parameter IP ist nicht definiert!";
  return;
    }
    if ($httpCMND eq "" || !defined($httpCMND))
    {
      Log3 $hash, 3, $hash->{NAME}.": Parameter httpCMND ist nicht definiert!";
      return;
    }
    if ($httpCMND_Login eq "" || !defined($httpCMND_Login))
    {
      $shellyURL = "http://".$IP."/".$httpCMND;
    }
    else
    {
      if ( $httpCMND_Login =~ m/:/i)
      {
        $shellyURL = "http://".$httpCMND_Login."@".$IP."/".$httpCMND;
      }
      else
      {
        Log3 $hash, 3, $hash->{NAME}.": <user>:<password> nicht gesetzt oder fehlerhaft!";
        return;
      }
    }
  $hash->{helper}{httpCMND} = $httpCMND;
    my $param = {
                    url        => $shellyURL,
                    timeout    => 5,
                    hash       => $hash,                                                                                 # Muss gesetzt werden, damit die Callback funktion wieder $hash hat
                    method     => "GET",                                                                                 # Lesen von Inhalten
                    header     => "User-Agent: TeleHeater/2.2.3\r\nAccept: application/json",                            # Den Header gemäß abzufragender Daten ändern
                    callback   => \&X_ParseShellyHttpResponse                                                                  # Diese Funktion soll das Ergebnis dieser HTTP Anfrage bearbeiten
                };

    HttpUtils_NonblockingGet($param);                                                                                    # Starten der HTTP Abfrage. Es gibt keinen Return-Code.
}

sub X_ParseShellyHttpResponse($)
{
my ($param, $err, $data) = @_;
my $hash = $param->{hash};
my $name = $hash->{NAME};
my $rc = "";
my $httpCMND = $hash->{helper}{httpCMND};
my $IOdevice = InternalVal($name,"LASTInputDev","");
my $shellyID = ReadingsVal($name,"id","");
  if($err ne "")                                                                                                      # wenn ein Fehler bei der HTTP Abfrage aufgetreten ist
  {
  Log3 $name, 3, "Fehler bei dem URL-Aufruf: ".$param->{url}." - $err";                                           # Eintrag fürs Log
    #readingsSingleUpdate($hash, "fullResponse", "ERROR", 0);                                                        # Readings erzeugen
$hash->{helper}{fullResponse} = "ERROR: ".$err;
  }
  elsif($data ne "")                                                                                                  # wenn die Abfrage erfolgreich war ($data enthält die Ergebnisdaten des HTTP Aufrufes)
  {
    Log3 $name, 3, $param->{url}." returned: $data";                                                         # Eintrag fürs Log
# An dieser Stelle die Antwort parsen / verarbeiten mit $data
    #readingsSingleUpdate($hash, "fullResponse", $data, 0);
    my $json = new JSON;
    my $perl_scalar = $json->decode($data);
$hash->{helper}{fullResponse} = $json->pretty->encode($perl_scalar);
$rc = fhem("set ".$IOdevice." publish -r shellies/".$shellyID."/".$httpCMND." ".$data);
#Log3 $name, 3, $name.": rc json2reading: ".json2reading($name, $data);
}
# Damit ist die Abfrage zuende.
   # Evtl. einen InternalTimer neu schedulen
}



sub StorePassword($$) {

    my ($hash, $password) = @_;
    my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd";
    my $key = getUniqueId().$index;
    my $enc_pwd = "";
my $name = $hash->{NAME};


    if(eval "use Digest::MD5;1")
    {
        $key = Digest::MD5::md5_hex(unpack "H*", $key);
        $key .= Digest::MD5::md5_hex($key);
    }

    for my $char (split //, $password)
    {

        my $encode=chop($key);
        $enc_pwd.=sprintf("%.2x",ord($char)^ord($encode));
        $key=$encode.$key;
    }

    my $err = setKeyValue($index, $enc_pwd);
   
if(defined($err)) {
Log3 $hash->{NAME}, 3, "$name: error while saving the password - $err";
return "error while saving the password - $err";
}
    Log3 $hash->{NAME}, 3, "$name: password successfully saved";
return "password successfully saved";
}

sub ReadPassword($) {

    my ($hash) = @_;
    my $name = $hash->{NAME};
    my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd";
    my $key = getUniqueId().$index;
    my ($password, $err);

    Log3 $name, 4, "($name) - Read password from file";

    ($err, $password) = getKeyValue($index);

    if ( defined($err) )
    {
      Log3 $name, 4, "($name) - unable to read password from file: $err";
      return undef;
    }
    if ( defined($password) )
    {
      if ( eval "use Digest::MD5;1" )
      {
        $key = Digest::MD5::md5_hex(unpack "H*", $key);
        $key .= Digest::MD5::md5_hex($key);
      }
      my $dec_pwd = '';
      for my $char (map { pack('C', hex($_)) } ($password =~ /(..)/g))
      {
        my $decode=chop($key);
        $dec_pwd.=chr(ord($char)^ord($decode));
        $key=$decode.$key;
      }
      return $dec_pwd;
    }
    else
    {
      Log3 $name, 4, "($name) - No password in file";
      return undef;
    }
}


1;
=pod
=item summary    Utilitiies for Shelly devices as MQTT2_CLIENT.
=item summary_DE Hilfsprogramme f&uuml;r Shellies, die als MQTT2_CLIENT definiert sind.
=begin html

<a name="myShellyUtils"></a>
<h3>myShellyUtils</h3>
Please look at German help <a href="commandref_de.html#mySHELLYUtils">myShellyUtils</a>

=end html
=begin html_DE

<a name="myShellyUtils"></a>

<h3>myShellyUtils</h3>

<h3>setlist Befehle</h3>
<ul>
  <code>X_PerformShellyHttpRequest(&lt;device&gt;,&lt;ip&gt;,&lt;command&gt;,&lt;user:password&gt;)</code>
  <br>
  Führt einen Shelly http Befehl aus und führt ein MQTT publish mit dem zurückgegebenen json - String aus.<br>
  Sollte der Shelly ein <b>RESTRICT LOGIN</b> besitzen, muss vorab einmalig der login zu diesem fhem device festgelegt werden.<br>

  <b>StorePassword</b>.
  <br>
  <code>set &lt;device name&gt; x_httpcom_login &lt;user:password&gt;</code><br>
  Dabei muss der user und das password dem "RESTRICT LOGIN" des Shelly entsprechen
  <br>
  Beispiele:<br>
  <ul>
   <code>attr device setlist settings:noArg { X_PerformShellyHttpRequest($NAME,ReadingsVal($NAME,"ip","").",".$EVTPART1.",".ReadPassword($defs{$NAME})) }</code><br>
  </ul>
</ul>
=end html_DE
=cut