• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Нужна помощь Помогите дописать скетч ESP8266+MQTT+DHT11+управление светом

Andrew0510

New member
Здравствуйте, я новичок в этой сфере.
Есть скетч, сейчас читает температуру и влажность и постит в MQTT брокер.
Помогите дописать, чтобы можно было по MQTT включать/выключать реле.
Код:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

#define wifi_ssid "TP-LINK_53A620"
#define wifi_password "10091993asd"

#define mqtt_server "server-adress"
#define mqtt_user "login"
#define mqtt_password "password"

#define humidity_topic "sensor/humidity"
#define temperature_topic "sensor/temperature"

#define DHTTYPE DHT11
#define DHTPIN  14

WiFiClient espClient;
PubSubClient client(espClient);
DHT dht(DHTPIN, DHTTYPE, 11); // 11 works fine for ESP8266
const int lamp = 13;


void setup() {
  Serial.begin(115200);
  dht.begin();
  setup_wifi();
  client.setServer(mqtt_server, 19217);
  pinMode(lamp, OUTPUT);
  digitalWrite(lamp, LOW);
}

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(wifi_ssid);

  WiFi.begin(wifi_ssid, wifi_password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    // If you do not want to use a username and password, change next line to
    // if (client.connect("ESP8266Client")) {
    if (client.connect("ESP8266Client", mqtt_user, mqtt_password)) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

bool checkBound(float newValue, float prevValue, float maxDiff) {
  return !isnan(newValue) &&
         (newValue < prevValue - maxDiff || newValue > prevValue + maxDiff);
}

long lastMsg = 0;
float temp = 0.0;
float hum = 0.0;
float diff = 1.0;

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  long now = millis();
  if (now - lastMsg > 2000) {
    lastMsg = now;

    float newTemp = dht.readTemperature();
    float newHum = dht.readHumidity();

    if (checkBound(newTemp, temp, diff)) {
      temp = newTemp;
      Serial.print("New temperature:");
      Serial.println(String(temp).c_str());
      client.publish(temperature_topic, String(temp).c_str(), true);
    }

    if (checkBound(newHum, hum, diff)) {
      hum = newHum;
      Serial.print("New humidity:");
      Serial.println(String(hum).c_str());
      client.publish(humidity_topic, String(hum).c_str(), true);
    }
  }
}
Пин под реле прописал - 13 выход.
Спасибо
 

=AK=

New member
Код:
void MQTT_callback(char* topic){
  ... // здесь обрабатывайте пришедший топик
}

void setup() {
  Serial.begin(115200);
  dht.begin();
  setup_wifi();
  client.setServer(mqtt_server, 19217);
  client.setCallback(MQTT_callback); // укажите, какая функция должна вызываться
  String topic = " ... ";  // определите свой топик
  client.subscribe(topic.c_str()));   // подпишитесь на него
  pinMode(lamp, OUTPUT);
  digitalWrite(lamp, LOW);
}
 

andrik_zp

Member
Подскажите, в который раз наблюдаю как для обьявления пина отводят двухбайтную константу "const int lamp = 13;" зачем так делать если достаточно простого макроса #define lamp 13
 

Ers

New member
define пришли из С
удобнее и правильнее по памяти
Код:
const byte lamp = 13;
 

Andrew0510

New member
Нашел другую версию скетча, разобрался с ней. Буду ее допиливать под свои нужды.
Всем спасибо.

Код:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

#define DHTPIN 13
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

const char *ssid =  "+++++";  // Имя вайфай точки доступа
const char *pass =  "+++++++"; // Пароль от точки доступа

const char *mqtt_server = "192.198.155.155"; // Имя сервера MQTT
const int mqtt_port = 16835; // Порт для подключения к серверу MQTT
const char *mqtt_user = "у меня нет"; // Логи от сервер
const char *mqtt_pass = "у меня нет"; // Пароль от сервера

#define BUFFER_SIZE 100

bool LedState = false;
int tm=300;
int tmvrem=300; // минута по умолчанию
int tm1=300;
int autom=0; //если 0 - то ручное, если 1 - то автоматическое
int hum_min = 45; //минимальная влажность
int hum_max = 65; //максимальная влажность
float temp=0;
float h,t;
// Функция получения данных от сервера
void callback(const MQTT::Publish& pub){
  Serial.print(pub.topic());   // выводим в сериал порт название топика
  Serial.print(" => ");
  Serial.print(pub.payload_string()); // выводим в сериал порт значение полученных данных
 
  String payload = pub.payload_string();

  if(autom == 0){
    if(String(pub.topic()) == "control/lamp") // проверяем из нужного ли нам топика пришли данные
    {
     int stled = payload.toInt(); // преобразуем полученные данные в тип integer
     digitalWrite(0,stled);  //  включаем или выключаем светодиод в зависимоти от полученных значений данных
     }
  }
  if(String(pub.topic()) == "test/aut1") // проверяем из нужного ли нам топика пришли данные
  {
  autom = payload.toInt(); // преобразуем полученные данные в тип integer
  }
  if(String(pub.topic()) == "test/hmin1") // проверяем из нужного ли нам топика пришли данные
  {
  hum_min = payload.toInt(); // преобразуем полученные данные в тип integer
  }
  if(String(pub.topic()) == "test/hmax1") // проверяем из нужного ли нам топика пришли данные
  {
  hum_max = payload.toInt(); // преобразуем полученные данные в тип integer
  }
  if(String(pub.topic()) == "test/vrem") // проверяем из нужного ли нам топика пришли данные
  {
  tmvrem = payload.toInt(); // преобразуем полученные данные в тип integer
  }    
}

