86_Robonect.pm 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292
  1. ##############################################
  2. # $Id: 86_Robonect.pm 15258 2017-10-14 18:43:54Z andi291 $
  3. # ABU 20160307 First release
  4. # ABU 20160321 Added first parsing algos
  5. # ABU 20160311 Migrated to JSON
  6. # ABU 20160412 Integrated basic set-mechanism, added internals, changed callback-routine
  7. # ABU 20160413 Renamed to robonect, added status offline
  8. # ABU 20160414 Changed final two Automower to Robonect
  9. # ABU 20160414 Renamed private fn "decode"
  10. # ABU 20160415 Renamed private fn "decode" again, set eventonchangedreading, removed debug, increased interval to 90
  11. # ABU 20160416 Added logs, removed eventonchangedreading, added debug
  12. # ABU 20160416 Removed logs, added eventonchangedreading, removed debug, added 1=true for json data
  13. # ABU 20160426 Fixed decode warning, added error support
  14. # ABU 20160515 Added splitFn and doku
  15. # BJOERNAR 20160715 added duration and wlan-signal
  16. # ABU 20160831 Integrated API-changes for RC9, added attribute timeout for httpData
  17. # ABU 20160831 added calculations for duration and wlan - show in hours and percent
  18. # ABU 20160901 rounded duration and wlan
  19. # ABU 20161120 addaed encode_utf8 at json decode, tuned 0.5b repiar-stuff, added hibernate
  20. # ABU 20161126 added summary
  21. # ABU 20161129 fixed hash issues which prevents the module from loading
  22. # ABU 20170301 fixed hybernate-check in set
  23. # ABU 20170406 fixed hybernate-check in timer
  24. # ABU 20170422 fixed doku
  25. # ABU 20170427 fixed numerich undefs
  26. # ABU 20170428 do not delete private hash data in undef
  27. # ABU 20170428 do not define defptr in define
  28. # ABU 20170428 fixed in define section: removed me and my secret, removed IP-check for DNS-Support
  29. # ABU 20170428 removed setting attributes in define (eventonchange and pollInterval)
  30. # ABU 20170428 masked decode_json in eval and added error-path
  31. # ABU 20170501 added setkey/getkey for username and password
  32. # ABU 20170501 added eval-error-logging
  33. # ABU 20170501 changed verbose 3 to verbose 4
  34. # ABU 20170501 tuned documentation
  35. # ABU 20170516 removed useless print
  36. # ABU 20170525 bugfixed winterschlaf again
  37. # ABU 20171006 added options for Maehauftrag
  38. # ABU 20171006 added "umlautfilter" for test
  39. # ABU 20171006 added "health" for test
  40. # ABU 20171010 finished health for test, added chck for undef at each reading
  41. package main;
  42. use strict;
  43. use warnings;
  44. use HttpUtils;
  45. use Encode;
  46. use JSON;
  47. my $EOD = "feierabend";
  48. my $HOME = "home";
  49. my $AUTO = "auto";
  50. my $MANUAL = "manuell";
  51. my $JOB = "maehauftrag";
  52. my $START = "start";
  53. my $STOP = "stop";
  54. my $OFFLINE = "offline";
  55. my $HYBERNATE = "winterschlaf";
  56. my $USER = "benutzername";
  57. my $PW = "passwort";
  58. #available get cmds
  59. my %gets = (
  60. "status" => "noArg",
  61. "health" => "noArg"
  62. );
  63. #available set cmds
  64. my %sets = (
  65. $EOD => "noArg",
  66. $HOME => "noArg",
  67. $AUTO => "noArg",
  68. $MANUAL => "noArg",
  69. $JOB => "",
  70. $START => "noArg",
  71. $STOP => "noArg",
  72. $HYBERNATE => "on,off",
  73. $USER => "",
  74. $PW => ""
  75. );
  76. my %commands = (
  77. #GET_STATUS => "cmd=status",
  78. SET_MODE => {$HOME=>"cmd=mode&mode=home", $MANUAL=>"cmd=mode&mode=man", $JOB=>"cmd=mode&mode=job", $AUTO=>"cmd=mode&mode=auto", $EOD=>"cmd=mode&mode=eod", $STOP=>"cmd=stop", $START=>"cmd=start"}
  79. );
  80. #set to 1 for debug
  81. my $debug = 0;
  82. #elements within group next
  83. my %elements = (
  84. # "robonect" =>
  85. # {
  86. "successful" => {ALIAS=>"kommunikation", "true"=>"erfolgreich", "false"=>"fehlgeschlagen", 1=>"erfolgreich", 0=>"fehlgeschlagen"},
  87. "status" =>
  88. {
  89. ALIAS => "allgemein",
  90. "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"},
  91. "mode" => {ALIAS=>"modus", 0=>"automatik", 1=>"manuell", 2=>"home", 3=>"demo"},
  92. "battery" => {ALIAS=>"batteriezustand"},
  93. "duration" => {ALIAS=>"dauer"},
  94. "hours" => {ALIAS=>"betriebsstunden"}
  95. },
  96. "health" =>
  97. {
  98. ALIAS => "erweitert",
  99. "alarm" =>
  100. {
  101. ALIAS => "alarm",
  102. "voltage3v3extmin" => {ALIAS=>"unterspannung_extern_3V3", "false"=> "bereit", "true"=>"alarm"},
  103. "voltage3v3extmax" => {ALIAS=>"ueberspannung_extern_3V3", "false"=> "bereit", "true"=>"alarm"},
  104. "voltage3v3intmin" => {ALIAS=>"unterspannung_intern_3V3", "false"=> "bereit", "true"=>"alarm"},
  105. "voltage3v3intmax" => {ALIAS=>"ueberspannung_intern_3V3", "false"=> "bereit", "true"=>"alarm"},
  106. "voltagebattmin" => {ALIAS=>"unterspannung_batterie", "false"=> "bereit", "true"=>"alarm"},
  107. "voltagebattmax" => {ALIAS=>"ueberspannung_batterie", "false"=> "bereit", "true"=>"alarm"},
  108. "temperatureMin" => {ALIAS=>"zu_kalt", "false"=> "bereit", "true"=>"alarm"},
  109. "temperatureMax" => {ALIAS=>"zu_warm", "false"=> "bereit", "true"=>"alarm"},
  110. "humidityMax" => {ALIAS=>"zu_feucht", "false"=> "bereit", "true"=>"alarm"},
  111. },
  112. "voltages" =>
  113. {
  114. ALIAS => "spannung",
  115. "ext3v3" => {ALIAS=>"extern"},
  116. "int3v3" => {ALIAS=>"intern"},
  117. "batt" => {ALIAS=>"batterie"},
  118. },
  119. "climate" =>
  120. {
  121. ALIAS => "umwelt",
  122. "temperature" => {ALIAS=>"temperatur"},
  123. "humidity" => {ALIAS=>"feuchte"},
  124. }
  125. },
  126. "timer" =>
  127. {
  128. ALIAS => "timer",
  129. "status" => {ALIAS=>"status", 0=>"deaktiviert", 1=>"aktiv", 2=>"standby"},
  130. "next" =>
  131. {
  132. ALIAS => "timer",
  133. "date" => {ALIAS=>"startdatum"},
  134. "time" => {ALIAS=>"startzeit"},
  135. #"date" => {ALIAS=>"start-unix"},
  136. }
  137. },
  138. "wlan" =>
  139. {
  140. ALIAS => "wlan",
  141. "signal" => {ALIAS=>"signal"}
  142. },
  143. "error" =>
  144. {
  145. ALIAS => "fehler",
  146. "error_code" => {ALIAS=>"code"},
  147. "error_message" => {ALIAS=>"nachricht"},
  148. "date" => {ALIAS=>"datum"},
  149. "time" => {ALIAS=>"zeit"}
  150. }
  151. # }
  152. );
  153. #this table is used to replace special chars
  154. my %umlaute = ("ä" => "ä", "ü" => "ü", "ö" => "ö","Ä" => "Ä", "Ü" => "Ü", "Ö" => "Ö", "ß" => "ß");
  155. #Init this device
  156. #This declares the interface to fhem
  157. #############################
  158. sub Robonect_Initialize($) {
  159. my ($hash) = @_;
  160. $hash->{DefFn} = 'Robonect_Define';
  161. $hash->{UndefFn} = 'Robonect_Undef';
  162. $hash->{SetFn} = 'Robonect_Set';
  163. $hash->{GetFn} = 'Robonect_Get';
  164. $hash->{AttrFn} = 'Robonect_Attr';
  165. $hash->{ShutdownFn} = 'Robonect_Shutdown';
  166. $hash->{ReadyFn} = 'Robonect_Ready';
  167. $hash->{DbLog_splitFn} = 'Robonect_DbLog_split';
  168. $hash->{AttrList} = "do_not_notify:1,0 " . #supress any notification (including log)
  169. "showtime:1,0 " . #shows time instead of received value in state
  170. "credentials " . #user/password combination for authentication in mower, stored in a credentials file
  171. "basicAuth " . #user/password combination for authentication in mower
  172. "pollInterval " . #interval to poll in seconds
  173. "timeout " . #http-timeout
  174. "useHealth " . #if true, poll for health
  175. "$readingFnAttributes "; #standard attributes
  176. }
  177. #Define this device
  178. #Is called at every define
  179. #############################
  180. sub Robonect_Define($$)
  181. {
  182. my ($hash, $def) = @_;
  183. my @a = split("[ \t][ \t]*", $def);
  184. #device name
  185. my $name = $a[0];
  186. #set verbose to 5, if debug enabled
  187. $attr{$name}{verbose} = 5 if ($debug eq 1);
  188. my $tempStr = join (", ", @a);
  189. Log3 ($name, 5, "define $name: enter $hash, attributes: $tempStr");
  190. #too less arguments
  191. #return "wrong syntax - define <name> Robonect <ip-adress> [<user> <password>]" if (int(@a) < 3);
  192. return "wrong syntax - define <name> Robonect <ip-adress>" if (int(@a) < 3);
  193. #check IP
  194. my $ip = $a[2];
  195. #remove whitespaces
  196. $ip =~ s/^\s+|\s+$//g;
  197. #removed IP-check - can also be a name
  198. #Syntax ok
  199. #if ($ip =~ m/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)
  200. #{
  201. # my @octs = split (".", $ip);
  202. #
  203. # foreach my $octet (@octs)
  204. # {
  205. # return "wrong syntax - $octet has an invalid range. Allowed is 0..255" if (($octet >= 256) or ($octet <= -1));
  206. # }
  207. #}
  208. #else
  209. #{
  210. # return "wrong syntax - IP must be supplied correctly <0..254>.<0..254>.<0..254>.<0..254>";
  211. #}
  212. #wrong syntax for IP
  213. #return "wrong syntax - IP must be supplied correctly <0..254>.<0..254>.<0..254>.<000..254>" if (int(@a) < 3);
  214. #assign name and port
  215. $hash->{NAME} = $name;
  216. $hash->{IP} = $ip;
  217. #backup name for a later rename
  218. $hash->{DEVNAME} = $name;
  219. #get first info and launch timer
  220. InternalTimer(gettimeofday(), "Robonect_GetUpdate", $hash, 0);
  221. #finally create decice
  222. #defptr is needed to supress FHEM input
  223. #removed according Rudis recommendation
  224. #$modules{Robonect}{defptr}{$name} = $hash;
  225. #default event-on-changed-reading for all readings
  226. #removed according Rudis recommendation
  227. #$attr{$name}{"event-on-change-reading"} = ".*";
  228. #default poll-interval
  229. #removed according Rudis recommendation
  230. #$attr{$name}{"pollInterval"} = 90;
  231. Log3 ($name, 5, "exit define");
  232. return undef;
  233. }
  234. #Release this device
  235. #Is called at every delete / shutdown
  236. #############################
  237. sub Robonect_Undef($$)
  238. {
  239. my ($hash, $name) = @_;
  240. Log3 ($name, 5, "enter undef $name: hash: $hash name: $name");
  241. #kill interval timer
  242. RemoveInternalTimer($hash);
  243. #close port
  244. Robonect_Shutdown ($hash);
  245. #remove module. Refer to DevName, because module may be renamed
  246. delete $modules{KNX}{defptr}{$hash->{DEVNAME}};
  247. #removed according to Rudis recommendation
  248. #remove name
  249. #delete $hash->{NAME};
  250. #remove backuped name
  251. #delete $hash->{DEVNAME};
  252. Log3 ($name, 5, "exit undef");
  253. return undef;
  254. }
  255. #Release this device
  256. #Is called at every delete / shutdown
  257. #############################
  258. sub Robonect_Shutdown($)
  259. {
  260. my ($hash) = @_;
  261. #hash may be de-referenced already
  262. my $name = "robonect-not_named_any_more";
  263. $name = $hash->{NAME} if (ref($hash) eq "HASH");
  264. Log3 ($name, 5, "enter shutdown $name: hash: $hash name: $name");
  265. Log3 ($name, 5, "exit shutdown");
  266. return undef;
  267. }
  268. #This function is called from fhem from rime to time
  269. #############################
  270. sub Robonect_Ready($)
  271. {
  272. my ($hash) = @_;
  273. my $name = $hash->{NAME};
  274. Log3 ($name, 5, "enter ready $name: hash: $hash name: $name");
  275. Log3 ($name, 5, "exit ready");
  276. return undef;
  277. }
  278. #Reads info from the mower
  279. #############################
  280. sub Robonect_Get($@)
  281. {
  282. my ($hash, @a) = @_;
  283. my $name = $hash->{NAME};
  284. my $tempStr = join (", ", @a);
  285. Log3 ($name, 5, "enter get $name: $name hash: $hash, attributes: $tempStr");
  286. #backup cmd
  287. my $cmd = $a[1];
  288. #lower cmd
  289. $cmd = lc($cmd);
  290. #create response, if cmd is wrong or gui asks
  291. my $cmdTemp = Robonect_getCmdList ($hash, $cmd, %gets);
  292. return $cmdTemp if (defined ($cmdTemp));
  293. my ($userName, $passWord) = Robonect_getCredentials ($hash);
  294. #basic url
  295. my $url = "http://" . $hash->{IP} . "/json?";
  296. #append userdata, if given
  297. $url = $url . "user=" . $userName . "&pass=" . $passWord . "&" if (defined ($userName) and defined ($passWord));
  298. #append command
  299. #$url = $url . $commands{GET_STATUS};
  300. $url = $url . "cmd=" . $cmd;
  301. my $httpData;
  302. $httpData->{url} = $url;
  303. $httpData->{loglevel} = AttrVal ($name, "verbose", 2);
  304. $httpData->{loglevel} = 5;
  305. $httpData->{hideurl} = 0;
  306. $httpData->{callback} = \&Robonect_callback;
  307. $httpData->{hash} = $hash;
  308. #$httpData->{cmd} = $commands{GET_STATUS};
  309. $httpData->{cmd} = "cmd=" . $cmd;
  310. $httpData->{timeout} = AttrVal ($name, "timeout", 4);
  311. HttpUtils_NonblockingGet($httpData);
  312. Log3 ($name, 5, "exit get");
  313. my $err = $httpData->{err};
  314. if (defined ($err) and (length ($err) > 0))
  315. {
  316. return $err;
  317. }
  318. else
  319. {
  320. return "update requested";
  321. }
  322. }
  323. #Sends commands to the mower
  324. #############################
  325. sub Robonect_Set($@)
  326. {
  327. my ($hash, @a) = @_;
  328. my $name = $hash->{NAME};
  329. my $tempStr = join (", ", @a);
  330. Log3 ($name, 5, "enter set $name: $name hash: $hash, attributes: $tempStr");
  331. #backup cmd
  332. my $cmd = $a[1];
  333. #lower cmd
  334. $cmd = lc($cmd);
  335. #create response, if cmd is wrong or gui asks
  336. my $cmdTemp = Robonect_getCmdList ($hash, $cmd, %sets);
  337. return $cmdTemp if (defined ($cmdTemp));
  338. my ($userName, $passWord) = Robonect_getCredentials ($hash);
  339. my $decodedCmd = $commands{SET_MODE}{$cmd};
  340. #if command is hybernate, do this
  341. if ($cmd eq lc($HYBERNATE))
  342. {
  343. Log3 ($name, 5, "set - got hybernate for set-command");
  344. my $val = lc($a[2]);
  345. $val = "off" if (!defined ($val));
  346. if ($val =~ m/on/)
  347. {
  348. readingsSingleUpdate($hash, $HYBERNATE, "on", 1);
  349. Log3 ($name, 5, "set - activated hybernate");
  350. }
  351. elsif ($val =~ m/off/)
  352. {
  353. readingsSingleUpdate($hash, $HYBERNATE, "off", 1);
  354. Log3 ($name, 5, "set - deactivated hybernate");
  355. }
  356. else
  357. {
  358. return "only on or off are supported for $HYBERNATE";
  359. }
  360. }
  361. #if command is user
  362. elsif ($cmd eq lc($USER))
  363. {
  364. setKeyValue("ROBONECT_USER_$name", $a[2]);
  365. Log3 ($name, 5, "set - wrote username");
  366. }
  367. #if command is password
  368. elsif ($cmd eq lc($PW))
  369. {
  370. setKeyValue("ROBONECT_PW_$name", $a[2]);
  371. Log3 ($name, 5, "set - wrote password");
  372. }
  373. #else proceed with communication to mower
  374. #execute it
  375. elsif (defined ($decodedCmd))
  376. {
  377. my $url = "http://" . $hash->{IP} . "/json?";
  378. #append userdata, if given
  379. $url = $url . "user=" . $userName . "&pass=" . $passWord . "&" if (defined ($userName) and defined ($passWord));
  380. #append command
  381. $url = $url . $decodedCmd;
  382. #execute for alle "extra" arguments
  383. for (my $i = 2; $i < @a; $i++)
  384. {
  385. my $cmdAttr = $a[$i];
  386. my ($key, $val) = split (/=/, $cmdAttr);
  387. if (defined ($key) and defined ($val) and (length ($key) > 0) and (length ($val) > 0))
  388. {
  389. $url = $url . "&" . $key . "=" . $val;
  390. Log3 ($name, 5, "set - found option. Key:$key Value:$val")
  391. }
  392. else
  393. {
  394. Log3 ($name, 1, "set - found incomplete option. Key:$key Value:$val")
  395. }
  396. }
  397. Log3 ($name, 5, "set - complete call-string: $url");
  398. my $httpData;
  399. $httpData->{url} = $url;
  400. $httpData->{loglevel} = AttrVal ($name, "verbose", 2);
  401. $httpData->{loglevel} = 5;
  402. $httpData->{hideurl} = 0;
  403. $httpData->{callback} = \&Robonect_callback;
  404. $httpData->{hash} = $hash;
  405. $httpData->{cmd} = $decodedCmd;
  406. HttpUtils_NonblockingGet($httpData);
  407. return $httpData->{err};
  408. #BUllshit - never gets called
  409. #Robonect_GetUpdate($hash);
  410. }
  411. Log3 ($name, 5, "exit set");
  412. return;
  413. }
  414. #called on every mod of the attributes
  415. #############################
  416. sub Robonect_Attr(@)
  417. {
  418. my ($cmd,$name,$attr_name,$attr_value) = @_;
  419. Log3 ($name, 5, "enter attr $name: $name, attrName: $attr_name");
  420. #if($cmd eq "set")
  421. #{
  422. # if(($attr_name eq "debug") and (($attr_value eq "1") or ($attr_value eq "true")))
  423. # {
  424. # #todo
  425. # }
  426. #}
  427. Log3 ($name, 5, "exit attr");
  428. return undef;
  429. }
  430. #Split reading for DBLOG
  431. #############################
  432. sub Robonect_DbLog_split($) {
  433. my ($event) = @_;
  434. my ($reading, $value, $unit);
  435. my $tempStr = join (", ", @_);
  436. Log (5, "splitFn - enter, attributes: $tempStr");
  437. #detect reading - real reading or state?
  438. my $isReading = "false";
  439. $isReading = "true" if ($event =~ m/: /);
  440. #split input-string
  441. my @strings = split (" ", $event);
  442. my $startIndex = undef;
  443. $unit = "";
  444. return undef if (not defined ($strings[0]));
  445. #real reading?
  446. if ($isReading =~ m/true/)
  447. {
  448. #first one is always reading
  449. $reading = $strings[0];
  450. $reading =~ s/:?$//;
  451. $startIndex = 1;
  452. }
  453. #plain state
  454. else
  455. {
  456. #for reading state nothing is supplied
  457. $reading = "state";
  458. $startIndex = 0;
  459. }
  460. return undef if (not defined ($strings[$startIndex]));
  461. #per default join all single pieces
  462. $value = join(" ", @strings[$startIndex..(int(@strings) - 1)]);
  463. #numeric value?
  464. #if ($strings[$startIndex] =~ /^[+-]?\d*[.,]?\d+/)
  465. if ($strings[$startIndex] =~ /^[+-]?\d*[.,]?\d+$/)
  466. {
  467. $value = $strings[$startIndex];
  468. #single numeric value? Assume second par is unit...
  469. if ((defined ($strings[$startIndex + 1])) && !($strings[$startIndex+1] =~ /^[+-]?\d*[.,]?\d+/))
  470. {
  471. $unit = $strings[$startIndex + 1] if (defined ($strings[$startIndex + 1]));
  472. }
  473. }
  474. #numeric value?
  475. #if ($strings[$startIndex] =~ /^[+-]?\d*[.,]?\d+/)
  476. #{
  477. # $value = $strings[$startIndex];
  478. # $unit = $strings[$startIndex + 1] if (defined ($strings[$startIndex + 1]));
  479. #}
  480. #string or raw
  481. #else
  482. #{
  483. # $value = join(" ", @strings[$startIndex..(int(@strings) - 1)]);
  484. #}
  485. Log (5, "splitFn - READING: $reading, VALUE: $value, UNIT: $unit");
  486. return ($reading, $value, $unit);
  487. }
  488. #Called on the interval timer, if enabled
  489. #############################
  490. sub Robonect_GetUpdate($)
  491. {
  492. my ($hash) = @_;
  493. my $name = $hash->{NAME};
  494. Log3 ($name, 5, "enter update $name: $name");
  495. #evaluate reading hybernate
  496. my $hybernate = $hash->{READINGS}{$HYBERNATE}{VAL};
  497. #supress sending, if hybernate is set
  498. if (!defined ($hybernate) or ($hybernate =~ m/[off]|[0]/))
  499. {
  500. #get status
  501. my @callAttr;
  502. $callAttr[0] = $name;
  503. $callAttr[1] = "status";
  504. Robonect_Get ($hash, @callAttr);
  505. #try to poll health, if desired
  506. my $useHealth = AttrVal($name,"useHealth",undef);
  507. if (defined ($useHealth) and ($useHealth =~ m/[1]|([oO][nN])/))
  508. {
  509. $callAttr[1] = "health";
  510. Robonect_Get ($hash, @callAttr);
  511. }
  512. }
  513. my $interval = AttrVal($name,"pollInterval",90);
  514. #reset timer
  515. InternalTimer(gettimeofday() + $interval, "Robonect_GetUpdate", $hash, 1) if ($interval > 0);
  516. Log3 ($name, 5, "exit update");
  517. }
  518. #Private function which handles http-responses
  519. #############################
  520. sub Robonect_callback ($)
  521. {
  522. my ($param, $err, $data) = @_;
  523. my $hash = $param->{hash};
  524. my $name = $hash->{NAME};
  525. #wenn ein Fehler bei der HTTP Abfrage aufgetreten ist
  526. if($err ne "")
  527. {
  528. Log3 ($name, 4, "callback - error while requesting ".$param->{url}." - $err");
  529. $hash->{LAST_COMM_STATUS} = $err;
  530. #set reading with failure - notify only, when state has not changed
  531. readingsSingleUpdate($hash, "state", $OFFLINE, 1);
  532. }
  533. #wenn die Abfrage erfolgreich war ($data enthält die Ergebnisdaten des HTTP Aufrufes)
  534. elsif($data ne "")
  535. {
  536. Log3 ($name, 4, "callback - url ".$param->{url}." returned: $data");
  537. #repair V5.0b
  538. $data =~ s/:"/,"/g;
  539. $data = "" if (!defined($data));
  540. #execute in eval to be safe - therefore $answer may be undef
  541. my $answer = undef;
  542. eval '$answer = decode_json (encode_utf8($data))';
  543. #try to replaye german special chars
  544. if (defined ($answer) and (length ($answer) > 0))
  545. {
  546. my $umlautkeys = join ("|", keys(%umlaute));
  547. $answer =~ s/($umlautkeys)/$umlaute{$1}/g;
  548. }
  549. #backup error from eval
  550. my $evalErr = $@;
  551. if (not defined($answer))
  552. {
  553. my $err = "callback - error while decoding content";
  554. $err = $err . ": " . $evalErr if (defined ($evalErr));
  555. Log3 ($name, 2, $err);
  556. readingsSingleUpdate($hash, "fehler_aktuell", "cannot decode content", 1);
  557. return undef;
  558. }
  559. Log3 ($name, 4, "callback - url ".$param->{url}." repaired: $data");
  560. my ($key, $value) = Robonect_decodeContent ($hash, $answer, "successful", undef, undef);
  561. $hash->{LAST_CMD} = $param->{cmd};
  562. $hash->{LAST_COMM_STATUS} = "success: " . $value;
  563. Log3 ($name, 5, "callback - communication ok");
  564. #my %tmp = %$answer;
  565. #print "answer: ", %tmp, "\n";
  566. #status-readings
  567. #answer may be undefined due to eval
  568. if ($answer->{successful} =~ m/(true)|(1)/)
  569. {
  570. Log3 ($name, 5, "callback - update readings");
  571. readingsBeginUpdate($hash);
  572. #($key, $value) = Robonect_decodeContent ($hash, $answer, "successful", undef);
  573. #readingsBulkUpdate($hash, $key, $value);
  574. ($key, $value) = Robonect_decodeContent ($hash, $answer, "status", "status", undef);
  575. if (defined ($value) and !($value =~ m/undef/))
  576. {
  577. readingsBulkUpdate($hash, $key, $value);
  578. readingsBulkUpdate($hash, "state", $value);
  579. }
  580. ($key, $value) = Robonect_decodeContent ($hash, $answer, "status", "mode", undef);
  581. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  582. ($key, $value) = Robonect_decodeContent ($hash, $answer, "status", "battery", undef);
  583. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  584. $value = 0;
  585. ($key, $value) = Robonect_decodeContent ($hash, $answer, "status", "duration", undef);
  586. readingsBulkUpdate($hash, $key, sprintf ("%d", $value/3600)) if (defined($value) and ($value =~ m/(?:\d*\.)?\d+/));
  587. ($key, $value) = Robonect_decodeContent ($hash, $answer, "status", "hours", undef);
  588. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  589. ($key, $value) = Robonect_decodeContent ($hash, $answer, "timer", "status", undef);
  590. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  591. ($key, $value) = Robonect_decodeContent ($hash, $answer, "timer", "next", "date");
  592. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  593. ($key, $value) = Robonect_decodeContent ($hash, $answer, "timer", "next", "time");
  594. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  595. $value = -95;
  596. ($key, $value) = Robonect_decodeContent ($hash, $answer, "wlan", "signal", undef);
  597. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  598. if (defined($value) and ($value =~ m/(?:\d*\.)?\d+/))
  599. {
  600. $value = sprintf ("%d", ($value + 95) / 0.6);
  601. readingsBulkUpdate($hash, $key . "-prozent", $value);
  602. }
  603. #try to decode health, if desired
  604. my $useHealth = AttrVal($name,"useHealth",undef);
  605. if (defined ($useHealth) and ($useHealth =~ m/[1]|([oO][nN])/))
  606. {
  607. ($key, $value) = Robonect_decodeContent ($hash, $answer, "health", "alarm", "voltagebattmin");
  608. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  609. ($key, $value) = Robonect_decodeContent ($hash, $answer, "health", "alarm", "voltagebattmax");
  610. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  611. ($key, $value) = Robonect_decodeContent ($hash, $answer, "health", "alarm", "temperatureMin");
  612. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  613. ($key, $value) = Robonect_decodeContent ($hash, $answer, "health", "alarm", "temperatureMax");
  614. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  615. ($key, $value) = Robonect_decodeContent ($hash, $answer, "health", "alarm", "humidityMax");
  616. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  617. ($key, $value) = Robonect_decodeContent ($hash, $answer, "health", "voltages", "batt");
  618. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  619. ($key, $value) = Robonect_decodeContent ($hash, $answer, "health", "umwelt", "temperature");
  620. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  621. ($key, $value) = Robonect_decodeContent ($hash, $answer, "health", "umwelt", "humidity");
  622. readingsBulkUpdate($hash, $key, $value) if (defined ($value) and !($value =~ m/undef/));
  623. }
  624. readingsEndUpdate($hash, 1);
  625. }
  626. #error?
  627. #answer may be undefined due to eval
  628. my $errorOccured = $answer->{status}->{status};
  629. if (defined ($errorOccured) and ($errorOccured =~ m/7/))
  630. {
  631. readingsSingleUpdate($hash, "fehler_aktuell", $answer->{error}->{error_message}, 1);
  632. }
  633. #no error
  634. elsif (defined ($errorOccured))
  635. {
  636. my $hashref = $hash->{READINGS};
  637. my %readings = %$hashref;
  638. #delete readings
  639. foreach my $key (keys %readings)
  640. {
  641. #delete $readings{$key} if ($key =~ m/^fehler.*/);
  642. delete $hash->{READINGS}{$key} if ($key =~ m/^fehler.*/);
  643. #delete $hash->{READINGS}{$key} if ($key =~ m/^fehler-aktuell.*/);
  644. }
  645. }
  646. }
  647. }
  648. #Private function to get json-content
  649. #############################
  650. sub Robonect_decodeContent ($$$$$)
  651. {
  652. my ($hash, $msg, $key1, $key2, $key3) = @_;
  653. my $name = $hash->{NAME};
  654. my $rdName = undef;
  655. my $rdValue = undef;
  656. my $template = undef;
  657. if (defined ($key2) && defined ($key3))
  658. {
  659. $template = $elements{$key1}{$key2}{$key3};
  660. $rdName = $elements{$key1}{$key2}{ALIAS} . "-" . $template->{ALIAS};
  661. $rdValue = $msg->{$key1}->{$key2}->{$key3};
  662. }
  663. elsif (defined ($key2))
  664. {
  665. $template = $elements{$key1}{$key2};
  666. $rdName = $elements{$key1}{ALIAS} . "-" . $template->{ALIAS};
  667. $rdValue = $msg->{$key1}->{$key2};
  668. }
  669. else
  670. {
  671. $template = $elements{$key1};
  672. $rdValue = $msg->{$key1};
  673. $rdName = $template->{ALIAS};
  674. }
  675. $rdValue = "undef" if (not defined ($rdValue));
  676. $rdValue = $template->{$rdValue} if (defined ($template->{$rdValue}));
  677. Log3 ($name, 5, "decodeContent - NAME: $rdName, VALUE: $rdValue");
  678. return $rdName, $rdValue;
  679. }
  680. #Private function to evaluate credentials
  681. #############################
  682. sub Robonect_decodeAnswer ($$$)
  683. {
  684. my ($hash, $getCmd, @readings) = @_;
  685. my $name = $hash->{NAME};
  686. my @list;
  687. foreach my $reading (@readings)
  688. {
  689. my $answer = undef;
  690. my $transval = undef;
  691. my ($header, $key, $value) = undef;
  692. $header = $reading->{header};
  693. $key = $reading->{key};
  694. $value = $reading->{value};
  695. if ($header =~ m/robonect/i)
  696. {
  697. $answer->{name} = $getCmd . "-" . $elements{$header}{$key}{ALIAS};
  698. $transval = $elements{$header}{$key}{$value};
  699. }
  700. else
  701. {
  702. $answer->{name} = $getCmd . "-" . $elements{"robonect"}{$header}{ALIAS} . "-" . $elements{"robonect"}{$header}{$key}{ALIAS};
  703. $transval = $elements{"robonect"}{$header}{$key}{$value};
  704. }
  705. if (defined($transval))
  706. {
  707. $answer->{value} = $transval;
  708. }
  709. else
  710. {
  711. $answer->{value} = $value;
  712. }
  713. #$answer->{name} = $getCmd . "-" . $answer->{name};
  714. Log3 ($name, 5, "decodeAnswer - NAME: $answer->{name}, VALUE: $answer->{value}");
  715. push (@list, $answer);
  716. }
  717. return @list;
  718. }
  719. #Private function to evaluate credentials
  720. #############################
  721. sub Robonect_getCredentials ($)
  722. {
  723. my ($hash) = @_;
  724. my $name = $hash->{NAME};
  725. my $userName = undef;
  726. my $passWord = undef;
  727. #use username and password previously defined with set and stored in "registry"
  728. my ($errUsr, $user) = getKeyValue("ROBONECT_USER_$name");
  729. Log3 ($name, 4, "credentials - Error while getting value USER: " . $errUsr) if (defined ($errUsr));
  730. my ($errPw, $password) = getKeyValue("ROBONECT_PW_$name");
  731. Log3 ($name, 4, "credentials - Error while getting value PASSWORD: " . $errPw) if (defined ($errPw));
  732. if (defined ($user) and defined ($password))
  733. {
  734. Log3 ($name, 5, "credentials - found with key-value");
  735. return $userName, $passWord;
  736. }
  737. #parse basicAuth - overrules getKeyValue
  738. my $basicAuth = AttrVal ($name, "basicAuth", undef);
  739. if (defined ($basicAuth))
  740. {
  741. #if the string does NOT contain a ":", assume base64-encoded data
  742. if (not ($basicAuth =~ m/:/))
  743. {
  744. $basicAuth = decode_base64 ($basicAuth);
  745. Log3 ($name, 5, "credentials - found encrypted data");
  746. }
  747. #try to split
  748. my @plainAuth = split (":", $basicAuth);
  749. #found plain authentication
  750. if (int(@plainAuth) == 2)
  751. {
  752. $userName = $plainAuth[0];
  753. $passWord = $plainAuth[1];
  754. Log3 ($name, 5, "credentials - found plain or decrypted data");
  755. }
  756. else
  757. {
  758. Log3 ($name, 0, "credentials - user/pw combination not correct");
  759. }
  760. }
  761. #parse credential-File - overrules basicAuth ang getKeyValue
  762. my $credentials = AttrVal ($name, "credentials", undef);
  763. if(defined($credentials))
  764. {
  765. #cannot open file
  766. if(!open(CFG, $credentials))
  767. {
  768. Log3 ($name, 0, "cannot open credentials file: $credentials") ;
  769. }
  770. #read it
  771. else
  772. {
  773. my @cfg = <CFG>;
  774. close(CFG);
  775. my %creds;
  776. eval join("", @cfg);
  777. #extract it
  778. $userName =~ $creds{$name}{username};
  779. $passWord =~ $creds{$name}{password};
  780. Log3 ($name, 5, "credentials - found in file");
  781. }
  782. }
  783. return $userName, $passWord;
  784. }
  785. #Private function to evaluate command-lists
  786. #############################
  787. sub Robonect_getCmdList ($$$)
  788. {
  789. my ($hash, $cmd, %cmdArray) = @_;
  790. my $name = $hash->{NAME};
  791. #return, if cmd is valid
  792. return undef if (defined ($cmd) and defined ($cmdArray{$cmd}));
  793. #response for gui or the user, if command is invalid
  794. my $retVal;
  795. foreach my $mySet (keys %cmdArray)
  796. {
  797. #append set-command
  798. $retVal = $retVal . " " if (defined ($retVal));
  799. $retVal = $retVal . $mySet;
  800. #get options
  801. my $myOpt = $cmdArray{$mySet};
  802. #append option, if valid
  803. $retVal = $retVal . ":" . $myOpt if (defined ($myOpt) and (length ($myOpt) > 0));
  804. $myOpt = "" if (!defined($myOpt));
  805. #Logging makes me crazy...
  806. #Log3 ($name, 5, "parse cmd-table - Set:$mySet, Option:$myOpt, RetVal:$retVal");
  807. }
  808. if (!defined ($retVal))
  809. {
  810. $retVal = "error while parsing set-table" ;
  811. }
  812. else
  813. {
  814. $retVal = "Unknown argument $cmd, choose one of " . $retVal;
  815. }
  816. return $retVal;
  817. }
  818. 1;
  819. =pod
  820. =begin html
  821. <a name="Robonect"></a>
  822. <h3>Robonect</h3>
  823. <ul>
  824. <p>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!</p>
  825. <p><a name="RobonectDefine"></a> <b>Define</b></p>
  826. <ul>
  827. <code>define &lt;name&gt; Robonect &lt;ip-adress or name&gt;</code>
  828. <p>Setting Winterschlaf prevents communicating with the mower.</p>
  829. <p>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.</p>
  830. <p>Example:</p>
  831. <pre>
  832. define myMower Robonect 192.168.13.5
  833. define myMower Robonect myMowersDNSName
  834. </pre>
  835. </ul>
  836. <p><a name="RobonectSet"></a> <b>Set</b></p>
  837. <ul>
  838. <b>Set</b>
  839. <ul>
  840. <li>auto<br>
  841. Sets the mower to automatic mode. The mower follows the internal timer, until another mode is chosen. The mower can be stopped with stop at any time. After using stop: be aware, that it continues
  842. mowing only if the timer supplies an active slot AND start is executed before.
  843. </li>
  844. <li>manuell<br>
  845. This sets the mower to manual mode. The internal timer is ignored. Mowing starts with start and ends with stop.
  846. </li>
  847. <li>home<br>
  848. This sends the mower directly home. Until you switch to auto or manuell, no further mowing work is done.
  849. </li>
  850. <li>feierabend<br>
  851. This sends the mower home for the rest of the actual timeslot. At the next active timeslot mowing is continued automatically.
  852. </li>
  853. <li>start<br>
  854. Start mowing in manual mode or in automatic mode at active timer-slot.
  855. </li>
  856. <li>stop<br>
  857. Stops mowing immediately. The mower does not drive home. It stands there, until battery is empty. Use with care!
  858. </li>
  859. <li>maehauftrag<br>
  860. This command starts a single mowing-task. It can be applied as much parameters as you want. For example you can influence start-/stop-time and duration.<br>
  861. The parameters have to be named according the robonect-API (no doublechecking!).<br>
  862. <br>
  863. Example:<br>
  864. Lauch at 15:00, Duration 120 minutes, do not use a remote-start-point, do not change mode after finishing task
  865. <pre>
  866. set myMower maehauftrag start=15:00 duration=120 remotestart=0 after=4
  867. </pre>
  868. </li>
  869. <li>winterschlaf &lt;on, off&gt;<br>
  870. If set to on, no polling is executet. Please use this during winter.
  871. </li>
  872. <li>user &ltuser&gt;<br>
  873. One alternative to store authentication: username for robonect-logon is stored in FhemUtils or database (not encrypted).<br
  874. If set, the attributes regarding authentication are ignored.
  875. </li>
  876. <li>password &lt;password&gt;<br>
  877. One alternative to store authentication: password for robonect-logon is stored in FhemUtils or database (not encrypted).<br
  878. If set, the attributes regarding authentication are ignored.
  879. </li>
  880. </ul>
  881. </ul>
  882. <p><a name="RobonectGet"></a> <b>Get</b></p>
  883. <ul>
  884. <b>Get</b>
  885. <ul>
  886. <li>status<br>
  887. Gets the actual state of the mower - normally not needed, because the status is polled cyclic.
  888. </li>
  889. <li>health<br>
  890. This one gets more detailed information - like voltages and temperatures. It is NOT SUPPORTED BY ALL MOWERS!!!<br>
  891. If enabled via attribute, health is polled accordingly status.
  892. </li>
  893. </ul>
  894. </ul>
  895. <p><a name="RobonectAttr"></a> <b>Attributes</b></p>
  896. <ul><br>
  897. Common attributes:<br>
  898. <a href="#DbLogInclude">DbLogInclude</a><br>
  899. <a href="#DbLogExclude">DbLogExclude</a><br>
  900. <a href="#IODev">IODev</a><br>
  901. <a href="#alias">alias</a><br>
  902. <a href="#comment">comment</a><br>
  903. <a href="#devStateIcon">devStateIcon</a><br>
  904. <a href="#devStateStyle">devStateStyle</a><br>
  905. <a href="#do_not_notify">do_not_notify</a><br>
  906. <a href="#readingFnAttributes">readingFnAttributes</a><br>
  907. <a href="#event-aggregator">event-aggregator</a><br>
  908. <a href="#event-min-interval">event-min-interval</a><br>
  909. <a href="#event-on-change-reading">event-on-change-reading</a><br>
  910. <a href="#event-on-update-reading">event-on-update-reading</a><br>
  911. <a href="#eventMap">eventMap</a><br>
  912. <a href="#group">group</a><br>
  913. <a href="#icon">icon</a><br>
  914. <a href="#room">room</a><br>
  915. <a href="#showtime">showtime</a><br>
  916. <a href="#sortby">sortby</a><br>
  917. <a href="#stateFormat">stateFormat</a><br>
  918. <a href="#userReadings">userReadings</a><br>
  919. <a href="#userattr">userattr</a><br>
  920. <a href="#verbose">verbose</a><br>
  921. <a href="#webCmd">webCmd</a><br>
  922. <a href="#widgetOverride">widgetOverride</a><br>
  923. <br>
  924. </ul>
  925. <p><a name="RobonectCredentials"></a> <b>credentials</b></p>
  926. <ul>
  927. If you supply a valid path to a credentials file, this combination is used to log in at robonect. This mechism overrules basicAuth.
  928. </ul>
  929. <p><a name="RobonectBasicAuth"></a> <b>basicAuth</b></p>
  930. <ul>
  931. You can supply username and password plain or base-64-encoded. For a base64-encoder, use google.
  932. <p>Example:</p>
  933. <pre>
  934. define myMower Robonect 192.168.5.1
  935. attr myMower basicAuth me:mySecret
  936. </pre>
  937. <pre>
  938. define myMower Robonect 192.168.5.1
  939. attr myMower basicAuth bWU6bXlTZWNyZXQ=
  940. </pre>
  941. </ul>
  942. <p><a name="RobonectPollInterval"></a> <b>pollInterval</b></p>
  943. <ul>
  944. Supplies the interval top poll the robonect in seconds. Per default 90s is set.
  945. </ul>
  946. <p><a name="RobonectTimeout"></a> <b>timeout</b></p>
  947. <ul>
  948. Timeout for httpData to recive data. Default is 4s.
  949. </ul>
  950. <p><a name="RobonectHealth"></a> <b>useHealth</b></p>
  951. <ul>
  952. If set to 1, the health-status of the mower will be polled. Be aware NOT ALL MOWERS ARE SUPPORTED!<br>
  953. Please refer to logfile or LAST_COMM_STATUS if the function does not seem to be working.
  954. </ul>
  955. </ul>
  956. =end html
  957. =device
  958. =item summary Communicates to HW-module robonect
  959. =item summary_DE Kommuniziert mit dem HW-Modul Robonect
  960. =begin html_DE
  961. <a name="Robonect"></a>
  962. <h3>Robonect</h3>
  963. <ul>
  964. <p>Robonect ist ein Nachr&uml;stmodul f&uuml;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&ouml;tigsten Kommandos. Dieses Modul ben&ouml;tigt libjson-perl. Bitte NICHT VERGESSEN zu installieren!</p>
  965. <p><a name="RobonectDefine"></a> <b>Define</b></p>
  966. <ul>
  967. <code>define &lt;name&gt; Robonect &lt;IP-Adresse oder Name&gt;</code>
  968. <p>Mit gesetztem Winterschlaf wird die Kommunikation zum M&auml;her unterbunden.</p>
  969. <p>Die Zugangsinformationen k&ouml;nnen im Klartext bei der Definition angegeben werden. Wahlweise auch per Attribut. Standardm&auml;&szlig;ig wird der Status vom RObonect alle 90s aktualisiert.</p>
  970. <p>Beispiel:</p>
  971. <pre>
  972. define myMower Robonect 192.168.13.5
  973. define myMower Robonect myMowersDNSName
  974. </pre>
  975. </ul>
  976. <p><a name="RobonectSet"></a> <b>Set</b></p>
  977. <ul>
  978. <b>Set</b>
  979. <ul>
  980. <li>auto<br>
  981. Dies versetzt den M&auml;her in den Automatikmodus. Der M&auml;her reagiert nur auf den internen Timer, bis eine andere Betriebsart gew&auml;hlt wird. Der M&auml;her kann mit Stop jederzeit
  982. angehalten werden. Es wird erst wieder begonnen zu m&auml;hen, wenn der Timer (wieder) ein aktives Fenster hat UND Start gesendet wurde.
  983. </li>
  984. <li>manuell<br>
  985. Dies versetzt den M&auml;her in den manuellen modus. Der interne Timer wird nicht beachtet. Der M&auml;her reagiert nur auf Start oder Stopp Befehle von FHEM.
  986. </li>
  987. <li>home<br>
  988. Dies schickt den M&auml;her direkt nach hause. Weiteres m&auml;hen wird verhindert, bis auf manuell oder auto umgeschalten wird.
  989. </li>
  990. <li>feierabend<br>
  991. Dies schickt den M&auml;her f&uuml;r den aktuellen Timerslot direkt nach hause. Beim n&auml;chsten aktiven Timerslot wird weitergem&auml;ht.
  992. </li>
  993. <li>start<br>
  994. Startet den M&auml;hvorgang im manuellen Modus oder im Automatikmodus bei aktivem Zeitslot.
  995. </li>
  996. <li>stop<br>
  997. Beendet den M&auml;hvorgang. Der M&auml;her f&auml;hrt nicht nach Hause und beginnt nicht wieder zu m&auml;hen. Er bleibt stehen, bis die Batterie leer ist. Nur mit Bedacht benutzen!
  998. </li>
  999. <li>maehauftrag<br>
  1000. Hiermit wird ein (einmaliger) Auftrag an den M&auml;her abgesetzt. Es können beliebig viele Parameter mitgegeben werden. So kann zum Beispiel der Modus nach dem Auftrag,
  1001. sowie Start- oder Stoppzeit beeinflusst werden.<br>
  1002. Die Parameter m&uuml;ssen wie in der API des Robonect beschrieben lauten. Es erfolgt keine syntaktische Prüfung!<br>
  1003. <br>
  1004. Beispiel:<br>
  1005. Startzeit 15 Uhr, Dauer 120 Minuten, keinen Fernstartpunkt verwenden, keine Betriebsartenumschaltung nach Auftragsende
  1006. <pre>
  1007. set myMower maehauftrag start=15:00 duration=120 remotestart=0 after=4
  1008. </pre>
  1009. </li>
  1010. <li>winterschlaf &lt;on, off&gt;<br>
  1011. Wenn aktiviert, wird das Pollen unterbunden. Empfiehlt sich f&uuml;r die Winterpause.
  1012. </li>
  1013. <li>user &ltuser&gt;<br>
  1014. Alternativ zur Angabe per Argument kann per Set-Befehl der Benutzername zur Anmeldung am Robonect hier einmalig eingegeben werden. Er wird im Klartext in FhemUtils oder der DB gespeichert.<br>
  1015. Wenn angegeben, werden die Attribute zur Authentisierung ignoriert.
  1016. </li>
  1017. <li>password &lt;password&gt;<br>
  1018. Alternativ zur Angabe per Argument kann per Set-Befehl das Passwort zur Anmeldung am Robonect hier einmalig eingegeben werden. Er wird im Klartext in FhemUtils oder der DB gespeichert.<br>
  1019. Wenn angegeben, werden die Attribute zur Authentisierung ignoriert.
  1020. </li>
  1021. </ul>
  1022. </ul>
  1023. <p><a name="RobonectGet"></a> <b>Get</b></p>
  1024. <ul>
  1025. <b>Get</b>
  1026. <ul>
  1027. <li>status<br>
  1028. Holt den aktuellen Status des M&auml;hers. Wird normalerweise nicht ben&ouml;tigt, da automatisch gepolled wird.
  1029. </li>
  1030. <li>health<br>
  1031. Mit diesem Kommando können detailliertere Informationen vom M&auml;her gelesen werden. Beispielsweise sind einge Spannungen und Umweltbedingungen verf&uuml;gbar.<br>
  1032. Es werden NICHT ALLE M&Auml;HER UNTERST&Uuml;TZT!!!
  1033. Wenn das entsprechende Attribut gesetzt ist, wird health analog status gepolled.
  1034. This one gets more detailed information - like voltages and temperatures. It is NOT SUPPORTED BY ALL MOWERS!!!<br>
  1035. If enabled via attribute, health is polled accordingly status.
  1036. </li>
  1037. </ul>
  1038. </ul>
  1039. <p><a name="RobonectAttr"></a> <b>Attributes</b></p>
  1040. <ul><br>
  1041. Common attributes:<br>
  1042. <a href="#DbLogInclude">DbLogInclude</a><br>
  1043. <a href="#DbLogExclude">DbLogExclude</a><br>
  1044. <a href="#IODev">IODev</a><br>
  1045. <a href="#alias">alias</a><br>
  1046. <a href="#comment">comment</a><br>
  1047. <a href="#devStateIcon">devStateIcon</a><br>
  1048. <a href="#devStateStyle">devStateStyle</a><br>
  1049. <a href="#do_not_notify">do_not_notify</a><br>
  1050. <a href="#readingFnAttributes">readingFnAttributes</a><br>
  1051. <a href="#event-aggregator">event-aggregator</a><br>
  1052. <a href="#event-min-interval">event-min-interval</a><br>
  1053. <a href="#event-on-change-reading">event-on-change-reading</a><br>
  1054. <a href="#event-on-update-reading">event-on-update-reading</a><br>
  1055. <a href="#eventMap">eventMap</a><br>
  1056. <a href="#group">group</a><br>
  1057. <a href="#icon">icon</a><br>
  1058. <a href="#room">room</a><br>
  1059. <a href="#showtime">showtime</a><br>
  1060. <a href="#sortby">sortby</a><br>
  1061. <a href="#stateFormat">stateFormat</a><br>
  1062. <a href="#userReadings">userReadings</a><br>
  1063. <a href="#userattr">userattr</a><br>
  1064. <a href="#verbose">verbose</a><br>
  1065. <a href="#webCmd">webCmd</a><br>
  1066. <a href="#widgetOverride">widgetOverride</a><br>
  1067. <br>
  1068. </ul>
  1069. <p><a name="RobonectCredentials"></a> <b>credentials</b></p>
  1070. <ul>
  1071. Hier kann ein Link auf ein credentials-file angegeben werden. Die Zugansinformationen werden dann aus der Datei geholt. Dieser Mechanismus &uuml;berschreibt basicAuth.
  1072. </ul>
  1073. <p><a name="RobonectBasicAuth"></a> <b>basicAuth</b></p>
  1074. <ul>
  1075. Hier werden die Zugangsinformationen entweder im Klartext oder base-64-codiert &uuml;bergeben. Base64-encoder gibts bei google.
  1076. <p>Example:</p>
  1077. <pre>
  1078. define myMower Robonect 192.168.5.1
  1079. attr myMower basicAuth me:mySecret
  1080. </pre>
  1081. <pre>
  1082. define myMower Robonect 192.168.5.1
  1083. attr myMower basicAuth bWU6bXlTZWNyZXQ=
  1084. </pre>
  1085. </ul>
  1086. <p><a name="RobonectPollInterval"></a> <b>pollInterval</b></p>
  1087. <ul>
  1088. Hier kann das polling-interval in Sekunden angegeben werden. Default sind 90s.
  1089. </ul>
  1090. <p><a name="RobonectTimeout"></a> <b>timeout</b></p>
  1091. <ul>
  1092. F&uuml;r das holen der Daten per Wlan kann hier ein Timeout angegeben werden. Default sind 4s.
  1093. </ul>
  1094. <p><a name="RobonectHealth"></a> <b>useHealth</b></p>
  1095. <ul>
  1096. Wenn dieses Attribut auf 1 gesetzt wird, wird der health-status analog dem normalen Status gepolled.<br>
  1097. Bitte beachtet, dass NICHT ALLE M&Auml;HER UNTERST&Uuml;TZT WERDEN!
  1098. Wenn die Funktion nicht gegeben zu sein scheint, bitte den LAST_COMM_STATUS und das Logfile beachten.
  1099. </ul>
  1100. </ul>
  1101. =end html_DE
  1102. =cut