MQTT协议使用

dandan8个月前程序开发4642

服务端

因为使用的发布/订阅模式,似乎不需要自己写服务端,只要安装现成开源服务器即可,这里选了EMQX

#到官网,选择服务器版本,下载安装,已centos7为例:
#下载源码包
wget https://www.emqx.com/zh/downloads/broker/5.6.1/emqx-5.6.1-el7-amd64.tar.gz
#安装
mkdir -p emqx && tar -zxvf emqx-5.6.1-el7-amd64.tar.gz -C emqx
#运行
./emqx/bin/emqx start

安装启动完成后,默认通过ip:18083进入管理后台,默认账号admin密码public,可以通过管理后台查看客户端信息以及使用在线websocket客户端。


授权

需要防止别人恶性伪装成客户端来请求,需要增加授权机制,待续


客户端(go)

package main

import (
   "fmt"
   MQTT "github.com/eclipse/paho.mqtt.golang"
   "log"
   "os"
   "os/signal"
   "time"
)

func main() {
   client()
}
func client() {
   // 创建 MQTT 客户端配置
   opts := MQTT.NewClientOptions()
   //设置mqtt服务器地址
   opts.AddBroker("tcp://服务器地址:1883")
   //设置当前客户端的id
   opts.SetClientID("go-mqtt-client")
   opts.SetUsername("adminUser1") // 设置用户名
   //opts.SetPassword("your_password") // 设置密码,如果有的话
   //opts.SetCleanSession(true) //不接收之前的历史消息,实际未测试到应用场景,因为不会过滤掉遗嘱消息

   // 设置遗嘱消息,会在客户端断开时发送,1代表至少发送一次,false代表不保留,如果用true,那么其他设备一旦订阅这个主题,就会收到该消息
   //opts.SetWill("full/topic/LWT", "Admin Offline", 1, false)
   // 创建 MQTT 客户端实例
   client := MQTT.NewClient(opts)

   // 连接到 MQTT 服务器
   if token := client.Connect(); token.Wait() && token.Error() != nil {
      log.Fatal(token.Error())
   }

   // 设置消息接收回调函数
   messageHandler := func(client MQTT.Client, msg MQTT.Message) {
      fmt.Printf("【%s】:%s\n", msg.Topic(), msg.Payload())
   }

   // 订阅主题并设置消息处理函数,接收主题推送
   if token := client.Subscribe("elec/sys/#", 0, messageHandler); token.Wait() && token.Error() != nil {
      log.Fatal(token.Error())
   }

   time.Sleep(3 * time.Second)
   //发送消息,让电源开关打开
   sendMsg(client, "elec/sys/id1/cmnd/Power", "on")
   // 创建一个用于接收操作系统中断信号的通道
   c := make(chan os.Signal, 1)
   // 注册通道以接收操作系统中断信号(通常是 Ctrl+C)
   signal.Notify(c, os.Interrupt)
   // 阻塞程序,直到收到中断信号
   <-c
   // 中断信号已收到,执行清理工作并断开与 MQTT 服务器的连接
   client.Disconnect(250)
}

func sendMsg(client MQTT.Client, topic, msg string) {
   token := client.Publish(topic, 0, false, msg)
   token.Wait()
   fmt.Printf("发出给【%s】消息:%s\n", topic, msg)
}


客户端(设备)

买的是插座,所以:

1、先插到电源上;

2、长按开关,然后用手机在wifi列表里,找到他的名字,连接;

3、连接后会自动打开wifi选择,选择家里wif,输入账号密码,连接wifi成功

4、连接成功后,就可以用内网ip,直接访问设备后台

5、在后台首页Configure进去,然后选择Configure MQTT进去,然后配置服务器的ip、端口等各信息,可以参考官网,示例如下:

Host:服务器ip地址
Port:默认一般是1883
Client:应该是设备标识,目前不知道如何应用
User:用户名,后台会显示,并且如果要校验账号,则会用到
Password:对应密码,如果要校验账号时就必须要
Topic: 官网说时设备唯一主题,但实际测试设置啥都感觉没影响?比如我设置了id1
Full Topic:完整主题,假如我设置elec/sys/id1,那么设备就会忘这个主题推下面接收消息的案例,并且如果要往设备推,也要用这个

