Ардуино нано, mqtt, много топиков
- Войдите на сайт для отправки комментариев
Втр, 18/12/2018 - 11:14
Добрый.
Подскажите плиз. Есть ардуино нано, w5100 - работает климат-контролем в доме. Ардуинка шлет контроллеру данные о климате по mqtt, получает от него команды.
Суть проблемы: если ардуинка подписана\публикует много топиков, то часты зависания mqtt. Ардуинка с одним топиком работает месяцами без сбоев.
Может где я в коде напартачил.
Код:
#include <OneWire.h> #include <DallasTemperature.h> #include <DHT.h> #include <Wire.h> #include <SPI.h> #include <PubSubClient.h> #include <Ethernet2.h> #include <Bounce.h> // ======================================================================= // Конфигурация устройства MQTT: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xE8, 0xFE, 0xE7 }; IPAddress ip(192, 168, 1, 77); IPAddress dnServer(192, 168, 1, 1); IPAddress gateway(192, 168, 1, 1); IPAddress subnet(255, 255, 255, 0); const char *mqtt_server = "192.168.1.70"; // Имя сервера MQTT const int mqtt_port = 1883; // Порт для подключения к серверу MQTT const char *mqtt_user = "***"; // Логи от сервер const char *mqtt_pass = "***"; // Пароль от сервера EthernetClient ethClient; PubSubClient client(ethClient); // ======================================================================= //ds18b20 OneWire oneWire(5); // вход датчиков 18b20 DallasTemperature ds(&oneWire); DeviceAddress ds_budka = {0x28, 0x53, 0xD9, 0x1E, 0x00, 0x00, 0x80, 0x65}; //2853D91E00008065 //подсчет времени //опрос датчиков long previousMillis_sensor = 0; // храним время последнего опроса датчиков long interval_sensor = 30000; //интервал //mqtt long previousMillis_mqtt_send = 0; // храним время последнего подключения long interval_mqtt_send = 15000; //интервал //mqtt broker long previousMillis_mqtt_connect = 0; // храним время последнего подключения long interval_mqtt_connect = 60000; //интервал unsigned long currentMillis_mqtt_connect = 0; int t_kux; int h_kux; int t_kux_tmp = 0; int h_kux_tmp = 0; int t_san; int h_san; int t_san_tmp = 0; int h_san_tmp = 0; int t_budka; int t_budka_tmp = 0; byte i = 0; //геркон крышки унитаза const byte inGorshok = 2; //вход крышка унитаза //#define outSirena A6 //выход сирена //создаем объект класса Bounce. Указываем пин, к которому подключена кнопка, и время дребезга в мс. Bounce bouncer1 = Bounce(inGorshok, 50); boolean flag_karlson_san = false; //флаг карлсона санузел boolean flag_karlson_kux = false; //флаг карлсона кухня boolean flag_gorshok = false; //флаг сирены крышки горшка boolean flag_budka = false; //флаг отопление будка boolean flag_heating_kux = false; //флаг отопление кухня //вход для dht const byte DHTPIN2 = 4; // датчик санузел const byte DHTPIN3 = 3; // датчик кухня #define DHTTYPE_2301 DHT21 // DHT 21 (AM2301) кухня + улица #define DHTTYPE_2302 DHT22 // DHT 22 (AM2302) санузел //выходы вентиляторов const byte outPin1 = 6; // кухня const byte outPin2 = 7; // санузел const byte outPin3 = 8; // будка const byte outSirena = 9; // сирена //выходы отопление кухня const byte outPin4 = A4; // кухня DHT dht2(DHTPIN2, DHTTYPE_2302); DHT dht3(DHTPIN3, DHTTYPE_2301); // ======================================================================= // Функция получения данных от сервера void callback(char* topic, byte* payload, unsigned int length) { //-------------------------------------------------------------------------------------- if (String(topic) == "ihouse/climat/san/karlson") { if ((char)payload[0] == '0') flag_karlson_san = true; if ((char)payload[0] == '1') flag_karlson_san = false; digitalWrite(outPin2, flag_karlson_san); } if (String(topic) == "ihouse/climat/kux/karlson") { if ((char)payload[0] == '0') flag_karlson_kux = true; if ((char)payload[0] == '1') flag_karlson_kux = false; digitalWrite(outPin1, flag_karlson_kux); } if (String(topic) == "ihouse/climat/budka/heating") { if ((char)payload[0] == '0') flag_budka = true; if ((char)payload[0] == '1') flag_budka = false; digitalWrite(outPin3, flag_budka); } if (String(topic) == "ihouse/climat/kux/heating") { if ((char)payload[0] == '0') flag_heating_kux = true; if ((char)payload[0] == '1') flag_heating_kux = false; digitalWrite(outPin4, flag_heating_kux); } if (String(topic) == "ihouse/gadget/gorshok") { if ((char)payload[0] == '1') flag_gorshok = true; if ((char)payload[0] == '0') flag_gorshok = false; } } // ======================================================================= void mqtt_reconnect() { unsigned long currentMillis_mqtt_connect = millis(); // подключаемся к MQTT серверу if (currentMillis_mqtt_connect - previousMillis_mqtt_connect >= interval_mqtt_connect) { String clientId = "nanoclimat-"; clientId += String(random(0xffff), HEX); if (client.connect(clientId.c_str(), mqtt_user, mqtt_pass)) { client.publish("ihouse/climat/kux/karlson", String(flag_karlson_kux).c_str()); client.publish("ihouse/climat/san/karlson", String(flag_karlson_san).c_str()); client.publish("ihouse/climat/budka/heating", String(flag_budka).c_str()); client.publish("ihouse/climat/kux/heating", String(flag_heating_kux).c_str()); //подписываемся по топики client.subscribe("ihouse/climat/kux/karlson"); client.loop(); client.subscribe("ihouse/climat/san/karlson"); client.loop(); client.subscribe("ihouse/climat/budka/heating"); client.loop(); client.subscribe("ihouse/climat/kux/heating"); client.loop(); client.subscribe("ihouse/gadget/gorshok"); client.loop(); } previousMillis_mqtt_connect = currentMillis_mqtt_connect; } } // ======================================================================= void setup() { client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); delay(10); Ethernet.begin(mac, ip, dnServer, gateway, subnet); delay(10); dht2.begin(); dht3.begin(); ds.begin(); //для релюшек pinMode(outPin1, OUTPUT); digitalWrite(outPin1, HIGH); pinMode(outPin2, OUTPUT); digitalWrite(outPin2, HIGH); pinMode(outPin3, OUTPUT); digitalWrite(outPin3, HIGH); pinMode(outPin4, OUTPUT); digitalWrite(outPin4, HIGH); //геркон горшка pinMode(inGorshok, INPUT); //сирена горшка pinMode(outSirena, OUTPUT); digitalWrite(outSirena, LOW); } // ======================================================================= // Функция отправки в топик void MQTT_Send() { unsigned long currentMillis_mqtt_send = millis(); if (currentMillis_mqtt_send - previousMillis_mqtt_send >= interval_mqtt_send) { previousMillis_mqtt_send = currentMillis_mqtt_send; client.publish("ihouse/work/climat", String(random(1000)).c_str()); } delay(10); } // ======================================================================= void loop() { unsigned long currentMillis_sensor = millis(); //-------------------------------------------------------------------------------------- if (!client.connected()) { mqtt_reconnect(); } client.loop(); MQTT_Send(); //-------------------------------------------------------------------------------------- //проверка состояния геркона - санузел if ( bouncer1.update() ) { //если считано значение 1 if (bouncer1.read() == HIGH) { client.publish("ihouse/climat/san/gorshok", String(1).c_str()); } else { client.publish("ihouse/climat/san/gorshok", String(0).c_str()); } } //-------------------------------------------------------------------------------------- //проверка статуса крышки горшка if (flag_gorshok == true) { digitalWrite(outSirena, HIGH); } else { digitalWrite(outSirena, LOW); } //-------------------------------------------------------------------------------------- //влажность+температура+давление if (currentMillis_sensor - previousMillis_sensor > interval_sensor) { previousMillis_sensor = currentMillis_sensor; i++; } //санузел if (i == 1) { if (dht2.readHumidity() <= 100) h_san = dht2.readHumidity(); if (dht2.readTemperature() <= 50) t_san = dht2.readTemperature(); if (t_san != t_san_tmp) { client.publish("ihouse/climat/san/temp", String(t_san).c_str()); t_san_tmp = t_san; } if (h_san != h_san_tmp) { client.publish("ihouse/climat/san/hum", String(h_san).c_str()); h_san_tmp = h_san; } } //кухня if (i == 2) { if (dht3.readHumidity() <= 100) h_kux = dht3.readHumidity(); if (dht3.readTemperature() <= 50) t_kux = dht3.readTemperature(); if (t_kux != t_kux_tmp) { client.publish("ihouse/climat/kux/temp", String(t_kux).c_str()); t_kux_tmp = t_kux; } if (h_kux != h_kux_tmp) { client.publish("ihouse/climat/kux/hum", String(h_kux).c_str()); h_kux_tmp = h_kux; } } //dallas подготовка if (i == 3) { ds.requestTemperatures(); // считываем температуру с датчиков } //dallas считывание if (i == 4) { if (ds.getTempC(ds_budka) <= 50) t_budka = ds.getTempC(ds_budka); if (t_budka != t_budka_tmp) { client.publish("ihouse/climat/budka/temp", String(t_budka).c_str()); t_budka_tmp = t_budka; } i = 0; } }
благодарю
Суть проблемы: если ардуинка подписана\публикует много топиков, то часты зависания mqtt. Ардуинка с одним топиком работает месяцами без сбоев.
Может где я в коде напартачил.
Принято к сведению. Спасибо, будем знать теперь.
то часты зависания mqtt.
тема не раскрыта, что зависает? сам скетч или внешний сервер?
Update: Ставлю на недостаток памяти МК.
Избавляйтесь от лишних библиотек DallasTemperature.h Bounce.h - переписывайте самостоятельно работу с кнопками и DS18B20.
Уменьшите пути к топикам, вместо ihouse/climat/budka/temp например сокращайте на ih/cl/bd/tm
Если не поможет - вместо PubSubClient.h переходите на самостоятельное общение с mqtt сервером
Надо посмотреть объем свободной памяти при компиляции скетча, в котором "много топиков". Потом уже и плясать.
Надо посмотреть объем свободной памяти при компиляции скетча, в котором "много топиков". Потом уже и плясать.
то часты зависания mqtt.
тема не раскрыта, что зависает? сам скетч или внешний сервер?
Update: Ставлю на недостаток памяти МК.
Избавляйтесь от лишних библиотек DallasTemperature.h Bounce.h - переписывайте самостоятельно работу с кнопками и DS18B20.
Уменьшите пути к топикам, вместо ihouse/climat/budka/temp например сокращайте на ih/cl/bd/tm
Если не поможет - вместо PubSubClient.h переходите на самостоятельное общение с mqtt сервером
скетч.
Надо посмотреть объем свободной памяти при компиляции скетча, в котором "много топиков". Потом уже и плясать.
Натыкайте вызов в луп, выводите в Serial, смотрите - утекает ли память:
скетч.
?
Вместо вот такого:
откройте для себя strcmp_P, и все строки - в PROGMEM, макросом F().
Вместо вот такого:
откройте для себя strcmp_P, и все строки - в PROGMEM, макросом F().
можно пример, где посмотреть реализацию можно?
http://arduino.ru/forum/programmirovanie/ispolzovanie-makrosa-f