├── BlynkDashboard.png ├── BlynkyHome.ino ├── BlynkyHome.jpg ├── NTPtime.cpp ├── NTPtime.h ├── README.md └── SchemaBlynkyHome.png /BlynkDashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vdwel/BlynkyHome/d6b4b4190414f9e78feea927d4ef8b3a8c52bf39/BlynkDashboard.png -------------------------------------------------------------------------------- /BlynkyHome.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * To do: 3 | * Storage and interface for configuration 4 | * Initial configuration, first time switch on, enter basestation if no connection for longer period after reboot. 5 | * V2 = uptime 6 | * V8 = LEDstatus 7 | * V7 = counter 8 | * V3 = ambientLight 9 | * V4 = currentMode 10 | * V5 = Humidity 11 | * V6 = Temp from humidity sensor 12 | * V9 = Pressure 13 | * V28 = alarmArmed 14 | * V0 = lightStatus 15 | * V11 = kitchenIntensity 16 | * V13 = hallIntensity 17 | * V25 =lightTreshold 18 | * V1 = temperature 19 | * V30 = busy 20 | * V31 = Mode change 21 | * V27 = Arm Alarm 22 | * V29 = Toggle light 23 | * V26 = Light Treshold slider 24 | * V10 = Kitchen intensity 25 | * V12 = Hall intensity 26 | */ 27 | 28 | #define BLYNK_PRINT Serial // Comment this out to disable prints and save space 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include "DHT.h" 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | //#define HOME //uncomment for home server 48 | #define ADDR_KITCHEN 0 //EEPROM adress for kitchen light intensity 49 | #define ADDR_HALL 4 50 | #define ADDR_LIGHTTRESHOLD 8 51 | #define DHTPIN 0 52 | #define DHTTYPE DHT21 53 | #define ALTITUDE 0.0 54 | #define LED 16 55 | #define transmitterPIN 14 56 | #define temperaturePIN 12 57 | #define SID "...." 58 | #define PAS "...." 59 | #define HOMESERVER "X.X.X.X" 60 | #define thingspeakAPIkey "...." 61 | #define movementPIN 2 62 | #define MOVEMENT_TIMEOUT 600000 63 | #define SWITCH_MODE0 36000 //10:00 64 | #define SWITCH_MODE1 57600 //16:00 65 | #define SWITCH_MODE2 68400 //19:00 66 | #define SWITCH_MODE3 84600 //23:30 67 | #define TIMEZONE 1 68 | #define DAYLIGHTSAVINGTIME 0 69 | #define KAKU_CHAN 'H' 70 | #define KAKU_DEV 1 71 | #define NEW_KAKU 1 72 | #define NEW_KAKU_TRANSMITTERID1 14881086 73 | #define NEW_KAKU_TRANSMITTERID2 10469306 74 | #define HOSTNAME "lights" 75 | #define VERSION "0.042" 76 | 77 | #ifdef HOME 78 | #define AUTH "...." 79 | #else 80 | #define AUTH "...." 81 | #endif 82 | 83 | //Mode 0: licht uit 84 | //Mode 1: wacht tot het te donker wordt, dan licht aan 85 | //Mode 2: licht aaan 86 | //Mode 3: licht aan als beweging wordt gedetecteerd, wacht tot het te licht wordt, dan licht uit 87 | 88 | SimpleTimer timer; 89 | float temperature = 0; 90 | bool movementDetected = 0; 91 | int currentMode = 3; 92 | OneWire ds(temperaturePIN); 93 | int ambientLight; 94 | bool lightStatus = LOW; 95 | bool alarmArmed = LOW; 96 | int lightTreshold; 97 | int kitchenIntensity; 98 | int hallIntensity; 99 | KaKuSwitch kaKuSwitch(transmitterPIN); 100 | double bar, hum; 101 | SFE_BMP180 pressure; 102 | DHT dht(DHTPIN, DHTTYPE); 103 | bool updating = 0; 104 | unsigned long updateStarted_time = 0; 105 | 106 | 107 | 108 | ESP8266WebServer server(80); 109 | ESP8266HTTPUpdateServer httpUpdater; 110 | 111 | void connectWiFi(const char* ssid = SID, const char* pass = PAS, int timeout = 10); 112 | void callBack(); 113 | void readTemp(); 114 | void readHumiditySensor(); 115 | void readPressure(); 116 | void periodicUpdateThingspeak(); 117 | void interruptHandler(); 118 | void startWebServer(); 119 | void handleSensorData(); 120 | void stateMachine(); 121 | void licht_uit(); 122 | void licht_aan(); 123 | void updateThingspeak(String APIkey, String tsData); 124 | void handleRoot(); 125 | 126 | void setup() 127 | { 128 | Serial.begin(115200); 129 | EEPROM.begin(512); 130 | EEPROM.get(ADDR_KITCHEN, kitchenIntensity); 131 | EEPROM.get(ADDR_HALL, hallIntensity); 132 | EEPROM.get(ADDR_LIGHTTRESHOLD, lightTreshold); 133 | connectWiFi(); 134 | #ifdef HOME 135 | Blynk.config(AUTH, HOMESERVER); 136 | #else 137 | Blynk.config(AUTH); 138 | #endif 139 | timer.setInterval(1000L, callBack); 140 | //timer.setInterval(3600000L, notifyUptime); 141 | timer.setInterval(15000L, readTemp); 142 | timer.setInterval(15000L, readHumiditySensor); 143 | timer.setInterval(15000L, readPressure); 144 | timer.setInterval(60000, periodicUpdateThingspeak); 145 | pinMode(LED, OUTPUT); 146 | pinMode(transmitterPIN, OUTPUT); 147 | pinMode(movementPIN, INPUT_PULLUP); 148 | pinMode(temperaturePIN, INPUT_PULLUP); 149 | attachInterrupt(digitalPinToInterrupt(movementPIN), interruptHandler, CHANGE); 150 | ambientLight = analogRead(A0); 151 | pressure.begin(); 152 | startWebServer(); 153 | 154 | // Port defaults to 8266 155 | // ArduinoOTA.setPort(8266); 156 | 157 | // Hostname defaults to esp8266-[ChipID] 158 | ArduinoOTA.setHostname(HOSTNAME); 159 | 160 | // No authentication by default 161 | // ArduinoOTA.setPassword((const char *)"123"); 162 | 163 | ArduinoOTA.onStart([]() { 164 | Serial.println("Start"); 165 | }); 166 | ArduinoOTA.onEnd([]() { 167 | Serial.println("End"); 168 | }); 169 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 170 | Serial.printf("Progress: %u%%\n", (progress / (total / 100))); 171 | }); 172 | ArduinoOTA.onError([](ota_error_t error) { 173 | Serial.printf("Error[%u]: ", error); 174 | if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); 175 | else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); 176 | else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); 177 | else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); 178 | else if (error == OTA_END_ERROR) Serial.println("End Failed"); 179 | }); 180 | ArduinoOTA.begin(); 181 | } 182 | 183 | void loop() 184 | { 185 | if (WiFi.status() != WL_CONNECTED) { 186 | connectWiFi(); 187 | } 188 | server.handleClient(); 189 | ArduinoOTA.handle(); 190 | if (!updating){ 191 | Blynk.run(); 192 | timer.run(); 193 | Blynk.run(); 194 | stateMachine(); 195 | Blynk.run(); 196 | } else { 197 | if ((millis() - updateStarted_time) > 300000){ 198 | updating = false; 199 | attachInterrupt(digitalPinToInterrupt(movementPIN), interruptHandler, CHANGE); 200 | } 201 | } 202 | } 203 | 204 | void stateMachine() 205 | { 206 | static int prevMode = 3; 207 | static unsigned long lastMovementDetected = 0; 208 | static unsigned long previousTime = 0; 209 | unsigned long currentMillis = millis(); 210 | unsigned long currentTime = (getTime(TIMEZONE, DAYLIGHTSAVINGTIME) % 86400L); 211 | if (currentMode != prevMode){ 212 | prevMode = currentMode; 213 | switch (currentMode) { 214 | case 0: 215 | licht_uit(); 216 | break; 217 | case 2: 218 | licht_aan(); 219 | break; 220 | } 221 | } 222 | switch (currentMode) { 223 | case 1: 224 | if ((lightStatus == LOW) & (ambientLight < lightTreshold)) { 225 | lightStatus == HIGH; 226 | licht_aan(); 227 | } 228 | break; 229 | case 3: 230 | if (movementDetected) { 231 | if ((lightStatus == LOW) & (ambientLight < lightTreshold)){ 232 | licht_aan(); 233 | lastMovementDetected = currentMillis; 234 | } 235 | } 236 | if (lightStatus == HIGH){ 237 | if ((currentMillis - lastMovementDetected) > MOVEMENT_TIMEOUT){ 238 | licht_uit(); 239 | } 240 | } 241 | break; 242 | } 243 | if (movementDetected) { 244 | if (alarmArmed){ 245 | alarmArmed = LOW; 246 | Blynk.notify("Movement detected in the livingroom!!"); 247 | } 248 | lastMovementDetected = currentMillis; 249 | movementDetected = 0; 250 | } 251 | if ((previousTime < SWITCH_MODE3) & (currentTime >= SWITCH_MODE3)) { 252 | currentMode = 3; 253 | BLYNK_LOG("Switching to mode %d", currentMode); 254 | previousTime = currentTime; 255 | } 256 | if ((previousTime < SWITCH_MODE2) & (currentTime >= SWITCH_MODE2)) { 257 | currentMode = 2; 258 | BLYNK_LOG("Switching to mode %d", currentMode); 259 | previousTime = currentTime; 260 | } 261 | if ((previousTime < SWITCH_MODE1) & (currentTime >= SWITCH_MODE1)) { 262 | currentMode = 1; 263 | BLYNK_LOG("Switching to mode %d", currentMode); 264 | previousTime = currentTime; 265 | } 266 | if ((previousTime < SWITCH_MODE0) & (currentTime >= SWITCH_MODE0)) { 267 | currentMode = 0; 268 | BLYNK_LOG("Switching to mode %d", currentMode); 269 | previousTime = currentTime; 270 | } 271 | previousTime = currentTime; 272 | } 273 | 274 | 275 | void callBack(){ 276 | int oldHallIntensity; 277 | EEPROM.get(ADDR_HALL, oldHallIntensity); 278 | int oldKitchenIntensity; 279 | EEPROM.get(ADDR_KITCHEN, oldKitchenIntensity); 280 | int oldLightTreshold; 281 | EEPROM.get(ADDR_LIGHTTRESHOLD, oldLightTreshold); 282 | static long counter = 0; 283 | static bool LEDstatus = HIGH; 284 | digitalWrite(LED, LEDstatus); 285 | if (oldHallIntensity != hallIntensity){ 286 | if (lightStatus){ 287 | switchKaku(transmitterPIN, NEW_KAKU_TRANSMITTERID2, 1, 3, true, 3, hallIntensity); 288 | } 289 | EEPROM.put(ADDR_HALL, hallIntensity); 290 | EEPROM.commit(); 291 | } 292 | if (oldKitchenIntensity != kitchenIntensity){ 293 | if (lightStatus){ 294 | switchKaku(transmitterPIN, NEW_KAKU_TRANSMITTERID2, 1, 4, true, 3, kitchenIntensity); 295 | } 296 | EEPROM.put(ADDR_KITCHEN, kitchenIntensity); 297 | EEPROM.commit(); 298 | } 299 | if (oldLightTreshold != lightTreshold){ 300 | EEPROM.put(ADDR_LIGHTTRESHOLD, lightTreshold); 301 | EEPROM.commit(); 302 | } 303 | LEDstatus = !LEDstatus; 304 | counter += 1; 305 | if (counter > 1000) { 306 | counter = 0; 307 | } 308 | long uptime = millis() / 60000L; 309 | ambientLight = analogRead(A0); 310 | Blynk.virtualWrite(V2, uptime); 311 | Blynk.run(); 312 | Blynk.virtualWrite(V8, LEDstatus*255); 313 | Blynk.run(); 314 | Blynk.virtualWrite(V7, counter); 315 | Blynk.run(); 316 | Blynk.virtualWrite(V3, ambientLight); 317 | Blynk.run(); 318 | Blynk.virtualWrite(V4, currentMode); 319 | Blynk.run(); 320 | Blynk.virtualWrite(V28, alarmArmed*255); 321 | Blynk.run(); 322 | Blynk.virtualWrite(V0, lightStatus*255); 323 | Blynk.run(); 324 | Blynk.virtualWrite(V11, kitchenIntensity); 325 | Blynk.run(); 326 | Blynk.virtualWrite(V13, hallIntensity); 327 | Blynk.run(); 328 | Blynk.virtualWrite(V25, lightTreshold); 329 | Blynk.run(); 330 | Blynk.virtualWrite(V1, temperature); 331 | Blynk.run(); 332 | } 333 | 334 | void notifyUptime() 335 | { 336 | long uptime = millis() / 60000L; 337 | Blynk.notify(String("Running for ") + uptime + " minutes."); 338 | } 339 | 340 | BLYNK_WRITE(31) 341 | { 342 | if(param[0].asInt()){ 343 | currentMode = (currentMode + 1) % 4; 344 | } 345 | } 346 | 347 | BLYNK_WRITE(27) 348 | { 349 | if(param[0].asInt()){ 350 | alarmArmed = HIGH; 351 | } 352 | } 353 | 354 | BLYNK_WRITE(29) 355 | { 356 | if(param[0].asInt()){ 357 | if (lightStatus){ 358 | licht_uit(); 359 | } else { 360 | licht_aan(); 361 | } 362 | } 363 | } 364 | 365 | BLYNK_WRITE(26) 366 | { 367 | lightTreshold = param[0].asInt(); 368 | } 369 | 370 | BLYNK_WRITE(10) 371 | { 372 | kitchenIntensity = param[0].asInt(); 373 | } 374 | 375 | BLYNK_WRITE(12) 376 | { 377 | hallIntensity = param[0].asInt(); 378 | } 379 | 380 | void readTemp() 381 | { 382 | unsigned long epoch = getTime(TIMEZONE, DAYLIGHTSAVINGTIME); 383 | int hours = (epoch % 86400L) / 3600; 384 | int minutes = (epoch % 3600) / 60; 385 | int seconds = (epoch % 60); 386 | char timeString[8]; 387 | //sprintf(timeString,"%02d:%02d:%02d",hours, minutes, seconds); 388 | //BLYNK_LOG("The time is %s", timeString); // UTC is the time at Greenwich Meridian (GMT) 389 | 390 | byte i; 391 | byte present = 0; 392 | byte type_s; 393 | byte data[12]; 394 | byte addr[8]; 395 | float celsius, fahrenheit; 396 | 397 | if ( !ds.search(addr)) { 398 | BLYNK_LOG("No more addresses."); 399 | ds.reset_search(); 400 | delay(250); 401 | return; 402 | } 403 | 404 | if (OneWire::crc8(addr, 7) != addr[7]) { 405 | // BLYNK_LOG("CRC is not valid!"); 406 | return; 407 | } 408 | 409 | // the first ROM byte indicates which chip 410 | switch (addr[0]) { 411 | case 0x10: 412 | type_s = 1; 413 | break; 414 | case 0x28: 415 | type_s = 0; 416 | break; 417 | case 0x22: 418 | type_s = 0; 419 | break; 420 | default: 421 | return; 422 | } 423 | 424 | ds.reset(); 425 | ds.select(addr); 426 | ds.write(0x44, 1); // start conversion, with parasite power on at the end 427 | 428 | //delay(1000); // maybe 750ms is enough, maybe not 429 | // we might do a ds.depower() here, but the reset will take care of it. 430 | 431 | present = ds.reset(); 432 | ds.select(addr); 433 | ds.write(0xBE); // Read Scratchpad 434 | 435 | for ( i = 0; i < 9; i++) { // we need 9 bytes 436 | data[i] = ds.read(); 437 | } 438 | 439 | // Convert the data to actual temperature 440 | // because the result is a 16 bit signed integer, it should 441 | // be stored to an "int16_t" type, which is always 16 bits 442 | // even when compiled on a 32 bit processor. 443 | int16_t raw = (data[1] << 8) | data[0]; 444 | if (type_s) { 445 | raw = raw << 3; // 9 bit resolution default 446 | if (data[7] == 0x10) { 447 | // "count remain" gives full 12 bit resolution 448 | raw = (raw & 0xFFF0) + 12 - data[6]; 449 | } 450 | } else { 451 | byte cfg = (data[4] & 0x60); 452 | // at lower res, the low bits are undefined, so let's zero them 453 | if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms 454 | else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms 455 | else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms 456 | //// default is 12 bit resolution, 750 ms conversion time 457 | } 458 | celsius = (float)raw / 16.0; 459 | fahrenheit = celsius * 1.8 + 32.0; 460 | temperature = celsius; 461 | ds.reset_search(); 462 | } 463 | 464 | void periodicUpdateThingspeak() 465 | { 466 | char h_buffer[10]; 467 | char p_buffer[10]; 468 | char t_buffer[10]; 469 | char l_buffer[10]; 470 | String humidityString = dtostrf(hum, 5, 2, h_buffer); 471 | String pressureString = dtostrf(bar, 7, 2, p_buffer); 472 | String temp = dtostrf(temperature, 3, 2, t_buffer); 473 | String light = dtostrf(ambientLight, 7, 2, t_buffer); 474 | updateThingspeak(thingspeakAPIkey, "field1="+temp+"&field2="+humidityString+"&field3="+pressureString+"&field4="+light); 475 | 476 | } 477 | 478 | void connectWiFi(const char* ssid, const char* pass, int timeout) 479 | { 480 | int timeoutCounter = 0; 481 | 482 | while (WiFi.status() != WL_CONNECTED) { 483 | timeoutCounter = 0; 484 | BLYNK_LOG("Connecting to %s", ssid); 485 | if (pass && strlen(pass)) { 486 | WiFi.begin(ssid, pass); 487 | } else { 488 | WiFi.begin(ssid); 489 | } 490 | 491 | while ((WiFi.status() != WL_CONNECTED) & (timeoutCounter 2000) 565 | { 566 | Serial.printf("movement detected\n"); 567 | movementDetected = 1; 568 | } 569 | last_interrupt_time = interrupt_time; 570 | } 571 | 572 | void startWebServer(){ 573 | if(WiFi.waitForConnectResult() == WL_CONNECTED){ 574 | server.on("/reboot", HTTP_GET,[](){ 575 | server.send(200, "text/plain", "Rebooting!!"); 576 | ESP.restart(); 577 | }); 578 | server.on ( "/", handleRoot ); 579 | server.on ( "/licht.html", handleRoot ); 580 | server.on ( "/data", handleSensorData ); 581 | server.on ( "/on", HTTP_GET, [](){ 582 | licht_aan(); 583 | server.send(200, "text/plain", "Lights on!!"); 584 | }); 585 | server.on("/version", HTTP_GET, [](){ 586 | server.send ( 200, "text/html", VERSION ); 587 | }); 588 | server.on ( "/off", HTTP_GET, [](){ 589 | licht_uit(); 590 | server.send(200, "text/plain", "Lights off!!"); 591 | }); 592 | httpUpdater.setup(&server); 593 | server.begin(); 594 | MDNS.addService("http", "tcp", 80); 595 | 596 | Serial.printf("Ready! Open http://%s.local in your browser\n", HOSTNAME); 597 | } else { 598 | Serial.printf("WiFi Failed"); 599 | } 600 | } 601 | 602 | void handleSensorData() { 603 | char sensorData[256]; 604 | StaticJsonBuffer<200> jsonBuffer; 605 | JsonObject& json = jsonBuffer.createObject(); 606 | json["Temperature"] = temperature; 607 | json["Humidity"] = hum; 608 | json["Pressure"] = bar; 609 | json["ambientLight"] = ambientLight; 610 | 611 | json.prettyPrintTo(sensorData, sizeof(sensorData)); 612 | server.send ( 200, "text/html", sensorData ); 613 | } 614 | 615 | 616 | void readHumiditySensor() 617 | { 618 | float h = dht.readHumidity(); 619 | float t = dht.readTemperature(); 620 | float f = dht.readTemperature(true); 621 | 622 | if (isnan(h) || isnan(t) || isnan(f)) { 623 | BLYNK_LOG("Failed to read from DHT sensor!"); 624 | return; 625 | } 626 | 627 | // Compute heat index in Fahrenheit (the default) 628 | float hif = dht.computeHeatIndex(f, h); 629 | // Compute heat index in Celsius (isFahreheit = false) 630 | float hic = dht.computeHeatIndex(t, h, false); 631 | Blynk.virtualWrite(V5, h); 632 | Blynk.run(); 633 | Blynk.virtualWrite(V6, t); 634 | Blynk.run(); 635 | hum = h; 636 | } 637 | 638 | void readPressure() 639 | { 640 | char status; 641 | static double T,P,p0,a; 642 | 643 | // Loop here getting pressure readings every 10 seconds. 644 | 645 | // If you want sea-level-compensated pressure, as used in weather reports, 646 | // you will need to know the altitude at which your measurements are taken. 647 | // We're using a constant called ALTITUDE in this sketch: 648 | 649 | 650 | // If you want to measure altitude, and not pressure, you will instead need 651 | // to provide a known baseline pressure. This is shown at the end of the sketch. 652 | 653 | // You must first get a temperature measurement to perform a pressure reading. 654 | 655 | // Start a temperature measurement: 656 | // If request is successful, the number of ms to wait is returned. 657 | // If request is unsuccessful, 0 is returned. 658 | 659 | status = pressure.startTemperature(); 660 | if (status != 0) 661 | { 662 | // Wait for the measurement to complete: 663 | delay(status); 664 | 665 | // Retrieve the completed temperature measurement: 666 | // Note that the measurement is stored in the variable T. 667 | // Function returns 1 if successful, 0 if failure. 668 | 669 | status = pressure.getTemperature(T); 670 | if (status != 0) 671 | { 672 | // Start a pressure measurement: 673 | // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait). 674 | // If request is successful, the number of ms to wait is returned. 675 | // If request is unsuccessful, 0 is returned. 676 | 677 | status = pressure.startPressure(3); 678 | if (status != 0) 679 | { 680 | // Wait for the measurement to complete: 681 | delay(status); 682 | 683 | // Retrieve the completed pressure measurement: 684 | // Note that the measurement is stored in the variable P. 685 | // Note also that the function requires the previous temperature measurement (T). 686 | // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.) 687 | // Function returns 1 if successful, 0 if failure. 688 | 689 | status = pressure.getPressure(P,T); 690 | if (status != 0) 691 | { 692 | // The pressure sensor returns abolute pressure, which varies with altitude. 693 | // To remove the effects of altitude, use the sealevel function and your current altitude. 694 | // This number is commonly used in weather reports. 695 | // Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m. 696 | // Result: p0 = sea-level compensated pressure in mb 697 | 698 | p0 = pressure.sealevel(P,ALTITUDE); // we're at 1655 meters (Boulder, CO) 699 | // On the other hand, if you want to determine your altitude from the pressure reading, 700 | // use the altitude function along with a baseline pressure (sea-level or other). 701 | // Parameters: P = absolute pressure in mb, p0 = baseline pressure in mb. 702 | // Result: a = altitude in m. 703 | 704 | a = pressure.altitude(P,p0); 705 | } 706 | else Serial.println("error retrieving pressure measurement"); 707 | } 708 | else Serial.println("error starting pressure measurement"); 709 | } 710 | else Serial.println("error retrieving temperature measurement"); 711 | } 712 | else Serial.println("error starting temperature measurement"); 713 | Blynk.virtualWrite(V9, int(p0)); 714 | Blynk.run(); 715 | bar = p0; 716 | } 717 | 718 | void handleRoot() { 719 | char page[2500]; 720 | 721 | if (server.hasArg("keuken") && server.hasArg("gang")) { 722 | kitchenIntensity = server.arg("keuken").toInt(); 723 | hallIntensity = server.arg("gang").toInt(); 724 | } 725 | 726 | if (server.hasArg("button")) { 727 | Serial.println(server.arg("button")); 728 | if (server.arg("button") == "Licht aan") { 729 | licht_aan(); 730 | } 731 | if (server.arg("button") == "Licht uit") { 732 | licht_uit(); 733 | } 734 | } 735 | 736 | snprintf ( page, 2500, 737 | 738 | "\n\ 739 | \n\ 740 | \n\ 741 | \n\ 742 | \n\ 743 | \n\ 744 | \n\ 745 | \n\ 746 | \n\ 749 | \n\ 750 |
\n\ 751 |
\n\ 752 |

