ESP, IoT [BigClock] Большие часы на WS2812, ESP8266, Народный мониторинг

Какой вариант датчика используется у вас? Интересно, использует ли кто BME280, как у меня?)

  • BMP280

    Голосов: 22 26.8%
  • BME280

    Голосов: 60 73.2%

  • Всего проголосовало
    82
[BigClock] Большие часы на WS2812, ESP8266, Народный мониторинг
Создаю отдельную тему по разработке прошивки на базе NodeMCU.

Мой проект сделан на ДВП, на нее наклеил ленту, объем цифрам сделал из сэндвич панели, поверх белый лист бумаги.
Корпус из дерева, покрашен акриловой краской, смесь белой и коричневой.

Данная прошивка проверяет время по NTP, часы RTC теоретически не нужны.
Барометр на базе BME280.
Имеется датчик освещенности и датчик DS18B20
Clock_схема.pngсхема пайки.jpgClock_схема3.jpg
Плата: NodeMCU 1.0 (ESP 12-E Module)
Если в качестве микроконтроллера вы используете Wemos D1 - в менеджере плат для компиляции все равно выбирайте "NodeMCU v1.0 (ESP-12E)", в противном случае, если выберете плату Wemos D1 (xxxx), - будет работать нестабильно.
Выбирайте ядро ESP версии 2.7.4.

ESP8266 (SDK v2.7+)

Необходимые библиотеки находим в репозитории программы IDE.
Настраиваем прошивку под себя, если нужно, меняем пароли для точки и OTA, WiFi можно не задавать.

Если не задавали настройки WiFi, то стартует точка, адрес стандартный 192.168.4.1 пароль по умолчанию administrator, задавать не менее 8 символов, иначе название точки не отобразится, а будет ее внутреннее имя, типа ESP12345.
Адрес портала http://clock.local/ или по IP адресу, выданному роутером.
Данные для OTA: имя: admin пароль: pass

Для подключения к сервису "Народный мониторинг" MAC адрес отображается на соответствующей странице, вводите этот адрес при регистрации устройства.

Новая версия на гитхаб, последние изменения и публикация свежих версий будет там)

Версия от 16.04.2023 CLOCK_ESP_2.0:
  • оптимизация под новый портал
  • переделано давление с инт на флоат для мониторинга
  • переделан интерфейс на UI
  • добавлена ручная синхронизация времени
  • заменена библиотека rtc на microDS3231
  • багфиксы)
  • добавлена в код точка, для десятичного знака уличной температуры
  • добавлена строка с версией прошивки
  • исправление даты
  • добавление DFPlayer, спасибо: @Maxx1200 и @Romshteks
  • добавлен режим с датой (номер 5)
  • обновлена библиотека EEManager (сбросятся настройки!!!)
  • добавлен режим с показом первого нуля в часах
  • добавлена возможность устанавливать цветовое оформление в настройках прошивки, визуальные правки
  • fix GMT
  • заменены библиотеки датчиков
  • визуальные правки
  • может что-то еще))
Проект на гитхаб со всеми библиотеками и mp3
  • Дофига изменений))
  • Появилась web страничка с настройками на базе GyverPortal.
  • Изменены библиотеки.
  • Переписан код, распределил по вкладкам.
исправлено:
  • баг со сменой цвета на последней цифре
добавлен
  • символ давления, включать в настройках
исправлено:
  • переделан вывод сегментов
  • переделана функция показа точек
добавлено:
  • выбор режима мигания секунд 1 и 2 раза в сек
  • можно вручную задать порядок отображения датчиков и время показа каждого датчика
  • откл. WiFi без мониторинга
  • корректировка показания датчиков
внедрение датчика BME280, добавлен режим влажности с возможностью включить символ проценты
[*]багфиксы
багфиксы
незначительные изменения кода (настройки под себя и комментарии)
  • все настройки вынесены в Constants, вроде:)
  • добавлен web сервер, для обновления через браузер, изначально прошить через кабель, потом можете вносить изменения под себя и обновляться через бинарный файл
  • добавлены библиотеки
  • изменение в коде, из-за выноса настроек:)
  • добавлен НГ режим :)
  • возможно исправлена анимация, про которую писали, с точками и цифрами :)
  • теперь при запуске часов идет проверка с датчика времени, и если все ОК, то запускаются часы без синхронизации
  • исправлена функция освещенности заменой switch на if/else
  • подправлен код с switch в других местах
Увидел в коде небольшую ошибку с НГ режимом, не важно, включен он или нет, все равно будет) только разными методами)
leds[cursor] = (digit & mask) ? CHSV(random(0, 255), random(0, 255), random(0, 255)) : CRGB (0, 0, 0);
leds[cursor] = (digit & mask) ? ledColor : CRGB (0, 0, 0);
  • исправлен НГ режим
  • отключена точка доступа за ненадобностью
  • оптимизирован код
  • выбор в настройках кол-во разделительных точек
  • можно запускать с RTC модулем и без него
  • изменена библиотека NTP
  • поправлен код :)
Внимание: у кого мигает первый светодиод, необходимо изменить ядро ESP на 2.7.4 (инструменты/Плата/Менеджер плат).
Новые версии нестабильные на октябрь 2021г.
 

Вложения

Изменено:

Комментарии

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
@bort707,это и называется псевдо рандом)
в таких случаях советуют сбрасывать значение каждый раз или привязывать ко времени.
вот это и планирую к реализации...
по высшей математике тоже что-то было про случайные числа... тоже занимательные были лекции...
 

kDn

