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

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

  • BMP280

    Голосов: 23 29.1%
  • BME280

    Голосов: 56 70.9%

  • Всего проголосовало
    79
[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г.
 

Вложения

Изменено:

Комментарии

kym13

★★✩✩✩✩✩
14 Ноя 2020
472
70
ASM )) Скетч проверил всё работает. Отлично часы идут секунда в секунду со временем компа. С помощью этого скетча можно устанавливать время в новых модулях 3231,1307 и т.д. Есть ещё пожелание как бы уменьшить частоту вывода показаний? Очень часто выводятся данные, прям мельтешат. Это же в первую очередь часы. Например 40 сек часы оставшиеся 20 сек на температуру, влажность и т. д. по 4 сек. или сделать чтобы можно было программно выставить вывод данных раз в минуту, в две, три...десять. по типу смены цвета. Датчик освещения работает адекватно.
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
Это же в первую очередь часы
потом стоишь минуту, ждешь показаний))
мои и так говорят, долго меняется))
я тебе в прошлой теме специально делал вывод под тебя)) сделай по аналогии))
чтобы можно было программно выставить вывод данных
подумаю)
@Старик Похабыч, можно и так)

@Старик Похабыч, у нас был разговор, как реализовать моргание в 500мс, а не по 1с.
Но так и не решили, ушли в другую тему, как грамотнее сделать?
Есть мысля запустить мигание в loop, а уже в функциях с датчиками они и так глушатся принудительно)
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
а как сейчас реализовано ?
C++:
  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(); // выключение точек
  }
void Dots_off()  { // отключаем точки принудительно, где не нужны
  for (uint8_t i = 0; i < DOTS_NUM; i++) {
    leds[(LEDS_IN_SEGMENT * 14) + i] = 0x000000;
  }
}
там где не нужны
Dots_off();
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,251
1,297
Москва
Тогда можно реально поменять:
C++:
if (Dot == 0) Dots = false; else Dots = true;
if (Dots) { // показ точек
на
C++:
//if (Dot == 0) Dots = false; else Dots = true;
 if (!Dot) { // показ точек
Покажи место где Dor вычисляектся
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
@Старик Похабыч,
C++:
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);
};
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,251
1,297
Москва
В таком разрезе не выйдет без доп. ухищрений.
У тебя период изменения 1 секунда.
Тогда нужно что то типа:
C++:
if (old_sec!=second)
{
dot_timer=millis();
old_sec=second;
Dot=true;
}
if  (millis()-dot_timer>500) Dot=false;
old_sec статическая байтовая переменная
dot_timer статическая 32битная переменная

это все вместо
Dot = second % 2;
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
В таком разрезе не выйдет без доп. ухищрений.
так я и предлагал сделать в loop
C++:
Dots_on();
delay(500);
Dots_off();
delay(500);
это упрощенно, для понимания, а в датчиках уже указано Dots_off();
это все вместо
Dot = second % 2;
проверим...
 

kym13

★★✩✩✩✩✩
14 Ноя 2020
472
70
foka44 )) Да Вы правы раз в 2 сек. моргают, проверил по другим часам.
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
Если так, то точек нет)
C++:
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; // точки мигают раз в сек
  static byte old_sec;
  static uint32_t dot_timer;
  if (old_sec != second)
  {
    dot_timer = millis();
    old_sec = second;
    Dot = true;
  }
  if  (millis() - dot_timer > 500) Dot = false;
  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 (!Dot) { // показ точек
    for (uint8_t i = 0; i < DOTS_NUM; i++) {
      leds[(LEDS_IN_SEGMENT * 14) + i] = ledColor;
    }
  }
  else {
    Dots_off(); // выключение точек
  }
а если так, то горят)
C++:
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; // точки мигают раз в сек
  static byte old_sec;
  static uint32_t dot_timer;
  if (old_sec != second)
  {
    dot_timer = millis();
    old_sec = second;
    Dot = true;
  }
  if  (millis() - dot_timer > 500) Dot = false;
  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 (Dot) { // показ точек
    for (uint8_t i = 0; i < DOTS_NUM; i++) {
      leds[(LEDS_IN_SEGMENT * 14) + i] = ledColor;
    }
  }
  else {
    Dots_off(); // выключение точек
  }

