定时插座

http://192.168.31.160/LED-Control?ledPwm=0&time=22:59:50

ledPwm:0.关机时间,1.开机时间,2.设置时间,3.手动开,4.手动关, 5.删除时间

现在时间: 00:01:19

开列表: []

 

关列表: []

 

继电器状态: 开启

 

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <FS.h>
#include <Ticker.h>
#define MAX_SCHEDULES 20 // 假设最多支持20个时间计划

Ticker ticker;
int count;  // 计时器计数变量

String  onTimes[MAX_SCHEDULES];
int onTimesindex = 0;
String  offTimes[MAX_SCHEDULES];
int offTimesindex = 0;
int relay = 0; // 继电器引脚,NodeMCU D5
ESP8266WebServer esp8266_server(80);
String currentTime;

int hours = 0;    // 当前小时数
int minutes = 0;  // 当前分钟数
int seconds = 0;  // 当前秒数

void setup(void) {
  pinMode(relay, OUTPUT);
  Serial.begin(9600);
  Serial.println("");
  ticker.attach(1, tickerCount);
  digitalWrite(relay, HIGH);
  pinMode(LED_BUILTIN, OUTPUT);

  WiFi.begin("yang1234", "y123456789"); // 输入你的WiFi SSID和密码
  Serial.println("Connecting ...");

  int i = 0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(i++);
    Serial.print(' ');
  }

  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());

  if (SPIFFS.begin()) {
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }

  esp8266_server.on("/LED-Control", handleLEDControl);
//  esp8266_server.on("/", HTTP_GET, handleRoot); // 新增根路径的处理函数
  esp8266_server.onNotFound(handleUserRequest);

  esp8266_server.begin();
  Serial.println("HTTP server started");
}

void loop(void) {
  esp8266_server.handleClient();
}

void tickerCount() {
//  if (count <= 0) {
//    digitalWrite(relay, LOW);
//    count = 0;
//  } else {
//    delay(1000);
//    count--;
//  }

  // 每秒增加1秒
  seconds++;
  if (seconds >= 60) {
    seconds = 0;
    minutes++;
    if (minutes >= 60) {
      minutes = 0;
      hours++;
      if (hours >= 24) { // 如果小时数大于等于24,重置为0点
        hours = 0;
      }
    }
  }
  
  // 构建时间字符串
  currentTime = String(hours < 10 ? "0" : "") + hours + ":" +
                      String(minutes < 10 ? "0" : "") + minutes + ":" +
                      String(seconds < 10 ? "0" : "") + seconds;
    Serial.print("currentTime=");
  Serial.println(currentTime);

  // 检查onTimes数组,如果有匹配则打开继电器
  
  for (int i = 0; i < MAX_SCHEDULES; i++) {
    String onTime = String(onTimes[i]);
    if (onTime == currentTime) {
      Serial.println("off");

      digitalWrite(relay, HIGH);
      break;
    }
  }
  
  // 检查offTimes数组,如果有匹配则关闭继电器
  
  for (int i = 0; i < MAX_SCHEDULES; i++) {
    String offTime = String(offTimes[i]);
    if (offTime == currentTime) {
      digitalWrite(relay, LOW);
      Serial.println("on");
      break;
    }
  }
}

