MQTT really slow to subscribe

The EtherTen combines an Uno-equivalent Arduino-compatible board and Wiznet-based Ethernet support, along with a microSD card slot and Power-over-Ethernet support. [Product page]
Post Reply
keiranwyllie
Posts: 40
Joined: Tue Aug 16, 2016 9:17 am

MQTT really slow to subscribe

Post by keiranwyllie » Sat Oct 22, 2016 12:54 am

Hi,

I'm using an EtherTen with relay driver shields attached. My sketch sets it up to subscribe to several MQTT topics that are published from another EtherTen with a security sensor shield attached.

The published topics from the security sensor are sent immediately to the MQTT broker (which is great), however it takes up to 10 seconds from the other EtherTen shield to subscribe and retrieve the new values.

Any ideas why this would happen?

My intent in the future is to run the security sensor shield of a UNO once my wifi shield arrives.

Code: Select all

// This subscribes to MQTT IOT get the PIR sensor states //

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <Wire.h>

#define SHIELD_1_I2C_ADDRESS  0x20  // 0x20 is the address with all jumpers removed
#define SHIELD_2_I2C_ADDRESS  0x21  // 0x21 is the address with a jumper on position A0
#define MAC_I2C_ADDRESS       0x50  // Microchip 24AA125E48 I2C ROM address

// Update these with values suitable for your network.
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 2, 110);
IPAddress server(192, 168, 2, 149);

byte shield1BankA = 0; // Current status of all outputs on first shield, one bit per output
byte shield2BankA = 0; // Current status of all outputs on second shield, one bit per output

EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);

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

  // Switch on the Driveway Lights
  if (strcmp(topic, "sensor1") == 0) {
    if ((char)payload[0] == '1')
    {
      setLatchChannelOn(2);
      delay(100);
      Serial.println("Driveway Lights On");
      client.publish("sensor1", "1");
    }
    else if ((char)payload[0] == '0') //Controlled from Home Assistant
    {
      setLatchChannelOff(2);
      client.publish("sensor1", "0");
    }
  }

  // Switch on the Workshop Light
  if (strcmp(topic, "sensor2") == 0) {
    if ((char)payload[0] == '1')
    {
      setLatchChannelOn(2);
      delay(100);
      Serial.println("Workshop Light On");
      client.publish("sensor2", "1");
    }
    else if ((char)payload[0] == '0') //Controlled from Home Assistant
    {
      setLatchChannelOff(2);
      client.publish("sensor2", "0");
    }
  }
  /*
    // Switch on the #############
    if (strcmp(topic, "sensor2") == 0) {
      if ((char)payload[0] == '1')
      {
        setLatchChannelOn(2);
        delay(100);
        Serial.println("Workshop Light On");
        client.publish("sensor2", "1");
      }
      else if ((char)payload[0] == '0') //Controlled from Home Assistant
      {
        setLatchChannelOff(2);
        client.publish("sensor2", "0");
      }
    }

    // Switch on the ####################
    if (strcmp(topic, "sensor2") == 0) {
      if ((char)payload[0] == '1')
      {
        setLatchChannelOn(2);
        delay(100);
        Serial.println("Workshop Light On");
        client.publish("sensor2", "1");
      }
      else if ((char)payload[0] == '0') //Controlled from Home Assistant
      {
        setLatchChannelOff(2);
        client.publish("sensor2", "0");
      }
    } */
}

void setup()
{
  Wire.begin(); // Wake up I2C bus
  Serial.begin(38400);
  Ethernet.begin(mac, ip);
  // Note - the default maximum packet size is 128 bytes. If the
  // combined length of clientId, username and password exceed this,
  // you will need to increase the value of MQTT_MAX_PACKET_SIZE in
  // PubSubClient.h

  if (client.connect("leftArduinoClient")) {
    client.subscribe("sensor1");
    client.subscribe("sensor2");
    client.subscribe("sensor3");
    client.subscribe("sensor4");
  }

  /* Set up the Relay8 shields */
  initialiseShield(SHIELD_1_I2C_ADDRESS);
  sendRawValueToLatch1(0);  // If we don't do this, channel 6 turns on! I don't know why

  initialiseShield(SHIELD_2_I2C_ADDRESS);
  sendRawValueToLatch2(0);  // If we don't do this, channel 6 turns on! I don't know why

  pinMode(2, INPUT);
  digitalWrite(2, LOW);
  pinMode(3, INPUT);
  digitalWrite(3, LOW);
  pinMode(4, INPUT);
  digitalWrite(4, LOW);
  pinMode(5, INPUT);
  digitalWrite(5, LOW);
  pinMode(6, INPUT);
  digitalWrite(6, LOW);
}

void loop()
{
  if (digitalRead(2) == HIGH) //Digital pin for Hall Light
  {
    toggleLatchChannel(1);
    delay(1000);
  }

  if (digitalRead(3) == HIGH) //Digital pin for Fountain
  {
    toggleLatchChannel(6);
    delay(1000);
  }

  if (digitalRead(4) == HIGH) //Digital pin for Entrance Lights
  {
    toggleLatchChannel(7);
    delay(1000);
  }

  if (digitalRead(5) == HIGH) //Digital pin for Foyer Lights
  {
    toggleLatchChannel(8);
    delay(1000);
  }

  if (digitalRead(6) == HIGH) //Digital pin for Driveway Lights - to be removed
  {
    toggleLatchChannel(9);
    delay(1000);
  }

  client.loop();
}

void initialiseShield(int shieldAddress)
{
  // Set addressing style
  Wire.beginTransmission(shieldAddress);
  Wire.write(0x12);
  Wire.write(0x20); // use table 1.4 addressing
  Wire.endTransmission();

  // Set I/O bank A to outputs
  Wire.beginTransmission(shieldAddress);
  Wire.write(0x00); // IODIRA register
  Wire.write(0x00); // Set all of bank A to outputs
  Wire.endTransmission();
}

void toggleLatchChannel(byte channelId)
{
  if ( channelId >= 1 && channelId <= 8 )
  {
    byte shieldOutput = channelId;
    byte channelMask = 1 << (shieldOutput - 1);
    shield1BankA = shield1BankA ^ channelMask;
    sendRawValueToLatch1(shield1BankA);
  }
  else if ( channelId >= 9 && channelId <= 16 )
  {
    byte shieldOutput = channelId - 8;
    byte channelMask = 1 << (shieldOutput - 1);
    shield2BankA = shield2BankA ^ channelMask;
    sendRawValueToLatch2(shield2BankA);
  }
}

void setLatchChannelOn (byte channelId)
{
  if ( channelId >= 1 && channelId <= 8 )
  {
    byte shieldOutput = channelId;
    byte channelMask = 1 << (shieldOutput - 1);
    shield1BankA = shield1BankA | channelMask;
    sendRawValueToLatch1(shield1BankA);
  }
  else if ( channelId >= 9 && channelId <= 16 )
  {
    byte shieldOutput = channelId - 8;
    byte channelMask = 1 << (shieldOutput - 1);
    shield2BankA = shield2BankA | channelMask;
    sendRawValueToLatch2(shield2BankA);
  }
}

void setLatchChannelOff (byte channelId)
{
  if ( channelId >= 1 && channelId <= 8 )
  {
    byte shieldOutput = channelId;
    byte channelMask = 255 - ( 1 << (shieldOutput - 1));
    shield1BankA = shield1BankA & channelMask;
    sendRawValueToLatch1(shield1BankA);
  }
  else if ( channelId >= 9 && channelId <= 16 )
  {
    byte shieldOutput = channelId - 8;
    byte channelMask = 255 - ( 1 << (shieldOutput - 1));
    shield2BankA = shield2BankA & channelMask;
    sendRawValueToLatch2(shield2BankA);
  }
}

void sendRawValueToLatch1(byte rawValue)
{
  Wire.beginTransmission(SHIELD_1_I2C_ADDRESS);
  Wire.write(0x12);        // Select GPIOA
  Wire.write(rawValue);    // Send value to bank A
  shield1BankA = rawValue;
  Wire.endTransmission();
}

void sendRawValueToLatch2(byte rawValue)
{
  Wire.beginTransmission(SHIELD_2_I2C_ADDRESS);
  Wire.write(0x12);        // Select GPIOA
  Wire.write(rawValue);    // Send value to bank A
  shield2BankA = rawValue;
  Wire.endTransmission();
}

/** Required to read the MAC address ROM */
byte readRegister(byte r)
{
  unsigned char v;
  Wire.beginTransmission(MAC_I2C_ADDRESS);
  Wire.write(r);  // Register to read
  Wire.endTransmission();

  Wire.requestFrom(MAC_I2C_ADDRESS, 1); // Read a byte
  while (!Wire.available())
  {
    // Wait
  }
  v = Wire.read();
  return v;
}

keiranwyllie
Posts: 40
Joined: Tue Aug 16, 2016 9:17 am

Re: MQTT really slow to subscribe

Post by keiranwyllie » Sat Oct 29, 2016 5:07 am

Looks like I've narrowed it down a little. It seems that if I disconnect the EtherTen running the security sensor shield, then any switching done through Home Assistant (via MQTT broker) occurs straight away. Once I connect the EtherTen back up to my network, I get delays again.

Post Reply