Close

Direct Program

A project log for Home automation on the cheap

Using an esp8266, arduino nano, a salvaged usb power supply, and a couple relays you can automate anything

thjubeckthjubeck 01/09/2017 at 05:420 Comments

UPDATE: ADDED comments and updated EEPROM to work correctly after power off. Will be doing a mini update with an optimized version of the code that includes a auto-start hot spot for setting up connections on the fly

NOTE: I recommend using the EEPROM clear function in examples before uploading this code as I have had issues with this and other micro-controllers where I did not clear the EEPROM before using.

So I finally broke down and figured out how to program this without the additional micro-controller. I used a Wemos D1 mini (the esp8266 on a breakout) which allowed me to power directly from the 5v and program easier. Connect the inputs and outputs to the Wemos directly and power directly from the 5v. This sketch includes debouncing, telnet control, and OTA update abilities both with the IDE and directly to the ESP8266. This sketch uses a push button where all the other examples use a toggle switch so please keep that in mind if replacing the old sketch.

As a note I have not tried uploading using the web page so if anyone wants to comment on how that works please let me know.

To set up arduino to program the ESP8266 directly, please see this link.

CREDS: Debouncing

Programming

WEMOS info

OTA

Direct Upload

EEPROM

IMPORTANT NOTE!!!!: The pins on the WEMOS are referenced by the GPIO number not the D1 number on the board

You will have to update the SSID and Password but Should Work besides that.

//Define all Libraries to be used

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <EEPROM.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>

//Define Outputs, inputs, and if started bit. Remember on the WEMOS board these are the GPIO numbers not what is on the board
boolean LightStart = false;
int LightRelay = 14;
int Light = 0;
int LightSwitch =2;

static int relayValLight = 0;  //Define relayValLight as 0

char ser;   //Define the character ser that will be used later

int reading;           // the current reading from the input pin
int previous = HIGH;    // the previous reading from the input pin

void toggleLight(); //Define the toggle light function

//Set Debounce Time

long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;  // the debounce time; increase if the output flickers

//how many clients should be able to telnet to this ESP8266
#define MAX_SRV_CLIENTS 3

//Define Wifi SSID and Password
const char* ssid = "YourSSIDGoesHere";
const char* password = "YourPasswordGoesHere";
const char* host = "myesp8266"; // This value can be changed and should be if you use multiple devices

//Define Port to start server on
WiFiServer server(23);
//Define Max Clients that can connect
WiFiClient serverClients[MAX_SRV_CLIENTS];

//Needed for httpUpgrade webpage. Define server at port 80
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;


void setup() {
 //EEPROM start. This is a function of the ESP8266 that is needed for EEPROM to work
  EEPROM.begin(512);
  WiFi.begin(ssid, password);
  uint8_t i = 0;
  while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500);

  Serial.begin(115200);
  server.begin();
  server.setNoDelay(true);
  
  //Setup Outputs and Inputs
  pinMode(LightSwitch, INPUT_PULLUP);
  pinMode(LightRelay, OUTPUT);
  pinMode(Light, OUTPUT);
  

// WIFI OTA SECTION

  // Port defaults to 8266
  // ArduinoOTA.setPort(8266);

  // Hostname defaults to esp8266-[ChipID]
  ArduinoOTA.setHostname(host);

  // No authentication by default
  //ArduinoOTA.setPassword((const char *)"123");

  ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  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("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
 
//Create UPDATE WEB PAGE this webpage will be at http://[hostname as defined earlier].local/update
  MDNS.begin(host);
  httpUpdater.setup(&httpServer);
  httpServer.begin();
  MDNS.addService("http", "tcp", 80);

// My switch has an indicator light so I blink it here to indicate setup done


  digitalWrite(Light,HIGH);
  delay(500);
  digitalWrite(Light,LOW);

//Call toggle light function to set old value
   toggleLight();
  
//Uncomment this section to show the ip address in serial monitor 
 // Serial.println("Ready");
 //Serial.print("IP address: ");
 //Serial.println(WiFi.localIP());
}

void loop() {
   //Watch for update from http
  httpServer.handleClient();
  //Watch for ota update
  ArduinoOTA.handle();
  
  //initalize i for number of server clients
  uint8_t i;
 
  //check if there are any new clients
  if (server.hasClient()){
    for(i = 0; i < MAX_SRV_CLIENTS; i++){
      //find free/disconnected spot
      if (!serverClients[i] || !serverClients[i].connected()){
        if(serverClients[i]) serverClients[i].stop();
        serverClients[i] = server.available();
        continue;
      }
    }
    //no free/disconnected spot so reject
    WiFiClient serverClient = server.available();
    serverClient.stop();
  }
  
  //check clients for data
  for(i = 0; i < MAX_SRV_CLIENTS; i++){
    if (serverClients[i] && serverClients[i].connected()){
      if(serverClients[i].available()){
        //get data from the telnet client and push it to the UART
        while(serverClients[i].available()) 
        
    //read data from client 
    ser = serverClients[i].read();
   
    //If input from client is 4 then run toggle light function
    if(ser == '2')
       toggleLight();
    //If input from client is 4 then read the pin and give feedback
    else if(ser == '4')
        serverClients[i].println(digitalRead(LightRelay));
      }
    }
  }
//Take reading of switch
   reading = digitalRead(LightSwitch);
 //Check if debounce time has passed
if ( (millis() - lastDebounceTime) > debounceDelay) { 
  // Check reading against previous 
    if (reading == LOW && previous == HIGH){ 
      //if something has changed run toggle light function
              toggleLight(); 
         } 
  }
  //After checking if anything changed and setting output store reading as previous
  previous = reading;
 
}

//Toggle light function
void toggleLight()
 {
  //Check if this is the first run
  if (LightStart == true){
  //If it is not first run then toggle light value
   relayValLight ^= 1; // xor current value with 1 (causes value to toggle)
    //If the value is 1 then set the lights to ON
  if (relayValLight){ 
      digitalWrite(LightRelay, HIGH);
      digitalWrite(Light, HIGH);
    //store the value to EEPROM address 0
    EEPROM.write(0,relayValLight);
    //set last debounce to the current time
      lastDebounceTime = millis(); 
    //Commit changes to EEPROM
    EEPROM.commit();
    }
  //else covers if the value is 0 everything is set to OFF
    else{
      digitalWrite(LightRelay, LOW);
      digitalWrite(Light, LOW);
    //store the value to EEPROM address 0
    EEPROM.write(0,relayValLight);
    //Set the last debounce to the current time
    lastDebounceTime = millis(); 
    //Commit changes to EEPROM
    EEPROM.commit();
    }
  }
  //If this is the first run then set all values accordingly
  else {
  //Set relay variable from the EEPROM
   relayValLight = EEPROM.read(0);
   //Set indicator light and relay to the EEPROM value
   digitalWrite(LightRelay,relayValLight);
   digitalWrite(Light,relayValLight);
   //Set the start bit to true. This function is only ran once at startup
   LightStart = true;
  }
 }

Discussions