void handleLEDControl() {
  String ledPwm = esp8266_server.arg("ledPwm");
  
  int ledPwmVal = ledPwm.toInt();

  if (ledPwmVal == 0) {
    String timeParam = esp8266_server.arg("time");

    offTimes[offTimesindex] = timeParam;
    offTimesindex ++;
    
  }
  else if (ledPwmVal == 2) {
    String timeParam = esp8266_server.arg("time");

    // 解析时间参数的格式为hh:mm:ss
    int parsedHours, parsedMinutes, parsedSeconds;
    if (sscanf(timeParam.c_str(), "%d:%d:%d", &parsedHours, &parsedMinutes, &parsedSeconds) == 3) {
      hours = parsedHours;
      minutes = parsedMinutes;
      seconds = parsedSeconds;
      currentTime = String(hours < 10 ? "0" : "") + hours + ":" + String(minutes < 10 ? "0" : "") + minutes + ":" +String(seconds < 10 ? "0" : "") + seconds;
    }
  } else if (ledPwmVal == 1) {
      String timeParam = esp8266_server.arg("time");
        onTimes[onTimesindex] = timeParam;
        onTimesindex++;

  }else if (ledPwmVal == 3) {
      digitalWrite(relay, HIGH);
  }
  else if (ledPwmVal == 4) {
      digitalWrite(relay, LOW);
  }  else if(ledPwmVal == 5){
    //删除时间日期
    String timeParam = esp8266_server.arg("time");
     int len = sizeof(offTimes) / sizeof(offTimes[0]);
      // 使用一个循环查找要删除的元素并删除
      int indexToDelete = -1;
        for (int i = 0; i < sizeof(offTimes) / sizeof(offTimes[0]); i++) {
          if (offTimes[i] == timeParam) {
            indexToDelete = i;
            offTimesindex --;
            break;
          }
        }
        // 如果找到要删除的元素,就删除它
        if (indexToDelete != -1) {
          for (int i = indexToDelete; i < sizeof(offTimes) / sizeof(offTimes[0]) - 1; i++) {
            offTimes[i] = offTimes[i + 1];
          }
          // 将最后一个元素设置为空字符串或者你需要的默认值
          offTimes[sizeof(offTimes) / sizeof(offTimes[0]) - 1] = "";
        }


      len = sizeof(onTimes) / sizeof(onTimes[0]);
      // 使用一个循环查找要删除的元素并删除
        indexToDelete = -1;
        for (int i = 0; i < sizeof(onTimes) / sizeof(onTimes[0]); i++) {
          if (onTimes[i] == timeParam) {
            indexToDelete = i;
            onTimesindex --;
            break;
          }
        }
        
        // 如果找到要删除的元素,就删除它
        if (indexToDelete != -1) {
          for (int i = indexToDelete; i < sizeof(onTimes) / sizeof(onTimes[0]) - 1; i++) {
            onTimes[i] = onTimes[i + 1];
          }
          // 将最后一个元素设置为空字符串或者你需要的默认值
          onTimes[sizeof(onTimes) / sizeof(onTimes[0]) - 1] = "";
        }
      
  
    }
  
  int digitalValue = digitalRead(relay); // 读取 0 号数字引脚的电平状态
  String relayStatus;
  if (digitalValue == 1){
    relayStatus = "开启";
    }
  else{
    relayStatus = "关闭";
    }



  // 生成HTML内容,包括onTimes和offTimes
  String htmlContent = R"(
        <!DOCTYPE html>
        <html>
        <head>
          <title>插座开关</title>
          <meta charset="UTF-8">

          <script>

            // 在这里插入Arduino生成的时间变量
            var currentTime = ")" + currentTime + R"(";
            var timeParts = currentTime.split(":");
            var hours = timeParts[0];
            var minutes = timeParts[1];
            var seconds = timeParts[2];

            function updateTime() {
              var timeDisplay = document.getElementById("timeDisplay");
              // 分割时间字符串为小时、分钟和秒
              
                    // 每次加1秒
              seconds++;
              // 如果秒数达到60,将秒数重置为0并增加分钟
              if (seconds === 60) {
                seconds = 0;
                minutes++;
        
                // 如果分钟达到60,将分钟重置为0并增加小时
                if (minutes === 60) {
                  minutes = 0;
                  hours++;
        
                  // 如果小时达到24,将小时重置为0
                  if (hours === 24) {
                    hours = 0;
                  }
                }
              }
              // 格式化小时、分钟和秒,确保它们始终显示两位数
              var formattedHours = ('0' + hours).slice(-2);
              var formattedMinutes = ('0' + minutes).slice(-2);
              var formattedSeconds = ('0' + seconds).slice(-2);
              
              // 构建格式化后的时间字符串
              var formattedTime = formattedHours + ":" + formattedMinutes + ":" + formattedSeconds;
//             console.log(formattedTime);
              // 更新时间显示
              timeDisplay.textContent = formattedTime;
            }
            
            // 每秒钟调用一次updateTime函数
            setInterval(updateTime, 1000);
            
            // 当页面加载完成时立即更新时间
            window.onload = updateTime;

            
          </script>
        </head>
        <body>
          <h1>ledPwm:0.关机时间,1.开机时间,2.设置时间,3.手动开,4.手动关, 5.删除时间</h1>
          <p>现在时间: <span id="timeDisplay">00:00:00</span></p>
          <p>开列表: )" + getScheduleString(onTimes, onTimesindex)  + R"(<p>
          <p>关列表: )" + getScheduleString(offTimes, offTimesindex) + R"(<p>
          <p><span id="relayStatus">继电器状态: )" + relayStatus + R"(</span></p>

        </body>
        </html>
      )";

  esp8266_server.send(200, "text/html", htmlContent);
}

String getScheduleString(String* scheduleArray, int scheduleCount) {
  String result = "[";
  for (int i = 0; i < scheduleCount; i++) {
    result += "\"" + scheduleArray[i] + "\"";
    if (i < scheduleCount - 1) {
      result += ", ";
    }
  }
  result += "]";
  return result;
}

void handleUserRequest() {
  
  String reqResource = esp8266_server.uri();
  Serial.print("reqResource: ");
  Serial.println(reqResource);

  bool fileReadOK = handleFileRead(reqResource);

  if (!fileReadOK) {
    esp8266_server.send(404, "text/plain", "404 Not Found");
  }
}

bool handleFileRead(String resource) {
  if (resource.endsWith("/")) {
    resource = "/index.html";
  }

  String contentType = getContentType(resource);

  if (SPIFFS.exists(resource)) {
    File file = SPIFFS.open(resource, "r");
    esp8266_server.streamFile(file, contentType);
    file.close();
    return true;
  }
  return false;
}

String getContentType(String filename) {
  if (filename.endsWith(".htm")) return "text/html";
  else if (filename.endsWith(".html")) return "text/html";
  else if (filename.endsWith(".css")) return "text/css";
  else if (filename.endsWith(".js")) return "application/javascript";
  else if (filename.endsWith(".png")) return "image/png";
  else if (filename.endsWith(".gif")) return "image/gif";
  else if (filename.endsWith(".jpg")) return "image/jpeg";
  else if (filename.endsWith(".ico")) return "image/x-icon";
  else if (filename.endsWith(".xml")) return "text/xml";
  else if (filename.endsWith(".pdf")) return "application/x-pdf";
  else if (filename.endsWith(".zip")) return "application/x-zip";
  else if (filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}

 python 代码

import requests

import re

import ast

ip = "192.168.31.160"
# ESP-EBFB77 138
from datetime import datetime

now = datetime.now()
current_time = now.strftime("%H:%M:%S")

print(current_time)
off_list = ['07:22:00', "09:48:00","12:30:00", "17:51:00", "23:37:00", "23:50:00"]
on_list = ["07:25:00", "09:51:00", "17:56:00", "23:52:00"]

url = "http://%s/LED-Control?ledPwm=2&time=%s" % (ip, str(current_time))
print(url)
response = requests.post(url)
response.encoding = 'utf-8'  # 明确指定编码方式为UTF-8
html = response.text
print(html)

r_list = re.compile("开列表: (\\[.*?\\]).*?<p>关列表: (\\[.*?\\]).*?继电器状态: (.*?)<", re.S).findall(html)
print(r_list)

re_on_list = []
re_off_list = []
jdq = ''

if r_list:
    re_on_list = ast.literal_eval(r_list[0][0])
    re_off_list = ast.literal_eval(r_list[0][1])
    jdq = r_list[0][2]
    # print(re_on_list, off, jdq)

for one_time in off_list:
    if one_time in re_off_list:
        continue
    url = "http://%s/LED-Control?ledPwm=0&time=%s" % (ip, str(one_time))
    response = requests.post(url)


for one_time in on_list:
    if one_time in re_on_list:
        continue
    url = "http://%s/LED-Control?ledPwm=1&time=%s" % (ip, str(one_time))

    response = requests.post(url)

print(jdq)

2.河南古灯

有继电器,ws2812,光敏电阻,人体传感器HC-SR501,esp8266

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <FS.h>
#include <Ticker.h>
#define MAX_SCHEDULES 20 // 假设最多支持20个时间计划

Ticker ticker;
int count;  // 计时器计数变量

String  onTimes[MAX_SCHEDULES];
int onTimesindex = 0;
String  offTimes[MAX_SCHEDULES];
int offTimesindex = 0;
int relay = D1; // 继电器引脚,NodeMCU D5
const int lresistorPin = A0; // 光敏电阻
const int irSensorPin = D2; // 将人体传感器连接到D2引脚


// 定义阈值
const int ldrThreshold = 800; // 光敏电阻阈值,可以根据环境调整
const int pirThreshold = 1; // 人体传感器阈值,根据需要调整

const int THREE_MINUTES_IN_SECONDS = 180;  // 全局变量定义3分钟的秒数,人体感应时候+3分钟
ESP8266WebServer esp8266_server(80);
String currentTime;

int hours = 0;    // 当前小时数
int minutes = 0;  // 当前分钟数
int seconds = 0;  // 当前秒数

void setup(void) {
  pinMode(relay, OUTPUT);
  pinMode(irSensorPin, INPUT);
  Serial.begin(9600);
  Serial.println("");
  ticker.attach(1, tickerCount);
  digitalWrite(relay, LOW);
  pinMode(LED_BUILTIN, OUTPUT);

  WiFi.begin("yang1234", "y123456789"); // 输入你的WiFi SSID和密码
  Serial.println("Connecting ...");

  int i = 0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(i++);
    Serial.print(' ');
  }

  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());

  if (SPIFFS.begin()) {
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }

  esp8266_server.on("/LED-Control", handleLEDControl);
//  esp8266_server.on("/", HTTP_GET, handleRoot); // 新增根路径的处理函数
  esp8266_server.onNotFound(handleUserRequest);

  esp8266_server.begin();
  Serial.println("HTTP server started");
}

void loop(void) {
  esp8266_server.handleClient();
    // 读取光敏电阻值
  int ldrValue = analogRead(lresistorPin);

  // 读取人体传感器值
  int pirValue = digitalRead(irSensorPin);
//  Serial.print("人体传感器: ");
//  Serial.println(pirValue);
//  Serial.print("光敏电阻: ");
//  Serial.println(ldrValue);
  // 如果光敏电阻和人体传感器条件满足,则执行操作
  if (ldrValue > ldrThreshold && pirValue == pirThreshold) {
    digitalWrite(relay, HIGH);
    // 清空关数组offTimes
    for (int i = 0; i < MAX_SCHEDULES; i++) {
      offTimes[i] = "";
    }
    offTimesindex = 0;

    // 获取当前时间
    String currentTime = getCurrentTime();
    Serial.println("Current Time: " + currentTime);

    // 当前时间加3分钟
    int currentHours = hours;
    int currentMinutes = minutes +  (THREE_MINUTES_IN_SECONDS / 60); // 转换为分钟;
    if (currentMinutes >= 60) {
      currentHours++;
      currentMinutes -= 60;
    }

    // 构建关时间字符串
    String offTime = String(currentHours < 10 ? "0" : "") + currentHours + ":" +
                     String(currentMinutes < 10 ? "0" : "") + currentMinutes + ":" +
                     String(seconds < 10 ? "0" : "") + seconds;

    // 加入关数组offTimes
    offTimes[offTimesindex] = offTime;
    offTimesindex++;
  }
  
}

