NodeMCU for Room automation

Hello everyone,
looking at guidelines found here and there in the blink portal i managed to set up my room automation system, made up of 4 relays, and a servo that opens/closes the door lock.
I’m already quite satisfied with it even tough there are some minor issues i didn’t manage to solve even by looking everywhere.

  • i don’t know how to transform the uptime seconds in the dd:hh:mm:ss format to show it with the display value widget on the app

  • the 9g micro servo* i use buzzes sometimes when the action is completed, but its power supply is now controlled by a relay, so really a minor issue

  • quite often when opening the blank app i get " your device was disconnected" and it only starts working after some seconds

hope you can help me optimize my code since I’m not really an expert :grin:
thanks everyone for your work :blush:

/*************************************************************
  Download latest Blynk library here:
    https://github.com/blynkkk/blynk-library/releases/latest

  Blynk is a platform with iOS and Android apps to control
  Arduino, Raspberry Pi and the likes over the Internet.
  You can easily build graphic interfaces for all your
  projects by simply dragging and dropping widgets.

    Downloads, docs, tutorials: http://www.blynk.cc
    Sketch generator:           http://examples.blynk.cc
    Blynk community:            http://community.blynk.cc
    Social networks:            http://www.fb.com/blynkapp
                                http://twitter.com/blynk_app

  Blynk library is licensed under MIT license
  This example code is in public domain.

 *************************************************************
  This example runs directly on NodeMCU.

  Note: This requires ESP8266 support package:
    https://github.com/esp8266/Arduino

  Please be sure to select the right NodeMCU module
  in the Tools -> Board menu!

  For advanced settings please follow ESP examples :
   - ESP8266_Standalone_Manual_IP.ino
   - ESP8266_Standalone_SmartConfig.ino
   - ESP8266_Standalone_SSL.ino

  Change WiFi ssid, pass, and Blynk auth token to run :)
  Feel free to apply it to any other example. It's simple!
 *************************************************************/

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial
// define the physical pins the relays are connected to. Make sure you use GPIO numbers and not D numbers. D6 = GPIO12 etc 
#define RELAY1_PIN 5  // D1
#define RELAY2_PIN 4  // D2
#define RELAY3_PIN 14  // D5
#define RELAY4_PIN 12  // D6
#define servoPin D0  // D0

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h>
#include <WidgetRTC.h>
#include <ArduinoOTA.h>
#include <Servo.h>
#include <SPI.h>

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "xxxxxxxxxxxxxx";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "xxxxxxxxx";
char pass[] = "xxxxxxx";
char hostOTA[] = "OTAUpdates";
char passOTA[] = "1234";

BlynkTimer timer;

WidgetRTC rtc;

Servo servo;

// Digital clock display of the time
void clockDisplay()
{
  // You can call hour(), minute(), ... at any time
  // Please see Time library examples for details

  String currentTime = String(hour()) + ":" + minute() + ":" + second();
  String currentDate = String(day()) + " " + month() + " " + year();
  Serial.print("Current time: ");
  Serial.print(currentTime);
  Serial.print(" ");
  Serial.print(currentDate);
  Serial.println();

  // Send time to the App
  Blynk.virtualWrite(V1, currentTime);
  // Send date to the App
  Blynk.virtualWrite(V2, currentDate);
}

void myTimerEvent()
{
  // You can send any value at any time.
  // Please don't send more that 10 values per second.
  Blynk.virtualWrite(V3, millis() / 1000);
}

  BLYNK_READ(V2) {
  Blynk.virtualWrite(V2, millis() / 1000);
}

BLYNK_READ(V1) {
  Blynk.virtualWrite(V1, millis());
}

BLYNK_READ(V3) {
  Blynk.virtualWrite(V3, millis());
}



// Keep this flag not to re-sync on every reconnection
bool isFirstConnect = true;
BLYNK_CONNECTED() {
  if (isFirstConnect) {
    Blynk.syncVirtual(V21, V22, V23, V24, V25);
    isFirstConnect = false;
  }
  }