★★★★★✩✩
18 Ноя 2019
1,103
437
@bort707, @ASM,
Если задача сводится к тому чтобы добавить разнообразия в цветах относительно заданного кол-ва, то имеет смысл добавлять рандомное смещение относительно текущего индекса, взятое по модулю максимального индекса. Если же для смещения исключить 0 и макс. индекс, то подряд идущих одинаковых цветов не будет.

Ну и отдельно - в контроллерах попросту нет случайных значений, а есть ГПСЧ. Поскольку настоящую случайность получить достаточно непростая задача.
 
  • Лойс +1
Реакции: Lumenjer и bort707

bort707

★★★★★★✩
21 Сен 2020
3,067
915
в таких случаях советуют сбрасывать значение каждый раз или привязывать ко времени.
вот это и планирую к реализации...
значительно проще отбрасывать значение, если оно совпадает с предыдущим. И никакой "высшей математики"...

Ну или как предлагает @kDn выше - результат будет тот же
 

Lumenjer

★★★✩✩✩✩
10 Дек 2020
220
112
это и называется псевдо рандом)
Может псевдо-псевдо рандом?) Т.к:
Ну и отдельно - в контроллерах попросту нет случайных значений, а есть ГПСЧ.

А вообще, о рандоме можете почитать тут почитать, а о том, как примерно добиваются "настоящего" рандома - тут
 
  • Лойс +1
Реакции: ASM

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
Какие сложные реализации для массива из 0-15 чисел) даже если кто-то добавит количество цветов, всё равно, небольшое количество будет) Индексы, модули, исключение мин и макс... Тогда цветов будет меньше на 2...
Отбросить предыдущее ещё более реальнее выглядит, можно подумать над реализацией кода))

C++:
void Digit (uint8_t digit, uint8_t cursor) { // функция отображения символов

  for (uint8_t mask = 0b01000000; mask > 0; mask = mask >> 1) {
    for (uint8_t i = 0; i < LEDS_IN_SEGMENT; i++) {
      if (new_god) {
        leds[cursor] = (digit & mask) ? ColorTable[random(NUM_COLORS)] : CRGB (0, 0, 0);
      }
      else {
        leds[cursor] = (digit & mask) ? ledColor : CRGB (0, 0, 0);
      }
      cursor ++;
    }
  }
}
byte new = 0;
if (LEDS_IN_SEGMENT [ i ] != LEDS_IN_SEGMENT[ i - 1 ]){
LEDS_IN_SEGMENT[ new ++] = LEDS_IN_SEGMENT[ i ];
}
}
return new;
Как-то так)
Вот от этого будем отталкиваться)
 
Изменено:

bort707

★★★★★★✩
21 Сен 2020
3,067
915
Вот от этого будем отталкиваться)
ерунда какая-то...
Что такое LEDS_IN_SEGMENT ? - судя по коду выше - это целое, число светиков в сегменте.
Тогда почему вы обращаетесь с ним, как с массивом?
Вы что пытаетесь добиться вот этой записью? - - LEDS_IN_SEGMENT [ i ]
 

balent

✩✩✩✩✩✩✩
29 Ноя 2021
53
7
@kym13,MAX -это уже на заднем плане, все руки не дойдут переделать их на большие матрицы,есть уже, остается снять маленькие и приколхозить большие, думаю, потянет. Не пробовал никто?
 
Изменено:

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
Не добрался до ПК, не экспериментировал больше с НГ.
Вчера выключил НГ режим, мерцания, на которые я указывал, пропали.
Посмотрю режим со сменой цветов, а то никто не отписался, исправилось ли, заодно проверю, как работает)

Увидел этот баг) либо точки сначала меняют цвет, либо часы) не помогла рекомендация поменять местами значит)
Мерцания пару раз увидел)
 
Изменено:

kamikadzze

✩✩✩✩✩✩✩
3 Ноя 2020
19
1
У меня 4 платы осталось, могу выслать конвертом. Конечно не идеально разведено и монтаж компактный но работает
прошивку бы допилить и я корпус буду новый рисовать
если есть платка на этот проект-дайте знать
 

Divin

★★★✩✩✩✩
30 Янв 2021
441
192
@ASM, У меня к вам "деловое" предложение - Я рисую схему подключения
Lamp+TM1637.jpg
А вы добавите к прошивке датчик bmp 280 , если конечно вы захотите этим заниматься , я полный профан в программировании.
 

Divin

★★★✩✩✩✩
30 Янв 2021
441
192
@ASM, я нашел варианты подключения этого датчика, но как интегрировать его в прошивку абсолютно без понятия, если не будете против в личку скину ссылку на библиотеку и подключение. Прошу прощения а ТМ это что?
 

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
@Divin, надо изучать логику работы) я не интересовался этим модулем)
вот есть тема у Алекса
лучше создать новую тему, если нет аналогичной и ждать помощи там) совсем разные схемы и компоненты, код будет другой)
 

Divin

★★★✩✩✩✩
30 Янв 2021
441
192
@ASM, Вы меня не так поняли - я рисую схему подключения именно для этого проекта, схема которую я указал в сообщении только для примера - образец, естественно что в проекте часов с большим индикатором маленький дисплей не нужен :)
 

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
@Divin, тогда просто заменить датчик и библиотеки, изначально у меня было вроде на нем, сейчас поищу примеры...

C++:
/*Блокнотик
  +  задержка wifi при вкл эл-ва
  +  загрузка при старте
  + ограничение по току
  - MQTT
  + IoT
  секунды 500мс
*/
#include <ESP8266WiFi.h>
#include <EasyNTPClient.h>
#include <WiFiUdp.h>
#include <RTClib.h>
RTC_DS3231 rtc;
#include <FastLED.h>
//#include <BMP280_DEV.h>
//BMP280_DEV bmp280;
#include <Wire.h>
#include <SparkFunBME280.h>
BME280 bmp280;
#include <OneWire.h>
#include <DallasTemperature.h>
WiFiUDP udp;

/////////////////////НАСТРОЙКИ И СХЕМА//////////////////
//питание платы от БП не выше 5В
//DS3231 SDA=>D2 SCL+>D1 питание с 5В БП или с 3.3В
//BMP/BME 280 SDA=>D2 SCL+>D1 питание 3.3В
//DS18B20 питание 5В, если уличный без модуля ставим резистор между питанием и сигнальным на 4.7К
const char *ssid = "";  //имя WiFi сети вашего роутера
const char *password = "";    //пароль от сети
#define ONE_WIRE_BUS_2 D5     // PIN датчика ds18b20
int UpdatePeriod = 12;        // период в часах, как часто обновлять время из интернета, лучше не пишите маленькие числа:)
#define LEDS_IN_SEGMENT 4     // задаём сколько у нас светодиодов в сегменте
#define DOTS_NUM 2            // задаём сколько у нас разделительных точек
#define NUM_COLORS 16         // количество цветов, записаны в ColorTable
#define COLOR_CHANGE 0        // смена цвета ( 0 - никогда, 1 - раз в минуту, 2 - каждые десять минут, 3 - каждый час, 4 - каждые десять часов)
// если в схеме один фоторезистор не модулем, то вешаем резистор от 1К до 10К. Если у вас высокая освещенность, то 1К, если слабая, то до 10К
// один вывод фоторезистора на пин A0, или любой другой, второй на GND. Между GND и питанием ставим резистор
#define BRI_PIN A0            // PIN фоторезистора
#define max_bright 255        // максимальная яркость (0 - 255)
#define min_bright 5          // минимальная яркость (0 - 255)
#define bright_constant 1023  // константа усиления от внешнего света (0 - 1023), чем МЕНЬШЕ константа, тем "резче" будет прибавляться яркость
#define coef 0.4              // коэффициент фильтра (0.0 - 1.0), чем больше - тем медленнее меняется яркость
#define auto_bright 1         // автоматическая подстройка яркости от уровня внешнего освещения (1 - включить, 0 - выключить)
EasyNTPClient ntpClient(udp, "pool.ntp.org", (3 * 60 * 60)); //заменить первую цифру на свой часовой пояс, 3 для МСК
#define COLOR_ORDER GRB       // тип ленты, поменять порядок GRB на свой тип, если неправильные цвета
#define LED_PIN 6             // PIN дата от ленты, подключать через резистор 330Ом
int brg = 10000;              // как часто проверять изменение по датчику освещенности в мс, 10000 соответствуют 10сек
byte type_brg = 0;            // выбрать тип датчика, 0 - аналог, 1 - цифровой
byte cnctd = 20;              // кол-во попыток подключиться к роутеру, 2 запроса в сек
uint32_t milliamps = 1000;    // ограничение по току в мА
int delay_narod = 600;        // как часто отправлять значения датчиков на мониторинг, минимум 5 минут, значение в секундах, плюс запас в 5 сек, на всякий случай, получается минимум 305
// при отправке больше 2х запросов в 5 минут, получите бан по IP
// регистрирумся на narodmon.ru, загружаем настроенный скетч, в меню профиль, отладка по IP копируем Mac
// снова профиль, мои датчики, вводим Mac и настраиваем датчики по усмотрению и радуемся их работе :)
static bool Monitoring = true; // включаем мониторинг, иначе false
byte prs = 0;                  // 0 - не показываем символ давления, 1 - показать
/////////////////////КОНЕЦ НАСТРОЕК/////////////////