设置完毕后,等待他重启即可。然后去服务器后台,应该就能看到这个设备连接上了

发送消息说明

#假设设备上配置的完整主题是elec/sys/id1,那么开启电源就是
主题:elec/sys/id1/cmnd/Power 
内容:1或者on都可以

接收消息说明

#假设设备上配置的完整主题是elec/sys,并且在管理端的客户端上,订阅了elec/sys/#主题,则会收到下面消息
主题:elec/sys/id1/LWT 
内容:Online或Offline (目前不知道是不是通过遗嘱消息来实现,只要一订阅里吗会收到)

主题:elec/sys/id1/STATE
内容:应该是设备状态信息
示例:{"Time":"2024-05-11T15:42:43","Uptime":"0T00:05:09","UptimeSec":309,"Heap":25,"SleepMode":"Dynamic","Sleep":50,"LoadAvg":19,"MqttCount":1,"POWER":"OFF","Wif{"AP":1,"SSId":"TP-LINK_DANDAN","BSSId":"68:77:24:51:2B:26","Channel":6,"Mode":"11n","RSSI":84,"Signal":-58,"LinkCount":1,"Downtime":"0T00:00:03"}}

主题:elec/sys/id1/SENSOR
内容:应该也是插座一些信息,暂不知道含义
示例:{"Time":"2024-05-11T15:42:43","ENERGY":{"TotalStartTime":"2024-05-11T15:30:12","Total":0.000,"Yesterday":0.000,"Today":0.000,"Period":0,"Power":0,"Apparenter":0,"ReactivePower":0,"Factor":0.00,"Voltage":0,"Current":0.000}}

主题:elec/sys/id1/RESULT
内容:有电源变化,其他还未知
示例:{"POWER":"ON"}

主题:elec/sys/id1/POWER
内容:电源状态,不知道和上面这个差异在哪
示例:ON


目前困惑

设备发消息和收消息的主题前缀是一样的,那么管理端要接收消息,就得订阅通配主题elec/sys/# ,然后服务端控制电源就会往elec/sys/id1/cmnd/Power发,这导致服务端也收到这个消息了,这是本身mqtt设计如此,应用中自己忽略吗?还是怎么回事? 感觉额外在接收多余的信息了。


实际生产可能是通过规则引擎,在服务器端收到消息的时候,先进行过滤,服务端只收需要的信息,并且用比如kafka的架构,让消息先到kafka,然后再消费来处理业务,那这样发消息的客户端 和 收消息的业务处理端就分开了,未实践, 如果设备量不大,就这样写一个客户端自己处理似乎也能跑。

相关文章

wsl2安装docker+dify+xinference

1、wsl2安装ubuntu,这里指定版本安装一个新环境 wsl --install -d Ubuntu-22.042、安装完的ubuntu是在c盘的,放到其他...

golang环境安装(mac m1)

1、进官网https://www.gomirrors.org/下载tar格式的报,选arm64的2、在电脑新建一个目录,专门用于放go的项目3、将下载的包放到目录里,使用终端,进入该目录后,并进行解压...

mac m1 中go使用kafka

当前docker-comose:version: '3' services:   Etcd:     con...

通过frp进行内网穿透

因为ngrok会定义刷新域名,有点限制,如果没有服务器域名,用他合适,如果有自己的服务器、域名,则用frp:按照https://blog.csdn.net/mirage003/article/deta...

mac m1 pro 解决微信公众号本地调试问题(未成功)

最终未成功,买natapp先凑合用了,临时记录下nginx安装1、微信公众号后台,公众号设置,功能设置,网页授权域名,添加好该域名。(需要上传文件到根目录)2、natapp上购买vip隧道,9元/月;...

linux安装go环境

1、在 https://go.dev/dl/  下载linux的包2、上传到服务器,解压,比如放到/opt后,执行下命令,解压到当前目录得到go文件夹tar -xzf&n...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。