Нужна помощь с циклами. MQTT+реле+кнопки

Господа форумчане! Всех с Наступающим!
Может образуется у кого минутка глянуть код. Не пойму в чём причина. Собран код из двух отдельных. По отдельности работает каждый. Если месте, только та часть которая отсылает статус нажатой кнопки в MQTT, а включение реле из клиента не происходит. Статус устройства тоже передаётся без проблем. В порт постоянно летит: Failed to recognize incoming topic! - т.е. нет подписки на исходящие топики Publish. Подозреваю, что где-то заковырка с циклами.

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

const int button1 = 16; // указываем пин D0 GPIO16 для первой кнопки
const int button2 = 5; // указываем пин D1 GPIO5 для второй кнопки
const int button3 = 4; // указываем пин D2 GPIO4 для третьей кнопки

const int gpioRelay3 = 14; // указываем пин D5 GPIO14 для реле 1
const int gpioRelay1 = 12;  // указываем пин D6 GPIO12 для реле 2
const int gpioRelay2 = 13;  // указываем пин D7 GPIO13 для реле 3

const int relayOn = 0x1; // Уровни управления реле
const int relayOff = 0x0; // Уровни управления реле

//const char* ssid = "***"; // Имя точки доступа Wi-Fi
//const char* password = "***"; // Пароль от точки доступа

const char* ssid = "***"; // Имя точки доступа Wi-Fi
const char* password = "***"; // Пароль от точки доступа

const char* mqtt_server = "***";  // Имя сервера MQTT
const int mqtt_port = ***;             // Порт для подключения к серверу MQTT
const char* mqtt_clientId = "***";  // определяем ID
const char* mqtt_user = "***";      // Логин от сервера
const char* mqtt_pass = "***";      // Пароль от сервера

const char* mqttTopicControlRelay1 = "relay1/control"; // Топик для внешнего управления реле 1
const char* mqttTopicControlRelay2 = "relay2/control"; // Топик для внешнего управления реле 2
const char* mqttTopicControlRelay3 = "relay3/control"; // Топик для внешнего управления реле 3
const int   mqttRelayControlQos = 1;

const char* mqttTopicStatusRelay1 = "relay1/status"; // Топики для публикации статуса реле 1
const char* mqttTopicStatusRelay2 = "relay2/status"; // Топики для публикации статуса реле 2
const char* mqttTopicStatusRelay3 = "relay3/status"; // Топики для публикации статуса реле 3

const char* mqttRelayStatusOn = "on";  // Текстовое отображение для состояния реле
const char* mqttRelayStatusOff = "off"; // Текстовое отображение для состояния реле
const bool  mqttRelayStatusRetained = false; // Текстовое отображение для состояния реле

const char* mqttTopicDeviceStatus = "device/status";
const char* mqttDeviceStatusOn = "online";    
const char* mqttDeviceStatusOff = "offline";
const int   mqttDeviceStatusQos = 1;
const bool  mqttDeviceStatusRetained = true;

byte gpioStatus1 = relayOff; // Текущее состояние реле 1
byte gpioStatus2 = relayOff; // Текущее состояние реле 2
byte gpioStatus3 = relayOff; // Текущее состояние реле 3

byte relaySetStatus1 = relayOff; // Полученное ("новое") состояние реле 1
byte relaySetStatus2 = relayOff; // Полученное ("новое") состояние реле 2
byte relaySetStatus3 = relayOff; // Полученное ("новое") состояние реле 3

#define BUFFER_SIZE 100

void callback(char* topic, byte* payload, unsigned int length); // Функция обработки входящих сообщений
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0; // Время публикации предыдущего сообщения  (мс) 

#define MSG_BUFFER_SIZE	(50)

char msg[MSG_BUFFER_SIZE];
int value = 0; // Переменная для формирования публикуемого сообщения

