MQTT Не отрабатывается подписка на один из топиков
- Войдите на сайт для отправки комментариев
Сб, 14/03/2020 - 13:41
Пишу скетч для датчиков и управления нагрузками. Столкнулся с проблемой. Все подписки на топики отрабатываются, кроме одной. Причем аналогичная подписка на похожий топик работает прекрасно.
Строка 088, с подпиской на топик /Dimmer02/ работает(Строки 296-303). Данные прилетают и отрабатываются. Строка 089 с подпиской на топик /Dimmer05/ не работает(Строки 306-313). При этом, если в строке 088 подписаться на топик /Dimmer05/, то все прекрасно отрабатывается. Прошу прощения, за большущую портянку листинга, возможно где то есть некий не очевидный для меня косяк, влияющий на эту проблему. Что я делаю не так?
// Контроллер для управления нагрузками в комнате и подвале // на основе контроллера mqtt_ethernet_Pervushino-03 /**************************************************** Управление 1. Вытяжка на форточке в комнате. ШИМ (Pin 3) 2. Люстра 1 в комнате. Вкл/Выкл (Включатель-кнопка без фиксации)(Pin 2) 3. Люстра 2 в комнате. Вкл/Выкл (Включатель-кнопка без фиксации)(Pin 6) 4. Вытяжка подвал ШИМ (Pin 5) 5. Форточка в комнате. Открыть/закрыть (Датчики Открыто и Закрыто) (Pin 7) 6. Штора на окне в комнате. Окткрыть/закрыть (Датчики Открыто и Закрыто) (Pin 8) Датчики 1. Датчик движения в комнате (Pin A0) 2. Датчик концентрации Газ/Дым в комнате (Pin A1) 3. Включатель освещения в комнате (Pin A2) Первое нажатие - включение Люстры №1 Второе нажатие - включение Люстры №2 Третье нажатие - Выключение Люстры №1 Четвртое нажатие - Выключение Люстры №2 4. Датчик двери на веранду (Геркон) (Pin A3) 5. Датчик концентрации Газ/Дым в подвале 6. Датчик положения форточки (Закрыто) 7. Датчик положения форточки (Окрыто) 8. Датчик положения шторы (Закрыто) 9. Датчик положения шторы (Открыто) ****************************************************/ //#include <SPI.h> #include <Wire.h> #include "Adafruit_MQTT.h" #include "Adafruit_MQTT_Client.h" #include <Ethernet.h> #include <EthernetClient.h> //#include <Dns.h> #include <Dhcp.h> /************************* Ethernet Client Setup *****************************/ byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x1E};// //byte mac[] = {0x04, 0xA0, 0x98, 0x3C, 0x37, 0xFE}; //Uncomment the following, and set to a valid ip if you don't have dhcp available. //IPAddress iotIP (192, 168, 0, 42); //Uncomment the following, and set to your preference if you don't have automatic dns. //IPAddress dnsIP (8, 8, 8, 8); //If you uncommented either of the above lines, make sure to change "Ethernet.begin(mac)" to "Ethernet.begin(mac, iotIP)" or "Ethernet.begin(mac, iotIP, dnsIP)" /************************* Описание параметров брокера *********************************/ #define AIO_SERVER "192.168.1.1" //Адресс брокера #define AIO_SERVERPORT 1883 //Порт брокера #define AIO_USERNAME "user" //Пользователь брокера #define AIO_KEY "111" //Пароль пользователя брокера /************ Global State (you don't need to change this!) ******************/ // Реле управления начало #define RelayPin2 2 // пин реле управления Люстра 1 комната #define RelayPin6 6 // пин реле управления Люстра 2 комната #define RelayPin7 7 // пин реле управления Форточка комната #define RelayPin8 8 // пин реле управления Штора комната // Реле управления конец // ШИМ управление начало //#define PWM3 3 // Вытяжка на форточке в комнате. ШИМ (Pin 3) //int PWM3 = 3; // Вытяжка на форточке в комнате. ШИМ (Pin 3) //int PWM5 = 5; // Вытяжка подвал ШИМ (Pin 5) #define PWM3 3 // Вытяжка на форточке в комнате. ШИМ (Pin 3) #define PWM5 5 // Вытяжка подвал ШИМ (Pin 5) // ШИМ управление конец // Датчики и кнопки начало int Move0 = A0; // Датчик движения комната int GazPin1 = A1; // Датчик Газ/Дым(Концентрация) комната int Buttons2 = A2; // Кнопка управления люстрами комната int Buttons3 = A3; // Датчик открытия/закрытия двери комната (Геркон) // Датчики и кнопки конец //Set up the ethernet client EthernetClient client; Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY); //Соединение с брокером // You don't need to change anything below this line! #define halt(s) { Serial.println(F( s )); while(1); } /****************************** Feeds ***************************************/ //Создаем топики датчиков Adafruit_MQTT_Subscribe relay02 = Adafruit_MQTT_Subscribe(&mqtt, "/Switch2/"); // Создаем подписку на топик Люстра 1 Комната Adafruit_MQTT_Subscribe relay06 = Adafruit_MQTT_Subscribe(&mqtt, "/Switch3/"); // Создаем подписку на топик Люстра 2 Комната Adafruit_MQTT_Subscribe relay07 = Adafruit_MQTT_Subscribe(&mqtt, "/Openable02/"); // Создаем подписку на топик Форточка комната Adafruit_MQTT_Subscribe relay08 = Adafruit_MQTT_Subscribe(&mqtt, "/Openable07/"); // Создаем подписку на топик Штора комната Adafruit_MQTT_Publish TopStatusRelay2 = Adafruit_MQTT_Publish(&mqtt, "/SSwitch2/"); // Создаем топик статуса реле №2 Adafruit_MQTT_Publish TopStatusRelay6 = Adafruit_MQTT_Publish(&mqtt, "/SSwitch3/"); // Создаем топик статуса реле №6 Adafruit_MQTT_Publish TopStatusRelay7 = Adafruit_MQTT_Publish(&mqtt, "/SOpenable02/"); // Создаем топик статуса Форточка комната Adafruit_MQTT_Publish TopStatusRelay8 = Adafruit_MQTT_Publish(&mqtt, "/SOpenable07/"); // Создаем топик статуса Штора комната Adafruit_MQTT_Subscribe Dimmer02 = Adafruit_MQTT_Subscribe(&mqtt, "/Dimmer02/"); // Создаем подписку на топик вытяжка комната Adafruit_MQTT_Subscribe Dimmer05 = Adafruit_MQTT_Subscribe(&mqtt, "/Dimmer05/"); // Создаем подписку на топик свет комната //Adafruit_MQTT_Publish TopStatusDimmer02 = Adafruit_MQTT_Publish(&mqtt, "/SDimmer02/"); // Создаем топик статуса Вытяжка комната //Adafruit_MQTT_Publish TopStatusDimmer05 = Adafruit_MQTT_Publish(&mqtt, "/SDimmer05/"); // Создаем топик статуса реле №8 Adafruit_MQTT_Publish Topg1 = Adafruit_MQTT_Publish(&mqtt, "/SS02/"); // Создаем топик датчика газа/дыма №2 комната Adafruit_MQTT_Publish Topm0 = Adafruit_MQTT_Publish(&mqtt, "/SM03/"); // Создаем топик датчика Движения №3 комната Adafruit_MQTT_Publish TopSt3 = Adafruit_MQTT_Publish(&mqtt, "/SSt03/"); // Создаем топик датчика Движения №3 комната /*************************** Sketch Code ************************************/ // Объявляем глобальные переменные float dhtx ; //Переменная почти для всех датчиков char temp[8]; //Переменная почти для всех датчиков int temp2 ; //Переменная для управления ШИМ void setup() { Serial.begin(115200); //Определяем подключение по LAN Начало Serial.println(F("Ждем подключения по LAN")); // this check is only needed on the Leonardo: while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } // start the Ethernet connection: if (Ethernet.begin(mac) == 0) { Serial.println(F("Failed to configure Ethernet using DHCP")); // no point in carrying on, so do nothing forevermore: for (;;) ; } // print your local IP address: printIPAddress(); //Определяем подключение по LAN Конец Serial.println(F("Adafruit MQTT demo")); // Initialise the Client Serial.print(F("\nInit the Client...")); Ethernet.begin(mac); delay(1000); //give the ethernet a second to initialize //Проверяем подключение LAN Начакло switch (Ethernet.maintain()) { case 1: //renewed fail Serial.println(F("Error: renewed fail")); break; case 2: //renewed success Serial.println(F("Renewed success")); //print your local IP address: printIPAddress(); break; case 3: //rebind fail Serial.println(F("Error: rebind fail")); break; case 4: //rebind success Serial.println(F("Rebind success")); //print your local IP address: printIPAddress(); break; default: //nothing happened break; } //Проверяем подключение LAN Конец // Подготовка пинов управления реле начало pinMode(RelayPin2, OUTPUT); pinMode(RelayPin6, OUTPUT); pinMode(RelayPin7, OUTPUT); pinMode(RelayPin8, OUTPUT); digitalWrite(RelayPin2, LOW); digitalWrite(RelayPin6, LOW); digitalWrite(RelayPin7, LOW); digitalWrite(RelayPin8, LOW); // Подготовка пинов управления реле конец // Подготовка пинов управления PWM начало pinMode(PWM3,OUTPUT) ; // Вытяжка на форточке в комнате. ШИМ (Pin 3) pinMode(PWM5,OUTPUT) ; // Вытяжка подвал ШИМ (Pin 5) analogWrite(PWM3,0) ; analogWrite(PWM5,0) ; // Подготовка пинов управления PWM конец mqtt.subscribe(&relay02); mqtt.subscribe(&relay06); mqtt.subscribe(&relay07); mqtt.subscribe(&relay08); mqtt.subscribe(&Dimmer02); mqtt.subscribe(&Dimmer05); } // Конец секции Setup boolean k = false ; // Переменная для первоночального состояния реле после старта контроллера // нужно для того, что бы в Majordomo правильно отражалось состояние реле void(* resetFunc) (void) = 0; //Объявляем функцию reset String StatusRelay02,StatusRelay06,StatusRelay07,StatusRelay08 = "Off" ; void loop() { // Начало главного цикла программы // Ensure the connection to the MQTT server is alive (this will make the first // connection and automatically reconnect when disconnected). See the MQTT_connect // function definition further below. // delay(10000); // Пауза отправки данных в брокер 10 сек MQTT_connect(); // ping the server to keep the mqtt connection alive if(! mqtt.ping()) { mqtt.disconnect(); } // Блок обработки реле и PWM начало Adafruit_MQTT_Subscribe *subscription; if (k == false){ // Проверяем первый ли это цикл программы k = true; // dhtx = 0; TopStatusRelay2.publish(dhtx); // Отправляем в топик актуальное состояние реле №2 после старта контроллера TopStatusRelay6.publish(dhtx); // Отправляем в топик актуальное состояние реле №6 после старта контроллера TopStatusRelay7.publish(dhtx); // Отправляем в топик актуальное состояние реле №7 после старта контроллера TopStatusRelay8.publish(dhtx); // Отправляем в топик актуальное состояние реле №8 после старта контроллера } while ((subscription = mqtt.readSubscription(10000))) { // Запускаем цикл ожидания прихода управляющих топиков. Он же пауза отправки данных с датчиков if (subscription == &relay02) { // Если пришёл топик на реле №2 то выполняем действие Serial.print(F("relay02: ")); // Печатаем в порт заголовок для реле №2 Serial.println((char *)relay02.lastread); // Печатаем в порт значение управляющего топика для реле №2 StatusRelay02 = ((char *)relay02.lastread); // Присваиваем в переменную значение управляющего топика для реле №2 if (StatusRelay02 == "Off") { // Если значение пришедшего топика равно Off digitalWrite(RelayPin2, LOW); // Выключаем реле №2 Serial.println (F("Выключено")); // Печатаем в порт сообщение dhtx = 0; // TopStatusRelay2.publish(dhtx); // Отправляем в брокер текущее состояние реле №2 } if (StatusRelay02 == "On") { // Если значение пришедшего топика равно On digitalWrite(RelayPin2, HIGH); // Включаем реле №2 Serial.println (F("Включено")); // Печатаем в порт сообщение dhtx = 1; // TopStatusRelay2.publish(dhtx); // Отправляем в брокер текущее состояние реле №2 } } if (subscription == &relay06) { Serial.print(F("relay06: ")); Serial.println((char *)relay06.lastread); StatusRelay06 = ((char *)relay06.lastread); if (StatusRelay06 == "Off") { digitalWrite(RelayPin6, LOW); Serial.println (F("Выключено")); dhtx = 0; TopStatusRelay6.publish(dhtx); } if (StatusRelay06 == "On") { digitalWrite(RelayPin6, HIGH); Serial.println (F("Включено")); dhtx = 1; TopStatusRelay6.publish(dhtx); } } if (subscription == &relay07) { Serial.print(F("relay07: ")); Serial.println((char *)relay07.lastread); StatusRelay07 = ((char *)relay07.lastread); if (StatusRelay07 == "Off") { digitalWrite(RelayPin7, LOW); Serial.println (F("Выключено")); dhtx = 0; TopStatusRelay7.publish(dhtx); } if (StatusRelay07 == "On") { digitalWrite(RelayPin7, HIGH); Serial.println (F("Включено")); dhtx = 1; TopStatusRelay7.publish(dhtx); } } if (subscription == &relay08) { Serial.print(F("relay08: ")); Serial.println((char *)relay08.lastread); StatusRelay08 = ((char *)relay08.lastread); if (StatusRelay08 == "Off") { digitalWrite(RelayPin8, LOW); Serial.println (F("Выключено")); dhtx = 0; TopStatusRelay8.publish(dhtx); } if (StatusRelay08 == "On") { digitalWrite(RelayPin8, HIGH); Serial.println (F("Включено")); dhtx = 1; TopStatusRelay7.publish(dhtx); } } // Блок обработки PWM начало // Блок PWM Dimmer02 начало if (subscription == &Dimmer02) { Serial.print(F("Dimmer02: ")); Serial.println((char *)Dimmer02.lastread); temp2 = atoi((char *)Dimmer02.lastread); // преобразуем строковое значение топика в цифровое Serial.print(F("temp2: ")); Serial.println(temp2*255/100); // Преобразуем диапазон от 0 до 100 в от 0 до 255 analogWrite(PWM3,temp2*255/100); // Преобразуем диапазон от 0 до 100 в от 0 до 255 и отправляем в ШИМ } // Блок PWM Dimmer02 конец // Блок PWM Dimmer05 начало if (subscription == &Dimmer05) { Serial.print(F("Dimmer05: ")); Serial.println((char *)Dimmer05.lastread); temp2 = atoi((char *)Dimmer05.lastread); // преобразуем строковое значение топика в цифровое Serial.print(F("temp2: ")); Serial.println(temp2*255/100); // Преобразуем диапазон от 0 до 100 в от 0 до 255 analogWrite(PWM5,temp2*255/100); // Преобразуем диапазон от 0 до 100 в от 0 до 255 и отправляем в ШИМ } // Блок PWM Dimmer05 конец // Блок обработки PWM конец } // Блок обработки реле и PWM конец //------------- Датчик Газа и дыма комната начало процедуры int GazLevel = analogRead(GazPin1); itoa(GazLevel, temp, 10); Serial.print(F(" Газ/Дым Комната: ")); Serial.println (temp); Topg1.publish(temp); // Отправляем значения с датчика комната в брокер //------------- Датчик Газа и дыма комната конец процедуры //------------- Датчик движения комната начало процедуры int Move0Level = analogRead(Move0); itoa(Move0Level, temp, 10); Serial.print(F(" Движение комната: ")); Serial.println (temp); Topm0.publish(temp); // Отправляем значения с датчика комната в брокер //------------- Датчик движения комната конец процедуры //------------- Датчик статуса двери комната-веранда начало процедуры int Buttons3Status = analogRead(Buttons3); itoa(Buttons3Status, temp, 10); Serial.print(F(" Статус двери комната-веранда: ")); Serial.println (temp); TopSt3.publish(temp); // Отправляем значения с датчика комната в брокер //------------- Датчик статуса двери комната-веранда конец процедуры } // Конец главного цикла программы // Function to connect and reconnect as necessary to the MQTT server. // Should be called in the loop function and it will take care if connecting. void MQTT_connect() { int8_t ret; // Stop if already connected. if (mqtt.connected()) { return; } Serial.print(F("Connecting to MQTT... ")); while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected Serial.println(mqtt.connectErrorString(ret)); Serial.println(F("Retrying MQTT connection in 5 seconds... and restart")); mqtt.disconnect(); delay(5000); // wait 5 seconds resetFunc(); // reset system } Serial.println(F("MQTT Connected!")); } void printIPAddress() { Serial.print(F("My IP address: ")); for (byte thisByte = 0; thisByte < 4; thisByte++) { // print the value of each byte of the IP address: Serial.print(Ethernet.localIP()[thisByte], DEC); Serial.print(F(".")); } Serial.println(); }
Проверяй, не превысил ли какой-нибудь лимит на максимум подписок, или исчерпал память контроллера.
Проверяй, не превысил ли какой-нибудь лимит на максимум подписок, или исчерпал память контроллера.
Скорее нет, чем да. Пробовал исключить подписку на /Dimmer02/, оставив только подписку /Dimmer05/. Все равно не работает. Так же пробовал менять очерёдность подписок в скетче. Безрезультатно. Если бы дело было в лимитах на подписки или нехватке памяти, то работа топиков поменялась местами.
Кроме того, провозившись с данной проблемой какое то время, были созданы другие топики, которые нормально отрабатываются.
UpDate: Всё таки дело в лимитах. Убрал все упоминания на подписку /Dimmer02/ и подписка /Dimmer05/ заработала. Буду выяснять что именно мешает.
UpDate2: Пробовал залить скетч в Mega 2560. Тоже не работает. Похоже дело не в нехватке памяти.
Выяснилось, что таких конструкций может быть не более пяти. Шестая строчка всегда не работает.(Данные топика не прилетают в скетч):
Интересно, но нигде про это информацию не нашел.
Спасибо!
Информация находится в https://github.com/adafruit/Adafruit_MQTT_Library/blob/master/Adafruit_MQTT.h
Информация находится в https://github.com/adafruit/Adafruit_MQTT_Library/blob/master/Adafruit_MQTT.h
Спасибо!
Простите великодушно за чайниковский вопрос. А это можно победить? Или это как то связано с аппаратными ограничениями? Ну ладно еще Arduino UNO. Там не так много портов и памяти. А вот Arduino Mega 2560, так там есть где развернуться! Ан нет, фигушки... Просветите плиз! Попробую почитать доку, но я еще весьма слаб в своих познаниях ардуино и его программирования.
Насчёт Меги не знаю - по логике вещей на ней должно быть доступно 15 топиков.
Связано с ограничениями по размеру RAM в МК. Если есть запас свободной - исправляйте дефайн. Можно там же с длиной топика поэкспериментировать.