基础概念
- 产品: 物模型的集合, 用于描述设备的功能和属性
- 设备: 物模型的实例, 用于描述设备的具体信息
- 物模型: 用于描述设备的功能和属性, 物模型分为物模型属性和物模型事件以及物模型功能
- 物模型属性: 用于描述设备的属性, 如温度、湿度、开关等
- 物模型事件: 用于描述获取设备模型数据的接口, 如获取温度、湿度等数据的接口
- 物模型功能: 用于描述控制设备的功能, 如控制灯的开关、控制风扇的转速等
- 协议指令: 设备协议文档提供的功能, 如控modbus协议的读线圈(01)、读保持寄存器(03)、写保持寄存器(10)等
- 协议驱动: 用于描述和设备交互的协议, 如MQTT、CoAP、HTTP、MODBUS等
- 网络组件: 用于描述平台和设备交互时需要的网络信息, 如IP地址、端口号、协议等
- 产品类型: 用于归档相同功能能的产品, 如环境传感器、车机等
使用流程
- 直连设备
添加设备类型为直连设备的产品及其物模型(包括模型属性、模型事件、模型功能) -> 配置直连设备
- 网关子设备
添加设备类型为网关子设备的产品及其物模型(包括模型属性、模型事件、模型功能) -> 添加网关设备 -> 添加网关子设备 -> 配置事件源(采集器)
协议驱动
- 当我们要采集设备的数据或者控制设备时, 首先需要知道设备采用的协议规范,这个规范一般由设备厂家提供协议文档, 驱动就是开发者用开发语言实现协议文档中定义的功能, 如MQTT、CoAP、HTTP、MODBUS等
- iboot平台已经开源了modbus、dtu、mqtt三种协议驱动, 并且已经配置好了, 开发者下载源码后无需做配置即可使用
- 具体驱动配置参考驱动配置
设备类型
设备类型分为直连设备、网关设备、网关子设备。如何区分一款设备是什么设备类型的就变得尤为重要。首先我们要先确定一点什么是真正产生数据和提供控制功能的设备,接着判断这款设备是否可以直接和平台进行交互,如果可以直接连接交互的就是直连设备不能直接连接需要通过网关设备连接的就叫网关子设备, 比如基于rs485的温湿度传感器他是一款真正生成数据的设备, 但是这设备没办法直接连接平台需要通过dtu(串口服务器)将rs485转成tcp协议, 然后再通过dtu网关设备连接平台, 这款设备就叫网关子设备其中的dtu(串口服务器)就是网关设备。
设备管理
- 直连设备: 由于目前没有可用的直连协议驱动, 需要开发者先自行实现协议驱动, 然后再配置直连设备
- 网关子设备: 网关子设备需要先添加网关设备, 然后再添加网关子设备, 最后再配置事件源(采集)
当前系统开源的协议驱动 modbus、dtu(modbus)、mqtt这三个驱动都属于网关设备和网关子设备, 其中网关设备的默认产品已经都添加到系统中, 开发者只需要添加网关子设备产品即可, 然后再添加网关设备以及网关子设备, 最后再配置事件源(采集)
物模型
- 物模型用于描述设备的功能和属性, 物模型分为模型属性和模型事件以及模型功能。
- 为了理解iboot平台的物模型概念我们需要先了解设备的协议指令, 设备的协议文档是由设备厂家提供的(如果是标准协议则文档由制定协议的联盟提供), 此文档写明了此设备拥有哪些功能以及这些功能需要有哪些参数, 比如modbus标准协议文档中定义了读线圈(01)、读保持寄存器(03)、写保持寄存器(10)等功能且每个功能都需要指定寄存器地址、读取寄存器数量等参数, 这些功能就是设备的协议指令。
- iboot的事件模型和功能模型就是用来配置协议指令的参数, 如果将协议指令当成一个函数那么事件模型和功能模型都是用来配置函数参数的, 其中下行配置就是调用此函数(协议指令)的参数, 上行配置就是调用此函数(协议指令)后返回的值。
模型属性
模型属性用于描述设备的属性, 如温度、湿度、开关等, 也是配置事件模型和功能模型时需要用到的参数. 事件模型和功能模型的上行配置和下行配置可以通过@来提及此模型属性, 如@temp来提及模型属性中的温度, 这样系统就会自动将温度属性的值填充到事件模型和功能模型的上行配置和下行配置中了
- 属性精度: 用于描述属性的精度也就是保留几位小数, 如温度的精度为0.1保留一位小数
- 属性增益: 用于描述属性的增益也就是放大倍数, 如设备采集的温度是放大10倍上报的, 则增益为10, 那系统会对采集值自动除以10
- 属性解析器: 用于对采集的属性值进行解析, 比如属性精度和属性增益的解析目前是用系统默认的解析器, 开发者也可以自定义解析器
- 枚举属性: 用于描述属性的枚举值, 如开关属性的枚举值为0和1, 0表示关, 1表示开
- json属性类型: 用于描述属性的json格式, 如温度和湿度的json格式为
{
"temp": 25.5,
"humidity": 50.5
}
- 属性类型: 包括 只读、只写、读写三种类型, 只读属性一般时从设备获取的字段, 只写属性一般是需要向设备发送的字段, 读写属性既包含在设备获取以及写入设备的字段
自定义解析器
目前自定义解析器可以通过代码实现也可以通过脚本引擎实现
- 通过代码实现
@Component
public class CustomResolver implements DataValueResolver, InitializingBean {
public String name() {
return "自定义解析器";
}
public Object resolver(UpModelAttr attr, Object value) {
// 解析器逻辑
return value;
}
@Override
public void afterPropertiesSet() throws Exception {
// 注册解析器
DataValueResolverFactory.register("custom", this);
}
}
- 通过脚本引擎实现
详情见 脚本引擎
事件模型
事件模型用于描述获取设备数据的接口, 如获取温度、湿度等数据的接口, 然后返回的数据需要在上行配置中通过@提及的方式选择对应的模型属性从而和系统的模型属性进行绑定
- 在线状态: 用于作为获取网关子设备的状态, 由于网关子设备是通过网关设备连接的, 所以网关子设备的在线状态平台没有办法直接获取, 那么平台通过某个事件模型是否能获取到网关子设备的数据来判断网关子设备的状态, 如果将获取温度的事件模型作为在线状态的校验那么如果此事件获取到了网关子设备的温度值则就认为是在线的反之为离线, 平台会启用定时任务来定时获取此事件模型的数据, 如果获取到了则认为是在线的, 如果获取不到则认为是离线的, 定时获取状态代码如下:
/**
* 物模型的设备在线状态协议管理
* 一般用于网关子设备的状态采集
*/
public class DeviceStatusModelApiManager implements Runnable, ApplicationReadyListener {
// 详情看源码
}
功能模型
功能模型用于描述控制设备的功能, 如控制灯的开关、控制风扇的转速等
数据采集
iboot的数据采集可以通过两种方式实现, 一种是通过配置事件源实现, 一种是通过配置工业物联网下面的采集任务实现(这种方式暂时不可用)
- 事件源采集器
其中产品列表和设备组两个参数用于配置只采集指定设备组和产品列表下面的设备
- 采集任务实现
// 事件源任务分配
public class EventSourceTask implements Runnable {
private Executor executor;
private EventSourceDto sourceDto;
private IotCacheManager cacheManager;
public EventSourceTask(Executor executor, EventSourceDto sourceDto, IotCacheManager cacheManager) {
this.executor = executor;
this.sourceDto = sourceDto;
this.cacheManager = cacheManager;
}
@Override
public void run() {
if(CollectionUtil.isNotEmpty(sourceDto.getGroups())) {
sourceDto.getGroups().forEach(group -> {
// 执行采集任务, 为每个组创建一个任务, 如果事件源太多可以加大线程池核心数来执行任务
executor.execute(new CollectGroupTask(group, sourceDto, cacheManager));
});
}
}
}
// 采集任务
public class CollectGroupTask implements Runnable{
private DeviceGroup group;
private List<ModelApi> apis;
private EventSourceDto source;
private IotCacheManager cacheManager;
private static Logger logger = LoggerFactory.getLogger("IOT:MODEL:COLLECT");
public CollectGroupTask(DeviceGroup group, EventSourceDto source, IotCacheManager cacheManager) {
this.group = group;
this.source = source;
this.apis = source.getApis();
this.cacheManager = cacheManager;
}
@Override
public void run() {
// 省略具体代码, 具体实现可以参考源码
}
}
数据存储
采集到的数据通过监听采集器事件来获取, 然后将数据存储到数据库中, 目前iboot平台已经开源了关系型数据库的默认实现, 开发者也可以自定义实现
- 关系型数据库(默认实现)
// 平台的默认实现
public class RDBMSPersistenceListener implements DataPersistenceListener {
private final DefaultRdbmsSqlManager rdbmsSqlManager;
public RDBMSPersistenceListener(DefaultRdbmsSqlManager rdbmsSqlManager) {
this.rdbmsSqlManager = rdbmsSqlManager;
}
@Override
public void persistence(List collectData) {
rdbmsSqlManager.batchInsert(CollectData.class, collectData);
}
}
- 自定义实现
开发者可以通过实现DataPersistenceListener接口来自定义数据存储的方式, 比如将数据存储到redis、kafka、时序数据库等
@Component
public class CustomPersistenceListener implements DataPersistenceListener {
// 引入对应的存储组件等
// private final RedisTemplate redisTemplate;
// private final KafkaTemplate kafkaTemplate;
// private final InfluxDB influxDB;
@Override
public void persistence(List collectData) {
// 自定义实现
}
}
实时数据缓存
系统中采集到的数据会进行缓存, 主要缓存最新的一条和前一条记录。可以通过spring注入RealtimeDataService的方式来操作缓存, 例如获取指定设备的最新数据和前一条数据
@Component
public class CacheOperatorDemo {
// 其他接口可以参考源码
private final RealtimeDataService realtimeDataService;
public CacheOperatorDemo(RealtimeDataService realtimeDataService) {
this.realtimeDataService = realtimeDataService;
}
public void getLatestData(String uid, String field) {
// 获取指定设备的最新数据
ModelAttrRealtimeData data = realtimeDataService.getRealtimeData(uid, field);
if(data != null) {
// 最新实时数据
SignalOrFieldValue realtime = data.getRealtime();
// 前一条数据
SignalOrFieldValue prev = data.getPrev();
}
}
}
设备状态缓存
设备状态包含设备的常用信息比如所属产品、所属组等还有包含设备的实时在线状态。系统可以通过spring注入IotCacheManager的方式来操作设备数据缓存, 例如获取指定设备的状态
public class CacheOperatorDemo {
// 其他接口可以参考源码
private final IotCacheManager cacheManager;
public CacheOperatorDemo(IotCacheManager cacheManager) {
this.cacheManager = cacheManager;
}
public void getDeviceStatus(String uid) {
// 获取指定设备的状态
RealtimeStatus status = cacheManager.getByUid(uid);
}
}
电子地图
电子地图是指将设备的位置信息展示在地图上, 系统已经开源了电子地图的默认实现, 目前使用高德地图作为默认地图, 开发者需要申请高德的地图key, 然后在系统的配置文件中配置
# 高德地图key
amap.key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx