From ddacdedd4976aacb16db752829af9ed33fef4ec8 Mon Sep 17 00:00:00 2001 From: vlapa Date: Sat, 13 Jun 2026 18:10:53 +0300 Subject: First --- .gitignore | 5 + .vscode/extensions.json | 10 ++ platformio.ini | 21 +++ src/main.cpp | 345 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 381 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 platformio.ini create mode 100644 src/main.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..16499d5 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,21 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:d1_mini] +platform = espressif8266 +board = d1_mini +framework = arduino + +upload_speed = 460800 ;921600 +monitor_speed = 115200 + +lib_deps = + arduino-libraries/NTPClient + knolleary/PubSubClient \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..6dedfcc --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,345 @@ +#include +#include +#include +#include +#include +#include +#include + +#define PIN_RELAY D1 + +// Время работы (более понятные имена) +const uint8_t DAY_START_HOUR = 7; // Начало дня +const uint8_t NIGHT_START_HOUR = 23; // Начало ночи +const uint8_t DAY_WORK_MINUTES = 10; // Дневной интервал (минут) +const uint8_t NIGHT_WORK_MINUTES = 20; // Ночной интервал (минут) +const uint8_t DAY_START_MINUTE = 25; // Старт дневного интервала + +// Ночные интервалы (для ясности) +const uint8_t NIGHT_INTERVAL1_START = 0; +const uint8_t NIGHT_INTERVAL2_START = 40; + +// Интервал синхронизации (сейчас 30 минут для тестирования?) +const uint32_t SYNC_INTERVAL_MS = 30 * 60 * 1000; // 30 минут + +// const char *ssid = "link"; +const char *ssid = "MikroTik-2"; +const char *pass = "dkfgf#*12091997"; +const char *ntp_server = "ntp3.vniiftri.ru"; +const char *host = "89.110.92.137"; +const uint16_t port = 8000; +const char *address_page = "/"; + +const uint32_t utcOffsetInSeconds = 10800; +const uint32_t utcPeriodMseconds = 30 * 60 * 1000; // 86400000-р/сут; 604800000-р/нед +uint32_t lastSync = 0; + +WiFiUDP ntpUDP; +NTPClient timeClient(ntpUDP, ntp_server, utcOffsetInSeconds, utcPeriodMseconds); + +const uint16_t TIME_SLEEP = 60000; +const uint8_t NUMBER_OF_ATTEMPTS = 20; +bool flagBegining = true; + +const char *mqtt_client = "esp8266-761924"; +const char *mqtt_client2 = "Villa_Septik"; +const char *mqtt_user = "mqtt"; +const char *mqtt_pass = "qwe1243"; +const char *mqtt_server = "89.110.92.137"; +const char *mqtt_port = "1883"; +const char *outTopicData = "/data"; + +ESP8266WebServer server(80); +ESP8266HTTPUpdateServer httpUpdater; + +WiFiClient espClient; +PubSubClient client(espClient); + +//----------------------------------- +inline bool mqtt_subscribe(PubSubClient &client, const String &topic) +{ + Serial.print("Subscribing to: "); + Serial.println(topic); + return client.subscribe(topic.c_str()); +} + +//----------------------------------- +inline bool mqtt_publish(PubSubClient &client, const String &topic, const String &value) +{ + Serial.print(topic); + Serial.print(" = "); + Serial.println(value); + return client.publish(topic.c_str(), value.c_str()); +} + +//----------------------------------- +void mqttDataOut(uint8_t a) +{ + String topic, topicValue; + + topic = "/"; + topic += mqtt_client2; + topic += outTopicData; + topicValue = a; + topicValue += ";;;;"; + + uint8_t count = NUMBER_OF_ATTEMPTS; + while (!mqtt_publish(client, topic, topicValue) && count--) + { + mqtt_publish(client, topic, topicValue); + delay(500); + } +} + +//----------------------------------- +bool setupMQTT() +{ + client.setServer(mqtt_server, String(mqtt_port).toInt()); + + Serial.print("MQTT connect : "); + Serial.println(mqtt_server); + + uint8_t count = NUMBER_OF_ATTEMPTS; + while (!(client.connect(mqtt_client, mqtt_user, mqtt_pass)) && count--) + { + Serial.print(count); + Serial.print('>'); + delay(500); + } + + if (client.connected()) + { + Serial.println("MQTT connected - OK !"); + return true; + } + else + { + return false; + } +} + +//=========================================== +// подключение к WiFi +bool setupWiFi() +{ + digitalWrite(LED_BUILTIN, LOW); + Serial.println("\n\nSetup WiFi: "); + + WiFi.begin(ssid, pass); + uint8_t count = NUMBER_OF_ATTEMPTS; + while (WiFi.status() != WL_CONNECTED) + { + Serial.print(count); + Serial.print('>'); + if (!count--) + return false; + delay(500); + } + digitalWrite(LED_BUILTIN, HIGH); + + //----------------------------------- + // индикация IP + Serial.print("\nWiFi connected !\nIP: "); + Serial.println(WiFi.localIP()); + + //----------------------------------- + // индикация силы сигнала + int8_t RSSI_MAX = -50; + int8_t RSSI_MIN = -100; + int8_t dBm = WiFi.RSSI(); + Serial.print("RSSI dBm = "); + Serial.println(dBm); + String l = ""; + (dBm <= RSSI_MIN) ? l += 0 : (dBm >= RSSI_MAX) ? l += 100 + : l += 2 * (dBm + 100); + Serial.print("RSSI % = "); + Serial.println(l); + + return true; +} + +//=========================================== +// синхронизация с NTP: +bool syncNTP() +{ + Serial.println("\nСинхронизируем время: "); + uint8_t count = NUMBER_OF_ATTEMPTS; + while (!timeClient.update()) + { + Serial.print(count); + Serial.print('.'); + if (!count--) + return false; + delay(500); + } + Serial.println(timeClient.getFormattedTime()); + + return true; +} + +//=========================================== +// Проверка валидности времени: +bool isTimeValid() +{ + // Проверяем, что время получено (не эпоха 1970 года) + return timeClient.getEpochTime() > 1000000; +} + +bool calculateRelayState() +{ + uint8_t h = timeClient.getHours(); + uint8_t m = timeClient.getMinutes(); + + // Дневной режим + if (h >= DAY_START_HOUR && h < NIGHT_START_HOUR) + { + return (m >= DAY_START_MINUTE && + m < DAY_START_MINUTE + DAY_WORK_MINUTES); + } + + // Ночной режим + if (m < NIGHT_WORK_MINUTES) // Первый интервал + return true; + + if (m >= NIGHT_INTERVAL2_START && + m < NIGHT_INTERVAL2_START + NIGHT_WORK_MINUTES) // Второй интервал + return true; + + return false; +} + +void controlRelay() +{ + static bool lastRelayState = false; + bool newRelayState = calculateRelayState(); + + if (newRelayState != lastRelayState) + { + if (setupMQTT()) + { + mqttDataOut(newRelayState); + Serial.println("Данные успешно отправлены"); + } + digitalWrite(PIN_RELAY, newRelayState ? HIGH : LOW); + Serial.printf("Реле %s в %02d:%02d\n", + newRelayState ? "ВКЛ" : "ВЫКЛ", + timeClient.getHours(), + timeClient.getMinutes()); + lastRelayState = newRelayState; + } +} + +// void goToDeepSleep() +// { +// Serial.println("Переход в глубокий сон на 1 минуту..."); +// server.close(); // Закрываем сервер перед сном +// delay(100); +// // Настраиваем пробуждение через TIME_SLEEP миллисекунд +// ESP.deepSleep(TIME_SLEEP * 1000); // deepSleep принимает микросекунды! +// } + +//=========================================== +void setup() +{ + Serial.begin(115200); + + pinMode(PIN_RELAY, OUTPUT); + digitalWrite(PIN_RELAY, LOW); + + timeClient.begin(); + + server.begin(); + httpUpdater.setup(&server); + + lastSync = millis(); +} + +//=========================================== +void loop() +{ + // Синхронизация времени + if (millis() - lastSync >= SYNC_INTERVAL_MS || flagBegining) + { + if (setupWiFi()) + { + if (syncNTP()) + { + Serial.println("Время успешно синхронизировано"); + } + } + + // Всегда отключаем Wi-Fi после синхронизации + // WiFi.disconnect(); + // delay(100); + // WiFi.mode(WIFI_OFF); + // Serial.println("\nWi-Fi отключен для экономии энергии"); + + lastSync = millis(); + flagBegining = false; + } + + // Управление реле только если время валидно + if (isTimeValid()) + { + controlRelay(); + } + + // if (!flagBegining && WiFi.getMode() == WIFI_OFF) + // { + // goToDeepSleep(); + // } + + server.handleClient(); + delay(10); +} + +// if (millis() - lastSync >= utcPeriodMseconds || flagBegining) +// { +// if (setupWiFi()) +// syncNTP(); +// WiFi.disconnect(); // Отключаемся от роутера +// delay(100); // Небольшая задержка для завершения процесса +// WiFi.mode(WIFI_OFF); // Полностью выключаем Wi-Fi +// Serial.println("Wi-Fi отключен."); +// lastSync = millis(); +// } + +// //----------------------------- +// // Работа по дневному тарифу: +// if (timeClient.getHours() >= TIME_DAY && timeClient.getHours() < TIME_NIGHT) +// { +// if (timeClient.getMinutes() >= TIME_BEGINNING_DAY && timeClient.getMinutes() < TIME_BEGINNING_DAY + TIME_WORK_DAY_MINUT) +// digitalWrite(PIN_RELAY, HIGH); +// } +// else +// { +// digitalWrite(PIN_RELAY, LOW); +// } + +// //----------------------------- +// // Работа по ночному тарифу: +// if (timeClient.getHours() >= TIME_NIGHT && timeClient.getHours() < TIME_DAY) +// { +// if (timeClient.getMinutes() >= 0 && timeClient.getMinutes() < TIME_WORK_NIGHT_MINUT) +// { +// digitalWrite(PIN_RELAY, HIGH); +// } +// else +// { +// digitalWrite(PIN_RELAY, LOW); +// } + +// if (timeClient.getMinutes() >= 40 && timeClient.getMinutes() < 40 + TIME_WORK_NIGHT_MINUT) +// { +// digitalWrite(PIN_RELAY, HIGH); +// } +// else +// { +// digitalWrite(PIN_RELAY, LOW); +// } +// } + +// server.handleClient(); +// delay(10); + +//=========================================== -- cgit v1.2.3