Большие часы на адресных светодиодах WS2812B

Большие часы на адресных светодиодах WS2812B
Всем привет, хочу рассказать о том как я попробовал повторить проект, но столкнулся с некоторыми проблемами.

Как-то раз на просторах зарубежного интернета я нашел вот такой проект часов на базе светодиодной ленты WS2812B: Big, Auto Dim, Room Clock, и мне захотелось его повторить. Часы устроены как семи сегментный циферблат и работают на RTC модуле DS3231 . Часы умеют показывать температуру, имеют кнопки для настройки и перевода на зимнее время и обратно, позже я добавил датчик влажности DHT11. Температура уже вместе с влажностью считывалась с этого датчика и выводилась раз в минуту. Хоть и в модуле часов есть температурный датчик, но похоже он показывал температуру не корректно из-за самонагрева (ИМХО).




Untitled Sketch_МП.png
И главное нанести много горячих соплей

IMG_20180907_120755.jpg


Когда все было собрано, повозившись с библиотеками, все заработало. И тут возникло одно большое НО: положения яркости в только в двух позициях меня не устраивало. Тем более на границе значений происходило мерцание. Установка яркости на статичном значении меня тоже не очень устраивала ибо днем при установленном тусклом свете ничего не было видно, а ночью даже со значениями близким к минимуму можно было осветить всю Москву. Поинтересовавшись как в других проектах с этим справляется Alex было решено заменить такой код настройки яркости.

C:
void BrightnessCheck(){
  const byte sensorPin = BRI_PIN; // light sensor pin
  const byte brightnessLow = 1; // Low brightness value
  const byte brightnessHigh = 50; // High brightness value
  int sensorValue = analogRead(sensorPin); // Read sensor
  Serial.print("Sensor is: ");Serial.println(sensorValue);
  sensorValue = map(sensorValue, 0, 255, 1, 100);
  LEDS.setBrightness(sensorValue);
  };
вот такими строчками:
C:
void BrightnessCheck() {

  if (auto_bright) {                         // если включена адаптивная яркость
    if (millis() - bright_timer > 100) {     // каждые 100 мс
      bright_timer = millis();               // сброить таймер
      new_bright = map(analogRead(BRI_PIN), 0, bright_constant, min_bright, max_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);      // установить новую яркость
    }
  }
};

Тут стоит упомянуть что программистом я не являюсь и большинство проблем я пытаюсь решить методом тыка и перебора.

И тут все заработало, моей радости не было придела, пока не наступила ночь. Появилась проблема с отключением ленты при полной темноте. Иногда это было только на минуту, а иногда на целую ночь. Еще есть проблема со слабим мерцанием светодиодов если освещения в комнате было мало (например когда работал телик), но это было редко и длилось это одну минуту.

Что касается кода вот сылка на GitHub. Кое-что я перевел для лучшего понимания.

Давно хотел поделиться готовым и работоспособным проектом в кругах аудитории Алекса, но вышло так что собственно нормальной работоспособностью тут не пахнет. Буду благодарени, если у кто сможет помочь.
 
Изменено:

Комментарии

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

★★★★★★★
14 Авг 2019
4,253
1,297
Москва
Но лучше все равно сделать доп. проверку. Сейчас у тебя интервал идет по 1 секунде, а если сделаешь по 1 минуте ? Сколько раз за минуту будет сервер долбить ? А потом кто то с шаловливыми ручонками залезет в прошивку и поменяет значения... Забанят Россию на всех серверах времени перманентно
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
Но лучше все равно сделать доп. проверку
если делать доп. проверку, то не будет принудительного обновления при включении, сейчас при включении обновились принудительно и пошел цикл, который проверяет, прошли ли 12 часов, которые указаны в настройках, если нет, то работает как обычно, если прошли, то обновляем время и заново ждем интервала в 12 часов...
такой вариант лучше будет?
C++:
#include <ESP8266WiFi.h>
#include <EasyNTPClient.h>
#include <WiFiUdp.h>
#include <RTClib.h>
RTC_DS3231 rtc;

int UpdatePeriod = 12; //период в часах
int Period = UpdatePeriod * 3600; //вычисление секунд

const char *ssid = "";
const char *password = "";

WiFiUDP udp;
EasyNTPClient ntpClient(udp, "pool.ntp.org", (3 * 60 * 60));

void setup() {
  Serial.begin(115200);
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  Serial.println("Обновление");
  syncTime();
}

void syncTime() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  long ntpTime = ntpClient.getUnixTime();
  rtc.adjust(DateTime(ntpTime));
  Serial.println("Обновление...");

  // Выключаем WIFI после обновления
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  WiFi.forceSleepBegin();
  delay(1000);
}
int GetTime() {
  DateTime now = rtc.now();
  Serial.print(now.hour());   Serial.print(":"); 
  Serial.print(now.minute()); Serial.print(":"); 
  Serial.println(now.second()); 
  delay(1000);
};
void loop() {
  uint32_t newtime = millis()%1000;
  if (newtime < Period -1) {
    GetTime();
  }
  else {
    syncTime();
  }
}
 

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

★★★★★★★
14 Авг 2019
4,253
1,297
Москва
На словах выглядит похоже. В коде тоже. Т.к. длительность подключения и к сети займет скорее всего больше 1 секунды, то должно сработать.

Вот это плохо:
C++:
while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
Тут , если не будет доступа к инету, будет зависон капитальный. Если 10 раз не вышло подключиться - надо выходить без обновления времени, а что делать. При этом можно сократить время до следующего обновления.

При получении даты лучше сравнить ее например с последней полученной, или еще с какой реально, но не прям сейчашной, должна быть больше скажем 2020-го года. На случай сбоя и получения даты 1970г
 
  • Лойс +1
Реакции: ASM

bort707

★★★★★★✩
21 Сен 2020
3,046
909
если делать доп. проверку, то не будет принудительного обновления при включении, сейчас при включении обновились принудительно и пошел цикл, который проверяет, прошли ли 12 часов, которые указаны в настройках, если нет, то работает как обычно, если прошли, то обновляем время и заново ждем интервала в 12 часов...
@ASM, все эти проблемы с периодами происходят от того, что вы выбрали, на мой взягляд, неудачный принцип отсчета интервалов. Логика деления миллис на период - If( millis() % period) - имхо, довольно-таки кривая. Я бы вместо этого пользовался традиционным вычитанием if ((millis() - old_millis) > period)
 
  • Лойс +1
Реакции: ASM

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

★★★★★★★
14 Авг 2019
4,253
1,297
Москва
А вообще , если так жестко привязываться к вайфаю, то можно вообще без RTC обойтись.
Можно использовать модуль #
include <time.h>
После подключения вайфай периодически выравнивать часы по сетевому времени (3 это часовой пояс для МСК):
configTime(3600 * 3, 0, "pool.ntp.org");
А с периодичностью в 1 сек в монитор порта выводить:
tnow = time(nullptr);
Serial.print(String(ctime(&tnow)));

На ESP8266 работает.
 

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

★★★★★★★
14 Авг 2019
4,253
1,297
Москва
Тут если хотя бы раз считано время с сети, то какое то время часы будут идти, так же как RTC, по внутренним часам, если питание не пропадет. У RTC тут один плюс - встроенная батарейка, которая хранит время в случае потери питания. ESP так не сделает, для этого надо брать STM :D
 

ASM

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

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

★★★★★★★
14 Авг 2019
4,253
1,297
Москва
Ну я написал МОЖНО, а не НУЖНО.
Можно используя define сделать разные версии, где то включать подключение к WIFI , где то отключать RTC и использовать только WIFI. а при отсутствии RTC и сигнала WIFI выдавать какое то сообщение на дисплее. Есть чем развлечься следующие пару месяцев :D
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
@Старик Похабыч, не, этого пока не нужно) нам надо запустить ESP на наших часах чтобы работали) потом можно пилить различные фишечки связанные с WiFi))
if ((millis() - old_millis) > period)
не понимаю, old_millis тут откуда берется, к чему привязать?)
C++:
while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
так лучше?)
C++:
  if (WiFi.status() != WL_CONNECTED) {
    for (uint8_t i = 0; i > 10; i++) {
      delay(500);
      Serial.print(".");
    }
  }
  else {
    Serial.println("Connected!");
  }
}
 
Изменено:

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
При получении даты лучше сравнить ее например с последней полученной, или еще с какой реально, но не прям сейчашной, должна быть больше скажем 2020-го года. На случай сбоя и получения даты 1970г
C++:
void syncTime() {
  WiFi.begin(ssid, password);
  /*
    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    }*/
  if (WiFi.status() != WL_CONNECTED) {
    for (uint8_t i = 0; i > 10; i++) {
      delay(500);
      Serial.print(".");
    }
  }
  else {
    Serial.println("Connected!");
  }
    long ntpTime = ntpClient.getUnixTime();
    if (ntpTime > 1609459200){
    rtc.adjust(DateTime(ntpTime));
    Serial.println("Обновление...");
    // Выключаем WIFI после обновления
    WiFi.disconnect();
    WiFi.mode(WIFI_OFF);
    WiFi.forceSleepBegin();
    delay(1000);
  }
  else
  {
    Serial.print("Error Date");
    GetTime();
  }
}
вот)
 
