基于ESP32的智能台灯-PWM网页调光-实时时间-OLED显示-语音闹钟-WEB远程操控

具体的项目,我免费分享在我的项目里,供大家参考学习:

chenyuhan1997/ESP32-SMART-WIFI-PWM-LED-ALARM-CLOCK: Desk lamp with PWM adjustable brightness, alarm clock can be set, LED display real-time time, music and alarm can be played by voice (github.com)https://github.com/chenyuhan1997/ESP32-SMART-WIFI-PWM-LED-ALARM-CLOCK同时,我也把项目上传在了CSDN上,欢迎大家下载浏览。

(1条消息) 基于ESP32的语音智能台灯-智能家居文档类资源-CSDN文库

具体的效果图如下,大家可以看一看,我找了些3D打印剩下的盒子来进行拼装工作。效果很不错,不过没有画PCB,卖相并不讨喜。

所用到的技术除PWM调光外,和我之前所制作的ESP32语音舵机(闹钟盒子)基本相差不大。不过网页会更好看一些。

(2条消息) ESP32的网络定时舵机控制,廉价语音定时开关箱,OLED实时显示时间-智能家居文档类资源-CSDN文库

首先看下成品图:

接下来讲将具体的一个代码和用到的方法。

首先是使用的库:

#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "SPIFFS.h"
#include "ESPAsyncWebServer.h"
#include "AsyncTCP.h"
#include "ArduinoJson.h"
//人工语音合成库
#include "SoundData.h"
#include "XT_DAC_Audio.h"
// 引入驱动OLED0.91所需的库
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//舵机使用的不是直接的舵机库
#include <Arduino.h>
#include "time.h"
#include <soc/rtc_cntl_reg.h>

我们使用了FreeRTOS系统,所以需要进行CPU分配

#define pro_cpu   0   
#define app_cpu   1

同时进行0.91屏的初始定义和引脚定义

#define SCREEN_WIDTH 128 // 设置OLED宽度,单位:像素
#define SCREEN_HEIGHT 32 // 设置OLED高度,单位:像素
//宏定义部分引脚
#define buzzer 15        //蜂鸣器
#define dismiss_button 13    //关闭按钮
//cpu分配
#define OLED_RESET 4  //声明RST的引脚
#define Yuyin_IO 25

接下来是一些初始变量

//人工语音函数
XT_Wav_Class ForceWithYou(rawData);     //引言的XT库中对FORCE的处理                                      
XT_DAC_Audio_Class DacAudio(Yuyin_IO,0);      //设置引脚
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);//ssd设置规范化
//设置类型变量声明
const  char  *ssid = "ccc2021"; //你的网络名称
const  char *password = "cyh1217552389"; //你的网络密码
const  char  *ntpServer = "pool.ntp.org"; //ntpserver的类型
const  long  gmtOffset_sec = 8 * 3600; //声明变量
const int daylightOffset_sec = 0;
//html输入文本

const char* TEXT_INPUT2 = "HTML_INT_INPUT2";// Integer type input

//PWM灯光设置
const int output = 12;// Connected to D2 Pin of ESP32
String sliderValue = "0";//initial Slider value
// setting PWM properties
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 8;
const char* PARAM_INPUT = "value";


//定时器程序的相关定义,这里主要是声明的意思
static hw_timer_t* sync_timer_handler = NULL; //固定声明一个定时器
//全局标志位的定义,主要是初始化和相关声明
//闹钟参数
char present_time[6];//存储当前的小时和分钟,当缓冲区
String _date, _time, _date_formatted;//读取数据的字符串
uint32_t DemoCounter=0;
char timeHour[10];
String inputMessage;
String inputParam;
String alarm_time;
String myString;

这里不做过多的赘述

使用异步服务器:

AsyncWebServer server(80);//将WEB服务器的端口pnning到80,就是服务器初始化的标准

定时器声明:

//定时器详情
static const uint16_t timer_divider = 80;//所有的定时器频率
static uint64_t alarm_timer_exact_count;//实际的闹钟计

接下来看看重要的相关函数定义:

首先是我们的HTML端的一个书写:

// HTML web page界面的设置
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
 <head>
   <meta name="viewport" charset="utf-8" content="width=device-width, initial-scale=1">
   <title>ESP32 智能 闹钟</title>
   <style>
     html {font-family: Arial; display: inline-block; text-align: center;}
     h2 {font-size: 2.3rem;}
     p {font-size: 1.9rem;}
     body {max-width: 400px; margin:0px auto; padding-bottom: 25px;}
     .slider { -webkit-appearance: none; margin: 14px; width: 360px; height: 25px; background: #FFD65C;
       outline: none; -webkit-transition: .2s; transition: opacity .2s;}
     .slider::-webkit-slider-thumb {-webkit-appearance: none; appearance: none; width: 35px; height: 35px; background: #003249; cursor: pointer;}
     .slider::-moz-range-thumb { width: 35px; height: 35px; background: #003249; cursor: pointer; } 
   </style>
 </head>
<body>
  <h2><u>ESP32 智能 闹钟</u></h2>
  <p>PWM VALUE = <span id="textSliderValue">%SLIDERVALUE%</span></p>
  <p><input type="range" onchange="updateSliderPWM(this)" id="pwmSlider" min="0" max="255" value="%SLIDERVALUE%" step="1" class="slider"></p>
<script>
function updateSliderPWM(element) 
{
  var sliderValue = document.getElementById("pwmSlider").value;
  document.getElementById("textSliderValue").innerHTML = sliderValue;
  console.log(sliderValue);
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/slider?value="+sliderValue, true);
  xhr.send();
}
</script>
  <div style="display: block; margin: 0 auto; width: 50%; background: #ccc;">  
    <form action="/get">
    <br>
      <h2>输入闹钟( XX:XX:XX ) : </h2>
      <input type="text" name="HTML_INT_INPUT2" id = "alarm_inset">
      <input type="submit" value="Submit">
    </form><br>
    <br> 
    <button onclick="showUname()" align="center">显示上一次设定时间</button>
    <div id="uname-show"></div>
    <script>
       function showUname(){
            document.getElementById("uname-show").innerHTML = "<h1>" + document.getElementById("alarm_inset").value + "</h1>";
        }
    </script>
    <br>
    </div>
</body>
</html>
)rawliteral";



void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}










void web_server_task_function(void* paramters)
{
  Serial.println("Setting up the HTTP server");//串口打印设置HTTP服务器
 // Send web page with input fields to client
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
    Serial.println("HTTP START");
  });

  // Send a GET request to <ESP_IP>/get?input1=<inputMessage>
  server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage;
    String inputParam;
    // GET input2 value on <ESP_IP>/get?input2=<inputMessage>
    if (request->hasParam(TEXT_INPUT2)) {
      inputMessage = request->getParam(TEXT_INPUT2)->value();
      inputParam = TEXT_INPUT2;
      alarm_time = inputMessage;
      Serial.println("alarm clock : ");
    }
    else{
      inputMessage = "No Input Text sent on ESP32";
      inputParam = "none";
    }
    Serial.println(inputMessage);
    request->send(200, "text/html", "HTTP GET request sent to your ESP on input field (" 
                                     + inputParam + ") with value: " + inputMessage +
                                     "<br><a href=\"/\">Return to Home Page</a>");
  });

  server.on("/slider", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage;
    // GET input1 value on <ESP_IP>/slider?value=<inputMessage>
    if (request->hasParam(PARAM_INPUT)) {
      inputMessage = request->getParam(PARAM_INPUT)->value();
      sliderValue = inputMessage;
      ledcWrite(ledChannel, sliderValue.toInt());
    }
    else 
    {
      inputMessage = "No message was sent";
    }
    Serial.println(inputMessage);
    request->send(200, "text/plain", "OK");
  });

  
  server.begin();//starting the server
  Serial.println("HTTP server setup completed");
  vTaskDelete(NULL);
  
}

其次最重要的就是实时闹钟这部分,我们获取了时间字符串,然后很简单的进行了一个输入字符串的比对,就完成了定闹钟的操作:

void printLocalTime()
{
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo))
  {
    display.println("Failed to obtain time");
    return;
  }
  display.println(&timeinfo, "%F"); // 格式化输出
  display.println(&timeinfo, "%T"); // 格式化输出
  display.println(&timeinfo, "%A"); // 格式化输出
}

void OLED_Function(void *pvParameters){
  for(;;){
  vTaskDelay(1000);
  //清除屏幕
  display.clearDisplay();
  //设置光标位置
  display.setCursor(0, 0);
  printLocalTime();
  display.display();
  Serial.println("DISPLAY ONCE AGAIN!");
    }
  }



void clock_task_function(void* parameters)
{
  Serial.println("clock function start!");
  while(1)
  {
    struct tm timeinfo;
    if (!getLocalTime(&timeinfo))
    {
    Serial.println("Failed to obtain time");
    return;
    }
    Serial.println("start print");
    strftime(timeHour, 10, "%T", &timeinfo);
    myString = String(timeHour);
    Serial.println(myString);
    Serial.println("TIME WRITE success!");
    vTaskDelay(1000/portTICK_PERIOD_MS);//这里设置的是无任务时间
  }
}




void alarm_task_function(void* parameters)
{
     Serial.println("alarm function start!");
     while(1)
     {
         Serial.println("alarm is setting!");
         vTaskDelay(1000/portTICK_PERIOD_MS);
         if(alarm_time == myString)//这里使用了memcmp函数,这个函数是将两个内存的字节进行比较,当时间校正一致时,才能发生循环
        {
         
          Serial.println("Time Right!");
          while(1)//循环
          {
          
             for(int i=0; i<2; i++)//蜂鸣器循环叫3轮
             {
                digitalWrite(buzzer, HIGH);
                vTaskDelay(500/portTICK_PERIOD_MS);
                digitalWrite(buzzer, LOW);
                vTaskDelay(500/portTICK_PERIOD_MS);
                Serial.println("alarm is sound loundly");
                YuyinBB();
              }

              
             if(!digitalRead(dismiss_button))//如果按了关闭按钮,两个标志位变False,并且串口打印闹钟关闭提醒
             { 
                Serial.println("clock is close!");              
                break;
              }
             vTaskDelay(1000/portTICK_PERIOD_MS);//经典延时
           }                                                                                                    
       }
  }
}

最后就是FREERTOS的任务分配:

  xTaskCreatePinnedToCore(clock_task_function, "clock_task", 2048, NULL, 1, &clock_task_handler, pro_cpu);//clock task
  xTaskCreatePinnedToCore(alarm_task_function, "alarm_task", 2048, NULL, 1, &alarm_task_handler, app_cpu);//alarm task
  xTaskCreatePinnedToCore(web_server_task_function, "server_task", 6000, NULL, 1, &web_server_task_handler, pro_cpu);//web server tasks
  xTaskCreatePinnedToCore(OLED_Function, "oled_Task", 10000, NULL, 1, NULL, app_cpu);
  //NTPClient初始化

其中需要去提及的就是廉价语音的一个实现。这个我推荐直接参考我之前的文章

(1条消息) ESP32的智能网络定时舵机和语音控制+OLED实时时间显示_Reedsway在重庆的博客-CSDN博客_esp32 语音控制

这里就不再赘述。

  • 11
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ReedswayYuH.C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值