我得到了一些迫切需要的帮助。
我的设置包括两个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;
}
答案 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的信号 - 没有机械部件可以振荡产生“假”脉冲。尝试编写一个简短的测试程序,只需一次激活一个序列中的所有继电器,而无需读取任何外部输入。这样你就会知道,如果问题来自代码中的错误,或者是硬件问题。