小爱同学+8266的小爱语音台灯,基于Blinker库

“我们的动力源于对电子的热爱”

为大家详细介绍最近的语音台灯,不用了解各种通讯协议,直接调用函数,小白也会!

链接:https://pan.baidu.com/s/12m0TMhjH7SR9DHA_pTowBg?pwd=m4zf 
提取码:m4zf

小爱同学+8266的小爱语音台灯,基于Blinker库_第1张图片

目录

想法的产生

软件描写

使用Blinker.app 

 将设备接入米家

 Arduino IDE

环境搭建:

 EC11编码按键

WS2812

 工程代码

代码详解

硬件搭建 

灯板

台灯主板

亮度控制

电池充电芯片4056

灯板供电升压 芯片XL6007E1

ESP-12S

供电切换

 WS2812焊接

 外壳

 工程链接


想法的产生

刷B站时发现一位博主 用8266+blinker库制作了一个语音台灯,讲解的非常详细

原视频链接:

ESP8266联动小爱同学/点灯科技远程控灯,小白也能轻松搞定。_哔哩哔哩_bilibili

会用到的点灯科技公司网址:点灯科技-点灯物联网解决方案

有不懂的可以直接查看开发文档,遇到的问题都可以在论坛上查到

小爱同学+8266的小爱语音台灯,基于Blinker库_第2张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第3张图片

 我能不能做一个像米家台灯一样的物联网台灯呢,于是就有了这个项目

台灯要可以小爱同学语音控制,还可以在手机上查看台灯的状态信息,还有实体按键控制

8266-12s + EC11编码按钮 + WS2812

小爱同学+8266的小爱语音台灯,基于Blinker库_第4张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第5张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第6张图片

软件描写

使用Blinker.app 

需要到点灯科技官网下载

小爱同学+8266的小爱语音台灯,基于Blinker库_第7张图片

注册好后进入此界面(台灯是我已经注册好的) ,点击右上角+添加设备,点击独立设备

 小爱同学+8266的小爱语音台灯,基于Blinker库_第8张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第9张图片

 我用的ESP8266,所以选择网络接入,接下来生成密钥(设备身份证)

 小爱同学+8266的小爱语音台灯,基于Blinker库_第10张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第11张图片

 界面就会生成新的设备了, 可以点击编辑按钮添加组件,当组件触发后只需要在8266中的回调函数执行相应任务就行了           

 小爱同学+8266的小爱语音台灯,基于Blinker库_第12张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第13张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第14张图片

 将设备接入米家

 需要8266烧入代码,点灯科技有示例代码,认真看就懂

#define BLINKER_WIFI
#define BLINKER_MIOT_LIGHT  //小爱同学light接口函数

#include 

char auth[] = "********";              //换成APP获取到的密匙
char ssid[] = "********";              //WiFi账号
char pswd[] = "********";              //WIFI密码

Blinker库下载:https://github.com/blinker-iot/blinker-library/archive/master.zip

只能说人家介绍的非常详细:点灯科技-点灯物联网解决方案

看不明白的也可以跟着视频:ESP8266联动小爱同学/点灯科技远程控灯,小白也能轻松搞定。_哔哩哔哩_bilibili

小爱同学+8266的小爱语音台灯,基于Blinker库_第15张图片

进入米家APP>我的>其他平台设备>添加,找到电灯科技,返回时就会看到绑定的点灯科技了,点击同步设备就可以看到我们的台灯了

 小爱同学+8266的小爱语音台灯,基于Blinker库_第16张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第17张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第18张图片

 Arduino IDE

环境搭建:

本次的台灯用到了两个库

#include   
//下载地址:https://github.com/blinker-iot/blinker-library/archive/master.zip

#include 
//可直接在IDE > 项目 > 加载库 > 添加库 里面找到

 EC11编码按键

我自己写的不太好用,这位老师讲的好,编码器代码源于:

【Arduino实验篇】第29课 旋转编码器实验_哔哩哔哩_bilibili

