Commit 679b696abebc2dc6a232c5a59168c4d41765ebf0

Authored by YunaiV
1 parent 268a2ad4

feat(iot):HTTP 协议增加 IotDirectDeviceHttpProtocolIntegrationTest 测试类

yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/topic/event/IotDeviceEventPostReqDTO.java
@@ -5,7 +5,7 @@ import lombok.Data; @@ -5,7 +5,7 @@ import lombok.Data;
5 /** 5 /**
6 * IoT 设备事件上报 Request DTO 6 * IoT 设备事件上报 Request DTO
7 * <p> 7 * <p>
8 - * 用于 thing.event.{eventId}.post 消息的 params 参数 8 + * 用于 thing.event.post 消息的 params 参数
9 * 9 *
10 * @author 芋道源码 10 * @author 芋道源码
11 * @see <a href="https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services">阿里云 - 设备上报事件</a> 11 * @see <a href="https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services">阿里云 - 设备上报事件</a>
@@ -16,7 +16,7 @@ public class IotDeviceEventPostReqDTO { @@ -16,7 +16,7 @@ public class IotDeviceEventPostReqDTO {
16 /** 16 /**
17 * 事件标识符 17 * 事件标识符
18 */ 18 */
19 - private String eventId; 19 + private String identifier;
20 20
21 /** 21 /**
22 * 事件输出参数 22 * 事件输出参数
@@ -31,27 +31,24 @@ public class IotDeviceEventPostReqDTO { @@ -31,27 +31,24 @@ public class IotDeviceEventPostReqDTO {
31 /** 31 /**
32 * 创建事件上报 DTO 32 * 创建事件上报 DTO
33 * 33 *
34 - * @param eventId 事件标识符 34 + * @param identifier 事件标识符
35 * @param value 事件值 35 * @param value 事件值
36 * @return DTO 对象 36 * @return DTO 对象
37 */ 37 */
38 - public static IotDeviceEventPostReqDTO of(String eventId, Object value) {  
39 - return of(eventId, value, null); 38 + public static IotDeviceEventPostReqDTO of(String identifier, Object value) {
  39 + return of(identifier, value, null);
40 } 40 }
41 41
42 /** 42 /**
43 * 创建事件上报 DTO(带时间) 43 * 创建事件上报 DTO(带时间)
44 * 44 *
45 - * @param eventId 事件标识符 45 + * @param identifier 事件标识符
46 * @param value 事件值 46 * @param value 事件值
47 * @param time 上报时间 47 * @param time 上报时间
48 * @return DTO 对象 48 * @return DTO 对象
49 */ 49 */
50 - public static IotDeviceEventPostReqDTO of(String eventId, Object value, Long time) {  
51 - return new IotDeviceEventPostReqDTO()  
52 - .setEventId(eventId)  
53 - .setValue(value)  
54 - .setTime(time); 50 + public static IotDeviceEventPostReqDTO of(String identifier, Object value, Long time) {
  51 + return new IotDeviceEventPostReqDTO().setIdentifier(identifier).setValue(value).setTime(time);
55 } 52 }
56 53
57 } 54 }
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceAuthUtils.java
1 package cn.iocoder.yudao.module.iot.core.util; 1 package cn.iocoder.yudao.module.iot.core.util;
2 2
  3 +import cn.hutool.core.util.StrUtil;
