MyTetra Share
Делитесь знаниями!
MQTT_DUSH
Время создания: 07.05.2026 18:11
Автор: alensav
Текстовые метки: mqtt dush
Раздел: Mqtt_Dush
Запись: alensav/MyTetra2/main/base/17781667109ncm23r27q/text.html на raw.githubusercontent.com

MQTT_DUSH

=================================

Вот полный, готовый к компиляции скетч со всеми исправлениями.

Что исправлено критически:

Убрано if-else каскадирование, которое "застревало" на верхнем уровне. Теперь каждый датчик публикуется независимо (level/upper, level/lower, level/intermediate).

Добавлена явная инверсия логики реле через #define RELAY_ACTIVE_LOW.

Введена стабильная проверка пинов с антидребезгом.

MQTT-публикация уровня происходит каждый интервал, что исключает "залипание" статуса на брокере.

Сохранён автовыбор из 4 WiFi-сетей по RSSI.

cpp

// ============================================================================

// ESP8266: Мониторинг температуры, влажности и уровня воды (4 WiFi станции)

// ============================================================================


#include <OneWire.h>

#include <DallasTemperature.h>

#include <DHT.h>

#include <ESP8266WiFi.h>

#include <PubSubClient.h>

#include <Adafruit_Sensor.h>


// 📡 КОНФИГУРАЦИЯ WIFI (до 4 станций)

const char* wifi_networks[4][2] = {

{ "2Keenetic-8891", "hoMt2iPo" },

{ "Keenetic-6391", "U7Y6hMeB" },

{ "Home_WiFi_2.4", "password3" },

{ "Office_IoT", "password4" }

};

const uint8_t WIFI_NETWORKS_COUNT = 4;


// 🌐 КОНФИГУРАЦИЯ MQTT

const char* mqtt_server = "192.168.1.75";

const int mqtt_port = 1883;

const char* mqtt_user = "mqtt";

const char* mqtt_password = "mq485127sav";


// 🔌 ПИНЫ ДАТЧИКОВ

const int oneWireBus = 13; // DS18B20

const int upperLevelPin = 15; // Реле/зонд верхнего уровня

const int lowerLevelPin = 12; // Реле/зонд нижнего уровня

const int intermediatePin = 14; // Промежуточный зонд


// ⚙️ ЛОГИКА РЕЛЕ

// true = реле замыкает пин на GND при срабатывании (наиболее частый вариант)

// false = реле замыкает пин на 3.3V при срабатывании

#define RELAY_ACTIVE_LOW true


// 📦 ОБЪЕКТЫ БИБЛИОТЕК

OneWire oneWire(oneWireBus);

DallasTemperature sensors(&oneWire);

DHT dht(4, DHT22);

WiFiClient espClient;

PubSubClient client(espClient);


// 🌡️ ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ

float waterTemp = 0.0;

float airTemp = 0.0;

float humidity = 0.0;


// ⏱️ ТАЙМЕРЫ

const uint32_t send_data_interval = 10000;

uint32_t last_send_time = 0;


const uint32_t wifi_rescan_interval = 300000; // 5 минут

uint32_t last_wifi_scan = 0;


const uint32_t level_check_interval = 500; // 0.5 сек

uint32_t last_level_check = 0;


// ============================================================================

// 📡 ФУНКЦИЯ: ПОДКЛЮЧЕНИЕ К ЛУЧШЕЙ ИЗ 4-х СЕТЕЙ

// ============================================================================