int getEncodeTurn(void)   //按键编码器
{
  static int oldA = HIGH;
  static int oldB = HIGH;
  static int swcount = 0;           //按键开关延时
  int result = 0;

  int newA = digitalRead(add);      //add.cut.sw是自己定义的引脚
  int newB = digitalRead(cut);

if(newA != oldA || newB != oldB)
  {
     if(oldA == HIGH && newA == oldA)
     {
        result = (oldB * 2 - 1);
     }
  }
  oldA = newA;
  oldB = newB;

  if(!digitalRead(sw)){               //按压检测,开关台灯
    delay(30);
    if(!digitalRead(sw)){
       while(!digitalRead(sw)){;}     //松手检测,长按就会触发看门狗,重启,替代复位开关
       if(LED!=0){LED = 0;}
       else {LED = startled;}         //开启时等于初始亮度
       delay(100);
    }   
  }
  
  return result;
}

WS2812

我的指示灯灯珠的IN脚接的是GPIO16,好像用常见的库点不亮灯,找问题花了一点时间,发现FastLED.h可以驱动.我需要自己调颜色,用到了一下操作:

跟多使用方法可以看看:FastLED库 – 太极创客 (taichi-maker.com)

#include 

#define LED_PIN     16     //我的LED信号线IN接在16引脚
#define NUM_LEDS    1    //我的灯带一共级联了1颗LED
CRGB leds[NUM_LEDS];

void setup() {
  FastLED.addLeds(leds, NUM_LEDS);
  FastLED.setBrightness(100);  //可以设置全局亮度,调低亮度不刺眼
}

void loop() {
  
  leds[0].r = 0;     
  leds[0].g = 100;   
  leds[0].b = 30;     
  FastLED.show();
  delay(1000);
  
  leds[0].r = 100;    
  leds[0].g = 20;    
  leds[0].b = 0;     
  FastLED.show();
  delay(1000);

  leds[0].r = 0;    
  leds[0].g = 80;    
  leds[0].b = 100;   
  FastLED.show();
  delay(1000);
}

 工程代码

直接粘,省的下载

#define BLINKER_WIFI
#define BLINKER_MIOT_LIGHT  //小爱同学light接口函数

#include 
#include 

char auth[] = "**********";               //换成APP获取到的密匙
char ssid[] = "**********";               //WiFi账号
char pswd[] = "**********";               //WIFI密码


#define LED_PIN     16    //我的LED信号线IN接在16引脚
#define NUM_LEDS    1     //我的灯带一共级联了1颗LED
CRGB leds[NUM_LEDS];

#define add    4    //+
#define sw     2    //sw
#define cut    5    //-
#define stdby  14   //充电停止
#define chrg   12   //充电检测
#define pwm    13   //pwm输出引脚

#define BUTTON_1 "ButtonKey"
#define Slider_1 "SliderKey"
#define Slider_2 "SliderKey"

BlinkerButton Button1("sw");     //按钮名称”sw“
BlinkerSlider Slider1("lightw"); //滑块名称”lightw“
BlinkerSlider Slider2("timing"); //滑块名称”timing“
BlinkerNumber NMU1("runtime");   //文本显示运行时间,"runtime"为文本框名称
BlinkerNumber NMU2("battery");   //文本显示电压,"battery"为文本框名称
BlinkerImage  Image1("charge");  //APP充电图标显示

int LED = 0;               //LED亮度1-100
int startled = 20;         //台灯开启的初始亮度
int timeoff = 0;           //台灯关闭时间
int timestart;             //记录定时开始的时间
int chstate = 8;           //供电状态,控制指示灯颜色和app图片
float batteryv = 0;        //电池电压
bool oState = false;
bool blinkerrun = true;    //按键是否有触发判断
bool Mi_get = false;       //小爱同学是否触发

//·································································//
void button1_callback(const String & state)    //APP按钮控制开关
{
    BLINKER_LOG("get button state: ", state);
       
    Blinker.vibrate();        //手机震动
    
    if (state=="on") {    
      if(LED == 0){                //灯已经打开就不操作
        LED = startled;            //开灯占空比设置为20
      }
        Button1.print("on");       // 反馈给APP按键开关状态   
    } 
    else if(state=="off"){
        LED = 0;                   //占空比为0,实现关灯
        Button1.print("off");      // 反馈给APP按键开关状态  
              
        timeoff = 0;               //台灯关闭时间清零
        Slider2.print(0);          //调整定时滑块 
    }     
    Slider1.print(LED);         //调整亮度滑块 
}
void slider1_callback(int32_t value)           //滑块亮度控制
{    
    LED=value;   //接收亮度值
   
      if(LED == 0){
        
         Button1.print("off");      // 反馈给APP按键开关状态  
         
         timeoff = 0;               //台灯关闭时间清零
         Slider2.print(0);          //调整定时滑块 
      }
      else{
         Button1.print("on");       // 反馈给APP按键开关状态  
      }
      
    Slider1.print(LED);             //调整亮度滑块 
      
}
void slider2_callback(int32_t value)           //APP滑块定时
{    
    BLINKER_LOG("get slider value: ", value);
   
    if(value!= 0){
      timeoff = value;                //接收台灯关闭时间
      timestart = Blinker.runTime();  //记录开始时间,单位s
      
      if(LED == 0){                   //如果灯还未开,启动定时器并开灯
        LED = startled;  
        Button1.print("on");          // 反馈给APP按键开关状态   
        Slider1.print(LED);           // 调整亮度滑块 
      }             
    }
}
void timing(void)                              //定时处理
{
  if(timeoff > 0){
      if(Blinker.runTime() - timestart == 60){  //一分钟进入一次
        timeoff--;
        Slider2.print(timeoff);           //调整滑块      
        if(timeoff == 0){
          LED = 0;                        //关闭灯
          Button1.print("off");           //反馈给APP按键开关状态
          Slider1.print(LED);             //调整亮度滑块               
        }
      }
    } 
}
void miotPowerState(const String & state)//小爱同学语音控制开关
{
    Mi_get = true;   //小爱同学触发标志
    
    if (state == BLINKER_CMD_OFF) {     
        LED = 0;          //占空比为0,实现关灯       
        BlinkerMIOT.powerState("off");
        BlinkerMIOT.print();
    }
    else if (state == BLINKER_CMD_ON) {
      if(LED == 0){
        LED = startled;          //如果灯是关闭的,开灯占空比设置为20     
      } 
      BlinkerMIOT.powerState("on");    
      BlinkerMIOT.print();
    }
}
void miotBright(const String & bright)   //小爱同学亮度控制的回调函数
{
    Mi_get = true;   //小爱同学触发标志
     
    LED = bright.toInt();
        
    BlinkerMIOT.brightness(LED);
    BlinkerMIOT.print(); 
}
void miotQuery(int32_t queryCode)        // 查询设备状态回调函数
{
    Mi_get = true;   //小爱同学触发标志
    
    switch (queryCode)
    {
        case BLINKER_CMD_QUERY_ALL_NUMBER :         // 查询所有设备
            BLINKER_LOG("MIOT Query All");
            BlinkerMIOT.powerState(oState ? "on" : "off");          
            BlinkerMIOT.brightness(LED);            //小爱同学查询亮度
            BlinkerMIOT.print();
            break;
        case BLINKER_CMD_QUERY_POWERSTATE_NUMBER :  // 查询电源类设备
            BLINKER_LOG("MIOT Query Power State");
            BlinkerMIOT.powerState(oState ? "on" : "off");
            BlinkerMIOT.print();
            break;
        default :                                   // 查询其他设备
            BlinkerMIOT.powerState(oState ? "on" : "off");
            BlinkerMIOT.print();
            break;
    }
}
void miotMode(uint8_t mode)              //小爱同学模式控制
{
    Mi_get = true;   //小爱同学触发标志
    
    if (mode == BLINKER_CMD_MIOT_NIGHT) {
        LED = 5;  // 夜光模式
    } 
    else if (mode == BLINKER_CMD_MIOT_READING) {
        LED = 60;   // 阅读模式
    }
    else if (mode == BLINKER_CMD_MIOT_COMPUTER) {
        LED = 20;  // 电脑模式
    }
    BlinkerMIOT.mode(mode);
    BlinkerMIOT.print();
}
void Mi_ser()                            //小爱同学触发处理
{
  static int count = 0;
  if(Mi_get){
    count++;
    if(count >= 500){
      Mi_get = false;  //小爱同学触发标志
      count = 0; 
      
      if(LED==0){
        Button1.print("off");      // 反馈给APP按键开关状态  
        timeoff = 0;               //台灯关闭时间清零
        Slider2.print(timeoff);    //调整定时滑块 
      }
      else{
        Button1.print("on");  
        Slider1.print(LED);         //调整亮度滑块 
      }
    }
  }
}
void heartbeat()          //心跳包数据同步,30-60s上传一次,包含运行时间数据
{ 
    int runtime = 0;           //台灯运行时间
    
    runtime = Blinker.runTime();    //Blinker.runTime()单位为s
    NMU1.print(runtime / 60);       //上传台灯运行时间
    Slider1.print(LED);             //调整亮度滑块    
    Image1.print(chstate);          //供电状态  
    NMU2.print(batteryv);           //上传电池电压
}
void charge_ser()         //指示灯颜色,含有电池电压检测
{ 
  static bool flag = true;
  
    batteryv = 6.0*analogRead(A0)/1024-0.18;
 
    if(!digitalRead(stdby)){           //充满电,低电平有效
      chstate = 2;     
      leds[0].r = 0;      //绿色
      leds[0].g = 50;  
      leds[0].b = 15;   
      FastLED.show();     
    }      
    else if(!digitalRead(chrg)){       //充电
      chstate = 3;    
      leds[0].r = 40;      //橙色
      leds[0].g = 10;  
      leds[0].b = 0;   
      FastLED.show();
    }   
    else if(batteryv < 3.4  && digitalRead(chrg)){
      chstate = 1;
      leds[0].r = 40;      //红色
      leds[0].g = 0;  
      leds[0].b = 0;   
      FastLED.show();
    }
    else if(digitalRead(stdby) && digitalRead(chrg) //电池供电
      && batteryv >= 3.4){
      chstate = 0;
      if(LED == 0){
        leds[0].r = 0;     
        leds[0].g = 0;  
        leds[0].b = 0;   
        FastLED.show();
      }
      else{
        leds[0].r = 0;      //蓝色
        leds[0].g = 40;  
        leds[0].b = 50;   
        FastLED.show();
      }
    }                                      
}    
void bright_led()         //输出PWM波
{
  static int  showled;
  static int  first;
  static int  lon;
  static bool flag = false;

  if(first != LED){    //检测变化
    first = LED;
    flag = true;
  }
  
    if(showled > LED*9){
      if(flag){
        lon = (showled - LED*9)/15;  //将一次变化分为20次执行
        flag = false;
      }
      showled -=lon; 
      if(showled < LED*9){showled = LED*9;}   //防止偏差过大
    }
    else if(showled < LED*9){
      if(flag){
        lon = (LED*9 - showled)/15;
        flag = false;
      }
      showled += lon; 
      if(showled > LED*9){showled = LED*9;} 
    }
    Serial.println(showled);
  analogWrite(pwm,showled);  //输出PWM波
}    
int getEncodeTurn(void)   //按键编码器
{
  static int oldA = HIGH;
  static int oldB = HIGH;
  static int swcount = 0;           //按键开关延时
  int result = 0;
  int newA = digitalRead(add);
  int newB = digitalRead(cut);

  swcount++;
  if(swcount > 3000){   //延时
    swcount=0;           
    blinkerrun = true;        //按键编码器发后,blinker禁用一段时间  
    
    Slider1.print(LED);         //调整亮度滑块
    if(LED==0){Button1.print("off");}     // 反馈给APP按键开关状态  
    else{Button1.print("on");}  
  }
  
  if(newA != oldA || newB != oldB)
  {
     swcount=0;           
     blinkerrun = false;
     
     if(oldA == HIGH && newA == oldA)
     {
        result = (oldB * 2 - 1);
        Serial.println(result);  
     }
  }
  oldA = newA;
  oldB = newB;

  if(!digitalRead(sw)){       //按压检测,开关台灯
    blinkerrun = false;          //按键操作时,禁用blinker操作
    swcount=0;   
    delay(30);
    if(!digitalRead(sw)){
       while(!digitalRead(sw)){;}     //松手检测,长按就会触发看门狗,重启
       if(LED!=0){LED = 0;}
       else {LED = startled;}       //开启时等于初始亮度
       delay(100);
    }   
  }
  
  return result;
}
void setup()
{  
    Serial.begin(115200);
    FastLED.addLeds(leds, NUM_LEDS);
    FastLED.setBrightness(50);  //可以设置全局亮度,调低亮度不刺眼
     
    pinMode(add,INPUT);  //+
    pinMode(sw,INPUT); //sw
    pinMode(cut,INPUT);  //- 
    pinMode(stdby,INPUT); //充电停止
    pinMode(chrg,INPUT); //充电检测  
    pinMode(pwm, OUTPUT);  //亮度
    
    analogWriteFreq(25000);   //输出pwm频率为25kHz 
   
    Blinker.begin(auth, ssid, pswd);
        
    Button1.attach(button1_callback);             // 按键回调
    Slider1.attach(slider1_callback);             // 滑块回调
    Slider2.attach(slider2_callback);             // 滑块回调
    
    BlinkerMIOT.attachBrightness(miotBright);     // 灯光亮度控制回调
    BlinkerMIOT.attachMode(miotMode);             // 模式控制回调
    BlinkerMIOT.attachPowerState(miotPowerState); // 电源控制回调
    BlinkerMIOT.attachQuery(miotQuery);           // 查询设备状态回调
    Blinker.attachHeartbeat(heartbeat);           // 心跳包回调
  
}
void loop()
{
  if(blinkerrun){  //blinkerrun来源于getEncodeTurn(); 按键编码器触发标志
      Blinker.run(); 
      timing();           //定时处理   
      charge_ser();       //指示灯
      Mi_ser();           //小爱同学触发处理
      Serial.println("run!");  
  } 

  int change = getEncodeTurn();  //获得编码器信息
  LED = LED + change;
  if(LED<0){LED = 0;}
  if(LED>100){LED = 100;}
  
  bright_led();     //PWM输出 
  
  Serial.print("LED:"); 
  Serial.println(LED); 
                 
}

