Issues (56)

src/Api/BaseApi.php (2 issues)

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: sheldon
5
 * Date: 18-6-14
6
 * Time: 下午4:39.
7
 */
8
9
namespace MiotApi\Api;
10
11
use MiotApi\Exception\JsonException;
12
use MiotApi\Util\Jsoner\JsonLastError;
13
use MiotApi\Util\Request;
14
15
class BaseApi
16
{
17
    /**
18
     * App-Id
19
     * 在开放平台申请: https://open.home.mi.com.
20
     *
21
     * @var
22
     */
23
    protected $appId;
24
25
    /**
26
     * Access-Token
27
     * 小米账号登录后的Oauth Token
28
     * 需要使用者自己实现小米oauth并获取到用户的access token
29
     * oauth使用的应用id一定要与 App-Id一致.
30
     *
31
     * @var
32
     */
33
    protected $accessToken;
34
35
    /**
36
     * 名字空间
37
     * 必须是 miot-spec-v2.
38
     *
39
     * @var string
40
     */
41
    protected $specNS = 'miot-spec-v2';
42
43
    protected $httpClient;
44
45
    protected $host = 'api.home.mi.com';
46
47
    protected $port = 443;
48
49
    protected $timeout = 10;
50
51
    /**
52
     * Api constructor.
53
     *
54
     * @param null   $appId
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $appId is correct as it would always require null to be passed?
Loading history...
55
     * @param null   $accessToken
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $accessToken is correct as it would always require null to be passed?
Loading history...
56
     * @param string $specNS
57
     */
58
    public function __construct($appId = null, $accessToken = null, $specNS = 'miot-spec-v2')
59
    {
60
        $this->appId = $appId;
61
        $this->accessToken = $accessToken;
62
        $this->specNS = $specNS;
63
    }
64
65
    /**
66
     * 设置 请求的 host
67
     * 默认为大陆host,如果要获取其他地区设备的时候,可以使用此方法设置host.
68
     *
69
     * @param $host
70
     */
71
    public function setHost($host)
72
    {
73
        $this->host = $host;
74
    }
75
76
    /**
77
     * 读取抽象设备列表.
78
     *
79
     * @param bool $compact 如果希望读取设备列表时,只想读取最简单的信息,compact设置为true
80
     *
81
     * @return array|mixed
82
     */
83
    public function devices($compact = false)
84
    {
85
        $params = [];
86
        if ($compact) {
87
            $params = [
88
                'compact' => $compact,
89
            ];
90
        }
91
92
        return $this->get('/api/v1/devices', $params);
93
    }
94
95
    /**
96
     * GET.
97
     *
98
     * @param $uri
99
     * @param array $params
100
     *
101
     * @return array|bool|mixed
102
     */
103
    public function get($uri, $params = [])
104
    {
105
        $httpClient = $this->httpClient();
106
107
        $result = $httpClient
108
            ->setRequestURI($uri)
109
            ->setType('GET')
110
            ->setQueryParams($params)
111
            ->execute()
112
            ->getResponseText();
113
114
        if ($result) {
115
            $returnData = json_decode($result, true);
116
            $lastError = JsonLastError::check();
117
118
            return $returnData === null || !is_null($lastError) ? false : $returnData;
119
        } else {
120
            return [
121
                'status'  => '-705002036',
122
                'message' => $httpClient->getError(),
123
            ];
124
        }
125
    }
126
127
    /**
128
     * 获取http Client.
129
     *
130
     * @return Request
131
     */
132
    private function httpClient()
133
    {
134
        $this->httpClient = new Request($this->host, '', $this->port, true, $this->timeout);
135
        $this->httpClient->setHeader('App-Id', $this->appId);
136
        $this->httpClient->setHeader('Access-Token', $this->accessToken);
137
        $this->httpClient->setHeader('Spec-NS', $this->specNS);
138
139
        return $this->httpClient;
140
    }
141
142
    /**
143
     * 读取设备信息
144
     * 读取一个设备 : GET /api/v1/device-information?dids=xxxx
145
     * 读取多个设备: GET /api/v1/device-information?dids=xxxx,yyy,zzzzz.
146
     *
147
     * @param $dids
148
     *
149
     * @return array|mixed
150
     */
151
    public function deviceInformation($dids)
152
    {
153
        if (is_array($dids)) {
154
            $dids = implode(',', $dids);
155
        }
156
157
        $params = [
158
            'dids' => $dids,
159
        ];
160
161
        return $this->get('/api/v1/device-information', $params);
162
    }
163
164
    /**
165
     * 读取属性
166
     * 读取一个属性 : GET /api/v1/properties?pid=AAAD.1.1
167
     * 读取多个属性:GET /api/v1/properties?pid=AAAD.1.1,AAAD.2.3
168
     * 语音控制需要增加voice字段:GET /api/v1/properties?pid=AAAD.1.1,AAAD.2.3&voice={"recognition":"灯开了吗","semantics":"xxx"}.
169
     *
170
     * @param $pid
171
     * @param string $voice
172
     *
173
     * @return array|mixed
174
     */
175
    public function properties($pid, $voice = '')
176
    {
177
        if (is_array($pid)) {
178
            $pid = implode(',', $pid);
179
        }
180
181
        $params = [
182
            'pid' => $pid,
183
        ];
184
185
        if ($voice) {
186
            $params['voice'] = $voice;
187
        }
188
189
        return $this->get('/api/v1/properties', $params);
190
    }
191
192
    /**
193
     * 设置属性.
194
     *
195
     * @param $data
196
     *
197
     * @throws JsonException
198
     *
199
     * @return array|bool|mixed
200
     */
201
    public function setProperties($data)
202
    {
203
        if (!is_array($data)) {
204
            $data = json_decode($data, true);
205
            $lastError = JsonLastError::check();
206
            if (!is_null($lastError)) {
207
                throw new JsonException('It\'s not a json string.');
208
            }
209
        }
210
211
        $data = json_encode($data);
212
213
        return $this->put('/api/v1/properties', $data);
214
    }
215
216
    /**
217
     * PUT.
218
     *
219
     * @param $uri
220
     * @param $data
221
     *
222
     * @return array|bool|mixed
223
     */
224
    public function put($uri, $data)
225
    {
226
        $httpClient = $this->httpClient();
227
        $httpClient->setAdditionalCurlOpt(CURLOPT_POSTFIELDS, $data);
228
229
        $result = $httpClient
230
            ->setRequestURI($uri)
231
            ->setType('PUT')
232
            ->execute()
233
            ->getResponseText();
234
235
        if ($result) {
236
            $returnData = json_decode($result, true);
237
            $lastError = JsonLastError::check();
238
239
            return $returnData === null || !is_null($lastError) ? false : $returnData;
240
        } else {
241
            return [
242
                'status'  => '-705002036',
243
                'message' => $httpClient->getError(),
244
            ];
245
        }
246
    }
247
248
    /**
249
     * 调用方法
250
     * 一次请求只能调用一个设备的一个方法
251
     * PUT /api/v1/action.
252
     *
253
     * @param $data
254
     *
255
     * @throws JsonException
256
     *
257
     * @return array|bool|mixed
258
     */
259
    public function invokeActions($data)
260
    {
261
        if (!is_array($data)) {
262
            $data = json_decode($data, true);
263
            $lastError = JsonLastError::check();
264
            if (!is_null($lastError)) {
265
                throw new JsonException('It\'s not a json string.');
266
            }
267
        }
268
269
        $data = json_encode($data);
270
271
        return $this->put('/api/v1/action', $data);
272
    }
273
274
    /**
275
     * 读取用户在米家设置好的场景列表.
276
     *
277
     * @return array|mixed
278
     */
279
    public function scenes()
280
    {
281
        return $this->get('/api/v1/scenes');
282
    }
283
284
    /**
285
     * 主动触发某个场景.
286
     *
287
     * @param $sceneId
288
     *
289
     * @return array|bool|mixed
290
     */
291
    public function triggerScene($sceneId)
292
    {
293
        $data = [
294
            'id' => $sceneId,
295
        ];
296
        $data = json_encode($data);
297
298
        return $this->post('/api/v1/scene', $data);
299
    }
300
301
    /**
302
     * POST.
303
     *
304
     * @param $uri
305
     * @param $data
306
     *
307
     * @return array|bool|mixed
308
     */
309
    public function post($uri, $data)
310
    {
311
        $httpClient = $this->httpClient();
312
        $httpClient->setAdditionalCurlOpt(CURLOPT_POSTFIELDS, $data);
313
314
        $result = $httpClient
315
            ->setRequestURI($uri)
316
            ->setType('POST')
317
            ->execute()
318
            ->getResponseText();
319
320
        if ($result) {
321
            $returnData = json_decode($result, true);
322
            $lastError = JsonLastError::check();
323
324
            return $returnData === null || !is_null($lastError) ? false : $returnData;
325
        } else {
326
            return [
327
                'status'  => '-705002036',
328
                'message' => $httpClient->getError(),
329
            ];
330
        }
331
    }
332
333
    /**
334
     * 读取家庭列表.
335
     *
336
     * @return array|mixed
337
     */
338
    public function homes()
339
    {
340
        return $this->get('/api/v1/homes');
341
    }
342
343
    /**
344
     * 订阅属性变化
345
     * 开始订阅:
346
     * POST /api/v1/subscriptions
347
     * Content-Type: application/json
348
     * Content-Length: 134
349
     * ​ * {
350
     * "topic": "properties-changed",
351
     * "properties": [
352
     * "AAAB.1.1",
353
     * "AAAC.1.1",
354
     * "AAAD.1.1",
355
     * "AAAD.1.2"
356
     * ],
357
     * "receiver-url": "xxx"
358
     * }.
359
     *
360
     * 订阅成功,应答如下:
361
     * HTTP/1.1 207 Multi-Status
362
     * Content-Type: application/json
363
     * Content-Length: 156
364
     * {
365
     * "expired": 36000,    // 超时时间,单位为秒。
366
     * "properties": [
367
     * {
368
     * "pid": "AAAB.1.1",
369
     * "status": 0
370
     * },
371
     * {
372
     * "pid": "AAAC.1.1",
373
     * "status": -704002023
374
     * },
375
     * {
376
     * "pid": "AAAD.1.1",
377
     * "status": 0
378
     * }
379
     * {
380
     * "pid": "AAAD.1.2",
381
     * "status": 705202023
382
     * }
383
     * ]
384
     * }
385
     *
386
     * @param $properties
387
     * @param $customData
388
     * @param $receiverUrl
389
     *
390
     * @return array|bool|mixed
391
     */
392
    public function subscript($properties, $customData, $receiverUrl)
393
    {
394
        $data = [
395
            'topic'        => 'properties-changed',
396
            'properties'   => $properties,
397
            'custom-data'  => $customData,
398
            'receiver-url' => $receiverUrl,
399
        ];
400
        $data = json_encode($data);
401
402
        return $this->post('/api/v1/subscriptions', $data);
403
    }
404
405
    /**
406
     * 退订属性变化
407
     * POST /api/v1/subscriptions
408
     * Content-Type: application/json
409
     * Content-Length: 134
410
     * ​ * {
411
     * "topic": "properties-changed",
412
     * "properties": [
413
     * "AAAB.1.1",
414
     * "AAAC.1.1",
415
     * "AAAD.1.1",
416
     * "AAAD.1.2"
417
     * ],
418
     * "receiver-url": "xxx"
419
     * }.
420
     *
421
     * 退订成功,应答如下:
422
     * HTTP/1.1 207 Multi-Status
423
     * Content-Type: application/json
424
     * Content-Length: 156
425
     * {
426
     * "expired": 36000,    // 超时时间,单位为秒。
427
     * "properties": [
428
     * {
429
     * "pid": "AAAB.1.1",
430
     * "status": 0
431
     * },
432
     * {
433
     * "pid": "AAAC.1.1",
434
     * "status": -704002023
435
     * },
436
     * {
437
     * "pid": "AAAD.1.1",
438
     * "status": 0
439
     * }
440
     * {
441
     * "pid": "AAAD.1.2",
442
     * "status": 705202023
443
     * }
444
     * ]
445
     * }
446
     *
447
     * @param $properties
448
     *
449
     * @return array|bool|mixed
450
     */
451
    public function unSubscript($properties)
452
    {
453
        $data = [
454
            'topic'      => 'properties-changed',
455
            'properties' => $properties,
456
        ];
457
        $data = json_encode($data);
458
459
        return $this->delete('/api/v1/subscriptions', $data);
460
    }
461
462
    /**
463
     * DELETE.
464
     *
465
     * @param $uri
466
     * @param $data
467
     *
468
     * @return array|bool|mixed
469
     */
470
    public function delete($uri, $data)
471
    {
472
        $httpClient = $this->httpClient();
473
        $httpClient->setAdditionalCurlOpt(CURLOPT_POSTFIELDS, $data);
474
475
        $result = $httpClient
476
            ->setRequestURI($uri)
477
            ->setType('DELETE')
478
            ->execute()
479
            ->getResponseText();
480
481
        if ($result) {
482
            $returnData = json_decode($result, true);
483
            $lastError = JsonLastError::check();
484
485
            return $returnData === null || !is_null($lastError) ? false : $returnData;
486
        } else {
487
            return [
488
                'status'  => '-705002036',
489
                'message' => $httpClient->getError(),
490
            ];
491
        }
492
    }
493
}
494