使用emqx webhook 桥接 web

emqx 4

首先要在规则引擎中 配置好 规则 和 资源

资源

主要是选择 资源类型 和 请求 URL (后端接收消息的接口路径)
在这里插入图片描述
在这里插入图片描述

规则sql
SELECT
  topic,clientid,qos,bin2hexstr(payload) as payload,username
FROM
  "/transfusion/zhsy/sub/#"
代码片段

	// 接收消息的 接口路径 与 资源中配置的 路径一致
    @PostMapping("/api/v4/mqtt/publish")
    public void getMessage(HttpServletRequest httpServletRequest) throws IOException {

        String s = httpServletRequest.getReader().readLine();
        httpServletRequest.getReader().close();
        Map map = JsonUtils.parseObject(s, Map.class);

        log.debug("接收数据的时间",s);

        String topic = ObjectUtils.isNotEmpty(map.get("topic")) ? map.get("topic").toString() : "";
        String clientid = ObjectUtils.isNotEmpty(map.get("clientid")) ? map.get("clientid").toString() : "";
        String event = ObjectUtils.isNotEmpty(map.get("event")) ? map.get("event").toString() : "";



        // 判断设备是否离线
        if (ObjectUtils.isNotEmpty(clientid) && ObjectUtils.isNotEmpty(event)) {

            if (event.equals("client.connected")) {
                log.info("设备 上线消息");
//                  deviceMapper.update(new UpdateWrapper<Device>().lambda().set(Device::getDeviceStatus,).eq(Device::getDeviceSn,clientid));
            } else if (event.equals("client.disconnected")) {
                log.info("设备 离线消息");
                Long existCount = deviceMapper.selectCount(new QueryWrapper<Device>().lambda().eq(Device::getDeviceSn, clientid).eq(Device::getIsDelete, 0));
                if(existCount > 0){
                    deviceMapper.update(new UpdateWrapper<Device>().lambda().set(Device::getDeviceStatus, 1).eq(Device::getDeviceSn, clientid).eq(Device::getIsDelete, 0));
                }
            }

        }




        // 接收数据
        if (ObjectUtils.isNotEmpty(topic) && topic.contains("/transfusion/zhsy/sub")) {

            SubscribeMessageBo subscribeMessageBo = new SubscribeMessageBo();
            subscribeMessageBo.setUsername(map.get("username").toString());
            subscribeMessageBo.setTopic(topic);
            subscribeMessageBo.setPayload(map.get("payload").toString().toLowerCase());
            subscribeMessageBo.setClientid(map.get("clientid").toString());

            //截取 设备 imei
            String sn = StringUtils.substringAfter(subscribeMessageBo.getTopic(), "sub/");
//            String deviceSn = "";
//            if (ObjectUtils.isEmpty(RedisUtils.getCacheObject(sn))) {
//                log.info("是否存在设备:{}", deviceSn);
//                Device device = deviceMapper.selectOne(new QueryWrapper<Device>().lambda().eq(Device::getDeviceSn, sn).eq(Device::getIsDelete, 0));
//                Assert.isTrue(ObjectUtils.isNotEmpty(device), "该设备不存在");
//                deviceSn = device.getDeviceSn();
//                RedisUtils.setCacheObject(deviceSn, deviceSn);
//            } else {
//                deviceSn = RedisUtils.getCacheObject(sn).toString();
//            }


            log.info("设备号:{}", sn);
            String payload = handlingPayloadToHexStr(subscribeMessageBo.getPayload());
            log.info("接收的消息指令:{}", payload);

            //保存日志
            saveLog(subscribeMessageBo.getPayload(), subscribeMessageBo.getTopic(), 0);

            //解析数据
            String[] dataArray = StrUtil.split(payload, 2);
            int length = dataArray.length;
            //帧头
            String s1 = dataArray[0] + dataArray[1];
            //帧尾
            String s2 = dataArray[length - 2] + dataArray[length - 1];
            //消息类型  状态 和 报警类型
            String s3 = dataArray[2] + dataArray[3];


            Device device = new Device();
            device.setDeviceSn(sn);


            //拼接 16进制 字符
            String payloadMessage = dataArray[0] + dataArray[1] + dataArray[2] + dataArray[3] + dataArray[4] + dataArray[5];
            // 转化为 byte
            byte[] bytes1 = hexStringToByteArray(payloadMessage);
            // 校验 sum
            byte b = calculateChecksum(bytes1);
            // 校验的最终值
            String s4 = byteToHexString(b);
            log.info("计算的和:{}", s4);

            //最终要返回的数据
            String value = payloadMessage + "0000" + s4 + dataArray[length - 2] + dataArray[length - 1];
            byte[] bytes = HexUtil.decodeHex(value);
            log.info("最终返回的数据:{}", bytes);

            /**
             * 返回响应
             */
            //拼装响应数据
            HashMap<String, Object> hashMap = new HashMap<>();
            String pubTopic = "/transfusion/zhsy/pub/";
            hashMap.put("topic", pubTopic + sn);
            hashMap.put("payload", Base64.encode(bytes));
            hashMap.put("qos", 1);
            hashMap.put("clientid", sn);
            hashMap.put("encoding", "base64");
            hashMap.put("retain", false);

            String result = JsonUtils.toJsonString(hashMap);
            Map<String, String> headers = new HashMap<>();
            headers.put("content-type", "application/json;charset=UTF-8");
            headers.put("accept", "application/json");
            String user = "admin:public";
            String encode = Base64.encode(user.getBytes(StandardCharsets.UTF_8));
            headers.put("Authorization", "Basic " + encode);

            //查看节点健康状态
			//String body = HttpRequest.get("http://hmkj.hmisp.com:9081/status").addHeaders(headers).executeAsync().body();


			// 向 emqx 发布 消息
            String body = HttpRequest.post("http://hmkj.hmisp.com:9081/api/v4/mqtt/publish").body(result).addHeaders(headers).execute().body();
            log.info("响应结果:{}", body);


            //保存日志 转换为 16进制字符串
            String s5 = handlingPayloadToHexStr(bytes);
            saveLog(s5, pubTopic, 1);
            log.info("发布的指令:{}", s5);

            /**
             * 校验数据
             */
            if ("3faa".equals(s1) && "5665".equals(s2)) {
                if ("736d".equals(s3)) {
                    //状态指令
                    if ("00".equals(dataArray[length - 4])) {
                        //待机指令
                        device.setDeviceStatus(2);
                    } else if ("01".equals(dataArray[length - 4])) {
                        //检测指令
                        device.setDeviceStatus(4);
                    } else if ("02".equals(dataArray[length - 4])) {
                        //无液报警
                        device.setDeviceStatus(3);
                    }
                } else if ("626c".equals(s3)) {
                    //电量指令
                    if ("00".equals(dataArray[length - 4])) {
                        //低电量
                        device.setQuantity(1);
                    } else if ("01".equals(dataArray[length - 4])) {
                        //中电量
                        device.setQuantity(2);
                    } else if ("02".equals(dataArray[length - 4])) {
                        //高电量
                        device.setQuantity(3);
                    }
                }
                // 修改设备状态
                int update = deviceMapper.update(device, new QueryWrapper<Device>().lambda().eq(Device::getDeviceSn, sn));
                log.info("状态修改是否成功! {}", update);

                /**
                 * 通过 websocket  后台向前台 发送更新的消息
                 */
                send(sn);
            } else {
                log.info("该指令格式错误:{}", payload);
            }
        }


    }


    @Resource
    public WebSocketEndPoint webSocketEndPoint;

    /**
     * 通过 websocket  后台向前台 发送更新的消息
     */
    public void send(String sn){
        String userId = deviceMapper.selectUser(sn);
        //更新的数据
        LargeDeviceVo largeDeviceVo = deviceMapper.selectLarge(sn);
        AddUpVo addUpVo =  deviceMapper.statisticCount();
        Map<String,Object> objects = new HashMap<>();
        objects.put("newData",largeDeviceVo);
        objects.put("num",addUpVo);

        webSocketEndPoint.sendMessageToOne(userId,JsonUtils.toJsonString(objects), null);
    }