代码详解

举一个按钮的例子:

按钮名称要和点灯APP上的名称一致,例如我将按钮组件命为“SW”,

BlinkerButton Button1("sw");     //按钮名称”sw“

小爱同学+8266的小爱语音台灯,基于Blinker库_第19张图片

 然后在setup里面注册一下按钮的回调函数

Button1.attach(button1_callback);             // 按键回调

 当APP组件触发后就会执行回调函数里面的内容,我创建的是一个开关按钮,所以它会返回state状态值"on"或"off"

void button1_callback(const String & state)    //APP按钮控制开关
{  
    if (state=="on") {    
     
    } 
    else if(state=="off"){
      
    }     
}

我们也可以从设备端将状态传给APP上的按钮,按钮就会呈现"on"或"off"状态

Button1.print("on");
Button1.print("off");

 实验代码:

#define BLINKER_WIFI
#define BLINKER_MIOT_LIGHT  //小爱同学light接口函数

#include 


char auth[] = "**********";               //换成APP获取到的密匙
char ssid[] = "**********";               //WiFi账号
char pswd[] = "**********";               //WIFI密码


#define BUTTON_1 "ButtonKey"

BlinkerButton Button1("sw");     //按钮名称”sw“

void button1_callback(const String & state)    //APP按钮控制开关
{  
    if (state=="on") {    
     
    } 
    else if(state=="off"){
      
    }     
}

