ESP8266无线开关

IOT项目------ESP8266无线开关

ESP8266无线开关实现方案

系统概述

本系统基于ESP8266模组构建一个无线开关控制系统,通过Wi-Fi连接实现远程设备控制。系统包含:

  • ESP8266作为主控制器
  • 继电器模块控制电器开关
  • 本地按钮用于手动控制
  • 云端/局域网通信
  • PyQt上位机界面显示状态

硬件介绍

所需组件

  1. ESP8266开发板 (NodeMCU或Wemos D1 Mini)
  2. 继电器模块 (5V/10A)
  3. 面包板和跳线
  4. LED指示灯 (可选)
  5. 按钮开关
  6. 电源适配器

电路连接

复制代码
ESP8266      继电器模块
GPIO5   -->   IN引脚
3.3V    -->   VCC
GND     -->   GND

ESP8266      按钮
GPIO4   -->   一端
3.3V    -->   另一端(通过10K上拉电阻)

软件介绍

VSCode开发环境配置

  1. 安装PlatformIO插件
  2. 创建新项目,选择ESP8266平台
  3. 添加必要的库依赖:
    • ArduinoJson (用于数据解析)
    • PubSubClient (MQTT通信,可选)

主要代码结构

cpp 复制代码
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ArduinoJson.h>

// WiFi配置
const char* ssid = "Your_WiFi_SSID";
const char* password = "Your_WiFi_Password";

// 引脚定义
const int relayPin = 5;    // GPIO5控制继电器
const int buttonPin = 4;   // GPIO4连接按钮

// 状态变量
bool switchState = false;
bool lastButtonState = HIGH;

ESP8266WebServer server(80);

void setup() {
  Serial.begin(115200);
  
  // 初始化引脚
  pinMode(relayPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  digitalWrite(relayPin, LOW);
  
  // 连接WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  // 设置Web服务器路由
  server.on("/", handleRoot);
  server.on("/switch", handleSwitch);
  server.on("/status", handleStatus);
  
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  server.handleClient();
  
  // 按钮检测
  bool currentButtonState = digitalRead(buttonPin);
  if (currentButtonState == LOW && lastButtonState == HIGH) {
    toggleSwitch();
    delay(200); // 防抖
  }
  lastButtonState = currentButtonState;
}

void handleRoot() {
  String html = "<html><body>";
  html += "<h1>ESP8266 Wireless Switch</h1>";
  html += "<p>Current State: " + String(switchState ? "ON" : "OFF") + "</p>";
  html += "<a href='/switch?state=1'><button>Turn ON</button></a>";
  html += "<a href='/switch?state=0'><button>Turn OFF</button></a>";
  html += "</body></html>";
  server.send(200, "text/html", html);
}

void handleSwitch() {
  if (server.hasArg("state")) {
    switchState = server.arg("state").toInt();
    digitalWrite(relayPin, switchState);
    server.send(200, "application/json", "{\"status\":\"success\",\"state\":" + String(switchState) + "}");
  } else {
    server.send(400, "application/json", "{\"status\":\"error\",\"message\":\"Missing state parameter\"}");
  }
}

void handleStatus() {
  String json = "{\"state\":" + String(switchState) + "}";
  server.send(200, "application/json", json);
}

void toggleSwitch() {
  switchState = !switchState;
  digitalWrite(relayPin, switchState);
}

示例演示

操作步骤

  1. 将代码上传到ESP8266
  2. 打开串口监视器查看IP地址
  3. 在浏览器中输入ESP8266的IP地址
  4. 点击网页按钮控制开关
  5. 物理按钮也可用于切换状态

API接口

  • GET / - 显示控制网页
  • GET /switch?state=0/1 - 控制开关状态
  • GET /status - 获取当前状态(JSON格式)

优化建议

1. 增加PyCharm PyQt上位机界面

使用PyCharm创建PyQt5应用程序来监控和控制ESP8266开关:

python 复制代码
import sys
import requests
from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, 
                             QHBoxLayout, QPushButton, QLabel, QWidget,
                             QMessageBox)
from PyQt5.QtCore import QTimer, Qt

