2021与蓝度共同重构项目,服务端
chenjiantian
2021-12-06 295411fed71f1ea1286316ccc395d28cc5743fa8
通信协议完善
已添加38个文件
2044 ■■■■■ 文件已修改
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/AmqpClient.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/AmqpConnectionListener.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/AmqpMessageListener.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/IAmqpSubscriptionConfig.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/InitAmqpListener.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/MqttMainBoardConfig.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/A1Frame.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/A5Frame.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/BaseRequestFrame.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/FrameBuilder.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/IRequestFrame.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/BaseResponseInnerFrame.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/IRequestInnerFrame.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/IResponseInnerFrame.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/EmptyRequestInnerFrame.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/LightBrightnessReqInnerFrame.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/LightHeartbeatReqInnerFrame.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/response/LightBrightnessRespInnerFrame.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/response/LightHeartbeatRespInnerFrame.java 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/BaseInvokeSyncService.java 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/IInvoke.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/dto/CommonFrame.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/dto/CommonReportMessage.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/dto/InvokeParam.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/dto/WrapResponseCommonFrame.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A1OrderEnum.java 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A2OrderEnum.java 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A5LightDataEnum.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A5OrderEnum.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/FunctionCodeEnum.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/MQTTConnectTypeEnum.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/mainboard/MainBoardInvokeSyncService.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/topic/IBaseTopic.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/topic/ICustomizeTopic.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/util/CRC32Utils.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/util/FrameUtils.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/util/SupplementUtils.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/test/java/com/sandu/ximon/admin/BaseTopicTests.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/AmqpClient.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,89 @@
package com.sandu.ximon.admin.manager.iot.amqp;
import org.apache.commons.codec.binary.Base64;
import org.apache.qpid.jms.JmsConnection;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.util.Hashtable;
/**
 * @author chenjiantian
 * @date 2021/12/2 17:18
 * ampq订阅客户端
 */
