├── Examples ├── Config.php ├── CLI_Webhooks_Registration_Example.php ├── Webhook_Server_Example.php ├── CLI_Welcome_API_Example.php ├── CLI_WS_API_Example.php ├── WEB_AuthorizationGrant_Example.php ├── CLI_Therm_API_Example.php └── Utils.php ├── src ├── Netatmo │ ├── Common │ │ ├── NAClientErrorCode.php │ │ ├── NACameraAlimSubStatus.php │ │ ├── NACameraImageInfo.php │ │ ├── NACameraStatus.php │ │ ├── NASDKErrorCode.php │ │ ├── NAWifiRssiThreshold.php │ │ ├── NACameraVideoStatus.php │ │ ├── NACameraHomeInfo.php │ │ ├── NARadioRssiTreshold.php │ │ ├── NACameraPersonInfo.php │ │ ├── NABatteryLevelModule.php │ │ ├── NACameraInfo.php │ │ ├── NABatteryLevelWindGaugeModule.php │ │ ├── NABatteryLevelIndoorModule.php │ │ ├── NABatteryLevelThermostat.php │ │ ├── NAThermZone.php │ │ ├── NACameraSDEvent.php │ │ ├── NAStationSensorsMinMax.php │ │ ├── NACameraEventType.php │ │ ├── NACameraEventInfo.php │ │ ├── NAUserUnit.php │ │ ├── NAScopes.php │ │ └── NARestErrorCode.php │ ├── Exceptions │ │ ├── NACurlErrorType.php │ │ ├── NAInternalErrorType.php │ │ ├── NAJsonErrorType.php │ │ ├── NANotLoggedErrorType.php │ │ ├── NASDKException.php │ │ ├── NAApiErrorType.php │ │ └── NAClientException.php │ ├── Objects │ │ ├── NAObjectWithPicture.php │ │ ├── NAPerson.php │ │ ├── NAObject.php │ │ ├── NACamera.php │ │ ├── NAEvent.php │ │ └── NAHome.php │ ├── autoload.php │ ├── Clients │ │ ├── NAWSApiClient.php │ │ ├── NAWelcomeApiClient.php │ │ ├── NAThermApiClient.php │ │ └── NAApiClient.php │ └── Handlers │ │ └── NAResponseHandler.php ├── Objects │ ├── NAHome.php │ ├── NACamera.php │ ├── NAEvent.php │ ├── NAPerson.php │ └── NAObject.php ├── Clients │ ├── NAWSApiClient.php │ ├── NAThermApiClient.php │ └── NAWelcomeApiClient.php ├── Exceptions │ ├── NASDKException.php │ └── NAClientException.php ├── Handlers │ └── NAResponseHandler.php └── Constants │ └── AppliCommonPublic.php └── README.md /Examples/Config.php: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NAClientErrorCode.php: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NACameraAlimSubStatus.php: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NACameraImageInfo.php: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NACameraStatus.php: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NASDKErrorCode.php: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NAWifiRssiThreshold.php: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NACameraVideoStatus.php: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /src/Netatmo/Exceptions/NACurlErrorType.php: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /src/Netatmo/Exceptions/NAInternalErrorType.php: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /src/Netatmo/Exceptions/NAJsonErrorType.php: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /src/Netatmo/Exceptions/NANotLoggedErrorType.php: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /src/Netatmo/Exceptions/NASDKException.php: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /src/Objects/NAHome.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/Objects/NACamera.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/Objects/NAEvent.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/Objects/NAPerson.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NACameraHomeInfo.php: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /src/Clients/NAWSApiClient.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NARadioRssiTreshold.php: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /src/Clients/NAThermApiClient.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/Exceptions/NASDKException.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/Clients/NAWelcomeApiClient.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/Handlers/NAResponseHandler.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/Exceptions/NAClientException.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NACameraPersonInfo.php: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NABatteryLevelModule.php: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NACameraInfo.php: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NABatteryLevelWindGaugeModule.php: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /src/Objects/NAObject.php: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NABatteryLevelIndoorModule.php: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NABatteryLevelThermostat.php: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NAThermZone.php: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NACameraSDEvent.php: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NAStationSensorsMinMax.php: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /src/Netatmo/Objects/NAObjectWithPicture.php: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NACameraEventType.php: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NACameraEventInfo.php: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NAUserUnit.php: -------------------------------------------------------------------------------- 1 | 28 | -------------------------------------------------------------------------------- /src/Netatmo/Exceptions/NAApiErrorType.php: -------------------------------------------------------------------------------- 1 | http_code = $code; 14 | $this->http_message = $message; 15 | $this->result = $result; 16 | if(isset($result["error"]) && is_array($result["error"]) && isset($result["error"]["code"])) 17 | { 18 | parent::__construct($result["error"]["code"], $result["error"]["message"], API_ERROR_TYPE); 19 | } 20 | else 21 | { 22 | parent::__construct($code, $message, API_ERROR_TYPE); 23 | } 24 | } 25 | } 26 | 27 | ?> 28 | -------------------------------------------------------------------------------- /src/Netatmo/Exceptions/NAClientException.php: -------------------------------------------------------------------------------- 1 | . 15 | */ 16 | class NAClientException extends NASDKException 17 | { 18 | public $error_type; 19 | /** 20 | * Make a new API Exception with the given result. 21 | * 22 | * @param $result 23 | * The result from the API server. 24 | */ 25 | public function __construct($code, $message, $error_type) 26 | { 27 | $this->error_type = $error_type; 28 | parent::__construct($code, $message); 29 | } 30 | } 31 | 32 | ?> 33 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NAScopes.php: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /Examples/CLI_Webhooks_Registration_Example.php: -------------------------------------------------------------------------------- 1 | $client_id, 15 | "client_secret" => $client_secret, 16 | "username" => $test_username, 17 | "password" => $test_password, 18 | "scope" => Netatmo\Common\NAScopes::SCOPE_READ_CAMERA); 19 | $client = new Netatmo\Clients\NAWelcomeApiClient($config); 20 | 21 | //Retrieve access token 22 | try 23 | { 24 | $tokens = $client->getAccessToken(); 25 | } 26 | catch(Netatmo\Exceptions\NAClientException $ex) 27 | { 28 | $error_msg = "An error happened while trying to retrieve your tokens \n" . $ex->getMessage() . "\n"; 29 | handleError($error_msg, TRUE); 30 | } 31 | 32 | // Adding/droping Webhooks for the current user 33 | try 34 | { 35 | //Adding a Webhook for your app for the current user 36 | $client->subscribeToWebhook(""); //insert the URL of your webhook endpoint here 37 | 38 | //Droping your webhook notification for the current user 39 | $client->dropWebhook(); 40 | } 41 | catch(Netatmo\Exceptions\NAClientException $ex) 42 | { 43 | echo "An error occured while trying to subscribe to a webhook"; 44 | die(); 45 | } 46 | 47 | ?> 48 | -------------------------------------------------------------------------------- /src/Netatmo/Objects/NAPerson.php: -------------------------------------------------------------------------------- 1 | getVar(NACameraPersonInfo::CPI_PSEUDO, FALSE)) 19 | return TRUE; 20 | else return FALSE; 21 | } 22 | 23 | /** 24 | * @return bool 25 | * @brief returns whether or not this person is unknown 26 | */ 27 | 28 | public function isUnknown() 29 | { 30 | return !$this->isKnown(); 31 | } 32 | 33 | /** 34 | * @return bool 35 | * @brief returns whether or not this person is at home 36 | */ 37 | public function isAway() 38 | { 39 | return $this->getVar(NACameraPersonInfo::CPI_OUT_OF_SIGHT); 40 | } 41 | 42 | public function getFace() 43 | { 44 | $face = $this->getVar(NACameraPersonInfo::CPI_FACE); 45 | return $this->getPictureURL($face); 46 | } 47 | 48 | /** 49 | * @return timestamp 50 | * @brief returns last time this person has been seen 51 | */ 52 | public function getLastSeen() 53 | { 54 | return $this->getVar(NACameraPersonInfo::CPI_LAST_SEEN); 55 | } 56 | 57 | /** 58 | * @return string 59 | * @brief returns this person's name 60 | */ 61 | public function getPseudo() 62 | { 63 | return $this->getVar(NACameraPersonInfo::CPI_PSEUDO); 64 | } 65 | } 66 | ?> 67 | -------------------------------------------------------------------------------- /src/Netatmo/Common/NARestErrorCode.php: -------------------------------------------------------------------------------- 1 | 48 | -------------------------------------------------------------------------------- /Examples/Webhook_Server_Example.php: -------------------------------------------------------------------------------- 1 | 40 | -------------------------------------------------------------------------------- /src/Netatmo/Objects/NAObject.php: -------------------------------------------------------------------------------- 1 | object = $array; 16 | } 17 | 18 | /** 19 | * @param string field : array key 20 | * @param $default : default value in case field is not set 21 | * @return object field or default if field is not set 22 | * @brief returns an object's field 23 | */ 24 | public function getVar($field, $default = NULL) 25 | { 26 | if(isset($this->object[$field])) 27 | return $this->object[$field]; 28 | else return $default; 29 | } 30 | 31 | /** 32 | * @param string $field : field to be set 33 | * @param $value value to set to field 34 | * @brief set an object's field 35 | */ 36 | public function setVar($field, $value) 37 | { 38 | $this->object[$field] = $value; 39 | } 40 | 41 | /** 42 | * @return id 43 | * @btief returns object id 44 | */ 45 | public function getId() 46 | { 47 | return $this->getVar("id"); 48 | } 49 | 50 | /** 51 | * @return array $object 52 | * @brief return this object as an array 53 | */ 54 | public function toArray() 55 | { 56 | return $this->object; 57 | } 58 | 59 | /** 60 | * @return JSON document 61 | * @brief returns object as a JSON document 62 | */ 63 | public function toJson() 64 | { 65 | return json_encode($this->toArray()); 66 | } 67 | 68 | /** 69 | * @return string 70 | * @brief return string representation of object : JSON doc 71 | */ 72 | public function __toString() 73 | { 74 | return $this->toJson(); 75 | } 76 | 77 | } 78 | 79 | ?> 80 | -------------------------------------------------------------------------------- /src/Netatmo/autoload.php: -------------------------------------------------------------------------------- 1 | 60 | -------------------------------------------------------------------------------- /src/Constants/AppliCommonPublic.php: -------------------------------------------------------------------------------- 1 | 94 | -------------------------------------------------------------------------------- /src/Netatmo/Objects/NACamera.php: -------------------------------------------------------------------------------- 1 | getVar(NACameraInfo::CI_STATUS); 19 | $sd = $this->getVar(NACameraInfo::CI_SD_STATUS); 20 | $power = $this->getVar(NACameraInfo::CI_ALIM_STATUS); 21 | 22 | if($on_off === NACameraStatus::CS_ON 23 | && $sd === NACameraStatus::CS_ON 24 | && $power === NACameraStatus::CS_ON) 25 | { 26 | return TRUE; 27 | } 28 | return FALSE; 29 | } 30 | 31 | /** 32 | * @return string $name 33 | * @brief returns the camera name 34 | */ 35 | public function getName() 36 | { 37 | return $this->getVar(NACameraInfo::CI_NAME); 38 | } 39 | 40 | /** 41 | * @return string $vpn_url 42 | * @brief returns the vpn_url of the camera 43 | * @throw new NASDKErrorException 44 | */ 45 | public function getVpnUrl() 46 | { 47 | if(!is_null($this->getVar(NACameraInfo::CI_VPN_URL))) 48 | return $this->getVar(NACameraInfo::CI_VPN_URL); 49 | else throw new NASDKException(NASDKErrorCode::FORBIDDEN_OPERATION, "You don't have access to this field due to the scope of your application"); 50 | } 51 | 52 | /** 53 | * @return boolean $is_local 54 | * @brief returns whether or not the camera shares the same public address than this application 55 | * @throw new NASDKErrorException 56 | */ 57 | public function isLocal() 58 | { 59 | if(!is_null($this->getVar(NACameraInfo::CI_IS_LOCAL))) 60 | return $this->getVar(NACameraInfo::CI_IS_LOCAL); 61 | else throw new NASDKException(NASDKErrorCode::FORBIDDEN_OPERATION, "You don't have access to this field due to the scope of your application"); 62 | } 63 | 64 | public function getSDCardStatus() 65 | { 66 | return $this->getVar(NACameraInfo::CI_SD_STATUS); 67 | } 68 | 69 | public function getPowerAdapterStatus() 70 | { 71 | return $this->getVar(NACameraInfo::CI_ALIM_STATUS); 72 | } 73 | 74 | public function getMonitoringStatus() 75 | { 76 | return $this->getVar(NACameraInfo::CI_STATUS); 77 | } 78 | } 79 | 80 | ?> 81 | -------------------------------------------------------------------------------- /src/Netatmo/Clients/NAWSApiClient.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class NAWSApiClient extends NAApiClient 13 | { 14 | 15 | /* 16 | * @type PRIVATE & PARTNER API 17 | * @param string $device_id 18 | * @param bool $get_favorites : used to retrieve (or not) user's favorite public weather stations 19 | * @return array of devices 20 | * @brief Method used to retrieve data for the given weather station or all weather station linked to the user 21 | */ 22 | public function getData($device_id = NULL, $get_favorites = TRUE) 23 | { 24 | $params = array(); 25 | $optionals = array('device_id' => $device_id, 'get_favorites' => $get_favorites); 26 | foreach($optionals as $key => $value) 27 | { 28 | if(!is_null($value)) $params[$key] = $value; 29 | } 30 | 31 | return $this->api('getstationsdata', 'GET', $params); 32 | } 33 | 34 | /* 35 | * @type PUBLIC, PRIVATE & PARTNER API 36 | * @param string $device_id 37 | * @param string $module_id (optional) if specified will retrieve the module's measurements, else it will retrieve the main device's measurements 38 | * @param string $scale : interval of time between two measurements. Allowed values : max, 30min, 1hour, 3hours, 1day, 1week, 1month 39 | * @param string $type : type of measurements you wanna retrieve. Ex : "Temperature, CO2, Humidity". 40 | * @param timestamp (utc) $start (optional) : starting timestamp of requested measurements 41 | * @param timestamp (utc) $end (optional) : ending timestamp of requested measurements. 42 | * @param int $limit (optional) : limits numbers of measurements returned (default & max : 1024) 43 | * @param bool $optimize (optional) : optimize the bandwith usage if true. Optimize = FALSE enables an easier result parsing 44 | * @param bool $realtime (optional) : Remove time offset (+scale/2) for scale bigger than max 45 | * @return array of measures and timestamp 46 | * @brief Method used to retrieve specifig measures of the given weather station 47 | */ 48 | public function getMeasure($device_id, $module_id, $scale, $type, $start = NULL, $end = NULL, $limit = NULL, $optimize = NULL, $realtime = NULL) 49 | { 50 | $params = array('device_id' => $device_id, 51 | 'scale' => $scale, 52 | 'type' => $type); 53 | 54 | $optionals = array('module_id' => $module_id, 55 | 'date_begin' => $start, 56 | 'date_end' => $end, 57 | 'limit' => $limit, 58 | 'optimize' => $optimize, 59 | 'real_time' => $realtime); 60 | foreach($optionals as $key => $value) 61 | { 62 | if(!is_null($value)) $params[$key] = $value; 63 | } 64 | 65 | return $this->api('getmeasure', 'GET', $params); 66 | } 67 | 68 | public function getRainMeasure($device_id, $rainGauge_id, $scale, $start = NULL, $end = NULL, $limit = NULL, $optimize = NULL, $realtime = NULL) 69 | { 70 | if($scale === "max") 71 | { 72 | $type = "Rain"; 73 | } 74 | else $type = "sum_rain"; 75 | 76 | return $this->getMeasure($device_id, $rainGauge_id, $scale, $type, $start, $end, $limit, $optimize, $realtime); 77 | } 78 | 79 | public function getWindMeasure($device_id, $windSensor_id, $scale, $start = NULL, $end = NULL, $limit = NULL, $optimize = NULL, $realtime = NULL) 80 | { 81 | $type = "WindStrength,WindAngle,GustStrength,GustAngle,date_max_gust"; 82 | return $this->getMeasure($device_id, $windSensor_id, $scale, $type, $start, $end, $limit, $optimize, $realtime); 83 | } 84 | 85 | } 86 | 87 | ?> 88 | -------------------------------------------------------------------------------- /Examples/CLI_Welcome_API_Example.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | $client_id, 17 | "client_secret" => $client_secret, 18 | "username" => $test_username, 19 | "password" => $test_password, 20 | "scope" => $scope); 21 | $client = new Netatmo\Clients\NAWelcomeApiClient($conf); 22 | 23 | //Retrieve access token 24 | try 25 | { 26 | $tokens = $client->getAccessToken(); 27 | } 28 | catch(Netatmo\Exceptions\NAClientException $ex) 29 | { 30 | $error_msg = "An error happened while trying to retrieve your tokens \n" . $ex->getMessage() . "\n"; 31 | handleError($error_msg, TRUE); 32 | } 33 | 34 | //Try to retrieve user's Welcome information 35 | try 36 | { 37 | //retrieve every user's homes and their last 10 events 38 | $response = $client->getData(NULL, 10); 39 | $homes = $response->getData(); 40 | } 41 | catch(Netatmo\Exceptions\NASDKException $ex) 42 | { 43 | handleError("An error happened while trying to retrieve home information: ".$ex->getMessage() ."\n", TRUE); 44 | } 45 | 46 | if(is_null($homes) || empty($homes)) 47 | { 48 | handleError("No home found for this user...", TRUE); 49 | } 50 | printMessageWithBorder("User's Homes"); 51 | foreach($homes as $home) 52 | { 53 | printHomeInformation($home); 54 | } 55 | 56 | $home = $homes[0]; 57 | $tz = $home->getTimezone(); 58 | $persons = $home->getPersons(); 59 | 60 | if(!empty($persons)) 61 | { 62 | $known = $home->getKnownPersons(); 63 | $person = $known[0]; 64 | //retrieve last every events that happened after the last time person has been seen 65 | try 66 | { 67 | $response = $client->getLastEventOf($home->getId(), $person->getId()); 68 | $eventList = $response->getData(); 69 | } 70 | catch(Netatmo\Exceptions\NASDKException $ex) 71 | { 72 | handleError("An error occured while retrieving last event of ".$person->getPseudo() . "\n"); 73 | } 74 | if(!empty($eventList)) 75 | { 76 | printMessageWithBorder("Events until last time ".$person->getPseudo(). " was seen"); 77 | 78 | foreach($eventList as $event) 79 | { 80 | printEventInformation($event, $tz); 81 | } 82 | // let's retrieve 10 events that happens right before last event of the given person 83 | $lastIndex = count($eventList) -1; 84 | $lastEvent = $eventList[$lastIndex]; 85 | $event = $eventList[0]; 86 | try 87 | { 88 | $response = $client->getNextEvents($home->getId(), $lastEvent->getId(), 10); 89 | $data = $response->getData(); 90 | } 91 | catch(Netatmo\Exceptions\NASDKException $ex) 92 | { 93 | handleError("An error occured while retrieving events: ". $ex->getMessage(). "\n"); 94 | } 95 | 96 | if(!empty($data)) 97 | { 98 | printMessageWithBorder("The 10 events that happened right before ". $person->getPseudo()." was seen"); 99 | foreach($data as $event) 100 | { 101 | printEventInformation($event, $tz); 102 | } 103 | } 104 | 105 | try 106 | { 107 | $snapshot = $event->getSnapshot(); 108 | if(!is_null($snapshot)) 109 | { 110 | printMessageWithBorder("Event's snapshot"); 111 | echo $snapshot . "\n"; 112 | } 113 | } 114 | catch(Netatmo\Exceptions\NASDKException $ex) 115 | { 116 | handleError("An error occured while retrieving event's snapshot: ". $ex->getMessage()."\n"); 117 | } 118 | } 119 | } 120 | ?> 121 | -------------------------------------------------------------------------------- /src/Netatmo/Clients/NAWelcomeApiClient.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class NAWelcomeApiClient extends NAApiClient 16 | { 17 | 18 | /* 19 | * @type PRIVATE API 20 | * @param string $home_id 21 | * @param integer size (optional): number of events requested per home 22 | * @return NAResponseHandler 23 | * @brief Method use to retrieve data for the given home, or all the home belonging to the user 24 | */ 25 | public function getData($home_id = NULL, $size = 30) 26 | { 27 | $params = array('size' => $size); 28 | if(!is_null($home_id)) $params['home_id'] = $home_id; 29 | 30 | return new NAResponseHandler($this->api('gethomedata', $params)); 31 | } 32 | 33 | /* 34 | * @type PRIVATE API 35 | * @param string $home_id 36 | * @param string $person_id 37 | * @param integer $offset (optional): number of events you want to retrieve further than the last event of the given person. Default 0. 38 | * @return NAResponseHandler 39 | * @brief Method used to retrieve every events until the last one of the given person (plus eventually the given offset) 40 | */ 41 | public function getLastEventOf($home_id, $person_id, $offset = 0) 42 | { 43 | $params = array("home_id" => $home_id, 44 | "person_id" => $person_id, 45 | "offset" => $offset); 46 | 47 | return new NAResponseHandler($this->api("getlasteventof", $params)); 48 | } 49 | 50 | /* 51 | * @type PRIVATE API 52 | * @param string $home_id 53 | * @param string $event_id 54 | * @return NAResponseHandler 55 | * @brief Method used to retrieve every events until the given one 56 | */ 57 | public function getEventsUntil($home_id, $event_id) 58 | { 59 | $params = array("home_id" => $home_id, 60 | "event_id" => $event_id); 61 | 62 | return new NAResponseHandler($this->api("geteventsuntil", $params)); 63 | } 64 | 65 | /* 66 | * @type PRIVATE API 67 | * @param string $home_id 68 | * @param string $event_id 69 | * @param size (optional) Number of events you want to retrieve. Default 30 70 | * @return NAResponseHandler 71 | * @brief Method used to retrieve events older than the given one 72 | */ 73 | public function getNextEvents($home_id, $event_id, $size = 30) 74 | { 75 | $params = array("home_id" => $home_id, 76 | "event_id" => $event_id, 77 | "size" => $size); 78 | 79 | return new NAResponseHandler($this->api("getnextevents", $params)); 80 | } 81 | 82 | /* 83 | * @type PRIVATE API 84 | * @param array $picture: contains picture information such as id, version & key. Correspond to events snapshot or persons face 85 | * @return picture's URL 86 | * @brief Method used to retrieve an event snapshot or a person face 87 | */ 88 | public function getCameraPicture($picture) 89 | { 90 | 91 | if(isset($picture['id']) && isset($picture['key'])) 92 | { 93 | $src = $this->getVariable('services_uri'); 94 | $src.= "/getcamerapicture?image_id=".$picture['id']."&key=".$picture['key']; 95 | return $src; 96 | } 97 | else throw new NAApiErrorType(NARestErrorCode::MISSING_ARGS, "Missing args", NULL); 98 | 99 | } 100 | 101 | /** 102 | * @param string $url : webhook url 103 | * @brief register your app to webhook notification for the current user 104 | */ 105 | public function subscribeToWebhook($url) 106 | { 107 | $this->addWebhook($url, "app_camera"); 108 | } 109 | 110 | /** 111 | * @brief drop webhook notifications for the current user 112 | */ 113 | public function dropWebhook() 114 | { 115 | parent::dropWebhook("app_camera"); 116 | } 117 | } 118 | 119 | ?> 120 | -------------------------------------------------------------------------------- /src/Netatmo/Objects/NAEvent.php: -------------------------------------------------------------------------------- 1 | getVar(NACameraEventInfo::CEI_SNAPSHOT); 24 | return $this->getPictureURL($snapshot); 25 | } 26 | 27 | /** 28 | * @return string 29 | * @brief returns event's description 30 | */ 31 | public function getMessage() 32 | { 33 | return $this->getVar(NACameraEventInfo::CEI_MESSAGE); 34 | } 35 | 36 | /** 37 | * @return timestamp 38 | * @brief returns at which time the event has been triggered 39 | */ 40 | public function getTime() 41 | { 42 | return $this->getVar(NACameraEventInfo::CEI_TIME); 43 | } 44 | 45 | /** 46 | * @return string 47 | * @brief returns the event's type 48 | */ 49 | public function getEventType() 50 | { 51 | return $this->getVar(NACameraEventInfo::CEI_TYPE); 52 | } 53 | 54 | /** 55 | * @return int 56 | * @brief returns event's subtype for SD Card & power adapter events 57 | * @throw NASDKException 58 | */ 59 | public function getEventSubType() 60 | { 61 | if($this->getEventType() === NACameraEventType::CET_SD 62 | || $this->getEventType() === NACameraEventType::CET_ALIM) 63 | { 64 | return $this->getVar(NACameraEventInfo::CEI_SUB_TYPE); 65 | } 66 | else throw new NASDKException(NASDKErrorCode::INVALID_FIELD, "This field does not exist for this type of event"); 67 | } 68 | 69 | /** 70 | * @return string 71 | * @brief returns id of the camera that triggered the event 72 | */ 73 | public function getCameraId() 74 | { 75 | return $this->getVar(NACameraEventInfo::CEI_CAMERA_ID); 76 | } 77 | 78 | /** 79 | * @return string 80 | * @brief returns id of the person seen in the event 81 | * @throw NASDKException 82 | */ 83 | public function getPersonId() 84 | { 85 | if($this->getEventType() === NACameraEventType::CET_PERSON 86 | || $this->getEventType() === NACameraEventType::CET_PERSON_AWAY 87 | ) 88 | { 89 | return $this->getVar(NACameraEventInfo::CEI_PERSON_ID); 90 | } 91 | else throw new NASDKException(NASDKErrorCode::INVALID_FIELD, "This field does not exist for this type of event"); 92 | 93 | } 94 | 95 | public function hasVideo() 96 | { 97 | if(in_array($this->getEventType(), $this->videoEvents)) 98 | return TRUE; 99 | else return FALSE; 100 | } 101 | 102 | /** 103 | * @return string 104 | * @brief returns event's video id 105 | * @throw NASDKException 106 | */ 107 | public function getVideo() 108 | { 109 | if($this->hasVideo()) 110 | return $this->getVar(NACameraEventInfo::CEI_VIDEO_ID); 111 | else throw new NASDKException(NASDKErrorCode::INVALID_FIELD, "This type of event does not have videos"); 112 | } 113 | 114 | /** 115 | * @return string 116 | * @brief returns event's video status 117 | * @throw NASDKException 118 | */ 119 | public function getVideoStatus() 120 | { 121 | if($this->hasVideo()) 122 | return $this->getVar(NACameraEventInfo::CEI_VIDEO_STATUS); 123 | else throw new NASDKException(NASDKErrorCode::INVALID_FIELD, "This type of event does not have videos"); 124 | 125 | } 126 | 127 | /** 128 | * @return boolean 129 | * @brief returns whether or not this event corresponds to the moment where the person arrived home 130 | * @throw NASDKException 131 | */ 132 | public function isPersonArrival() 133 | { 134 | if($this->getEventType() === NACameraEventType::CET_PERSON) 135 | { 136 | return $this->getVar(NACameraEventInfo::CEI_IS_ARRIVAL); 137 | } 138 | else throw new NASDKException(NASDKErrorCode::INVALID_FIELD, "This field does not exist for this type of event"); 139 | 140 | } 141 | } 142 | ?> 143 | -------------------------------------------------------------------------------- /src/Netatmo/Handlers/NAResponseHandler.php: -------------------------------------------------------------------------------- 1 | decodedBody = $responseBody; 26 | } 27 | 28 | /** 29 | * @return array $decodedBody 30 | * @brief return raw data retrieved from Netatmo API 31 | */ 32 | public function getDecodedBody() 33 | { 34 | return $this->decodedBody; 35 | } 36 | 37 | /** 38 | * return array $dataCollection : array of home or event objects 39 | * @brief return data as collection objects 40 | * @throw NASDKException 41 | */ 42 | public function getData() 43 | { 44 | if(!is_null($this->decodedBody) && !empty($this->decodedBody)) 45 | { 46 | if(is_null($this->dataCollection) || empty($this->dataCollection)) 47 | { 48 | if(isset($this->decodedBody['homes'])) 49 | { 50 | $this->buildHomeCollectionFromResponse(); 51 | } 52 | else if (isset($this->decodedBody['events_list'])) 53 | { 54 | $this->buildEventCollectionFromResponse(); 55 | } 56 | } 57 | 58 | return $this->dataCollection; 59 | 60 | } 61 | 62 | else throw new NASDKException(NASDKErrorCode::UNABLE_TO_CAST, "Empty Response."); 63 | 64 | } 65 | 66 | /** 67 | * @brief convert raw data to home objects 68 | * @throw NASDKException 69 | */ 70 | public function buildHomeCollectionFromResponse() 71 | { 72 | $this->validateCastToHomeCollection(); 73 | 74 | $homeCollection = array(); 75 | 76 | foreach($this->decodedBody['homes'] as $homeArray) 77 | { 78 | $this->validateCastToHome($homeArray); 79 | $home = new NAHome($homeArray); 80 | $homeCollection[] = $home; 81 | } 82 | 83 | $this->dataCollection = $homeCollection; 84 | } 85 | 86 | /** 87 | * @brief check if array of data is castable to collection of home objects 88 | * @throw NASDKException 89 | */ 90 | protected function validateCastToHomeCollection() 91 | { 92 | if(is_array($this->decodedBody) && $this->validateArrayForCast($this->decodedBody, 'homes')) 93 | return; 94 | 95 | throw new NASDKException(NASDKErrorCode::UNABLE_TO_CAST, "Unable to cast data to NAHome object"); 96 | } 97 | 98 | /** 99 | * @brief check if array of data is castable to NAHome object 100 | * @throw NASDKException 101 | */ 102 | protected function validateCastToHome($data) 103 | { 104 | if(isset($data['id']) 105 | && $this->validateArrayForCast($data, 'persons') 106 | && $this->validateArrayForCast($data, 'events') 107 | && $this->validateArrayForCast($data, 'cameras') 108 | ) 109 | return; 110 | 111 | throw new NASDKException(NASDKErrorCode::UNABLE_TO_CAST, "Unable to cast data to home object"); 112 | } 113 | 114 | /** 115 | * @brief check if array is castable 116 | */ 117 | private function validateArrayForCast($array, $name) 118 | { 119 | if(isset($array[$name]) && is_array($array[$name])) 120 | return true; 121 | else return false; 122 | } 123 | 124 | /** 125 | * @brief convert raw data to collection of event objects 126 | * @throw NASDKException 127 | */ 128 | public function buildEventCollectionFromResponse() 129 | { 130 | $this->validateCastToEventCollection(); 131 | 132 | $eventCollection = array(); 133 | 134 | foreach($this->decodedBody['events_list'] as $eventArray) 135 | { 136 | $this->validateCastToEventObject($eventArray); 137 | $event = new NAEvent($eventArray); 138 | $eventCollection[] = $event; 139 | } 140 | 141 | $this->dataCollection = $eventCollection; 142 | } 143 | 144 | /** 145 | * @brief check if array of data is castable to collection of event objects 146 | * @throw NASDKException 147 | */ 148 | protected function validateCastToEventCollection() 149 | { 150 | if(is_array($this->decodedBody) 151 | && $this->validateArrayForCast($this->decodedBody, 'events_list') 152 | ) 153 | return; 154 | 155 | throw new NASDKException(NASDKErrorCode::UNABLE_TO_CAST, "Impossible to cast to NAEvent"); 156 | } 157 | 158 | /** 159 | * @brief check if array of data is castable to NAEvent object 160 | * @throw NASDKException 161 | */ 162 | protected function validateCastToEventObject($data) 163 | { 164 | if(isset($data['id']) && isset($data['time']) && isset($data['type'])) 165 | return; 166 | 167 | throw new NASDKException(NASDKErrorCode::UNABLE_TO_CAST, "Unable to cast data to event object"); 168 | } 169 | } 170 | ?> 171 | -------------------------------------------------------------------------------- /Examples/CLI_WS_API_Example.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | $client_id, 38 | "client_secret" => $client_secret, 39 | "username" => $test_username, 40 | "password" => $test_password); 41 | 42 | $client = new Netatmo\Clients\NAWSApiClient($config); 43 | 44 | //Authentication with Netatmo server (OAuth2) 45 | try 46 | { 47 | $tokens = $client->getAccessToken(); 48 | } 49 | catch(Netatmo\Exceptions\NAClientException $ex) 50 | { 51 | handleError("An error happened while trying to retrieve your tokens: " .$ex->getMessage()."\n", TRUE); 52 | } 53 | 54 | //Retrieve user's Weather Stations Information 55 | 56 | try 57 | { 58 | //retrieve all stations belonging to the user, and also his favorite ones 59 | $data = $client->getData(NULL, TRUE); 60 | printMessageWithBorder("Weather Stations Basic Information"); 61 | } 62 | catch(Netatmo\Exceptions\NAClientException $ex) 63 | { 64 | handleError("An error occured while retrieving data: ". $ex->getMessage()."\n", TRUE); 65 | } 66 | 67 | if(empty($data['devices'])) 68 | { 69 | echo 'No devices affiliated to user'; 70 | } 71 | else 72 | { 73 | 74 | $users = array(); 75 | $friends = array(); 76 | $fav = array(); 77 | $device = $data['devices'][0]; 78 | $tz = isset($device['place']['timezone']) ? $device['place']['timezone'] : "GMT"; 79 | 80 | //devices are already sorted in the following way: first weather stations owned by user, then "friend" WS, and finally favorites stations. Still let's store them in different arrays according to their type 81 | foreach($data['devices'] as $device) 82 | { 83 | 84 | //favorites have both "favorite" and "read_only" flag set to true, whereas friends only have read_only 85 | if(isset($device['favorite']) && $device['favorite']) 86 | $fav[] = $device; 87 | else if(isset($device['read_only']) && $device['read_only']) 88 | $friends[] = $device; 89 | else $users[] = $device; 90 | } 91 | 92 | //print first User's device Then friends, then favorite 93 | printDevices($users, "User's weather stations"); 94 | printDevices($friends, "User's friends weather stations"); 95 | printDevices($fav, "User's favorite weather stations"); 96 | 97 | // now get some daily measurements for the last 30 days 98 | $type = "temperature,Co2,humidity,noise,pressure"; 99 | 100 | //first for the main device 101 | try 102 | { 103 | $measure = $client->getMeasure($device['_id'], NULL, "1day" , $type, time() - 24*3600*30, time(), 30, FALSE, FALSE); 104 | printMeasure($measure, $type, $tz, $device['_id'] ."'s daily measurements of the last 30 days"); 105 | } 106 | catch(Netatmo\Exceptions\NAClientException $ex) 107 | { 108 | handleError("An error occured while retrieving main device's daily measurements: " . $ex->getMessage() . "\n"); 109 | } 110 | 111 | //Then for its modules 112 | foreach($device['modules'] as $module) 113 | { 114 | //requested data type depends on the module's type 115 | switch($module['type']) 116 | { 117 | case "NAModule3": $type = "sum_rain"; 118 | break; 119 | case "NAModule2": $type = "WindStrength,WindAngle,GustStrength,GustAngle,date_max_gust"; 120 | break; 121 | case "NAModule1" : $type = "temperature,humidity"; 122 | break; 123 | default : $type = "temperature,Co2,humidity"; 124 | } 125 | try 126 | { 127 | $measure = $client->getMeasure($device['_id'], $module['_id'], "1day" , $type, time()-24*3600*30 , time(), 30, FALSE, FALSE); 128 | printMeasure($measure, $type, $tz, $module['_id']. "'s daily measurements of the last 30 days "); 129 | } 130 | catch(Netatmo\Exceptions\NAClientException $ex) 131 | { 132 | handleError("An error occured while retrieving main device's daily measurements: " . $ex->getMessage() . "\n"); 133 | } 134 | 135 | } 136 | 137 | //Finally, retrieve general info about last month for main device 138 | $type = "max_temp,date_max_temp,min_temp,date_min_temp,max_hum,date_max_hum,min_hum,date_min_hum,max_pressure,date_max_pressure,min_pressure,date_min_pressure,max_noise,date_max_noise,min_noise,date_min_noise,max_co2,date_max_co2,min_co2,date_min_co2"; 139 | try 140 | { 141 | $measures = $client->getMeasure($device['_id'], NULL, "1month", $type, NULL, "last", 1, FALSE, FALSE); 142 | printMeasure($measures, $type, $tz, "Last month information of " .$device['_id'], TRUE); 143 | } 144 | catch(Netatmo\Exceptions\NAClientException $ex) 145 | { 146 | handleError("An error occcured while retrieving last month info: ".$ex->getMessage() . " \n"); 147 | } 148 | } 149 | ?> 150 | -------------------------------------------------------------------------------- /src/Netatmo/Objects/NAHome.php: -------------------------------------------------------------------------------- 1 | object[NACameraHomeInfo::CHI_PERSONS] = $personArray; 28 | } 29 | 30 | if(isset($array[NACameraHomeInfo::CHI_EVENTS])) 31 | { 32 | $eventArray = array(); 33 | foreach($array[NACameraHomeInfo::CHI_EVENTS] as $event) 34 | { 35 | $eventArray[] = new NAEvent($event); 36 | } 37 | $this->object[NACameraHomeInfo::CHI_EVENTS] = $eventArray; 38 | } 39 | 40 | if(isset($array[NACameraHomeInfo::CHI_CAMERAS])) 41 | { 42 | $cameraArray = array(); 43 | foreach($array[NACameraHomeInfo::CHI_CAMERAS] as $camera) 44 | { 45 | $cameraArray[] = new NACamera($camera); 46 | } 47 | $this->object[NACameraHomeInfo::CHI_CAMERAS] = $cameraArray; 48 | } 49 | } 50 | 51 | /** 52 | * @return string 53 | * @brief returns home's name 54 | */ 55 | public function getName() 56 | { 57 | return $this->getVar(NACameraHomeInfo::CHI_NAME); 58 | } 59 | 60 | /** 61 | * @return array of event objects 62 | * @brief returns home timeline of event 63 | */ 64 | public function getEvents() 65 | { 66 | return $this->getVar(NACameraHomeInfo::CHI_EVENTS, array()); 67 | } 68 | 69 | /** 70 | * @return array of person objects 71 | * @brief returns every person belonging to this home 72 | */ 73 | public function getPersons() 74 | { 75 | return $this->getVar(NACameraHomeInfo::CHI_PERSONS, array()); 76 | } 77 | 78 | /** 79 | * @return array of person objects 80 | * @brief returns every known person belonging to this home 81 | */ 82 | public function getKnownPersons() 83 | { 84 | $knowns = array(); 85 | foreach($this->getVar(NACameraHomeInfo::CHI_PERSONS, array()) as $person) 86 | { 87 | if($person->isKnown()) 88 | $knowns[] = $person; 89 | } 90 | return $knowns; 91 | } 92 | 93 | /** 94 | * @return array of person objects 95 | * @brief returns every unknown person belonging to this home 96 | */ 97 | public function getUnknownPersons() 98 | { 99 | $unknowns = array(); 100 | foreach($this->getVar(NACameraHomeInfo::CHI_PERSONS, array()) as $person) 101 | { 102 | if($person->isUnknown()) 103 | $unknowns[] = $person; 104 | } 105 | return $unknowns; 106 | } 107 | 108 | /** 109 | * @return array of camera objects 110 | * @brief returns every camera belonging to this home 111 | */ 112 | public function getCameras() 113 | { 114 | return $this->getVar(NACameraHomeInfo::CHI_CAMERAS, array()); 115 | } 116 | 117 | /** 118 | * @return string 119 | * @brief returns home's timezone 120 | */ 121 | public function getTimezone() 122 | { 123 | $place = $this->getVar(NACameraHomeInfo::CHI_PLACE); 124 | return isset($place['timezone'])? $place['timezone'] : 'GMT'; 125 | } 126 | 127 | /** 128 | * @return NACamera 129 | * @brief return the camera object corresponding to the id asked 130 | * @throw NASDKErrorException 131 | */ 132 | public function getCamera($camera_id) 133 | { 134 | foreach($this->getVar(NACameraHomeInfo::CHI_CAMERAS, array()) as $camera) 135 | { 136 | if($camera->getId() === $camera_id) 137 | { 138 | return $camera; 139 | } 140 | } 141 | throw new NASDKException(NASDKErrorCode::NOT_FOUND, "camera $camera_id not found in home: " . $this->getId()); 142 | } 143 | 144 | /** 145 | * @return NAPerson 146 | * @brief returns NAPerson object corresponding to the id in parameter 147 | * @throw NASDKErrorException 148 | */ 149 | public function getPerson($person_id) 150 | { 151 | foreach($this->getVar(NACameraHomeInfo::CHI_PERSONS, array()) as $camera) 152 | { 153 | if($person->getId() === $person_id) 154 | return $person; 155 | } 156 | 157 | throw new NASDKException(NASDKErrorCode::NOT_FOUND, "person $person_id not found in home: " . $this->getId()); 158 | } 159 | 160 | /** 161 | * @return array of NAPerson 162 | * @brief returns every person that are not home 163 | */ 164 | public function getPersonAway() 165 | { 166 | $away = array(); 167 | 168 | foreach($this->getVar(NACameraHomeInfo::CHI_PERSONS, array()) as $person) 169 | { 170 | if($person->isAway()) 171 | $away[] = $person; 172 | } 173 | return $away; 174 | } 175 | 176 | /** 177 | * @return array of NAPerson 178 | * @brief returns every person that are home 179 | */ 180 | public function getPersonAtHome() 181 | { 182 | $home = array(); 183 | 184 | foreach($this->getVar(NACameraHomeInfo::CHI_PERSONS, array()) as $person) 185 | { 186 | if(!$person->isAway()) 187 | $home[] = $person; 188 | } 189 | return $home; 190 | } 191 | } 192 | ?> 193 | -------------------------------------------------------------------------------- /Examples/WEB_AuthorizationGrant_Example.php: -------------------------------------------------------------------------------- 1 | $client_id, 14 | "client_secret" => $client_secret, 15 | "scope" => Netatmo\Common\NAScopes::SCOPE_READ_STATION); 16 | $client = new Netatmo\Clients\NAWSApiClient($config); 17 | 18 | //if code is provided in get param, it means user has accepted your app and been redirected here 19 | if(isset($_GET["code"])) 20 | { 21 | //get the tokens, you can store $tokens['refresh_token'] in order to quickly retrieve a new access_token next time 22 | try{ 23 | $tokens = $client->getAccessToken(); 24 | } 25 | catch(Netatmo\Exceptions\NAClientException $ex) 26 | { 27 | echo "An error occured while trying to retrieve your tokens \n"; 28 | echo "Reason: ".$ex->getMessage()."\n"; 29 | die(); 30 | } 31 | //retrieve user's weather station data 32 | try{ 33 | $data = $client->getData(); 34 | } 35 | catch(Netatmo\Exceptions\NAClientException $ex) 36 | { 37 | echo "An error occured while retrieving data: ". $ex->getMessage()."\n"; 38 | die(); 39 | } 40 | 41 | if(!isset($data['devices']) || !is_array($data['devices']) || count($data['devices']) < 1) 42 | { 43 | echo "User has no devices \n"; 44 | die(); 45 | } 46 | 47 | //In this example, we will only deal with the first weather station linked to the user account 48 | $device = $data['devices'][0]; 49 | 50 | //last month report 51 | $reports = getMonthReport($device, $client); 52 | 53 | //Get device timezone 54 | if(!is_null($device) && !empty($device)) 55 | { 56 | if(isset($device['place']['timezone'])) 57 | $tz = $device['place']['timezone']; 58 | else $tz = 'GMT'; 59 | 60 | //print data 61 | ?> 62 | 63 | 64 | 65 |
66 |

