sparkwlf
Published © MIT

KitchenHelper-This is a visual timer controlled by voice.

This kitchen timer product provides convenient operation for food cooks. Users can easily set the timer, visually check and understand the t

IntermediateFull instructions provided2 hours85
KitchenHelper-This is a visual timer controlled by voice.

Things used in this project

Hardware components

NodeMCU ESP8266 Breakout Board
NodeMCU ESP8266 Breakout Board
×1
Gravity: Speech Synthesis Module(Support English and Chinese)
DFRobot Gravity: Speech Synthesis Module(Support English and Chinese)
×1
Speaker, Piezo
Speaker, Piezo
×1
DHT11 Temperature & Humidity Sensor (4 pins)
DHT11 Temperature & Humidity Sensor (4 pins)
×1
Jumper wires (generic)
Jumper wires (generic)
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

KitchHelper BOX

Cap

Schematics

KitchenHelper Box

Line connection diagram

Code

KitchenHelp program

C/C++
#include <Arduino.h>
#ifdef ESP32
#include <WiFi.h>
#else
#include "ESP8266WiFi.h"        // 本程序使用 ESP8266WiFi库
#endif

#include <DHT.h>                //引入DHT11库
#include <ESP8266WebServer.h>   //  ESP8266WebServer库
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <EEPROM.h>
#include <FastLED.h>
#include <Ticker.h>
#include <PubSubClient.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#include <ArduinoOTA.h>
#include "config.h"

int otaFlag=0;                        //0:普通工作模式,1:刷机模式
bool otaInProgress = false;

String devwxid="";
String deviceId="";
String deviceType="0";
String wifiSetting = "0";             //0代表未完成,1代表完成

const char *pubTOPIC = "pub_topic_mqtt";

int recCount=0;
unsigned char recBuffer[5];           //定义串口接收数组
WiFiClient espClient;
PubSubClient mqttClient(espClient);

CRGB leds[NUM_LEDS];              //建立光带leds
//CHSV timerHSVColor(39,255,50);   //HSV方法定义计时器显示颜色timerHSVColor(色调,饱和度,亮度)
int curColor;
uint32_t curDelay;

Ticker ledActionTimer;

WiFiUDP ntpUDP;          //创建UDP实例
NTPClient timeClient(ntpUDP, "pool.ntp.org");

//Last time when the LEDs were updated
bool needTo_sendDHT=false;
DHT dhtSensor(DHT_DATA_PIN,DHTTYPE);   
float sensor_hum;
float sensor_tem; 

Ticker delayTimer;

//定义闪存WIFI信息结构体
struct config_type{
  char stassid[32];
  char stapsw[64];
  char devid[16];
  char curMode[16];  
};
config_type devConfig;

int clockCount;
Ticker clockTicker;  //每隔1分钟采集一次网络时间

int dhtCount;
Ticker dhtTicker;               

Ticker ringTimer;               //定义铃声
int ringCount = 0;              //定义播放次数计数器  

int input1Time=0;               //定义第一面的计时秒数
int input2Time=0;               //定义第二面的计时秒数
int lightUpInterval=0;          //定义循环时间
int lightsOff=NUM_LEDS-1;       //要熄灭的led灯
int timerCount=0;           
Ticker timerTicker;

uint32_t timesTotal=0;
bool timerFlag=false;             //计时标志
Ticker totalTimerTicker;          //秒数计时

ESP8266WebServer esp8266_server(80);  // 建立ESP8266WebServer对象,对象名称为esp8266_server
                                    
void setup(){
  //设置串口波特率,以便打印信息
  Serial.begin(9600);
  while(Serial.read()>= 0) {}   //清除串口缓存
  //Serial1.begin(115200);

  // INIT LED
  FastLED.addLeds<LED_TYPE, LED_DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);   // 光带初始化WS2812B (Neopixel)
  FastLED.setMaxPowerInVoltsAndMilliamps(5, 100);                         //电源管理:设置最大电压(5v)和最大电流(500mA),让不会消耗Arduino太大电流。
  FastLED.setBrightness(max_bright);                                      // 设置光带亮度 
  FastLED.clear();
  FastLED.show();
  delay(100);
  loadConfig();        //获取ESP8266闪存数据
  if (strcmp(devConfig.curMode, "") == 0) {
    //Serial1.println("当前为离线模式WIFI未设置");
    VoicePlay(0x05,0,0);            //发送语音告知
    delay(2000);
    //curRGBColor.r=0;
    //curRGBColor.g=0;
    //curRGBColor.b=255;
    //leds[0]=CRGB::Red;             //熄灭最后一盏灯
    //leds[11]=CRGB::Green;             //熄灭最后一盏灯
    //leds[2]=CRGB::Blue;             //熄灭最后一盏灯
    //FastLED.show();
    for (int i=0;i<3;i++) {
      fill_solid(leds, NUM_LEDS,CRGB::Red);   
      FastLED.show();  
      delay(500);
      fill_solid(leds, NUM_LEDS,CRGB::Black);   
      FastLED.show(); 
      delay(500);
    } 
  }

  if (strcmp(devConfig.curMode, "1") == 0) {  
    connectWiFi();
    if (WiFi.status() == WL_CONNECTED) {
      Serial1.println(F("WIFI IS SUCCESSED...")); 
      VoicePlay(0x06,0,0);            //发送在线语音告知
      
      ledOff();
      
      for (int i=0;i<3;i++) {
        fill_solid(leds, NUM_LEDS,CRGB::Green);   
        FastLED.show();  
        delay(500);
        fill_solid(leds, NUM_LEDS,CRGB::Black);   
        FastLED.show(); 
        delay(500);
      } 

      // INIT OTA
      ArduinoOTA.setHostname(ESP_NAME);
      ArduinoOTA.onStart([]() {
      otaInProgress = true;
        Serial.println(F("Start updating..."));
      });
      ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
        Serial.println(progress / (total / 100));
      });
      ArduinoOTA.onEnd([]() {
        Serial.println(F("\nend"));
        otaInProgress = false;
      });
      ArduinoOTA.onError([](ota_error_t error) {
      String msg;
      if (error == OTA_AUTH_ERROR)
        msg = F("auth failed");
      else if (error == OTA_BEGIN_ERROR)
        msg = F("begin failed");
      else if (error == OTA_CONNECT_ERROR)
        msg = F("connect failed");
      else if (error == OTA_RECEIVE_ERROR)
        msg = F("receive failed");
      else if (error == OTA_END_ERROR)
        msg = F("end failed");
        Serial.printf_P(PSTR("Error: %s"), msg.c_str());
      });
      ArduinoOTA.begin();

            
      //初始化ONENET通信,客户端设置MQTT服务器 & 回调函数
      mqttClient.setServer(MQTT_SERVER, MQTT_PORT);
      mqttClient.setCallback(mqttCallback);
      //mqttClient.setBufferSize(MQTT_BUFF_SIZE);
      mqttConnect();
      delay(300); 

      // CLOCK
      timeClient.begin();
      timeClient.setTimeOffset(28800);
      getNtpTime();
  
      clockTicker.attach(1,tickerClockCount);
      delay(50);       
    }
  }

  if (strcmp(devConfig.curMode, "2") == 0) { 
    initWiFi();        //进入配网函数
  }
  
  FastLED.clear();
  FastLED.show();  
  delay(100); 
  
  //DHT
  dhtSensor.begin();
  getDHTdata();
  dhtTicker.attach(1, tickerDhtCount); 
}

