1# -*- coding: UTF-8 -*-
2
3import _linkkit as _lk
4import ujson
5
6"""
7
8
9
10阿里云物联网平台提供安全可靠的设备连接通信能力,支持设备数据采集上云,规则引擎流转数据和云端数据下发设备端。此外,也提供方便快捷的设备管理能力,支持物模型定义,数据结构化存储,和远程调试、监控、运维。 基于iot模块可以简单快速的使用阿里云物联网平台能力。
11
12iot模块的主要实现是一个Device 类,通过它的构造函数获取device实例,就可以轻松设置相关回调函数和调用相关方法。阿里云物联网平台中涉及三个基本概念如下:
13
14- 属性(prop)
15    云端/设备端数据互通的通道,云端通过改变prop值,反馈到设备端,设备端修改prop值,保存到云端
16
17- 事件(event)
18    设备端到云端的事件通知
19
20- 服务(service)
21    云端到设备端的服务调用
22
23详细使用示例请参考主页”参考案例”中的云端连接/控制部分
24
25
26"""
27
28class Device(object):
29    """
30
31    初始化物联网平台Device类,获取device实例
32
33    :param data(dict): data字典的key信息如下
34
35        .. list-table::
36
37            * - 属性
38              - 类型
39              - 是否必填
40              - 说明
41            * - deviceName
42              - 字符串
43              - Y
44              - 物联网平台上注册的设备名称
45            * - deviceSecret
46              - 字符串
47              - Y
48              - 物联网平台上注册的deviceSecret
49            * - productKey
50              - 字符串
51              - Y
52              - 物联网平台上注册的productKey
53            * - productSecret
54              - 字符串
55              - 可选
56              - 物联网平台上注册的productSecret
57            * - region
58              - 字符串
59              - 可选
60              - 默认值是'cn-shanghai'
61
62        使用示例::
63
64            import iot
65
66            productKey = "a1uTFk4xjko"
67            productSecret = "xxxxxxx"
68            deviceName  =    "mpy_001"
69            deviceSecret  =   "xxxxxxxxxxxxxxx"
70            key_info = {
71                'region' : 'cn-shanghai' ,
72                'productKey': productKey ,
73                'deviceName': deviceName ,
74                'deviceSecret': deviceSecret ,
75                'productSecret': productSecret
76            }
77            device = iot.Device(key_info)
78
79
80
81    """
82
83    def __init__(self,data):
84
85        def __str_is_empty(value):
86            if value is None or value == "":
87                return True
88            else:
89                return False
90
91        if not isinstance(data,dict):
92            raise ValueError("Class Device init param must be dict")
93
94        if not 'productKey' in data:
95            raise ValueError('Device init : param must have key "productKey"')
96        elif __str_is_empty(data['productKey']):
97            raise ValueError("productKey wrong")
98
99        if not 'deviceName' in data:
100            raise ValueError('Device init : param must have key "deviceName"')
101        elif __str_is_empty(data['deviceName']):
102            raise ValueError("deviceName wrong")
103
104        if not 'deviceSecret' in data:
105            raise ValueError('Device init : param must have key "deviceSecret"')
106        elif __str_is_empty(data['deviceSecret']):
107            raise ValueError("deviceSecret wrong")
108
109        if 'productSecret' in data:
110            self.productSecret = data['productSecret']
111        else:
112            self.productSecret = ""
113
114        if 'region' in data:
115            self.region = data['region']
116        else:
117            self.region = "cn-shanghai"
118
119        self.data = data
120
121        # ret = _lk.init(region,data['productKey'],data['deviceName'],data['deviceSecret'],productSecret)
122        # print("init return :")
123        # print(ret)
124        # _lk.register_dyn_dev()
125
126        self._callback = {}
127
128
129
130    # def publish(self):
131    #     pass
132
133    # def subscribe(self):
134    #     pass
135
136    # def unsubscribe(self):
137    #     pass
138
139
140
141    def on(self,event,callback):
142
143        """
144        通过这个函数,可以设置物联网平台各种事件的处理函数,函数接收两个参数分别是事件名称和事件处理函数
145
146        :param event(str)): 需要注册的事件名称,类型是字符串
147
148            .. list-table::
149
150                * - 事件名称
151                  - 事件说明
152                * - connect
153                  - 当iot设备连接到物联网平台的时候触发'connect' 事件
154                * - disconnect
155                  - 当连接断开时,触发'disconnect'事件
156                * - props
157                  - 当iot云端下发属性设置时,触发'props'事件
158                * - service
159                  - 当iot云端调用设备service时,触发'service'事件
160                * - error
161                  - 当设备跟iot平台通信过程中遇到错误时,触发'error'事件
162
163        :param callback: 回调函数
164
165        使用示例::
166
167            def on_connect():
168                print('linkkit is connected')
169
170            device.on('connect',on_connect)
171
172            def on_disconnect():
173                print('linkkit is disconnected')
174
175            device.on('disconnect',on_disconnect)
176
177            def on_props(request):
178                print('clound req data is %s' %(request))
179
180            device.on('props',on_props)
181
182
183            def on_service(id,request):
184                print('clound req id  is %d , req is %s' %(id,request))
185
186            device.on('service',on_service)
187
188
189            def on_error(err):
190                print('err msg is %s '%(err))
191
192            device.on('error',on_error)
193
194
195        """
196
197        # if not callable(callback):
198        #     raise ValueError("the 2nd param of function on must be function")
199
200        # if (event == 'connect'):
201        #     _lk.register_call_back(_lk.ON_CONNECT,callback)
202        # elif (event == 'disconnect'):
203        #     _lk.register_call_back(_lk.ON_DISCONNECT,callback)
204        # elif (event == 'close'):
205        #     _lk.register_call_back(_lk.ON_CLOSE,callback)
206        # elif (event == 'error'):
207        #     _lk.register_call_back(_lk.ON_ERROR,callback)
208        # elif (event == 'props'):
209        #     _lk.register_call_back(_lk.ON_PROPS,callback)
210        # elif (event == 'service'):
211        #     _lk.register_call_back(_lk.ON_SERVICE,callback)
212        self._callback[event] = callback
213
214    def connect(self):
215        '''
216        连接物联网平台连接函数,该函数是异步调用
217        '''
218
219        for key in self._callback:
220            event = key
221            callback = self._callback[key]
222            print(event)
223                    # if not callable(callback):
224        #     raise ValueError("the 2nd param of function on must be function")
225
226            if (event == 'connect'):
227                _lk.register_call_back(_lk.ON_CONNECT,callback)
228            elif (event == 'disconnect'):
229                _lk.register_call_back(_lk.ON_DISCONNECT,callback)
230            elif (event == 'close'):
231                _lk.register_call_back(_lk.ON_CLOSE,callback)
232            elif (event == 'error'):
233                _lk.register_call_back(_lk.ON_ERROR,callback)
234            elif (event == 'props'):
235                _lk.register_call_back(_lk.ON_PROPS,callback)
236            elif (event == 'service'):
237                _lk.register_call_back(_lk.ON_SERVICE,callback)
238
239
240        ret = _lk.init(self.region,self.data['productKey'],self.data['deviceName'],self.data['deviceSecret'],self.productSecret)
241        _lk.register_dyn_dev()
242
243        _lk.connect()
244
245    def postProps(self,data):
246        """
247        上报设备属性
248
249
250        :param data(dict): 字典的key信息如下
251
252            .. list-table::
253
254                  * - 属性
255                    - 类型
256                    - 是否必填
257                    - 说明
258                  * - params
259                    - 字典
260                    - Y
261                    - 属性的值对应的是物联网平台的json数据
262
263        使用示例::
264
265            data = {
266                'params': {
267                'test_prop' : 100
268                }
269            }
270            device.postProps(data)
271
272        """
273        if not isinstance(data, dict):
274            raise ValueError("postProps func param must be dict")
275
276        if not 'params' in data:
277            raise ValueError('data must have key: "params"')
278        return _lk.post_property(ujson.dumps(data['params']))
279
280
281
282    def postEvent(self,data):
283        """
284        上报设备的事件
285
286        :param data(dict): 字典的key信息如下
287
288            .. list-table::
289
290                  * - 属性
291                    - 类型
292                    - 是否必填
293                    - 说明
294                  * - params
295                    - 字典
296                    - Y
297                    - 属性的值对应的是物联网平台的json数据
298                  * - id
299                    - 字符串
300                    - Y
301                    - 事件名称,请参考物模型上定义的事件id
302
303        使用示例::
304
305            data = {
306                'id': 'EventTest' ,
307                'params': {
308                'test_event' : 100
309                }
310            }
311            device.postEvent(data)
312
313
314        """
315        if isinstance(data, dict):
316            if not 'id' in data:
317                raise ValueError('data must have key:  "id"')
318            if not 'params' in data:
319                raise ValueError('data must have key: "params"')
320
321        else:
322            raise ValueError("postEvent func param must be dict")
323        return _lk.post_event(data['id'],ujson.dumps(data['params']))
324
325
326    def close(self):
327        '''
328        关闭物联网设备节点,断开连接
329        '''
330        return _lk.close()
331
332    def do_yield(self,time):
333        """
334        激活物联网平台接收云端消息,并设置接收超时时间为:timeout, 单位是 ms.为了保证云端消息被接收到,执行了异步命令以后,需要循环执行这个方法,直到拿云端的返回
335        """
336        _lk.do_yield(time)
337
338
339    # def __register_callback(self):
340    #     _lk.register_call_back(1,self.__on_connect)
341    #     _lk.register_call_back(3,self.__on_disconnect)
342    #     _lk.register_call_back(5,self.__on_service_request)
343    #     _lk.register_call_back(7,self.__on_prop_set)
344    #     _lk.register_call_back(9,self.__on_thing_prop_post)
345    #     _lk.register_call_back(10,self.__on_thing_event_post)
346
347
348# class GateWay(object):
349
350#     def addTopo(self):
351#         pass
352
353#     def getTopo(self):
354#         pass
355
356#     def removeTopo(self):
357#         pass
358
359#     def login(self):
360#         pass
361
362#     def logout(self):
363#         pass
364
365#     def regiestSubDevice(self):
366#         pass
367
368# def register():
369    # pass
370