2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-02-25 22:15:09 +00:00

36_Shelly.pm:bug fix call readingsBegin/EndUpdate in sub()

git-svn-id: https://svn.fhem.de/fhem/trunk@28128 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
Starkstrombastler 2023-11-05 17:40:58 +00:00
parent 13765f7d01
commit a6854b4479

View File

@ -36,6 +36,7 @@
# Bug Fix: update interval of GetStatus call # Bug Fix: update interval of GetStatus call
# 5.04 Bug Fix: undefined values on restart # 5.04 Bug Fix: undefined values on restart
# Energymeter activated # Energymeter activated
# 5.05 Bug Fix: Begin/End-Update in sub ()
package main; package main;
@ -50,7 +51,7 @@ use vars qw{%attr %defs};
sub Log($$); sub Log($$);
#-- globals on start #-- globals on start
my $version = "5.04 01.11.2023"; my $version = "5.05 05.11.2023";
my $defaultINTERVAL = 60; my $defaultINTERVAL = 60;
my $secndIntervalMulti = 4; # Multiplier for 'long update' my $secndIntervalMulti = 4; # Multiplier for 'long update'
@ -373,7 +374,7 @@ my %shelly_models = (
"shellyproem50" => [1,0,0, 1,1,0], # has two single-phase meter and one relay "shellyproem50" => [1,0,0, 1,1,0], # has two single-phase meter and one relay
"shellypro3em" => [0,0,0, 1,1,0], # has one (1) three-phase meter "shellypro3em" => [0,0,0, 1,1,0], # has one (1) three-phase meter
"shellyprodual" => [0,2,0, 4,1,4], "shellyprodual" => [0,2,0, 4,1,4],
"walldisplay1" => [1,0,0, 0,1,1] # similar to ShellyPlus1PM "walldisplay1" => [1,0,0, 0,2,1] # similar to ShellyPlus1PM
); );
my %shelly_events = ( # events, that can be used by webhooks; key is mode, value is shelly-event my %shelly_events = ( # events, that can be used by webhooks; key is mode, value is shelly-event
@ -456,9 +457,9 @@ my %fhem_events = ( # events, that can be used by webhooks; key is shelly-event,
"input.button_doublepush" => "double_push", "input.button_doublepush" => "double_push",
"input.button_triplepush" => "triple_push", "input.button_triplepush" => "triple_push",
#touch #touch
"input.touch_swipe_up" => "swipe_up", "input.touch_swipe_up" => "touch_up",
"input.touch_swipe_down" => "swipe_down", "input.touch_swipe_down" => "touch_down",
"input.touch_multi_touch" => "multi_touch", "input.touch_multi_touch" => "touch_multi",
#emeter #emeter
"em.active_power_change" => "Active_Power", "em.active_power_change" => "Active_Power",
"em.voltage_change" => "Voltage", "em.voltage_change" => "Voltage",
@ -879,13 +880,13 @@ sub Shelly_get_model {
$AttrList =~ s/\smaxpower//; $AttrList =~ s/\smaxpower//;
} }
if( $shelly_models{$model}[3]==0 ){ #no metering, eg. shellyi3 if($shelly_models{$model}[3]==0 ){ #no metering, eg. shellyi3 but we have units for RSSI
$AttrList =~ s/$attributes{'metering'}/""/e; $AttrList =~ s/$attributes{'metering'}/""/e;
if( $model eq "shellyuni" || $model =~ /walldisplay/ ){ # if( $model eq "shellyuni" || $model =~ /walldisplay/ ){
$AttrList =~ s/$attributes{'showunits'}/" showunits:none,original"/e; # shellyuni measures voltage $AttrList =~ s/$attributes{'showunits'}/" showunits:none,original"/e; # shellyuni measures voltage
}else{ # }else{
$AttrList =~ s/$attributes{'showunits'}/""/e; # $AttrList =~ s/$attributes{'showunits'}/""/e;
} # }
} }
if( $shelly_models{$model}[5] <= 0 ){ #no inputs, but buttons, eg. shellyplug if( $shelly_models{$model}[5] <= 0 ){ #no inputs, but buttons, eg. shellyplug
@ -1373,7 +1374,7 @@ sub Shelly_Attr(@) {
$hash->{CMD}="Delete"; $hash->{CMD}="Delete";
}else{ #processing set commands, and init is done }else{ #processing set commands, and init is done
Log3 $name,3,"[Shelly_Attr:webhook] $name command is $cmd, attribute webhook old: ".AttrVal($name,"webhook","NoVal")." new: $attrVal"; Log3 $name,3,"[Shelly_Attr:webhook] $name command is $cmd, attribute webhook old: ".AttrVal($name,"webhook","NoVal")." new: $attrVal";
if( $shelly_models{$model}[4] != 1 && $init_done && $model ne "shellybulb" ){ # only for 2nd-Generation devices if( $shelly_models{$model}[4]==0 && $init_done && $model ne "shellybulb" ){ # only for 2nd-Generation devices
$error="Setting the webhook attribute only works for 2nd-Generation devices"; $error="Setting the webhook attribute only works for 2nd-Generation devices";
Log3 $name,3,"[Shelly_Attr:webhook] device $name is a $model. $error."; Log3 $name,3,"[Shelly_Attr:webhook] device $name is a $model. $error.";
return $error; return $error;
@ -1459,7 +1460,7 @@ sub Shelly_Get ($@) {
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $v; my $v;
Log3 $name,4,"[Shelly_Get] receiving command get $name ".$a[1].($a[2]?" ".$a[2]:"") ; Log3 $name,6,"[Shelly_Get] receiving command get $name ".$a[1].($a[2]?" ".$a[2]:"") ;
my $model = AttrVal($name,"model","generic"); my $model = AttrVal($name,"model","generic");
my $mode = AttrVal($name,"mode",""); my $mode = AttrVal($name,"mode","");
@ -1484,7 +1485,7 @@ sub Shelly_Get ($@) {
#-- some help on registers #-- some help on registers
}elsif($a[1] eq "registers") { }elsif($a[1] eq "registers") {
return "Please get registers of 2nd-Gen devices via Shelly-App or homepage of the Shelly" return "Please get registers of 2nd-Gen devices via Shelly-App or homepage of the Shelly"
if( $shelly_models{$model}[4]==1 ); # at the moment, we do not handle registers of Gen2-Devices -> ToDo if( $shelly_models{$model}[4]>=1 ); # at the moment, we do not handle registers of Gen2-Devices -> ToDo
my ($txt,$txt2); my ($txt,$txt2);
if( ($model =~ /shelly2.*/) && ($mode eq "roller") ){ if( ($model =~ /shelly2.*/) && ($mode eq "roller") ){
$txt = "roller"; $txt = "roller";
@ -1508,7 +1509,7 @@ sub Shelly_Get ($@) {
#-- configuration register #-- configuration register
}elsif($a[1] eq "config") { }elsif($a[1] eq "config") {
return "Please set/get configuration of 2nd-Gen devices via Shelly-App or homepage of the Shelly" return "Please set/get configuration of 2nd-Gen devices via Shelly-App or homepage of the Shelly"
if( $shelly_models{$model}[4]==1 ); # at the moment, we do not handle configuration of Gen2-Devices -> ToDo if( $shelly_models{$model}[4]>=1 ); # at the moment, we do not handle configuration of Gen2-Devices -> ToDo
my $reg = $a[2]; my $reg = $a[2];
my ($val,$chan); my ($val,$chan);
if( int(@a) == 4 ){ if( int(@a) == 4 ){
@ -1593,7 +1594,8 @@ sub Shelly_Set ($@) {
my $mode = AttrVal($name,"mode",""); my $mode = AttrVal($name,"mode","");
my ($channel,$time); my ($channel,$time);
Log3 $name,5,"[Shelly_Set] calling for device $name with command $cmd".( defined($value)?" and value $value":", without value" ); Log3 $name,5,"[Shelly_Set] calling for device $name with command $cmd".( defined($value)?" and value $value":", without value" )
if(defined($value));
#-- WEB asking for command list #-- WEB asking for command list
if( $cmd eq "?" ) { if( $cmd eq "?" ) {
@ -1614,7 +1616,7 @@ sub Shelly_Set ($@) {
}elsif( $model =~ /shelly(rgbw|bulb).*/ && $mode eq "color" ){ }elsif( $model =~ /shelly(rgbw|bulb).*/ && $mode eq "color" ){
$newkeys .= " ".join(" ", sort keys %setsrgbwc) ; $newkeys .= " ".join(" ", sort keys %setsrgbwc) ;
} }
if(0 && $shelly_models{$model}[0]>0 && $shelly_models{$model}[4]==1 ){ if(0 && $shelly_models{$model}[0]>0 && $shelly_models{$model}[4]>=1 ){
# xx-for-timer does not work # xx-for-timer does not work
$newkeys =~ s/on-for-timer//; $newkeys =~ s/on-for-timer//;
$newkeys =~ s/off-for-timer//; $newkeys =~ s/off-for-timer//;
@ -1627,7 +1629,7 @@ sub Shelly_Set ($@) {
#-- following commands do not occur in command list, eg. out_on, input_on, single_push #-- following commands do not occur in command list, eg. out_on, input_on, single_push
#-- command received via web to register local changes of the device #-- command received via web to register local changes of the device
if( $cmd =~ /^(out|button|input|single|double|triple|long|voltage|temperature|humidity|Active_Power|Voltage|Current)_(on|off|push|over|under|a|b|c|changed)/ if( $cmd =~ /^(out|button|input|single|double|triple|long|touch|voltage|temperature|humidity|Active_Power|Voltage|Current)_(on|off|push|up|down|multi|over|under|a|b|c|changed)/
|| $cmd =~ /^(stopped|opening|closing|is_open|is_closed)/ ){ || $cmd =~ /^(stopped|opening|closing|is_open|is_closed)/ ){
my $signal=$1; my $signal=$1;
my $isWhat=$2; my $isWhat=$2;
@ -1660,6 +1662,9 @@ sub Shelly_Set ($@) {
# after a second, the pushbuttons state is back to OFF, call status of inputs # after a second, the pushbuttons state is back to OFF, call status of inputs
RemoveInternalTimer($hash,"Shelly_shelly"); # not Shelly_status RemoveInternalTimer($hash,"Shelly_shelly"); # not Shelly_status
InternalTimer(int(gettimeofday()+1.9), "Shelly_shelly", $hash,0); InternalTimer(int(gettimeofday()+1.9), "Shelly_shelly", $hash,0);
}elsif( $signal eq "touch" ){ # devices with an touch-display
#$subs = ($shelly_models{$model}[5] == 1) ? "" : "_".$value;
readingsBulkUpdateMonitored($hash, "touch", $isWhat, 1 );
}elsif( $signal =~ /^(voltage|temperature|humidity)/ ){ }elsif( $signal =~ /^(voltage|temperature|humidity)/ ){
$subs = defined($value)?"_".$value:"" ; $subs = defined($value)?"_".$value:"" ;
readingsBulkUpdateMonitored($hash,$signal.$subs."_range", $isWhat ); readingsBulkUpdateMonitored($hash,$signal.$subs."_range", $isWhat );
@ -1787,7 +1792,7 @@ sub Shelly_Set ($@) {
readingsSingleUpdate($hash,"name",$newname,1); readingsSingleUpdate($hash,"name",$newname,1);
$newname =~ s/ /%20/g; #spaces not allowed in urls $newname =~ s/ /%20/g; #spaces not allowed in urls
Log3 $name,1,"[Shelly_Set] Renaming $name to $newname"; Log3 $name,1,"[Shelly_Set] Renaming $name to $newname";
if( $shelly_models{$model}[4] == 1 ){ if( $shelly_models{$model}[4]>=1 ){
$cmd="rpc/Sys.SetConfig?config={%22device%22:{%22name%22:%22$newname%22}}" ; $cmd="rpc/Sys.SetConfig?config={%22device%22:{%22name%22:%22$newname%22}}" ;
# {"device" :{" name" : "arg"}} # {"device" :{" name" : "arg"}}
}else{ }else{
@ -2299,17 +2304,17 @@ sub Shelly_pwd($){
##2ndGen devices will answer with "null\R" ##2ndGen devices will answer with "null\R"
if( $cmd eq "update" ){ if( $cmd eq "update" ){
if( $shelly_models{$model}[4] == 1 ){ if( $shelly_models{$model}[4]>=1 ){
$cmd="rpc/Shelly.Update?stage=%22stable%22" ; #beta $cmd="rpc/Shelly.Update?stage=%22stable%22" ; #beta
}else{ }else{
$cmd="ota?update=true"; $cmd="ota?update=true";
} }
}elsif( $cmd eq "reboot" ){ }elsif( $cmd eq "reboot" ){
if( $shelly_models{$model}[4] == 1 ){ if( $shelly_models{$model}[4]>=1 ){
$cmd="rpc/Shelly.Reboot" ; $cmd="rpc/Shelly.Reboot" ;
} }
}elsif( $cmd eq "rc" || $cmd eq "calibrate" ){ }elsif( $cmd eq "rc" || $cmd eq "calibrate" ){
if( $shelly_models{$model}[4] == 1 ){ if( $shelly_models{$model}[4]>=1 ){
$cmd="rpc/Cover.Calibrate?id=0" ; #Gen2 $cmd="rpc/Cover.Calibrate?id=0" ; #Gen2
}elsif( $shelly_models{$model}[1]==1 && AttrVal($name,"mode",undef) eq "roller" ){ }elsif( $shelly_models{$model}[1]==1 && AttrVal($name,"mode",undef) eq "roller" ){
$cmd="roller/0/calibrate"; $cmd="roller/0/calibrate";
@ -2350,16 +2355,19 @@ sub Shelly_pwd($){
if( $cmd eq "settings/" ){ if( $cmd eq "settings/" ){
$hash->{SHELLYID} = $jhash->{'device'}{'hostname'}; $hash->{SHELLYID} = $jhash->{'device'}{'hostname'};
return return
}elsif( $cmd =~ /ota/ ){ # ota?update=true
readingsSingleUpdate($hash,"config","updating",1);
return undef;
} }
Log3 $name,4,"[Shelly_configure] device $name processing \"$cmd\" "; Log3 $name,4,"[Shelly_configure] device $name processing \"$cmd\" ";#4
#-- isolate register name #-- isolate register name
my $reg = substr($cmd,index($cmd,"?")+1); my $reg = substr($cmd,index($cmd,"?")+1);
my $chan= substr($cmd,index($cmd,"?")-1,1); my $chan= substr($cmd,index($cmd,"?")-1,1);
$reg = substr($reg,0,index($reg,"=")) $reg = substr($reg,0,index($reg,"="))
if(index($reg,"=") > 0); if(index($reg,"=") > 0);
my $val = $jhash->{$reg}; my $val = $jhash->{$reg};
#Debug "$reg $chan $val";
$chan = $shelly_models{$model}[7] == 1 ? "" : "[channel $chan]"; $chan = $shelly_models{$model}[7] == 1 ? "" : "[channel $chan]";
if( defined($val) ){ if( defined($val) ){
@ -2411,7 +2419,7 @@ sub Shelly_status {
} }
#-- check if 2nd generation device #-- check if 2nd generation device
my $is2G = ($shelly_models{$model}[4] == 1); my $is2G = ($shelly_models{$model}[4]>=1);
#3G { #3G {
# preparing NonBlockingGet #-------------------------------------------------- # preparing NonBlockingGet #--------------------------------------------------
@ -2478,7 +2486,8 @@ sub Shelly_status {
if( !$jhash ){ if( !$jhash ){
Shelly_error_handling($hash,"Shelly_status","invalid JSON data"); Shelly_error_handling($hash,"Shelly_status","invalid JSON data");
return; return;
}elsif(ReadingsVal($name,"network","") !~ /connected to/){ # }elsif(ReadingsVal($name,"network","") !~ /connected to/){
}else{
# as we have received a valid JSON, we know network is connected: # as we have received a valid JSON, we know network is connected:
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
readingsBulkUpdateIfChanged($hash,"network","<html>connected to <a href=\"http://".$hash->{TCPIP}."\">".$hash->{TCPIP}."</a></html>",1); readingsBulkUpdateIfChanged($hash,"network","<html>connected to <a href=\"http://".$hash->{TCPIP}."\">".$hash->{TCPIP}."</a></html>",1);
@ -2532,7 +2541,7 @@ sub Shelly_shelly {
Log3 $name,4,"[Shelly_shelly] $name is a ".($shelly_models{$model}[4]==0?"first":"second")." Gen device"; Log3 $name,4,"[Shelly_shelly] $name is a ".($shelly_models{$model}[4]==0?"first":"second")." Gen device";
#-- check if 2nd generation device #-- check if 2nd generation device
if ($shelly_models{$model}[4] != 1){ if( $shelly_models{$model}[4]==0 ){
Log3 $name,4,"[Shelly_shelly] intentionally aborting, $name is not 2nd Gen"; Log3 $name,4,"[Shelly_shelly] intentionally aborting, $name is not 2nd Gen";
return undef ; return undef ;
} }
@ -2616,8 +2625,7 @@ sub Shelly_proc1G {
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
Shelly_readingsBulkUpdate($hash,"network","<html>connected to <a href=\"http://".$hash->{TCPIP}."\">".$hash->{TCPIP}."</a></html>",1); Shelly_readingsBulkUpdate($hash,"network","<html>connected to <a href=\"http://".$hash->{TCPIP}."\">".$hash->{TCPIP}."</a></html>",1);
readingsBulkUpdateMonitored($hash,"network_rssi",$jhash->{'wifi_sta'}{'rssi'} ) readingsBulkUpdateMonitored($hash,"network_rssi",Shelly_rssi($hash,$jhash->{'wifi_sta'}{'rssi'}) );
if( $jhash->{'wifi_sta'}{'rssi'} );
readingsBulkUpdateMonitored($hash,"network_ssid",$jhash->{'wifi_sta'}{'ssid'} ) readingsBulkUpdateMonitored($hash,"network_ssid",$jhash->{'wifi_sta'}{'ssid'} )
if( $jhash->{'wifi_sta'}{'ssid'} ); if( $jhash->{'wifi_sta'}{'ssid'} );
@ -3045,7 +3053,7 @@ sub Shelly_proc2G {
my $timer = $hash->{INTERVAL}; my $timer = $hash->{INTERVAL};
# check we have a second gen device # check we have a second gen device
if( $shelly_models{$model}[4]!=1 ){ if( $shelly_models{$model}[4]==0 ){
return "ERROR: calling Proc2G for a not 2ndGen Device"; return "ERROR: calling Proc2G for a not 2ndGen Device";
} }
@ -3054,7 +3062,7 @@ sub Shelly_proc2G {
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
if($shelly_models{$model}[0]>1 && ($shelly_models{$model}[1]==0 || $mode eq "relay")){ if($shelly_models{$model}[0]>1 && ($shelly_models{$model}[1]==0 || $mode eq "relay")){
readingsBulkUpdate($hash,"state","OK",1); #set state for mulitchannel relay-devices; for rollers state is 'stopped' or 'drive...' readingsBulkUpdate($hash,"state","OK",1); #set state for multichannel relay-devices; for rollers state is 'stopped' or 'drive...'
} }
############retrieving the relay state for relay <id> ############retrieving the relay state for relay <id>
if( $shelly_models{$model}[0]>0 && $comp eq "relay"){ if( $shelly_models{$model}[0]>0 && $comp eq "relay"){
@ -3070,7 +3078,6 @@ sub Shelly_proc2G {
readingsBulkUpdateMonitored($hash,"state",($shelly_models{$model}[0] == 1)?$ison:"OK"); readingsBulkUpdateMonitored($hash,"state",($shelly_models{$model}[0] == 1)?$ison:"OK");
############retrieving the roller state and position ############retrieving the roller state and position
}elsif( $rollers>0 && $comp eq "roller") { }elsif( $rollers>0 && $comp eq "roller") {
Log3 $name,4,"[Shelly_proc2G:roller] Processing roller state for device $name (we have $rollers rollers)"; Log3 $name,4,"[Shelly_proc2G:roller] Processing roller state for device $name (we have $rollers rollers)";
@ -3220,10 +3227,7 @@ if(0){ # check calculation of reactive power!
$ison =~ s/1|(true)/on/; $ison =~ s/1|(true)/on/;
readingsBulkUpdateMonitored($hash,"input".$subs,$ison); readingsBulkUpdateMonitored($hash,"input".$subs,$ison);
}elsif( $comp eq "status" ){ }elsif( $comp eq "status" ){
Log3 $name,6,"[Shelly_proc2G:status] Processing status for device $name L.3181";
#processing the answer rpc/Shelly.GetStatus from shelly_shelly(): #processing the answer rpc/Shelly.GetStatus from shelly_shelly():
Log3 $name,4,"[Shelly_proc2G:status] $name: Processing the answer rpc/Shelly.GetStatus from Shelly_shelly()"; Log3 $name,4,"[Shelly_proc2G:status] $name: Processing the answer rpc/Shelly.GetStatus from Shelly_shelly()";
# in this section we read (as far as available): # in this section we read (as far as available):
@ -3242,7 +3246,7 @@ if(0){ # check calculation of reactive power!
#Note: check if cloud is allowed will result from configuration #Note: check if cloud is allowed will result from configuration
if(ReadingsVal($name,"cloud","none") !~ /disabled/){ if(ReadingsVal($name,"cloud","none") !~ /disabled/){
my $hasconn = ($jhash->{'cloud'}{'connected'}); my $hasconn = ($jhash->{'cloud'}{'connected'});
Log3 $name,5,"[Shelly_proc2G] $name: hasconn=" . ($hasconn?"true":"false"); Log3 $name,5,"[Shelly_proc2G:status] $name: hasconn=" . ($hasconn?"true":"false");
$hasconn = $hasconn ? "connected" : "not connected"; $hasconn = $hasconn ? "connected" : "not connected";
readingsBulkUpdateIfChanged($hash,"cloud","enabled($hasconn)"); readingsBulkUpdateIfChanged($hash,"cloud","enabled($hasconn)");
} }
@ -3254,46 +3258,45 @@ if(0){ # check calculation of reactive power!
# /rpc/Shelly.GetStatus/sys:available_updates:beta:version only when there is a beta version # /rpc/Shelly.GetStatus/sys:available_updates:beta:version only when there is a beta version
# /rpc/Shelly.GetStatus/available_updates {} # /rpc/Shelly.GetStatus/available_updates {}
my $update = $jhash->{'sys'}{'available_updates'}{'stable'}{'version'}; my $update = $jhash->{'sys'}{'available_updates'}{'stable'}{'version'};
my $firmware = ReadingsVal($name,"firmware","none"); my $firmware = ReadingsVal($name,"firmware","none"); # eg 1.2.5(update....
$firmware = $1 if( $firmware =~ /^(.*?)\(/ ){
if( $firmware =~ /^(.*?)\(/ ); $firmware = $1;
}
my $txt = ($firmware =~ /beta/ )?"update possible to latest stable v":"update needed to v"; my $txt = ($firmware =~ /beta/ )?"update possible to latest stable v":"update needed to v";
if( $update ){ if( $update ){ #stable
Log3 $name,5,"[Shelly_proc2G] $name: $txt$update current in device: $firmware"; Log3 $name,5,"[Shelly_proc2G:status] $name: $txt$update current in device: $firmware";
$firmware .= "($txt$update)"; $firmware .= "($txt$update)";
readingsBulkUpdateIfChanged($hash,"firmware",$firmware); readingsBulkUpdateIfChanged($hash,"firmware",$firmware);
}else{ # maybe there is a beta version available }else{ # maybe there is a beta version available
$update = $jhash->{'sys'}{'available_updates'}{'beta'}{'version'}; $update = $jhash->{'sys'}{'available_updates'}{'beta'}{'version'};
if( $update ){ if( $update ){
Log3 $name,5,"[Shelly_proc2G] $name: $firmware --> $update"; Log3 $name,5,"[Shelly_proc2G:status] $name: $firmware --> $update beta";
$firmware .= "(update possible to v$update)"; $firmware .= "(update possible to v$update beta)";
readingsBulkUpdateIfChanged($hash,"firmware",$firmware); readingsBulkUpdateIfChanged($hash,"firmware",$firmware);
} }
} }
#checking if connected to wifi / LAN #checking if connected to wifi / LAN
#is similiar given as answer to rpc/Wifi.GetStatus #is similiar given as answer to rpc/Wifi.GetStatus
my $eth_ip = $jhash->{'eth'}{'ip'};
my $local_ip = $jhash->{'wifi'}{'sta_ip'}; my $eth_ip = $jhash->{'eth'}{'ip'} ? $jhash->{'eth'}{'ip'} : "-";
my $wifi_status= $jhash->{'wifi'}{'status'}; my $wifi_ssid = $jhash->{'wifi'}{'ssid'} ? $jhash->{'wifi'}{'ssid'} : "-";
if( $eth_ip ){ my $wifi_rssi = ($jhash->{'wifi'}{'rssi'} ? $jhash->{'wifi'}{'rssi'} : "-");
if( $eth_ip ne "" && $wifi_status eq "got ip" ){ readingsBulkUpdateIfChanged($hash,"network_ssid",$wifi_ssid);
readingsBulkUpdateIfChanged($hash,"network_rssi",Shelly_rssi($hash,$wifi_rssi) );
#my $wifi_status= $jhash->{'wifi'}{'status'}; # sometimes not supported by ShellyWallDisplay fw 1.2.4
if( $eth_ip ne "-" && $wifi_ssid ne "-" ){
readingsBulkUpdateIfChanged($hash,"network","<html>connected to <a href=\"http://".$eth_ip."\">".$eth_ip."</a> (LAN, Wifi)</html>"); readingsBulkUpdateIfChanged($hash,"network","<html>connected to <a href=\"http://".$eth_ip."\">".$eth_ip."</a> (LAN, Wifi)</html>");
}elsif( $eth_ip ne "" ){ }elsif( $eth_ip ne "-" && $wifi_ssid eq "-" ){
Shelly_readingsBulkUpdate($hash,"network","<html>connected to <a href=\"http://".$eth_ip."\">".$eth_ip."</a> (LAN)</html>"); readingsBulkUpdateIfChanged($hash,"network","<html>connected to <a href=\"http://".$eth_ip."\">".$eth_ip."</a> (LAN)</html>");
} }elsif( $eth_ip eq "-" && $wifi_ssid ne "-" ){
}elsif( $local_ip && $wifi_status eq "got ip"){ my $wifi_ip = $jhash->{'wifi'}{'sta_ip'};
readingsBulkUpdateIfChanged($hash,"network","<html>connected to <a href=\"http://".$local_ip."\">".$local_ip."</a> (Wifi)</html>"); readingsBulkUpdateIfChanged($hash,"network","<html>connected to <a href=\"http://".$wifi_ip."\">".$wifi_ip."</a> (Wifi)</html>");
}else{ }else{
Shelly_error_handling($hash,"Shelly_proc2G:status","not connected"); Shelly_error_handling($hash,"Shelly_proc2G:status","not connected");
} }
if( $wifi_status eq "got ip"){ Log3 $name,4,"[Shelly_proc2G:status] $name ethernet=$eth_ip,wifi=$wifi_ssid @ $wifi_rssi";
readingsBulkUpdateIfChanged($hash,"network_ssid",$jhash->{'wifi'}{'ssid'});
readingsBulkUpdateIfChanged($hash,"network_rssi",$jhash->{'wifi'}{'rssi'}.$si_units{rssi}[$hash->{units}]);
}else{ # if( $wifi_status eq "disconnected"){
readingsBulkUpdateIfChanged($hash,"network_ssid",'-');
readingsBulkUpdateIfChanged($hash,"network_rssi",'-');
}
#Inputs in button-mode (Taster) CANNOT be read out! #Inputs in button-mode (Taster) CANNOT be read out!
#Inputs of cover devices are strongly attached to the device. #Inputs of cover devices are strongly attached to the device.
@ -3483,7 +3486,7 @@ sub Shelly_EMData {
my $model = AttrVal($name,"model","generic"); my $model = AttrVal($name,"model","generic");
# check we have a second gen device # check we have a second gen device
if( $shelly_models{$model}[4]!=1 || $model ne "shellypro3em" ){ if( $shelly_models{$model}[4]==0 || $model ne "shellypro3em" ){
return "$name ERROR: calling Proc2G for a not 2ndGen Device"; return "$name ERROR: calling Proc2G for a not 2ndGen Device";
} }
@ -4036,12 +4039,12 @@ sub Shelly_interval($){
if ( $hash && !$err && !$data ){ if ( $hash && !$err && !$data ){
my $callback; my $callback;
my $url = "http://$creds".$hash->{TCPIP}; my $url = "http://$creds".$hash->{TCPIP};
if(1){ if($shelly_models{$model}[4]<2){
$url .= "/relay/$channel$cmd"; $url .= "/relay/$channel$cmd";
$callback="/relay/$channel$cmd"; $callback="/relay/$channel$cmd";
}else{ }else{ # eg Wall-Display
$cmd =~ /(id=\d)/; $cmd =~ /\?id=(\d)/;
$callback= $url."/rpc/Switch.GetStatus?$1"; $callback = $url."/rpc/Switch.GetStatus?id=".$1;
$url .= $cmd; $url .= $cmd;
} }
Log3 $name,4,"[Shelly_onoff] issue a non-blocking call to $url; callback to Shelly_onoff with command $callback"; Log3 $name,4,"[Shelly_onoff] issue a non-blocking call to $url; callback to Shelly_onoff with command $callback";
@ -4072,9 +4075,12 @@ if(1){
return; return;
} }
my $onofftimer = 0;
if( $jhash->{'was_on'} ){
my $was_on = $jhash->{'was_on'};
}else{
my $ison = $jhash->{'ison'}; my $ison = $jhash->{'ison'};
my $hastimer = undef; my $hastimer = undef;
my $onofftimer = 0;
my $timerstr = "-"; my $timerstr = "-";
my $source = $jhash->{'source'}; my $source = $jhash->{'source'};
my $overpower = $jhash->{'overpower'}; my $overpower = $jhash->{'overpower'};
@ -4117,6 +4123,7 @@ if(1){
readingsBulkUpdateMonitored($hash,"overpower".$subs,$overpower) readingsBulkUpdateMonitored($hash,"overpower".$subs,$overpower)
if( $shelly_models{$model}[3]>0 && $model ne "shelly1" ); if( $shelly_models{$model}[3]>0 && $model ne "shelly1" );
readingsEndUpdate($hash,1); readingsEndUpdate($hash,1);
} #------
#-- Call status after switch. #-- Call status after switch.
if( $hash->{INTERVAL}>0 ){ if( $hash->{INTERVAL}>0 ){
@ -4176,10 +4183,10 @@ if(1){
Log3 $name,7,"[Shelly_webhook] device $name will be called by Webhook."; Log3 $name,7,"[Shelly_webhook] device $name will be called by Webhook.";
my $URL = "http://$creds".$hash->{TCPIP}; my $URL = "http://$creds".$hash->{TCPIP};
$URL .=($gen?"/rpc/Webhook.":"/settings/actions"); #Gen2 : Gen1 $URL .=($gen>=1?"/rpc/Webhook.":"/settings/actions"); #Gen2 : Gen1
if( $cmd eq "Create" ){ if( $cmd eq "Create" ){
$URL .= "Create" if( $gen == 1 ); $URL .= "Create" if( $gen >= 1 );
}elsif( $cmd eq "Update" ){ }elsif( $cmd eq "Update" ){
$URL .= "Update?id=1"; $URL .= "Update?id=1";
}elsif( $cmd eq "Delete" ){ }elsif( $cmd eq "Delete" ){
@ -4276,14 +4283,14 @@ if(1){
# only first emeter-action (activ power) is enabled # only first emeter-action (activ power) is enabled
$URL =~ s/enable\=true/enable\=false/ if( $e > 0 ); $URL =~ s/enable\=true/enable\=false/ if( $e > 0 );
} }
} if($name eq "Y199"){Debug $URL.$urls;}else{ }
Log3 $name,5,"[Shelly_webhook] $name $cmd component=$element count=$c event=$e"; Log3 $name,5,"[Shelly_webhook] $name $cmd component=$element count=$c event=$e";
Log3 $name,5,"[Shelly_webhook] issue a non-blocking call to \n$URL$urls"; Log3 $name,5,"[Shelly_webhook] issue a non-blocking call to \n$URL$urls";
HttpUtils_NonblockingGet({ HttpUtils_NonblockingGet({
url => $URL.$urls, url => $URL.$urls,
timeout => $timeout, timeout => $timeout,
callback => sub($$$){ Shelly_webhook($hash,$cmd,$_[1],$_[2]) } callback => sub($$$){ Shelly_webhook($hash,$cmd,$_[1],$_[2]) }
}); } }); # }
} }
} }
} }
@ -4524,9 +4531,9 @@ sub Shelly_webhookurl ($@) {
my ($gen,$urls_pre,$urls_part1,$urls_post); my ($gen,$urls_pre,$urls_part1,$urls_post);
my $model = AttrVal($name,"model","generic"); my $model = AttrVal($name,"model","generic");
$gen = $shelly_models{$model}[4]; # 0 is Gen1, 1 is Gen2 $gen = $shelly_models{$model}[4]; # 0 is Gen1, 1 is Gen2
$urls_pre = ($gen?"&urls=[%22":"&urls[]="); # Gen2 : Gen1 $urls_pre = ($gen>=1?"&urls=[%22":"&urls[]="); # Gen2 : Gen1
$urls_part1=$host_url; $urls_part1=$host_url;
$urls_post= ($gen?"%22]":""); $urls_post= ($gen>=1?"%22]":"");
#-- building the command for fhem #-- building the command for fhem
@ -4558,6 +4565,21 @@ sub Shelly_webhookurl ($@) {
} }
sub Shelly_rssi {
my ($hash, $rssi) = @_;
if( $rssi eq "-" ) { return "-";}
my $ret = $rssi;
if( $hash->{units} == 1){ $ret .= $si_units{rssi}[1];
if( $rssi < -76 ) { $ret .= " (bad)";}
elsif( $rssi < -55 ) { $ret .= " (fair)";}
elsif( $rssi < -35 ) { $ret .= " (good)";}
else { $ret .= " (excellent)";}
}
Log3 $hash->{NAME},5,"[Shelly_rssi] returns $ret to device ".$hash->{NAME};
return $ret;
}
######################################################################################## ########################################################################################
# #
# Shelly_error_handling - handling error from callback functions # Shelly_error_handling - handling error from callback functions
@ -4568,36 +4590,48 @@ sub Shelly_webhookurl ($@) {
sub Shelly_error_handling { sub Shelly_error_handling {
my ($hash, $func, $err) = @_; my ($hash, $func, $err, $verbose) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my ($errN,$errS);
$verbose=1 if( !defined($verbose) );
my $flag=0;
if( $hash->{".updateTime"} ){ # is set by 'readingsBeginUpdate()'
$flag=1;
}else{
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
Log3 $name,2,"[$func] device $name has error \"$err\" "; }
Log3 $name,6,"[$func] device $name has error \"$err\" ";
if( $err =~ /timed out/ ){ if( $err =~ /timed out/ ){
if( $err =~ /read/ ){ if( $err =~ /read/ ){
$err = "Error: Timeout reading"; $errN = "Error: Timeout reading";
}elsif( $err =~ /connect/ ){ }elsif( $err =~ /connect/ ){
$err = "Error: Timeout connecting"; $errN = "Error: Timeout connecting";
}else{ }else{
$err = "Error: Timeout"; $errN = "Error: Timeout";
} }
readingsBulkUpdateIfChanged($hash,"network",$err,1); readingsBulkUpdateIfChanged($hash,"network",$errN,1);
$err = "Error: Network"; $errS = "Error: Network";
}elsif( $err eq "not connected" ){ # from Shelly_proc2G:status }elsif( $err eq "not connected" ){ # from Shelly_proc2G:status
readingsBulkUpdateIfChanged($hash,"network","not connected",1); $errN = $err;
$err = "Error: Network"; #disconnected readingsBulkUpdateIfChanged($hash,"network",$errN,1);
$errS = "Error: Network"; #disconnected
}elsif( $err =~ /113/ ){ # keine Route zum Zielrechner (113) }elsif( $err =~ /113/ ){ # keine Route zum Zielrechner (113)
readingsBulkUpdateIfChanged($hash,"network","not connected (no route)",1); $errN = "not connected (no route)";
$err = "Error: Network"; #disconnected readingsBulkUpdateIfChanged($hash,"network",$errN,1);
$errS = "Error: Network"; #disconnected
}elsif( $err =~ /JSON/ ){ }elsif( $err =~ /JSON/ ){
readingsBulkUpdateIfChanged($hash,"network",$err,1); $errN = $err;
$err = "Error: JSON"; readingsBulkUpdateIfChanged($hash,"network",$errN,1);
$errS = "Error: JSON";
}else{ }else{
$err = "Error"; $errS = "Error";
} }
Log3 $name,1,"[$func] Device $name has Error \'$err\' "; Log3 $name,$verbose,"[$func] Device $name has Error \'$errN\', state is set to \'$errS\' ";
readingsBulkUpdate($hash,"network_disconnects",ReadingsNum($name,"network_disconnects",0)+1) if( ReadingsVal($name,"state","") ne $err ); readingsBulkUpdate($hash,"network_disconnects",ReadingsNum($name,"network_disconnects",0)+1) if( ReadingsVal($name,"state","") ne $errS );
readingsBulkUpdateMonitored($hash,"state",$err, 1 ); readingsBulkUpdateMonitored($hash,"state",$errS, 1 );
if( $flag==0 ){
readingsEndUpdate($hash,1); readingsEndUpdate($hash,1);
}
return undef; return undef;
} }
@ -4622,9 +4656,15 @@ sub
readingsBulkUpdateMonitored($$$@) # derived from fhem.pl readingsBulkUpdateIfChanged() readingsBulkUpdateMonitored($$$@) # derived from fhem.pl readingsBulkUpdateIfChanged()
{ {
my ($hash,$reading,$value,$changed)= @_; my ($hash,$reading,$value,$changed)= @_;
#$changed=0 if( $changed eq undef );
my $MaxAge=AttrVal($hash->{NAME},"maxAge",21600); # default 6h my $MaxAge=AttrVal($hash->{NAME},"maxAge",21600); # default 6h
if( ReadingsAge($hash->{NAME},$reading,$MaxAge)>=$MaxAge || $value ne ReadingsVal($hash->{NAME},$reading,"") ){ if( ReadingsAge($hash->{NAME},$reading,$MaxAge)>=$MaxAge || $value ne ReadingsVal($hash->{NAME},$reading,"") ){ #|| $changed>=1
Log3 $hash->{NAME},6,"$reading: maxAge=$MaxAge ReadingsAge=".ReadingsAge($hash->{NAME},$reading,0)." value=$value ? ".ReadingsVal($hash->{NAME},$reading,""); Log3 $hash->{NAME},3,"$reading: maxAge=$MaxAge ReadingsAge="
.ReadingsAge($hash->{NAME},$reading,0)." new value=$value vs old="
.ReadingsVal($hash->{NAME},$reading,"")
#.($changed?":: $changed":" ::-0-")
;
#$changed=1 if ($changed == 2 );#touch
return readingsBulkUpdate($hash,$reading,$value,$changed); return readingsBulkUpdate($hash,$reading,$value,$changed);
}else{ }else{
return undef; return undef;