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 в МК. Если есть запас свободной - исправляйте дефайн. Можно там же с длиной топика поэкспериментировать.