Garage Controller

This is my garage controller using Adafruit Huzzah ESP8266. First project using Blynk and enjoying it.

3 Likes

wow! but would love to see some code with this?

not sure i understand all the features?

also - the new APP will allow you to change the names on the button from OFF to ‘UP’ and things more suitable :slight_smile:

Here is a copy of my code.
I’m waiting for the new iOS version to try some of the new features.

/* V0 - ADJUSTER
 * V1 - TEMPERATURE
 * V2 - SETPOINT
 * V3 - DEADBAND
 * V4 - VALUE++
 * V5 - VALUE--
 * V6 - ADJUST++
 * V7 - lOW SET
 * V8 - OUTSIDE TEMP
 * V9 - LOW HOUR
 * V10 - HIGH SET
 * V11 - HEATER STATE FOR TREND
 * V12 - ELAPSED TIMER
 * V13 - HIGH HOUR
 * V14 - DIAGNOSTIC CODE
 * V15 - DOOR OPERATOR
 * V16 - OPERATION
 * V17 - DOOR SWITCH
 * 
 * EEPROM0 - SETPOINT
 * EEPROM1 - DEADBAND
 * EEPROM2 - BOOT
 * EEPROM3 - OPERATION
 * EEPROM4 - LOW SET
 * EEPROM5 - LOW HOUR
 * EEPROM6 - HIGH SET
 * EEPROM7 - HIGH HOUR
 */
//#define BLYNK_DEBUG
#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
#include <OneWire.h>
#include <EEPROM.h>
#include <TimeLib.h>
#include <Bounce2.h>

#define therm 4
#define door 12
#define door_swt 14

char auth[] = "";
const char* ssid     = "High Country";
const char* password = "";

IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov
const int timeZone = -4;  // Eastern Daylight Time (USA)
WiFiUDP Udp;
unsigned int localPort = 8888;  // local port to listen for UDP packets
time_t getNtpTime();
void sendNTPpacket(IPAddress &address);

byte Sensor[8] ={0x28,0xFF,0xD0,0x90,0x50,0x14,0x04,0x3A};
byte Outside[8] ={0x28,0xF0,0xAB,0xD6,0x06,0x00,0x00,0xF6};

byte adj = 0;
float temp = 18;
byte set = 15;
byte low_set = 10;
byte low_hr = 21;
byte high_set = 19;
byte high_hr = 6;
float out = 0;
byte db = 2;
boolean heater_state = 0;
String str = "";
byte count = 0;
long start = 0;
long etime = 0;
byte boot;
byte oper = 0;
boolean t_sync = 0;
byte diag = 0;
boolean door_sta;  

SimpleTimer timer;
OneWire ds(5);
Bounce debouncer = Bounce(); 

void updateData(){
  switch(count){
    
  case 0:  Blynk.virtualWrite(V1,temp);
           break;
  case 1:  Blynk.virtualWrite(V2, set);
           break;
  case 2:  Blynk.virtualWrite(V3, (float)db/10);
           break;
  case 3:  if(heater_state==1){Blynk.virtualWrite(V11, 30);}
           else{Blynk.virtualWrite(V11, 0);}
           break;
  case 4:  if(heater_state==0){str = "Off";}
           else{etime=((millis()-start)/1000);str=String(etime/60)+":";if(etime%60<10){str+="0";}str+=String(etime%60);}
           Blynk.virtualWrite(V12,str);
           break;
  case 5:  diag=0;
           if(boot>0){diag+=1;}
           if(t_sync==0){diag+=2;}
           Blynk.virtualWrite(V14, diag);
           break;
  case 6:  Blynk.virtualWrite(V8, out);
           break;
  case 7:  if(oper==0){str = "Off";}
           if(oper==1){str = "Down";}
           if(oper==2){str = "U/D";}
           Blynk.virtualWrite(V16, str);
           break;
  case 8:  Blynk.virtualWrite(V7, low_set);
           break;         
  case 9:  str=String(low_hr)+":00";
           Blynk.virtualWrite(V9, str);
           break;         
  case 10: Blynk.virtualWrite(V10, high_set);
           break;          
  case 11: str=String(high_hr)+":00";
           Blynk.virtualWrite(V13, str);
           break;           
  case 12: switch(adj){
             case 0: str = "SET";break;
             case 1: str = "DB";break;
             case 2: str = "L_S";break;
             case 3: str = "L_H";break;
             case 4: str = "H_S";break;
             case 5: str = "H_H";break;
             case 6: str = "OPER";break;
             case 7: str = "RST";break;
           }
           Blynk.virtualWrite(V0, str);
           break;
  case 13: if(door_sta==1){str = "CLD";}
           else{str = "OPEN";}
           Blynk.virtualWrite(V17, str);
           break;
                     
  }
  if(count==13){count=0;}
  else{count++;}
  
  debouncer.update();
  door_sta = debouncer.read();
}

