close-circle
Close
0%
0%

HariFun#132 Sixteen Channel WiFi Remote

Playing with the PCF8574 8-bit I/O Expander

Similar projects worth following
close
16 buttons wirelessly connected to 16 LEDs using a pair of ESP-1 WiFi Modules and four PCF8574 I/O expanders.



Binary Counter Sketch

// PCF8574 Binary Counter Test
// Hari Wiguna, 2016

#include <Wire.h>

uint8_t address = 0x21;

void BinaryCountTest()
{
  for (uint8_t val = 0; val <= 255; val++)
  {
    Serial.print(val);
    Serial.print(" ");
    Wire.beginTransmission(address);
    Wire.write(~val);
    uint8_t error = Wire.endTransmission();
    Serial.println(error);
    delay(200);
  }
}

void setup() {
  Serial.begin(9600);
  
  //Wire.begin(); // Arduino needs (SDA=A4,SCL=A5)
  Wire.begin(0,2); // ESP8266 needs (SDA=GPIO0,SCL=GPIO2)
}

void loop() {
  BinaryCountTest();
}

  • 1
    Step 1

    === WebServer Sketch ===

    // PCF8574 WebServer, listens for /inline?state=
    // Hari Wiguna, 2016
    
    #include <ESP8266WiFi.h>
    #include <WiFiClient.h>
    #include <ESP8266WebServer.h>
    #include <ESP8266mDNS.h>
    
    // Declare and set these two variables here or in an include file
    //const byte credentialCount = 2; //IMPORTANT! Change this to match how many credentials you have!
    //const char* credentials[] =
    //{
    //  "ssid1","pwd1",
    //  "ssid2","pwd2"
    //};
    #include "C:\Users\hwiguna\Documents\Creds\creds.txt"
    
    const byte bufMax = 20;
    char ssid[bufMax];
    char password[bufMax];
    
    ESP8266WebServer server(80);
    
    void ScanWiFi()
    {
      bool found = false;
      
      // Set WiFi to station mode and disconnect from an AP if it was previously connected
      WiFi.mode(WIFI_STA);
      WiFi.disconnect();
      delay(100);
    
      Serial.println("scan start");
    
      // WiFi.scanNetworks will return the number of networks found
      int n = WiFi.scanNetworks();
      Serial.println("scan done");
      if (n == 0)
        Serial.println("no networks found");
      else
      {
        Serial.print(n);
        Serial.println(" networks found");
        for (int i = 0; (i < n) && !found; ++i)
        {
          // Print SSID and RSSI for each network found
          Serial.print(i + 1);
          Serial.print(": ");
          Serial.print(WiFi.SSID(i));
          Serial.print(" (");
          Serial.print(WiFi.RSSI(i));
          Serial.print(")");
          Serial.print((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "* ");
          delay(10);
    
          char foundssid[bufMax];
          WiFi.SSID(i).toCharArray(foundssid, bufMax);
    
          for (byte i = 0; i < credentialCount; i++)
          {
            if ( strcmp( foundssid, credentials[i*2]) == 0)
            {
              Serial.print("<-- MATCH");
              strcpy(ssid, credentials[i*2]);
              strcpy(password, credentials[i*2 + 1]);
              found = true;
              exit;
            }
          }
          Serial.println();
        }
      }
      Serial.println("");
    }
    
    //------------------------------------
    #include <Wire.h>
    
    int mode = 0;
    uint8_t error, address, curVal, val;
    
    void LedRefresh(uint8 addr)
    {
      Wire.beginTransmission(addr);
      Wire.write(~val);
      error = Wire.endTransmission();
    }
    
    void SetLeds(int num)
    {
      val = num & 0xFF;
      LedRefresh(address);
      
      val = num >> 8;
      LedRefresh(address + 1);
    }
    
    //------------------------------------
    void handleRoot() {
      server.send(200, "text/plain", "hello from esp8266!");
    }
    
    void handleNotFound(){
      String message = "File Not Found\n\n";
      message += "URI: ";
      message += server.uri();
      message += "\nMethod: ";
      message += (server.method() == HTTP_GET)?"GET":"POST";
      message += "\nArguments: ";
      message += server.args();
      message += "\n";
      for (uint8_t i=0; i<server.args(); i++){
        message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
      }
      server.send(404, "text/plain", message);
    }
    
    void setup(void){
      Serial.begin(115200);
    
      ScanWiFi(); 
      WiFi.begin(ssid, password);
      Serial.println("");
    
      // Wait for connection
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println("");
      Serial.print("Connected to ");
      Serial.println(ssid);
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());
    
      if (MDNS.begin("esp8266")) {
        Serial.println("MDNS responder started");
      }
    
      server.on("/", handleRoot);
    
    
      //=== PCF8574 Specific code ===
      server.on("/inline", [](){
        String state = server.arg("state");
        int num = state.toInt();
        String out = String(num);
        server.send(200, "text/plain", out);
        SetLeds(num);
      });
      //=== PCF8574 Specific code ===
    
    
      server.onNotFound(handleNotFound);
    
      server.begin();
      Serial.println("HTTP server started");
    
      //--- LED ---
      //Wire.begin(); // Arduino needs (SDA=A4,SCL=A5)
      Wire.begin(0, 2); // ESP8266 needs (SDA=GPIO0,SCL=GPIO2)
      address = 0x20;
    }
    
    void loop(void){
      server.handleClient();
    }
  • 2
    Step 2

    === WebClient Sketch ===

    // PCF8574 WebClient, watches buttons and sends /inline?state=x to WebServer
    // Hari Wiguna, 2016
    
    #include <ESP8266WiFi.h>
    
    // Declare and set these two variables here or in an include file
    //const byte credentialCount = 2; //IMPORTANT! Change this to match how many credentials you have!
    //const char* credentials[] =
    //{
    //  "ssid1","pwd1",
    //  "ssid2","pwd2"
    //};
    #include "C:\Users\hwiguna\Documents\Creds\creds.txt"
    
    const byte bufMax = 20;
    char ssid[bufMax];
    char password[bufMax];
    
    const char* host = "192.168.254.114"; // As reported by the webserver
    
    void ScanWiFi()
    {
      bool found = false;
    
      // Set WiFi to station mode and disconnect from an AP if it was previously connected
      WiFi.mode(WIFI_STA);
      WiFi.disconnect();
      delay(100);
    
      Serial.println("scan start");
    
      // WiFi.scanNetworks will return the number of networks found
      int n = WiFi.scanNetworks();
      Serial.println("scan done");
      if (n == 0)
        Serial.println("no networks found");
      else
      {
        Serial.print(n);
        Serial.println(" networks found");
        for (int i = 0; (i < n) && !found; ++i)
        {
          // Print SSID and RSSI for each network found
          Serial.print(i + 1);
          Serial.print(": ");
          Serial.print(WiFi.SSID(i));
          Serial.print(" (");
          Serial.print(WiFi.RSSI(i));
          Serial.print(")");
          Serial.print((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "* ");
          delay(10);
    
          char foundssid[bufMax];
          WiFi.SSID(i).toCharArray(foundssid, bufMax);
    
          for (byte i = 0; i < credentialCount; i++)
          {
            if ( strcmp( foundssid, credentials[i * 2]) == 0)
            {
              Serial.print("<-- MATCH");
              strcpy(ssid, credentials[i * 2]);
              strcpy(password, credentials[i * 2 + 1]);
              found = true;
              exit;
            }
          }
          Serial.println();
        }
      }
      Serial.println("");
    }
    
    
    //------------------------------------
    #include <Wire.h>
    
    int mode = 0;
    uint8_t error, address, curVal, val;
    int prevValue = 0;
    
    uint8_t ReadButtons(uint8 offset)
    {
      int addr = address + offset;
      uint8 val;
    
      //-- To read we need to first set all outputs to HIGH --
      Wire.beginTransmission(addr);
      Wire.write(0xFF); // Get ready to read all bits
      error = Wire.endTransmission();
    
      //-- Read all switches --
      Wire.beginTransmission( addr );
      Wire.requestFrom((int)addr, 1); // Ask for 1 byte from slave
      val = ~Wire.read(); // read that one byte, invert so pressing the button would set the bit high
      error = Wire.endTransmission();
    
      return val;
    }
    
    
    void setup() {
      Serial.begin(115200);
      delay(10);
    
      //Wire.begin(); // Arduino needs (SDA=A4,SCL=A5)
      Wire.begin(0, 2); // ESP8266 needs (SDA=GPIO0,SCL=GPIO2)
      address = 0x20;
    
      ScanWiFi();
      WiFi.begin(ssid, password);
    
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
    
      Serial.println("");
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
    }
    
    int value = 0;
    
    void loop() {
      delay(10);
    
      uint8_t val0 = ReadButtons(0);
      uint8_t val1 = ReadButtons(1);
    
      value = val0 + (val1 << 8);
      if (value != prevValue)
      {
        Serial.print("\nconnecting to ");
        Serial.println(host);
    
        // Use WiFiClient class to create TCP connections
        WiFiClient client;
        const int httpPort = 80;
        if (!client.connect(host, httpPort)) {
          Serial.println("connection failed");
          return;
        }
    
        // We now create a URI for the request
        String url = "/inline?state=";
        url += value;
    
        Serial.print("Requesting URL: ");
        Serial.println(url);
    
        // This will send the request to the server
        client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                     "Host: " + host + "\r\n" +
                     "Connection: close\r\n\r\n");
        int timeout = millis() + 5000;
        while (client.available() == 0) {
          if (timeout - millis() < 0) {
            Serial.println(">>> Client Timeout !");
            client.stop();
            return;
          }
        }
    
        // Read all the lines of the reply from server and print them to Serial
        //    while (client.available()) {
        //      String line = client.readStringUntil('\r');
        //      Serial.print(line);
        //    }
    
        //    Serial.println();
        //    Serial.println("closing connection");
    
        prevValue = value;
      }
    }
  • 3
    Step 3

    Schematics

    Top circuit is the WebClient, sending the button state as part of the web request.

    Bottom circuit is the WebServer, looks at the web request and sets the LEDs accordingly.

    Note how we set the I2C address to 0x00 on the left PCF8574 and 0x01 on the right PCF8574.

    Not shown is the 3.3V USB to Serial module needed to program the ESPs.

View all 3 instructions

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates