Skip to main content

数据接入驱动开发

本文将会详细介绍如何使用 Python SDK 开发自定义数据接入驱动. 示例项目目上传至 https://github.com/air-iot/sdk-python-examples/tree/master/driver.

介绍

数据接入驱动 是为实现从不同的协议、设备或其它平台系统采集数据而开发的特定程序. 每个 数据接入驱动 程序需要根据协议的特点实现数据采集功能,然后将采集到的数据通过 Python SDK 提供的接口发送到平台.

Python SDK 提供了 数据接入驱动 开发的相关内容. 包括驱动的接口定义, 以及与平台交互功能. 开发者只需要在项目中引入 airiot_python_sdk 依赖, 定义配置信息(schema及配置类),然后实现 DriverApp 接口中的方法即可.

开发步骤

1. 创建项目

数据接入驱动开发, 对项目结构未做要求, 根据自己的习惯创建项目即可. 使用的 Python 版本见 版本说明.

2. 引入SDK

安装使用

info

驱动二次开发相关内容都在 driver 子包内.

3. 定义schema

数据接入驱动 需要定义一个 schema 用于描述驱动的配置信息. schema 是一个类似于 json 格式的对象, 详细格式说明见 数据接入驱动schema说明. 以下是一个简单的示例:

({
"driver": {
"properties": {
"settings": {
"title": "模型配置",
"type": "object",
"properties": {
"server": {
"type": "string",
"title": "MQTT Broker",
"descripption": "MQTT 服务器地址. 例如: tcp://127.0.0.1:1883"
},
"username": {
"type": "string",
"title": "用户名",
},
"password": {
"type": "string",
"title": "密码",
"fieldType": "password"
},
"network": {
"type": "object",
"title": "通讯监控参数",
"properties": {
"timeout": {
"title": "通讯超时时间(s)",
"description": "经过多长时间仪表还没有任何数据上传,认定为通讯故障",
"type": "number"
}
},
"form": [{
"key": "timeout",
}]
}
},
"required": ["server", "username", "password"]
},
"tags": {
"title": "数据点",
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string",
"title": "Key",
"description": "数据点在 JSON 对象中的 Key. 例如: 'temperature'",
},
},
"required": ["key"]
}
},
"commands": {
"title": "命令",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "名称"
},
"ops": {
"type": "array",
"title": "指令",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "主题",
"description": "发送消息的主题. 例如: /cmd/control",
},
"message": {
"type": "string",
"title": "消息",
"description": "发送的消息. 例如: {\"cmd\":\"start\"}",
},
"qos": {
"type": "number",
"title": "QoS",
"description": "消息质量. 0,1,2",
"enum": ["0", "1", "2"],
"enum_title": ["QoS0", "QoS1", "QoS2"]
},
},
"required": ["name", "message"]
}
}
}
}
}
}
},
"model": {
"properties": {
"settings": {
"title": "模型配置",
"type": "object",
"properties": {
"topic": {
"type": "string",
"title": "主题",
"descripption": "接收数据的主题. 例如: /data/#"
},
"parseScript": {
"type": "string",
"title": "数据处理脚本",
"fieldType": "deviceScriptEdit",
"description": "消息处理脚本. 函数名必须为 'handler'",
"defaultScript": "/**\n" +
" * 数据处理脚本, 处理从 mqtt 接收到的数据.\n" +
" *\n" +
" * @param {string} topic 消息主题\n" +
" * @param {string} message 消息内容\n" +
" * @return 消息解析结果\n" +
" */\n" +
"function handler(topic, message) {\n" +
"\t\n" +
"\t// 脚本返回值必须为对象数组\n" +
"\t// \tid: 资产编号\n" +
"\t//\ttime: 时间戳(毫秒)\n" +
"\t// fields: 数据点数据. 该字段为 JSON 对象, key 为数据点标识, value 为数据点的值\n" +
"\treturn [\n" +
"\t\t{\"id\": \"SN10001\", \"time\": new Date().getTime(), \"fields\": {\"key1\": \"this is a string value\", \"key2\": true, \"key3\": 123.456}}\n" +
"\t];\n" +
"}"
},
"commandScript": {
"type": "string",
"title": "指令处理脚本",
"fieldType": "deviceScriptEdit",
"description": "指令处理脚本. 函数名必须为 'handler'",
"defaultScript": "/**\n" +
" * 指令处理脚本. 发送指令时会将指令内容传递给脚本, 然后由指定返回最终要发送的信息.\n" +
" *\n" +
" * @param {string} 工作表标识\n" +
" * @param {string} 资产编号\n" +
" * @param {object} 命令内容\n" +
" * @return {object} 最终要发送的消息, 及目标 topic\n" +
" */\n" +
"function handler(tableId, deviceId, command) {\n" +
"\t\n" +
"\t// 脚本返回值必须为下面对象结构\n" +
"\t//\t\ttopic: 消息发送的目标 topic\n" +
"\t//\t\tpayload: 消息内容\n" +
"\treturn {\n" +
"\t\t\"topic\": \"cmd/\" + deviceId,\n" +
"\t\t\"payload\": \"发送内容\"\n" +
"\t};\n" +
"}"
},
"network": {
"type": "object",
"title": "通讯监控参数",
"properties": {
"timeout": {
"title": "通讯超时时间(s)",
"description": "经过多长时间仪表还没有任何数据上传,认定为通讯故障",
"type": "number"
}
},
"form": [{
"key": "timeout",
}]
}
},
"required": ["server", "username", "password", "topic"]
},
"tags": {
"title": "数据点",
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string",
"title": "Key",
"description": "数据点在 JSON 对象中的 Key. 例如: 'temperature'",
},
},
"required": ["key"]
}
},
"commands": {
"title": "命令",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "名称"
},
"ops": {
"type": "array",
"title": "指令",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "主题",
"description": "发送消息的主题. 例如: /cmd/control",
},
"message": {
"type": "string",
"title": "消息",
"description": "发送的消息. 例如: {\"cmd\":\"start\"}",
},
"qos": {
"type": "number",
"title": "QoS",
"description": "消息质量. 0,1,2",
"enum": ["0", "1", "2"],
"enum_title": ["QoS0", "QoS1", "QoS2"]
},
},
"required": ["name", "message"]
}
}
}
}
}
}
},
"device": {
"properties": {
"settings": {
"title": "设备配置",
"type": "object",
"properties": {
"customDeviceId": {
"type": "string",
"title": "设备编号",
"descripption": "自定义设备编号. 如果未定义则使用平台中的资产编号"
},
"network": {
"type": "object",
"title": "通讯监控参数",
"properties": {
"timeout": {
"title": "通讯超时时间(s)",
"description": "经过多长时间仪表还没有任何数据上传,认定为通讯故障",
"type": "number"
}
}
}
},
"required": []
}
}
}
})

