Utilising Additional GPIO (MCP23017) Pins in my NodeMCU MQTT Project

Hi All

I am using the code below to read my magnetic door and PIR sensors and publish to my MQTT server.

The code is working well but I have the need to add more GPIO pins using a MCP23017 to the project.

This is where I am getting confused as the pin numbers in the original code refers to the NodeMCU pins. How do I go about using the mcp pins in this project as well?

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

#define WLAN_SSID       "myssid"
#define WLAN_PASS       "****"

WiFiClient client;
PubSubClient mqtt(client, "192.168.0.76", 1883);

#define SENSOR_COUNT 6
#define DEVICE_NAME "Alarm-Node2"

byte sensorPins[SENSOR_COUNT] = {0, 2, 14, 12, 13, 10}; // The NODEMCU pins to which the sensors are connected.
boolean sensorStates[SENSOR_COUNT] = {1, 1, 1, 1, 1, 1};
String deviceName = DEVICE_NAME;
String sensorNames[SENSOR_COUNT] = {"D3","D4","D5","D6","D7","D12"}; // 

Adafruit_MCP23017 mcp;

void setup() {
mcp.begin();      // use default address 0
//mcp.begin();      // use default address 0
    // the the pinmode for all used pins to INPUT_PULLUP
    for (byte i = 0; i < SENSOR_COUNT; i++) {
        byte pin = sensorPins[i];
        pinMode(pin, INPUT);
    mcp.pinMode(0, INPUT);
    mcp.pinMode(1, INPUT);
    mcp.pinMode(2, INPUT);
    mcp.pinMode(3, INPUT);
    mcp.pinMode(4, INPUT);
    mcp.pinMode(5, INPUT);
    mcp.pinMode(6, INPUT);
    mcp.pinMode(7, INPUT);
    mcp.pinMode(8, INPUT);
    mcp.pinMode(9, INPUT);
    mcp.pinMode(10, INPUT);
    mcp.pinMode(11, INPUT);
    mcp.pinMode(12, INPUT);
    mcp.pinMode(13, INPUT);
    mcp.pinMode(14, INPUT);
    mcp.pinMode(15, INPUT);    
}

    // Initiate the serial connection for debugging.
    Serial.begin(115200);
    delay(10);
    
    Serial.println("Starting ...");
}
void loop() {

    // Check if the Wifi is connected, if not, call the WiFi_connect() method.
    if (WiFi.status() != WL_CONNECTED) {
        WiFi_connect();
    }
    
    // Check if there is a connection with the MQTT server, if not, call the MQTT_connect() method.
    if (!mqtt.connected()) {
        Serial.println("MQTT Disconnected!");
        MQTT_connect();
    }
    
    // Call the loop method, to periodically ping the server to keep the connection alive.
    mqtt.loop();

    // Loop thru all the sensors defined at the start.
    for (byte i = 0; i < SENSOR_COUNT; i++) {
    
        // Create some helper variables.
        byte pin = sensorPins[i];
        boolean pinState = digitalRead(pin);
        boolean lastPinState =  sensorStates[i];
        String sensorName = sensorNames[i];

        // Check if the state for the current pin has changed.
        if (pinState != lastPinState) {

            // Define a string with the topic to which we want to post the new state to ...
            // and convert it into a char * array which we need for the pubsubclient.
            String feedNameString =  String("/device/" + deviceName + "/sensor/" + sensorName);
            char topic[feedNameString.length() + 1];
            feedNameString.toCharArray(topic, feedNameString.length() + 1);

            // Output the new state to the serial for debugging.
            Serial.print("New state for sensor ");
            Serial.print(topic);
            Serial.print(": ");
            Serial.print(pinState);

            // Publish the new state to the MQTT server.
            // The message is sent as a retained message to always 
            // have the last state available on the broker.
            // The QoS is set to 1, to make sure the delivery 
            // of the mseeage to the broker is guaranteed.
            if (mqtt.publish(MQTT::Publish(topic, pinState ? "1" : "0").set_retain().set_qos(1).set_dup())) {
                Serial.println(F(" ... Published!"));
            } else {
                Serial.println(F(" ... MQTT PUBLISH FAILED!"));
            }
            
            // Store the new pinstate in the pinStates array.
            sensorStates[i] = pinState;
        }
    }

    // Wait 50 miliseconds before we repeat the runloop.
    delay(50);
}

