android通过mqtt协议 与esp8266 通讯,通过发布和订阅消息,控制esp8266...
android通过mqtt协议 与esp8266 通讯,通过发布和订阅消息,控制esp8266小灯的开关,基于此可以实现物联网的其他功能的实现提供arduino 和android手机app源码不含esp8266模块Android和ESP8266玩MQTT绝对是物联网入门的经典项目,今天我就把自己踩过坑又简化后的方案分享给大家——用Android手机APP发消息,ESP8266接收到直接控制小灯开关
android通过mqtt协议 与esp8266 通讯,通过发布和订阅消息,控制esp8266小灯的开关,基于此可以实现物联网的其他功能的实现 提供arduino 和android手机app源码 不含esp8266模块
Android和ESP8266玩MQTT绝对是物联网入门的经典项目,今天我就把自己踩过坑又简化后的方案分享给大家——用Android手机APP发消息,ESP8266接收到直接控制小灯开关,举一反三的话,家里的风扇、窗帘、温湿度监测联动都能靠这套逻辑堆出来。

android通过mqtt协议 与esp8266 通讯,通过发布和订阅消息,控制esp8266小灯的开关,基于此可以实现物联网的其他功能的实现 提供arduino 和android手机app源码 不含esp8266模块
首先说MQTT服务器,我直接用的免费公共MQTT broker:EMQX。地址是broker.emqx.io,端口1883(TCP协议),1884是WebSocket,今天主要讲TCP的。
1. Arduino端(ESP8266)
硬件连接
这里虽然不含ESP8266模块,但我简单提下 wiring 逻辑:
- LED长脚(阳极)→ ESP8266的D1引脚(对应GPIO5)
- LED短脚(阴极)→ 串联一个220Ω电阻 → ESP8266的GND引脚
- ESP8266接5V或者3.3V电源,GND接GND,CH_PD接VCC或者拉高。
代码实现
先安装Arduino的ESP8266开发板支持库和PubSubClient库(MQTT通信库)。
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// WiFi配置
const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";
// MQTT配置
const char* mqtt_server = "broker.emqx.io";
const int mqtt_port = 1883;
const char* client_id = "ESP8266_LED_01"; // 每个设备ID要唯一,随便改
const char* mqtt_topic_sub = "iot/esp8266/led01/control"; // 订阅的控制主题
const char* mqtt_topic_pub = "iot/esp8266/led01/status"; // 发布的状态主题
// WiFi和MQTT客户端
WiFiClient espClient;
PubSubClient client(espClient);
// LED引脚
const int ledPin = D1;
// WiFi连接状态
unsigned long lastReconnectAttempt = 0;
// 连接WiFi函数
void setupWiFi() {
delay(10);
Serial.println("Connecting to " + String(ssid));
WiFi.begin(ssid, password);
// 一直等到连接成功
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected! IP address: " + WiFi.localIP().toString());
}
// 连接MQTT服务器函数
void setupMQTT() {
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
// MQTT消息回调函数(收到消息后自动触发)
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Received message [");
Serial.print(topic);
Serial.print("]: ");
String message;
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println(message);
// 解析控制命令
if (message == "ON") {
digitalWrite(ledPin, HIGH);
// 发送状态到服务器,方便APP显示
client.publish(mqtt_topic_pub, "ON");
Serial.println("LED turned on");
} else if (message == "OFF") {
digitalWrite(ledPin, LOW);
client.publish(mqtt_topic_pub, "OFF");
Serial.println("LED turned off");
}
}
// 重连MQTT函数(网络波动时自动重连)
boolean reconnect() {
if (client.connect(client_id)) {
Serial.println("MQTT connected!");
client.subscribe(mqtt_topic_sub); // 连接成功后立即订阅主题
} else {
Serial.print("Failed to connect, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
}
return client.connected();
}
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
setupWiFi();
setupMQTT();
}
void loop() {
// 检查MQTT连接状态
if (!client.connected()) {
unsigned long now = millis();
if (now - lastReconnectAttempt > 5000) {
lastReconnectAttempt = now;
if (reconnect()) {
lastReconnectAttempt = 0;
}
}
} else {
client.loop(); // 处理MQTT消息
}
}
代码分析
- WiFi连接与重连:
setupWiFi()是一次性连接,loop()里的重连逻辑是处理MQTT的,因为公共broker偶尔会断。 - 消息回调:重点在
callback()函数,收到iot/esp8266/led01/control的主题消息后,先转成String,再判断是ON还是OFF,同时发状态回iot/esp8266/led01/status。 - PubSubClient库:这个库非常轻量,很适合资源少的ESP8266,
client.setCallback()绑定处理函数,client.subscribe()和client.publish()是核心API。
2. Android端
依赖库
Android Studio里的build.gradle(Module: app)添加依赖:
dependencies {
// MQTT通信库
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
// UI库
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
}
权限配置
AndroidManifest.xml里添加:
<!-- 网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 访问网络状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 后台服务权限(MQTT服务需要) -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
...
<!-- 声明Paho服务 -->
<service android:name="org.eclipse.paho.android.service.MqttService" />
...
</application>
代码实现
MainActivity.java
package com.example.mqttledcontrol;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.CompoundButton;
import android.widget.Toast;
import android.widget.ToggleButton;
import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.io.UnsupportedEncodingException;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final String MQTT_BROKER = "tcp://broker.emqx.io:1883";
private static final String MQTT_CLIENT_ID = "Android_LED_Control_" + UUID.randomUUID().toString().substring(0, 8); // 唯一ID
private static final String MQTT_TOPIC_CONTROL = "iot/esp8266/led01/control";
private static final String MQTT_TOPIC_STATUS = "iot/esp8266/led01/status";
private MqttAndroidClient mqttAndroidClient;
private ToggleButton tbLed;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tbLed = findViewById(R.id.tb_led);
// 请求网络权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.INTERNET}, 1);
}
// 初始化MQTT客户端
initMqttClient();
// 连接MQTT服务器
connectMqtt();
// 绑定按钮监听
tbLed.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (mqttAndroidClient.isConnected()) {
publishMessage(MQTT_TOPIC_CONTROL, isChecked ? "ON" : "OFF");
} else {
Toast.makeText(this, "MQTT未连接!", Toast.LENGTH_SHORT).show();
tbLed.setChecked(!isChecked);
}
});
}
private void initMqttClient() {
mqttAndroidClient = new MqttAndroidClient(getApplicationContext(), MQTT_BROKER, MQTT_CLIENT_ID);
mqttAndroidClient.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean reconnect, String serverURI) {
Log.d(TAG, "MQTT连接成功!重连:" + reconnect);
Toast.makeText(getApplicationContext(), "MQTT连接成功!", Toast.LENGTH_SHORT).show();
// 连接成功后订阅状态主题
subscribeTopic(MQTT_TOPIC_STATUS);
}
@Override
public void connectionLost(Throwable cause) {
Log.e(TAG, "MQTT连接断开:" + cause.getMessage());
Toast.makeText(getApplicationContext(), "MQTT连接断开!", Toast.LENGTH_SHORT).show();
}
@Override
public void messageArrived(String topic, MqttMessage message) {
Log.d(TAG, "收到消息 [ " + topic + " ] : " + new String(message.getPayload()));
// 收到ESP8266的状态消息,同步按钮状态
if (topic.equals(MQTT_TOPIC_STATUS)) {
String status = new String(message.getPayload());
runOnUiThread(() -> tbLed.setChecked(status.equals("ON")));
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
Log.d(TAG, "消息发送成功!Token: " + token.hashCode());
}
});
}
private void connectMqtt() {
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true); // 每次连接都是新会话
options.setAutomaticReconnect(true); // 自动重连
options.setKeepAliveInterval(60); // 心跳间隔(秒)
options.setConnectionTimeout(30); // 连接超时(秒)
try {
mqttAndroidClient.connect(options, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d(TAG, "MQTT连接请求成功!");
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e(TAG, "MQTT连接请求失败:" + exception.getMessage());
Toast.makeText(getApplicationContext(), "连接失败:" + exception.getMessage(), Toast.LENGTH_SHORT).show();
}
});
} catch (MqttException e) {
e.printStackTrace();
}
}
private void publishMessage(String topic, String message) {
try {
byte[] payload = message.getBytes("UTF-8");
MqttMessage mqttMessage = new MqttMessage(payload);
mqttMessage.setQos(0); // QoS等级0:最多一次,不保证送达,适合小灯控制这种实时性不高的场景
mqttMessage.setRetained(false); // 不保留消息
mqttAndroidClient.publish(topic, mqttMessage);
} catch (UnsupportedEncodingException | MqttException e) {
e.printStackTrace();
}
}
private void subscribeTopic(String topic) {
try {
mqttAndroidClient.subscribe(topic, 0, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d(TAG, "订阅成功:" + topic);
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e(TAG, "订阅失败:" + exception.getMessage());
}
});
} catch (MqttException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mqttAndroidClient.isConnected()) {
try {
mqttAndroidClient.disconnect();
} catch (MqttException e) {
e.printStackTrace();
}
}
}
}
布局文件(activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ESP8266小灯控制"
android:textSize="24sp"
android:layout_marginBottom="30dp"/>
<ToggleButton
android:id="@+id/tb_led"
android:layout_width="200dp"
android:layout_height="100dp"
android:textOn="小灯 ON"
android:textOff="小灯 OFF"
android:textSize="20sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tips: 连接MQTT服务器中..."
android:textSize="14sp"
android:textColor="#999999"
android:layout_marginTop="20dp"/>
</LinearLayout>
代码分析
- MqttAndroidClient:这是Paho的Android版本,比纯Java的v3库多了Service支持,更适合后台运行。
- MQTT连接:
connectMqtt()里的MqttConnectOptions设置了自动重连、清洁会话、心跳间隔这些参数,公共broker推荐自动重连。 - 消息双向同步:按钮按下发控制消息,收到状态消息后同步按钮状态(避免APP杀掉重开后状态不一致),这里要注意
runOnUiThread(),因为MQTT消息是在后台线程处理的,更新UI必须在主线程。 - 权限请求:Android 6.0+需要动态请求INTERNET权限,虽然一般默认给,但加上保险。
3. 测试步骤
- 烧录Arduino代码到ESP8266。
- 安装Android APK到手机。
- 手机和ESP8266连同一WiFi。
- 打开APP,等提示MQTT连接成功。
- 按下ToggleButton,ESP8266的小灯就亮灭啦!
4. 功能扩展思路
既然基础逻辑通了,其他物联网功能就是:
- 增加传感器:比如DHT11测温湿度,ESP8266定时publish到主题,APP订阅显示。
- 增加控制设备:比如继电器控制风扇,APP发1和0到主题。
- 自定义主题:把主题改成
iot/你的房间/你的设备/控制,避免和别人冲突。 - 本地MQTT服务器:如果公共broker不稳定,可以用树莓派搭个本地的EMQX或Mosquitto。
如果有问题,欢迎留言!

更多推荐



所有评论(0)