mirror of
https://github.com/ucloud/iotstack-driver-sdk-python.git
synced 2025-04-25 13:48:50 +08:00
Initial commit
This commit is contained in:
commit
e44e3835b1
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
build
|
||||
dist
|
||||
MANIFEST
|
||||
uiotedge_driver_link_sdk.egg-info
|
||||
.pypirc
|
230
README.md
Normal file
230
README.md
Normal file
@ -0,0 +1,230 @@
|
||||
## API参考文档
|
||||
|
||||
主要的API参考文档如下:
|
||||
|
||||
#### from uiotedgedriverlinksdk
|
||||
* **[getLogger()](#getLogger)**
|
||||
|
||||
---
|
||||
|
||||
#### from uiotedgedriverlinksdk.client
|
||||
* **[getConfig()](#getConfig)**
|
||||
* **[Config()](#Config)**
|
||||
* Config#**[getDeviceInfos()](#getDeviceInfos)**
|
||||
* Config#**[getDriverInfo()](#getDriverInfo)**
|
||||
|
||||
|
||||
---
|
||||
|
||||
#### from uiotedgedriverlinksdk.exception
|
||||
* BaseEdgeException
|
||||
* EdgeDriverLinkException
|
||||
* EdgeDriverLinkTimeoutException
|
||||
* EdgeDriverLinkDeviceConfigException
|
||||
* EdgeDriverLinkDeviceOfflineException
|
||||
* EdgeDriverLinkOfflineException
|
||||
* EdgeDriverLinkDeviceProductSecretException
|
||||
|
||||
|
||||
---
|
||||
#### from uiotedgedriverlinksdk.client
|
||||
|
||||
* **[SubDevice()](#subdevice)**
|
||||
* SubDevice#**[set_product_sn()](#set_product_sn)**
|
||||
* SubDevice#**[set_device_sn()](#set_device_sn)**
|
||||
* SubDevice#**[set_product_secret()](#set_product_secret)**
|
||||
* SubDevice#**[set_msg_callback()](#set_msg_callback)**
|
||||
* SubDevice#**[login()](#login)**
|
||||
* SubDevice#**[logout()](#logout)**
|
||||
* SubDevice#**[publish()](#publish)**
|
||||
* SubDevice#**[registerDevice()](#registerDevice)**
|
||||
|
||||
---
|
||||
|
||||
#### from uiotedgedriverlinksdk.edge
|
||||
|
||||
* **[register_device()](#register)**
|
||||
* **[set_on_topo_change_callback()](#set_on_topo_change_callback)**
|
||||
* **[set_on_status_change_callback()](#set_on_status_change_callback)**
|
||||
* **[get_topo()](#get_topo)**
|
||||
* **[add_topo()](#add_topo)**
|
||||
* **[delete_topo()](#delete_topo)**
|
||||
|
||||
|
||||
---
|
||||
* **[get_edge_online_status()](#get_edge_online_status)**
|
||||
|
||||
---
|
||||
<a name="getLogger"></a>
|
||||
### getLogger()
|
||||
返回驱动内置logger。
|
||||
|
||||
---
|
||||
<a name="getConfig"></a>
|
||||
### getConfig()
|
||||
返回驱动相关配置。
|
||||
|
||||
---
|
||||
<a name="Config"></a>
|
||||
### Config()
|
||||
基于当前驱动配置字符串构造新的Config对象。
|
||||
|
||||
---
|
||||
<a name="getDeviceInfos"></a>
|
||||
### Config. getDeviceInfos()
|
||||
返回所有设备相关信息,返回DeviceInfo`List`
|
||||
DeviceInfo包括如下信息:
|
||||
|
||||
* productSN `str `: 官网申请的productKey。
|
||||
* deviceSN `str `: 设备名
|
||||
* config`dict `:设备自定义配置
|
||||
|
||||
---
|
||||
<a name="getDriverInfo"></a>
|
||||
### Config. getDriverInfo()
|
||||
返回驱动相关信息,返回DriverInfo`List`
|
||||
|
||||
---
|
||||
<a name="subdevice"></a>
|
||||
### SubDevice(product_sn,device_sn, on_msg_callback)
|
||||
设备接入客户端类, 用户主要通过它上下线设备和主动上报消息
|
||||
|
||||
* product_sn`str`: 云端分配的ProductSN
|
||||
* device_sn`str`: 云端分配的DeviceSN
|
||||
* on_msg_callback`func(topic:str, msg:b'')`: 云端下发消息回调,消息类型 []byte, 例如:` def callbacl(topic:str, msg:b''): print(str(msg,'utf-8')`
|
||||
|
||||
---
|
||||
<a name="set_product_sn"></a>
|
||||
### SubDevice.set_product_sn(product_sn)
|
||||
设置子设备的productSN
|
||||
|
||||
* product_sn`str`: 云端分配的ProductSN
|
||||
|
||||
|
||||
---
|
||||
<a name="set_device_sn"></a>
|
||||
### SubDevice.set_device_sn(device_sn)
|
||||
设备子设备的DeviceSN
|
||||
|
||||
* device_sn`str`: 云端分配的DeviceSN
|
||||
|
||||
|
||||
---
|
||||
<a name="set_product_secret"></a>
|
||||
### SubDevice.set_product_secret(product_secret)
|
||||
设置子设备的Product Secret
|
||||
|
||||
* product_secret`str`: 云端分配的Product Secret
|
||||
|
||||
|
||||
---
|
||||
<a name="set_product_secret"></a>
|
||||
### SubDevice.set_product_secret(product_secret)
|
||||
设置子设备的Product Secret
|
||||
|
||||
* product_secret`str`: 云端分配的Product Secret
|
||||
|
||||
|
||||
---
|
||||
<a name="set_msg_callback"></a>
|
||||
### SubDevice.set_msg_callback(msg_callback)
|
||||
设置子设备的接收消息的回调函数
|
||||
|
||||
* set_msg_callback`func`: 子设备收消息回调,例如:` def callbacl(topic:str, msg:b''): print(str(msg,'utf-8')`
|
||||
|
||||
|
||||
---
|
||||
<a name="login"></a>
|
||||
### SubDevice.login(sync=False, timeout=5)
|
||||
上报上线事件到Link IoT Edge
|
||||
|
||||
* sync`bool`: 是否异步登陆
|
||||
* timeout`int`: 等待响应超时时间,单位s(秒)
|
||||
|
||||
---
|
||||
<a name="logout"></a>
|
||||
### SubDevice.logout(sync=False, timeout=5)
|
||||
上报下线事件到Link IoT Edge
|
||||
|
||||
* sync`bool`: 是否异步登陆
|
||||
* timeout`int`: 等待响应超时时间,单位s(秒)
|
||||
|
||||
---
|
||||
<a name="publish"></a>
|
||||
### SubDevice.publish(topic, payload)
|
||||
上报消息到Link IoT Edge。异步
|
||||
|
||||
* topic`str`: 上报消息到Link IoT Edge的mqtt topic。
|
||||
* payload`[]byte`: 上报消息到Link IoT Edge的消息内容
|
||||
|
||||
|
||||
---
|
||||
|
||||
<a name="registerDevice"></a>
|
||||
### SubDevice.registerDevice(timeout)
|
||||
动态注册一个设备到Link IoT Edge。同步
|
||||
|
||||
* timeout`int`: 等待响应超时时间,单位s(秒)
|
||||
---
|
||||
|
||||
|
||||
---
|
||||
<a name="register"></a>
|
||||
### register_device(product_sn, device_sn, product_secret, timeout=5)
|
||||
上报动态注册到Link IoT Edge。同步执行,等待响应
|
||||
|
||||
* product_sn`str`: 云端分配的ProductSN
|
||||
* device_sn`str`: 自定义的DeviceSN
|
||||
* product_secret`str`: ProductSecret
|
||||
* timeout`int`: 等待响应超时时间,单位s(秒)
|
||||
|
||||
---
|
||||
<a name="set_on_topo_change_callback"></a>
|
||||
### set_on_topo_change_callback(callback)
|
||||
云端topo信息变化的下发消息的回调函数
|
||||
|
||||
* callback`func`: 云端下发消息回调,消息类型 {}, 例如: `def callback(msg): print(msg)`
|
||||
|
||||
|
||||
---
|
||||
<a name="set_on_status_change_callback"></a>
|
||||
### set_on_status_change_callback(callback)
|
||||
云端设备启用和禁用信息变化的下发消息的回调函数
|
||||
|
||||
* callback`func`: 云端下发消息回调,消息类型 {}, 例如: `def callback(msg): print(msg)`
|
||||
|
||||
|
||||
---
|
||||
<a name="get_topo"></a>
|
||||
### get_topo(timeout=5)
|
||||
上报get topo信息到Link IoT Edge。同步执行,等待响应
|
||||
|
||||
* timeout`int`: 等待响应超时时间,单位s(秒)
|
||||
|
||||
---
|
||||
<a name="add_topo"></a>
|
||||
### add_topo(product_sn, device_sn, timeout=5)
|
||||
上报add topo信息到Link IoT Edge
|
||||
|
||||
* product_sn`str`: 云端分配的ProductSN
|
||||
* device_sn`str`: 云端分配的DeviceSN
|
||||
* timeout`int`: 等待响应超时时间,单位s(秒)
|
||||
|
||||
---
|
||||
<a name="delete_topo"></a>
|
||||
### delete_topo(product_sn, device_sn, timeout=5)
|
||||
上报delete topo信息到Link IoT Edge
|
||||
|
||||
* product_sn`str`: 云端分配的ProductSN
|
||||
* device_sn`str`: 云端分配的DeviceSN
|
||||
* timeout`int`: 等待响应超时时间,单位s(秒)
|
||||
|
||||
|
||||
---
|
||||
|
||||
<a name="get_edge_online_status"></a>
|
||||
### get_edge_online_status()
|
||||
获取网关的在线状态,返回True / False
|
||||
|
||||
---
|
||||
|
BIN
examples/demo/demo.zip
Normal file
BIN
examples/demo/demo.zip
Normal file
Binary file not shown.
88
examples/demo/index.py
Normal file
88
examples/demo/index.py
Normal file
@ -0,0 +1,88 @@
|
||||
import json
|
||||
import logging
|
||||
import time
|
||||
|
||||
from uiotedgedriverlinksdk import getLogger
|
||||
from uiotedgedriverlinksdk.client import Config, SubDevice
|
||||
from uiotedgedriverlinksdk.exception import BaseEdgeException
|
||||
|
||||
# 配置log
|
||||
log = getLogger()
|
||||
log.setLevel(logging.DEBUG)
|
||||
|
||||
# 主函数
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
# 获取驱动及子设备配置信息
|
||||
driverConfig = Config().getDriverInfo()
|
||||
log.info('driver config:{}'.format(driverConfig))
|
||||
|
||||
# 从驱动配置获取设备数据上报周期
|
||||
uploadPeriod = 5
|
||||
if "period" in driverConfig.keys() and isinstance(driverConfig['period'], int):
|
||||
uploadPeriod = int(driverConfig['period'])
|
||||
|
||||
deviceInfoList = Config().getDeviceInfos()
|
||||
log.info('device list config:{}'.format(deviceInfoList))
|
||||
except Exception as e:
|
||||
log.error('load driver config error: {}'.format(str(e)))
|
||||
exit(1)
|
||||
|
||||
try:
|
||||
# 判断是否绑定子设备
|
||||
if len(deviceInfoList) < 1:
|
||||
log.error(
|
||||
'subdevice null, please bind sub device for driver')
|
||||
while True:
|
||||
time.sleep(60)
|
||||
|
||||
# 取其中一个子设备
|
||||
subDeviceInfo = deviceInfoList[0]
|
||||
|
||||
# 获取子设备的ProductSN ,key值为 ‘productSN’
|
||||
productSN = subDeviceInfo['productSN']
|
||||
# 获取子设备的DeviceSN ,key值为 ‘deviceSN’
|
||||
deviceSN = subDeviceInfo['deviceSN']
|
||||
|
||||
def callback(topic: str, payload: b''):
|
||||
log.info("recv message from {} : {}".format(topic, str(payload)))
|
||||
|
||||
# 初始化一个子设备对象
|
||||
subDevice = SubDevice(product_sn=productSN,
|
||||
device_sn=deviceSN, on_msg_callback=callback)
|
||||
# 子设备上线
|
||||
subDevice.login()
|
||||
|
||||
# 获取当前子设备的配置
|
||||
deviceConfig = subDeviceInfo['config']
|
||||
log.info('sub device config:{}'.format(deviceConfig))
|
||||
|
||||
# 从子设备配置获取子设备上报topic定义
|
||||
topic = "/{}/{}/upload".format(productSN, deviceSN) # 此处为默认topic
|
||||
if 'topic' in deviceConfig and isinstance(deviceConfig['topic'], str):
|
||||
topic = deviceConfig['topic'].format(productSN, deviceSN)
|
||||
|
||||
# 从子设备配置获取子设备上报参数名称
|
||||
param = 'RelayStatus' # 此处定义默认属性名称: RelayStatus
|
||||
if 'paramName' in deviceConfig and isinstance(deviceConfig['paramName'], str):
|
||||
param = deviceConfig['paramName']
|
||||
|
||||
i = 0
|
||||
while True:
|
||||
relayStatus = ("on", "off")[i % 2 == 0]
|
||||
payload = {
|
||||
"timestamp": time.time(),
|
||||
param: relayStatus
|
||||
}
|
||||
byts = json.dumps(payload).encode('utf-8')
|
||||
|
||||
subDevice.publish(topic, byts)
|
||||
log.info("upload {} : {}".format(topic, str(byts)))
|
||||
|
||||
time.sleep(uploadPeriod)
|
||||
i = i+1
|
||||
|
||||
except BaseEdgeException:
|
||||
log.error('Edge Exception: {}'.format(str(e)))
|
||||
except Exception as e:
|
||||
log.error('Exception error: {}'.format(str(e)))
|
13
examples/demo/pack.sh
Normal file
13
examples/demo/pack.sh
Normal file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash -e
|
||||
if [ -e "./demo.zip" ] ; then
|
||||
rm ./demo.zip
|
||||
fi
|
||||
|
||||
mkdir tmp
|
||||
cp index.py tmp/
|
||||
cd tmp
|
||||
pip3 install -t . uiotedge_driver_link_sdk==0.0.41 #打包驱动SDK
|
||||
zip -r demo.zip .
|
||||
cd ..
|
||||
cp tmp/demo.zip .
|
||||
rm -rf tmp
|
156
examples/ws/ws/index.py
Normal file
156
examples/ws/ws/index.py
Normal file
@ -0,0 +1,156 @@
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import signal
|
||||
import sys
|
||||
|
||||
import tornado.httpserver
|
||||
import tornado.ioloop
|
||||
import tornado.web
|
||||
from tornado.websocket import WebSocketHandler
|
||||
|
||||
from uiotedgedriverlinksdk import getLogger
|
||||
from uiotedgedriverlinksdk.client import Config, SubDevice, getConfig
|
||||
from uiotedgedriverlinksdk.edge import (add_topo, delete_topo, get_topo,
|
||||
register_device,
|
||||
set_on_status_change_callback,
|
||||
set_on_topo_change_callback)
|
||||
from uiotedgedriverlinksdk.exception import (
|
||||
BaseEdgeException, EdgeDriverLinkDeviceOfflineException,
|
||||
EdgeDriverLinkException, EdgeDriverLinkOfflineException,
|
||||
EdgeDriverLinkTimeoutException)
|
||||
|
||||
log = getLogger()
|
||||
log.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
class WebSocketSever(WebSocketHandler):
|
||||
def check_origin(self, origin):
|
||||
return True
|
||||
|
||||
def set_default_headers(self):
|
||||
self.set_header("Access-Control-Allow-Origin", "*") # 这个地方可以写域名
|
||||
self.set_header("Access-Control-Allow-Headers", "*")
|
||||
self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
|
||||
|
||||
def initialize(self, loop):
|
||||
self.loop = loop
|
||||
self.client_id = ''
|
||||
self.product_sn = ''
|
||||
self.device_sn = ''
|
||||
self.client = SubDevice()
|
||||
|
||||
def on_message_callback(self, topic, msg):
|
||||
self.write_message(str(msg))
|
||||
|
||||
def open(self):
|
||||
try:
|
||||
product_sn = self.get_argument('product_sn')
|
||||
device_sn = self.get_argument('device_sn')
|
||||
except tornado.web.MissingArgumentError as e:
|
||||
self.close(reason=str(e))
|
||||
else:
|
||||
log.info("websocket connect from: {}.{}".format(
|
||||
product_sn, device_sn))
|
||||
self.product_sn = product_sn
|
||||
self.device_sn = device_sn
|
||||
self.client_id = product_sn+'.'+device_sn
|
||||
|
||||
try:
|
||||
self.client.set_product_sn(product_sn)
|
||||
self.client.set_device_sn(device_sn)
|
||||
self.client.login()
|
||||
|
||||
self.client.set_msg_callback(self.on_message_callback)
|
||||
|
||||
self.write_message('login success')
|
||||
|
||||
except Exception as e:
|
||||
self.close(reason=str(e))
|
||||
|
||||
def on_message(self, message):
|
||||
try:
|
||||
if self.client_id == '' or self.client is None:
|
||||
self.client.logout()
|
||||
self.close(reason='unknown client identify')
|
||||
return
|
||||
|
||||
data = json.loads(message)
|
||||
log.info("websocket [{}] from:{}".format(
|
||||
data, self.client_id))
|
||||
|
||||
if 'action' in data:
|
||||
action = data['action']
|
||||
if action == 'add_topo':
|
||||
add_topo(self.product_sn, self.device_sn)
|
||||
elif action == 'delete_topo':
|
||||
delete_topo(self.product_sn, self.device_sn)
|
||||
elif action == "logout":
|
||||
self.client.logout()
|
||||
self.close(reason='client exit')
|
||||
return
|
||||
elif action == 'get_topo':
|
||||
topo = get_topo()
|
||||
self.write_message(topo)
|
||||
|
||||
elif 'topic' in data and 'payload' in data:
|
||||
payload = data['payload']
|
||||
if isinstance(payload, dict):
|
||||
byts = json.dumps(payload)
|
||||
log.info('send time:{}'.format(
|
||||
datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')))
|
||||
self.client.publish(
|
||||
topic=data['topic'], payload=byts.encode('utf-8'))
|
||||
log.info('send time:{}'.format(
|
||||
datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')))
|
||||
elif isinstance(payload, str):
|
||||
byts = payload.encode('utf-8')
|
||||
log.info('send time:{}'.format(
|
||||
datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')))
|
||||
self.client.publish(
|
||||
topic=data['topic'], payload=byts)
|
||||
|
||||
else:
|
||||
print('unknown message')
|
||||
except Exception as e:
|
||||
self.client.logout()
|
||||
self.close(reason=str(e))
|
||||
|
||||
def allow_draft76(self):
|
||||
return True
|
||||
|
||||
def on_close(self):
|
||||
self.client.logout()
|
||||
log.info("websocket closed from:{}, with reason: {}".format(
|
||||
self.client_id, self.close_reason))
|
||||
|
||||
|
||||
class Application(tornado.web.Application):
|
||||
def __init__(self, handlers, setting):
|
||||
super(Application, self).__init__(handlers, **setting)
|
||||
|
||||
|
||||
def main():
|
||||
from tornado.platform.asyncio import AnyThreadEventLoopPolicy
|
||||
import asyncio
|
||||
|
||||
asyncio.set_event_loop_policy(AnyThreadEventLoopPolicy())
|
||||
lo = tornado.ioloop.IOLoop.current()
|
||||
handlers = [
|
||||
(r"/ws", WebSocketSever, dict(loop=lo))
|
||||
]
|
||||
setting = dict(xsrf_cookies=False)
|
||||
app = Application(handlers, setting)
|
||||
app.listen(port=4567)
|
||||
print("websocket start listen port on:{}".format('4567'))
|
||||
lo.start()
|
||||
|
||||
|
||||
def exit_handler(signum, frame):
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
signal.signal(signal.SIGINT, exit_handler)
|
||||
signal.signal(signal.SIGTERM, exit_handler)
|
||||
main()
|
18
examples/ws/ws/pack.sh
Normal file
18
examples/ws/ws/pack.sh
Normal file
@ -0,0 +1,18 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
if [ -e "./ws.zip" ] ; then
|
||||
rm ./ws.zip
|
||||
fi
|
||||
|
||||
mkdir tmp
|
||||
cp index.py tmp
|
||||
|
||||
cd tmp
|
||||
pip3 install -t . uiotedge_driver_link_sdk==0.0.41 #打包驱动SDK
|
||||
pip3 install -t . tornado -i https://mirrors.aliyun.com/pypi/simple/ #打包自己的依赖
|
||||
zip -r ws.zip .
|
||||
|
||||
cd ..
|
||||
cp tmp/ws.zip .
|
||||
rm -rf tmp
|
||||
|
BIN
examples/ws/ws/ws.zip
Normal file
BIN
examples/ws/ws/ws.zip
Normal file
Binary file not shown.
11
run.sh
Normal file
11
run.sh
Normal file
@ -0,0 +1,11 @@
|
||||
#!/bin/bash -e
|
||||
python3 setup.py check
|
||||
python3 setup.py build
|
||||
sudo python3 setup.py install --force
|
||||
sudo python3 setup.py sdist bdist_wheel || true
|
||||
sudo python3 -m twine upload dist/*.whl
|
||||
|
||||
sudo rm -rf build
|
||||
sudo rm -rf dist
|
||||
sudo rm -rf uiotedge_driver_link_sdk.egg-info
|
||||
|
23
setup.py
Normal file
23
setup.py
Normal file
@ -0,0 +1,23 @@
|
||||
import sys
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
if not (sys.version_info[0] == 3):
|
||||
sys.exit("Link IoT Edge only support Python 3")
|
||||
|
||||
setup(
|
||||
name='uiotedge_driver_link_sdk',
|
||||
version='0.0.41',
|
||||
author='ucloud.cn',
|
||||
url='https://pypi.org/project/uiotedge_driver_link_sdk/',
|
||||
author_email='joy.zhou@ucloud.cn',
|
||||
packages=['uiotedgedriverlinksdk'],
|
||||
platforms="any",
|
||||
license='Apache 2 License',
|
||||
install_requires=[
|
||||
"asyncio-nats-client>=0.10.0",
|
||||
"cachetools>=4.0.0"
|
||||
],
|
||||
description="UIoT Edge Driver Link SDK",
|
||||
long_description="UIoT Edge Driver Link SDK\n https://www.ucloud.cn/site/product/uiot.html"
|
||||
)
|
154
uiotedgedriverlinksdk/__init__.py
Normal file
154
uiotedgedriverlinksdk/__init__.py
Normal file
@ -0,0 +1,154 @@
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import queue
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
from nats.aio.client import Client as NATS
|
||||
from nats.aio.errors import NatsError
|
||||
|
||||
_driver_id = ''
|
||||
_driver_name = ''
|
||||
_deviceInfos = []
|
||||
_driverInfo = None
|
||||
_driver_name = ''
|
||||
|
||||
# get Config
|
||||
_config_path = './etc/uiotedge/config.json'
|
||||
with open(_config_path, 'r') as load_f:
|
||||
try:
|
||||
load_dict = json.load(load_f)
|
||||
print(str(load_dict))
|
||||
# print('----config: {} -------'.format(load_dict))
|
||||
|
||||
_driver_id = load_dict['driverID']
|
||||
|
||||
if 'driverName' in load_dict.keys():
|
||||
_driver_name = load_dict['driverName']
|
||||
else:
|
||||
_driver_name = _driver_id
|
||||
|
||||
if 'deviceList' in load_dict.keys():
|
||||
_deviceInfos = load_dict['deviceList']
|
||||
|
||||
if 'driverInfo' in load_dict.keys():
|
||||
_driverInfo = load_dict['driverInfo']
|
||||
except Exception as e:
|
||||
print('load config file error:{}'.format(e))
|
||||
sys.exit(1)
|
||||
|
||||
print("driver_id: {}, driver name:{}".format(_driver_id, _driver_name))
|
||||
|
||||
|
||||
class _Logger(object):
|
||||
def __init__(self, name):
|
||||
self.url = os.environ.get(
|
||||
'UIOTEDGE_NATS_ADDRESS') or 'tcp://127.0.0.1:4222'
|
||||
self.nc = NATS()
|
||||
self.loop = asyncio.new_event_loop()
|
||||
self.queue = queue.Queue()
|
||||
self.name = name
|
||||
self.logger = logging.getLogger()
|
||||
format_str = logging.Formatter(
|
||||
'%(asctime)s - %(levelname)s: %(message)s')
|
||||
sh = logging.StreamHandler()
|
||||
sh.setFormatter(format_str)
|
||||
self.logger.addHandler(sh)
|
||||
|
||||
async def _publish(self):
|
||||
try:
|
||||
await self.nc.connect(servers=[self.url], loop=self.loop)
|
||||
logging.debug('nats for logger connect success')
|
||||
except Exception as e1:
|
||||
logging.error(e1)
|
||||
sys.exit(1)
|
||||
|
||||
while True:
|
||||
try:
|
||||
msg = self.queue.get()
|
||||
bty = json.dumps(msg)
|
||||
await self.nc.publish(subject='edge.log.upload',
|
||||
payload=bty.encode('utf-8'))
|
||||
await self.nc.flush()
|
||||
except NatsError as e:
|
||||
logging.error(e)
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
|
||||
def start(self):
|
||||
self.loop.run_until_complete(self._publish())
|
||||
|
||||
def debug(self, msg):
|
||||
data = {
|
||||
'module': self.name,
|
||||
'level': 'debug',
|
||||
'message': msg,
|
||||
'timestamp': int(time.time()),
|
||||
}
|
||||
self.queue.put(data)
|
||||
self.logger.debug(msg)
|
||||
|
||||
def info(self, msg):
|
||||
data = {
|
||||
'module': self.name,
|
||||
'level': 'info',
|
||||
'message': msg,
|
||||
'timestamp': int(time.time()),
|
||||
}
|
||||
self.queue.put(data)
|
||||
self.logger.info(msg)
|
||||
|
||||
def error(self, msg):
|
||||
data = {
|
||||
'module': self.name,
|
||||
'level': 'error',
|
||||
'message': msg,
|
||||
'timestamp': int(time.time()),
|
||||
}
|
||||
self.queue.put(data)
|
||||
self.logger.error(msg)
|
||||
|
||||
def warn(self, msg):
|
||||
data = {
|
||||
'module': self.name,
|
||||
'level': 'warn',
|
||||
'message': msg,
|
||||
'timestamp': int(time.time()),
|
||||
}
|
||||
self.queue.put(data)
|
||||
self.logger.warn(msg)
|
||||
|
||||
def critical(self, msg):
|
||||
data = {
|
||||
'module': self.name,
|
||||
'level': 'critical',
|
||||
'message': msg,
|
||||
'timestamp': int(time.time()),
|
||||
}
|
||||
self.queue.put(data)
|
||||
self.logger.critical(msg)
|
||||
|
||||
def setLevel(self, level):
|
||||
self.logger.setLevel(level)
|
||||
|
||||
|
||||
_uiotedge_logger = _Logger(_driver_name)
|
||||
|
||||
|
||||
def _init_logger():
|
||||
global _uiotedge_logger
|
||||
_uiotedge_logger.start()
|
||||
logging.debug('init logger success')
|
||||
|
||||
|
||||
_t_logger = threading.Thread(target=_init_logger)
|
||||
_t_logger.setDaemon(True)
|
||||
_t_logger.start()
|
||||
|
||||
|
||||
def getLogger():
|
||||
global _uiotedge_logger
|
||||
return _uiotedge_logger
|
105
uiotedgedriverlinksdk/client.py
Normal file
105
uiotedgedriverlinksdk/client.py
Normal file
@ -0,0 +1,105 @@
|
||||
import json
|
||||
|
||||
from uiotedgedriverlinksdk import _deviceInfos, _driverInfo
|
||||
from uiotedgedriverlinksdk.edge import (add_connect_map, del_connect_map,
|
||||
device_login_async, device_login_sync,
|
||||
device_logout_async,
|
||||
device_logout_sync, register_device,
|
||||
send_message)
|
||||
from uiotedgedriverlinksdk.exception import (
|
||||
EdgeDriverLinkDeviceConfigException, EdgeDriverLinkDeviceOfflineException,
|
||||
EdgeDriverLinkDeviceProductSecretException)
|
||||
|
||||
|
||||
class SubDevice(object):
|
||||
def __init__(self, product_sn: str = '', device_sn: str = '', on_msg_callback=None):
|
||||
self.device_sn = device_sn
|
||||
self.product_sn = product_sn
|
||||
self.product_secret = ''
|
||||
self.callback = on_msg_callback
|
||||
self.online = False
|
||||
if self.product_sn != '' and self.device_sn != '':
|
||||
self._identity = self.product_sn+'.'+self.device_sn
|
||||
|
||||
def set_product_sn(self, product_sn: str):
|
||||
self.product_sn = product_sn
|
||||
if self.product_sn != '' and self.device_sn != '':
|
||||
self._identity = self.product_sn+'.'+self.device_sn
|
||||
|
||||
def set_device_sn(self, device_sn: str):
|
||||
self.device_sn = device_sn
|
||||
if self.product_sn != '' and self.device_sn != '':
|
||||
self._identity = self.product_sn+'.'+self.device_sn
|
||||
|
||||
def set_product_secret(self, product_secret: str):
|
||||
self.product_secret = product_secret
|
||||
|
||||
def set_msg_callback(self, msg_callback):
|
||||
self.callback = msg_callback
|
||||
|
||||
def get_device_info(self):
|
||||
return {
|
||||
"productSN": self.product_sn,
|
||||
"deviceSN": self.device_sn
|
||||
}
|
||||
|
||||
def registerDevice(self, timeout=5):
|
||||
if self.product_sn == '' or self.device_sn == '' or self.product_secret == '':
|
||||
raise EdgeDriverLinkDeviceProductSecretException
|
||||
|
||||
register_device(self.product_sn, self.device_sn,
|
||||
self.product_secret, timeout=timeout)
|
||||
|
||||
def logout(self, sync=False, timeout=5):
|
||||
if self.online:
|
||||
if sync:
|
||||
device_logout_sync(product_sn=self.product_sn,
|
||||
device_sn=self.device_sn,
|
||||
timeout=timeout)
|
||||
else:
|
||||
device_logout_async(product_sn=self.product_sn,
|
||||
device_sn=self.device_sn)
|
||||
self.online = False
|
||||
del_connect_map(self._identity)
|
||||
|
||||
def login(self, sync=False, timeout=5):
|
||||
if self._identity == '':
|
||||
raise EdgeDriverLinkDeviceConfigException
|
||||
|
||||
add_connect_map(self._identity, self)
|
||||
|
||||
if sync:
|
||||
device_login_sync(product_sn=self.product_sn,
|
||||
device_sn=self.device_sn, timeout=timeout)
|
||||
else:
|
||||
device_login_async(product_sn=self.product_sn,
|
||||
device_sn=self.device_sn)
|
||||
self.online = True
|
||||
|
||||
def publish(self, topic: str, payload: b''):
|
||||
if self.online:
|
||||
send_message(topic, payload, is_cached=False,
|
||||
duration=0)
|
||||
else:
|
||||
raise EdgeDriverLinkDeviceOfflineException
|
||||
|
||||
|
||||
class Config(object):
|
||||
def __init__(self, config=None):
|
||||
self.config = config
|
||||
|
||||
def getDriverInfo(self):
|
||||
return _driverInfo
|
||||
|
||||
def getDeviceInfos(self):
|
||||
return _deviceInfos
|
||||
|
||||
|
||||
def getConfig():
|
||||
if _driverInfo is None:
|
||||
config = {"deviceList": _deviceInfos}
|
||||
else:
|
||||
config = {
|
||||
"config": _driverInfo,
|
||||
"deviceList": _deviceInfos}
|
||||
return json.dumps(config)
|
484
uiotedgedriverlinksdk/edge.py
Normal file
484
uiotedgedriverlinksdk/edge.py
Normal file
@ -0,0 +1,484 @@
|
||||
import base64
|
||||
import json
|
||||
import queue
|
||||
import random
|
||||
import string
|
||||
import threading
|
||||
import time
|
||||
|
||||
from cachetools import TTLCache
|
||||
|
||||
from uiotedgedriverlinksdk import _driver_id, getLogger
|
||||
from uiotedgedriverlinksdk.exception import (EdgeDriverLinkException,
|
||||
EdgeDriverLinkOfflineException,
|
||||
EdgeDriverLinkTimeoutException)
|
||||
from uiotedgedriverlinksdk.nats import (_nat_publish_queue,
|
||||
_nat_subscribe_queue, publish_nats_msg)
|
||||
|
||||
_logger = getLogger()
|
||||
_action_queue_map = {}
|
||||
_connect_map = {}
|
||||
|
||||
_cache = TTLCache(maxsize=10, ttl=30)
|
||||
|
||||
|
||||
def get_edge_online_status():
|
||||
global _cache
|
||||
is_online = _cache.get('edge_status')
|
||||
if is_online:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def add_connect_map(key: str, value):
|
||||
global _connect_map
|
||||
_connect_map[key] = value
|
||||
|
||||
|
||||
def del_connect_map(key: str):
|
||||
global _connect_map
|
||||
_connect_map.pop(key)
|
||||
|
||||
|
||||
def _generate_request_id():
|
||||
return ''.join(random.sample(string.ascii_letters + string.digits, 16)).lower()
|
||||
|
||||
|
||||
class _device_notify(object):
|
||||
def __init__(self, callback):
|
||||
self.callback = callback
|
||||
|
||||
def run(self, message):
|
||||
self.callback(message)
|
||||
|
||||
|
||||
_on_topo_change_callback = None
|
||||
|
||||
|
||||
def set_on_topo_change_callback(callback):
|
||||
global _on_topo_change_callback
|
||||
_on_topo_change_callback = _device_notify(callback)
|
||||
|
||||
|
||||
_on_status_change_callback = None
|
||||
|
||||
|
||||
def set_on_status_change_callback(callback):
|
||||
global _on_status_change_callback
|
||||
_on_status_change_callback = _device_notify(callback)
|
||||
|
||||
|
||||
def get_topo(timeout=5):
|
||||
global _action_queue_map
|
||||
request_id = _generate_request_id()
|
||||
topic = '/$system/%s/%s/subdev/topo/get' % (
|
||||
_generate_request_id(), "123456")
|
||||
|
||||
get_topo = {
|
||||
'RequestID': request_id,
|
||||
"Params": []
|
||||
}
|
||||
try:
|
||||
data = json.dumps(get_topo)
|
||||
_publish(topic=topic, payload=data.encode('utf-8'),
|
||||
is_cached=False, duration=0)
|
||||
q = queue.Queue()
|
||||
_action_queue_map[request_id] = q
|
||||
|
||||
msg = q.get(timeout=5)
|
||||
if msg['RetCode'] != 0:
|
||||
raise EdgeDriverLinkException(msg['RetCode'], msg['Message'])
|
||||
|
||||
return msg
|
||||
|
||||
except queue.Empty:
|
||||
raise EdgeDriverLinkTimeoutException
|
||||
except EdgeDriverLinkException as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
raise e
|
||||
finally:
|
||||
_action_queue_map.pop(request_id)
|
||||
|
||||
|
||||
def add_topo(product_sn, device_sn, timeout=5):
|
||||
global _action_queue_map
|
||||
if get_edge_online_status():
|
||||
request_id = _generate_request_id()
|
||||
topic = '/$system/%s/%s/subdev/topo/add' % (
|
||||
product_sn, device_sn)
|
||||
|
||||
add_topo = {
|
||||
'RequestID': request_id,
|
||||
"Params": [
|
||||
{
|
||||
'ProductSN': product_sn,
|
||||
'DeviceSN': device_sn
|
||||
}
|
||||
]
|
||||
}
|
||||
try:
|
||||
data = json.dumps(add_topo)
|
||||
_publish(topic=topic, payload=data.encode('utf-8'),
|
||||
is_cached=False, duration=0)
|
||||
q = queue.Queue()
|
||||
_action_queue_map[request_id] = q
|
||||
|
||||
msg = q.get(timeout=5)
|
||||
|
||||
_action_queue_map.pop(request_id)
|
||||
if msg['RetCode'] != 0:
|
||||
raise EdgeDriverLinkException(msg['RetCode'], msg['Message'])
|
||||
|
||||
except queue.Empty:
|
||||
raise EdgeDriverLinkTimeoutException
|
||||
except EdgeDriverLinkException as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
raise e
|
||||
else:
|
||||
raise EdgeDriverLinkOfflineException
|
||||
|
||||
|
||||
def delete_topo(product_sn, device_sn, timeout=5):
|
||||
global _action_queue_map
|
||||
if get_edge_online_status():
|
||||
request_id = _generate_request_id()
|
||||
topic = '/$system/%s/%s/subdev/topo/delete' % (
|
||||
product_sn, device_sn)
|
||||
|
||||
delete_topo = {
|
||||
'RequestID': request_id,
|
||||
"Params": [
|
||||
{
|
||||
'ProductSN': product_sn,
|
||||
'DeviceSN': device_sn
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
try:
|
||||
data = json.dumps(delete_topo)
|
||||
_publish(topic=topic, payload=data.encode('utf-8'),
|
||||
is_cached=False, duration=0)
|
||||
q = queue.Queue()
|
||||
_action_queue_map[request_id] = q
|
||||
|
||||
msg = q.get(timeout=5)
|
||||
|
||||
_action_queue_map.pop(request_id)
|
||||
if msg['RetCode'] != 0:
|
||||
raise EdgeDriverLinkException(msg['RetCode'], msg['Message'])
|
||||
|
||||
except queue.Empty:
|
||||
raise EdgeDriverLinkTimeoutException
|
||||
except EdgeDriverLinkException as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
raise e
|
||||
else:
|
||||
raise EdgeDriverLinkOfflineException
|
||||
|
||||
|
||||
def register_device(product_sn, device_sn, product_secret, timeout=5):
|
||||
global _action_queue_map
|
||||
if get_edge_online_status():
|
||||
request_id = _generate_request_id()
|
||||
register_data = {
|
||||
'RequestID': request_id,
|
||||
"Params": [
|
||||
{
|
||||
'ProductSN': product_sn,
|
||||
'DeviceSN': device_sn,
|
||||
'ProductSecret': product_secret
|
||||
}
|
||||
]
|
||||
}
|
||||
topic = '/$system/%s/%s/subdev/register' % (
|
||||
product_sn, device_sn)
|
||||
|
||||
try:
|
||||
data = json.dumps(register_data)
|
||||
_publish(topic=topic, payload=data.encode('utf-8'),
|
||||
is_cached=False, duration=0)
|
||||
q = queue.Queue()
|
||||
_action_queue_map[request_id] = q
|
||||
|
||||
msg = q.get(timeout=timeout)
|
||||
_action_queue_map.pop(request_id)
|
||||
if msg['RetCode'] != 0:
|
||||
raise EdgeDriverLinkException(msg['RetCode'], msg['Message'])
|
||||
|
||||
except queue.Empty:
|
||||
raise EdgeDriverLinkTimeoutException
|
||||
except EdgeDriverLinkException as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
raise e
|
||||
else:
|
||||
raise EdgeDriverLinkOfflineException
|
||||
|
||||
|
||||
def device_login_async(product_sn, device_sn):
|
||||
request_id = _generate_request_id()
|
||||
topic = '/$system/%s/%s/subdev/login' % (
|
||||
product_sn, device_sn)
|
||||
|
||||
device_login_msg = {
|
||||
'RequestID': request_id,
|
||||
"Params": [
|
||||
{
|
||||
'ProductSN': product_sn,
|
||||
'DeviceSN': device_sn
|
||||
}
|
||||
]
|
||||
}
|
||||
data = json.dumps(device_login_msg)
|
||||
_publish(topic=topic, payload=data.encode('utf-8'),
|
||||
is_cached=False, duration=0)
|
||||
|
||||
|
||||
def device_logout_async(product_sn, device_sn):
|
||||
request_id = _generate_request_id()
|
||||
topic = '/$system/%s/%s/subdev/logout' % (
|
||||
product_sn, device_sn)
|
||||
|
||||
device_logout_msg = {
|
||||
'RequestID': request_id,
|
||||
"Params": [
|
||||
{
|
||||
'ProductSN': product_sn,
|
||||
'DeviceSN': device_sn
|
||||
}
|
||||
]
|
||||
}
|
||||
data = json.dumps(device_logout_msg)
|
||||
_publish(topic=topic, payload=data.encode('utf-8'),
|
||||
is_cached=False, duration=0)
|
||||
|
||||
|
||||
def device_login_sync(product_sn, device_sn, timeout=5):
|
||||
global _action_queue_map
|
||||
request_id = _generate_request_id()
|
||||
topic = '/$system/%s/%s/subdev/login' % (
|
||||
product_sn, device_sn)
|
||||
|
||||
device_login_msg = {
|
||||
'RequestID': request_id,
|
||||
"Params": [
|
||||
{
|
||||
'ProductSN': product_sn,
|
||||
'DeviceSN': device_sn
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
try:
|
||||
data = json.dumps(device_login_msg)
|
||||
_publish(topic=topic, payload=data.encode('utf-8'),
|
||||
is_cached=False, duration=0)
|
||||
q = queue.Queue()
|
||||
_action_queue_map[request_id] = q
|
||||
|
||||
msg = q.get(timeout=timeout)
|
||||
_action_queue_map.pop(request_id)
|
||||
if msg['RetCode'] != 0:
|
||||
raise EdgeDriverLinkException(msg['RetCode'], msg['Message'])
|
||||
|
||||
except queue.Empty:
|
||||
raise EdgeDriverLinkTimeoutException
|
||||
except EdgeDriverLinkException as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
|
||||
def device_logout_sync(product_sn, device_sn, timeout=5):
|
||||
global _action_queue_map
|
||||
request_id = _generate_request_id()
|
||||
topic = '/$system/%s/%s/subdev/logout' % (
|
||||
product_sn, device_sn)
|
||||
|
||||
device_logout_msg = {
|
||||
'RequestID': request_id,
|
||||
"Params": [
|
||||
{
|
||||
'ProductSN': product_sn,
|
||||
'DeviceSN': device_sn
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
try:
|
||||
data = json.dumps(device_logout_msg)
|
||||
_publish(topic=topic, payload=data.encode('utf-8'),
|
||||
is_cached=False, duration=0)
|
||||
q = queue.Queue()
|
||||
_action_queue_map[request_id] = q
|
||||
|
||||
msg = q.get(timeout=timeout)
|
||||
_action_queue_map.pop(request_id)
|
||||
if msg['RetCode'] != 0:
|
||||
raise EdgeDriverLinkException(msg['RetCode'], msg['Message'])
|
||||
|
||||
except queue.Empty:
|
||||
raise EdgeDriverLinkTimeoutException
|
||||
except EdgeDriverLinkException as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
|
||||
def send_message(topic: str, payload: b'', is_cached=False, duration=0):
|
||||
_publish(topic=topic, payload=payload,
|
||||
is_cached=is_cached, duration=duration)
|
||||
|
||||
|
||||
def _on_broadcast_message(message):
|
||||
global _on_topo_change_callback
|
||||
global _on_status_change_callback
|
||||
global _action_queue_map
|
||||
_logger.debug("recv message:{} " .format(str(message)))
|
||||
try:
|
||||
js = json.loads(message)
|
||||
topic = js['topic']
|
||||
|
||||
data = str(base64.b64decode(js['payload']), "utf-8")
|
||||
# _logger.debug("broadcast message payload: " + data)
|
||||
|
||||
msg = json.loads(data)
|
||||
|
||||
if isinstance(topic, str) and topic.startswith("/$system/"):
|
||||
# on topo change callback
|
||||
if topic.endswith("/subdev/topo/notify/add"):
|
||||
if _on_topo_change_callback:
|
||||
msg['operation'] = 'add'
|
||||
_on_topo_change_callback.run(msg)
|
||||
|
||||
elif topic.endswith("/subdev/topo/notify/delete"):
|
||||
if _on_topo_change_callback:
|
||||
msg['operation'] = 'delete'
|
||||
_on_topo_change_callback.run(msg)
|
||||
|
||||
elif topic.endswith('/subdev/enable'):
|
||||
if _on_status_change_callback:
|
||||
msg['operation'] = 'enable'
|
||||
_on_status_change_callback.run(msg)
|
||||
|
||||
elif topic.endswith('/subdev/disable'):
|
||||
if _on_status_change_callback:
|
||||
msg['operation'] = 'disable'
|
||||
_on_status_change_callback.run(msg)
|
||||
|
||||
else:
|
||||
request_id = msg['RequestID']
|
||||
if request_id in _action_queue_map:
|
||||
q = _action_queue_map[request_id]
|
||||
q.put(msg)
|
||||
else:
|
||||
_logger.debug('unknown message topic:{}'.format(topic))
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
_logger.error(e)
|
||||
|
||||
|
||||
def _on_message(message):
|
||||
global _connect_map
|
||||
_logger.debug("recv message: {}".format(str(message)))
|
||||
try:
|
||||
js = json.loads(message)
|
||||
identify = js['productSN'] + \
|
||||
'.'+js['deviceSN']
|
||||
|
||||
topic = js['topic']
|
||||
msg = base64.b64decode(js['payload'])
|
||||
# _logger.debug("normal message payload: {}".format(str(msg, 'utf-8')))
|
||||
if identify in _connect_map:
|
||||
sub_dev = _connect_map[identify]
|
||||
if sub_dev.callback:
|
||||
sub_dev.callback(topic, msg)
|
||||
else:
|
||||
_logger.error('unknown message topic:{}'.format(topic))
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
_logger.error(e)
|
||||
|
||||
|
||||
def _publish(topic: str, payload: b'', is_cached=False, duration=0):
|
||||
try:
|
||||
payload_encode = base64.b64encode(payload)
|
||||
data = {
|
||||
'src': 'local',
|
||||
'topic': topic,
|
||||
'isCatched': is_cached,
|
||||
'duration': duration,
|
||||
'payload': str(payload_encode, 'utf-8')
|
||||
}
|
||||
publish_nats_msg(data)
|
||||
except Exception as e:
|
||||
_logger.error(e)
|
||||
raise e
|
||||
|
||||
|
||||
def _set_edge_status():
|
||||
global _cache
|
||||
_cache['edge_status'] = True
|
||||
|
||||
|
||||
def init_subscribe_handler():
|
||||
while True:
|
||||
msg = _nat_subscribe_queue.get()
|
||||
# _logger.debug(msg)
|
||||
subject = msg.subject
|
||||
data = msg.data.decode()
|
||||
|
||||
if subject == "edge.local.broadcast":
|
||||
_on_broadcast_message(data)
|
||||
elif subject == "edge.state.reply":
|
||||
_set_edge_status()
|
||||
else:
|
||||
_on_message(data)
|
||||
|
||||
|
||||
def _get_device_list():
|
||||
global _connect_map
|
||||
result = []
|
||||
for v in _connect_map.values():
|
||||
result.append(v.get_device_info())
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def fetch_online_status():
|
||||
min_retry_timeout = 1
|
||||
max_retry_timeout = 15
|
||||
retry_timeout = min_retry_timeout
|
||||
while True:
|
||||
device_list = _get_device_list()
|
||||
data = {
|
||||
'payload': {
|
||||
'driverID': _driver_id,
|
||||
'devices': device_list
|
||||
},
|
||||
'subject': 'edge.state.req'
|
||||
}
|
||||
|
||||
_nat_publish_queue.put(data)
|
||||
|
||||
if get_edge_online_status():
|
||||
time.sleep(max_retry_timeout)
|
||||
else:
|
||||
if retry_timeout < max_retry_timeout:
|
||||
retry_timeout = retry_timeout + 1
|
||||
time.sleep(retry_timeout)
|
||||
|
||||
|
||||
_t_sub = threading.Thread(target=init_subscribe_handler)
|
||||
_t_sub.setDaemon(True)
|
||||
_t_sub.start()
|
||||
|
||||
_t_online = threading.Thread(target=fetch_online_status)
|
||||
_t_online.setDaemon(True)
|
||||
_t_online.start()
|
39
uiotedgedriverlinksdk/exception.py
Normal file
39
uiotedgedriverlinksdk/exception.py
Normal file
@ -0,0 +1,39 @@
|
||||
class BaseEdgeException(Exception):
|
||||
def gatherAttrs(self):
|
||||
return ",".join("{}={}"
|
||||
.format(k, getattr(self, k))
|
||||
for k in self.__dict__.keys())
|
||||
|
||||
def __str__(self):
|
||||
return "[{}:{}]".format(self.__class__.__name__, self.gatherAttrs())
|
||||
|
||||
|
||||
class EdgeDriverLinkException(BaseEdgeException):
|
||||
def __init__(self, code, msg):
|
||||
self.code = code
|
||||
self.msg = msg
|
||||
|
||||
|
||||
class EdgeDriverLinkTimeoutException(BaseEdgeException):
|
||||
def __str__(self):
|
||||
return "[{}:{}]".format(self.__class__.__name__, 'wait response timeout, please check network or edge connect state.')
|
||||
|
||||
|
||||
class EdgeDriverLinkDeviceConfigException(BaseEdgeException):
|
||||
def __str__(self):
|
||||
return "[{}:{}]".format(self.__class__.__name__, 'device param error, please make sure product_sn and device_sn not null.')
|
||||
|
||||
|
||||
class EdgeDriverLinkDeviceOfflineException(BaseEdgeException):
|
||||
def __str__(self):
|
||||
return "[{}:{}]".format(self.__class__.__name__, 'device offline, please login first.')
|
||||
|
||||
|
||||
class EdgeDriverLinkOfflineException(BaseEdgeException):
|
||||
def __str__(self):
|
||||
return "[{}:{}]".format(self.__class__.__name__, 'edge offline, please connect first.')
|
||||
|
||||
|
||||
class EdgeDriverLinkDeviceProductSecretException(BaseEdgeException):
|
||||
def __str__(self):
|
||||
return "[{}:{}]".format(self.__class__.__name__, 'product secret param error, please make sure product secret not null.')
|
114
uiotedgedriverlinksdk/nats.py
Normal file
114
uiotedgedriverlinksdk/nats.py
Normal file
@ -0,0 +1,114 @@
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import queue
|
||||
import random
|
||||
import signal
|
||||
import string
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
from nats.aio.client import Client as NATS
|
||||
from nats.aio.errors import NatsError
|
||||
from uiotedgedriverlinksdk import _driver_id, getLogger
|
||||
|
||||
_logger = getLogger()
|
||||
|
||||
|
||||
def exit_handler(signum, frame):
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
_nat_publish_queue = queue.Queue()
|
||||
_nat_subscribe_queue = queue.Queue()
|
||||
|
||||
|
||||
class natsClientPub(object):
|
||||
def __init__(self):
|
||||
self.url = os.environ.get(
|
||||
'UIOTEDGE_NATS_ADDRESS') or 'tcp://127.0.0.1:4222'
|
||||
self.nc = NATS()
|
||||
self.loop = asyncio.new_event_loop()
|
||||
|
||||
async def _publish(self):
|
||||
global _nat_publish_queue
|
||||
try:
|
||||
await self.nc.connect(servers=[self.url], loop=self.loop)
|
||||
except Exception as e1:
|
||||
_logger.error(e1)
|
||||
sys.exit(1)
|
||||
|
||||
while True:
|
||||
try:
|
||||
msg = _nat_publish_queue.get()
|
||||
bty = json.dumps(msg['payload'])
|
||||
await self.nc.publish(subject=msg['subject'],
|
||||
payload=bty.encode('utf-8'))
|
||||
await self.nc.flush()
|
||||
except NatsError as e:
|
||||
_logger.error(e)
|
||||
except Exception as e:
|
||||
_logger.error(e)
|
||||
|
||||
def start(self):
|
||||
self.loop.run_until_complete(self._publish())
|
||||
# self.loop.run_forever()
|
||||
|
||||
|
||||
class natsClientSub(object):
|
||||
def __init__(self):
|
||||
self.url = os.environ.get(
|
||||
'UIOTEDGE_NATS_ADDRESS') or 'tcp://127.0.0.1:4222'
|
||||
self.nc = NATS()
|
||||
self.loop = asyncio.new_event_loop()
|
||||
|
||||
async def _connect(self):
|
||||
try:
|
||||
await self.nc.connect(servers=[self.url], loop=self.loop)
|
||||
except Exception as e1:
|
||||
_logger.error(e1)
|
||||
sys.exit(1)
|
||||
|
||||
async def message_handler(msg):
|
||||
global _nat_subscribe_queue
|
||||
# subject = msg.subject
|
||||
# reply = msg.reply
|
||||
# data = msg.data.decode()
|
||||
# sdk_print("Received a message on '{subject} {reply}': {data}".format(
|
||||
# subject=subject, reply=reply, data=data))
|
||||
_nat_subscribe_queue.put(msg)
|
||||
await self.nc.subscribe("edge.local."+_driver_id, queue=_driver_id, cb=message_handler, is_async=True)
|
||||
await self.nc.subscribe("edge.local.broadcast", queue=_driver_id, cb=message_handler, is_async=True)
|
||||
await self.nc.subscribe("edge.state.reply", queue=_driver_id, cb=message_handler, is_async=True)
|
||||
await self.nc.flush()
|
||||
|
||||
def start(self):
|
||||
self.loop.run_until_complete(self._connect())
|
||||
self.loop.run_forever()
|
||||
|
||||
|
||||
def publish_nats_msg(msg):
|
||||
global _nat_publish_queue
|
||||
data = {
|
||||
'subject': 'edge.router.'+_driver_id,
|
||||
'payload': msg
|
||||
}
|
||||
_nat_publish_queue.put(data)
|
||||
|
||||
|
||||
def start_pub():
|
||||
natsClientPub().start()
|
||||
|
||||
|
||||
def start_sub():
|
||||
natsClientSub().start()
|
||||
|
||||
|
||||
_t_nats_pub = threading.Thread(target=start_pub)
|
||||
_t_nats_pub.setDaemon(True)
|
||||
_t_nats_pub.start()
|
||||
|
||||
_t_nats_sub = threading.Thread(target=start_sub)
|
||||
_t_nats_sub.setDaemon(True)
|
||||
_t_nats_sub.start()
|
Loading…
x
Reference in New Issue
Block a user