4. 实现驱动接口

数据接入驱动二次开发SDK中, 有两个重要接口: 数据接入驱动接口驱动与平台交互接口, 分别为 DriverAppDataSender.

  • 数据接入驱动接口(DriverApp) 该接口中定义平台控制驱动程序运行的相关方法, 是平台控制驱动程序的入口. SDK 在驱动程序启动后, 会监听平台下发的控制指令, 然后调用 数据接入驱动接口 中的方法并将执行结果返回给平台. 开发者需要实现这个接口, 并提供一个工厂类 DriverAppFactory, 并且将工厂类传递给驱动启动器 Launcher. 接口定义及详细说明见 数据接入驱动接口说明.

  • 驱动与平台交互接口(DataSender) 是驱动程序与平台进行交互的接口. 驱动程序在运行过程中, 除了接收平台的控制之外, 也需要与平台进行各种交互. 例如: 向平台发送采集的到数据, 向平台发送指令执行结果、调试日志等. SDK 中定义了 驱动与平台交互接口 DataSender 以及实现类, 该实现类会通过工厂类方法传入, 可以在工厂类方法中创建 DriverApp 时保存该对象. 接口定义及详细说明见 驱动与平台交互接口说明.

注: 向平台上报采集到的数据时, 必须通过 驱动与平台交互接口 中的 writePoint 方法发送, 不能直接调用 MQTT 客户端发送. 因为 SDK 会对发送的数据进行一些处理, 包括有效范围处理、数值映射、缩放比例、小数位等处理. :::