void setup_wifi() {

  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());
  
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void reconnect() {
  if (!client.connected()) {  
    Serial.print("MQTT connection...");
    client.setServer(mqtt_server, mqtt_port); // Подключение к MQTT клиенту
    client.setCallback(mqttOnIncomingMsg); // подписка на входящие топики   

      // Пробуем подключиться с LWT сообщением "offline"
    if (client.connect(mqtt_clientId, mqtt_user, mqtt_pass, mqttTopicDeviceStatus, mqttDeviceStatusQos, mqttDeviceStatusRetained, mqttDeviceStatusOff)) { //
      Serial.println("ok");
      
      client.publish(mqttTopicDeviceStatus, mqttDeviceStatusOn, mqttDeviceStatusRetained); // Публикуем статус устройства
                 
      client.subscribe(mqttTopicControlRelay1, mqttRelayControlQos); // Подписываемся на топик управления реле 1
      client.subscribe(mqttTopicControlRelay2, mqttRelayControlQos); // Подписываемся на топик управления реле 2
      client.subscribe(mqttTopicControlRelay3, mqttRelayControlQos); // Подписываемся на топик управления реле 3
     
      client.publish(mqttTopicStatusRelay1, (gpioStatus1 == relayOn ? mqttRelayStatusOn : mqttRelayStatusOff), mqttRelayStatusRetained); // Публикуем текущее состояние реле 1
      client.publish(mqttTopicStatusRelay2, (gpioStatus2 == relayOn ? mqttRelayStatusOn : mqttRelayStatusOff), mqttRelayStatusRetained); // Публикуем текущее состояние реле 2
      client.publish(mqttTopicStatusRelay3, (gpioStatus3 == relayOn ? mqttRelayStatusOn : mqttRelayStatusOff), mqttRelayStatusRetained); // Публикуем текущее состояние реле 3
      
      client.subscribe("BTN1");  // подписывааемся на топик с данными для 1-ой кнопки button1
      client.subscribe("BTN2");  // подписывааемся на топик с данными для 2-ой кнопки button2
      client.subscribe("BTN3");  // подписывааемся на топик с данными для 3-ой кнопки button3
      
      Serial.println("connected");
    } else {
       Serial.print("failed, rc=");
       Serial.print(client.state());
       Serial.println(" try again in 5 seconds");
       delay(5000);
      }
    if (client.connected()){
      client.loop();
    }
  }
}

void setup() {
  pinMode(LED_BUILTIN, OUTPUT); // Инициализация светодиода
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
 
  pinMode(gpioRelay1, OUTPUT); // Настройка выводов реле 1
  pinMode(gpioRelay2, OUTPUT); // Настройка выводов реле 2
  pinMode(gpioRelay3, OUTPUT); // Настройка выводов реле 3
  
  digitalWrite(gpioRelay1, relayOff); // Сброс реле 1 в исходное состояние "отключено"
  digitalWrite(gpioRelay2, relayOff); // Сброс реле 2 в исходное состояние "отключено"
  digitalWrite(gpioRelay3, relayOff); // Сброс реле 3 в исходное состояние "отключено"
}

void mqttOnIncomingMsg(char* topic, byte* payload, unsigned int length) {
  // Для более корректного сравнения строк приводим их к нижнему регистру и обрезаем пробелы с краев
  String _topic = topic;
  _topic.toLowerCase();
  _topic.trim();
  String _payload;
  for (unsigned int i=0; i<length; i++) {
    _payload += String((char)payload[i]);
  }
  _payload.toLowerCase();
  _payload.trim();
  
  if (_topic.equals(mqttTopicControlRelay1)) { // Сравниваем с топиками
    if (_payload.equals(mqttRelayStatusOn)) relaySetStatus1 = relayOn;   // это топик управления реле 1
    if (_payload.equals(mqttRelayStatusOff)) relaySetStatus1 = relayOff; // это топик управления реле 1
  } else if (_topic.equals(mqttTopicControlRelay2)) {
    if (_payload.equals(mqttRelayStatusOn)) relaySetStatus2 = relayOn;   // это топик управления реле 2
    if (_payload.equals(mqttRelayStatusOff)) relaySetStatus2 = relayOff; // это топик управления реле 2
  } else if (_topic.equals(mqttTopicControlRelay3)) {
    if (_payload.equals(mqttRelayStatusOn)) relaySetStatus3 = relayOn;   // это топик управления реле 3
    if (_payload.equals(mqttRelayStatusOff)) relaySetStatus3 = relayOff; // это топик управления реле 3
  } else {
    Serial.println("Failed to recognize incoming topic!");
  }
}

