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,46 +5,140 @@ tenant-id: {{adminTenentId}}
5 Authorization: Bearer {{token}} 5 Authorization: Bearer {{token}}
6 6
7 { 7 {
8 - "productId": 1,  
9 - "productKey": "123456", 8 + "productId": 1002,
  9 + "productKey": "smart-sensor-002",
10 "properties": [ 10 "properties": [
11 { 11 {
12 - "identifier": "CurrentTemperature",  
13 - "name": "当前温度", 12 + "identifier": "Temperature",
  13 + "name": "温度",
14 "accessMode": "r", 14 "accessMode": "r",
15 "required": true, 15 "required": true,
16 "dataType": { 16 "dataType": {
17 "type": "float", 17 "type": "float",
18 "specs": { 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 "accessMode": "r", 30 "accessMode": "r",
31 "required": true, 31 "required": true,
32 "dataType": { 32 "dataType": {
33 "type": "float", 33 "type": "float",
34 "specs": { 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 ### 请求 /iot/think-model-function/update 接口 => 成功 142 ### 请求 /iot/think-model-function/update 接口 => 成功
49 PUT {{baseUrl}}/iot/think-model-function/update 143 PUT {{baseUrl}}/iot/think-model-function/update
50 Content-Type: application/json 144 Content-Type: application/json
@@ -53,46 +147,137 @@ Authorization: Bearer {{token}} @@ -53,46 +147,137 @@ Authorization: Bearer {{token}}
53 147
54 { 148 {
55 "id": 1, 149 "id": 1,
56 - "productId": 1,  
57 - "productKey": "123456", 150 + "productId": 1001,
  151 + "productKey": "smart-sensor-001",
58 "properties": [ 152 "properties": [
59 { 153 {
60 - "identifier": "CurrentTemperature",  
61 - "name": "当前温度", 154 + "identifier": "Temperature",
  155 + "name": "温度",
62 "accessMode": "r", 156 "accessMode": "r",
63 "required": true, 157 "required": true,
64 "dataType": { 158 "dataType": {
65 "type": "float", 159 "type": "float",
66 "specs": { 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 "accessMode": "r", 172 "accessMode": "r",
79 "required": true, 173 "required": true,
80 "dataType": { 174 "dataType": {
81 "type": "float", 175 "type": "float",
82 "specs": { 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 ### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功 281 ### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功
97 GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456 282 GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456
98 tenant-id: {{adminTenentId}} 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 \ No newline at end of file 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 package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; 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 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; 6 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
4 import com.alibaba.excel.annotation.ExcelProperty; 7 import com.alibaba.excel.annotation.ExcelProperty;
5 import io.swagger.v3.oas.annotations.media.Schema; 8 import io.swagger.v3.oas.annotations.media.Schema;
@@ -23,15 +26,15 @@ public class IotThinkModelFunctionRespVO { @@ -23,15 +26,15 @@ public class IotThinkModelFunctionRespVO {
23 26
24 @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) 27 @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
25 @ExcelProperty("属性列表") 28 @ExcelProperty("属性列表")
26 - private List<IotThingModelProperty> properties; 29 + private List<ThingModelProperty> properties;
27 30
28 @Schema(description = "服务列表") 31 @Schema(description = "服务列表")
29 @ExcelProperty("服务列表") 32 @ExcelProperty("服务列表")
30 - private String services; 33 + private List<ThingModelService> services;
31 34
32 @Schema(description = "事件列表") 35 @Schema(description = "事件列表")
33 @ExcelProperty("事件列表") 36 @ExcelProperty("事件列表")
34 - private String events; 37 + private List<ThingModelEvent> events;
35 38
36 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 39 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
37 @ExcelProperty("创建时间") 40 @ExcelProperty("创建时间")
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
1 package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; 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 import io.swagger.v3.oas.annotations.media.Schema; 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 @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") 13 @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO")
9 @Data 14 @Data
@@ -22,12 +27,12 @@ public class IotThinkModelFunctionSaveReqVO { @@ -22,12 +27,12 @@ public class IotThinkModelFunctionSaveReqVO {
22 27
23 @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) 28 @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
24 @NotEmpty(message = "属性列表不能为空") 29 @NotEmpty(message = "属性列表不能为空")
25 - private List<IotThingModelProperty> properties; 30 + private List<ThingModelProperty> properties;
26 31
27 @Schema(description = "服务列表") 32 @Schema(description = "服务列表")
28 - private String services; 33 + private List<ThingModelService> services;
29 34
30 @Schema(description = "事件列表") 35 @Schema(description = "事件列表")
31 - private String events; 36 + private List<ThingModelEvent> events;
32 37
33 } 38 }
34 \ No newline at end of file 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 package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction; 1 package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction;
2 2
3 import cn.hutool.json.JSONUtil; 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 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; 7 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO;
6 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; 8 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
7 import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; 9 import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
8 -import org.mapstruct.AfterMapping;  
9 import org.mapstruct.Mapper; 10 import org.mapstruct.Mapper;
10 import org.mapstruct.Mapping; 11 import org.mapstruct.Mapping;
11 -import org.mapstruct.MappingTarget;  
12 import org.mapstruct.factory.Mappers; 12 import org.mapstruct.factory.Mappers;
13 13
  14 +import java.util.ArrayList;
14 import java.util.List; 15 import java.util.List;
15 16
16 @Mapper 17 @Mapper
@@ -18,34 +19,43 @@ public interface IotThinkModelFunctionConvert { @@ -18,34 +19,43 @@ public interface IotThinkModelFunctionConvert {
18 19
19 IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class); 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 IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean); 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 IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean); 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 // 批量转换 DO 列表到 RespVO 列表 58 // 批量转换 DO 列表到 RespVO 列表
42 List<IotThinkModelFunctionRespVO> convertList(List<IotThinkModelFunctionDO> list); 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 package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; 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 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; 5 import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
5 import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; 6 import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
6 import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
@@ -10,6 +11,10 @@ import lombok.extern.slf4j.Slf4j; @@ -10,6 +11,10 @@ import lombok.extern.slf4j.Slf4j;
10 import org.springframework.stereotype.Service; 11 import org.springframework.stereotype.Service;
11 import org.springframework.validation.annotation.Validated; 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 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
14 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY; 19 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY;
15 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS; 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,10 +32,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
27 log.info("创建物模型,参数:{}", createReqVO); 32 log.info("创建物模型,参数:{}", createReqVO);
28 // 验证 ProductKey 对应的产品物模型是否已存在 33 // 验证 ProductKey 对应的产品物模型是否已存在
29 validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey()); 34 validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey());
30 - // 插入 35 + // 转换请求对象为数据对象
31 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); 36 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO);
  37 + // 自动生成属性上报事件和属性设置、获取服务
  38 + generateDefaultEventsAndServices(createReqVO, thinkModelFunction);
  39 + // 插入数据库
32 thinkModelFunctionMapper.insert(thinkModelFunction); 40 thinkModelFunctionMapper.insert(thinkModelFunction);
33 - // 返回 41 + // 返回生成的 ID
34 return thinkModelFunction.getId(); 42 return thinkModelFunction.getId();
35 } 43 }
36 44
@@ -43,9 +51,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @@ -43,9 +51,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
43 @Override 51 @Override
44 public void deleteThinkModelFunction(Long id) { 52 public void deleteThinkModelFunction(Long id) {
45 log.info("删除物模型,id:{}", id); 53 log.info("删除物模型,id:{}", id);
46 - // 校验存在 54 + // 校验物模型是否存在
47 validateThinkModelFunctionExists(id); 55 validateThinkModelFunctionExists(id);
48 - // 删除 56 + // 删除物模型
49 thinkModelFunctionMapper.deleteById(id); 57 thinkModelFunctionMapper.deleteById(id);
50 } 58 }
51 59
@@ -68,12 +76,15 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @@ -68,12 +76,15 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
68 @Override 76 @Override
69 public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) { 77 public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
70 log.info("更新物模型,参数:{}", updateReqVO); 78 log.info("更新物模型,参数:{}", updateReqVO);
71 - // 校验存在 79 + // 校验物模型是否存在
72 validateThinkModelFunctionExists(updateReqVO.getId()); 80 validateThinkModelFunctionExists(updateReqVO.getId());
73 - // 校验 productKey 是否重复 81 + // 校验 ProductKey 是否唯一
74 validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey()); 82 validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey());
75 - // 更新 83 + // 转换请求对象为数据对象
76 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); 84 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
  85 + // 自动生成或更新属性上报事件和属性设置、获取服务
  86 + generateDefaultEventsAndServices(updateReqVO, thinkModelFunction);
  87 + // 更新数据库
77 thinkModelFunctionMapper.updateById(thinkModelFunction); 88 thinkModelFunctionMapper.updateById(thinkModelFunction);
78 } 89 }
79 90
@@ -83,4 +94,151 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @@ -83,4 +94,151 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
83 throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY); 94 throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY);
84 } 95 }
85 } 96 }
86 -}  
87 \ No newline at end of file 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 +}