WiFiClient wclient;     
PubSubClient client(wclient, mqtt_server, mqtt_port);

void setup() {
  Serial.begin(115200);
  delay(10);
  Serial.println();
  Serial.println();
  pinMode(12, OUTPUT); // отмечаем, что порт будет ВЫХОДОМ
  dht.begin();        // запускаем библиотеку датчика
}

void loop() {
  TempHum(); // показания с датчиков
   delay(10);
     if(autom == 1){
       RunProg();
     }
  // подключаемся к wi-fi
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Connecting to ");
    Serial.print(ssid);
    Serial.println("...");
    WiFi.begin(ssid, pass);

    if (WiFi.waitForConnectResult() != WL_CONNECTED)
      return;
    Serial.println("WiFi connected");
  }

  // подключаемся к MQTT серверу
  if (WiFi.status() == WL_CONNECTED) {
    if (!client.connected()) {
      Serial.println("Connecting to MQTT server");
      if (client.connect(MQTT::Connect("arduinoClient2")
                         .set_auth(mqtt_user, mqtt_pass))) {
        Serial.println("Connected to MQTT server");
        client.set_callback(callback);
        client.subscribe("control/lamp"); // подписывааемся по топик с данными для светодиода
        client.subscribe("test/aut1");
        client.subscribe("test/hmin1");
        client.subscribe("test/hmax1");
        client.subscribe("test/vrem");
      } else {
        Serial.println("Could not connect to MQTT server");  
      }
    }

    if (client.connected()){ // если есть соединение
      client.loop();
      TempSend(); // Функция отправки показаний с термодатчика
     }
 
}
} // конец основного цикла

// Функция отправки показаний с термодатчика
void TempSend(){
  if (tm==0)
  {
   h = dht.readHumidity();
   t = dht.readTemperature();
   // Read temperature as Celsius (the default)
  client.publish("sensor/temperature",String(t)); // отправляем в топик для термодатчика значение температуры
  Serial.println(t);
  client.publish("sensor/humidity",String(h)); // отправляем в топик для термодатчика значение влажности
  Serial.println(h);
  if(autom == 1){
  client.publish("test/aut","Включена");
  }
  if(autom == 0){
  client.publish("test/aut","Выключена");
  }
  Serial.println(autom);
  tm = tmvrem;  // пауза меду отправками значений
  }
  tm--;
  delay(10); 
}
// чтение данных с датчика, раз в 3с.
void TempHum(){
   if (tm1==0)
  {
     h = dht.readHumidity();
     t = dht.readTemperature();
     tm1 = 300;
  }
   tm1--;
  delay(10);
}
// работа по уставкам
void RunProg(){
  if(h >= hum_max){
    digitalWrite(12,1);  //  выключаем 1 GPIO 0
  }
if(h <= hum_min){
    digitalWrite(12,0);  //  включаем 0  GPIO 0
  }
}
 

Ers

New member
потому как задан тип, и нормальная IDE еще до компиляции это будет учитывать и если что подсказывать. А по размеру - зачем тратить 4 байта на int, если достаточно всего лишь одного.
 

enjoynering

Well-known member
потому как задан тип, и нормальная IDE еще до компиляции это будет учитывать и если что подсказывать. А по размеру - зачем тратить 4 байта на int, если достаточно всего лишь одного.
А где про это прочитать? Я конечно вам верю, но все же хотел послушать маститых теоретиков с примерами. Все что я читал, наоборот советуют использовать #define. А тип переменной если он меньше 32-бит для esp выйгрыша не дает, тк компилятор оставляет дырки - гуглите packing & padding
 
Последнее редактирование:

enjoynering

Well-known member
Прочитал. Кроме проблем с более трудным отлавливанием багов и трюка со скобками я ничего не нашел про уменьшение памяти. Я добавил свои соображения о памяти в прошлый ответ.

еще добавлю - ваша константа будет ПОСТОЯННО висеть в heap памяти, когда define будет подгружаться вместе функцией и уничтожаться после ее завершения освобождая heap. или я не прав? так что по памяти правильнее все таки define
 
Последнее редактирование:

enjoynering

Well-known member
а какой вам еще тайный умысел нужен?
вы написали

удобнее и правильнее по памяти
вот мне стало интересно чего там такого правильного? а в ответ тишина пока. и я там еще в предыдущий ответ добавил. хотелось бы ваших комментариев.
 

Ers

New member
про память я имел ввиду заменить int на byte, не более. А правильного - дополнительная защита от возможности получить багу при использовании define.
 

enjoynering

Well-known member
про память я имел ввиду заменить int на byte, не более. А правильного - дополнительная защита от возможности получить багу при использовании define.
извините что не правильно вас понял.

но еще раз хочу заметить что замена int на byte для esp ничего не даст. тк esp 32 битный и компилятор все равно выделит ячейку в 32 и тупо скажет там теперь 8 бит и 24 никому не нужных нуля, те дырка. читайте тут - alignment and padding. можно заставить компилятор паковать переменные в 32 бита, но тогда падает быстродействие, или я неправ?

вот на 8 битных atmel там такие трюки - замена int на byte, дают выйгрыш.

в общем я увидел только одно достоинство - новичку лучше работать с constant тк по незнанию может наворотить с define. тем же кто понимает макросы лучше constant не использовать.
главный минус - константа будет ПОСТОЯННО висеть в heap памяти, когда define будет подгружаться вместе функцией и уничтожаться после ее завершения освобождая heap.

или я не прав? рассудите нас гуру C++.
 
Последнее редактирование:
Сверху Снизу