5. 配置驱动

这里所说 驱动配置 主要是一些静态配置信息(与 schema 中定义的配置无关), 其中包括 平台配置信息, 驱动配置信息自定义配置信息. 这些信息一般通过配置文件(application.yml)、环境变量、命令行参数等方式传入. 其中一些配置信息由平台启动驱动时通过命令行参数传入.

这些配置信息, 在开发过程中可以根据实际情况进行调整. 但是在打包时必须按照平台的要求进行配置. 打包时的配置信息见 驱动配置说明.

info

自定义配置信息 是指驱动本身的一些配置信息, 对驱动使用者不可见. 例如: 连接池大小. 这些信息一般通过配置文件(application.yml)、环境变量、命令行参数等方式传入.

平台配置信息

平台配置信息 主要为平台的连接信息. 包括: MQTT 连接信息, 驱动管理服务 连接信息. 内容如下:

# 驱动管理服务配置信息
driver-grpc:
# 在开发时, 需要配置为平台的地址
host: 192.168.11.101
# 端口默认为 9224, 一般无须修改. 如果有修改, 可在运维管理系统中查看 `driver` 服务的端口号
port: 9224
# 平台 MQTT 配置信息
mq:
mqtt:
# 在开发时, 需要配置为平台的地址
host: 192.168.11.101
port: 1883
username: admin
password: public
# 如果驱动对外提供 web 接口服务, 则需要按以下方式配置 web 服务的端口号
server:
port: 8080
info

相关服务的端口号可在运维管理系统中查看. 平台中的 driver 服务的端口对应 driver-grpc.port 配置项, mqtt 服务的端口对应 mq.mqtt.port 配置项.

驱动配置信息

驱动配置信息 主要包括 驱动ID, 驱动名称, 驱动实例ID, 所属项目ID.

  • 驱动ID 为驱动的唯一标识, 必须在平台中唯一.
  • 驱动名称 为该驱动在平台中的显示名称.
  • 驱动实例ID 为该驱动实例的唯一标识. 同一个驱动可以创建多个实例, 每个实例的 驱动ID 相同但 驱动实例ID 唯一. 该信息由平台在 驱动管理 中创建驱动实例时生成.
  • 所属项目ID 每个驱动实例都属于一个项目, 该驱动实例只会拿到该项目中的模型和设备信息.
id: 驱动ID
name: 驱动名称
info
  1. 驱动ID驱动名称 需要在 config.yml 中手动定义.

  2. 驱动实例ID所属项目ID 在开发过程中, 需要将这些信息手动配置到 application.yml 中. 在打包时无须定义, 在平台中安装驱动时这些信息会由平台通过命令行参数传入.

示例配置

id: python_sdk_demo_driver
name: PythonSDK示例驱动
# 驱动管理服务配置信息
driver-grpc:
# 在开发时, 需要配置为平台的地址
host: 192.168.11.101
# 端口默认为 9224, 一般无须修改. 如果有修改, 可在运维管理系统中查看 `driver` 服务的端口号
port: 9224
# 平台 MQTT 配置信息
mq:
mqtt:
# 在开发时, 需要配置为平台的地址
host: 192.168.11.101
port: 1883
username: admin
password: public
# 如果驱动对外提供 web 接口服务, 则需要按以下方式配置 web 服务的端口号
server:
port: 8080

6. 打包

