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 определяют переменные, которые нигде потом не используются.
Вот этот кусок - ну зачем такие лишние извращения-то?
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); }Если достаточно:
void callback(char* topic, byte* payload, unsigned int length) { const char* strPayload = (const char*) payload; if(length < 2) // payload слишком маленький { return; } if (!strcmp(topic,"test/device/arduino01/rel1")) { REL1 = !!strncmp(strPayload,"OF",2); } else if (!strcmp(topic,"test/device/arduino01/rel2")) { REL2 = !!strncmp(strPayload,"OF",2); } else if (!strcmp(topic,"test/device/arduino01/rel3")) { REL3 = !!strncmp(strPayload,"OF",2); } else if (!strcmp(topic,"test/device/arduino01/rel4")) { REL4 = !!strncmp(strPayload,"OF",2); } else if (!strcmp(topic,"test/device/arduino01/rel5")) { REL5 = !!strncmp(strPayload,"OF",2); } else if (!strcmp(topic,"test/device/arduino01/rel6")) { REL6 = !!strncmp(strPayload,"OF",2); } else if (!strcmp(topic,"test/device/arduino01/rel7")) { REL7 = !!strncmp(strPayload,"OF",2); } else if (!strcmp(topic,"test/device/arduino01/rel8")) { REL8 = !!strncmp(strPayload,"OF",2); } else if (!strcmp(topic,"test/device/arduino01/rel9")) { REL9 = !!strncmp(strPayload,"OF",2); } else if (!strcmp(topic,"test/device/arduino01/rel10")) { REL10 = !!strncmp(strPayload,"OF",2); } else if (!strcmp(topic,"test/device/arduino01/kotel1/get")) { char tUstav11; tUstav11 = atoi(strPayload); if (tUstav11 != tUstav1 ) { tUstav1 = tUstav11; } } }И это ещё не вся оптимизация, там по сравнению подстрок можно выкинуть "test/device/arduino01" и проверять на окончание имени топика только, по сути.
Плюс - можно загнать строки в PROGMEM макросом F(), и юзать strcmp_P - будет экономия оперативы ;) Короче, там есть, куда работать.
З.Ы. Единственное "но" - надо бы payload сравнивать не strcmp, а strncmp, а то там нетути завершающего '\0', наверняка. Так что выше - только идея по начальной оптимизации, не более ;)
З.З.Ы. Поправил на strncmp. И да - строка 48, где идёт вызов atoi - также небезопасна по распашке памяти, потому что идёт до завершающего '\0'. Но тоже - правится легко. По итогу же - не надо постоянных плясок с аллокацией памяти ;)
А вообще, навскидку - все эти привязки реле к топику можно сделать тыщей способов, сократив код callback до нескольких строк, буквально. Как бешеный вариант навскидку (далеко не самый оптимальный):
typedef struct { const char* topic; char* pin; } binding; binding bindings[] = { { "/rel1", &REL1 }, { "/rel2", &REL2 }, ... }; void callback(char* topic, byte* payload, unsigned int length) { const char* strPayload = (const char*) payload; size_t topicLen = strlen(topic); if(length < 2) // payload слишком маленький { return; } for(size_t i=0;i<sizeof(bindings)/sizeof(bindings[0]);i++) { if(!memmem(topic, topicLen, bindings[i].topic, strlen(bindings[i].topic))) { *(bindings[i].pin) = !!strncmp(strPayload,"OF",2); } } }Можно также избавиться от digitalWrite в loop, и писать в пин прямо в callback:
typedef struct { const char* topic; uint8_t pin; } binding; binding bindings[] = { { "/rel1", 10 // пин номер 10 у нас привязан к топику rel1 }, { "/rel2", 11 // пин номер 11 у нас привязан к топику rel2 }, ... }; void callback(char* topic, byte* payload, unsigned int length) { const char* strPayload = (const char*) payload; size_t topicLen = strlen(topic); if(length < 2) // payload слишком маленький { return; } for(size_t i=0;i<sizeof(bindings)/sizeof(bindings[0]);i++) { if(!memmem(topic, topicLen, bindings[i].topic, strlen(bindings[i].topic))) { digitalWrite(bindings[i].pin, !!strncmp(strPayload,"OF",2)); } } }// Arduino_w5100_mqtt_10 rele_2Temp_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 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]; unsigned long timing; // Переменная для хранения точки отсчета 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 }; IPAddress ip(192, 168, 1, 22); IPAddress server(192, 168, 1, 25); byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; DHT dht(DHTPIN, DHTTYPE); typedef struct { const char* topic; uint8_t pin; } binding; binding bindings[] = { { "/rel1", 19 // пин номер 19 у нас привязан к топику rel1 }, { "/rel2", 16 // пин номер 16 у нас привязан к топику rel2 }, { "/rel3", 4 }, { "/rel4", 5 }, { "/rel5", 6 }, { "/rel6", 7 }, { "/rel7", 8 }, { "/rel8", 9 }, { "/rel9", 18 }, { "/rel10", 17 }, }; void callback(char* topic, byte* payload, unsigned int length) { const char* strPayload = (const char*) payload; size_t topicLen = strlen(topic); if(length < 2) // payload слишком маленький { return; } for(size_t i=0;i<sizeof(bindings)/sizeof(bindings[0]);i++) { if(!memmem(topic, topicLen, bindings[i].topic, strlen(bindings[i].topic))) { digitalWrite(bindings[i].pin, !!strncmp(strPayload,"OF",2)); } } } 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); dht.begin(); sensors.begin(); sensors.setResolution(Thermometer1, 10); sensors.setResolution(Thermometer2, 10); 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.subscribe("test/device/arduino01/#"); } } void loop() { client.loop(); sensors.requestTemperatures(); float temperature1 = sensors.getTempC(Thermometer1); float temperature2 = sensors.getTempC(Thermometer2); dtostrf(temperature1, 3, 0, tmp1); client.publish("test/device/arduino01/temp1",tmp1); dtostrf(temperature2, 3, 0, tmp2); client.publish("test/device/arduino01/temp2",tmp2); // ----------------dht float humidity = dht.readHumidity(); // humidity float tempC = dht.readTemperature(); // temperature [C] char tmpBuffer[6]; // 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(tempC); Serial.print(", humidity: "); Serial.println(humidity); client.publish("test/device/arduino01/sensor/temp", dtostrf(tempC, 3, 0, tmpBuffer)); // переменая с плав запятой, символов всего, после запятой, переменная char client.publish("test/device/arduino01/sensor/hum", dtostrf(humidity, 3, 0, tmpBuffer)); } if (millis() - timing > 10000){ timing = millis(); if (!client.connected()) { reconnect(); } } }-