String getCurrentTime() {
  return String(hours < 10 ? "0" : "") + hours + ":" +
         String(minutes < 10 ? "0" : "") + minutes + ":" +
         String(seconds < 10 ? "0" : "") + seconds;
}

void tickerCount() {
//  if (count <= 0) {
//    digitalWrite(relay, LOW);
//    count = 0;
//  } else {
//    delay(1000);
//    count--;
//  }

  // 每秒增加1秒
  seconds++;
  if (seconds >= 60) {
    seconds = 0;
    minutes++;
    if (minutes >= 60) {
      minutes = 0;
      hours++;
      if (hours >= 24) { // 如果小时数大于等于24,重置为0点
        hours = 0;
      }
    }
  }
  
  // 构建时间字符串
  currentTime = String(hours < 10 ? "0" : "") + hours + ":" +
                      String(minutes < 10 ? "0" : "") + minutes + ":" +
                      String(seconds < 10 ? "0" : "") + seconds;
    Serial.print("currentTime=");
  Serial.println(currentTime);

  // 检查onTimes数组,如果有匹配则打开继电器
  
  for (int i = 0; i < MAX_SCHEDULES; i++) {
    String onTime = String(onTimes[i]);
    if (onTime == currentTime) {
      Serial.println("off");

      digitalWrite(relay, HIGH);
      break;
    }
  }
  
  // 检查offTimes数组,如果有匹配则关闭继电器
  
  for (int i = 0; i < MAX_SCHEDULES; i++) {
    String offTime = String(offTimes[i]);
    if (offTime == currentTime) {
      digitalWrite(relay, LOW);
      Serial.println("on");
      break;
    }
  }
}

void handleLEDControl() {
  String ledPwm = esp8266_server.arg("ledPwm");
  
  int ledPwmVal = ledPwm.toInt();

  if (ledPwmVal == 0) {
    String timeParam = esp8266_server.arg("time");

    offTimes[offTimesindex] = timeParam;
    offTimesindex ++;
    
  }
  else if (ledPwmVal == 2) {
    String timeParam = esp8266_server.arg("time");

    // 解析时间参数的格式为hh:mm:ss
    int parsedHours, parsedMinutes, parsedSeconds;
    if (sscanf(timeParam.c_str(), "%d:%d:%d", &parsedHours, &parsedMinutes, &parsedSeconds) == 3) {
      hours = parsedHours;
      minutes = parsedMinutes;
      seconds = parsedSeconds;
      currentTime = String(hours < 10 ? "0" : "") + hours + ":" + String(minutes < 10 ? "0" : "") + minutes + ":" +String(seconds < 10 ? "0" : "") + seconds;
    }
  } else if (ledPwmVal == 1) {
      String timeParam = esp8266_server.arg("time");
        onTimes[onTimesindex] = timeParam;
        onTimesindex++;

  }else if (ledPwmVal == 3) {
      digitalWrite(relay, HIGH);
  }
  else if (ledPwmVal == 4) {
      digitalWrite(relay, LOW);
  }  else if(ledPwmVal == 5){
    //删除时间日期
    String timeParam = esp8266_server.arg("time");
     int len = sizeof(offTimes) / sizeof(offTimes[0]);
      // 使用一个循环查找要删除的元素并删除
      int indexToDelete = -1;
        for (int i = 0; i < sizeof(offTimes) / sizeof(offTimes[0]); i++) {
          if (offTimes[i] == timeParam) {
            indexToDelete = i;
            offTimesindex --;
            break;
          }
        }
        // 如果找到要删除的元素,就删除它
        if (indexToDelete != -1) {
          for (int i = indexToDelete; i < sizeof(offTimes) / sizeof(offTimes[0]) - 1; i++) {
            offTimes[i] = offTimes[i + 1];
          }
          // 将最后一个元素设置为空字符串或者你需要的默认值
          offTimes[sizeof(offTimes) / sizeof(offTimes[0]) - 1] = "";
        }


      len = sizeof(onTimes) / sizeof(onTimes[0]);
      // 使用一个循环查找要删除的元素并删除
        indexToDelete = -1;
        for (int i = 0; i < sizeof(onTimes) / sizeof(onTimes[0]); i++) {
          if (onTimes[i] == timeParam) {
            indexToDelete = i;
            onTimesindex --;
            break;
          }
        }
        
        // 如果找到要删除的元素,就删除它
        if (indexToDelete != -1) {
          for (int i = indexToDelete; i < sizeof(onTimes) / sizeof(onTimes[0]) - 1; i++) {
            onTimes[i] = onTimes[i + 1];
          }
          // 将最后一个元素设置为空字符串或者你需要的默认值
          onTimes[sizeof(onTimes) / sizeof(onTimes[0]) - 1] = "";
        }
      
  
    }

  
  int digitalValue = digitalRead(relay); // 读取 0 号数字引脚的电平状态
  String relayStatus;
  if (digitalValue == 1){
    relayStatus = "开启";
    }
  else{
    relayStatus = "关闭";
    }



  // 生成HTML内容,包括onTimes和offTimes
  String htmlContent = R"(
        <!DOCTYPE html>
        <html>
        <head>
          <title>插座开关</title>
          <meta charset="UTF-8">

          <script>

            // 在这里插入Arduino生成的时间变量
            var currentTime = ")" + currentTime + R"(";
            var timeParts = currentTime.split(":");
            var hours = timeParts[0];
            var minutes = timeParts[1];
            var seconds = timeParts[2];

            function updateTime() {
              var timeDisplay = document.getElementById("timeDisplay");
              // 分割时间字符串为小时、分钟和秒
              
                    // 每次加1秒
              seconds++;
              // 如果秒数达到60,将秒数重置为0并增加分钟
              if (seconds === 60) {
                seconds = 0;
                minutes++;
        
                // 如果分钟达到60,将分钟重置为0并增加小时
                if (minutes === 60) {
                  minutes = 0;
                  hours++;
        
                  // 如果小时达到24,将小时重置为0
                  if (hours === 24) {
                    hours = 0;
                  }
                }
              }
              // 格式化小时、分钟和秒,确保它们始终显示两位数
              var formattedHours = ('0' + hours).slice(-2);
              var formattedMinutes = ('0' + minutes).slice(-2);
              var formattedSeconds = ('0' + seconds).slice(-2);
              
              // 构建格式化后的时间字符串
              var formattedTime = formattedHours + ":" + formattedMinutes + ":" + formattedSeconds;
//             console.log(formattedTime);
              // 更新时间显示
              timeDisplay.textContent = formattedTime;
            }
            
            // 每秒钟调用一次updateTime函数
            setInterval(updateTime, 1000);
            
            // 当页面加载完成时立即更新时间
            window.onload = updateTime;

            
          </script>
        </head>
        <body>
        <h1>ledPwm:0.设置关机时间列表,1.设置开机时间列表,2.设置现在时间,3.手动开,4.手动关, 5.删除时间</h1>
        <p>现在时间: <span id="timeDisplay">00:00:00</span></p>
        <p>光敏电阻阈值: )" + String(ldrThreshold) + R"(</p>
        <p>人体传感器阈值: )" + String(pirThreshold) + R"(</p>
        <p>开列表: )" + getScheduleString(onTimes, onTimesindex)  + R"(<p>
        <p>关列表: )" + getScheduleString(offTimes, offTimesindex) + R"(<p>
        <p><span id="relayStatus">继电器状态: )" + relayStatus + R"(</span></p>

        </body>
        </html>
      )";

  esp8266_server.send(200, "text/html", htmlContent);
}

String getScheduleString(String* scheduleArray, int scheduleCount) {
  String result = "[";
  for (int i = 0; i < scheduleCount; i++) {
    result += "\"" + scheduleArray[i] + "\"";
    if (i < scheduleCount - 1) {
      result += ", ";
    }
  }
  result += "]";
  return result;
}

void handleUserRequest() {
  
  String reqResource = esp8266_server.uri();
  Serial.print("reqResource: ");
  Serial.println(reqResource);

  bool fileReadOK = handleFileRead(reqResource);

  if (!fileReadOK) {
    esp8266_server.send(404, "text/plain", "404 Not Found");
  }
}

bool handleFileRead(String resource) {
  if (resource.endsWith("/")) {
    resource = "/index.html";
  }

  String contentType = getContentType(resource);

  if (SPIFFS.exists(resource)) {
    File file = SPIFFS.open(resource, "r");
    esp8266_server.streamFile(file, contentType);
    file.close();
    return true;
  }
  return false;
}

String getContentType(String filename) {
  if (filename.endsWith(".htm")) return "text/html";
  else if (filename.endsWith(".html")) return "text/html";
  else if (filename.endsWith(".css")) return "text/css";
  else if (filename.endsWith(".js")) return "application/javascript";
  else if (filename.endsWith(".png")) return "image/png";
  else if (filename.endsWith(".gif")) return "image/gif";
  else if (filename.endsWith(".jpg")) return "image/jpeg";
  else if (filename.endsWith(".ico")) return "image/x-icon";
  else if (filename.endsWith(".xml")) return "text/xml";
  else if (filename.endsWith(".pdf")) return "application/x-pdf";
  else if (filename.endsWith(".zip")) return "application/x-zip";
  else if (filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}

3.人体感应彩灯

使用ws2812 人体传感器HC-SR501,esp8266.(使用光明电阻过一会wifi重启不知原因)

#include <DNSServer.h>
#include "FastLED.h"            // 此示例程序需要使用FastLED库
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <FS.h>
#include <Ticker.h>
#define MAX_SCHEDULES 20 // 假设最多支持20个时间计划

Ticker ticker;
int count;  // 计时器计数变量

String  onTimes[MAX_SCHEDULES];
int onTimesindex = 0;
String  offTimes[MAX_SCHEDULES];
int offTimesindex = 0;

const int irSensorPin = D2; // 将人体传感器连接到D2引脚
String litLedsCountStr; // led数量,字符串

// 定义阈值

const int pirThreshold = 1; // 人体传感器阈值,根据需要调整
int pirValue;
const int THREE_MINUTES_IN_SECONDS =60;  // 全局变量定义3分钟的秒数,人体感应时候+60秒
ESP8266WebServer esp8266_server(80);
String currentTime;

int hours = 0;    // 当前小时数
int minutes = 0;  // 当前分钟数
int seconds = 0;  // 当前秒数


#define NUM_LEDS 60             // LED灯珠数量
#define LED_DT D6                // Arduino输出控制信号引脚
#define LED_TYPE WS2812         // LED灯带型号
#define COLOR_ORDER GRB         // RGB灯珠中红色、绿色、蓝色LED的排列顺序

uint8_t max_bright = 128;       // LED亮度控制变量,可使用数值为 0 ~ 255, 数值越大则光带亮度越高
CRGB leds[NUM_LEDS];            // 建立光带leds
uint8_t beginHue;



void setup(void) {

  pinMode(irSensorPin, INPUT);
  Serial.begin(115200);
  Serial.println("");
  ticker.attach(1, tickerCount);
  LEDS.addLeds<LED_TYPE, LED_DT, COLOR_ORDER>(leds, NUM_LEDS);  // 初始化光带
  
  FastLED.setBrightness(max_bright);                            // 设置光带亮度
  pinMode(LED_BUILTIN, OUTPUT);
  
  
  
  WiFi.begin("yang1234", "y123456789"); // 输入你的WiFi SSID和密码
  Serial.println("Connecting ...");

  int i = 0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(i++);
    Serial.print(' ');
  }

  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());

  if (SPIFFS.begin()) {
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }

  esp8266_server.on("/LED-Control", handleLEDControl);