можно попробовать вынести из массива в запрос, объединить в одно место, может будет лучше...
 

foka44

✩✩✩✩✩✩✩
1 Мар 2021
10
0
Если так, то точек нет)
C++:
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; // точки мигают раз в сек
  static byte old_sec;
  static uint32_t dot_timer;
  if (old_sec != second)
  {
    dot_timer = millis();
    old_sec = second;
    Dot = true;
  }
  if  (millis() - dot_timer > 500) Dot = false;
  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 (!Dot) { // показ точек
    for (uint8_t i = 0; i < DOTS_NUM; i++) {
      leds[(LEDS_IN_SEGMENT * 14) + i] = ledColor;
    }
  }
  else {
    Dots_off(); // выключение точек
  }
а если так, то горят)
C++:
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; // точки мигают раз в сек
  static byte old_sec;
  static uint32_t dot_timer;
  if (old_sec != second)
  {
    dot_timer = millis();
    old_sec = second;
    Dot = true;
  }
  if  (millis() - dot_timer > 500) Dot = false;
  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 (Dot) { // показ точек
    for (uint8_t i = 0; i < DOTS_NUM; i++) {
      leds[(LEDS_IN_SEGMENT * 14) + i] = ledColor;
    }
  }
  else {
    Dots_off(); // выключение точек
  }

можно попробовать вынести из массива в запрос, объединить в одно место, может будет лучше...
Это то что надо, благодарю, моргают как надо
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,251
1,297
Москва
Так выведи Dot в монитор порта.
GetTime() как часто вызывается ? Что бы работало должна как минимум 2 раза в секунду вызываться
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
@Старик Похабыч, я сейчас переписываю функцию, сделаю проще)
C++:
void Dots (boolean Dot_On)  {
  for (uint8_t i = 0; i < DOTS_NUM; i++) {
    leds[(LEDS_IN_SEGMENT * 14) + i] = (Dot_On) ? ledColor : CRGB (0, 0, 0);
  }
}
  Dots(Dot);
  Dots(!Dot);
лучше?)
 

foka44

✩✩✩✩✩✩✩
1 Мар 2021
10
0
@foka44, да ладно?) у меня нет)
C++:
/////////////////////////////////////////////
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; // точки мигают раз в сек
  static byte old_sec;
  static uint32_t dot_timer;
  if (old_sec != second)
  {
    dot_timer = millis();
    old_sec = second;
    Dot = true;
  }
  if  (millis() - dot_timer > 500) Dot = false;
  return (hour * 100 + minute);
};
/////////////////////////////////////////////
void TimeToArray() { // вывод времени на экран
  int Now = GetTime(); // получаем время
  boolean color_change_flag = false;
 
 if (Dot) { // показ точек
  Dots_on();
 }
  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_on()  { // показ точек
   for (uint8_t i = 0; i < DOTS_NUM; i++) {
      leds[(LEDS_IN_SEGMENT * 14) + i] = ledColor;
    }
  }
/////////////////////////////////////////////
void Dots_off()  { // отключаем точки принудительно, где не нужны
  for (uint8_t i = 0; i < DOTS_NUM; i++) {
    leds[(LEDS_IN_SEGMENT * 14) + i] = 0x000000;
  }
}
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
Так выведи Dot в монитор порта.
Serial.println((String)"Dot " + Dot);
20:57:35
Dot 1
20:57:36
Dot 1
20:57:37
Dot 1
20:57:38
Dot 1
20:57:39
Dot 1
20:57:40
Dot 1
C++:
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; // точки мигают раз в сек
  static byte old_sec;
  static uint32_t dot_timer;
  if (old_sec != second)
  {
    dot_timer = millis();
    old_sec = second;
    Dot = true;
  }
  if  (millis() - dot_timer > 500) Dot = false;
  return (hour * 100 + minute);
};

void Dots (boolean Dot_On)  {
  for (uint8_t i = 0; i < DOTS_NUM; i++) {
    leds[(LEDS_IN_SEGMENT * 14) + i] = (Dot_On) ? ledColor : CRGB (0, 0, 0);
  }
}