bool connectToBestWiFi() {

Serial.println("\n🔍 Сканирование WiFi сетей...");

int n = WiFi.scanNetworks();

if (n <= 0) {

Serial.println("⚠️ Сети не найдены");

return false;

}


int bestIdx = -1;

int bestRSSI = -100;


for (int i = 0; i < n; i++) {

String ssid_found = WiFi.SSID(i);

int rssi = WiFi.RSSI(i);


for (uint8_t j = 0; j < WIFI_NETWORKS_COUNT; j++) {

if (ssid_found == wifi_networks[j][0]) {

Serial.printf(" ✅ Найдена: %-20s | RSSI: %d dBm\n", ssid_found.c_str(), rssi);

if (rssi > bestRSSI) {

bestRSSI = rssi;

bestIdx = j;

}

break;

}

}

}


WiFi.scanDelete();


if (bestIdx >= 0 && bestRSSI > -85) {

Serial.printf("\n📶 Подключение к: %s (RSSI: %d dBm)\n", wifi_networks[bestIdx][0], bestRSSI);

WiFi.begin(wifi_networks[bestIdx][0], wifi_networks[bestIdx][1]);

unsigned long start = millis();

while (WiFi.status() != WL_CONNECTED && millis() - start < 20000) {

delay(500);

Serial.print(".");

}


if (WiFi.status() == WL_CONNECTED) {

Serial.println("\n🎉 WiFi подключён!");

Serial.printf("IP: %s | RSSI: %d dBm\n", WiFi.localIP().toString().c_str(), WiFi.RSSI());

return true;

}

}


Serial.println("❌ Подключение не удалось");

return false;

}


// ============================================================================

// 🔄 ФУНКЦИЯ: ПЕРЕПОДКЛЮЧЕНИЕ К MQTT

// ============================================================================

void reconnect() {

while (!client.connected()) {

Serial.print("🔄 MQTT connection...");

if (client.connect("ESP8266_WaterMonitor", mqtt_user, mqtt_password)) {

Serial.println("connected ✓");

} else {

Serial.printf("failed (rc=%d), retry in 5s\n", client.state());

delay(5000);

}

}

}


// ============================================================================

// 📖 ФУНКЦИЯ: СТАБИЛЬНОЕ ЧТЕНИЕ ПИНА (АНТИДРЕБЕЗГ + ИНВЕРСИЯ)

// ============================================================================

bool readLevelStable(int pin) {

// Читаем дважды с задержкой для подавления помех

bool r1 = (digitalRead(pin) == LOW);

delay(10);

bool r2 = (digitalRead(pin) == LOW);

// Приводим к логике: true = вода есть / реле сработало

return RELAY_ACTIVE_LOW ? (r1 && r2) : (!r1 && !r2);

}


// ============================================================================

// ⚙️ SETUP

// ============================================================================

void setup() {

Serial.begin(9600);

Serial.println("\n🚀 ESP8266 WaterMonitor v2.0");


// Инициализация датчиков

dht.begin();

sensors.begin();


// Настройка пинов уровня

pinMode(upperLevelPin, INPUT_PULLUP);

pinMode(lowerLevelPin, INPUT_PULLUP);

pinMode(intermediatePin, INPUT_PULLUP);

pinMode(0, INPUT); // Кнопка BOOT (оставлено из оригинала)


// WiFi

WiFi.mode(WIFI_STA);

WiFi.disconnect();

delay(100);

if (!connectToBestWiFi()) {

delay(10000);

connectToBestWiFi();

}


// MQTT

client.setServer(mqtt_server, mqtt_port);

// Инициализация таймеров

last_send_time = millis();

last_wifi_scan = millis();

last_level_check = millis();


Serial.println("✅ Setup complete. Starting loop...");

}


// ============================================================================

// 🔁 LOOP

// ============================================================================