void loop()
{          
  unsigned long curMillis = millis();             //获取当前系统时间

  // put your main code here, to run repeatedly:
  getSerialData(); 
  if (recCount==5) {                      //串口数据包长度正确        
    recCount=0;
    if ((recBuffer[0]==0xAA) && (recBuffer[1]==0x55) && (recBuffer[3]==0x55) && (recBuffer[4]==0xAA)) {
      unsigned char cmdUart=recBuffer[2];
      switch (cmdUart) {
        case 0xB8:                          //8分熟牛排                
          led1Default();                    //led计时初始化          
          input1Time=60;                    //第一面定义60秒计时
          input2Time=90;                    //第二面定义90秒计时 
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);                 //设置每隔1秒触发一次tickerTimerCount函数  
          break;
        case 0xB5:                          //5分熟牛排
          led1Default();                    
          input1Time=40;                    //第一面定义40秒计时
          input2Time=60;                    //第二面定义60秒计时 
          lightUpInterval=(int) (input1Time / NUM_LEDS); 
          timerTicker.attach(1, tickerTimerCount);                 //设置每隔1秒触发一次tickerTimerCount函数  
          break;
        case 0xBF:                          //全熟牛排
          led1Default();                    
          input1Time=60;                    //第一面定义60秒计时
          input2Time=120;                   //第二面定义120秒计时 
          lightUpInterval=(int) (input1Time / NUM_LEDS); 
          timerTicker.attach(1, tickerTimerCount);                 //设置每隔1秒触发一次tickerTimerCount函数  
          break;
        case 0xD8:                            //清蒸大闸蟹
          led1Default();                      //led计时初始化
          input1Time=1320;                    //冷水大火蒸22分钟计时
          input2Time=300;                     //关火后焖5分钟计时 
          lightUpInterval=(int) (input1Time / NUM_LEDS); 
          timerTicker.attach(1, tickerTimerCount);                 //设置每隔1秒触发一次tickerTimerCount函数  
          break;

        case 0xF0:                          //调亮一点
          max_bright=max_bright+1;
          FastLED.setBrightness(max_bright); 
          break;
        case 0xF1:                          //调暗一点
          max_bright=max_bright-1;
          if (max_bright <= 0){
            max_bright=0;
          }
          FastLED.setBrightness(max_bright);
          break;

        case 0xFE:                          //启动WIFI配置模式
          restoreFactory(true);
          break;
        case 0xFF:                          //恢复初始设置
          delay(3000);
          restoreFactory(false);
          break;
       
        case 0xDD:                          //切换到时钟模式
          //timerTicker.detach();
          Serial.println(F("switch NETWORK TIME... \n"));
          //delay(2000);
          //VoicePlay(0x01,0,0);
          break;          
        case 0xEE:                          //取消计时|停止计时
          ledOff();
          
          ringTimer.detach();
          
          input1Time=0;                     
          input2Time=0;          
          if (timerFlag == true)  {           //时间计时中
            totalTimerTicker.detach();
            int mHours, mMinutes, mSeconds;
            convertSecondsToTime(timesTotal, mHours, mMinutes, mSeconds);            
            VoicePlay(0x0E,mHours,0); 
            delay(10);   
            VoicePlay(0x0F,mMinutes,0); 
            delay(20);   
            VoicePlay(0x10,mSeconds,0);
            timesTotal=0;
          }
          else  {
            VoicePlay(0x01,0,0); 
          }
          timerFlag=false;
          break;
          
        case 0xD0:                          //三十秒计时 
          led1Default();
          input1Time=30;                   
          input2Time=0;          
          lightUpInterval=(int) (input1Time / NUM_LEDS);                    
          timerTicker.attach(1, tickerTimerCount);                 //设置每隔1秒触发一次tickerTimerCount函数
          //Serial.println("30s start()........");
          break;
        case 0xD1:                          //四十秒计时          
          led1Default();          
          input1Time=40;                  
          input2Time=0; 
          lightUpInterval=(int) (input1Time / NUM_LEDS);       
          timerTicker.attach(1, tickerTimerCount);                //设置每隔1秒触发一次tickerTimerCount函数
          break;
        case 0xD2:                          //五十秒计时
          led1Default();          
          input1Time=50;                   
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);      //设置每隔1秒触发一次tickerTimerCount函数
          break;
        case 0xD3:                          //一分钟钟计时          
          led1Default();          
          input1Time=60;                  
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);                 //设置每隔1秒触发一次tickerTimerCount函数
          break;
        case 0xD4:                          //一分半计时          
          led1Default();          
          input1Time=90;                 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);                //设置每隔1秒触发一次tickerTimerCount函数
          break;
        case 0xD5:                          //两分钟计时          
          led1Default();          
          input1Time=120;                  //定义120秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);                 //设置每隔1秒触发一次tickerTimerCount函数
          break;
        case 0xD6:                          //两分半计时          
          led1Default();          
          input1Time=150;                  //定义150秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);                 //设置每隔1秒触发一次tickerTimerCount函数
          break;
        case 0xD7:                          //三分计时          
          led1Default();          
          input1Time=180;                  //定义180秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);                //设置每隔1秒触发一次tickerTimerCount函数
          break;
        case 0xC4:                          //四分计时          
          led1Default();          
          input1Time=240;                  //定义320秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);                 //设置每隔1秒触发一次tickerTimerCount函数
          break;
        case 0xC5:                          //五分计时          
          led1Default();          
          input1Time=300;                  //定义300秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);                 //设置每隔1秒触发一次tickerTimerCount函数
          break;
        case 0xC6:                          //六分计时          
          led1Default();          
          input1Time=360;                  //定义360秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xC7:                          //七分计时          
          led1Default();          
          input1Time=420;                  //定义420秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xC8:                          //八分计时
          led1Default();          
          input1Time=480;                  //定义480秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xC9:                          //九分计时          
          led1Default();          
          input1Time=540;                  //定义540秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xA1:                          //十分钟计时          
          led1Default();          
          input1Time=600;                  //定义600秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        
        case 0xA2:                          //十五分钟计时          
          led1Default();          
          input1Time=900;                  //定义900秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xA3:                          //二十分钟计时          
          led1Default();          
          input1Time=1200;                  //定义1200秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xA6:                          //二十五分钟计时          
          led1Default();          
          input1Time=1500;                  //定义1500秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xA4:                          //三十分钟计时          
          led1Default();          
          input1Time=1800;                  //定义1800秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xA7:                          //三十五分钟计时          
          led1Default();          
          input1Time=2100;                  //定义2100秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xA8:                          //四十分钟计时          
          led1Default();          
          input1Time=2400;                  //定义2400秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xB6:                          //四十五分钟计时          
          led1Default();          
          input1Time=2700;                  //定义2700秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xB7:                          //五十分钟计时          
          led1Default();          
          input1Time=3000;                  //定义3000秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xA5:                          //一小时计时          
          led1Default();          
          input1Time=3600;                  //定义3600秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xC3:                          //一个半小时计时          
          led1Default();          
          input1Time=5400;                  //定义5400秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xC2:                          //两小时计时          
          led1Default();          
          input1Time=7200;                  //定义7200秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;
        case 0xC1:                          //两小时半计时          
          led1Default();          
          input1Time=9000;                  //定义9000秒计时 
          input2Time=0;
          lightUpInterval=(int) (input1Time / NUM_LEDS);
          timerTicker.attach(1, tickerTimerCount);
          break;

        case 0xB1:                          //开始计时
          ledOff();
          timesTotal=0;
          timerFlag=true;                   //计时标志
          totalTimerTicker.attach(1,gatherTimesTicker);                 //设置每隔1秒触发一次gatherTimesTicker计时函数  
          break;        
          
        default:
          break;
      }
    }
  }
  
  if (input1Time > 0) {                  //A面计时
    if (timerCount >= input1Time ) {
      timerTicker.detach();
      
      ledOff();
      input1Time=0;
      timerCount=0;

      if (input2Time>0) {
        switch (input2Time) {
          case 60:
            VoicePlay(0x09,0,0);            //计时开始,发送语音告知
            break;
          case 90:
            VoicePlay(0x0A,0,0);            //计时开始,发送语音告知
            break;
          case 120:
            VoicePlay(0x0B,0,0);            //计时开始,发送语音告知
            break;
          case 300:
            VoicePlay(0x07,0,0);            //蒸后关火焖计时开始,发送语音告知
            break;
          default:
            VoicePlay(0x08,0,0);              //A面完成语音告知
            break;
        }
              
        led2Default();  
          
        lightUpInterval=(int) (input2Time / NUM_LEDS);   
        timerTicker.attach(1, tickerTimerCount);                //设置每隔1秒触发一次tickerTimerCount函数        
      }
      else{
        VoicePlay(0x01,0,0); 
        dhtTicker.attach(1, tickerDhtCount); 
        clockTicker.attach(1,tickerClockCount);    
        //delay(50);
        //ledOff();                         //再刷新一次 
      }
    }
  }

  if ((input2Time > 0) && (input1Time == 0)) {                  //B面计时
    if (timerCount >= input2Time) {      // 当到达计时时间时       
      timerTicker.detach();              //关闭定时器
      ledOff();                          //熄灭最后一盏灯
     
      timerCount = 0; 
      input2Time=0;
      input1Time=0;
      VoicePlay(0x01,0,0);              //B面完成语音告知  
      
      dhtTicker.attach(1, tickerDhtCount); 
      clockTicker.attach(1,tickerClockCount);    
    }
  }

  if (timerFlag){           //正在计时中......
    //ppLed();
    timerLed();
  }

  if ((input1Time ==0 ) && (input2Time ==0)) {    
    //每隔2分钟DHT采集一次数据
    if (dhtCount >= 120)  {
      //Serial.println("开始采集DHT信息... \n");
      getDHTdata();
      dhtCount=0;         
    }
    
    bool wifiIsConnected = WiFi.isConnected();
    if (wifiIsConnected){
      //check OTA update progress
      if (otaFlag ==  1) {
        ArduinoOTA.handle();
        if (otaInProgress) {
            return;
        }
      }
            
      // put your main code here, to run repeatedly:
      //每隔1分钟采集一次网络时间数据
      if (clockCount  >= 60) {
        clockCount=0;
        getNtpTime();
      }
    
      // HANDLE MQTT  
      static unsigned long lastMqttConnMillis = 0;
      //Serial1.println("HANDLE MQTT....");
      if (!mqttClient.connected()) {
        Serial1.println(F("当前MQTT未连接"));
        if (curMillis - lastMqttConnMillis > 3000) {
          Serial1.println(F("Disconnected from MQTT"));
          mqttConnect();
          lastMqttConnMillis = curMillis;
        }
      }
      else {
        mqttClient.loop();      

        if(needTo_sendDHT)  {
          //MQTT发送数据      
          //String dhtData ="温度:"+String(sensor_tem) +"℃"+","+"湿度:"+ String(sensor_hum)+"%" ; //生成要传输的数据
          //strcpy(c_DHT,dhtData.c_str());
          sendDHTdata();
          delay(100);
        }
      }
    }
  }
  delay(50);
  FastLED.show();
   // 释放内存  
  //freeRam();  
}

Credits

sparkwlf

sparkwlf

3 projects • 0 followers
上善若水,厚德载物。

Comments