summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvlapa <vlapa@ya.ru>2026-07-15 01:11:18 +0300
committervlapa <vlapa@ya.ru>2026-07-15 01:11:18 +0300
commitc555a32f61656fda2a7c7424c199efcadc17aca6 (patch)
tree12eacf246f621d471adab8f1baee8a6da0336e06
-rw-r--r--.gitignore3
-rw-r--r--include/tablo_ws2812-old.h312
-rw-r--r--include/tablo_ws2812.h242
-rw-r--r--platformio.ini21
-rw-r--r--src/config-source.h40
-rw-r--r--src/main.cpp474
6 files changed, 1092 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0f734d6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.pio
+.vscode
+config.h
diff --git a/include/tablo_ws2812-old.h b/include/tablo_ws2812-old.h
new file mode 100644
index 0000000..019acaf
--- /dev/null
+++ b/include/tablo_ws2812-old.h
@@ -0,0 +1,312 @@
+/*=========================================================
+ Tablo ws2812
+ = vlapa = v.509
+ 2021.02.01 - 2023.11.14
+=========================================================*/
+#pragma once
+
+#define PIXEL_PIN 20 //D2
+#define RAZR_PIXEL 22
+
+const uint8_t digit = 5; // кол-во разрядов табло
+#define PIXEL_COUNT RAZR_PIXEL * digit
+
+#include <Adafruit_NeoPixel.h>
+Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
+
+//********************************************************************
+// плата
+void visibleWork(const String& visData, uint32_t color, uint8_t bright)
+
+{ // данные, цвет
+ strip.setBrightness(bright);
+
+ for (uint8_t razr = 0; razr < digit; ++razr)
+ {
+ uint8_t x;
+ if (visData.charAt(razr) == 'A')
+ {
+ x = 10;
+ }
+ else if (visData.charAt(razr) == 'B')
+ {
+ x = 11;
+ }
+ else if (visData.charAt(razr) == 'C')
+ {
+ x = 12;
+ }
+ else if (visData.charAt(razr) == 'D')
+ {
+ x = 13;
+ }
+ else if (visData.charAt(razr) == 'E')
+ {
+ x = 14;
+ }
+ else if (visData.charAt(razr) == 'p')
+ {
+ x = 15;
+ }
+ else if (visData.charAt(razr) == 'h')
+ {
+ x = 16;
+ }
+ else
+ {
+ x = visData.substring(razr, razr + 1).toInt();
+ }
+
+ switch (x)
+ {
+ case 0:
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if (i >= 0 && i < 36)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 1:
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if (i > 11 && i < 24)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 2:
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i > 5 && i < 18) || (i > 23 && i < 42))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 3:
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i > 5 && i < 30) || (i > 36 && i < 42))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 4:
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i >= 0 && i < 6) || (i > 11 && i < 24) || (i > 35 && i < 42))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 5:
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i >= 0 && i < 12) || (i > 17 && i < 30) || (i > 35 && i < 42))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 6:
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i >= 0 && i < 12) || (i > 17 && i < 42))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 7:
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if (i > 5 && i < 24)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 8:
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ break;
+ case 9:
+ for (int i = 0; i < RAZR_PIXEL; i++)
+ {
+ if ((i >= 0 && i < 30) || (i > 35 && i < 42))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 10: // градус ( A )
+ for (int i = 0; i < RAZR_PIXEL; i++)
+ {
+ if ((i >= 0 && i < 18) || (i > 35 && i < 42))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 11: // минус ( B )
+ for (int i = 0; i < RAZR_PIXEL; i++)
+ {
+ if ((i > 35) && (i < 42))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 12: // двоеточие ( C )
+ for (int i = 0; i < RAZR_PIXEL; i++)
+ {
+ if ((i == 36) || (i == 37) || (i == 40) || (i == 41))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 13: // null (пусто) ( D )
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ break;
+ case 14: // точка ( E )
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i == 26) || (i == 27))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 15: // давление ( p )
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i < 18) || (i > 29))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 16: // влажность ( h )
+ for (int i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i < 6) || (i > 17 && i < 24) || (i > 29))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ }
+ }
+ strip.show();
+}
+
+//********************************************************************
+// Эффекты табло:
+// void visible_effect()
+// {
+// uint8_t a, b, c;
+// for (uint8_t k = 0; k < 3; ++k)
+// {
+// (k == 0) ? a = 255 : b = c = 0;
+// (k == 1) ? b = 255 : a = c = 0;
+// (k == 2) ? c = 255 : b = a = 0;
+
+// for (uint8_t i = 0; i < PIXEL_COUNT; ++i)
+// {
+// // uint32_t col = 255;
+// for (uint8_t i = 0; i < PIXEL_COUNT; ++i)
+// {
+// // uint32_t col = random(200, 65535);
+// strip.setPixelColor(i, strip.Color(a, b, c));
+// strip.show();
+// delay(10);
+// }
+// }
+// }
+
+// // for (uint8_t i = 0; i < PIXEL_COUNT; ++i)
+// // {
+// // uint32_t col = random(200, 65535);
+// // strip.setPixelColor(i, col);
+// // strip.show();
+// // delay(10);
+// // }
+// delay(1000);
+
+// for (uint8_t i = 0; i < PIXEL_COUNT; ++i)
+// {
+// strip.setPixelColor(i, 0);
+// strip.show();
+// }
+// } \ No newline at end of file
diff --git a/include/tablo_ws2812.h b/include/tablo_ws2812.h
new file mode 100644
index 0000000..5901849
--- /dev/null
+++ b/include/tablo_ws2812.h
@@ -0,0 +1,242 @@
+/*=========================================================
+ Tablo ws2812_22ledX5
+ 2026.02.21 -
+
+ A - градус
+ В - минус
+ С - двоеточие
+ D - пусто
+ E - точка
+ F - p
+ G - h
+=========================================================*/
+#pragma once
+
+#define PIXEL_PIN 5
+#define RAZR_PIXEL 22
+#define PIXEL_COUNT 110
+#define DIGIT 5
+
+#include <Adafruit_NeoPixel.h>
+Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
+
+//********************************************************
+// "Перевод" данных в пиксели:
+void visibleWork(String visData, uint32_t color, uint8_t bright)
+{
+ // Serial.println(visData);
+ strip.setBrightness(bright);
+ for (uint8_t razr = 0; razr < DIGIT; ++razr)
+ {
+ uint8_t temp;
+ if (visData.charAt(razr) == 'A')
+ {
+ temp = 10;
+ }
+ else if (visData.charAt(razr) == 'B')
+ {
+ temp = 11;
+ }
+ else if (visData.charAt(razr) == 'C')
+ {
+ temp = 12;
+ }
+ else if (visData.charAt(razr) == 'D')
+ {
+ temp = 13;
+ }
+ else if (visData.charAt(razr) == 'E')
+ {
+ temp = 14;
+ }
+ else
+ {
+ temp = visData.substring(razr, razr + 1).toInt();
+ }
+ switch (temp)
+ {
+ case 0:
+ for (uint8_t i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if (i >= 0 && i < 20)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 1:
+ for (uint8_t i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if (i > 4 && i < 13)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 2:
+ for (uint8_t i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i > 1 && i < 9) || (i > 11 && i < 22))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 3:
+ for (uint8_t i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i > 1 && i < 16) || (i == 20 || i == 21))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 4:
+ for (uint8_t i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i >= 0 && i < 3) || (i > 4 && i < 13) || (i > 18 && i < 22))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 5:
+ for (uint8_t i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i >= 0 && i < 6) || (i > 7 && i < 16) || (i > 18 && i < 22))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 6:
+ for (uint8_t i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if ((i >= 0 && i < 6) || (i > 7 && i < 22))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 7:
+ for (uint8_t i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if (i > 1 && i < 13)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 8:
+ for (uint8_t i = 0; i < RAZR_PIXEL; ++i)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ break;
+ case 9:
+ for (uint8_t i = 0; i < RAZR_PIXEL; i++)
+ {
+ if ((i >= 0 && i < 16) || (i > 18 && i < 22))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 10: // градус ( A )
+ for (uint8_t i = 0; i < RAZR_PIXEL; i++)
+ {
+ if (i == 0 || i == 1 || i == 3 || i == 4 || i == 6 || i == 7 ||
+ i == 20 || i == 21)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 11: // минус ( B )
+ for (uint8_t i = 0; i < RAZR_PIXEL; i++)
+ {
+ if (i == 8 || (i > 18 && i < 22))
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 12: // двоеточие ( C ) короткое тире
+ for (uint8_t i = 0; i < RAZR_PIXEL; i++)
+ {
+ if (i == 20 || i == 21)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ case 13: // null (пусто) ( D )
+ for (uint8_t i = 0; i < RAZR_PIXEL; ++i)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ break;
+ case 14: // точка ( E )
+ for (uint8_t i = 0; i < RAZR_PIXEL; ++i)
+ {
+ if (i == 13 || i == 14)
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, color);
+ }
+ else
+ {
+ strip.setPixelColor(i + razr * RAZR_PIXEL, strip.Color(0, 0, 0));
+ }
+ }
+ break;
+ }
+ }
+} \ No newline at end of file
diff --git a/platformio.ini b/platformio.ini
new file mode 100644
index 0000000..0da2ce3
--- /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 = 921600
+monitor_speed = 115200
+
+lib_deps =
+ adafruit/Adafruit NeoPixel
+ arduino-libraries/NTPClient
diff --git a/src/config-source.h b/src/config-source.h
new file mode 100644
index 0000000..628439d
--- /dev/null
+++ b/src/config-source.h
@@ -0,0 +1,40 @@
+//////////////////////////////////////////////////////////
+//
+// Файл нужно заполнить и переименовать в config.h !!!
+//
+/////////////////////////////////////////////////////////
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+// WiFi настройки:
+static const char *WIFI_SSID = "";
+static const char *WIFI_PASS = "";
+
+// NTP настройки:
+static const char *NTP_SERVER = "1.ru.pool.ntp.org"; // "ntp3.vniiftri.ru";
+
+// Серверные настройки:
+static const char *SERVER_HOST = "";
+static const int SERVER_PORT = 8000;
+static const char *SERVER_PATH = "/";
+
+// Настройки табло
+static const uint8_t TIME_DAY = 8;
+static const uint8_t TIME_NIGHT = 18;
+static const uint8_t BRIGHT_DAY = 4;
+static const uint8_t BRIGHT_NIGHT = 1;
+
+// Названия датчиков
+static const char* SENSOR_1 = ""; // улица
+static const char* SENSOR_2 = ""; // комната
+
+// Цвета (можно вынести для удобства)
+static const uint32_t COLOR_TIME = 16766720; // желтый
+static const uint32_t COLOR_TEMP = 16711935; // красный
+static const uint32_t COLOR_TEMP_OUT = 9127187; // коричневый
+static const uint32_t COLOR_PRESS = 9830400; // розовый
+static const uint32_t COLOR_WIFI = 16728935; // томато
+static const uint32_t COLOR_HUM = 52945; // бирюзовый
+
+#endif \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..51cfe96
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,474 @@
+/////////////////////////////////////////////////
+//
+// 2026-06-12 ... 2026-07-08 v.012
+//
+/////////////////////////////////////////////////
+#include <Arduino.h>
+#include <ESP8266WiFi.h>
+#include <ESP8266HTTPUpdateServer.h>
+#include <NTPClient.h>
+#include <WiFiUdp.h>
+#include <ESP8266HTTPClient.h>
+#include <Adafruit_NeoPixel.h>
+
+#include "config.h"
+#include "tablo_ws2812.h"
+
+const uint32_t utcOffsetInSeconds = 10800;
+const uint32_t utcPeriodMseconds = 86400000; // 86400000-р/сут
+
+WiFiUDP ntpUDP;
+NTPClient timeClient(ntpUDP, NTP_SERVER, utcOffsetInSeconds, utcPeriodMseconds);
+
+String sensorKeys;
+
+WiFiClient espClient;
+HTTPClient http;
+
+uint32_t timeUpdateH = 02; // время обновления NTP
+uint32_t timeUpdateM = 05; // время обновления NTP
+String z = ""; // строка данных для отображения
+
+bool flagVis = true;
+bool flagSec = true;
+uint8_t brightVis = 0;
+uint32_t timeReadOld = 0;
+uint8_t visData[] = {5, 2, 2, 2, 2};
+uint8_t displayMode = 0;
+unsigned long lastModeSwitch = 0;
+
+unsigned long lastHTTPRequest = 0;
+const unsigned long HTTP_UPDATE_INTERVAL = 60000; // Обновляем раз в минуту
+
+struct
+{
+ float temp_in = 0.0;
+ uint16_t pres = 0;
+ uint8_t hum = 0;
+ float temp_out = 0.0;
+} dataSensors;
+
+const uint8_t NUMBER_OF_ATTEMPTS = 20;
+
+ESP8266WebServer server(80);
+ESP8266HTTPUpdateServer httpUpdater;
+
+//===================================================
+// подключение к WiFi
+bool setupWiFi()
+{
+ z = "ABABA";
+ visibleWork(z, COLOR_WIFI, BRIGHT_DAY);
+ strip.show();
+
+ digitalWrite(LED_BUILTIN, LOW);
+ Serial.println("\n\nSetup WiFi: ");
+
+ WiFi.begin(WIFI_SSID, WIFI_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
+ z = "DDDDD";
+ visibleWork(z, COLOR_WIFI, BRIGHT_DAY);
+ strip.show();
+ String l = WiFi.localIP().toString();
+ l = l.substring(l.lastIndexOf('.') + 1, l.length());
+ (l.toInt() < 100) ? l = "DDE" + l : l = "DE" + l;
+ visibleWork(l, COLOR_WIFI, BRIGHT_DAY);
+ strip.show();
+ Serial.print("\nWiFi connected !\nIP: ");
+ Serial.println(WiFi.localIP());
+ delay(2000);
+ visibleWork("DDDDD", COLOR_WIFI, BRIGHT_DAY);
+ strip.show();
+
+ //-----------------------------------
+ // индикация силы сигнала
+ int8_t RSSI_MAX = -50;
+ int8_t RSSI_MIN = -100;
+ int8_t dBm = WiFi.RSSI();
+ Serial.print("RSSI dBm = ");
+ Serial.println(dBm);
+ l = "";
+ (dBm <= RSSI_MIN) ? l += 0 : (dBm >= RSSI_MAX) ? l += 100
+ : l += 2 * (dBm + 100);
+ Serial.print("RSSI % = ");
+ Serial.println(l);
+ Serial.println();
+ (l.toInt() < 100) ? l = "DDE" + l : l = "DE" + l;
+
+ visibleWork(l, COLOR_WIFI, BRIGHT_DAY);
+ strip.show();
+ delay(2000);
+ visibleWork("DDDDD", COLOR_WIFI, BRIGHT_DAY);
+ strip.show();
+
+ return true;
+}
+
+//===================================================
+// синхронизация с NTP:
+bool setupNTP()
+{
+ 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();
+ Serial.println(timeClient.getFormattedTime());
+ Serial.println();
+
+ return true;
+}
+
+//===================================================
+// Запрос POST на сервер:
+String http_response()
+{
+ String payload;
+ String url = "http://" + String(SERVER_HOST) + ":" + String(SERVER_PORT) + SERVER_PATH;
+
+ Serial.println("Sending POST to: " + url);
+ Serial.println("Data: " + sensorKeys);
+
+ http.begin(espClient, url);
+ http.addHeader("Content-Type", "text/plain");
+ http.setTimeout(5000);
+
+ // Отправляем POST с нашими ключами
+ int httpCode = http.POST(sensorKeys);
+
+ // Анализируем ответ
+ if (httpCode == HTTP_CODE_OK)
+ {
+ Serial.printf("Response code: %d\n", httpCode);
+ payload = http.getString();
+ Serial.println("Server response: \n" + payload);
+ http.end();
+ return payload;
+ }
+ else
+ {
+ Serial.printf("POST failed, error: %s\n",
+ http.errorToString(httpCode).c_str());
+ http.end();
+ return ""; // Возвращаем пустую строку при ошибке
+ }
+}
+
+//===================================================
+// Парсим ответ сервера:
+bool parse_data_http(String data)
+{
+ if (data.length() == 0)
+ {
+ Serial.println("Warning: Empty data received");
+ return false;
+ }
+
+ // Находим все разделители для первой части (до первой *)
+ int idx1 = data.indexOf(';'); // после temp_in
+ int idx2 = data.indexOf(';', idx1 + 1); // после pres
+ int idx3 = data.indexOf(';', idx2 + 1); // после hum
+
+ // Находим вторую звездочку (перед temp_out)
+ int firstStar = data.indexOf('*');
+ int secondStar = data.indexOf('*', firstStar + 1);
+
+ if (idx1 == -1 || idx2 == -1 || idx3 == -1 || secondStar == -1)
+ {
+ Serial.println("Warning: Invalid data format: " + data);
+ return false;
+ }
+
+ // Парсим первую часть
+ dataSensors.temp_in = data.substring(1, idx1).toFloat(); // Пропускаем первый *
+ dataSensors.pres = data.substring(idx1 + 1, idx2).toInt();
+ dataSensors.hum = data.substring(idx2 + 1, idx3).toInt();
+
+ // Парсим вторую температуру (после второй звездочки)
+ int startTempOut = secondStar + 1;
+ int endTempOut = data.indexOf(';', startTempOut);
+
+ if (endTempOut == -1)
+ {
+ endTempOut = data.indexOf('*', startTempOut);
+ }
+ if (endTempOut == -1)
+ {
+ endTempOut = data.length();
+ }
+
+ dataSensors.temp_out = data.substring(startTempOut, endTempOut).toFloat();
+
+ Serial.printf("Parsed: T_in=%.2f, P=%d, H=%d, T_out=%.2f\n",
+ dataSensors.temp_in, dataSensors.pres,
+ dataSensors.hum, dataSensors.temp_out);
+
+ return true;
+}
+
+//===================================================
+// Форматируем время:
+void TimeMillis()
+{
+ z = "";
+
+ if (timeClient.getHours() < 10)
+ z += "D";
+ z += timeClient.getHours();
+
+ (flagSec) ? z += "B" : z += "D";
+
+ if (timeClient.getMinutes() < 10)
+ z += "0";
+
+ z += timeClient.getMinutes();
+
+ if ((timeClient.getHours() >= TIME_DAY) && (timeClient.getHours() < TIME_NIGHT))
+ {
+ brightVis = BRIGHT_DAY;
+ }
+ else
+ {
+ brightVis = BRIGHT_NIGHT;
+ }
+}
+
+//===================================================
+// Форматируем температуру:
+void fTemp(float t)
+{
+ z = "";
+
+ // Отрицательная температура
+ bool isNegative = (t < 0);
+ if (isNegative)
+ {
+ t = -t;
+ z += "B"; // Минус
+ }
+
+ // Целая часть
+ int whole = (int)t;
+ if (whole < 10 && !isNegative)
+ {
+ z += "D"; // Ведущий ноль для выравнивания
+ }
+ z += String(whole);
+
+ // Дробная часть (с правильным округлением)
+ int frac = (int)((t - whole) * 10 + 0.5);
+ if (frac > 0)
+ {
+ z += "E"; // Точка
+ z += String(frac);
+ }
+
+ // Градус
+ z += "A";
+
+ // Дополняем до 5 символов (если нужно)
+ while (z.length() < 5)
+ {
+ z = "D" + z;
+ }
+}
+
+// Форматируем давление, влажность:
+void fOther(int o)
+{
+ if (o < 10)
+ {
+ z = "DDDD";
+ }
+ else if (o < 100)
+ {
+ z = "DDD";
+ }
+ else
+ {
+ z = "DD";
+ }
+ z += o;
+}
+
+//===================================================
+// Обновляем данные отображения:
+void updateDisplay()
+{
+ if (!flagVis)
+ return;
+
+ switch (displayMode)
+ {
+ case 0:
+ TimeMillis();
+ visibleWork(z, COLOR_TIME, brightVis);
+ strip.show();
+ flagVis = false;
+ break;
+
+ case 1:
+ fTemp(dataSensors.temp_in);
+ visibleWork(z, COLOR_TEMP, brightVis);
+ strip.show();
+ flagVis = false;
+
+ // Обновляем данные с сервера не чаще чем раз в минуту
+ if (millis() - lastHTTPRequest >= HTTP_UPDATE_INTERVAL)
+ {
+ String response = http_response();
+ if (response.length() > 0)
+ {
+ if (parse_data_http(response))
+ {
+ lastHTTPRequest = millis();
+ }
+ }
+ else
+ {
+ Serial.println("Warning: Using cached sensor data");
+ }
+ }
+ break;
+
+ case 2:
+ fOther(dataSensors.pres);
+ visibleWork(z, COLOR_PRESS, brightVis);
+ strip.show();
+ flagVis = false;
+ break;
+
+ case 3:
+ fOther(dataSensors.hum);
+ visibleWork(z, COLOR_HUM, brightVis);
+ strip.show();
+ flagVis = false;
+ break;
+
+ case 4:
+ fTemp(dataSensors.temp_out);
+ visibleWork(z, COLOR_TEMP_OUT, brightVis);
+ strip.show();
+ flagVis = false;
+ break;
+
+ default:
+ break;
+ }
+}
+
+//===================================================
+void setup()
+{
+ Serial.begin(115200);
+ Serial.println("\n\n=== TABLO STARTING ===");
+
+ ESP.wdtEnable(5000);
+ pinMode(LED_BUILTIN, OUTPUT);
+ digitalWrite(LED_BUILTIN, HIGH);
+
+ strip.begin();
+ z = "DDDDD";
+ visibleWork(z, COLOR_WIFI, BRIGHT_DAY);
+ strip.show();
+
+ if (!setupWiFi())
+ {
+ Serial.println("WiFi setup failed, restarting...");
+ ESP.restart();
+ }
+
+ timeClient.begin();
+ if (!setupNTP())
+ {
+ Serial.println("NTP setup failed, restarting...");
+ ESP.restart();
+ }
+
+ sensorKeys = String(SENSOR_1) + "," + String(SENSOR_2);
+
+ // Первый запрос к серверу
+ String response = http_response();
+ if (response.length() > 0)
+ {
+ parse_data_http(response);
+ }
+
+ server.begin();
+ httpUpdater.setup(&server);
+ Serial.println("HTTP server started");
+
+ lastModeSwitch = millis();
+}
+
+//===================================================
+void loop()
+{
+ // Проверка WiFi
+ if (WiFi.status() != WL_CONNECTED)
+ {
+ Serial.println("WiFi lost, reconnecting...");
+ if (!setupWiFi())
+ ESP.restart();
+ }
+
+ // Синхронизация NTP каждые 6 часов
+ static unsigned long lastNTPSync = 0;
+ if (millis() - lastNTPSync > 21600000)
+ {
+ if (timeClient.update())
+ {
+ lastNTPSync = millis();
+ Serial.println("NTP synchronized");
+ }
+ }
+
+ // Обновление дисплея
+ if (flagVis)
+ updateDisplay();
+
+ // Отображение секундного тире (только для часов)
+ if (displayMode == 0)
+ {
+ if (millis() - timeReadOld >= 500)
+ {
+ flagSec = !flagSec;
+ timeReadOld = millis();
+ flagVis = true;
+ }
+ }
+
+ // Переключение режимов
+ unsigned long current = millis();
+ if (current - lastModeSwitch >= (unsigned long)visData[displayMode] * 1000)
+ {
+ displayMode = (displayMode + 1) % (sizeof(visData) / sizeof(visData[0]));
+ lastModeSwitch = current;
+ flagVis = true;
+ timeReadOld = current;
+ }
+
+ // Feed watchdog
+ ESP.wdtFeed();
+
+ server.handleClient();
+ delay(1); // Уменьшил до 1 мс для более быстрого реагирования
+} \ No newline at end of file