MQTT and wire.h are not working together

Hello,

I am developing device for my home automation project, which would accept commands received from MQTT and would switch on/off 8 relays. I am using Arduino UNO, with Ethernet shield W5100 and i2c port extender PCF8574P, which is managing relays.

Test code without MQTT support, which is managing i2c using wire.h library, perfectly works.

Test code with MQTT support perfectly works as well. I am able to publish topics to MQTT server, subscribe topics and print received topics to serial, but it stops working after I send anything to i2c. I was trying 2 different MQTT libraries PubSubClient and arduino-mqtt (GitHub - 256dpi/arduino-mqtt: MQTT library for Arduino), but got the same result with both.

My code is below. The line of code which is causing problems is indicated with comment.

Any ideas what could be wrong?

Thank You in advance.

#define CLIENT_ID       "a2"
#include <SPI.h>
#include <Ethernet.h>
#include <MQTT.h>
#include <Wire.h> // I2C biblioteka

// Update these with values suitable for your network.
const byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };

EthernetClient ethClient;
MQTTClient client;

const byte i2c_io_address = 0x20;
byte i2c_io_output_Status = 0;
byte statusr = 0;


void messageReceived(String &topic, String &payload) {
    
  Serial.println("MQTT incoming message: " + topic + " - " + payload);

  
  if (topic == "a2/r0"){
    // whatever you want for this topic
    update_output(0, payload);
    client.publish("a2/rr0", statusr);
  }

  // #### IF LINE BELOW IS UNCOMMENTED, PROBLEM #####
  //expanderWrite(i2c_io_output_Status, i2c_io_address);

 
  Serial.println("Message processed");
  Serial.println();
}

