2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 09:16:53 +00:00

36_Shelly.pm: Neue Version mit Support für 2nd Generation Shelly. Unerwünschte Effekte noch möglich.

git-svn-id: https://svn.fhem.de/fhem/trunk@25989 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
phenning 2022-04-22 16:04:09 +00:00
parent 2bfc5e528d
commit 2a0598ffc3

View File

@ -3,7 +3,7 @@
# Shelly.pm # Shelly.pm
# #
# FHEM module to communicate with Shelly switch/roller actor devices # FHEM module to communicate with Shelly switch/roller actor devices
# Prof. Dr. Peter A. Henning, 2018 # Prof. Dr. Peter A. Henning, 2022
# #
# $Id$ # $Id$
# #
@ -39,7 +39,7 @@ use vars qw{%attr %defs};
sub Log($$); sub Log($$);
#-- globals on start #-- globals on start
my $version = "3.4"; my $version = "4.0";
#-- these we may get on request #-- these we may get on request
my %gets = ( my %gets = (
@ -109,20 +109,25 @@ my %setsrgbwc = (
); );
my %shelly_models = ( my %shelly_models = (
#(relays,rollers,dimmers,meters) #(relays,rollers,dimmers,meters,NG)
"generic" => [0,0,0,0], "generic" => [0,0,0,0,0],
"shelly1" => [1,0,0,0], "shelly1" => [1,0,0,0,0],
"shelly1pm" => [1,0,0,1], "shelly1pm" => [1,0,0,1,0],
"shelly2" => [2,1,0,1], "shelly2" => [2,1,0,1,0],
"shelly2.5" => [2,1,0,2], "shelly2.5" => [2,1,0,2,0],
"shellyplug" => [1,0,0,1], "shellyplug" => [1,0,0,1,0],
"shelly4" => [4,0,0,4], "shelly4" => [4,0,0,4,0],
"shellyrgbw" => [0,0,4,1], "shellypro4" => [4,0,0,4,0],
"shellydimmer" => [0,0,1,1], "shellyrgbw" => [0,0,4,1,0],
"shellyem" => [1,0,0,2], "shellydimmer" => [0,0,1,1,0],
"shellyem3" => [1,0,0,3], "shellyem" => [1,0,0,2,0],
"shellybulb" => [0,0,1,1], "shelly3em" => [1,0,0,3,0],
"shellyuni" => [2,0,0,1] "shellybulb" => [0,0,1,1,0],
"shellyuni" => [2,0,0,1,0],
#-- 2nd generation devices
"shellyplus1" => [1,0,0,0,1],
"shellyplus1pm" => [1,0,0,1,1],
"shellypro4pm" => [4,0,0,4,1]
); );
my %shelly_regs = ( my %shelly_regs = (
@ -172,7 +177,7 @@ sub Shelly_Define($$) {
return "[Shelly] Define the IP address of the Shelly device as a parameter" return "[Shelly] Define the IP address of the Shelly device as a parameter"
if(@a != 3); if(@a != 3);
return "[Shelly] Invalid IP address ".$a[2]." of Shelly device" return "[Shelly] invalid IP address ".$a[2]." of Shelly"
if( $a[2] !~ m|\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?(\:\d+)?| ); if( $a[2] !~ m|\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?(\:\d+)?| );
my $dev = $a[2]; my $dev = $a[2];
@ -287,7 +292,7 @@ sub Shelly_Attr(@) {
if ( ($cmd eq "set") && ($attrName =~ /model/) ) { if ( ($cmd eq "set") && ($attrName =~ /model/) ) {
my $regex = "((".join(")|(",(keys %shelly_models))."))"; my $regex = "((".join(")|(",(keys %shelly_models))."))";
if( $attrVal !~ /$regex/){ if( $attrVal !~ /$regex/){
Log3 $name,1,"[Shelly_Attr] wrong value of model attribute, see documentation for possible values"; Log3 $name,1,"[Shelly_Attr] wrong value of model attribute for device $name, see documentation for possible values";
return return
} }
if( $model =~ /shelly.*/ ){ if( $model =~ /shelly.*/ ){
@ -348,7 +353,7 @@ sub Shelly_Attr(@) {
#--------------------------------------- #---------------------------------------
}elsif ( ($cmd eq "set") && ($attrName =~ /mode/) ) { }elsif ( ($cmd eq "set") && ($attrName =~ /mode/) ) {
if( defined($model) && $model !~ /shelly(2|(rgb|bulb)).*/){ if( defined($model) && $model !~ /shelly(2|(rgb|bulb)).*/){
Log3 $name,1,"[Shelly_Attr] setting the mode attribute only works for model=shelly2|shelly2.5|shellyrgbw|shellybulb"; Log3 $name,1,"[Shelly_Attr] setting the mode attribute for device $name only works for model=shelly2|shelly2.5|shellyrgbw|shellybulb";
return return
} }
if( $model =~ /shelly2.*/ ){ if( $model =~ /shelly2.*/ ){
@ -356,7 +361,7 @@ sub Shelly_Attr(@) {
fhem("deletereading ".$name." energy.*"); fhem("deletereading ".$name." energy.*");
fhem("deletereading ".$name." overpower.*"); fhem("deletereading ".$name." overpower.*");
if( $attrVal !~ /((relay)|(roller))/){ if( $attrVal !~ /((relay)|(roller))/){
Log3 $name,1,"[Shelly_Attr] wrong mode value $attrVal, must be relay or roller"; Log3 $name,1,"[Shelly_Attr] wrong mode value $attrVal for device $name, must be relay or roller";
return; return;
}elsif( $attrVal eq "relay"){ }elsif( $attrVal eq "relay"){
fhem("deletereading ".$name." position.*"); fhem("deletereading ".$name." position.*");
@ -375,7 +380,7 @@ sub Shelly_Attr(@) {
fhem("deletereading ".$name." energy.*"); fhem("deletereading ".$name." energy.*");
fhem("deletereading ".$name." overpower.*"); fhem("deletereading ".$name." overpower.*");
if( $attrVal !~ /((white)|(color))/){ if( $attrVal !~ /((white)|(color))/){
Log3 $name,1,"[Shelly_Attr] wrong mode value $attrVal, must be white or color"; Log3 $name,1,"[Shelly_Attr] wrong mode value $attrVal for device $name, must be white or color";
return; return;
}elsif( $attrVal eq "color"){ }elsif( $attrVal eq "color"){
fhem("deletereading ".$name." pct.*"); fhem("deletereading ".$name." pct.*");
@ -392,7 +397,7 @@ sub Shelly_Attr(@) {
#--------------------------------------- #---------------------------------------
}elsif ( ($cmd eq "set") && ($attrName eq "maxtime") ) { }elsif ( ($cmd eq "set") && ($attrName eq "maxtime") ) {
if( ($model !~ /shelly2.*/) || ($mode ne "roller" ) ){ if( ($model !~ /shelly2.*/) || ($mode ne "roller" ) ){
Log3 $name,1,"[Shelly_Attr] setting the maxtime attribute only works for model=shelly2/2.5 and mode=roller"; Log3 $name,1,"[Shelly_Attr] setting the maxtime attribute for device $name only works for model=shelly2/2.5 and mode=roller";
return return
} }
Shelly_configure($hash,"settings?maxtime=".$attrVal); Shelly_configure($hash,"settings?maxtime=".$attrVal);
@ -400,7 +405,7 @@ sub Shelly_Attr(@) {
#--------------------------------------- #---------------------------------------
}elsif ( ($cmd eq "set") && ($attrName eq "pct100") ) { }elsif ( ($cmd eq "set") && ($attrName eq "pct100") ) {
if( ($model !~ /shelly2.*/) || ($mode ne "roller" ) ){ if( ($model !~ /shelly2.*/) || ($mode ne "roller" ) ){
Log3 $name,1,"[Shelly_Attr] setting the pct100 attribute only works for model=shelly2/2.5 and mode=roller"; Log3 $name,1,"[Shelly_Attr] setting the pct100 attribute for device $name only works for model=shelly2/2.5 and mode=roller";
return return
} }
@ -411,7 +416,8 @@ sub Shelly_Attr(@) {
if ($init_done) { if ($init_done) {
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "Shelly_status", $hash, 0); InternalTimer(gettimeofday()+$hash->{INTERVAL}, "Shelly_status", $hash, 0)
if( $hash->{INTERVAL} ne "0" );
} }
} }
return return
@ -497,7 +503,7 @@ sub Shelly_Get ($@) {
my $newkeys = join(" ", sort keys %gets); my $newkeys = join(" ", sort keys %gets);
$newkeys =~ s/:noArg//g $newkeys =~ s/:noArg//g
if( $a[1] ne "?"); if( $a[1] ne "?");
return "[Shelly_Get] with unknown argument $a[1], choose one of ".$newkeys; return "[Shelly_Get] for device $name with unknown argument $a[1], choose one of ".$newkeys;
} }
if(defined($v)) { if(defined($v)) {
@ -569,14 +575,16 @@ sub Shelly_Set ($@) {
} }
#-- commands strongly dependent on Shelly type #-- commands strongly dependent on Shelly type
#-- we have a Shelly 1, Uni, 4 or ShellyPlug switch type device ################################################################################################################
#-- we have a Shelly 1, Uni, Shelly 4 or ShellyPlug switch type device
#-- 2nd generation: Weh habe a Shelly 4PM device
#-- or we have a Shelly 2 switch type device #-- or we have a Shelly 2 switch type device
if( ($model =~ /shelly1.*/) || ($model eq "shellyuni") || ($model eq "shelly4") || ($model eq "shellyplug") || (($model =~ /shelly2.*/) && ($mode eq "relay")) ){ if( ($model =~ /shelly(plus)?1.*/) || ($model eq "shellyuni") || ($model =~ /shelly(pro)?4(pm)?/) || ($model eq "shellyplug") || (($model =~ /shelly2.*/) && ($mode eq "relay")) ){
#-- WEB asking for command list #-- WEB asking for command list
if( $cmd eq "?" ) { if( $cmd eq "?" ) {
$newkeys = join(" ", sort keys %setssw); $newkeys = join(" ", sort keys %setssw);
return "[Shelly_Set] Unknown argument " . $cmd . ", choose one of ".$newkeys; return "[Shelly_Set] unknown argument for device $name " . $cmd . ", choose one of ".$newkeys;
} }
#-- command received via web to register local changes of the device output #-- command received via web to register local changes of the device output
if( $cmd =~ /^out_((on)|(off))/){ if( $cmd =~ /^out_((on)|(off))/){
@ -585,7 +593,7 @@ sub Shelly_Set ($@) {
my $subs = ($shelly_models{$model}[0] ==1) ? "" : "_".$value; my $subs = ($shelly_models{$model}[0] ==1) ? "" : "_".$value;
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
if($model =~ /shelly(1|(plug)).*/){ if($model =~ /shelly(plus)?(1|(plug)).*/){
readingsBulkUpdateIfChanged($hash,"state",$ison) readingsBulkUpdateIfChanged($hash,"state",$ison)
} }
readingsBulkUpdate($hash,"relay".$subs,$ison); readingsBulkUpdate($hash,"relay".$subs,$ison);
@ -613,11 +621,11 @@ sub Shelly_Set ($@) {
if( !defined($channel) ){ if( !defined($channel) ){
$channel = AttrVal($name,"defchannel",undef); $channel = AttrVal($name,"defchannel",undef);
if( !defined($channel) ){ if( !defined($channel) ){
$msg = "Error: wrong channel $channel given and defchannel attribute not set properly"; $msg = "Error: wrong channel $channel given and defchannel attribute not set properly for device $name";
Log3 $name, 1,"[Shelly_Set] ".$msg; Log3 $name, 1,"[Shelly_Set] ".$msg;
return $msg; return $msg;
}else{ }else{
Log3 $name, 4,"[Shelly_Set] switching default channel $channel"; Log3 $name, 4,"[Shelly_Set] switching default channel $channel for device $name";
} }
} }
} }
@ -625,7 +633,7 @@ sub Shelly_Set ($@) {
if( $cmd =~ /(.*)-for-timer/ ){ if( $cmd =~ /(.*)-for-timer/ ){
$cmd = $1; $cmd = $1;
if( $time !~ /\d+/ ){ if( $time !~ /\d+/ ){
$msg = "Error: wrong time spec $time, must be <integer>"; $msg = "Error: wrong time spec $time for device $name, must be <integer>";
Log3 $name, 1,"[Shelly_Set] ".$msg; Log3 $name, 1,"[Shelly_Set] ".$msg;
return $msg; return $msg;
} }
@ -648,10 +656,10 @@ sub Shelly_Set ($@) {
Log3 $name, 1,"[Shelly_Set] readingsProxy device ".$name."_$i created"; Log3 $name, 1,"[Shelly_Set] readingsProxy device ".$name."_$i created";
} }
}else{ }else{
Log3 $name, 1,"[Shelly_Set] no separate channel device created, only one channel present"; Log3 $name, 1,"[Shelly_Set] no separate channel device created for device $name, only one channel present";
} }
} }
################################################################################################################
#-- we have a Shelly 2 roller type device #-- we have a Shelly 2 roller type device
}elsif( ($model =~ /shelly2.*/) && ($mode eq "roller") ){ }elsif( ($model =~ /shelly2.*/) && ($mode eq "roller") ){
my $channel = $value; my $channel = $value;
@ -659,7 +667,7 @@ sub Shelly_Set ($@) {
#-- WEB asking for command list #-- WEB asking for command list
if( $cmd eq "?" ) { if( $cmd eq "?" ) {
$newkeys = join(" ", sort keys %setsrol); $newkeys = join(" ", sort keys %setsrol);
return "[Shelly_Set] Unknown argument " . $cmd . ", choose one of ".$newkeys; return "[Shelly_Set] Unknown argument " . $cmd . " for device $name, choose one of ".$newkeys;
} }
if( $cmd eq "zero" ) { if( $cmd eq "zero" ) {
@ -667,7 +675,7 @@ sub Shelly_Set ($@) {
} }
if( ($hash->{MOVING} ne "stopped") && ($cmd ne "stop") ){ if( ($hash->{MOVING} ne "stopped") && ($cmd ne "stop") ){
$msg = "Error: roller blind still moving, wait for some time"; $msg = "Error: roller blind $name still moving, wait for some time";
Log3 $name,1,"[Shelly_Set] ".$msg; Log3 $name,1,"[Shelly_Set] ".$msg;
return $msg return $msg
} }
@ -703,7 +711,7 @@ sub Shelly_Set ($@) {
} }
if( !$max ){ if( !$max ){
Log3 $name,1,"[Shelly_Set] please set the maxtime attribute for proper operation"; Log3 $name,1,"[Shelly_Set] please set the maxtime attribute for proper operation of device $name";
$max = 20; $max = 20;
} }
$time = int(abs($targetpct-$pct)/100*$max); $time = int(abs($targetpct-$pct)/100*$max);
@ -714,12 +722,12 @@ sub Shelly_Set ($@) {
$hash->{TARGETPCT} = $targetpct; $hash->{TARGETPCT} = $targetpct;
Shelly_updown($hash,$cmd); Shelly_updown($hash,$cmd);
} }
################################################################################################################
#-- we have a Shelly dimmer type device or rgbw type device in white mode #-- we have a Shelly dimmer type device or rgbw type device in white mode
}elsif( ($model =~ /shellydimmer/) || (($model =~ /shellyrgbw.*/) && ($mode eq "white")) ){ }elsif( ($model =~ /shellydimmer/) || (($model =~ /shellyrgbw.*/) && ($mode eq "white")) ){
if( $cmd eq "?" ) { if( $cmd eq "?" ) {
$newkeys = join(" ", sort keys %setsrgbww); $newkeys = join(" ", sort keys %setsrgbww);
return "[Shelly_Set] Unknown argument " . $cmd . ", choose one of ".$newkeys; return "[Shelly_Set] Unknown argument " . $cmd . " for device $name, choose one of ".$newkeys;
} }
if( $cmd =~ /^((on)|(off)|(toggle)).*/ ){ if( $cmd =~ /^((on)|(off)|(toggle)).*/ ){
@ -734,18 +742,18 @@ sub Shelly_Set ($@) {
if( !defined($channel) ){ if( !defined($channel) ){
$channel = AttrVal($name,"defchannel",undef); $channel = AttrVal($name,"defchannel",undef);
if( !defined($channel) ){ if( !defined($channel) ){
$msg = "Error: wrong channel $channel given and defchannel attribute not set properly"; $msg = "Error: wrong channel $channel given and defchannel attribute not set properly for device $name";
Log3 $name, 1,"[Shelly_Set] ".$msg; Log3 $name, 1,"[Shelly_Set] ".$msg;
return $msg; return $msg;
}else{ }else{
Log3 $name, 4,"[Shelly_Set] switching default channel $channel"; Log3 $name, 4,"[Shelly_Set] switching default channel $channel for device $name";
} }
} }
} }
if( $cmd =~ /(.*)-for-timer/ ){ if( $cmd =~ /(.*)-for-timer/ ){
$cmd = $1; $cmd = $1;
if( $time !~ /\d+/ ){ if( $time !~ /\d+/ ){
$msg = "Error: wrong time spec $time, must be <integer>"; $msg = "Error: wrong time spec $time for device $name, must be <integer>";
Log3 $name, 1,"[Shelly_Set] ".$msg; Log3 $name, 1,"[Shelly_Set] ".$msg;
return $msg; return $msg;
} }
@ -776,11 +784,11 @@ sub Shelly_Set ($@) {
if( !defined($channel) ){ if( !defined($channel) ){
$channel = AttrVal($name,"defchannel",undef); $channel = AttrVal($name,"defchannel",undef);
if( !defined($channel) ){ if( !defined($channel) ){
$msg = "Error: wrong channel $channel given and defchannel attribute not set properly"; $msg = "Error: wrong channel $channel given and defchannel attribute not set properly for device $name";
Log3 $name, 1,"[Shelly_Set] ".$msg; Log3 $name, 1,"[Shelly_Set] ".$msg;
return $msg; return $msg;
}else{ }else{
Log3 $name, 4,"[Shelly_Set] dimming default channel $channel"; Log3 $name, 4,"[Shelly_Set] dimming default channel $channel for device $name";
} }
} }
} }
@ -791,6 +799,7 @@ sub Shelly_Set ($@) {
Shelly_dim($hash,"white/$channel","?brightness=".$value); Shelly_dim($hash,"white/$channel","?brightness=".$value);
} }
} }
################################################################################################################
#-- we have a Shelly dimmer type device or rgbw type device in white mode #-- we have a Shelly dimmer type device or rgbw type device in white mode
}elsif( ($model =~ /shellybulb.*/) && ($mode eq "white") ){ }elsif( ($model =~ /shellybulb.*/) && ($mode eq "white") ){
if( $cmd eq "?" ) { if( $cmd eq "?" ) {
@ -810,18 +819,18 @@ sub Shelly_Set ($@) {
if( !defined($channel) ){ if( !defined($channel) ){
$channel = AttrVal($name,"defchannel",undef); $channel = AttrVal($name,"defchannel",undef);
if( !defined($channel) ){ if( !defined($channel) ){
$msg = "Error: wrong channel $channel given and defchannel attribute not set properly"; $msg = "Error: wrong channel $channel given and defchannel attribute not set properly for device $name";
Log3 $name, 1,"[Shelly_Set] ".$msg; Log3 $name, 1,"[Shelly_Set] ".$msg;
return $msg; return $msg;
}else{ }else{
Log3 $name, 4,"[Shelly_Set] switching default channel $channel"; Log3 $name, 4,"[Shelly_Set] switching default channel $channel for device $name";
} }
} }
} }
if( $cmd =~ /(.*)-for-timer/ ){ if( $cmd =~ /(.*)-for-timer/ ){
$cmd = $1; $cmd = $1;
if( $time !~ /\d+/ ){ if( $time !~ /\d+/ ){
$msg = "Error: wrong time spec $time, must be <integer>"; $msg = "Error: wrong time spec $time for device $name, must be <integer>";
Log3 $name, 1,"[Shelly_Set] ".$msg; Log3 $name, 1,"[Shelly_Set] ".$msg;
return $msg; return $msg;
} }
@ -842,11 +851,11 @@ sub Shelly_Set ($@) {
if( !defined($channel) ){ if( !defined($channel) ){
$channel = AttrVal($name,"defchannel",undef); $channel = AttrVal($name,"defchannel",undef);
if( !defined($channel) ){ if( !defined($channel) ){
$msg = "Error: wrong channel $channel given and defchannel attribute not set properly"; $msg = "Error: wrong channel $channel given and defchannel attribute not set properly for device $name";
Log3 $name, 1,"[Shelly_Set] ".$msg; Log3 $name, 1,"[Shelly_Set] ".$msg;
return $msg; return $msg;
}else{ }else{
Log3 $name, 4,"[Shelly_Set] dimming default channel $channel"; Log3 $name, 4,"[Shelly_Set] dimming default channel $channel for device $name";
} }
} }
} }
@ -855,14 +864,14 @@ sub Shelly_Set ($@) {
$channel = shift @a; $channel = shift @a;
Shelly_dim($hash,"light/0","?temp=".$value); Shelly_dim($hash,"light/0","?temp=".$value);
} }
################################################################################################################
#-- we have a Shelly rgbw type device in color mode #-- we have a Shelly rgbw type device in color mode
}elsif( ($model =~ /shelly(rgbw|bulb).*/) && ($mode eq "color")){ }elsif( ($model =~ /shelly(rgbw|bulb).*/) && ($mode eq "color")){
my $channel = $value; my $channel = $value;
#-- WEB asking for command list #-- WEB asking for command list
if( $cmd eq "?" ) { if( $cmd eq "?" ) {
$newkeys = join(" ", sort keys %setsrgbwc); $newkeys = join(" ", sort keys %setsrgbwc);
return "[Shelly_Set] Unknown argument " . $cmd . ", choose one of ".$newkeys; return "[Shelly_Set] Unknown argument " . $cmd . " for device $name, choose one of ".$newkeys;
} }
if( $cmd =~ /^((on)|(off)|(toggle)).*/ ){ if( $cmd =~ /^((on)|(off)|(toggle)).*/ ){
@ -872,7 +881,7 @@ sub Shelly_Set ($@) {
$time = $value; $time = $value;
$cmd = $1; $cmd = $1;
if( $time !~ /\d+/ ){ if( $time !~ /\d+/ ){
$msg = "Error: wrong time spec $time, must be <integer>"; $msg = "Error: wrong time spec $time for device $name, must be <integer>";
Log3 $name, 1,"[Shelly_Set] ".$msg; Log3 $name, 1,"[Shelly_Set] ".$msg;
return $msg; return $msg;
} }
@ -896,19 +905,19 @@ sub Shelly_Set ($@) {
$cmd .= "&gain=100" if ($model eq "shellybulb"); $cmd .= "&gain=100" if ($model eq "shellybulb");
Shelly_dim($hash,"color/0","?".$cmd); Shelly_dim($hash,"color/0","?".$cmd);
}elsif( $cmd eq "rgb" ){ }elsif( $cmd eq "rgb" ){
my $red=hex(substr($value,0,2)); my $red =hex(substr($value,0,2));
my $green=hex(substr($value,2,2)); my $green=hex(substr($value,2,2));
my $blue=hex(substr($value,4,2)); my $blue =hex(substr($value,4,2));
$cmd=sprintf("red=%d&green=%d&blue=%d",$red,$green,$blue); $cmd =sprintf("red=%d&green=%d&blue=%d",$red,$green,$blue);
$cmd .= "&gain=100" if ($model eq "shellybulb"); $cmd .= "&gain=100" if ($model eq "shellybulb");
Shelly_dim($hash,"color/0","?".$cmd); Shelly_dim($hash,"color/0","?".$cmd);
}elsif( $cmd eq "rgbw" ){ }elsif( $cmd eq "rgbw" ){
my $red=hex(substr($value,0,2)); my $red =hex(substr($value,0,2));
my $green=hex(substr($value,2,2)); my $green=hex(substr($value,2,2));
my $blue=hex(substr($value,4,2)); my $blue =hex(substr($value,4,2));
my $white=hex(substr($value,6,2)); my $white=hex(substr($value,6,2));
$cmd=sprintf("red=%d&green=%d&blue=%d&white=%d",$red,$green,$blue,$white); $cmd =sprintf("red=%d&green=%d&blue=%d&white=%d",$red,$green,$blue,$white);
$cmd .= "&gain=100" if ($model eq "shellybulb"); $cmd .= "&gain=100" if ($model eq "shellybulb");
Shelly_dim($hash,"color/0","?".$cmd); Shelly_dim($hash,"color/0","?".$cmd);
}elsif( $cmd eq "white" ){ }elsif( $cmd eq "white" ){
$cmd=sprintf("white=%d",$value); $cmd=sprintf("white=%d",$value);
@ -961,7 +970,7 @@ sub Shelly_pwd($){
if ( $hash && !$err && !$data ){ if ( $hash && !$err && !$data ){
my $url = "http://$creds".$hash->{TCPIP}."/".$cmd; my $url = "http://$creds".$hash->{TCPIP}."/".$cmd;
my $timeout = AttrVal($name,"timeout",4); my $timeout = AttrVal($name,"timeout",4);
Log3 $name, 5,"[Shelly_configure] Issue a non-blocking call to $url"; Log3 $name, 5,"[Shelly_configure] issue a non-blocking call to $url";
HttpUtils_NonblockingGet({ HttpUtils_NonblockingGet({
url => $url, url => $url,
timeout => $timeout, timeout => $timeout,
@ -973,12 +982,12 @@ sub Shelly_pwd($){
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return; return;
} }
Log3 $name, 5,"[Shelly_configure] has obtained data $data"; Log3 $name, 5,"[Shelly_configure] device $name has returned data $data";
my $json = JSON->new->utf8; my $json = JSON->new->utf8;
my $jhash = eval{ $json->decode( $data ) }; my $jhash = eval{ $json->decode( $data ) };
if( !$jhash ){ if( !$jhash ){
Log3 $name,1,"[Shelly_configure] has invalid JSON data"; Log3 $name,1,"[Shelly_configure] invalid JSON data for device $name";
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return; return;
} }
@ -1002,52 +1011,89 @@ sub Shelly_pwd($){
return undef; return undef;
} }
######################################################################################## ########################################################################################
# #
# Shelly_status - Retrieve data from device # Shelly_status - Retrieve data from device
# acts as callable program Shelly_status($hash) # acts as callable program Shelly_status($hash)
# and as callback program Shelly_status($hash,$err,$data) # and as callback program Shelly_status($hash,$err,$data) (only for 1G)
# #
# Parameter hash # Parameter hash
# #
######################################################################################## ########################################################################################
sub Shelly_status { sub Shelly_status {
my ($hash, $err, $data) = @_; my ($hash, $err, $data) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $state = $hash->{READINGS}{state}{VAL}; my $state = $hash->{READINGS}{state}{VAL};
my $model = AttrVal($name,"model","generic"); my $model = AttrVal($name,"model","generic");
my $creds = Shelly_pwd($hash); my $creds = Shelly_pwd($hash);
if ( $hash && !$err && !$data ){ #-- check if 2nd generation device
my $url = "http://$creds".$hash->{TCPIP}."/status"; my $is2G = ($shelly_models{$model}[4] == 1);
my $timeout = AttrVal($name,"timeout",4);
Log3 $name, 5,"[Shelly_status] Issue a non-blocking call to $url"; #-- for 1G devices status is received in one single call
HttpUtils_NonblockingGet({ if( !$is2G ){
if ( $hash && !$err && !$data ){
my $url = "http://$creds".$hash->{TCPIP}."/status";
my $timeout = AttrVal($name,"timeout",4);
Log3 $name, 5,"[Shelly_status] issue a non-blocking call to $url";
HttpUtils_NonblockingGet({
url => $url, url => $url,
timeout => $timeout, timeout => $timeout,
callback => sub($$$){ Shelly_status($hash,$_[1],$_[2]) } callback => sub($$$){ Shelly_status($hash,$_[1],$_[2]) }
}); });
return undef; return undef;
}elsif ( $hash && $err ){ }elsif ( $hash && $err ){
Log3 $name, 1,"[Shelly_status] has error $err"; Log3 $name, 1,"[Shelly_status] device $name has error $err";
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
readingsSingleUpdate($hash,"network","not connected",1); readingsSingleUpdate($hash,"network","not connected",1);
#-- cyclic update nevertheless #-- cyclic update nevertheless
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "Shelly_status", $hash, 1) InternalTimer(gettimeofday()+$hash->{INTERVAL}, "Shelly_status", $hash, 1)
if( $hash->{INTERVAL} ne "0" ); if( $hash->{INTERVAL} ne "0" );
return $err; return $err;
}else{
Shelly_proc1G($hash,$err,$data);
return undef;
}
#-- 2G devices need to submit the call several times
}else{
#-- get status of relays -> component is Switch
my $url = "http://$creds".$hash->{TCPIP}."/rpc/Switch.GetStatus?id=";
my $timeout = AttrVal($name,"timeout",4);
for( my $id=0; $id< $shelly_models{$model}[0]; $id++){
Log3 $name, 5,"[Shelly_status] issue a non-blocking call to ".$url.$id;
HttpUtils_NonblockingGet({
url => $url.$id,
timeout => $timeout,
callback => sub($$$$){ Shelly_proc2G($hash,$_[1],$_[2],"relay") }
});
}
return undef;
} }
}
Log3 $name, 5,"[Shelly_status] has obtained data $data";
########################################################################################
#
# Shelly_proc1G - process data from device 1st generation
# In 1G devices status are all in one call
#
########################################################################################
sub Shelly_proc1G {
my ($hash, $err, $data) = @_;
my $name = $hash->{NAME};
my $state = $hash->{READINGS}{state}{VAL};
my $model = AttrVal($name,"model","generic");
Log3 $name, 5,"[Shelly_proc1G] device $name has returned data $data";
my $json = JSON->new->utf8; my $json = JSON->new->utf8;
my $jhash = eval{ $json->decode( $data ) }; my $jhash = eval{ $json->decode( $data ) };
if( !$jhash ){ if( !$jhash ){
Log3 $name,1,"[Shelly_status] invalid JSON data"; Log3 $name,1,"[Shelly_proc1G] invalid JSON data for device $name";
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return; return;
} }
@ -1067,8 +1113,9 @@ sub Shelly_pwd($){
if ($jhash->{'temperature'}) { if ($jhash->{'temperature'}) {
readingsBulkUpdateIfChanged($hash,"inttemp",$jhash->{'temperature'}); readingsBulkUpdateIfChanged($hash,"inttemp",$jhash->{'temperature'});
} }
#-- we have a Shelly 1/1pw, Shelly 4, Shelly 2/2.5, ShellyPlug or ShellyEM switch type device #############################################################################################################################
if( ($model =~ /shelly1.*/) || ($model eq "shellyuni") || ($model eq "shellyplug") || ($model eq "shelly4") || ($model eq "shellyem") || (($model =~ /shelly2.*/) && ($mode eq "relay")) ){ #-- 1st generation: we have a shelly1, shelly1pm, shellypro4, shelly2, shelly25, shellyplug or shellyem switch type device
if( ($model =~ /shelly1.*/) || ($model eq "shellyuni") || ($model eq "shellyplug") || ($model =~ /shelly(pro)?4/) || ($model =~ /shellyem.?/) || (($model =~ /shelly2.*/) && ($mode eq "relay")) ){
for( my $i=0;$i<$channels;$i++){ for( my $i=0;$i<$channels;$i++){
$subs = (($channels == 1) ? "" : "_".$i); $subs = (($channels == 1) ? "" : "_".$i);
$ison = $jhash->{'relays'}[$i]{'ison'}; $ison = $jhash->{'relays'}[$i]{'ison'};
@ -1089,13 +1136,13 @@ sub Shelly_pwd($){
readingsBulkUpdateIfChanged($hash,"voltage",$voltage); readingsBulkUpdateIfChanged($hash,"voltage",$voltage);
} }
my $metern = ($model eq "shellyem")?"emeters":"meters"; my $metern = ($model =~ /shellyem.?/)?"emeters":"meters";
for( my $i=0;$i<$meters;$i++){ for( my $i=0;$i<$meters;$i++){
$subs = ($meters == 1) ? "" : "_".$i; $subs = ($meters == 1) ? "" : "_".$i;
$power = $jhash->{$metern}[$i]{'power'}; $power = $jhash->{$metern}[$i]{'power'};
$energy = int($jhash->{$metern}[$i]{'total'}/6)/10; $energy = int($jhash->{$metern}[$i]{'total'}/6)/10;
readingsBulkUpdateIfChanged($hash,"power".$subs,$power); readingsBulkUpdateIfChanged($hash,"power".$subs,$power);
if ($model eq "shellyem") { if ($model =~ /shellyem.?/) {
my $voltage = $jhash->{$metern}[$i]{'voltage'}; my $voltage = $jhash->{$metern}[$i]{'voltage'};
readingsBulkUpdateIfChanged($hash,'voltage'.$subs,$voltage); readingsBulkUpdateIfChanged($hash,'voltage'.$subs,$voltage);
my $reactivePower = $jhash->{$metern}[$i]{'reactive'}; my $reactivePower = $jhash->{$metern}[$i]{'reactive'};
@ -1108,8 +1155,8 @@ sub Shelly_pwd($){
} }
readingsBulkUpdateIfChanged($hash,"energy".$subs,$energy); readingsBulkUpdateIfChanged($hash,"energy".$subs,$energy);
} }
#############################################################################################################################
#-- we have a Shelly 2 roller type device #-- we have a shelly2 or shelly25 roller type device
}elsif( ($model =~ /shelly2.*/) && ($mode eq "roller") ){ }elsif( ($model =~ /shelly2.*/) && ($mode eq "roller") ){
for( my $i=0;$i<$rollers;$i++){ for( my $i=0;$i<$rollers;$i++){
$subs = ($rollers == 1) ? "" : "_".$i; $subs = ($rollers == 1) ? "" : "_".$i;
@ -1143,7 +1190,7 @@ sub Shelly_pwd($){
#-- we have no data from the device #-- we have no data from the device
}else{ }else{
Log3 $name,1,"[Shelly_status] device $name with model=$model returns no blind position, consider chosing a different model=shelly2/2.5" Log3 $name,1,"[Shelly_proc1G] device $name with model=$model returns no blind position, consider chosing a different model=shelly2/2.5"
if( $model !~ /shelly2.*/ ); if( $model !~ /shelly2.*/ );
$pct = ReadingsVal($name,"pct",undef); $pct = ReadingsVal($name,"pct",undef);
#-- we have a reading #-- we have a reading
@ -1172,7 +1219,8 @@ sub Shelly_pwd($){
readingsBulkUpdateIfChanged($hash,"stop_reason".$subs,$rstopreason); readingsBulkUpdateIfChanged($hash,"stop_reason".$subs,$rstopreason);
readingsBulkUpdateIfChanged($hash,"last_dir".$subs,$rlastdir); readingsBulkUpdateIfChanged($hash,"last_dir".$subs,$rlastdir);
} }
#-- we have a Shelly dimmer or RGBW white device #############################################################################################################################
#-- we have a shellydimmer or shellyrgbw white device
}elsif( ($model eq "shellydimmer") || ($model eq "shellyrgbw" && $mode eq "white") ){ }elsif( ($model eq "shellydimmer") || ($model eq "shellyrgbw" && $mode eq "white") ){
for( my $i=0;$i<$dimmers;$i++){ for( my $i=0;$i<$dimmers;$i++){
$subs = (($dimmers == 1) ? "" : "_".$i); $subs = (($dimmers == 1) ? "" : "_".$i);
@ -1191,8 +1239,8 @@ sub Shelly_pwd($){
} }
readingsBulkUpdateIfChanged($hash,"state","OK") readingsBulkUpdateIfChanged($hash,"state","OK")
if ($dimmers > 1); if ($dimmers > 1);
#############################################################################################################################
#-- we have a Shelly Bulb / Duo in white mode #-- we have a shellybulb or shellyduo in white mode
}elsif( $model eq "shellybulb" && $mode eq "white" ){ }elsif( $model eq "shellybulb" && $mode eq "white" ){
for( my $i=0;$i<$dimmers;$i++){ for( my $i=0;$i<$dimmers;$i++){
$subs = (($dimmers == 1) ? "" : "_".$i); $subs = (($dimmers == 1) ? "" : "_".$i);
@ -1207,14 +1255,15 @@ sub Shelly_pwd($){
readingsBulkUpdateIfChanged($hash,"state".$subs,$ison); readingsBulkUpdateIfChanged($hash,"state".$subs,$ison);
readingsBulkUpdateIfChanged($hash,"pct".$subs,$bri); readingsBulkUpdateIfChanged($hash,"pct".$subs,$bri);
readingsBulkUpdateIfChanged($hash,"ct".$subs,$ct); readingsBulkUpdateIfChanged($hash,"ct".$subs,$ct);
readingsBulkUpdateIfChanged($hash,"overpower".$subs,$overpower); readingsBulkUpdateIfChanged($hash,"overpower".$subs,$overpower)
if($overpower);
readingsBulkUpdateIfChanged($hash,"power".$subs,$power); readingsBulkUpdateIfChanged($hash,"power".$subs,$power);
readingsBulkUpdateIfChanged($hash,"energy".$subs,$energy); readingsBulkUpdateIfChanged($hash,"energy".$subs,$energy);
} }
readingsBulkUpdateIfChanged($hash,"state","OK") readingsBulkUpdateIfChanged($hash,"state","OK")
if ($dimmers > 1); if ($dimmers > 1);
#############################################################################################################################
#-- we have a Shelly RGBW color device #-- we have a shellyrgbw color device
}elsif( $model =~ /shelly(rgbw|bulb)/ && $mode eq "color" ){ }elsif( $model =~ /shelly(rgbw|bulb)/ && $mode eq "color" ){
$ison = $jhash->{'lights'}[0]{'ison'}; $ison = $jhash->{'lights'}[0]{'ison'};
$ison =~ s/0|(false)/off/; $ison =~ s/0|(false)/off/;
@ -1250,7 +1299,8 @@ sub Shelly_pwd($){
readingsBulkUpdateIfChanged($hash,"energy".$subs,$energy); readingsBulkUpdateIfChanged($hash,"energy".$subs,$energy);
} }
} }
#-- common to all Shelly models #############################################################################################################################
#-- common to all models
my $hasupdate = $jhash->{'update'}{'has_update'}; my $hasupdate = $jhash->{'update'}{'has_update'};
my $firmware = $jhash->{'update'}{'old_version'}; my $firmware = $jhash->{'update'}{'old_version'};
$firmware =~ /.*\/(v[0-9.]+(-rc\d|)).*/; $firmware =~ /.*\/(v[0-9.]+(-rc\d|)).*/;
@ -1294,6 +1344,101 @@ sub Shelly_pwd($){
return undef; return undef;
} }
########################################################################################
#
# Shelly_proc2G - process data from device 2nd generation
# Necessary because in 2G devices status are per channel
#
########################################################################################
sub Shelly_proc2G {
my ($hash, $err, $data, $comp) = @_;
my $name = $hash->{NAME};
my $state = $hash->{READINGS}{state}{VAL};
my $model = AttrVal($name,"model","generic");
#Log 1,"=============> Status 2G $name model $model component $comp err $err data $data";
#-- error in non blocking call
if ( $hash && $err ){
Log3 $name, 1,"[Shelly_proc2G] device $name has error $err";
readingsSingleUpdate($hash,"state","Error",1);
readingsSingleUpdate($hash,"network","not connected",1);
#-- cyclic update nevertheless
RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "Shelly_status", $hash, 1)
if( $hash->{INTERVAL} ne "0" );
return $err;
}
Log3 $name, 5,"[Shelly_proc2G] device $name has returned data $data";
my $json = JSON->new->utf8;
my $jhash = eval{ $json->decode( $data ) };
#-- error in data
if( !$jhash ){
Log3 $name,1,"[Shelly_proc2G] invalid JSON data for device $name";
readingsSingleUpdate($hash,"state","Error",1);
return;
}
readingsSingleUpdate($hash,"state","OK",1);
my $mode = AttrVal($name,"mode","");
my $channel = $jhash->{'id'};
my $channels = $shelly_models{$model}[0];
my $rollers = $shelly_models{$model}[1];
my $dimmers = $shelly_models{$model}[2];
my $meters = $shelly_models{$model}[3];
my ($subs,$ison,$overpower,$voltage,$current,$power,$energy,$pfactor);
readingsBeginUpdate($hash);
if( $channel == 0){
readingsBulkUpdateIfChanged($hash,"network","<html>connected to <a href=\"http://".$hash->{TCPIP}."\">".$hash->{TCPIP}."</a></html>",1);
#-- for all models set internal temperature reading - but only for first call
if ($jhash->{'temperature'}){
readingsBulkUpdateIfChanged($hash,"inttemp",$jhash->{'temperature'}{'tC'});
}
}
#############################################################################################################################
#-- 2nd generation: we have a shellyplus1(pm) or shellypro4pm switch type device
if( ($model =~ /shellyplus1(pm)?/) || ($model eq "shellypro4pm") ){
$subs = (($channels == 1) ? "" : "_".$channel);
$ison = $jhash->{'output'};
$ison =~ s/0|(false)/off/;
$ison =~ s/1|(true)/on/;
readingsBulkUpdateIfChanged($hash,"relay".$subs,$ison);
#$overpower = $jhash->{'relays'}[$i]{'overpower'};
#readingsBulkUpdateIfChanged($hash,"overpower".$subs,$overpower)
# if(defined($overpower));
if( $meters > 0 ){
$voltage = $jhash->{'voltage'};
$current = $jhash->{'current'};
$power = $jhash->{'apower'};
$pfactor = $jhash->{'pf'};
$energy = $jhash->{'energy'}{'total'};
readingsBulkUpdateIfChanged($hash,"voltage".$subs,$voltage);
readingsBulkUpdateIfChanged($hash,"current".$subs,$current);
readingsBulkUpdateIfChanged($hash,"power".$subs,$power);
readingsBulkUpdateIfChanged($hash,"pfactor".$subs,$pfactor);
readingsBulkUpdateIfChanged($hash,"energy".$subs,$energy);
}
}
#############################################################################################################################
#-- common to all models
readingsEndUpdate($hash,1);
#-- cyclic update
RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "Shelly_status", $hash, 1)
if( $hash->{INTERVAL} ne "0" );
return undef;
}
######################################################################################## ########################################################################################
# #
# Shelly_dim - Set Shelly dimmer state # Shelly_dim - Set Shelly dimmer state
@ -1318,7 +1463,7 @@ sub Shelly_pwd($){
if ( $hash && !$err && !$data ){ if ( $hash && !$err && !$data ){
my $url = "http://$creds".$hash->{TCPIP}."/$channel$cmd"; my $url = "http://$creds".$hash->{TCPIP}."/$channel$cmd";
my $timeout = AttrVal($name,"timeout",4); my $timeout = AttrVal($name,"timeout",4);
Log3 $name, 5,"[Shelly_dim] Issue a non-blocking call to $url"; Log3 $name, 5,"[Shelly_dim] issue a non-blocking call to $url";
HttpUtils_NonblockingGet({ HttpUtils_NonblockingGet({
url => $url, url => $url,
timeout => $timeout, timeout => $timeout,
@ -1330,17 +1475,17 @@ sub Shelly_pwd($){
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return; return;
} }
Log3 $name, 5,"[Shelly_dim] has obtained data $data"; Log3 $name, 5,"[Shelly_dim] device $name has returned data $data";
my $json = JSON->new->utf8; my $json = JSON->new->utf8;
my $jhash = eval{ $json->decode( $data ) }; my $jhash = eval{ $json->decode( $data ) };
if( !$jhash ){ if( !$jhash ){
if( ($model =~ /shellyrgbw.*/) && ($data =~ /Device mode is not dimmer!/) ){ if( ($model =~ /shellyrgbw.*/) && ($data =~ /Device mode is not dimmer!/) ){
Log3 $name,1,"[Shelly_dim] Device $name is not a dimmer"; Log3 $name,1,"[Shelly_dim] device $name is not a dimmer";
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return return
}else{ }else{
Log3 $name,1,"[Shelly_dim] has invalid JSON data"; Log3 $name,1,"[Shelly_dim] invalid JSON data for device $name";
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return; return;
} }
@ -1359,20 +1504,20 @@ sub Shelly_pwd($){
if( index($cmd,"&") ne "-1"){ if( index($cmd,"&") ne "-1"){
$cmd = substr($cmd,0,index($cmd,"&")); $cmd = substr($cmd,0,index($cmd,"&"));
if( $hastimer && $hastimer ne "1" ){ if( $hastimer && $hastimer ne "1" ){
Log3 $name,1,"[Shelly_dim] returns with problem, timer not set"; Log3 $name,1,"[Shelly_dim] returns with problem for device $name, timer not set";
} }
} }
if( $ison ne $cmd2 ) { if( $ison ne $cmd2 ) {
Log3 $name,1,"[Shelly_dim] returns without success, cmd=$cmd but ison=$ison"; Log3 $name,1,"[Shelly_dim] returns without success for device $name, cmd=$cmd but ison=$ison";
} }
}elsif( $cmd =~ /\?brightness=(.*)/){ }elsif( $cmd =~ /\?brightness=(.*)/){
my $cmd2 = $1; my $cmd2 = $1;
if( $bright ne $cmd2 ) { if( $bright ne $cmd2 ) {
Log3 $name,1,"[Shelly_dim] returns without success, desired brightness $cmd, but device brightness=$bright"; Log3 $name,1,"[Shelly_dim] returns without success for device $name, desired brightness $cmd, but device brightness=$bright";
} }
} }
if( defined($overpower) && $overpower eq "1") { if( defined($overpower) && $overpower eq "1") {
Log3 $name,1,"[Shelly_dim] switched off automatically because of overpower signal"; Log3 $name,1,"[Shelly_dim] device $name switched off automatically because of overpower signal";
} }
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
@ -1414,7 +1559,7 @@ sub Shelly_pwd($){
if ( $hash && !$err && !$data ){ if ( $hash && !$err && !$data ){
my $url = "http://$creds".$hash->{TCPIP}."/roller/0".$cmd; my $url = "http://$creds".$hash->{TCPIP}."/roller/0".$cmd;
my $timeout = AttrVal($name,"timeout",4); my $timeout = AttrVal($name,"timeout",4);
Log3 $name, 5,"[Shelly_updown] Issue a non-blocking call to $url"; Log3 $name, 5,"[Shelly_updown] issue a non-blocking call to $url";
HttpUtils_NonblockingGet({ HttpUtils_NonblockingGet({
url => $url, url => $url,
timeout => $timeout, timeout => $timeout,
@ -1432,11 +1577,11 @@ sub Shelly_pwd($){
my $jhash = eval{ $json->decode( $data ) }; my $jhash = eval{ $json->decode( $data ) };
if( !$jhash ){ if( !$jhash ){
if( ($model =~ /shelly2.*/) && ($data =~ /Device mode is not roller!/) ){ if( ($model =~ /shelly2.*/) && ($data =~ /Device mode is not roller!/) ){
Log3 $name,1,"[Shelly_updown] Device $name is not in roller mode"; Log3 $name,1,"[Shelly_updown] device $name is not in roller mode";
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return return
}else{ }else{
Log3 $name,1,"[Shelly_updown] has invalid JSON data"; Log3 $name,1,"[Shelly_updown] has invalid JSON data for device $name";
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return; return;
} }
@ -1495,7 +1640,7 @@ sub Shelly_updown2($){
if ( $hash && !$err && !$data ){ if ( $hash && !$err && !$data ){
my $url = "http://$creds".$hash->{TCPIP}."/relay/".$channel.$cmd; my $url = "http://$creds".$hash->{TCPIP}."/relay/".$channel.$cmd;
my $timeout = AttrVal($name,"timeout",4); my $timeout = AttrVal($name,"timeout",4);
Log3 $name, 5,"[Shelly_onoff] Issue a non-blocking call to $url"; Log3 $name, 5,"[Shelly_onoff] issue a non-blocking call to $url";
HttpUtils_NonblockingGet({ HttpUtils_NonblockingGet({
url => $url, url => $url,
timeout => $timeout, timeout => $timeout,
@ -1507,17 +1652,17 @@ sub Shelly_updown2($){
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return; return;
} }
Log3 $name, 5,"[Shelly_onoff] has obtained data $data"; Log3 $name, 5,"[Shelly_onoff] device $name has returned data $data";
my $json = JSON->new->utf8; my $json = JSON->new->utf8;
my $jhash = eval{ $json->decode( $data ) }; my $jhash = eval{ $json->decode( $data ) };
if( !$jhash ){ if( !$jhash ){
if( ($model =~ /shelly2.*/) && ($data =~ /Device mode is not relay!/) ){ if( ($model =~ /shelly2.*/) && ($data =~ /Device mode is not relay!/) ){
Log3 $name,1,"[Shelly_onoff] Device $name is not in relay mode"; Log3 $name,1,"[Shelly_onoff] device $name is not in relay mode";
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return return
}else{ }else{
Log3 $name,1,"[Shelly_onoff] has invalid JSON data"; Log3 $name,1,"[Shelly_onoff] has invalid JSON data for device $name";
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return; return;
} }
@ -1535,14 +1680,14 @@ sub Shelly_updown2($){
if( index($cmd,"&") ne "-1"){ if( index($cmd,"&") ne "-1"){
$cmd = substr($cmd,0,index($cmd,"&")); $cmd = substr($cmd,0,index($cmd,"&"));
if( $hastimer ne "1" ){ if( $hastimer ne "1" ){
Log3 $name,1,"[Shelly_onoff] returns with problem, timer not set"; Log3 $name,1,"[Shelly_onoff] returns with problem for device $name, timer not set";
} }
} }
if( $ison ne $cmd ) { if( $ison ne $cmd ) {
Log3 $name,1,"[Shelly_onoff] returns without success, cmd=$cmd but ison=$ison"; Log3 $name,1,"[Shelly_onoff] returns without success for device $name, cmd=$cmd but ison=$ison";
} }
if( defined($overpower) && $overpower eq "1") { if( defined($overpower) && $overpower eq "1") {
Log3 $name,1,"[Shelly_onoff] switched off automatically because of overpower signal"; Log3 $name,1,"[Shelly_onoff] device $name switched off automatically because of overpower signal";
} }
#-- #--
my $subs = ($shelly_models{$model}[0] ==1) ? "" : "_".$channel; my $subs = ($shelly_models{$model}[0] ==1) ? "" : "_".$channel;
@ -1588,7 +1733,7 @@ sub Shelly_updown2($){
if ( $hash && !$err && !$data ){ if ( $hash && !$err && !$data ){
my $url = "http://$creds".$hash->{TCPIP}."/meter/".$channel; my $url = "http://$creds".$hash->{TCPIP}."/meter/".$channel;
my $timeout = AttrVal($name,"timeout",4); my $timeout = AttrVal($name,"timeout",4);
Log3 $name, 5,"[Shelly_meter] Issue a non-blocking call to $url"; Log3 $name, 5,"[Shelly_meter] issue a non-blocking call to $url";
HttpUtils_NonblockingGet({ HttpUtils_NonblockingGet({
url => $url, url => $url,
timeout => $timeout, timeout => $timeout,
@ -1596,16 +1741,16 @@ sub Shelly_updown2($){
}); });
return undef; return undef;
}elsif ( $hash && $err ){ }elsif ( $hash && $err ){
Log3 $name, 1,"[Shelly_meter has error $err"; Log3 $name, 1,"[Shelly_meter] device $name has error $err";
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return; return;
} }
Log3 $name, 5,"[Shelly_meter] has obtained data $data"; Log3 $name, 5,"[Shelly_meter] device $name has returned data $data";
my $json = JSON->new->utf8; my $json = JSON->new->utf8;
my $jhash = eval{ $json->decode( $data ) }; my $jhash = eval{ $json->decode( $data ) };
if( !$jhash ){ if( !$jhash ){
Log3 $name,1,"[Shelly_meter] invalid JSON data"; Log3 $name,1,"[Shelly_meter] invalid JSON data for device $name";
readingsSingleUpdate($hash,"state","Error",1); readingsSingleUpdate($hash,"state","Error",1);
return; return;
} }
@ -1660,7 +1805,7 @@ sub Shelly_updown2($){
<br />set the value of a configuration register</li> <br />set the value of a configuration register</li>
<li>password &lt;password&gt;<br>This is the only way to set the password for the Shelly web interface</li> <li>password &lt;password&gt;<br>This is the only way to set the password for the Shelly web interface</li>
</ul> </ul>
For Shelly switching devices (model=shelly1|shelly1pm|shellyuni|shelly4|shellyplug|shellyem or (model=shelly2/2.5 and mode=relay)) For Shelly switching devices (model=shelly1|shelly1pm|shellyuni|shelly4|shellypro4pm|shellyplug|shellyem|shelly3em or (model=shelly2/2.5 and mode=relay))
<ul> <ul>
<li> <li>
<code>set &lt;name&gt; on|off|toggle [&lt;channel&gt;] </code> <code>set &lt;name&gt; on|off|toggle [&lt;channel&gt;] </code>