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