MCP23017 IOs Expander not working when programmed to subscribe and publish to mqtt

Hi everone. I'm in a deliberate dilemma of wanting to expand the ESP32's digital ports and connect to the network via RJ45 cable.
First I installed the MCP23017 port expander including more than one (1) (Thus identifying the addresses) and it simply worked well with the example codes from the Adafruit-MCP23017 library itself.
Separately, I configured the ENC28J60 shield to connect the esp32 to the network using the cable. Luckily I also managed to get it working.
Finally I wanted to put together the codes so that I could control the inputs and outputs (Buttons and LEDs) and also through the home assistant via mqtt. I was only able to make the buttons and LEDs connected directly to the ESP32 work, I can control the LEDs through the buttons as well as through the home assistant via mqtt.
The problem now is to control the LEDs connected to the GPIO expander. They don't trigger anything. Neither through the home assistant nor through the buttons. The buttons connected to the expanders also show no effect when pressed. I was supposed to see it through the serial monitor, in the same way I see those connected to the ESP32.

#include <SPI.h>
#include <Wire.h>
#include <Bounce2.h>
#include <EthernetENC.h>
#include <PubSubClient.h>
#include <Adafruit_MCP23X17.h>

// Instanciar objeto mcp
Adafruit_MCP23X17 mcp1;    
Adafruit_MCP23X17 mcp2;


// Definir o endereço MAC e IP para o ENC28J60
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 177);

// //Definir detalhes do MQTT broker
const char* mqtt_server = "192.168.1.29";
const int mqtt_port = 1883;
const char* mqtt_username = "mqtt_user";
const char* mqtt_password = "mqtt_pass";

// Define GPIO pins
const int lampada_varanda = 2;
const int interruptor_varanda = 4;
const int interruptor_sala_de_estar = 0;
const int lampada_sala_de_estar = 0;
int lampada_varandaValue = LOW;
int lampada_sala_de_estarValue = LOW;

EthernetClient ethClient;
PubSubClient client(ethClient);

void callback(char* topic, byte* payload, unsigned int length) {
  // lidar com a mensagem chegou
  String content = "";
  char character;
  for (int num = 0; num < length; num++) {
    character = payload[num];
    content.concat(character);
  }
  Serial.println(topic);
  Serial.println(content); // Mensagens enviadas por ações de botõo são retornadas pelo broker e impressas no monitor serial
  if (content == "1on") {
    lampada_varandaValue = HIGH;
  }

  if (content == "1off") {
    lampada_varandaValue = LOW;
  }

  
  if (content == "2on") {
    lampada_sala_de_estarValue = HIGH;
  }

  if (content == "2off") {
    lampada_sala_de_estarValue = LOW;
  }

    digitalWrite(lampada_varanda, lampada_varandaValue);
    digitalWrite(lampada_sala_de_estar, lampada_sala_de_estarValue);

}
    Bounce bouncer1 = Bounce();
    Bounce bouncer2 = Bounce();
void setup() {
  // Iniciar o Moitor Serial
  Serial.begin(115200);
  Wire.begin();

     // Inicializar as instâncias dos MCP23017
if (!mcp1.begin_I2C(0x20)) {
    Serial.println("Erro ao inicializar o MCP23017 1. Por favor, verifique as conexções.");
    while (1);
  }

  if (!mcp2.begin_I2C(0x21)) {
    Serial.println("Erro ao inicializar o MCP23017 2. Por favor, verifique as conexções.");
    while (1);
  }

  // Setup Ethernet
  Ethernet.begin(mac, ip);

  // Setup MQTT
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

  // Setup GPIO
  pinMode(lampada_varanda, OUTPUT);
  pinMode(interruptor_varanda, INPUT_PULLUP);
  digitalWrite(interruptor_varanda, HIGH);
  bouncer1.attach(interruptor_varanda);
  bouncer1.interval(5);

  mcp1.pinMode(interruptor_sala_de_estar, INPUT);
  mcp2.pinMode(lampada_sala_de_estar, OUTPUT);
  digitalWrite(interruptor_sala_de_estar, HIGH);
  bouncer2.attach(interruptor_sala_de_estar);
  bouncer2.interval(5);
}

