2021与蓝度共同重构项目,服务端
liuhaonan
2021-12-09 43fb2ac961d450659a270f1db9053ec545327aa1
Merge remote-tracking branch 'origin/master'
已添加53个文件
3061 ■■■■■ 文件已修改
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 147 ●●●●● 补丁 | 查看 | 原始文档 | 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/A2Frame.java 49 ●●●●● 补丁 | 查看 | 原始文档 | 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 59 ●●●●● 补丁 | 查看 | 原始文档 | 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/report/A5AtmosphereHeartbeatReportInnerFrame.java 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5C3CommonReportInnerFrame.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5C3ErrorCodeReportInnerFrame.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5C3HeartbeatReportInnerFrame.java 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5LightErrorCodeReportInnerFrame.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5LightHeartbeatReportInnerFrame.java 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5LightTimeSyncReportInnerFrame.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/A1TernaryCodeReqInnerFrame.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/A5LightBrightnessReqInnerFrame.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/A5LightHeartbeatReqInnerFrame.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/A5LightResetReqInnerFrame.java 22 ●●●●● 补丁 | 查看 | 原始文档 | 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/response/A1DeviceMacRespInnerFrame.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/response/A1TernaryCodeRespInnerFrame.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/response/A5LightBrightnessRespInnerFrame.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/response/A5LightHeartbeatRespInnerFrame.java 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/BaseInvokeSyncService.java 160 ●●●●● 补丁 | 查看 | 原始文档 | 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 19 ●●●●● 补丁 | 查看 | 原始文档 | 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/A5AtmosphereReportEnum.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A5C3ReportEnum.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A5LightDataEnum.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/rrpc/enums/A5LightReportEnum.java 29 ●●●●● 补丁 | 查看 | 原始文档 | 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 100 ●●●●● 补丁 | 查看 | 原始文档 | 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 30 ●●●●● 补丁 | 查看 | 原始文档 | 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 148 ●●●●● 补丁 | 查看 | 原始文档 | 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,147 @@
package com.sandu.ximon.admin.manager.iot.amqp;
import com.alibaba.fastjson.JSON;
import com.sandu.ximon.admin.manager.iot.frame.inner.report.*;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.CommonFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.CommonReportMessage;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A5C3ReportEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A5LightReportEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A5OrderEnum;
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 frame      ä¸ŠæŠ¥å¸§
     */
    private void processTask(String productKey, String deviceName, CommonFrame frame) {
        if (frame == null) {
            return;
        }
        log.info("处理订阅");
        log.info(frame.toString());
        if (frame.getOrderType().equals(A5OrderEnum.RESPONSE_LIGHT_DATA.getCode())) {
            // å•灯数据上报处理
            lightDataReportAnalysis(productKey, deviceName, frame);
        } else if (frame.getOrderType().equals(A5OrderEnum.RESPONSE_C3_DATA.getCode())) {
            // C3充电桩上报处理
            c3ChargingReportAnalysis(productKey, deviceName, frame);
        } else if (frame.getOrderType().equals(A5OrderEnum.RESPONSE_ATMOSPHERE_DATA.getCode())) {
            // å¤§æ°”数据指令上报
            atmosphereAnalysis(productKey, deviceName, frame);
        }
    }
    private void c3ChargingReportAnalysis(String productKey, String deviceName, CommonFrame frame) {
        String functionCode = frame.getPayload().substring(2, 4);
        if (A5C3ReportEnum.NETWORK_REQUEST.getCode().equals(functionCode)) {
            A5C3CommonReportInnerFrame netRequestFrame = new A5C3CommonReportInnerFrame().transformFrame(frame.getPayload());
        } else if (A5C3ReportEnum.QR_CODE_REQUEST.getCode().equals(functionCode)) {
            A5C3CommonReportInnerFrame codeRequestFrame = new A5C3CommonReportInnerFrame().transformFrame(frame.getPayload());
        } else if (A5C3ReportEnum.HEART_BEAT.getCode().equals(functionCode)) {
            A5C3HeartbeatReportInnerFrame heartbeatReportInnerFrame = new A5C3HeartbeatReportInnerFrame().transformFrame(frame.getPayload());
        } else if (A5C3ReportEnum.CHARGE_COMPLETE.getCode().equals(functionCode)) {
            A5C3CommonReportInnerFrame completeRequestFrame = new A5C3CommonReportInnerFrame().transformFrame(frame.getPayload());
        } else if (A5C3ReportEnum.CHARGE_STOP.getCode().equals(functionCode)) {
            A5C3CommonReportInnerFrame stopRequestFrame = new A5C3CommonReportInnerFrame().transformFrame(frame.getPayload());
        } else if (A5C3ReportEnum.ERROR_CODE.getCode().equals(functionCode)) {
            A5C3ErrorCodeReportInnerFrame errorCodeRequestFrame = new A5C3ErrorCodeReportInnerFrame().transformFrame(frame.getPayload());
        }
    }
    private void atmosphereAnalysis(String productKey, String deviceName, CommonFrame frame) {
        A5AtmosphereHeartbeatReportInnerFrame transformFrame = new A5AtmosphereHeartbeatReportInnerFrame().transformFrame(frame.getPayload());
//        log.info("大气心跳上报");
//        log.info(transformFrame.toString());
    }
    private void lightDataReportAnalysis(String productKey, String deviceName, CommonFrame frame) {
        String functionCode = frame.getPayload().substring(2, 4);
        if (A5LightReportEnum.HeartBeat_Data.getCode().equals(functionCode)) {
//            log.info("心跳相应");
            A5LightHeartbeatReportInnerFrame heartbeatReportInnerFrame = new A5LightHeartbeatReportInnerFrame().transformFrame(frame.getPayload());
//            log.info(heartbeatReportInnerFrame.toString());
        } else if (A5LightReportEnum.Time_Synchronized.getCode().equals(functionCode)) {
//            log.info("请求时间同步");
            A5LightTimeSyncReportInnerFrame syncRespInnerFrame = new A5LightTimeSyncReportInnerFrame().transformFrame(frame.getPayload());
//            log.info(syncRespInnerFrame.toString());
        } else if (A5LightReportEnum.Error_Code.getCode().equals(functionCode)) {
//            log.info("故障码上报");
            A5LightErrorCodeReportInnerFrame codeRespInnerFrame = new A5LightErrorCodeReportInnerFrame().transformFrame(frame.getPayload());
//            log.info(codeRespInnerFrame.toString());
        }
    }
}
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/A2Frame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
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;
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 A2Frame extends BaseRequestFrame implements IRequestFrame {
    private String orderType;
    private String payloadLength;
    private String payload;
    public A2Frame(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_CONTROL.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,59 @@
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 builderA2() {
        return new FrameBuilder(FunctionCodeEnum.MAIN_BOARD_CONTROL.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.MAIN_BOARD_CONTROL.getCode().equals(functionCode)) {
            iRequestFrame = new A2Frame(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/report/A5AtmosphereHeartbeatReportInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,165 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.report;
import cn.hutool.core.util.StrUtil;
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
 * A5-84-01
 * å¤§æ°”心跳包 åº”ç­”
 */
@Data
@ToString(callSuper = true)
public class A5AtmosphereHeartbeatReportInnerFrame extends BaseResponseInnerFrame<A5AtmosphereHeartbeatReportInnerFrame> {
    //  ç›®æ ‡åœ°å€    2
    private String destinationAddress;
    //  å¿ƒè·³åŒ…数据   58
    private HeartBeatDataPackage heartBeatDataPackage;
    private String originFrame;
    @Override
    public A5AtmosphereHeartbeatReportInnerFrame transformFrame(String hex) {
        //  é•¿åº¦ä¸ä¸€è‡´æ—¶ï¼Œè¿”回null
        if (StrUtil.isBlank(hex)) {
            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, 76);
        HeartBeatDataPackage heartBeatDataPackage = new HeartBeatDataPackage();
        heartBeatDataPackage.transformFrame(heartBeatData);
        setHeartBeatDataPackage(heartBeatDataPackage);
        setCrc32(hex.substring(hex.length() - 8));
        //  æ ¡éªŒCRC32
        String frame = hex.substring(2, hex.length() - 8);
        this.setValidate(CRC32Utils.validateFrame(frame, getCrc32()));
        return this;
    }
    @Data
    public static class HeartBeatDataPackage implements IResponseInnerFrame<HeartBeatDataPackage> {
        //  è®¾å¤‡åž‹å·    2
        private String deviceType;
        //  æ¨¡å—预热状态标志    1
        private String moduleWarmUpStatusFlag;
        //  æ¸©åº¦å€¼
        private Double temperature;
        //  æ¹¿åº¦å€¼
        private Double humidity;
        //  é£Žé€Ÿ
        private Double windSpeed;
        //  é£Žå‘
        private Double windDirection;
        //  å¤§æ°”压
        private Integer pressure;
        //  å…‰å¼º
        private Integer lightIntensity;
        //  å™ªéŸ³
        private Integer noise;
        //  PM2.5
        private Integer pm25;
        //  PM10
        private Integer pm10;
        //  æ€»æ‚¬æµ®é¢—粒物(TSP)
        private Integer tsp;
        //  SO2二氧化硫/甲醛相对值
        private Integer so2;
        private Integer ech2o;
        //  NO2二氧化氮/TVOC
        private Integer no2;
        private Integer tvoc;
        //  CO一氧化碳 /二氧化碳
        private Integer co;
        private Integer co2;
        //  O3臭氧
        private Integer o3;
        //  F氟化物
        private Integer fluoride;
        @Override
        public HeartBeatDataPackage transformFrame(String hex) {
            if (hex.length() != 64) {
                return null;
            }
            Integer type = 0;
            this.deviceType = hex.substring(0, 4);
            if(this.deviceType.equals(DeviceType.SENSOR_V1.getType())) {
                type = 1;
            }
            this.moduleWarmUpStatusFlag = hex.substring(4, 6);
            this.temperature = Double.parseDouble(
                    parseVal(hex,6,8)
                            + "."
                            + parseVal(hex,8,10)
            );
            this.humidity = Double.parseDouble(
                    parseVal(hex,10,12)
                            + "."
                            + parseVal(hex,12,14)
            );
            this.windSpeed = parseVal(hex,14,18) * .1;
            this.windDirection = parseVal(hex,18,22) * .1;
            this.pressure = parseVal(hex,22,26);
            this.lightIntensity = parseVal(hex,26,32);
            this.noise = parseVal(hex,32, 36);
            this.pm25 = parseVal(hex,36, 40);
            this.pm10 = parseVal(hex,40,44);
            this.tsp = parseVal(hex,44,48);
            /**
             * ä»¥ä¸‹åŒºåˆ†ç‰ˆæœ¬
             */
            if(type.equals(1)) {
                this.ech2o = parseVal(hex,48, 52);
                this.tvoc = parseVal(hex,52, 56);
                this.co2 = parseVal(hex,56, 60);
            } else {
                this.so2 = parseVal(hex,48, 52);
                this.ech2o = parseVal(hex,48, 52);
                this.tvoc = parseVal(hex,52, 56);
                this.no2 = parseVal(hex,52, 56);
                this.co = parseVal(hex,56, 60);
                this.co2 = parseVal(hex,56, 60);
            }
            this.o3 = parseVal(hex,60, 62);
            this.fluoride = parseVal(hex,62, 64);
            return this;
        }
        private Integer parseVal (String frame, int start, int end) {
            return Integer.parseInt(frame.substring(start,end),16);
        }
    }
    public enum DeviceType {
        SENSOR_V1("0101");
        private String type;
        DeviceType(String type) {
            this.type = type;
        }
        public String getType() {
            return type;
        }
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5C3CommonReportInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.report;
import cn.hutool.core.util.StrUtil;
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 18:20
 * A5-82-40/41/43/44
 * c3充电桩 ä¸ŠæŠ¥ ç½‘络请求/二维码请求/上报充电结束/上报充电中断
 */
@Data
@ToString(callSuper = true)
public class A5C3CommonReportInnerFrame extends BaseResponseInnerFrame<A5C3CommonReportInnerFrame> {
    //  ç›®æ ‡åœ°å€    4
    private String destinationAddress;
    @Override
    public A5C3CommonReportInnerFrame transformFrame(String hex) {
        //  é•¿åº¦ä¸ä¸€è‡´æ—¶ï¼Œè¿”回null
        if (StrUtil.isBlank(hex)) {
            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, 16));
        setCrc32(hex.substring(hex.length() - 8));
        //  æ ¡éªŒCRC32
        String frame = hex.substring(2, hex.length() - 8);
        this.setValidate(CRC32Utils.validateFrame(frame, getCrc32()));
        return this;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5C3ErrorCodeReportInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.report;
import cn.hutool.core.util.StrUtil;
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
 * A5-81-42
 * å•灯上报ampq æ•…障码
 */
@Data
@ToString(callSuper = true)
public class A5C3ErrorCodeReportInnerFrame extends BaseResponseInnerFrame<A5C3ErrorCodeReportInnerFrame> {
    /**
     * ç›®æ ‡åœ°å€ 2
     */
    private String destinationAddress;
    /**
     * æ•…障码
     */
    private String errorCode;
    @Override
    public A5C3ErrorCodeReportInnerFrame transformFrame(String hex) {
        if (StrUtil.isBlank(hex)) {
            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, 16));
        setErrorCode(hex.substring(16, hex.length() - 8));
        setCrc32(hex.substring(hex.length() - 8));
        //  æ ¡éªŒCRC32
        String frame = getFunctionCode() + getPayloadLength() + getDestinationAddress() + getErrorCode();
        this.setValidate(CRC32Utils.validateFrame(frame, getCrc32()));
        return this;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5C3HeartbeatReportInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.report;
import cn.hutool.core.util.StrUtil;
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
 * A5-82-45
 * c3充电桩故障码 ä¸ŠæŠ¥
 */
@Data
@ToString(callSuper = true)
public class A5C3HeartbeatReportInnerFrame extends BaseResponseInnerFrame<A5C3HeartbeatReportInnerFrame> {
    //  ç›®æ ‡åœ°å€    4
    private String destinationAddress;
    //  å¿ƒè·³åŒ…数据
    private HeartBeatDataPackage heartBeatDataPackage;
    @Override
    public A5C3HeartbeatReportInnerFrame transformFrame(String hex) {
        //  é•¿åº¦ä¸ä¸€è‡´æ—¶ï¼Œè¿”回null
        if (StrUtil.isBlank(hex)) {
            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, 16));
        String heartBeatData = hex.substring(16, hex.length() - 8);
        HeartBeatDataPackage heartBeatDataPackage = new HeartBeatDataPackage();
        heartBeatDataPackage.transformFrame(heartBeatData);
        setHeartBeatDataPackage(heartBeatDataPackage);
        setCrc32(hex.substring(hex.length() - 8));
        //  æ ¡éªŒCRC32
        String frame = hex.substring(2, hex.length() - 8);
        this.setValidate(CRC32Utils.validateFrame(frame, getCrc32()));
        return this;
    }
    @Data
    public static class HeartBeatDataPackage implements IResponseInnerFrame<HeartBeatDataPackage> {
        //  c3Mac(id hex)
        private String c3Mac;
        //  å¹´
        private String year;
        //  æœˆ
        private String month;
        //  æ—¥
        private String day;
        //  æ—¶
        private String hour;
        //  åˆ†
        private String min;
        //  ç§’
        private String sec;
        //  å……电桩口
        private String chargingPort;
        //  å……电桩口状态位
        private String statusBit;
        //  è®¾å¤‡æ¸©åº¦    0.1℃
        private String deviceTemperature;
        //  ç”µç½‘电压    0.1V
        private String gridVoltage;
        //  ç”µç½‘电流    0.1A
        private String gridCurrent;
        //  é¢‘率  0.01Hz
        private String frequency;
        //  åŠŸçŽ‡å› ç´     0.001
        private String powerFactor;
        //  æœ‰åŠŸåŠŸçŽ‡    0.1KW
        private String activePower;
        //  æ— åŠŸåŠŸçŽ‡    0.1KFar
        private String reactivePower;
        //  å·²å……电量    0.01KWh
        private String chargedCapacity;
        //  é¢„约电量    1KWh
        private String reservedCapacity;
        //  å‰©ä½™é‡‘额    0.1元
        private String remainingAmount;
        //  å·²å……æ—¶é•¿
        private String alreadyChargingTime;
        @Override
        public HeartBeatDataPackage transformFrame(String hex) {
            if (StrUtil.isBlank(hex)) {
                return null;
            }
            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.chargingPort = hex.substring(12, 16);
            this.statusBit = hex.substring(16, 18);
            this.deviceTemperature = hex.substring(18, 22);
            this.gridVoltage = hex.substring(22, 26);
            this.gridCurrent = hex.substring(26, 30);
            this.frequency = hex.substring(30, 34);
            this.powerFactor = hex.substring(34, 38);
            this.activePower = hex.substring(38, 42);
            this.reactivePower = hex.substring(42, 46);
            this.chargedCapacity = hex.substring(46, 50);
            this.reservedCapacity = hex.substring(50, 54);
            this.remainingAmount = hex.substring(54, 58);
            this.alreadyChargingTime = hex.substring(58, 64);
            return this;
        }
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5LightErrorCodeReportInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.report;
import cn.hutool.core.util.StrUtil;
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
 * A5-81-42
 * å•灯上报ampq æ•…障码
 */
@Data
@ToString(callSuper = true)
public class A5LightErrorCodeReportInnerFrame extends BaseResponseInnerFrame<A5LightErrorCodeReportInnerFrame> {
    /**
     * ç›®æ ‡åœ°å€ 2
     */
    private String destinationAddress;
    /**
     * æ•…障码
     */
    private String errorCode;
    @Override
    public A5LightErrorCodeReportInnerFrame transformFrame(String hex) {
        if (StrUtil.isBlank(hex)) {
            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));
        setErrorCode(hex.substring(12, 16));
        setCrc32(hex.substring(hex.length() - 8));
        //  æ ¡éªŒCRC32
        String frame = getFunctionCode() + getPayloadLength() + getDestinationAddress() + getErrorCode();
        this.setValidate(CRC32Utils.validateFrame(frame, getCrc32()));
        return this;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/report/A5LightHeartbeatReportInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.report;
import cn.hutool.core.util.StrUtil;
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
 * A5-81-40
 * ç¯è¯»å¿ƒè·³åŒ… ä¸ŠæŠ¥
 */
@Data
@ToString(callSuper = true)
public class A5LightHeartbeatReportInnerFrame extends BaseResponseInnerFrame<A5LightHeartbeatReportInnerFrame> {
    //  ç›®æ ‡åœ°å€    2
    private String destinationAddress;
    //  å¿ƒè·³åŒ…数据   58
    private HeartBeatDataPackage heartBeatDataPackage;
    private String originFrame;
    @Override
    public A5LightHeartbeatReportInnerFrame transformFrame(String hex) {
        //  é•¿åº¦ä¸ä¸€è‡´æ—¶ï¼Œè¿”回null
        if (StrUtil.isBlank(hex)) {
            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(2, hex.length() - 8);
        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/frame/inner/report/A5LightTimeSyncReportInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.report;
import cn.hutool.core.util.StrUtil;
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
 * A5-81-41
 * å•灯上报ampq è¯·æ±‚时间同步
 */
@Data
@ToString(callSuper = true)
public class A5LightTimeSyncReportInnerFrame extends BaseResponseInnerFrame<A5LightTimeSyncReportInnerFrame> {
    /**
     * ç›®æ ‡åœ°å€ 2
     */
    private String destinationAddress;
    /**
     * 0x00:请求同步
     */
    private String responseStatus;
    @Override
    public A5LightTimeSyncReportInnerFrame transformFrame(String hex) {
        if (StrUtil.isBlank(hex)) {
            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, hex.length() - 8));
        setCrc32(hex.substring(hex.length() - 8));
        //  æ ¡éªŒ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/request/A1TernaryCodeReqInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.request;
import cn.hutool.core.util.HexUtil;
import com.sandu.ximon.admin.manager.iot.frame.inner.IRequestInnerFrame;
/**
 * @author chenjiantian
 * @date 2021/12/6 14:46
 * A1->0A/0B/0C
 * è®¾ç½®é˜¿é‡Œäº‘三元码 ProductKey DeviceName DeviceSecret
 */
public class A1TernaryCodeReqInnerFrame implements IRequestInnerFrame {
    private final String ternaryCodeHex;
    /**
     * @param ternaryCode ProductKey/DeviceName/DeviceSecret
     */
    public A1TernaryCodeReqInnerFrame(String ternaryCode) {
        ternaryCodeHex = HexUtil.encodeHexStr(ternaryCode);
    }
    @Override
    public String getEncodeFrame() {
        if (this.ternaryCodeHex.length() % 2 != 0) {
            return "0" + ternaryCodeHex;
        }
        return ternaryCodeHex;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/request/A5LightBrightnessReqInnerFrame.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 A5LightBrightnessReqInnerFrame implements IRequestInnerFrame {
    private final String payload;
    /**
     * @param lightLevel äº®åº¦ç­‰çº§ [0,100]
     */
    public A5LightBrightnessReqInnerFrame(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/A5LightHeartbeatReqInnerFrame.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 A5LightHeartbeatReqInnerFrame 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/request/A5LightResetReqInnerFrame.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->25 æ¸…除单灯累计数据
 */
public class A5LightResetReqInnerFrame implements IRequestInnerFrame {
    @Override
    public String getEncodeFrame() {
        String functionCode = A5LightDataEnum.LightReset.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/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/response/A1DeviceMacRespInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.response;
import com.sandu.ximon.admin.manager.iot.frame.inner.BaseResponseInnerFrame;
import lombok.Data;
import lombok.ToString;
/**
 * @author chenjiantian
 * @date 2021/12/6 14:46
 * A1->0x89
 * 0x89:读取芯片唯一设备地址应答
 * 12字节        1字节    è§£é‡Šï¼šè®¾å¤‡ç±»åž‹00代表MQTT串口,01代表CAT1
 * ç¡¬ä»¶MAC        è®¾å¤‡ç±»åž‹
 */
@Data
@ToString(callSuper = true)
public class A1DeviceMacRespInnerFrame extends BaseResponseInnerFrame<A1DeviceMacRespInnerFrame> {
    /**
     * 12字节 ç¡¬ä»¶MAC
     */
    private String mac;
    /**
     * 1字节 è®¾å¤‡ç±»åž‹ è®¾å¤‡ç±»åž‹00代表MQTT串口,01代表CAT1
     */
    private String type;
    @Override
    public A1DeviceMacRespInnerFrame transformFrame(String payload) {
        mac = payload.substring(0, 24);
        type = payload.substring(24);
        return this;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/response/A1TernaryCodeRespInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.response;
import cn.hutool.core.util.HexUtil;
import com.sandu.ximon.admin.manager.iot.frame.inner.BaseResponseInnerFrame;
import lombok.Data;
import lombok.ToString;
/**
 * @author chenjiantian
 * @date 2021/12/6 14:46
 * A1->8A/8B/8C
 * è®¾ç½®é˜¿é‡Œäº‘三元码 ProductKey DeviceName DeviceSecret å“åº”内容
 */
@Data
@ToString(callSuper = true)
public class A1TernaryCodeRespInnerFrame extends BaseResponseInnerFrame<A1TernaryCodeRespInnerFrame> {
    /**
     * ä¸‰å…ƒç 
     */
    private String ternaryCode;
    @Override
    public A1TernaryCodeRespInnerFrame transformFrame(String hex) {
        ternaryCode = HexUtil.decodeHexStr(hex);
        return this;
    }
}
ximon-admin/src/main/java/com/sandu/ximon/admin/manager/iot/frame/inner/response/A5LightBrightnessRespInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.response;
import cn.hutool.core.util.StrUtil;
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
 * A5-81-01灯亮度控制 åº”ç­”
 */
@Data
@ToString(callSuper = true)
public class A5LightBrightnessRespInnerFrame extends BaseResponseInnerFrame<A5LightBrightnessRespInnerFrame> {
    /**
     * ç›®æ ‡åœ°å€ 2
     */
    private String destinationAddress;
    /**
     * å•灯亮度状态 1
     */
    private String responseStatus;
    @Override
    public A5LightBrightnessRespInnerFrame transformFrame(String hex) {
        if (StrUtil.isBlank(hex)) {
            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/A5LightHeartbeatRespInnerFrame.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
package com.sandu.ximon.admin.manager.iot.frame.inner.response;
import cn.hutool.core.util.StrUtil;
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
 * A5-81-02
 * ç¯è¯»å¿ƒè·³åŒ… åº”ç­”
 */
@Data
@ToString(callSuper = true)
public class A5LightHeartbeatRespInnerFrame extends BaseResponseInnerFrame<A5LightHeartbeatRespInnerFrame> {
    //  ç›®æ ‡åœ°å€    2
    private String destinationAddress;
    //  å¿ƒè·³åŒ…数据   58
    private HeartBeatDataPackage heartBeatDataPackage;
    private String originFrame;
    @Override
    public A5LightHeartbeatRespInnerFrame transformFrame(String hex) {
        //  é•¿åº¦ä¸ä¸€è‡´æ—¶ï¼Œè¿”回null
        if (StrUtil.isBlank(hex)) {
            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(2, hex.length() - 8);
        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,160 @@
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 {
    /**
     * å‘送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;
    }
     /**
     * è°ƒç”¨è‡ªå®šä¹‰topic
     * https://help.aliyun.com/document_detail/69584.htm?spm=a2c4g.11186623.0.0.25b33982bSQSom#reference-snk-mrz-wdb
     *
     * @param deviceName è®¾å¤‡å
     * @param param      å‚æ•°
     * @return è®¾å¤‡è¿”回的结果
     */
    protected 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
 * amqp消息实体类
 */
@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,19 @@
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
 * å“åº”总体帧
 * é‡Œé¢çš„负荷payload å·²ç»è½¬åŒ–成相应类型的responseInnerFrame实体类
 */
@Data
@ToString(callSuper = true)
public class WrapResponseCommonFrame<T extends BaseResponseInnerFrame<T>> extends CommonFrame {
    private T responseInnerFrame;
}
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/A5AtmosphereReportEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.sandu.ximon.admin.manager.iot.rrpc.enums;
/**
 * @author chenjiantian
 * A5-84 å¤§æ°”上报:(MQTT异步)
 */
public enum A5AtmosphereReportEnum {
    //  ä¸ŠæŠ¥å¿ƒè·³åŒ…
    HeartBeat_Data("01"),
    ;
    A5AtmosphereReportEnum(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/A5C3ReportEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
package com.sandu.ximon.admin.manager.iot.rrpc.enums;
/**
 * @author chenjiantian
 * A5-83 C3充电桩上报:(amqp)
 */
public enum A5C3ReportEnum {
    /**
     *网络请求
     */
    NETWORK_REQUEST("40"),
    /**
     * äºŒç»´ç è¯·æ±‚
     */
    QR_CODE_REQUEST("41"),
    /**
     * ä¸ŠæŠ¥å¿ƒè·³åŒ…
     */
    HEART_BEAT("42"),
    /**
     * ä¸ŠæŠ¥å……电结束
     */
    CHARGE_COMPLETE("43"),
    /**
     * ä¸ŠæŠ¥å……电中断
     */
    CHARGE_STOP("44"),
    /**
     * ä¸ŠæŠ¥æ•…障码
     */
    ERROR_CODE("45")
    ;
    A5C3ReportEnum(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,29 @@
package com.sandu.ximon.admin.manager.iot.rrpc.enums;
/**
 * @author chenjiantian
 * A5-01 å•灯数据指令 åˆ—表
 */
public enum A5LightDataEnum {
    //  å•灯控制
    LightControl("01"),
    //  è¯»å¿ƒè·³åŒ…
    ReadHeartBeat("02"),
    //  å®šæ—¶æŽ§åˆ¶
    TimingLightControl("03"),
    //  å…‰æ„ŸæŽ§åˆ¶
    LightSensorControl("04"),
    // æ¸…除单灯累计数据
    LightReset("25");
    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/A5LightReportEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
package com.sandu.ximon.admin.manager.iot.rrpc.enums;
/**
 * @author chenjiantian
 * A5-81 å•灯主动上报:(amqp)
 */
public enum A5LightReportEnum {
    //  ä¸ŠæŠ¥å¿ƒè·³åŒ…
    HeartBeat_Data("40"),
    //  è¯·æ±‚时间同步
    Time_Synchronized("41"),
    //  æ•…障码
    Error_Code("42"),
    //  æœ¬åœ°å®šæ—¶/光控开关灯动作上报
    Timing_LightSwitch_Report("43"),
    //  è¯·æ±‚通讯协议模式(上电后10秒一次,发6次)
    Protocol_Model_Request("44");
    A5LightReportEnum(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,100 @@
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);
        if (commonFrame == null) {
            throw new BusinessException("rrpc请求失败");
        }
        WrapResponseCommonFrame<T> responseCommonFrame = new WrapResponseCommonFrame<>();
        BeanUtils.copyProperties(commonFrame, responseCommonFrame);
        try {
            responseCommonFrame.setResponseInnerFrame(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,30 @@
package com.sandu.ximon.admin.manager.iot.rrpc.topic;
import com.aliyuncs.iot.model.v20180120.InvokeThingServiceResponse;
import com.sandu.ximon.admin.manager.iot.frame.IRequestFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.CommonFrame;
import com.sandu.ximon.admin.manager.iot.rrpc.dto.InvokeParam;
/**
 * @author chenjiantian
 * @date 2021/12/6 11:11
 * è‡ªå®šä¹‰toic
 */
public interface ICustomizeTopic {
    /**
     * èŽ·å–äº§å“å—
     *
     * @return äº§å“å—
     */
    String getProductKey();
    /**
     * å‘送rrpc è¯·æ±‚
     *
     * @param deviceName    è®¾å¤‡å
     * @param iRequestFrame ç¼–码帧
     * @return è¿”回的解码帧实体类
     */
    CommonFrame sendRRPC(String deviceName, IRequestFrame iRequestFrame);
}
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,148 @@
package com.sandu.ximon.admin;
import com.aliyuncs.iot.model.v20180120.QueryDeviceDetailResponse;
import com.aliyuncs.iot.model.v20180120.RegisterDeviceResponse;
import com.sandu.common.execption.BusinessException;
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.*;
import com.sandu.ximon.admin.manager.iot.frame.inner.response.A1DeviceMacRespInnerFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.response.A1TernaryCodeRespInnerFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.response.A5LightBrightnessRespInnerFrame;
import com.sandu.ximon.admin.manager.iot.frame.inner.response.A5LightHeartbeatRespInnerFrame;
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.A2OrderEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.enums.A5OrderEnum;
import com.sandu.ximon.admin.manager.iot.rrpc.mainboard.MainBoardInvokeSyncService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
@Slf4j
class BaseTopicTests {
    @Test
    void queryDeviceDetail() {
        QueryDeviceDetailResponse.Data data = MainBoardInvokeSyncService.getInstance().queryDeviceDetail("32313243305007ff3055ffff01", null);
        System.out.println(data.toString());
    }
    @Test
    void rrpcLightControl() {
        A5LightBrightnessReqInnerFrame lightControlFrame = new A5LightBrightnessReqInnerFrame(80);
        A5Frame a5Frame = new A5Frame(A5OrderEnum.REQUEST_LIGHT_DATA.getCode(), lightControlFrame);
        WrapResponseCommonFrame<A5LightBrightnessRespInnerFrame> frame = MainBoardInvokeSyncService.getInstance()
                .sendRRPC("32313243305008ff1a06ffff", a5Frame, A5LightBrightnessRespInnerFrame.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 register() {
        String baseMac = "baseDevice";
        String MAINBOARD_PDK = "a1JsfPG4iKW";
        A1Frame a1Frame = new A1Frame(A1OrderEnum.REQUEST_READ_DEVICE_UNIQUE_MAC.getCode(), new EmptyRequestInnerFrame());
        CommonFrame commonFrame = MainBoardInvokeSyncService.getInstance()
                .sendRRPC(baseMac, a1Frame);
        if(commonFrame == null){
            throw new BusinessException("读取设备唯一ID失败");
        }
        A1DeviceMacRespInnerFrame a1DeviceMacRespInnerFrame = new A1DeviceMacRespInnerFrame().transformFrame(commonFrame.getPayload());
        log.info(commonFrame.toString());
        String uniqueMac = a1DeviceMacRespInnerFrame.getMac();
        uniqueMac = uniqueMac.toLowerCase();
        log.info("唯一码{}",uniqueMac);
        MainBoardInvokeSyncService.getInstance().registerDevice(uniqueMac);
        QueryDeviceDetailResponse.Data deviceDetail = MainBoardInvokeSyncService.getInstance().queryDeviceDetail(uniqueMac, null);
        if(deviceDetail == null){
            throw new BusinessException("注册失败");
        }
        log.info(deviceDetail.toString());
        WrapResponseCommonFrame<A1TernaryCodeRespInnerFrame> productKeyResp = MainBoardInvokeSyncService.getInstance()
                .sendRRPC(baseMac,
                        FrameBuilder.builderA1().innerFrame(new A1TernaryCodeReqInnerFrame(MAINBOARD_PDK))
                                .orderType(A1OrderEnum.REQUEST_SET_PRODUCT_KEY.getCode()).build(),
                        A1TernaryCodeRespInnerFrame.class);
        A1TernaryCodeRespInnerFrame responseInnerFrame = productKeyResp.getResponseInnerFrame();
        if(!MAINBOARD_PDK.equals(responseInnerFrame.getTernaryCode())){
            throw new BusinessException("设备配置ProductKey失败");
        }
        WrapResponseCommonFrame<A1TernaryCodeRespInnerFrame> responseCommonFrame = MainBoardInvokeSyncService.getInstance()
                .sendRRPC(baseMac,
                        FrameBuilder.builderA1().innerFrame(new A1TernaryCodeReqInnerFrame(uniqueMac))
                                .orderType(A1OrderEnum.REQUEST_SET_DEVICE_NAME.getCode()).build(),
                        A1TernaryCodeRespInnerFrame.class);
        A1TernaryCodeRespInnerFrame deviceNameFrame = responseCommonFrame.getResponseInnerFrame();
        if(!uniqueMac.equals(deviceNameFrame.getTernaryCode())){
            throw new BusinessException("设备配置名失败");
        }
        WrapResponseCommonFrame<A1TernaryCodeRespInnerFrame> wrapResponseCommonFrame = MainBoardInvokeSyncService.getInstance()
                .sendRRPC(baseMac,
                        FrameBuilder.builderA1().innerFrame(new A1TernaryCodeReqInnerFrame(deviceDetail.getDeviceSecret()))
                                .orderType(A1OrderEnum.REQUEST_SET_DEVICE_SECRET.getCode()).build(),
                        A1TernaryCodeRespInnerFrame.class);
        A1TernaryCodeRespInnerFrame deviceSecretFrame = wrapResponseCommonFrame.getResponseInnerFrame();
        if (!deviceDetail.getDeviceSecret().equals(deviceSecretFrame.getTernaryCode())) {
            throw new BusinessException("设备密钥失败");
        }
        CommonFrame rebootFrame = MainBoardInvokeSyncService.getInstance()
                .sendRRPC(baseMac,
                        FrameBuilder.builderA2().innerFrame(new EmptyRequestInnerFrame())
                                .orderType(A2OrderEnum.REQUEST_MAIN_BOARD_RESET.getCode()).build());
        if (rebootFrame.getPayload().equals("00")) {
            System.out.println("重启成功");
        }
    }
    @Test
    void LightHeartbeat() {
        IRequestFrame build = FrameBuilder.builderA5()
                .orderType(A5OrderEnum.REQUEST_LIGHT_DATA.getCode())
                .innerFrame(new A5LightHeartbeatReqInnerFrame())
                .build();
        WrapResponseCommonFrame<A5LightHeartbeatRespInnerFrame> responseCommonFrame = MainBoardInvokeSyncService.getInstance().sendRRPC("32313243305008ff1a06ffff", build, A5LightHeartbeatRespInnerFrame.class);
        System.out.println("responseCommonFrame.toString()");
        System.out.println(responseCommonFrame.toString());
    }
    @Test
    void LightReset() {
        String deviceName = "32313243305007ff3055ffff01";
        IRequestFrame build = FrameBuilder.builderA5()
                .orderType(A5OrderEnum.REQUEST_LIGHT_DATA.getCode())
                .innerFrame(new A5LightResetReqInnerFrame())
                .build();
        CommonFrame commonFrame = MainBoardInvokeSyncService.getInstance()
                .sendRRPC(deviceName, build);
        System.out.println(commonFrame.toString());
        CommonFrame rebootFrame = MainBoardInvokeSyncService.getInstance()
                .sendRRPC(deviceName,
                        FrameBuilder.builderA2().innerFrame(new EmptyRequestInnerFrame())
                                .orderType(A2OrderEnum.REQUEST_MAIN_BOARD_RESET.getCode()).build());
        if (rebootFrame.getPayload().equals("00")) {
            System.out.println("重启成功");
        }
    }
}