Изменено:

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

★★★★★★★
14 Авг 2019
4,253
1,297
Москва
Вот так я делаю на 10 попыток
C++:
byte trys=0;
  while (WiFi.status() != WL_CONNECTED) {
    trys++;
    delay(500);
    Serial.print(".");
    if (trys>10)
      {
      Serial.println("no connection!");
      return false;
      }
  }
 

bort707

★★★★★★✩
21 Сен 2020
3,046
909
тогда так сделаю)
C++:
 if (millis() % 1000 < Period - 1)
{GetTime();}
  else
{syncTime();}
Можете обьяснить, зачемтак делать?
это же безумно кривой код...
Вы хотя бы задумывались, как он работает?
Первая часть условия if - millis() % 1000 - означает что Период у вас не может быть длиннее секунды.
Предположим, период Period = 500
Тогда получается. что каждую миллисекунду первые 500мс вы читаете время с RTC - (зачем???)
А в вторую половину секунду - с максимально взможной частотой долбите запросами NTP сервер
Такое впечатление, что вы этот код где-то списали и не понимаете в нем ни буквы.

Вам что нужно - раз в period сделать синхронизацию времени с сервера? - так что мешает сделать это классически через миллис?
 
Изменено:

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

★★★★★★★
14 Авг 2019
4,253
1,297
Москва
Объясню, ранее был вывод по 3 скеунды туда, 2 секунды сюда, 4 на это и 3 на то. Вот в воспоминания того вывода все и упирается. А задача да, другая
 

bort707

★★★★★★✩
21 Сен 2020
3,046
909
Объясню, ранее был вывод по 3 скеунды туда, 2 секунды сюда, 4 на это и 3 на то. Вот в воспоминания того вывода все и упирается. А задача да, другая
да. я помню, там с этими периодами тоже был откровенный г-код :) Но он хотя бы работал :) А теперь ребята "из того же материала" пытаются слепить конфетку. Так не бывает. Работу со временем надо переписать нормально
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
@bort707, так напиши как надо, что тянешь то, есть замечание, напиши как надо)) я и так один пишу, не зная программирования)) такими темпами до лета будем делать))
Вопрос назревал давно перейти на ESP, но что-то на этом заглохло) вот я сел писать, помогайте))
 

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

★★★★★★★
14 Авг 2019
4,253
1,297
Москва
Так ты учись! Разные задачи требуют разных методов. Можно так все сделать через хитрое очко, что люди языком будут цокать!
А как сделаешь ты, это только тебе решать
 

ASM

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

bort707

★★★★★★✩
21 Сен 2020
3,046
909
я и так один пишу, не зная программирования
меня это и удивляет. нафига ты взялся писать, не зная программирования? :) А взялся - так изучай. иначе ничего хорошего не выйдет.
Вот этот урок Гайвера не читал? Уроки Ардуино Функции времени
Смотри внимательно раздел "Таймер на миллис", в конце даже пример есть на несколько таймеров разом

@Старик Похабыч, так я же для всех делаю, а не какой-то платный заказ) вместе же проще)
ну так и мы же тебе все время подсказываем, разве нет ? :)

Понимаешь, мы с Похабычем легко могли бы за вас все написать. Я даже сказал бы, что все что вы тут мучаете пару месяцев - любой из нас написал бы за один вечер. Но нафига??? смысл ведь не в том. чтобы часы сделать., смысл научиться чему-то новому. Научиться ты должен сам, а не мы тебе поднести на блюде
 
Изменено:

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
смысл научиться чему-то новому
этим надо постоянно заниматься, через полгода все забудется, надо будет заново вспоминать...
В школе изучали Паскаль, у меня была пятерка)) Если сейчас сяду, то надо все заново изучать, ничего уже не помню)))
 

bort707

★★★★★★✩
21 Сен 2020
3,046
909
этим надо постоянно заниматься, через полгода все забудется, надо будет заново вспоминать...
понадобится - изучишь во второй раз . Еще раз забудешь - так и в третий.
Могу тебя порадовать на личном опыте - после третьего изучения в голове остается существенно больше, чем после первого :)))