public class AmqpClient {
    private final AmqpConnectionListener amqpConnectionListener = new AmqpConnectionListener();
    private final AmqpMessageListener amqpMessageListener = new AmqpMessageListener();
    private IAmqpSubscriptionConfig config;
    public AmqpClient(IAmqpSubscriptionConfig config) {
        this.config = config;
    }
    /**
     * å¯åЍampq订阅客户端
     *
     * @throws Exception
     */
    public void execute() throws Exception {
        for (int i = 0; i < config.getConnectionCount(); i++) {
            long timeStamp = System.currentTimeMillis();
            //签名方法:支持hmacmd5、hmacsha1和hmacsha256。
            String signMethod = "hmacsha1";
            // userName组装方法,请参见AMQP客户端接入说明文档。
            String userName = config.getClientId() + "-" + i + "|authMode=aksign"
                    + ",signMethod=" + signMethod
                    + ",timestamp=" + timeStamp
                    + ",authId=" + config.getAccessKey()
                    + ",iotInstanceId=" + config.getIotInstanceId()
                    + ",consumerGroupId=" + config.getConsumerGroupId()
                    + "|";
            //计算签名,password组装方法,请参见AMQP客户端接入说明文档。
            String signContent = "authId=" + config.getAccessKey() + "&timestamp=" + timeStamp;
            String password = doSign(signContent, config.getAccessSecret(), signMethod);
            String connectionUrl = "failover:(amqps://" + config.getHost() + ":5671?amqp.idleTimeout=80000)"
                    + "?failover.reconnectDelay=30";
            Hashtable<String, String> hashtable = new Hashtable<>();
            hashtable.put("connectionfactory.SBCF", connectionUrl);
            hashtable.put("queue.QUEUE", "default");
            hashtable.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.jms.jndi.JmsInitialContextFactory");
            Context context = new InitialContext(hashtable);
            ConnectionFactory cf = (ConnectionFactory) context.lookup("SBCF");
            Destination queue = (Destination) context.lookup("QUEUE");
            // åˆ›å»ºè¿žæŽ¥ã€‚
            Connection connection = cf.createConnection(userName, password);
//            connections.add(connection);
            ((JmsConnection) connection).addConnectionListener(amqpConnectionListener);
            // åˆ›å»ºä¼šè¯ã€‚
            // Session.CLIENT_ACKNOWLEDGE: æ”¶åˆ°æ¶ˆæ¯åŽï¼Œéœ€è¦æ‰‹åŠ¨è°ƒç”¨message.acknowledge()。
            // Session.AUTO_ACKNOWLEDGE: SDK自动ACK(推荐)。
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            connection.start();
            // åˆ›å»ºReceiver连接。
            MessageConsumer consumer = session.createConsumer(queue);
            consumer.setMessageListener(amqpMessageListener);
        }
    }
    /**
     * ç­¾åæ ¡éªŒ
     */
    public String doSign(String toSignString, String secret, String signMethod) throws Exception {
        SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(), signMethod);
        Mac mac = Mac.getInstance(signMethod);
        mac.init(signingKey);
        byte[] rawHmac = mac.doFinal(toSignString.getBytes());
        return Base64.encodeBase64String(rawHmac);
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/AmqpConnectionListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,55 @@
package com.sandu.ximon.admin.manager.iot.amqp;
import org.apache.qpid.jms.JmsConnectionListener;
import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import java.net.URI;
/**
 * @author chenjiantian
 * @date 2021/12/2 17:31
 */
public class AmqpConnectionListener implements JmsConnectionListener {
    @Override
    public void onConnectionEstablished(URI uri) {
    }
    @Override
    public void onConnectionFailure(Throwable throwable) {
    }
    @Override
    public void onConnectionInterrupted(URI uri) {
    }
    @Override
    public void onConnectionRestored(URI uri) {
    }
    @Override
    public void onInboundMessage(JmsInboundMessageDispatch jmsInboundMessageDispatch) {
    }
    @Override
    public void onSessionClosed(Session session, Throwable throwable) {
    }
    @Override
    public void onConsumerClosed(MessageConsumer messageConsumer, Throwable throwable) {
    }
    @Override
    public void onProducerClosed(MessageProducer messageProducer, Throwable throwable) {
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/AmqpMessageListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,86 @@
package com.sandu.ximon.admin.manager.iot.amqp;
import com.alibaba.fastjson.JSON;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.CommonReportMessage;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.CommonFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.util.FrameUtils;
import lombok.extern.slf4j.Slf4j;
import javax.jms.Message;
import javax.jms.MessageListener;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @author chenjiantian
 * @date 2021/12/2 17:33
 * å¤„理amqp订阅消息
 */
@Slf4j
public class AmqpMessageListener implements MessageListener {
    protected final static ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),
            Runtime.getRuntime().availableProcessors() * 2, 60, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(50000), new NameTreadFactory());
    static class NameTreadFactory implements ThreadFactory {
        private final AtomicInteger mThreadNum = new AtomicInteger(1);
        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r, "ampq-msg-thread-" + mThreadNum.getAndIncrement());
        }
    }
    @Override
    public void onMessage(Message message) {
        EXECUTOR_SERVICE.submit(() -> processMessage(message));
    }
    /**
     * åœ¨è¿™é‡Œå¤„理您收到消息后的具体业务逻辑。
     */
    private void processMessage(Message message) {
        try {
            byte[] body = message.getBody(byte[].class);
            String content = new String(body);
            Map map = JSON.parseObject(content, Map.class);
            String topic = message.getStringProperty("topic");
            String messageId = message.getStringProperty("messageId");
            log.info("收到订阅" + topic + "," + messageId);
            log.info(content);
            if (null != map.get("status")) {
                // ä¸Šä¸‹çº¿ä¸ŠæŠ¥å¤„理
            } else {
                // è®¾å¤‡æ•°æ®ä¸ŠæŠ¥
                CommonReportMessage commonReportMessage = JSON.parseObject(content, CommonReportMessage.class);
                CommonFrame connectFrame = FrameUtils.transformMessageToFrame(commonReportMessage.getItems().getParams().getValue());
                processTask(commonReportMessage.getProductKey(), commonReportMessage.getDeviceName(), connectFrame);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }
    /**
     * å¤„理任务
     *
     * @param productKey   äº§å“ç 
     * @param deviceName   äº§å“åç§°
     * @param connectFrame ä¸ŠæŠ¥å¸§
     */
    private void processTask(String productKey, String deviceName, CommonFrame connectFrame) {
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/IAmqpSubscriptionConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
package com.sandu.ximon.admin.manager.iot.amqp;
/**
 * @author chenjiantian
 * @date 2021/12/2 16:24
 * amqp服务器订阅需要的参数 https://help.aliyun.com/document_detail/143601.html
 */
public interface IAmqpSubscriptionConfig {
    /**
     * ç™»å½•物联网平台控制台,将鼠标移至账号头像上,然后单击AccessKey管理,获取AccessKey ID和AccessKey Secret。
     *
     * @return AccessKey
     */
    String getAccessKey();
    /**
     * ç™»å½•物联网平台控制台,将鼠标移至账号头像上,然后单击AccessKey管理,获取AccessKey ID和AccessKey Secret。
     *
     * @return accessSecret
     */
    String getAccessSecret();
    /**
     * ç™»å½•物联网平台控制台,在对应实例的规则引擎 > æœåŠ¡ç«¯è®¢é˜… > æ¶ˆè´¹ç»„列表查看您的消费组ID。
     *
     * @return æ¶ˆè´¹ç»„ID。
     */
    String getConsumerGroupId();
    /**
     * å®žä¾‹ID。获取ID方法,请参见如何获取实例ID?。
     * æ‚¨å¯ç™»å½•物联网平台控制台,找到对应的实例,单击实例,进入实例详情页面查看实例ID。
     *
     * @return å®žä¾‹ID
     */
    String getIotInstanceId();
    /**
     * è¡¨ç¤ºå®¢æˆ·ç«¯ID,建议使用您的AMQP客户端所在服务器UUID、MAC地址、IP等唯一标识。长度不可超过64个字符。
     *
     * @return å®¢æˆ·ç«¯ID
     */
    String getClientId();
    /**
     * å¯åЍAMQP客户端的连接数,最大不超过64个。用于实时消息推送的扩容。
     * æ¶ˆè´¹ç»„详情页面会以${clientId}+"-"+数字形式,显示连接的客户端。其中数字最小值为0。
     *
     * @return è¿žæŽ¥æ•°
     */
    Integer getConnectionCount();
    /**
     * AMQP接入域名。
     * ${YourHost}详细说明,请参见查看实例终端节点。
     *
     * @return AMQP接入域名
     */
    String getHost();
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/InitAmqpListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.sandu.ximon.admin.manager.iot.amqp;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
 * @author chenjiantian
 * @date 2021/12/2 17:45
 */
@Component
@AllArgsConstructor
public class InitAmqpListener {
    private final MqttMainBoardConfig mqttMainBoardConfig;
    @PostConstruct
    public void initListener() throws Exception {
        new AmqpClient(
                mqttMainBoardConfig
        ).execute();
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/amqp/MqttMainBoardConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
package com.sandu.ximon.admin.manager.iot.amqp;
import org.springframework.context.annotation.Configuration;
/**
 * @author chenjiantian
 * @date 2021/12/2 17:02
 * iot产品配置类
 */
@Configuration
public class MqttMainBoardConfig implements IAmqpSubscriptionConfig {
    public final static String ACCESS_KEY = "LTAI4G27Af8MZEF55phdMQ4y";
    public final static String ACCESS_SECRET = "KUc2yOtr7TRB4FuF5Wr0dWeTblbEuh";
    @Override
    public String getAccessKey() {
        return ACCESS_KEY;
    }
    @Override
    public String getAccessSecret() {
        return ACCESS_SECRET;
    }
    @Override
    public String getConsumerGroupId() {
//        return "oOS84YAW41j6S3za2eIk000100";
        return "vKqsPWhrUiEXDI0WEGA9000100";
    }
    /**
     * æ—§ç‰ˆå…¬å…±å®žä¾‹åŒºåŸŸä¸æ˜¾ç¤ºå…·ä½“ID值:
     * ä½¿ç”¨ç‰©è”网平台的云端SDK调用API时,无需传入实例ID(IotInstanceId),请删除IotInstanceId相关的请求代码。
     * æŽ¥å…¥è®¾å¤‡å’ŒAMQP客户端时,需传入空值,例如iotInstanceId = ""。
     */
    @Override
    public String getIotInstanceId() {
        return "";
    }
    @Override
    public String getClientId() {
        return "MQTT_MAIN_BOARD_CLIENT";
    }
    @Override
    public Integer getConnectionCount() {
        return 1;
    }
    @Override
    public String getHost() {
        return "1371426293786326.iot-amqp.cn-shanghai.aliyuncs.com";
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/A1Frame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
package com.sandu.ximon.admin.manager.iot.frame;
import com.sandu.ximon.admin.manager.iot.frame.inner.IRequestInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A1OrderEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.FunctionCodeEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.MQTTConnectTypeEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.util.SupplementUtils;
/**
 * @author chenjiantian
 * @date 2021/12/6 13:54
 * A1 åŠŸèƒ½å°è£…çš„å¸§
 */
public class A1Frame extends BaseRequestFrame implements IRequestFrame {
    private String orderType;
    private String payloadLength;
    private String payload;
    public A1Frame(String orderType, IRequestInnerFrame innerFrame) {
        this.orderType = orderType;
        this.payloadLength = SupplementUtils.suppleZero(Integer.toHexString((innerFrame.getEncodeFrame().length() / 2)).toUpperCase(), 4);
        this.payload = innerFrame.getEncodeFrame();
    }
    @Override
    public String getConnectType() {
        return MQTTConnectTypeEnum.SYNCHRONIZATION.getCode();
    }
    @Override
    public String getFunctionCode() {
        return FunctionCodeEnum.MAIN_BOARD_CONFIG.getCode();
    }
    @Override
    public String getOrderType() {
        return orderType;
    }
    @Override
    public String getPayloadLength() {
        return payloadLength;
    }
    @Override
    public String getPayload() {
        return payload;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/A5Frame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
package com.sandu.ximon.admin.manager.iot.frame;
import com.sandu.ximon.admin.manager.iot.frame.inner.IRequestInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A5OrderEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.FunctionCodeEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.MQTTConnectTypeEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A1OrderEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.util.SupplementUtils;
/**
 * @author chenjiantian
 * @date 2021/12/6 13:54
 * A5 åŠŸèƒ½å°è£…çš„å¸§
 */
public class A5Frame extends BaseRequestFrame {
    private String orderType;
    private String payloadLength;
    private String payload;
    public A5Frame(String orderType, IRequestInnerFrame innerFrame) {
        this.orderType = orderType;
        this.payloadLength = SupplementUtils.suppleZero(Integer.toHexString((innerFrame.getEncodeFrame().length() / 2)).toUpperCase(), 4);
        this.payload = innerFrame.getEncodeFrame();
    }
    @Override
    public String getConnectType() {
        return MQTTConnectTypeEnum.SYNCHRONIZATION.getCode();
    }
    @Override
    public String getFunctionCode() {
        return FunctionCodeEnum.DATA_TRANSPORT_DATA.getCode();
    }
    @Override
    public String getOrderType() {
        return orderType;
    }
    @Override
    public String getPayloadLength() {
        return payloadLength;
    }
    @Override
    public String getPayload() {
        return payload;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/BaseRequestFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.sandu.ximon.admin.manager.iot.frame;
import com.sandu.ximon.admin.manager.iot.rrpc.util.CRC32Utils;
import com.sandu.ximon.admin.manager.iot.rrpc.util.FrameUtils;
/**
 * @author chenjiantian
 * @date 2021/12/6 15:06
 */
public abstract class BaseRequestFrame implements IRequestFrame {
    @Override
    public String getEncodeFrame() {
        StringBuilder build = new StringBuilder();
        String tmp = build.append(getFunctionCode()).append(getOrderType()).append(getPayloadLength()).append(getPayload()).toString().toUpperCase();
        String crc32 = CRC32Utils.getCRC32(tmp);
        String frame = getConnectType() + tmp + crc32;
        return FrameUtils.encodeReportMessage(frame);
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/FrameBuilder.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
package com.sandu.ximon.admin.manager.iot.frame;
import com.sandu.ximon.admin.manager.iot.frame.inner.IRequestInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.FunctionCodeEnum;
/**
 * @author chenjiantian
 * @date 2021/12/6 17:02
 * æž„建一个请求帧
 */
public class FrameBuilder {
    private IRequestFrame iRequestFrame;
    private IRequestInnerFrame innerFrame;
    private String functionCode;
    private String orderType;
    private FrameBuilder(String functionCode) {
        this.functionCode = functionCode;
    }
    public static FrameBuilder builderA1() {
        return new FrameBuilder(FunctionCodeEnum.MAIN_BOARD_CONFIG.getCode());
    }
    public static FrameBuilder builderA5() {
        return new FrameBuilder(FunctionCodeEnum.DATA_TRANSPORT_DATA.getCode());
    }
    public FrameBuilder orderType(String orderType) {
        this.orderType = orderType;
        return this;
    }
    public FrameBuilder innerFrame(IRequestInnerFrame innerFrame) {
        this.innerFrame = innerFrame;
        return this;
    }
    public IRequestFrame build() {
        if (orderType == null || innerFrame == null) {
            throw new RuntimeException("参数不能为空");
        }
        if (FunctionCodeEnum.MAIN_BOARD_CONFIG.getCode().equals(functionCode)) {
            iRequestFrame = new A1Frame(orderType, innerFrame);
        } else if (FunctionCodeEnum.DATA_TRANSPORT_DATA.getCode().equals(functionCode)) {
            iRequestFrame = new A5Frame(orderType, innerFrame);
        } else {
            throw new RuntimeException("找不到符合条件的请求帧");
        }
        return iRequestFrame;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/IRequestFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
package com.sandu.ximon.admin.manager.iot.frame;
/**
 * @author chenjiantian
 * @date 2021/12/6 13:47
 * æ€»ä½“帧
 */
public interface IRequestFrame {
    /**
     * èŽ·å–å¾…å‘é€çš„ç¼–ç å¸§
     *
     * @return ç¼–码后的帧
     */
    String getEncodeFrame();
    /**
     * èŽ·å–è¿žæŽ¥ç±»åž‹ {{@link com.sandu.ximon.admin.manager.iot.rrpc.enums.MQTTConnectTypeEnum}}
     *
     * @return è¿žæŽ¥ç±»åž‹
     */
    String getConnectType();
    /**
     * èŽ·å–åŠŸèƒ½ç ï¼ŒA1-A5
     *
     * @return åŠŸèƒ½ç 
     */
    String getFunctionCode();
    /**
     * èŽ·å–å‘½ä»¤ç ï¼Œæ¯ä¸ªåŠŸèƒ½éƒ½æœ‰ä¸åŒå‘½ä»¤
     *
     * @return å‘½ä»¤ç 
     */
    String getOrderType();
    /**
     * è´Ÿè·é•¿åº¦
     *
     * @return è´Ÿè·é•¿åº¦
     */
    String getPayloadLength();
    /**
     * èŽ·å–è´Ÿè·
     *
     * @return è´Ÿè·
     */
    String getPayload();
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/BaseResponseInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
package com.sandu.ximon.admin.manager.iot.frame.inner;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
 * @author chenjiantian
 * @date 2021/12/6 17:40
 * å†…部帧 å“åº”实体类 æ‰€æœ‰å“åº”都要继承它
 */
@Getter
@Setter
@ToString
public abstract class BaseResponseInnerFrame<T> implements IResponseInnerFrame<T> {
    /**
     * è¿žæŽ¥ç±»åž‹ 1
     */
    protected String connectType;
    /**
     * åŠŸèƒ½ç  1
     */
    protected String functionCode;
    /**
     * è´Ÿè·é•¿åº¦ 2
     */
    protected String payloadLength;
    /**
     * CRC校验   4
     */
    private String crc32;
    /**
     * æ˜¯å¦é€šè¿‡CRC校验
     */
    private boolean isValidate;
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/IRequestInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.sandu.ximon.admin.manager.iot.frame.inner;
/**
 * @author chenjiantian
 * @date 2021/12/6 13:49
 * è´Ÿè·å¸§
 */
public interface IRequestInnerFrame {
    /**
     * èŽ·å–å¾…å‘é€çš„ç¼–ç å¸§
     *
     * @return ç¼–码后的帧
     */
    String getEncodeFrame();
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/IResponseInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.sandu.ximon.admin.manager.iot.frame.inner;
/**
 * @author chenjiantian
 * @date 2021/12/6 13:49
 * å†…服
 */
public interface IResponseInnerFrame<T> {
    /**
     * è½¬åŒ–为具体的内部帧实体类
     * @param hex è®¾å¤‡è¿”回的 æ€»ä½“帧负荷payload
     * @return è§£ç åŽçš„实体类
     */
    T transformFrame(String hex);
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/EmptyRequestInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.request;
import com.sandu.ximon.admin.manager.iot.frame.inner.IRequestInnerFrame;
/**
 * @author chenjiantian
 * @date 2021/12/6 15:44
 * é€šç”¨çš„空帧
 */
public class EmptyRequestInnerFrame implements IRequestInnerFrame {
    @Override
    public String getEncodeFrame() {
        return "";
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/LightBrightnessReqInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.request;
import com.sandu.ximon.admin.manager.iot.frame.inner.IRequestInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A5LightDataEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.MQTTConnectTypeEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.util.CRC32Utils;
import com.sandu.ximon.admin.manager.iot.rrpc.util.SupplementUtils;
/**
 * @author chenjiantian
 * @date 2021/12/6 14:46
 * A5->01->01
 * "开/关灯(即亮度值)
 * 0x00:关灯
 * å…¶å®ƒï¼šå¼€ç¯&亮度值"
 */
public class LightBrightnessReqInnerFrame implements IRequestInnerFrame {
    private final String payload;
    /**
     * @param lightLevel äº®åº¦ç­‰çº§ [0,100]
     */
    public LightBrightnessReqInnerFrame(Integer lightLevel) {
        String destinationAddress = "FFFF";
        //  å°†æ•´åž‹äº®åº¦è½¬æ¢ä¸ºHex
        if (lightLevel < 0) {
            lightLevel = 0;
        } else if (lightLevel > 100) {
            lightLevel = 100;
        }
        payload = destinationAddress + SupplementUtils.suppleZero(Integer.toHexString(lightLevel), 2);
    }
    @Override
    public String getEncodeFrame() {
        String functionCode = A5LightDataEnum.LightControl.getCode();
        String payloadLength = "0003";
        String frame = functionCode + payloadLength + payload;
        return MQTTConnectTypeEnum.SYNCHRONIZATION.getCode() + frame.toUpperCase() + CRC32Utils.getCRC32(frame.toUpperCase());
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/LightHeartbeatReqInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.request;
import com.sandu.ximon.admin.manager.iot.frame.inner.IRequestInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A5LightDataEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.MQTTConnectTypeEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.util.CRC32Utils;
/**
 * @author chenjiantian
 * @date 2021/12/6 18:16
 * A5->01->02 è¯»å¿ƒè·³åŒ…
 */
public class LightHeartbeatReqInnerFrame implements IRequestInnerFrame {
    @Override
    public String getEncodeFrame() {
        String functionCode = A5LightDataEnum.ReadHeartBeat.getCode();
        String payloadLength = "0002";
        String payload = "FFFF";
        String frame = functionCode + payloadLength + payload;
        return MQTTConnectTypeEnum.SYNCHRONIZATION.getCode() + frame.toUpperCase() + CRC32Utils.getCRC32(frame.toUpperCase());
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/response/LightBrightnessRespInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.response;
import com.sandu.ximon.admin.manager.iot.frame.inner.BaseResponseInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.util.CRC32Utils;
import lombok.Data;
import lombok.ToString;
/**
 * @author chenjiantian
 * @date 2021/12/6 14:46
 * ç¯äº®åº¦æŽ§åˆ¶ åº”ç­”
 */
@Data
@ToString(callSuper = true)
public class LightBrightnessRespInnerFrame extends BaseResponseInnerFrame<LightBrightnessRespInnerFrame> {
    /**
     * ç›®æ ‡åœ°å€ 2
     */
    private String destinationAddress;
    /**
     * å•灯亮度状态 1
     */
    private String responseStatus;
    @Override
    public LightBrightnessRespInnerFrame transformFrame(String hex) {
        if (hex == null || hex.length() != 22) {
            return null;
        }
        // MQTT通信方式(1)
        setConnectType(hex.substring(0, 2));
        //  åŠŸèƒ½ç (1)
        setFunctionCode(hex.substring(2, 4));
        //  è´Ÿè·é•¿åº¦(2)
        setPayloadLength(hex.substring(4, 8));
        setDestinationAddress(hex.substring(8, 12));
        setResponseStatus(hex.substring(12, 14));
        setCrc32(hex.substring(14, 22));
        //  æ ¡éªŒCRC32
        String frame = getFunctionCode() + getPayloadLength() + getDestinationAddress() + getResponseStatus();
        this.setValidate(CRC32Utils.validateFrame(frame, getCrc32()));
        return this;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/response/LightHeartbeatRespInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,121 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.response;
import com.sandu.ximon.admin.manager.iot.frame.inner.BaseResponseInnerFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.IResponseInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.util.CRC32Utils;
import lombok.Data;
import lombok.ToString;
/**
 * @author chenjiantian
 * @date 2021/12/6 18:20
 * ç¯è¯»å¿ƒè·³åŒ… åº”ç­”
 */
@Data
@ToString(callSuper = true)
public class LightHeartbeatRespInnerFrame extends BaseResponseInnerFrame<LightHeartbeatRespInnerFrame> {
    //  ç›®æ ‡åœ°å€    2
    private String destinationAddress;
    //  å¿ƒè·³åŒ…数据   58
    private HeartBeatDataPackage heartBeatDataPackage;
    private String originFrame;
    @Override
    public LightHeartbeatRespInnerFrame transformFrame(String hex) {
        //  é•¿åº¦ä¸ä¸€è‡´æ—¶ï¼Œè¿”回null
        if (hex == null || hex.length() != 116) {
            return null;
        }
        // MQTT通信方式(1)
        setConnectType(hex.substring(0, 2));
        //  åŠŸèƒ½ç (1)
        setFunctionCode(hex.substring(2, 4));
        //  è´Ÿè·é•¿åº¦(2)
        setPayloadLength(hex.substring(4, 8));
        setDestinationAddress(hex.substring(8, 12));
        String heartBeatData = hex.substring(12, 108);
        HeartBeatDataPackage heartBeatDataPackage = new HeartBeatDataPackage();
        heartBeatDataPackage.transformFrame(heartBeatData);
        setHeartBeatDataPackage(heartBeatDataPackage);
        setCrc32(hex.substring(108, 116));
        //  æ ¡éªŒCRC32
        String frame = hex.substring(0, 14);
        this.setValidate(CRC32Utils.validateFrame(frame, getCrc32()));
        return this;
    }
    @Data
    public static class HeartBeatDataPackage implements IResponseInnerFrame<HeartBeatDataPackage> {
        //  å¹´RTC 1
        private String year;
        //  æœˆRTC 1
        private String month;
        //  æ—¥RTC 1
        private String day;
        //  æ—¶RTC 1
        private String hour;
        //  åˆ†RTC 1
        private String min;
        //  ç§’RTC 1
        private String sec;
        //  è®¾å¤‡æ¸©åº¦ 2  1字节整数1字节小数
        private String deviceTemperature;
        //  äº®åº¦ç™¾åˆ†æ¯” 1
        private String lightPercent;
        //  ç”µç½‘电压 2 1字节整数1字节小数
        private String gridVol;
        //  ç”µç½‘电流 2 1字节整数1字节小数
        private String gridCur;
        //  èµ«å…¹ 2 1字节整数1字节小数
        private String hertz;
        //  åŠŸçŽ‡å› ç´  2 1字节整数1字节小数
        private String powerFactor;
        //  æœ‰åŠŸåŠŸçŽ‡ 2 1字节整数1字节小数
        private String activePower;
        //  æ— åŠŸåŠŸçŽ‡ 2 1字节整数1字节小数
        private String reactivePower;
        //  æœ€è¿‘一次亮灯时间 4 ç§’
        private String recentlyLightSec;
        //  ç´¯è®¡äº®ç¯æ—¶é—´ 4
        private String totalLightTime;
        //  æœ€è¿‘一次用电电量 4
        private String recentlyUsingPower;
        //  ç´¯è®¡ç”¨ç”µç”µé‡ 4
        private String totalUsingPower;
        //  ä¿ç•™ 11
        private String retain;
        //  åŽŸå¸§
        private String originFrame;
        @Override
        public HeartBeatDataPackage transformFrame(String hex) {
            this.originFrame = hex;
            this.year = hex.substring(0, 2);
            this.month = hex.substring(2, 4);
            this.day = hex.substring(4, 6);
            this.hour = hex.substring(6, 8);
            this.min = hex.substring(8, 10);
            this.sec = hex.substring(10, 12);
            this.deviceTemperature = hex.substring(12, 16);
            this.lightPercent = hex.substring(16, 18);
            this.gridVol = hex.substring(18, 22);
            this.gridCur = hex.substring(22, 26);
            this.hertz = hex.substring(26, 30);
            this.powerFactor = hex.substring(30, 34);
            this.activePower = hex.substring(34, 38);
            this.reactivePower = hex.substring(38, 42);
            this.recentlyLightSec = hex.substring(42, 50);
            this.totalLightTime = hex.substring(50, 58);
            this.recentlyUsingPower = hex.substring(58, 66);
            this.totalUsingPower = hex.substring(66, 74);
            this.retain = hex.substring(74, 96);
            return this;
        }
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/BaseInvokeSyncService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,169 @@
package com.sandu.ximon.admin.manager.iot.rrpc;
import com.alibaba.fastjson.JSON;
import com.aliyuncs.AcsRequest;
import com.aliyuncs.AcsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.iot.model.v20180120.*;
import com.sandu.common.execption.BusinessException;
import com.sandu.ximon.admin.manager.iot.frame.IRequestFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.BaseResponseInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.CommonFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.InvokeParam;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.WrapResponseCommonFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.topic.IBaseTopic;
import com.sandu.ximon.admin.manager.iot.rrpc.topic.ICustomizeTopic;
import java.util.List;
/**
 * @author chenjiantian
 * @date 2021/12/2 18:21
 */
public abstract class BaseInvokeSyncService implements IInvoke, IBaseTopic, ICustomizeTopic {
    /**
     * èŽ·å–äº§å“å—
     *
     * @return äº§å“å—
     */
    public abstract String getProductKey();
    /**
     * å‘送rrpc è¯·æ±‚
     *
     * @param deviceName    è®¾å¤‡å
     * @param iRequestFrame ç¼–码帧
     * @return è¿”回的解码帧实体类
     */
    public abstract CommonFrame sendRRPC(String deviceName, IRequestFrame iRequestFrame);
    /**
     * å‘送rrpc è¯·æ±‚
     *
     * @param deviceName    è®¾å¤‡å
     * @param iRequestFrame ç¼–码帧
     * @param clz           å†…部帧响应实体类 å¦‚果不想自己解析 å¯å¸¦ä¸Š
     * @return è¿”回的解码帧实体类 åŒæ—¶æŠŠå†…部帧解码之后也携带上
     */
    public abstract <T extends BaseResponseInnerFrame<T>> WrapResponseCommonFrame<T> sendRRPC(String deviceName, IRequestFrame iRequestFrame, Class<T> clz);
    /**
     * åŸºç¡€é€šä¿¡åŒæ­¥è°ƒç”¨
     *
     * @param request è¯·æ±‚封装
     * @param <T>     è¿”回类型
     * @return è¿”回结果
     */
    protected <T extends AcsResponse> T invokeSync(AcsRequest<T> request) {
        // èŽ·å¾—æœåŠ¡è°ƒç”¨å“åº”
        T response = null;
        try {
            response = getClient().getAcsResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return response;
    }
    @Override
    public RegisterDeviceResponse.Data registerDevice(String deviceName) {
        RegisterDeviceRequest request = new RegisterDeviceRequest();
        request.setDeviceName(deviceName);
        request.setProductKey(getProductKey());
        RegisterDeviceResponse response = invokeSync(request);
        if (response != null && response.getSuccess()) {
            return response.getData();
        }
        return null;
    }
    @Override
    public boolean deleteDevice(String deviceName) {
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        request.setDeviceName(deviceName);
        request.setProductKey(getProductKey());
        DeleteDeviceResponse response = invokeSync(request);
        return response != null && response.getSuccess();
    }
    @Override
    public QueryDeviceDetailResponse.Data queryDeviceDetail(String deviceName, String lotId) {
        QueryDeviceDetailRequest request = new QueryDeviceDetailRequest();
        request.setIotId(lotId);
        request.setDeviceName(deviceName);
        request.setProductKey(getProductKey());
        QueryDeviceDetailResponse response = invokeSync(request);
        if (response != null && response.getSuccess()) {
            return response.getData();
        }
        return null;
    }
    @Override
    public List<BatchQueryDeviceDetailResponse.DataItem> batchQueryDeviceDetail(List<String> deviceNames) {
        BatchQueryDeviceDetailRequest request = new BatchQueryDeviceDetailRequest();
        request.setDeviceNames(deviceNames);
        request.setProductKey(getProductKey());
        BatchQueryDeviceDetailResponse response = invokeSync(request);
        if (response != null && response.getSuccess()) {
            return response.getData();
        }
        return null;
    }
    @Override
    public boolean saveDeviceProp(String deviceName, String props) {
        throw new BusinessException("未实现");
//        SaveDevicePropRequest request = new SaveDevicePropRequest();
//        request.setDeviceName(deviceName);
//        request.setProductKey(PRODUCT_KEY);
//        request.setProps(JSON.);
    }
    @Override
    public List<BatchGetDeviceStateResponse.DeviceStatus> batchGetDeviceState(List<String> deviceNames) {
        BatchGetDeviceStateRequest request = new BatchGetDeviceStateRequest();
        request.setDeviceNames(deviceNames);
        request.setProductKey(getProductKey());
        BatchGetDeviceStateResponse response = invokeSync(request);
        if (response != null && response.getSuccess()) {
            return response.getDeviceStatusList();
        }
        return null;
    }
    @Override
    public InvokeThingServiceResponse.Data invokeThing(String deviceName, InvokeParam param) {
        // å¡«å……服务调用的参数
        InvokeThingServiceRequest request = new InvokeThingServiceRequest();
        // è®¾å¤‡è¯ä¹¦ä¹‹productKey
        request.setProductKey(getProductKey());
        // è®¾å¤‡è¯ä¹¦ä¹‹deviceName
        request.setDeviceName(deviceName);
        // è¦è°ƒç”¨çš„æœåŠ¡æ ‡è¯†ç¬¦ï¼Œå–å†³äºŽæœåŠ¡ç«¯å®šä¹‰ ç›®å‰rrpc标识代表同步调用
        request.setIdentifier("rrpc");
        request.setArgs(JSON.toJSONString(param));
        // èŽ·å¾—æœåŠ¡è°ƒç”¨å“åº”
        InvokeThingServiceResponse response = null;
        try {
            response = getClient().getAcsResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
        }
        if (response == null) {
            throw new BusinessException("调用rrpc失败");
        }
        if (!response.getSuccess()) {
            throw new BusinessException("调用rrpc失败," + response.getErrorMessage());
        }
        // æœåŠ¡è°ƒç”¨æˆåŠŸï¼Œä»…ä»£è¡¨å‘é€æœåŠ¡æŒ‡ä»¤çš„æˆåŠŸï¼Œä¸ä»£è¡¨æ‰§è¡ŒæœåŠ¡æœ¬èº«æ˜¯å¦æˆåŠŸ
        if (response.getSuccess()) {
            // ä»…同步服务有result
            return response.getData();
        }
        return null;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/IInvoke.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
package com.sandu.ximon.admin.manager.iot.rrpc;
import com.aliyuncs.DefaultAcsClient;
/**
 * @author chenjiantian
 * @date 2021/12/3 11:11
 */
public interface IInvoke {
    /**
     * èŽ·å– RRPC å®¢æˆ·ç«¯
     * @return RRPC å®¢æˆ·ç«¯
     * @return
     */
    DefaultAcsClient getClient();
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/dto/CommonFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
package com.sandu.ximon.admin.manager.iot.rrpc.dto;
import lombok.Data;
/**
 * @author chenjiantian
 * @date 2021/12/3 16:50
 * å­—节:1    1            2            ä¸å®šé•¿        4
 * åŠŸèƒ½ç A    å‘½ä»¤ç±»åž‹A    è´Ÿè·é•¿åº¦A    è´Ÿè·æ•°æ®A    å¸§æ ¡éªŒA
 *
 * æ€»ä½“帧
 */
@Data
public class CommonFrame {
    /**
     * MQTT通信方式 {{@link com.sandu.ximon.admin.manager.iot.rrpc.enums.MQTTConnectTypeEnum}}
     */
    private String connectType;
    /**
     * åŠŸèƒ½ç ï¼Œ1字节
     */
    private String functionCode;
    /**
     * å‘½ä»¤ç±»åž‹ ï¼Œ1字节
     */
    private String orderType;
    /**
     * è´Ÿè·é•¿åº¦,2字节
     */
    private String payloadLength;
    /**
     * å“åº”payload ä¸å®šå­—节
     */
    private String payload;
    /**
     * æ ¡éªŒç ï¼Œ4字节
     */
    private String crc32;
    /**
     * æ˜¯å¦é€šè¿‡æ ¡éªŒ
     */
    private boolean isValidate;
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/dto/CommonReportMessage.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
package com.sandu.ximon.admin.manager.iot.rrpc.dto;
import lombok.Data;
/**
 * @author chenjiantian
 * @date 2021/12/3 17:27
 * è®¾å¤‡ä¸ŠæŠ¥æ¶ˆæ¯å®žä½“ç±»
 */
@Data
public class CommonReportMessage {
    private String deviceType;
    private String iotId;
    private String requestId;
    private String productKey;
    private String deviceName;
    private Items items;
    @Data
    public static class Items {
        private Params params;
    }
    @Data
    public static class Params {
        private Long time;
        private String value;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/dto/InvokeParam.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package com.sandu.ximon.admin.manager.iot.rrpc.dto;
import lombok.Data;
/**
 * @author chenjiantian
 * @date 2021/12/3 11:19
 */
@Data
public class InvokeParam {
    /**
     * // æ“ä½œæ ‡è¯†ç 
     *     // 100:转发充电桩
     *     // 127:更新地址
     *     // 110:定时任务
     *     // 111:串口控制
     *     // 116:硬件状态查询
     *     // 125:更新大气数据
     *     // 130:开启灯带
     *     // 131:关闭灯带
     */
    private String operate;
    /**
     * æ•°æ®å¸§
     */
    private String frame;
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/dto/WrapResponseCommonFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.sandu.ximon.admin.manager.iot.rrpc.dto;
import com.sandu.ximon.admin.manager.iot.frame.inner.BaseResponseInnerFrame;
import lombok.Data;
import lombok.ToString;
/**
 * @author chenjiantian
 * @date 2021/12/3 16:50
 *
 */
@Data
@ToString(callSuper = true)
public class WrapResponseCommonFrame<T extends BaseResponseInnerFrame<T>> extends CommonFrame {
    private T responseTransform;
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A1OrderEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,117 @@
package com.sandu.ximon.admin.manager.iot.rrpc.enums;
/**
 * @author chenjiantian
 * ä¸»æ¿æ¨¡å—配置(A1)下的命令
 */
public enum A1OrderEnum {
    //-------------------------------------------- æœåŠ¡å™¨ä¸‹å‘----------------------------------------------------//
    /**
     * å†™é…ç½®ä¿¡æ¯è¯·æ±‚
     */
    REQUEST_WRITE_CONFIG("01"),
    /**
     * è¯»é…ç½®ä¿¡æ¯è¯·æ±‚
     */
    REQUEST_READ_CONFIG("02"),
    /**
     * è¯»ç‰ˆæœ¬ä¿¡æ¯è¯·æ±‚
     */
    REQUEST_READ_VERSION("03"),
    /**
     * æ—¶é—´åŒæ­¥é…ç½®
     */
    REQUEST_SYNCHRONIZATION_TIME("04"),
    /**
     * å¿ƒè·³åŒ…间隔时间配置
     */
    REQUEST_HEART_INTERVAL_TIME("05"),
    /**
     * è¯»ä¸²å£é…ç½®ä¿¡æ¯è¯·æ±‚
     */
    REQUEST_READ_SERIAL_PORT("06"),
    /**
     * å†™ä¸²å£é…ç½®ä¿¡æ¯è¯·æ±‚
     */
    REQUEST_WRITE_SERIAL_PORT("07"),
    /**
     * ç½‘络连接模式切换配置
     */
    REQUEST_CONNECTION_SWITCH("08"),
    /**
     * è¯»å–芯片唯一设备地址
     */
    REQUEST_READ_DEVICE_UNIQUE_MAC("09"),
    /**
     * è®¾ç½®é˜¿é‡Œäº‘三元码ProductKey
     */
    REQUEST_SET_PRODUCT_KEY("0A"),
    /**
     * è®¾ç½®é˜¿é‡Œäº‘三元码DeviceName
     */
    REQUEST_SET_DEVICE_NAME("0B"),
    /**
     * è®¾ç½®é˜¿é‡Œäº‘三元码DeviceSecret
     */
    REQUEST_SET_DEVICE_SECRET("0C"),
    //-------------------------------------------- ä¸»æ¿ä¸ŠæŠ¥----------------------------------------------------//
    /**
     * å†™é…ç½®ä¿¡æ¯åº”ç­”
     */
    RESPONSE_WRITE_CONFIG("81"),
    /**
     * è¯»é…ç½®ä¿¡æ¯åº”ç­”
     */
    RESPONSE_READ_CONFIG("82"),
    /**
     * è¯»ç‰ˆæœ¬ä¿¡æ¯åº”ç­”
     */
    RESPONSE_READ_VERSION("83"),
    /**
     * æ—¶é—´åŒæ­¥é…ç½®åº”ç­”/请求
     */
    RESPONSE_SYNCHRONIZATION_TIME("84"),
    /**
     * å¿ƒè·³åŒ…间隔时间配置应答
     */
    RESPONSE_HEART_INTERVAL_TIME("85"),
    /**
     * è¯»ä¸²å£é…ç½®ä¿¡æ¯åº”ç­”
     */
    RESPONSE_READ_SERIAL_PORT("86"),
    /**
     * å†™ä¸²å£é…ç½®ä¿¡æ¯åº”ç­”
     */
    RESPONSE_WRITE_SERIAL_PORT("87"),
    /**
     * ç½‘络连接模式切换配置应答
     */
    RESPONSE_CONNECTION_SWITCH("88"),
    /**
     * è¯»å–芯片唯一设备地址
     */
    RESPONSE_READ_DEVICE_UNIQUE_MAC("89"),
    /**
     * è®¾ç½®é˜¿é‡Œäº‘三元码ProductKey
     */
    RESPONSE_SET_PRODUCT_KEY("8A"),
    /**
     * è®¾ç½®é˜¿é‡Œäº‘三元码DeviceName
     */
    RESPONSE_SET_DEVICE_NAME("8B"),
    /**
     * è®¾ç½®é˜¿é‡Œäº‘三元码DeviceSecret
     */
    RESPONSE_SET_DEVICE_SECRET("8C");
    A1OrderEnum(String code) {
        this.code = code;
    }
    private final String code;
    public String getCode() {
        return code;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A2OrderEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,149 @@
package com.sandu.ximon.admin.manager.iot.rrpc.enums;
/**
 * @author chenjiantian
 * ä¸»æ¿æ¨¡å—控制命令(A2)下的命令
 */
public enum A2OrderEnum {
    //-------------------------------------------- æœåŠ¡å™¨ä¸‹å‘----------------------------------------------------//
    /**
     * ä¸»æ¿è‡ªæˆ‘复位命令
     */
    REQUEST_MAIN_BOARD_RESET("01"),
    /**
     * å…¨éƒ¨å¤–设电源控制命令
     */
    REQUEST_ALL_DEVICE_POWER_CONTROL("02"),
    /**
     * å•灯控制器电源控制命令
     */
    REQUEST_SINGLE_LAMP_POWER_CONTROL("03"),
    /**
     * å¤§æ°”数据电源控制命令
     */
    REQUEST_ATMOSPHERE_POWER_CONTROL("04"),
    /**
     * å……电桩C2电源控制命令
     */
    REQUEST_C2_POWER_CONTROL("05"),
    /**
     * å……电桩C3电源控制命令
     */
    REQUEST_C3_POWER_CONTROL("06"),
    /**
     * æ†ä½“倾斜监测电源控制命令
     */
    REQUEST_POLE_MONITOR_POWER_CONTROL("07"),
    /**
     * æ‘„像头电源控制命令
     */
    REQUEST_CAMERA_POWER_CONTROL("08"),
    /**
     * LED屏电源控制命令
     */
    REQUEST_LED_POWER_CONTROL("09"),
    /**
     * AP电源控制命令
     */
    REQUEST_AP_POWER_CONTROL("0A"),
    /**
     * ä¸€é”®æ•‘助电源控制命令
     */
    REQUEST_HELP_POWER_CONTROL("0B"),
    /**
     * IP音柱电源控制命令
     */
    REQUEST_BROADCAST_POWER_CONTROL("0C"),
    /**
     * ç»§ç”µå™¨1电源控制命令
     */
    REQUEST_RELAY1_POWER_CONTROL("0D"),
    /**
     * ç»§ç”µå™¨2电源控制命令
     */
    REQUEST_RELAY2_POWER_CONTROL("0E"),
    /**
     * (预留)
     */
    REQUEST_CONTAIN("0F"),
    /**
     * å¯åŠ¨å¤–è®¾æ³¨å†Œå‘½ä»¤
     */
    REQUEST_START_DEVICE_REGISTER("30"),
    //-------------------------------------------- ä¸»æ¿ä¸ŠæŠ¥----------------------------------------------------//
    /**
     * ä¸»æ¿è‡ªæˆ‘复位命令
     */
    RESPONSE_MAIN_BOARD_RESET("81"),
    /**
     * å…¨éƒ¨å¤–设电源控制命令
     */
    RESPONSE_ALL_DEVICE_POWER_CONTROL("82"),
    /**
     * å•灯控制器电源控制命令
     */
    RESPONSE_SINGLE_LAMP_POWER_CONTROL("83"),
    /**
     * å¤§æ°”数据电源控制命令
     */
    RESPONSE_ATMOSPHERE_POWER_CONTROL("84"),
    /**
     * å……电桩C2电源控制命令
     */
    RESPONSE_C2_POWER_CONTROL("85"),
    /**
     * å……电桩C3电源控制命令
     */
    RESPONSE_C3_POWER_CONTROL("86"),
    /**
     * æ†ä½“倾斜监测电源控制命令
     */
    RESPONSE_POLE_MONITOR_POWER_CONTROL("87"),
    /**
     * æ‘„像头电源控制命令
     */
    RESPONSE_CAMERA_POWER_CONTROL("88"),
    /**
     * LED屏电源控制命令
     */
    RESPONSE_LED_POWER_CONTROL("89"),
    /**
     * AP电源控制命令
     */
    RESPONSE_AP_POWER_CONTROL("8A"),
    /**
     * ä¸€é”®æ•‘助电源控制命令
     */
    RESPONSE_HELP_POWER_CONTROL("8B"),
    /**
     * IP音柱电源控制命令
     */
    RESPONSE_BROADCAST_POWER_CONTROL("8C"),
    /**
     * ç»§ç”µå™¨1电源控制命令
     */
    RESPONSE_RELAY1_POWER_CONTROL("8D"),
    /**
     * ç»§ç”µå™¨2电源控制命令
     */
    RESPONSE_RELAY2_POWER_CONTROL("8E"),
    /**
     * (预留)
     */
    RESPONSE_CONTAIN("8F"),
    /**
     * å¯åŠ¨å¤–è®¾æ³¨å†Œå‘½ä»¤
     */
    RESPONSE_START_DEVICE_REGISTER("B0");
    A2OrderEnum(String code) {
        this.code = code;
    }
    private final String code;
    public String getCode() {
        return code;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A5LightDataEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package com.sandu.ximon.admin.manager.iot.rrpc.enums;
/**
 * @author chenjiantian
 * A5-01 å•灯数据指令 åˆ—表
 */
public enum A5LightDataEnum {
    //  å•灯控制
    LightControl("01"),
    //  è¯»å¿ƒè·³åŒ…
    ReadHeartBeat("02"),
    //  å®šæ—¶æŽ§åˆ¶
    TimingLightControl("03"),
    //  å…‰æ„ŸæŽ§åˆ¶
    LightSensorControl("04");
    A5LightDataEnum(String code) {
        this.code = code;
    }
    private final String code;
    public String getCode() {
        return code;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A5OrderEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
package com.sandu.ximon.admin.manager.iot.rrpc.enums;
/**
 * @author chenjiantian
 * ä¸»å¤–设数据(A5)下的命令
 */
public enum A5OrderEnum {
    //-------------------------------------------- æœåŠ¡å™¨ä¸‹å‘----------------------------------------------------//
    /**
     *单灯数据指令
     */
    REQUEST_LIGHT_DATA("01"),
    //  å¤§æ°”数据指令
    REQUEST_ATMOSPHERE_DATA("04"),
    //  å……电桩C2数据指令
    REQUEST_C2_DATA("03"),
    //  å……电桩C3数据指令
    REQUEST_C3_DATA("02"),
    //  æ†ä½“监测数据指令
    REQUEST_POLE_MONITOR_DATA("05"),
    //  LORA模块数据指令
    REQUEST_LORA_DATA("06"),
    //  GPS模块数据指令
    REQUEST_GPS_DATA("07"),
    //-------------------------------------------- è®¾å¤‡ä¸ŠæŠ¥----------------------------------------------------//
    //  å•灯数据指令上报
    RESPONSE_LIGHT_DATA("81"),
    //  å¤§æ°”数据指令上报
    RESPONSE_ATMOSPHERE_DATA("84"),
    //  å……电桩C2数据指令上报
    RESPONSE_C2_DATA("83"),
    //  å……电桩C3数据指令上报
    RESPONSE_C3_DATA("82"),
    //  æ†ä½“监测数据指令上报
    RESPONSE_POLE_MONITOR_DATA("85"),
    //  LORA模块数据指令上报
    RESPONSE_LORA_DATA("86"),
    //  GPS模块数据指令上报
    RESPONSE_GPS_DATA("87");
    A5OrderEnum(String code) {
        this.code = code;
    }
    private final String code;
    public String getCode() {
        return code;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/FunctionCodeEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
package com.sandu.ximon.admin.manager.iot.rrpc.enums;
/**
 * @author chenjiantian
 * åŠŸèƒ½ç  ä¸€çº§åˆ†ç±»
 */
public enum FunctionCodeEnum {
    /**
     * ä¸»æ¿æ¨¡å—配置  ç”¨äºŽè®¾ç½®ä¸»æ¿çš„配置参数等
     */
    MAIN_BOARD_CONFIG("A1"),
    /**
     * ä¸»æ¿æ¨¡å—控制命令    ç”¨äºŽæŽ§åˆ¶ä¸»æ¿çš„æŽ¥å£å‘½ä»¤
     */
    MAIN_BOARD_CONTROL("A2"),
    /**
     * ä¸»æ¿æ¨¡å—调试信息    ç”¨äºŽè®¾ç½®æˆ–读出一些调试测试信息等
     */
    MAIN_BOARD_TEST("A3"),
    /**
     * è¿œç¨‹å‡çº§å‘½ä»¤  ç”¨äºŽMQTT模块远程升级功能
     */
    REMOTE_UPDATE("A4"),
    /**
     * å¤–设数据    ç”¨äºŽå¤–设数据传输使用接口
     */
    DATA_TRANSPORT_DATA("A5");
    private final String code;
    FunctionCodeEnum(String code) {
        this.code = code;
    }
    public String getCode() {
        return code;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/MQTTConnectTypeEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.sandu.ximon.admin.manager.iot.rrpc.enums;
/**
 * MQTT通信方式
 * (前导码)
 * @author chenjiantian
 */
public enum MQTTConnectTypeEnum {
    /**
     * åŒæ­¥
     */
    SYNCHRONIZATION("FE"),
    /**
     * å¼‚æ­¥
     */
    ASYNCHRONOUS("F0"),
    /**
     * å¹¿æ’­
     */
    BROADCAST("FA");
    MQTTConnectTypeEnum(String code){
        this.code = code;
    }
    private final String code;
    public String getCode() {
        return code;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/mainboard/MainBoardInvokeSyncService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,97 @@
package com.sandu.ximon.admin.manager.iot.rrpc.mainboard;
import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.iot.model.v20180120.InvokeThingServiceResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.sandu.common.execption.BusinessException;
import com.sandu.ximon.admin.manager.iot.amqp.MqttMainBoardConfig;
import com.sandu.ximon.admin.manager.iot.frame.IRequestFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.BaseResponseInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.BaseInvokeSyncService;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.CommonFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.InvokeParam;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.WrapResponseCommonFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.util.FrameUtils;
import org.springframework.beans.BeanUtils;
import java.util.Map;
/**
 * @author chenjiantian
 * @date 2021/12/3 11:31
 * ä¸»æ¿rrpc通信实现类
 */
public class MainBoardInvokeSyncService extends BaseInvokeSyncService {
    private static volatile DefaultAcsClient client = null;
    private final static String PRODUCT_KEY = "a1JsfPG4iKW";
    @Override
    public String getProductKey() {
        return PRODUCT_KEY;
    }
    @Override
    public CommonFrame sendRRPC(String deviceName, IRequestFrame iRequestFrame) {
        InvokeParam param = new InvokeParam();
        param.setOperate("1001");
        param.setFrame(iRequestFrame.getEncodeFrame());
        InvokeThingServiceResponse.Data data = invokeThing(deviceName, param);
        if (data == null) {
            return null;
        }
        String result = data.getResult();
        result = result.replace("\\", "");
        Map map = JSON.parseObject(result, Map.class);
        result = (String) map.get("msg");
        CommonFrame connectFrame = FrameUtils.transformMessageToFrame(result);
        return connectFrame;
    }
    @Override
    public <T extends BaseResponseInnerFrame<T>> WrapResponseCommonFrame<T> sendRRPC(String deviceName, IRequestFrame iRequestFrame, Class<T> clz) {
        CommonFrame commonFrame = sendRRPC(deviceName, iRequestFrame);
        WrapResponseCommonFrame<T> responseCommonFrame = new WrapResponseCommonFrame<>();
        BeanUtils.copyProperties(commonFrame, responseCommonFrame);
        try {
            responseCommonFrame.setResponseTransform(clz.newInstance().transformFrame(responseCommonFrame.getPayload()));
        } catch (InstantiationException | IllegalAccessException e) {
            throw new BusinessException(String.format("找不到%s的构造函数", clz.getName()));
        }
        return responseCommonFrame;
    }
    public static void main(String[] args) {
        String s = "FEA581000BFE010003FFFF004597147735AB2D28";
        System.out.println(FrameUtils.decodeReportMessage(s));
    }
    private static class SingletonClassInstance {
        private static final MainBoardInvokeSyncService INSTANCE = new MainBoardInvokeSyncService();
    }
    private MainBoardInvokeSyncService() {
    }
    public static MainBoardInvokeSyncService getInstance() {
        return SingletonClassInstance.INSTANCE;
    }
    @Override
    public DefaultAcsClient getClient() {
        if (client == null) {
            synchronized (MainBoardInvokeSyncService.class) {
                if (client == null) {
                    IClientProfile profile = DefaultProfile.getProfile("cn-shanghai", MqttMainBoardConfig.ACCESS_KEY, MqttMainBoardConfig.ACCESS_SECRET);
                    DefaultProfile.addEndpoint("cn-shanghai", "Iot", "iot.cn-shanghai.aliyuncs.com");
                    client = new DefaultAcsClient(profile);
                }
            }
        }
        return client;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/topic/IBaseTopic.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,80 @@
package com.sandu.ximon.admin.manager.iot.rrpc.topic;
import com.aliyuncs.iot.model.v20180120.BatchGetDeviceStateResponse;
import com.aliyuncs.iot.model.v20180120.BatchQueryDeviceDetailResponse;
import com.aliyuncs.iot.model.v20180120.QueryDeviceDetailResponse;
import com.aliyuncs.iot.model.v20180120.RegisterDeviceResponse;
import java.util.List;
/**
 * @author chenjiantian
 * @date 2021/12/3 11:42
 * åŸºç¡€é€šä¿¡topic
 */
public interface IBaseTopic {
    /**
     * æ³¨å†Œè®¾å¤‡
     * https://help.aliyun.com/document_detail/69470.htm?spm=a2c4g.11186623.0.0.25b366d8EyOkmb#reference-pc2-kpz-wdb
     * æ³¨å†Œè®¾å¤‡æŒ‡åœ¨ç‰©è”网平台产品下添加设备。在指定产品下成功注册设备后,阿里云物联网平台为设备颁发全局唯一的设备ID(IotId),用来标识该设备。在进行与设备相关的操作时,您可能需要提供目标设备的IotId。
     * æ‚¨ä¹Ÿå¯ä»¥ä½¿ç”¨ProductKey和DeviceName组合来标识一个设备。其中ProductKey是新建产品时,物联网平台为产品颁发的ProductKey,DeviceName是注册设备时,由您指定或由系统随机生成的设备名称。IotId的优先级高于ProductKey和DeviceName组合。
     * @param deviceName è®¾å¤‡å å¦‚果不传入该参数,则由系统随机生成设备名称。
     * @return è¿”回的结果
     */
    RegisterDeviceResponse.Data registerDevice(String deviceName);
    /**
     * åˆ é™¤è®¾å¤‡
     * @param deviceName è®¾å¤‡å
     * @return æ˜¯å¦æˆåŠŸã€‚
     */
    boolean deleteDevice(String deviceName);
//    /**
//     * æŸ¥è¯¢è®¾å¤‡å±žæ€§å¿«ç…§
//     * @param deviceName è®¾å¤‡å
//     * @param lotId è¦æŸ¥è¯¢å±žæ€§æ‰€å±žçš„设备ID或数字孪生节点ID:如果传入该参数,则无需传入ProductKey和DeviceName。IotId作为设备唯一标识符,和ProductKey与DeviceName组合是一一对应的关系。如果您同时传入IotId和ProductKey与DeviceName组合,则以IotId为准。
//     */
//    void queryDeviceProperty(String deviceName,String lotId);
    /**
     * https://help.aliyun.com/document_detail/69594.htm?spm=a2c4g.11186623.0.0.25b366d8EyOkmb#reference-rrg-lpz-wdb
     * è°ƒç”¨è¯¥æŽ¥å£æŸ¥è¯¢æŒ‡å®šè®¾å¤‡çš„详细信息。
     * å•个阿里云账号调用该接口的每秒请求数(QPS)最大限制为50。
     * @param deviceName è®¾å¤‡å
     * @param lotId è¦æŸ¥è¯¢å±žæ€§æ‰€å±žçš„设备ID或数字孪生节点ID:如果传入该参数,则无需传入ProductKey和DeviceName。IotId作为设备唯一标识符,和ProductKey与DeviceName组合是一一对应的关系。如果您同时传入IotId和ProductKey与DeviceName组合,则以IotId为准。
     * @return è®¾å¤‡è¯¦æƒ…
     */
    QueryDeviceDetailResponse.Data queryDeviceDetail(String deviceName, String lotId);
    /**
     * https://help.aliyun.com/document_detail/123470.htm?spm=a2c4g.11186623.0.0.25b366d8EyOkmb#doc-api-Iot-BatchQueryDeviceDetail
     * å•次调用最多能查询100个设备。
     * åªèƒ½æ‰¹é‡æŸ¥è¯¢å½“前阿里云账号下的设备详情。如果传入的设备信息中,有设备不属于当前账号,则直接返回失败结果。
     * è‹¥ä¼ å…¥çš„设备信息中,包含不存在的设备,则只返回存在的设备详情。
     * å•个阿里云账号调用该接口的每秒请求数(QPS)最大限制为5。
     * @param deviceNames è®¾å¤‡ååˆ—表
     * @return è®¾å¤‡è¯¦æƒ…列表
     */
    List<BatchQueryDeviceDetailResponse.DataItem> batchQueryDeviceDetail(List<String> deviceNames);
    /**
     * ä¸ºæŒ‡å®šè®¾å¤‡è®¾ç½®æ ‡ç­¾ã€‚ å•个阿里云账号调用该接口的每秒请求数(QPS)最大限制为50。
     * Props的总大小不超过5 KB。单个设备的设备标签总数不超过100个。单次修改或新增的设备标签数不超过100个
     * https://help.aliyun.com/document_detail/69618.htm?spm=a2c4g.11186623.0.0.25b366d8EyOkmb#reference-xd3-qrz-wdb
     * @param deviceName è®¾å¤‡å
     * @param props JSON格式{"color":"red","shape":"round"}
     * @return æ˜¯å¦æˆåŠŸ
     */
    boolean saveDeviceProp(String deviceName,String props);
    /**
     * æŸ¥çœ‹åŒä¸€äº§å“ä¸‹æŒ‡å®šè®¾å¤‡çš„运行状态。
     * è¯¥æŽ¥å£ç”¨äºŽæŸ¥çœ‹ä¸€ä¸ªäº§å“ä¸‹å¤šä¸ªè®¾å¤‡çš„运行状态,单次最多可查询50个设备。
     * å•个阿里云账号调用该接口的每秒请求数(QPS)最大限制为50。
     * @param deviceNames è®¾å¤‡ååˆ—表
     * @return è®¾å¤‡çŠ¶æ€åˆ—è¡¨
     */
    List<BatchGetDeviceStateResponse.DeviceStatus> batchGetDeviceState(List<String> deviceNames);
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/topic/ICustomizeTopic.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package com.sandu.ximon.admin.manager.iot.rrpc.topic;
import com.aliyuncs.iot.model.v20180120.InvokeThingServiceResponse;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.InvokeParam;
/**
 * @author chenjiantian
 * @date 2021/12/6 11:11
 * è‡ªå®šä¹‰toic
 */
public interface ICustomizeTopic {
    /**
     * è°ƒç”¨è‡ªå®šä¹‰topic
     * https://help.aliyun.com/document_detail/69584.htm?spm=a2c4g.11186623.0.0.25b33982bSQSom#reference-snk-mrz-wdb
     * @param deviceName è®¾å¤‡å
     * @param param å‚æ•°
     * @return è®¾å¤‡è¿”回的结果
     */
    InvokeThingServiceResponse.Data invokeThing(String deviceName, InvokeParam param);
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/util/CRC32Utils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package com.sandu.ximon.admin.manager.iot.rrpc.util;
import cn.hutool.core.util.HexUtil;
import java.util.zip.CRC32;
/**
 * @author chenjiantian
 * @date 2021/12/3 18:43
 */
public class CRC32Utils {
    public static String getCRC32(String hex) {
        CRC32 crc32 = new CRC32();
        byte[] bytes = HexUtil.decodeHex(hex);
        crc32.update(bytes);
        long value = crc32.getValue();
        return SupplementUtils.suppleZero(Long.toHexString(value).toUpperCase(),8);
    }
    public static boolean validateFrame(String frame, String crc32) {
        String crc32Validate = getCRC32(frame);
        if(crc32.equals(crc32Validate)){
            return true;
        }
        return false;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/util/FrameUtils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
package com.sandu.ximon.admin.manager.iot.rrpc.util;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.CommonFrame;
/**
 * @author chenjiantian
 * @date 2021/12/3 17:36
 */
public class FrameUtils {
    /**
     * æŠŠä¸ŠæŠ¥çš„内容 è½¬åŒ–成帧实体类
     * @param value ä¸ŠæŠ¥å†…容 {{@link com.sandu.ximon.admin.manager.iot.rrpc.dto.CommonReportMessage.Params}}
     * @return å¸§å®žä½“ç±»
     */
    public static CommonFrame transformMessageToFrame(String value) {
        String hex = decodeReportMessage(value);
        if (hex == null || hex.length() < 18) {
            return null;
        }
        //  å°†åå…­è¿›åˆ¶æ•°è½¬ä¸ºå¤§å†™
        hex = hex.toUpperCase();
        CommonFrame frame = new CommonFrame();
        // MQTT通信方式(1)
        frame.setConnectType(hex.substring(0, 2));
        //  åŠŸèƒ½ç (1)
        frame.setFunctionCode(hex.substring(2, 4));
        //  å‘½ä»¤ç±»åž‹(1)
        frame.setOrderType(hex.substring(4, 6));
        //  è´Ÿè·é•¿åº¦(2)
        frame.setPayloadLength(hex.substring(6, 10));
        //  å“åº”payload
        frame.setPayload(hex.substring(10, hex.length() - 8));
        //  æ ¡éªŒç (4)
        frame.setCrc32(hex.substring(hex.length() - 8));
        //  åˆ¤æ–­æ ¡éªŒæ˜¯å¦é€šè¿‡
        String content = hex.substring(2, hex.length() - 8);
        frame.setValidate(CRC32Utils.validateFrame(content, frame.getCrc32()));
        return frame;
    }
    public static void main(String[] args) {
        System.out.println(transformMessageToFrame("/qWEACrwAQAi//8BAQEYAB4CAAAAAAAAAApcAAAAEAAVAAAAAwAQAagAAMPfU3KbHyny").toString());
    }
    /**
     * å°†è®¾å¤‡ä¸ŠæŠ¥çš„内容解码
     *
     * @param value è®¾å¤‡ä¸ŠæŠ¥çš„内容
     * @return è§£ç åŽçš„内容,16进制
     */
    public static String decodeReportMessage(String value) {
        if (StrUtil.isBlank(value)) {
            return null;
        }
        byte[] decode = Base64.decode(value.getBytes());
        return HexUtil.encodeHexStr(decode);
    }
    /**
     * å°†å‡†å¤‡å‘送的内容编码
     * @param value å¾…编码内容
     * @return ç¼–码后的内容 å­—符串
     */
    public static String encodeReportMessage(String value) {
        if (StrUtil.isBlank(value)) {
            return null;
        }
        byte[] bytes = HexUtil.decodeHex(value);
        String encode = Base64.encode(bytes);
        return encode;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/util/SupplementUtils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
package com.sandu.ximon.admin.manager.iot.rrpc.util;
/**
 * @author chenjiantian
 */
public class SupplementUtils {
    /**
     * æˆªå–指定长度的字符串,不足以0填充前面
     * @param hex å­—符串
     * @param totalBit æˆªå–长度
     * @return æˆªå–后的字符串
     */
    public static String suppleZero(String hex, Integer totalBit) {
        if (hex.length() > totalBit) {
            return hex.substring(0, totalBit);
        } else if (hex.length() == totalBit) {
            return hex;
        }
        totalBit = totalBit - hex.length();
        StringBuilder hexBuilder = new StringBuilder(hex);
        for (int i = 0; i < totalBit; i++) {
            hexBuilder.insert(0, "0");
        }
        hex = hexBuilder.toString();
        return hex;
    }
}
ximon-admin/src/test/java/com/sandu/ximon/admin/BaseTopicTests.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
package com.sandu.ximon.admin;
import com.aliyuncs.iot.model.v20180120.QueryDeviceDetailResponse;
import com.sandu.ximon.admin.manager.iot.frame.A1Frame;
import com.sandu.ximon.admin.manager.iot.frame.A5Frame;
import com.sandu.ximon.admin.manager.iot.frame.FrameBuilder;
import com.sandu.ximon.admin.manager.iot.frame.IRequestFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.request.EmptyRequestInnerFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.request.LightBrightnessReqInnerFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.request.LightHeartbeatReqInnerFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.response.LightBrightnessRespInnerFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.response.LightHeartbeatRespInnerFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.CommonFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.WrapResponseCommonFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A1OrderEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A5LightDataEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A5OrderEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.mainboard.MainBoardInvokeSyncService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class BaseTopicTests {
    @Test
    void queryDeviceDetail() {
        QueryDeviceDetailResponse.Data data = MainBoardInvokeSyncService.getInstance().queryDeviceDetail("32313243305005ff0431ffff", null);
        System.out.println(data.toString());
    }
    @Test
    void rrpcLightControl() {
        LightBrightnessReqInnerFrame lightControlFrame = new LightBrightnessReqInnerFrame(80);
        A5Frame a5Frame = new A5Frame(A5OrderEnum.REQUEST_LIGHT_DATA.getCode(), lightControlFrame);
        WrapResponseCommonFrame<LightBrightnessRespInnerFrame> frame = MainBoardInvokeSyncService.getInstance()
                .sendRRPC("32313243305008ff1a06ffff", a5Frame, LightBrightnessRespInnerFrame.class);
//        LightControlResponseInnerFrame lightControlResponseInnerFrame = new LightControlResponseInnerFrame();
//        LightControlResponseInnerFrame innerFrame = lightControlResponseInnerFrame.transformFrame(commonFrame.getPayload());
        System.out.println(frame.toString());
    }
    @Test
    void readDeviceUniqueMac() {
        A1Frame a1Frame = new A1Frame(A1OrderEnum.REQUEST_READ_DEVICE_UNIQUE_MAC.getCode(), new EmptyRequestInnerFrame());
        CommonFrame commonFrame = MainBoardInvokeSyncService.getInstance()
                .sendRRPC("baseDevice", a1Frame);
        System.out.println(commonFrame.toString());
    }
    @Test
    void registerWithReturn() {
        String de = "baseDevice".toLowerCase();
        QueryDeviceDetailResponse.Data data = MainBoardInvokeSyncService.getInstance().queryDeviceDetail("baseDevice", null);
        System.out.println(data.toString());
    }
    @Test
    void LightHeartbeat() {
        IRequestFrame build = FrameBuilder.builderA5()
                .orderType(A5OrderEnum.REQUEST_LIGHT_DATA.getCode())
                .innerFrame(new LightHeartbeatReqInnerFrame())
                .build();
        WrapResponseCommonFrame<LightHeartbeatRespInnerFrame> responseCommonFrame = MainBoardInvokeSyncService.getInstance().sendRRPC("32313243305008ff1a06ffff", build, LightHeartbeatRespInnerFrame.class);
        System.out.println("responseCommonFrame.toString()");
        System.out.println(responseCommonFrame.toString());
    }
}