diff --git a/src/main/java/com/ruoyi/device/controller/ThingsBoardController.java b/src/main/java/com/ruoyi/device/controller/ThingsBoardController.java new file mode 100644 index 0000000..e514d0b --- /dev/null +++ b/src/main/java/com/ruoyi/device/controller/ThingsBoardController.java @@ -0,0 +1,86 @@ +package com.ruoyi.device.controller; + +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.device.domain.api.IThingsBoardDomain; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.Data; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * ThingsBoard设备属性管理Controller + * + * @author ruoyi + * @date 2026-02-06 + */ +@RestController +@RequestMapping("/thingsboard") +@Tag(name = "ThingsBoard设备属性管理", description = "提供设备属性的读写操作") +public class ThingsBoardController extends BaseController { + + private static final Logger log = LoggerFactory.getLogger(ThingsBoardController.class); + + @Autowired + private IThingsBoardDomain thingsBoardDomain; + + /** + * 设置设备属性 + * + * @param request 设置属性请求 + * @return 操作结果 + */ + @PostMapping("/attribute") + @Operation(summary = "设置设备属性", description = "设置ThingsBoard设备的属性值") + public R setDeviceAttribute(@RequestBody SetAttributeRequest request) { + log.info("收到设置设备属性请求: deviceIotId={}, key={}, value={}", + request.getDeviceIotId(), request.getKey(), request.getValue()); + + // 参数校验 + if (request.getDeviceIotId() == null || request.getDeviceIotId().trim().isEmpty()) { + return R.fail("设备IOT ID不能为空"); + } + if (request.getKey() == null || request.getKey().trim().isEmpty()) { + return R.fail("属性键不能为空"); + } + if (request.getValue() == null) { + return R.fail("属性值不能为空"); + } + + // 调用Domain层设置属性 + boolean success = thingsBoardDomain.setDeviceAttribute( + request.getDeviceIotId(), + request.getKey(), + request.getValue() + ); + + if (success) { + log.info("设备属性设置成功: deviceIotId={}, key={}", + request.getDeviceIotId(), request.getKey()); + return R.ok(); + } else { + log.error("设备属性设置失败: deviceIotId={}, key={}", + request.getDeviceIotId(), request.getKey()); + return R.fail("设备属性设置失败"); + } + } + + /** + * 设置属性请求对象 + */ + @Data + public static class SetAttributeRequest { + @Parameter(description = "设备IOT ID(ThingsBoard设备ID)", required = true) + private String deviceIotId; + + @Parameter(description = "属性键", required = true) + private String key; + + @Parameter(description = "属性值", required = true) + private Object value; + } +} \ No newline at end of file diff --git a/src/main/java/com/ruoyi/device/domain/api/IThingsBoardDomain.java b/src/main/java/com/ruoyi/device/domain/api/IThingsBoardDomain.java index 9e51b4a..1588483 100644 --- a/src/main/java/com/ruoyi/device/domain/api/IThingsBoardDomain.java +++ b/src/main/java/com/ruoyi/device/domain/api/IThingsBoardDomain.java @@ -143,4 +143,15 @@ public interface IThingsBoardDomain { * @return 类型安全的遥测数据映射,只包含预定义的遥测数据 */ TelemetryMap getPredefinedTuohengDeviceTelemetry(String deviceId); + + /** + * 设置设备属性 + * 将指定的属性键值对保存到 ThingsBoard 设备的 SERVER_SCOPE 属性中 + * + * @param deviceId 设备ID(ThingsBoard 的 iotDeviceId) + * @param key 属性键 + * @param value 属性值 + * @return 是否设置成功 + */ + boolean setDeviceAttribute(String deviceId, String key, Object value); } \ No newline at end of file diff --git a/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java b/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java index c6b07cf..9eb0093 100644 --- a/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java +++ b/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java @@ -344,7 +344,7 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain { } @Override - @Cacheable(value = DeviceCacheConfig.THINGSBOARD_ATTRIBUTES_CACHE, key = "'tuoheng_' + #deviceId", unless = "#result == null || #result.isEmpty()") + @Cacheable(value = DeviceCacheConfig.THINGSBOARD_ATTRIBUTES_CACHE, key = "#deviceId", unless = "#result == null || #result.isEmpty()") public AttributeMap getTuohengDeviceAttributes(String deviceId) { AttributeMap attributeMap = new AttributeMap(); @@ -375,7 +375,7 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain { } @Override - @Cacheable(value = DeviceCacheConfig.THINGSBOARD_TELEMETRY_CACHE, key = "'tuoheng_' + #deviceId", unless = "#result == null || #result.isEmpty()") + @Cacheable(value = DeviceCacheConfig.THINGSBOARD_TELEMETRY_CACHE, key = "#deviceId", unless = "#result == null || #result.isEmpty()") public TelemetryMap getTuohengDeviceTelemetry(String deviceId) { TelemetryMap telemetryMap = new TelemetryMap(); @@ -462,4 +462,48 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain { return predefinedTelemetry; } + + @Override + @CacheEvict(value = DeviceCacheConfig.THINGSBOARD_ATTRIBUTES_CACHE, + allEntries = false, + key = "#deviceId") + public boolean setDeviceAttribute(String deviceId, String key, Object value) { + try { + log.info("设置设备属性: deviceId={}, key={}, value={}", deviceId, key, value); + + // 将 deviceId 字符串转换为 DeviceId 对象 + DeviceId deviceIdObj = new DeviceId(UUID.fromString(deviceId)); + + // 构建 JsonNode 对象 + com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper(); + com.fasterxml.jackson.databind.node.ObjectNode jsonNode = mapper.createObjectNode(); + + // 根据值的类型设置到 JsonNode + if (value instanceof String) { + jsonNode.put(key, (String) value); + } else if (value instanceof Integer) { + jsonNode.put(key, (Integer) value); + } else if (value instanceof Long) { + jsonNode.put(key, (Long) value); + } else if (value instanceof Double) { + jsonNode.put(key, (Double) value); + } else if (value instanceof Boolean) { + jsonNode.put(key, (Boolean) value); + } else { + jsonNode.put(key, value.toString()); + } + + // 调用 ThingsBoard REST API 保存属性 + // saveDeviceAttributes 方法会将属性保存到 SERVER_SCOPE + client.saveDeviceAttributes(deviceIdObj, "SERVER_SCOPE", jsonNode); + + log.info("设备属性设置成功: deviceId={}, key={}", deviceId, key); + + return true; + } catch (Exception e) { + log.error("设置设备属性失败: deviceId=, key={}, error={}", + deviceId, key, e.getMessage(), e); + return false; + } + } } \ No newline at end of file