Garage Controller

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