void loop() {
  // ConnectConectar ao MQTT
  if (!client.connected()) {
    reconnect();
  }

  //Lidando com as mensagens do mqtt broker de novo
  client.loop();

    if (bouncer1.update()) {
    if (bouncer1.read() == HIGH) {
      if (lampada_varandaValue == LOW) {
      lampada_varandaValue = HIGH;
      client.publish("casa/interruptores/varanda", "1on");
      } else {
        lampada_varandaValue = LOW;
        client.publish("casa/interruptores/varanda", "1off");
      }
    }
  }
   int buttonState = mcp1.digitalRead(interruptor_sala_de_estar);
    if (bouncer2.update()) {
    if (bouncer2.read() == HIGH) {
      if (lampada_sala_de_estarValue == LOW) {
      lampada_sala_de_estarValue = HIGH;
      client.publish("casa/interruptores/sala_estar", "2on");
      } else {
        lampada_sala_de_estarValue = LOW;
        client.publish("casa/interruptores/sala_estar", "2off");
      }
    }
  }

}
void reconnect() {
  // Repetição até se conectar
  while (!client.connected()) {
    Serial.println("Tentando conectar ao servidor MQTT...");

    // Tentativa de conecxão
    if (client.connect("ESP32Client", mqtt_username, mqtt_password)) {
      Serial.println("Conectado");
      // Subcrevendo - se ao tópico (se Necessário)
      client.subscribe("casa/interruptores/#");
    } else {
      Serial.print("Falha ao conectar, rc= ");
      Serial.println(client.state());
      Serial.println("Tentar de novo em 5 segundos");
      // Esperar 5 segundos antes de tentar outra vez
      delay(5000);
    }
  }
}

If anyone can take a look at my code and help me understand where I'm going wrong. It's a project to automate my home.
Hugs.
Dércio

The code to send the "buttonState" is missing.

I just added the buttonstate but in this code i'm using debounce. The buttonstate has no job here. look that on "varanda" every thing is wirking but on "Sala_de_estar" that is on MCP, is not working. The configurations are the same, the only difference is pinMode definition

is monitoring pin 0 on the ESP32.

For debouncing buttons on the MCP23107 see the following

Thanks. I'll try it and revert back :back:

No, according to my declaration, is monitoring GPIO 0 of MCP1

So far I'm halfway there, I've managed to get the lampada_sala_de_estar to activate by the home assistant via mqtt using the same code. I made a small change here:

and it looked like this:

mcp2.digitalWrite(lampada_sala_de_estar, lampada_sala_de_estarValue);

What's missing now is being able to activate it via the physical switch, just like I do with the Lampada_varanda which is connected directly to the ESP32. Thanks.

Hi @mikb55 , i tried this library but it is giving me the follow error:

In file included from \\PISERVER\Documentos\Arduino\ESP32_Ligado_ao_ENC28J60_ligar_LED_com_bot_ino\ESP32_Ligado_ao_ENC28J60_ligar_LED_com_bot_ino.ino:4:
C:\Users\D�rcio Ricardo\Documents\Arduino\libraries\Bounce2mcp-master/Bounce2mcp.h:42:10: fatal error: Adafruit_MCP23017.h: No such file or directory
 #include <Adafruit_MCP23017.h>
          ^~~~~~~~~~~~~~~~~~~~~
compilation terminated.
exit status 1
Error compiling for board ESP32 Dev Module.

Hi @dricardo. The "Bounce2mcp" library was written for an older version of the "Adafruit MCP23017 Arduino Library" library. The Adafruit developers changed the header filename from Adafruit_MCP23017.h to Adafruit_MCP23X17.h since that time. So when you try to use the "Bounce2mcp" library while a modern version of "Adafruit MCP23017 Arduino Library" is installed, you get this error.

Since it is likely there are other breaking changes beyond the header filename, I think the best approach for now is to install the older version of the "Adafruit MCP23017 Arduino Library". I'll provide instructions you can follow to do that. I'll assume you are using Arduino IDE 2.x. If you are instead using Arduino IDE 1.x, some small adjustments to the instructions will be needed. You'll probably be able to extrapolate what to do, but if you have problems just let me know and I'll provide assistance.

  1. Select Sketch > Include Library > Manage Libraries... from the Arduino IDE menus to open the "Library Manager" view in the left side panel.
  2. Type Adafruit MCP23017 Arduino Library in the "Filter your search..." field.
  3. Scroll down through the list of libraries until you see the "Adafruit MCP23017 Arduino Library" entry.
  4. You will see a drop-down version menu at the bottom of the entry. Select "1.3.0" from the menu.
  5. Click the "INSTALL" button at the bottom of the entry.
  6. Wait for the installation to finish.

Now try compiling your sketch again. Hopefully this time it will work without any problems.

1 Like

Thanks @ptillisch for your assistance, i did your instruction and now i'm getting this error:

c:\Users\D�rcio Ricardo\Documents\Arduino\libraries\Bounce2mcp-master/Bounce2mcp.h:51:10: note:   candidate expects 3 arguments, 2 provided

exit status 1

Compilation error: could not convert 'mcp1.Adafruit_MCP23017::begin((& Wire))' from 'void' to 'bool'

Comming from the following bordered lines:
if (!mcp1.begin(0x20))
if (!mcp2.begin(0x21))

  Serial.begin(115200);
  Wire.begin();

     // Inicializar as instâncias dos MCP23017
if (!mcp1.begin(0x20)) {
    Serial.println("Erro ao inicializar o MCP23017 1. Por favor, verifique as conexções.");
    while (1);
  }

  if (!mcp2.begin(0x21)) {
    Serial.println("Erro ao inicializar o MCP23017 2. Por favor, verifique as conexções.");
    while (1);
  }