void setup() {
 
 Serial.begin(115200);
 Blinker.begin(auth, ssid, pswd);

 Button1.attach(button1_callback);             // 按键回调
}

void loop() {

  Blinker.run();

}

话不多说,其他函数点灯科技里介绍很详细:点灯科技-点灯物联网解决方案

硬件搭建 

灯板

我采用了3串4并的模式,用的5050灯珠,在嘉立创开的铝基板(白色阻焊不能白嫖,用丝印代替) ,供电电压达到9v就很亮了

小爱同学+8266的小爱语音台灯,基于Blinker库_第20张图片

台灯主板

小爱同学+8266的小爱语音台灯,基于Blinker库_第21张图片焊接好的实物小爱同学+8266的小爱语音台灯,基于Blinker库_第22张图片

亮度控制

采用8266直接控制MOS管,这个不太严谨,但能用

也就是台灯是PWM控制亮度的,开关频率达到了30kHz,一点也不晃眼

小爱同学+8266的小爱语音台灯,基于Blinker库_第23张图片

 

电池充电芯片4056

最大充电电流可达1A,可以通过调节,就是图中的R1,我选取1.2K,充电电流实测可达0.9A

小爱同学+8266的小爱语音台灯,基于Blinker库_第24张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第25张图片

 小爱同学+8266的小爱语音台灯,基于Blinker库_第26张图片

 并且4056有两个引脚输出充电状态,可以用8266检测,并将信息有一个2812指示灯显示

