diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http index b29ae8ddf..e31540710 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http @@ -5,46 +5,140 @@ tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} { - "productId": 1, - "productKey": "123456", + "productId": 1002, + "productKey": "smart-sensor-002", "properties": [ { - "identifier": "CurrentTemperature", - "name": "当前温度", + "identifier": "Temperature", + "name": "温度", "accessMode": "r", "required": true, "dataType": { "type": "float", "specs": { - "min": "-40", - "max": "120", - "unit": "°C", - "unitName": "摄氏度", - "step": "0.1" + "min": -40.0, + "max": 125.0, + "step": 0.1, + "unit": "℃" } - } + }, + "description": "当前温度值" }, { - "identifier": "CurrentHumidity", - "name": "当前湿度", + "identifier": "Humidity", + "name": "湿度", "accessMode": "r", "required": true, "dataType": { "type": "float", "specs": { - "min": "0", - "max": "100", - "unit": "%", - "unitName": "百分比", - "step": "0.1" + "min": 0.0, + "max": 100.0, + "step": 0.1, + "unit": "%" } - } + }, + "description": "当前湿度值" + }, + { + "identifier": "GeoLocation", + "name": "地理位置", + "accessMode": "r", + "required": false, + "dataType": { + "type": "struct", + "specs": [ + { + "identifier": "Longitude", + "name": "经度", + "dataType": { + "type": "double", + "specs": { + "min": -180.0, + "max": 180.0, + "step": 0.000001, + "unit": "°" + } + }, + "description": "设备所在位置的经度" + }, + { + "identifier": "Latitude", + "name": "纬度", + "dataType": { + "type": "double", + "specs": { + "min": -90.0, + "max": 90.0, + "step": 0.000001, + "unit": "°" + } + }, + "description": "设备所在位置的纬度" + } + ] + }, + "description": "设备的地理位置信息" } ], - "services": "{}", - "events": "{}" + "services": [ + { + "identifier": "Reboot", + "name": "重启设备", + "callType": "async", + "inputData": [], + "description": "远程重启设备", + "method": "thing.service.reboot" + }, + { + "identifier": "SetThreshold", + "name": "设置温度阈值", + "callType": "sync", + "inputData": [ + { + "identifier": "Threshold", + "name": "阈值", + "dataType": { + "type": "float", + "specs": { + "min": -40.0, + "max": 125.0, + "step": 0.1, + "unit": "℃" + } + }, + "description": "报警温度阈值" + } + ], + "description": "设置设备的温度报警阈值", + "method": "thing.service.setThreshold" + } + ], + "events": [ + { + "identifier": "HighTemperatureAlert", + "name": "高温报警", + "type": "alert", + "outputData": [ + { + "identifier": "CurrentTemperature", + "name": "当前温度", + "dataType": { + "type": "float", + "specs": { + "unit": "℃" + } + }, + "description": "触发报警时的温度值" + } + ], + "description": "当温度超过阈值时触发高温报警事件", + "method": "thing.event.highTemperatureAlert" + } + ] } + ### 请求 /iot/think-model-function/update 接口 => 成功 PUT {{baseUrl}}/iot/think-model-function/update Content-Type: application/json @@ -53,46 +147,137 @@ Authorization: Bearer {{token}} { "id": 1, - "productId": 1, - "productKey": "123456", + "productId": 1001, + "productKey": "smart-sensor-001", "properties": [ { - "identifier": "CurrentTemperature", - "name": "当前温度", + "identifier": "Temperature", + "name": "温度", "accessMode": "r", "required": true, "dataType": { "type": "float", "specs": { - "min": "-40", - "max": "130", - "unit": "°C", - "unitName": "摄氏度", - "step": "0.1" + "min": -40.0, + "max": 125.0, + "step": 0.1, + "unit": "℃" } - } + }, + "description": "当前温度值" }, { - "identifier": "CurrentHumidity", - "name": "当前湿度", + "identifier": "Humidity", + "name": "湿度", "accessMode": "r", "required": true, "dataType": { "type": "float", "specs": { - "min": "0", - "max": "100", - "unit": "%", - "unitName": "百分比", - "step": "0.1" + "min": 0.0, + "max": 100.0, + "step": 0.1, + "unit": "%" } - } + }, + "description": "当前湿度值" + }, + { + "identifier": "GeoLocation", + "name": "地理位置", + "accessMode": "r", + "required": false, + "dataType": { + "type": "struct", + "specs": [ + { + "identifier": "Longitude", + "name": "经度", + "dataType": { + "type": "double", + "specs": { + "min": -180.0, + "max": 180.0, + "step": 0.000001, + "unit": "°" + } + }, + "description": "设备所在位置的经度" + }, + { + "identifier": "Latitude", + "name": "纬度", + "dataType": { + "type": "double", + "specs": { + "min": -90.0, + "max": 90.0, + "step": 0.000001, + "unit": "°" + } + }, + "description": "设备所在位置的纬度" + } + ] + }, + "description": "设备的地理位置信息" } ], - "services": "{}", - "events": "{}" + "services": [ + { + "identifier": "Reboot", + "name": "重启设备", + "callType": "async", + "inputData": [], + "description": "远程重启设备" + }, + { + "identifier": "SetThreshold", + "name": "设置温度阈值", + "callType": "sync", + "inputData": [ + { + "identifier": "Threshold", + "name": "阈值", + "dataType": { + "type": "float", + "specs": { + "min": -40.0, + "max": 125.0, + "step": 0.1, + "unit": "℃" + } + }, + "description": "报警温度阈值" + } + ], + "description": "设置设备的温度报警阈值" + } + ], + "events": [ + { + "identifier": "HighTemperatureAlert", + "name": "高温报警", + "type": "alert", + "outputData": [ + { + "identifier": "CurrentTemperature", + "name": "当前温度", + "dataType": { + "type": "float", + "specs": { + "unit": "℃" + } + }, + "description": "触发报警时的温度值" + } + ], + "description": "当温度超过阈值时触发高温报警事件" + } + ] } + ### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功 GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456 tenant-id: {{adminTenentId}} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java new file mode 100644 index 000000000..909d63459 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; + +@Data +public class ThingModelArgument { + private String identifier; + private String name; + private ThingModelDataType dataType; + private String direction; // 用于区分输入或输出参数,"input" 或 "output" + private String description; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java new file mode 100644 index 000000000..3ea23e8db --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; + +@Data +public class ThingModelArraySpecs { + private int size; // 数组长度 + private ThingModelDataType item; // 数组元素的类型 +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java new file mode 100644 index 000000000..114add210 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java @@ -0,0 +1,11 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelArrayType extends ThingModelDataType { + private ThingModelArraySpecs specs; +} + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java new file mode 100644 index 000000000..f7e7e456b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java @@ -0,0 +1,10 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelBoolType extends ThingModelDataType { + // Bool 类型一般不需要额外的 specs +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java new file mode 100644 index 000000000..613cbd766 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import lombok.Data; + +@Data +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = ThingModelIntType.class, name = "int"), + @JsonSubTypes.Type(value = ThingModelFloatType.class, name = "float"), + @JsonSubTypes.Type(value = ThingModelDoubleType.class, name = "double"), + @JsonSubTypes.Type(value = ThingModelTextType.class, name = "text"), + @JsonSubTypes.Type(value = ThingModelDateType.class, name = "date"), + @JsonSubTypes.Type(value = ThingModelBoolType.class, name = "bool"), + @JsonSubTypes.Type(value = ThingModelEnumType.class, name = "enum"), + @JsonSubTypes.Type(value = ThingModelStructType.class, name = "struct"), + @JsonSubTypes.Type(value = ThingModelArrayType.class, name = "array") +}) +public abstract class ThingModelDataType { + private String type; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java new file mode 100644 index 000000000..11cb3a729 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java @@ -0,0 +1,10 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelDateType extends ThingModelDataType { + // Date 类型一般不需要额外的 specs +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java new file mode 100644 index 000000000..d60302179 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelDoubleType extends ThingModelDataType { + private ThingModelDoubleSpecs specs; +} + +@Data +class ThingModelDoubleSpecs { + private Double min; + private Double max; + private Double step; + private String unit; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java new file mode 100644 index 000000000..f76962661 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java @@ -0,0 +1,11 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.Map; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelEnumType extends ThingModelDataType { + private Map specs; // 枚举值和描述的键值对 +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java new file mode 100644 index 000000000..857f688e9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import java.util.List; + +@Data +public class ThingModelEvent { + private String identifier; + private String name; + private String type; // "info"、"alert"、"error" + private List outputData; + private String description; + private String method; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java new file mode 100644 index 000000000..c9d5516ad --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelFloatType extends ThingModelDataType { + private ThingModelFloatSpecs specs; +} + +@Data +class ThingModelFloatSpecs { + private Float min; + private Float max; + private Float step; + private String unit; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java new file mode 100644 index 000000000..d48f50e47 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelIntType extends ThingModelDataType { + private ThingModelIntSpecs specs; +} + +@Data +class ThingModelIntSpecs { + private Integer min; + private Integer max; + private Integer step; + private String unit; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java new file mode 100644 index 000000000..f82198152 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; + +@Data +public class ThingModelProperty { + private String identifier; + private String name; + private String accessMode; // "rw"、"r"、"w" + private boolean required; + private ThingModelDataType dataType; + private String description; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java new file mode 100644 index 000000000..521e9ab08 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import java.util.List; + +@Data +public class ThingModelService { + private String identifier; + private String name; + private String callType; // "sync"、"async" + private List inputData; + private List outputData; + private String description; + private String method; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java new file mode 100644 index 000000000..449db55c2 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java @@ -0,0 +1,11 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; + +@Data +public class ThingModelStructField { + private String identifier; + private String name; + private ThingModelDataType dataType; + private String description; +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java new file mode 100644 index 000000000..d3d35f16c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.List; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelStructType extends ThingModelDataType { + private List specs; +} + + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java new file mode 100644 index 000000000..0f6ea2bcb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelTextType extends ThingModelDataType { + private ThingModelTextSpecs specs; +} + +@Data +class ThingModelTextSpecs { + private Integer length; // 最大长度 +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java deleted file mode 100644 index 0187ae514..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java +++ /dev/null @@ -1,90 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.util.List; - -@Schema(description = "管理后台 - IoT 产品物模型属性") -@Data -public class IotThingModelProperty { - - @Schema(description = "属性标识符") - private String identifier; - - @Schema(description = "属性名称") - private String name; - - @Schema(description = "访问模式 (r/rw)") - private String accessMode; - - @Schema(description = "是否必需") - private boolean required; - - @Schema(description = "数据类型") - private DataType dataType; - - @Schema(description = "数据类型") - @Data - public static class DataType { - - @Schema(description = "数据类型(float, double, struct, enum等)") - private String type; - - @Schema(description = "单一类型的规格(适用于float, double等)") - private Specs specs; - - @Schema(description = "结构体字段(适用于struct类型)") - private List structSpecs; - - @Schema(description = "规格") - @Data - public static class Specs { - - @Schema(description = "最小值") - private String min; - - @Schema(description = "最大值") - private String max; - - @Schema(description = "单位符号") - private String unit; - - @Schema(description = "单位名称") - private String unitName; - - @Schema(description = "步进值") - private String step; - } - - @Schema(description = "结构体字段") - @Data - public static class StructField { - - @Schema(description = "字段标识符") - private String identifier; - - @Schema(description = "字段名称") - private String name; - - @Schema(description = "字段的数据类型") - private DataType dataType; - } - } - - @Schema(description = "枚举规格") - @Data - public static class EnumSpecs { - - @Schema(description = "枚举值") - private int value; - - @Schema(description = "枚举名称") - private String name; - - public EnumSpecs(int value, String name) { - this.value = value; - this.name = name; - } - } -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java index 5d525e5b5..42ac727a4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java @@ -1,5 +1,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -23,15 +26,15 @@ public class IotThinkModelFunctionRespVO { @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("属性列表") - private List properties; + private List properties; @Schema(description = "服务列表") @ExcelProperty("服务列表") - private String services; + private List services; @Schema(description = "事件列表") @ExcelProperty("事件列表") - private String events; + private List events; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java index 705846210..00132fa8b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java @@ -1,9 +1,14 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import java.util.*; -import jakarta.validation.constraints.*; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") @Data @@ -22,12 +27,12 @@ public class IotThinkModelFunctionSaveReqVO { @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) @NotEmpty(message = "属性列表不能为空") - private List properties; + private List properties; @Schema(description = "服务列表") - private String services; + private List services; @Schema(description = "事件列表") - private String events; + private List events; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java index 783ef658a..41e0c583b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java @@ -1,16 +1,17 @@ package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction; import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; -import org.mapstruct.AfterMapping; import org.mapstruct.Mapper; import org.mapstruct.Mapping; -import org.mapstruct.MappingTarget; import org.mapstruct.factory.Mappers; +import java.util.ArrayList; import java.util.List; @Mapper @@ -18,34 +19,43 @@ public interface IotThinkModelFunctionConvert { IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class); - // 将 SaveReqVO 转换为 DO - @Mapping(target = "properties", ignore = true) + // 将 SaveReqVO 转换为 DO 对象,处理 properties, services, events 字段 + @Mapping(target = "properties", expression = "java(convertPropertiesToJson(bean.getProperties()))") + @Mapping(target = "services", expression = "java(convertServicesToJson(bean.getServices()))") + @Mapping(target = "events", expression = "java(convertEventsToJson(bean.getEvents()))") IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean); - // 将 DO 转换为 RespVO - @Mapping(target = "properties", ignore = true) - IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean); - - // 处理 properties 字段的转换,从 VO 到 DO - @AfterMapping - default void convertPropertiesToDO(IotThinkModelFunctionSaveReqVO source, @MappingTarget IotThinkModelFunctionDO target) { - target.setProperties(JSONUtil.toJsonStr(source.getProperties())); + default String convertPropertiesToJson(List properties) { + return properties != null ? JSONUtil.toJsonStr(properties) : "[]"; } - // 处理 properties 字段的转换,从 DO 到 VO - @AfterMapping - default void convertPropertiesToVO(IotThinkModelFunctionDO source, @MappingTarget IotThinkModelFunctionRespVO target) { - target.setProperties(JSONUtil.toList(source.getProperties(), IotThingModelProperty.class)); + default String convertServicesToJson(List services) { + return services != null ? JSONUtil.toJsonStr(services) : "[]"; + } + + default String convertEventsToJson(List events) { + return events != null ? JSONUtil.toJsonStr(events) : "[]"; + } + + // 将 DO 转换为 RespVO 对象,处理 properties, services, events 字段 + @Mapping(target = "properties", expression = "java(convertJsonToProperties(bean.getProperties()))") + @Mapping(target = "services", expression = "java(convertJsonToServices(bean.getServices()))") + @Mapping(target = "events", expression = "java(convertJsonToEvents(bean.getEvents()))") + IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean); + + default List convertJsonToProperties(String propertiesJson) { + return propertiesJson != null ? JSONUtil.toList(propertiesJson, ThingModelProperty.class) : new ArrayList<>(); + } + + default List convertJsonToServices(String servicesJson) { + return servicesJson != null ? JSONUtil.toList(servicesJson, ThingModelService.class) : new ArrayList<>(); + } + + default List convertJsonToEvents(String eventsJson) { + return eventsJson != null ? JSONUtil.toList(eventsJson, ThingModelEvent.class) : new ArrayList<>(); } // 批量转换 DO 列表到 RespVO 列表 List convertList(List list); - - // 批量转换处理 properties 字段 - @AfterMapping - default void convertPropertiesListToVO(List sourceList, @MappingTarget List targetList) { - for (int i = 0; i < sourceList.size(); i++) { - convertPropertiesToVO(sourceList.get(i), targetList.get(i)); - } - } } + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 89c5f6b98..66fc01779 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; -import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.*; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; @@ -10,6 +11,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS; @@ -27,10 +32,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe log.info("创建物模型,参数:{}", createReqVO); // 验证 ProductKey 对应的产品物模型是否已存在 validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey()); - // 插入 + // 转换请求对象为数据对象 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); + // 自动生成属性上报事件和属性设置、获取服务 + generateDefaultEventsAndServices(createReqVO, thinkModelFunction); + // 插入数据库 thinkModelFunctionMapper.insert(thinkModelFunction); - // 返回 + // 返回生成的 ID return thinkModelFunction.getId(); } @@ -43,9 +51,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Override public void deleteThinkModelFunction(Long id) { log.info("删除物模型,id:{}", id); - // 校验存在 + // 校验物模型是否存在 validateThinkModelFunctionExists(id); - // 删除 + // 删除物模型 thinkModelFunctionMapper.deleteById(id); } @@ -68,12 +76,15 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Override public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) { log.info("更新物模型,参数:{}", updateReqVO); - // 校验存在 + // 校验物模型是否存在 validateThinkModelFunctionExists(updateReqVO.getId()); - // 校验 productKey 是否重复 + // 校验 ProductKey 是否唯一 validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey()); - // 更新 + // 转换请求对象为数据对象 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); + // 自动生成或更新属性上报事件和属性设置、获取服务 + generateDefaultEventsAndServices(updateReqVO, thinkModelFunction); + // 更新数据库 thinkModelFunctionMapper.updateById(thinkModelFunction); } @@ -83,4 +94,151 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY); } } -} \ No newline at end of file + + /** + * @ TODO 还要再优化 + * 根据属性列表,自动生成属性上报事件和属性设置、获取服务 + */ + private void generateDefaultEventsAndServices(IotThinkModelFunctionSaveReqVO reqVO, IotThinkModelFunctionDO thinkModelFunction) { + // 获取属性列表 + List properties = reqVO.getProperties(); + if (properties == null) { + properties = new ArrayList<>(); + } + + // 生成属性上报事件 + List events = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>(); + ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties); + events.add(propertyPostEvent); + + // 生成属性设置和获取服务 + List services = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>(); + ThingModelService propertySetService = generatePropertySetService(properties); + if (propertySetService != null) { + services.add(propertySetService); + } + ThingModelService propertyGetService = generatePropertyGetService(properties); + if (propertyGetService != null) { + services.add(propertyGetService); + } + + // 更新 thinkModelFunction 对象的 events 和 services 字段 + thinkModelFunction.setEvents(JSONUtil.toJsonStr(events)); + thinkModelFunction.setServices(JSONUtil.toJsonStr(services)); + } + + /** + * 生成属性上报事件 + */ + private ThingModelEvent generatePropertyPostEvent(List properties) { + ThingModelEvent event = new ThingModelEvent(); + event.setIdentifier("post"); + event.setName("属性上报"); + event.setType("info"); + event.setDescription("属性上报事件"); + event.setMethod("thing.event.property.post"); + + // 将属性列表转换为事件的输出参数 + List outputData = new ArrayList<>(); + for (ThingModelProperty property : properties) { + ThingModelArgument arg = new ThingModelArgument(); + arg.setIdentifier(property.getIdentifier()); + arg.setName(property.getName()); + arg.setDataType(property.getDataType()); + arg.setDescription(property.getDescription()); + arg.setDirection("output"); // 设置为输出参数 + outputData.add(arg); + } + event.setOutputData(outputData); + + return event; + } + + /** + * 生成属性设置服务 + */ + private ThingModelService generatePropertySetService(List properties) { + List inputData = new ArrayList<>(); + for (ThingModelProperty property : properties) { + if ("w".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) { + ThingModelArgument arg = new ThingModelArgument(); + arg.setIdentifier(property.getIdentifier()); + arg.setName(property.getName()); + arg.setDataType(property.getDataType()); + arg.setDescription(property.getDescription()); + arg.setDirection("input"); // 设置为输入参数 + inputData.add(arg); + } + } + if (inputData.isEmpty()) { + // 如果没有可写属性,不生成属性设置服务 + return null; + } + + ThingModelService service = new ThingModelService(); + service.setIdentifier("set"); + service.setName("属性设置"); + service.setCallType("async"); + service.setDescription("属性设置服务"); + service.setMethod("thing.service.property.set"); + service.setInputData(inputData); + // 属性设置服务一般不需要输出参数 + service.setOutputData(new ArrayList<>()); + + return service; + } + + /** + * 生成属性获取服务 + */ + private ThingModelService generatePropertyGetService(List properties) { + List outputData = new ArrayList<>(); + for (ThingModelProperty property : properties) { + if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) { + ThingModelArgument arg = new ThingModelArgument(); + arg.setIdentifier(property.getIdentifier()); + arg.setName(property.getName()); + arg.setDataType(property.getDataType()); + arg.setDescription(property.getDescription()); + arg.setDirection("output"); // 设置为输出参数 + outputData.add(arg); + } + } + if (outputData.isEmpty()) { + // 如果没有可读属性,不生成属性获取服务 + return null; + } + + ThingModelService service = new ThingModelService(); + service.setIdentifier("get"); + service.setName("属性获取"); + service.setCallType("async"); + service.setDescription("属性获取服务"); + service.setMethod("thing.service.property.get"); + + // 定义输入参数:属性标识符列表 + ThingModelArgument inputArg = new ThingModelArgument(); + inputArg.setIdentifier("properties"); + inputArg.setName("属性标识符列表"); + inputArg.setDescription("需要获取的属性标识符列表"); + inputArg.setDirection("input"); // 设置为输入参数 + + // 创建数组类型,元素类型为文本类型(字符串) + ThingModelArrayType arrayType = new ThingModelArrayType(); + arrayType.setType("array"); + ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs(); + // 不指定数组长度,size 可以为 0 或者省略 + ThingModelTextType textType = new ThingModelTextType(); + textType.setType("text"); + // 如果有需要,可以设置 TextType 的 specs,如长度限制 + arraySpecs.setItem(textType); + arrayType.setSpecs(arraySpecs); + + inputArg.setDataType(arrayType); + + service.setInputData(Collections.singletonList(inputArg)); + service.setOutputData(outputData); + + return service; + } +}