From 94af0948a3539e4c9f2acf9f9a169bcf2658c5e9 Mon Sep 17 00:00:00 2001 From: dev0 <> Date: Sun, 23 Dec 2018 10:56:08 +0000 Subject: [PATCH] 34_ESPEasy: improved deepsleep support git-svn-id: https://svn.fhem.de/fhem/trunk@18034 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 1 + fhem/FHEM/34_ESPEasy.pm | 289 +++++++++++++++++++++++++++++++++------- 2 files changed, 245 insertions(+), 45 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index c7456d3b2..04306a2b9 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: 34_ESPEasy: improved deepsleep support - feature: 73_AutoShuttersControl: add maxBrightness for morning open - feature: 73_AutoShuttersControl: support for shading, fix bugs - feature: 37_harmony: use websockets if xmpp is not available diff --git a/fhem/FHEM/34_ESPEasy.pm b/fhem/FHEM/34_ESPEasy.pm index 3efe7c815..cd3a1874a 100644 --- a/fhem/FHEM/34_ESPEasy.pm +++ b/fhem/FHEM/34_ESPEasy.pm @@ -37,7 +37,7 @@ use HttpUtils; use Color; use SetExtensions; -my $module_version = "2.01"; # Version of this module +my $module_version = "2.1"; # Version of this module # ------------------------------------------------------------------------------ # modul version and required ESP Easy firmware / JSON lib version @@ -59,6 +59,8 @@ my $d_displayTextEncode = 1; # urlEncode Text for Displays my $d_displayTextWidth = 0; # display width, 0 => disable formating my $d_bridgePort = 8383; # bridge port if none specified my $d_disableLogin = 0; # Disable login if HTTP Code 302 +my $d_maxCmdDuration = 3; # max cmd exec time, subtracted from awake time +my $d_sleepReading = 'sleepState'; # Reading used for Indication of deep sleep # ------------------------------------------------------------------------------ # defaults for user defined cmds @@ -158,12 +160,14 @@ my %ee_attr = ( }, device => { adjustValue => { widget => "" }, + deepsleep => { widget => "0,1" }, disableRiskyCmds => { widget => "" }, displayTextEncode => { widget => "1,0" }, displayTextWidth => { widget => "" }, IODev => { widget => "" }, Interval => { widget => "" }, mapLightCmds => { widget => "lights,nfx" }, + maxCmdDuration => { widget => "slider,0,0.25,15,1" }, parseCmdResponse => { widget => "" }, pollGPIOs => { widget => "" }, presenceCheck => { widget => "1,0" }, @@ -263,6 +267,7 @@ sub ESPEasy_initDevSets($) sendto => { args => 2, url => $d_urlSys, widget => "", usage => " " }, sendtohttp => { args => 3, url => $d_urlSys, widget => "", usage => " " }, sendtoudp => { args => 3, url => $d_urlSys, widget => "", usage => " " }, + nosleep => { args => 0, url => $d_urlSys, widget => "", usage => "" }, taskvalueset => { args => 3, url => $d_urlSys, widget => "", usage => " " }, taskvaluesetandrun => {args=> 3, url => $d_urlSys, widget => "", usage => " " }, taskrun => { args => 1, url => $d_urlSys, widget => "", usage => "" }, @@ -568,6 +573,7 @@ sub ESPEasy_Define($$) # only called when defined, not on reload. use constant HAS_AF_INET6 => defined eval { Socket::AF_INET6() }; Log3 $name, 2, "$type $name: WARNING: Your system seems to have no IPv6 support." if !HAS_AF_INET6; } + $hash->{MODEL} = 'Bridge v'.$module_version; } #--- DEVICE ------------------------------------------------- @@ -710,7 +716,7 @@ sub ESPEasy_Get_queuesize(@) sub ESPEasy_Get_queuecontent(@) { my ($hash, $name, $cmd, @args) = @_; - my $host = $args[0]; + my $host = defined $args[0] ? $args[0] : ""; my $ret; my $i = 0; my $j = 0; my $mseclog = AttrVal("global","mseclog",0); @@ -745,7 +751,7 @@ sub ESPEasy_Set($$@) my ($type, $subtype) = ($hash->{TYPE}, $hash->{SUBTYPE}); # case insensitive - $cmd = lc($cmd) if $cmd; + $cmd = lc($cmd) if $cmd && $cmd !~ m/^(attrTemplate)$/; # get current cmd list if cmd is __unknown__ my $clist = ESPEasy_isCmdAvailable($hash,$cmd); @@ -900,11 +906,9 @@ sub ESPEasy_Set($$@) Log3 $name, 5, "$type $name: set $name $cmd ".join(" ",@params). " (mappings done)" if $cmd !~ m/^(\?|user|pass|help)$/; Log3 $name, 5, "$type $name: IOWrite ( \$defs{$name}, \$defs{$name}, $cmd, (\"".join("\",\"",@params)."\") )"; - Log3 $name, 2, "$type $name: Device seems to be in sleep mode, sending command nevertheless." - if (defined $hash->{SLEEP} && $hash->{SLEEP} ne "0"); # send cmd with required args to IO Device - my $parseCmd = ESPEasy_isParseCmd($hash,$cmd); # should response be parsed and dispatched + my $parseCmd = ESPEasy_isParseCmd($hash,$cmd); # should response be parsed and dispatched? IOWrite($hash, $hash, $parseCmd, $cmd, @params); return undef; } @@ -1077,6 +1081,10 @@ sub ESPEasy_Read($) { push(@values,"i||".$intVal."||".$json->{data}{ESP}{$intVal}."||0"); } + # if ESP is awaked then yield dequeuing + my $s = defined $json->{data}{ESP}{sleep} ? $json->{data}{ESP}{sleep} : undef; + ESPEasy_httpReqDequeue_onAwake($bhash, $peer, $s, $espName, $ident); + # push sensor value in @values foreach my $vKey (keys %{$json->{data}{SENSOR}}) { if(ref $json->{data}{SENSOR}{$vKey} eq ref {} @@ -1138,7 +1146,11 @@ sub ESPEasy_Write($$$@) #called from logical's IOWrite (end of SetFn) ESPEasy_statusRequest($hash); return undef; } - my $retry = 0; + + $hash->{helper}{maxCmdDuration}{$dhash->{HOST}} + = defined $dhash->{MAX_CMD_DURATION} + ? $dhash->{MAX_CMD_DURATION} + : $d_maxCmdDuration; # a hash is more easy to handle in the following subs... my $cmdHash = { @@ -1153,6 +1165,7 @@ sub ESPEasy_Write($$$@) #called from logical's IOWrite (end of SetFn) ts => ESPEasy_timeStamp(), authRetry => 0, admpwd => $dhash->{sec}{admpwd}, + sleep => defined $dhash->{ESP_SLEEP} ? $dhash->{ESP_SLEEP} : undef, }; ESPEasy_httpReq($hash, $cmdHash); @@ -1246,6 +1259,18 @@ sub ESPEasy_Notify($$) ESPEasy_initDevSets($hash); } + elsif ($3 eq "deepsleep") { + my $ds = defined $1 || (defined $4 && $4 == 0) ? 0 : 1; + $hash->{ESP_SLEEP} = $ds; + InternalTimer(0, sub() { + readingsSingleUpdate($hash, $d_sleepReading, ($ds eq "1" ? "sleeping" : "awaked"), 1)}, $name) + } + + elsif ($3 eq "maxCmdDuration") { + $hash->{MAX_CMD_DURATION} = defined $1 ? $d_maxCmdDuration : $4; + } + + else { #Log 5, "$type $name: Attribute $3 not handeled by NotifyFn "; } @@ -1255,7 +1280,17 @@ sub ESPEasy_Notify($$) elsif (m/^(INITIALIZED|REREADCFG|DEFINED $name)$/) { ESPEasy_initDevSets($hash); ESPEasy_initDevAttrs($hash); - ESPEasy_TcpServer_Open($hash) if $hash->{SUBTYPE} eq "bridge"; + if ($hash->{SUBTYPE} eq "bridge") { + ESPEasy_TcpServer_Open($hash); + } + else { + $hash->{MAX_CMD_DURATION} = AttrVal($name, "maxCmdDuration", $d_maxCmdDuration); + my $ds = AttrVal($name, "deepsleep", undef); + if (defined $ds) { + $hash->{ESP_SLEEP} = $ds; + InternalTimer(0, sub(){readingsSingleUpdate($hash, $d_sleepReading, ($ds eq "1" ? "sleeping" : "awaked"), 1)}, $name); + } + } } else { #should never be reached @@ -1344,7 +1379,7 @@ sub ESPEasy_Attr(@) $ret = "0,1,2" if ($cmd eq "set" && not $aVal =~ m/^(0|1|2)$/) } - elsif ($aName =~ m/^(autosave|autocreate|authentication|disable|deepSleep)$/ + elsif ($aName =~ m/^(autosave|autocreate|authentication|disable|deepsleep)$/ || $aName =~ m/^(presenceCheck|displayTextEncode|resendFailedCmd)$/) { $ret = "0,1" if ($cmd eq "set" && not $aVal =~ m/^(0|1)$/)} @@ -1424,6 +1459,11 @@ sub ESPEasy_Attr(@) : ($hash->{INTERVAL} = $aVal) } + elsif ($aName eq "maxCmdDuration") { + $ret = "decimal or floating point" + if ($cmd eq "set" && $aVal !~ m/^\d+(\.\d)*$/); + } + elsif ($aName eq "userSetCmds") { $ret = ESPEasy_Attr_userSetCmds($hash, $cmd, $aName, $aVal); $ret = "a perl hash. See command reference for details.\n\n" @@ -1436,7 +1476,7 @@ sub ESPEasy_Attr(@) ." ct => { args => 1, url => \"/myUrl\", widget => \"colorpicker,CT,2000,100,4500\", usage => \"\" }\n" ." }\n" .")\n" - if $ret; + if defined $ret; } if (!$init_done) { @@ -1490,7 +1530,7 @@ sub ESPEasy_Attr_userSetCmds(@) { # Delete Attribute, afterwards notifyFn will build new cmdhash in $data{ESPEasy}{$name}{sets}... else { - # do nothing + return undef; } # eval() above accepts single string expressions... @@ -1567,6 +1607,18 @@ sub ESPEasy_Delete($$) } +# ------------------------------------------------------------------------------ +sub ESPEasy_State($$$$) +{ + my ($hash, $time, $reading, $val) = @_; + + if($reading eq "state" && $val eq "inactive") { + readingsSingleUpdate($hash, "state", "inactive", 1); + } + return undef; +} + + # ------------------------------------------------------------------------------ sub ESPEasy_dispatch($$$@) #called by bridge -> send to logical devices { @@ -1591,18 +1643,6 @@ sub ESPEasy_dispatch($$$@) #called by bridge -> send to logical devices } -# ------------------------------------------------------------------------------ -sub ESPEasy_State($$$$) -{ - my ($hash, $time, $reading, $val) = @_; - - if($reading eq "state" && $val eq "inactive") { - readingsSingleUpdate($hash, "state", "inactive", 1); - } - return undef; -} - - # ------------------------------------------------------------------------------ sub ESPEasy_dispatchParse($$$) # called by logical device (defined by { # $hash->{ParseFn}) @@ -1651,6 +1691,9 @@ sub ESPEasy_dispatchParse($$$) # called by logical device (defined by Log3 $name, 5, "$type $name: Received: $msg"; if (defined $hash && $hash->{TYPE} eq "ESPEasy" && $hash->{SUBTYPE} eq "device") { + + readingsBeginUpdate($hash); + my @logInternals; foreach (@v) { my ($cmd,$reading,$value,$vType) = split("\\|\\|",$_); @@ -1695,19 +1738,23 @@ sub ESPEasy_dispatchParse($$$) # called by logical device (defined by $value = $orgVal; } - readingsSingleUpdate($hash, $reading, $value, 1); + my $genEvent = $reading ne "sleepState" + ? 1 + : ( AttrVal($name, "deepsleep", 0) eq 1 ? 1 : 0 ); + + readingsBulkUpdate($hash, $reading, $value, $genEvent); my $adj = ($orgVal ne $value) ? " [adjusted]" : ""; Log3 $name, 4, "$type $name: $reading: $value".$adj if defined $value && $reading !~ m/^\./; #no leading dot # used for presence detection - $hash->{helper}{received}{$reading} = time(); + $hash->{helper}{received}{$reading} = time() if $reading ne $d_sleepReading; # recalc RGB reading if a PWM channel has changed if (AttrVal($name,"rgbGPIOs",0) && $reading =~ m/\d$/i) { my ($r,$g,$b) = ESPEasy_gpio2RGB($hash); if (($r ne "" && uc ReadingsVal($name,"rgb","") ne uc $r.$g.$b) ) { - readingsSingleUpdate($hash, "rgb", $r.$g.$b, 1); + readingsBulkUpdate($hash, "rgb", $r.$g.$b, 1); } } @@ -1716,10 +1763,7 @@ sub ESPEasy_dispatchParse($$$) # called by logical device (defined by # --- Internals ----------------------------------------------- elsif ($cmd eq "i") { # add human readable text to node_type_id - $value .= defined $ee_map{build}{$value}{type} - ? ": " . $ee_map{build}{$value}{type} - : ": unknown node type id" - if $reading eq "node_type_id"; + $value = defined $ee_map{build}{$value}{type} ? $ee_map{build}{$value}{type} : $value;# if $reading eq "node_type_id"; # no value given $value = "" if !defined $value || $value eq ""; @@ -1738,7 +1782,7 @@ sub ESPEasy_dispatchParse($$$) # called by logical device (defined by $hash->{"WARNING"} = $value; # CommandTrigger(undef, "$name ...."); } - #readingsSingleUpdate($hash, $reading, $value, 1); + #readingsBulkUpdate($hash, $reading, $value, 1); } # --- Notice (just log) --------------------------------------- @@ -1760,9 +1804,33 @@ sub ESPEasy_dispatchParse($$$) # called by logical device (defined by Log3 $name, 5, "$type $name: Internals: ".join(" ",@logInternals) if scalar @logInternals > 0; - ESPEasy_checkPresence($hash) if ReadingsVal($name,"presence","") ne "present"; - ESPEasy_setState($hash); + if (defined $hash->{ESP_BUILD}) { + my $model = defined $hash->{ESP_NODE_TYPE_ID} ? $hash->{ESP_NODE_TYPE_ID} . " - Build " : "ESP Easy - Build "; + $model .= $hash->{ESP_BUILD}; + $hash->{MODEL} = $model; +# readingsBulkUpdate($hash, "model", $model, 0); + } + # Remove sleepState Reading if device does not use deep sleep + CommandDeleteReading(undef, "$name $d_sleepReading") + if (ReadingsVal($name, $d_sleepReading, undef) + && defined $hash->{ESP_SLEEP} && $hash->{ESP_SLEEP} eq "0" + ); + + readingsEndUpdate($hash, 1); + +# ESPEasy_checkPresence($hash) if ReadingsVal($name,"presence","") ne "present"; +# ESPEasy_setState($hash); + + # yield presenceCheck and setState + InternalTimer( + gettimeofday(), + sub() { + ESPEasy_checkPresence($hash) if ReadingsVal($name,"presence","") ne "present"; + ESPEasy_setState($hash); + }, + "$name.checkPresence.setState" + ); } else { #autocreate failed @@ -1821,6 +1889,7 @@ sub ESPEasy_httpReq(@) my $url; # queue http requests or continue if there are no queued cmds + # command will also be queued if ESP is in deepsleep mode return undef if ESPEasy_httpReqQueue($hash, $cmdHash); $cmdHash->{retry}++; @@ -2031,16 +2100,25 @@ sub ESPEasy_httpReqQueue(@) $hash->{helper}{sessions}{$host} = 0 if !defined $hash->{helper}{sessions}{$host}; # is queueing enabled? if ($hash->{MAX_HTTP_SESSIONS}) { - # do queueing if max sessions are already in use - if ($hash->{helper}{sessions}{$host} >= $hash->{MAX_HTTP_SESSIONS} ) { + # queue if max sessions are already in use or if ESP is deepsleep mode + if ($hash->{helper}{sessions}{$host} >= $hash->{MAX_HTTP_SESSIONS} + # ESP already send data, so we know if and wheen it goes to sleep + || ( defined $hash->{helper}{awaked} && defined $hash->{helper}{awaked}{$host} && $hash->{helper}{awaked}{$host} - gettimeofday() < $hash->{helper}{maxCmdDuration}{$host} ) + # ESP did not send any data right now, but device has defined $hash->{ESP_SLEEP} + || ( !(defined $hash->{helper}{awaked} && defined $hash->{helper}{awaked}{$host}) && defined $cmdHash->{sleep} && $cmdHash->{sleep} > 0 ) + ) { # max queue size reached if ($queueSize < $hash->{MAX_QUEUE_SIZE}) { push(@{$hash->{helper}{queue}{$host}}, $cmdHash); - Log3 $name, 4, "$type $name: Queuing: $host $cmdHash->{ident} '$cmd $cmdArgs' ($queueSize)"; + Log3 $name, 4, "$type $name: Queuing: $host $cmdHash->{ident} cmd:" + . "'$cmd $cmdArgs' queueSize:".($queueSize +1)." reason:" + . ($hash->{helper}{sessions}{$host} >= $hash->{MAX_HTTP_SESSIONS} + ? "maxSessions" + : "deepsleep"); return 1; } else { - Log3 $name, 2, "$type $name: set $cmd $cmdArgs (skipped due to queue size exceeded: $hash->{MAX_QUEUE_SIZE})"; + Log3 $name, 2, "$type $name: set $cmd $cmdArgs (skipped due to max queue size exceeded: $hash->{MAX_QUEUE_SIZE})"; return 1; } } @@ -2062,11 +2140,20 @@ sub ESPEasy_httpReqDequeue($$) && defined $hash->{helper}{queue}{$host} && scalar @{$hash->{helper}{queue}{$host}} ) { - my $cmdHash = shift @{ $hash->{helper}{queue}{$host} }; + # ESP will be go into deep sleep soon. stop queueing. + if (defined $hash->{helper}{awaked} && defined $hash->{helper}{awaked}{$host} + && ($hash->{helper}{awaked}{$host} - gettimeofday()) < $hash->{helper}{maxCmdDuration}{$host} + ) { + Log3 $name, 4, "$type $name: $host is going into deep sleep in <= " + . $hash->{helper}{maxCmdDuration}{$host} . "s. De-queueing stopped. " + . scalar @{$hash->{helper}{queue}{$host}}. " outstanding commands left."; + return undef; + } + my $cmdHash = shift @{ $hash->{helper}{queue}{$host} }; Log3 $name, 4, "$type $name: Dequeuing: $host $cmdHash->{ident} " . "'$cmdHash->{cmd} " . join(",",@{$cmdHash->{cmdArgs}})."'" - . " (".scalar @{$hash->{helper}{queue}{$host}}.")"; + . " queuesize:".scalar @{$hash->{helper}{queue}{$host}}; # delete queue if empty delete $hash->{helper}{queue}{$host} if defined $hash->{helper}{queue} && defined $hash->{helper}{queue}{$host} && scalar @{$hash->{helper}{queue}{$host}} == 0; @@ -2079,6 +2166,72 @@ sub ESPEasy_httpReqDequeue($$) } +# ------------------------------------------------------------------------------ +# Mark a peer as being in deep sleep or in awaked state and de-queue. +# called within ReadFn. +# ------------------------------------------------------------------------------ +# $hash->{helper}{awaked}{$host} > 0 : awaked, value is next sleep time +# $hash->{helper}{awaked}{$host} = 0 : sleeping +# $hash->{helper}{awaked}{$host} = -1 : sleep awaited +# $hash->{helper}{awaked}{$host} ! defined : no sleep mode used by peer +# ------------------------------------------------------------------------------ +sub ESPEasy_httpReqDequeue_onAwake($$$$$) { + my ($hash, $host, $sleep, $espName, $ident) = @_; + my ($name, $type) = ($hash->{NAME}, $hash->{TYPE}); + + if (defined $sleep && $sleep > 0) { + + if ( ( !defined $hash->{helper}{awaked} || !defined $hash->{helper}{awaked}{$host} ) + || ( defined $hash->{helper}{awaked} && defined $hash->{helper}{awaked}{$host} && $hash->{helper}{awaked}{$host} == 0 ) ) { + + $hash->{helper}{awaked}{$host} = gettimeofday() + $sleep; + + # --- schedule dispatch "sleeping" ------------------------------------ + InternalTimer( $hash->{helper}{awaked}{$host}, sub() { + $hash->{helper}{awaked}{$host} = 0; + my @value = ("r||$d_sleepReading||sleeping||0"); + ESPEasy_dispatch($hash,$ident,$host,@value); + }, "$type.$name.$host.sleepStarted" + ); + + # --- schedule dispatch "sleep awaited" ------------------------------- + my $mcd + = defined $hash->{helper}{maxCmdDuration} + && defined $hash->{helper}{maxCmdDuration}{$host} + ? $hash->{helper}{maxCmdDuration}{$host} + : $d_maxCmdDuration; + my $awaited = $hash->{helper}{awaked}{$host} - $mcd; + my @dpsa = ("r||$d_sleepReading||sleep awaited in ".$mcd."s: $hash->{helper}{awaked}{$host}||0"); + InternalTimer( $awaited, sub() { + ESPEasy_dispatch($hash, $ident, $host, @dpsa); + $hash->{helper}{awaked}{$host} = -1; + }, "$type.$name.$host.sleepAwaited" + ); + + # --- dispatch "awaked" ----------------------------------------------- + # eg. 2018.12.21 10:35:03.479 4: ESPEasy em1: sleepState: awaked for 25s (-5s): [2018-12-21 10:35:23] + my @dpa = ("r||$d_sleepReading||awaked for ".$sleep."s (-".$mcd."s): ".$awaited."||0"); + ESPEasy_dispatch($hash, $ident, $host, @dpa); + + # --- yield dequeuing ------------------------------------------------- + InternalTimer( gettimeofday(), sub() { + ESPEasy_httpReqDequeue($hash, $host); + }, "$type.$name.$host.dequeue" + ); + + return 1; + } # if !defined... + } # if (defined $sleep + + # Peer did not send $sleep or $sleep == 0 + elsif (!$sleep) { + delete $hash->{helper}{awaked}{$host} if defined $hash->{helper}{awaked} && $hash->{helper}{awaked}{$host}; + } +#Debug "End"; + return 0; +} + + # ------------------------------------------------------------------------------ sub ESPEasy_statusRequest($) #called by device { @@ -2396,6 +2549,15 @@ sub ESPEasy_isParseCmd($$) #called by device } +# ------------------------------------------------------------------------------ +sub ESPEasy_IsPeerAwaked($$) { + my ($hash, $host) = @_; + return undef if !defined defined $hash->{awaked}{$host}; + return 0 if ($hash->{awaked}{$host} == 0); + return 1 if ($hash->{awaked}{$host} > 0); +} + + # ------------------------------------------------------------------------------ sub ESPEasy_sendHttpClose($$$) { my ($hash,$code,$response) = @_; @@ -2541,7 +2703,7 @@ sub ESPEasy_setState($) my $addTime = 3; my @ret; foreach my $reading (sort keys %{$hash->{helper}{received}}) { - next if $reading =~ m/^(\.ignored_.*|state|presence|_lastAction|_lastError|\w+_mode)$/; + next if $reading =~ m/^(\.ignored_.*|state|presence|_lastAction|_lastError|\w+_mode|$d_sleepReading)$/; next if $interval && ReadingsAge($name,$reading,1) > $interval+$addTime; push(@ret, substr($reading,0,AttrVal($name,"setState",3)) .": ".ReadingsVal($name,$reading,"")); @@ -3212,10 +3374,14 @@ sub ESPEasy_dumpSingleLine($) target="_new">R128 (self compiled) or an ESPEasy precompiled image >= R140_RC3
-
  • perl module JSON
    - Use "cpan install JSON" or operating system's package manager to install - Perl JSON Modul. Depending on your os the required package is named: - libjson-perl or perl-JSON. +
  • + ESPEasy Mega with option to set sleep awake time (Config -> Sleep Mode + -> Sleep awake time) is required to control ESP Easy nodes in deep + sleep. Receiving sensor values works with all other supported versions.
    +
  • +
  • Perl module JSON. Use "cpan install JSON" or operating system's package + manager to install Perl JSON Modul. Depending on your os the required + package is named: libjson-perl or perl-JSON.
  • @@ -3564,6 +3730,12 @@ sub ESPEasy_dumpSingleLine($) feature works quite slow on your ESP Easy nodes.
    +
  • attrTemplate
    + See global attrTemplate. Attribute + useSetExtensions + must be activated or the command is unavailable. +

  • +
  • clearReadings
    Delete all readings that are auto created by received sensor values since last FHEM restart.
    @@ -3865,7 +4037,7 @@ sub ESPEasy_dumpSingleLine($) rainbow [speed +/- 0-50] rgb <rrggbb> [fadetime] [delay +/-ms] scan <rrggbb> [rrggbb background] [speed 0-50] - simpleclock [bigtickcolor] [smalltickcolor] [hourcolor] [minutecolor] [secondcolor] + simpleclock [bigtickcolor] [smalltickcolor] [hourcolor] [minutecolor] [secondcolor] [backgroundcolor] sparkle <rrggbb> [rrggbb background] [speed 0-50] speed <value 0-50> stop @@ -4225,6 +4397,20 @@ sub ESPEasy_dumpSingleLine($) Default: 0

  • +
  • deepsleep
    + This attribut defines the default deep sleep state that is assumed if the + ESP has not sent its status to FHEM. Eg. directly after a FHEM restart. + If the ESP has sent its status, this value is ignored. Useful if you want + to be sure that a set command would be queued and sent when the ESP awakes + after a restart/rereadcfg of FHEM.
    + Furthermore events for reading sleepState are generated if enabled. + ESPEasy Mega with option to set sleep awake time (Config -> Sleep Mode + -> Sleep awake time) is required to use this feature. +
    + Possible values: 0,1
    + Default: 0 +

  • +
  • disableRiskyCmds
    Used to disable supposed dangerous set cmds: erase, reset, resetflashwritecounter
    Possible values: 0,1
    @@ -4272,6 +4458,19 @@ sub ESPEasy_dumpSingleLine($) eg. attr <esp> mapLightCmds Lights

  • +
  • maxCmdDuration
    + Only used if an ESP Easy node works in deep sleep mode. This attribut defines + the amount of seconds your ESP node needs to work off a single command. + In other words: This value defines how much awake time must be left to + send a command to your ESP node before it goes into deep sleep mode. + Commands that are not send will be queued und worked off when the node + awakes again.
    + ESPEasy Mega with option to set sleep awake time (Config -> Sleep Mode + -> Sleep awake time) is required to use this feature.
    + Possible values: secs >= 0, but < awake time
    + Default: 3 +

  • +
  • presenceCheck
    Used to enable/disable presence check for ESPs
    Presence check determines the presence of a device by readings age. If any