void mqttChangeRelaysState() { // Переключение состояния реле

  if (relaySetStatus1 != gpioStatus1) { // Новое состояние реле 1 отличается от текущего, требуется переключение
    gpioStatus1 = relaySetStatus1;
    digitalWrite(gpioRelay1, gpioStatus1);
    client.publish(mqttTopicStatusRelay1, (gpioStatus1 == relayOn ? mqttRelayStatusOn : mqttRelayStatusOff), mqttRelayStatusRetained);
    Serial.print("Relay 1 has changed its state: ");
    Serial.println(gpioStatus1 == relayOn ? mqttRelayStatusOn : mqttRelayStatusOff);
  }
  
  if (relaySetStatus2 != gpioStatus2) { // Новое состояние реле 2 отличается от текущего, требуется переключение
    gpioStatus2 = relaySetStatus2;
    digitalWrite(gpioRelay2, gpioStatus2);
    client.publish(mqttTopicStatusRelay2, (gpioStatus2 == relayOn ? mqttRelayStatusOn : mqttRelayStatusOff), mqttRelayStatusRetained);
    Serial.print("Relay 2 has changed its state: ");
    Serial.println(gpioStatus2 == relayOn ? mqttRelayStatusOn : mqttRelayStatusOff);
  }
  
  if (relaySetStatus3 != gpioStatus3) { // Новое состояние реле 3 отличается от текущего, требуется переключение
    gpioStatus3 = relaySetStatus3;
    digitalWrite(gpioRelay3, gpioStatus3);
    client.publish(mqttTopicStatusRelay3, (gpioStatus3 == relayOn ? mqttRelayStatusOn : mqttRelayStatusOff), mqttRelayStatusRetained);
    Serial.print("Relay 3 has changed its state: ");
    Serial.println(gpioStatus3 == relayOn ? mqttRelayStatusOn : mqttRelayStatusOff);
  }
}

void loop() {
  if (digitalRead(button1) == LOW) {
    client.publish("BTN1", "0");
  } else 
  if (digitalRead(button1) == HIGH) {
    client.publish("BTN1", "1"); 
  }  
  if (digitalRead(button2) == LOW) {
    client.publish("BTN2", "0");
  } else 
  if (digitalRead(button2) == HIGH) {
    client.publish("BTN2", "1"); 
  } 
  if (digitalRead(button3) == LOW) {
    client.publish("BTN3", "0");
  } else 
  if (digitalRead(button3) == HIGH) {
    client.publish("BTN3", "1"); 
  } 
  delay(100);

  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  mqttChangeRelaysState(); // Управление реле
}

Посоветуйте чего-нибудь дельного, пожалуйста.

Иди Новый год отмечать)))

2 лайка

Взаимно )))

1 лайк

Я, немного в новом годе одним пальцем, но вот именно с реле ничего в коде и не увидел (в том чтобы отсыпалось, принималось и так далее). Может в этом проблема?))

скину пример, за 5000)))
и ручное управление, и через сайт, с отображением статуса кнопок!
а на словах… брал и создавал еще локальный брокер… один брокер для кнопок второй для интернет управления… в общем 5к, и будет код))) с наступающим)))

1 лайк

Совсем школяры охамели :rage: Для платных предложений есть коммерческий раздел, нефиг здесь пакостить

1 лайк

v258аааааргументируйте! первое пропустим, а вот насчет второго не понятно… я думаю человек провозится 3рое суток, и ему лучше заплатить… реализацию путем добавления еще и локального брокера подсказал…

Коммерческие предложения - в коммерческом разделе. В крайнем случае в личке. Что непонятного?

2 лайка

v258 и многих это раздражает ?))) кроме вас… и в чем пакость то ? все таки не понятно…

В чем твоя проблема, мальчик? На каникулах заняться нечем?

1 лайк

Почти весь код, это честно стырено у kotyara12. И отдельно он работает. По кнопкам для отправки это всего получается с 4 по 5, с 108 по 110 строку ну и в LOOP. остальное должно работать на реле с обратной связью. Так вот именно подписка на публикацию в void reconnect(). как мне кажется, почему-то тормозится. Я инженер, но не программист. Тут мне трудно разобраться. Потому прошу помощи.

v258

как дяденька вы себя передо мной не зарекомендовали, и как то не красиво соскакивать с темы, озадачивая бессмысленными вопросами, когда проблема на вашей стороне, плюньте на все, и идите тоже встречать новый год, удачи)))

“Не мешайте школяру бабло рубить”? Может мне еще чего сделать?

Для начала, переписать обработчик кнопок.

сколько раз у вас публикуются эти сообщения? Я бы в дебаге ничего не увидел, кроме спама. Возьмите какую нибудь библиотеку обработки кнопок, и сделайте публикацию только по изменению состояния кнопки.
Как всё получиться, возвращайтесь, и дальше callback`и настроим.

Сообщения публикуются постоянно, пока кнопка не будет отжата. Это своеобразный датчик. Попробую переработать. Но, как мне кажется, тут задача отрабатывается на все 100

Да на все 100 мс! У тебя бедного брокера долбят непрерывно. А оно можно так? Не пошлёт брокер?

Может его уже за флуд на всех бесплатных брокерах забанили? :wink: А на платных - это их коммерческое дело.

отсылать информацию надо тогда и только тогда когда она изменилась, ИМХО, с MQTT дел не имел

Может быть и забанили :joy: Вот на днях уже давал ссылку Публичные облачные сервера для IoT устройств – kotyara12.ru судя по описанию брокеров большинство так или иначе ограничивает.

Не видно ничего этого «остального».