//  esp8266_server.on("/", HTTP_GET, handleRoot); // 新增根路径的处理函数
  esp8266_server.onNotFound(handleUserRequest);

  esp8266_server.begin();
  Serial.println("HTTP server started");
  cdoff(); // 关闭所有LED

}

void loop(void) {
  esp8266_server.handleClient();

  // 读取人体传感器值
  int pirValue = digitalRead(irSensorPin);
  // 如果光敏电阻和人体传感器条件满足,则执行操作
  if ( pirValue == pirThreshold) {
    cdon();
    Serial.println("满足开");
    Serial.print("人体传感器: ");
    Serial.println(pirValue);

    // 清空关数组offTimes
    for (int i = 0; i < MAX_SCHEDULES; i++) {
      offTimes[i] = "";
    }
    offTimesindex = 0;

    // 获取当前时间
    String currentTime = getCurrentTime();
    Serial.println("Current Time: " + currentTime);

    // 当前时间加3分钟
    int currentHours = hours;
    int currentMinutes = minutes +  (THREE_MINUTES_IN_SECONDS / 60); // 转换为分钟;
    if (currentMinutes >= 60) {
      currentHours++;
      currentMinutes -= 60;
    }

    // 构建关时间字符串
    String offTime = String(currentHours < 10 ? "0" : "") + currentHours + ":" +
                     String(currentMinutes < 10 ? "0" : "") + currentMinutes + ":" +
                     String(seconds < 10 ? "0" : "") + seconds;

    // 加入关数组offTimes
    offTimes[offTimesindex] = offTime;
    offTimesindex++;
  }
  
}

String getCurrentTime() {
  return String(hours < 10 ? "0" : "") + hours + ":" +
         String(minutes < 10 ? "0" : "") + minutes + ":" +
         String(seconds < 10 ? "0" : "") + seconds;
}

void tickerCount() {

  // 每秒增加1秒
  seconds++;
  if (seconds >= 60) {
    seconds = 0;
    minutes++;
    if (minutes >= 60) {
      minutes = 0;
      hours++;
      if (hours >= 24) { // 如果小时数大于等于24,重置为0点
        hours = 0;
      }
    }
  }
  
  // 构建时间字符串
  currentTime = String(hours < 10 ? "0" : "") + hours + ":" +
                      String(minutes < 10 ? "0" : "") + minutes + ":" +
                      String(seconds < 10 ? "0" : "") + seconds;
    Serial.print("currentTime=");
  Serial.println(currentTime);

  // 检查onTimes数组,如果有匹配则打开继电器
  
  for (int i = 0; i < MAX_SCHEDULES; i++) {
    String onTime = String(onTimes[i]);
    if (onTime == currentTime) {
      
      Serial.println("时间到on");
      cdon();
      
      break;
    }
  }
  
  // 检查offTimes数组,如果有匹配则关闭继电器
  
  for (int i = 0; i < MAX_SCHEDULES; i++) {
    String offTime = String(offTimes[i]);
    if (offTime == currentTime) {
      Serial.println("时间到off");
      cdoff();
      
      break;
    }
  }
}


