. */ /* * ***************************Includes**********************************/ require_once dirname(__FILE__) . '/../../../../core/php/core.inc.php'; require_once dirname(__FILE__) . '/../../3rdparty/NeatoBotvacClient.php'; require_once dirname(__FILE__) . '/../../3rdparty/NeatoBotvacRobot.php'; class neato extends eqLogic { /***************************Attributs*******************************/ public static $_widgetPossibility = array('custom' => true, 'custom::layout' => false); public static $_encryptConfigKey = array('password'); /* * ***********************Methode static*************************** */ public static function templateWidget(){ $return = array('info' => array('string' => array())); $return['info']['string']['state'] = array( 'template' => 'tmplmultistate', 'test' => array( array('operation' => '#value# == 2','state_light' => ''), array('operation' => '#value# == 3','state_light' => ''), array('operation' => '#value# > 3 || #value# < 2','state_light' => '') ) ); return $return; } public static function cron15($_eqlogic_id = null,$_data = null) { if ($_eqlogic_id !== null) { $eqLogics = array(eqLogic::byId($_eqlogic_id)); } else { $eqLogics = eqLogic::byType('neato'); } foreach ($eqLogics as $neato) { log::add('neato', 'debug', 'cron15: Neato object : '.$neato->getName()); $changed = false; if ($neato->getIsEnable() != 1) { continue; } $serial = $neato->getLogicalId(); $secret = $neato->getConfiguration('secret'); if($_data != null && is_array($_data)){ $result = $_data; }else{ $robot = new NeatoBotvacRobot($serial, $secret, $neato->getConfiguration('model'), $neato->getConfiguration('robotid')); $result = $robot->getState(); } log::add('neato', 'debug', json_encode($result)); if (!isset($result['details'])) { continue; } $batterylevel = $result['details']['charge']; if ($batterylevel < 0) { $batterylevel = 0; } else if ($batterylevel > 97) { $batterylevel = 100; } if ($batterylevel != $neato->getStatus('battery')) { $neato->batteryStatus($batterylevel); $changed = true; } $oldapi = false; if (oldapi===true) { $firmware = $result['meta']['firmware']; if ($neato->getConfiguration('firmware', '') != $firmware) { $neato->setConfiguration('firmware', $firmware); $neato->save(); } $modelCleaning = $result['availableServices']['houseCleaning']; if ($neato->getConfiguration('modelCleaning', '') != $modelCleaning) { $neato->setConfiguration('modelCleaning', $modelCleaning); $neato->save(); } $maps = $result['availableServices']['maps']; if ($neato->getConfiguration('maps', '') != $maps) { $neato->setConfiguration('maps', $maps); $neato->save(); } $changed = $neato->checkAndUpdateCmd('docked', $result['details']['isDocked']) || $changed; $changed = $neato->checkAndUpdateCmd('charging', $result['details']['isCharging']) || $changed; $changed = $neato->checkAndUpdateCmd('scheduled', $result['details']['isScheduleEnabled']) || $changed; $changed = $neato->checkAndUpdateCmd('etattech', $result['state']) || $changed; } else { $changed = $neato->checkAndUpdateCmd('docked', $result['details']['is_docked']) || $changed; $changed = $neato->checkAndUpdateCmd('charging', $result['details']['is_charging']) || $changed; $changed = $neato->checkAndUpdateCmd('etattech', $result['state']) || $changed; } $state = $result['state']; switch ($state) { case "idle": case 1: $state = __('Prêt à nettoyer', __FILE__); break; case "busy": case 2: $state = __('En cours de nettoyage', __FILE__); break; case "paused": case 3: $state = __('En pause', __FILE__); break; } $changed = $neato->checkAndUpdateCmd('etat', $state) || $changed; $alert = $result['error']; switch ($alert) { case 'ui_alert_recovering_location': $alert = __('Recherche position', __FILE__); break; case 'ui_error_dust_bin_emptied': $alert = __('Bac à poussières vidé', __FILE__); break; case 'ui_alert_dust_bin_full': $alert = __('Bac à poussières plein', __FILE__); break; case 'ui_error_dust_bin_full': $alert = __('Bac à poussières plein', __FILE__); break; case 'ui_error_navigation_origin_unclean': $alert = __('Bloqué', __FILE__); break; case 'ui_error_navigation_noprogress': $alert = __('Bloqué', __FILE__); break; case 'ui_alert_charging_power': $alert = __('Besoin de me charger', __FILE__); break; case 'ui_alert_invalid': $alert = __('Aucune alerte', __FILE__); break; case '': $alert = __('Aucune alerte', __FILE__); break; case 'ui_alert_return_to_base': $alert = __('Retour à la base', __FILE__); break; case 'ui_alert_return_to_start': $alert = __('Retour au départ', __FILE__); break; case 'ui_error_bumper_stuck': $alert = __('Pare-chocs bloqué', __FILE__); break; case 'ui_error_brush_stuck': $alert = __('Brosse bloquée', __FILE__); break; case 'ui_error_brush_overload': $alert = __('Brosse bloquée', __FILE__); break; case 'ui_error_picked_up': $alert = __('Reposez moi au sol', __FILE__); break; case 'ui_alert_return_to_charge': $alert = __('Besoin de me charger', __FILE__); break; case 'ui_alert_busy_charging': $alert = __('Besoin de me charger', __FILE__); break; case 'ui_error_deck_debris': $alert = __('Laser Obstrué', __FILE__); break; case 'ui_error_navigation_undockingfailed': $alert = __('Bloqué', __FILE__); break; case 'ui_error_navigation_falling': $alert = __('Bloqué', __FILE__); break; case 'ui_error_navigation_nomotioncommands': $alert = __('Bloqué', __FILE__); break; case 'ui_error_navigation_pathproblems_returninghome': $alert = __('Bloqué', __FILE__); break; case 'ui_error_navigation_rightdrop_leftbump': $alert = __('Bloqué', __FILE__); case 'ui_error_navigation_backdrop_leftbump': $alert = __('Bloqué', __FILE__); break; } $changed = $neato->checkAndUpdateCmd('alert', $alert) || $changed; if ($changed == true) { $neato->refreshWidget(); } } } public static function getRobot() { try { $email = config::byKey('email', 'neato', 0); $password = config::byKey('password', 'neato', 0); $client = new NeatoBotvacClient(false); $auth = $client->authorize($email, $password, true); if ($auth === false) { log::add('neato', 'debug', 'Unable to authorize for neato client'); $client = new NeatoBotvacClient(false, "vorwerk"); $auth = $client->authorize($email, $password, true); } if ($auth === false) { log::add('neato', 'debug', 'Unable to authorize for vorwerk client'); $client = new NeatoBotvacClient(false, "orbital"); $auth = $client->authorize($email, $password, true); } if ($auth !== false) { log::add('neato', 'debug', 'Token: ' . $auth); $result = $client->getRobots(); if ($result !== false) { if (isset($result["robots"])) { $robots = $result["robots"]; } else { $robots = $result; } foreach ($robots as $robot) { log::add('neato', 'debug', json_encode($robot)); $eqLogic = eqLogic::byLogicalId($robot['serial'], 'neato'); if (!is_object($eqLogic)) { $eqLogic = new self(); $eqLogic->setLogicalId($robot['serial']); $eqLogic->setCategory('automatism', 1); $eqLogic->setName('Neato ' . $robot['name']); $eqLogic->setConfiguration('battery_type', 'Batterie'); $eqLogic->setConfiguration('mac', $robot['mac_address']); $eqLogic->setEqType_name('neato'); $eqLogic->setIsVisible(1); $eqLogic->setIsEnable(1); } if (isset($robot['secret_key'])) { $eqLogic->setConfiguration('secret', $robot['secret_key']); $eqLogic->setConfiguration('model', $robot['model']); //$eqLogic->setConfiguration('firmware', "unknown"); //$eqLogic->setConfiguration('robotid', $robot['serial']); } else { $eqLogic->setConfiguration('secret', $client->token); $eqLogic->setConfiguration('model', $robot['model_name']); $eqLogic->setConfiguration('firmware', $robot['firmware']); $eqLogic->setConfiguration('robotid', $robot['id']); } $eqLogic->save(); $robot_client = new NeatoBotvacRobot($eqLogic->getConfiguration('serial'), $eqLogic->getConfiguration('secret'), $eqLogic->getConfiguration('model'), $eqLogic->getConfiguration('robotid')); if ($robot_client->apimodel == "ability") { $maps = []; foreach ($robot_client->getRanks() as $map) { $rank_id = $map['rank_uuid']; $floor_id = $map['floorplan_uuid']; $floor_name = $map['name']; array_push($maps,array("id"=>$floor_id,"name"=>$floor_name)); } $robot['persistent_maps'] = $maps; } if($robot['persistent_maps'] && count($robot['persistent_maps']) > 0){ foreach($robot['persistent_maps'] as $maps){ $cmd = $eqLogic->getCmd(null, 'start::'.$maps['id']); if (!is_object($cmd)) { $cmd = new neatocmd(); $cmd->setLogicalId('start::'.$maps['id']); $cmd->setName(__('Démarrer ', __FILE__).$maps['name']); $cmd->setOrder(4); } $cmd->setType('action'); $cmd->setSubType('other'); $cmd->setEqLogic_id($eqLogic->getId()); $cmd->save(); $cmd = $eqLogic->getCmd(null, 'starteco::'.$maps['id']); if (!is_object($cmd)) { $cmd = new neatocmd(); $cmd->setLogicalId('starteco::'.$maps['id']); $cmd->setIsVisible(0); $cmd->setName(__('Démarrer Turbo ', __FILE__).$maps['name']); } $cmd->setConfiguration('boundary',$boundary['id']); $cmd->setType('action'); $cmd->setSubType('other'); $cmd->setEqLogic_id($eqLogic->getId()); $cmd->save(); $boundaries = $robot_client->getMapBoundaries($maps['id']); log::add('neato','debug','boundaries : '.json_encode($boundaries)); if(isset($boundaries['data']) && isset($boundaries['data']['boundaries'])){ foreach($boundaries['data']['boundaries'] as $boundary){ if($boundary['name'] == ''){ continue; } $cmd = $eqLogic->getCmd(null, 'start::'.$boundary['id']); if (!is_object($cmd)) { $cmd = new neatocmd(); $cmd->setLogicalId('start::'.$boundary['id']); $cmd->setName(__('Démarrer ', __FILE__).$maps['name'].' '.$boundary['name']); $cmd->setOrder(4); } $cmd->setConfiguration('boundary',$boundary['id']); $cmd->setType('action'); $cmd->setSubType('other'); $cmd->setEqLogic_id($eqLogic->getId()); $cmd->save(); $cmd = $eqLogic->getCmd(null, 'starteco::'.$boundary['id']); if (!is_object($cmd)) { $cmd = new neatocmd(); $cmd->setLogicalId('starteco::'.$boundary['id']); $cmd->setIsVisible(0); $cmd->setName(__('Démarrer Turbo ', __FILE__).$maps['name'].' '.$boundary['name']); } $cmd->setConfiguration('boundary',$boundary['id']); $cmd->setType('action'); $cmd->setSubType('other'); $cmd->setSubType('other'); $cmd->setEqLogic_id($eqLogic->getId()); $cmd->save(); } } } } } $eqLogic->cron15($eqLogic->getId()); } } else { log::add('neato', 'debug', 'Unable to authorize for orbital client'); } } catch (Exception $e) { log::add('neato', 'debug', log::exception($e)); } } public function getImage() { $file = dirname(__FILE__) . '/../config/' . $this->getConfiguration('model') . '.png'; if (file_exists($file)) { return 'plugins/neato/core/config/' . $this->getConfiguration('model') . '.png'; } else { return 'plugins/neato/plugin_info/neato_icon.png'; } } public function postSave() { $etat = $this->getCmd(null, 'etat'); if (!is_object($etat)) { $etat = new neatocmd(); $etat->setName(__('Etat', __FILE__)); $etat->setIsVisible(0); } $etat->setEqLogic_id($this->getId()); $etat->setLogicalId('etat'); $etat->setType('info'); $etat->setSubType('string'); $etat->save(); $etattech = $this->getCmd(null, 'etattech'); if (!is_object($etattech)) { $etattech = new neatocmd(); $etattech->setName(__('Code état', __FILE__)); $etattech->setOrder(3); $etattech->setTemplate('dashboard','neato::state'); $etattech->setTemplate('mobile','neato::state'); } $etattech->setEqLogic_id($this->getId()); $etattech->setLogicalId('etattech'); $etattech->setType('info'); $etattech->setSubType('string'); $etattech->save(); $alert = $this->getCmd(null, 'alert'); if (!is_object($alert)) { $alert = new neatocmd(); $alert->setName(__('Alerte', __FILE__)); $alert->setOrder(2); } $alert->setEqLogic_id($this->getId()); $alert->setLogicalId('alert'); $alert->setType('info'); $alert->setSubType('string'); $alert->save(); $charging = $this->getCmd(null, 'charging'); if (!is_object($charging)) { $charging = new neatocmd(); $charging->setName(__('En charge', __FILE__)); $charging->setIsVisible(0); $charging->setConfiguration('repeatEventManagement','never'); } $charging->setEqLogic_id($this->getId()); $charging->setLogicalId('charging'); $charging->setType('info'); $charging->setSubType('binary'); $charging->save(); $docked = $this->getCmd(null, 'docked'); if (!is_object($docked)) { $docked = new neatocmd(); $docked->setName(__('Sur dock', __FILE__)); $docked->setIsVisible(0); $docked->setConfiguration('repeatEventManagement','never'); } $docked->setEqLogic_id($this->getId()); $docked->setLogicalId('docked'); $docked->setType('info'); $docked->setSubType('binary'); $docked->save(); $scheduled = $this->getCmd(null, 'scheduled'); if (!is_object($scheduled)) { $scheduled = new neatocmd(); $scheduled->setName(__('Programmation', __FILE__)); $scheduled->setIsVisible(0); $scheduled->setConfiguration('repeatEventManagement','never'); } $scheduled->setEqLogic_id($this->getId()); $scheduled->setLogicalId('scheduled'); $scheduled->setType('info'); $scheduled->setSubType('binary'); $scheduled->save(); $start = $this->getCmd(null, 'start'); if (!is_object($start)) { $start = new neatocmd(); $start->setLogicalId('start'); $start->setName(__('Démarrer', __FILE__)); $start->setOrder(4); } $start->setType('action'); $start->setSubType('other'); $start->setEqLogic_id($this->getId()); $start->save(); $starteco = $this->getCmd(null, 'starteco'); if (!is_object($starteco)) { $starteco = new neatocmd(); $starteco->setLogicalId('starteco'); $starteco->setIsVisible(0); $starteco->setName(__('Démarrer Turbo, __FILE__)); } $starteco->setType('action'); $starteco->setSubType('other'); $starteco->setEqLogic_id($this->getId()); $starteco->save(); $pause = $this->getCmd(null, 'pause'); if (!is_object($pause)) { $pause = new neatocmd(); $pause->setLogicalId('pause'); $pause->setName(__('Pause', __FILE__)); $pause->setIsVisible(0); } $pause->setType('action'); $pause->setSubType('other'); $pause->setEqLogic_id($this->getId()); $pause->save(); $resume = $this->getCmd(null, 'resume'); if (!is_object($resume)) { $resume = new neatocmd(); $resume->setLogicalId('resume'); $resume->setName(__('Reprendre', __FILE__)); $resume->setIsVisible(0); } $resume->setType('action'); $resume->setSubType('other'); $resume->setEqLogic_id($this->getId()); $resume->save(); $base = $this->getCmd(null, 'base'); if (!is_object($base)) { $base = new neatocmd(); $base->setLogicalId('base'); $base->setName(__('Retour base', __FILE__)); $base->setOrder(5); } $base->setType('action'); $base->setSubType('other'); $base->setEqLogic_id($this->getId()); $base->save(); $stop = $this->getCmd(null, 'stop'); if (!is_object($stop)) { $stop = new neatocmd(); $stop->setLogicalId('stop'); $stop->setIsVisible(1); $stop->setName(__('Arrêter', __FILE__)); $stop->setOrder(4); } $stop->setType('action'); $stop->setSubType('other'); $stop->setEqLogic_id($this->getId()); $stop->save(); $refresh = $this->getCmd(null, 'refresh'); if (!is_object($refresh)) { $refresh = new neatocmd(); } $refresh->setName(__('Rafraichir', __FILE__)); $refresh->setLogicalId('refresh'); $refresh->setEqLogic_id($this->getId()); $refresh->setType('action'); $refresh->setSubType('other'); $refresh->save(); } } class neatoCmd extends cmd { /***************************Attributs*******************************/ /*************************Methode static****************************/ /***********************Methode d'instance**************************/ public function imperihomeGenerate($ISSStructure) { $eqLogic = $this->getEqLogic(); $object = $eqLogic->getObject(); if ($this->getLogicalId() == 'alert') { $info_device = array( "id" => $this->getId(), "name" => $eqLogic->getName(), "room" => (is_object($object)) ? $object->getId() : 99999, "type" => imperihome::convertType($this, $ISSStructure, true), 'params' => array(), ); $cmd_params = imperihome::generateParam($this, $info_device['type'], $ISSStructure); $info_device['params'] = $cmd_params['params']; $info_device['params'][0]['value'] = '#' . $eqLogic->getCmd('info', 'etat')->getId() . '# - #' . $eqLogic->getCmd('info', 'alert')->getId() . '#'; return $info_device; } $type = 'DevMultiSwitch'; $info_device = array( 'id' => $this->getId(), 'name' => $eqLogic->getName(), 'room' => (is_object($object)) ? $object->getId() : 99999, 'type' => $type, 'params' => array(), ); $info_device['params'] = $ISSStructure[$info_device['type']]['params']; $info_device['params'][0]['value'] = '#' . $eqLogic->getCmd('info', 'etat')->getId() . '#'; $info_device['params'][1]['value'] = 'Retour base,Arrêter,Reprendre,Pause,Démarrer Turbo Maison,Démarrer Eco Maison,Rafraichir'; return $info_device; } public function imperihomeAction($_action, $_value) { if ($_action == 'setChoice') { $eqLogic = $this->getEqLogic(); switch ($_value) { case 'Retour base': $eqLogic->getCmd('action', 'base')->execCmd(); break; case 'Arrêter': $eqLogic->getCmd('action', 'stop')->execCmd(); break; case 'Reprendre': $eqLogic->getCmd('action', 'resume')->execCmd(); break; case 'Pause': $eqLogic->getCmd('action', 'pause')->execCmd(); break; case 'Démarrer Turbo Maison': $eqLogic->getCmd('action', 'start')->execCmd(); break; case 'Démarrer Eco Maison': $eqLogic->getCmd('action', 'starteco')->execCmd(); break; case 'Rafraichir': $eqLogic->getCmd('action', 'refresh')->execCmd(); break; } } } public function imperihomeCmd() { return ($this->getLogicalId() == 'etat' || $this->getLogicalId() == 'alert'); } public function execute($_options = null) { if ($this->getType() == '') { return ''; } $eqLogic = $this->getEqlogic(); $robot = new NeatoBotvacRobot($eqLogic->getLogicalId(), $eqLogic->getConfiguration('secret'), $eqLogic->getConfiguration('model'), $eqLogic->getConfiguration('robotid')); switch ($this->getLogicalId()) { case 'refresh': $eqLogic->cron15($eqLogic->getId()); return; break; case 'stop': $result = $robot->stopCleaning(); break; case 'pause': $result = $robot->pauseCleaning(); break; case 'resume': $result = $robot->resumeCleaning(); break; case 'base': $result = $robot->sendToBase(); break; case 'start': $result = $robot->startCleaning(false,$eqLogic->getConfiguration('modelCleaning', '')); break; case 'starteco': $result = $robot->startCleaning(true,$eqLogic->getConfiguration('modelCleaning', '')); break; } if(strpos($this->getLogicalId(),'start::') !== false){ if($this->getConfiguration('boundary') != ''){ $result = $robot->startCleaning(false,$eqLogic->getConfiguration('modelCleaning', ''),$eqLogic->getConfiguration('maps', ''),$this->getConfiguration('boundary', '')); }else{ $result = $robot->startCleaning(false,$eqLogic->getConfiguration('modelCleaning', ''),$eqLogic->getConfiguration('maps', '')); } }else if(strpos($this->getLogicalId(),'starteco::') !== false){ if($this->getConfiguration('boundary') != ''){ $result = $robot->startCleaning(true,$eqLogic->getConfiguration('modelCleaning', ''),$eqLogic->getConfiguration('maps', ''),$this->getConfiguration('boundary', '')); }else{ $result = $robot->startCleaning(true,$eqLogic->getConfiguration('modelCleaning', ''),$eqLogic->getConfiguration('maps', '')); } } log::add('neato','debug','Command execution result : '.json_encode($result)); if(!isset($result['result']) && !isset($result['ability'])){ throw new \Exception(__('Echec de l\'éxecution de la commande',__FILE__)); } if(isset($result['result']) && $result['result'] != 'ok'){ throw new \Exception(__('Echec de l\'éxecution de la commande : ',__FILE__).$result['result']); } if(isset($result['message'])){ throw new \Exception(__('Echec de l\'éxecution de la commande : ',__FILE__).$result['message']); } log::add('neato','debug','Command execution result : '.json_encode($result)); $eqLogic->cron15($eqLogic->getId(),$result); } /************************Getteur Setteur****************************/ } ?>