From 081ffe40a1fb82c5cd01139b57a40d99c55e9a0b Mon Sep 17 00:00:00 2001 From: Starkstrombastler <> Date: Fri, 7 Feb 2025 16:58:46 +0000 Subject: [PATCH] 36_Shelly.pm: Slat Control git-svn-id: https://svn.fhem.de/fhem/trunk@29632 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 1 + fhem/FHEM/36_Shelly.pm | 97 ++++++++++++++++++++++++++++-------------- 2 files changed, 65 insertions(+), 33 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index bcace865f..80d232aad 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,6 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it + - feature: 36_Shelly: Slat Control / Roller Gen2+ - feature: 73_PRESENCE2.pm: neues Attribut pingParam commandRef überarbeitet - bugfix: 98_vitoconnect.pm: installationID check at least length 2 diff --git a/fhem/FHEM/36_Shelly.pm b/fhem/FHEM/36_Shelly.pm index 5a42808e9..48d3a6e8f 100644 --- a/fhem/FHEM/36_Shelly.pm +++ b/fhem/FHEM/36_Shelly.pm @@ -148,6 +148,8 @@ # 6.02 Beta4 fix: reading state of ShellyEM50 # 6.02 fix: command "set button_on" w/o channel # 6.02.1 fix: update of input/output readings +# 6.02.2 fix: update interval if interval is set to 0 +# new: slat control für rollers Gen2+ # to do roller: get maxtime open/close from shelly gen1 # get status on stopp even when interval == 0 @@ -171,17 +173,17 @@ sub Shelly_Set ($@); sub Shelly_status(@); #-- globals on start -my $version = "6.02.1 03.02.2025"; +my $version = "6.02.2 07.02.2025"; my $defaultINTERVAL = 60; my $multiplyIntervalOnError = 1.0; # mechanism disabled if value=1 my %shelly_firmware = ( # latest known versions # as of 29.08.2024 # used by sub Shelly_firmwarecheck - "gen1" => "1.14.0", + "gen1" => "1.14.0", # v1.14.1-rc1 "shelly4" => "1.6.6", - "gen2" => "1.3.3", # some: 1.4.4 - "walldisplay" => "2.2.1" + "gen2" => "1.3.3", # some: 1.4.4 v1.5.0-beta2 + "walldisplay" => "2.2.1" # v2.3.0-beta5 ); #-- Time slices in seconds for time zone Germany CET/CEST @@ -200,7 +202,7 @@ my %periods = ( my %attributes = ( "modes" => " mode:relay,roller,white,color", "multichannel" => " defchannel", - "roller" => " pct100:open,closed maxtime maxtime_close maxtime_open", + "roller" => " pct100:open,closed maxtime maxtime_close maxtime_open slat_control slat_pos", "dimmer" => " dimstep", "input" => " showinputs:show,hide", "emeter" => " Energymeter_F Energymeter_P Energymeter_R EMchannels:ABC_,L123_,_ABC,_L123". @@ -1332,6 +1334,11 @@ sub Shelly_Attr(@) { if( $shelly_models{$attrVal}[2]==0 ){ # no dimmer $hash->{'.AttrList'} =~ s/ dimstep//; } + + if( $shelly_models{$attrVal}[1]>0 && $mode ne "roller" || $shelly_models{$attrVal}[4]==0 ){ # no roller or Gen1 + $hash->{'.AttrList'} =~ s/ slat_control//; + $hash->{'.AttrList'} =~ s/ slat_pos//; + } if( $attrVal =~ /pro3em|proem50/ ){ # "shellyproem50" "shellypro3em" $hash->{'.AttrList'} =~ s/\smaxpower//; @@ -1664,6 +1671,18 @@ sub Shelly_Attr(@) { } #--------------------------------------- + }elsif( $cmd eq "set" && $attrName eq "slat_control" ){ + $error="The slat_control attribute is set by \'get settings\' only"; + Log3 $name,1,"[Shelly_Attr] $name\: $error "; + return $error; + #--------------------------------------- + }elsif( $cmd eq "set" && $attrName eq "slat_pos" ){ + if( $attrVal<0 || $attrVal>100 ){ + $error="slat_pos must be within the range 0...100"; + Log3 $name,1,"[Shelly_Attr] $name\: $error"; + return $error; + } + #--------------------------------------- }elsif( $cmd eq "set" && $attrName eq "pct100" ){ if( ($shelly_models{$model}[1] == 0 || $mode ne "roller") && $init_done ){ $error="Setting the pct100 attribute only works for devices in roller mode"; @@ -2425,7 +2444,6 @@ sub Shelly_Set ($@) { readingsSingleUpdate($hash,"position",$1,1); } Shelly_status($hash,"Shelly_Set $cmd",0.8); # scheduled update if not pending - # Shelly_status($hash,"Shelly_Set $cmd (2nd)",5) if( $cmd =~ /opening|closing/ ); # update in 5 seconds when driving return undef; #--------------------------- }elsif( $cmd =~ /actions/ ){ @@ -2932,7 +2950,8 @@ sub Shelly_Set ($@) { }elsif( $cmd eq "pct" || $cmd =~ /pos/ || $cmd eq "delta" ){ my $targetpct = $value; my $pos = ReadingsVal($name,"position",""); - my $pct = ReadingsVal($name,"pct",undef); + my $pct = ReadingsVal($name,"pct",0); + $pct = 0 if( $pct eq "unknown" ); # when position is lost if( $cmd eq "pct" && "$value" =~ /[\+-]\d*/ ){ $targetpct = eval($pct."$value"); } @@ -3002,6 +3021,9 @@ sub Shelly_Set ($@) { $targetpct = ($pctnormal ? $targetpct : 100 - $targetpct); $cmd="/rpc/Cover.GoToPosition"; $CMD2="?pos=$targetpct&id=$channel"; + if( AttrVal($name,"slat_control",undef ) eq "enabled" ){ + $CMD2 .="&slat_pos=".AttrVal($name,"slat_pos",50 ); + } }else{ $cmd="/rpc/$cmd"; $CMD2="?id=$channel"; @@ -3473,7 +3495,7 @@ sub Shelly_status(@){ Log3 $name,5,"[Shelly_status:1] $name: callFn=".($callFn//"undefiniert")." sched=".($scheduled//"no").", helper=".$hash->{helper}{timer}; #4 if( $scheduled//0 ){ Log3 $name,6,"[Shelly_status:1a] $name: set internal Timer ---and------BYE------"; - readingsSingleUpdate($hash,"/_nextUpdateTimer","$scheduled Sec $callFn",1) + readingsSingleUpdate($hash,"/_nextUpdateTimer","$scheduled sec $callFn",1) if( AttrVal($name,'timeout',undef) ); RemoveInternalTimer($hash,"Shelly_status"); InternalTimer(time()+$scheduled, "Shelly_status", $hash); @@ -3529,7 +3551,6 @@ sub Shelly_status(@){ $msg .= "D next status call scheduled in $timer seconds"; } Log3 $name,4,$msg; - readingsSingleUpdate($hash,"/_nextUpdateTimer",($timer>0?$timer:"-")." ".$callFn,1) if( AttrVal($name,'timeout',undef) ); } #end Shelly_status() ########################## @@ -3620,9 +3641,6 @@ sub Shelly_status1G { } } Shelly_readingsBulkUpdate($hash,"timer".$subs,$remaining,"time"); - ## #-- next update timer - ## $statusTmr1G = minNum($hash->{INTERVAL},$remaining+0.95) if( $remaining>0 ); - ## Shelly_readingsBulkUpdate($hash,"/_nextUpdateTimer",$statusTmr1G,"time") if( AttrVal($name,'timeout',undef) ); } #-- we have a shellyuni device @@ -4020,7 +4038,6 @@ sub Shelly_status1G { #-- override scheduling next status update: perform multiple updates $statusTmr1G = $statusTmr1G / ceil($statusTmr1G/$hash->{INTERVAL}); # use POSIX required } - Shelly_readingsBulkUpdate($hash,"/_nextUpdateTimer",$statusTmr1G,"time") if( AttrVal($name,'timeout',undef) ); Log3 $name,6,"[Shelly_status1G:ti] $name timer=$statusTmr1G INTERVAL=".$hash->{INTERVAL}." helper=".$hash->{helper}{timer}; readingsEndUpdate($hash,1); @@ -4364,7 +4381,7 @@ sub Shelly_status2G { my $timer = $hash->{INTERVAL}; # timer in seconds for next update of status via Shelly_status() if( $hash->{helper}{timer}>0 ){ $timer=$hash->{helper}{timer}; - Log3 $name,2,"$name have set timer to helper"; + Log3 $name,2,"$name have set timer=$timer to helper"; } readingsBeginUpdate($hash); @@ -4732,8 +4749,10 @@ sub Shelly_status2G { $tmrDur = round($tmrDur,1); Log3 $name,4,"[Shelly_status2G:tmr] $name calculated timer$subs from start and duration is $tmrDur"; #5 } - $timer = minNum( $timer, $tmrDur ); - Log3 $name,4,"[Shelly_status2G:timer] $name calculated update timer is $timer"; #5 +Log3 $name,2,"[Shelly_status2G:timex] $name calculated update timer is $timer vs duration=$tmrDur"; #5 +# $timer = minNum( $timer, $tmrDur ); + $timer = $hash->{INTERVAL}>0 ? minNum( $hash->{INTERVAL},$tmrDur ) : $tmrDur;# + Log3 $name,2,"[Shelly_status2G:timer] $name calculated update timer is $timer"; #5 $tmrDur .= " sec = ".FmtDateTime($tmrEnd) if( $hash->{units} ); readingsBulkUpdateMonitored($hash,"timer".$subs,$tmrDur); }elsif( $jhash->{$CC}{move_started_at} ){ # cover, if moving @@ -4863,20 +4882,7 @@ sub Shelly_status2G { fhem("deletereading $name error",1) if( ReadingsAge($name,"error",-1)>36000 ); # delete after 10 hours, silent #-- scheduling next status update - ##my $callFn=$hash->{callFn}; - ##$callFn = "ov" if( !defined($callFn) ); - ##delete $hash->{callFn}; - Log3 $name,7,"[Shelly_status2G:ti] $name timer=$timer INTERVAL=".$hash->{INTERVAL}." helper=".$hash->{helper}{timer}; - if( $timer == $hash->{INTERVAL} ){ - Shelly_status($hash,"Shelly_status2G iv0",$timer); - }elsif( $timer < $hash->{INTERVAL} || $hash->{INTERVAL} == 0 ){ - #-- override scheduling next status update - Shelly_status($hash,"Shelly_status2G ov",$timer); - }elsif( $timer > $hash->{INTERVAL} + 3 ){ - #-- override scheduling next status update: perform multiple updates - $timer = $timer / ceil($timer/$hash->{INTERVAL}); # use POSIX required - Shelly_status($hash,"Shelly_status2G tw",$timer); - } + Shelly_status($hash,"Shelly_status2G",$timer) if( $timer>0 ); if( $hash->{helper}{timer} == 0 && $hash->{INTERVAL}>0 ){ #-- call settings @@ -4900,6 +4906,7 @@ sub Shelly_settings2G { my $name = $hash->{NAME}; my $comp = $param->{comp}; my $model= AttrVal($name,"model","generic"); + my @chnls=@{$shelly_models{$model}}; # extract the array of 'model' out of the hash my $subs; my $range_extender_enable; @@ -5074,13 +5081,21 @@ sub Shelly_settings2G { } } - # looking for roller maxtime values - if( $shelly_models{$model}[1]>0 && AttrVal($name,"mode","-") eq "roller" ){ + # looking for roller maxtime and slat-control values + if( $shelly_models{$model}[1]>0 && AttrVal($name,"mode","-") eq "roller" ){ # $chnls foreach my $limit ( 'maxtime_open','maxtime_close' ){ my $maxtime=$jhash->{'cover:0'}{$limit}; # set attribute in silent mode, but do not save to cfg-file fhem("attr -silent $name $limit $maxtime") if( AttrVal($name,$limit,0) != $maxtime ); } + my $sc=$jhash->{'cover:0'}{slat}{enable}//-1; + if( $sc == 1 ){ + # $sc = $jhash->{'cover:0'}{slat}{open_time}; + # $sc .= ",".$jhash->{'cover:0'}{slat}{close_time}; + fhem("attr -silent $name slat_control enabled"); + }elsif( $sc == 0 ){ + fhem("attr -silent $name slat_control disabled"); + } }else{ ### looking for auto_on & auto_off (components: switch & light) my @comps= ( "switch", "cover", "light" ); @@ -7672,12 +7687,20 @@ sub Shelly_HttpResponse($){ attr <name> maxtime_open <int> Gen1
attr <name> maxtime_open <float> Gen2
time needed (in seconds) for a complete drive upward +
  • + + attr <name> slat_control enabled|disabled +
    whether slat control is enabled by the Shelly
  • +
  • + + attr <name> slat_pos <0...100> +
    percentual value for the pos of the slats
  • attr <name> pct100 open|closed (default:open)
    roller or blind devices only: is pct=100 open or closed ?
  • -
    For energy meter ShellyPro3EM /ShellyProEM50 +
    For energy meter ShellyPro3EM/ShellyProEM50