void handleLEDControl() {
  String ledPwm = esp8266_server.arg("ledPwm");
  
  int ledPwmVal = ledPwm.toInt();

  if (ledPwmVal == 0) {
    String timeParam = esp8266_server.arg("time");

    offTimes[offTimesindex] = timeParam;
    offTimesindex ++;
    
  }
  else if (ledPwmVal == 2) {
    String timeParam = esp8266_server.arg("time");

    // 解析时间参数的格式为hh:mm:ss
    int parsedHours, parsedMinutes, parsedSeconds;
    if (sscanf(timeParam.c_str(), "%d:%d:%d", &parsedHours, &parsedMinutes, &parsedSeconds) == 3) {
      hours = parsedHours;
      minutes = parsedMinutes;
      seconds = parsedSeconds;
      currentTime = String(hours < 10 ? "0" : "") + hours + ":" + String(minutes < 10 ? "0" : "") + minutes + ":" +String(seconds < 10 ? "0" : "") + seconds;
    }
  } else if (ledPwmVal == 1) {
      String timeParam = esp8266_server.arg("time");
        onTimes[onTimesindex] = timeParam;
        onTimesindex++;

  }else if (ledPwmVal == 3) {
      cdon();
  }
  else if (ledPwmVal == 4) {
      cdoff();
  }  else if(ledPwmVal == 5){
    //删除时间日期
    String timeParam = esp8266_server.arg("time");
     int len = sizeof(offTimes) / sizeof(offTimes[0]);
      // 使用一个循环查找要删除的元素并删除
      int indexToDelete = -1;
        for (int i = 0; i < sizeof(offTimes) / sizeof(offTimes[0]); i++) {
          if (offTimes[i] == timeParam) {
            indexToDelete = i;
            offTimesindex --;
            break;
          }
        }
        // 如果找到要删除的元素,就删除它
        if (indexToDelete != -1) {
          for (int i = indexToDelete; i < sizeof(offTimes) / sizeof(offTimes[0]) - 1; i++) {
            offTimes[i] = offTimes[i + 1];
          }
          // 将最后一个元素设置为空字符串或者你需要的默认值
          offTimes[sizeof(offTimes) / sizeof(offTimes[0]) - 1] = "";
        }


      len = sizeof(onTimes) / sizeof(onTimes[0]);
      // 使用一个循环查找要删除的元素并删除
        indexToDelete = -1;
        for (int i = 0; i < sizeof(onTimes) / sizeof(onTimes[0]); i++) {
          if (onTimes[i] == timeParam) {
            indexToDelete = i;
            onTimesindex --;
            break;
          }
        }
        
        // 如果找到要删除的元素,就删除它
        if (indexToDelete != -1) {
          for (int i = indexToDelete; i < sizeof(onTimes) / sizeof(onTimes[0]) - 1; i++) {
            onTimes[i] = onTimes[i + 1];
          }
          // 将最后一个元素设置为空字符串或者你需要的默认值
          onTimes[sizeof(onTimes) / sizeof(onTimes[0]) - 1] = "";
        }
      
  
    }

// String relayStatus = "开启";
litLedsCountStr = getLitLedsCountAsString(leds, NUM_LEDS);

  // 生成HTML内容,包括onTimes和offTimes
  String htmlContent = R"(
        <!DOCTYPE html>
        <html>
        <head>
          <title>插座开关</title>
          <meta charset="UTF-8">

          <script>

            // 在这里插入Arduino生成的时间变量
            var currentTime = ")" + currentTime + R"(";
            var timeParts = currentTime.split(":");
            var hours = timeParts[0];
            var minutes = timeParts[1];
            var seconds = timeParts[2];

            function updateTime() {
              var timeDisplay = document.getElementById("timeDisplay");
              // 分割时间字符串为小时、分钟和秒
              
                    // 每次加1秒
              seconds++;
              // 如果秒数达到60,将秒数重置为0并增加分钟
              if (seconds === 60) {
                seconds = 0;
                minutes++;
        
                // 如果分钟达到60,将分钟重置为0并增加小时
                if (minutes === 60) {
                  minutes = 0;
                  hours++;
        
                  // 如果小时达到24,将小时重置为0
                  if (hours === 24) {
                    hours = 0;
                  }
                }
              }
              // 格式化小时、分钟和秒,确保它们始终显示两位数
              var formattedHours = ('0' + hours).slice(-2);
              var formattedMinutes = ('0' + minutes).slice(-2);
              var formattedSeconds = ('0' + seconds).slice(-2);
              
              // 构建格式化后的时间字符串
              var formattedTime = formattedHours + ":" + formattedMinutes + ":" + formattedSeconds;
//             console.log(formattedTime);
              // 更新时间显示
              timeDisplay.textContent = formattedTime;
            }
            
            // 每秒钟调用一次updateTime函数
            setInterval(updateTime, 1000);
            
            // 当页面加载完成时立即更新时间
            window.onload = updateTime;

            
          </script>
        </head>
        <body>
        <h1>ledPwm:0.设置关机时间列表,1.设置开机时间列表,2.设置现在时间,3.手动开,4.手动关, 5.删除时间</h1>
        <p>现在时间: <span id="timeDisplay">00:00:00</span></p>
        <p>人体传感器阈值: )" + String(pirValue) + R"(</p>
        <p>开列表: )" + getScheduleString(onTimes, onTimesindex)  + R"(<p>
        <p>关列表: )" + getScheduleString(offTimes, offTimesindex) + R"(<p>
        <p><span id="relayStatus">灯珠数量: )" + litLedsCountStr + R"(</span></p>

        </body>
        </html>
      )";

  esp8266_server.send(200, "text/html", htmlContent);
}

