MQTT订阅和去抖问题的速度很慢

时间:2016-10-24 02:30:22

标签: arduino mqtt mosquitto

我得到了一些迫切需要的帮助。

我的设置包括两个arduinos(EtherTens)和一个Raspberry Pi(运行Mosquitto MQTT代理和Home Assistant)。在一个Arduino上我有一个安全传感器屏蔽,附有两个PIR,并向经纪人发布状态(这100%应该如何工作)。

在我的另一个arduino上,我有两个继电器8驱动器屏蔽(它们使用I2C)连接到两个8通道继电器板(总共连接了16个继电器)。

我已经切换了连接的开关,以便在家中切换几个灯以进行硬件激活,并且我已将其设置为通过带有MQTT主题的Home Assistant激活。

我遇到的问题是在房子内打开其他灯时随机继电器激活。我认为某处存在线路干扰,我希望软件去抖可以解决问题,但我在代码中丢失了(我的拨动开关设置已经有10k下拉电阻)。 另一个问题是运行继电器防护罩的Arduino实际上(我的意思是真的)订阅经纪人的速度很慢......我有时会在任何地方说话长达10秒。

是否有人能够建议最好的方法来修复我的代码?

// 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

const int buttonPin2 = 2;
const int buttonPin3 = 3;
const int buttonPin4 = 4;
const int buttonPin5 = 5;
const int buttonPin6 = 6;

int buttonState2;
int buttonState3;
int buttonState4;
int buttonState5;
int buttonState6;

int lastButtonState2 = LOW;
int lastButtonState3 = LOW;
int lastButtonState4 = LOW;
int lastButtonState5 = LOW;
int lastButtonState6 = LOW;

unsigned long lastDebounceTime2 = 0;
unsigned long lastDebounceTime3 = 0;
unsigned long lastDebounceTime4 = 0;
unsigned long lastDebounceTime5 = 0;
unsigned long lastDebounceTime6 = 0;

unsigned long debounceDelay2 = 50;
unsigned long debounceDelay3 = 50;
unsigned long debounceDelay4 = 50;
unsigned long debounceDelay5 = 50;
unsigned long debounceDelay6 = 50;

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 Hallway Light
  if (strcmp(topic, "left/hallwaylight") == 0) {
    if ((char)payload[0] == '1')
  {
      setLatchChannelOn(1);
      client.publish("left/hallwaylight/state", "1");
      delay(500);
    }
     else if ((char)payload[0] == '0') //Controlled from Home Assistant
    {
      setLatchChannelOff(1);
      delay(500);
      client.publish("left/hallwaylight/state", "0");
    }
}

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

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

// Switch on the Entrance Lights
if (strcmp(topic, "left/entrancelights") == 0) {
  if ((char)payload[0] == '1')
  {
    setLatchChannelOn(7);
    client.publish("left/entrancelights/state", "1");
    delay(500);
  }
  else if ((char)payload[0] == '0') //Controlled from Home Assistant
  {
    setLatchChannelOff(7);
    delay(500);
    client.publish("left/entrancelights/state", "0");
  }
}

// Switch on the Foyer Lights
if (strcmp(topic, "left/foyerlights") == 0) {
  if ((char)payload[0] == '1')
  {
    setLatchChannelOn(6);
    client.publish("left/foyerlights/state", "1");
    delay(500);
  }
  else if ((char)payload[0] == '0') //Controlled from Home Assistant
  {
    setLatchChannelOff(6);
    delay(500);
    client.publish("left/foyerlights/state", "0");
  }
}

// Switch on the Driveway Lights - Sensor 1
if (strcmp(topic, "left/drivewaylights") == 0) {
  if ((char)payload[0] == '1')
  {
    setLatchChannelOn(9);
    client.publish("left/drivewaylights/state", "1");
    delay(500);
  }
  else if ((char)payload[0] == '0') //Controlled from Home Assistant
  {
    setLatchChannelOff(9);
    delay(500);
    client.publish("left/drivewaylights/state", "0");
  }
}

// Switch on the Spa Light
if (strcmp(topic, "left/spalight") == 0) {
  if ((char)payload[0] == '1')
  {
    setLatchChannelOn(10);
    client.publish("left/spalight/state", "1");
    delay(500);
  }
  else if ((char)payload[0] == '0') //Controlled from Home Assistant
  {
    setLatchChannelOff(10);
    delay(500);
    client.publish("left/spalight/state", "0");
  }
}

