设备/实体
概述
本章节主要介绍Beaver IoT平台关键对象: 设备、实体。以及如何基于注解、编程式、YAML构建它们。
关键对象
Device
Device
是设备的实例,里面有:
- id
- 所属集成的id
- 名称
- 额外数据: 采用Map结构存储设备的额外信息,如设备的序列号或者生产日期等其它自定义信息
- key:设备key, key规则详见关键编码概念介绍章节
- identifier: 设备identifier, identifier规则详见关键编码概念介绍章节
- 包含的实体
设备在保存后,除了名称和额外数据都不建议再改变其它元数据。
Entity
Entity
是实体的实例,对象内容是实体的元数据(不包含实体的值),包括:
- id
- 设备key: 如果是设备的实体,那么会含有 设备的key,规则详见关键编码概念介绍章节
- 集成ID
- 实体名称
- 访问权限: 只对Property类型的实体有意义,只读/只写/读写
- identifier:实体identifier, identifier规则详见关键编码概念介绍章节
- 实体值类型:包括:STRING, LONG, DOUBLE, BOOLEAN, BINARY, OBJECT
- 实体类型: 包括:属性实体, 事件实体, 服务实体
- 实体属性: 实体的属性,如单位, 精度, 最大值, 最小值, 最大长度, 最小长度, 枚举等
- 子实体:实体的子实体,当前最多支持两层关系
- key: 实体key, key规则详见关键编码概念介绍章节
实体在保存后,除了名称和实体属性都不建议再改变其它元数据。
对象构建
本节将会介绍设备和实体的构建方法。
基于注解构建
注解说明
类注解
@IntegrationEntities
:标识当前类为集成实体类@DeviceTemplateEntities
:标识当前类为设备实体模板类name
:设备模板名称
@DeviceEntities
:标识当前类为设备实体类identifier
:设备identifiername
:设备名称additional
:设备额外数据,通过@KeyValue注解声明
@Entities
:标识当前类为子实体类
字段注解
@Entity
:标识当前属性为实体type
:实体类型EntityType
,包括:属性实体, 事件实体, 服务实体name
:实体名称identifier
:实体identifierattributes
:@Attribute
注解声明实体属性,包括如单位, 精度, 最大值, 最小值, 最大长度, 最小长度, 枚举格式等accessMod
:实体访问方式AccessMod
,只对Property类型的实体有意义,包括:只读, 只写, 读写visible
:实体是否对用户可见visible
。部分集成内部管理使用的实体,包括添加和删除设备的服务实体等,不需要对用户可见
@Attribute
:实体属性注解enumClass
:枚举类unit
:单位fractionDigits
:精度max
:最大值min
:最小值maxLength
:最大长度minLength
:最小长度format
:格式
构建集成实体
- 定义集成实体
@Data
@EqualsAndHashCode(callSuper = true)
@IntegrationEntities
public class MyIntegrationEntities extends ExchangePayload {
@Entity(type = EntityType.EVENT, name = "Event Entity Name", identifier = "event_entity")
private String eventEntity;
@Entity(type = EntityType.PROPERTY, name = "Property Entity Name", identifier = "property_entity", accessMod = AccessMod.R)
private Boolean propertyEntity;
@Entity(type = EntityType.SERVICE, identifier = "service_entity", attributes = @Attribute(enumClass = SampleEnum.class))
private Long serviceEntity;
public enum SampleEnum {
SAMPLE_ENUM_1, SAMPLE_ENUM_2;
}
}
- 默认情况下,@Entity实体注解采用对象字段(驼峰转下划线)名作为实体name、identifier,开发者可通过name、identifier属性自定义实体名称、identifier
- 当订阅实体事件时,注解的实体对象同时可用于接收ExchangePayload事件数据,即可通过Getter方法获取到属性值,从而简化代码开发,可参见事件订阅章节。 需注意当用于接收事件数据时,实体对象需继承ExchangePayload类,并且实体属性包含对应的Getter方法
- 定义集成子实体
@Data
@EqualsAndHashCode(callSuper = true)
@IntegrationEntities
public class MyIntegrationEntities extends ExchangePayload {
@Entity(type = EntityType.EVENT, name = "Parent Entity Name", identifier = "parent_entity")
private ParentEntity parentEntity;
@Data
@EqualsAndHashCode(callSuper = true)
@Entities
public static class ParentEntity extends ExchangePayload {
// Entity type EVENT inherits from ParentEntity
@Entity(name = "Child 1 Name", identifier = "child_1")
private Long childEntity1;
@Entity(name = "Child 2 Name", identifier = "child_2")
private Long childEntity2;
}
}
设备的子实体定义方式相同,需在子实体类上添加@Entities注解,即可完成子实体的构建,子实体不能再包含子实体。子实体默认继承父实体的属性,即子实体不需要设置type类型。父实体的数据类型为OBJECT
。
定义设备实体模板
在实际场景中,集成下可能会有很多相同类型的设备,因此每个设备都含有相同种类的实体,如:一个集成可以对接多个环境传感器,每个传感器都有属于自己的温度和湿度实体。
@Data
@EqualsAndHashCode(callSuper = true)
@DeviceTemplateEntities(name="Environment Device Template")
public class EnvironmentDeviceEntities extends ExchangePayload {
@Entity(name = "temperature", identifier = "temperature", accessMod = AccessMod.RW, type = EntityType.PROPERTY)
private Double temperature;
@Entity
private Long humidity;
}
定义设备实体
@Data
@EqualsAndHashCode(callSuper = true)
@DeviceEntities(name="Default Device Name", additional = {@KeyValue(key = "seriesNumber", value = "sample_number")}, identifier = "default_device")
public class MyDeviceEntities extends ExchangePayload {
@Entity(name = "temperature", identifier = "temperature", accessMod = AccessMod.RW, type = EntityType.PROPERTY)
private Double temperature;
@Entity
private Long humidity;
}
当实体类为设备实体,Beaver IoT平台会初始化这个设备并添加到数据库中。
编程式构建
Beaver IoT 平台提供了DeviceBuilder
、EntityBuilder
等Builder类,开发者可通过编程式构建设备、实体等对象。
构建集成实体
- 不包含子实体
Entity entityConfig = new EntityBuilder(integrationId) //设置集成标识
.identifier("webhookStatus") //设置实体标识
.property("webhookStatus", AccessMod.R) //设置作为属性实体
// .service("accessKey") //设置作为服务实体
// .event("accessKey") //设置作为事件实体
.attributes(new AttributeBuilder().maxLength(300).enums(IntegrationStatus.class).build()) //设置实体属性,也可以使用attributes(Supplier<Map<String, Object>> supplier)方法进行构建
.valueType(EntityValueType.STRING) //设置实体值类型
.build();
- 包含子实体
- 示例1
- 示例2
- 示例3
//示例1: 通过EntityBuilder的children()方法构建子实体
Entity entityConfig = new EntityBuilder(integrationId)
.identifier("settings")
.property("settings", AccessMod.RW)
.valueType(EntityValueType.OBJECT)
.children() //设置子实体
.valueType(EntityValueType.STRING).property("accessKey", AccessMod.RW).end()
.children()
.valueType(EntityValueType.STRING).property("secretKey", AccessMod.RW).end()
.build();
//示例2: 通过EntityBuilder的children(Supplier<List<Entity>> supplier)方法设置子实体
Entity parentEntity = new EntityBuilder(integrationId)
.identifier("settings")
.property("settings", AccessMod.RW)
.valueType(EntityValueType.OBJECT)
.children(()->{
Entity childEntity = new EntityBuilder() //定义子实体
.identifier("accessKey")
.property("accessKey", AccessMod.RW)
.valueType(EntityValueType.STRING)
.build();
return List.of(childEntity);
}) //设置子实体,可以是List<Entity>或是单个实体
.build();
//示例3: 通过EntityBuilder的children(List<Entity> entities)方法设置子实体
Entity childEntity = new EntityBuilder() //定义子实体
.identifier("accessKey")
.property("accessKey", AccessMod.RW)
.valueType(EntityValueType.STRING)
.build();
Entity parentEntity = new EntityBuilder(integrationId)
.identifier("settings")
.property("settings", AccessMod.RW)
.valueType(EntityValueType.OBJECT)
.children(childEntity) //设置子实体,可以是List<Entity>或是单个实体
.build();
构建设备及实体
- 构建设备
Device device = new DeviceBuilder(integrationConfig.getId())
.name("deviceDemo")
.identifier("deviceDemoIdentifier")
.additional(Map.of("sn", "demoSN"))
.build();
- 构建设备实体
- 示例1(推荐)
- 示例2
- 示例3
- 示例4(@DeviceTemplateEntities)
Device device = new DeviceBuilder(integrationConfig.getId())
.name("deviceDemo")
.identifier("deviceDemoIdentifier")
.entity(entity)
.additional(Map.of("sn", "demoSN"))
.entity(()->{
return new EntityBuilder(integrationId)
.identifier("temperature")
.property("temperature", AccessMod.R)
.valueType(EntityValueType.STRING)
.build();
})
.build();
Entity entity = new EntityBuilder(integrationId)
.identifier("temperature")
.property("temperature", AccessMod.R)
.valueType(EntityValueType.STRING)
.build();
Device device = new DeviceBuilder(integrationConfig.getId())
.name("deviceDemo")
.identifier("deviceDemoIdentifier")
.entity(entity)
.additional(Map.of("sn", "demoSN"))
.build();
Device device = new DeviceBuilder(integrationConfig.getId())
.name("deviceDemo")
.identifier("deviceDemoIdentifier")
.entity(entityConfig)
.additional(Map.of("sn", "demoSN"))
.build();
s //highlight-next-line
Entity entity = new EntityBuilder(integrationId, device.getKey())
.identifier("temperature")
.property("temperature", AccessMod.R)
.valueType(EntityValueType.STRING)
.build();
device.setEntities(Collections.singletonList(entity));
Device device = new DeviceBuilder(INTEGRATION_ID)
.name(deviceName)
.identifier("deviceDemoIdentifier")
.additional(Map.of("sn", "demoSN"))
.entities(()-> new AnnotatedTemplateEntityBuilder(INTEGRATION_ID, "deviceDemoIdentifier")
.build(MyDeviceEntities.class))
.build();
构建实体属性
Beaver IoT 平台提供了AttributeBuilder类,开发者可通过编程式构建实体属性。当前平台支持的属性包括:单位、精度、最大值、最小值、最大长度、最小长度、枚举格式等,也可以支持开发者自定义属性,例如:
Map<String, Object> build = new AttributeBuilder()
.unit("s") // 单位为秒
.fractionDigits(0) // 小数位数为0,表示精确到秒
.min(0.0) // 设定合理的最小值(根据实际需求调整)
.maxLength(10) // 设定合理的最大长度(根据实际需求调整)
.minLength(1) // 设定合理的最小长度(根据实际需求调整)
.format("yyyy-MM-dd HH:mm:ss") // 时间格式精确到秒
.build();
添加/删除设备实体
添加或者删除设备在Beaver IoT中是集成的两个特殊的服务类型的实体。集成如果需要支持添加或者删除设备,需要定义这两个 实体,并且处理他们的调用事件,最后将这两个实体显式地放到集成定义中。
新增设备
新增设备事件,平台将会在ExchangePayload上下文中携带设备名称device_name
,开发者可以从ExchangePayload的上下文中获取,或实现AddDeviceAware
接口获取新增的设备信息。
- 方式1(推荐)
- 方式2
- 定义实体
@Data
@EqualsAndHashCode(callSuper = true)
@Entities
public static class AddDevice extends ExchangePayload implements AddDeviceAware {
@Entity
private String ip;
}
- 获取设备名
@EventSubscribe(payloadKeyExpression = "my-integration.integration.add_device.*")
public void onAddDevice(Event<MyIntegrationEntities.AddDevice> event) {
String deviceName = event.getPayload().getAddDeviceName();
...
}
- 获取设备名
@EventSubscribe(payloadKeyExpression = "my-integration.integration.add_device.*")
public void onAddDevice(Event<MyIntegrationEntities.AddDevice> event) {
String deviceName = event.getPayload().getContext().get(ExchangeContextKeys.DEVICE_NAME_ON_ADD);
...
}
删除设备
删除设备事件,平台将会在ExchangePayload上下文中携带删除的设备device
,开发者可以从ExchangePayload的上下文中获取,或实现DeleteDeviceAware
接口获取新增的设备信息。
- 方式1(推荐)
- 方式2
- 定义设备删除的实体
@Data
@EqualsAndHashCode(callSuper = true)
@Entities
public static class DeleteDevice extends ExchangePayload implements DeleteDeviceAware {
// 应当为空
}
设备删除的实体不应该包含任何实体,即这个类应该为空。
- 获取删除的设备
@EventSubscribe(payloadKeyExpression = "my-integration.integration.delete_device")
public void onDeleteDevice(Event<MyIntegrationEntities.DeleteDevice> event) {
Device device = event.getPayload().getDeletedDevice();
...
}
- 获取删除的设备
@EventSubscribe(payloadKeyExpression = "my-integration.integration.delete_device")
public void onDeleteDevice(Event<MyIntegrationEntities.DeleteDevice> event) {
Device device = event.getPayload().getContext().get(ExchangeContextKeys.DEVICE_ON_DELETE);
...
}