############################################## # $Id$ # ABU 20160307 First release # ABU 20160321 Added first parsing algos # ABU 20160311 Migrated to JSON # ABU 20160412 Integrated basic set-mechanism, added internals, changed callback-routine # ABU 20160413 Renamed to robonect, added status offline # ABU 20160414 Changed final two Automower to Robonect # ABU 20160414 Renamed private fn "decode" # ABU 20160415 Renamed private fn "decode" again, set eventonchangedreading, removed debug, increased interval to 90 # ABU 20160416 Added logs, removed eventonchangedreading, added debug # ABU 20160416 Removed logs, added eventonchangedreading, removed debug, added 1=true for json data # ABU 20160426 Fixed decode warning, added error support # ABU 20160515 Added splitFn and doku # BJOERNAR 20160715 added duration and wlan-signal # ABU 20160831 Integrated API-changes for RC9, added attribute timeout for httpData # ABU 20160831 added calculations for duration and wlan - show in hours and percent # ABU 20160901 rounded duration and wlan # ABU 20161120 addaed encode_utf8 at json decode, tuned 0.5b repiar-stuff, added hibernate # ABU 20161126 added summary # ABU 20161129 fixed hash issues which prevents the module from loading package main; use strict; use warnings; use HttpUtils; use Encode; use JSON; my $EOD = "feierabend"; my $HOME = "home"; my $AUTO = "auto"; my $MANUAL = "manuell"; my $START = "start"; my $STOP = "stop"; my $OFFLINE = "offline"; my $HYBERNATE = "winterschlaf"; #available get cmds my %gets = ( "status" => "noArg" ); #available set cmds my %sets = ( "feierabend" => "noArg", $HOME => "noArg", $AUTO => "noArg", $MANUAL => "noArg", $START => "noArg", $STOP => "noArg", $HYBERNATE => "on,off" ); my %commands = ( GET_STATUS => "cmd=status", SET_MODE => {$HOME=>"cmd=mode&mode=home", $MANUAL=>"cmd=mode&mode=man", $AUTO=>"cmd=mode&mode=auto", $EOD=>"cmd=mode&mode=eod", $STOP=>"cmd=stop", $START=>"cmd=start"} ); #set to 1 for debug my $debug = 0; #elements within group next my %elements = ( # "robonect" => # { "successful" => {ALIAS=>"kommunikation", "true"=>"erfolgreich", "false"=>"fehlgeschlagen", 1=>"erfolgreich", 0=>"fehlgeschlagen"}, "status" => { ALIAS => "allgemein", "status" => {ALIAS=>"status", 0=>"schlafen", 1=>"parken", 2=>"maehen", 3=>"suche-base", 4=>"laden", 5=>"suche", 7=>"fehler", 8=>"schleife-fehlt", 16=>"abgeschaltet", 17=>"schlafen"}, "mode" => {ALIAS=>"modus", 0=>"automatik", 1=>"manuell", 2=>"home", 3=>"demo"}, "battery" => {ALIAS=>"batteriezustand"}, "duration" => {ALIAS=>"dauer"}, "hours" => {ALIAS=>"betriebsstunden"} }, "timer" => { ALIAS => "timer", "status" => {ALIAS=>"status", 0=>"deaktiviert", 1=>"aktiv", 2=>"standby"}, "next" => { ALIAS => "timer", "date" => {ALIAS=>"startdatum"}, "time" => {ALIAS=>"startzeit"}, #"date" => {ALIAS=>"start-unix"}, } }, "wlan" => { ALIAS => "wlan", "signal" => {ALIAS=>"signal"} }, "error" => { ALIAS => "fehler", "error_code" => {ALIAS=>"code"}, "error_message" => {ALIAS=>"nachricht"}, "date" => {ALIAS=>"datum"}, "time" => {ALIAS=>"zeit"} } # } ); #Init this device #This declares the interface to fhem ############################# sub Robonect_Initialize($) { my ($hash) = @_; $hash->{DefFn} = 'Robonect_Define'; $hash->{UndefFn} = 'Robonect_Undef'; $hash->{SetFn} = 'Robonect_Set'; $hash->{GetFn} = 'Robonect_Get'; $hash->{AttrFn} = 'Robonect_Attr'; $hash->{ShutdownFn} = 'Robonect_Shutdown'; $hash->{ReadyFn} = 'Robonect_Ready'; $hash->{DbLog_splitFn} = 'Robonect_DbLog_split'; $hash->{AttrList} = "do_not_notify:1,0 " . #supress any notification (including log) "showtime:1,0 " . #shows time instead of received value in state "credentials " . #user/password combination for authentication in mower, stored in a credentials file "basicAuth " . #user/password combination for authentication in mower "pollInterval " . #interval to poll in seconds "timeout " . #interval to poll in seconds "$readingFnAttributes "; #standard attributes } #Define this device #Is called at every define ############################# sub Robonect_Define($$) { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); #device name my $name = $a[0]; #set verbose to 5, if debug enabled $attr{$name}{verbose} = 5 if ($debug eq 1); my $tempStr = join (", ", @a); Log3 ($name, 5, "define $name: enter $hash, attributes: $tempStr"); #too less arguments return "wrong syntax - define Robonect [ ]" if (int(@a) < 3); #check IP my $ip = $a[2]; #remove whitespaces $ip =~ s/^\s+|\s+$//g; #Syntax ok if ($ip =~ m/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) { my @octs = split (".", $ip); foreach my $octet (@octs) { return "wrong syntax - $octet has an invalid range. Allowed is 0..255" if (($octet >= 256) or ($octet <= -1)); } } else { return "wrong syntax - IP must be supplied correctly <0..254>.<0..254>.<0..254>.<0..254>"; } #wrong syntax for IP return "wrong syntax - IP must be supplied correctly <0..254>.<0..254>.<0..254>.<000..254>" if (int(@a) < 3); #assign name and port $hash->{NAME} = $name; $hash->{IP} = $ip; #backup name for a later rename $hash->{DEVNAME} = $name; #get first info and launch timer InternalTimer(gettimeofday(), "Robonect_GetUpdate", $hash, 0); #finally create decice #defptr is needed to supress FHEM input $modules{Robonect}{defptr}{$name} = $hash; #default event-on-changed-reading for all readings $attr{$name}{"event-on-change-reading"} = ".*"; #defaul poll-interval $attr{$name}{"pollInterval"} = 90; Log3 ($name, 5, "exit define"); return undef; } #Release this device #Is called at every delete / shutdown ############################# sub Robonect_Undef($$) { my ($hash, $name) = @_; Log3 ($name, 5, "enter undef $name: hash: $hash name: $name"); #kill interval timer RemoveInternalTimer($hash); #close port Robonect_Shutdown ($hash); #remove module. Refer to DevName, because module may be renamed delete $modules{KNX}{defptr}{$hash->{DEVNAME}}; #remove name delete $hash->{NAME}; #remove backuped name delete $hash->{DEVNAME}; Log3 ($name, 5, "exit undef"); return undef; } #Release this device #Is called at every delete / shutdown ############################# sub Robonect_Shutdown($) { my ($hash) = @_; #hash may be de-referenced already my $name = "robonect-not_named_any_more"; $name = $hash->{NAME} if (ref($hash) eq "HASH"); Log3 ($name, 5, "enter shutdown $name: hash: $hash name: $name"); Log3 ($name, 5, "exit shutdown"); return undef; } #This function is called from fhem from rime to time ############################# sub Robonect_Ready($) { my ($hash) = @_; my $name = $hash->{NAME}; Log3 ($name, 5, "enter ready $name: hash: $hash name: $name"); Log3 ($name, 5, "exit ready"); return undef; } #Reads info from the mower ############################# sub Robonect_Get($@) { my ($hash, @a) = @_; my $name = $hash->{NAME}; my $tempStr = join (", ", @a); Log3 ($name, 5, "enter get $name: $name hash: $hash, attributes: $tempStr"); #backup cmd my $cmd = $a[1]; #lower cmd $cmd = lc($cmd); #create response, if cmd is wrong or gui asks my $cmdTemp = Robonect_getCmdList ($hash, $cmd, %gets); return $cmdTemp if (defined ($cmdTemp)); my ($userName, $passWord) = Robonect_getCredentials ($hash); #basic url my $url = "http://" . $hash->{IP} . "/json?"; #append userdata, if given $url = $url . "user=" . $userName . "&pass=" . $passWord . "&" if (defined ($userName) and defined ($passWord)); #append command $url = $url . $commands{GET_STATUS}; my $httpData; $httpData->{url} = $url; $httpData->{loglevel} = AttrVal ($name, "verbose", 2); $httpData->{loglevel} = 5; $httpData->{hideurl} = 0; $httpData->{callback} = \&Robonect_callback; $httpData->{hash} = $hash; $httpData->{cmd} = $commands{GET_STATUS}; $httpData->{timeout} = AttrVal ($name, "timeout", 4); HttpUtils_NonblockingGet($httpData); Log3 ($name, 5, "exit get"); my $err = $httpData->{err}; if (defined ($err) and (length ($err) > 0)) { return $err; } else { return "update requested"; } } #Sends commands to the mower ############################# sub Robonect_Set($@) { my ($hash, @a) = @_; my $name = $hash->{NAME}; my $tempStr = join (", ", @a); Log3 ($name, 5, "enter set $name: $name hash: $hash, attributes: $tempStr"); #backup cmd my $cmd = $a[1]; #lower cmd $cmd = lc($cmd); #create response, if cmd is wrong or gui asks my $cmdTemp = Robonect_getCmdList ($hash, $cmd, %sets); return $cmdTemp if (defined ($cmdTemp)); my ($userName, $passWord) = Robonect_getCredentials ($hash); my $decodedCmd = $commands{SET_MODE}{$cmd}; #if command is hybernate, do this if ($cmd = lc($HYBERNATE)) { Log3 ($name, 5, "got hybernate for set-command"); my $val = lc($a[2]); $val = "off" if (!defined ($val)); if ($val =~ m/on/) { readingsSingleUpdate($hash, $HYBERNATE, "on", 1); Log3 ($name, 5, "activated hybernate"); } elsif ($val =~ m/off/) { readingsSingleUpdate($hash, $HYBERNATE, "off", 1); Log3 ($name, 5, "deactivated hybernate"); } else { return "only on or off are supported for $HYBERNATE"; } } #else proceed with communication to mower #execute it elsif (defined ($decodedCmd)) { my $url = "http://" . $hash->{IP} . "/json?"; #append userdata, if given $url = $url . "user=" . $userName . "&pass=" . $passWord . "&" if (defined ($userName) and defined ($passWord)); #append command $url = $url . $decodedCmd; print "URL: $url\n"; my $httpData; $httpData->{url} = $url; $httpData->{loglevel} = AttrVal ($name, "verbose", 2); $httpData->{loglevel} = 5; $httpData->{hideurl} = 0; $httpData->{callback} = \&Robonect_callback; $httpData->{hash} = $hash; $httpData->{cmd} = $decodedCmd; HttpUtils_NonblockingGet($httpData); return $httpData->{err}; Robonect_GetUpdate($hash); } Log3 ($name, 5, "exit set"); return; } #called on every mod of the attributes ############################# sub Robonect_Attr(@) { my ($cmd,$name,$attr_name,$attr_value) = @_; Log3 ($name, 5, "enter attr $name: $name, attrName: $attr_name"); #if($cmd eq "set") #{ # if(($attr_name eq "debug") and (($attr_value eq "1") or ($attr_value eq "true"))) # { # #todo # } #} Log3 ($name, 5, "exit attr"); return undef; } #Split reading for DBLOG ############################# sub Robonect_DbLog_split($) { my ($event) = @_; my ($reading, $value, $unit); my $tempStr = join (", ", @_); Log (5, "splitFn - enter, attributes: $tempStr"); #detect reading - real reading or state? my $isReading = "false"; $isReading = "true" if ($event =~ m/: /); #split input-string my @strings = split (" ", $event); my $startIndex = undef; $unit = ""; return undef if (not defined ($strings[0])); #real reading? if ($isReading =~ m/true/) { #first one is always reading $reading = $strings[0]; $reading =~ s/:?$//; $startIndex = 1; } #plain state else { #for reading state nothing is supplied $reading = "state"; $startIndex = 0; } return undef if (not defined ($strings[$startIndex])); #per default join all single pieces $value = join(" ", @strings[$startIndex..(int(@strings) - 1)]); #numeric value? #if ($strings[$startIndex] =~ /^[+-]?\d*[.,]?\d+/) if ($strings[$startIndex] =~ /^[+-]?\d*[.,]?\d+$/) { $value = $strings[$startIndex]; #single numeric value? Assume second par is unit... if ((defined ($strings[$startIndex + 1])) && !($strings[$startIndex+1] =~ /^[+-]?\d*[.,]?\d+/)) { $unit = $strings[$startIndex + 1] if (defined ($strings[$startIndex + 1])); } } #numeric value? #if ($strings[$startIndex] =~ /^[+-]?\d*[.,]?\d+/) #{ # $value = $strings[$startIndex]; # $unit = $strings[$startIndex + 1] if (defined ($strings[$startIndex + 1])); #} #string or raw #else #{ # $value = join(" ", @strings[$startIndex..(int(@strings) - 1)]); #} Log (5, "splitFn - READING: $reading, VALUE: $value, UNIT: $unit"); return ($reading, $value, $unit); } #Called on the interval timer, if enabled ############################# sub Robonect_GetUpdate($) { my ($hash) = @_; my $name = $hash->{NAME}; Log3 ($name, 5, "enter update $name: $name"); #evaluate reading hybernate my $hybernate = $hash->{READINGS}{$HYBERNATE}{VAL}; #supress sending, if hybernate is set if (!defined ($hybernate) or ($hybernate =~ m/off/)) { #get status my @callAttr; $callAttr[0] = $name; $callAttr[1] = "status"; Robonect_Get ($hash, @callAttr); } my $interval = AttrVal($name,"pollInterval",90); #reset timer InternalTimer(gettimeofday() + $interval, "Robonect_GetUpdate", $hash, 1) if ($interval > 0); Log3 ($name, 5, "exit update"); } #Private function which handles http-responses ############################# sub Robonect_callback ($) { my ($param, $err, $data) = @_; my $hash = $param->{hash}; my $name = $hash->{NAME}; #wenn ein Fehler bei der HTTP Abfrage aufgetreten ist if($err ne "") { Log3 ($name, 3, "callback - error while requesting ".$param->{url}." - $err"); $hash->{LAST_COMM_STATUS} = $err; #set reading with failure - notify only, when state has not changed readingsSingleUpdate($hash, "state", $OFFLINE, 1); } #wenn die Abfrage erfolgreich war ($data enthält die Ergebnisdaten des HTTP Aufrufes) elsif($data ne "") { Log3 ($name, 3, "callback - url ".$param->{url}." returned: $data"); #repair V5.0b $data =~ s/:"/,"/g; $data = "" if (!defined($data)); my $answer = decode_json (encode_utf8($data)); Log3 ($name, 3, "callback - url ".$param->{url}." repaired: $data"); my ($key, $value) = Robonect_decodeContent ($hash, $answer, "successful", undef, undef); $hash->{LAST_CMD} = $param->{cmd}; $hash->{LAST_COMM_STATUS} = "success: " . $value; Log3 ($name, 5, "callback - communication ok"); #my %tmp = %$answer; #print "answer: ", %tmp, "\n"; #status-readings if ($answer->{successful} =~ m/(true)|(1)/) { Log3 ($name, 5, "callback - update readings"); readingsBeginUpdate($hash); #($key, $value) = Robonect_decodeContent ($hash, $answer, "successful", undef); #readingsBulkUpdate($hash, $key, $value); ($key, $value) = Robonect_decodeContent ($hash, $answer, "status", "status", undef); readingsBulkUpdate($hash, $key, $value); readingsBulkUpdate($hash, "state", $value); ($key, $value) = Robonect_decodeContent ($hash, $answer, "status", "mode", undef); readingsBulkUpdate($hash, $key, $value); ($key, $value) = Robonect_decodeContent ($hash, $answer, "status", "battery", undef); readingsBulkUpdate($hash, $key, $value); $value = 0; ($key, $value) = Robonect_decodeContent ($hash, $answer, "status", "duration", undef); readingsBulkUpdate($hash, $key, sprintf ("%d", $value/3600)); ($key, $value) = Robonect_decodeContent ($hash, $answer, "status", "hours", undef); readingsBulkUpdate($hash, $key, $value); ($key, $value) = Robonect_decodeContent ($hash, $answer, "timer", "status", undef); readingsBulkUpdate($hash, $key, $value); ($key, $value) = Robonect_decodeContent ($hash, $answer, "timer", "next", "date"); readingsBulkUpdate($hash, $key, $value); ($key, $value) = Robonect_decodeContent ($hash, $answer, "timer", "next", "time"); readingsBulkUpdate($hash, $key, $value); $value = -95; ($key, $value) = Robonect_decodeContent ($hash, $answer, "wlan", "signal", undef); readingsBulkUpdate($hash, $key, $value); if (defined($value)) { $value = sprintf ("%d", ($value + 95) / 0.6); readingsBulkUpdate($hash, $key . "-prozent", $value); } readingsEndUpdate($hash, 1); } #error? my $errorOccured = $answer->{status}->{status}; if (defined ($errorOccured) and ($errorOccured =~ m/7/)) { readingsSingleUpdate($hash, "fehler_aktuell", $answer->{error}->{error_message}, 1); } #no error elsif (defined ($errorOccured)) { my $hashref = $hash->{READINGS}; my %readings = %$hashref; #delete readings foreach my $key (keys %readings) { #delete $readings{$key} if ($key =~ m/^fehler.*/); delete $hash->{READINGS}{$key} if ($key =~ m/^fehler.*/); #delete $hash->{READINGS}{$key} if ($key =~ m/^fehler-aktuell.*/); } } } } #Private function to get json-content ############################# sub Robonect_decodeContent ($$$$$) { my ($hash, $msg, $key1, $key2, $key3) = @_; my $name = $hash->{NAME}; my $rdName = undef; my $rdValue = undef; my $template = undef; if (defined ($key2) && defined ($key3)) { $template = $elements{$key1}{$key2}{$key3}; $rdName = $elements{$key1}{$key2}{ALIAS} . "-" . $template->{ALIAS}; $rdValue = $msg->{$key1}->{$key2}->{$key3}; } elsif (defined ($key2)) { $template = $elements{$key1}{$key2}; $rdName = $elements{$key1}{ALIAS} . "-" . $template->{ALIAS}; $rdValue = $msg->{$key1}->{$key2}; } else { $template = $elements{$key1}; $rdValue = $msg->{$key1}; $rdName = $template->{ALIAS}; } $rdValue = "undef" if (not defined ($rdValue)); $rdValue = $template->{$rdValue} if (defined ($template->{$rdValue})); Log3 ($name, 5, "decodeContent - NAME: $rdName, VALUE: $rdValue"); return $rdName, $rdValue; } #Private function to evaluate credentials ############################# sub Robonect_decodeAnswer ($$$) { my ($hash, $getCmd, @readings) = @_; my $name = $hash->{NAME}; my @list; foreach my $reading (@readings) { my $answer = undef; my $transval = undef; my ($header, $key, $value) = undef; $header = $reading->{header}; $key = $reading->{key}; $value = $reading->{value}; if ($header =~ m/robonect/i) { $answer->{name} = $getCmd . "-" . $elements{$header}{$key}{ALIAS}; $transval = $elements{$header}{$key}{$value}; } else { $answer->{name} = $getCmd . "-" . $elements{"robonect"}{$header}{ALIAS} . "-" . $elements{"robonect"}{$header}{$key}{ALIAS}; $transval = $elements{"robonect"}{$header}{$key}{$value}; } if (defined($transval)) { $answer->{value} = $transval; } else { $answer->{value} = $value; } #$answer->{name} = $getCmd . "-" . $answer->{name}; Log3 ($name, 5, "decodeAnswer - NAME: $answer->{name}, VALUE: $answer->{value}"); push (@list, $answer); } return @list; } #Private function to evaluate credentials ############################# sub Robonect_getCredentials ($) { my ($hash) = @_; my $name = $hash->{NAME}; my $userName = undef; my $passWord = undef; #parse basicAuth my $basicAuth = AttrVal ($name, "basicAuth", undef); if (defined ($basicAuth)) { #if the string does NOT contain a ":", assume base64-encoded data if (not ($basicAuth =~ m/:/)) { $basicAuth = decode_base64 ($basicAuth); Log3 ($name, 5, "credentials - found encrypted data"); } #try to split my @plainAuth = split (":", $basicAuth); #found plain authentication if (int(@plainAuth) == 2) { $userName = $plainAuth[0]; $passWord = $plainAuth[1]; Log3 ($name, 5, "credentials - found plain data"); } else { Log3 ($name, 0, "credentials - user/pw combination not correct"); } } #parse credential-File - overrules basicAuth my $credentials = AttrVal ($name, "credentials", undef); if(defined($credentials)) { #cannot open file if(!open(CFG, $credentials)) { Log3 ($name, 0, "cannot open credentials file: $credentials") ; } #read it else { my @cfg = ; close(CFG); my %creds; eval join("", @cfg); #extract it $userName =~ $creds{$name}{username}; $passWord =~ $creds{$name}{password}; Log3 ($name, 5, "credentials - found in file"); } } return $userName, $passWord; } #Private function to evaluate command-lists ############################# sub Robonect_getCmdList ($$$) { my ($hash, $cmd, %cmdArray) = @_; my $name = $hash->{NAME}; #return, if cmd is valid return undef if (defined ($cmd) and defined ($cmdArray{$cmd})); #response for gui or the user, if command is invalid my $retVal; foreach my $mySet (keys %cmdArray) { #append set-command $retVal = $retVal . " " if (defined ($retVal)); $retVal = $retVal . $mySet; #get options my $myOpt = $cmdArray{$mySet}; #append option, if valid $retVal = $retVal . ":" . $myOpt if (defined ($myOpt) and (length ($myOpt) > 0)); $myOpt = "" if (!defined($myOpt)); Log3 ($name, 5, "parse cmd-table - Set:$mySet, Option:$myOpt, RetVal:$retVal"); } if (!defined ($retVal)) { $retVal = "error while parsing set-table" ; } else { $retVal = "Unknown argument $cmd, choose one of " . $retVal; } return $retVal; } 1; =pod =begin html

Robonect

    Robonect is a after-market wifi-module for robomowers based on the husky G3-control. It was developed by Fabian H. and can be optained at www.robonect.de. This module gives you access to the basic commands. This module will not work without libjson-perl! Do not forget to install it first!

    Define

      define <name> Robonect <ip-adress> [<user> <password>]

      Setting Winterschlaf prevents communicating with the mower.

      The authentication can be supplied in the definition as plaine text or in a differen way - see the attributes. Per default the status is polled every 90s.

      Example:

            define myMower Robonect 192.168.13.5 test tmySecret
            

    Set

      Switch the mower to automatic-timer: set <name> auto Send the mower home - prevents further runs triggered by timer (persistent): set <name> home Sends the mower home for the actual timer-slot. The next timer-slot starts the mower again: set <name> feierabend Start the mower (only needed after a manual stop: set <name> start Stop the mower immediately: set <name> stop

    Get

      Gets the actual state of the mower - normally not needed, because the status is polled cyclic.

    Attributes

    credentials

      If you supply a valid path to a credentials file, this combination is used to log in at robonect. This mechism overrules basicAuth.

    basicAuth

      You can supply username and password plain or base-64-encoded. For a base64-encoder, use google.

      Example:

            define myMower 192.168.5.1
      	  attr myMower basicAuth me:mySecret
            
            define myMower 192.168.5.1
      	  attr myMower basicAuth bWU6bXlTZWNyZXQ=
            

    pollInterval

      Supplies the interval top poll the robonect in seconds. Per default 90s is set.

    timeout

      Timeout for httpData to recive data. Default is 4s.
=end html =device =item summary Communicates to HW-module robonect =item summary_DE Kommuniziert mit dem HW-Modul Robonect =begin html_DE

Robonect

    Robonect ist ein Nachrüstmodul für automower, die auf der Husky-G3-Steuerung basieren. Es wurde von Fabian H. entwickelt und kann unter www.robonect.de bezogen werden. Dieses Modul gibt Euch Zugriff auf die nötigsten Kommandos. Dieses Modul benötigt libjson-perl. Bitte NICHT VERGESSEN zu installieren!

    Define

      define <name> Robonect <ip-adress> [<user> <password>]

      Mit gesetztem Winterschlaf wird die Kommunikation zum Mäher unterbunden.

      Die Zugangsinformationen können im Klartext bei der Definition angegeben werden. Wahlweise auch per Attribut. Standardmäßig wird der Status vom RObonect alle 90s aktualisiert.

      Beispiel:

            define myMower Robonect 192.168.13.5 test tmySecret
            

    Set

      Versetzt den Mäher in den timerbasierten Automatikmodus: set <name> auto Schickt den Mäher nach hause. Ein erneutes Starten per Timer wird verhindert (persistent): set <name> home Schickt den Mäher nach Hause. Beim nächsten Timerstart fährt der Mäher wieder regulär: set <name> feierabend Startet den Mäher (wird nur nach einem manuellen Stop benötigt): set <name> start Stoppt den Mäher: set <name> stop

    Get

      Holt den aktuellen Status des Mähers. Wird normalerweise nicht benötigt, da automatisch gepolled wird.

    Attributes

    credentials

      Hier kann ein Link auf ein credentials-file angegeben werden. Die Zugansinformationen werden dann aus der Datei geholt. Dieser Mechanismus überschreibt basicAuth.

    basicAuth

      Hier werden die Zugangsinformationen entweder im Klartext oder base-64-codiert übergeben. Base64-encoder gibts bei google.

      Example:

            define myMower 192.168.5.1
      	  attr myMower basicAuth me:mySecret
            
            define myMower 192.168.5.1
      	  attr myMower basicAuth bWU6bXlTZWNyZXQ=
            

    pollInterval

      Hier kann das polling-interval in Sekunden angegeben werden. Default sind 90s.

    timeout

      Für das holen der Daten per Wlan kann hier ein Timeout angegeben werden. Default sind 4s.
=end html_DE =cut