openhab_arduino_mqtt Ардуино перестает реагировать на команды и слать топики
- Войдите на сайт для отправки комментариев
Пнд, 01/06/2020 - 14:17
Добрый день.
Сам я не программист(прошу отнестись с пониманием)
Из разных источников собрал код под свои нужды.
Управление через OpenHab Ардуиной по протоколу MQTT.
Управление/получение информации от ардуино идет какое то время нормально(например сутки).
Потом ардуино перестает реагировать на команды и отправлять температуру.
Предполагаю, что переполняется память. Но точно не знаю.
Уважаемые программисты подскажите, что в коде поправить что бы работало стабильно.
// Arduino_w5100_mqtt_10 rele_6Temp_2Konc_DHT11 #include <SPI.h> #include <Ethernet.h> #include <PubSubClient.h> #include <OneWire.h> #include <DallasTemperature.h> #include <DHT.h> #define ONE_WIRE_BUS 2 // пин для датчиков температуры #define rel1_pin 19 #define rel2_pin 16 #define rel3_pin 4 #define rel4_pin 5 #define rel5_pin 6 #define rel6_pin 7 #define rel7_pin 8 #define rel8_pin 9 #define rel9_pin 18 #define rel10_pin 17 #define DHTPIN 3 #define DHTTYPE DHT11 // DHT 11 const int konc1_pin = 14; const int konc2_pin = 15; int val1 = 0; int val2 = 0; char REL1; char REL2; char REL3; char REL4; char REL5; char REL6; char REL7; char REL8; char REL9; char REL10; char tmp1[10]; char tmp2[10]; char tmp3[10]; char tmp4[10]; char tmp5[10]; char tmp6[10]; char tUstav1; char StrtUstav11[3]; unsigned long loopTime; unsigned long currentTime; OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress Thermometer1 = { 0x28, 0x1C, 0xC1, 0x5D, 0x06, 0x00, 0x00, 0x43 }; DeviceAddress Thermometer2 = { 0x28, 0xFF, 0xE7, 0x2C, 0xA6, 0x15, 0x01, 0xCB }; DeviceAddress Thermometer3 = { 0x28, 0xFF, 0xE7, 0x2C, 0xA6, 0x15, 0x01, 0xCB }; DeviceAddress Thermometer4 = { 0x28, 0xFF, 0xE7, 0x2C, 0xA6, 0x15, 0x01, 0xCB }; DeviceAddress Thermometer5 = { 0x28, 0xFF, 0xE7, 0x2C, 0xA6, 0x15, 0x01, 0xCB }; DeviceAddress Thermometer6 = { 0x28, 0xFF, 0xE7, 0x2C, 0xA6, 0x15, 0x01, 0xCB }; IPAddress ip(192, 168, 1, 22); IPAddress server(192, 168, 1, 25); byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; DHT dht(DHTPIN, DHTTYPE); void callback(char* topic, byte* payload, unsigned int length) { // Выделяем необходимое кол-во памяти для копии payload byte* p = (byte*)malloc(length); // Копирование payload в новый буфер memcpy(p, payload, length); // то что было ранее payload[length] = '\0'; //free(p); \\это не понятно куда поставить Serial.print(topic); Serial.print(" "); String strTopic = String(topic); String strPayload = String((char*)payload); Serial.println(strPayload); if (strTopic == "test/device/arduino01/rel1") { if (strPayload == "ON"){REL1 = 1;} else if (strPayload == "OFF"){REL1 = 0;} } else if (strTopic == "test/device/arduino01/rel2") { if (strPayload == "ON") {REL2 = 1;} else if (strPayload == "OFF") {REL2 = 0;} } else if (strTopic == "test/device/arduino01/rel3") { if (strPayload == "ON") {REL3 = 1;} else if (strPayload == "OFF") {REL3 = 0;} } else if (strTopic == "test/device/arduino01/rel3") { if (strPayload == "ON") {REL3 = 1;} else if (strPayload == "OFF") {REL3 = 0;} } else if (strTopic == "test/device/arduino01/rel4") { if (strPayload == "ON") {REL4 = 1;} else if (strPayload == "OFF") {REL4 = 0;} } else if (strTopic == "test/device/arduino01/rel5") { if (strPayload == "ON") {REL5 = 1;} else if (strPayload == "OFF") {REL5 = 0;} } else if (strTopic == "test/device/arduino01/rel6") { if (strPayload == "ON") {REL6 = 1;} else if (strPayload == "OFF") {REL6 = 0;} } else if (strTopic == "test/device/arduino01/rel7") { if (strPayload == "ON") {REL7 = 1;} else if (strPayload == "OFF") {REL7 = 0;} } else if (strTopic == "test/device/arduino01/rel8") { if (strPayload == "ON") {REL8 = 1;} else if (strPayload == "OFF") {REL8 = 0;} } else if (strTopic == "test/device/arduino01/rel9") { if (strPayload == "ON") {REL9 = 1;} else if (strPayload == "OFF") {REL9 = 0;} } else if (strTopic == "test/device/arduino01/rel10") { if (strPayload == "ON") {REL10 = 1;} else if (strPayload == "OFF") {REL10 = 0;} } else if (strTopic == "test/device/arduino01/kotel1/get") { char tUstav11; tUstav11 = atoi((char*)payload); if (tUstav11 != tUstav1 ) { tUstav1 = tUstav11; } } // Освобождаем память (куда поставить это не понятно, возможно надо выше условий) free(p); } EthernetClient ethClient; PubSubClient client(server, 1883, callback, ethClient); void reconnect() { while (!client.connected()) { Serial.println("Attempting MQTT connection..."); // Attempt to connect if (client.connect("arduinoClient")) { Serial.println("connected"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(3000); } } } void setup() { Serial.begin(9600); pinMode(rel1_pin, OUTPUT); digitalWrite(rel1_pin, HIGH); pinMode(rel2_pin, OUTPUT); digitalWrite(rel2_pin, HIGH); pinMode(rel3_pin, OUTPUT); digitalWrite(rel3_pin, HIGH); pinMode(rel4_pin, OUTPUT); digitalWrite(rel4_pin, HIGH); pinMode(rel5_pin, OUTPUT); digitalWrite(rel5_pin, HIGH); pinMode(rel6_pin, OUTPUT); digitalWrite(rel6_pin, HIGH); pinMode(rel7_pin, OUTPUT); digitalWrite(rel7_pin, HIGH); pinMode(rel8_pin, OUTPUT); digitalWrite(rel8_pin, HIGH); pinMode(rel9_pin, OUTPUT); digitalWrite(rel9_pin, HIGH); pinMode(rel10_pin, OUTPUT); digitalWrite(rel10_pin, HIGH); pinMode(konc1_pin, INPUT); pinMode(konc2_pin, INPUT); dht.begin(); sensors.begin(); sensors.setResolution(Thermometer1, 10); sensors.setResolution(Thermometer2, 10); sensors.setResolution(Thermometer3, 10); sensors.setResolution(Thermometer4, 10); sensors.setResolution(Thermometer5, 10); sensors.setResolution(Thermometer6, 10); currentTime = millis(); loopTime = currentTime; Ethernet.begin(mac, ip); if (client.connect("arduinoClient")) { Serial.println("online"); client.publish("test/device/arduino01/rel1", "OFF"); client.publish("test/device/arduino01/rel2", "OFF"); client.publish("test/device/arduino01/rel3", "OFF"); client.publish("test/device/arduino01/rel4", "OFF"); client.publish("test/device/arduino01/rel5", "OFF"); client.publish("test/device/arduino01/rel6", "OFF"); client.publish("test/device/arduino01/rel7", "OFF"); client.publish("test/device/arduino01/rel8", "OFF"); client.publish("test/device/arduino01/rel9", "OFF"); client.publish("test/device/arduino01/rel10", "OFF"); client.publish("test/device/arduino01/kotel1/get", "37"); client.subscribe("test/device/arduino01/#"); } } void loop() { if (REL1 == 0) digitalWrite(rel1_pin, HIGH); else if (REL1 == 1) digitalWrite(rel1_pin, LOW); if (REL2 == 0) digitalWrite(rel2_pin, HIGH); else if (REL2 == 1) digitalWrite(rel2_pin, LOW); if (REL3 == 0) digitalWrite(rel3_pin, HIGH); else if (REL3 == 1) digitalWrite(rel3_pin, LOW); if (REL4 == 0) digitalWrite(rel4_pin, HIGH); else if (REL4 == 1) digitalWrite(rel4_pin, LOW); if (REL5 == 0) digitalWrite(rel5_pin, HIGH); else if (REL5 == 1) digitalWrite(rel5_pin, LOW); if (REL6 == 0) digitalWrite(rel6_pin, HIGH); else if (REL6 == 1) digitalWrite(rel6_pin, LOW); if (REL7 == 0) digitalWrite(rel7_pin, HIGH); else if (REL7 == 1) digitalWrite(rel7_pin, LOW); if (REL8 == 0) digitalWrite(rel8_pin, HIGH); else if (REL8 == 1) digitalWrite(rel8_pin, LOW); if (REL9 == 0) digitalWrite(rel9_pin, HIGH); else if (REL9 == 1) digitalWrite(rel9_pin, LOW); if (REL10 == 0) digitalWrite(rel10_pin, HIGH); else if (REL10 == 1) digitalWrite(rel10_pin, LOW); /* val1 = digitalRead(konc1_pin); // считываем значение с концевика1 if (val1 == HIGH) { client.publish("test/device/arduino01/konc1", "ON"); } else if (val1 == LOW) { client.publish("test/device/arduino01/konc1", "OFF"); } val2 = digitalRead(konc2_pin); // считываем значение с концевика2 if (val2 == HIGH) { client.publish("test/device/arduino01/konc2", "ON"); } else if (val2 == LOW) { client.publish("test/device/arduino01/konc2", "OFF"); } if ((sensors.getTempC(Thermometer2)) < tUstav1 && REL2==0) { REL2 = 1; client.publish("test/device/arduino01/rel2", "ON"); Serial.println("REL2 - ON"); } else if ((sensors.getTempC(Thermometer2)) >= tUstav1 && REL2==1) { REL2=0; client.publish("test/device/arduino01/rel2", "OFF"); Serial.println("REL2 - OFF"); } */ client.loop(); currentTime = millis(); sensors.requestTemperatures(); if(currentTime >= (loopTime + 15000)){ if (!client.connected()) { reconnect(); } float temperature1 = sensors.getTempC(Thermometer1); float temperature2 = sensors.getTempC(Thermometer2); dtostrf(temperature1, -2, 1, tmp1); client.publish("test/device/arduino01/temp1",tmp1); dtostrf(temperature2, -2, 1, tmp2); client.publish("test/device/arduino01/temp2",tmp2); dtostrf(tUstav1, -2, 0, StrtUstav11); client.publish("test/device/arduino01/kotel1/get", StrtUstav11); ///////////////////////////// //dht //delay(2000); float humidity = dht.readHumidity(); // humidity float tempC = dht.readTemperature(); // temperature [C] char tmpBuffer[20]; // check if any reads failed and exit early (to try again). /* if (isnan(humidity) || isnan(tempC)) { Serial.println("error reading sensor data"); return; } else {*/ //Serial.print("[sensor data] temperature[C]: "); Serial.print(tempC); Serial.print(", humidity: "); Serial.println(humidity); client.publish("test/device/arduino01/sensor/temp", dtostrf(tempC, 6, 2, tmpBuffer)); // переменая с плав запятой, символов всего, после запятой, переменная char client.publish("test/device/arduino01/sensor/hum", dtostrf(humidity, 6, 2, tmpBuffer)); // } loopTime = currentTime; } }
Что сразу бросилось в глаза:
1. Для чего выделяется память в строке №65, если она после этого нигде и никак не используется?
2. В строке №69 есть риск "распашки памяти". Если Вам передали массив, длиной length то в нём нет элемента с номером length - Вы вылезли за массив. Хорошо если там "ничего важного", а если там что-то нужное, вы портите это своим нулём.
3. В строке №312 заявка на проблемы с переполнением счётчика millis
4. В строках №№319 и 321 написана какая-то странность - полный размер результата - 2 символа, при этом 1 знак после десятичной точки. Не возбраняется, конечно, но выглядит странно.
5. Непонятно, для чего размер буфера в строке №330 такой большой, когда используется только 7 символов (строки №№ 343 и 344)
6. Строки №№ 41-44 определяют переменные, которые нигде потом не используются.
Вот этот кусок - ну зачем такие лишние извращения-то?
Если достаточно:
И это ещё не вся оптимизация, там по сравнению подстрок можно выкинуть "test/device/arduino01" и проверять на окончание имени топика только, по сути.
Плюс - можно загнать строки в PROGMEM макросом F(), и юзать strcmp_P - будет экономия оперативы ;) Короче, там есть, куда работать.
З.Ы. Единственное "но" - надо бы payload сравнивать не strcmp, а strncmp, а то там нетути завершающего '\0', наверняка. Так что выше - только идея по начальной оптимизации, не более ;)
З.З.Ы. Поправил на strncmp. И да - строка 48, где идёт вызов atoi - также небезопасна по распашке памяти, потому что идёт до завершающего '\0'. Но тоже - правится легко. По итогу же - не надо постоянных плясок с аллокацией памяти ;)
А вообще, навскидку - все эти привязки реле к топику можно сделать тыщей способов, сократив код callback до нескольких строк, буквально. Как бешеный вариант навскидку (далеко не самый оптимальный):
Можно также избавиться от digitalWrite в loop, и писать в пин прямо в callback:
-