67 |

id :

68 | "; 78 | echo "

Month report

"; 79 | foreach($reports as $report) 80 | { 81 | if(is_array($report)) 82 | printDashBoardDataInHtml($report, $tz); 83 | else echo "

".$report."

"; 84 | } 85 | echo "
"; 86 | } 87 | ?> 88 | 89 | 90 | 91 | redirect to Netatmo OAuth 103 | else if(isset($_GET['start'])) 104 | { 105 | //Ok redirect to Netatmo Authorize URL 106 | $redirect_url = $client->getAuthorizeUrl(); 107 | header("HTTP/1.1 ". 302); 108 | header("Location: " . $redirect_url); 109 | die(); 110 | } 111 | // Homepage : start button 112 | else 113 | { 114 | ?> 115 | 116 | 117 |
118 | 119 |
120 | 121 | 122 | $value) 134 | { 135 | echo "

"; 136 | echo $key.": "; 137 | if($key === 'time_utc' || preg_match("/^date_.*/", $key)) 138 | { 139 | printTimeInTz($value, $tz, 'j F H:i'); 140 | } 141 | else { 142 | echo $value; 143 | printUnit($key); 144 | } 145 | echo"

"; 146 | } 147 | } 148 | 149 | /** 150 | * @param array $module 151 | * @param string $tz device's timezone 152 | * @brief print a Netatmo Weather Station's module in HTML 153 | */ 154 | function printModuleInHtml($module, $tz) 155 | { 156 | echo "
"; 157 | echo "

". $module['module_name']. "

"; 158 | echo "

id: ".$module['_id']. "

"; 159 | echo "

type: "; 160 | switch($module['type']) 161 | { 162 | case "NAModule1" : echo "Outdoor"; 163 | break; 164 | case "NAModule2" : echo "Wind Sensor"; 165 | break; 166 | case "NAModule3" : echo "Rain Gauge"; 167 | break; 168 | case "NAModule4" : echo "Indoor"; 169 | break; 170 | } 171 | echo "

"; 172 | printDashboardDataInHtml($module['dashboard_data'], $tz); 173 | echo "
"; 174 | } 175 | 176 | /** 177 | * @param array $device 178 | * @param NAWSApiClient $client 179 | * @return array $report : array with device or module ids as keys, and their data of the month as values 180 | * @brief retrieve month data for a device and its modules 181 | */ 182 | function getMonthReport($device, $client) 183 | { 184 | $report = array(); 185 | //step between two measurements 186 | $scale = '1month'; 187 | //type of measures wanted 188 | $type = "Temperature,CO2,Humidity,Pressure,Noise,max_temp,date_max_temp,min_temp,date_min_temp,max_hum,date_max_hum,min_hum,date_min_hum,max_pressure,date_max_pressure,min_pressure,date_min_pressure,max_noise,date_max_noise,min_noise,date_min_noise,max_co2,date_max_co2,min_co2,date_min_co2"; 189 | // main device 190 | try{ 191 | $measure = $client->getMeasure($device['_id'], NULL, $scale, $type, NULL, "last", NULL, FALSE, FALSE); 192 | $measure = addMeasureKeys($measure, $type); 193 | $report[$device['_id']] = $measure; 194 | } 195 | catch(Netatmo\Exceptions\NAClientException $ex) 196 | { 197 | $report[$device['_id']] = "Error retrieving measure for ".$device['_id'].": " .$ex->getMessage(); 198 | } 199 | 200 | foreach($device['modules'] as $module) 201 | { 202 | switch($module['type']) 203 | { 204 | //Outdoor 205 | case "NAModule1": $type = "temperature,humidity"; 206 | break; 207 | //Wind Sensor 208 | case "NAModule2": $type = "WindStrength,WindAngle,GustStrength,GustAngle,date_max_gust"; 209 | break; 210 | //Rain Gauge 211 | case "NAModule3": $type = "sum_rain"; 212 | break; 213 | // Indoor 214 | case "NAModule4": $type = "temperature,Co2,humidity,noise,pressure"; 215 | break; 216 | } 217 | try{ 218 | $measure = $client->getMeasure($device['_id'], $module['_id'], $scale, $type, NULL, "last", NULL, FALSE, FALSE); 219 | $measure = addMeasureKeys($measure, $type); 220 | $report[$module['_id']] = $measure; 221 | } 222 | catch(Netatmo\Exceptions\NAClientException $ex) 223 | { 224 | $report[$module['_id']] = "Error retrieving measure for " .$module['_id']. ": ".$ex->getMessage(); 225 | } 226 | } 227 | return $report; 228 | } 229 | /** 230 | * @param array measures : measure sent back by getMeasure method 231 | * @param string $type : types of measure requested 232 | * @return array $measurements : array of measures mapped by type 233 | * @brief add the type as a key for each measure 234 | */ 235 | function addMeasureKeys($measures, $type) 236 | { 237 | $measurements = array(); 238 | $keys = explode(",", $type); 239 | foreach($measures as $measure) 240 | { 241 | foreach($measure as $key => $val) 242 | { 243 | $measurements[$keys[$key]] = $val; 244 | } 245 | } 246 | return $measurements; 247 | } 248 | ?> 249 | -------------------------------------------------------------------------------- /src/Netatmo/Clients/NAThermApiClient.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class NAThermApiClient extends NAApiClient 12 | { 13 | 14 | private function setThermPoint($device_id, $module_id, $mode, $endtime = NULL, $temp = NULL) 15 | { 16 | $params = array('device_id' => $device_id, 17 | 'module_id' => $module_id, 18 | 'setpoint_mode' => $mode); 19 | 20 | if(!is_null($endtime)) $params['setpoint_endtime'] = $endtime; 21 | if(!is_null($temp)) $params['setpoint_temp'] = $temp; 22 | 23 | return $this->api('setthermpoint', 'POST', $params); 24 | } 25 | 26 | /* 27 | * @type PRIVATE & PARTNER API 28 | * @param string $device_id 29 | * @return array of devices 30 | * @brief Method used to retrieve data for the given Thermostat or all the thermostats belonging to the user 31 | */ 32 | public function getData($device_id = NULL) 33 | { 34 | $params = array(); 35 | if(!is_null($device_id)) $params['device_id'] = $device_id; 36 | 37 | return $this->api('getthermostatsdata', 'GET', $params); 38 | } 39 | 40 | 41 | /* 42 | * @type PRIVATE & PARTNER API 43 | * @param string $device_id 44 | * @param string $module_id 45 | * @param timestamp (utc) $endtime (optional) 46 | * @brief Sets the given thermostat to away mode until the given date or until change. 47 | */ 48 | public function setToAwayMode($device_id, $module_id, $endtime = NULL) 49 | { 50 | return $this->setThermPoint($device_id, $module_id, 'away', $endtime); 51 | } 52 | 53 | /* 54 | * @type PRIVATE & PARTNER API 55 | * @param string $device_id 56 | * @param string $module_id 57 | * @param timestamp (utc) $endtime (optional) 58 | * @brief Sets the given thermostat to frost-guard mode until the given date or until change 59 | */ 60 | public function setToFrostGuardMode($device_id, $module_id, $endtime = NULL) 61 | { 62 | return $this->setThermPoint($device_id, $module_id, 'hg', $endtime); 63 | } 64 | 65 | /* 66 | * @type PRIVATE & PARTNER API 67 | * @param string $device_id 68 | * @param string $module_id 69 | * @brief Turn off the given thermostat 70 | */ 71 | public function turnOff($device_id, $module_id) 72 | { 73 | return $this->setThermPoint($device_id, $module_id, 'off'); 74 | } 75 | 76 | /* 77 | * @type PRIVATE & PARTNER API 78 | * @param string $device_id 79 | * @param string $module_id 80 | * @brief Order the given thermostat to follow its schedule 81 | */ 82 | public function setToProgramMode($device_id, $module_id) 83 | { 84 | return $this->setThermPoint($device_id, $module_id, 'program'); 85 | } 86 | 87 | /* 88 | * @type PRIVATE & PARTNER API 89 | * @param string $device_id 90 | * @param string $module_id 91 | * @param float $temp 92 | * @param timestamp (utc) $endtime (optional) 93 | * @brief Sets a manual temperature to the given thermostat for a specified amount of time 94 | */ 95 | public function setToManualMode($device_id, $module_id, $temp, $endtime = NULL) 96 | { 97 | return $this->setThermPoint($device_id, $module_id, 'manual', $endtime, $temp); 98 | } 99 | 100 | /* 101 | * @type PRIVATE & PARTNER API 102 | * @param string $device_id 103 | * @param string $module_id 104 | * @param timestamp(utc) $endtime 105 | * @brief Order the given thermostat to heat to its max temperature 106 | */ 107 | public function setToMaxMode($device_id, $module_id, $endtime) 108 | { 109 | return $this->setThermPoint($device_id, $module_id, 'max', $endtime); 110 | } 111 | 112 | /* 113 | * @type PRIVATE & PARTNER API 114 | * @param string $device_id 115 | * @param string $module_id 116 | * @param array $zones 117 | * @param array $timetable 118 | * @param string $name 119 | * @brief Create a new heating schedule for the given thermostat 120 | */ 121 | public function createSchedule($device_id, $module_id, $zones, $timetable, $name) 122 | { 123 | $params = array('device_id' => $device_id, 124 | 'module_id' => $module_id, 125 | 'zones' => $zones, 126 | 'timetable' => $timetable, 127 | 'name' => $name); 128 | return $this->api('createnewschedule', 'POST', $params); 129 | } 130 | 131 | /* 132 | * @type PRIVATE & PARTNER API 133 | * @param string $device_id 134 | * @param string $module_id 135 | * @param string $schedule_id 136 | * @brief switch to the given existing heating schedule 137 | */ 138 | public function switchSchedule($device_id, $module_id, $schedule_id) 139 | { 140 | $params = array('device_id' => $device_id, 141 | 'module_id' => $module_id, 142 | 'schedule_id' => $schedule_id); 143 | return $this->api('switchschedule', 'POST', $params); 144 | } 145 | 146 | /* 147 | * @type PRIVATE & PARTNER API 148 | * @param string $device_id 149 | * @param string $device_id 150 | * @param string $schedule_id 151 | * @param string $name 152 | * @brief Rename an existing heating schedule 153 | */ 154 | public function renameSchedule($device_id, $module_id, $schedule_id, $name) 155 | { 156 | $params= array('device_id' => $device_id, 157 | 'module_id' => $module_id, 158 | 'schedule_id' => $schedule_id, 159 | 'name' => $name); 160 | return $this->api('renameschedule', 'POST', $params); 161 | } 162 | 163 | /* 164 | * @type PRIVATE & PARTNER API 165 | * @param string $device_id 166 | * @param string $module_id 167 | * @param string $schedule_id 168 | * @brief Delete the given heating schedule. Beware, there should always be at least one schedule left for the device. 169 | */ 170 | public function deleteSchedule($device_id, $module_id, $schedule_id) 171 | { 172 | $params = array('device_id' => $device_id, 173 | 'module_id' => $module_id, 174 | 'schedule_id' => $schedule_id); 175 | return $this->api('deleteschedule', 'POST', $params); 176 | } 177 | 178 | /* 179 | * @type PRIVATE & PARTNER API 180 | * @param string $device_id 181 | * @param string $module_id 182 | * @param array $zones 183 | * @param array $timetable 184 | * @brief change the thermostat's heating schedule the given one 185 | */ 186 | public function syncSchedule($device_id, $module_id, $zones, $timetable) 187 | { 188 | $params = array('device_id' => $device_id, 189 | 'module_id' => $module_id, 190 | 'zones' => $zones, 191 | 'timetable' => $timetable); 192 | return $this->api('syncschedule', 'POST', $params); 193 | } 194 | 195 | /* 196 | * @type PUBLIC, PRIVATE & PARTNER API 197 | * @param string $device_id 198 | * @param string $module_id (optional) if specified will retrieve the module's measurements, else it will retrieve the main device's measurements 199 | * @param string scale : interval of time between two measurements. Allowed values : max, 30min, 1hour, 3hours, 1day, 1week, 1month 200 | * @param string type : type of measurements you wanna retrieve. Ex : "Sp_Temperature, Temperature". 201 | * @param timestamp (utc) $start (optional) : starting timestamp of requested measurements 202 | * @param timestamp (utc) $end (optional) : ending timestamp of requested measurements. 203 | * @param int $limit (optional) : limits numbers of measurements returned (default & max : 1024) 204 | * @param bool $optimize (optional) : optimize the bandwith usage if true. Optimize = FALSE enables an easier result parsing 205 | * @param bool $realtime (optional) : Remove time offset (+scale/2) for scale bigger than max 206 | * @return array of measures and timestamp 207 | * @brief Method used to retrieve specifig measures of the given weather station 208 | */ 209 | 210 | public function getMeasure($device_id, $module_id = NULL, $scale, $type, $start = NULL, $end = NULL, $limit = NULL, $optimize = NULL, $realtime = NULL) 211 | { 212 | $params = array('device_id' => $device_id, 213 | 'scale' => $scale, 214 | 'type' => $type); 215 | 216 | $optionals = array('module_id' => $module_id, 217 | 'date_begin' => $start, 218 | 'date_end' => $end, 219 | 'limit' => $limit, 220 | 'optimize' => $optimize, 221 | 'real_time' => $realtime); 222 | foreach($optionals as $key => $value) 223 | { 224 | if(!is_null($value)) $params[$key] = $value; 225 | } 226 | 227 | return $this->api('getmeasure', 'GET', $params); 228 | } 229 | } 230 | ?> 231 | -------------------------------------------------------------------------------- /Examples/CLI_Therm_API_Example.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | $client_id, 16 | "client_secret" => $client_secret, 17 | "username" => $test_username, 18 | "password" => $test_password, 19 | "scope" => $scope); 20 | $client = new Netatmo\Clients\NAThermApiClient($conf); 21 | 22 | //Retrieve access token 23 | try 24 | { 25 | $tokens = $client->getAccessToken(); 26 | } 27 | catch(Netatmo\Exceptions\NAClientException $ex) 28 | { 29 | $error_msg = "An error happened while trying to retrieve your tokens \n" . $ex->getMessage() . "\n"; 30 | handleError($error_msg, TRUE); 31 | } 32 | 33 | //Retrieve User's thermostats info: 34 | try 35 | { 36 | $thermData = $client->getData(); 37 | } 38 | catch(Netatmo\Exceptions\NAClientException $ex) 39 | { 40 | handleError("An error occured while retrieve thermostat data: " . $ex->getMessage() . "\n", TRUE); 41 | } 42 | 43 | if(count($thermData['devices']) === 0) 44 | echo ("You don't have any thermostats linked to your account. \n"); 45 | else 46 | { 47 | printMessageWithBorder("Thermostats Basic Information"); 48 | 49 | //We'll use the first device later 50 | $device = $thermData['devices'][0]; 51 | $module_id = $device['modules'][0]['_id']; 52 | // keep record of current program and mode to restore it 53 | $currentProgram = getCurrentProgram($device["modules"][0]); 54 | list($initialMode, $initialTemp, $initialEndtime) = getCurrentMode($device["modules"][0]); 55 | 56 | //first print devices information 57 | foreach($thermData['devices'] as $dev) 58 | { 59 | printThermBasicInfo($dev); 60 | } 61 | 62 | 63 | 64 | //Create a new schedule 65 | $scheduleName = "testSchedule"; 66 | //build schedule's zones & timetable 67 | $zones = array( 68 | array("type" => Netatmo\Common\NAThermZone::THERMOSTAT_SCHEDULE_SLOT_DAY, 69 | "id" => 0, 70 | "temp" => 19), 71 | array("type" => Netatmo\Common\NAThermZone::THERMOSTAT_SCHEDULE_SLOT_NIGHT, 72 | "id" => 1, 73 | "temp" => 17), 74 | array("type" => Netatmo\Common\NAThermZone::THERMOSTAT_SCHEDULE_SLOT_AWAY, 75 | "id" => 2, 76 | "temp" => 12), 77 | array("type" => Netatmo\Common\NAThermZone::THERMOSTAT_SCHEDULE_SLOT_HG, 78 | "id" => 3, 79 | "temp" => 7), 80 | array("type" => Netatmo\Common\NAThermZone::THERMOSTAT_SCHEDULE_SLOT_ECO, 81 | "id" => 4, 82 | "temp" => 16), 83 | ); 84 | 85 | // weekly timetable = When to use which zone (offset in min + if of the zone) 86 | $timetable = array( 87 | // monday 88 | array("m_offset" => 0, "id" => 1), 89 | array("m_offset" => 420, "id" => 0), 90 | array("m_offset" => 480, "id" => 4), 91 | array("m_offset" => 1140, "id" => 0), 92 | array("m_offset" => 1320, "id" => 1), 93 | // tuesday 94 | array("m_offset" => 1860, "id" => 0), 95 | array("m_offset" => 1920, "id" => 4), 96 | array("m_offset" => 2580, "id" => 0), 97 | array("m_offset" => 2760, "id" => 1), 98 | // Wednesday 99 | array("m_offset" => 3300, "id" => 0), 100 | array("m_offset" => 3360, "id" => 4), 101 | array("m_offset" => 4020, "id" => 0), 102 | array("m_offset" => 4200, "id" => 1), 103 | // Thursday 104 | array("m_offset" => 4740, "id" => 0), 105 | array("m_offset" => 4800, "id" => 4), 106 | array("m_offset" => 5460, "id" => 0), 107 | array("m_offset" => 5640, "id" => 1), 108 | // Friday 109 | array("m_offset" => 6180, "id" => 0), 110 | array("m_offset" => 6240, "id" => 4), 111 | array("m_offset" => 6900, "id" => 0), 112 | array("m_offset" => 7080, "id" => 1), 113 | // Saturday 114 | array("m_offset" => 7620, "id" => 0), 115 | array("m_offset" => 8520, "id" => 1), 116 | // Sunday 117 | array("m_offset" => 9060, "id" => 0), 118 | array("m_offset" => 9960, "id" => 1) 119 | ); 120 | try 121 | { 122 | $res = $client->createSchedule($device['_id'], $module_id, $zones, $timetable, $scheduleName); 123 | $schedule_id = $res['schedule_id']; 124 | printMessageWithBorder("New test Schedule created"); 125 | } 126 | catch(Netatmo\Exceptions\NAClientException $ex) 127 | { 128 | handleError("An error occured while creating a new schedule: " . $ex->getMessage() . "\n", TRUE); 129 | } 130 | 131 | //Switch to our new schedule 132 | if(!is_null($schedule_id)) 133 | { 134 | try 135 | { 136 | $client->switchSchedule($device['_id'], $module_id, $schedule_id); 137 | } 138 | catch(Netatmo\Exceptions\NAClientException $ex) 139 | { 140 | handleError("An error occured while changing the device schedule: " . $ex->getMessage(). "\n", TRUE); 141 | } 142 | printMessageWithBorder("Schedule changed to testSchedule"); 143 | } 144 | 145 | //Let's set this thermostat to away mode 146 | try 147 | { 148 | $client->setToAwayMode($device['_id'], $module_id); 149 | printMessageWithBorder($device['station_name'] . " is now in Away Mode"); 150 | 151 | } 152 | catch(Netatmo\Exceptions\NAClientException $ex) 153 | { 154 | handleError("An error occured while setting the thermostat to away mode: ".$ex->getMessage()."\n"); 155 | } 156 | 157 | //Get daily measurements of the last 30 days 158 | $type = "temperature,max_temp,min_temp"; 159 | try 160 | { 161 | $measurements = $client->getMeasure($thermData['devices'][0]['_id'], $thermData['devices'][0]['modules'][0]['_id'], "1day", $type, time()-3600*24*30, time(), 30, FALSE, FALSE); 162 | printMeasure($measurements, $type, $device['place']['timezone'], "Daily Measurements of the last 30 days"); 163 | 164 | } 165 | catch(Netatmo\Exceptions\NAClientException $ex) 166 | { 167 | handleError("An error occured while retrieving measures: " . $ex->getMessage(). "\n"); 168 | } 169 | 170 | 171 | //Rename test schedule 172 | try 173 | { 174 | $client->renameSchedule($device['_id'], $module_id, $schedule_id, "To be deleted"); 175 | printMessageWithBorder("Schedule renamed"); 176 | } 177 | catch(Netatmo\Exceptions\NAClientException $ex) 178 | { 179 | handleError("An error occured while renaming schedule $schedule_id: " . $ex->getMessage() ."\n"); 180 | } 181 | 182 | //switch back to previous program 183 | if(!is_null($currentProgram)) 184 | { 185 | try 186 | { 187 | $client->switchSchedule($device['_id'], $module_id, $currentProgram); 188 | printMessageWithBorder("Switching back to the original schedule"); 189 | sleep(30); //wait for thermostat to reconnect so that the change will be effective and initial schedule will be set back 190 | } 191 | catch(Netatmo\Exceptions\NAClientException $ex) 192 | { 193 | handleError("An error occured while switching back to original schedule: ". $ex->getMessage() ."\n"); 194 | } 195 | } 196 | // let's remove test schedule 197 | try 198 | { 199 | $client->deleteSchedule($device['_id'], $module_id, $schedule_id); 200 | printMessageWithBorder("test Schedule deleted"); 201 | sleep(20); 202 | } 203 | catch(Netatmo\Exceptions\NAClientException $ex) 204 | { 205 | handleError("An error occured while removing schedule $schedule_id " . $ex->getMessage() ."\n"); 206 | } 207 | 208 | //let's change to a manual set point : 19°C for 10 min 209 | try 210 | { 211 | $client->setToManualMode($device["_id"], $module_id, 19, time() + 10 * 60); 212 | printMessageWithBorder("Manual setpoint set"); 213 | 214 | } 215 | catch(Netatmo\Exceptions\NAClientException $ex) 216 | { 217 | handleError("An error occured while setting a manual setpoint ". $ex->getMessage() . "\n"); 218 | } 219 | 220 | //Finally set back to the intial mode 221 | try 222 | { 223 | switch($initialMode) 224 | { 225 | case "away" : $client->setToAwayMode($device["_id"], $module_id, $initialEndtime); 226 | break; 227 | case "manual" : $client->setToManualMode($device["_id"], $module_id, $initialTemp, $initialEndtime); 228 | break; 229 | case "program": $client->setToProgramMode($device["_id"], $module_id); 230 | break; 231 | case "frost_guard": $client->setToFrostGuardMode($device["_id"], $module_id, $initialEndtime); 232 | break; 233 | case "off": $client->turnOff($device["_id"], $module_id); 234 | break; 235 | case "max": $client->setToMaxMode($device["_id"], $module_id, $initialEndtime); 236 | break; 237 | } 238 | printMessageWithBorder("Back to original mode: " . $initialMode); 239 | sleep(20); //wait for thermostat synchronization to make sure, it's back in its initial mode 240 | } 241 | catch(Netatmo\Exceptions\NAClientException $ex) 242 | { 243 | handleError("An error occured while setting back the initial mode: ". $ex->getMessage() . " \n"); 244 | } 245 | } 246 | ?> 247 | -------------------------------------------------------------------------------- /Examples/Utils.php: -------------------------------------------------------------------------------- 1 | setTimestamp($time); 28 | echo $date->format($format); 29 | } 30 | 31 | function printBorder($message) 32 | { 33 | $size = strlen($message); 34 | for($i = 0; $i < $size; $i++) 35 | echo("-"); 36 | echo("\n"); 37 | } 38 | 39 | function printMessageWithBorder($message) 40 | { 41 | $message = "- " . $message . " -"; 42 | printBorder($message); 43 | echo $message . "\n"; 44 | printBorder($message); 45 | } 46 | 47 | function printMeasure($measurements, $type, $tz, $title = NULL, $monthly = FALSE) 48 | { 49 | if(!empty($measurements)) 50 | { 51 | if(!empty($title)) 52 | printMessageWithBorder($title); 53 | 54 | if($monthly) 55 | $dateFormat = 'F: '; 56 | else $dateFormat = 'j F: '; 57 | //array of requested info type, needed to map result values to what they mean 58 | $keys = explode(",", $type); 59 | 60 | foreach($measurements as $timestamp => $values) 61 | { 62 | printTimeinTz($timestamp, $tz, $dateFormat); 63 | echo"\n"; 64 | foreach($values as $key => $val) 65 | { 66 | echo $keys[$key] . ": "; 67 | if($keys[$key] === "time_utc" || preg_match("/^date_.*/", $keys[$key])) 68 | echo printTimeInTz($val, $tz, "j F H:i"); 69 | else{ 70 | echo $val; 71 | printUnit($keys[$key]); 72 | } 73 | if(count($values)-1 === $key || $monthly) 74 | echo "\n"; 75 | else echo ", "; 76 | } 77 | } 78 | } 79 | } 80 | 81 | /** 82 | * function printing a weather station or modules basic information such as id, name, dashboard data, modules (if main device), type(if module) 83 | * 84 | */ 85 | function printWSBasicInfo($device) 86 | { 87 | if(isset($device['station_name'])) 88 | echo ("- ".$device['station_name']. " -\n"); 89 | else if($device['module_name']) 90 | echo ("- ".$device['module_name']. " -\n"); 91 | 92 | echo ("id: " . $device['_id']. "\n"); 93 | 94 | if(isset($device['type'])) 95 | { 96 | echo ("type: "); 97 | switch($device['type']) 98 | { 99 | // Outdoor Module 100 | case "NAModule1": echo ("Outdoor\n"); 101 | break; 102 | //Wind Sensor 103 | case "NAModule2": echo("Wind Sensor\n"); 104 | break; 105 | 106 | //Rain Gauge 107 | case "NAModule3": echo("Rain Gauge\n"); 108 | break; 109 | //Indoor Module 110 | case "NAModule4": echo("Indoor\n"); 111 | break; 112 | case "NAMain" : echo ("Main device \n"); 113 | break; 114 | } 115 | 116 | } 117 | 118 | if(isset($device['place']['timezone'])) 119 | $tz = $device['place']['timezone']; 120 | else $tz = 'GMT'; 121 | 122 | if(isset($device['dashboard_data'])) 123 | { 124 | echo ("Last data: \n"); 125 | foreach($device['dashboard_data'] as $key => $val) 126 | { 127 | if($key === 'time_utc' || preg_match("/^date_.*/", $key)) 128 | { 129 | echo $key .": "; 130 | printTimeInTz($val, $tz, 'j F H:i'); 131 | echo ("\n"); 132 | } 133 | else if(is_array($val)) 134 | { 135 | //do nothing : don't print historic 136 | } 137 | else { 138 | echo ($key .": " . $val); 139 | printUnit($key); 140 | echo "\n"; 141 | } 142 | } 143 | 144 | if(isset($device['modules'])) 145 | { 146 | echo (" \n\nModules: \n"); 147 | foreach($device['modules'] as $module) 148 | printWSBasicInfo($module); 149 | } 150 | } 151 | 152 | echo" ---------------------- \n"; 153 | } 154 | 155 | function printUnit($key) 156 | { 157 | $typeUnit = array('temp' => '°C', 'hum' => '%', 'noise' => 'db', 'strength' => 'km/h', 'angle' => '°', 'rain' => 'mm', 'pressure' => 'mbar', 'co2' => 'ppm'); 158 | foreach($typeUnit as $type => $unit) 159 | { 160 | if(preg_match("/$type.*$(?getName()) ? printMessageWithBorder($home->getName()) : printMessageWithBorder($home->getId()); 241 | echo ("id: ". $home->getId() ."\n"); 242 | 243 | $tz = $home->getTimezone(); 244 | $persons = $home->getPersons(); 245 | 246 | if(!empty($persons)) 247 | { 248 | printMessageWithBorder("Persons"); 249 | //print person list 250 | foreach($persons as $person) 251 | { 252 | printPersonInformation($person, $tz); 253 | } 254 | } 255 | 256 | $events = $home->getEvents(); 257 | if(!empty($events)) 258 | { 259 | printMessageWithBorder('Timeline of Events'); 260 | //print event list 261 | foreach($events as $event) 262 | { 263 | printEventInformation($event, $tz); 264 | } 265 | } 266 | 267 | $cameras = $home->getCameras(); 268 | if(!empty($cameras)) 269 | { 270 | printMessageWithBorder("Cameras"); 271 | foreach($cameras as $camera) 272 | { 273 | printCameraInformation($camera); 274 | } 275 | } 276 | } 277 | 278 | 279 | function printPersonInformation(Netatmo\Objects\NAPerson $person, $tz) 280 | { 281 | $person->isKnown() ? printMessageWithBorder($person->getPseudo()) : printMessageWithBorder("Inconnu"); 282 | echo("id: ". $person->getId(). "\n"); 283 | if($person->isAway()) 284 | echo("is away from home \n" ); 285 | else echo("is home \n"); 286 | 287 | echo ("Last seen on: "); 288 | printTimeInTz($person->getLastSeen(), $tz, "j F H:i"); 289 | echo ("\n"); 290 | } 291 | 292 | function printEventInformation(Netatmo\Objects\NAEvent $event, $tz) 293 | { 294 | printTimeInTz($event->getTime(), $tz, "j F H:i"); 295 | $message = removeHTMLTags($event->getMessage()); 296 | echo(": ".$message. "\n"); 297 | } 298 | 299 | function printCameraInformation(Netatmo\Objects\NACamera $camera) 300 | { 301 | !is_null($camera->getName()) ? printMessageWithBorder($camera->getName()) : printMessageWithBorder($camera->getId()); 302 | 303 | echo("id: ". $camera->getId() ."\n"); 304 | echo("Monitoring status: ". $camera->getVar(Netatmo\Common\NACameraInfo::CI_STATUS) ."\n"); 305 | echo("SD card status: " .$camera->getVar(Netatmo\Common\NACameraInfo::CI_SD_STATUS) . "\n"); 306 | echo ("Power status: ". $camera->getVar(Netatmo\Common\NACameraInfo::CI_ALIM_STATUS) ."\n"); 307 | 308 | if($camera->getGlobalStatus()) 309 | $globalStatus = "OK"; 310 | else $globalStatus = "NOK"; 311 | 312 | echo ("Global Status: ". $globalStatus ."\n"); 313 | 314 | } 315 | 316 | function removeHTMLTags($string) 317 | { 318 | return preg_replace("/<.*?>/", "", $string); 319 | } 320 | 321 | ?> 322 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Netatmo-API-PHP 2 | 3 | ##Updating to v2.x 4 | This release is a major update, and might break the compatibility with older versions. If you were using an older version of our SDK, you will have to stop using NAApiClient class and use either NAThermApiClient or NAWSApiClient instead. 5 | 6 | As a matter of fact, those are adding an additional abstraction layer which will make it easier for you to use : API call using "api" client method are now replaced with dedicated methods along with the parameters they expect for each product API. 7 | 8 | You also might need to change the include path of the SDK files as they are now stored in the "src" folder (API clients are stored in "src/Netatmo/Clients/" folder). 9 | 10 | ### Updating to v2.1.x 11 | This release introduced namespaces to avoid collisions with other packages, which is a breaking change as classes provided by the Netatmo SDK are no longer available in the global namespace. For instance, NAThermApiClient becomes Netatmo\Clients\NAThermApiClient. For more information, please see http://php.net/manual/en/language.namespaces.php. 12 | 13 | It means the use of Netatmo SDK classes in the global namespace is deprecated. It is still possible to use them so far, so that it won't break your existing code. However, we recommend to update your code as soon as possible to take into account those changes. 14 | 15 | It also introduced an autoloader respecting the PSR-4 standards, so you only need to include the src/Netatmo/autoload.php file and you're good to go. 16 | 17 | ## Install and Configure 18 | 19 | To install the sdk, extract the downloaded files to your project directory. Then, just include the src/Netatmo/autoload.php file and instantiate a new NAWSApiClient (or NAThermApiClient, or NAWelcomeApiClient) object with your application client_id and client_secret: 20 | 21 | 22 | 23 | $config = array(); 24 | $config['client_id'] = 'YOUR_APP_ID'; 25 | $config['client_secret'] = 'YOUR_APP_SECRET'; 26 | $config['scope'] = 'read_station read_thermostat write_thermostat'; 27 | $client = new Netatmo\Clients\NAApiClient($config); 28 | 29 | ## Authenticate & Authorize 30 | 31 | The SDK provides helper-methods to authenticate and authorize your app to access a user's data 32 | 33 | ### Retrieving an access token through a user credential grant 34 | 35 | $username = 'YOUR_USERNAME'; 36 | $pwd = 'YOUR_PWD'; 37 | $client->setVariable('username', $username); 38 | $client->setVariable('password', $pwd); 39 | try 40 | { 41 | $tokens = $client->getAccessToken(); 42 | $refresh_token = $tokens['refresh_token']; 43 | $access_token = $tokens['access_token']; 44 | } 45 | catch(Netatmo\Exceptions\NAClientException $ex) 46 | { 47 | echo "An error occcured while trying to retrive your tokens \n"; 48 | } 49 | 50 | Please note that you should NOT store users' credentials (which is not secure) and repeatedly perform user credentials authentication as your application's users will receive emails to warn them someone is using their credentials to connect to their account. Instead, you should use the refresh token sent back to you at the end of the authentication process to get a new access token each time it has expired. For more information, about access and refresh tokens, please refer to OAuth2 protocol documentation. 51 | 52 | ### Retrieving an access token through Authorization code grant 53 | 54 | //test if "code" is provided in get parameters (which would mean that user has already accepted the app and has been redirected here) 55 | if(isset($_GET['code'])) 56 | { 57 | try 58 | { 59 | $tokens = $client->getAccessToken(); 60 | $refresh_token = $tokens['refresh_token']; 61 | $access_token = $tokens['access_token']; 62 | } 63 | catch(Netatmo\Exceptions\NAClientException $ex) 64 | { 65 | echo " An error occured while trying to retrieve your tokens \n"; 66 | } 67 | } 68 | else if(isset($_GET['error'])) 69 | { 70 | if($_GET['error'] === 'access_denied') 71 | echo "You refused that this application access your Netatmo Data"; 72 | else echo "An error occured \n"; 73 | } 74 | else 75 | { 76 | //redirect to Netatmo Authorize URL 77 | $redirect_url = $client->getAuthorizeUrl(); 78 | header("HTTP/1.1 ". OAUTH2_HTTP_FOUND); 79 | header("Location: ". $redirect_url); 80 | die(); 81 | } 82 | 83 | ## Use API methods 84 | 85 | ### Netatmo Weather Station API client implementation - PHP SDK 86 | 87 | If you need further information about how the Netatmo Weather Station works, please see https://dev.netatmo.com/resources/technical/reference/weather 88 | 89 | #### Retrieving Netatmo Weather Station's data 90 | 91 | Once an access token has been retrieved, it can be used to retrieved user's devices data 92 | 93 | 94 | $data = $client->getData(NULL, TRUE); 95 | foreach($data['devices'] as $device) 96 | { 97 | echo $device['station_name'] . "\n"; 98 | print_r($device['dashboard_data']); 99 | foreach($device['modules'] as $module) 100 | { 101 | echo $module['module_name']; 102 | print_r($module['dashboard_data']); 103 | } 104 | } 105 | 106 | $data will be an array containing a list of devices along with their modules and their last data stored: First the devices belonging to the user, then user's friends devices, and finally the user's favorites devices. 107 | 108 | To retrieve a specific device's data, you have to provide its id: 109 | 110 | $data = $client->getData('YOUR_DEVICE_ID'); 111 | 112 | If it is one of the user's favorite device, you'll have to set the "get_favorites" parameter to TRUE in order to retrieve it: 113 | 114 | $data = $client->getData('YOUR_FAV_DEVICE_ID', TRUE); 115 | 116 | #### Retrieving Netatmo Weather Station's measurements 117 | 118 | You can also retrieve specific measurements of a given period for a given device: 119 | 120 | $device = $data['devices'][0]; 121 | $module = $device['modules'][0]; 122 | $scale = "1day"; 123 | $type = $module['data_type']; 124 | $date_begin = time() -24*3600*7; //1 week ago 125 | $date_end = time() //now 126 | $optimized = FALSE; 127 | $real_time = FALSE; 128 | $measurements = $client->getMeasure($device['_id'], $module_id, $scale, $type, $date_begin, $date_end, $optimized, $real_time); 129 | 130 | Please note that not giving a module_id will retrieve main device measurements. 131 | The scale parameter corresponds to the step between two measures, the type depends on the device or module data_type and the scale. For more details regarding its allowed values, please take a glance at https://dev.netatmo.com/resources/technical/reference/common/getmeasure. 132 | Set the optimized flag to true, if you need the json response to be lighter but a little trickier to parse : you'll only have the beginning timestamp provided, and you'll have to compute the others using the scale. 133 | Finally, the real_time flag enables to remove the timestamp offset in scales higher than 'max'. As a matter of fact, since data are aggregated timestamps are offset by + scale/2 by default. 134 | 135 | ### Netatmo Thermostat API client implementation - PHP SDK 136 | 137 | If you need further information about how the Netatmo Thermostat works, please see https://dev.netatmo.com/resources/technical/reference/energy 138 | 139 | #### Retrieving Netatmo Thermostat's data 140 | 141 | The Thermostat API client just works the same way as the Weather Station API Client: 142 | 143 | $client = new Netatmo\Clients\NAThermApiClient($config); 144 | 145 | It also has its own method to retrieve user's thermostats data which returns an array of devices along with their data 146 | 147 | $data = $client->getData(); 148 | 149 | In order to retrieve a specific thermostat, you need to provide its id 150 | 151 | $data = $client->getData($device_id); 152 | 153 | #### Retrieving Netatmo Thermostat's measurements 154 | 155 | Thermostat also has its getMeasure method, which works in the exact same way as the weather station one, in order to retrieve specific data of a given period: 156 | 157 | $device = $data['devices'][0]; 158 | $module = $device['modules'][0]; 159 | $scale = "1day"; 160 | $type = "Temperature,max_temp,min_temp,date_max_temp"; 161 | $date_begin = time() -24*3600*7; //1 week ago 162 | $date_end = time(); //now 163 | $limit = NULL; 164 | $optimized = FALSE; 165 | $real_time = FALSE; 166 | $measurements = $client->getMeasure($device['_id'], $module_id, $scale, $type, $date_begin, $date_end, $limit, $optimized, $real_time); 167 | 168 | 169 | #### Sending orders to the Netatmo Thermostat 170 | 171 | You can easily change the thermostat setpoint: 172 | 173 | try{ 174 | $client->setToAwayMode($device['_id'], $module['_id']); 175 | $client->setToFrostGuardMode($device['_id'], $module['_id']); 176 | $client->setToProgramMode($device['_id'], $module['_id']); 177 | } 178 | catch(Netatmo\Exceptions\NAClientException $ex) 179 | { 180 | "An error occured"; 181 | } 182 | 183 | And you can also give time-limited orders: 184 | 185 | $endtime = time() +2*3600; 186 | $client->setToAwayMode($device['_id'], $module['_id'], $endtime); // away for 2 hours 187 | $client->setToFrostGuardMode($device['_id'], $module['_id'], $endtime); 188 | 189 | Some orders require a time-limit: 190 | 191 | $endtime = time() + 2*3600; 192 | $client->setToMaxMode($device['_id'], $module['_id'], $endtime); 193 | 194 | Finally, you have the ability to just set a Manual temperature setpoint to your thermostat: 195 | 196 | $endtime = time() + 2*3600; 197 | $temp = 21.5; 198 | $client->setToManualMode($device['_id'], $module['_id'], $temp, $endtime); 199 | 200 | You also have the possibility to turn off your thermostat: 201 | 202 | $client->turnOff($device['_id'], $module['_id']); 203 | 204 | (To turn it back on, set another setpoint ex : order the thermostat to follow its schedule) 205 | 206 | #### Dealing with Netatmo Thermostat's weekly schedules 207 | 208 | The Netatmo Thermostat SDK also enables you to deal with the thermostat schedule: 209 | 210 | You can create a new schedule: 211 | 212 | $res = $client->createSchedule($device['_id'], $module['_id'], $zones, $timetable, 'new schedule'); 213 | 214 | You'll find the id of the created schedule in the return value. 215 | 216 | $schedule_id = $res['schedule_id']; 217 | 218 | Then switch the thermostat current schedule to another existing schedule: 219 | 220 | $client->switchSchedule($device['_id'], $module['_id'], $schedule_id); 221 | 222 | And modify your current schedule: 223 | 224 | $client->syncSchedule($device['_id'], $module['_id'], $zones, $timetable); 225 | 226 | Then you can rename a schedule: 227 | 228 | $client->renameSchedule($device['_id'], $module['_id'], $schedule_id, 'new Name'); 229 | 230 | Finally, you can also delete a schedule: 231 | 232 | $client->deleteSchedule($device['_id'], $module['_id'], $schedule_id); 233 | 234 | ### Netatmo Welcome API client implementation - PHP SDK 235 | 236 | If you need more information regarding how the Netatmo Welcome works, please see https://dev.netatmo.com/resources/technical/reference/security 237 | 238 | ### Retrieving Netatmo Welcome data 239 | 240 | The Netatmo Welcome SDK works in a slightly different way than Netatmo Weather Stations and Netatmo Thermostat SDK do. 241 | First, instantiate the client: 242 | 243 | $client = new Netatmo\Clients\NAWelcomeApiClient($config); 244 | 245 | The Netatmo Welcome SDK enables you to retrieve the data (persons, cameras, events) of every home belonging to an user: 246 | 247 | $res = $client->getData(): 248 | 249 | If you only want to retrieve information about a specific user's home, just specify its id: 250 | 251 | $res = client->getData($home_id); 252 | 253 | Please note that you can limit the number of events requested per home, using the $size parameter (default value is 30): 254 | 255 | $res = client->getData(NULL, 10); // will retrieve every home belonging to the user and only the 10 last associated events 256 | 257 | The difference with Weather Station and Thermostats SDK is that the client returns NAResponseHandler objects. Those enable you to either get the raw data returned by the Netatmo API as PHP arrays or to get it as array of objects (NAHome or NAEvent): 258 | 259 | $array = $res->getDecodedBody(); 260 | $objects = $res->getData(); 261 | 262 | 263 | ### Retrieving specific events from a given home 264 | 265 | In addition of retrieving all information for a home, you can also get only events you're interested in. In that purpose, you can use the three following methods: 266 | 267 | - First, you can retrieve every event until the last one of a specific person 268 | 269 | $res = $client->getLastEventOf($home_id, $person_id); 270 | $events = $res->getData(); 271 | 272 | This function also accepts an offset parameter, which gives the abitility to retrieve a certain number of events older than the requested one. Default value is 0. 273 | 274 | $res = $client->getLastEventOf($home_id, $event_id, 5); 275 | $events = $res->getData(); 276 | 277 | - Then, you also have the ability to retrieve every events until a specific one 278 | 279 | $res = $client->getEventsUntil($home_id, $event_id); 280 | $events = $res->getData(); 281 | 282 | - Finally, you can also get events that happened before a specific one. In that purpose, you should specify how many events you want to retrieve using the $size parameter. Default value is 30. 283 | 284 | $res = $client->getNextEvents($home_id, $event_id, 10); // get the 10 events that happened right before event_id 285 | $events = $res->getData(); 286 | 287 | ### Retrieving a picture linked to an event or a person face 288 | 289 | After retrieving event's or person's information using one of the previous methods, you might want to be able to get the picture corresponding to an event snapshot or a person face. In order to do so, you will need the snapshot or face information of that event if you're dealing with raw data in PHP array: 290 | 291 | $img = $client->getCameraPicture($event['snapshot']); 292 | 293 | If you are working with the objects provided by the SDK, just call the object getter on the picture, to retrieve its URL: 294 | 295 | $pictureURL = $event->getSnapshot(); 296 | $faceURL = $person->getFace(); 297 | 298 | ### Quick Example 299 | 300 | $scope = Netatmo\Common\NAScopes::SCOPE_READ_CAMERA; 301 | 302 | //Client configuration from Config.php 303 | $conf = array('client_id' => $client_id, 304 | 'client_secret' => $client_secret, 305 | 'username' => $test_username, 306 | 'password' => $test_password, 307 | 'scope' => $scope); 308 | $client = new Netatmo\Clients\NAWelcomeApiClient($conf); 309 | 310 | //Retrieve access token 311 | try 312 | { 313 | $tokens = $client->getAccessToken(); 314 | } 315 | catch(Netatmo\Exceptions\NAClientException $ex) 316 | { 317 | echo "An error happened while trying to retrieve your tokens \n" . $ex->getMessage() . "\n"; 318 | } 319 | 320 | //Try to retrieve user's Welcome information 321 | try 322 | { 323 | //retrieve every user's homes and their last 10 events 324 | $response = $client->getData(NULL, 10); 325 | $homes = $response->getData(); 326 | } 327 | catch(Netatmo\Exceptions\NASDKException $ex) 328 | { 329 | echo "An error happened while trying to retrieve home information: ".$ex->getMessage() ."\n"; 330 | } 331 | 332 | //print homes names 333 | foreach($homes as $home) 334 | { 335 | echo $home->getName() . "\n"; 336 | } 337 | 338 | ### Webhooks for Netatmo Welcome 339 | 340 | Your app can subscribe to Webhooks notification for Netatmo Welcome events. There's two differente way to sign up for this: either by filling in the Webhook URL in your application settings on our developer plaftorm (each user accepting the app will be concerned by webhooks notifications) or you can use the API to manage yourself webhooks registration for users: 341 | 342 | $client->subscribeToWebhook($webhook_url); 343 | 344 | And for unsubscribing webhooks for an user: 345 | 346 | $client->dropWebhook(); 347 | 348 | ## Error handling 349 | 350 | ###SDK Errors 351 | The SDK throws NASDKException when an error happens. It encapsulates Networking errors, API errors and SDK objects error for Netatmo Welcome SDK. 352 | 353 | try{ 354 | $client->getData(); 355 | } 356 | catch(Netatmo\Exceptions\NASDKException $ex) 357 | { 358 | //Handle error here 359 | echo $ex->getMessage(); 360 | } 361 | 362 | 363 | ### API Client errors 364 | The client throws NAClientException if it encounters an error dealing with the API or Networking protocol: 365 | 366 | try{ 367 | $client->getData(); 368 | } 369 | catch(Netatmo\Exceptions\NAClientException $ex) 370 | { 371 | //Handle error here 372 | echo $ex->getMessage(); 373 | } 374 | 375 | ## Details 376 | Please read https://dev.netatmo.com/resources/technical/reference for further information. 377 | -------------------------------------------------------------------------------- /src/Netatmo/Clients/NAApiClient.php: -------------------------------------------------------------------------------- 1 | . 24 | */ 25 | class NAApiClient 26 | { 27 | /** 28 | * Array of persistent variables stored. 29 | */ 30 | protected $conf = array(); 31 | protected $refresh_token; 32 | protected $access_token; 33 | protected $expires_at; 34 | /** 35 | * Returns a persistent variable. 36 | * 37 | * To avoid problems, always use lower case for persistent variable names. 38 | * 39 | * @param $name 40 | * The name of the variable to return. 41 | * @param $default 42 | * The default value to use if this variable has never been set. 43 | * 44 | * @return 45 | * The value of the variable. 46 | */ 47 | public function getVariable($name, $default = NULL) 48 | { 49 | return isset($this->conf[$name]) ? $this->conf[$name] : $default; 50 | } 51 | /** 52 | * Returns the current refresh token 53 | */ 54 | public function getRefreshToken() 55 | { 56 | return $this->refresh_token; 57 | } 58 | 59 | /** 60 | * Sets a persistent variable. 61 | * 62 | * To avoid problems, always use lower case for persistent variable names. 63 | * 64 | * @param $name 65 | * The name of the variable to set. 66 | * @param $value 67 | * The value to set. 68 | */ 69 | public function setVariable($name, $value) 70 | { 71 | $this->conf[$name] = $value; 72 | return $this; 73 | } 74 | 75 | private function updateSession() 76 | { 77 | $cb = $this->getVariable("func_cb"); 78 | $object = $this->getVariable("object_cb"); 79 | if($object && $cb) 80 | { 81 | if(method_exists($object, $cb)) 82 | { 83 | call_user_func_array(array($object, $cb), array(array("access_token"=> $this->access_token, "refresh_token" => $this->refresh_token))); 84 | } 85 | } 86 | else if($cb && is_callable($cb)) 87 | { 88 | call_user_func_array($cb, array(array("access_token" => $this->access_token, "refresh_token" => $this->refresh_token))); 89 | } 90 | } 91 | 92 | private function setTokens($value) 93 | { 94 | if(isset($value["access_token"])) 95 | { 96 | $this->access_token = $value["access_token"]; 97 | $update = true; 98 | } 99 | if(isset($value["refresh_token"])) 100 | { 101 | $this->refresh_token = $value["refresh_token"]; 102 | $update = true; 103 | } 104 | if(isset($value["expires_in"])) 105 | { 106 | $this->expires_at = time() + $value["expires_in"] - 30; 107 | } 108 | if(isset($update)) $this->updateSession(); 109 | } 110 | 111 | /** 112 | * Set token stored by application (in session generally) into this object 113 | **/ 114 | public function setTokensFromStore($value) 115 | { 116 | if(isset($value["access_token"])) 117 | $this->access_token = $value["access_token"]; 118 | if(isset($value["refresh_token"])) 119 | $this->refresh_token = $value["refresh_token"]; 120 | } 121 | public function unsetTokens() 122 | { 123 | $this->access_token = null; 124 | $this->refresh_token = null; 125 | $this->expires_at = null; 126 | } 127 | /** 128 | * Initialize a NA OAuth2.0 Client. 129 | * 130 | * @param $config 131 | * An associative array as below: 132 | * - code: (optional) The authorization code. 133 | * - username: (optional) The username. 134 | * - password: (optional) The password. 135 | * - client_id: (optional) The application ID. 136 | * - client_secret: (optional) The application secret. 137 | * - refresh_token: (optional) A stored refresh_token to use 138 | * - access_token: (optional) A stored access_token to use 139 | * - object_cb : (optionale) An object for which func_cb method will be applied if object_cb exists 140 | * - func_cb : (optional) A method called back to store tokens in its context (session for instance) 141 | */ 142 | public function __construct($config = array()) 143 | { 144 | // If tokens are provided let's store it 145 | if(isset($config["access_token"])) 146 | { 147 | $this->access_token = $config["access_token"]; 148 | unset($access_token); 149 | } 150 | if(isset($config["refresh_token"])) 151 | { 152 | $this->refresh_token = $config["refresh_token"]; 153 | } 154 | // We must set uri first. 155 | $uri = array("base_uri" => BACKEND_BASE_URI, "services_uri" => BACKEND_SERVICES_URI, "access_token_uri" => BACKEND_ACCESS_TOKEN_URI, "authorize_uri" => BACKEND_AUTHORIZE_URI); 156 | foreach($uri as $key => $val) 157 | { 158 | if(isset($config[$key])) 159 | { 160 | $this->setVariable($key, $config[$key]); 161 | unset($config[$key]); 162 | } 163 | else 164 | { 165 | $this->setVariable($key, $val); 166 | } 167 | } 168 | 169 | if(isset($config['scope']) && is_array($config['scope'])) 170 | { 171 | foreach($config['scope'] as $scope) 172 | { 173 | trim($scope); 174 | } 175 | 176 | $scope = implode(' ', $config['scope']); 177 | $this->setVariable('scope', $scope); 178 | unset($config['scope']); 179 | } 180 | 181 | // Other else configurations. 182 | foreach ($config as $name => $value) 183 | { 184 | $this->setVariable($name, $value); 185 | } 186 | 187 | if($this->getVariable("code") == null && isset($_GET["code"])) 188 | { 189 | $this->setVariable("code", $_GET["code"]); 190 | } 191 | } 192 | 193 | /** 194 | * Default options for cURL. 195 | */ 196 | public static $CURL_OPTS = array( 197 | CURLOPT_CONNECTTIMEOUT => 10, 198 | CURLOPT_RETURNTRANSFER => TRUE, 199 | CURLOPT_HEADER => TRUE, 200 | CURLOPT_TIMEOUT => 60, 201 | CURLOPT_USERAGENT => 'netatmoclient', 202 | CURLOPT_SSL_VERIFYPEER => TRUE, 203 | CURLOPT_HTTPHEADER => array("Accept: application/json"), 204 | ); 205 | 206 | 207 | /** 208 | * Makes an HTTP request. 209 | * 210 | * This method can be overriden by subclasses if developers want to do 211 | * fancier things or use something other than cURL to make the request. 212 | * 213 | * @param $path 214 | * The target path, relative to base_path/service_uri or an absolute URI. 215 | * @param $method 216 | * (optional) The HTTP method (default 'GET'). 217 | * @param $params 218 | * (optional The GET/POST parameters. 219 | * @param $ch 220 | * (optional) An initialized curl handle 221 | * 222 | * @return 223 | * The json_decoded result or NAClientException if pb happend 224 | */ 225 | public function makeRequest($path, $method = 'GET', $params = array()) 226 | { 227 | $ch = curl_init(); 228 | $opts = self::$CURL_OPTS; 229 | if ($params) 230 | { 231 | if(isset($params['access_token'])) 232 | { 233 | $opts[CURLOPT_HTTPHEADER][] = 'Authorization: Bearer ' . $params['access_token']; 234 | unset($params['access_token']); 235 | } 236 | 237 | switch ($method) 238 | { 239 | case 'GET': 240 | $path .= '?' . http_build_query($params, NULL, '&'); 241 | break; 242 | // Method override as we always do a POST. 243 | default: 244 | if ($this->getVariable('file_upload_support')) 245 | { 246 | $opts[CURLOPT_POSTFIELDS] = $params; 247 | } 248 | else 249 | { 250 | $opts[CURLOPT_POSTFIELDS] = http_build_query($params, NULL, '&'); 251 | } 252 | break; 253 | } 254 | } 255 | $opts[CURLOPT_URL] = $path; 256 | // Disable the 'Expect: 100-continue' behaviour. This causes CURL to wait 257 | // for 2 seconds if the server does not support this header. 258 | if (isset($opts[CURLOPT_HTTPHEADER])) 259 | { 260 | $existing_headers = $opts[CURLOPT_HTTPHEADER]; 261 | $existing_headers[] = 'Expect:'; 262 | $ip = $this->getVariable("ip"); 263 | if($ip) 264 | $existing_headers[] = 'CLIENT_IP: '.$ip; 265 | $opts[CURLOPT_HTTPHEADER] = $existing_headers; 266 | } 267 | else 268 | { 269 | $opts[CURLOPT_HTTPHEADER] = array('Expect:'); 270 | } 271 | curl_setopt_array($ch, $opts); 272 | $result = curl_exec($ch); 273 | 274 | 275 | $errno = curl_errno($ch); 276 | // CURLE_SSL_CACERT || CURLE_SSL_CACERT_BADFILE 277 | if ($errno == 60 || $errno == 77) 278 | { 279 | echo "WARNING ! SSL_VERIFICATION has been disabled since ssl error retrieved. Please check your certificate http://curl.haxx.se/docs/sslcerts.html\n"; 280 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 281 | $result = curl_exec($ch); 282 | } 283 | 284 | if ($result === FALSE) 285 | { 286 | $e = new NACurlErrorType(curl_errno($ch), curl_error($ch)); 287 | curl_close($ch); 288 | throw $e; 289 | } 290 | curl_close($ch); 291 | 292 | // Split the HTTP response into header and body. 293 | list($headers, $body) = explode("\r\n\r\n", $result); 294 | $headers = explode("\r\n", $headers); 295 | //Only 2XX response are considered as a success 296 | if(strpos($headers[0], 'HTTP/2') !== FALSE) 297 | { 298 | $decode = json_decode($body, TRUE); 299 | if(!$decode) 300 | { 301 | if (preg_match('/^HTTP\/2 ([0-9]{3,3}) (.*)$/', $headers[0], $matches)) 302 | { 303 | throw new NAJsonErrorType($matches[1], $matches[2]); 304 | } 305 | else throw new NAJsonErrorType(200, "OK"); 306 | } 307 | return $decode; 308 | } 309 | else 310 | { 311 | if (!preg_match('/^HTTP\/2 ([0-9]{3,3}) (.*)$/', $headers[0], $matches)) 312 | { 313 | $matches = array("", 400, "bad request"); 314 | } 315 | $decode = json_decode($body, TRUE); 316 | if(!$decode) 317 | { 318 | throw new NAApiErrorType($matches[1], $matches[2], null); 319 | } 320 | 321 | throw new NAApiErrorType($matches[1], $matches[2], $decode); 322 | } 323 | } 324 | 325 | /** 326 | * Retrieve an access token following the best grant to recover it (order id : code, refresh_token, password) 327 | * 328 | * @return 329 | * A valid array containing at least an access_token as an index 330 | * @throw 331 | * A NAClientException if unable to retrieve an access_token 332 | */ 333 | public function getAccessToken() 334 | { 335 | //find best way to retrieve access_token 336 | if($this->access_token) 337 | { 338 | if(!is_null($this->expires_at) && $this->expires_at < time()) // access_token expired. 339 | { 340 | if($this->refresh_token) 341 | { 342 | return $this->getAccessTokenFromRefreshToken($this->refresh_token);//exception will be thrown otherwise 343 | } 344 | else 345 | { 346 | throw new NAInternalErrorType("Access token expired"); 347 | } 348 | } 349 | return array("access_token" => $this->access_token); 350 | } 351 | if($this->getVariable('code'))// grant_type == authorization_code. 352 | { 353 | return $this->getAccessTokenFromAuthorizationCode($this->getVariable('code')); 354 | } 355 | else if($this->refresh_token)// grant_type == refresh_token 356 | { 357 | return $this->getAccessTokenFromRefreshToken(); 358 | } 359 | else if($this->getVariable('username') && $this->getVariable('password')) //grant_type == password 360 | { 361 | return $this->getAccessTokenFromPassword($this->getVariable('username'), $this->getVariable('password')); 362 | } 363 | else throw new NAInternalErrorType("No access token stored"); 364 | } 365 | 366 | 367 | /** 368 | * Get url to redirect to oauth2.0 netatmo authorize endpoint 369 | * This is the url where app server needing netatmo access need to route their user (via redirect) 370 | * 371 | * 372 | * @param scope 373 | * scope used here 374 | * @param state 375 | * state returned in redirect_uri 376 | */ 377 | public function getAuthorizeUrl($state = null) 378 | { 379 | $redirect_uri = $this->getRedirectUri(); 380 | if($state == null) 381 | { 382 | $state = rand(); 383 | } 384 | $scope = $this->getVariable('scope'); 385 | $params = array("scope" => $scope, "state" => $state, "client_id" => $this->getVariable("client_id"), "client_secret" => $this->getVariable("client_secret"), "response_type" => "code", "redirect_uri" => $redirect_uri); 386 | return $this->getUri($this->getVariable("authorize_uri"), $params); 387 | } 388 | 389 | /** 390 | * Get access token from OAuth2.0 token endpoint with authorization code. 391 | * 392 | * This function will only be activated if both access token URI, client 393 | * identifier and client secret are setup correctly. 394 | * 395 | * @param $code 396 | * Authorization code issued by authorization server's authorization 397 | * endpoint. 398 | * 399 | * @return 400 | * A valid OAuth2.0 JSON decoded access token in associative array 401 | * @thrown 402 | * A NAClientException if unable to retrieve an access_token 403 | */ 404 | private function getAccessTokenFromAuthorizationCode($code) 405 | { 406 | $redirect_uri = $this->getRedirectUri(); 407 | $scope = $this->getVariable('scope'); 408 | if($this->getVariable('access_token_uri') && ($client_id = $this->getVariable('client_id')) != NULL && ($client_secret = $this->getVariable('client_secret')) != NULL && $redirect_uri != NULL) 409 | { 410 | $ret = $this->makeRequest($this->getVariable('access_token_uri'), 411 | 'POST', 412 | array( 413 | 'grant_type' => 'authorization_code', 414 | 'client_id' => $client_id, 415 | 'client_secret' => $client_secret, 416 | 'code' => $code, 417 | 'redirect_uri' => $redirect_uri, 418 | 'scope' => $scope, 419 | ) 420 | ); 421 | $this->setTokens($ret); 422 | return $ret; 423 | } 424 | else 425 | throw new NAInternalErrorType("missing args for getting authorization code grant"); 426 | } 427 | 428 | /** 429 | * Get access token from OAuth2.0 token endpoint with basic user 430 | * credentials. 431 | * 432 | * This function will only be activated if both username and password 433 | * are setup correctly. 434 | * 435 | * @param $username 436 | * Username to be check with. 437 | * @param $password 438 | * Password to be check with. 439 | * 440 | * @return 441 | * A valid OAuth2.0 JSON decoded access token in associative array 442 | * @thrown 443 | * A NAClientException if unable to retrieve an access_token 444 | */ 445 | private function getAccessTokenFromPassword($username, $password) 446 | { 447 | $scope = $this->getVariable('scope'); 448 | if ($this->getVariable('access_token_uri') && ($client_id = $this->getVariable('client_id')) != NULL && ($client_secret = $this->getVariable('client_secret')) != NULL) 449 | { 450 | $ret = $this->makeRequest( 451 | $this->getVariable('access_token_uri'), 452 | 'POST', 453 | array( 454 | 'grant_type' => 'password', 455 | 'client_id' => $client_id, 456 | 'client_secret' => $client_secret, 457 | 'username' => $username, 458 | 'password' => $password, 459 | 'scope' => $scope, 460 | ) 461 | ); 462 | $this->setTokens($ret); 463 | return $ret; 464 | } 465 | else 466 | throw new NAInternalErrorType("missing args for getting password grant"); 467 | } 468 | 469 | /** 470 | * Get access token from OAuth2.0 token endpoint with basic user 471 | * credentials. 472 | * 473 | * This function will only be activated if both username and password 474 | * are setup correctly. 475 | * 476 | * @param $username 477 | * Username to be check with. 478 | * @param $password 479 | * Password to be check with. 480 | * 481 | * @return 482 | * A valid OAuth2.0 JSON decoded access token in associative array 483 | * @thrown 484 | * A NAClientException if unable to retrieve an access_token 485 | */ 486 | private function getAccessTokenFromRefreshToken() 487 | { 488 | if ($this->getVariable('access_token_uri') && ($client_id = $this->getVariable('client_id')) != NULL && ($client_secret = $this->getVariable('client_secret')) != NULL && ($refresh_token = $this->refresh_token) != NULL) 489 | { 490 | if($this->getVariable('scope') != null) 491 | { 492 | $ret = $this->makeRequest( 493 | $this->getVariable('access_token_uri'), 494 | 'POST', 495 | array( 496 | 'grant_type' => 'refresh_token', 497 | 'client_id' => $this->getVariable('client_id'), 498 | 'client_secret' => $this->getVariable('client_secret'), 499 | 'refresh_token' => $refresh_token, 500 | 'scope' => $this->getVariable('scope'), 501 | ) 502 | ); 503 | } 504 | else 505 | { 506 | $ret = $this->makeRequest( 507 | $this->getVariable('access_token_uri'), 508 | 'POST', 509 | array( 510 | 'grant_type' => 'refresh_token', 511 | 'client_id' => $this->getVariable('client_id'), 512 | 'client_secret' => $this->getVariable('client_secret'), 513 | 'refresh_token' => $refresh_token, 514 | ) 515 | ); 516 | } 517 | $this->setTokens($ret); 518 | return $ret; 519 | } 520 | else 521 | throw new NAInternalErrorType("missing args for getting refresh token grant"); 522 | } 523 | 524 | /** 525 | * Make an OAuth2.0 Request. 526 | * 527 | * Automatically append "access_token" in query parameters 528 | * 529 | * @param $path 530 | * The target path, relative to base_path/service_uri 531 | * @param $method 532 | * (optional) The HTTP method (default 'GET'). 533 | * @param $params 534 | * (optional The GET/POST parameters. 535 | * 536 | * @return 537 | * The JSON decoded response object. 538 | * 539 | * @throws OAuth2Exception 540 | */ 541 | protected function makeOAuth2Request($path, $method = 'GET', $params = array(), $reget_token = true) 542 | { 543 | try 544 | { 545 | $res = $this->getAccessToken(); 546 | } 547 | catch(NAApiErrorType $ex) 548 | { 549 | throw new NANotLoggedErrorType($ex->getCode(), $ex->getMessage()); 550 | } 551 | $params["access_token"] = $res["access_token"]; 552 | try 553 | { 554 | $res = $this->makeRequest($path, $method, $params); 555 | return $res; 556 | } 557 | catch(NAApiErrorType $ex) 558 | { 559 | if($reget_token == true) 560 | { 561 | switch($ex->getCode()) 562 | { 563 | case NARestErrorCode::INVALID_ACCESS_TOKEN: 564 | case NARestErrorCode::ACCESS_TOKEN_EXPIRED: 565 | //Ok token has expired let's retry once 566 | if($this->refresh_token) 567 | { 568 | try 569 | { 570 | $this->getAccessTokenFromRefreshToken();//exception will be thrown otherwise 571 | } 572 | catch(Exception $ex2) 573 | { 574 | //Invalid refresh token TODO: Throw a special exception 575 | throw $ex; 576 | } 577 | } 578 | else throw $ex; 579 | 580 | return $this->makeOAuth2Request($path, $method, $params, false); 581 | break; 582 | default: 583 | throw $ex; 584 | } 585 | } 586 | else throw $ex; 587 | } 588 | return $res; 589 | } 590 | /** 591 | * Make an API call. 592 | * 593 | * Support both OAuth2.0 or normal GET/POST API call, with relative 594 | * or absolute URI. 595 | * 596 | * If no valid OAuth2.0 access token found in session object, this function 597 | * will automatically switch as normal remote API call without "access_token" 598 | * parameter. 599 | * 600 | * Assume server reply in JSON object and always decode during return. If 601 | * you hope to issue a raw query, please use makeRequest(). 602 | * 603 | * @param $path 604 | * The target path, relative to base_path/service_uri or an absolute URI. 605 | * @param $method 606 | * (optional) The HTTP method (default 'GET'). 607 | * @param $params 608 | * (optional The GET/POST parameters. 609 | * 610 | * @return 611 | * The JSON decoded body response object. 612 | * 613 | * @throws NAClientException 614 | */ 615 | public function api($path, $method = 'GET', $params = array(), $secure = false) 616 | { 617 | if (is_array($method) && empty($params)) 618 | { 619 | $params = $method; 620 | $method = 'GET'; 621 | } 622 | 623 | // json_encode all params values that are not strings. 624 | foreach ($params as $key => $value) 625 | { 626 | if (!is_string($value)) 627 | { 628 | $params[$key] = json_encode($value); 629 | } 630 | } 631 | $res = $this->makeOAuth2Request($this->getUri($path, array(), $secure), $method, $params); 632 | if(isset($res["body"])) return $res["body"]; 633 | else return $res; 634 | } 635 | 636 | /** 637 | * Make a REST call to a Netatmo server that do not need access_token 638 | * 639 | * @param $path 640 | * The target path, relative to base_path/service_uri or an absolute URI. 641 | * @param $method 642 | * (optional) The HTTP method (default 'GET'). 643 | * @param $params 644 | * (optional The GET/POST parameters. 645 | * 646 | * @return 647 | * The JSON decoded response object. 648 | * 649 | * @throws NAClientException 650 | */ 651 | public function noTokenApi($path, $method = 'GET', $params = array()) 652 | { 653 | if (is_array($method) && empty($params)) 654 | { 655 | $params = $method; 656 | $method = 'GET'; 657 | } 658 | 659 | // json_encode all params values that are not strings. 660 | foreach ($params as $key => $value) 661 | { 662 | if (!is_string($value)) 663 | { 664 | $params[$key] = json_encode($value); 665 | } 666 | } 667 | 668 | return $this->makeRequest($path, $method, $params); 669 | } 670 | 671 | static public function str_replace_once($str_pattern, $str_replacement, $string) 672 | { 673 | if (strpos($string, $str_pattern) !== false) 674 | { 675 | $occurrence = strpos($string, $str_pattern); 676 | return substr_replace($string, $str_replacement, strpos($string, $str_pattern), strlen($str_pattern)); 677 | } 678 | return $string; 679 | } 680 | 681 | /** 682 | * Since $_SERVER['REQUEST_URI'] is only available on Apache, we 683 | * generate an equivalent using other environment variables. 684 | */ 685 | function getRequestUri() 686 | { 687 | if (isset($_SERVER['REQUEST_URI'])) { 688 | $uri = $_SERVER['REQUEST_URI']; 689 | } 690 | else { 691 | if (isset($_SERVER['argv'])) { 692 | $uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['argv'][0]; 693 | } 694 | elseif (isset($_SERVER['QUERY_STRING'])) { 695 | $uri = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING']; 696 | } 697 | else { 698 | $uri = $_SERVER['SCRIPT_NAME']; 699 | } 700 | } 701 | // Prevent multiple slashes to avoid cross site requests via the Form API. 702 | $uri = '/' . ltrim($uri, '/'); 703 | 704 | return $uri; 705 | } 706 | 707 | /** 708 | * Returns the Current URL. 709 | * 710 | * @return 711 | * The current URL. 712 | */ 713 | protected function getCurrentUri() 714 | { 715 | $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' 716 | ? 'https://' 717 | : 'http://'; 718 | $current_uri = $protocol . $_SERVER['HTTP_HOST'] . $this->getRequestUri(); 719 | $parts = parse_url($current_uri); 720 | 721 | $query = ''; 722 | if (!empty($parts['query'])) { 723 | $params = array(); 724 | parse_str($parts['query'], $params); 725 | $params = array_filter($params); 726 | if (!empty($params)) { 727 | $query = '?' . http_build_query($params, NULL, '&'); 728 | } 729 | } 730 | 731 | // Use port if non default. 732 | $port = isset($parts['port']) && 733 | (($protocol === 'http://' && $parts['port'] !== 80) || ($protocol === 'https://' && $parts['port'] !== 443)) 734 | ? ':' . $parts['port'] : ''; 735 | 736 | // Rebuild. 737 | return $protocol . $parts['host'] . $port . $parts['path'] . $query; 738 | } 739 | 740 | /** 741 | * Returns the Current URL. 742 | * 743 | * @return 744 | * The current URL. 745 | */ 746 | protected function getRedirectUri() 747 | { 748 | $redirect_uri = $this->getVariable("redirect_uri"); 749 | if(!empty($redirect_uri)) return $redirect_uri; 750 | else return $this->getCurrentUri(); 751 | } 752 | 753 | /** 754 | * Build the URL for given path and parameters. 755 | * 756 | * @param $path 757 | * (optional) The path. 758 | * @param $params 759 | * (optional) The query parameters in associative array. 760 | * 761 | * @return 762 | * The URL for the given parameters. 763 | */ 764 | protected function getUri($path = '', $params = array(), $secure = false) 765 | { 766 | $url = $this->getVariable('services_uri') ? $this->getVariable('services_uri') : $this->getVariable('base_uri'); 767 | if($secure == true) 768 | { 769 | $url = self::str_replace_once("http", "https", $url); 770 | } 771 | if(!empty($path)) 772 | if (substr($path, 0, 4) == "http") 773 | $url = $path; 774 | else if(substr($path, 0, 5) == "https") 775 | $url = $path; 776 | else 777 | $url = rtrim($url, '/') . '/' . ltrim($path, '/'); 778 | 779 | if (!empty($params)) 780 | $url .= '?' . http_build_query($params, NULL, '&'); 781 | 782 | return $url; 783 | } 784 | 785 | public function getPartnerDevices() 786 | { 787 | return $this->api("partnerdevices", "POST"); 788 | } 789 | 790 | /** 791 | * @param string url : webhook url 792 | * @param string app_type : type of webhook 793 | * @brief register a webhook notification sent to your app for the current user 794 | */ 795 | protected function addWebhook($url, $app_type) 796 | { 797 | $params = array('url' => $url, 'app_type' => $app_type); 798 | $this->api('addwebhook', $params); 799 | } 800 | 801 | /** 802 | * @param string $app_type: type of webhook 803 | * @brief drop webhook notification for the current user 804 | */ 805 | protected function dropWebhook($app_type) 806 | { 807 | $params = array('app_type' => $app_type); 808 | $this->api('dropwebhook', $params); 809 | } 810 | } 811 | /** 812 | * API Helpers 813 | * 814 | * @author Originally written by Fred Potter . 815 | */ 816 | class NAApiHelper 817 | { 818 | public $client; 819 | public $devices = array(); 820 | public function __construct($client) 821 | { 822 | $this->client = $client; 823 | } 824 | public function api($method, $action, $params = array()) 825 | { 826 | if(isset($this->client)) 827 | return $this->client->api($method, $action, $params); 828 | else return NULL; 829 | } 830 | public function simplifyDeviceList($app_type = "app_station") 831 | { 832 | $this->devices = $this->client->api("devicelist", "POST", array("app_type" => $app_type)); 833 | foreach($this->devices["devices"] as $d => $device) 834 | { 835 | $moduledetails = array(); 836 | foreach($device["modules"] as $module) 837 | { 838 | foreach($this->devices["modules"] as $moduledetail) 839 | { 840 | if($module == $moduledetail['_id']) 841 | { 842 | $moduledetails[] = $moduledetail; 843 | } 844 | } 845 | } 846 | unset($this->devices["devices"][$d]["modules"]); 847 | $this->devices["devices"][$d]["modules"]=$moduledetails; 848 | } 849 | unset($this->devices["modules"]); 850 | return($this->devices); 851 | } 852 | public function getMeasure($device, $device_type, $date_begin, $module=null, $module_type = null) 853 | { 854 | $params = array("scale" => "max", "date_begin" => $date_begin, "date_end" => $date_begin+5*60, "device_id" => $device); 855 | $result = array(); 856 | if(!is_null($module)) 857 | { 858 | switch($module_type) 859 | { 860 | case "NAModule1": 861 | $params["type"] = "Temperature,Humidity"; 862 | break; 863 | case "NAModule4": 864 | $params["type"] = "Temperature,CO2,Humidity"; 865 | break; 866 | case "NAModule3": 867 | $params["type"] = "Rain"; 868 | break; 869 | } 870 | 871 | $params["module_id"] = $module; 872 | } 873 | else 874 | { 875 | switch($device_type) 876 | { 877 | case "NAMain": 878 | $params["type"] = "Temperature,CO2,Humidity,Pressure,Noise"; 879 | break; 880 | case "NAPlug": 881 | $params["type"] = "Temperature,Sp_Temperature,BoilerOn,BoilerOff"; 882 | } 883 | } 884 | $types = explode(",", $params["type"]); 885 | if($types === FALSE) 886 | { 887 | $types = array($params["type"]); 888 | } 889 | $meas = $this->client->api("getmeasure", "POST", $params); 890 | if(isset($meas[0])) 891 | { 892 | $result['time'] = $meas[0]['beg_time']; 893 | foreach($meas[0]['value'][0] as $key => $val) 894 | { 895 | $result[$types[$key]] = $val; 896 | } 897 | } 898 | return($result); 899 | 900 | } 901 | public function getLastMeasures() 902 | { 903 | $results = array(); 904 | foreach ($this->devices["devices"] as $device) 905 | { 906 | $result = array(); 907 | if(isset($device["station_name"])) $result["station_name"] = $device["station_name"]; 908 | if(isset($device["modules"][0])) $result["modules"][0]["module_name"] = $device["module_name"]; 909 | $result["modules"][0] = array_merge($result["modules"][0], $device["dashboard_data"]); 910 | foreach ($device["modules"] as $module) 911 | { 912 | $addmodule = array(); 913 | if(isset($module["module_name"])) $addmodule["module_name"] = $module["module_name"]; 914 | $addmodule = array_merge($addmodule, $module["dashboard_data"]); 915 | $result["modules"][] = $addmodule; 916 | } 917 | $results[] = $result; 918 | } 919 | return($results); 920 | } 921 | public function getAllMeasures($date_begin) 922 | { 923 | $results = array(); 924 | foreach ($this->devices["devices"] as $device) 925 | { 926 | $result = array(); 927 | if(isset($device["station_name"])) $result["station_name"] = $device["station_name"]; 928 | if(isset($device["modules"][0])) $result["modules"][0]["module_name"] = $device["module_name"]; 929 | $result["modules"][0] = array_merge($result["modules"][0], $this->getMeasure($device["_id"], $device["type"], $date_begin)); 930 | foreach ($device["modules"] as $module) 931 | { 932 | $addmodule = array(); 933 | if(isset($module["module_name"])) $addmodule["module_name"] = $module["module_name"]; 934 | $addmodule = array_merge($addmodule, $this->getMeasure($device["_id"], $device["type"], $date_begin, $module["_id"], $module["type"])); 935 | $result["modules"][] = $addmodule; 936 | } 937 | $results[] = $result; 938 | } 939 | return($results); 940 | } 941 | } 942 | 943 | 944 | 945 | ?> 946 | --------------------------------------------------------------------------------