// настроим библиотеку 1-Wire для связи с датчиком
OneWire oneWire_out(ONE_WIRE_BUS_2);
// создадим объект для работы с библиотекой DallasTemperature
DallasTemperature sensors(&oneWire_out); //уличный ds18b20
int Period = UpdatePeriod * 3600; //вычисление секунд
#define NUM_LEDS (LEDS_IN_SEGMENT * 28 + DOTS_NUM) // вычисляем кол-во светодиодов
/////////////////////////////////////////////
CRGB leds[NUM_LEDS];  // определение СД ленты
uint8_t  digits[] = { // определяем символы для отображения
  // код начинается с 0b0, далее идут 7 цифр, каждая цифра это номер фрагмента, 1 - включен, 0- отключен
  // далее указан получающийся символ и порядковый номер в массиве
  0b00111111,     // Символ 0          0
  0b00100001,     // Символ 1          1
  0b01110110,     // Символ 2          2
  0b01110011,     // Символ 3          3
  0b01101001,     // Символ 4          4
  0b01011011,     // Символ 5          5
  0b01011111,     // Символ 6          6
  0b00110001,     // Символ 7          7
  0b01111111,     // Символ 8          8
  0b01111011,     // Символ 9          9
  0b01111000,     // Символ * градус  10
  0b00011110,     // Символ C         11
  0b00000000,     // Без символа      12
  0b01000000,     // Символ -         13
  0b01111100      // Символ P         14
};
bool Dot = true;    // переменная для точек
int last_digit = 0; // последний символ равен нулю
byte set_light;     // переменная для освещенности
byte brightness;    // переменная для освещенности
int new_bright, new_bright_f; // переменная для освещенности
unsigned long bright_timer, off_timer; // переменная для освещенности
unsigned long timing;                  // переменная для мониторинга
float temperature, pressure, altitude; // переменные для библиотеки датчика bmp280
float tempH, tempS, presH;             // переменные для мониторинга
CRGB ledColor = CRGB::Blue;   // цвет в hex
CRGB ColorTable[NUM_COLORS] = { // Таблица цветов
  CRGB::Amethyst,
  CRGB::Aqua,
  CRGB::Blue,
  CRGB::Chartreuse,
  CRGB::DarkGreen,
  CRGB::DarkMagenta,
  CRGB::DarkOrange,
  CRGB::DeepPink,
  CRGB::Fuchsia,
  CRGB::Gold,
  CRGB::GreenYellow,
  CRGB::LightCoral,
  CRGB::Tomato,
  CRGB::Salmon,
  CRGB::Red,
  CRGB::Orchid
};
/////////////////////////////////////////////
void setup() {
  Serial.begin(115200);
  Wire.begin();
  bmp280.setI2CAddress(0x76); //Connect to a second sensor
  if (bmp280.beginI2C() == false) Serial.println("Sensor B connect failed");

  LEDS.setBrightness(50);
  FastLED.addLeds<WS2812B, LED_PIN, RGB>(leds, NUM_LEDS); // подключение ленты
  FastLED.setMaxPowerInVoltsAndMilliamps (5, milliamps);
  //  bmp280.begin(BMP280_I2C_ALT_ADDR);
  //  bmp280.setTimeStandby(TIME_STANDBY_2000MS);
  //  bmp280.startNormalConversion();
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  /*
    if (!bmp.begin()) {                               // Проверка инициализации датчика
    Serial.println("Could not find a valid BME280 sensor, check wiring!"); // Печать, об ошибки инициализации.
    while (1);                                          // Зацикливаем
    }*/
  syncTime();

}
/////////////////////////////////////////////
void BrightnessCheck() { // функция освещенности
  static uint32_t last_br = millis();
  if ((millis() - last_br) < brg) return;
  last_br = millis();
  if (auto_bright) {                         // если включена адаптивная яркость
    if (millis() - bright_timer > 100) {     // каждые 100 мс
      bright_timer = millis();               // сбросить таймер
      switch (type_brg) {
        case 1:
          new_bright = map(digitalRead(BRI_PIN), 0, bright_constant, max_bright, min_bright);   // считать показания с фоторезистора, перевести диапазон
          break;
        default:
          new_bright = map(analogRead(BRI_PIN), 0, bright_constant, max_bright, min_bright);   // считать показания с фоторезистора, перевести диапазон
      }
      //      Serial.println((String)"Освещенность: " + new_bright);
      new_bright = constrain(new_bright, min_bright, max_bright);
      new_bright_f = new_bright_f * coef + new_bright * (1 - coef);
      LEDS.setBrightness(new_bright_f);      // установить новую яркость
    }
  }
};
/////////////////////////////////////////////
void syncTime() {
  WiFi.begin(ssid, password);
  byte trys = 0;
  Serial.println("");
  while (WiFi.status() != WL_CONNECTED) {
    trys++;
    //    delay(500);
    NoSignal();
    Serial.print(".");
    if (trys > cnctd)
    {
      Serial.println("Нет связи с роутером при старте!");
      return;
    }
  }
  long ntpTime = ntpClient.getUnixTime();
  if (ntpTime > 1609459200) {
    rtc.adjust(DateTime(ntpTime));
    Serial.println("");
    Serial.println("Время записано!");
    //    Serial.println(WiFi.localIP());
    //    Serial.println(udp.localPort());
  }
  else
  {
    Serial.println("");
    Serial.println("Отказ в записи! Время получено неправильное!");
    GetTime();
  }/*
  // Выключаем WIFI после обновления
  // похоже теперь не нужна, раз подключили мониторинг :)
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  WiFi.forceSleepBegin();
  delay(1000);*/
}
/////////////////////////////////////////////
int GetTime() {
  DateTime now = rtc.now();
  int hour = now.hour();
  int minute = now.minute();
  int second = now.second();
  Serial.println((String)hour + ":" + minute + ":" + second);
  Dot = second % 2; // точки мигают раз в сек
  return (hour * 100 + minute);
};
/////////////////////////////////////////////
void TimeToArray() { // вывод времени на экран
  int Now = GetTime(); // получаем время
  boolean Dots = true; // точки
  boolean color_change_flag = false;
  if (Dot == 0) Dots = false; else Dots = true;
  if (Dots) { // показ точек
    for (uint8_t i = 0; i < DOTS_NUM; i++) {
      leds[(LEDS_IN_SEGMENT * 14) + i] = ledColor;
    }
  }
  else {
    Dots_off(); // выключение точек
  }
  for (int i = 1; i <= 4; i++) { // 4 сегмента
    int digit = Now % 10; // получаем последнюю цифру в времени
    int cursor = NUM_LEDS - i * LEDS_IN_SEGMENT * 7;
    if (i > 2) {
      cursor -= DOTS_NUM;
    }
    if ( i == 4 & digit == 0)Digit(digits[12], cursor); // если впереди ноль, то выключаем его, например 01:23 будет как 1:23
    else
      Digit(digits[digit], cursor);                     // иначе показываем символ

    if ( i == COLOR_CHANGE) {                           // как часто менять цвет
      if (digit != last_digit) {
        color_change_flag = true;
        last_digit = digit;
      }
    }
    Now /= 10;
  };
  if (color_change_flag) ledColor =  ColorTable[random(NUM_COLORS)];     // случайный цвет из таблицы
};
/////////////////////////////////////////////
void Dots_off()  { // отключаем точки принудительно, где не нужны
  for (uint8_t i = 0; i < DOTS_NUM; i++) {
    leds[(LEDS_IN_SEGMENT * 14) + i] = 0x000000;
  }
}
/////////////////////////////////////////////
void Digit (uint8_t digit, uint8_t cursor) { // функция отображения символов
  for (uint8_t mask = 0b01000000; mask > 0; mask = mask >> 1) {
    for (uint8_t i = 0; i < LEDS_IN_SEGMENT; i++) {
      leds[cursor] = (digit & mask) ? ledColor : CRGB (0, 0, 0);
      cursor ++;
    }
  }
}
/////////////////////////////////////////////
void TempToArray() { // вывод температуры с датчика BMP280 на экран
  bmp280.beginI2C();
  //  bmp280.getMeasurements(temperature, pressure, altitude);
  tempH = (bmp280.readTempC());
  int celsius = tempH;
  //  int celsius = temperature; //датчик на стене, выше роста, корректировка минус 1 градус, сейчас на столе стенд
  //  tempH = temperature;


  Serial.println ((String) celsius + " | " + tempH);
  Dots_off(); // выключаем точки
  Digit(digits[10], (NUM_LEDS - LEDS_IN_SEGMENT * 7)); // символ градуса

  int digit = abs (celsius % 10);
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 14));

  digit = celsius / 10;
  if (digit == 0)Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // если впереди ноль, то выключаем его
  else
    Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // иначе показываем как есть

  Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // отключаем 1 сегмент
};
/////////////////////////////////////////////
void PressToArray() { // вывод давления на экран
  bmp280.beginI2C();
  presH = (bmp280.readFloatPressure() * 0.0075);
  int davlenie = presH;
  //  bmp280.getMeasurements(temperature, pressure, altitude);
  //  int davlenie = pressure * 0.75;

  //  presH = pressure * 0.75;

  Serial.println ((String) davlenie + " | " + presH);

  Dots_off(); // выключаем точки

  int digit = davlenie % 10;
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 7));

  digit = davlenie % 100 / 10;
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 14));

  digit = davlenie / 100;
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM));
  switch (prs) {
    case 1:
      Digit(digits[14], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // показываем символ P
      break;
    default:
      Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // отключаем первый сегмент
  }
};
/////////////////////////////////////////////
void TempStreetToArray() { // вывод уличной температуры на экран
  sensors.requestTemperatures(); // опрос датчика уличной температуры
  int celsius = sensors.getTempCByIndex(0); // чтение уличной температуры с датчика 0, налогично следующий будет 1
  tempS = sensors.getTempCByIndex(0);
  Serial.println ((String) celsius + " | " + sensors.getTempCByIndex(0));

  Dots_off(); // выключаем точки

  Digit(digits[10], (NUM_LEDS - LEDS_IN_SEGMENT * 7)); // символ градуса

  int digit = abs (celsius % 10);
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 14));

  digit = abs (celsius / 10);
  if (digit == 0)Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // если впереди ноль, то выключаем его
  else
    Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // иначе показываем как есть

  if (sensors.getTempCByIndex(0) <= -1)Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // если < или = -1, то показываем -
  else
    Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // иначе выключаем 1 сегмент
};
/////////////////////////////////////////////
void body() { // вывод информации
  static bool TempShow = true; // флаг для температуры в помещении
  static bool TempSShow = true; // флаг для температуры на улице
  static bool PressShow = true; // флаг для давления
  uint32_t tmrall = millis() % 12000 / 1000; //берем интервал в 12сек
  static uint32_t tmrall_old = 10000;        //в расчет берутся 10сек, в исключение 2 сек, ниже будет понятно:)
  if (tmrall_old != tmrall)
  {
    tmrall_old = tmrall;
    if (tmrall < 6) //6 сек показывают часы
    {
      TimeToArray();
      TempShow = true;
      TempSShow = true;
      PressShow = true;
    }
    else if (tmrall < 8) //2 секунды показывается температура, добавляем +2
    {
      if (TempShow)
      {
        TempToArray();
        TempShow = false;
      }
    }
    else if (tmrall < 10) //2 секунды показывается температура, добавляем +2
    {
      if (TempSShow)
      {
        TempStreetToArray();
        TempSShow = false;
      }
    }
    else
    {
      if (PressShow) // остальное время показывается давление
      {
        PressToArray();
        PressShow = false;
      }
    }
    FastLED.show(); // команда для включения светодиодов
  };
}
/////////////////////////////////////////////
void loop() {
  BrightnessCheck();
  if (millis() % 1000 < Period - 1)
  {
    body();
  }
  else {
    syncTime();
  }

  if (Monitoring) {
    if (millis() - timing > delay_narod * 1000) {
      timing = millis();
      narod();
    }
  }
}
/////////////////////////////////////////////
void narod() { //функция для народного мониторинга
  WiFi.begin(ssid, password);
  byte tryss = 0;
  Serial.println("Start_narod");
  while (WiFi.status() != WL_CONNECTED) {
    tryss++;
    delay(500);
    Serial.print("_");
    if (tryss > 20)
    {
      Serial.println("Нет связи с роутером, narod!");
      return;
    }
  }
  String buf = "#" + WiFi.macAddress();
  // добавление и удаление датчиков по шаблону
  buf = buf + "\n#T1#" + tempH;
  buf = buf + "\n#T2#" + tempS;
  buf = buf + "\n#T3#" + presH;
  buf = buf + "\n##";
  WiFiClient client;
  client.connect("narodmon.ru", 8283);
  client.print(buf);
  Serial.println("Показания отправлены!");
}
/////////////////////////////////////////////
void NoSignal() { // анимация загрузки :)
  Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM));
  FastLED.show(); delay(125);
  Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM));
  FastLED.show(); delay(125);
  Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 14));
  FastLED.show(); delay(125);
  Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 7));
  FastLED.show(); delay(125);
  LEDS.clear();
}
 

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
и более ранний
C++:
#include <ESP8266WiFi.h>
#include <EasyNTPClient.h>
#include <WiFiUdp.h>
#include <RTClib.h>
RTC_DS3231 rtc;
#include <FastLED.h>
#include <BMP280_DEV.h>
BMP280_DEV bmp280;
#include <OneWire.h>
#include <DallasTemperature.h>
WiFiUDP udp;

