基于ESP32的远程开关灯控制(ESP32+舵机+Android+物联网云平台)

devtools/2025/2/11 14:42:48/

目录

  • 材料+环境准备
    • 物理材料
    • 软件环境
  • 物联网平台配置(MQTT)
    • MQTT
    • 阿里云平台配置
      • 创建产品
      • 添加设备
      • 自定义topic
  • esp32配置
    • 接线
    • 代码
  • Android部分和云平台数据流转

前言:出租屋、宿舍网上关灯问题,计划弄一个智能开关以及带一点安防能力,如检测有人进入之类的,同时也是回顾一下以前掌握的知识。

材料+环境准备

本身这个东西不难做,网上也有了很多的实现案例,没什么技术难度,但是有一定的实用效果。
本设计分为三个部分:ESP32(硬件)、Android、阿里云

物理材料

esp32开发板:控制核心、网络连接
舵机(SG90-180°):用于控制拨动开关实现开关灯
杜邦线:连接模块或者进行跳线接线
供电部分:考虑供电部分的话,需要锂电池、充放电模块、电烙铁等焊接工具。
扩展:超声波模块,用于检测是否有人进入,或者实现夜间回家自动开灯等。

软件环境

esp32 arduino开发环境,需要设置首选项,json、下载esp32开发板的包(耗时长,可能失败),网上有一些离线安装的方法教程可以参考。
esp32 esp-idf框架,这个也是一个esp32的开发环境,可以在vscode上集成,听说用起来很方便,和arduino二选一即可,我目前用的arduino,配置好了esp-idf框架还未使用(感觉编译要太长的时间了。。。。)
android studio:用于开发android软件,方便调试,自己开发具有更高的扩展性,方便连接到云平台,这个需要一定的基础,最好以前弄过,不然搭环境下软件也挺费时间。
阿里云:主要也是为了实现无距离限制控制,这就是上云的好处,此外也可以实现,如果不在家,有人进了房子配合超声波或者激光实现提醒入侵检测的功能。此外也许也可以通过其他的物联网平台和对应的app实现远程控制,比如电灯科技还可以加入米家,实现小爱语言远程控制,但是相对而言可扩展性小。

物联网平台配置(MQTT)

首先要介绍云平台是因为其他两个部分都需要连接到云平台,所以这里的配置有限,另外就是介绍mqtt协议进行介绍,方便理解后续代码的含义。

MQTT

八股文我就不说了,直接说大概实现的原理和通讯的过程。
条件:设备联网可以使用mqtt协议、云平台(中间做消息流转)
云平台首先要创建产品、创建设备,产品可以理解为一个类,设备是实现的子类,这些子类可以有一些共同的特性,这是产品里面定义的。一个设备就是对应实际的一个物理设备,创建好设备后,会有对应的密码、设备名称、ID之类的一些标志,用来将你的设备连接到云平台。这应该就是mqtt协议中规定好的。
MQTT是一种基于发布/订阅(publish/subscribe)模式的“轻量级”通讯协议。发布就是指发布消息,你发布消息给云平台,或者云平台发布给你。订阅就是你订阅某一个主题(topic),这样云平台就可以通过这个主题来给你发布消息。
消息流转:设备和云平台可以通过订阅和发布的方式进行消息传递,但是设备和设备之间无法直接进行通讯,需要通过云平台来进行中间消息转发。这个是通过云平台实现的,云平台设置即可,无需代码实现。

阿里云平台配置

本次设计是通过阿里云物联网平台实现相应的功能。
阿里云物联网平台
注册登录,阿里云物联网平台提供免费的公共实例可以试用。

创建产品

产品创建

添加设备

然后为对应产品添加设备,需要添加两个设备,一个是esp32的,一个是手机app的。
在这里插入图片描述
创建好设备后可以查看设备,里面有相关的连接信息。
mqtt连接信息
这些信息都需要在后续中使用,届时进行查看复制进入对应代码区即可。

自定义topic

