|
|
@@ -1,5 +1,24 @@
|
|
|
package org.jetlinks.community.device.entity;
|
|
|
|
|
|
+import cn.hutool.core.collection.CollectionUtil;
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
+import io.swagger.v3.oas.annotations.media.Schema;
|
|
|
+import lombok.AllArgsConstructor;
|
|
|
+import lombok.Data;
|
|
|
+import lombok.NoArgsConstructor;
|
|
|
+import org.hswebframework.ezorm.rdb.mapping.annotation.ColumnType;
|
|
|
+import org.hswebframework.web.exception.BusinessException;
|
|
|
+import org.jetlinks.core.metadata.DataType;
|
|
|
+import org.jetlinks.core.metadata.DeviceMetadata;
|
|
|
+import org.jetlinks.core.metadata.PropertyMetadata;
|
|
|
+import javax.persistence.Column;
|
|
|
+import java.sql.JDBCType;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
/**
|
|
|
* @author lifang
|
|
|
* @version 1.0.0
|
|
|
@@ -7,42 +26,168 @@ package org.jetlinks.community.device.entity;
|
|
|
* @Description 设备影子
|
|
|
* @createTime 2021年10月14日 09:36:00
|
|
|
*/
|
|
|
+@Data
|
|
|
public class DeviceShadowEntity {
|
|
|
|
|
|
/**
|
|
|
* 设备状态
|
|
|
*/
|
|
|
- private String state;
|
|
|
+ @Column
|
|
|
+ @ColumnType(jdbcType = JDBCType.CLOB)
|
|
|
+ @Schema(description = "影子状态")
|
|
|
+ private ShadowState state;
|
|
|
|
|
|
/**
|
|
|
* 元数据,仅限设备属性
|
|
|
*/
|
|
|
- private String metadata;
|
|
|
+// @Column
|
|
|
+// @ColumnType(jdbcType = JDBCType.CLOB)
|
|
|
+ @Schema(description = "影子元数据")
|
|
|
+ private ShadowMetadata metadata;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置影子设备时间
|
|
|
+ */
|
|
|
+// @Column
|
|
|
+// @ColumnType(jdbcType = JDBCType.DATE)
|
|
|
+ @Schema(defaultValue = "更新时间戳")
|
|
|
+ private long timestamp;
|
|
|
|
|
|
+ {
|
|
|
+ timestamp=System.currentTimeMillis();
|
|
|
+ }
|
|
|
+// @Version
|
|
|
+// @Column
|
|
|
+// @Schema(defaultValue = "版本号")
|
|
|
+// private String version;
|
|
|
|
|
|
- private String timestamp;
|
|
|
/**
|
|
|
* 校验数据格式
|
|
|
* @return
|
|
|
*/
|
|
|
- public boolean verify(){
|
|
|
- return true;
|
|
|
+ public void validate(DeviceMetadata metadata){
|
|
|
+ boolean metadataIsNull = ObjectUtil.isNull(this.metadata);
|
|
|
+ boolean stateIsNull = ObjectUtil.isNull(this.state);
|
|
|
+ //状态和元数据只能同时为空或同时不为空
|
|
|
+ if(metadataIsNull!=stateIsNull){
|
|
|
+ throw new BusinessException("state和metadata只能同时为空或同时不为空");
|
|
|
+ }
|
|
|
+ Map<String, Object> stateDesired = this.state.desired;
|
|
|
+ Map<String, Object> stateReport = this.state.reported;
|
|
|
+ if(!metadataIsNull){
|
|
|
+ //数据存在则判断数据
|
|
|
+ Map<String, MetadataUpdateTime> metadataDesired = this.metadata.desired;
|
|
|
+ if (CollectionUtil.isNotEmpty(CollectionUtil.subtract(new ArrayList<>(stateDesired.keySet()),
|
|
|
+ new ArrayList<>(metadataDesired.keySet())))) {
|
|
|
+ throw new BusinessException("state.desired和metadata.desired的key值请保持一致");
|
|
|
+ }
|
|
|
+ Map<String, MetadataUpdateTime> metadataReport= this.metadata.reported;
|
|
|
+ if (CollectionUtil.isNotEmpty(CollectionUtil.subtract(new ArrayList<>(stateReport.keySet()),
|
|
|
+ new ArrayList<>(metadataReport.keySet())))) {
|
|
|
+ throw new BusinessException("state.reported和metadata.reported的key值请保持一致");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Set<String> desiredKeys = stateDesired.keySet();
|
|
|
+ for (String desiredKey : desiredKeys) {
|
|
|
+ PropertyMetadata propertyMetadata = metadata.getPropertyOrNull(desiredKey);
|
|
|
+ if(propertyMetadata==null){
|
|
|
+ throw new BusinessException(String.format("desired 中的 属性{%s}不存在",desiredKey));
|
|
|
+ }
|
|
|
+ DataType valueType = propertyMetadata.getValueType();
|
|
|
+ valueType.validate(stateDesired.get(desiredKey));
|
|
|
+ }
|
|
|
+
|
|
|
+ Set<String> reportedKeys = stateReport.keySet();
|
|
|
+
|
|
|
+ for (String reportedKey : reportedKeys) {
|
|
|
+ PropertyMetadata propertyMetadata = metadata.getPropertyOrNull(reportedKey);
|
|
|
+ if(propertyMetadata==null){
|
|
|
+ throw new BusinessException(String.format("report 中的 属性{%s}不存在",reportedKey));
|
|
|
+ }
|
|
|
+ DataType valueType = propertyMetadata.getValueType();
|
|
|
+ valueType.validate(stateDesired.get(reportedKey));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 影子状态
|
|
|
*/
|
|
|
+ @Data
|
|
|
+ @NoArgsConstructor
|
|
|
+ @AllArgsConstructor
|
|
|
public class ShadowState{
|
|
|
-
|
|
|
+ /**
|
|
|
+ * 平台向设备下发期望值
|
|
|
+ */
|
|
|
+ private Map<String,Object> desired;
|
|
|
+ /**
|
|
|
+ * 设备向平台上报期望值
|
|
|
+ */
|
|
|
+ private Map<String,Object> reported;
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 影子元数据
|
|
|
+ * 影子元数据,存储更新时间
|
|
|
*/
|
|
|
+ @Data
|
|
|
+ @NoArgsConstructor
|
|
|
+ @AllArgsConstructor
|
|
|
public class ShadowMetadata{
|
|
|
+ /**
|
|
|
+ * 平台向设备下发期望值
|
|
|
+ */
|
|
|
+ private Map<String,MetadataUpdateTime> desired;
|
|
|
+ /**
|
|
|
+ * 设备向平台上报期望值
|
|
|
+ */
|
|
|
+ private Map<String,MetadataUpdateTime> reported;
|
|
|
|
|
|
+ }
|
|
|
+
|
|
|
+ @Data
|
|
|
+ @NoArgsConstructor
|
|
|
+ @AllArgsConstructor
|
|
|
+ public class MetadataUpdateTime{
|
|
|
+ private long timestamp;
|
|
|
+ }
|
|
|
|
|
|
+ public static void main(String[] args) {
|
|
|
+ String s="{\n" +
|
|
|
+ " \"state\": {\n" +
|
|
|
+ " \"desired\": {\n" +
|
|
|
+ " \"color\": \"RED\", \n" +
|
|
|
+ " \"sequence\": [\n" +
|
|
|
+ " \"RED\", \n" +
|
|
|
+ " \"GREEN\", \n" +
|
|
|
+ " \"BLUE\"\n" +
|
|
|
+ " ]\n" +
|
|
|
+ " }, \n" +
|
|
|
+ " \"reported\": {\n" +
|
|
|
+ " \"color\": \"GREEN\"\n" +
|
|
|
+ " }\n" +
|
|
|
+ " }, \n" +
|
|
|
+ " \"metadata\": {\n" +
|
|
|
+ " \"desired\": {\n" +
|
|
|
+ " \"color\": {\n" +
|
|
|
+ " \"timestamp\": 1469564492\n" +
|
|
|
+ " }, \n" +
|
|
|
+ " \"sequence\": {\n" +
|
|
|
+ " \"timestamp\": 1469564492\n" +
|
|
|
+ " }\n" +
|
|
|
+ " }, \n" +
|
|
|
+ " \"reported\": {\n" +
|
|
|
+ " \"color\": {\n" +
|
|
|
+ " \"timestamp\": 1469564492\n" +
|
|
|
+ " }\n" +
|
|
|
+ " }\n" +
|
|
|
+ " }, \n" +
|
|
|
+ " \"timestamp\": 1469564492, \n" +
|
|
|
+ " \"version\": 1\n" +
|
|
|
+ "}";
|
|
|
+ DeviceShadowEntity map = JSONUtil.toBean(s, DeviceShadowEntity.class);
|
|
|
+ System.out.println(map);
|
|
|
}
|
|
|
}
|