diff --git a/fhem/FHEM/lib/AttrTemplate/mqtt2.template b/fhem/FHEM/lib/AttrTemplate/mqtt2.template index 7ba614ef9..b8fabb491 100644 --- a/fhem/FHEM/lib/AttrTemplate/mqtt2.template +++ b/fhem/FHEM/lib/AttrTemplate/mqtt2.template @@ -4698,43 +4698,55 @@ name:wled_controller filter:TYPE=MQTT2_DEVICE desc:To control a WLED device, see https://github.com/Aircoookie/WLED/wiki for details). order:W_01 -par:BASE_ID;BASE_ID typically is wled;{ AttrVal("DEVICE","readingList","") =~ m,([^:]+)[/][^/]+[/][^/]+:, ? $1 : undef } -par:DEVNAME;Device name as configured;{ AttrVal("DEVICE","readingList","") =~ m,[^:]+[/]([^/]+)[/][^/]+:, ? $1 : undef } -par:ICON;ICON as set, defaults to hue_filled_iris;{ AttrVal("DEVICE","icon","hue_filled_iris") } +{ Svn_GetFile('contrib/AttrTemplate/99_attrT_WLED_Utils.pm', 'FHEM/99_attrT_WLED_Utils.pm', sub(){ CommandReload(undef, '99_attrT_WLED_Utils') }) } +par:BASE_ID;BASE_ID typically is wled;{ AttrVal('DEVICE','readingList','') =~ m,([^:]+)[/][^/]+[/][^/]+:, ? $1 : undef } +par:DEVNAME;Device name as configured;{ AttrVal('DEVICE','readingList','') =~ m,[^:]+[/]([^/]+)[/][^/]+:, ? $1 : undef } +par:ICON;ICON as set, defaults to hue_filled_iris;{ AttrVal('DEVICE','icon','hue_filled_iris') } attr DEVICE icon ICON attr DEVICE setList\ on:noArg BASE_ID/DEVNAME on\ off:noArg BASE_ID/DEVNAME off\ toggle:noArg BASE_ID/DEVNAME t\ rgb:colorpicker,RGB BASE_ID/DEVNAME/col #$EVTPART1\ - brightness:colorpicker,BRI,0,1,255 BASE_ID/DEVNAME\ + brightness:colorpicker,BRI,0,1,255 BASE_ID/DEVNAME/api A=$EVTPART1\ + dimup:noArg BASE_ID/DEVNAME/api A=~10\ + dimdown:noArg BASE_ID/DEVNAME/api A=~-10\ speed:colorpicker,BRI,0,1,255 BASE_ID/DEVNAME/api SX=$EVTPART1\ intensity:colorpicker,BRI,0,1,255 BASE_ID/DEVNAME/api IX=$EVTPART1\ - palette:selectnumbers,0,1,46,0,lin BASE_ID/DEVNAME/api FP=$EVTPART1\ - effect:selectnumbers,0,1,101,0,lin BASE_ID/DEVNAME/api FX=$EVTPART1\ - loadPreset:selectnumbers,0,1,3,0,lin BASE_ID/DEVNAME/api PL=$EVTPART1\ - dimup:noArg BASE_ID/DEVNAME/api A=~10\ - dimdown:noArg BASE_ID/DEVNAME/api A=~-10 + effect:{'selectnumbers,0,1,'.ReadingsNum($name,'.effectscount',5).',0,lin'} BASE_ID/DEVNAME/api FX=$EVTPART1\ + effectname:{'select,'.join(',',sort(split(',',ReadingsVal($name,'.effects','Solid,Police'))))} {FHEM::attrT_WLED_Utils::WLED_set($NAME,'effect',$EVTPART1)}\ + effect_next:noArg BASE_ID/DEVNAME/api FX=~1\ + effect_prev:noArg BASE_ID/DEVNAME/api FX=~-1\ + effect_random:noArg BASE_ID/DEVNAME/api FX=r\ + effect_reset:noArg BASE_ID/DEVNAME/api FX=0\ + palette:{'selectnumbers,0,1,'.ReadingsNum($name,'.palettescount',5).',0,lin'} BASE_ID/DEVNAME/api FP=$EVTPART1\ + palettename:{'select,'.join(',',sort(split(',',ReadingsVal($name,'.palettes','Default,Party'))))} {FHEM::attrT_WLED_Utils::WLED_set($NAME,'palette',$EVTPART1)}\ + palette_next:noArg BASE_ID/DEVNAME/api FP=~1\ + palette_prev:noArg BASE_ID/DEVNAME/api FP=~-1\ + palette_random:noArg BASE_ID/DEVNAME/api FP=r\ + palette_reset:noArg BASE_ID/DEVNAME/api FP=0\ + preset:selectnumbers,0,1,15,0,lin BASE_ID/DEVNAME/api PL=$EVTPART1\ + apiraw BASE_ID/DEVNAME/api $EVTPART1\ + seg BASE_ID/DEVNAME/api {'seg':{'i':[$EVTPART1,[$EVTPART2]]}} attr DEVICE readingList \ BASE_ID/DEVNAME/status:.* LWT\ BASE_ID/DEVNAME/g:.* brightness\ - BASE_ID/DEVNAME/g:.* { $EVENT ? {"state"=>"on"} : {"state"=>"off"} }\ - BASE_ID/DEVNAME/c:.* { {"rgb"=>substr("$EVENT",1,6)} }\ - BASE_ID/DEVNAME/v:.* api\ - BASE_ID/DEVNAME/v:.* { $EVENT =~ m,(?<=)([\d]+)(?=<\/sx>), ? $1 eq ReadingsVal($NAME,"speed","unknown") ? return : {"speed"=>$1} : return; }\ - BASE_ID/DEVNAME/v:.* {$EVENT =~ m,(?<=)([\d]+)(?=<\/ix>), ? $1 eq ReadingsVal($NAME,"intensity","unknown") ? return : {"intensity"=>$1} : return }\ - BASE_ID/DEVNAME/v:.* {$EVENT =~ m,(?<=)([\d]+)(?=<\/fp>), ? $1 eq ReadingsVal($NAME,"palette","unknown") ? return : {"palette"=>$1} : return }\ - BASE_ID/DEVNAME/v:.* {$EVENT =~ m,(?<=)([\d]+)(?=<\/fx>), ? $1 eq ReadingsVal($NAME,"effect","unknown") ? return :{"effect"=>"$1"} : return } + BASE_ID/DEVNAME/g:.* {$EVENT ? {state => 'on'} : {state => 'off'}}\ + BASE_ID/DEVNAME/c:.* {{rgb => substr($EVENT,1,6)}}\ + BASE_ID/DEVNAME/v:.* {FHEM::attrT_WLED_Utils::WLED_get($NAME,$EVENT)} deletereading -q DEVICE (?!associatedWith|IODev).* -attr DEVICE devStateIcon {Color::devStateIcon( $name, "rgb", "rgb", "brightness", "state" )} -attr DEVICE eventMap /effect 0:Solid/effect 2:Breathe/effect 63:Pride/effect 48:Police/ -attr DEVICE webCmd rgb:brightness:Solid:Breathe:Pride:Police -attr DEVICE setStateList on off toggle +attr DEVICE devStateIcon {ReadingsVal($name,'LWT','offline') eq 'offline' ? '.*:message_attention@red' : Color::devStateIcon($name,'rgb','rgb','brightness','state')} +attr DEVICE webCmd rgb:brightness:effectname:speed:intensity:palettename:preset +attr DEVICE webCmdLabel RGB:Brightness\ +:Effect:Speed:Intensity\ +:Palette:Preset +attr DEVICE setStateList on off toggle dimdown dimup effect_prev effect_next effect_random palette_prev palette_next palette_random palette_reset effect_reset attr DEVICE comment For questions about the use of different widgets for color selection see discussion at https://forum.fhem.de/index.php/topic,98880.msg995308.html set DEVICE attrTemplate speechcontrol_type_light_255 farewell:template has been applied successfully.
Note: webCmd and eventMap are just examples; adopt this to your needs. attr DEVICE model wled_controller -setreading DEVICE attrTemplateVersion 20200522 or prior +setreading DEVICE attrTemplateVersion 20211220 + ########################################### diff --git a/fhem/contrib/AttrTemplate/99_attrT_WLED_Utils.pm b/fhem/contrib/AttrTemplate/99_attrT_WLED_Utils.pm new file mode 100644 index 000000000..5c7cb9eb7 --- /dev/null +++ b/fhem/contrib/AttrTemplate/99_attrT_WLED_Utils.pm @@ -0,0 +1,149 @@ +############################################## +# $Id$ +# contributed by DeeSPe, https://forum.fhem.de/index.php/topic,98880.msg1192196.html#msg1192196 + +package FHEM::attrT_WLED_Utils; ## no critic 'Package declaration' + +use strict; +use warnings; + +use GPUtils qw(GP_Import); + +## Import der FHEM Funktionen +BEGIN { + GP_Import( + qw( + defs + InternalVal + ReadingsVal + ReadingsNum + AttrVal + readingsBeginUpdate + readingsBulkUpdate + readingsBulkUpdateIfChanged + readingsEndUpdate + HttpUtils_NonblockingGet + ) + ); +} + +sub ::attrT_WLED_Utils_Initialize { goto &Initialize } + +# initialize ################################################################## +sub Initialize { + my $hash = shift; + return; +} + +# Enter you functions below _this_ line. + +sub WLED_get { + my $dev = shift // return; + my $event = shift // undef; + my $c; + my $h = { + sx => 'speed', + ix => 'intensity', + fp => 'palette', + fx => 'effect', + ps => 'preset' + }; + for (keys %{$h}) { + next if $event !~ m/(?<=<$_>)([\d]+)(?=<\/$_>)/x; + if ($1 != ReadingsNum($dev,$h->{$_},-2)){ + $c->{$h->{$_}} = $1; + } + } + my $io = InternalVal($dev,'LASTInputDev',AttrVal($dev,'IODev',InternalVal($dev,'IODev',undef)->{NAME})) // return defined $event ? $c : undef; + my $ip = InternalVal($dev,$io.'_CONN',ReadingsVal($dev,'ip', undef)) =~ m/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/x ? $1 : return defined $event ? $c : undef; + HttpUtils_NonblockingGet({ + url=>"http://$ip/json", + callback=>sub($$$){ + my ($hash,$err,$data) = @_; + WLED_setReadings($dev,$data); + } + }); + return defined $event ? $c : undef; +} + +sub WLED_setReadings { + my $dev = shift // return; + my $data = shift // return; + my $fx = $data =~ m/effects..\[([^[]*?)]/x ? WLED_subst($1) : ''; + my $pl = $data =~ m/palettes..\[([^[]*?)]/x ? WLED_subst($1) : ''; + my $hash = $defs{$dev}; + my @f = split m{,}, $fx; + my @p = split m{,}, $pl; + readingsBeginUpdate($hash); + readingsBulkUpdate($hash,'effectname',$f[ReadingsNum($dev,'effect',0)]); + readingsBulkUpdate($hash,'palettename',$p[ReadingsNum($dev,'palette',0)]); + readingsEndUpdate($hash,1); + readingsBeginUpdate($hash); + readingsBulkUpdateIfChanged($hash,'.effectscount',(scalar @f)-1); + readingsBulkUpdateIfChanged($hash,'.effects',$fx); + readingsBulkUpdateIfChanged($hash,'.palettescount',(scalar @p)-1); + readingsBulkUpdateIfChanged($hash,'.palettes',$pl); + readingsEndUpdate($hash,0); + return; +} + +sub WLED_subst { + my $s = shift; + $s =~ s/["\n]//gx; + $s =~ s/[\s\&]/_/gx; + $s =~ s/\+/Plus/gx; + return $s; +} + +sub WLED_set { + my $dev = shift // return; + my $read = shift // return; + my $val = shift // return; + my $wled = lc(InternalVal($dev,'CID',undef)) // return; + my $arr = ReadingsVal($dev,'.'.$read.'s',undef) // return WLED_get($dev); + $wled =~ s/_/\//; + my $top = $wled.'/api F'; + $top .= $read eq 'effect'?'X=':'P='; + my $id; + my $i = 0; + for (split(',',$arr)){ + if ($_ ne $val) { + $i++; + next; + } else { + $id = $i; + last; + } + } + return defined $id ? $top.$id : undef; +} + +1; + +__END__ + + +=pod +=item summary helper functions needed for WLED MQTT2_DEVICE +=item summary_DE needed Hilfsfunktionen für WLED MQTT2_DEVICE +=begin html + + +