Thanks you @mikb55 for suggest me the Bounce2mcp library, it worked for me but I struggled to make it work with adafruit_mcp23017 library.
And
@ptillisch thank you very much. I did exactly what you told me to do, but i found some arrors. However, i didn't sleep until find the solution because you tips were the right way forward. I did some changes on
mcp.begin and wire.begin.

The best way to explain what i did to get job done is to post my final code to compare with the first one.

#include <Wire.h>
#include <SPI.h>
#include <PubSubClient.h>
#include <EthernetENC.h>
#include <Bounce2.h>
//#include <Adafruit_MCP23X17.h>
#include <Bounce2mcp.h>
#include <Adafruit_MCP23017.h>


// Instantiate mcp object
Adafruit_MCP23017 mcp1;    
Adafruit_MCP23017 mcp2;

// Define MAC and IP address for the ENC28J60
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 177);

// Define MQTT broker details
const char* mqtt_server = "192.168.1.29";
const int mqtt_port = 1883;
const char* mqtt_username = "mqtt_user";
const char* mqtt_password = "mqtt_pass";

// Define GPIO pins
const int lampada_varanda = 2;
const int interruptor_varanda = 4;
const int interruptor_sala_de_estar = 0;
const int lampada_sala_de_estar = 0;
int lampada_varandaValue = LOW;
int lampada_sala_de_estarValue = LOW;


EthernetClient ethClient;
PubSubClient client(ethClient);

void callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived
  String content = "";
  char character;
  for (int num = 0; num < length; num++) {
    character = payload[num];
    content.concat(character);
  }
  Serial.println(topic);
  Serial.println(content); // message sent out by button actions is returned from broker and serial printed

  if (content == "1on") {
    lampada_varandaValue = HIGH;
  }

  if (content == "1off") {
    lampada_varandaValue = LOW;
  }

  
  if (content == "2on") {
    lampada_sala_de_estarValue = HIGH;
  }

  if (content == "2off") {
    lampada_sala_de_estarValue = LOW;
  }

    digitalWrite(lampada_varanda, lampada_varandaValue);
    mcp2.digitalWrite(lampada_sala_de_estar, lampada_sala_de_estarValue);

}
    Bounce bouncer1 = Bounce();
    Bounce bouncer2 = Bounce();
    BounceMcp debouncer = BounceMcp(); 
void setup() {
  // Start Serial
  Serial.begin(115200);
  ///Wire.begin();
mcp1.begin(0, &Wire);
mcp2.begin(1, &Wire);

  // Setup Ethernet
  Ethernet.begin(mac, ip);

  // Setup MQTT
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

  // Setup GPIO
  pinMode(lampada_varanda, OUTPUT);
  pinMode(interruptor_varanda, INPUT_PULLUP);
  digitalWrite(interruptor_varanda, HIGH);
  bouncer1.attach(interruptor_varanda);
  bouncer1.interval(50);

  mcp2.pinMode(lampada_sala_de_estar, OUTPUT);
  mcp1.pinMode(interruptor_sala_de_estar, INPUT_PULLUP);
  mcp1.digitalWrite(interruptor_sala_de_estar, HIGH);
  debouncer.attach(mcp1, interruptor_sala_de_estar, 50);
}

void loop() {
  // Connect to MQTT
  if (!client.connected()) {
    reconnect();
  }

  // Handle MQTT messages
  client.loop();
  
    if (bouncer1.update()) {
    if (bouncer1.read() == HIGH) {
      if (lampada_varandaValue == LOW) {
      lampada_varandaValue = HIGH;
      client.publish("casa/interruptores/varanda", "1on");
      } else {
        lampada_varandaValue = LOW;
        client.publish("casa/interruptores/varanda", "1off");
      }
    }
  }

    if (debouncer.update()) {
    if (debouncer.read() == HIGH) {

      if (lampada_sala_de_estarValue == LOW) {
    mcp2.digitalWrite(lampada_sala_de_estar, HIGH);
      client.publish("casa/interruptores/sala_estar", "2on");
      } else {
        mcp2.digitalWrite(lampada_sala_de_estar, LOW);
        client.publish("casa/interruptores/sala_estar", "2off");
      }
    }
  }
  
}

void reconnect() {
  // Loop until reconnected
  while (!client.connected()) {
    Serial.println("Tentando conectar ao servidor MQTT...");

    // Attempt to connect
    if (client.connect("ESP32Client", mqtt_username, mqtt_password)) {
      Serial.println("Conectado");
      // Subscribe to topics if needed
      client.subscribe("casa/interruptores/#");
    } else {
      Serial.print("Falha ao conectar, rc= ");
      Serial.println(client.state());
      Serial.println("Tentar de novo em 5 segundos");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}


You are welcome. Great job on working your way through all the problems! Thanks for taking the time to post an update.

Regards,
Per

1 Like