/*
* v4 版本的 调用 api 的 认证方式 
*/
    @GetMapping("api/v4/auth")
    public void getUserName(){
        String msg = "{\"backend\":\"built_in_database\",\"mechanism\":\"password_based\",\"password_hash_algorithm\":{\"name\":\"plain\",\"salt_position\":\"disable\"},\"user_id_type\":\"username\"}";
        Map<String, String> headers = new HashMap<>();
        headers.put("content-type","application/json;charset=UTF-8");
        headers.put("accept","application/json");
        String username = "b3172aa5f2e9c4f1";
        String password = "734pju9CRaK0omgTjCD38RIQ79CxTs3efYEMvA6OT0gwH";
        headers.put("Authorization",Credentials.basic(username,password));
        String body = HttpRequest.post("http://192.168.20.53:18083/api/v4/authentication").body(msg).addHeaders(headers).execute().body();
        log.info(body);
    }


    /**
     * v4版本 api 设置 账号密码
     */
    @GetMapping("api/v4/setUser")
    public void setUser() {
        Map<String, String> headers = new HashMap<>();
        headers.put("content-type", "application/json;charset=UTF-8");
        headers.put("accept", "application/json");
        String user = "admin:public";
        String encode = Base64.encode(user.getBytes(StandardCharsets.UTF_8));
        headers.put("Authorization", "Basic " + encode);
        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("clientid", "localhost_consumer");
        hashMap.put("password", "123456");
        String body = HttpRequest.post("http://hmkj.hmisp.com:9081/api/v4/auth_clientid").body(JsonUtils.toJsonString(hashMap)).addHeaders(headers).execute().body();
        log.info(body);
    }