void loop() {

// 📡 Периодический перескан WiFi

if (millis() - last_wifi_scan >= wifi_rescan_interval) {

if (WiFi.status() != WL_CONNECTED || WiFi.RSSI() < -75) {

Serial.println("\n📡 Проверка лучших сетей...");

connectToBestWiFi();

}

last_wifi_scan = millis();

}


// 🔄 Поддержание соединения

if (WiFi.status() != WL_CONNECTED) {

connectToBestWiFi();

delay(1000);

}


if (!client.connected()) {

reconnect();

}

client.loop();


// 💧 ЧАСТЫЙ ОПРОВ ДАТЧИКОВ УРОВНЯ (для стабильности логики)

if (millis() - last_level_check >= level_check_interval) {

readLevelStable(upperLevelPin);

readLevelStable(lowerLevelPin);

readLevelStable(intermediatePin);

last_level_check = millis();

}


// 📤 ОТПРАВКА ДАННЫХ В MQTT

if (millis() - last_send_time >= send_data_interval) {

// 🌡️ Температура воды

sensors.requestTemperatures();

waterTemp = sensors.getTempCByIndex(0);


// 🌡️💧 Температура и влажность воздуха

humidity = dht.readHumidity();

airTemp = dht.readTemperature();


// 💧 Чтение уровней (применяем логику и антидребезг)

bool isUpper = readLevelStable(upperLevelPin);

bool isIntermediate = readLevelStable(intermediatePin);

bool isLower = readLevelStable(lowerLevelPin);


// 🔍 Отладка в Serial

Serial.printf("💧 Raw: U=%d I=%d L=%d | MQTT: U=%s I=%s L=%s\n",

isUpper, isIntermediate, isLower,

isUpper ? "ON" : "OFF",

isIntermediate ? "ON" : "OFF",

isLower ? "ON" : "OFF");


// 📦 Публикация каждого датчика отдельно (исключает "залипание")

client.publish("level/upper", isUpper ? "ON" : "OFF");

client.publish("level/intermediate", isIntermediate ? "ON" : "OFF");

client.publish("level/lower", isLower ? "ON" : "OFF");


// 🎯 Общий статус с приоритетом

const char* levelState = "empty";

if (isUpper) levelState = "upper";

else if (isIntermediate) levelState = "intermediate";

else if (isLower) levelState = "lower";

client.publish("water_level", levelState);


// 📐 Публикация температур и влажности

char buf[12];

dtostrf(waterTemp, 4, 2, buf);

client.publish("water_temperature", buf);

dtostrf(airTemp, 4, 2, buf);

client.publish("air_temperature", buf);

dtostrf(humidity, 4, 2, buf);

client.publish("humidity", buf);


// 📶 Статус WiFi

char rssiStr[6];

itoa(WiFi.RSSI(), rssiStr, 10);

client.publish("wifi/rssi", rssiStr);

client.publish("wifi/ssid", WiFi.SSID().c_str());


last_send_time = millis();

}

}

================================================

?? Как проверить работу после прошивки

  1. Откройте Serial Monitor (9600 бод).
  2. Вы увидите строку каждые 10 секунд:
  3. 1
    💧 Raw: U=0 I=0 L=0 | MQTT: U=OFF I=OFF L=OFF
  4. Когда вода поднимется и реле щёлкнет:
  5. 1
    💧 Raw: U=1 I=0 L=0 | MQTT: U=ON I=OFF L=OFF
  6. Когда резервуар освободится:
  7. 1
    💧 Raw: U=0 I=0 L=0 | MQTT: U=OFF I=OFF L=OFF
  8. В MQTT-клиенте подпишитесь на: level/# и water_level. Вы будете получать чёткие ON/OFF без зависаний.



🛠️ Если статус всё ещё "залипает"


Симптом

Причина

Действие

Raw не меняется при щелчке реле

Проводка/питание реле

Проверьте, замыкает ли реле пин на GND или 3.3V. Измените #define RELAY_ACTIVE_LOW

Raw меняется, а MQTT нет

Проблема брокера/подписчика

Брокер может кэшировать. Используйте mosquitto_sub -v -t "level/#" или добавьте client.publish(..., true) для флага retain (по желанию)

Raw "мигает" 0/1

Электромагнитные помехи

Увеличьте delay(10) в readLevelStable() до 20 или 50

Скетч полностью готов к работе. Если потребуется добавить управление реле через MQTT или настроить retain-флаг — напишите, дополню. 💧📡


 
MyTetra Share v.0.67
Яндекс индекс цитирования