Cirkit Designer LogoCirkit DesignerYour all-in-one circuit design IDE Launch Cirkit Designer App

Wi-Fi Controlled Smart Relay Switch with ESP8266 and MCP23017

View and Edit Project In Cirkit DesignerImage of Wi-Fi Controlled Smart Relay Switch with ESP8266 and MCP23017

Circuit Documentation

Summary

The circuit in question is designed to control an 8-channel relay module using an MCP23017 I/O expander, which is interfaced with an ESP8266 microcontroller. The ESP8266 is responsible for connecting to a Wi-Fi network and communicating with an MQTT server to receive commands for controlling the relays. The MCP23017 expands the limited number of GPIOs available on the ESP8266 to control more devices, in this case, the relays. The relays are actuated by toggle switches connected to the MCP23017, and their state can be remotely monitored and controlled via MQTT. A 5V battery provides power to the circuit, and multiple single-pole single-throw (SPST) toggle switches are used to manually control the relays.

Component List

MCP23017 - I/O Expander

5V 8-Channel Relay Module

ESP8266 - Microcontroller

5V Battery

Toggle Switch SPST (Multiple Instances)

Wiring Details

MCP23017 - I/O Expander

5V 8-Channel Relay Module

ESP8266 - Microcontroller

5V Battery

Toggle Switch SPST (Multiple Instances)

Documented Code

#include <ESP8266WiFi.h>
#include <Adafruit_MCP23017.h>
#include <PubSubClient.h>

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* mqtt_server = "YOUR_MQTT_SERVER_ADDRESS";
const char* mqtt_user = "YOUR_MQTT_USER";
const char* mqtt_password = "YOUR_MQTT_PASSWORD";

WiFiClient espClient;
PubSubClient client(espClient);
Adafruit_MCP23017 mcp;

// Relay and switch pin mappings on MCP23017
const uint8_t relayPins[] = {0, 1, 2, 3, 4, 5, 6, 7};
const uint8_t switchPins[] = {8, 9, 10, 11, 12, 13, 14, 15};
bool relayState[8] = {false, false, false, false, false, false, false, false};

void setup() {
  Serial.begin(115200);
  setupWiFi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(mqttCallback);

  // Initialize MCP23017
  mcp.begin(0);  // Default address 0x20

  // Set up relay pins as output
  for (uint8_t i = 0; i < 8; i++) {
    mcp.pinMode(relayPins[i], OUTPUT);
    mcp.digitalWrite(relayPins[i], LOW);  // Ensure relays are OFF initially
  }

  // Set up switch pins as input with pull-up
  for (uint8_t i = 0; i < 8; i++) {
    mcp.pinMode(switchPins[i], INPUT);
    mcp.pullUp(switchPins[i], HIGH);
  }
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  // Monitor switches and toggle corresponding relay
  for (uint8_t i = 0; i < 8; i++) {
    if (mcp.digitalRead(switchPins[i]) == LOW) {  // Switch is pressed
      toggleRelay(i);
      delay(200);  // Debounce delay
    }
  }
}

// Function to connect to WiFi
void setupWiFi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
}

// Function to handle MQTT reconnection
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP8266Client", mqtt_user, mqtt_password)) {
      Serial.println("connected");
      // Subscribe to relay control topics
      for (uint8_t i = 0; i < 8; i++) {
        String topic = "living-room/relay" + String(i+1) + "/set";
        client.subscribe(topic.c_str());
      }
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

// MQTT callback function to process messages
void mqttCallback(char* topic, byte* payload, unsigned int length) {
  String message;
  for (unsigned int i = 0; i < length; i++) {
    message += (char)payload[i];
  }

  // Control relays based on MQTT message
  for (uint8_t i = 0; i < 8; i++) {
    String relayTopic = "living-room/relay" + String(i+1) + "/set";
    if (String(topic) == relayTopic) {
      if (message == "ON") {
        setRelay(i, true);
      } else if (message == "OFF") {
        setRelay(i, false);
      }
    }
  }
}

// Toggle relay function
void toggleRelay(uint8_t relayNum) {
  relayState[relayNum] = !relayState[relayNum];
  mcp.digitalWrite(relayPins[relayNum], relayState[relayNum] ? HIGH : LOW);
  
  // Publish relay state to MQTT
  String stateTopic = "living-room/relay" + String(relayNum+1) + "/state";
  client.publish(stateTopic.c_str(), relayState[relayNum] ? "ON" : "OFF");
}

// Set relay state directly
void setRelay(uint8_t relayNum, bool state) {
  relayState[relayNum] = state;
  mcp.digitalWrite(relayPins[relayNum], state ? HIGH : LOW);

  // Publish relay state to MQTT
  String stateTopic = "living-room/relay" + String(relayNum+1) + "/state";
  client.publish(stateTopic.c_str(), state ? "ON" : "OFF");
}

This code is designed to run on the ESP8266 microcontroller. It initializes the Wi-Fi connection, connects to the MQTT server, and sets up the MCP23017 I/O expander. The ESP8266 monitors the state of the toggle switches through the MCP23017 and toggles the state of the corresponding relay. It also listens for MQTT messages to control the relays remotely and publishes the state of the relays back to the MQTT server.