Commit f5f8c418dcde92e70b15292af2b0a2636074bf16

Authored by YunaiV
1 parent f6366d9b

【功能新增】IoT:设备状态上传的部分实现

Showing 14 changed files with 96 additions and 52 deletions
yudao-module-iot/yudao-module-iot-api/pom.xml
... ... @@ -12,6 +12,7 @@
12 12 <packaging>jar</packaging>
13 13  
14 14 <name>${project.artifactId}</name>
  15 + <!-- TODO 芋艿:需要在整理下,特别是 PF4J -->
15 16 <description>
16 17 物联网 模块 API,暴露给其它模块调用
17 18 </description>
... ... @@ -42,6 +43,13 @@
42 43 </exclusions>
43 44 </dependency>
44 45  
  46 + <!-- 工具类相关 -->
  47 + <dependency>
  48 + <groupId>com.fasterxml.jackson.core</groupId>
  49 + <artifactId>jackson-databind</artifactId>
  50 + <scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
  51 + </dependency>
  52 +
45 53 <!-- 参数校验 -->
46 54 <dependency>
47 55 <groupId>org.springframework.boot</groupId>
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java
... ... @@ -3,11 +3,10 @@ package cn.iocoder.yudao.module.iot.api.device;
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
5 5 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
6   -import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
  6 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStateUpdateReqDTO;
7 7 import cn.iocoder.yudao.module.iot.enums.ApiConstants;
8 8 import jakarta.validation.Valid;
9 9 import org.springframework.web.bind.annotation.PostMapping;
10   -import org.springframework.web.bind.annotation.PutMapping;
11 10 import org.springframework.web.bind.annotation.RequestBody;
12 11  
13 12 /**
... ... @@ -26,8 +25,8 @@ public interface IotDeviceUpstreamApi {
26 25 *
27 26 * @param updateReqDTO 更新设备状态 DTO
28 27 */
29   - @PutMapping(PREFIX + "/update-status")
30   - CommonResult<Boolean> updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqDTO updateReqDTO);
  28 + @PostMapping(PREFIX + "/update-state")
  29 + CommonResult<Boolean> updateDeviceState(@Valid @RequestBody IotDeviceStateUpdateReqDTO updateReqDTO);
31 30  
32 31 /**
33 32 * 上报设备属性数据
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceEventReportReqDTO.java
... ... @@ -2,8 +2,6 @@ package cn.iocoder.yudao.module.iot.api.device.dto;
2 2  
3 3 import jakarta.validation.constraints.NotEmpty;
4 4 import lombok.Data;
5   -import lombok.NoArgsConstructor;
6   -import lombok.experimental.SuperBuilder;
7 5  
8 6 import java.util.Map;
9 7  
... ... @@ -11,8 +9,6 @@ import java.util.Map;
11 9 * IoT 设备【事件】数据上报 Request DTO
12 10 */
13 11 @Data
14   -@SuperBuilder
15   -@NoArgsConstructor
16 12 public class IotDeviceEventReportReqDTO extends IotDeviceUpstreamAbstractReqDTO {
17 13  
18 14 /**
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDevicePropertyReportReqDTO.java
... ... @@ -2,8 +2,6 @@ package cn.iocoder.yudao.module.iot.api.device.dto;
2 2  
3 3 import jakarta.validation.constraints.NotEmpty;
4 4 import lombok.Data;
5   -import lombok.NoArgsConstructor;
6   -import lombok.experimental.SuperBuilder;
7 5  
8 6 import java.util.Map;
9 7  
... ... @@ -11,8 +9,6 @@ import java.util.Map;
11 9 * IoT 设备【属性】数据上报 Request DTO
12 10 */
13 11 @Data
14   -@SuperBuilder
15   -@NoArgsConstructor
16 12 public class IotDevicePropertyReportReqDTO extends IotDeviceUpstreamAbstractReqDTO {
17 13  
18 14 /**
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStatusUpdateReqDTO.java renamed to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceStateUpdateReqDTO.java
... ... @@ -2,24 +2,20 @@ package cn.iocoder.yudao.module.iot.api.device.dto;
2 2  
3 3 import cn.iocoder.yudao.framework.common.validation.InEnum;
4 4 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
5   -import jakarta.validation.constraints.NotEmpty;
  5 +import jakarta.validation.constraints.NotNull;
6 6 import lombok.Data;
7   -import lombok.NoArgsConstructor;
8   -import lombok.experimental.SuperBuilder;
9 7  
10 8 /**
11 9 * IoT 设备状态更新 Request DTO
12 10 */
13 11 @Data
14   -@SuperBuilder
15   -@NoArgsConstructor
16   -public class IotDeviceStatusUpdateReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  12 +public class IotDeviceStateUpdateReqDTO extends IotDeviceUpstreamAbstractReqDTO {
17 13  
18 14 /**
19 15 * 设备状态
20 16 */
21   - @NotEmpty(message = "设备状态不能为空")
  17 + @NotNull(message = "设备状态不能为空")
22 18 @InEnum(IotDeviceStateEnum.class) // 只使用:在线、离线
23   - private Integer status;
  19 + private Integer state;
24 20  
25 21 }
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/IotDeviceUpstreamAbstractReqDTO.java
1 1 package cn.iocoder.yudao.module.iot.api.device.dto;
2 2  
  3 +import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
  4 +import com.fasterxml.jackson.databind.annotation.JsonSerialize;
3 5 import jakarta.validation.constraints.NotEmpty;
4 6 import lombok.Data;
5   -import lombok.NoArgsConstructor;
6   -import lombok.experimental.SuperBuilder;
7 7  
8 8 import java.time.LocalDateTime;
9 9  
... ... @@ -13,8 +13,6 @@ import java.time.LocalDateTime;
13 13 * @author 芋道源码
14 14 */
15 15 @Data
16   -@SuperBuilder
17   -@NoArgsConstructor
18 16 public abstract class IotDeviceUpstreamAbstractReqDTO {
19 17  
20 18 /**
... ... @@ -41,6 +39,7 @@ public abstract class IotDeviceUpstreamAbstractReqDTO {
41 39 /**
42 40 * 上报时间
43 41 */
  42 + @JsonSerialize(using = TimestampLocalDateTimeSerializer.class) // 解决 iot plugins 序列化 LocalDateTime 是数组,导致无法解析的问题
44 43 private LocalDateTime reportTime;
45 44  
46 45 }
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java
... ... @@ -12,7 +12,11 @@ public enum IotDeviceMessageIdentifierEnum {
12 12  
13 13 PROPERTY_GET("get"),
14 14 PROPERTY_SET("set"),
15   - PROPERTY_REPORT("report");
  15 + PROPERTY_REPORT("report"),
  16 +
  17 + STATE_ONLINE("online"),
  18 + STATE_OFFLINE("offline");
  19 +
16 20  
17 21 /**
18 22 * 标志符
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.api.device;
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
5 5 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
6   -import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
  6 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStateUpdateReqDTO;
7 7 import cn.iocoder.yudao.module.iot.service.device.upstream.IotDeviceUpstreamService;
8 8 import org.springframework.validation.annotation.Validated;
9 9 import org.springframework.web.bind.annotation.RestController;
... ... @@ -23,8 +23,8 @@ public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi {
23 23 private IotDeviceUpstreamService deviceUpstreamService;
24 24  
25 25 @Override
26   - public CommonResult<Boolean> updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) {
27   - deviceUpstreamService.updateDeviceStatus(updateReqDTO);
  26 + public CommonResult<Boolean> updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
  27 + deviceUpstreamService.updateDeviceState(updateReqDTO);
28 28 return success(true);
29 29 }
30 30  
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java
1 1 package cn.iocoder.yudao.module.iot.emq.service;
2 2  
3   -import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
4 3 import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
5 4 import jakarta.annotation.Resource;
6 5 import lombok.extern.slf4j.Slf4j;
... ... @@ -34,11 +33,11 @@ public class EmqxServiceImpl implements EmqxService {
34 33 String productKey = topic.split("/")[2];
35 34 String deviceName = topic.split("/")[3];
36 35 String message = new String(mqttMessage.getPayload());
37   - IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder()
  36 +// IotDevicePropertyReportReqDTO createDTO = IotDevicePropertyReportReqDTO.builder()
38 37 // .productKey(productKey)
39 38 // .deviceName(deviceName)
40 39 // .properties(message) // TODO 芋艿:临时去掉,看看
41   - .build();
  40 +// .build();
42 41 // iotDeviceDataService.saveDeviceProperty(createDTO);
43 42 }
44 43 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java
... ... @@ -395,10 +395,10 @@ public class IotDeviceServiceImpl implements IotDeviceService {
395 395 // 2.1 情况一:属性上报
396 396 String requestId = IdUtil.fastSimpleUUID();
397 397 if (Objects.equals(reportReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) {
398   - deviceUpstreamService.reportDeviceProperty(IotDevicePropertyReportReqDTO.builder()
399   - .requestId(requestId).reportTime(LocalDateTime.now())
400   - .productKey(device.getProductKey()).deviceName(device.getDeviceName())
401   - .properties((Map<String, Object>) reportReqVO.getData()).build());
  398 + deviceUpstreamService.reportDeviceProperty(((IotDevicePropertyReportReqDTO)
  399 + new IotDevicePropertyReportReqDTO().setRequestId(requestId).setReportTime(LocalDateTime.now())
  400 + .setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName()))
  401 + .setProperties((Map<String, Object>) reportReqVO.getData()));
402 402 return;
403 403 }
404 404 // 2.2 情况二:事件上报
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamService.java
... ... @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.service.device.upstream;
2 2  
3 3 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
4 4 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
5   -import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
  5 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStateUpdateReqDTO;
6 6  
7 7 /**
8 8 * 设备上行 Service 接口
... ... @@ -18,7 +18,7 @@ public interface IotDeviceUpstreamService {
18 18 *
19 19 * @param updateReqDTO 更新设备状态 DTO
20 20 */
21   - void updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO);
  21 + void updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO);
22 22  
23 23 /**
24 24 * 上报设备属性数据
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/upstream/IotDeviceUpstreamServiceImpl.java
1 1 package cn.iocoder.yudao.module.iot.service.device.upstream;
2 2  
  3 +import cn.hutool.core.lang.Assert;
3 4 import cn.hutool.core.util.IdUtil;
  5 +import cn.hutool.core.util.ObjUtil;
4 6 import cn.hutool.core.util.StrUtil;
5 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  8 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  9 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
6 10 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
7 11 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
8   -import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
  12 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStateUpdateReqDTO;
9 13 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceUpstreamAbstractReqDTO;
10 14 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
11 15 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
12 16 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
  17 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
13 18 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
14 19 import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer;
15 20 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
... ... @@ -19,6 +24,7 @@ import org.springframework.stereotype.Service;
19 24 import org.springframework.validation.annotation.Validated;
20 25  
21 26 import java.time.LocalDateTime;
  27 +import java.util.Objects;
22 28  
23 29 /**
24 30 * 设备上行 Service 实现类
... ... @@ -37,9 +43,39 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
37 43 private IotDeviceProducer deviceProducer;
38 44  
39 45 @Override
40   - public void updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) {
41   - log.info("[updateDeviceStatus][更新设备状态: {}]", updateReqDTO);
42   - // TODO 芋艿:插件状态
  46 + public void updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
  47 + Assert.isTrue(ObjectUtils.equalsAny(updateReqDTO.getState(),
  48 + IotDeviceStateEnum.ONLINE.getState(), IotDeviceStateEnum.OFFLINE.getState()),
  49 + "状态不合法");
  50 + // 1.1 获得设备
  51 + log.info("[updateDeviceState][更新设备状态: {}]", updateReqDTO);
  52 + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(
  53 + updateReqDTO.getProductKey(), updateReqDTO.getDeviceName());
  54 + if (device == null) {
  55 + log.error("[updateDeviceState][设备({}/{}) 不存在]",
  56 + updateReqDTO.getProductKey(), updateReqDTO.getDeviceName());
  57 + return;
  58 + }
  59 + // 1.2 记录设备的最后时间
  60 + updateDeviceLastTime(device, updateReqDTO);
  61 + // 1.3 当前状态一致,不处理
  62 + if (Objects.equals(device.getState(), updateReqDTO.getState())) {
  63 + return;
  64 + }
  65 +
  66 + // 2. 更新设备状态
  67 + TenantUtils.executeIgnore(() ->
  68 + deviceService.updateDeviceState(device.getId(), updateReqDTO.getState()));
  69 +
  70 + // 3. TODO 芋艿:子设备的关联
  71 +
  72 + // 4. 发送设备消息
  73 + IotDeviceMessage message = BeanUtils.toBean(updateReqDTO, IotDeviceMessage.class)
  74 + .setType(IotDeviceMessageTypeEnum.STATE.getType())
  75 + .setIdentifier(ObjUtil.equals(updateReqDTO.getState(), IotDeviceStateEnum.ONLINE.getState())
  76 + ? IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier()
  77 + : IotDeviceMessageIdentifierEnum.STATE_OFFLINE.getIdentifier());
  78 + sendDeviceMessage(message, device);
43 79 }
44 80  
45 81 @Override
... ...
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/api/DeviceDataApiClient.java
... ... @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
5 5 import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceEventReportReqDTO;
6 6 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
7   -import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStatusUpdateReqDTO;
  7 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStateUpdateReqDTO;
8 8 import lombok.extern.slf4j.Slf4j;
9 9 import org.springframework.web.client.RestTemplate;
10 10  
... ... @@ -29,9 +29,9 @@ public class DeviceDataApiClient implements IotDeviceUpstreamApi {
29 29  
30 30 // TODO @haohao:返回结果,不用 CommonResult 哈。
31 31 @Override
32   - public CommonResult<Boolean> updateDeviceStatus(IotDeviceStatusUpdateReqDTO updateReqDTO) {
33   - String url = deviceDataUrl + URL_PREFIX + "/update-status";
34   - return doPost(url, updateReqDTO, "updateDeviceStatus");
  32 + public CommonResult<Boolean> updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
  33 + String url = deviceDataUrl + URL_PREFIX + "/update-state";
  34 + return doPost(url, updateReqDTO, "updateDeviceState");
35 35 }
36 36  
37 37 @Override
... ...
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/service/HttpVertxHandler.java
1 1 package cn.iocoder.yudao.module.iot.plugin.http.service;
2 2  
  3 +import cn.hutool.core.util.IdUtil;
3 4 import cn.hutool.json.JSONObject;
4 5 import cn.hutool.json.JSONUtil;
5 6 import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
6 7 import cn.iocoder.yudao.module.iot.api.device.dto.IotDevicePropertyReportReqDTO;
  8 +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStateUpdateReqDTO;
  9 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
7 10 import io.vertx.core.Handler;
8 11 import io.vertx.ext.web.RequestBody;
9 12 import io.vertx.ext.web.RoutingContext;
10 13 import lombok.extern.slf4j.Slf4j;
11 14  
  15 +import java.time.LocalDateTime;
12 16 import java.util.Map;
13 17  
14 18 @Slf4j
... ... @@ -43,20 +47,27 @@ public class HttpVertxHandler implements Handler&lt;RoutingContext&gt; {
43 47 String id = jsonData.getStr("id");
44 48  
45 49 try {
46   - IotDevicePropertyReportReqDTO reportReqDTO = IotDevicePropertyReportReqDTO.builder()
47   - .productKey(productKey)
48   - .deviceName(deviceName)
49   - .properties((Map<String, Object>) requestBody.asJsonObject().getMap().get("properties"))
50   - .build();
  50 + // TODO @haohao:pluginKey 需要设置
  51 + // 设备上线
  52 + deviceDataApi.updateDeviceState(((IotDeviceStateUpdateReqDTO)
  53 + new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID())
  54 + .setPluginKey("http")
  55 + .setReportTime(LocalDateTime.now())
  56 + .setProductKey(productKey).setDeviceName(deviceName))
  57 + .setState(IotDeviceStateEnum.ONLINE.getState()));
51 58  
52   - deviceDataApi.reportDeviceProperty(reportReqDTO);
  59 + // 属性上报
  60 + deviceDataApi.reportDeviceProperty(((IotDevicePropertyReportReqDTO)
  61 + new IotDevicePropertyReportReqDTO().setRequestId(IdUtil.fastSimpleUUID())
  62 + .setPluginKey("http").setReportTime(LocalDateTime.now())
  63 + .setProductKey(productKey).setDeviceName(deviceName))
  64 + .setProperties((Map<String, Object>) requestBody.asJsonObject().getMap().get("properties")));
53 65  
54 66 ctx.response()
55 67 .setStatusCode(200)
56 68 .putHeader("Content-Type", "application/json; charset=UTF-8")
57 69 .end(createResponseJson(200, new JSONObject(), id, "success",
58 70 "thing.event.property.post", "1.0").toString());
59   -
60 71 } catch (Exception e) {
61 72 log.error("[HttpVertxHandler] 上报属性数据失败", e);
62 73 ctx.response()
... ...