void TimeToArray() {
  int Now = GetTime();
  Dots(Dot);
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,251
1,297
Москва
Все логично тебе надо вызывать функцию чаще. А раз в секунду вызывать у тебя смена состояния может быть только раз в секунду. А выключаться должно во вторую половину секунды.
Если делать отдельную процедуру смены точек, то мигание будет не совпадать со сменой секунд.
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
мигание будет не совпадать со сменой секунд
мигает себе и мигает) главное по 500мс, чтобы видно было глазу)
Все логично тебе надо вызывать функцию чаще
попробовал вставлять GetTime(); в разные места, приводит к беспорядку...

всегда выводит Dot 1, ни одной записи с Dot 0

на сегодня все, надо отдыхать)
 
Изменено:

Старик Похабыч

★★★★★★★
14 Авг 2019
4,251
1,297
Москва
удаляй все к оленям. что внутри:
static byte old_sec;
static uint32_t dot_timer;
if (old_sec != second)
{
dot_timer = millis();
old_sec = second;
Dot = true;
}

в loop загоняй такой кусок

static uint32_t dot_timer=0;
if (millis()-dot_timer)>500
{
dot_timer = millis();
Dot=!Dot;
}

А далее все будет зависеть от частоты перерисовки часов. Они тоже должны рисоваться минимум 2 раза в секунду
 
  • Лойс +1
Реакции: ASM

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
@Старик Похабыч, точки лезут везде, и в датчиках даже) в часах не мигают)
Код:
..
Время записано!
15:10:41
Dot 0
15:10:41
Dot 1
24 | 24.32
6 | 6.88
746 | 746.70
15:10:48
Dot 0
15:10:49
Dot 0
15:10:50
Dot 0
15:10:51
Dot 0
15:10:52
Dot 0
15:10:53
Dot 0
24 | 24.34
6 | 6.69
746 | 746.76
15:11:0
Dot 1
15:11:1
Dot 1
15:11:2
Dot 1
15:11:3
Dot 1
15:11:4
Dot 1
15:11:5
Dot 1
24 | 24.33
6 | 6.75
746 | 746.77
15:11:12
Dot 0
надо переделывать нашу елочку с выводом датчиков, на возможность в настройках включать, сколько по времени выводить каждый датчик.
я так думаю, текущий код не позволяет это сделать)
C++:
  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;
      }
    }
ты же что-то с case показывал пример, думаю стоит его разобрать) =>
 
Изменено:

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
разобрался с кодом, но сразу возникают вопросы, если сделать чаще опросы, или как некоторые просят время 54 сек, датчик 2, датчик 2, датчик 2, то получается очень много case?)
C++:
void loop_test() {
  uint32_t tmrall = millis() % t_summ * 1000 / 1000; //
  switch (tmrall)
  {
    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
      {
        TimeToArray();
      }
      break;
    case 6:
    case 7:
      {
        TempToArray();
      }
      break;
    case 8:
    case 9:
      {
        TempStreetToArray();
      }
      break;

    case 10:
    case 11:
      {
        PressToArray();
      }
      break;
    case 12:
    case 13:
      break;

  }
  uint32_t last_show;
  if (millis() - last_show > 100)
  {
    FastLED.show();
    last_show = millis();
  }
}
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,251
1,297
Москва
Да, тогда такое на фиг не надо.
Теперь делаем по взрослому.
Считай что у тебя 4 режима работы: 0- время, 1 датчик 1, 2 датчик 2, 3 датчики 3.

Изначально у тебя режим 0. Запоминаешь время начала режима. оно будет ВРЕМЯ (так для всех режимов), устанавливаешь ОТРЕЗОК_ВРЕМНИЕ для текущего режима, оно будет 54.

И далее делаешь так:

если (миллис()-ВРЕМЯ > ОТРЕЗОК_ВРЕМЕНИ )то
{
если (РЕЖИМ ==3), то режим будет 0, иначе РЕЖИМ++;
ОТРЕЗОКВРЕМЕНИ=сколькодлиться_режим (РЕЖИМ)
}

Это все было о выборе режима по интервалам.
Теперь надо выводить данные.
Выводить их можно 2-мя способоами: по времени и по изменению содержимого. Давай по времени
если (millis()-ВРЕМЯПОСЛЕДНЕГОВЫВОДА> ИНТЕРВАЛА ВЫВОДА)
{
ВРЕМЯПОСЛЕДНЕГОВЫВОДА=millis();
выводим данные исходя из режима
}
 
  • Лойс +1
Реакции: ASM