· 5 years ago · Jan 26, 2021, 12:46 PM
1<?php
2
3namespace App\Libraries;
4
5use Carbon\Carbon;
6use GuzzleHttp\Client;
7use Illuminate\Http\Response;
8use Illuminate\Support\Facades\Log;
9
10/**
11 * Classe para gerencimaneto de estações Climáticas ultilizado a API FieldClimate OU (METOS)
12 *
13 * @author Wellington Junio <wellington@sysout.com.br>
14 * @since 18/01/2021
15 * @version 1.0.0
16 */
17class FieldClimate {
18
19 private $httpClient;
20 private $headers;
21 private $url;
22 private $public_key;
23 private $private_key;
24 public $timestamp;
25
26 public function __construct()
27 {
28 $this->timestamp = gmdate('D, d M Y H:i:s T');
29
30 $this->httpClient = new Client();
31 $this->headers = [
32 'headers' => [
33 "Accept" => "application/json",
34 "Date" => "{$this->timestamp}"
35 ],
36 ];
37
38 // Prod
39 $this->url = 'https://api.fieldclimate.com/v2';
40
41 $this->setKeys(
42 env('METOS_PUBLIC_KEY'),
43 env('METOS_PRIVATE_KEY')
44
45 );
46 }
47
48 /**
49 * Seta as chaves que definem o dominio da conta
50 *
51 * @param [type] $public_key
52 * @param [type] $private_key
53 * @return void
54 */
55 private function setKeys($public_key, $private_key){
56
57 $this->public_key = $public_key;
58 $this->private_key = $private_key;
59
60 }
61
62 /**
63 * Retorna o hash necessário para realizar a requisição na Api
64 *
65 * @param [type] $method
66 * @param [type] $request
67 * @return void
68 */
69 private function signatureHash($method, $request){
70
71 $content_to_sign = $method.$request.$this->timestamp.$this->public_key;
72
73 $signature = hash_hmac("sha256", $content_to_sign, $this->private_key);
74
75 $this->headers['headers']['Authorization'] = "hmac {$this->public_key}:{$signature}";
76 }
77
78 /**
79 * Verifica se o sistema está funcionando
80 *
81 * @return void
82 */
83 public function verifySystemStatus(){
84
85 $request = '/system/status';
86
87 $newUrl = $this->url.$request;
88
89 $this->signatureHash('GET', $request);
90
91 $response = $this->httpClient->request('GET', $newUrl, $this->headers);
92
93 return $response->getBody()->getContents();
94
95 }
96
97 /**
98 * Retorna os id's das estações vinculadas ao usuário
99 *
100 * @return void
101 */
102 private function getEspecificStations($code){
103
104 $request = '/user/stations';
105
106 $newUrl = $this->url.$request;
107
108 $this->signatureHash('GET', $request);
109
110 $response = $this->httpClient->request('GET', $newUrl, $this->headers);
111
112 if($response->getStatusCode() == 200) {
113
114 $stations = json_decode($response->getBody()->getContents(), true);
115
116 if(isset($stations)){
117
118 foreach($stations as $st){
119
120 return $st['name']['original'] == $code ? $code : false ;
121
122 }
123
124 }
125
126 }
127
128 }
129
130 /**
131 * Retorna os sensores
132 *
133 * @return void
134 */
135 private function getSensors(){
136
137 $request = '/system/sensors';
138
139 $newUrl = $this->url.$request;
140
141 $this->signatureHash('GET', $request);
142
143 $response = $this->httpClient->request('GET', $newUrl, $this->headers);
144
145 if($response->getStatusCode() == 200) {
146
147 $measure = json_decode($response->getBody()->getContents(), true);
148 $measure = collect($measure);
149
150 return ($measure);
151 }
152
153 }
154
155 /**
156 * Retorna todas as estações existentes na conta informada pela private e public key
157 *
158 * @param [type] $station
159 * @return void
160 */
161 public function getDevice($station){
162
163 $request = '/station/'.$station;
164
165 $newUrl = $this->url.$request;
166
167 $this->signatureHash('GET', $request);
168
169 $response = $this->httpClient->request('GET', $newUrl, $this->headers);
170
171 if($response->getStatusCode() == 200) {
172
173 $dataStation = json_decode($response->getBody()->getContents(), true);
174
175 // Monta a estrutura padrão de devices
176 $station = (object) [];
177 $station->id = $dataStation['name']['original'];
178 $station->name = $dataStation['info']['device_name'];
179 $station->lat = $dataStation['position']['geo']['coordinates'][0];
180 $station->lng = $dataStation['position']['geo']['coordinates'][1];
181
182 return $station;
183
184 }
185
186 return null;
187
188 }
189
190 /**
191 * Carrega as medições de uma determinada data
192 *
193 * @param [type] $station
194 * @param [type] $date
195 * @return void
196 */
197 public function loadMeasure($station, $date){
198
199 $to = $date->endOfDay()->timestamp;
200 $from = $date->startOfDay()->timestamp;
201
202 $request = '/data/'. $station->device_id .'/'. 'hour' .'/from/'. $from .'/to/'. $to;
203 $newUrl = $this->url.$request;
204
205 try {
206
207 $this->signatureHash('GET', $request);
208
209 $response = $this->httpClient->request('GET', $newUrl, $this->headers);
210 if($response->getStatusCode() == 200) {
211
212 $device = json_decode($response->getBody()->getContents(), true);
213
214 if(isset($device['dates'][0]) && $device['dates'][0]){
215
216 $measure = $this->buildMeasure($device, $date->format('Y-m-d') == now()->format('Y-m-d'));
217 $measure['station'] = [
218 "code" => $station->device_id,
219 "name" => $station->custom_name,
220 "lng" => $station->lat,
221 "lat" => $station->lng
222 ];
223
224 $measure['type'] = 'Metos';
225 $measure['key'] = 'geodata-weather';
226
227 return $measure;
228 }
229
230
231 }
232
233 return response('Não foram encontradas medições atuais.', Response::HTTP_NOT_FOUND);
234
235 } catch (\Exception $e) {
236
237 throw $e;
238 }
239 }
240
241 /**
242 * Monta as medições na forma padrão
243 *
244 * @param [type] $device
245 * @return void
246 */
247 public function buildMeasure($device, $isToday){
248
249 $sensors = [
250 'Drybulb temperature' => 'temperature',
251 'Precipitation' => 'pluviometry',
252 'Wind direction' => 'wind-direction',
253 'Solar Panel' => 'solar-radiation',
254 'Dew Point' => 'dew-point',
255 'Wind speed' => 'wind-speed',
256 ];
257
258 $measure = [
259 'sensors' => [],
260 'updated_at' => $device['dates'][0]
261 ];
262
263 if($isToday) {
264 $measure['updated_at'] = end($device['dates']);
265 }
266
267 foreach($device['data'] as $s){
268
269 if(isset($s['name_original']) && isset($sensors[$s['name_original']])){
270
271 $sensor = [
272 'key' => $sensors[$s['name_original']],
273 'unit' => $s['unit'],
274 'values' => []
275 ];
276
277 switch ($sensor['key']) {
278
279 case 'temperature':
280
281 $sensor['values']['min'] = min($s['values']['min']);
282 $sensor['values']['max'] = max($s['values']['max']);
283 $sensor['values']['last'] = end($s['values']['avg']);
284
285 break;
286
287 case 'pluviometry':
288
289 $sensor['values']['min'] = min($s['values']['sum']);
290 $sensor['values']['max'] = max($s['values']['sum']);
291 $sensor['values']['last'] = array_sum($s['values']['sum']);
292
293 break;
294
295 case 'wind-direction':
296
297 // $sensor['values']['last'] = $s['values']['last'][0];
298 break;
299
300 case 'solar-radiation':
301
302 $sensor['values']['last'] = end($s['values']['last']);
303 break;
304
305 case 'dew-point':
306
307 $sensor['values']['last'] = end($s['values']['avg']);
308 break;
309
310 case 'wind-speed':
311
312 $sensor['values']['last'] = end($s['values']['avg'][0]);
313 $sensor['values']['max'] = max($s['values']['max']);
314
315 break;
316
317 default:
318
319 break;
320
321 }
322
323 array_push($measure['sensors'], $sensor);
324
325 }
326
327 }
328
329 return $measure;
330
331 }
332
333 /**
334 * Retorna dados para a montagem do calendário
335 *
336 * @param [type] $station
337 * @param [type] $from
338 * @return void
339 */
340 public function loadCalendar($station, $from){
341
342 $to = $from->endOfMonth()->timestamp;
343 $from = $from->firstOfMonth()->timestamp;
344
345 $request = '/data/'. $station .'/'. 'daily' .'/from/'. $from .'/to/'. $to;
346
347 $newUrl = $this->url.$request;
348
349 try {
350
351 $this->signatureHash('GET', $request);
352
353 $response = $this->httpClient->request('GET', $newUrl, $this->headers);
354 if($response->getStatusCode() == 200) {
355
356 $responseData = json_decode($response->getBody()->getContents(), true);
357 return $this->buildCalendar($responseData);
358
359 }
360
361 return [];
362
363 } catch (\Exception $e){
364
365 throw $e;
366
367 }
368
369 }
370
371 /**
372 * Monta o calendário a partir dos dados requisitados no load do mesmo
373 *
374 * @param [type] $responseData
375 * @return void
376 */
377 public function buildCalendar($responseData){
378
379 $days = $responseData['dates'];
380 $cMeasure = collect($responseData['data']);
381
382 $tempMeasure = $cMeasure->whereIn('name_original', ['Drybulb temperature', 'HC Air temperature'])->first();
383 $precMeasure = $cMeasure->where('name_original', 'Precipitation')->first()['values']['sum'];
384
385 $rainArr = [
386 'dates' => [],
387 'gathered_rain' => 0
388 ];
389
390 if($tempMeasure){
391
392 foreach($tempMeasure['values']['avg'] as $index => $avgTemp){
393
394 $rain = $precMeasure[$index];
395 $day = Carbon::createFromFormat('Y-m-d H:i:s', $days[$index])->format('Y-m-d');
396
397 array_push($rainArr['dates'], [
398 'status' => $rain > 2.00 ? 'rain':'sun',
399 'date' => $day,
400 'pluviometry' => (string) ($rain ?? 0)
401 ]);
402
403 }
404
405 }
406
407 return $rainArr;
408
409 }
410
411 /**
412 * Adiciona estação direto ao site da api através do código informado
413 *
414 * @param [type] $code
415 * @return void
416 */
417 public function addStation($code) {
418
419 $request = '/station/'. $code .'/rw';
420
421 $newUrl = $this->url.$request;
422
423 $this->signatureHash('POST', $request);
424
425 $this->headers['body'] = [
426 "name" => "Custom station name"
427 ];
428
429 dd($this->headers);
430
431 // $ch = curl_init();
432 // curl_setopt($ch, CURLOPT_URL, $newUrl);
433 // // SSL important
434 // curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
435 // curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
436 // curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers['headers']);
437 // curl_setopt( $ch, CURLOPT_POST, TRUE );
438 // curl_setopt( $ch, CURLOPT_POSTFIELDS, $this->headers['body']);
439
440 // $output = curl_exec($ch);
441 // dd($output, $ch);
442 // curl_close($ch);
443
444
445 $response = $this->httpClient->request('POST', $newUrl, $this->headers);
446
447 if($response->getStatusCode() == 200) {
448
449 $rData = json_decode($response->getBody()->getContents(), true);
450 dd($rData);
451 }
452
453 }
454
455}
456