mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-21 20:06:18 +00:00
36_Shelly.pm: Version 3.0. Shellybulb/Duo, Timeout für Netz sowie Zusammenarbeit mit 36_ShellyMonitor.pm
git-svn-id: https://svn.fhem.de/fhem/trunk@23525 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
bf2012387b
commit
7985a36b80
@ -39,7 +39,7 @@ use vars qw{%attr %defs};
|
|||||||
sub Log($$);
|
sub Log($$);
|
||||||
|
|
||||||
#-- globals on start
|
#-- globals on start
|
||||||
my $version = "2.20";
|
my $version = "3.0";
|
||||||
|
|
||||||
#-- these we may get on request
|
#-- these we may get on request
|
||||||
my %gets = (
|
my %gets = (
|
||||||
@ -82,6 +82,18 @@ my %setsrgbww = (
|
|||||||
"pct" => "B",
|
"pct" => "B",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
my %setsbulbw = (
|
||||||
|
"on" => "O",
|
||||||
|
"off" => "F",
|
||||||
|
"toggle" => "T",
|
||||||
|
"on-for-timer" => "X",
|
||||||
|
"off-for-timer" => "E",
|
||||||
|
"config" => "K",
|
||||||
|
"password" => "P",
|
||||||
|
"ct:colorpicker,CT,3000,10,6500" => "R",
|
||||||
|
"pct:slider,0,1,100" => "W"
|
||||||
|
);
|
||||||
|
|
||||||
my %setsrgbwc = (
|
my %setsrgbwc = (
|
||||||
"on" => "O",
|
"on" => "O",
|
||||||
"off" => "F",
|
"off" => "F",
|
||||||
@ -98,6 +110,7 @@ my %setsrgbwc = (
|
|||||||
|
|
||||||
my %shelly_models = (
|
my %shelly_models = (
|
||||||
#(relays,rollers,dimmers,meters)
|
#(relays,rollers,dimmers,meters)
|
||||||
|
"generic" => [0,0,0,0],
|
||||||
"shelly1" => [1,0,0,0],
|
"shelly1" => [1,0,0,0],
|
||||||
"shelly1pm" => [1,0,0,1],
|
"shelly1pm" => [1,0,0,1],
|
||||||
"shelly2" => [2,1,0,1],
|
"shelly2" => [2,1,0,1],
|
||||||
@ -106,7 +119,8 @@ my %shelly_models = (
|
|||||||
"shelly4" => [4,0,0,4],
|
"shelly4" => [4,0,0,4],
|
||||||
"shellyrgbw" => [0,0,4,1],
|
"shellyrgbw" => [0,0,4,1],
|
||||||
"shellydimmer" => [0,0,1,1],
|
"shellydimmer" => [0,0,1,1],
|
||||||
"shellyem" => [1,0,0,2]
|
"shellyem" => [1,0,0,2],
|
||||||
|
"shellybulb" => [0,0,1,1]
|
||||||
);
|
);
|
||||||
|
|
||||||
my %shelly_regs = (
|
my %shelly_regs = (
|
||||||
@ -138,7 +152,7 @@ sub Shelly_Initialize ($) {
|
|||||||
$hash->{SetFn} = "Shelly_Set";
|
$hash->{SetFn} = "Shelly_Set";
|
||||||
$hash->{RenameFn} = "Shelly_Rename";
|
$hash->{RenameFn} = "Shelly_Rename";
|
||||||
|
|
||||||
$hash->{AttrList}= "verbose model:".join(",",(keys %shelly_models))." mode:relay,roller,white,color defchannel maxtime maxpower interval pct100:open,closed shellyuser ".
|
$hash->{AttrList}= "verbose model:".join(",",(keys %shelly_models))." mode:relay,roller,white,color defchannel maxtime maxpower interval timeout pct100:open,closed shellyuser ".
|
||||||
$readingFnAttributes;
|
$readingFnAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,6 +185,7 @@ sub Shelly_Define($$) {
|
|||||||
#-- InternalTimer blocks if init_done is not true
|
#-- InternalTimer blocks if init_done is not true
|
||||||
my $oid = $init_done;
|
my $oid = $init_done;
|
||||||
$init_done = 1;
|
$init_done = 1;
|
||||||
|
|
||||||
readingsBeginUpdate($hash);
|
readingsBeginUpdate($hash);
|
||||||
my $err = Shelly_status($hash);
|
my $err = Shelly_status($hash);
|
||||||
if( !defined($err) ){
|
if( !defined($err) ){
|
||||||
@ -182,6 +197,9 @@ sub Shelly_Define($$) {
|
|||||||
}
|
}
|
||||||
readingsEndUpdate($hash,1);
|
readingsEndUpdate($hash,1);
|
||||||
|
|
||||||
|
#-- get settings
|
||||||
|
$err = Shelly_configure($hash,"settings/");
|
||||||
|
|
||||||
#-- perform status update in a minute or so
|
#-- perform status update in a minute or so
|
||||||
InternalTimer(time()+60, "Shelly_status", $hash,0);
|
InternalTimer(time()+60, "Shelly_status", $hash,0);
|
||||||
|
|
||||||
@ -255,7 +273,7 @@ sub Shelly_Attr(@) {
|
|||||||
my $hash = $main::defs{$name};
|
my $hash = $main::defs{$name};
|
||||||
my $ret;
|
my $ret;
|
||||||
|
|
||||||
my $model = AttrVal($name,"model","");
|
my $model = AttrVal($name,"model","generic");
|
||||||
my $mode = AttrVal($name,"mode","");
|
my $mode = AttrVal($name,"mode","");
|
||||||
|
|
||||||
#-- temporary code
|
#-- temporary code
|
||||||
@ -318,7 +336,7 @@ sub Shelly_Attr(@) {
|
|||||||
|
|
||||||
if( $model =~ /shelly2.*/ ){
|
if( $model =~ /shelly2.*/ ){
|
||||||
$new = $pre." mode:relay,roller ".$pos;
|
$new = $pre." mode:relay,roller ".$pos;
|
||||||
}elsif( $model eq "shellyrgbw" ){
|
}elsif( $model =~ /shelly(rgbw|bulb)/){
|
||||||
$new = $pre." mode:white,color ".$pos;
|
$new = $pre." mode:white,color ".$pos;
|
||||||
}elsif( $model =~ /shelly.*/){
|
}elsif( $model =~ /shelly.*/){
|
||||||
$new = $pre." ".$pos;
|
$new = $pre." ".$pos;
|
||||||
@ -327,8 +345,8 @@ sub Shelly_Attr(@) {
|
|||||||
|
|
||||||
#---------------------------------------
|
#---------------------------------------
|
||||||
}elsif ( ($cmd eq "set") && ($attrName =~ /mode/) ) {
|
}elsif ( ($cmd eq "set") && ($attrName =~ /mode/) ) {
|
||||||
if( $model !~ /shelly(2|(rgb)).*/ ){
|
if( $model !~ /shelly(2|(rgb|bulb)).*/ ){
|
||||||
Log3 $name,1,"[Shelly_Attr] setting the mode attribute only works for model=shelly2|shelly2.5|shellyrgbw";
|
Log3 $name,1,"[Shelly_Attr] setting the mode attribute only works for model=shelly2|shelly2.5|shellyrgbw|shellybulb";
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if( $model =~ /shelly2.*/ ){
|
if( $model =~ /shelly2.*/ ){
|
||||||
@ -350,7 +368,7 @@ sub Shelly_Attr(@) {
|
|||||||
fhem("deletereading ".$name." power.*");
|
fhem("deletereading ".$name." power.*");
|
||||||
fhem("deletereading ".$name." energy.*");
|
fhem("deletereading ".$name." energy.*");
|
||||||
fhem("deletereading ".$name." overpower.*");
|
fhem("deletereading ".$name." overpower.*");
|
||||||
}elsif( $model eq "shellyrgbw" ){
|
}elsif( $model eq "shellyrgbw" || $model eq "shellybulb" ){
|
||||||
fhem("deletereading ".$name." power.*");
|
fhem("deletereading ".$name." power.*");
|
||||||
fhem("deletereading ".$name." energy.*");
|
fhem("deletereading ".$name." energy.*");
|
||||||
fhem("deletereading ".$name." overpower.*");
|
fhem("deletereading ".$name." overpower.*");
|
||||||
@ -359,6 +377,7 @@ sub Shelly_Attr(@) {
|
|||||||
return;
|
return;
|
||||||
}elsif( $attrVal eq "color"){
|
}elsif( $attrVal eq "color"){
|
||||||
fhem("deletereading ".$name." pct.*");
|
fhem("deletereading ".$name." pct.*");
|
||||||
|
fhem("deletereading ".$name." ct.*");
|
||||||
fhem("deletereading ".$name." state_.*");
|
fhem("deletereading ".$name." state_.*");
|
||||||
}elsif( $attrVal eq "white"){
|
}elsif( $attrVal eq "white"){
|
||||||
fhem("deletereading ".$name." L-.*");
|
fhem("deletereading ".$name." L-.*");
|
||||||
@ -411,7 +430,7 @@ sub Shelly_Get ($@) {
|
|||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $v;
|
my $v;
|
||||||
|
|
||||||
my $model = AttrVal($name,"model","");
|
my $model = AttrVal($name,"model","generic");
|
||||||
my $mode = AttrVal($name,"mode","");
|
my $mode = AttrVal($name,"mode","");
|
||||||
|
|
||||||
#-- get version
|
#-- get version
|
||||||
@ -429,9 +448,9 @@ sub Shelly_Get ($@) {
|
|||||||
$txt = "roller";
|
$txt = "roller";
|
||||||
}elsif( $model eq "shellydimmer" ){
|
}elsif( $model eq "shellydimmer" ){
|
||||||
$txt = "light";
|
$txt = "light";
|
||||||
}elsif( ($model eq "shellyrgbw") && ($mode eq "white") ){
|
}elsif( ($model eq "shellyrgbw" || $model eq "shellybulb") && ($mode eq "white") ){
|
||||||
$txt = "white";
|
$txt = "white";
|
||||||
}elsif( ($model eq "shellyrgbw") && ($mode eq "color") ){
|
}elsif( ($model eq "shellyrgbw" || $model eq "shellybulb") && ($mode eq "color") ){
|
||||||
$txt = "color";
|
$txt = "color";
|
||||||
}else{
|
}else{
|
||||||
$txt = "relay";
|
$txt = "relay";
|
||||||
@ -446,6 +465,9 @@ sub Shelly_Get ($@) {
|
|||||||
$chan = $a[3];
|
$chan = $a[3];
|
||||||
}elsif( int(@a) == 3 ){
|
}elsif( int(@a) == 3 ){
|
||||||
$chan = 0;
|
$chan = 0;
|
||||||
|
}elsif( int(@a) == 2 ){
|
||||||
|
$reg = "";
|
||||||
|
$chan = undef;
|
||||||
}else{
|
}else{
|
||||||
my $msg = "Error: wrong number of parameters";
|
my $msg = "Error: wrong number of parameters";
|
||||||
Log3 $name,1,"[Shelly_Get] ".$msg;
|
Log3 $name,1,"[Shelly_Get] ".$msg;
|
||||||
@ -453,16 +475,18 @@ sub Shelly_Get ($@) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
my $pre = "settings/";
|
my $pre = "settings/";
|
||||||
if( ($model =~ /shelly2.*/) && ($mode eq "roller") ){
|
if( $reg ne "" ){
|
||||||
$pre .= "roller/0?";
|
if( ($model =~ /shelly2.*/) && ($mode eq "roller") ){
|
||||||
}elsif( $model eq "shellydimmer" ){
|
$pre .= "roller/0?";
|
||||||
$pre .= "light/0?";
|
}elsif( $model eq "shellydimmer" ){
|
||||||
}elsif( ($model eq "shellyrgbw") && ($mode eq "white") ){
|
$pre .= "light/0?";
|
||||||
$pre .= "white/0?";
|
}elsif( ($model eq "shellyrgbw" || $model eq "shellybulb") && ($mode eq "white") ){
|
||||||
}elsif( ($model eq "shellyrgbw") && ($mode eq "color") ){
|
$pre .= "white/0?";
|
||||||
$pre .= "color/0?";
|
}elsif( ($model eq "shellyrgbw" || $model eq "shellybulb") && ($mode eq "color") ){
|
||||||
}else{
|
$pre .= "color/0?";
|
||||||
$pre .= "relay/$chan?";
|
}elsif( defined($chan)){
|
||||||
|
$pre .= "relay/$chan?";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$v = Shelly_configure($hash,$pre.$reg);
|
$v = Shelly_configure($hash,$pre.$reg);
|
||||||
|
|
||||||
@ -531,9 +555,9 @@ sub Shelly_Set ($@) {
|
|||||||
my $pre = "settings/";
|
my $pre = "settings/";
|
||||||
if( ($model =~ /shelly2.*/) && ($mode eq "roller") ){
|
if( ($model =~ /shelly2.*/) && ($mode eq "roller") ){
|
||||||
$pre .= "roller/0?";
|
$pre .= "roller/0?";
|
||||||
}elsif( ($model eq "shellyrgbw") && ($mode eq "white") ){
|
}elsif( ($model eq "shellyrgbw" || $model eq "shellybulb") && ($mode eq "white") ){
|
||||||
$pre .= "white/0?";
|
$pre .= "white/0?";
|
||||||
}elsif( ($model eq "shellyrgbw") && ($mode eq "color") ){
|
}elsif( ($model eq "shellyrgbw" || $model eq "shellybulb") && ($mode eq "color") ){
|
||||||
$pre .= "color/0?";
|
$pre .= "color/0?";
|
||||||
}else{
|
}else{
|
||||||
$pre .= "relay/$chan?";
|
$pre .= "relay/$chan?";
|
||||||
@ -757,8 +781,73 @@ 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
|
||||||
|
}elsif( ($model =~ /shellybulb.*/) && ($mode eq "white") ){
|
||||||
|
if( $cmd eq "?" ) {
|
||||||
|
$newkeys = join(" ", sort keys %setsbulbw);
|
||||||
|
return "[Shelly_Set] Unknown argument " . $cmd . ", choose one of ".$newkeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $cmd =~ /^((on)|(off)|(toggle)).*/ ){
|
||||||
|
$channel = $value;
|
||||||
|
if( $cmd =~ /(.*)-for-timer/ ){
|
||||||
|
$time = $value;
|
||||||
|
$channel = shift @a;
|
||||||
|
}
|
||||||
|
if( $shelly_models{$model}[2] == 1){
|
||||||
|
$channel = 0
|
||||||
|
}elsif( !defined($channel) || ($channel !~ /[0123]/) || $channel >= $shelly_models{$model}[3] ){
|
||||||
|
if( !defined($channel) ){
|
||||||
|
$channel = AttrVal($name,"defchannel",undef);
|
||||||
|
if( !defined($channel) ){
|
||||||
|
$msg = "Error: wrong channel $channel given and defchannel attribute not set properly";
|
||||||
|
Log3 $name, 1,"[Shelly_Set] ".$msg;
|
||||||
|
return $msg;
|
||||||
|
}else{
|
||||||
|
Log3 $name, 4,"[Shelly_Set] switching default channel $channel";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( $cmd =~ /(.*)-for-timer/ ){
|
||||||
|
$cmd = $1;
|
||||||
|
if( $time !~ /\d+/ ){
|
||||||
|
$msg = "Error: wrong time spec $time, must be <integer>";
|
||||||
|
Log3 $name, 1,"[Shelly_Set] ".$msg;
|
||||||
|
return $msg;
|
||||||
|
}
|
||||||
|
$cmd = $cmd."&timer=$time";
|
||||||
|
}
|
||||||
|
if( $cmd eq "toggle"){
|
||||||
|
$cmd = (ReadingsVal($name,"state","off") eq "on") ? "off" : "on";
|
||||||
|
}
|
||||||
|
Shelly_dim($hash,"light/$channel","?turn=".$cmd);
|
||||||
|
#Shelly_onoff($hash,"white/$channel","?turn=".$cmd);
|
||||||
|
#-- command received via web to register local changes of the device input
|
||||||
|
|
||||||
|
}elsif( $cmd eq "pct" || $cmd eq "brightness" ){
|
||||||
|
$channel = shift @a;
|
||||||
|
if( $shelly_models{$model}[2] == 1){
|
||||||
|
$channel = 0
|
||||||
|
}elsif( !defined($channel) || ($channel !~ /[0123]/) || $channel >= $shelly_models{$model}[3] ){
|
||||||
|
if( !defined($channel) ){
|
||||||
|
$channel = AttrVal($name,"defchannel",undef);
|
||||||
|
if( !defined($channel) ){
|
||||||
|
$msg = "Error: wrong channel $channel given and defchannel attribute not set properly";
|
||||||
|
Log3 $name, 1,"[Shelly_Set] ".$msg;
|
||||||
|
return $msg;
|
||||||
|
}else{
|
||||||
|
Log3 $name, 4,"[Shelly_Set] dimming default channel $channel";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Shelly_dim($hash,"light/$channel","?brightness=".$value);
|
||||||
|
}elsif( $cmd eq "ct" ){
|
||||||
|
$channel = shift @a;
|
||||||
|
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 =~ /shellyrgbw.*/) && ($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 "?" ) {
|
||||||
@ -794,12 +883,14 @@ sub Shelly_Set ($@) {
|
|||||||
}
|
}
|
||||||
my ($red,$green,$blue)=Color::hsv2rgb($hue,$saturation,$value);
|
my ($red,$green,$blue)=Color::hsv2rgb($hue,$saturation,$value);
|
||||||
$cmd=sprintf("red=%d&green=%d&blue=%d",int($red*255+0.5),int($green*255+0.5),int($blue*255+0.5));
|
$cmd=sprintf("red=%d&green=%d&blue=%d",int($red*255+0.5),int($green*255+0.5),int($blue*255+0.5));
|
||||||
|
$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");
|
||||||
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));
|
||||||
@ -807,6 +898,7 @@ sub Shelly_Set ($@) {
|
|||||||
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");
|
||||||
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);
|
||||||
@ -837,7 +929,7 @@ sub Shelly_pwd($){
|
|||||||
|
|
||||||
########################################################################################
|
########################################################################################
|
||||||
#
|
#
|
||||||
# Shelly_configure - Configure Shelly device
|
# Shelly_configure - Configure Shelly device or read general configuration
|
||||||
# acts as callable program Shelly_configure($hash,$channel,$cmd)
|
# acts as callable program Shelly_configure($hash,$channel,$cmd)
|
||||||
# and as callback program Shelly_configure($hash,$channel,$cmd,$err,$data)
|
# and as callback program Shelly_configure($hash,$channel,$cmd,$err,$data)
|
||||||
#
|
#
|
||||||
@ -848,21 +940,22 @@ sub Shelly_pwd($){
|
|||||||
sub Shelly_configure {
|
sub Shelly_configure {
|
||||||
my ($hash, $cmd, $err, $data) = @_;
|
my ($hash, $cmd, $err, $data) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $url;
|
|
||||||
my $state = $hash->{READINGS}{state}{VAL};
|
my $state = $hash->{READINGS}{state}{VAL};
|
||||||
my $net = $hash->{READINGS}{network}{VAL};
|
my $net = $hash->{READINGS}{network}{VAL};
|
||||||
return
|
return
|
||||||
if( $net !~ /connected/ );
|
if( $net !~ /connected/ );
|
||||||
|
|
||||||
my $model = AttrVal($name,"model","");
|
my $model = AttrVal($name,"model","generic");
|
||||||
my $creds = Shelly_pwd($hash);
|
my $creds = Shelly_pwd($hash);
|
||||||
|
|
||||||
if ( $hash && !$err && !$data ){
|
if ( $hash && !$err && !$data ){
|
||||||
$url = "http://$creds".$hash->{TCPIP}."/".$cmd;
|
my $url = "http://$creds".$hash->{TCPIP}."/".$cmd;
|
||||||
|
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,
|
||||||
callback=>sub($$$){ Shelly_configure($hash,$cmd,$_[1],$_[2]) }
|
timeout => $timeout,
|
||||||
|
callback => sub($$$){ Shelly_configure($hash,$cmd,$_[1],$_[2]) }
|
||||||
});
|
});
|
||||||
return undef;
|
return undef;
|
||||||
}elsif ( $hash && $err ){
|
}elsif ( $hash && $err ){
|
||||||
@ -880,6 +973,12 @@ sub Shelly_pwd($){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#-- if settings command, we obtain only basic settings
|
||||||
|
if( $cmd eq "settings/" ){
|
||||||
|
$hash->{SHELLYID} = $jhash->{'device'}{'hostname'};
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
#-- 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);
|
||||||
@ -907,17 +1006,19 @@ sub Shelly_pwd($){
|
|||||||
sub Shelly_status {
|
sub Shelly_status {
|
||||||
my ($hash, $err, $data) = @_;
|
my ($hash, $err, $data) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $url;
|
|
||||||
my $state = $hash->{READINGS}{state}{VAL};
|
my $state = $hash->{READINGS}{state}{VAL};
|
||||||
|
|
||||||
|
my $model = AttrVal($name,"model","generic");
|
||||||
my $creds = Shelly_pwd($hash);
|
my $creds = Shelly_pwd($hash);
|
||||||
|
|
||||||
if ( $hash && !$err && !$data ){
|
if ( $hash && !$err && !$data ){
|
||||||
$url = "http://$creds".$hash->{TCPIP}."/status";
|
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";
|
Log3 $name, 5,"[Shelly_status] Issue a non-blocking call to $url";
|
||||||
HttpUtils_NonblockingGet({
|
HttpUtils_NonblockingGet({
|
||||||
url => $url,
|
url => $url,
|
||||||
callback=>sub($$$){ Shelly_status($hash,$_[1],$_[2]) }
|
timeout => $timeout,
|
||||||
|
callback => sub($$$){ Shelly_status($hash,$_[1],$_[2]) }
|
||||||
});
|
});
|
||||||
return undef;
|
return undef;
|
||||||
}elsif ( $hash && $err ){
|
}elsif ( $hash && $err ){
|
||||||
@ -941,9 +1042,7 @@ sub Shelly_pwd($){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $model = AttrVal($name,"model","shelly1");
|
my $mode = AttrVal($name,"mode","");
|
||||||
my $mode = AttrVal($name,"mode","");
|
|
||||||
|
|
||||||
my $channels = $shelly_models{$model}[0];
|
my $channels = $shelly_models{$model}[0];
|
||||||
my $rollers = $shelly_models{$model}[1];
|
my $rollers = $shelly_models{$model}[1];
|
||||||
my $dimmers = $shelly_models{$model}[2];
|
my $dimmers = $shelly_models{$model}[2];
|
||||||
@ -1067,8 +1166,30 @@ 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
|
||||||
|
}elsif( $model eq "shellybulb" && $mode eq "white" ){
|
||||||
|
for( my $i=0;$i<$dimmers;$i++){
|
||||||
|
$subs = (($dimmers == 1) ? "" : "_".$i);
|
||||||
|
$ison = $jhash->{'lights'}[$i]{'ison'};
|
||||||
|
$ison =~ s/0|(false)/off/;
|
||||||
|
$ison =~ s/1|(true)/on/;
|
||||||
|
my $bri = $jhash->{'lights'}[$i]{'brightness'};
|
||||||
|
my $ct = $jhash->{'lights'}[$i]{'temp'};
|
||||||
|
$overpower = $jhash->{'lights'}[$i]{'overpower'};
|
||||||
|
$power = $jhash->{'meters'}[$i]{'power'};
|
||||||
|
$energy = (defined($jhash->{'meters'}[$i]{'total'}))?int($jhash->{'meters'}[$i]{'total'}/6)/10:"undefined";
|
||||||
|
readingsBulkUpdateIfChanged($hash,"state".$subs,$ison);
|
||||||
|
readingsBulkUpdateIfChanged($hash,"pct".$subs,$bri);
|
||||||
|
readingsBulkUpdateIfChanged($hash,"ct".$subs,$ct);
|
||||||
|
readingsBulkUpdateIfChanged($hash,"overpower".$subs,$overpower);
|
||||||
|
readingsBulkUpdateIfChanged($hash,"power".$subs,$power);
|
||||||
|
readingsBulkUpdateIfChanged($hash,"energy".$subs,$energy);
|
||||||
|
}
|
||||||
|
readingsBulkUpdateIfChanged($hash,"state","OK")
|
||||||
|
if ($dimmers > 1);
|
||||||
|
|
||||||
#-- we have a Shelly RGBW color device
|
#-- we have a Shelly RGBW color device
|
||||||
}elsif( $model eq "shellyrgbw" && $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/;
|
||||||
$ison =~ s/1|(true)/on/;
|
$ison =~ s/1|(true)/on/;
|
||||||
@ -1077,6 +1198,13 @@ sub Shelly_pwd($){
|
|||||||
my $green = $jhash->{'lights'}[0]{'green'};
|
my $green = $jhash->{'lights'}[0]{'green'};
|
||||||
my $blue = $jhash->{'lights'}[0]{'blue'};
|
my $blue = $jhash->{'lights'}[0]{'blue'};
|
||||||
my $white = $jhash->{'lights'}[0]{'white'};
|
my $white = $jhash->{'lights'}[0]{'white'};
|
||||||
|
my $gain = $jhash->{'lights'}[0]{'gain'};
|
||||||
|
if ( defined $gain && $gain != 100 ) {
|
||||||
|
$red = int ($red*$gain/100.0);
|
||||||
|
$blue = int ($blue*$gain/100.0);
|
||||||
|
$green = int ($green*$gain/100.0);
|
||||||
|
$white = int ($white*$gain/100.0);
|
||||||
|
}
|
||||||
my $rgb = sprintf("%02X%02X%02X", $red,$green,$blue);
|
my $rgb = sprintf("%02X%02X%02X", $red,$green,$blue);
|
||||||
|
|
||||||
readingsBulkUpdateIfChanged($hash,"rgb",$rgb);
|
readingsBulkUpdateIfChanged($hash,"rgb",$rgb);
|
||||||
@ -1138,21 +1266,22 @@ sub Shelly_pwd($){
|
|||||||
sub Shelly_dim {
|
sub Shelly_dim {
|
||||||
my ($hash, $channel, $cmd, $err, $data) = @_;
|
my ($hash, $channel, $cmd, $err, $data) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $url;
|
|
||||||
my $state = $hash->{READINGS}{state}{VAL};
|
my $state = $hash->{READINGS}{state}{VAL};
|
||||||
my $net = $hash->{READINGS}{network}{VAL};
|
my $net = $hash->{READINGS}{network}{VAL};
|
||||||
return
|
return
|
||||||
if( $net !~ /connected/ );
|
if( $net !~ /connected/ );
|
||||||
|
|
||||||
my $model = AttrVal($name,"model","");
|
my $model = AttrVal($name,"model","generic");
|
||||||
my $creds = Shelly_pwd($hash);
|
my $creds = Shelly_pwd($hash);
|
||||||
|
|
||||||
if ( $hash && !$err && !$data ){
|
if ( $hash && !$err && !$data ){
|
||||||
$url = "http://$creds".$hash->{TCPIP}."/$channel$cmd";
|
my $url = "http://$creds".$hash->{TCPIP}."/$channel$cmd";
|
||||||
|
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,
|
||||||
callback=>sub($$$){ Shelly_dim($hash,$channel,$cmd,$_[1],$_[2]) }
|
timeout => $timeout,
|
||||||
|
callback => sub($$$){ Shelly_dim($hash,$channel,$cmd,$_[1],$_[2]) }
|
||||||
});
|
});
|
||||||
return undef;
|
return undef;
|
||||||
}elsif ( $hash && $err ){
|
}elsif ( $hash && $err ){
|
||||||
@ -1229,13 +1358,12 @@ sub Shelly_pwd($){
|
|||||||
sub Shelly_updown {
|
sub Shelly_updown {
|
||||||
my ($hash, $cmd, $err, $data) = @_;
|
my ($hash, $cmd, $err, $data) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $url;
|
|
||||||
my $state = $hash->{READINGS}{state}{VAL};
|
my $state = $hash->{READINGS}{state}{VAL};
|
||||||
my $net = $hash->{READINGS}{network}{VAL};
|
my $net = $hash->{READINGS}{network}{VAL};
|
||||||
return
|
return
|
||||||
if( $net !~ /connected/ );
|
if( $net !~ /connected/ );
|
||||||
|
|
||||||
my $model = AttrVal($name,"model","");
|
my $model = AttrVal($name,"model","generic");
|
||||||
my $creds = Shelly_pwd($hash);
|
my $creds = Shelly_pwd($hash);
|
||||||
|
|
||||||
#-- empty cmd parameter
|
#-- empty cmd parameter
|
||||||
@ -1243,11 +1371,13 @@ sub Shelly_pwd($){
|
|||||||
if( !defined($cmd) );
|
if( !defined($cmd) );
|
||||||
|
|
||||||
if ( $hash && !$err && !$data ){
|
if ( $hash && !$err && !$data ){
|
||||||
$url = "http://$creds".$hash->{TCPIP}."/roller/0".$cmd;
|
my $url = "http://$creds".$hash->{TCPIP}."/roller/0".$cmd;
|
||||||
|
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,
|
||||||
callback=>sub($$$){ Shelly_updown($hash,$cmd,$_[1],$_[2]) }
|
timeout => $timeout,
|
||||||
|
callback => sub($$$){ Shelly_updown($hash,$cmd,$_[1],$_[2]) }
|
||||||
});
|
});
|
||||||
return undef;
|
return undef;
|
||||||
}elsif ( $hash && $err ){
|
}elsif ( $hash && $err ){
|
||||||
@ -1313,21 +1443,22 @@ sub Shelly_updown2($){
|
|||||||
sub Shelly_onoff {
|
sub Shelly_onoff {
|
||||||
my ($hash, $channel, $cmd, $err, $data) = @_;
|
my ($hash, $channel, $cmd, $err, $data) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $url;
|
|
||||||
my $state = $hash->{READINGS}{state}{VAL};
|
my $state = $hash->{READINGS}{state}{VAL};
|
||||||
my $net = $hash->{READINGS}{network}{VAL};
|
my $net = $hash->{READINGS}{network}{VAL};
|
||||||
return
|
return
|
||||||
if( $net !~ /connected/ );
|
if( $net !~ /connected/ );
|
||||||
|
|
||||||
my $model = AttrVal($name,"model","");
|
my $model = AttrVal($name,"model","generic");
|
||||||
my $creds = Shelly_pwd($hash);
|
my $creds = Shelly_pwd($hash);
|
||||||
|
|
||||||
if ( $hash && !$err && !$data ){
|
if ( $hash && !$err && !$data ){
|
||||||
$url = "http://$creds".$hash->{TCPIP}."/relay/".$channel.$cmd;
|
my $url = "http://$creds".$hash->{TCPIP}."/relay/".$channel.$cmd;
|
||||||
|
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,
|
||||||
callback=>sub($$$){ Shelly_onoff($hash,$channel,$cmd,$_[1],$_[2]) }
|
timeout => $timeout,
|
||||||
|
callback => sub($$$){ Shelly_onoff($hash,$channel,$cmd,$_[1],$_[2]) }
|
||||||
});
|
});
|
||||||
return undef;
|
return undef;
|
||||||
}elsif ( $hash && $err ){
|
}elsif ( $hash && $err ){
|
||||||
@ -1405,22 +1536,22 @@ sub Shelly_updown2($){
|
|||||||
sub Shelly_meter {
|
sub Shelly_meter {
|
||||||
my ($hash, $channel, $err, $data) = @_;
|
my ($hash, $channel, $err, $data) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $url;
|
|
||||||
my $state = $hash->{READINGS}{state}{VAL};
|
my $state = $hash->{READINGS}{state}{VAL};
|
||||||
my $net = $hash->{READINGS}{network}{VAL};
|
my $net = $hash->{READINGS}{network}{VAL};
|
||||||
return
|
return
|
||||||
if( $net !~ /connected/ );
|
if( $net !~ /connected/ );
|
||||||
|
|
||||||
my $model = AttrVal($name,"model","");
|
my $model = AttrVal($name,"model","generic");
|
||||||
|
|
||||||
my $creds = Shelly_pwd($hash);
|
my $creds = Shelly_pwd($hash);
|
||||||
|
|
||||||
if ( $hash && !$err && !$data ){
|
if ( $hash && !$err && !$data ){
|
||||||
$url = "http://$creds".$hash->{TCPIP}."/meter/".$channel;
|
my $url = "http://$creds".$hash->{TCPIP}."/meter/".$channel;
|
||||||
|
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,
|
||||||
callback=>sub($$$){ Shelly_meter($hash,$channel,$_[1],$_[2]) }
|
timeout => $timeout,
|
||||||
|
callback => sub($$$){ Shelly_meter($hash,$channel,$_[1],$_[2]) }
|
||||||
});
|
});
|
||||||
return undef;
|
return undef;
|
||||||
}elsif ( $hash && $err ){
|
}elsif ( $hash && $err ){
|
||||||
@ -1466,15 +1597,20 @@ sub Shelly_updown2($){
|
|||||||
Notes: <ul>
|
Notes: <ul>
|
||||||
<li>The attribute <code>model</code> <b>must</b> be set</li>
|
<li>The attribute <code>model</code> <b>must</b> be set</li>
|
||||||
<li>This module needs the JSON package</li>
|
<li>This module needs the JSON package</li>
|
||||||
<li>In Shelly switch devices or the Shelly dimmer device one may set URL values that are "hit" when the input or output status changes. Here one must set
|
<li>In Shelly button, switch, roller or dimmer devices one may set URL values that are "hit" when the input or output status changes.
|
||||||
|
This is useful to transmit status changes arising from locally pressed buttons directly to FHEM by setting
|
||||||
|
<ul>
|
||||||
|
<li> <i>Button switched ON url</i>: http://<FHEM IP address>:<Port>/fhem?XHR=1&cmd=get%20<Devicename>%20status</li>
|
||||||
|
</ul>
|
||||||
|
If one wants to detach the button from the output, one may generate an additional reading <i>button</i> by setting in the Shelly
|
||||||
<ul>
|
<ul>
|
||||||
<li> For <i>Button switched ON url</i>: http://<FHEM IP address>:<Port>/fhem?XHR=1&cmd=set%20<Devicename>%20<b>button_on</b>%20[<channel>]</li>
|
<li> For <i>Button switched ON url</i>: http://<FHEM IP address>:<Port>/fhem?XHR=1&cmd=set%20<Devicename>%20<b>button_on</b>%20[<channel>]</li>
|
||||||
<li> For <i>Button switched OFF url</i>: http://<FHEM IP address>:<Port>/fhem?XHR=1&cmd=set%20<Devicename>%20<b>button_off</b>%20[<channel>]</li>
|
<li> For <i>Button switched OFF url</i>: http://<FHEM IP address>:<Port>/fhem?XHR=1&cmd=set%20<Devicename>%20<b>button_off</b>%20[<channel>]</li>
|
||||||
<li> For <i>Output switched ON url</i>: http://<FHEM IP address>:<Port>/fhem?XHR=1&cmd=set%20<Devicename>%20<b>out_on</b>%20[<channel>]</li>
|
|
||||||
<li> For <i>Output switched OFF url</i>: http://<FHEM IP address>:<Port>/fhem?XHR=1&cmd=set%20<Devicename>%20<b>out_off</b>%20[<channel>]</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
Attention: Of course, a csrfToken must be included as well - or a proper <i>allowed</i> device declared.</li>
|
Attention: Of course, a csrfToken must be included as well - or a proper <i>allowed</i> device declared.</li>
|
||||||
|
<li>If the model attribute is set to <i>generic</i>, the device does not contain any actors, it is just a placeholder for arbitrary sensors</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a name="Shellyset" id="Shellyset"></a>
|
<a name="Shellyset" id="Shellyset"></a>
|
||||||
<h4>Set</h4>
|
<h4>Set</h4>
|
||||||
For all Shelly devices
|
For all Shelly devices
|
||||||
@ -1546,8 +1682,8 @@ sub Shelly_updown2($){
|
|||||||
<h4>Get</h4>
|
<h4>Get</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<code>get <name> config <registername> [<channel>]</code>
|
<code>get <name> config [<registername>] [<channel>]</code>
|
||||||
<br />get the value of a configuration register and writes it in reading config</li>
|
<br />get the value of a configuration register and writes it in reading config. If the register name is omitted, only general data like e.g. the SHELLYID are fetched.</li>
|
||||||
<li>
|
<li>
|
||||||
<code>get <name> registers</code>
|
<code>get <name> registers</code>
|
||||||
<br />displays the names of the configuration registers for this device</li>
|
<br />displays the names of the configuration registers for this device</li>
|
||||||
@ -1562,13 +1698,17 @@ sub Shelly_updown2($){
|
|||||||
<h4>Attributes</h4>
|
<h4>Attributes</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>attr <name> shellyuser <shellyuser></code><br>username for addressing the Shelly web interface</li>
|
<li><code>attr <name> shellyuser <shellyuser></code><br>username for addressing the Shelly web interface</li>
|
||||||
<li><<code>attr <name> model shelly1|shelly1pm|shelly2|shelly2.5|shelly4|shellyplug|shellydimmer|shellyrgbw </code>
|
<li><<code>attr <name> model generic|shelly1|shelly1pm|shelly2|shelly2.5|shelly4|shellyplug|shellydimmer|shellyrgbw </code>
|
||||||
<br />type of the Shelly device</li>
|
<br />type of the Shelly device. >If the model attribute is set to <i>generic</i>, the device does not contain any actors,
|
||||||
|
it is just a placeholder for arbitrary sensors</li>
|
||||||
<li><code>attr <name> mode relay|roller (only for model=shelly2/2.5) mode white|color (only for model=shellyrgbw)</code>
|
<li><code>attr <name> mode relay|roller (only for model=shelly2/2.5) mode white|color (only for model=shellyrgbw)</code>
|
||||||
<br />type of the Shelly device</li>
|
<br />type of the Shelly device</li>
|
||||||
<li>
|
<li>
|
||||||
<code><interval></code>
|
<code><interval></code>
|
||||||
<br />Update interval for reading in seconds. The default is 60 seconds, a value of 0 disables the automatic update. </li>
|
<br />Update interval for reading in seconds. The default is 60 seconds, a value of 0 disables the automatic update. </li>
|
||||||
|
<li>
|
||||||
|
<code><timeout></code>
|
||||||
|
<br />Timeout in seconds for HttpUtils_NonblockingGet. The default is 4 seconds. Careful: Use this attribute only if you get timeout errors in your log.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<br/>For Shelly switching devices (mode=relay for model=shelly2/2.5, standard for all other switching models)
|
<br/>For Shelly switching devices (mode=relay for model=shelly2/2.5, standard for all other switching models)
|
||||||
<ul>
|
<ul>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user