驱动打包就是将开发完成的程序打包为可以在平台部署的驱动. 平台自身支持运行在 windowslinuxmacOS 系统中, 并且支持 x86arm 平台. 在 windows 系统中平台服务和驱动程序都是直接运行在操作系统中, 而在 linux 系统中是以 容器 的方式运行, 平台中的每个服务和驱动程序都是一个独立的容器, 所以针对不同的操作系统打包方式也不相同. 下面分别介绍在 windowslinux 系统中如何打包驱动, 对于不同平台只需要保证使用软件和库支持即可.

windows系统打包

  1. 将程序和相关资源打包. 可以使用 PyInstaller 等工具将程序打包为可执行文件, 或者直接使用 python main.py 等方式运行程序. 注: 使用 python main.py 的方式运行程序时, 需要将 python 运行环境一起打包

  2. 准备驱动配置文件 config.yml. 可以将 config.yml 文件放在根目录下, 或放在其它目录中, 然后在程序中加载.

info

注: config.yml 中需要填写好 驱动ID驱动名称 两个配置项.

  1. 准备驱动安装配置文件 service.yml . 在平台中安装驱动时, 需要提供一些驱动的基本信息, 例如: 版本号、驱动描述、端口号等. 这些信息需要在 service.yml 中定义, 平台会根据该文件中的配置信息进行安装. service.yml 的具体格式如下:
# 必填项. 驱动名称
Name: python_sdk_demo_driver
# 非必填项. 如果驱动对外提供 rest 服务, 则需要填写 rest 接口的统一路径前缀.
# 当填写该配置项时, 平台会自动在网关中添加该路径的路由, 并将请求转发到该驱动, 代理端口为 service.yml 文件中的 server.port 配置项.
Path: /python_sdk_demo_driver
# 必填项. 例如: 1.0.0
Version: 1.0.0
# 非必填项.
Description: 驱动描述信息
# 驱动的配置文件名称, 平台在创建驱动时会查找驱动打包文件中查找该文件. 一般固定填写 service.yml
ConfigType: service.yml
# 必填项. 固定为 driver
GroupName: driver
# 必填项. 驱动启动命令. 还可以添加一些启动参数
# 如果使用 PyInstaller 工具打包, 直接运行打包后的可执行文件即可.
# 例如, 打包后的可执行文件名为 my-program.exe, 直接填写 Command: my-program.exe [args...]
Command: python main.py
  1. 将所有资源打包为 zip 文件.

将项目中的源码或打包后的文件、config.ymlservice.yml 和其它资源打包为 zip 文件, 平台会根据该文件进行安装. 建议打包后的 zip 文件结构如下:

外层目录结构 配置文件目录结构

linux系统打包

由于在 linux 系统中, 驱动程序是以 容器 的方式运行, 所以打包时需要先将驱动程序打包为 docker 镜像. 然后再将镜像文件和 service.yml 打包为 .tar.gz 压缩包. 具体打包步骤如下:

  1. 将程序和相关资源打包. 可以使用 PyInstaller 等工具将程序打包为可执行文件, 或者直接使用带有 python 运行环境的镜像作为基础镜像进行构建自己的镜像. 注: 使用 python main.py 的方式运行程序时, 需要将 python 运行环境一起打包

  2. 准备 Dockerfile 文件. 以下是一个简单的 Dockerfile 文件示例, 具体内容根据自身的需求进行修改:

# 根据自身的需求选择合适的基础镜像
FROM python:3.10.12-alpine

WORKDIR /app

# 如果驱动配置文件在 jar 文件外面
COPY config.yml /app/
# 复制 jar 文件
COPY main.py /app/main.py

# 启动命令, 根据自身的需求添加启动参数
# 注: 必须使用 ENTRYPOINT 启动程序
ENTRYPOINT ["python", "main.py"]
  1. 构建 docker 镜像.

使用上一步中的 Dockerfile 文件构建 docker 镜像, 具体命令如下:

