Commit 1f8576f6432fe5201497d2c3704de809d7185307

Authored by 安浩浩
1 parent 9e776924

修改:IOT 根据属性列表,自动生成属性上报事件和属性设置、获取服务

Showing 22 changed files with 662 additions and 171 deletions
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}}
5 5 Authorization: Bearer {{token}}
6 6  
7 7 {
8   - "productId": 1,
9   - "productKey": "123456",
  8 + "productId": 1002,
  9 + "productKey": "smart-sensor-002",
10 10 "properties": [
11 11 {
12   - "identifier": "CurrentTemperature",
13   - "name": "当前温度",
  12 + "identifier": "Temperature",
  13 + "name": "温度",
14 14 "accessMode": "r",
15 15 "required": true,
16 16 "dataType": {
17 17 "type": "float",
18 18 "specs": {
19   - "min": "-40",
20   - "max": "120",
21   - "unit": "°C",
22   - "unitName": "摄氏度",
23   - "step": "0.1"
  19 + "min": -40.0,
  20 + "max": 125.0,
  21 + "step": 0.1,
  22 + "unit": "℃"
24 23 }
25   - }
  24 + },
  25 + "description": "当前温度值"
26 26 },
27 27 {
28   - "identifier": "CurrentHumidity",
29   - "name": "当前湿度",
  28 + "identifier": "Humidity",
  29 + "name": "湿度",
30 30 "accessMode": "r",
31 31 "required": true,
32 32 "dataType": {
33 33 "type": "float",
34 34 "specs": {
35   - "min": "0",
36   - "max": "100",
37   - "unit": "%",
38   - "unitName": "百分比",
39   - "step": "0.1"
  35 + "min": 0.0,
  36 + "max": 100.0,
  37 + "step": 0.1,
  38 + "unit": "%"
40 39 }
41   - }
  40 + },
  41 + "description": "当前湿度值"
  42 + },
  43 + {
  44 + "identifier": "GeoLocation",
  45 + "name": "地理位置",
  46 + "accessMode": "r",
  47 + "required": false,
  48 + "dataType": {
  49 + "type": "struct",
  50 + "specs": [
  51 + {
  52 + "identifier": "Longitude",
  53 + "name": "经度",
  54 + "dataType": {
  55 + "type": "double",
  56 + "specs": {
  57 + "min": -180.0,
  58 + "max": 180.0,
  59 + "step": 0.000001,
  60 + "unit": "°"
  61 + }
  62 + },
  63 + "description": "设备所在位置的经度"
  64 + },
  65 + {
  66 + "identifier": "Latitude",
  67 + "name": "纬度",
  68 + "dataType": {
  69 + "type": "double",
  70 + "specs": {
  71 + "min": -90.0,
  72 + "max": 90.0,
  73 + "step": 0.000001,
  74 + "unit": "°"
  75 + }
  76 + },
  77 + "description": "设备所在位置的纬度"
  78 + }
  79 + ]
  80 + },
  81 + "description": "设备的地理位置信息"
  82 + }
  83 + ],
  84 + "services": [
  85 + {
  86 + "identifier": "Reboot",
  87 + "name": "重启设备",
  88 + "callType": "async",
  89 + "inputData": [],
  90 + "description": "远程重启设备",
  91 + "method": "thing.service.reboot"
  92 + },
  93 + {
  94 + "identifier": "SetThreshold",
  95 + "name": "设置温度阈值",
  96 + "callType": "sync",
  97 + "inputData": [
  98 + {
  99 + "identifier": "Threshold",
  100 + "name": "阈值",
  101 + "dataType": {
  102 + "type": "float",
  103 + "specs": {
  104 + "min": -40.0,
  105 + "max": 125.0,
  106 + "step": 0.1,
  107 + "unit": "℃"
  108 + }
  109 + },
  110 + "description": "报警温度阈值"
  111 + }
  112 + ],
  113 + "description": "设置设备的温度报警阈值",
  114 + "method": "thing.service.setThreshold"
42 115 }
43 116 ],
44   - "services": "{}",
45   - "events": "{}"
  117 + "events": [
  118 + {
  119 + "identifier": "HighTemperatureAlert",
  120 + "name": "高温报警",
  121 + "type": "alert",
  122 + "outputData": [
  123 + {
  124 + "identifier": "CurrentTemperature",
  125 + "name": "当前温度",
  126 + "dataType": {
  127 + "type": "float",
  128 + "specs": {
  129 + "unit": "℃"
  130 + }
  131 + },
  132 + "description": "触发报警时的温度值"
  133 + }
  134 + ],
  135 + "description": "当温度超过阈值时触发高温报警事件",
  136 + "method": "thing.event.highTemperatureAlert"
  137 + }
  138 + ]