void reconnect() {
  
  // Loop until we're reconnected
  while (!client.connected()) {
    
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(CLIENT_ID, "try", "try")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("a2/connected","CONNECTED");
      // ... and resubscribe
      client.subscribe("a2/r0");

      Serial.println("..subscribed");
    } else {
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup()
{
Serial.begin(115200);
 Serial.println(F("----------------------------------"));
 Serial.println(F("-------------START----------------")); 

  
  // setup ethernet communication using DHCP
  if(Ethernet.begin(mac) == 0) {
    Serial.println(F("Ethernet configuration using DHCP failed"));
  }
  Serial.println(F("Ethernet configured via DHCP"));

    Serial.print(F("IP address: "));
    Serial.println(Ethernet.localIP());
    Serial.println();
  // setup mqtt client
  
  client.begin("10.11.11.10", ethClient);
  client.onMessage(messageReceived);
  
  reconnect();

  // Allow the hardware to sort itself out
  delay(1500);
}

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



// Funkcija rasanti viena baita i i2c kanalu ispleteja
// Function which writes to i2c port extender PCF8574P/AP
void expanderWrite(byte _data, byte expanderAddress) {
    Wire.beginTransmission(expanderAddress);
    Wire.write(_data);
    Wire.endTransmission();
}

//Function which sets required bit of byte depending on payload received from MQTT
void update_output(byte i2c_output_pinNO, String payload) {
      byte task = 0;
      byte ok = 0;
      
      if (payload == "ON"){
        task = 1;
        ok = 1;
      }
      if (payload == "OFF"){
        task = 0;
        ok = 1; 
      }
      byte current_state = bitRead(i2c_io_output_Status, i2c_output_pinNO);
      if ((task == 0 || task == 2) && current_state == 1 && ok == 1) {
        bitWrite(i2c_io_output_Status, i2c_output_pinNO, 0);
        statusr = 0;
      }
      if ((task == 1 || task == 2) && current_state == 0 && ok == 1) {
        bitWrite(i2c_io_output_Status, i2c_output_pinNO, 1); 
        statusr = 1;       
      }
      Serial.print("Byte to be sent to i2c port extender: ");
      Serial.println(i2c_io_output_Status);
}

If code line causing problems is commented, everything works fine. Serial output is below.


-------------START----------------
Ethernet configured via DHCP
IP address: 10.11.11.183

Attempting MQTT connection...connected
..subscribed
MQTT incoming message: a2/r0 - OFF
Byte to be sent to i2c port extender: 0
Message processed

MQTT incoming message: a2/r0 - ON
Byte to be sent to i2c port extender: 1
Message processed

MQTT incoming message: a2/r0 - OFF
Byte to be sent to i2c port extender: 0
Message processed

If I uncomment line causing problems, eveything stops during execution of that line. Next line ("Message processed") is not executed.


-------------START----------------
Ethernet configured via DHCP
IP address: 10.11.11.183

Attempting MQTT connection...connected
..subscribed
MQTT incoming message: a2/r0 - OFF
Byte to be sent to i2c port extender: 0

Any ideas what could be wrong?

Thank You in advance.

Sincerely,

Ignas

The I2C code is quite small and not complex, so the main reason for such freezing is deactivated interrupts (because the I2C code depends on interrupts working). But I cannot find any deactivation of interrupts in your MQTT library but the library is rather resource consuming and not suited for the UNO because of it's use of the String class. As this fragments the memory quite fast It may be possible that you run into an out of memory situation.

You wrote you tried with the PubSubClient library too. That library is much better suited as it uses only character arrays for the string handling. Please post the code you used with that library.

Please find code using PubSubClient library. I have started from PubSubClient, but I have tried alternative before posting qeustion.

#define CLIENT_ID       "a2"
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <Wire.h> // I2C biblioteka

// Update these with values suitable for your network.
const byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(10, 11, 11, 207); //if configured static IP
IPAddress server(10, 11, 11, 10);

// Callback function header
void callback(char* topic, byte* payload, unsigned int length);
EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);


const byte i2c_io_address = 0x20;
byte i2c_io_output_Status = 0;
byte statusr = 0;

void callback(char* topic, byte* payload, unsigned int length) {
    
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i=0;i<length;i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  
  if (strcmp(topic,"a2/r0")==0){
    // whatever you want for this topic
    update_output(0, payload, length);
    client.publish("a2/rr0", statusr);
  }

  // #### IF LINE BELOW IS UNCOMMENTED, PROBLEM #####
  // expanderWrite(i2c_io_output_Status, i2c_io_address);

  
  Serial.println("Message processed");
  Serial.println();
}

void reconnect() {
  
  // Loop until we're reconnected
  while (!client.connected()) {
    
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(CLIENT_ID)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("a2/connected","CONNECTED");
      // ... and resubscribe
      client.subscribe("a2/r0");

      Serial.println("..subscribed");
    } else {
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup()
{
Serial.begin(115200);
 Serial.println(F("----------------------------------"));
 Serial.println(F("-------------START----------------")); 

  
  // setup ethernet communication using DHCP
  if(Ethernet.begin(mac) == 0) {
    Serial.println(F("Ethernet configuration using DHCP failed"));
  }
  Serial.println(F("Ethernet configured via DHCP"));
 

  // setup static IP
  // Ethernet.begin(mac, ip);
  
    Serial.print(F("IP address: "));
    Serial.println(Ethernet.localIP());
    Serial.println();
  // setup mqtt client
  reconnect();

  
  // Allow the hardware to sort itself out
  delay(1500);
}

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



// Funkcija rasanti viena baita i i2c kanalu ispleteja
// Function which writes to i2c port extender PCF8574P/AP
void expanderWrite(byte _data, byte expanderAddress) {
    Wire.beginTransmission(expanderAddress);
    Wire.write(_data);
    Wire.endTransmission();
}

//Function which sets required bit of byte depending on payload received from MQTT
void update_output(byte i2c_output_pinNO, byte* payload, unsigned int length) {
      byte task = 0;
      byte ok = 0;
      
      //konverstuojam i String
      payload[length] = '\0';
      String s = String((char*)payload);
      Serial.println(s);
      
      if (s == "ON"){
        task = 1;
        ok = 1;
      }
      if (s == "OFF"){
        task = 0;
        ok = 1; 
      }
      byte current_state = bitRead(i2c_io_output_Status, i2c_output_pinNO);
      if ((task == 0 || task == 2) && current_state == 1 && ok == 1) {
        bitWrite(i2c_io_output_Status, i2c_output_pinNO, 0);
        statusr = 0;
      }
      if ((task == 1 || task == 2) && current_state == 0 && ok == 1) {
        bitWrite(i2c_io_output_Status, i2c_output_pinNO, 1); 
        statusr = 1;       
      }
      Serial.print("Byte to be sent to i2c port extender: ");
      Serial.println(i2c_io_output_Status);
}

If code line causing problems is commented, everything works fine. Serial output is below.


-------------START----------------
Ethernet configured via DHCP
IP address: 10.11.11.183

Attempting MQTT connection...connected
..subscribed
Message arrived [a2/r0] ON
ON
Byte to be sent to i2c port extender: 1
Message processed

Message arrived [a2/r0] OFF
OFF
Byte to be sent to i2c port extender: 0
Message processed

Message arrived [a2/r0] ON
ON
Byte to be sent to i2c port extender: 1
Message processed

If I uncomment line causing problems, eveything stops during execution of that line. Next line ("Message processed") is not executed.


-------------START----------------
Ethernet configured via DHCP
IP address: 10.11.11.183

Attempting MQTT connection...connected
..subscribed
Message arrived [a2/r0] ON
ON
Byte to be sent to i2c port extender: 1

Post a wiring diagram of the setup you're testing with!

The PubSubClient library doesn't use interrupts so the code cannot be the problem. If it's not the software, it must be the hardware.

If you use complete boards, post links to the schematics of them.

Hello,

thank You for Your help. I have sorted out the problem.

There was Wire.begin(); missing in setup section.

Please find corrected working code if anybody is interested.

#define CLIENT_ID       "a2"
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <Wire.h> // I2C biblioteka

// Update these with values suitable for your network.
const byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(10, 11, 11, 207); //if configured static IP
IPAddress server(10, 11, 11, 10);

// Callback function header
void callback(char* topic, byte* payload, unsigned int length);
EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);


const byte i2c_io_address = 0x20;
byte i2c_io_output_Status = 0;
byte statusr = 0;

void callback(char* topic, byte* payload, unsigned int length) {
   
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i=0;i<length;i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

 
  if (strcmp(topic,"a2/r0")==0){
    // whatever you want for this topic
    update_output(0, payload, length);
    client.publish("a2/rr0", statusr);
  }

  // #### IF LINE BELOW IS UNCOMMENTED, PROBLEM #####
  // expanderWrite(i2c_io_output_Status, i2c_io_address);

 
  Serial.println("Message processed");
  Serial.println();
}

void reconnect() {
 
  // Loop until we're reconnected
  while (!client.connected()) {
   
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(CLIENT_ID)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("a2/connected","CONNECTED");
      // ... and resubscribe
      client.subscribe("a2/r0");

      Serial.println("..subscribed");
    } else {
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup()
{
Serial.begin(115200);
 Serial.println(F("----------------------------------"));
 Serial.println(F("-------------START----------------"));

 
  // setup ethernet communication using DHCP
  if(Ethernet.begin(mac) == 0) {
    Serial.println(F("Ethernet configuration using DHCP failed"));
  }
  Serial.println(F("Ethernet configured via DHCP"));
 

  // setup static IP
  // Ethernet.begin(mac, ip);
 
    Serial.print(F("IP address: "));
    Serial.println(Ethernet.localIP());
    Serial.println();

    Wire.begin();
    delay(30);
    
  // setup mqtt client
  reconnect();

 
  // Allow the hardware to sort itself out
  delay(500);
  
}

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



// Funkcija rasanti viena baita i i2c kanalu ispleteja
// Function which writes to i2c port extender PCF8574P/AP
void expanderWrite(byte _data, byte expanderAddress) {
    Wire.beginTransmission(expanderAddress);
    Wire.write(_data);
    Wire.endTransmission();
}

//Function which sets required bit of byte depending on payload received from MQTT
void update_output(byte i2c_output_pinNO, byte* payload, unsigned int length) {
      byte task = 0;
      byte ok = 0;
     
      //konverstuojam i String
      payload[length] = '\0';
      String s = String((char*)payload);
      Serial.println(s);
     
      if (s == "ON"){
        task = 1;
        ok = 1;
      }
      if (s == "OFF"){
        task = 0;
        ok = 1;
      }
      byte current_state = bitRead(i2c_io_output_Status, i2c_output_pinNO);
      if ((task == 0 || task == 2) && current_state == 1 && ok == 1) {
        bitWrite(i2c_io_output_Status, i2c_output_pinNO, 0);
        statusr = 0;
      }
      if ((task == 1 || task == 2) && current_state == 0 && ok == 1) {
        bitWrite(i2c_io_output_Status, i2c_output_pinNO, 1);
        statusr = 1;       
      }
      Serial.print("Byte to be sent to i2c port extender: ");
      Serial.println(i2c_io_output_Status);
}

Sincerely,

Ignas