diff --git a/FHEM/lib/AttrTemplate/mqtt2.template b/FHEM/lib/AttrTemplate/mqtt2.template index 512a7f797..cdaa52954 100644 --- a/FHEM/lib/AttrTemplate/mqtt2.template +++ b/FHEM/lib/AttrTemplate/mqtt2.template @@ -1184,8 +1184,8 @@ set DEVICE attrTemplate tasmota_basic_state_power1 CALLSPEECHRECOGN=0 JSONMAPTYP par:CMNDTOPIC;Command topic prefix, without trailing /;{ AttrVal('DEVICE','readingList','') =~ m,([^:]*)\b(tele|cmnd|stat)(/.*)?/LWT:, ? "${1}cmnd$3" : undef } par:TELETOPIC;info topic prefix, without trailing /;{ AttrVal('DEVICE','readingList','') =~ m,([^:]*)\b(tele|cmnd|stat)(/.*)?/LWT:, ? "${1}tele$3" : undef } par:STATTOPIC;ack topic prefix, without trailing /;{ AttrVal('DEVICE','readingList','') =~ m,([^:]*)\b(tele|cmnd|stat)(/.*)?/LWT:, ? "${1}stat$3" : undef } -attr DEVICE comment Mains channel for DEVICE, see also DEVICE_CH2 for rgb LED -attr DEVICE devStateIcon {my $onl = ReadingsVal($name,"LWT","false") eq "Online"?"10px-kreis-gruen":"10px-kreis-rot"; my $light = ReadingsVal($name,"state","off");"".FW_makeImage($onl)." ".FW_makeImage($light)." uptime: ".ReadingsVal($name,"Uptime",undef)} +attr DEVICE comment Mains channel for DEVICE, see also DEVICE_CH2 for rgbw LEDs +attr DEVICE devStateIcon {my $onl = ReadingsVal($name,'LWT','false') eq 'Online'?'10px-kreis-gruen':'10px-kreis-rot'; my $light = ReadingsVal($name,'state','off');"".FW_makeImage($onl)." ".FW_makeImage($light)." uptime: ".ReadingsVal($name,'Uptime',undef)} setreading DEVICE associatedWith DEVICE_CH2 copy DEVICE DEVICE_CH2 deleteattr DEVICE_CH2 stateFormat @@ -1215,6 +1215,44 @@ set DEVICE,DEVICE_CH2 attrTemplate speechcontrol_type_switch attr DEVICE,DEVICE_CH2 model tasmota_plug_with_rgbw_split setreading DEVICE,DEVICE_CH2 attrTemplateVersion 20220228 +# plug with LED flashed with Tasmota. +name:tasmota_plug_with_rgb_split +filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*(tele|cmnd|stat).* +desc:plug with seperate RGB LEDs flashed with Tasmota.
NOTE: a second device will be created for the rgb device.
Tested with Tasmota V. 11.0.0 and noname device with 5050 LEDs using template: {"NAME":"Custom_rgb_nightlight","GPIO":[418,0,320,0,417,416,0,0,33,32,0,224,0,0],"FLAG":0,"BASE":18} +order:A_01c1a1 +set DEVICE attrTemplate tasmota_basic_state_power1 CALLSPEECHRECOGN=0 JSONMAPTYPE=2 +par:CMNDTOPIC;Command topic prefix, without trailing /;{ AttrVal('DEVICE','readingList','') =~ m,([^:]*)\b(tele|cmnd|stat)(/.*)?/LWT:, ? "${1}cmnd$3" : undef } +par:TELETOPIC;info topic prefix, without trailing /;{ AttrVal('DEVICE','readingList','') =~ m,([^:]*)\b(tele|cmnd|stat)(/.*)?/LWT:, ? "${1}tele$3" : undef } +par:STATTOPIC;ack topic prefix, without trailing /;{ AttrVal('DEVICE','readingList','') =~ m,([^:]*)\b(tele|cmnd|stat)(/.*)?/LWT:, ? "${1}stat$3" : undef } +attr DEVICE comment Mains channel for DEVICE, see also DEVICE_CH2 for rgb LED +attr DEVICE devStateIcon {my $onl = ReadingsVal($name,'LWT','false') eq 'Online'?'10px-kreis-gruen':'10px-kreis-rot'; my $light = ReadingsVal($name,'state','off');"".FW_makeImage($onl)." ".FW_makeImage($light)." uptime: ".ReadingsVal($name,'Uptime',undef)} +setreading DEVICE associatedWith DEVICE_CH2 +copy DEVICE DEVICE_CH2 +deleteattr DEVICE_CH2 stateFormat +attr DEVICE_CH2 comment RGB channel for DEVICE +setreading DEVICE_CH2 associatedWith DEVICE +attr DEVICE_CH2 setList \ + off:noArg CMNDTOPIC/POWER2 0\ + on:noArg CMNDTOPIC/POWER2 1\ + toggle:noArg CMNDTOPIC/POWER2 2\ + rgb:colorpicker,RGB CMNDTOPIC/Color\ + pct:colorpicker,BRI,0,5,100 CMNDTOPIC/Dimmer\ + white:noArg CMNDTOPIC/Color 12\ + dimup:noArg { my $num=int((ReadingsNum($NAME,'pct',0)+4)/10)*10+10; return qq {CMNDTOPIC/Dimmer $num}; }\ + dimdown:noArg { my $num=int((ReadingsNum($NAME,'pct',0)+7)/10)*10-10; return qq {CMNDTOPIC/Dimmer $num}; } +attr DEVICE_CH2 readingList \ + STATTOPIC/RESULT:.* { json2nameValue($EVENT,'',$JSONMAP) }\ + STATTOPIC/POWER2:.* state +attr DEVICE_CH2 jsonMap POWER2:0 Dimmer:pct Channel_4:0 Channel_1:0 Channel_2:0 Channel_3:0 HSBColor:0 POWER1:0 Heap:0 LedTable:0 LoadAvg:0 MqttCount:0 SaveData:0 Scheme:0 SetOption26:0 Sleep:0 SleepMode:0 Speed:0 StateText1:0 StateText2:0 StateText3:0 StateText4:0 Time:0 Uptime:0 UptimeSec:0 Wifi_SSId:0 Wifi_RSSI:0 Wifi_LinkCount:0 Wifi_Downtime:0 Wifi_Channel:0 Wifi_BSSId:0 Wifi_AP:0 ANALOG_A0:0 SetOption26:0 Sleep:0 SleepMode:0 Speed:0 StateText1:0 StateText2:0 StateText3:0 StateText4:0 Time:0 Uptime:0 UptimeSec:0 Wifi_SSId:0 Wifi_RSSI:0 Wifi_LinkCount:0 Wifi_Downtime:0 Wifi_Channel:0 Wifi_BSSId:0 Wifi_AP:0 ANALOG_A0:0 Color:rgb +attr DEVICE_CH2 webCmd pct:rgb +attr DEVICE_CH2 devStateIcon {Color::devStateIcon($name,'rgb','rgb','pct','state')} +attr DEVICE_CH2 setStateList on off toggle +deletereading -q DEVICE_CH2 (?!associatedWith|IODev).* +set DEVICE,DEVICE_CH2 attrTemplate speechcontrol_type_switch +attr DEVICE,DEVICE_CH2 model tasmota_plug_with_rgb_split +setreading DEVICE,DEVICE_CH2 attrTemplateVersion 20220404 + + #tasmota device with Infrared-circuit name:tasmota_ir desc:Demonstrates multiple options how to configure tasmota devices as IR remote control extension.
Forum Thread IR-Remote
Forum Thread tasmota_ir-Template
Tasmota IR-Remote Docu
Tasmota IR Communication Docu
Simple IR-circuit
irsend syntax
NOTE: This is more like a showcase for several options to send and receive commands, not really a "ready to use" device. Most likely, it's a good idea to add repeats to the commands. @@ -2597,17 +2635,16 @@ attr DEVICE setList\ x_update:noArg shellies/DEVNAME/command update_fw\ x_mqttcom shellies/DEVNAME/command $EVTPART1 attr DEVICE readingList \ - shellies/DEVNAME/relay/0:.* state\ - shellies/DEVNAME/relay/0:.* relay0\ + shellies/DEVNAME/relay/0:.* {{ state => $EVENT, relay0 => $EVENT}}\ shellies/DEVNAME/input/0:.* input0\ shellies/DEVNAME/online:.* online\ shellies/DEVNAME/announce:.* { json2nameValue($EVENT) }\ shellies/announce:.* { $EVENT =~ m,..id...DEVNAME...mac.*, ? json2nameValue($EVENT) : return } -attr DEVICE devStateIcon {my $onl = ReadingsVal($name,"online","false") eq "false" ? "rot" : ReadingsVal($name,"new_fw","false") eq "true" ? "gelb" : "gruen"; my $light = ReadingsVal($name,"state","off"); my $show = '" : "http://".ReadingsVal($name,"ip","none").' "target="_blank">'; $show .= FW_makeImage("10px-kreis-".$onl).""; "
$show ".FW_makeImage($light)."
" } +attr DEVICE devStateIcon {my $onl = ReadingsVal($name,'online','false') eq 'false' ? 'rot' : ReadingsVal($name,'new_fw','false') eq 'true' ? 'gelb' : 'gruen'; my $light = ReadingsVal($name,'state','off'); my $show = '" : 'http://'.ReadingsVal($name,'ip','none').' "target="_blank">'; $show .= FW_makeImage("10px-kreis-$onl").''; "
$show ".FW_makeImage($light).'
' } deletereading -q DEVICE (?!associatedWith|IODev).* set DEVICE x_mqttcom announce attr DEVICE model shelly1 -setreading DEVICE attrTemplateVersion 20211030 +setreading DEVICE attrTemplateVersion 20220404 option:{ CALLSPEECHRECOGN } set DEVICE attrTemplate speechcontrol_type_switch @@ -2645,10 +2682,10 @@ name:shelly1_w_energy_measuring filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* order:A_10b desc:Applies to single relay Shelly devices offering energy measuring like Shelly 1PM or Shelly Plug S -par:DEVNAME;Shelly1 name in the topic;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]*)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } par:RADIO_SETUSERREADING;Set userreading for total energy consumption;{ undef } par:RADIO_DONOTSETUSERREADING;Do not set userreading for total energy consumption;{ undef } -par:NEWUSERREADINGS;NEWUSERREADINGS as set if relay_0_energy_total is included, otherwise it will be added;{ my $old = AttrVal("DEVICE","userReadings",undef);; !defined $old ? 'relay_0_energy_total:relay_0_energy:.* monotonic {ReadingsNum("$name","relay_0_energy",0)}' : $old =~ m,relay_0_energy_total:relay_0_energy.*, ? $old : $old.', relay_0_energy_total:relay_0_energy:.* monotonic {ReadingsNum("$name","relay_0_energy",0)}' } +par:NEWUSERREADINGS;NEWUSERREADINGS as set if relay_0_energy_total is included, otherwise it will be added;{ my $old = AttrVal("DEVICE","userReadings",undef);; !defined $old ? 'relay_0_energy_total:relay_0_energy:.* monotonic {ReadingsNum($name,'relay_0_energy',0)}' : $old =~ m,relay_0_energy_total:relay_0_energy.*, ? $old : $old.', relay_0_energy_total:relay_0_energy:.* monotonic {ReadingsNum($name,'relay_0_energy',0)}' } par:CALLSPEECHRECOGN;Set this to 0 to not set any speech recogn. related attributes;{ 1 } attr DEVICE setList\ relay0:on,off,toggle shellies/DEVNAME/relay/0/command $EVTPART1\ @@ -2658,29 +2695,27 @@ attr DEVICE setList\ x_update:noArg shellies/DEVNAME/command update_fw\ x_mqttcom shellies/DEVNAME/command $EVTPART1 attr DEVICE readingList \ - shellies/DEVNAME/relay/0:.* state\ - shellies/DEVNAME/relay/0:.* relay0\ + shellies/DEVNAME/relay/0:.* {{ state => $EVENT, relay0 => $EVENT}}\ shellies/DEVNAME/input/0:.* input0\ shellies/DEVNAME/online:.* online\ shellies/announce:.* { $EVENT =~ m,..id...DEVNAME...mac.*, ? json2nameValue($EVENT) : return }\ shellies/DEVNAME/announce:.* { json2nameValue($EVENT) }\ shellies/DEVNAME/relay/0/power:.* relay_0_power\ - shellies/DEVNAME/relay/0/power:.* { my $compare = $EVTPART0 < 100 ? "off":"on"; ReadingsVal($NAME,"loadState","off") ne $compare ? { 'loadState' => $compare } : return }\ + shellies/DEVNAME/relay/0/power:.* { my $compare = $EVTPART0 < 100 ? 'off':'on'; ReadingsVal($NAME,'loadState','off') ne $compare ? { loadState => $compare } : return }\ shellies/DEVNAME/temperature:.* temperature\ - shellies/DEVNAME/temperature_f:.* temperature_f\ + shellies/DEVNAME/temperature_f:.* {}\ shellies/DEVNAME/input_event/0:.* { json2nameValue($EVENT) }\ shellies/DEVNAME/overtemperature:.* overtemperature\ - shellies/DEVNAME/relay/0/energy:.* relay_0_energy\ - shellies/DEVNAME/relay/0/energy:.* {'relay_0_kWh' => sprintf("%.2f",$EVENT/60/1000)}\ + shellies/DEVNAME/relay/0/energy:.* { relay_0_energy => $EVENT, relay_0_kWh => sprintf("%.2f",$EVENT/60/1000)}\ shellies/DEVNAME/longpush/0:.* longpush_0 -attr DEVICE devStateIcon {my $onl = ReadingsVal($name,"online","false") eq "false"?"10px-kreis-rot" : ReadingsVal($name,"new_fw","false") eq "true" ? "10px-kreis-gelb" : "10px-kreis-gruen"; my $light = ReadingsVal($name,"state","off"); my $cons = ReadingsVal($name,"relay_0_power","unknown"); my $total = ReadingsVal($name,"relay_0_kWh","unknown"); my $temp = ReadingsVal($name,"temperature","-100"); "".FW_makeImage($onl)." ".FW_makeImage($light)."
Verbrauch: $cons / Total: $total/ Temp: $temp °C
"} +attr DEVICE devStateIcon {my $onl = ReadingsVal($name,'online','false') eq 'false'?'10px-kreis-rot' : ReadingsVal($name,'new_fw','false') eq 'true' ? '10px-kreis-gelb' : '10px-kreis-gruen'; my $light = ReadingsVal($name,'state','off'); my $cons = ReadingsVal($name,'relay_0_power','unknown'); my $total = ReadingsVal($name,'relay_0_kWh','unknown'); my $temp = ReadingsVal($name,'temperature','-100'); "".FW_makeImage($onl)." ".FW_makeImage($light)."
Verbrauch: $cons / Total: $total/ Temp: $temp °C
"} attr DEVICE comment To get appropriate loadState values: Change the default limit "100" in readingList to your needs. attr DEVICE webCmd : attr DEVICE setStateList on off toggle deletereading -q DEVICE (?!associatedWith|IODev).* set DEVICE x_mqttcom announce attr DEVICE model shelly1_w_energy_measuring -setreading DEVICE attrTemplateVersion 20200831 +setreading DEVICE attrTemplateVersion 20220404 option:{ CALLSPEECHRECOGN } set DEVICE attrTemplate speechcontrol_type_switch option:{ RADIO_SETUSERREADING } @@ -2691,13 +2726,13 @@ name:shelly1_w_energy_measuring_washer_example filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* order:A_10b1 desc:Example how to configure a single relay Shelly device offering energy measuring like Shelly 1PM or Shelly Plug S to visualise state of a machine behind the plug. Icons will not allow to turn the machine off. -par:DEVNAME;Shelly1 name in the topic;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]*)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } set DEVICE attrTemplate shelly1_w_energy_measuring CALLSPEECHRECOGN=0 attr DEVICE devStateIcon { my $amp = ReadingsVal($name,"online","false") eq "false" ? "rot" : ReadingsVal($name,"new_fw","false") eq "true" ? "gelb" : "gruen"; my $pic = ReadingsVal($name,"loadState","") eq "on"?'scene_laundry_room_fem@green':'scene_laundry_room_fem'; my $text = ReadingsVal($name,"loadState","") eq "on"?"Waschmaschine läuft - Aktuell: ".ReadingsVal($name,"relay_0_power","")." W":'Standby'; my $show = "$amp" eq "gelb" ? "".FW_makeImage("10px-kreis-".$amp)."" : "".FW_makeImage("10px-kreis-".$amp).""; "
$show ".FW_makeImage($pic)." $text
" } -attr DEVICE userReadings total_temp:loadState:.on { ReadingsNum("$name","relay_0_kWh",0) },wash:loadState:.off { ReadingsNum("$name","total",0) - ReadingsNum("$name","total_temp",0) },price:loadState:.off {sprintf("%.2f",ReadingsNum("$name","wash",1)*ReadingsNum("kWh_Price","state",0.30))},time:loadState:.off {strftime("%H:%M", localtime(ReadingsAge("$name","total_temp",0)-3600))} +attr DEVICE userReadings total_temp:loadState:.on { ReadingsNum($name,'relay_0_kWh',0) },wash:loadState:.off { ReadingsNum($name,'total',0) - ReadingsNum($name,'total_temp',0) },price:loadState:.off {sprintf("%.2f",ReadingsNum($name,'wash',1)*ReadingsNum('kWh_Price','state',0.30))},time:loadState:.off {strftime("%H:%M", localtime(ReadingsAge($name,'total_temp',0)-3600))} attr DEVICE comment To get appropriate loadState values: Change the default limit "100" in readingList to your needs; using a seperate device named kWh_Price indicating actual energy price in state will lead to realistic price results or change the refference/the value "0.30" in userReadings "price". attr DEVICE model shelly1_w_energy_measuring_washer_example -setreading DEVICE attrTemplateVersion 20200831 +setreading DEVICE attrTemplateVersion 20220404 name:shelly2em filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* @@ -2746,7 +2781,7 @@ name:shelly3em filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* order:A_10c1 desc:Applies to Shelly 3em devices.
NOTE: early version, might still need some testing -par:DEVNAME;Shelly1 name in the topic;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]*)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } par:RADIO_SETUSERREADING;Set userreading for total energy consumption;{ undef } par:RADIO_DONOTSETUSERREADING;Do not set userreading for total energy consumption;{ undef } par:NEWUSERREADINGS;NEWUSERREADINGS as set if emeter_0_energy_total is included, otherwise it will be added;{ my $tobeadded = 'emeter_0_energy_total:emeter_0_energy:.* monotonic {ReadingsNum("$name","emeter_0_energy",0)}, emeter_1_energy_total:emeter_1_energy:.* monotonic {ReadingsNum("$name","emeter_1_energy",0)}, emeter_2_energy_total:emeter_2_energy:.* monotonic {ReadingsNum("$name","emeter_2_energy",0)}'; my $old = AttrVal("DEVICE","userReadings",undef); !defined $old ? $tobeadded : $old =~ m,emeter_0_energy_total:emeter_0_energy.*, ? $old : $old." $tobeadded" } @@ -2800,7 +2835,7 @@ name:shelly2_roller filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shelly2 using original firmware.
NOTE: shelly2 roller operated, change settings first! order:A_11b -par:DEVNAME;Shelly2 name in the topic;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]*)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } attr DEVICE comment shelly2 roller operated attr DEVICE setList \ open:noArg shellies/DEVNAME/roller/0/command open\ @@ -2835,7 +2870,7 @@ name:shelly25_roller_invert_0 filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shelly25 using original firmware.
NOTE: shelly25 roller operated, change settings first! order:A_11b1a -par:DEVNAME;Shellyswitch25 name in the topic;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]*)/, ? $1 : undef } +par:DEVNAME;Shellyswitch25 name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } attr DEVICE comment Shelly 2.5 in Roller-Mode. 100=opened / 0=closed attr DEVICE setList \ open:noArg shellies/DEVNAME/roller/0/command open\ @@ -2847,7 +2882,7 @@ attr DEVICE setList \ x_update:noArg shellies/DEVNAME/command update_fw\ x_mqttcom shellies/DEVNAME/command $EVTPART1 attr DEVICE readingList \ - shellies/DEVNAME/roller/0/pos:.* pct\ + shellies/DEVNAME/roller/0/pos:.* { { pct => $EVENT, state => $EVENT } }\ shellies/DEVNAME/status/0/rollers:.* power\ shellies/DEVNAME/online:.* online\ shellies/DEVNAME/announce:.* { json2nameValue($EVENT) }\ @@ -2855,7 +2890,6 @@ attr DEVICE readingList \ shellies/DEVNAME/roller/0:.* current\ shellies/DEVNAME/roller/0:open {{'state' => 'opening'}}\ shellies/DEVNAME/roller/0:close {{'state' => 'closing'}}\ - shellies/DEVNAME/roller/0/pos:.* state\ shellies/DEVNAME/input/1:.* input1\ shellies/DEVNAME/input/0:.* input0\ shellies/DEVNAME/relay/power:.* power\ @@ -2864,7 +2898,7 @@ attr DEVICE readingList \ shellies/DEVNAME/overtemperature:.* overtemperature\ shellies/DEVNAME/roller/0/power:.* roller_0_power\ shellies/DEVNAME/roller/0/energy:.* roller_0_energy\ - shellies/DEVNAME/temperature_f:.* temperature_f + shellies/DEVNAME/temperature_f:.* {} attr DEVICE devStateIcon .*/open:fts_shutter_up@red .*/close:fts_shutter_down@red true:10px-kreis-gruen false:10px-kreis-rot 0/stop:fts_shutter_100 100/stop:fts_shutter_10 9\d/stop:fts_shutter_10 8\d/stop:fts_shutter_20 7\d/stop:fts_shutter_30 6\d/stop:fts_shutter_40 5\d/stop:fts_shutter_50 4\d/stop:fts_shutter_60 3\d/stop:fts_shutter_70 2\d/stop:fts_shutter_80 1\d/stop:fts_shutter_90 0\d/stop:fts_shutter_100 set_.*:fts_shutter_updown attr DEVICE stateFormat \ online\ @@ -2878,13 +2912,13 @@ attr DEVICE eventMap open:opens close:closes set DEVICE x_mqttcom announce set DEVICE attrTemplate speechcontrol_type_blind attr DEVICE model shelly25_roller_invert_0 -setreading DEVICE attrTemplateVersion 20210126 +setreading DEVICE attrTemplateVersion 20220404 name:shelly25_roller_invert_1 filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shelly25 using original firmware.
NOTE: shelly25 roller operated, change settings first! order:A_11b1b -par:DEVNAME;Shellyswitch25 name in the topic;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]*)/, ? $1 : undef } +par:DEVNAME;Shellyswitch25 name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } attr DEVICE comment Shelly 2.5 in Roller-Mode. 0=opened / 100=closed attr DEVICE setList \ open:noArg shellies/DEVNAME/roller/0/command open\ @@ -2896,15 +2930,14 @@ attr DEVICE setList \ x_update:noArg shellies/DEVNAME/command update_fw\ x_mqttcom shellies/DEVNAME/command $EVTPART1 attr DEVICE readingList \ - shellies/DEVNAME/roller/0/pos:.* {'pct' => 100-$EVENT}\ + shellies/DEVNAME/roller/0/pos:.* { { pct => 100-$EVENT, state => 100-$EVENT } }\ shellies/DEVNAME/status/0/rollers:.* power\ shellies/DEVNAME/online:.* online\ shellies/DEVNAME/announce:.* { json2nameValue($EVENT) }\ shellies/announce:.* { $EVENT =~ m,..id...DEVNAME...mac.*, ? json2nameValue($EVENT) : return }\ shellies/DEVNAME/roller/0:.* current\ - shellies/DEVNAME/roller/0:open {{'state' => 'opening'}}\ - shellies/DEVNAME/roller/0:close {{'state' => 'closing'}}\ - shellies/DEVNAME/roller/0/pos:.* {'state' => 100-$EVENT}\ + shellies/DEVNAME/roller/0:open {{state => 'opening'}}\ + shellies/DEVNAME/roller/0:close {{state => 'closing'}}\ shellies/DEVNAME/input/1:.* input1\ shellies/DEVNAME/input/0:.* input0\ shellies/DEVNAME/relay/power:.* power\ @@ -2913,7 +2946,7 @@ attr DEVICE readingList \ shellies/DEVNAME/overtemperature:.* overtemperature\ shellies/DEVNAME/roller/0/power:.* roller_0_power\ shellies/DEVNAME/roller/0/energy:.* roller_0_energy\ - shellies/DEVNAME/temperature_f:.* temperature_f + shellies/DEVNAME/temperature_f:.* {} attr DEVICE devStateIcon .*/open:fts_shutter_up@red .*/close:fts_shutter_down@red true:10px-kreis-gruen false:10px-kreis-rot 0/stop:fts_shutter_100 100/stop:fts_shutter_10 9\d/stop:fts_shutter_10 8\d/stop:fts_shutter_20 7\d/stop:fts_shutter_30 6\d/stop:fts_shutter_40 5\d/stop:fts_shutter_50 4\d/stop:fts_shutter_60 3\d/stop:fts_shutter_70 2\d/stop:fts_shutter_80 1\d/stop:fts_shutter_90 0\d/stop:fts_shutter_100 set_.*:fts_shutter_updown attr DEVICE stateFormat
\ online\ @@ -2927,7 +2960,7 @@ attr DEVICE eventMap open:opens close:closes set DEVICE x_mqttcom announce set DEVICE attrTemplate speechcontrol_type_blind attr DEVICE model shelly25_roller_invert_1 -setreading DEVICE attrTemplateVersion 20210126 +setreading DEVICE attrTemplateVersion 20220404 # shelly2 using original firmware. # NOTE: a second device will be created for the second channel @@ -2936,7 +2969,7 @@ filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shelly2 using original firmware.
NOTE: a second device will be created for the second channel order:A_11a set DEVICE attrTemplate shellyplug -par:DEVNAME;Shelly2 name in the topic;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]*)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } set DEVICE attrTemplate set_associatedWith \CHANNELS=2 \MAKECOPIES=1 defmod DEVICE_CH2 MQTT2_\DEVICE DEVICE_CH2 attr DEVICE_CH2 readingList shellies/DEVNAME/relay/1:.* state @@ -2954,7 +2987,7 @@ name:shelly25_split filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shelly2.5 using original firmware.
NOTE: a second device will be created for the second channel order:A_11a1 -par:DEVNAME;Shelly2 name in the topic;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]*)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } par:RADIO_SETUSERREADING;Set userreading for total energy consumption;{ undef } par:RADIO_DONOTSETUSERREADING;Do not set userreading for total energy consumption;{ undef } par:CALLSPEECHRECOGN;Set this to 0 to not set any speech recogn. related attributes;{ 1 } @@ -2971,9 +3004,8 @@ attr DEVICE_CH2 readingList shellies/DEVNAME/relay/1:.* state\ shellies/DEVNAME/relay/1/power:.* { my $compare = $EVTPART0 < 100 ? "off":"on"; ReadingsVal($NAME,"loadState","off") ne $compare ? { 'loadState' => $compare } : return }\ shellies/DEVNAME/temperature:.* temperature\ shellies/DEVNAME/overtemperature:.* overtemperature\ - shellies/DEVNAME/temperature_f:.* temperature_f\ - shellies/DEVNAME/relay/1/energy:.* relay_1_energy\ - shellies/DEVNAME/relay/1/energy:.* {'relay_1_kWh' => sprintf("%.2f",$EVENT/60/1000)}\ + shellies/DEVNAME/temperature_f:.* {}\ + shellies/DEVNAME/relay/1/energy:.* { relay_1_energy => $EVENT, relay_1_kWh => sprintf("%.2f",$EVENT/60/1000)}\ shellies/DEVNAME/longpush/1:.* longpush_1\ shellies/DEVNAME/input_event/1:.* { json2nameValue($EVENT) } attr DEVICE_CH2 setList \ @@ -2990,7 +3022,7 @@ name:shelly4pro_split filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shelly4pro using original firmware
NOTE: for each of the second to fourth channel, a new device will be created order:A_14a1 -par:DEVNAME;Shelly4Pro name in the topic;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]*)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } set DEVICE attrTemplate shellyplug attr DEVICE getList \ power0:noArg shellies/DEVNAME/relay/0/power power0\ @@ -3027,9 +3059,9 @@ set DEVICE,DEVICE_CH2,DEVICE_CH3,DEVICE_CH4 attrTemplate speechcontrol_type_swit # source: https://forum.fhem.de/index.php/topic,97218.msg905689.html#msg905689 name:shelly4pro_unified filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* -desc:shelly4pro using original firmware
NOTE: UNTESTED! feedback is apreciated, please try also to add toggle commands
NOTE: only one device will be created. +desc:shelly4pro (Gen. 1) using original firmware
NOTE: UNTESTED! feedback is apreciated, please try also to add toggle commands
NOTE: only one device will be created. order:A_14b -par:DEVNAME;Shelly4Pro name in the topic;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]*)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } set DEVICE attrTemplate shellyplug attr DEVICE getList \ power0:noArg shellies/DEVNAME/relay/0/power power0\ @@ -3162,7 +3194,7 @@ name:shellyht filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shellyht using original firmware
Just adds stateFormat and icon order:A_161 -par:DEVNAME;name of this shelly;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]+)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } par:ICON;ICON as set, defaults to temperature_humidity;{ AttrVal("DEVICE","icon","temperature_humidity") } attr DEVICE icon ICON attr DEVICE setList \ @@ -3178,8 +3210,8 @@ name:shellyflood filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shellyht using original firmware
Just adds stateFormat and icon order:A_16a -par:DEVNAME;name of this shelly;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]+)/, ? $1 : undef } -par:ICON;ICON as set, defaults to humidity;{ AttrVal("DEVICE","icon","humidity") } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } +par:ICON;ICON as set, defaults to humidity;{ AttrVal('DEVICE','icon','humidity') } attr DEVICE icon ICON attr DEVICE setList \ x_update:noArg shellies/DEVNAME/command update_fw\ @@ -3205,7 +3237,7 @@ name:shellygas filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shellygas using original firmware
Adds stateFormat, setlist, icon, devStateIcon order:A_16b -par:DEVNAME;name of this shelly;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]+)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } attr DEVICE icon feinstaub attr DEVICE devStateIcon none:ampel_gruen mild:ampel_gelb heavy:ampel_rot test:ampel_gruen attr DEVICE setList \ @@ -3226,7 +3258,7 @@ name:shellydw filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shellydw using original firmware.
Note: can be configered als two- or three-state sensor. order:A_16b -par:DEVNAME;name of this shelly;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]+)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } par:ICON;ICON as set, defaults to fts_window_1w_open;{ AttrVal("DEVICE","icon","fts_window_1w_open") } attr DEVICE icon ICON attr DEVICE devStateIcon open:fts_window_1w_open@red tilted:fts_window_1w_tilt@yellow closed:fts_window_1w@green @@ -3250,7 +3282,7 @@ name:shelly_ix3 filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shelly ix3 using original firmware.
Note: untested attrTemplate order:A_16c -par:DEVNAME;name of this shelly;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]+)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } #par:ICON;ICON as set, defaults to fts_window_1w_open;{ AttrVal("DEVICE","icon","fts_window_1w_open") } #attr DEVICE icon ICON attr DEVICE readingList shellies/DEVNAME/online:.* online\ @@ -3314,7 +3346,7 @@ name:shelly2rgbw_4w_split filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shelly2rgbw configured with 4 white channels, one device for each channel
Tested with v1.4.8 order:A_17a -par:DEVNAME;name of this shelly;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]*)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } par:ICON;ICON as set, defaults to light_control;{ AttrVal("DEVICE","icon","light_control") } attr DEVICE icon ICON attr DEVICE readingList shellies/DEVNAME/white/0/status:.* {json2nameValue($EVENT,'',$JSONMAP)}\ @@ -3368,7 +3400,7 @@ name:shellydimmer filter:TYPE=MQTT2_DEVICE:FILTER=readingList=.*shellies.* desc:shellydimmer
Tested with 20191119-085746/master@e3a747f5 order:A_18 -par:DEVNAME;name of this shelly;{ AttrVal("DEVICE","readingList","") =~ m,shellies/([^/]+)/, ? $1 : undef } +par:DEVNAME;Shelly device name in the topic;{ AttrVal('DEVICE','readingList','') =~ m,shellies/([^/]*)/, ? $1 : undef } par:ICON;ICON as set, defaults to light_control;{ AttrVal("DEVICE","icon","light_control") } attr DEVICE icon ICON attr DEVICE setList\ @@ -3385,7 +3417,7 @@ attr DEVICE readingList \ shellies/DEVNAME/light/0/power:.* light_0_power\ shellies/DEVNAME/light/0/energy:.* light_0_energy\ shellies/DEVNAME/temperature:.* temperature\ - shellies/DEVNAME/temperature_f:.* temperature_f\ + shellies/DEVNAME/temperature_f:.* {}\ shellies/DEVNAME/online:.* online\ shellies/DEVNAME/overtemperature:.* overtemperature\ shellies/DEVNAME/overload:.* overload\ @@ -3397,7 +3429,7 @@ attr DEVICE devStateIcon {my $lderr = ReadingsVal($name,"loaderror","true") eq " set DEVICE x_mqttcom announce set DEVICE attrTemplate speechcontrol_type_light attr DEVICE model shellydimmer -setreading DEVICE attrTemplateVersion 20200831 +setreading DEVICE attrTemplateVersion 20220404 ########################################### diff --git a/contrib/RHASSPY/10_RHASSPY.pm b/contrib/RHASSPY/10_RHASSPY.pm index a10bcdb8b..ff179d40f 100644 --- a/contrib/RHASSPY/10_RHASSPY.pm +++ b/contrib/RHASSPY/10_RHASSPY.pm @@ -335,7 +335,7 @@ sub Define { $hash->{defaultRoom} = $defaultRoom; my $language = $h->{language} // shift @{$anon} // lc AttrVal('global','language','en'); - $hash->{MODULE_VERSION} = '0.5.27'; + #$hash->{MODULE_VERSION} = '0.5.27a'; $hash->{baseUrl} = $Rhasspy; initialize_Language($hash, $language) if !defined $hash->{LANGUAGE} || $hash->{LANGUAGE} ne $language; $hash->{LANGUAGE} = $language; @@ -393,9 +393,8 @@ sub firstInit { && InternalVal( InternalVal($name, 'IODev',undef)->{NAME}, 'IODev', 'none') eq 'MQTT2_CLIENT'; initialize_devicemap($hash); initialize_msgDialog($hash); - #initialize_TTS($hash); initialize_STT($hash); - if ( 0 && $hash->{Babble} ) { #deactivate + if ( 0 && $hash->{Babble} ) { #deactivated InternalVal($hash->{Babble},'TYPE','none') eq 'Babble' ? $sets{Babble} = [qw( optionA optionB )] : Log3($name, 1, "[$name] error: No Babble device available with name $hash->{Babble}!"); } @@ -852,7 +851,7 @@ sub initialize_rhasspyTweaks { if ($line =~ m{\A[\s]*(extrarooms)[\s]*=}x) { ($tweak, $values) = split m{=}x, $line, 2; $tweak = trim($tweak); - $values= join q{,}, split m{[\s]*,[\s]*}, $values; + $values= join q{,}, split m{[\s]*,[\s]*}x, $values; return "Error in $line! No content provided!" if !length $values && $init_done; $hash->{helper}{tweaks}{$tweak} = $values; next; @@ -927,7 +926,7 @@ hermes/dialogueManager/configure (JSON) my $matches = join q{|}, @{$toDisable}; for (@intents) { last if $enable eq 'true'; - next if $_ =~ m{$matches}ms; + next if $_ =~ m{$matches}xms; my $defaults = {intentId => "$_", enable => 'true'} ; $defaults = {intentId => "$_", enable => $hash->{helper}{tweaks}->{intentFilter}->{$_}} if defined $hash->{helper}->{tweaks} && defined $hash->{helper}{tweaks}->{intentFilter} && defined $hash->{helper}{tweaks}->{intentFilter}->{$_}; push @disabled, $defaults; @@ -964,14 +963,14 @@ sub init_custom_intents { for my $line (split m{\n}x, $attrVal) { next if !length $line; #return "invalid line $line" if $line !~ m{(?[^=]+)\s*=\s*(?(?([^(]+))\((?.*)\)\s*)}x; - return "invalid line $line" if $line !~ m{ + return "invalid line $line" if $line !~ m{ (?[^=]+)\s* #string up to =, w/o ending whitespace =\s* #separator = and potential whitespace (? #identifier (?([^(]+))#string up to opening bracket \( #opening bracket (?.*)\))\s* #everything up to the closing bracket, w/o ending whitespace - }xms; + }xms; ##no critic qw(Capture) my $intent = trim($+{intent}); return "no intent found in $line!" if (!$intent || $intent eq q{}) && $init_done; my $function = trim($+{function}); @@ -1363,10 +1362,10 @@ sub _getGenericOnOff { }; my @onwords = qw(on open an auf 1); for (@onwords) { - next if $allset !~ m{\b($_)([\b:\s]|\Z)}xmsi; - my $on = $1; - next if $allset !~ m{\b($onoff_map->{$_})([\b:\s]|\Z)}xmsi; - return ($on,$1); + next if $allset !~ m{\b($_)([\b:\s]|\Z)}xmsi; ##no critic qw(Capture) + my $on = $1; ##no critic qw(Capture) + next if $allset !~ m{\b($onoff_map->{$_})([\b:\s]|\Z)}xmsi; ##no critic qw(Capture) + return ($on,$1); ##no critic qw(Capture) } return (undef,undef); } @@ -1434,7 +1433,7 @@ sub _analyze_genDevType_setter { } } - if ($setter =~ m{\bscene:(?[\S]+)}xm) { + if ($setter =~ m{\bscene:(?[\S]+)}xm) { ##no critic qw(Capture) for my $scname (split m{,}xms, $+{scnames}) { my $clscene = $scname; # cleanup HUE scenes @@ -1520,7 +1519,7 @@ sub initialize_STT { next if !$values; if ( $keywd =~ m{\Aallowed\z}xms ) { - for my $amads (split m{[\b]*,[\b]*},$values) { + for my $amads (split m{[\b]*,[\b]*}x,$values) { if ( InternalVal($amads,'TYPE','unknown') ne 'AMADDevice' ) { return "$amads is not an AMADDevice!" if $init_done; Log3($hash, 2, "[RHASSPY] $amads in rhasspySTT is not an AMADDevice!"); @@ -1577,7 +1576,7 @@ sub initialize_STT { sub initialize_msgDialog { my $hash = shift // return; - my $attrVal = shift // AttrVal($hash->{NAME},'rhasspyMsgDialog',undef) // return; + my $attrVal = shift // AttrVal($hash->{NAME},'rhasspyMsgDialog',undef) // ''; my $mode = shift // 'set'; return disable_msgDialog($hash) if $mode ne 'set'; @@ -1632,11 +1631,12 @@ sub disable_msgDialog { && defined $hash->{helper}->{STT}->{config}->{AMADCommBridge} ) { $devsp = 'TYPE=AMADCommBridge'; } - if ($enable) { + if ( $enable ) { $devsp = $devsp ? 'TYPE=(AMADCommBridge|ROOMMATE|GUEST)' : 'TYPE=(ROOMMATE|GUEST)'; } - if ($hash->{autoTraining}) { - $devsp .= $devsp ? ',global' : 'global'; + if ( $hash->{autoTraining} ) { + $devsp .= ',global' if $devsp; + $devsp = 'global' if !$devsp; } if ( $devsp && devspec2array($devsp) ) { @@ -1720,7 +1720,7 @@ sub setDialogTimeout { #interactive dialogue as described in https://rhasspy.readthedocs.io/en/latest/reference/#dialoguemanager_continuesession and https://docs.snips.ai/articles/platform/dialog/multi-turn-dialog my @ca_strings; - $toEnable = split m{,}, $toEnable if ref $toEnable ne 'ARRAY'; + $toEnable = split m{,}xms, $toEnable if ref $toEnable ne 'ARRAY'; if (ref $toEnable eq 'ARRAY') { for (@{$toEnable}) { my $id = qq{$hash->{LANGUAGE}.$hash->{fhemId}:$_}; @@ -1754,7 +1754,6 @@ sub get_unique { return @unique if !$sorted; my @sorted = sort { length($b) <=> length($a) } @unique; - #Log3(undef, 5, "get_unique sorted to ".join q{ }, @sorted); return @sorted; } @@ -2268,7 +2267,7 @@ sub getNeedsConfirmation { if (defined $hash->{helper}{tweaks} && defined $hash->{helper}{tweaks}{confirmIntents} && defined $hash->{helper}{tweaks}{confirmIntents}{$intent} - && $re =~ m{\A($hash->{helper}{tweaks}{confirmIntents}{$intent})\z}m ) { + && $re =~ m{\A($hash->{helper}{tweaks}{confirmIntents}{$intent})\z}xms ) { $response = defined $hash->{helper}{tweaks}{confirmIntentResponses} && defined $hash->{helper}{tweaks}{confirmIntentResponses}{$intent} ? $hash->{helper}{tweaks}{confirmIntentResponses}{$intent} : getResponse($hash, 'DefaultConfirmationRequestRawInput'); @@ -2295,6 +2294,7 @@ sub getNeedsConfirmation { $Value = $words->{$data->{Value}} // $Value; $response =~ s{(\$\w+)}{$1}eegx; Log3( $hash, 5, "[$hash->{NAME}] getNeedsConfirmation is true on device level, response is $response" ); + $data->{'.DevName'} = $device; setDialogTimeout($hash, $data, $timeout, $response); return 1; } @@ -2659,20 +2659,22 @@ sub Notify { return notifySTT($hash, $dev_hash) if InternalVal($device,'TYPE', 'unknown') eq 'AMADCommBridge'; - if ( $name eq 'global' ) { + if ( $device eq 'global' ) { return if !$hash->{autoTraining}; my $events = $dev_hash->{CHANGED}; return if !$events; my @devs = devspec2array("$hash->{devspec}"); for my $evnt(@{$events}){ - next if $evnt !~ m{\A(?:ATTR|DELETEATTR|DELETED|RENAMED)\s+(\w+)(?:\s+)(.*)}; - my $dev = $1; - my $rest = $2; - next if !grep { $_ eq $dev } @devs; + next if $evnt !~ m{\A(?:ATTR|DELETEATTR|DELETED|RENAMED)\s+(\w+)(?:\s+)(.*)}xms; + my $dev = $1; ##no critic qw(Capture) + my $rest = $2; ##no critic qw(Capture) + next if !grep { $dev } @devs; - return resetRegIntTimer( 'autoTraining', time + $hash->{autoTraining}, \&RHASSPY_autoTraining, $hash, 0) if $evnt =~ m{\A(?:DELETED|RENAMED)\s+\w+}; - return resetRegIntTimer( 'autoTraining', time + $hash->{autoTraining}, \&RHASSPY_autoTraining, $hash, 0) if $rest =~ m{\A(alias|$hash->{prefix}|genericDeviceType|(alexa|siri|gassistant)Name|group)}xms; + if ( $evnt =~ m{\A(?:DELETED|RENAMED)\s+\w+}xms || $rest =~ m{\A(alias|$hash->{prefix}|genericDeviceType|(alexa|siri|gassistant)Name|group)}xms ) { + resetRegIntTimer( 'autoTraining', time + $hash->{autoTraining}, \&RHASSPY_autoTraining, $hash, 0); + return; + } } return; } @@ -2686,13 +2688,13 @@ sub Notify { for my $event (@events){ next if $event !~ m{(?:fhemMsgPushReceived|fhemMsgRcvPush):.(.+)}xms; - my $msgtext = trim($1); + my $msgtext = trim($1); ##no critic qw(Capture) Log3($name, 4 , qq($name received $msgtext from $device)); my $tocheck = $hash->{helper}->{msgDialog}->{config}->{close}; - return msgDialog_close($hash, $device) if $msgtext =~ m{\A[\b]*$tocheck[\b]*\z}i; + return msgDialog_close($hash, $device) if $msgtext =~ m{\A[\b]*$tocheck[\b]*\z}ix; $tocheck = $hash->{helper}->{msgDialog}->{config}->{open}; - return msgDialog_open($hash, $device, $msgtext) if $msgtext =~ m{\A[\b]*$tocheck}i; + return msgDialog_open($hash, $device, $msgtext) if $msgtext =~ m{\A[\b]*$tocheck}ix; return msgDialog_progress($hash, $device, $msgtext); } @@ -2711,7 +2713,7 @@ sub notifySTT { for my $event (@events){ next if $event !~ m{(?:receiveVoiceCommand):.(.+)}xms; - my $msgtext = trim($1); + my $msgtext = trim($1); ##no critic qw(Capture) my $client = ReadingsVal($device,'receiveVoiceDevice',undef) // return; return if $hash->{helper}->{STT}->{config}->{allowed} !~ m{\b(?:$client|everyone)(?:\b|\z)}xms; @@ -2719,8 +2721,8 @@ sub notifySTT { my $tocheck = $hash->{helper}->{STT}->{config}->{filterFromBabble}; if ( $tocheck ) { - return AnalyzePerlCommand( undef, Babble_DoIt($hash->{Babble},$msgtext) ) if $msgtext !~ m{\A[\b]*$tocheck[\b]*\z}i; - $msgtext =~ s{\A[\b]*$tocheck}{}i; + return AnalyzePerlCommand( undef, Babble_DoIt($hash->{Babble},$msgtext) ) if $msgtext !~ m{\A[\b]*$tocheck[\b]*\z}ix; + $msgtext =~ s{\A[\b]*$tocheck}{}ix; } return ttsDialog_open($hash, $client, $msgtext); } @@ -2737,7 +2739,7 @@ sub activateVoiceInput { if ($base =~ m{\b(default|base)(?:[\b]|\Z)}xms) { $base = $1; } else { - $base = (split m{,}, $base)[0]; + $base = (split m{,}x, $base)[0]; } my $siteId = $h->{siteId} // shift @{$anon} // $base; my $hotword = $h->{hotword} // shift @{$anon} // $h->{modelId} // "$hash->{LANGUAGE}$hash->{fhemId}"; @@ -2832,7 +2834,7 @@ sub testmode_next { } if ( $hash->{testline} < @{$hash->{helper}->{test}->{content}} ) { - my @ca_strings = split m{,}, ReadingsVal($hash->{NAME},'intents',''); + my @ca_strings = split m{,}x, ReadingsVal($hash->{NAME},'intents',''); my $sendData = { input => $line, sessionId => "$hash->{siteId}_$hash->{testline}_testmode", @@ -2907,13 +2909,13 @@ sub testmode_parse { $result = "$line => $intent $json"; } $hash->{helper}->{test}->{result}->[$hash->{testline}] = $result; - if (ref $dispatchFns->{$intent} eq 'CODE' && $intent =~m{\ASetOnOffGroup|SetColorGroup|SetNumericGroup|SetTimedOnOffGroup\z}) { + if (ref $dispatchFns->{$intent} eq 'CODE' && $intent =~m{\ASetOnOffGroup|SetColorGroup|SetNumericGroup|SetTimedOnOffGroup\z}xms) { my $devices = getDevicesByGroup($hash, $data); $result = ref $devices ne 'HASH' || !keys %{$devices} ? q{can't identify any device in group and room} : join q{,}, keys %{$devices}; $hash->{helper}->{test}->{result}->[$hash->{testline}] .= " => Devices in group and room: $result"; - } elsif (ref $dispatchFns->{$intent} eq 'CODE' && $intent =~m{\AGetOnOff|GetNumeric|GetState|GetTime|GetDate|MediaControls|SetNumeric|SetOnOff|SetTimedOnOff|SetScene|SetColor|SetTimer|MediaChannels|Shortcuts\z}) { + } elsif (ref $dispatchFns->{$intent} eq 'CODE' && $intent =~m{\AGetOnOff|GetNumeric|GetState|GetTime|GetDate|MediaControls|SetNumeric|SetOnOff|SetTimedOnOff|SetScene|SetColor|SetTimer|MediaChannels|Shortcuts\z}xms) { $result = $dispatchFns->{$intent}->($hash, $data); return; } @@ -2958,7 +2960,7 @@ sub setMsgDialogTimeout { my $timeout = shift // _getDialogueTimeout($hash); my $siteId = $data->{siteId}; - my $identity = (split m{_${siteId}_}, $data->{sessionId},3)[0] // return; + my $identity = (split m{_${siteId}_}x, $data->{sessionId},3)[0] // return; $hash->{helper}{msgDialog}->{$identity}->{data} = $data; resetRegIntTimer( $identity, time + $timeout, \&RHASSPY_msgDialogTimeout, $hash, 0); @@ -2985,7 +2987,7 @@ sub msgDialog_open { my $msgtext = shift // return; my $tocheck = $hash->{helper}->{msgDialog}->{config}->{open}; - $msgtext =~ s{\A[\b]*$tocheck}{}i; + $msgtext =~ s{\A[\b]*$tocheck}{}ix; $msgtext = trim($msgtext); Log3($hash, 5, "msgDialog_open called with $device and (cleaned) $msgtext"); @@ -3101,7 +3103,7 @@ sub setTtsDialogTimeout { my $timeout = shift // _getDialogueTimeout($hash); my $siteId = $data->{siteId}; - my $identity = (split m{_${siteId}_}, $data->{sessionId},3)[0] // return; + my $identity = (split m{_${siteId}_}x, $data->{sessionId},3)[0] // return; $hash->{helper}{ttsDialog}->{$identity}->{data} = $data; resetRegIntTimer( $identity, time + $timeout, \&RHASSPY_ttsDialogTimeout, $hash, 0); @@ -3518,7 +3520,7 @@ sub _getSiteIdbyRoom { my $siteId2 = ReadingsVal($hash->{NAME}, "room2siteId_$siteId", $siteId); for my $id ($siteId2, $siteId) { return $1 if $siteIdList =~ m{\b($id)(?:[,]|\Z)}xmsi; - return $1 if $siteIdList =~ m{\b($id[^,]+)(?:[,]|\Z)}xmsi; + return $1 if $siteIdList =~ m{\b($id[^,]+)(?:[,]|\Z)}xmsi; ##no critic qw(Capture) } return $siteId; } @@ -3612,7 +3614,7 @@ sub updateSlots { for my $device (@devs) { my $attrVal = AttrVal($device, 'genericDeviceType', ''); my $gdtmap = { blind => 'blinds|shutter' , thermometer => 'HumiditySensor' , contact => 'ContactSensor'}; - if ($attrVal eq $gdt || defined $gdtmap->{$gdt} && $attrVal =~ m{\A$gdtmap->{$gdt}\z} ) { + if ($attrVal eq $gdt || defined $gdtmap->{$gdt} && $attrVal =~ m{\A$gdtmap->{$gdt}\z}x ) { push @names, split m{,}x, $hash->{helper}{devicemap}{devices}{$device}->{names}; push @aliases, $hash->{helper}{devicemap}{devices}{$device}->{alias}; push @groupnames, split m{,}x, $hash->{helper}{devicemap}{devices}{$device}->{groups} if defined $hash->{helper}{devicemap}{devices}{$device}->{groups}; @@ -3819,7 +3821,7 @@ sub RHASSPY_ParseHttpResponse { } } if ( $siteIds ) { - my @ids = uniq(split m{,},$siteIds); + my @ids = uniq(split m{,}x,$siteIds); readingsBulkUpdate($hash, 'siteIds', join q{,}, @ids); } } @@ -4419,17 +4421,16 @@ sub handleIntentSetNumeric { my $unit = $data->{Unit}; my $change = $data->{Change}; my $type = $data->{Type}; - my $subType= $data->{Type}; if ( !defined $type && defined $change ){ $type = $internal_mappings->{Change}->{$change}->{Type}; $data->{Type} = $type if defined $type; - $subType = 'desired-temp' if $data->{Type} eq 'temperature'; } + my $subType = $data->{Type} eq 'temperature' ? 'desired-temp' : $data->{Type}; + my $value = $data->{Value}; my $room = getRoomName($hash, $data); - # Gerät über Name suchen, oder falls über Lautstärke ohne Device getriggert wurde das ActiveMediaDevice suchen if ( !defined $device && exists $data->{Device} ) { $device = getDeviceByName($hash, $room, $data->{Device}); @@ -4437,7 +4438,7 @@ sub handleIntentSetNumeric { $device = getActiveDeviceForIntentAndType($hash, $room, 'SetNumeric', $type) // return respond( $hash, $data, getResponse( $hash, 'NoActiveMediaDevice') ); - } else { + } elsif ( !defined $data->{'.DevName'} ) { $device = getDeviceByIntentAndType($hash, $room, 'SetNumeric', $type, $subType); } @@ -4457,7 +4458,7 @@ sub handleIntentSetNumeric { return setDialogTimeout($hash, $data, _getDialogueTimeout($hash), $response, $toActivate); } - my $mapping = getMapping($hash, $device, 'SetNumeric', $type); + my $mapping = getMapping($hash, $device, 'SetNumeric', { type => $type, subType => $subType }); if ( !defined $mapping ) { if ( defined $data->{'.inBulk'} ) { @@ -4546,6 +4547,8 @@ sub handleIntentSetNumeric { $newVal = max( $minVal, $newVal ) if defined $minVal; $newVal = min( $maxVal, $newVal ) if defined $maxVal; $data->{Value} //= $newVal; + $data->{Type} //= $type; + delete $data->{Change} if defined $data->{Change} && $data->{Change} ne 'cmdStop'; #check if confirmation is required return $hash->{NAME} if !defined $data->{'.inBulk'} && !$data->{Confirmation} && getNeedsConfirmation( $hash, $data, 'SetNumeric', $device ); @@ -4743,7 +4746,7 @@ sub handleIntentGetState { $device = getDeviceByName($hash, $room, $device) // return respond( $hash, $data, getResponse($hash, 'NoDeviceFound') ); - if ( $type eq 'scenes' ) { + if ( defined $type && $type eq 'scenes' ) { $response = getResponse( $hash, 'getRHASSPYOptions', $type ); @scenes = values %{$hash->{helper}{devicemap}{devices}{$device}{intents}{SetScene}->{SetScene}}; @scenes = uniq(@scenes) if @scenes; @@ -4810,7 +4813,7 @@ sub handleIntentMediaControls { return respond( $hash, $data, getResponse($hash, 'NoMappingFound') ) if !defined $mapping->{$command}; #check if confirmation is required - return $hash->{NAME} if !$data->{Confirmation} && getNeedsConfirmation( $hash, $data, 'MediaControls' ); + return $hash->{NAME} if !$data->{Confirmation} && getNeedsConfirmation( $hash, $data, 'MediaControls', $device ); my $cmd = $mapping->{$command}; # Execute Cmd analyzeAndRunCmd($hash, $device, $cmd); @@ -4863,7 +4866,7 @@ sub handleIntentSetScene{ return respond( $hash, $data, getResponse( $hash, 'NoValidData' ) ) if !$device || !defined $mapping; #check if confirmation is required - return $hash->{NAME} if !$data->{Confirmation} && getNeedsConfirmation( $hash, $data, 'SetScene' ); + return $hash->{NAME} if !$data->{Confirmation} && getNeedsConfirmation( $hash, $data, 'SetScene', $device ); my $cmd = qq(scene $scene); $cmd = $scene if $scene eq 'cmdBack' || $scene eq 'cmdFwd'; @@ -4885,7 +4888,7 @@ sub handleIntentGetTime { my $data = shift // return; Log3($hash->{NAME}, 5, "handleIntentGetTime called"); - (my $sec,my $min,my $hour,my $mday,my $mon,my $year,my $wday,my $yday,my $isdst) = localtime; + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime; my $response = getResponse( $hash, 'timeRequest' ); $response =~ s{(\$\w+)}{$1}eegx; Log3($hash->{NAME}, 5, "Response: $response"); @@ -4940,7 +4943,7 @@ sub handleIntentMediaChannels { my $cmd = $hash->{helper}{devicemap}{devices}{$device}{Channels}{$channel} // return respond( $hash, $data, getResponse($hash, 'NoMediaChannelFound') ); #check if confirmation is required - return $hash->{NAME} if !$data->{Confirmation} && getNeedsConfirmation( $hash, $data, 'MediaChannels' ); + return $hash->{NAME} if !$data->{Confirmation} && getNeedsConfirmation( $hash, $data, 'MediaChannels', $device ); # Cmd ausführen analyzeAndRunCmd($hash, $device, $cmd); @@ -4984,7 +4987,7 @@ sub handleIntentSetColor { return respond( $hash, $data, getResponse( $hash, 'NoDeviceFound' ) ) if !defined $device; #check if confirmation is required - return $hash->{NAME} if !defined $data->{'.inBulk'} && !$data->{Confirmation} && getNeedsConfirmation( $hash, $data, 'SetColor' ); + return $hash->{NAME} if !defined $data->{'.inBulk'} && !$data->{Confirmation} && getNeedsConfirmation( $hash, $data, 'SetColor', $device ); if ( defined $cmd || defined $cmd2 ) { $response = getResponse($hash, 'DefaultConfirmation'); @@ -5280,7 +5283,7 @@ sub handleIntentTimer { if ( !defined $soundoption ) { CommandDefMod($hash, "-temporary $roomReading at +$attime set $name speak siteId=\"$timerRoom\" text=\"$responseEnd\";deletereading $name ${roomReading}$addtrigger"); } else { - $soundoption =~ m{((?[0-9]*)[:]){0,1}((?[0-9.]*)[:]){0,1}(?(.+))}x; + $soundoption =~ m{((?[0-9]*)[:]){0,1}((?[0-9.]*)[:]){0,1}(?(.+))}x; ##no critic qw(Capture) my $file = $+{file} // Log3($hash->{NAME}, 2, "no WAV file for $label provided, check attribute rhasspyTweaks (item timerSounds)!") && return respond( $hash, $data, getResponse( $hash, 'DefaultError' ) ); my $repeats = $+{repeats} // 5; my $duration = $+{duration} // 15; @@ -5351,7 +5354,7 @@ sub handleIntentNotRecognized { Log3( $hash, 5, "[$hash->{NAME}] handleIntentNotRecognized called, input is $data->{input}" ); my $identity = qq($data->{sessionId}); my $siteId = $hash->{siteId}; - my $msgdev = (split m{_${siteId}_}, $identity,3)[0]; + my $msgdev = (split m{_${siteId}_}x, $identity,3)[0]; if ($msgdev) { $data->{text} = getResponse( $hash, 'NoIntentRecognized' ); @@ -5685,14 +5688,14 @@ sub _toCleanJSON { return $data if ref $data ne 'HASH'; my $json = toJSON($data); - $json =~ s{(":"(true|false)")}{": $2}gms; - $json =~ s{(":"null")}{": null}gms; - $json =~ s{":"}{": "}gms; + $json =~ s{(":"(true|false|null)")}{": $2}gxms; + #$json =~ s{(":"null")}{": null}gms; + $json =~ s{":"}{": "}gxms; $json =~ s{("enable": (?:false|true)),("intentId": "[^"]+")}{$2,$1}gms; return $json; } -sub _round { int( $_[0] + ( $_[0] < 0 ? -.5 : .5 ) ); } +sub _round { int( $_[0] + ( $_[0] < 0 ? -.5 : .5 ) ); } ##no critic qw(return unpack) sub _toregex { my $toclean = shift // return; @@ -5703,7 +5706,7 @@ sub _toregex { sub _shuffle_answer { my $txts = shift // return; - my @arr = split m{\|}, $txts; + my @arr = split m{\|}x, $txts; return $arr[ rand @arr ]; } @@ -5740,7 +5743,10 @@ __END__ - v.a. auch kontinuierliche Dialoge/Rückfragen, wann Input aufmachen # auto-training -Tests/Rückmeldungen fehlen bisher; sieht nicht funktional aus... +Erste Tests laufen; sieht teilweise funktional aus... + +# mehr wie ein Device? + =end ToDo