灯板供电升压 芯片XL6007E1

灯板供电实际8.5V左右,升压可以通过图中 R25 R24比值决定,但要注意此芯片最多输出2A电流

 Vout=\frac{R24+R25}{R25}*1.25v

小爱同学+8266的小爱语音台灯,基于Blinker库_第27张图片

小爱同学+8266的小爱语音台灯,基于Blinker库_第28张图片

ESP-12S

第一版用的三色RGB灯,需要三个io口,就导致GPIO0 GPIO15也使用上了,出现了一些问题。后面用到2812就解决问题了。IO口注意事项如下:

小爱同学+8266的小爱语音台灯,基于Blinker库_第29张图片

 用了8266的ADC检测电池电压,8266有10位ADC,输入最高1V。用了10k,2k电阻分压。

供电切换

简易的供电切换电路,有外部供电时就用外部供电并为电池充电。

小爱同学+8266的小爱语音台灯,基于Blinker库_第30张图片

开关用的是,需要将一个引脚剪掉,节省空间,放下电池(家里有条件的可以加两节18650)

小爱同学+8266的小爱语音台灯,基于Blinker库_第31张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第32张图片

 WS2812焊接

需要将灯直立起来,且只需要焊接 三个引脚

小爱同学+8266的小爱语音台灯,基于Blinker库_第33张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第34张图片

 外壳

为了打印出外壳,终于去学了下Solid Works,比原来的建模软件好用多了!

支撑的杆用的是PVC管子:粗杆用的外经10mm,壁厚1mm,细杆用的外经8mm,壁厚1mm

 为大家整理好了:

小爱同学+8266的小爱语音台灯,基于Blinker库_第35张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第36张图片小爱同学+8266的小爱语音台灯,基于Blinker库_第37张图片

 工程链接

链接:https://pan.baidu.com/s/12m0TMhjH7SR9DHA_pTowBg?pwd=m4zf 
提取码:m4zf

你可能感兴趣的:(开源,嵌入式硬件,物联网,智能家居)