项目介绍
项目名称
基于ESP-01S的智能电脑控制器
项目背景
随着科技的不断进步,物联网(IoT)技术正在迅速改变我们的生活和工作方式。为了利用这一趋势,我开发了基于ESP-01S的智能电脑控制器,旨在通过连接设备和数据,实现更智能、更方便的生活方式。
项目目标
基于ESP-01S的智能电脑控制器的主要目标是:
- 远程控制电脑开关
- 本地语音控制电脑开关
- 定时控制电脑开关
项目架构
设备层:
使用ESP-01S模块、继电器模块以及电源
网络层:
- 通过WiFi连接阿里云服务器以及本地的UDP通信
数据层:
- 本地存储数据并定期上传阿里云服务器
应用层:
- 基于阿里云平台的应用开发工具,可通过网页端、手机端、小程序端(未实装)的程序来进行远程控制,也可通过阿里云物联网平台对数据进行记录及修改。
主要功能
远程控制:
- 用户可以通过手机或电脑远程控制设备。
语音控制:
- 用户可以通过配合其他设备在局域网范围内实现语音控制
技术实现
硬件:
- 使用ESP-01S作为微控制器,控制继电器通断来实现功能
软件:
- 使用C语言基于Arduino IDE进行开发
- 使用MQTT、 HTTP/HTTPS、UDP等通信协议
应用场景
智能家居:
实现家庭设备的智能化管理,通过继电器可以拓展到控制其余用电设备
项目进展
已完成硬件设计以及部分软件开发
- 已实现通过阿里云物联网平台远程控制
- 配合其他设备实现本地语音控制
软件设计
- 本设计需配合基于ESP32的智能家居助手设计与实现 使用
通信流程
- ESP-01S通过广播IP(255,255,255,255)向设定的discoveryPort 端口发送"DISCOVER"字符串
- ESP32监听discoveryPort 端口 当收到“DISCOVER”字符串信息时 向该来源发送ESP32的IP以及通信端口号
数据格式:ESP32_IP:192.168.31.88,PORT:5088 - ESP-01S 收到IP以及端口号后解析并存储 并监听收到的端口号
- ESP-01S 向收到的IP以及端口号发送连接请求 格式为:“Relay:Link” (设备名称:Link )发送后进入延时等待收到"OK"信息
- ESP32监听PORT 当收到Link信息时 记录设备名称、发送方IP ,连接设备数 + 1 并回复"OK"
- ESP-01S 收到"OK"后 将 esp32Found标志位置为true 进入等待信息接收模式
代码部分
- 前排提醒:此代码需要配合 基于ESP32的智能家居助手设计与实现 共同使用!!!
// 引入 wifi 模块,并实例化,不同的芯片这里的依赖可能不同
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
static WiFiClient espClient;
// 引入阿里云 IoT SDK
#include <AliyunIoTSDK.h>
// 设置产品和设备的信息,从阿里云设备信息里查看
#define PRODUCT_KEY "xxxxxxxx"
#define DEVICE_NAME "xxxxxxxx"
#define DEVICE_SECRET "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
#define REGION_ID "cn-shanghai"
// 设置 wifi 信息
#define WIFI_SSID "xxxxxxxx"
#define WIFI_PASSWD "xxxxxxxx"
int udpPort = 5088;
const int discoveryPort = 5089;
WiFiUDP udp;
char incomingPacket[255];
IPAddress esp32Ip;
bool esp32Found = false;
static bool RelayState1 = false;
const int Relay = 0;//定义继电器使用IO
void setup()
{
Serial.begin(115200);
pinMode(Relay, OUTPUT); // 将GPIO0引脚设置为输出模式
// 初始化 wifi
wifiInit(WIFI_SSID, WIFI_PASSWD);
// 初始化 iot,需传入 wifi 的 client,和设备产品信息
AliyunIoTSDK::begin(espClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET, REGION_ID);
// 绑定一个设备属性回调,当远程修改此属性,会触发 powerCallback
// ComputerControl是在设备产品中定义的物联网模型的 id
AliyunIoTSDK::bindData("ComputerControl", powerCallback);
// 发送一个数据到云平台,ComputerControl是在设备产品中定义的物联网模型的 id
AliyunIoTSDK::send("ComputerControl", 1);
//继电器默认状态为关 即高
digitalWrite(Relay,HIGH);
udp.begin(discoveryPort);
}
void loop()
{
static bool flag1 = false;
if (!esp32Found) {
// 发送发现请求
udp.beginPacket(IPAddress(255, 255, 255, 255), discoveryPort);
udp.write("DISCOVER");
udp.endPacket();
Serial.println("Discovery packet sent");
// 等待响应
int packetSize = udp.parsePacket();
if (packetSize) {
int len = udp.read(incomingPacket, 255);
if (len > 0) {
incomingPacket[len] = 0;
}
Serial.printf("Received packet of size %d from %s:%d\n", packetSize, udp.remoteIP().toString().c_str(), udp.remotePort());
Serial.printf("Packet contents: %s\n", incomingPacket);
// 查找 IP 地址的起始位置
char* ipStart = strstr(incomingPacket, "ESP32_IP:");//数据格式:ESP32_IP:192.168.31.88,PORT:88
if (ipStart != NULL) {
// 移动到 IP 地址的起始位置
ipStart += strlen("ESP32_IP:");
// 查找 IP 地址的结束位置(逗号分隔)
char* ipEnd = strchr(ipStart, ',');
if (ipEnd != NULL) {
// 提取 IP 地址
char ip[16]; // 保存 IP 地址的字符串数组
strncpy(ip, ipStart, ipEnd - ipStart); // 拷贝 IP 地址到数组
ip[ipEnd - ipStart] = '\0'; // 添加字符串结束符
// 将 IP 地址转换为 IPAddress 类型
esp32Ip.fromString(ip);
Serial.print("ESP32 IP Address: ");
Serial.println(esp32Ip);
}
}
// 查找端口号的起始位置
char* portStart = strstr(incomingPacket, "PORT:");
if (portStart != NULL) {
// 移动到端口号的起始位置
portStart += strlen("PORT:");
// 提取端口号
udpPort = atoi(portStart);
Serial.print("Port: ");
Serial.println(udpPort);
}
if(!flag1){//!!!重复初始化影响消息接收
udp.begin(udpPort);//监听获取的udpPort端口
flag1 = true;
}
sendLinkMessage();//向获取的udpPort端口发送连接请求
//udp.begin(discoveryPort);//!!!重复初始化影响消息接收
Serial.printf("wait Port:%d\n",udpPort);
delay(2000);
int packetSize = udp.parsePacket();
char incomingPacket[255];
int len1 = udp.read(incomingPacket, 255);
if (len1 > 0) {
incomingPacket[len1] = 0;
}
if (strncmp(incomingPacket, "OK", 2) == 0){
esp32Found = true;
Serial.printf("Found ESP32!");
}
}
delay(2000); // 每隔 2 秒发送一次发现请求
}
else {
//等待接收数据
static bool udpInitFlag = false;
if(!udpInitFlag){//没有初始化
udp.begin(udpPort);//!!!重复初始化影响消息接收
udpInitFlag = true;
}
Serial.printf("wait Port :%d message\n",udpPort);
int packetSize = udp.parsePacket();
if (packetSize){
int len = udp.read(incomingPacket, 255);
if (len > 0) {
incomingPacket[len] = 0;
}
// 处理设备消息
Serial.printf("%s\n",incomingPacket);
if (strncmp(incomingPacket, "Relay:", 6) == 0) {
String message = String(incomingPacket);
String deviceName = message.substring(0, message.indexOf(':'));//数据格式Name:On/ Relay:On
String stateName = message.substring(message.indexOf(':') + 1 );
Serial.printf("%s",message.c_str());
if(strcmp(stateName.c_str(),"On") == 0){
// 启动设备
RelayState1 = 1;
digitalWrite(Relay,LOW);
Serial.println("Relay Open");
}
else if(strcmp(stateName.c_str(),"Off") == 0){
// 关闭设备
RelayState1 = 0;
digitalWrite(Relay,HIGH);
Serial.println("Relay Close");
}
else if(strcmp(stateName.c_str(),"Open") == 0){
// 开机
digitalWrite(Relay,LOW);
delay(500);
digitalWrite(Relay,HIGH);
Serial.println("Computer Open");
}
else if(strcmp(stateName.c_str(),"Close") == 0){
// 关机
digitalWrite(Relay,LOW);
delay(500);
digitalWrite(Relay,HIGH);
Serial.println("Computer Close");
}
}
}
}
AliyunIoTSDK::loop();
delay(1000);
}
void sendLinkMessage(){
// 发送数据给 ESP32
char stateString[] = "Relay:Link";
udp.beginPacket(esp32Ip, udpPort);
udp.printf(stateString);//udp.write
udp.endPacket();
Serial.print("Send Link Message:");
Serial.println(stateString);
}
void sendRelayData(){
// 发送数据给 ESP32
char stateString[20];
if(RelayState1 == false){
sprintf(stateString,"Relay:Off");
}
else{
sprintf(stateString,"Relay:On");
}
udp.beginPacket(esp32Ip, udpPort);
udp.printf(stateString);
udp.endPacket();
Serial.println("Data packet sent");
}
// 初始化 wifi 连接
void wifiInit(const char *ssid, const char *passphrase)
{
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, passphrase);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.println("WiFi not Connect");
}
Serial.println("Connected to AP");
}
// 电源属性修改的回调函数
void powerCallback(JsonVariant p)
{
RelayState1 = p["ComputerControl"];
if (RelayState1 == 1)
{
// 启动设备
digitalWrite(Relay,LOW);
Serial.println("Relay to HIGH");
}
else{
digitalWrite(Relay,HIGH);
Serial.println("Relay to LOW");
}
AliyunIoTSDK::send("ComputerControl", RelayState1);
}
使用教程
- 提醒:此代码需要配合 基于ESP32的智能家居助手设计与实现 共同使用!!!
- 开发板选择NodeMCU 1.0
- 首先将产品信息替换为自己的阿里云物联网平台设置的信息,REGION_ID根据所在地区修改
具体配置参考我的另一博客使用ESP-01S与阿里云物联网平台服务器的连接与配置(温湿度检测) - 然后将WiFi信息替换为自己家的WiFi连接信息
将上面两处代码中的ComputerControl修改为自己设置的属性名称即可
演示视频
- 本地语音控制
语音控制继电器演示视频
- APP控制
阿里云物联网平台应用演示