/////////////////////НАСТРОЙКИ И СХЕМА//////////////////
//питание платы от БП не выше 5В
//DS3231 SDA=>D2 SCL+>D1 питание с 5В БП или с 3.3В
//BMP/BME 280 SDA=>D2 SCL+>D1 питание 3.3В
//DS18B20 питание 5В, если уличный без модуля ставим резистор между питанием и сигнальным на 4.7К
const char *ssid = "";        //имя WiFi сети вашего роутера
const char *password = "";    //пароль от сети
#define ONE_WIRE_BUS_2 D5     //PIN датчика ds18b20
int UpdatePeriod = 12;        //период в часах, как часто обновлять время из интернета, лучше не пишите маленькие числа:)
#define LEDS_IN_SEGMENT 4     // задаём сколько у нас светодиодов в сегменте
#define DOTS_NUM 2            // задаём сколько у нас разделительных точек
#define NUM_COLORS 16         // количество цветов, записаны в ColorTable
#define COLOR_CHANGE 0        // смена цвета ( 0 - никогда, 1 - раз в минуту, 2 - каждые десять минут, 3 - каждый час, 4 - каждые десять часов)
//если в схеме один фоторезистор не модулем, то вешаем резистор от 1К до 10К. Если у вас высокая освещенность, то 1К, если слабая, то до 10К
//один вывод фоторезистора на пин A0, или любой другой, второй на GND. Между GND и питанием ставим резистор
#define BRI_PIN A0            // PIN фоторезистора
#define max_bright 255        // максимальная яркость (0 - 255)
#define min_bright 10         // минимальная яркость (0 - 255)
#define bright_constant 1023  // константа усиления от внешнего света (0 - 1023), чем МЕНЬШЕ константа, тем "резче" будет прибавляться яркость
#define coef 0.4              // коэффициент фильтра (0.0 - 1.0), чем больше - тем медленнее меняется яркость
#define auto_bright 1         // автоматическая подстройка яркости от уровня внешнего освещения (1 - включить, 0 - выключить)
EasyNTPClient ntpClient(udp, "pool.ntp.org", (3 * 60 * 60)); //заменить первую цифру на свой часовой пояс, 3 для МСК
#define COLOR_ORDER GRB       // тип ленты, поменять порядок GRB на свой тип, если неправильные цвета
#define LED_PIN 6             // PIN дата от ленты, подключать через резистор 330Ом
int brg = 10000;              // как часто проверять изменение по датчику освещенности в мс, 10000 соответствуют 10сек
byte type_brg = 0;            // выбрать тип датчика, 0 - аналог, 1 - цифровой
byte cnctd = 20;              // кол-во попыток подключиться к роутеру, 2 запроса в сек
uint32_t milliamps = 1000;    // ограничение по току в мА
/////////////////////КОНЕЦ НАСТРОЕК/////////////////

