保命声明:笔者在校属于中低水平学生,代码能力有限,若行文中有错漏之处欢迎大家指出。

服务器安装MQTT服务端

[https://www.emqx.io/zh]
[https://www.emqx.io/docs/zh/v5.0/getting-started/getting-started.html#启动-emqx]

  • EMQX的调试客户端教程

[https://mqttx.app/zh/docs/get-started]

  • 使用EMQX的MQTT服务端
docker pull emqx/emqx:5.0.8
docker run -d --name emqx -p 84:1883 -p 85:8083 -p 86:8084 -p 87:8883 -p 88:18083 emqx/emqx:5.0.8

EMQX后台网页127.0.0.1:88
(版本:MQTT5.0)
EMQX 的 HTTP API 默认的访问用户名是 admin 密码是 public。 默认密码建议您立即修改。
[https://its401.com/article/qq_37949192/103998723]
开源版MQTT服务端不会自动将收到的消息存储数据库
需要另一台设备订阅消息,否则消息会被丢弃

ArduinoIDE

安装esp32库、PubSubClient库(Nick O'Leary)(用于MQTT)

原理

霍尔传感器

[]
开关型传感器(型号:3144)(传感器使用M44开关型霍尔传感器)
数字口D0输出二元信号(有磁场,没磁场)
模拟口输出磁场大小,但是精度较低

模块有2个输出:
1、AO,霍尔实时输出
2、DO,霍尔信号经过比较器调整之后输出
模块特点:
1、尺寸小,36mm X 16mm
2、有3mm的安装螺丝孔
3、可以使用3-5.5v直流电源供电
4、有霍尔实时输出信号
5、有通过比较器整理之后更加稳定的输出信号
6、比较器输出能力16mA
7、有电源指示灯
8、比较器输出有指示灯
没有磁铁输出为1,有磁铁输出为0

MQTT

MQTT 即 Message Queuing Telemetry Transport,中文名为消息队列遥测传输协议,是一种基于发布/订阅模式的"轻量级"通讯协议。其本质上也是构建于 TCP/IP 协议上的一种通信协议,其地位在 OSI 七层网络协议中和 HTTP 协议并列,同属应用层的网络通信协议。

MQTT 协议的最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。也正是因为 MQTT 协议是一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

MQTT 协议是基于客户端-服务器的消息发布/订阅传输协议,在整个通信过程中,有三个重要的角色,分别是发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务端,消息发布者可以同时是订阅者。

MQTT 中的 Broker 类似于一个中转站,位于消息发布者和订阅者之间。在 Broker 中,可以接受客户发布的应用信息,处理来自客户端的订阅和退订请求以及向订阅的客户转发应用程序消息。Broker 通常由一个应用程序或一台设备充当。

在 MQTT 中,传输的消息分为:主题(topic)和负载(payload)两部分:

1、Topic,可以理解为消息的类型,订阅者订阅(Subscribe)后,就会收到该主题的消息内容。

2、Payload,可以理解为消息的内容,是指订阅者具体要使用的内容。

esp01s添加物理开关_esp01s添加物理开关


esp01s添加物理开关_esp01s添加物理开关_02


MQTT与BLE虽然都有类似的「消息订阅」机制,但是BLE没有云端服务器中转,即无法远程控制。BLE设备可以通过蓝牙网关连接云端服务器达到远程控制的效果。[https://github.com/Hypfer/Cybele]

实现

使用的硬件

  1. 合宙esp32-c3核心板[https://wiki.luatos.com/chips/esp32c3/board.html#led]
  2. 霍尔传感器模块
  3. 强磁铁

功能描述

  1. 警告功能
    板载LED_D4:

    快速闪烁:等待WIFI连接

    慢速闪烁:连接上WIFI但未连接上服务器

    常亮:WIFI及服务器连接成功
    板载LED_D5:

    不亮:门窗关闭

    常亮:门窗开启
  2. MQTT上报
    每5s上报一次门窗状态

代码

记得修改代码里的WIFI名称和密码
sketch_sep30b.ino

/*
功能:门窗开关监测
MQTT 5.0
server:192.168.50.80:84
ESP32双核,WIFI一般在另一核心
*/
#include <WiFi.h>
//#include <Arduino.h>
#include <PubSubClient.h>
/**全局变量**/
#define LED_D4 12 //高电平有效
#define LED_D5 13 //高电平有效
#define SENSOR_HW 7//3144霍尔传感器
#define LED 4 //低电平有效
  //WIFI
const char* ssid = "你的WIFI";
const char* password = "你的WIFI密码";
String hostname = "esp32-c3-door";
WiFiClient espClient;
  //MQTT
const char *mqtt_broker = "192.168.50.80";
const char *topic = "door_1";
const char *mqtt_username = "emqx";
const char *mqtt_password = "public";
const int mqtt_port = 84;
PubSubClient client(espClient);
  //TIMER0
hw_timer_t *tim1 = NULL;
int tim1_IRQ_count = 0;
int hall=1;
/**结束全局变量**/
/**函数头部声明**/
void flash_led_slow();
void flash_led_fast();
void initTimer0();
void timer0Interrupt();
void initWiFi();
void sensor_check();
void initMQTT();
void IRAM_ATTR upload_data();
/**结束函数头部声明*/
//初始化
void setup() {
pinMode(LED_D5,OUTPUT);
pinMode(LED,OUTPUT);
pinMode(LED_D4,OUTPUT);
pinMode(SENSOR_HW,INPUT);
digitalWrite(LED_D5,HIGH);
delay(500);
digitalWrite(LED_D5,LOW);
initWiFi();
initMQTT();
initTimer0();
upload_data();
}
//主循环
void loop() {
  // put your main code here, to run repeatedly:
  sensor_check();
}
/**函数主体*/
//初始化wifi
void initWiFi() {
  /*
  WiFi.mode(WIFI_STA);
  WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
  WiFi.setHostname(hostname.c_str()); //define hostname
  //wifi_station_set_hostname( hostname.c_str() );
  */
  WiFi.begin(ssid, password);
  //Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    flash_led_fast();
  }
  //Serial.println(WiFi.localIP());
}
//定时器
void initTimer0(){
  //原型:hw_timer_t * timerBegin(uint8_t num,uint16_t divider,bool countUp)
  tim1 = timerBegin(0, 80, true);//定时(divider):T = 1 /(80MHZ / 80)= 1微秒
  //原型:void timerAttachInterrupt(hw_timer_t * timer,void(* fn)(void),bool edge)
  //timerAttachInterrupt(tim1, timer0Interrupt, true);
  timerAttachInterrupt(tim1,&upload_data,true);
  //原型:void timerAlarmWrite(hw_timer_t * timer,uint64_t alarm_value,bool autoreload)
  timerAlarmWrite(tim1, 5000000, true);//1秒为1,000,000微秒,这里定时5s
  //原型:void timerAlarmEnable(hw_timer_t * timer)
  timerAlarmEnable(tim1);
}
void timer0Interrupt(){
tim1_IRQ_count++;
timerAlarmEnabled(tim1);//定时器自动重装的,可能重复了
}
//闪灯
void flash_led_slow(){
digitalWrite(LED_D4,HIGH);
delay(2000);
digitalWrite(LED_D4,LOW);
delay(2000);
}
void flash_led_fast(){
digitalWrite(LED_D4,HIGH);
delay(500);
digitalWrite(LED_D4,LOW);
delay(500);
}
//传感器
void sensor_check(){
  hall=digitalRead(SENSOR_HW);
  if(hall==0){
    digitalWrite(LED_D5,HIGH);
    digitalWrite(LED,LOW);
  }
  else{
    digitalWrite(LED_D5,LOW);
    digitalWrite(LED,HIGH);
  }
}
//传感器定时上报数据
void IRAM_ATTR upload_data(){
  int _t=digitalRead(SENSOR_HW);
  if(_t==0){//开门
  client.publish(topic,"关门");
  }
  if(_t==1){//关门
  client.publish(topic,"开门");
  }
}
//初始化MQTT连接
void initMQTT(){
  client.setServer(mqtt_broker, mqtt_port);
 // client.setCallback(callback);
  while (!client.connected()) {
    String client_id = "esp32-client-";
    client_id += String(WiFi.macAddress());
   // Serial.printf("The client %s connects to the public mqtt broker\n", client_id.c_str());
    if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
        //Serial.println("Public emqx mqtt broker connected");
    } else {
        //Serial.print("failed with state ");
        //Serial.print(client.state());
    }
    flash_led_slow();
}
}

效果

esp01s添加物理开关_#define_03


esp01s添加物理开关_esp01s添加物理开关_04