attrT_WLED_Utils

+
    + Functions to support attrTemplates for WLEDs
    +
+
    +
  • FHEM::attrT_WLED_Utils::WLED_get
    + FHEM::attrT_WLED_Utils::WLED_get($$)
    + This is used to provide some readings from the API. +
  • +
+
    +
  • FHEM::attrT_WLED_Utils::WLED_set
    + FHEM::attrT_WLED_Utils::WLED_set($$$)
    + This is used to set the effects and palettes with their names. +
  • +
+=end html +=cut diff --git a/fhem/contrib/AttrTemplate/99_attrTmqtt2_roborock_Utils.pm b/fhem/contrib/AttrTemplate/99_attrTmqtt2_roborock_Utils.pm index d44fbdaef..451fc9e25 100644 --- a/fhem/contrib/AttrTemplate/99_attrTmqtt2_roborock_Utils.pm +++ b/fhem/contrib/AttrTemplate/99_attrTmqtt2_roborock_Utils.pm @@ -1,5 +1,5 @@ ############################################## -# $Id: attrTmqtt2_roborock_Utils.pm 2020-01-19 Beta-User $ +# $Id$ # package main; diff --git a/fhem/contrib/RHASSPY/10_RHASSPY.pm b/fhem/contrib/RHASSPY/10_RHASSPY.pm index f85003228..86b214d6c 100644 --- a/fhem/contrib/RHASSPY/10_RHASSPY.pm +++ b/fhem/contrib/RHASSPY/10_RHASSPY.pm @@ -3162,8 +3162,10 @@ sub RHASSPY_ParseHttpResponse { $siteIds = encode($cp,$ref->{$_}{satellite_site_ids}); } } - my @ids = uniq(split q{,},$siteIds); - readingsBulkUpdate($hash, 'siteIds', join q{,}, @ids); + if ( $siteIds ) { + my @ids = uniq(split m{,},$siteIds); + readingsBulkUpdate($hash, 'siteIds', join q{,}, @ids); + } } elsif ( $url =~ m{api/intents}ix ) { my $refb;