数据接入驱动开发
本文将会详细介绍如何使用 Dotnet SDK
开发自定义数据接入驱动.
介绍
数据接入驱动
是为实现从不同的协议、设备或其它平台系统采集数据而开发的特定程序. 每个 数据接入驱动
程序需要根据协议的特点实现数据采集功能,然后将采集到的数据通过 Dotnet SDK
提供的接口发送到平台.
Dotnet SDK
提供了 数据接入驱动
开发的相关内容. 包括驱动的接口定义, 以及与平台交互功能. 开发者只需要实现接口中的方法.
开发步骤
1. 创建项目
- 创建项目C#控制台程序
- 创建
Programs.cs
文件
2. 引入SDK
- 添加nuget包,详细步骤见Dotnet sdk介绍-使用方式
- 引用命名空间
using AiriotSDK.Data;
using AiriotSDK.Driver;
using AiriotSDK.Tools;
3. 定义schema
数据接入驱动
需要定义一个 schema
用于描述驱动的配置信息. schema
是一个类似于 json
格式的对象, 详细格式说明见 数据接入驱动schema说明. 以下是一个简单的示例:
({
"title": "netcore-driver",
"key": "netcore-driver",
"model": {
"properties": {
"settings": {
"title": "设备配置",
"type": "object",
"properties": {
"interval": {
"type": "number",
"title": "采集周期"
},
"port": {
"type": "number",
"title": "端口"
}
}
},
"tags": {
"title": "数据点",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "名称"
},
"id": {
"type": "string",
"title": "标识"
},
"unit": {
"type": "string",
"title": "单位"
},
"fixed": {
"type": "number",
"title": "小数位数"
},
"mod": {
"type": "number",
"title": "缩放比例"
}
}
}
},
"commands": {
"title": "命令",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "名称"
},
"form": {
"type": "array",
"title": "表单项",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "参数名"
},
"type": {
"type": "string",
"title": "数据类型",
"enum": [
"string",
"number",
"boolean"
],
"enum_title": [
"字符串",
"数字",
"布尔型"
]
},
"format": {
"type": "string",
"title": "表单类型",
"enum": [
"",
"date",
"datetime",
"email",
"upload_file_input"
],
"enum_title": [
"默认",
"日期选择器",
"时间选择器",
"电子邮件输入框",
"文件上传"
]
},
"enum": {
"type": "array",
"title": "选择项值",
"items": {
"type": "string"
}
},
"enum_title": {
"type": "array",
"title": "选择项文字",
"items": {
"type": "string"
}
},
"required": {
"type": "boolean",
"title": "是否必填"
},
"default": {
"type": "string",
"title": "默认值"
},
"mod": {
"type": "number",
"title": "缩放比例"
},
"tagValue": {
"type": "object",
"title": "数值定义",
"properties": {
"minValue": {
"title": "最小值",
"type": "number"
},
"maxValue": {
"title": "最大值",
"type": "number"
},
"minRaw": {
"title": "原始最小值",
"type": "number"
},
"maxRaw": {
"title": "原始最大值",
"type": "number"
}
}
}
}
}
},
"ops": {
"title": "指令",
"type": "array",
"items": {
"type": "object",
"properties": {
"action": {
"type": "string",
"title": "布/撤防",
"enum": [
"arming",
"unArming",
"queryState"
],
"enum_title": [
"系统全布防",
"系统全撤防",
"查询模块状态"
]
},
"modelNo": {
"type": "number",
"title": "模块编号",
"description": "查询模块状态指令填写"
}
}
}
}
}
}
}
}
},
"device": {
"properties": {
"settings": {
"title": "设备配置",
"type": "object",
"properties": {
"interval": {
"type": "number",
"title": "采集周期"
}
}
},
"tags": {
"title": "数据点",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "名称"
},
"id": {
"type": "string",
"title": "标识"
},
"unit": {
"type": "string",
"title": "单位"
},
"fixed": {
"type": "number",
"title": "小数位数"
},
"mod": {
"type": "number",
"title": "缩放比例"
}
}
}
}
}
}
})
4. 根据schema返回对应配置
在上一步骤中, 通过 schema
定义了驱动的相关配置, 包括 驱动配置
、数据点配置
和 指令配置
.
整体格式说明
驱动从平台接收到的配置信息整体格式如下:
{
"id": "645b4249b4f5349780d205d5",
"name": "netcore-driver",
"driverType": "netcore-driver",
"device": {
"commands": [],
"settings": {}
},
"tables": [{
"id": "演示表001",
"device": {
"driver": "netcore-driver",
"groupId": "645b4249b4f5349780d205d5",
"settings": {
"interval": 10
},
"tags": [{
"id": "csdata001",
"name": "csdata001"
}, {
"id": "csdata002",
"name": "csdata002"
}],
"commands": [],
"events": null
},
"devices": [{
"id": "cstable001",
"name": "cstable001",
"device": {
"driver": "",
"groupId": "",
"settings": null,
"tags": null,
"commands": null,
"events": null
},
"disable": false,
"off": false
}]
}]
}
上述格式中的 device
、tables.device
和 tables.devices.device
分别为 驱动实例配置
、模型配置(工作表的设备配置)
和 资产配置(设备的设备配置)
.
其中 settings
为 驱动配置信息
, 与 schema
中的 settings
对应. tags
为 数据点配置信息
, 与 schema
中的 tags
对应.
commands
为 指令配置信息
, 与 schema
中的 commands
对应.
驱动实例
、模型
和 资产
中的 settings
可以不相同, 但 tags
和 commands
必须相同.
例如, 可以把统一的配置信息放在 驱动实例
中, 把不同的配置信息放在 模型
或 资产
中.
5. 实现驱动接口
SDK
中定义了 数据接入驱动接口
, 该接口是平台控制驱动的桥梁. 开发者需要实现这个接口.
/// <summary>
/// 驱动实力接口
/// </summary>
public interface IDriver
{
/// <summary>
/// 启动方法
/// </summary>
ErrorInfo Start(IDriverApp app, byte[] bytes);
/// <summary>
/// 驱动重载方法
/// </summary>
ErrorInfo Reload(IDriverApp app, byte[] bytes);
/// <summary>
/// 执行指令方法
/// </summary>
CommResult Run(IDriverApp app, Command cmd);
/// <summary>
/// 批量执行指令方法
/// </summary>
CommResult BatchRun(IDriverApp app, BatchCommand cmd);
/// <summary>
/// 数据点写入
/// </summary>
CommResult WriteTag(IDriverApp app, Command cmd);
/// <summary>
/// 调试驱动方法
/// </summary>
CommResult Debug(IDriverApp app, byte[] bytes);
/// <summary>
/// 停止驱动方法
/// </summary>
ErrorInfo Stop(IDriverApp app);
/// <summary>
/// 获取驱动schema
/// </summary>
CommResult Schema(IDriverApp app);
}
/// <summary>
/// 返回结果
/// </summary>
public class CommResult
{
public CommResult(bool status, string message, object data = null)
{
Data = data;
if (status)
{
Error = null;
}
else
{
Error = new ErrorInfo()
{
Code = -1,
Message = message
};
}
}
public ErrorInfo Error;
public object Data;
/// <summary>
/// 失败方法
/// </summary>
/// <param name="msg">错误提示信息</param>
/// <returns></returns>
public static CommResult Failure(string msg)
{
return new CommResult(false, msg);
}
/// <summary>
/// 成功方法
/// </summary>
/// <param name="msg">成功提示信息</param>
/// <param name="data">成功时返回的数据</param>
/// <returns></returns>
public static CommResult Success(string msg, object data = null)
{
return new CommResult(true, msg, data);
}
}
/// <summary>
/// 错误消息
/// </summary>
public class ErrorInfo
{
/// <summary>
/// 错误码
/// </summary>
public int Code { get; set; }
/// <summary>
/// 错误提示信息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 生成一条新的错误消息
/// </summary>
/// <param name="msg">错误提示信息</param>
/// <returns></returns>
public static ErrorInfo New(string msg)
{
return new ErrorInfo()
{
Code = -1,
Message = msg
};
}
}
注: 向平台上报采集到的数据时, 必须通过 驱动与平台交互接口
中的 writePoint
方法发送, 不能直接调用 MQTT
客户端发送. 因为 SDK
会对发送的数据进行一些处理, 包括有效范围处理、数值映射、缩放比例、小数位等处理.
6. 配置驱动
这里所说 驱动配置
主要是一些静态配置信息(与 schema 中定义的配置无关), 其中包括 平台配置信息
, 驱动配置信息
和 自定义配置信息
. 这些信息一般通过配置文件(rc)、环境变量、命令行参数等方式传入. 其中一些配置信息由平台启动驱动时通过命令行参数传入.
这些配置信息, 在开发过程中可以根据实际情况进行调整. 但是在打包时必须按照平台的要求进行配置. 打包时的配置信息见 驱动配置说明.
平台配置信息
平台配置信息
主要为平台的连接信息. 包括: MQTT
连接信息, 驱动管理服务
连接信息. 内容如下:
mq:
type: mqtt
mqtt:
host: 平台mqtt服务器ip地址
port: 平台mqtt服务器端口
serviceId: 所属项目ID
project: 驱动实例ID
driver:
id: 驱动ID
name: 驱动名称
driverGrpc:
host: 驱动管理服务ip地址
port: 驱动管理服务端口
相关服务的端口号可在运维管理系统中查看.
驱动配置信息
驱动配置信息
主要包括 驱动ID
, 驱动名称
, 驱动实例ID
, 所属项目ID
.
驱动ID
为驱动的唯一标识, 必须在平台中唯一.驱动名称
为该驱动在平台中的显示名称.驱动实例ID
为该驱动实例的唯一标识. 同一个驱动可以创建多个实例, 每个实例的驱动ID
相同但驱动实例ID
唯一. 该信息由平台在驱动管理
中创建驱动实例时生成.所属项目ID
每个驱动实例都属于一个项目, 该驱动实例只会拿到该项目中的模型和设备信息.
serviceId: 所属项目ID
project: 驱动实例ID
driver:
id: 驱动ID
name: 驱动名称
驱动ID
和驱动名称
需要在配置中手动定义.驱动实例ID
和所属项目ID
在开发过程中, 需要将这些信息手动配置. 在打包时无须定义, 在平台中安装驱动时这些信息会由平台通过命令行参数传入.
驱动配置说明
以下是完整的驱动配置文件, 请参考该配置文件进行配置.
mq:
type: mqtt
mqtt:
host: 127.0.0.1
port: 1883
serviceId: 所属项目ID
project: 驱动实例ID
driver:
id: 驱动ID
name: 驱动名称
driverGrpc:
host: 127.0.0.1
port: 9224
windows系统打包发布时的驱动配置
driverGrpc:
host: 127.0.0.1
port: 9224
mq:
type: mqtt
mqtt:
host: 127.0.0.1
port: 1883
driver:
id: netcore-driver
name: dotnet驱动例子
linux系统打包发布时的驱动配置
driver:
id: netcore-driver
name: dotnet驱动例子