46 139 }
47 140  
  141 +
48 142 ### 请求 /iot/think-model-function/update 接口 => 成功
49 143 PUT {{baseUrl}}/iot/think-model-function/update
50 144 Content-Type: application/json
... ... @@ -53,46 +147,137 @@ Authorization: Bearer {{token}}
53 147  
54 148 {
55 149 "id": 1,
56   - "productId": 1,
57   - "productKey": "123456",
  150 + "productId": 1001,
  151 + "productKey": "smart-sensor-001",
58 152 "properties": [
59 153 {
60   - "identifier": "CurrentTemperature",
61   - "name": "当前温度",
  154 + "identifier": "Temperature",
  155 + "name": "温度",
62 156 "accessMode": "r",
63 157 "required": true,
64 158 "dataType": {
65 159 "type": "float",
66 160 "specs": {
67   - "min": "-40",
68   - "max": "130",
69   - "unit": "°C",
70   - "unitName": "摄氏度",
71   - "step": "0.1"
  161 + "min": -40.0,
  162 + "max": 125.0,
  163 + "step": 0.1,
  164 + "unit": "℃"
72 165 }
73   - }
  166 + },
  167 + "description": "当前温度值"
74 168 },
75 169 {
76   - "identifier": "CurrentHumidity",
77   - "name": "当前湿度",
  170 + "identifier": "Humidity",
  171 + "name": "湿度",
78 172 "accessMode": "r",
79 173 "required": true,
80 174 "dataType": {
81 175 "type": "float",
82 176 "specs": {
83   - "min": "0",
84   - "max": "100",
85   - "unit": "%",
86   - "unitName": "百分比",
87   - "step": "0.1"
  177 + "min": 0.0,
  178 + "max": 100.0,
  179 + "step": 0.1,
  180 + "unit": "%"
88 181 }
89   - }
  182 + },
  183 + "description": "当前湿度值"
  184 + },
  185 + {
  186 + "identifier": "GeoLocation",
  187 + "name": "地理位置",
  188 + "accessMode": "r",
  189 + "required": false,
  190 + "dataType": {
  191 + "type": "struct",
  192 + "specs": [
  193 + {
  194 + "identifier": "Longitude",
  195 + "name": "经度",
  196 + "dataType": {
  197 + "type": "double",
  198 + "specs": {
  199 + "min": -180.0,
  200 + "max": 180.0,
  201 + "step": 0.000001,
  202 + "unit": "°"
  203 + }
  204 + },
  205 + "description": "设备所在位置的经度"
  206 + },
  207 + {
  208 + "identifier": "Latitude",
  209 + "name": "纬度",
  210 + "dataType": {
  211 + "type": "double",
  212 + "specs": {
  213 + "min": -90.0,
  214 + "max": 90.0,
  215 + "step": 0.000001,
  216 + "unit": "°"
  217 + }
  218 + },
  219 + "description": "设备所在位置的纬度"
  220 + }
  221 + ]
  222 + },
  223 + "description": "设备的地理位置信息"
  224 + }
  225 + ],
  226 + "services": [
  227 + {
  228 + "identifier": "Reboot",
  229 + "name": "重启设备",
  230 + "callType": "async",
  231 + "inputData": [],
  232 + "description": "远程重启设备"
  233 + },
  234 + {
  235 + "identifier": "SetThreshold",
  236 + "name": "设置温度阈值",
  237 + "callType": "sync",
  238 + "inputData": [
  239 + {
  240 + "identifier": "Threshold",
  241 + "name": "阈值",
  242 + "dataType": {
  243 + "type": "float",
  244 + "specs": {
  245 + "min": -40.0,
  246 + "max": 125.0,
  247 + "step": 0.1,
  248 + "unit": "℃"
  249 + }
  250 + },
  251 + "description": "报警温度阈值"
  252 + }
  253 + ],
  254 + "description": "设置设备的温度报警阈值"
90 255 }
91 256 ],
92   - "services": "{}",
93   - "events": "{}"
  257 + "events": [
  258 + {
  259 + "identifier": "HighTemperatureAlert",
  260 + "name": "高温报警",
  261 + "type": "alert",
  262 + "outputData": [
  263 + {
  264 + "identifier": "CurrentTemperature",
  265 + "name": "当前温度",
  266 + "dataType": {
  267 + "type": "float",
  268 + "specs": {
  269 + "unit": "℃"
  270 + }
  271 + },
  272 + "description": "触发报警时的温度值"
  273 + }
  274 + ],
  275 + "description": "当温度超过阈值时触发高温报警事件"
  276 + }
  277 + ]