class SwitchController(QMainWindow):
    def __init__(self):
        super().__init__()
        self.esp_ip = "192.168.1.100"  # 替换为ESP8266的IP
        self.initUI()
        self.setupTimer()
        
    def initUI(self):
        self.setWindowTitle('ESP8266 Switch Controller')
        self.setGeometry(300, 300, 300, 200)
        
        # 中央窗口部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 布局
        layout = QVBoxLayout()
        
        # 状态显示
        self.status_label = QLabel('状态: 未知')
        self.status_label.setAlignment(Qt.AlignCenter)
        self.status_label.setStyleSheet("font-size: 16px; font-weight: bold;")
        layout.addWidget(self.status_label)
        
        # 控制按钮
        button_layout = QHBoxLayout()
        
        self.on_button = QPushButton('打开')
        self.on_button.clicked.connect(self.turn_on)
        self.on_button.setStyleSheet("background-color: green; color: white;")
        button_layout.addWidget(self.on_button)
        
        self.off_button = QPushButton('关闭')
        self.off_button.clicked.connect(self.turn_off)
        self.off_button.setStyleSheet("background-color: red; color: white;")
        button_layout.addWidget(self.off_button)
        
        layout.addLayout(button_layout)
        
        # 连接状态
        self.connection_label = QLabel('连接状态: 未连接')
        layout.addWidget(self.connection_label)
        
        central_widget.setLayout(layout)
        
    def setupTimer(self):
        # 定时器用于定期更新状态
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_status)
        self.timer.start(2000)  # 每2秒更新一次
        
    def update_status(self):
        try:
            response = requests.get(f"http://{self.esp_ip}/status", timeout=3)
            if response.status_code == 200:
                data = response.json()
                state = data.get('state', 0)
                status_text = "ON" if state else "OFF"
                color = "green" if state else "red"
                self.status_label.setText(f'状态: {status_text}')
                self.status_label.setStyleSheet(f"font-size: 16px; font-weight: bold; color: {color};")
                self.connection_label.setText('连接状态: 已连接')
                self.connection_label.setStyleSheet("color: green;")
            else:
                self.connection_label.setText('连接状态: 响应错误')
                self.connection_label.setStyleSheet("color: orange;")
        except Exception as e:
            self.connection_label.setText(f'连接状态: 连接失败 - {str(e)}')
            self.connection_label.setStyleSheet("color: red;")
            
    def turn_on(self):
        self.send_switch_command(1)
        
    def turn_off(self):
        self.send_switch_command(0)
        
    def send_switch_command(self, state):
        try:
            response = requests.get(f"http://{self.esp_ip}/switch?state={state}", timeout=3)
            if response.status_code == 200:
                QMessageBox.information(self, "成功", f"开关已{'打开' if state else '关闭'}")
                self.update_status()
            else:
                QMessageBox.warning(self, "错误", "控制命令发送失败")
        except Exception as e:
            QMessageBox.critical(self, "错误", f"连接失败: {str(e)}")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    controller = SwitchController()
    controller.show()
    sys.exit(app.exec_())

3. 其他优化建议

ESP8266端优化:

  • 添加OTA(空中下载)功能,便于远程更新固件
  • 实现MQTT协议,支持更灵活的物联网平台集成
  • 添加看门狗定时器,提高系统稳定性
  • 实现EEPROM存储,保存开关状态以防断电丢失

PyQt上位机增强功能:

  • 添加多个设备管理功能
  • 实现历史记录和日志功能
  • 添加定时任务和场景模式
  • 支持设备发现和自动配置
  • 添加数据图表显示

安全优化:

  • 添加Web界面密码保护
  • 实现HTTPS加密通信
  • 添加设备身份验证

这个完整的方案提供了从硬件到软件,再到图形界面的完整无线开关解决方案,可以根据实际需求进一步扩展功能。

相关推荐
小叮当⇔1 天前
IOT项目——电源入门系列-第三章
物联网
TDengine (老段)1 天前
TDengine 配置参数作用范围对比
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
塔能物联运维1 天前
物联网运维中基于强化学习的自动化决策优化技术
运维·物联网·自动化
Hy行者勇哥1 天前
物联网多类型设备列表的智能化设计与实现
物联网
TDengine (老段)1 天前
从“事后抢险”到“事前防控”:江西水投用 TDengine 时序数据库重塑防汛模式
大数据·数据库·物联网·时序数据库·tdengine·涛思数据·1024程序员节
CiLerLinux1 天前
第三章 FreeRTOS 任务相关 API 函数
开发语言·单片机·物联网·c#
塔能物联运维2 天前
物联网固件安全更新中的动态密钥绑定与验证机制
物联网
DreamLife☼2 天前
Node-RED革命性实践:从智能家居网关到二次开发,全面重新定义可视化编程
mqtt·网关·低代码·智能家居·iot·1024程序员节·node-red
Despacito0o2 天前
Keil MDK-ARM 5.42a 完整安装指南(2025.4.19最新版)
arm开发·stm32·单片机·嵌入式硬件·物联网·51单片机·嵌入式实时数据库