void setup()
{
  // Debug console
  Serial.begin(9600);
 
  Blynk.begin(auth, ssid, pass);
  // You can also specify server:
  //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 8442);
  //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8442);

  servo.attach(servoPin);
  
// Begin synchronizing time
  rtc.begin();

  // Other Time library functions can be used, like:
  //   timeStatus(), setSyncInterval(interval)...
  // Read more: http://www.pjrc.com/teensy/td_libs_Time.html

  // Display digital clock every 1 seconds
  timer.setInterval(1000L, clockDisplay);

  // Setup a function to be called every second
  timer.setInterval(1000L, myTimerEvent);

  ArduinoOTA.setHostname(hostOTA);
  //ArduinoOTA.setPassword(passOTA);
  ArduinoOTA.onStart([]() {
    Serial.println("OTA: Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nOTA: End");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("OTA: Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("OTA: Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("OTA: Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("OTA: Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("OTA: End Failed");
  });
  ArduinoOTA.begin();
  Serial.println("OTA: Ready");

  pinMode(RELAY1_PIN,OUTPUT);
  pinMode(RELAY2_PIN,OUTPUT);
  pinMode(RELAY3_PIN,OUTPUT);
  pinMode(RELAY4_PIN,OUTPUT);
  digitalWrite(RELAY1_PIN, HIGH); // most modules are LOW active... so on boot start inactive (HIGH)
  digitalWrite(RELAY2_PIN, HIGH); // most modules are LOW active... so on boot start inactive (HIGH)
  digitalWrite(RELAY3_PIN, HIGH); // most modules are LOW active... so on boot start inactive (HIGH)
  digitalWrite(RELAY4_PIN, HIGH); // most modules are LOW active... so on boot start inactive (HIGH)
}

BLYNK_WRITE(21){ // virtual pin 21... create a button widget in SWITCH mode
  if(param.asInt()){
    digitalWrite(RELAY1_PIN, LOW); // if button is HIGH, turn on relay1
  } else {
    digitalWrite(RELAY1_PIN, HIGH); // if button is LOW, turn off relay1
  }
}

BLYNK_WRITE(22){ // virtual pin 22... create a button widget in SWITCH mode
  if(param.asInt()){
    digitalWrite(RELAY2_PIN, LOW); // if button is HIGH, turn on relay1
  } else {
    digitalWrite(RELAY2_PIN, HIGH); // if button is LOW, turn off relay1
  }
}

BLYNK_WRITE(23){ // virtual pin 23... create a button widget in SWITCH mode
  if(param.asInt()){
    digitalWrite(RELAY3_PIN, LOW); // if button is HIGH, turn on relay1
  } else {
    digitalWrite(RELAY3_PIN, HIGH); // if button is LOW, turn off relay1
  }
}

BLYNK_WRITE(24){ // virtual pin 24... create a button widget in SWITCH mode
  if(param.asInt()){
    digitalWrite(RELAY4_PIN, LOW); // if button is HIGH, turn on relay1
  } else {
    digitalWrite(RELAY4_PIN, HIGH); // if button is LOW, turn off relay1
  }

}  

BLYNK_WRITE(V25){
  servo.write(param.asInt());
  }



void loop()
{
  ArduinoOTA.handle();
  Blynk.run();
  timer.run(); // BlynkTimer is working...
  
}

*the nodemcu is connected to the lolin base shield, 5v powered, which powers itself the nodemcu, the 4 relays module, and the servo

You are using the RTC widget so it’s not uptime, rather it’s clock time.
It’s normally done with a sprintf command but I suspect in your case the RTC is not syncing.
Do you see something like the following in Serial Monitor?

RTC sync

I am unable to access the serial right now, ill go check as soon as possible but from the app i can see the time is right eventough every few secs it flashes with something different. Thats what i see

https://drive.google.com/file/d/0B2NkwmVcfzXRSlJMUXJLOFpUVWs/view?usp=drivesdk

https://drive.google.com/file/d/0B2NkwmVcfzXRYTY4YmlTTmRtODg/view?usp=drivesdk

There is a lot of data here, but the answers, or at least the reasons ARE here. i.e. servo buzzing - search this forum for for “Servo Jitter”.

And uptime code can be broken down by dividing the milliseconds into seconds (/1000), minutes (/60000) and hours (/3600000)… however, by then you might as well use the RTC :wink: EDIT - @Costas already caught that… my editor blocked out his response… opps

And “too much too fast” can cause intermittent disconnections… tighter code and good timer routines can help there.

One thing though… while some users can and will go the extra mile to help with code optimization, this isn’t a code factory forum, so the onus is and will always be for one to learn how to code for oneself, one baby step at a time (that’s how I learn :wink: ).

This is what I have for my clock display, optimised to show leading zeros where required.

//===== CLOCK =====
void clockDisplay()
{
    if (hour() < 10) { // Add a leading zero if its less than 10
    FillH = "0";
  } else {
    FillH = "";
  }  // END else
  
  if (minute() < 10) { // Add a leading zero if its less than 10
    FillM = "0";
  } else {
    FillM = "";
  }  // END else

  if (second() < 10) { // Add a leading zero if its less than 10
    FillS = "0";
  } else {
    FillS = "";
  }  // END else

  currentTime = String(FillH + hour()) + ":" + FillM + minute() + ":" + FillS + second();
  currentDate = String(month()) + "/" + day() + "/" + year();
  Blynk.virtualWrite(V12, currentTime);  // Send date to Display Widget
  Blynk.virtualWrite(V13, currentDate);  // Send date to Display Widget
  lcd.print(0, 0, currentTime);  // Send time to LCD Widget
  lcd.print(8, 1, String(month()) + "/" + day() + "/17");  // Send date to LCD Widget
}  // END clockDisplay Loop

Simple time and date formatting:

char Date[11];
char Time[9]; 
sprintf(Date, "%02d/%02d/%04d",  day(), month(), year());
sprintf(Time, "%02d:%02d:%02d", hour(), minute(), second());
3 Likes

Looking at your code you are sending RTC and millis() to the same value display widget. Remove all references to millis() in your sketch, the PUSH data function of myTimerEvent() should be used but not for sending millis() as you have RTC data in the clockDisplay() function. No millis() anywhere.

Hehe, case in point… I figured out how to do something in a way I understood, then after that I can compare with a better way and (eventually) understand it instead of simpley copy pasting it.

Thanks @Costas :+1:

1 Like

Thanks a lot to everyone for your help and advices, i did not mean to sound annoying, for someone who started basically a week ago your opinions are VERY importart :slight_smile: