может кто сталкивался, как только раскомментирую строку //t = analogRead(A0); nodemcu (ESP8266) постоянно теряет соединение с mqtt. Как решить? Код (C++): #include <ESP8266WiFi.h> #include <PubSubClient.h> // Update these with values suitable for your network. const char* ssid = ""; const char* password = ""; const char* mqtt_server = ""; WiFiClient espClient; PubSubClient client(espClient); long lastMsg = 0; char msg[50]; int value = 0; String waterlockstr; String serenagasstr; String wateralarmstr; String waterlevelstr; float diff = 150; int gas = 0; int t = 0; bool serena; void setup_wifi() { delay(10); // We start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } randomSeed(micros()); Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); pinMode(D2, OUTPUT); //Waterlock digitalWrite(D2, LOW); pinMode(D6, OUTPUT); //Waterlock digitalWrite(D6, LOW); pinMode(D1, OUTPUT); //Serena digitalWrite(D1, LOW); pinMode(A0, INPUT); //Gas } void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); String strTopic = String(topic); String message; for (int i = 0; i < length; i++) { message = message + (char)payload[i]; //Conver *byte to String } Serial.print(message); Serial.println(); if(strTopic == "waterlock") { waterlockstr = message; } else if(strTopic == "serenagas") { serenagasstr = message; } else if(strTopic == "fermentation/water_alarm") { wateralarmstr = message; } else if(strTopic == "fermentation/water_level") { waterlevelstr = message; } } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Create a random client ID String clientId = "ESP8266Client-"; clientId += String(random(0xffff), HEX); // Attempt to connect if (client.connect(clientId.c_str())) { Serial.println("connected"); // Once connected, publish an announcement... client.subscribe("waterlock"); client.subscribe("serenagas"); client.subscribe("fermentation/water_alarm"); client.subscribe("fermentation/water_level"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void setup() { Serial.begin(115200); setup_wifi(); client.setServer(mqtt_server, 1883); client.setCallback(callback); } void loop() { //t = analogRead(A0); if (!client.connected()) { reconnect(); } client.loop(); getAll(); if (wateralarmstr == "ALARM" || waterlevelstr == "ALARM" || waterlockstr == "1") { digitalWrite(D6, LOW); digitalWrite(D2, HIGH); } else if (wateralarmstr == "no worries" && waterlevelstr == "no worries" && waterlockstr == "0") { digitalWrite(D6, HIGH); digitalWrite(D2, LOW); } if (serenagasstr == "1") digitalWrite(D1, HIGH); else if (serenagasstr == "0") digitalWrite(D1, LOW); } bool checkBound(float newValue, float prevValue, float maxDiff) { return !isnan(newValue) && (newValue < prevValue - maxDiff || newValue > prevValue + maxDiff); } void getAll() { int newgas = t; //gas level if ((checkBound(newgas, gas, diff))) { gas = newgas; if (gas >= 150){ client.publish("serenagas", "1", true); } else if (gas < 150) { client.publish("serenagas", "0", true); } } }
Да нет там никаких проблем. Работают у меня несколько ESP с чтением АЦП и передачей данных по MQTT. Работают очень стабильно. Думаю ваш код начинает очень часто публиковать данные, когда переменная t начинает меняться. И разберитесь с типами данных. В случае вызова функции, тип переменных должен соответствовать типу переменных в описании функции. Ну, или нужно делать явное преобразование типов при передаче параметров в функцию. Код (C++): bool checkBound(float newValue, float prevValue, float maxDiff) { return !isnan(newValue) && (newValue < prevValue - maxDiff || newValue > prevValue + maxDiff); } void getAll() { int newgas = t; //gas level if ((checkBound(newgas, gas, diff))) { gas = newgas; if (gas >= 150){ client.publish("serenagas", "1", true); } else if (gas < 150) { client.publish("serenagas", "0", true); } } } Зачем вам float ?
убрал публикацию (void getAll()) совсем. все равно mqtt отваливался, пока не ограничил чтение АЦП раз в пять сек
У меня на ESP АЦП читается раз в секунду, на Leeonardo ETH каждые 100мс. На каждом цикле, думаю, точно не нужно. Данные собираются, усредняются (30 значений) обрабатываются, и если отличаются от предыдущего - отправляются по mqtt. Выкладывайте измененный скетч, посмотрим что там.
Вот этот вариант кривой, но вроде работает Код (C++): #include <ESP8266WiFi.h> #include <PubSubClient.h> // Update these with values suitable for your network. const char* ssid = ""; const char* password = ""; const char* mqtt_server = "192.168.1.1"; WiFiClient espClient; PubSubClient client(espClient); long lastMsg = 0; char msg[50]; int value = 0; String waterlockstr; String serenagasstr; String wateralarmstr; String waterlevelstr; int diff = 150; int gas = 0; int t = 0; unsigned long timepast = 0; int diff1 = 1; bool g = 0; // для публикации статуса waterlock bool t1; // для публикации статуса waterlock void setup_wifi() { delay(10); // We start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } randomSeed(micros()); Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); pinMode(D2, OUTPUT); //Waterlock digitalWrite(D2, LOW); pinMode(D6, OUTPUT); //Waterlock digitalWrite(D6, LOW); pinMode(D1, OUTPUT); //Serena digitalWrite(D1, LOW); pinMode(A0, INPUT); //Gas } void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); String strTopic = String(topic); String message; for (int i = 0; i < length; i++) { message = message + (char)payload[i]; //Conver *byte to String } Serial.print(message); Serial.println(); if(strTopic == "waterlock") { waterlockstr = message; } else if(strTopic == "serenagas") { serenagasstr = message; } else if(strTopic == "fermentation/water_alarm") { wateralarmstr = message; } else if(strTopic == "fermentation/water_level") { waterlevelstr = message; } } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Create a random client ID String clientId = "ESP8266Client-"; clientId += String(random(0xffff), HEX); // Attempt to connect if (client.connect(clientId.c_str())) { Serial.println("connected"); // Once connected, publish an announcement... client.subscribe("waterlock"); client.subscribe("serenagas"); client.subscribe("fermentation/water_alarm"); client.subscribe("fermentation/water_level"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void setup() { Serial.begin(115200); setup_wifi(); client.setServer(mqtt_server, 1883); client.setCallback(callback); } void loop() { if ((millis()-timepast) > 5000) { t = analogRead(A0); t1 = digitalRead(D2); timepast = millis(); } if (!client.connected()) { reconnect(); } client.loop(); getAll(); if (wateralarmstr == "no worries" && waterlevelstr == "no worries" && waterlockstr == "1") { digitalWrite(D6, LOW); digitalWrite(D2, HIGH); } else if (waterlockstr == "0") { digitalWrite(D6, HIGH); digitalWrite(D2, LOW); } if (wateralarmstr == "ALARM" && waterlockstr == "1") client.publish("waterlock", "0", true); if (waterlevelstr == "ALARM" && waterlockstr == "1") client.publish("waterlock", "0", true); if (serenagasstr == "1") digitalWrite(D1, HIGH); else if (serenagasstr == "0") digitalWrite(D1, LOW); delay(200); } bool checkBound(int newValue, int prevValue, int maxDiff) { return !isnan(newValue) && (newValue <= prevValue - maxDiff || newValue >= prevValue + maxDiff); } void getAll() { int newgas = t; //gas level bool newg = t1;// state waterlock if ((checkBound(newgas, gas, diff))) { gas = newgas; if (gas >= 150){ client.publish("serenagas", "1", true); } else if (gas < 150) { client.publish("serenagas", "0", true); } } if (checkBound(newg, g, diff1)){ g = newg; client.publish("waterlock", String(g).c_str(), true); } }
Вы монитор порта смотрели? Что выводится. Добавьте в setup : Код (C++): Serial.println("Setup start"); Будет понятно когда ESP перезагружается. Плюс побольше подобных строк в код, и по монитору порта смотреть, что происходит. Так вроде не видно причины, во втором варианте у вас есть таймаут в конце loop в 200мс, должно было все работать нормально и без этих 5 сек.
delay я уже потом добавил. в следующие выходные займусь отладкой. спасибо за подсказки а вообще у mosquitto есть предел по количеству топиков или сообщений в секунду?
Я не сталкивался. Нарывался на проблему с одинаковым Id клиента. Когда только начинал, код с одного ESP в дугой залил, не исправив. Один точно постоянно переподключался, второй уже не помню. В начале 16-го это было. После этого использую в качестве ID - часть MAC адреса. Код (C++): byte MAC[6]; // the MAC address of your ESP char Device_Name[14]; // ESP_+ last 3 byts of MAC address of your ESP char Login[] = "YourLogin"; char Password[] = "YourPassword"; WiFi.macAddress(MAC); sprintf(Device_Name,"ESP_%02X%02X%02X",(unsigned)MAC[3],(unsigned)MAC[4],(unsigned)MAC[5]); ............................ if (client.connect(Device_Name,Login,Password)) ............................ Я string не использую. Мне проще со строками в char.
Основное все - дома. Брокер Москито + OpenHAB + HomeKit. Все на малине. Здесь есть очень интересная и познавательная тема от @ИгорьК. В этой теме Игоря, код для ESP на Lua, но от этого смысл не меняется. Спойлер: Чем управляет, так много чем управляет. Дома подключено все верхнее освещение, датчики движения, NTP-часы с измерением температуры и влажности в каждой комнате, модуль внешней температуры с двумя датчиками (с двух сторон дома - берется минимальная температура), счетчики воды, снятия информации и управление системой защиты от протечек, мониторинг и управление теплым полом в ванной. Все на ESP8266. Свой вариант управления освещением выкладывал здесь Если все ушли и дома - свет по всей квартире отключается. На работе, контроль температуры в двух серверных, мониторинг сети и генератора. Серверные на Leonardo ETH, а генератор на ESP. На даче мониторинг аккумуляторных батарей в подвале +контроль питания + управление. Тоже Leonardo ETH. Сигнализация там давно, но SMS + звонки, переделывать пока нет смысла - работает. В этом году на даче у родителей жены подключил контроль температуры дома, ну и заодно, на улице + включение нагревателя к приезду. - сделано на ESP. Недавно делал модуль мониторинга и управления для машины. Прототип делал на Меге + GPRS Shield + Relay Shield. Здесь писал Связь через GPRS модем по протоколу mqtt на OpenHAB, со всеми вытекающими из этого плюшками . Очень хотелось подключить машину, со всеми возможностями контроля и уведомлений, в OpenHAB, и при этом сделать систему не сильно прожорливой, без WiFi и роутера. Пока система показала себя надежной. Хочу в последствии перенести модуль для машины на ESP + SIM800. Даже железо уже нашел, 2 месяца лежит, но руки не доходят. Вот, все это хозяйство к домашнему OpenHAB подключается, и с него же управляется.
без малинки не обойтись? у меня москито на роутере установлен, а в качестве сервера ESP32, с нарисованной вэб мордой, которую keenetic публикует в интернет . так что нам не страшен серый ip. Имеет такая схема право на жизнь?
Конечно имеет право на жизнь, она же работает! Как по мне - с малиной логичнее, да и в обслуживании ИМХО проще. У меня на малину только два порта прокинуты. Москито и NGINX. Перед глобальными изменениями просто делаю бэкап карты и все. Скажу больше, у меня две малины с OpenHAB работают. Одна рабочая, со старой версией, а вторая для экспериментов, с последней.