智能家居

智能家居简介

  智能家居是以住宅为平台,利用综合布线技术、网络通信技术、安全防范技术、自动控制技术、音视频技术将家居生活有关的设施集成,构建高效的住宅设施与家庭日程事务的管理系统,提升家居安全性、便利性、舒适性、艺术性,并实现环保节能的居住环境。

项目实现

  基于ESP8266、ESP32-CAM所开发设计智能家居设备,含温度检测,灯条控制,电脑LAN唤醒,智能摄像车等多个物联网智能家居项目,综合小爱同学,小度,天猫精灵等多平台适配。

具体步骤

  使用WiFi接入,当设备和手机在同一个局域网中,为局域网通信,其余情况,使用MQTT远程通信。

  Arduino IDE需安装好esp8266/esp32扩展

  Arduino IDE 1.8.7或更新版本

  务必使用 3.0.0 或以上release版本的 ESP8266/esp32 Arduino package

  1.PC的WOL唤醒,是通过UDP广播实现,配合主板实现网络唤醒开机,关机可以配合关机UDP广播实现,以 esp8266 为例:

  1#define BLINKER_WIFI
  2#define BLINKER_MIOT_OUTLET
  3
  4#define BLINKER_DUEROS_OUTLET
  5
  6#define BLINKER_ALIGENIE_OUTLET
  7
  8//#define BLINKER_WITHOUT_SSL
  9
 10#include <Servo.h> 
 11#include <Blinker.h>
 12#include <WiFiUDP.h>
 13#include <ESP8266Ping.h>
 14
 15char auth[] = "35a74dc36a92";
 16char ssid[] = "Sweet_meng";
 17char pswd[] = "aita0116.";
 18
 19BlinkerButton Button1("k1");
 20BlinkerSlider Slider1("ser-num");   //实时位置 滑块 数据键名  范围1-180
 21
 22Servo myservo;
 23int ser_num;
 24//唤醒目标电脑的mac地址
 25byte mac[] = {0x00, 0xE0, 0x70, 0x49, 0x1D, 0xE7};
 26byte preamble[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 27//幻数据包需要在局域网中广播发送,要控制的电脑的网段的255地址
 28IPAddress ip(192, 168, 0, 255);
 29//建立一个WiFiUDP对象 UDP
 30WiFiUDP UDP;
 31//UDP接收地址,我这里是使用的广播,注意网段
 32const char *UDPAddress = "192.168.0.108";
 33//UDP端口
 34const int UDPPort = 7101;
 35bool oState = false;
 36
 37void heartbeat()
 38{
 39    BLINKER_LOG("heartbeat,state: ", oState);
 40    if (HIGH == oState)
 41    {
 42        Button1.print("on");
 43    }
 44    else
 45    {
 46        Button1.print("off");
 47    }
 48}
 49
 50void button1_callback(const String &state)
 51{
 52    BLINKER_LOG("get button state: ", state);
 53    if (state == BLINKER_CMD_ON)
 54    {
 55        BLINKER_LOG("Toggle on!");
 56        UDP.beginPacket(ip, 9);               //UDP发送到目标(IP,端口)
 57        UDP.write(preamble, sizeof preamble); //写入包头(FF,FF,FF,FF,FF,FF)
 58        for (byte i = 0; i < 16; i++)
 59        {
 60            UDP.write(mac, sizeof mac);
 61        }
 62        BLINKER_LOG("唤醒主机");
 63        UDP.endPacket();
 64        Button1.print("on");
 65        oState = true;
 66    }
 67    else if (state == BLINKER_CMD_OFF)
 68    {
 69        BLINKER_LOG("Toggle off!");
 70        char sd[] = "shut";                   //与电脑相对应的指令
 71        UDP.beginPacket(UDPAddress, UDPPort); //准备发送,设置地址和端口
 72        UDP.write((char *)sd, 8);
 73        BLINKER_LOG("关闭主机");
 74        UDP.endPacket();
 75        Button1.print("off");
 76        oState = false;
 77    }
 78    BlinkerMIOT.powerState(oState ? "on" : "off");
 79    BlinkerMIOT.print();
 80
 81    BlinkerDuerOS.powerState(oState ? "on" : "off");
 82    BlinkerDuerOS.print();
 83
 84    BlinkerAliGenie.powerState(oState ? "on" : "off");
 85    BlinkerAliGenie.print();
 86}
 87
 88void slider1_callback(int32_t value)
 89{
 90    ser_num = value;
 91    myservo.write(ser_num);
 92    Blinker.delay(500);
 93    BLINKER_LOG("get slider value: ", value);
 94}
 95
 96void miotPowerState(const String &state)
 97{
 98    BLINKER_LOG("need set power state: ", state);
 99    if (state == BLINKER_CMD_ON)
100    {
101        UDP.beginPacket(ip, 9);               //UDP发送到目标(IP,端口)
102        UDP.write(preamble, sizeof preamble); //写入包头(FF,FF,FF,FF,FF,FF)
103        for (byte i = 0; i < 16; i++)
104        {
105            UDP.write(mac, sizeof mac);
106        }
107        BLINKER_LOG("唤醒主机");
108        UDP.endPacket();
109        oState = true;
110    }
111    else if (state == BLINKER_CMD_OFF)
112    {
113        char sd[] = "shut";                   //与电脑相对应的指令
114        UDP.beginPacket(UDPAddress, UDPPort); //准备发送,设置地址和端口
115        UDP.write((char *)sd, 8);
116        BLINKER_LOG("关闭主机");
117        UDP.endPacket();
118        oState = false;
119    }
120    BlinkerMIOT.powerState(oState ? "on" : "off");
121    BlinkerMIOT.print();
122}
123
124void miotQuery(int32_t queryCode)
125{
126    BLINKER_LOG("MIOT Query codes: ", queryCode);
127    switch (queryCode)
128    {
129    case BLINKER_CMD_QUERY_ALL_NUMBER:
130        BLINKER_LOG("MIOT Query All");
131        BlinkerMIOT.powerState(oState ? "on" : "off");
132        BlinkerMIOT.print();
133        break;
134    case BLINKER_CMD_QUERY_POWERSTATE_NUMBER:
135        BLINKER_LOG("MIOT Query Power State");
136        BlinkerMIOT.powerState(oState ? "on" : "off");
137        BlinkerMIOT.print();
138        break;
139    default:
140        BlinkerMIOT.powerState(oState ? "on" : "off");
141        BlinkerMIOT.print();
142        break;
143    }
144}
145
146void duerPowerState(const String &state)
147{
148    BLINKER_LOG("need set power state: ", state);
149    if (state == BLINKER_CMD_ON)
150    {
151        UDP.beginPacket(ip, 9);               //UDP发送到目标(IP,端口)
152        UDP.write(preamble, sizeof preamble); //写入包头(FF,FF,FF,FF,FF,FF)
153        for (byte i = 0; i < 16; i++)
154        {
155            UDP.write(mac, sizeof mac);
156        }
157        BLINKER_LOG("唤醒主机");
158        UDP.endPacket();
159        oState = true;
160    }
161    else if (state == BLINKER_CMD_OFF)
162    {
163        char sd[] = "shut";                   //与电脑相对应的指令
164        UDP.beginPacket(UDPAddress, UDPPort); //准备发送,设置地址和端口
165        UDP.write((char *)sd, 8);
166        BLINKER_LOG("关闭主机");
167        UDP.endPacket();
168        oState = false;
169    }
170    BlinkerDuerOS.powerState(oState ? "on" : "off");
171    BlinkerDuerOS.print();
172}
173
174void duerQuery(int32_t queryCode)
175{
176    BLINKER_LOG("DuerOS Query codes: ", queryCode);
177    switch (queryCode)
178    {
179    case BLINKER_CMD_QUERY_ALL_NUMBER:
180        BLINKER_LOG("DuerOS Query All");
181        BlinkerDuerOS.powerState(oState ? "on" : "off");
182        BlinkerDuerOS.time(millis());
183        BlinkerDuerOS.print();
184        break;
185    case BLINKER_CMD_QUERY_POWERSTATE_NUMBER:
186        BLINKER_LOG("DuerOS Query Power State");
187        BlinkerDuerOS.powerState(oState ? "on" : "off");
188        BlinkerDuerOS.print();
189        break;
190    case BLINKER_CMD_QUERY_TIME_NUMBER:
191        BLINKER_LOG("DuerOS Query time");
192        BlinkerDuerOS.time(millis());
193        BlinkerDuerOS.print();
194        break;
195    default:
196        BlinkerDuerOS.powerState(oState ? "on" : "off");
197        BlinkerDuerOS.time(millis());
198        BlinkerDuerOS.print();
199        break;
200    }
201}
202
203void aligeniePowerState(const String &state)
204{
205    BLINKER_LOG("need set power state: ", state);
206    if (state == BLINKER_CMD_ON)
207    {
208        UDP.beginPacket(ip, 9);               //UDP发送到目标(IP,端口)
209        UDP.write(preamble, sizeof preamble); //写入包头(FF,FF,FF,FF,FF,FF)
210        for (byte i = 0; i < 16; i++)
211        {
212            UDP.write(mac, sizeof mac);
213        }
214        BLINKER_LOG("唤醒主机");
215        UDP.endPacket();
216        oState = true;
217    }
218    else if (state == BLINKER_CMD_OFF)
219    {
220        char sd[] = "shut";                   //与电脑相对应的指令
221        UDP.beginPacket(UDPAddress, UDPPort); //准备发送,设置地址和端口
222        UDP.write((char *)sd, 8);
223        BLINKER_LOG("关闭主机");
224        UDP.endPacket();
225        oState = false;
226    }
227    BlinkerAliGenie.powerState(oState ? "on" : "off");
228    BlinkerAliGenie.print();
229}
230
231void aligenieQuery(int32_t queryCode)
232{
233    BLINKER_LOG("AliGenie Query codes: ", queryCode);
234    switch (queryCode)
235    {
236    case BLINKER_CMD_QUERY_ALL_NUMBER:
237        BLINKER_LOG("AliGenie Query All");
238        BlinkerAliGenie.powerState(oState ? "on" : "off");
239        BlinkerAliGenie.print();
240        break;
241    case BLINKER_CMD_QUERY_POWERSTATE_NUMBER:
242        BLINKER_LOG("AliGenie Query Power State");
243        BlinkerAliGenie.powerState(oState ? "on" : "off");
244        BlinkerAliGenie.print();
245        break;
246    default:
247        BlinkerAliGenie.powerState(oState ? "on" : "off");
248        BlinkerAliGenie.print();
249        break;
250    }
251}
252
253void dataRead(const String &data)
254{
255    BLINKER_LOG("Blinker readString: ", data);
256    Blinker.vibrate();
257    uint32_t BlinkerTime = millis();
258    Blinker.print("millis", BlinkerTime);
259}
260
261void setup()
262{
263    Serial.begin(115200);
264    BLINKER_DEBUG.stream(Serial);
265    // BLINKER_DEBUG.debugAll();
266
267    myservo.attach(0);  //servo.attach():设置舵机数据引脚
268    myservo.write(90);  //servo.write():设置转动角度
269
270    Button1.attach(button1_callback);
271    Slider1.attach(slider1_callback);
272    Blinker.attachHeartbeat(heartbeat);
273
274    Blinker.begin(auth, ssid, pswd);
275    Blinker.attachData(dataRead);
276
277    BlinkerMIOT.attachPowerState(miotPowerState);
278    BlinkerMIOT.attachQuery(miotQuery);
279
280    BlinkerDuerOS.attachPowerState(duerPowerState);
281    BlinkerDuerOS.attachQuery(duerQuery);
282
283    BlinkerAliGenie.attachPowerState(aligeniePowerState);
284    BlinkerAliGenie.attachQuery(aligenieQuery);
285}
286
287void loop()
288{
289    Blinker.run();
290}

  2.WS2812的灯带,配合FastLED库,可以配合实现多种灯光效果,以 esp8266 为例:

  1///////////////////////////////////////////////////////////////////////////K1灯效FastLED(依赖K2灯效FastLED)
  2
  3typedef void (*SimplePatternList1[])();
  4SimplePatternList1 gPatterns1 = {rainbow}; //rainbow, rainbowWithGlitter, confetti, sinelon, juggle, bpm 6种特效切换
  5
  6///////////////////////////////////////////////////////////////////////////K2灯效FastLED
  7// List of patterns to cycle through.  Each is defined as a separate function below.
  8typedef void (*SimplePatternList[])();
  9SimplePatternList gPatterns = {juggle}; //rainbow, rainbowWithGlitter, confetti, sinelon, juggle, bpm 6种特效切换
 10
 11uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current
 12uint8_t gHue = 0;                  // rotating "base color" used by many of the patterns
 13
 14#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
 15
 16void nextPattern()
 17{
 18    // add one to the current pattern number, and wrap around at the end
 19    gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE(gPatterns);
 20}
 21
 22void rainbow()
 23{
 24    // FastLED's built-in rainbow generator
 25    fill_rainbow(leds, NUM_LEDS, gHue, 3);
 26}
 27
 28void rainbowWithGlitter()
 29{
 30    // built-in FastLED rainbow, plus some random sparkly glitter
 31    rainbow();
 32    addGlitter(80);
 33}
 34
 35void addGlitter(fract8 chanceOfGlitter)
 36{
 37    if (random8() < chanceOfGlitter)
 38    {
 39        leds[random16(NUM_LEDS)] += CRGB::White;
 40    }
 41}
 42
 43void confetti()
 44{
 45    // random colored speckles that blink in and fade smoothly
 46    fadeToBlackBy(leds, NUM_LEDS, 10);
 47    int pos = random16(NUM_LEDS);
 48    leds[pos] += CHSV(gHue + random8(64), 200, 255);
 49}
 50
 51void sinelon()
 52{
 53    // a colored dot sweeping back and forth, with fading trails
 54    fadeToBlackBy(leds, NUM_LEDS, 20);
 55    int pos = beatsin16(13, 0, NUM_LEDS - 1);
 56    leds[pos] += CHSV(gHue, 255, 192);
 57}
 58
 59void bpm()
 60{
 61    // colored stripes pulsing at a defined Beats-Per-Minute (BPM)
 62    uint8_t BeatsPerMinute = 62;
 63    CRGBPalette16 palette = PartyColors_p;
 64    uint8_t beat = beatsin8(BeatsPerMinute, 64, 255);
 65    for (int i = 0; i < NUM_LEDS; i++)
 66    { //9948
 67        leds[i] = ColorFromPalette(palette, gHue + (i * 2), beat - gHue + (i * 10));
 68    }
 69}
 70
 71void juggle()
 72{
 73    // eight colored dots, weaving in and out of sync with each other
 74    fadeToBlackBy(leds, NUM_LEDS, 20);
 75    byte dothue = 0;
 76    for (int i = 0; i < 8; i++)
 77    {
 78        leds[beatsin16(i + 7, 0, NUM_LEDS - 1)] |= CHSV(dothue, 200, 255);
 79        dothue += 32;
 80    }
 81}
 82
 83///////////////////////////////////////////////////////////////////////////K3灯效
 84//冷却:空气上升时会冷却多少?
 85//冷却少=火焰高。 冷却更多=火焰更短。
 86//默认值50,建议范围20-100
 87#define COOLING 50
 88
 89//发出火花:有什么机会(总共255个)点燃新的火花?
 90//更高的机会=更多的怒吼。 机会降低=火势更加闪烁。
 91//默认值为120,建议范围为50-200。
 92#define SPARKING 120
 93bool gReverseDirection = false;
 94void Fire2012()
 95{
 96    // Array of temperature readings at each simulation cell
 97    static byte heat[NUM_LEDS];
 98
 99    // Step 1.  Cool down every cell a little
100    for (int i = 0; i < NUM_LEDS; i++)
101    {
102        heat[i] = qsub8(heat[i], random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
103    }
104
105    // Step 2.  Heat from each cell drifts 'up' and diffuses a little
106    for (int k = NUM_LEDS - 1; k >= 2; k--)
107    {
108        heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
109    }
110
111    // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
112    if (random8() < SPARKING)
113    {
114        int y = random8(7);
115        heat[y] = qadd8(heat[y], random8(160, 255));
116    }
117
118    // Step 4.  Map from heat cells to LED colors
119    for (int j = 0; j < NUM_LEDS; j++)
120    {
121        CRGB color = HeatColor(heat[j]);
122        int pixelnumber;
123        if (gReverseDirection)
124        {
125            pixelnumber = (NUM_LEDS - 1) - j;
126        }
127        else
128        {
129            pixelnumber = j;
130        }
131        leds[pixelnumber] = color;
132    }
133}
134
135///////////////////////////////////////////////////////////////////////////K4灯效
136#if FASTLED_VERSION < 3001000
137#error "Requires FastLED 3.1 or later; check github for latest code."
138#endif
139// This function draws rainbows with an ever-changing,
140// widely-varying set of parameters.
141void pride()
142{
143    static uint16_t sPseudotime = 0;
144    static uint16_t sLastMillis = 0;
145    static uint16_t sHue16 = 0;
146
147    uint8_t sat8 = beatsin88(87, 220, 250);
148    uint8_t brightdepth = beatsin88(341, 96, 224);
149    uint16_t brightnessthetainc16 = beatsin88(203, (25 * 256), (40 * 256));
150    uint8_t msmultiplier = beatsin88(147, 23, 60);
151
152    uint16_t hue16 = sHue16; //gHue * 256;
153    uint16_t hueinc16 = beatsin88(113, 1, 3000);
154
155    uint16_t ms = millis();
156    uint16_t deltams = ms - sLastMillis;
157    sLastMillis = ms;
158    sPseudotime += deltams * msmultiplier;
159    sHue16 += deltams * beatsin88(400, 5, 9);
160    uint16_t brightnesstheta16 = sPseudotime;
161
162    for (uint16_t i = 0; i < NUM_LEDS; i++)
163    {
164        hue16 += hueinc16;
165        uint8_t hue8 = hue16 / 256;
166
167        brightnesstheta16 += brightnessthetainc16;
168        uint16_t b16 = sin16(brightnesstheta16) + 32768;
169
170        uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
171        uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
172        bri8 += (255 - brightdepth);
173
174        CRGB newcolor = CHSV(hue8, sat8, bri8);
175
176        uint16_t pixelnumber = i;
177        pixelnumber = (NUM_LEDS - 1) - pixelnumber;
178
179        nblend(leds[pixelnumber], newcolor, 64);
180    }
181}
182void mode_2()
183{
184    if (BRIGHTNESS < 20)
185    {
186        BRIGHTNESS = 20;
187        Slider1.print(BRIGHTNESS);
188    }
189    FastLED.setBrightness(BRIGHTNESS); //实时更新亮度
190    gPatterns1[gCurrentPatternNumber]();
191    FastLED.show();
192    FastLED.delay(200 / UPDATES_PER_SECOND);
193    EVERY_N_MILLISECONDS(20) { gHue++; }   // slowly cycle the "base color" through the rainbow
194    EVERY_N_SECONDS(10) { nextPattern(); } // change patterns periodically
195}
196
197void mode_3()
198{
199    if (BRIGHTNESS < 20)
200    {
201        BRIGHTNESS = 20;
202        Slider1.print(BRIGHTNESS);
203    }
204    FastLED.setBrightness(BRIGHTNESS); //实时更新亮度
205    gPatterns[gCurrentPatternNumber]();
206    FastLED.show();
207    FastLED.delay(1000 / (UPDATES_PER_SECOND / 10));
208
209    // do some periodic updates
210    EVERY_N_MILLISECONDS(20) { gHue++; }   // slowly cycle the "base color" through the rainbow
211    EVERY_N_SECONDS(10) { nextPattern(); } // change patterns periodically
212}
213
214void mode_4()
215{
216    if (BRIGHTNESS < 20)
217    {
218        BRIGHTNESS = 20;
219        Slider1.print(BRIGHTNESS);
220    }
221    Fire2012();
222    FastLED.setBrightness(BRIGHTNESS); //实时更新亮度
223    FastLED.delay(1000 / UPDATES_PER_SECOND);
224}
225
226void mode_5()
227{
228    if (BRIGHTNESS < 20)
229    {
230        BRIGHTNESS = 20;
231        Slider1.print(BRIGHTNESS);
232    }
233    FastLED.setBrightness(BRIGHTNESS); //实时更新亮度
234    pride();
235    FastLED.show();
236    FastLED.delay(1000 / (UPDATES_PER_SECOND / 5));
237}
238

  3.ESP32-CAM带有一个摄像头,可以搭建一个视频监控车,ESP32-CAM底座原理图和PCB,以及小车底座PCB如下:

ESP32-CAM底座原理图

ESP32-CAM底座PCB

ESP32-CAM小车PCB

  以 esp32 为例:

 1int calculatePWM(int degree) //舵机角度
 2{
 3    //20ms周期,高电平0.5-2.5ms,对应0-180度角度
 4    const float deadZone = 6.4; //对应0.5ms(0.5ms/(20ms/256))
 5    const float max = 32;       //对应2.5ms
 6    if (degree < 0)
 7        degree = 0;
 8    if (degree > 180)
 9        degree = 180;
10    return (int)(((max - deadZone) / 180) * degree + deadZone);
11}
12
13void servo_360() //360度舵机控制
14{
15    if (y < 128)
16    {
17        ledcWrite(servo_channel, calculatePWM(88)); // 输出PWM
18    }
19    else if (y == 128)
20    {
21        ledcWrite(servo_channel, calculatePWM(92)); // 输出PWM
22    }
23    else if (y > 128)
24    {
25        ledcWrite(servo_channel, calculatePWM(96)); // 输出PWM
26    }
27}
28
29void xunhuan()
30{
31    ledcWrite(servo_channel, calculatePWM(angle)); // 输出PWM
32    ledcWrite(flashled_channel, flashled_pwm);     // 输出PWM
33    if ((y <= 37.5) && (x >= 37.5) && (x <= 217.5))//前进
34    {
35        ledcWrite(motorA1_channel, motor_pwm);
36        ledcWrite(motorA2_channel, 0);
37        ledcWrite(motorB1_channel, motor_pwm);
38        ledcWrite(motorB2_channel, 0);
39    }
40    if ((x <= 37.5) && (y >= 37.5) && (y <= 217.5))//左转
41    {
42        ledcWrite(motorA1_channel, 0);
43        ledcWrite(motorA2_channel, motor_pwm);
44        ledcWrite(motorB1_channel, motor_pwm);
45        ledcWrite(motorB2_channel, 0);
46    }
47    if ((x >= 217.5) && (y >= 37.5) && (y <= 217.5))//右转
48    {
49        ledcWrite(motorA1_channel, motor_pwm);
50        ledcWrite(motorA2_channel, 0);
51        ledcWrite(motorB1_channel, 0);
52        ledcWrite(motorB2_channel, motor_pwm);
53    }
54    if ((y >= 217.5) && (x >= 37.5) && (x <= 217.5))//后退
55    {
56        ledcWrite(motorA1_channel, 0);
57        ledcWrite(motorA2_channel, motor_pwm);
58        ledcWrite(motorB1_channel, 0);
59        ledcWrite(motorB2_channel, motor_pwm);
60    }
61     if ((x > 37.5) && (x < 217.5) && (y > 37.5) && (y < 217.5))//后退
62    {
63        ledcWrite(motorA1_channel, 0);
64        ledcWrite(motorA2_channel, 0);
65        ledcWrite(motorB1_channel, 0);
66        ledcWrite(motorB2_channel, 0);
67    }
68}

  本文相关项目完整源码已上传本人gitee,点击查看更多智能家居项目源码,如智能风扇,智能空调,智能插座等等。

版权