BLYNK_WRITE(V4){
  if(param.asInt()==1){
    switch(adj){
      case 0: set++;count=1;updateData();break;
      case 1: db++;count=2;updateData();break;
      case 2: low_set++;count=8;updateData();break;
      case 3: if(low_hr==23){low_hr=0;}else{low_hr++;}count=9;updateData();break;
      case 4: high_set++;count=10;updateData();break;
      case 5: if(high_hr==23){high_hr=0;}else{high_hr++;}count=11;updateData();break;
      case 6: if(oper==2){oper=0;}else{oper++;}count=7;updateData();break;
      case 7: boot=0;t_sync=0;EEPROM.write(2,boot);EEPROM.commit();count=5;updateData();break;
    }}}

BLYNK_WRITE(V5){
  if(param.asInt()==1){
    switch(adj){
      case 0: set--;count=1;updateData();break;
      case 1: db--;count=2;updateData();break;
      case 2: low_set--;count=8;updateData();break;
      case 3: if(low_hr==0){low_hr=23;}else{low_hr--;}count=9;updateData();break;
      case 4: high_set--;count=10;updateData();break;
      case 5: if(high_hr==0){high_hr=23;}else{high_hr--;}count=11;updateData();break;
      case 6: if(oper==0){oper=2;}else{oper--;}count=7;updateData();break;
    }}}

BLYNK_WRITE(V6){if(param.asInt()==1){if(adj==7){adj=0;}else{adj++;}count=12;updateData();}}

BLYNK_WRITE(V15){digitalWrite(door, param.asInt());}

float getTemp(byte add[8]){
  byte i, dat;
  byte data[12];
  ds.reset();
  ds.select(add);
  ds.write(0x44,1);
  dat = ds.read();
  while (!dat){
   dat = ds.read();}
  dat = ds.reset();
  ds.select(add);
  ds.write(0xBE);
  for ( i = 0; i < 9; i++) {
  data[i] = ds.read();}
  int16_t raw = (data[1] << 8) | data[0];
  byte cfg = (data[4] & 0x60);
  // at lower res, the low bits are undefined, so let's zero them
  if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
  else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
  else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
  //// default is 12 bit resolution, 750 ms conversion time
  return (float)raw / 16.0;  
}

void init_temp(byte add[8]){
  ds.reset();
  ds.select(add);
  ds.write(0x4E);         // Write scratchpad
  ds.write(0);            // TL
  ds.write(0);            // TH
  ds.write(0x3F);         // Configuration Register 12bit=0X7F 11bit=0X5F 10bit= 0X3F
  ds.write(0x48); 
}

void read_in(){
  temp=getTemp(Sensor)-2;
  if((temp>=set||door_sta==0)&&heater_state==1){heater_state=0;digitalWrite(therm,LOW);}
  if(temp<=(set-(float)db/10)&&heater_state==0&&door_sta==1){heater_state=1;digitalWrite(therm,HIGH);start=millis();}
}

void read_out(){
  out=getTemp(Outside);
}

