Добрый. Подскажите плиз. Есть ардуино нано, w5100 - работает климат-контролем в доме. Ардуинка шлет контроллеру данные о климате по mqtt, получает от него команды. Суть проблемы: если ардуинка подписана\публикует много топиков, то часты зависания mqtt. Ардуинка с одним топиком работает месяцами без сбоев. Может где я в коде напартачил. Код: Код (C++): #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; } } благодарю
Посмотрел свой дачный, подвальный, контроллер на Leonardo ETH, там правда W5500 и Ethernet2. Там публикуется 8 топиков и подписывается на 9 топиков. Не замечал проблем с ним, но я не выводил с него счетчика переподключений по MQTT. А что значит зависания MQTT? По коду не заметил чего-то сильно неправильного, но я бы убрал совсем работу со string. Не нужны там String. я использую const char * и char * Ну еще может быть вынес бы публикацию из mqtt реконнекта, заменив на взвод флага, а саму публикацию поставил бы в loop, при условии, что флаг взведен. У меня сделано так: Публикация: Код (C++): const char *Mqtt_Pub_Str[] = {"/mh/ds/bs/leo/starts", "/mh/ds/bs/leo/restarts", "/mh/ds/bs/leo/lte_reset", "/mh/ds/bs/leo/vcc", "/mh/ds/bs/leo/bat1u", "/mh/ds/bs/leo/bat2u", "/mh/ds/bs/leo/bat1i", "/mh/ds/bs/leo/bat2i" }; byte Mqtt_Update_flag = 0x07; // bit 0 - StartNumber. 1- SelfReStartNumber; 3- LTE_ReStartNumber byte Mqtt_Update_counter = 180; // byte Main_Data_byte[EEPROM_DATA_LENG]; void mqtt_publish_changes() { char buff[30]; byte i; if (Mqtt_Update_flag) { for (i = 0; i < 3; i++) { if ( Mqtt_Update_flag & (1 << i)) { itoa((int) Main_Data_byte[i], buff, 10); client.publish(Mqtt_Pub_Str[i], buff); Mqtt_Update_counter = 180; Mqtt_Update_flag &= ~(1 << i); return; } } for (i = 0; i < 5; i++) { if ( Mqtt_Update_flag & (1 << (3 + i))) { if (i == 3 || i == 4 ) sprintf(buff, "%d.%02d", ADC_Val[i] / 100, ADC_Val[i] % 100); // выведем ток с двумя знаками после запятой else sprintf(buff, "%d.%d", ADC_Val[i] / 10, ADC_Val[i] % 10); // выведем напряжение с одним знаком после запятой client.publish(Mqtt_Pub_Str[3 + i], buff); Mqtt_Update_counter = 180; Mqtt_Update_flag &= ~(1 << (3 + i)); return; } } } } Каждый вызов из loop() публикуется только одно значение и снимается флаг (соответствующий бит флага изменений). В следующий вызов, будет опубликовано следующее значение, и будет снят следующий бит, соответствующий публикуемому значению. Там где проверяются значения, если новое значение не равно текущему, записываем новое в текущее и взводим нужный бит в флаге изменений. Получение: Код (C++): #define MQTT_NUM_SUB_TOP 9 typedef struct _mqtt_subscribe_struct { const char *Mqtt_Sub_String; void (*function)(byte index, byte param); } MQTT_Subscibe_Struct; MQTT_Subscibe_Struct MQTT_Subsc_Data[] = { {"/mh/ds/bs/leo/count_res", &reset_counters }, {"/mh/ds/bs/leo/rel_00", &rel_switch}, {"/mh/ds/bs/leo/rel_01", &rel_switch}, {"/mh/ds/bs/leo/rel_02", &rel_switch}, {"/mh/ds/bs/leo/rel_03", &rel_switch}, {"/mh/ds/bs/leo/rel_10", &rel_switch}, {"/mh/ds/bs/leo/rel_11", &rel_switch}, {"/mh/ds/bs/leo/rel_12", &rel_switch}, {"/mh/ds/bs/leo/rel_13", &rel_switch}, }; void reset_counters(byte index, byte param) { byte i; if (param == 1) { for (i = 0; i < 3; i++) { Main_Data_byte[i] = 0; EEPROM.write(i, Main_Data_byte[i]); } Mqtt_Update_flag = 0xFF; client.publish(MQTT_Subsc_Data[0].Mqtt_Sub_String, "OFF", true); } } void rel_switch(byte index, byte param) { digitalWrite (DIG_Pins[index - 1], param); if( param == 0) Main_Data_byte[RELEY_STATE] &= ~(1 << index-1); else Main_Data_byte[RELEY_STATE] |= (1 << index-1); EEPROM.write(RELEY_STATE, Main_Data_byte[RELEY_STATE]); } void callback(char* topic, byte* payload, unsigned int length) { char message[15]; char i; if(length>14) return; for (i = 0; i < length; i++) message[i] = (char) payload[i]; message[i] = 0; for (i = 0; i < MQTT_NUM_SUB_TOP; i++) { if ( strcmp(topic, MQTT_Subsc_Data[i].Mqtt_Sub_String) == 0 ) { if (strcmp(message, "ON") == 0 ) (*(MQTT_Subsc_Data[i].function))(i, 1); else (*(MQTT_Subsc_Data[i].function))(i, 0); } } } void mqtt_subscribe(void) { byte i; for (i = 0; i < MQTT_NUM_SUB_TOP; i++) { client.subscribe(MQTT_Subsc_Data[i].Mqtt_Sub_String); client.loop(); //mqtt loop } }
Не подскажите, как избавиться от Стринг в строке: client.publish("ihouse/climat/san/temp", String(t_san).c_str()); t_san - тип int, но есть строки где boolean. ? благодарю
Использовать itoa: Код (C++): char buff[15]; itoa(t_san, buff, 10); client.publish("ihouse/climat/san/temp", buff); itoa(h_san, buff, 10); client.publish("ihouse/climat/san/hum", buff);