docker build -t myDriver:1.0.0 .
  1. 导出 docker 镜像并压缩.
docker save myDriver:1.0.0 | gzip > myDriver.tar.gz
  1. 准备驱动安装配置文件 service.yml . 该文件的格式与 windows系统打包 中的第三步中的 service.yml 文件格式相似但又有区别. 具体格式如下:
# 必填项. 驱动名称
Name: python_sdk_demo_driver
# 非必填项. 如果驱动对外提供 rest 服务, 则需要填写 rest 接口的统一路径前缀.
# 当填写该配置项时, 平台会自动在网关中添加该路径的路由, 并将请求转发到该驱动, 代理端口为 application.yml 文件中的 server.port 配置项.
Path: /python_sdk_demo_driver
# 必填项. 例如: 1.0.0, 通常用镜像版本号一致
Version: 1.0.0
# 非必填项.
Description: 驱动描述信息
# 必填项. 固定为 driver
GroupName: driver
# 容器端口映射类型, 非必填项. 如果驱动需要对外提供 rest 服务, 或暴露端口时, 需要填写该配置项.
# 可选项有 None Internal External
#
# None: 不暴露端口
# Internal: 只在平台内部暴露端口. 一般为驱动对外提供 rest 服务时, 将端口映射到网关上, 填写为 Internal 即可.
# External: 对外暴露端口. 一般为驱动为作 server 端, 需要对外暴露端口以供设备连接, 此时该端口会暴露在宿主机上, 填写为 External 即可.
Service: Internal
# 非必填项. 暴露的端口列表
Ports:
- Host: "8558" # 映射到宿主机的端口号, 如果不填写, 则会随机分配一个端口号
Container: "8558" # 容器内部的端口号, 即驱动服务监听的端口号
Protocol: "" # 协议类型, 可选项有 TCP UDP, 如果不填写, 则默认为 TCP
  1. 将所有资源打包为 gzip 文件. 将 docker镜像service.yml 文件打包为 gzip 文件. 打包命令如下:
tar czvf myDriver-linux.tar myDriver.tar service.yml

打包后的 gzip 文件结构如下:

目录结构

info

linux 系统整个打包过程对应的命令如下所示:

# 将驱动打包为镜像
docker build -t myDriver:1.0.0 .

# 导出镜像并压缩
docker save myDriver:1.0.0 | gzip > myDriver.tar.gz

# 将镜像文件和 service.yml 打包
tar czvf myDriver-linux.tar myDriver.tar.gz service.yml

# 最后得到 myDriver-linux.tar.gz 压缩文件

7. 部署

将上一步骤中得到的驱动安装包通过 运维管理系统 上传到平台, 平台会自动解析并安装驱动. 安装成功后, 就可以在项目中使用该驱动了.

安装驱动

  1. 登录 运维管理系统, 运维管理系统的默认登录地址为 http://IP:13030/, 将 IP 换成平台地址即可.
  2. 点击左侧菜单栏中的 服务管理 选项, 进入服务管理页面.
  3. 点击页面右上角的 离线上传驱动 按钮, 选择上一步中得到的 myDriver-linux.tar.gz 文件, 点击 确定 按钮, 平台会自动解析并安装驱动.

离线上传驱动

如果驱动安装失败, 可以在 运维管理系统首页 中查看详细的日志信息.

驱动安装日志

info

不同版本的平台, 离线上传驱动 按扭的位置可能不同.

使用驱动

当驱动成功安装到平台后, 就可以在项目中使用该驱动了.

具体使用方法请参考 驱动管理.

数据接入驱动接口说明

驱动接口定义

class DriverApp:
"""
驱动程序接口. 该接口定义驱动程序与平台交互的方法. 所有驱动程序都需要实现该接口.
"""

@abstractmethod
def get_version(self) -> str:
"""
获取驱动版本号. 例如: v4.0.0
:return: 驱动版本号
"""
pass