void mem(){
  boolean s = 0;
    if(set!=EEPROM.read(0)){EEPROM.write(0,set);s=1;}
    if(db!=EEPROM.read(1)){EEPROM.write(1,db);s=1;}
    if(oper!=EEPROM.read(3)){EEPROM.write(3,oper);s=1;}
    if(low_set!=EEPROM.read(4)){EEPROM.write(4,low_set);s=1;}
    if(low_hr!=EEPROM.read(5)){EEPROM.write(5,low_hr);s=1;}
    if(high_set!=EEPROM.read(6)){EEPROM.write(6,high_set);s=1;}
    if(high_hr!=EEPROM.read(7)){EEPROM.write(7,high_hr);s=1;}
    if(s==1){EEPROM.commit();}
}

void clockDisplay(){
  BLYNK_LOG("Current time: %02d:%02d:%02d %02d %02d %d",
            hour(), minute(), second(),
            day(), month(), year());
  if(t_sync==1){          
  if(oper!=0&&hour()>=low_hr&&set!=low_set){set=low_set;}
  if(oper==2&&hour()>=high_hr&&hour()<low_hr&&set!=high_set){set=high_set;}
  }         
}

void setup(){
  Serial.begin(9600);
  EEPROM.begin(8);
  set=EEPROM.read(0);
  db=EEPROM.read(1);
  oper=EEPROM.read(3);
  boot=EEPROM.read(2);
  low_set=EEPROM.read(4);
  low_hr=EEPROM.read(5);
  high_set=EEPROM.read(6);
  high_hr=EEPROM.read(7);
  boot++;
  EEPROM.write(2,boot);
  EEPROM.commit();
  
  Blynk.begin(auth, ssid, password);
   while (Blynk.connect() == false) {}

  Serial.print("IP number assigned by DHCP is ");
  Serial.println(WiFi.localIP());
  Serial.println("Starting UDP");
  Udp.begin(localPort);
  Serial.print("Local port: ");
  Serial.println(Udp.localPort());
  Serial.println("waiting for sync");
  setSyncProvider(getNtpTime);
  setSyncInterval(3600);

  timer.setInterval(500000L, clockDisplay);
  timer.setInterval(1250L, read_in);
  timer.setInterval(250L, updateData);
  timer.setInterval(300000L, mem);
  timer.setInterval(10000L, read_out);

  init_temp(Sensor);
  init_temp(Outside);

  pinMode(therm, OUTPUT);
  digitalWrite(therm, LOW);

  pinMode(door, OUTPUT);
  digitalWrite(door, LOW);

  pinMode(door_swt,INPUT_PULLUP);

  debouncer.attach(door_swt);
  debouncer.interval(1000); // interval in ms 

  read_in();
  read_out();
}

void loop(){
  Blynk.run();
  timer.run(); // Initiates SimpleTimer
}

/*-------- NTP code ----------*/

const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

time_t getNtpTime(){
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  Serial.println("Transmit NTP Request");
  t_sync=0;
  sendNTPpacket(timeServer);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      Serial.println("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      t_sync=1;
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Serial.println("No NTP Response :-(");
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address){
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:                 
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}
1 Like

Hi…great project! May I ask which HW model you specify in the Blynk app when building/running the app? I have had some success with “Uno” (runs but frequently disconnects) but nothing when specifying “ESP8266”. Thanks!

I’m using the ESP8266 in the App but the hardware in Adafruits Huzzah ESP8266

Re-designed my Project to use the new Menu widget. Now my page is simpler and more room for more widgets!

You’re using external eeprom, correct?

I am using the internal eeprom to store my settings.

Where can I find documentation about the eeprom on the ESP8266? Is all of the eeprom available for my use, or will I corrupt some ESP8266 data by doing something wrong?

Can the eeprom on the ESP8266 be used to help diagnose a watchdog timer trip out? Or is the eeprom meant to be written to sparingly?

thanks

I learnt how to use the eeprom from the examples on this web page https://github.com/sandeepmistry/esp8266-Arduino/tree/master/esp8266com/esp8266/libraries/EEPROM

I’ve only used it for storing about 10 bytes of data so I wouldn’t know what the limitation are and if it can be used for debugging.