注:产品可以设置物理模型,设置一些共有属性,这样物联网平台也可以进行控制和查看对应的属性,设置好物理模型后,会有专门对应的topic进行发送相关属性的消息,但同样也包含了一些其他无关信息,为了方便我可以可以自定义topic,这些操作都需要在产品中区定义实现。
定义topic类可以自己命名topic,并选择类型,发布还是订阅,或者两个都选,订阅的话表示这个主题是用来订阅的,也就是设备订阅了这个主题后,可以从云台中看到,并通过这个订阅发布消息。
发布的主题指的就是设备用来发布消息的,将消息传递至云平台的topic。
如果不需要向云平台发布消息,可以不进行定义,产品中需要手机向云平台发布开灯消息,所以需要进行定义。
我定义了两个主题一个是舵机的,一个是超声波,主要是想实现两个功能,都是基于发布和订阅的,这有利有弊,比较方便吧。
自定义topic
区别可以从下面的例子中看出来
我的设备定义了三个topic,分别是物理模型,自带的一个属性设置的topic,两个自定义topic
在这里插入图片描述
产品物理模型自带的topic
默认属性主题
可以看到自带的主题的操作权限,只有订阅,也就是设备用来订阅,无法进行发布,这样在设备列表中订阅的topic中无法实现发布消息功能,而另外两个自定义主题由于设置了发布和订阅,所以订阅后,同时也可以进行消息发布。

本节的主要目的创建产品,创建对应的自定义主题,创建两个设备获取连接信息,用于设备进行mqtt通讯连接。

esp32配置

本节主要介绍esp32的配置和物理设备的接线。

接线

接线
首先看接线,由于用到超声波,需要的也是5v的电压供电,但是开发板只有一个5V口,此外还要和充放电模块接线,所以这里肯定需要将几根线剪开连接起来,并用电工胶带绑好。
如果你只有一个就直接用杜邦线就可以,但是考虑供电也需要接线,或者找一个带usb口的充放电模块,这样直接用usb供电给开发板也可以。
如果自行设计PCB自然就会更方便,初步测试时就没有打板。

代码

现阶段,代码非常简单,因为有很多的封装库实现,所以控制代码调用函数就可以,设置都不用去管什么pwm控制,设置占空比什么什么的,非常方便,esp32和esp8266这些arduino的都是一样的,确实是加快了开发进程。
控制代码非常简单,主要就是上云,连接到阿里云了。
以下就是完整代码
主要包含功能:
ESP32连接wifi
初始化舵机(控制信号线),控制舵机(设置角度)
超声波测距,并自动开关灯(根据时间) getDistance()
上报(到云)人员经过超声波检测的时间,可以进行记录查看到有人进出房间的时间
(超声波这部分代码注销了,原因有很多,一个是不便调试,另外超声波的布置位置很不方便,也容易导致误触,线长的问题,另外就是房间的问题,不便部署,激光模块效果更优)
阿里云mqtt通讯连接的代码,回调处理代码,就是接收到云平台的订阅消息时做出的逻辑处理
aliyun_callback()
还有连接和订阅操作,这些都比较简单调用函数即可,这里的回调中实现了两种方式,一种是基于产品的物理模型提供的topic进行订阅和操作,一个是自定义的进行操作,自定义的topic相对比较简单。

#include <WiFi.h>
#include <ESP32Servo.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>#include <NTPClient.h>
#include <WiFiUdp.h>
#include <time.h> // 用于时间处理// 定义 NTP 客户端
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 8 * 3600, 60000); 
// 使用 pool.ntp.org 服务器,时区偏移为 8 小时(东八区)// WiFi配置
const char* ssid = "*****";//wifi名称
const char* password = "******";//wifi密码// 阿里云物联网平台配置
const char* mqtt_server = ""; // 替换为你的阿里云IoT endpoint
const char* mqtt_username = ""; // 替换为你的设备名称和产品Key
const char* mqtt_password = ""; // 替换为你的设备密钥
const char* mqtt_client_id = ""; // 替换为你的客户端ID
// esp32_601
// MQTT主题
const char* servo_topic = ""; // 替换为你的舵机控制主题
const char* person_detected_topic = ""; // 替换为你的人员检测主题WiFiClient espClient;               //创建网络连接客户端
PubSubClient mqttClient(espClient); //通过网络客户端连接创建mqtt连接客户端// 舵机引脚
const int servoPin = 27;
Servo myServo;//调试后的固定开关等角度值
const int light_off = 112;
const int light_on = 72;
// 这两个值需要自己进行调试,此外我设置的是90°的时候舵机是横向的
// 超声波引脚
const int trigPin = 25;
const int echoPin = 26;// led引脚
const int led0Pin = 2;
//板载led可以用来调试观察现象
// 初始化LED
void setupLED() {pinMode(led0Pin, OUTPUT);digitalWrite(led0Pin, LOW);  // 初始状态为关闭
}// 初始化舵机
void setupServo() {myServo.attach(servoPin); // 将舵机连接到指定引脚myServo.write(90);        // 初始角度设为90度
}// 初始化超声波传感器
void setupUltrasonic() {pinMode(trigPin, OUTPUT);pinMode(echoPin, INPUT);
}// 超声波测距函数
float getDistance() {digitalWrite(trigPin, LOW);delayMicroseconds(2);digitalWrite(trigPin, HIGH);delayMicroseconds(10);digitalWrite(trigPin, LOW);long duration = pulseIn(echoPin, HIGH); // 读取回波时间float distance = duration * 0.034 / 2;  // 计算距离(单位:厘米)return distance;
}//初始化连接wifi
void setup_wifi() {delay(10);Serial.println();Serial.print("Connecting to ");Serial.println(ssid);WiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(500);Serial.print(".");}Serial.println("");Serial.println("WiFi connected");Serial.print("IP address: ");Serial.println(WiFi.localIP());
}void aliyun_callback(char* topic, byte* payload, unsigned int length) {Serial.print("Message arrived [");Serial.print(topic);Serial.print("] ");for (int i = 0; i < length; i++) {Serial.print((char)payload[i]);}Serial.println();//上面是打印接收到的订阅信息,调试用// 处理舵机控制消息 --- 物理模型版本// if(strcmp(topic, "/sys/${}/${设备名}/thing/service/property/set")== 0){//   // 将 payload 转换为字符串//   char message[length + 1];//   memcpy(message, payload, length);//   message[length] = '\0'; // 添加字符串结束符//   Serial.println(message);//   // 解析 JSON 数据//   StaticJsonDocument<200> doc; // 根据 JSON 数据大小调整缓冲区大小//   DeserializationError error = deserializeJson(doc, message);//   // 检查解析是否成功//   if (error) {//       Serial.print("Failed to parse JSON: ");//       Serial.println(error.c_str());//       return;//   }//   // {"method":"thing.service.property.set","id":"1107300794","params":{"servo":1},"version":"1.0.0"}   这是物理模型消息模板,真正需要的数据就是{"servo":1}//   // 提取 JSON 字段//   int servo_angle = doc["params"]["servo"]; // 获取 command 字段//   // int angle = doc["angle"];             // 获取 angle 字段//   // int duration = doc["duration"];       // 获取 duration 字段//   myServo.write(servo_angle);//设置角度// }// 处理舵机控制消息  自定义模型,自己定义主题topic和解析,比较简单方便,不需要多余的处理if (strcmp(topic, servo_topic) == 0) {//获取消息  获取设置值// 将字节数组转换为字符串char payloadStr[length + 1];  // 加1是为了加上字符串结束符 '\0'memcpy(payloadStr, payload, length);payloadStr[length] = '\0';  // 确保字符串结束// 假设 payloadStr 是一个整数的文本格式  消息体内容只有舵机的设置参数为纯数字int intValue = atoi(payloadStr);Serial.print("Received integer value: ");Serial.println(intValue);if(intValue>=0 && intValue<=180){myServo.write(intValue); // 控制舵机转动到90度delay(500);myServo.write(90);//设置完后自动调整为90,这样不会卡住手动拨动灯开关}}
}void reconnect() {while (!mqttClient.connected()) {Serial.print("Attempting MQTT connection...");if (mqttClient.connect(mqtt_client_id, mqtt_username, mqtt_password)) {Serial.println("connected");mqttClient.subscribe(servo_topic);mqttClient.subscribe(person_detected_topic);//连接成功后订阅主题,这样才能接收到消息} else {Serial.print("failed, rc=");Serial.print(mqttClient.state());Serial.println(" try again in 5 seconds");delay(5000);}}
}
void setup() {Serial.begin(115200);setupLED();setupServo();          // 初始化舵机setupUltrasonic();     // 初始化超声波传感器setup_wifi();         //初始化连接wifi// 初始化 NTP 客户端timeClient.begin();timeClient.update(); // 获取时间//mqtt 初始化配置mqttClient.setServer(mqtt_server, 1883);mqttClient.setCallback(aliyun_callback);
}void loop() {if (!mqttClient.connected()) {reconnect();}mqttClient.loop();// 主循环中可以添加其他逻辑// 固件升级  先不考虑// 检测到有人进入 --两种情况,无人,报警// 检测有人进入,上报时间,获取时间并上报,同时根据时间判断是否开灯// float distance = 0;// distance = getDistance();未进行测量似乎结果为不确定的?不为0,不对可能为0// Serial.println("当前距离: " + String(distance));// if(distance < 50 && distance > 0){ //超声波//   //有人经过//   //获取时间//   // 更新 NTP 时间//   timeClient.update();//   // 获取当前小时数(24小时制)//   int currentHour = timeClient.getHours();//   if(currentHour >= 18 || currentHour < 7) { // 如果是18点(即下午6点)以后或早上6点之前//     myServo.write(light_on);//     Serial.println("It's evening or night, turning the light on.");//     delay(500);//     myServo.write(90);//   } else {//     // digitalWrite(ledPin, LOW); // 关灯//     myServo.write(light_off);//     Serial.println("It's daytime, turning the light off.");//     delay(500);//     myServo.write(90);//   }//   //上报消息//   unsigned long epochTime = timeClient.getEpochTime();//   // 将 Unix 时间戳转换为格式化字符串时间//   time_t rawTime = (time_t)epochTime;//   struct tm *ptm = gmtime(&rawTime);//   char timeStr[30];//   strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", ptm);  //   // 打印完整的时间字符串//   Serial.print("Current date and time: ");//   Serial.println(timeStr);//   // 发布人员检测消息//   String message = "Person detected at " + String(timeStr);//   mqttClient.publish(person_detected_topic, message.c_str());// }delay(200); // 延时20m秒
}

代码中都有详细的注释,不懂可以评论区留言。

// 阿里云物联网平台配置
const char* mqtt_server = ""; // 替换为你的阿里云IoT endpoint
const char* mqtt_username = ""; // 替换为你的设备名称和产品Key
const char* mqtt_password = ""; // 替换为你的设备密钥
const char* mqtt_client_id = ""; // 替换为你的客户端ID
// esp32_601
// MQTT主题
const char* servo_topic = ""; // 替换为你的舵机控制主题
const char* person_detected_topic = ""; // 替换为你的人员检测主题

这些就是上一节提到的创建设备时,可以查阅的相关连接参数,以及创建产品的时候自定义的消息topic

注意、踩坑: 这里有一个需要注意的地方就是主题这里,从云平台复制出来的主题,往往包含${deviceName}这个部分,这里需要替换为你对应的设备名称,记住是设备名称别复制错了。

/*********/${deviceName}/user/person_detect
假如你的设备名称是esp32
替换为
/*********/esp32/user/person_detect

另外回调函数中的处理

  // 处理舵机控制消息  自定义模型,自己定义主题topic和解析,比较简单方便,不需要多余的处理if (strcmp(topic, servo_topic) == 0) {

这里就是判断,到来的消息是哪个主题的,是否为舵机控制主题的,是才进入舵机主题消息的解析,因为发布的消息可能有别的主题的消息,不判断直接解析可能会出错,不同的topic的解析也不一样,因为数据内容可能不一样。

Android部分和云平台数据流转

剩下的部分就下一篇再介绍吧,码字不易,点个赞吧,有什么问题欢迎评论区留言。
关注我分享更多的实用小设计。💕


http://www.ppmy.cn/devtools/157954.html

相关文章

Git stash 暂存你的更改(隐藏存储)

一、Git Stash 概述 在开发的时候经常会遇到切换分支时需要你存储当前的更改&#xff0c;如果你暂时不想应用当前更改也不想放弃更改&#xff0c;那么你可以使用 git stash先将其隐藏存储&#xff0c;这样代码就会变成未修改的状态&#xff0c;等解决其他问题后&#xff0c;在…

爬虫案例-爬取某度文档利用飞桨ch_pp-ocrv3模型提高对图片的识别

文章目录 1.安装VC_redist.x64库和开启开发者模式2.第三方库的安装和paddlehub安装3、爬取某度文档的代码4、效果 1.安装VC_redist.x64库和开启开发者模式 下载VC_redist.x64: 点击这里 在开发者选项&#xff0c;打开开发人员模式 2.第三方库的安装和paddlehub安装 #以下是安装…

Android studio 创建aar包给Unity使用

1、aar 是什么&#xff1f; 和 Jar有什么区别 aar 和 jar包 都是压缩包&#xff0c;可以使用压缩软件打开 jar包 用于封装 Java 类及其相关资源 aar 文件是专门为 Android 平台设计的 &#xff0c;可以包含Android的专有内容&#xff0c;比如AndroidManifest.xml 文件 &#…

中国通信企业协会通信网络安全服务能力评定安全设计与集成服务能力评定三级要求准则...

安全设计与集成服务能力三级是通信网络安全服务能力评定安全设计与集成服务能力评定的最高等级&#xff0c;所需的要求也会更加严苛&#xff0c;不仅要满足安全设计与集成服务二级能力要求的所有条款&#xff0c;还要满足以下要求&#xff1a; 规模与资产要求 1)单位正规编制员…

哪吒闹海!SCI算法+分解组合+四模型原创对比首发!SGMD-FATA-Transformer-LSTM多变量时序预测

哪吒闹海&#xff01;SCI算法分解组合四模型原创对比首发&#xff01;SGMD-FATA-Transformer-LSTM多变量时序预测 目录 哪吒闹海&#xff01;SCI算法分解组合四模型原创对比首发&#xff01;SGMD-FATA-Transformer-LSTM多变量时序预测效果一览基本介绍程序设计参考资料 效果一览…

【Elasticsearch】集群配置性能优化

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

Spring Boot从入门到精通:核心知识点+实战指南

目录 一、Spring Boot 是什么&#xff1f;为什么它如此流行&#xff1f; 二、快速创建你的第一个Spring Boot应用 2.1 使用Spring Initializr生成项目 2.2 核心代码示例 三、深度解析Spring Boot核心机制 3.1 自动配置原理揭秘 3.2 自定义Starter实战 四、生产环境必备…

【CubeMX+STM32】SD卡 文件系统读写 FatFs+SDIO+DMA

本篇&#xff0c;将使用CubeMXKeil&#xff0c;创建一个SD卡的 FatFSSDIODMA 文件系统读写工程。 目录 一、简述 二、CubeMX 配置 FatFSSDIO DMA 三、Keil 编辑代码 四、实验效果 实现效果&#xff0c;如下图&#xff1a; 一、简述 上两篇&#xff0c;已循序渐进讲解了SD、…