3 import cn.hutool.crypto.digest.DigestUtil; 4 import cn.hutool.crypto.digest.DigestUtil;
4 import cn.hutool.crypto.digest.HmacAlgorithm; 5 import cn.hutool.crypto.digest.HmacAlgorithm;
5 import lombok.AllArgsConstructor; 6 import lombok.AllArgsConstructor;
@@ -53,27 +54,31 @@ public class IotDeviceAuthUtils { @@ -53,27 +54,31 @@ public class IotDeviceAuthUtils {
53 public static AuthInfo getAuthInfo(String productKey, String deviceName, String deviceSecret) { 54 public static AuthInfo getAuthInfo(String productKey, String deviceName, String deviceSecret) {
54 String clientId = buildClientId(productKey, deviceName); 55 String clientId = buildClientId(productKey, deviceName);
55 String username = buildUsername(productKey, deviceName); 56 String username = buildUsername(productKey, deviceName);
56 - String content = "clientId" + clientId +  
57 - "deviceName" + deviceName +  
58 - "deviceSecret" + deviceSecret +  
59 - "productKey" + productKey;  
60 - String password = buildPassword(deviceSecret, content); 57 + String password = buildPassword(deviceSecret,
  58 + buildContent(clientId, productKey, deviceName, deviceSecret));
61 return new AuthInfo(clientId, username, password); 59 return new AuthInfo(clientId, username, password);
62 } 60 }
63 61
64 - private static String buildClientId(String productKey, String deviceName) { 62 + public static String buildClientId(String productKey, String deviceName) {
65 return String.format("%s.%s", productKey, deviceName); 63 return String.format("%s.%s", productKey, deviceName);
66 } 64 }
67 65
68 - private static String buildUsername(String productKey, String deviceName) { 66 + public static String buildUsername(String productKey, String deviceName) {
69 return String.format("%s&%s", deviceName, productKey); 67 return String.format("%s&%s", deviceName, productKey);
70 } 68 }
71 69
72 - private static String buildPassword(String deviceSecret, String content) {  
73 - return DigestUtil.hmac(HmacAlgorithm.HmacSHA256, deviceSecret.getBytes()) 70 + public static String buildPassword(String deviceSecret, String content) {
  71 + return DigestUtil.hmac(HmacAlgorithm.HmacSHA256, StrUtil.utf8Bytes(deviceSecret))
74 .digestHex(content); 72 .digestHex(content);
75 } 73 }
76 74
  75 + public static String buildContent(String clientId, String productKey, String deviceName, String deviceSecret) {
  76 + return "clientId" + clientId +
  77 + "deviceName" + deviceName +
  78 + "deviceSecret" + deviceSecret +
  79 + "productKey" + productKey;
  80 + }
  81 +
77 public static DeviceInfo parseUsername(String username) { 82 public static DeviceInfo parseUsername(String username) {
78 String[] usernameParts = username.split("&"); 83 String[] usernameParts = username.split("&");
79 if (usernameParts.length != 2) { 84 if (usernameParts.length != 2) {
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotDirectDeviceHttpProtocolIntegrationTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.gateway.protocol.http;
  2 +
  3 +import cn.hutool.core.map.MapUtil;
  4 +import cn.hutool.core.util.IdUtil;
  5 +import cn.hutool.http.HttpResponse;
  6 +import cn.hutool.http.HttpUtil;
  7 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  8 +import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
  9 +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
  10 +import cn.iocoder.yudao.module.iot.core.topic.event.IotDeviceEventPostReqDTO;
  11 +import cn.iocoder.yudao.module.iot.core.topic.property.IotDevicePropertyPostReqDTO;
  12 +import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
  13 +import lombok.extern.slf4j.Slf4j;
  14 +import org.junit.jupiter.api.Test;
  15 +
  16 +
  17 +/**
  18 + * IoT 直连设备 HTTP 协议集成测试(手动测试)
  19 + *
  20 + * <p>测试场景:直连设备(IotProductDeviceTypeEnum 的 DIRECT 类型)通过 HTTP 协议直接连接平台
  21 + *
  22 + * <p>使用步骤:
  23 + * <ol>
  24 + * <li>启动 yudao-module-iot-gateway 服务(HTTP 端口 8082)</li>
  25 + * <li>运行 {@link #testAuth()} 获取 token,将返回的 token 粘贴到 {@link #TOKEN} 常量</li>
  26 + * <li>运行 {@link #testPropertyPost()} 测试属性上报,或运行 {@link #testEventPost()} 测试事件上报</li>
  27 + * </ol>
  28 + *
  29 + * @author 芋道源码
  30 + */
  31 +@Slf4j
  32 +@SuppressWarnings("HttpUrlsUsage")
  33 +public class IotDirectDeviceHttpProtocolIntegrationTest {
  34 +
  35 + private static final String SERVER_HOST = "127.0.0.1";
  36 + private static final int SERVER_PORT = 8092;
  37 +
  38 + // 设备信息(根据实际情况修改 PRODUCT_KEY、DEVICE_NAME、DEVICE_SECRET,从 iot_device 表查询)
  39 + private static final String PRODUCT_KEY = "4aymZgOTOOCrDKRT";
  40 + private static final String DEVICE_NAME = "small";
  41 + private static final String DEVICE_SECRET = "0baa4c2ecc104ae1a26b4070c218bdf3";
  42 +
  43 + /**
  44 + * 设备 Token:从 {@link #testAuth()} 方法获取后,粘贴到这里
  45 + */
  46 + private static final String TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwcm9kdWN0S2V5IjoiNGF5bVpnT1RPT0NyREtSVCIsImV4cCI6MTc2OTMwNTA1NSwiZGV2aWNlTmFtZSI6InNtYWxsIn0.mf3MEATCn5bp6cXgULunZjs8d00RGUxj96JEz0hMS7k";
  47 +
  48 + /**
  49 + * 认证测试:获取设备 Token
  50 + */
  51 + @Test
  52 + public void testAuth() {
  53 + // 1.1 构建请求
  54 + String url = String.format("http://%s:%d/auth", SERVER_HOST, SERVER_PORT);
  55 + IotDeviceAuthUtils.AuthInfo authInfo = IotDeviceAuthUtils.getAuthInfo(PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET);
  56 + IotDeviceAuthReqDTO authReqDTO = new IotDeviceAuthReqDTO()
  57 + .setClientId(authInfo.getClientId())
  58 + .setUsername(authInfo.getUsername())
  59 + .setPassword(authInfo.getPassword());
  60 + String payload = JsonUtils.toJsonString(authReqDTO);
  61 + // 1.2 输出请求
  62 + log.info("[testAuth][请求 URL: {}]", url);
  63 + log.info("[testAuth][请求体: {}]", payload);
  64 +
  65 + // 2.1 发送请求
  66 + String response = HttpUtil.post(url, payload);
  67 + // 2.2 输出结果
  68 + log.info("[testAuth][响应体: {}]", response);
  69 + log.info("[testAuth][请将返回的 token 复制到 TOKEN 常量中]");
  70 + }
  71 +
  72 + /**
  73 + * 属性上报测试
  74 + */
  75 + @Test
  76 + public void testPropertyPost() {
  77 + // 1.1 构建请求
  78 + String url = String.format("http://%s:%d/topic/sys/%s/%s/thing/property/post",
  79 + SERVER_HOST, SERVER_PORT, PRODUCT_KEY, DEVICE_NAME);
  80 + String payload = JsonUtils.toJsonString(MapUtil.builder()
  81 + .put("id", IdUtil.fastSimpleUUID())
  82 + .put("method", IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod())
  83 + .put("version", "1.0")
  84 + .put("params", IotDevicePropertyPostReqDTO.of(MapUtil.<String, Object>builder()
  85 + .put("width", 1)
  86 + .put("height", "2")
  87 + .build())
  88 + )
  89 + .build());
  90 + // 1.2 输出请求
  91 + log.info("[testPropertyPost][请求 URL: {}]", url);
  92 + log.info("[testPropertyPost][请求体: {}]", payload);
  93 +
  94 + // 2.1 发送请求
  95 + try (HttpResponse httpResponse = HttpUtil.createPost(url)
  96 + .header("Authorization", TOKEN)
  97 + .body(payload)
  98 + .execute()) {
  99 + // 2.2 输出结果
  100 + log.info("[testPropertyPost][响应体: {}]", httpResponse.body());
  101 + }
  102 + }
  103 +
  104 + /**
  105 + * 事件上报测试
  106 + */
  107 + @Test
  108 + public void testEventPost() {
  109 + // 1.1 构建请求
  110 + String url = String.format("http://%s:%d/topic/sys/%s/%s/thing/event/post",
  111 + SERVER_HOST, SERVER_PORT, PRODUCT_KEY, DEVICE_NAME);
  112 + String payload = JsonUtils.toJsonString(MapUtil.builder()
  113 + .put("id", IdUtil.fastSimpleUUID())
  114 + .put("method", IotDeviceMessageMethodEnum.EVENT_POST.getMethod())
  115 + .put("version", "1.0")
  116 + .put("params", IotDeviceEventPostReqDTO.of(
  117 + "eat",
  118 + MapUtil.<String, Object>builder().put("rice", 3).build(),
  119 + System.currentTimeMillis())
  120 + )
  121 + .build());
  122 + // 1.2 输出请求
  123 + log.info("[testEventPost][请求 URL: {}]", url);
  124 + log.info("[testEventPost][请求体: {}]", payload);
  125 +
  126 + // 2.1 发送请求
  127 + try (HttpResponse httpResponse = HttpUtil.createPost(url)
  128 + .header("Authorization", TOKEN)
  129 + .body(payload)
  130 + .execute()) {
  131 + // 2.2 输出结果
  132 + log.info("[testEventPost][响应体: {}]", httpResponse.body());
  133 + }
  134 + }
  135 +
  136 +}