From a1114be623660589b9db810099fee22fbe7acde5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A6=82=E6=A2=A6=E6=8A=80=E6=9C=AF?= <596392912@qq.com> Date: Sat, 10 Sep 2022 12:03:07 +0800 Subject: [PATCH] =?UTF-8?q?:memo:=20=E6=A2=B3=E7=90=86=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +- .../iot/mqtt/huawei/MqttClientTest.java | 77 ++++++++++++ .../net/dreamlu/iot/mqtt/huawei/MqttSign.java | 113 ++++++++++++++++++ 3 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 example/mica-mqtt-example/src/main/java/net/dreamlu/iot/mqtt/huawei/MqttClientTest.java create mode 100644 example/mica-mqtt-example/src/main/java/net/dreamlu/iot/mqtt/huawei/MqttSign.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d84213..bc42866 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ ### v2.0.1 - 2022-09-10 - :sparkles: 优化 MqttWebServer 配置。 -- :bug: 修复解码异常: BufferUnderflowException。 +- :sparkles: mica-mqtt-example 添加华为云iot连接示例。 +- :bug: 修复解码异常: `BufferUnderflowException`。 ### v2.0.0 - 2022-09-04 - :sparkles: mica mqtt server 完善方法,方便使用。 diff --git a/example/mica-mqtt-example/src/main/java/net/dreamlu/iot/mqtt/huawei/MqttClientTest.java b/example/mica-mqtt-example/src/main/java/net/dreamlu/iot/mqtt/huawei/MqttClientTest.java new file mode 100644 index 0000000..894c826 --- /dev/null +++ b/example/mica-mqtt-example/src/main/java/net/dreamlu/iot/mqtt/huawei/MqttClientTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.net.dreamlu.net). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dreamlu.iot.mqtt.huawei; + +import net.dreamlu.iot.mqtt.codec.ByteBufferUtil; +import net.dreamlu.iot.mqtt.core.client.MqttClient; + +import java.nio.charset.StandardCharsets; +import java.util.Timer; +import java.util.TimerTask; + +/** + * 客户端测试 + * + * @author L.cm + */ +public class MqttClientTest { + + public static void main(String[] args) { + // 设备id和密钥,请从华为云iot获取 + String deviceId = "630eb6f8664c6f7938db6ef0_test"; + String deviceSecret = ""; + // 计算MQTT连接参数。 + MqttSign sign = new MqttSign(deviceId, deviceSecret); + + String username = sign.getUsername(); + String password = sign.getPassword(); + String clientId = sign.getClientId(); + System.out.println("username: " + username); + System.out.println("password: " + password); + System.out.println("clientid: " + clientId); + + // 初始化 mqtt 客户端 + MqttClient client = MqttClient.create() + .ip("iot-mqtts.cn-north-4.myhuaweicloud.com") + .port(8883) + .username(username) + .password(password) + .clientId(clientId) + .useSsl() + .connect(); + + // 订阅命令下发topic + String cmdRequestTopic = "$oc/devices/" + deviceId + "/sys/commands/#"; + + client.subQos0(cmdRequestTopic, (topic, payload) -> { + System.out.println(topic + '\t' + ByteBufferUtil.toString(payload)); + }); + + // 属性上报消息 + String reportTopic = "$oc/devices/" + deviceId + "/sys/properties/report"; + String jsonMsg = "{\"services\":[{\"service_id\":\"Temperature\", \"properties\":{\"value\":57}},{\"service_id\":\"Battery\",\"properties\":{\"level\":88}}]}"; + + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + client.publish(reportTopic, jsonMsg.getBytes(StandardCharsets.UTF_8)); + } + }, 3000, 3000); + } + +} diff --git a/example/mica-mqtt-example/src/main/java/net/dreamlu/iot/mqtt/huawei/MqttSign.java b/example/mica-mqtt-example/src/main/java/net/dreamlu/iot/mqtt/huawei/MqttSign.java new file mode 100644 index 0000000..4f6924d --- /dev/null +++ b/example/mica-mqtt-example/src/main/java/net/dreamlu/iot/mqtt/huawei/MqttSign.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.net.dreamlu.net). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dreamlu.iot.mqtt.huawei; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Objects; + +/** + * 阿里云 mqtt 签名方式 + * + * @author L.cm + */ +public class MqttSign { + /** + * 用户名 + */ + private final String username; + /** + * 密码 + */ + private final String password; + /** + * 客户端id + */ + private final String clientId; + + public MqttSign(String deviceId, String deviceSecret) { + Objects.requireNonNull(deviceId, "deviceId is null"); + Objects.requireNonNull(deviceSecret, "deviceSecret is null"); + this.username = deviceId; + String timestamp = getTimeStamp(); + this.password = getPassword(deviceSecret, timestamp); + this.clientId = getClientId(deviceId, timestamp); + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getClientId() { + return clientId; + } + + private static String getPassword(String deviceSecret, String timestamp) { + return hmacSha256(deviceSecret, timestamp); + } + + private static String getClientId(String deviceId, String timestamp) { + return deviceId + "_0_0_" + timestamp; + } + + /*** + * 要求:10位数字 + */ + private static String getTimeStamp() { + return ZonedDateTime.ofInstant(Instant.now(), ZoneId.of("UTC")).format(DateTimeFormatter.ofPattern("yyyyMMddHH")); + } + + /*** + * 调用sha256算法进行哈希 + */ + private static String hmacSha256(String message, String tStamp) { + try { + Mac hmacSHA256 = Mac.getInstance("HmacSHA256"); + hmacSHA256.init(new SecretKeySpec(tStamp.getBytes(), "HmacSHA256")); + byte[] bytes = hmacSHA256.doFinal(message.getBytes()); + return byteArrayToHexString(bytes); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /*** + * byte数组转16进制字符串 + */ + private static String byteArrayToHexString(byte[] b) { + StringBuilder hs = new StringBuilder(); + String stmp; + for (int n = 0; b != null && n < b.length; n++) { + stmp = Integer.toHexString(b[n] & 0XFF); + if (stmp.length() == 1) { + hs.append('0'); + } + hs.append(stmp); + } + return hs.toString().toLowerCase(); + } + +} -- GitLab