@abstractmethod
def http_proxy_enabled(self) -> bool:
"""
是否启用 HTTP 请求代理. 用于代理驱动中的 HTTP 请求, 可以将驱动中的一些功能通过 grpc 代理暴露给平台, 由平台代理驱动中的 HTTP 请求.
:return: 是否启用 HTTP 请求代理. 返回 False 表示不启用, 返回 True 表示启用.
"""
return False

@abstractmethod
async def http_proxy(self, request_type: str, headers: dict[str, List[str]], data: str) -> any:
"""
HTTP 请求代理. 用于代理驱动中的 HTTP 请求, 例如: 获取设备数据, 获取设备属性, 控制设备等.\r\n
当前端请求驱动时, 会将请求转发给平台的 driver 服务, 由 driver 服务通过 listener 协议转发到驱动中, 由驱动自行处理请求并返回响应结果.\r\n
前端 <- http -> driver <- listener -> DriverApp
:param request_type: 请求类型标识, 每个请求类型标识对应一个请求. 例如: getDevices 表示查询设备列表请求.
:param headers: 请求头, 即前端请求时传递的 headers.
:param data: 请求参数.
:return: 请求响应结果
"""
pass

@abstractmethod
async def start(self, config: str):
"""
启动驱动. 当驱动程序启动时, SDK 会连接平台 driver 服务, 连接成功后会调用此方法.
:param config: 驱动配置, 即使用该驱动实例的工作表、设备等信息.
:return:
"""
pass

@abstractmethod
async def stop(self):
"""
停止驱动. 当驱动程序停止时, SDK 会断开平台 driver 服务的连接, 断开连接后会调用此方法.
:return:
"""
pass

@abstractmethod
async def run(self, serial_no: str, table_id: str, device_id: str, command: str) -> any:
"""
执行设备命令. 当前端需要控制设备时, 会调用此方法.
:param serial_no: 平台指令序列号, 每次发送指令时, 平台会生成一个唯一的序列号, 用于标识本次指令.
:param table_id: 设备所属工作表 ID.
:param device_id: 设备编号.
:param command: 指令内容.
:return: 指令执行结果
"""
pass

@abstractmethod
async def batch_run(self, serial_no: str, table_id: str, device_ids: List[str], command: str) -> any:
"""
批量执行设备命令. 当前端需要控制多个设备时, 会调用此方法.
:param serial_no: 平台指令序列号, 每次发送指令时, 平台会生成一个唯一的序列号, 用于标识本次指令.
:param table_id: 设备所属工作表 ID.
:param device_ids: 设备编号列表.
:param command: 指令内容.
:return: 指令执行结果
"""
pass

@abstractmethod
async def write_tag(self, serial_no: str, table_id: str, device_id: str, tag: str) -> any:
"""
向设备的指定数据点写入数据. 只有数据点的 rw 为 true 的数据点, 才能被写入数据.
:param serial_no: 平台指令序列号, 每次发送指令时, 平台会生成一个唯一的序列号, 用于标识本次指令.
:param table_id: 设备所属工作表 ID.
:param device_id: 设备编号列表.
:param tag: 数据点信息及写入的值.
:return: 指令执行结果
"""
pass

@abstractmethod
async def debug(self, debug: str) -> str:
"""
驱动调试. 当前端需要调试驱动时, 会调用此方法.(该方法暂未开放)
:param debug: 调试内容.
:return: 调试结果
"""
pass

@abstractmethod
async def schema(self) -> str:
"""
获取驱动的 schema. 当前端需要获取驱动的 schema 时, 会调用此方法.
:return: 驱动的 schema 定义
"""

工厂类定义

class DriverAppFactory:
"""
驱动程序实例构造工厂接口. 该接口定义驱动程序实例构造工厂的方法. 所有驱动程序实例构造工厂都需要实现该接口.
"""

def create(self, service_id: str, data_sender: DataSender) -> DriverApp:
"""
驱动程序实例构造工厂
:param service_id: 驱动实例ID
:param data_sender: 数据发送器
:return: 驱动程序实例
"""
pass

