Device/Entity Construction
Overview
This chapter mainly introduces the key objects of the Beaver IoT: devices and entities, as well as how to construct them using annotations, programmatic methods, and YAML.
Key Objects
Device
Device
is an instance of a device, containing:
- id
- integration id
- name
- additional data: Extra information stored in a Map structure, such as the device's serial number (SN)
- key: Device key, refer to Key Coding Concepts for key rules
- identifier: Device identifier, refer to Key Coding Concepts for identifier rules
- contained entities
After saving a device, it is recommended not to change any metadata except name and additional data.
Entity
Entity
is an instance of an entity, containing the entity's metadata (excluding the entity's value), including:
- id
- device key: If it is a device entity, it will contain the device's key. Refer to Key Coding Concepts for key rules
- integration ID
- entity name
- access permissions: Read-only/Write-only/Read-Write
- identifier: Entity identifier, refer to Key Coding Concepts for identifier rules
- entity value type: Includes: STRING, LONG, DOUBLE, BOOLEAN, BINARY, OBJECT
- entity type: Includes: Property entity, Event entity, Service entity
- entity attributes: Attributes of the entity, such as unit, precision, maximum value, minimum value, maximum length, minimum length, enum, etc.
- child entities: Child entities of the entity, currently supporting up to two levels of relationships
- key: Entity key, refer to Key Coding Concepts for key rules
After saving an entity, it is recommended not to change any metadata except name and entity attributes.
Object Construction
Annotation-Based Construction
The Beaver IoT platform provides an annotation-based method for constructing devices and entities. Developers only need to add corresponding annotations to the device class and entity class to complete the construction. The platform will load and initialize the corresponding entities and integrations at startup.
Annotation Explanation
Class Annotations
@IntegrationEntities
: Marks the current class as an integration entity class@DeviceEntities
: Marks the current class as a device entity classidentifier
: Device identifiername
: Device nameadditional
: Additional device data, declared via the @KeyValue annotation
@Entities
: Marks the current class as a child entity class
Field Annotations
@Entity
: Marks the current attribute as an entity attributetype
: Entity type, including: Property entity, Event entity, Service entityname
: Entity nameidentifier
: Entity identifierattributes
: Declares entity attributes via the @Attribute annotation, including unit, precision, maximum value, minimum value, maximum length, minimum length, enum, etc.accessMod
: Entity access permissions, including: Read-only, Write-only, Read-Write
@Attribute
: Entity attribute annotationenumClass
: Enumeration classunit
: UnitfractionDigits
: Precisionmax
: Maximum valuemin
: Minimum valuemaxLength
: Maximum lengthminLength
: Minimum lengthformat
: Format
Constructing Integration Entities
- Defining Integration Entities
@Data
@EqualsAndHashCode(callSuper = true)
@IntegrationEntities
public class MyIntegrationEntities extends ExchangePayload {
@Entity(type = EntityType.SERVICE, name = "Device Connection Benchmark", identifier = "benchmark")
private String benchmark;
@Entity(type = EntityType.PROPERTY, name = "Detect Status", identifier = "detect_status", attributes = @Attribute(enumClass = DetectStatus.class), accessMod = AccessMod.R)
private Long detectStatus;
@Entity(type = EntityType.SERVICE, identifier = "delete_device")
private String deleteDevice;
public enum DetectStatus {
STANDBY, DETECTING;
}
}
By default, the @Entity annotation uses the object field name (camelCase to snake_case) as the entity name and identifier. Developers can customize the entity name and identifier via the name and identifier properties. When subscribing to entities on the consumer side, the annotated entity object can also be used to receive ExchangePayload event data, simplifying code development. Refer to the Event Subscription chapter. Note that when receiving event data, the entity object should extend the ExchangePayload class and the entity attributes should include corresponding Getter methods.
- Defining Integration Child Entities
@Data
@EqualsAndHashCode(callSuper = true)
@IntegrationEntities
public class MyIntegrationEntities extends ExchangePayload {
@Entity(type = EntityType.EVENT, name = "Detect Report", identifier = "detect_report")
private DetectReport detectReport;
@Entity(type = EntityType.SERVICE, identifier = "add_device")
private AddDevice addDevice;
@Data
@EqualsAndHashCode(callSuper = true)
@Entities
public static class DetectReport extends ExchangePayload {
// Entity type inherits from parent entity (DetectReport)
@Entity
private Long consumedTime;
@Entity
private Long onlineCount;
@Entity
private Long offlineCount;
}
@Data
@EqualsAndHashCode(callSuper = true)
@Entities
public static class AddDevice extends ExchangePayload {
@Entity
private String ip;
}
}
When the entity class is a child entity, add the @Entities annotation to the child entity class to complete the construction. Child entities inherit the attributes of the parent entity by default, so there is no need to set the type for child entities.
Defining Device Entities
@Data
@EqualsAndHashCode(callSuper = true)
@DeviceEntities(name="demoDevice", additional = {@KeyValue(key = "sn", value = "demoSN")}, identifier = "demoSN")
public class MyDeviceEntities extends ExchangePayload {
@Entity(name = "temperature", identifier = "temperature", accessMod = AccessMod.RW, type = EntityType.PROPERTY)
public Double temperature;
@Entity
private String humidity;
}
When the entity class is a device entity, simply add the @DeviceEntities annotation. The Beaver IoT platform will complete the device initialization and construction.
Programmatic Construction
The Beaver IoT platform provides the DeviceBuilder
and EntityBuilder
classes, allowing developers to construct devices and entities programmatically.
Constructing Integration Entities
- Without Child Entities
Entity entityConfig = new EntityBuilder(integrationId) // the integration identifier
.identifier("webhookStatus") // Setting the entity identifier
.property("webhookStatus", AccessMod.R) // Set the entity as a property entity and set its access mod
// .service("accessKey") // Set the entity as a service entity
// .event("accessKey") // Set the entity as an event entity
.attributes(new AttributeBuilder().maxLength(300).enums(IntegrationStatus.class).build()) // Setting entity attributes. It can also be constructed using the attributes(Supplier<Map<String, Object>> supplier) method
.valueType(EntityValueType.STRING) // Setting the entity value type
.build();
- With Child Entities
- Example 1
- Example 2
- Example 3
Entity entityConfig = new EntityBuilder(integrationId)
.identifier("settings")
.property("settings", AccessMod.RW)
.valueType(EntityValueType.STRING)
.children()
.valueType(EntityValueType.STRING).property("accessKey", AccessMod.RW).end()
.children()
.valueType(EntityValueType.STRING).property("secretKey", AccessMod.RW).end()
.build();
Entity parentEntity = new EntityBuilder(integrationId)
.identifier("settings")
.property("settings", AccessMod.RW)
.valueType(EntityValueType.STRING)
.children(()->{
Entity childEntity = new EntityBuilder()
.identifier("accessKey")
.property("accessKey", AccessMod.RW)
.valueType(EntityValueType.STRING)
.build();
return List.of(childEntity);
})
.build();
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.STRING)
.children(childEntity) // or children list
.build();
Constructing Devices and Entities
- Constructing Devices
Device device = new DeviceBuilder(integrationConfig.getId())
.name("deviceDemo") // Device name
.identifier("deviceDemoIdentifier") // Device identifier
.additional(Map.of("sn", "demoSN")) // Additional data of the device
.build();
- Constructing Device Entities
- Example 1 (Recommended)
- Example 2
- Example 3
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();
// Define Entity
Entity entity = new EntityBuilder(integrationId)
.identifier("temperature")
.property("temperature", AccessMod.R)
.valueType(EntityValueType.STRING)
.build();
// Define Device
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();
Entity entity = new EntityBuilder(integrationId, device.getKey())
.identifier("temperature")
.property("temperature", AccessMod.R)
.valueType(EntityValueType.STRING)
.build();
device.setEntities(Collections.singletonList(entity));
Constructing Entity Attributes
Beaver IoT provides the AttributeBuilder class, allowing developers to construct entity attributes programmatically. Beaver IoT currently supports attributes such as unit, precision, maximum value, minimum value, maximum length, minimum length, enumeration format, etc. Developers can also define custom attributes, for example:
Map<String, Object> build = new AttributeBuilder()
.unit("s") // set unit
.fractionDigits(0) // set number of fraction digits
.min(0.0) // set min value
.maxLength(10) // set max length
.minLength(1) // set min length
.format("yyyy-MM-dd HH:mm:ss") // set display format
.build();
Adding/Deleting Device
Adding or removing devices in Beaver IoT are two special service entities of the integration. Integration that needs to support adding or removing devices needs to define these two entities and handle their invocation events, and finally put these two entities explicitly in definition of this integration.
Adding Devices
For events of adding devices, the platform will carry the device name device_name
in the ExchangePayload context. Developers can obtain this from the ExchangePayload context or implement the AddDeviceAware
interface to get the device information for adding.
- Method 1 (Recommended)
- Method 2
- Define the entity for adding devices
@Data
@EqualsAndHashCode(callSuper = true)
@Entities
public static class AddDevice extends ExchangePayload implements AddDeviceAware {
@Entity
private String ip;
}
- Get the device name
@EventSubscribe(payloadKeyExpression = "my-integration.integration.add_device.*", eventType = ExchangeEvent.EventType.DOWN)
public void onAddDevice(Event<MyIntegrationEntities.AddDevice> event) {
String deviceName = event.getPayload().getAddDeviceName();
...
}
@EventSubscribe(payloadKeyExpression = "my-integration.integration.add_device.*", eventType = ExchangeEvent.EventType.DOWN)
public void onAddDevice(Event<MyIntegrationEntities.AddDevice> event) {
String deviceName = event.getPayload().getContext().get(ExchangeContextKeys.DEVICE_NAME_ON_ADD);
...
}
Deleting Devices
For events of deleting devices, the platform will carry the device instance device
in the ExchangePayload context. Developers can obtain this from the ExchangePayload context or implement the DeleteDeviceAware
interface to get the device information for deleting.
- Method 1 (Recommended)
- Method 2
- Define the entity for deleting devices
@Data
@EqualsAndHashCode(callSuper = true)
@Entities
public static class DeleteDevice extends ExchangePayload implements DeleteDeviceAware {
// should be empty
}
The entity for deleting devices should not contain any attributes; this class should be empty.
@EventSubscribe(payloadKeyExpression = "my-integration.integration.delete_device", eventType = ExchangeEvent.EventType.DOWN)
public void onDeleteDevice(Event<MyIntegrationEntities.DeleteDevice> event) {
Device device = event.getPayload().getDeletedDevice();
...
}
@EventSubscribe(payloadKeyExpression = "my-integration.integration.delete_device", eventType = ExchangeEvent.EventType.DOWN)
public void onDeleteDevice(Event<MyIntegrationEntities.DeleteDevice> event) {
Device device = event.getPayload().getContext().get(ExchangeContextKeys.DEVICE_ON_DELETE);
...
}
YAML-Based Construction
To facilitate development, Beaver IoT also provides a YAML-based method for constructing devices and entities. Developers can define devices and entities in the integration YAML file to complete the construction. The platform will load and initialize the corresponding entities and integrations at startup.
integration:
my-integration: # integration identifier
# ...
initial-entities: # initial entities
- identifier: 'connect' # entity identifier
name: connect # entity name
value_type: string # entity value type
type: service # entity type
access_mod: RW # entity access mode
children: # children entities
- identifier: 'url'
name: connectUrl
value_type: string
type: service
initial-devices: # initial devices
- identifier: 'demoDevice' # device identifier
name: demoDevice # device name
entities: # device entities
- identifier: 'temperature'
name: temperature
value_type: long
access_mod: RW
type: property
Generally, annotation-based and programmatic construction methods for devices and entities are more flexible and can meet most requirement scenarios. YAML-based construction aims to provide multiple means to facilitate rapid construction of devices and entities for developers.