├── 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 |
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 |
--------------------------------------------------------------------------------