// Switch on the Pool Light
if (strcmp(topic, "left/poollight") == 0) {
  if ((char)payload[0] == '1')
  {
    setLatchChannelOn(11);
    client.publish("left/poollight/state", "1");
    delay(500);
  }
  else if ((char)payload[0] == '0') //Controlled from Home Assistant
  {
    setLatchChannelOff(11);
    delay(500);
    client.publish("left/poollight/state", "0");
  }
}

// Switch on the Tree Light
if (strcmp(topic, "left/treelight") == 0) {
  if ((char)payload[0] == '1')
  {
    setLatchChannelOn(12);
    client.publish("left/treelight/state", "1");
    delay(500);
  }
  else if ((char)payload[0] == '0') //Controlled from Home Assistant
  {
    setLatchChannelOff(12);
    delay(500);
    client.publish("left/treelight/state", "0");
  }
}

// Switch on the Fountains
if (strcmp(topic, "left/fountains") == 0) {
  if ((char)payload[0] == '1')
  {
    setLatchChannelOn(13);
    client.publish("left/fountains/state", "1");
    delay(500);
  }
  else if ((char)payload[0] == '0') //Controlled from Home Assistant
  {
    setLatchChannelOff(13);
    delay(500);
    client.publish("left/fountains/state", "0");
  }
}

// Switch on the Spa
if (strcmp(topic, "left/spa") == 0) {
  if ((char)payload[0] == '1')
  {
    setLatchChannelOn(16);
    client.publish("left/spa/state", "1");
    delay(500);
  }
  else if ((char)payload[0] == '0') //Controlled from Home Assistant
  {
    setLatchChannelOff(16);
    delay(500);
    client.publish("left/spa/state", "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

  /* 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(buttonPin2, INPUT);
pinMode(buttonPin3, INPUT);
pinMode(buttonPin4, INPUT);
pinMode(buttonPin5, INPUT);
pinMode(buttonPin6, INPUT);

}

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

int reading2 = digitalRead(buttonPin2);
int reading3 = digitalRead(buttonPin3);
int reading4 = digitalRead(buttonPin4);
int reading5 = digitalRead(buttonPin5);
int reading6 = digitalRead(buttonPin6);

if (reading2 != lastButtonState2) {
  lastDebounceTime2 = millis();
  }
if ((millis() - lastDebounceTime2) > debounceDelay2) {
  if (reading2 != buttonState2) {
    buttonState2 = reading2;

  if ((buttonPin2 == HIGH) && What to put here????) {
    toggleLatchChannel(1);
    client.publish("left/hallwaylight/state", "1");
  }
  /*if (digitalRead(2) == HIGH) //Digital pin for Hall Light
  {
    toggleLatchChannel(1);
    delay(1000);
  }*/
 }
}

lastButtonState2 = reading2;

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 reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
  Serial.print("Attempting MQTT connection...");
  // Attempt to connect
  if (client.connect("leftArduinoClient")) {
    Serial.println("connected");
    client.subscribe("left/#");
  } else {
    Serial.print("failed, rc=");
    Serial.print(client.state());
    Serial.println(" try again in 5 seconds");
    // Wait 5 seconds before retrying
    delay(5000);
   }
 }
}

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;
}

1 个答案:

答案 0 :(得分:0)

由于此功能的延迟,订阅代理可能需要很长时间:

void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
  Serial.print("Attempting MQTT connection...");
  // Attempt to connect
  if (client.connect("leftArduinoClient")) {
    Serial.println("connected");
    client.subscribe("left/#");
  } else {
    Serial.print("failed, rc=");
    Serial.print(client.state());
    Serial.println(" try again in 5 seconds");
    // Wait 5 seconds before retrying
    delay(5000);
   }
 }
}

如果第一次尝试连接失败,程序将等待5秒钟。如果是这种情况,您是否使用串行监视器进行了检查?你应该看到两个“失败的......”消息。

对于继电器:去抖仅适用于硬件开关 - 当您按下按钮时,电子触点会在短时间内来回反复连接和断开几次。将开关连接到微控制器时,它将读取连接到按钮的数字引脚的几个转换。去抖是一种忽略这些短脉冲的方法。

话虽如此,没有必要去除来自另一个微控制器或PC的信号 - 没有机械部件可以振荡产生“假”脉冲。尝试编写一个简短的测试程序,只需一次激活一个序列中的所有继电器,而无需读取任何外部输入。这样你就会知道,如果问题来自代码中的错误,或者是硬件问题。