86_Robonect.pm 41 KB

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