// настроим библиотеку 1-Wire для связи с датчиком
OneWire oneWire_out(ONE_WIRE_BUS_2);
// создадим объект для работы с библиотекой DallasTemperature
DallasTemperature sensors(&oneWire_out); //уличный ds18b20
int Period = UpdatePeriod * 3600; //вычисление секунд
#define NUM_LEDS (LEDS_IN_SEGMENT * 28 + DOTS_NUM) // вычисляем кол-во светодиодов
/////////////////////////////////////////////
CRGB leds[NUM_LEDS];  // определение СД ленты
uint8_t  digits[] = { // определяем символы для отображения
  // код начинается с 0b0, далее идут 7 цифр, каждая цифра это номер фрагмента, 1 - включен, 0- отключен
  // далее указан получающийся символ и порядковый номер в массиве
  0b00111111,     // Символ 0          0
  0b00100001,     // Символ 1          1
  0b01110110,     // Символ 2          2
  0b01110011,     // Символ 3          3
  0b01101001,     // Символ 4          4
  0b01011011,     // Символ 5          5
  0b01011111,     // Символ 6          6
  0b00110001,     // Символ 7          7
  0b01111111,     // Символ 8          8
  0b01111011,     // Символ 9          9
  0b01111000,     // Символ * градус  10
  0b00011110,     // Символ C         11
  0b00000000,     // Без символа      12
  0b01000000      // Символ -         13
};
bool Dot = true;    // переменная для точек
int last_digit = 0; // последний символ равен нулю
byte set_light;     // переменная для освещенности
byte brightness;    // переменная для освещенности
int new_bright, new_bright_f; // переменная для освещенности
unsigned long bright_timer, off_timer; // переменная для освещенности
float temperature, pressure, altitude;
CRGB ledColor = CRGB::Blue;   // цвет в hex
CRGB ColorTable[NUM_COLORS] = { // Таблица цветов
  CRGB::Amethyst,
  CRGB::Aqua,
  CRGB::Blue,
  CRGB::Chartreuse,
  CRGB::DarkGreen,
  CRGB::DarkMagenta,
  CRGB::DarkOrange,
  CRGB::DeepPink,
  CRGB::Fuchsia,
  CRGB::Gold,
  CRGB::GreenYellow,
  CRGB::LightCoral,
  CRGB::Tomato,
  CRGB::Salmon,
  CRGB::Red,
  CRGB::Orchid
};
/////////////////////////////////////////////
void setup() {
  Serial.begin(115200);
  Wire.begin();
  LEDS.setBrightness(50);
  FastLED.addLeds<WS2812B, LED_PIN, RGB>(leds, NUM_LEDS); // подключение ленты
  FastLED.setMaxPowerInVoltsAndMilliamps (5, milliamps);
  bmp280.begin(BMP280_I2C_ALT_ADDR);
  bmp280.setTimeStandby(TIME_STANDBY_2000MS);
  bmp280.startNormalConversion();
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  /*
    if (!bmp.begin()) {                               // Проверка инициализации датчика
    Serial.println("Could not find a valid BME280 sensor, check wiring!"); // Печать, об ошибки инициализации.
    while (1);                                          // Зацикливаем
    }*/
  syncTime();

}
/////////////////////////////////////////////
void BrightnessCheck() { // функция освещенности
  static uint32_t last_br = millis();
  if ((millis() - last_br) < brg) return;
  last_br = millis();
  if (auto_bright) {                         // если включена адаптивная яркость
    if (millis() - bright_timer > 100) {     // каждые 100 мс
      bright_timer = millis();               // сбросить таймер
      switch (type_brg) {
        case 1:
          new_bright = map(digitalRead(BRI_PIN), 0, bright_constant, max_bright, min_bright);   // считать показания с фоторезистора, перевести диапазон
          break;
        default:
          new_bright = map(analogRead(BRI_PIN), 0, bright_constant, max_bright, min_bright);   // считать показания с фоторезистора, перевести диапазон
      }
      Serial.println((String)"Освещенность: " + new_bright);
      new_bright = constrain(new_bright, min_bright, max_bright);
      new_bright_f = new_bright_f * coef + new_bright * (1 - coef);
      LEDS.setBrightness(new_bright_f);      // установить новую яркость
    }
  }
};
/////////////////////////////////////////////
void syncTime() {
  WiFi.begin(ssid, password);
  byte trys = 0;
  Serial.println("");
  while (WiFi.status() != WL_CONNECTED) {
    trys++;
    //    delay(500);
    NoSignal();
    Serial.print(".");
    if (trys > cnctd)
    {
      Serial.println("Нет связи с роутером!");
      return;
    }
  }
  long ntpTime = ntpClient.getUnixTime();
  if (ntpTime > 1609459200) {
    rtc.adjust(DateTime(ntpTime));
    Serial.println("");
    Serial.println("Время записано!");
  }
  else
  {
    Serial.println("");
    Serial.println("Отказ в записи! Время получено неправильное!");
    GetTime();
  }
  // Выключаем WIFI после обновления
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  WiFi.forceSleepBegin();
  delay(1000);
}
/////////////////////////////////////////////
int GetTime() {
  DateTime now = rtc.now();
  int hour = now.hour();
  int minute = now.minute();
  int second = now.second();
  Serial.println((String)hour + ":" + minute + ":" + second);
  Dot = second % 2; // точки мигают раз в сек
  return (hour * 100 + minute);
};
/////////////////////////////////////////////
void TimeToArray() { // вывод времени на экран
  int Now = GetTime(); // получаем время
  boolean Dots = true; // точки
  if (Dot == 0) Dots = false; else Dots = true;
  if (Dots) { // показ точек
    for (uint8_t i = 0; i < DOTS_NUM; i++) {
      leds[(LEDS_IN_SEGMENT * 14) + i] = ledColor;
    }
  }
  else {
    Dots_off(); // выключение точек
  }
  for (int i = 1; i <= 4; i++) { // 4 сегмента
    int digit = Now % 10; // получаем последнюю цифру в времени
    int cursor = NUM_LEDS - i * LEDS_IN_SEGMENT * 7;
    if (i > 2) {
      cursor -= DOTS_NUM;
    }
    if ( i == 4 & digit == 0)Digit(digits[12], cursor); // если впереди ноль, то выключаем его, например 01:23 будет как 1:23
    else
      Digit(digits[digit], cursor);                     // иначе показываем символ

    if ( i == COLOR_CHANGE) {                           // как часто менять цвет
      if (digit != last_digit) {
        ledColor =  ColorTable[random(NUM_COLORS)];     // случайный цвет из таблицы
      }
      last_digit = digit;
    }
    Now /= 10;
  };
};
/////////////////////////////////////////////
void Dots_off()  { // отключаем точки принудительно, где не нужны
  for (uint8_t i = 0; i < DOTS_NUM; i++) {
    leds[(LEDS_IN_SEGMENT * 14) + i] = 0x000000;
  }
}
/////////////////////////////////////////////
void Digit (uint8_t digit, uint8_t cursor) { // функция отображения символов
  for (uint8_t mask = 0b01000000; mask > 0; mask = mask >> 1) {
    for (uint8_t i = 0; i < LEDS_IN_SEGMENT; i++) {
      leds[cursor] = (digit & mask) ? ledColor : CRGB (0, 0, 0);
      cursor ++;
    }
  }
}
/////////////////////////////////////////////
void TempToArray() { // вывод температуры с датчика BMP280 на экран
  bmp280.getMeasurements(temperature, pressure, altitude);
  int celsius = temperature; //датчик на стене, выше роста, корректировка минус 1 градус, сейчас на столе стенд

  Serial.println ((String) celsius + " | " + temperature);
  Dots_off(); // выключаем точки
  Digit(digits[10], (NUM_LEDS - LEDS_IN_SEGMENT * 7)); // символ градуса

  int digit = abs (celsius % 10);
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 14));

  digit = celsius / 10;
  if (digit == 0)Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // если впереди ноль, то выключаем его
  else
    Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // иначе показываем как есть

  Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // отключаем 1 сегмент
};
/////////////////////////////////////////////
void PressToArray() { // вывод давления на экран
  bmp280.getMeasurements(temperature, pressure, altitude);
  int davlenie = pressure * 0.75;
  Serial.println ((String) davlenie + " | " + pressure * 0.75);

  Dots_off(); // выключаем точки

  int digit = davlenie % 10;
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 7));

  digit = davlenie % 100 / 10;
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 14));

  digit = davlenie / 100;
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM));

  Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // отключаем первый сегмент
};
/////////////////////////////////////////////
void TempStreetToArray() { // вывод уличной температуры на экран
  sensors.requestTemperatures(); // опрос датчика уличной температуры
  int celsius = sensors.getTempCByIndex(0); // чтение уличной температуры
  Serial.println ((String) celsius + " | " + sensors.getTempCByIndex(0));

  Dots_off(); // выключаем точки

  Digit(digits[10], (NUM_LEDS - LEDS_IN_SEGMENT * 7)); // символ градуса

  int digit = abs (celsius % 10);
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 14));

  digit = abs (celsius / 10);
  if (digit == 0)Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // если впереди ноль, то выключаем его
  else
    Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // иначе показываем как есть

  if (sensors.getTempCByIndex(0) <= -1)Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // если < или = -1, то показываем -
  else
    Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // иначе выключаем 1 сегмент
};
/////////////////////////////////////////////
void Asm() { //мой образец вывода
  static bool TempShow = true; // флаг для температуры в помещении
  static bool TempSShow = true; // флаг для температуры на улице
  static bool PressShow = true; // флаг для давления
  uint32_t tmrall = millis() % 12000 / 1000; //берем интервал в 12сек
  static uint32_t tmrall_old = 10000;        //в расчет берутся 10сек, в исключение 2 сек, ниже будет понятно:)
  if (tmrall_old != tmrall)
  {
    tmrall_old = tmrall;
    if (tmrall < 6) //6 сек показывают часы
    {
      TimeToArray();
      TempShow = true;
      TempSShow = true;
      PressShow = true;
    }
    else if (tmrall < 8) //2 секунды показывается температура, добавляем +2
    {
      if (TempShow)
      {
        TempToArray();
        TempShow = false;
      }
    }
    else if (tmrall < 10) //2 секунды показывается температура, добавляем +2
    {
      if (TempSShow)
      {
        TempStreetToArray();
        TempSShow = false;
      }
    }
    else
    {
      if (PressShow) // остальное время показывается давление
      {
        PressToArray();
        PressShow = false;
      }
    }
    FastLED.show(); // команда для включения светодиодов
  };
}
/////////////////////////////////////////////
void loop() {
  BrightnessCheck();
  if (millis() % 1000 < Period - 1)
  {
    Asm();
    //kym13();
  }
  else {
    syncTime();
  }
}
/////////////////////////////////////////////
void kym13() {
  static bool TempSShow = true; // флаг для температуры на улице
  uint32_t tmrall = millis() % 60000 / 1000;
  static uint32_t tmrall_old = 46000;
  if (tmrall_old != tmrall)
  {
    tmrall_old = tmrall;
    if (tmrall < 46) //46 сек показывают часы
    {
      TimeToArray();
      TempSShow = true;
    }
    else
    {
      if (TempSShow) // остальное время показывается давление
      {
        TempStreetToArray();
        TempSShow = false;
      }
    }
    FastLED.show(); // команда для включения светодиодов
  };
}
/////////////////////////////////////////////
void NoSignal() {
  for (int i = 0; i < 4; i++)
  {
    leds[i] = ledColor;
    FastLED.show();
    delay(40);
  }
  for (int i = 28; i < 32; i++)
  {
    leds[i] = ledColor;
    FastLED.show();
    delay(40);
  }
  for (int i = 58; i < 62; i++)
  {
    leds[i] = ledColor;
    FastLED.show();
    delay(40);
  }
  for (int i = 86; i < 90; i++)
  {
    leds[i] = ledColor;
    FastLED.show();
    delay(40);
  }
  LEDS.clear();
}
 

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
@Divin,да, смотри, должна быть в менеджере библиотек
 
  • Лойс +1
Реакции: Divin

Divin

★★★✩✩✩✩
30 Янв 2021
441
192
Внес изменения в последний скетч, все компилируется - с меня схема, постараюсь сделать в до среды!
C++:
#include "Constants.h"
#include "ESP8266WiFi.h"
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>
const char* host = "web";
const char* ssid = STASSID;
const char* password = STAPSK;
ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;
#include "EasyNTPClient.h"
#include <WiFiUdp.h>
#include "RTClib.h"
RTC_DS3231 rtc;
#include "FastLED.h"
//#include <BMP280_DEV.h>
//BMP280_DEV bmp280;
#include <Wire.h>
#include "SparkFunBME280.h"
BME280 bmp280;
#include "OneWire.h"
#include "DallasTemperature.h"
 
  • Лойс +1
Реакции: vvmxx и maksland

Divin

★★★✩✩✩✩
30 Янв 2021
441
192
А кто нибудь может подсказать схему подключения диодов в индикаторе
Резервная_копия_clock.jpg