emqx 5

设计图

在这里插入图片描述

规则

在这里插入图片描述

连接器

在这里插入图片描述

代码片段
/**
 * Description:
 * 关于 emqx 桥接 webhook 向 java 后端发送消息时需要注意的问题:
 *
 * @author xcx
 * @date 2024/3/14
 */
@RestController
@RequestMapping()
@Slf4j
public class MqttMessqgeController {
    @Resource
    private DeviceMapper deviceMapper;

    @Resource
    private LogMapper logMapper;

	// v5 版本 接收消息 接口路径
    @PostMapping("/api/v5/publish")
    public void getMessage(HttpServletRequest httpServletRequest) throws IOException {

        String s = httpServletRequest.getReader().readLine();
        httpServletRequest.getReader().close();
        Map map = JsonUtils.parseObject(s, Map.class);

        log.debug("接收数据的时间",s);

        String topic = ObjectUtils.isNotEmpty(map.get("topic")) ? map.get("topic").toString() : "";
        String clientid = ObjectUtils.isNotEmpty(map.get("clientid")) ? map.get("clientid").toString() : "";
        String event = ObjectUtils.isNotEmpty(map.get("event")) ? map.get("event").toString() : "";



        // 判断设备是否离线
        if (ObjectUtils.isNotEmpty(clientid) && ObjectUtils.isNotEmpty(event)) {

            if (event.equals("client.connected")) {
                log.info("设备 上线消息");
//                  deviceMapper.update(new UpdateWrapper<Device>().lambda().set(Device::getDeviceStatus,).eq(Device::getDeviceSn,clientid));
            } else if (event.equals("client.disconnected")) {
                log.info("设备 离线消息");
                Long existCount = deviceMapper.selectCount(new QueryWrapper<Device>().lambda().eq(Device::getDeviceSn, clientid).eq(Device::getIsDelete, 0));
                if(existCount > 0){
                    deviceMapper.update(new UpdateWrapper<Device>().lambda().set(Device::getDeviceStatus, 1).eq(Device::getDeviceSn, clientid).eq(Device::getIsDelete, 0));
                }
            }

        }




        // 接收数据
        if (ObjectUtils.isNotEmpty(topic) && topic.contains("/transfusion/zhsy/sub")) {

            SubscribeMessageBo subscribeMessageBo = new SubscribeMessageBo();
            subscribeMessageBo.setUsername(map.get("username").toString());
            subscribeMessageBo.setTopic(topic);
            subscribeMessageBo.setPayload(map.get("payload").toString().toLowerCase());
            subscribeMessageBo.setClientid(map.get("clientid").toString());

            //截取 设备 imei
            String sn = StringUtils.substringAfter(subscribeMessageBo.getTopic(), "sub/");
//            String deviceSn = "";
//            if (ObjectUtils.isEmpty(RedisUtils.getCacheObject(sn))) {
//                log.info("是否存在设备:{}", deviceSn);
//                Device device = deviceMapper.selectOne(new QueryWrapper<Device>().lambda().eq(Device::getDeviceSn, sn).eq(Device::getIsDelete, 0));
//                Assert.isTrue(ObjectUtils.isNotEmpty(device), "该设备不存在");
//                deviceSn = device.getDeviceSn();
//                RedisUtils.setCacheObject(deviceSn, deviceSn);
//            } else {
//                deviceSn = RedisUtils.getCacheObject(sn).toString();
//            }


            log.info("设备号:{}", sn);
            String payload = handlingPayloadToHexStr(subscribeMessageBo.getPayload());
            log.info("接收的消息指令:{}", payload);

            //保存日志
            saveLog(subscribeMessageBo.getPayload(), subscribeMessageBo.getTopic(), 0);

            //解析数据
            String[] dataArray = StrUtil.split(payload, 2);
            int length = dataArray.length;
            //帧头
            String s1 = dataArray[0] + dataArray[1];
            //帧尾
            String s2 = dataArray[length - 2] + dataArray[length - 1];
            //消息类型  状态 和 报警类型
            String s3 = dataArray[2] + dataArray[3];


            Device device = new Device();
            device.setDeviceSn(sn);


            //拼接 16进制 字符
            String payloadMessage = dataArray[0] + dataArray[1] + dataArray[2] + dataArray[3] + dataArray[4] + dataArray[5];
            // 转化为 byte
            byte[] bytes1 = hexStringToByteArray(payloadMessage);
            // 校验 sum
            byte b = calculateChecksum(bytes1);
            // 校验的最终值
            String s4 = byteToHexString(b);
            log.info("计算的和:{}", s4);

            //最终要返回的数据
            String value = payloadMessage + "0000" + s4 + dataArray[length - 2] + dataArray[length - 1];
            byte[] bytes = HexUtil.decodeHex(value);
            log.info("最终返回的数据:{}", bytes);

            /**
             * 返回响应
             */
            //拼装响应数据
            HashMap<String, Object> hashMap = new HashMap<>();
            String pubTopic = "/transfusion/zhsy/pub/";
            hashMap.put("topic", pubTopic + sn);
            hashMap.put("payload_encoding", "base64");
            hashMap.put("qos", 1);
            hashMap.put("payload",bytes);
            hashMap.put("retain", false);
            String result = JsonUtils.toJsonString(hashMap);


            Map<String, String> headers = new HashMap<>();
            headers.put("content-type", "application/json;charset=UTF-8");
            headers.put("accept", "application/json");

            // v5版本认证
            String username = "437a107f0f534c00";
            String password = "yNxDUxn9AgSv2wvujhspmodSYMKWOSJ9BTFWvx7iI9BFvH";
            headers.put("Authorization", Credentials.basic(username, password));


            //查看节点健康状态
//            String body = HttpRequest.get("http://hmkj.hmisp.com:9081/status").addHeaders(headers).executeAsync().body();

            String body = HttpRequest.post("http://hmkj.hmisp.com:18083/api/v5/publish").body(result).addHeaders(headers).execute().body();
            log.info("响应结果:{}", body);


            //保存日志 转换为 16进制字符串
            String s5 = handlingPayloadToHexStr(bytes);
            saveLog(s5, pubTopic, 1);
            log.info("发布的指令:{}", s5);

            /**
             * 校验数据
             */
            if ("3faa".equals(s1) && "5665".equals(s2)) {
                if ("736d".equals(s3)) {
                    //状态指令
                    if ("00".equals(dataArray[length - 4])) {
                        //待机指令
                        device.setDeviceStatus(2);
                    } else if ("01".equals(dataArray[length - 4])) {
                        //检测指令
                        device.setDeviceStatus(4);
                    } else if ("02".equals(dataArray[length - 4])) {
                        //无液报警
                        device.setDeviceStatus(3);
                    }
                } else if ("626c".equals(s3)) {
                    //电量指令
                    if ("00".equals(dataArray[length - 4])) {
                        //低电量
                        device.setQuantity(1);
                    } else if ("01".equals(dataArray[length - 4])) {
                        //中电量
                        device.setQuantity(2);
                    } else if ("02".equals(dataArray[length - 4])) {
                        //高电量
                        device.setQuantity(3);
                    }
                }
                // 修改设备状态
                int update = deviceMapper.update(device, new QueryWrapper<Device>().lambda().eq(Device::getDeviceSn, sn));
                log.info("状态修改是否成功! {}", update);

                /**
                 * 通过 websocket  后台向前台 发送更新的消息
                 */
                send(sn);
            } else {
                log.info("该指令格式错误:{}", payload);
            }
        }


    }


    @Resource
    public WebSocketEndPoint webSocketEndPoint;

    /**
     * 通过 websocket  后台向前台 发送更新的消息
     */
    public void send(String sn){
        String userId = deviceMapper.selectUser(sn);
        //更新的数据
        LargeDeviceVo largeDeviceVo = deviceMapper.selectLarge(sn);
        AddUpVo addUpVo =  deviceMapper.statisticCount();
        Map<String,Object> objects = new HashMap<>();
        objects.put("newData",largeDeviceVo);
        objects.put("num",addUpVo);

        webSocketEndPoint.sendMessageToOne(userId,JsonUtils.toJsonString(objects), null);
    }
}


总结

相比较于 v4版本的,访问接口的 认证方式不一样

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值