Ардуино нано, 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, смотрите - утекает ли память:
inline uint32_t getRamFree(void) { extern uint16_t __heap_start, *__brkval; uint16_t v; return (uint32_t) &v - (__brkval == 0 ? (uint32_t) &__heap_start : (uint32_t) __brkval); }скетч.
?
Вместо вот такого:
откройте для себя strcmp_P, и все строки - в PROGMEM, макросом F().
Вместо вот такого:
откройте для себя strcmp_P, и все строки - в PROGMEM, макросом F().
можно пример, где посмотреть реализацию можно?
http://arduino.ru/forum/programmirovanie/ispolzovanie-makrosa-f