String getScheduleString(String* scheduleArray, int scheduleCount) {
  String result = "[";
  for (int i = 0; i < scheduleCount; i++) {
    result += "\"" + scheduleArray[i] + "\"";
    if (i < scheduleCount - 1) {
      result += ", ";
    }
  }
  result += "]";
  return result;
}

void handleUserRequest() {
  
  String reqResource = esp8266_server.uri();
  Serial.print("reqResource: ");
  Serial.println(reqResource);

  bool fileReadOK = handleFileRead(reqResource);

  if (!fileReadOK) {
    esp8266_server.send(404, "text/plain", "404 Not Found");
  }
}

bool handleFileRead(String resource) {
  if (resource.endsWith("/")) {
    resource = "/index.html";
  }

  String contentType = getContentType(resource);

  if (SPIFFS.exists(resource)) {
    File file = SPIFFS.open(resource, "r");
    esp8266_server.streamFile(file, contentType);
    file.close();
    return true;
  }
  return false;
}

String getContentType(String filename) {
  if (filename.endsWith(".htm")) return "text/html";
  else if (filename.endsWith(".html")) return "text/html";
  else if (filename.endsWith(".css")) return "text/css";
  else if (filename.endsWith(".js")) return "application/javascript";
  else if (filename.endsWith(".png")) return "image/png";
  else if (filename.endsWith(".gif")) return "image/gif";
  else if (filename.endsWith(".jpg")) return "image/jpeg";
  else if (filename.endsWith(".ico")) return "image/x-icon";
  else if (filename.endsWith(".xml")) return "text/xml";
  else if (filename.endsWith(".pdf")) return "application/x-pdf";
  else if (filename.endsWith(".zip")) return "application/x-zip";
  else if (filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}

//色
typedef void (*SimplePatternList[])();
SimplePatternList gPatterns = { rainbow, rainbowWithGlitter, confetti, sinelon, juggle, bpm };
uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current
uint8_t gHue = 0; // rotating "base color" used by many of the patterns

#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))


void cdon() {
      gPatterns[gCurrentPatternNumber]();
    // send the 'leds' array out to the actual LED strip
    Serial.println("执行开");
    FastLED.show();  
    // insert a delay to keep the framerate modest
    FastLED.delay(1000/max_bright); 
    // do some periodic updates
    EVERY_N_MILLISECONDS( 20 ) { gHue++; } // slowly cycle the "base color" through the rainbow
    EVERY_N_SECONDS( 10 ) { nextPattern(); } // change
}

void cdoff() {
      Serial.println("执行关");
      fill_gradient_RGB(leds, 0, CRGB(0,0,0), 59, CRGB(0, 0, 0));;
      FastLED.show();
      delay(500);
      turnOffAllLeds();

}
void turnOffAllLeds() {
  // 设置所有LED颜色为黑色(关闭)
  for(int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Black;
  }
  // 更新LED灯的状态
  FastLED.show();
}

String getLitLedsCountAsString(CRGB leds[], int numLeds) {
  int litCount = 0; // 用于计数亮灯的数量
  for (int i = 0; i < numLeds; i++) {
    // 如果LED不是黑色(关闭)表示它是亮的
    if (leds[i]) { // 这里隐式检查leds[i]是否不等于CRGB::Black
      litCount++;
    }
  }
  // 将整数转换为String对象并返回
  return String(litCount);
}

void nextPattern()
{
  // add one to the current pattern number, and wrap around at the end
  gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE( gPatterns);
}

void rainbow() 
{
  // FastLED's built-in rainbow generator
  fill_rainbow( leds, NUM_LEDS, gHue, 7);
}

void rainbowWithGlitter() 
{
  // built-in FastLED rainbow, plus some random sparkly glitter
  rainbow();
  addGlitter(80);
}

void addGlitter( fract8 chanceOfGlitter) 
{
  if( random8() < chanceOfGlitter) {
    leds[ random16(NUM_LEDS) ] += CRGB::White;
  }
}

void confetti() 
{
  // random colored speckles that blink in and fade smoothly
  fadeToBlackBy( leds, NUM_LEDS, 10);
  int pos = random16(NUM_LEDS);
  leds[pos] += CHSV( gHue + random8(64), 200, 255);
}

void sinelon()
{
  // a colored dot sweeping back and forth, with fading trails
  fadeToBlackBy( leds, NUM_LEDS, 20);
  int pos = beatsin16( 13, 0, NUM_LEDS-1 );
  leds[pos] += CHSV( gHue, 255, 192);
}

void bpm()
{
  // colored stripes pulsing at a defined Beats-Per-Minute (BPM)
  uint8_t BeatsPerMinute = 62;
  CRGBPalette16 palette = PartyColors_p;
  uint8_t beat = beatsin8( BeatsPerMinute, 64, 255);
  for( int i = 0; i < NUM_LEDS; i++) { //9948
    leds[i] = ColorFromPalette(palette, gHue+(i*2), beat-gHue+(i*10));
  }
}

void juggle() {
  // eight colored dots, weaving in and out of sync with each other
  fadeToBlackBy( leds, NUM_LEDS, 20);
  byte dothue = 0;
  for( int i = 0; i < 8; i++) {
    leds[beatsin16( i+7, 0, NUM_LEDS-1 )] |= CHSV(dothue, 200, 255);
    dothue += 32;
  }
}