示例

class MyDriverApp(DriverApp):
"""
驱动程序类
"""


class MyDriverAppFactory(DriverAppFactory):
"""
驱动实例构造工厂
"""
def create(self, service_id: str, data_sender: DataSender) -> DriverApp:
return MyDriverApp()

驱动与平台交互接口说明

class DataSender:
"""
数据发送器, 用于向平台发送数据
"""

async def write_point(self, point: Point):
"""
向平台发送设备采集到的数据
:param point: 设备采集到的数据
:return:
:raise ValueError: point is None
"""
pass

def write_event(self, event: Event) -> Response:
"""
向平台发送事件信息
:param event: 事件信息
:return: 事件发送结果
:raises ValueError: event is None
"""
pass

def update_table_data(self, table_id: str, device_id: str, fields: dict[str, any]) -> Response:
"""
更新设备数据
:param table_id: 设备所属工作表标识
:param device_id: 设备编号
:param fields: 更新的字段信息. key 为字段名, value 为字段值.
:return: 设备信息修改结果
:raise ValueError: the table_id, device_id or fields is None or empty
"""
pass

def write_run_log(self, log: RunLog) -> Response:
"""
向平台发送指令执行日志
:param log: 执行日志
:return: 日志发送结果
:raise ValueError: log is None
"""
pass

def log_debug(self, table_id: str, device_id: str, message: str):
"""
发送 DEBUG 日志. 该日志信息可以在 "设备配置" 中的 "设备调试" 面板中查看.
:param table_id: 设备所属工作表标识
:param device_id: 设备编号
:param message: 日志内容
:return:
"""
pass

def log_info(self, table_id: str, device_id: str, message: str):
"""
发送 INFO 日志. 该日志信息可以在 "设备配置" 中的 "设备调试" 面板中查看.
:param table_id: 设备所属工作表标识
:param device_id: 设备编号
:param message: 日志内容
:return:
"""
pass

def log_warn(self, table_id: str, device_id: str, message: str):
"""
发送 WARN 日志. 该日志信息可以在 "设备配置" 中的 "设备调试" 面板中查看.
:param table_id: 设备所属工作表标识
:param device_id: 设备编号
:param message: 日志内容
:return:
"""
pass

def log_error(self, table_id: str, device_id: str, message: str):
"""
发送 ERROR 日志. 该日志信息可以在 "设备配置" 中的 "设备调试" 面板中查看.
:param table_id: 设备所属工作表标识
:param device_id: 设备编号
:param message: 日志内容
:return:
"""
pass

驱动配置说明

以下是完整的驱动配置文件, 请参考该配置文件进行配置.

id: python_sdk_demo_driver      # 驱动ID
name: PythonSDK示例驱动 # 驱动名称
# 驱动管理服务配置信息
driver-grpc:
# 在开发时, 需要配置为平台的地址
host: 192.168.11.101
# 端口默认为 9224, 一般无须修改. 如果有修改, 可在运维管理系统中查看 `driver` 服务的端口号
port: 9224
# 平台 MQTT 配置信息
mq:
mqtt:
# 在开发时, 需要配置为平台的地址
host: 192.168.11.101
port: 1883
username: admin
password: public
# 如果驱动对外提供 web 接口服务, 则需要按以下方式配置 web 服务的端口号
server:
port: 8080

windows系统打包发布时的驱动配置

id: python_sdk_demo_driver
name: PythonSDK示例驱动
driver-grpc:
host: 127.0.0.1
port: 9224
mq:
mqtt:
host: 127.0.0.1
port: 1883
username: admin
password: public
server:
port: 8080

linux系统打包发布时的驱动配置

id: python_sdk_demo_driver
name: PythonSDK示例驱动
driver-grpc:
host: driver
port: 9224
mq:
mqtt:
host: mqtt
port: 1883
username: admin
password: public
server:
port: 8080