Huis automatisering V%s

\n\ 753 |
\n\ 754 |
\n\ 755 |
\n\ 756 | \n\ 757 | \n\ 758 | \n\ 759 | \n\ 760 | \n\ 761 | \n\ 762 |
\n\ 763 |
\n\ 764 |
\n\ 765 |

\n\ 766 | Temperatuur: C
\n\ 767 | Luchtdruk: mb
\n\ 768 | Luchtvochtigheid:
\n\ 769 | Omgevingslicht:
\n\ 770 |
\n\ 771 |
\n\ 772 | \n\ 786 | \n\ 787 | ", VERSION, kitchenIntensity, hallIntensity, HOSTNAME 788 | ); 789 | 790 | 791 | server.send ( 200, "text/html", page ); 792 | } 793 | 794 | 795 | 796 | -------------------------------------------------------------------------------- /BlynkyHome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vdwel/BlynkyHome/d6b4b4190414f9e78feea927d4ef8b3a8c52bf39/BlynkyHome.jpg -------------------------------------------------------------------------------- /NTPtime.cpp: -------------------------------------------------------------------------------- 1 | #include "NTPtime.h" 2 | 3 | static unsigned int localPort = 2390; // local port to listen for UDP packets 4 | static IPAddress timeServerIP; // time.nist.gov NTP server address 5 | static const char* ntpServerName = "time.nist.gov"; 6 | static const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message 7 | static byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets 8 | 9 | static WiFiUDP udp; 10 | 11 | static unsigned long lastNTPtime = 0; 12 | static unsigned long millisAtLastNTPtime = 0; 13 | 14 | unsigned long getTime(int timezone, bool daylightSavingTime) 15 | { 16 | static unsigned long nextNTPupdate = 0; 17 | unsigned long currentMillis = millis(); 18 | unsigned long epoch = lastNTPtime + (currentMillis - millisAtLastNTPtime)/1000; 19 | if (epoch > nextNTPupdate) { 20 | unsigned long NTPTime = getNTPTime(); 21 | if (NTPTime > 0) { 22 | lastNTPtime=NTPTime; 23 | millisAtLastNTPtime = millis(); 24 | epoch = lastNTPtime; 25 | nextNTPupdate = epoch + 86400L; //next update in 24 hours 26 | } 27 | } 28 | epoch = epoch + (3600 * timezone); 29 | if (daylightSavingTime){ 30 | epoch = epoch + 3600; 31 | } 32 | return epoch; 33 | } 34 | 35 | unsigned long getNTPTime() 36 | { 37 | udp.begin(localPort); 38 | //get a random server from the pool 39 | WiFi.hostByName(ntpServerName, timeServerIP); 40 | 41 | sendNTPpacket(timeServerIP); // send an NTP packet to a time server 42 | // wait to see if a reply is available 43 | delay(1000); 44 | 45 | int cb = udp.parsePacket(); 46 | if (!cb) { 47 | return 0; 48 | } 49 | else { 50 | // We've received a packet, read the data from it 51 | udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer 52 | 53 | //the timestamp starts at byte 40 of the received packet and is four bytes, 54 | // or two words, long. First, esxtract the two words: 55 | 56 | unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); 57 | unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); 58 | // combine the four bytes (two words) into a long integer 59 | // this is NTP time (seconds since Jan 1 1900): 60 | unsigned long secsSince1900 = highWord << 16 | lowWord; 61 | 62 | // now convert NTP time into everyday time: 63 | // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: 64 | const unsigned long seventyYears = 2208988800UL; 65 | // subtract seventy years: 66 | unsigned long epoch = secsSince1900 - seventyYears; 67 | 68 | /* 69 | // print the hour, minute and second: 70 | int hours = (epoch % 86400L) / 3600; 71 | int minutes = (epoch % 3600) / 60; 72 | int seconds = (epoch % 60); 73 | char timeString[8]; 74 | sprintf(timeString,"%02d:%02d:%02d",hours, minutes, seconds); 75 | BLYNK_LOG("The UTC time is %s", timeString); // UTC is the time at Greenwich Meridian (GMT) 76 | */ 77 | udp.stop(); 78 | return epoch; 79 | } 80 | } 81 | 82 | // send an NTP request to the time server at the given address 83 | unsigned long sendNTPpacket(IPAddress& address) 84 | { 85 | // set all bytes in the buffer to 0 86 | memset(packetBuffer, 0, NTP_PACKET_SIZE); 87 | // Initialize values needed to form NTP request 88 | // (see URL above for details on the packets) 89 | packetBuffer[0] = 0b11100011; // LI, Version, Mode 90 | packetBuffer[1] = 0; // Stratum, or type of clock 91 | packetBuffer[2] = 6; // Polling Interval 92 | packetBuffer[3] = 0xEC; // Peer Clock Precision 93 | // 8 bytes of zero for Root Delay & Root Dispersion 94 | packetBuffer[12] = 49; 95 | packetBuffer[13] = 0x4E; 96 | packetBuffer[14] = 49; 97 | packetBuffer[15] = 52; 98 | 99 | // all NTP fields have been given values, now 100 | // you can send a packet requesting a timestamp: 101 | udp.beginPacket(address, 123); //NTP requests are to port 123 102 | udp.write(packetBuffer, NTP_PACKET_SIZE); 103 | udp.endPacket(); 104 | } -------------------------------------------------------------------------------- /NTPtime.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | unsigned long getTime(int timezone, bool daylightSavingTime); 5 | unsigned long getNTPTime(); 6 | unsigned long sendNTPpacket(IPAddress& address); 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BlynkyHome 2 | BlynkyHome is my funproject to play with NODEMCU/ESP8266, Blynk (a wonderfull kickstarter project), Thingspeak, a bunch of sensors and a KaKu (Klik aan Klik uit) system. It delivers automatic control of the lights in the livingroom. Automatic push notification when someone enters the room and information + logging of the temperature, barometric pressure, humidity and ambient light intensity. 3 | 4 | It can use the new KaKu protocol (which is much more reliable, if you ask me). 5 | 6 | Components I am using now: 7 | - NodeMCU 1.0 (new version) 8 | - DHT22 (humidity sensor) 9 | - GY-65 (BMP085, barometric sensor) 10 | - DS18B20 (temperature sensor) 11 | - LDR 12 | - PIR motion detection sensor 13 | - 433Mhz transmitter 14 | 15 | Designed and ordered a PCB to make everything nice. :-) 16 | 17 | More to come!! 18 | 19 | ![alt tag](https://github.com/vdwel/BlynkyHome/blob/master/BlynkyHome.jpg?raw=true) 20 | ![alt tag](https://github.com/vdwel/BlynkyHome/blob/master/BlynkDashboard.png?raw=true) 21 | -------------------------------------------------------------------------------- /SchemaBlynkyHome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vdwel/BlynkyHome/d6b4b4190414f9e78feea927d4ef8b3a8c52bf39/SchemaBlynkyHome.png --------------------------------------------------------------------------------