74_GardenaSmartDevice.pm 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. ###############################################################################
  2. #
  3. # Developed with Kate
  4. #
  5. # (c) 2017 Copyright: Marko Oldenburg (leongaultier at gmail dot com)
  6. # All rights reserved
  7. #
  8. # Special thanks goes to comitters:
  9. # - Michael (mbrak) Thanks for Commandref
  10. # - Matthias (Kenneth) Thanks for Wiki entry
  11. #
  12. #
  13. # This script is free software; you can redistribute it and/or modify
  14. # it under the terms of the GNU General Public License as published by
  15. # the Free Software Foundation; either version 2 of the License, or
  16. # any later version.
  17. #
  18. # The GNU General Public License can be found at
  19. # http://www.gnu.org/copyleft/gpl.html.
  20. # A copy is found in the textfile GPL.txt and important notices to the license
  21. # from the author is found in LICENSE.txt distributed with these scripts.
  22. #
  23. # This script is distributed in the hope that it will be useful,
  24. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  26. # GNU General Public License for more details.
  27. #
  28. #
  29. # $Id: 74_GardenaSmartDevice.pm 15024 2017-09-07 07:02:07Z CoolTux $
  30. #
  31. ###############################################################################
  32. ##
  33. ##
  34. ## Das JSON Modul immer in einem eval aufrufen
  35. # $data = eval{decode_json($data)};
  36. #
  37. # if($@){
  38. # Log3($SELF, 2, "$TYPE ($SELF) - error while request: $@");
  39. #
  40. # readingsSingleUpdate($hash, "state", "error", 1);
  41. #
  42. # return;
  43. # }
  44. #
  45. #
  46. ###### Wichtige Notizen
  47. #
  48. # apt-get install libio-socket-ssl-perl
  49. # http://www.dxsdata.com/de/2016/07/php-class-for-gardena-smart-system-api/
  50. #
  51. ##
  52. ##
  53. package main;
  54. my $missingModul = "";
  55. use strict;
  56. use warnings;
  57. use Time::Local;
  58. use Data::Dumper; #debugging
  59. # eval "use Encode qw(encode encode_utf8 decode_utf8);1" or $missingModul .= "Encode "; wird nicht benötigt
  60. eval "use JSON;1" or $missingModul .= "JSON ";
  61. my $version = "0.2.3";
  62. # Declare functions
  63. sub GardenaSmartDevice_Attr(@);
  64. sub GardenaSmartDevice_Define($$);
  65. sub GardenaSmartDevice_Initialize($);
  66. sub GardenaSmartDevice_Set($@);
  67. sub GardenaSmartDevice_Undef($$);
  68. sub GardenaSmartDevice_WriteReadings($$);
  69. sub GardenaSmartDevice_Parse($$);
  70. sub GardenaSmartDevice_ReadingLangGerman($$);
  71. sub GardenaSmartDevice_RigRadingsValue($$);
  72. sub GardenaSmartDevice_Zulu2LocalString($);
  73. sub GardenaSmartDevice_Initialize($) {
  74. my ($hash) = @_;
  75. $hash->{Match} = '^{"id":".*';
  76. $hash->{SetFn} = "GardenaSmartDevice_Set";
  77. $hash->{DefFn} = "GardenaSmartDevice_Define";
  78. $hash->{UndefFn} = "GardenaSmartDevice_Undef";
  79. $hash->{ParseFn} = "GardenaSmartDevice_Parse";
  80. $hash->{AttrFn} = "GardenaSmartDevice_Attr";
  81. $hash->{AttrList} = "readingValueLanguage:de,en ".
  82. "model ".
  83. $readingFnAttributes;
  84. foreach my $d(sort keys %{$modules{GardenaSmartDevice}{defptr}}) {
  85. my $hash = $modules{GardenaSmartDevice}{defptr}{$d};
  86. $hash->{VERSION} = $version;
  87. }
  88. }
  89. sub GardenaSmartDevice_Define($$) {
  90. my ( $hash, $def ) = @_;
  91. my @a = split( "[ \t]+", $def );
  92. splice( @a, 1, 1 );
  93. my $iodev;
  94. my $i = 0;
  95. foreach my $param ( @a ) {
  96. if( $param =~ m/IODev=([^\s]*)/ ) {
  97. $iodev = $1;
  98. splice( @a, $i, 3 );
  99. last;
  100. }
  101. $i++;
  102. }
  103. return "too few parameters: define <NAME> GardenaSmartDevice <device_Id> <model>" if( @a != 3 ) ;
  104. return "Cannot define Gardena Bridge device. Perl modul $missingModul is missing." if ( $missingModul );
  105. my ($name,$deviceId,$category) = @a;
  106. $hash->{DEVICEID} = $deviceId;
  107. $hash->{VERSION} = $version;
  108. AssignIoPort($hash,$iodev) if( !$hash->{IODev} );
  109. if(defined($hash->{IODev}->{NAME})) {
  110. Log3 $name, 3, "GardenaSmartDevice ($name) - I/O device is " . $hash->{IODev}->{NAME};
  111. } else {
  112. Log3 $name, 1, "GardenaSmartDevice ($name) - no I/O device";
  113. }
  114. $iodev = $hash->{IODev}->{NAME};
  115. my $d = $modules{GardenaSmartDevice}{defptr}{$deviceId};
  116. return "GardenaSmartDevice device $name on GardenaSmartBridge $iodev already defined."
  117. if( defined($d) && $d->{IODev} == $hash->{IODev} && $d->{NAME} ne $name );
  118. $attr{$name}{room} = "GardenaSmart" if( not defined( $attr{$name}{room} ) );
  119. $attr{$name}{model} = $category if( not defined( $attr{$name}{model} ) );
  120. Log3 $name, 3, "GardenaSmartDevice ($name) - defined GardenaSmartDevice with DEVICEID: $deviceId";
  121. readingsSingleUpdate($hash,'state','initialized',1);
  122. $modules{GardenaSmartDevice}{defptr}{$deviceId} = $hash;
  123. return undef;
  124. }
  125. sub GardenaSmartDevice_Undef($$) {
  126. my ( $hash, $arg ) = @_;
  127. my $name = $hash->{NAME};
  128. my $deviceId = $hash->{DEVICEID};
  129. delete $modules{GardenaSmartDevice}{defptr}{$deviceId};
  130. return undef;
  131. }
  132. sub GardenaSmartDevice_Attr(@) {
  133. my ( $cmd, $name, $attrName, $attrVal ) = @_;
  134. my $hash = $defs{$name};
  135. return undef;
  136. }
  137. sub GardenaSmartDevice_Set($@) {
  138. my ($hash, $name, $cmd, @args) = @_;
  139. my ($arg, @params) = @args;
  140. my $payload;
  141. my $abilities;
  142. ### mower
  143. if( lc $cmd eq 'parkuntilfurthernotice' ) {
  144. $payload = '"name":"park_until_further_notice"';
  145. } elsif( lc $cmd eq 'parkuntilnexttimer' ) {
  146. $payload = '"name":"park_until_next_timer"';
  147. } elsif( lc $cmd eq 'startresumeschedule' ) {
  148. $payload = '"name":"start_resume_schedule"';
  149. } elsif( lc $cmd eq 'startoverridetimer' ) {
  150. my $duration = join( " ", @args );
  151. $payload = '"name":"start_override_timer","parameters":{"duration":' . $duration . '}';
  152. ### watering_computer
  153. } elsif( lc $cmd eq 'manualoverride' ) {
  154. my $duration = join( " ", @args );
  155. $payload = '"name":"manual_override","parameters":{"duration":' . $duration . '}';
  156. } elsif( lc $cmd eq 'canceloverride' ) {
  157. $payload = '"name":"cancel_override"';
  158. ### Sensors
  159. } elsif( lc $cmd eq 'refresh' ) {
  160. my $sensname = join( " ", @args );
  161. if( lc $sensname eq 'temperature' ) {
  162. $payload = '"name":"measure_ambient_temperature"';
  163. $abilities = 'ambient_temperature';
  164. } elsif( lc $sensname eq 'light' ) {
  165. $payload = '"name":"measure_light"';
  166. $abilities = 'light';
  167. } elsif( lc $sensname eq 'humidity' ) {
  168. $payload = '"name":"measure_humidity"';
  169. $abilities = 'humidity';
  170. }
  171. } elsif( lc $cmd eq '' ) {
  172. } elsif( lc $cmd eq '' ) {
  173. } elsif( lc $cmd eq '' ) {
  174. } elsif( lc $cmd eq '' ) {
  175. } elsif( lc $cmd eq '' ) {
  176. } elsif( lc $cmd eq '' ) {
  177. } else {
  178. my $list = '';
  179. $list .= 'parkUntilFurtherNotice:noArg parkUntilNextTimer:noArg startResumeSchedule:noArg startOverrideTimer:slider,0,60,1440' if( AttrVal($name,'model','unknown') eq 'mower' );
  180. $list .= 'manualOverride:slider,0,1,59 cancelOverride:noArg' if( AttrVal($name,'model','unknown') eq 'watering_computer' );
  181. $list .= 'refresh:temperature,light' if( AttrVal($name,'model','unknown') eq 'sensor' );
  182. return "Unknown argument $cmd, choose one of $list";
  183. }
  184. $abilities = 'mower' if( AttrVal($name,'model','unknown') eq 'mower' );
  185. $abilities = 'outlet' if( AttrVal($name,'model','unknown') eq 'watering_computer' );
  186. $hash->{helper}{deviceAction} = $payload;
  187. readingsSingleUpdate( $hash, "state", "send command to gardena cloud", 1);
  188. IOWrite($hash,$payload,$hash->{DEVICEID},$abilities);
  189. Log3 $name, 4, "GardenaSmartBridge ($name) - IOWrite: $payload $hash->{DEVICEID} $abilities IODevHash=$hash->{IODev}";
  190. return undef;
  191. }
  192. sub GardenaSmartDevice_Parse($$) {
  193. my ($io_hash,$json) = @_;
  194. my $name = $io_hash->{NAME};
  195. my $decode_json = eval{decode_json($json)};
  196. if($@){
  197. Log3 $name, 3, "GardenaSmartBridge ($name) - JSON error while request: $@";
  198. }
  199. Log3 $name, 4, "GardenaSmartDevice ($name) - ParseFn was called";
  200. Log3 $name, 5, "GardenaSmartDevice ($name) - JSON: $json";
  201. if( defined($decode_json->{id}) ) {
  202. my $deviceId = $decode_json->{id};
  203. if( my $hash = $modules{GardenaSmartDevice}{defptr}{$deviceId} ) {
  204. my $name = $hash->{NAME};
  205. GardenaSmartDevice_WriteReadings($hash,$decode_json);
  206. Log3 $name, 4, "GardenaSmartDevice ($name) - find logical device: $hash->{NAME}";
  207. return $hash->{NAME};
  208. } else {
  209. Log3 $name, 3, "GardenaSmartDevice ($name) - autocreate new device " . makeDeviceName($decode_json->{name}) . " with deviceId $decode_json->{id}, model $decode_json->{category} and IODev IODev=$name";
  210. #return "UNDEFINED " . join('',split("[ \t]+",$decode_json->{name})) . " GardenaSmartDevice $decode_json->{id} $decode_json->{category} IODev=$name";
  211. return "UNDEFINED " . makeDeviceName($decode_json->{name}) . " GardenaSmartDevice $decode_json->{id} $decode_json->{category} IODev=$name";
  212. }
  213. }
  214. }
  215. sub GardenaSmartDevice_WriteReadings($$) {
  216. my ($hash,$decode_json) = @_;
  217. my $name = $hash->{NAME};
  218. my $abilities = scalar (@{$decode_json->{abilities}});
  219. readingsBeginUpdate($hash);
  220. do {
  221. if( ref($decode_json->{abilities}[$abilities]{properties}) eq "ARRAY" and scalar(@{$decode_json->{abilities}[$abilities]{properties}}) > 0 ) {;
  222. foreach my $propertie (@{$decode_json->{abilities}[$abilities]{properties}}) {
  223. readingsBulkUpdateIfChanged($hash,$decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name},GardenaSmartDevice_RigRadingsValue($hash,$propertie->{value})) if( defined($propertie->{value})
  224. and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'radio-quality'
  225. and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'battery-level'
  226. and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'internal_temperature-temperature'
  227. and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'ambient_temperature-temperature'
  228. and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'soil_temperature-temperature'
  229. and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'humidity-humidity'
  230. and $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} ne 'light-light' );
  231. readingsBulkUpdate($hash,$decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name},GardenaSmartDevice_RigRadingsValue($hash,$propertie->{value})) if( defined($propertie->{value})
  232. and ($decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'radio-quality'
  233. or $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'battery-level'
  234. or $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'internal_temperature-temperature'
  235. or $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'ambient_temperature-temperature'
  236. or $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'soil_temperature-temperature'
  237. or $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'humidity-humidity'
  238. or $decode_json->{abilities}[$abilities]{name}.'-'.$propertie->{name} eq 'light-light') );
  239. }
  240. }
  241. $abilities--;
  242. } while ($abilities >= 0);
  243. readingsBulkUpdate($hash,'state',ReadingsVal($name,'mower-status','readingsValError')) if( AttrVal($name,'model','unknown') eq 'mower' );
  244. readingsBulkUpdate($hash,'state',(ReadingsVal($name,'outlet-valve_open','readingsValError') == 1 ? GardenaSmartDevice_RigRadingsValue($hash,'open') : GardenaSmartDevice_RigRadingsValue($hash,'closed'))) if( AttrVal($name,'model','unknown') eq 'watering_computer' );
  245. readingsBulkUpdate($hash,'state','T: ' . ReadingsVal($name,'ambient_temperature-temperature','readingsValError') . '°C, H: ' . ReadingsVal($name,'humidity-humidity','readingsValError') . '%, L: ' . ReadingsVal($name,'light-light','readingsValError') . 'lux') if( AttrVal($name,'model','unknown') eq 'sensor' );
  246. readingsEndUpdate( $hash, 1 );
  247. Log3 $name, 4, "GardenaSmartDevice ($name) - readings was written}";
  248. }
  249. ##################################
  250. ##################################
  251. #### my little helpers ###########
  252. sub GardenaSmartDevice_ReadingLangGerman($$) {
  253. my ($hash,$readingValue) = @_;
  254. my $name = $hash->{NAME};
  255. my %langGermanMapp = (
  256. 'ok_cutting' => 'mähen',
  257. 'paused' => 'pausiert',
  258. 'ok_searching' => 'suche Ladestation',
  259. 'ok_charging' => 'lädt',
  260. 'ok_leaving' => 'mähen',
  261. 'wait_updating' => 'wird aktualisiert ...',
  262. 'wait_power_up' => 'wird eingeschaltet ...',
  263. 'parked_timer' => 'geparkt nach Zeitplan',
  264. 'parked_park_selected' => 'geparkt',
  265. 'off_disabled' => 'der Mäher ist ausgeschaltet',
  266. 'off_hatch_open' => 'deaktiviert. Abdeckung ist offen oder PIN-Code erforderlich',
  267. 'unknown' => 'unbekannter Status',
  268. 'error' => 'Fehler',
  269. 'error_at_power_up' => 'Neustart ...',
  270. 'off_hatch_closed' => 'Deaktiviert. Manueller Start erforderlich',
  271. 'ok_cutting_timer_overridden' => 'manuelles mähen',
  272. 'parked_autotimer' => 'geparkt durch SensorControl',
  273. 'parked_daily_limit_reached' => 'abgeschlossen',
  274. 'no_message' => 'kein Fehler',
  275. 'outside_working_area' => 'außerhalb des Arbeitsbereichs',
  276. 'no_loop_signal' => 'kein Schleifensignal',
  277. 'wrong_loop_signal' => 'falsches Schleifensignal',
  278. 'loop_sensor_problem_front' => 'Problem Schleifensensor, vorne',
  279. 'loop_sensor_problem_rear' => 'Problem Schleifensensor, hinten',
  280. 'trapped' => 'eingeschlossen',
  281. 'upside_down' => 'steht auf dem Kopf',
  282. 'low_battery' => 'niedriger Batteriestand',
  283. 'empty_battery' => 'Batterie leer',
  284. 'no_drive' => 'fährt nicht',
  285. 'lifted' => 'angehoben',
  286. 'stuck_in_charging_station' => 'eingeklemmt in Ladestation',
  287. 'charging_station_blocked' => 'Ladestation blockiert',
  288. 'collision_sensor_problem_rear' => 'Problem Stoßsensor hinten',
  289. 'collision_sensor_problem_front' => 'Problem Stoßsensor vorne',
  290. 'wheel_motor_blocked_right' => 'Radmotor rechts blockiert',
  291. 'wheel_motor_blocked_left' => 'Radmotor links blockiert',
  292. 'wheel_drive_problem_right' => 'Problem Antrieb, rechts',
  293. 'wheel_drive_problem_left' => 'Problem Antrieb, links',
  294. 'cutting_system_blocked' => 'Schneidsystem blockiert',
  295. 'invalid_sub_device_combination' => 'fehlerhafte Verbindung',
  296. 'settings_restored' => 'Standardeinstellungen',
  297. 'electronic_problem' => 'elektronisches Problem',
  298. 'charging_system_problem' => 'Problem Ladesystem',
  299. 'tilt_sensor_problem' => 'Kippsensor Problem',
  300. 'wheel_motor_overloaded_right' => 'rechter Radmotor überlastet',
  301. 'wheel_motor_overloaded_left' => 'linker Radmotor überlastet',
  302. 'charging_current_too_high' => 'Ladestrom zu hoch',
  303. 'temporary_problem' => 'vorübergehendes Problem',
  304. 'guide_1_not_found' => 'SK 1 nicht gefunden',
  305. 'guide_2_not_found' => 'SK 2 nicht gefunden',
  306. 'guide_3_not_found' => 'SK 3 nicht gefunden',
  307. 'difficult_finding_home' => 'Problem die Ladestation zu finden',
  308. 'guide_calibration_accomplished' => 'Kalibrierung des Suchkabels beendet',
  309. 'guide_calibration_failed' => 'Kalibrierung des Suchkabels fehlgeschlagen',
  310. 'temporary_battery_problem' => 'kurzzeitiges Batterieproblem',
  311. 'battery_problem' => 'Batterieproblem',
  312. 'alarm_mower_switched_off' => 'Alarm! Mäher ausgeschalten',
  313. 'alarm_mower_stopped' => 'Alarm! Mäher gestoppt',
  314. 'alarm_mower_lifted' => 'Alarm! Mäher angehoben',
  315. 'alarm_mower_tilted' => 'Alarm! Mäher gekippt',
  316. 'connection_changed' => 'Verbindung geändert',
  317. 'connection_not_changed' => 'Verbindung nicht geändert',
  318. 'com_board_not_available' => 'COM Board nicht verfügbar',
  319. 'slipped' => 'rutscht',
  320. 'out_of_operation' => 'ausser Betrieb',
  321. 'replace_now' => 'kritischer Batteriestand, wechseln Sie jetzt',
  322. 'low' => 'niedrig',
  323. 'ok' => 'oK',
  324. 'no_source' => 'oK',
  325. 'mower_charging' => 'Mäher wurde geladen',
  326. 'completed_cutting_autotimer' => 'Sensor Control erreicht',
  327. 'week_timer' => 'Wochentimer erreicht',
  328. 'countdown_timer' => 'Stoppuhr Timer',
  329. 'undefined' => 'unklar',
  330. 'unknown' => 'unklar',
  331. 'status_device_unreachable' => 'Gerät ist nicht in Reichweite',
  332. 'status_device_alive' => 'Gerät ist in Reichweite',
  333. 'bad' => 'schlecht',
  334. 'poor' => 'schwach',
  335. 'good' => 'gut',
  336. 'undefined' => 'unklar',
  337. 'idle' => 'nichts zu tun',
  338. 'firmware_cancel' => 'Firmwareupload unterbrochen',
  339. 'firmware_upload' => 'Firmwareupload',
  340. 'unsupported' => 'nicht unterstützt',
  341. 'up_to_date' => 'auf dem neusten Stand',
  342. 'mower' => 'Mäher',
  343. 'watering_computer' => 'Bewässerungscomputer',
  344. 'no_frost' => 'kein Frost',
  345. 'open' => 'offen',
  346. 'closed' => 'geschlossen',
  347. 'included' => 'inbegriffen',
  348. 'active' => 'aktiv',
  349. 'inactive' => 'nicht aktiv'
  350. );
  351. if( defined($langGermanMapp{$readingValue}) and (AttrVal('global','language','none') eq 'DE' or AttrVal($name,'readingValueLanguage','none') eq 'de') and AttrVal($name,'readingValueLanguage','none') ne 'en') {
  352. return $langGermanMapp{$readingValue};
  353. } else {
  354. return $readingValue;
  355. }
  356. }
  357. sub GardenaSmartDevice_RigRadingsValue($$) {
  358. my ($hash,$readingValue) = @_;
  359. my $rigReadingValue;
  360. if( $readingValue =~ /^(\d+)-(\d\d)-(\d\d)T(\d\d)/ ) {
  361. $rigReadingValue = GardenaSmartDevice_Zulu2LocalString($readingValue);
  362. } else {
  363. $rigReadingValue = GardenaSmartDevice_ReadingLangGerman($hash,$readingValue);
  364. }
  365. return $rigReadingValue;
  366. }
  367. sub GardenaSmartDevice_Zulu2LocalString($) {
  368. my $t = shift;
  369. my ($datehour,$datemin,$rest) = split(/:/,$t,3);
  370. my ($year, $month, $day, $hour,$min) = $datehour =~ /(\d+)-(\d\d)-(\d\d)T(\d\d)/;
  371. my $epoch = timegm (0,0,$hour,$day,$month-1,$year);
  372. my ($lyear,$lmonth,$lday,$lhour,$isdst) = (localtime($epoch))[5,4,3,2,-1];
  373. $lyear += 1900; # year is 1900 based
  374. $lmonth++; # month number is zero based
  375. if( defined($rest) ) {
  376. return ( sprintf("%04d-%02d-%02d %02d:%02d:%s",$lyear,$lmonth,$lday,$lhour,$datemin,substr($rest,0,2)));
  377. } elsif( $lyear < 2000 ) {
  378. return "illegal year";
  379. } else {
  380. return ( sprintf("%04d-%02d-%02d %02d:%02d",$lyear,$lmonth,$lday,$lhour,substr($datemin,0,2)));
  381. }
  382. }
  383. 1;
  384. =pod
  385. =item device
  386. =item summary Modul to control GardenaSmart Devices
  387. =item summary_DE Modul zur Steuerung von GardenaSmartger&aumlten
  388. =begin html
  389. <a name="GardenaSmartDevice"></a>
  390. <h3>GardenaSmartDevice</h3>
  391. <ul>
  392. In combination with GardenaSmartBridge this FHEM Module controls the GardenaSmart Device using the GardenaCloud
  393. <br><br>
  394. Once the Bridge device is created, the connected devices are automatically recognized and created in FHEM. <br>
  395. From now on the devices can be controlled and changes in the GardenaAPP are synchronized with the state and readings of the devices.
  396. <a name="GardenaSmartDevicereadings"></a>
  397. <br><br><br>
  398. <b>Readings</b>
  399. <ul>
  400. <li>battery-charging - Indicator if the Battery is charged (0/1) or with newer Firmware (false/true)</li>
  401. <li>battery-level - load percentage of the Battery</li>
  402. <li>battery-rechargeable_battery_status - healthyness of the battery (out_of_operation/replace_now/low/ok)</li>
  403. <li>device_info-category - category of device (mower/watering_computer)</li>
  404. <li>device_info-last_time_online - timestamp of last radio contact</li>
  405. <li>device_info-manufacturer - manufacturer</li>
  406. <li>device_info-product - product type</li>
  407. <li>device_info-serial_number - serial number</li>
  408. <li>device_info-sgtin - </li>
  409. <li>device_info-version - firmware version</li>
  410. <li>firmware-firmware_command - firmware command (idle/firmware_cancel/firmware_upload/unsupported)</li>
  411. <li>firmware-firmware_status - firmware status </li>
  412. <li>firmware-firmware_update_start - indicator when a firmwareupload is started</li>
  413. <li>firmware-firmware_upload_progress - progress indicator of firmware update</li>
  414. <li>firmware-inclusion_status - inclusion status</li>
  415. <li>internal_temperature-temperature - internal device temperature</li>
  416. <li>mower-error - actual error message
  417. <ul>
  418. <li>no_message</li>
  419. <li>outside_working_area</li>
  420. <li>no_loop_signal</li>
  421. <li>wrong_loop_signal</li>
  422. <li>loop_sensor_problem_front</li>
  423. <li>loop_sensor_problem_rear</li>
  424. <li>trapped</li>
  425. <li>upside_down</li>
  426. <li>low_battery</li>
  427. <li>empty_battery</li>
  428. <li>no_drive</li>
  429. <li>lifted</li>
  430. <li>stuck_in_charging_station</li>
  431. <li>charging_station_blocked</li>
  432. <li>collision_sensor_problem_rear</li>
  433. <li>collision_sensor_problem_front</li>
  434. <li>wheel_motor_blocked_right</li>
  435. <li>wheel_motor_blocked_left</li>
  436. <li>wheel_drive_problem_right</li>
  437. <li>wheel_drive_problem_left</li>
  438. <li>cutting_system_blocked</li>
  439. <li>invalid_sub_device_combination</li>
  440. <li>settings_restored</li>
  441. <li>electronic_problem</li>
  442. <li>charging_system_problem</li>
  443. <li>tilt_sensor_problem</li>
  444. <li>wheel_motor_overloaded_right</li>
  445. <li>wheel_motor_overloaded_left</li>
  446. <li>charging_current_too_high</li>
  447. <li>temporary_problem</li>
  448. <li>guide_1_not_found</li>
  449. <li>guide_2_not_found</li>
  450. <li>guide_3_not_found</li>
  451. <li>difficult_finding_home</li>
  452. <li>guide_calibration_accomplished</li>
  453. <li>guide_calibration_failed</li>
  454. <li>temporary_battery_problem</li>
  455. <li>battery_problem</li>
  456. <li>alarm_mower_switched_off</li>
  457. <li>alarm_mower_stopped</li>
  458. <li>alarm_mower_lifted</li>
  459. <li>alarm_mower_tilted</li>
  460. <li>connection_changed</li>
  461. <li>connection_not_changed</li>
  462. <li>com_board_not_available</li>
  463. <li>slipped</li>
  464. </ul>
  465. </li>
  466. <li>mower-manual_operation - (0/1) or with newer Firmware (false/true)</li>
  467. <li>mower-override_end_time - manual override end time</li>
  468. <li>mower-source_for_next_start - source for the next start
  469. <ul>
  470. <li>no_source</li>
  471. <li>mower_charging</li>
  472. <li>completed_cutting_autotimer</li>
  473. <li>week_timer</li>
  474. <li>countdown_timer</li>
  475. <li>undefined</li>
  476. </ul>
  477. </li>
  478. <li>mower-status - mower state (see state)</li>
  479. <li>mower-timestamp_next_start - timestamp of next scheduled start</li>
  480. <li>radio-connection_status - state of connection</li>
  481. <li>radio-quality - percentage of the radio quality</li>
  482. <li>radio-state - radio state (bad/poor/good/undefined)</li>
  483. <li>state - state of the mower
  484. <ul>
  485. <li>paused</li>
  486. <li>ok_cutting</li>
  487. <li>ok_searching</li>
  488. <li>ok_charging</li>
  489. <li>ok_leaving</li>
  490. <li>wait_updating</li>
  491. <li>wait_power_up</li>
  492. <li>parked_timer</li>
  493. <li>parked_park_selected</li>
  494. <li>off_disabled</li>
  495. <li>off_hatch_open</li>
  496. <li>unknown</li>
  497. <li>error</li>
  498. <li>error_at_power_up</li>
  499. <li>off_hatch_closed</li>
  500. <li>ok_cutting_timer_overridden</li>
  501. <li>parked_autotimer</li>
  502. <li>parked_daily_limit_reached</li>
  503. </ul>
  504. </li>
  505. </ul>
  506. <br><br>
  507. <a name="GardenaSmartDeviceattributes"></a>
  508. <b>Attributes</b>
  509. <ul>
  510. <li>readingValueLanguage - Change the Language of Readings (de,en/if not set the default is english and the global language is not set at german) </li>
  511. <li>model - </li>
  512. </ul>
  513. <br><br>
  514. <a name="GardenaSmartDeviceset"></a>
  515. <b>set</b>
  516. <ul>
  517. <li>parkUntilFurtherNotice</li>
  518. <li>parkUntilNextTimer</li>
  519. <li>startOverrideTimer - 0 to 59 Minutes</li>
  520. <li>startResumeSchedule</li>
  521. </ul>
  522. </ul>
  523. =end html
  524. =begin html_DE
  525. <a name="GardenaSmartDevice"></a>
  526. <h3>GardenaSmartDevice</h3>
  527. <ul>
  528. Zusammen mit dem Device GardenaSmartDevice stellt dieses FHEM Modul die Kommunikation zwischen der GardenaCloud und Fhem her.
  529. <br><br>
  530. Wenn das GardenaSmartBridge Device erzeugt wurde, werden verbundene Ger&auml;te automatisch erkannt und in Fhem angelegt.<br>
  531. Von nun an k&ouml;nnen die eingebundenen Ger&auml;te gesteuert werden. &Auml;nderungen in der APP werden mit den Readings und dem Status syncronisiert.
  532. <a name="GardenaSmartDevicereadings"></a>
  533. </ul>
  534. <br>
  535. <ul>
  536. <b>Readings</b>
  537. <ul>
  538. <li>battery-charging - Ladeindikator (0/1) oder mit neuerer Firmware (false/true)</li>
  539. <li>battery-level - Ladezustand der Batterie in Prozent</li>
  540. <li>battery-rechargeable_battery_status - Zustand der Batterie (Ausser Betrieb/Kritischer Batteriestand, wechseln Sie jetzt/Niedrig/oK)</li>
  541. <li>device_info-category - Eigenschaft des Ger&auml;tes (M&auml;her/Bew&auml;sserungscomputer/Bodensensor)</li>
  542. <li>device_info-last_time_online - Zeitpunkt der letzten Funk&uuml;bertragung</li>
  543. <li>device_info-manufacturer - Hersteller</li>
  544. <li>device_info-product - Produkttyp</li>
  545. <li>device_info-serial_number - Seriennummer</li>
  546. <li>device_info-sgtin - </li>
  547. <li>device_info-version - Firmware Version</li>
  548. <li>firmware-firmware_command - Firmware Kommando (Nichts zu tun/Firmwareupload unterbrochen/Firmwareupload/nicht unterst&uuml;tzt)</li>
  549. <li>firmware-firmware_status - Firmware Status </li>
  550. <li>firmware-firmware_update_start - Firmwareupdate (0/1) oder mit neuerer Firmware (false/true)</li>
  551. <li>firmware-firmware_upload_progress - Firmwareupdatestatus in Prozent</li>
  552. <li>firmware-inclusion_status - Einbindungsstatus</li>
  553. <li>internal_temperature-temperature - Interne Ger&auml;te Temperatur</li>
  554. <li>mower-error - Aktuelle Fehler Meldung
  555. <ul>
  556. <li>Kein Fehler</li>
  557. <li>Au&szlig;erhalb des Arbeitsbereichs</li>
  558. <li>Kein Schleifensignal</li>
  559. <li>Falsches Schleifensignal</li>
  560. <li>Problem Schleifensensor, vorne</li>
  561. <li>Problem Schleifensensor, hinten</li>
  562. <li>Eingeschlossen</li>
  563. <li>Steht auf dem Kopf</li>
  564. <li>Niedriger Batteriestand</li>
  565. <li>Batterie ist leer</li>
  566. <li>Kein Antrieb</li>
  567. <li>Angehoben</li>
  568. <li>Eingeklemmt in Ladestation</li>
  569. <li>Ladestation blockiert</li>
  570. <li>Problem Sto&szlig;sensor hinten</li>
  571. <li>Problem Sto&szlig;sensor vorne</li>
  572. <li>Radmotor rechts blockiert</li>
  573. <li>Radmotor links blockiert</li>
  574. <li>Problem Antrieb, rechts</li>
  575. <li>Problem Antrieb, links</li>
  576. <li>Schneidsystem blockiert</li>
  577. <li>Fehlerhafte Verbindung</li>
  578. <li>Standardeinstellungen</li>
  579. <li>Elektronisches Problem</li>
  580. <li>Problem Ladesystem</li>
  581. <li>Kippsensorproblem</li>
  582. <li>Rechter Radmotor &uuml;berlastet</li>
  583. <li>Linker Radmotor &uuml;berlastet</li>
  584. <li>Ladestrom zu hoch</li>
  585. <li>Vor&uuml;bergehendes Problem</li>
  586. <li>SK 1 nicht gefunden</li>
  587. <li>SK 2 nicht gefunden</li>
  588. <li>SK 3 nicht gefunden</li>
  589. <li>Problem die Ladestation zu finden</li>
  590. <li>Kalibration des Suchkabels beendet</li>
  591. <li>Kalibration des Suchkabels fehlgeschlagen</li>
  592. <li>Kurzzeitiges Batterieproblem</li>
  593. <li>Batterieproblem</li>
  594. <li>Alarm! M&auml;her ausgeschalten</li>
  595. <li>Alarm! M&auml;her gestoppt</li>
  596. <li>Alarm! M&auml;her angehoben</li>
  597. <li>Alarm! M&auml;her gekippt</li>
  598. <li>Verbindung geändert</li>
  599. <li>Verbindung nicht ge&auml;ndert</li>
  600. <li>COM board nicht verf&uuml;gbar</li>
  601. <li>Rutscht</li>
  602. </ul>
  603. </li>
  604. <li>mower-manual_operation - Manueller Betrieb (0/1) oder mit neuerer Firmware (false/true)</li>
  605. <li>mower-override_end_time - Zeitpunkt wann der manuelle Betrieb beendet ist</li>
  606. <li>mower-source_for_next_start - Grund f&uuml;r den n&auml;chsten Start
  607. <ul>
  608. <li>Kein Grund</li>
  609. <li>M&auml;her wurde geladen</li>
  610. <li>SensorControl erreicht</li>
  611. <li>Wochentimer erreicht</li>
  612. <li>Stoppuhr Timer</li>
  613. <li>Undefiniert</li>
  614. </ul>
  615. </li>
  616. <li>mower-status - M&auml;her Status (siehe state)</li>
  617. <li>mower-timestamp_next_start - Zeitpunkt des n&auml;chsten geplanten Starts</li>
  618. <li>radio-connection_status - Status der Funkverbindung</li>
  619. <li>radio-quality - Indikator f&uuml;r die Funkverbindung in Prozent</li>
  620. <li>radio-state - radio state (schlecht/schwach/gut/Undefiniert)</li>
  621. <li>state - Staus des M&auml;hers
  622. <ul>
  623. <li>Pausiert</li>
  624. <li>M&auml;hen</li>
  625. <li>Suche Ladestation</li>
  626. <li>L&auml;dt</li>
  627. <li>M&auml;hen</li>
  628. <li>Wird aktualisiert ...</li>
  629. <li>Wird eingeschaltet ...</li>
  630. <li>Geparkt nach Zeitplan</li>
  631. <li>Geparkt</li>
  632. <li>Der M&auml;her ist ausgeschaltet</li>
  633. <li>Deaktiviert. Abdeckung ist offen oder PIN-Code erforderlich</li>
  634. <li>Unbekannter Status</li>
  635. <li>Fehler</li>
  636. <li>Neustart ...</li>
  637. <li>Deaktiviert. Manueller Start erforderlich</li>
  638. <li>Manuelles M&auml;hen</li>
  639. <li>Geparkt durch SensorControl</li>
  640. <li>Abgeschlossen</li>
  641. </ul>
  642. </li>
  643. </ul>
  644. <br><br>
  645. <a name="GardenaSmartDeviceattributes"></a>
  646. <b>Attribute</b>
  647. <ul>
  648. <li>readingValueLanguage - &Auml;nderung der Sprache der Readings (de,en/wenn nichts gesetzt ist, dann Englisch es sei denn deutsch ist als globale Sprache gesetzt) </li>
  649. <li>model - </li>
  650. </ul>
  651. <a name="GardenaSmartDeviceset"></a>
  652. <b>set</b>
  653. <ul>
  654. <li>parkUntilFurtherNotice - Parken des M&auml;hers unter Umgehung des Zeitplans</li>
  655. <li>parkUntilNextTimer - Parken bis zum n&auml;chsten Zeitplan</li>
  656. <li>startOverrideTimer - Manuelles m&auml;hen (0 bis 59 Minuten)</li>
  657. <li>startResumeSchedule - Weiterf&uuml;hrung des Zeitplans</li>
  658. </ul>
  659. </ul>
  660. =end html_DE
  661. =cut