94 278 }
95 279  
  280 +
96 281 ### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功
97 282 GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456
98 283 tenant-id: {{adminTenentId}}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class ThingModelArgument {
  7 + private String identifier;
  8 + private String name;
  9 + private ThingModelDataType dataType;
  10 + private String direction; // 用于区分输入或输出参数,"input" 或 "output"
  11 + private String description;
  12 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class ThingModelArraySpecs {
  7 + private int size; // 数组长度
  8 + private ThingModelDataType item; // 数组元素的类型
  9 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +
  6 +@Data
  7 +@EqualsAndHashCode(callSuper = true)
  8 +public class ThingModelArrayType extends ThingModelDataType {
  9 + private ThingModelArraySpecs specs;
  10 +}
  11 +
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +
  6 +@Data
  7 +@EqualsAndHashCode(callSuper = true)
  8 +public class ThingModelBoolType extends ThingModelDataType {
  9 + // Bool 类型一般不需要额外的 specs
  10 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonSubTypes;
  4 +import com.fasterxml.jackson.annotation.JsonTypeInfo;
  5 +import lombok.Data;
  6 +
  7 +@Data
  8 +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
  9 +@JsonSubTypes({
  10 + @JsonSubTypes.Type(value = ThingModelIntType.class, name = "int"),
  11 + @JsonSubTypes.Type(value = ThingModelFloatType.class, name = "float"),
  12 + @JsonSubTypes.Type(value = ThingModelDoubleType.class, name = "double"),
  13 + @JsonSubTypes.Type(value = ThingModelTextType.class, name = "text"),
  14 + @JsonSubTypes.Type(value = ThingModelDateType.class, name = "date"),
  15 + @JsonSubTypes.Type(value = ThingModelBoolType.class, name = "bool"),
  16 + @JsonSubTypes.Type(value = ThingModelEnumType.class, name = "enum"),
  17 + @JsonSubTypes.Type(value = ThingModelStructType.class, name = "struct"),
  18 + @JsonSubTypes.Type(value = ThingModelArrayType.class, name = "array")
  19 +})
  20 +public abstract class ThingModelDataType {
  21 + private String type;
  22 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +
  6 +@Data
  7 +@EqualsAndHashCode(callSuper = true)
  8 +public class ThingModelDateType extends ThingModelDataType {
  9 + // Date 类型一般不需要额外的 specs
  10 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +
  6 +@Data
  7 +@EqualsAndHashCode(callSuper = true)
  8 +public class ThingModelDoubleType extends ThingModelDataType {
  9 + private ThingModelDoubleSpecs specs;
  10 +}
  11 +
  12 +@Data
  13 +class ThingModelDoubleSpecs {
  14 + private Double min;
  15 + private Double max;
  16 + private Double step;
  17 + private String unit;
  18 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +import java.util.Map;
  6 +
  7 +@Data
  8 +@EqualsAndHashCode(callSuper = true)
  9 +public class ThingModelEnumType extends ThingModelDataType {
  10 + private Map<String, String> specs; // 枚举值和描述的键值对
  11 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +import java.util.List;
  5 +
  6 +@Data
  7 +public class ThingModelEvent {
  8 + private String identifier;
  9 + private String name;
  10 + private String type; // "info"、"alert"、"error"
  11 + private List<ThingModelArgument> outputData;
  12 + private String description;
  13 + private String method;
  14 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +
  6 +@Data
  7 +@EqualsAndHashCode(callSuper = true)
  8 +public class ThingModelFloatType extends ThingModelDataType {
  9 + private ThingModelFloatSpecs specs;
  10 +}
  11 +
  12 +@Data
  13 +class ThingModelFloatSpecs {
  14 + private Float min;
  15 + private Float max;
  16 + private Float step;
  17 + private String unit;
  18 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +
  6 +@Data
  7 +@EqualsAndHashCode(callSuper = true)
  8 +public class ThingModelIntType extends ThingModelDataType {
  9 + private ThingModelIntSpecs specs;
  10 +}
  11 +
  12 +@Data
  13 +class ThingModelIntSpecs {
  14 + private Integer min;
  15 + private Integer max;
  16 + private Integer step;
  17 + private String unit;
  18 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class ThingModelProperty {
  7 + private String identifier;
  8 + private String name;
  9 + private String accessMode; // "rw"、"r"、"w"
  10 + private boolean required;
  11 + private ThingModelDataType dataType;
  12 + private String description;
  13 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +import java.util.List;
  5 +
  6 +@Data
  7 +public class ThingModelService {
  8 + private String identifier;
  9 + private String name;
  10 + private String callType; // "sync"、"async"
  11 + private List<ThingModelArgument> inputData;
  12 + private List<ThingModelArgument> outputData;
  13 + private String description;
  14 + private String method;
  15 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class ThingModelStructField {
  7 + private String identifier;
  8 + private String name;
  9 + private ThingModelDataType dataType;
  10 + private String description;
  11 +}
0 12 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +import java.util.List;
  6 +
  7 +@Data
  8 +@EqualsAndHashCode(callSuper = true)
  9 +public class ThingModelStructType extends ThingModelDataType {
  10 + private List<ThingModelStructField> specs;
  11 +}
  12 +
  13 +
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +
  6 +@Data
  7 +@EqualsAndHashCode(callSuper = true)
  8 +public class ThingModelTextType extends ThingModelDataType {
  9 + private ThingModelTextSpecs specs;
  10 +}
  11 +
  12 +@Data
  13 +class ThingModelTextSpecs {
  14 + private Integer length; // 最大长度
  15 +}
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java deleted
1   -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -
6   -import java.util.List;
7   -
8   -@Schema(description = "管理后台 - IoT 产品物模型属性")
9   -@Data
10   -public class IotThingModelProperty {
11   -
12   - @Schema(description = "属性标识符")
13   - private String identifier;
14   -
15   - @Schema(description = "属性名称")
16   - private String name;
17   -
18   - @Schema(description = "访问模式 (r/rw)")
19   - private String accessMode;
20   -
21   - @Schema(description = "是否必需")
22   - private boolean required;
23   -
24   - @Schema(description = "数据类型")
25   - private DataType dataType;
26   -
27   - @Schema(description = "数据类型")
28   - @Data
29   - public static class DataType {
30   -
31   - @Schema(description = "数据类型(float, double, struct, enum等)")
32   - private String type;
33   -
34   - @Schema(description = "单一类型的规格(适用于float, double等)")
35   - private Specs specs;
36   -
37   - @Schema(description = "结构体字段(适用于struct类型)")
38   - private List<StructField> structSpecs;
39   -
40   - @Schema(description = "规格")
41   - @Data
42   - public static class Specs {
43   -
44   - @Schema(description = "最小值")
45   - private String min;
46   -
47   - @Schema(description = "最大值")
48   - private String max;
49   -
50   - @Schema(description = "单位符号")
51   - private String unit;
52   -
53   - @Schema(description = "单位名称")
54   - private String unitName;
55   -
56   - @Schema(description = "步进值")
57   - private String step;
58   - }
59   -
60   - @Schema(description = "结构体字段")
61   - @Data
62   - public static class StructField {
63   -
64   - @Schema(description = "字段标识符")
65   - private String identifier;
66   -
67   - @Schema(description = "字段名称")
68   - private String name;
69   -
70   - @Schema(description = "字段的数据类型")
71   - private DataType dataType;
72   - }
73   - }
74   -
75   - @Schema(description = "枚举规格")
76   - @Data
77   - public static class EnumSpecs {
78   -
79   - @Schema(description = "枚举值")
80   - private int value;
81   -
82   - @Schema(description = "枚举名称")
83   - private String name;
84   -
85   - public EnumSpecs(int value, String name) {
86   - this.value = value;
87   - this.name = name;
88   - }
89   - }
90   -}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
1 1 package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
2 2  
  3 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
  5 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
3 6 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
4 7 import com.alibaba.excel.annotation.ExcelProperty;
5 8 import io.swagger.v3.oas.annotations.media.Schema;
... ... @@ -23,15 +26,15 @@ public class IotThinkModelFunctionRespVO {
23 26  
24 27 @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
25 28 @ExcelProperty("属性列表")
26   - private List<IotThingModelProperty> properties;
  29 + private List<ThingModelProperty> properties;
27 30  
28 31 @Schema(description = "服务列表")
29 32 @ExcelProperty("服务列表")
30   - private String services;
  33 + private List<ThingModelService> services;
31 34  
32 35 @Schema(description = "事件列表")
33 36 @ExcelProperty("事件列表")
34   - private String events;
  37 + private List<ThingModelEvent> events;
35 38  
36 39 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
37 40 @ExcelProperty("创建时间")
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
1 1 package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
2 2  
  3 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
  5 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
3 6 import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.*;
5   -import java.util.*;
6   -import jakarta.validation.constraints.*;
  7 +import jakarta.validation.constraints.NotEmpty;
  8 +import jakarta.validation.constraints.NotNull;
  9 +import lombok.Data;
  10 +
  11 +import java.util.List;
7 12  
8 13 @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO")
9 14 @Data
... ... @@ -22,12 +27,12 @@ public class IotThinkModelFunctionSaveReqVO {
22 27  
23 28 @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
24 29 @NotEmpty(message = "属性列表不能为空")
25   - private List<IotThingModelProperty> properties;
  30 + private List<ThingModelProperty> properties;
26 31  
27 32 @Schema(description = "服务列表")
28   - private String services;
  33 + private List<ThingModelService> services;
29 34  
30 35 @Schema(description = "事件列表")
31   - private String events;
  36 + private List<ThingModelEvent> events;
32 37  
33 38 }
34 39 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
1 1 package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction;
2 2  
3 3 import cn.hutool.json.JSONUtil;
4   -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThingModelProperty;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
  5 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
5 7 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO;
6 8 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
7 9 import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
8   -import org.mapstruct.AfterMapping;
9 10 import org.mapstruct.Mapper;
10 11 import org.mapstruct.Mapping;
11   -import org.mapstruct.MappingTarget;
12 12 import org.mapstruct.factory.Mappers;
13 13  
  14 +import java.util.ArrayList;
14 15 import java.util.List;
15 16  
16 17 @Mapper
... ... @@ -18,34 +19,43 @@ public interface IotThinkModelFunctionConvert {
18 19  
19 20 IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class);
20 21  
21   - // 将 SaveReqVO 转换为 DO
22   - @Mapping(target = "properties", ignore = true)
  22 + // 将 SaveReqVO 转换为 DO 对象,处理 properties, services, events 字段
  23 + @Mapping(target = "properties", expression = "java(convertPropertiesToJson(bean.getProperties()))")
  24 + @Mapping(target = "services", expression = "java(convertServicesToJson(bean.getServices()))")
  25 + @Mapping(target = "events", expression = "java(convertEventsToJson(bean.getEvents()))")
23 26 IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean);
24 27  
25   - // 将 DO 转换为 RespVO
26   - @Mapping(target = "properties", ignore = true)
  28 + default String convertPropertiesToJson(List<ThingModelProperty> properties) {
  29 + return properties != null ? JSONUtil.toJsonStr(properties) : "[]";
  30 + }
  31 +
  32 + default String convertServicesToJson(List<ThingModelService> services) {
  33 + return services != null ? JSONUtil.toJsonStr(services) : "[]";
  34 + }
  35 +
  36 + default String convertEventsToJson(List<ThingModelEvent> events) {
  37 + return events != null ? JSONUtil.toJsonStr(events) : "[]";
  38 + }
  39 +
  40 + // 将 DO 转换为 RespVO 对象,处理 properties, services, events 字段
  41 + @Mapping(target = "properties", expression = "java(convertJsonToProperties(bean.getProperties()))")
  42 + @Mapping(target = "services", expression = "java(convertJsonToServices(bean.getServices()))")
  43 + @Mapping(target = "events", expression = "java(convertJsonToEvents(bean.getEvents()))")
27 44 IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean);
28 45  
29   - // 处理 properties 字段的转换,从 VO 到 DO
30   - @AfterMapping
31   - default void convertPropertiesToDO(IotThinkModelFunctionSaveReqVO source, @MappingTarget IotThinkModelFunctionDO target) {
32   - target.setProperties(JSONUtil.toJsonStr(source.getProperties()));
  46 + default List<ThingModelProperty> convertJsonToProperties(String propertiesJson) {
  47 + return propertiesJson != null ? JSONUtil.toList(propertiesJson, ThingModelProperty.class) : new ArrayList<>();
33 48 }
34 49  
35   - // 处理 properties 字段的转换,从 DO 到 VO
36   - @AfterMapping
37   - default void convertPropertiesToVO(IotThinkModelFunctionDO source, @MappingTarget IotThinkModelFunctionRespVO target) {
38   - target.setProperties(JSONUtil.toList(source.getProperties(), IotThingModelProperty.class));
  50 + default List<ThingModelService> convertJsonToServices(String servicesJson) {
  51 + return servicesJson != null ? JSONUtil.toList(servicesJson, ThingModelService.class) : new ArrayList<>();
  52 + }
  53 +
  54 + default List<ThingModelEvent> convertJsonToEvents(String eventsJson) {
  55 + return eventsJson != null ? JSONUtil.toList(eventsJson, ThingModelEvent.class) : new ArrayList<>();
39 56 }
40 57  
41 58 // 批量转换 DO 列表到 RespVO 列表
42 59 List<IotThinkModelFunctionRespVO> convertList(List<IotThinkModelFunctionDO> list);
43   -
44   - // 批量转换处理 properties 字段
45   - @AfterMapping
46   - default void convertPropertiesListToVO(List<IotThinkModelFunctionDO> sourceList, @MappingTarget List<IotThinkModelFunctionRespVO> targetList) {
47   - for (int i = 0; i < sourceList.size(); i++) {
48   - convertPropertiesToVO(sourceList.get(i), targetList.get(i));
49   - }
50   - }
51 60 }
  61 +
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
1 1 package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
2 2  
3   -import cn.iocoder.yudao.framework.common.exception.ServiceException;
  3 +import cn.hutool.json.JSONUtil;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.*;
4 5 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
5 6 import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
6 7 import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
... ... @@ -10,6 +11,10 @@ import lombok.extern.slf4j.Slf4j;
10 11 import org.springframework.stereotype.Service;
11 12 import org.springframework.validation.annotation.Validated;
12 13  
  14 +import java.util.ArrayList;
  15 +import java.util.Collections;
  16 +import java.util.List;
  17 +
13 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
14 19 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY;
15 20 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS;
... ... @@ -27,10 +32,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
27 32 log.info("创建物模型,参数:{}", createReqVO);
28 33 // 验证 ProductKey 对应的产品物模型是否已存在
29 34 validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey());
30   - // 插入
  35 + // 转换请求对象为数据对象
31 36 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO);
  37 + // 自动生成属性上报事件和属性设置、获取服务
  38 + generateDefaultEventsAndServices(createReqVO, thinkModelFunction);
  39 + // 插入数据库
32 40 thinkModelFunctionMapper.insert(thinkModelFunction);
33   - // 返回
  41 + // 返回生成的 ID
34 42 return thinkModelFunction.getId();
35 43 }
36 44  
... ... @@ -43,9 +51,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
43 51 @Override
44 52 public void deleteThinkModelFunction(Long id) {
45 53 log.info("删除物模型,id:{}", id);
46   - // 校验存在
  54 + // 校验物模型是否存在
47 55 validateThinkModelFunctionExists(id);
48   - // 删除
  56 + // 删除物模型
49 57 thinkModelFunctionMapper.deleteById(id);
50 58 }
51 59  
... ... @@ -68,12 +76,15 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
68 76 @Override
69 77 public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
70 78 log.info("更新物模型,参数:{}", updateReqVO);
71   - // 校验存在
  79 + // 校验物模型是否存在
72 80 validateThinkModelFunctionExists(updateReqVO.getId());
73   - // 校验 productKey 是否重复
  81 + // 校验 ProductKey 是否唯一
74 82 validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey());
75   - // 更新
  83 + // 转换请求对象为数据对象
76 84 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
  85 + // 自动生成或更新属性上报事件和属性设置、获取服务
  86 + generateDefaultEventsAndServices(updateReqVO, thinkModelFunction);
  87 + // 更新数据库
77 88 thinkModelFunctionMapper.updateById(thinkModelFunction);
78 89 }
79 90  
... ... @@ -83,4 +94,151 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
83 94 throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY);
84 95 }
85 96 }
86   -}
87 97 \ No newline at end of file
  98 +
  99 + /**
  100 + * @ TODO 还要再优化
  101 + * 根据属性列表,自动生成属性上报事件和属性设置、获取服务
  102 + */
  103 + private void generateDefaultEventsAndServices(IotThinkModelFunctionSaveReqVO reqVO, IotThinkModelFunctionDO thinkModelFunction) {
  104 + // 获取属性列表
  105 + List<ThingModelProperty> properties = reqVO.getProperties();
  106 + if (properties == null) {
  107 + properties = new ArrayList<>();
  108 + }
  109 +
  110 + // 生成属性上报事件
  111 + List<ThingModelEvent> events = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>();
  112 + ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties);
  113 + events.add(propertyPostEvent);
  114 +
  115 + // 生成属性设置和获取服务
  116 + List<ThingModelService> services = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>();
  117 + ThingModelService propertySetService = generatePropertySetService(properties);
  118 + if (propertySetService != null) {
  119 + services.add(propertySetService);
  120 + }
  121 + ThingModelService propertyGetService = generatePropertyGetService(properties);
  122 + if (propertyGetService != null) {
  123 + services.add(propertyGetService);
  124 + }
  125 +
  126 + // 更新 thinkModelFunction 对象的 events 和 services 字段
  127 + thinkModelFunction.setEvents(JSONUtil.toJsonStr(events));
  128 + thinkModelFunction.setServices(JSONUtil.toJsonStr(services));
  129 + }
  130 +
  131 + /**
  132 + * 生成属性上报事件
  133 + */
  134 + private ThingModelEvent generatePropertyPostEvent(List<ThingModelProperty> properties) {
  135 + ThingModelEvent event = new ThingModelEvent();
  136 + event.setIdentifier("post");
  137 + event.setName("属性上报");
  138 + event.setType("info");
  139 + event.setDescription("属性上报事件");
  140 + event.setMethod("thing.event.property.post");
  141 +
  142 + // 将属性列表转换为事件的输出参数
  143 + List<ThingModelArgument> outputData = new ArrayList<>();
  144 + for (ThingModelProperty property : properties) {
  145 + ThingModelArgument arg = new ThingModelArgument();
  146 + arg.setIdentifier(property.getIdentifier());
  147 + arg.setName(property.getName());
  148 + arg.setDataType(property.getDataType());
  149 + arg.setDescription(property.getDescription());
  150 + arg.setDirection("output"); // 设置为输出参数
  151 + outputData.add(arg);
  152 + }
  153 + event.setOutputData(outputData);
  154 +
  155 + return event;
  156 + }
  157 +
  158 + /**
  159 + * 生成属性设置服务
  160 + */
  161 + private ThingModelService generatePropertySetService(List<ThingModelProperty> properties) {
  162 + List<ThingModelArgument> inputData = new ArrayList<>();
  163 + for (ThingModelProperty property : properties) {
  164 + if ("w".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
  165 + ThingModelArgument arg = new ThingModelArgument();
  166 + arg.setIdentifier(property.getIdentifier());
  167 + arg.setName(property.getName());
  168 + arg.setDataType(property.getDataType());
  169 + arg.setDescription(property.getDescription());
  170 + arg.setDirection("input"); // 设置为输入参数
  171 + inputData.add(arg);
  172 + }
  173 + }
  174 + if (inputData.isEmpty()) {
  175 + // 如果没有可写属性,不生成属性设置服务
  176 + return null;
  177 + }
  178 +
  179 + ThingModelService service = new ThingModelService();
  180 + service.setIdentifier("set");
  181 + service.setName("属性设置");
  182 + service.setCallType("async");
  183 + service.setDescription("属性设置服务");
  184 + service.setMethod("thing.service.property.set");
  185 + service.setInputData(inputData);
  186 + // 属性设置服务一般不需要输出参数
  187 + service.setOutputData(new ArrayList<>());
  188 +
  189 + return service;
  190 + }
  191 +
  192 + /**
  193 + * 生成属性获取服务
  194 + */
  195 + private ThingModelService generatePropertyGetService(List<ThingModelProperty> properties) {
  196 + List<ThingModelArgument> outputData = new ArrayList<>();
  197 + for (ThingModelProperty property : properties) {
  198 + if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
  199 + ThingModelArgument arg = new ThingModelArgument();
  200 + arg.setIdentifier(property.getIdentifier());
  201 + arg.setName(property.getName());
  202 + arg.setDataType(property.getDataType());
  203 + arg.setDescription(property.getDescription());
  204 + arg.setDirection("output"); // 设置为输出参数
  205 + outputData.add(arg);
  206 + }
  207 + }
  208 + if (outputData.isEmpty()) {
  209 + // 如果没有可读属性,不生成属性获取服务
  210 + return null;
  211 + }
  212 +
  213 + ThingModelService service = new ThingModelService();
  214 + service.setIdentifier("get");
  215 + service.setName("属性获取");
  216 + service.setCallType("async");
  217 + service.setDescription("属性获取服务");
  218 + service.setMethod("thing.service.property.get");
  219 +
  220 + // 定义输入参数:属性标识符列表
  221 + ThingModelArgument inputArg = new ThingModelArgument();
  222 + inputArg.setIdentifier("properties");
  223 + inputArg.setName("属性标识符列表");
  224 + inputArg.setDescription("需要获取的属性标识符列表");
  225 + inputArg.setDirection("input"); // 设置为输入参数
  226 +
  227 + // 创建数组类型,元素类型为文本类型(字符串)
  228 + ThingModelArrayType arrayType = new ThingModelArrayType();
  229 + arrayType.setType("array");
  230 + ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs();
  231 + // 不指定数组长度,size 可以为 0 或者省略
  232 + ThingModelTextType textType = new ThingModelTextType();
  233 + textType.setType("text");
  234 + // 如果有需要,可以设置 TextType 的 specs,如长度限制
  235 + arraySpecs.setItem(textType);
  236 + arrayType.setSpecs(arraySpecs);
  237 +
  238 + inputArg.setDataType(arrayType);
  239 +
  240 + service.setInputData(Collections.singletonList(inputArg));
  241 + service.setOutputData(outputData);
  242 +
  243 + return service;
  244 + }
  245 +}
... ...