void WiFi_connect() {
    // Print some debuggin info to the serial terminal.
    Serial.println(); Serial.println();
    Serial.print("Connecting to ");
    Serial.print(WLAN_SSID);
    Serial.print(" ");
    
    // Connect to the WiFi netwerk using the previously defined SSID and Password. 
    WiFi.begin(WLAN_SSID, WLAN_PASS);
    while (WiFi.status() != WL_CONNECTED) {
        // If there is no connection. Wait half a second before checking again.
        delay(500);
        Serial.print(".");
    }
    Serial.println();

    // After the connection is established, print the IP-adres to the serial terminal for debugging.
    Serial.print("WiFi connected! - ");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
}

void MQTT_connect() {
    // Define a string with the topic to which we want to post the connection state of this device to ...
    // and convert it into a char * array which we need for the pubsubclient.
    String feedNameString =  String("/device/" + deviceName + "/connected");
    char topic[feedNameString.length() + 1];
    feedNameString.toCharArray(topic, feedNameString.length() + 1);

    // As long as there is no active MQTT connection ...
    while (!mqtt.connected()) {
        Serial.print("Attempting MQTT connection ... ");

        // Try to connect to the MQTT broker. 
        // As the 'will' we set the topic and connection state to 0.
        // This means that is if the connection is dropped,
        // the broker will publish the connection state to the defined topic.
        if (mqtt.connect(MQTT::Connect(DEVICE_NAME).set_will(topic, "0", 1, true))) {
            Serial.println("Connected!");
            
            // After the connection is established, publish a new connection state. 
            mqtt.publish(MQTT::Publish(topic, "1").set_retain().set_qos(1));   
                 
        } else {

            // Wait half a second before trying again.
            Serial.println("Failed! - Try again in half a second.");
            delay(500);
        }
    }
}

I am trying to use one of the library examples as an guide on how to build further onto the main code:

#include <Wire.h>
#include "Adafruit_MCP23017.h"

// Basic pin reading and pullup test for the MCP23017 I/O expander
// public domain!

// Connect pin #12 of the expander to Analog 5 (i2c clock)
// Connect pin #13 of the expander to Analog 4 (i2c data)
// Connect pins #15, 16 and 17 of the expander to ground (address selection)
// Connect pin #9 of the expander to 5V (power)
// Connect pin #10 of the expander to ground (common ground)
// Connect pin #18 through a ~10kohm resistor to 5V (reset pin, active low)

// Input #0 is on pin 21 so connect a button or switch from there to ground

Adafruit_MCP23017 mcp;
  
void setup() {  
  mcp.begin();      // use default address 0

  mcp.pinMode(0, INPUT);
  mcp.pullUp(0, HIGH);  // turn on a 100K pullup internally

  pinMode(13, OUTPUT);  // use the p13 LED as debugging
}



void loop() {
  // The LED will 'echo' the button
  digitalWrite(13, mcp.digitalRead(0));
}

I would greatly appreciate advice and assistance.

This statement from the example:

digitalWrite(13, mcp.digitalRead(0));

means read the value of mcp23017 pin GPA0 then write that value to digital pin 13 of the arduino (which is connected to a led).

Here is the data sheet for the mcp23017:

There you see pin GPA0 is physical pin 21 (on the DIP package)

Adafruit has tried to write the library in such a way that the commands are similar to handling arduino digital pins:

mcp.pinMode(0, OUTPUT);
mcp.digitalWrite(0, HIGH);
mcp.digitalRead(0) ;
etc.