mirror of
https://github.com/AlexGyver/GyverLamp2.git
synced 2025-08-06 16:27:23 +03:00
0.11b
This commit is contained in:
Binary file not shown.
@@ -1,20 +1,36 @@
|
||||
// 0.10
|
||||
// исправлена обработка ключа
|
||||
// добавлена совместимость с nodemcu
|
||||
// поворот матрицы
|
||||
// обновление прошивок для разных схем
|
||||
// исправлен цвет огня
|
||||
// индикация обновления при запуске
|
||||
/*
|
||||
Версия 0.11b
|
||||
Добавлен редактор палитр
|
||||
Исправлены мелкие баги в эффектах
|
||||
Переподключение к роутеру после сброса сети
|
||||
Настройка ориентации матрицы из приложения
|
||||
Переработан эффект "Частицы"
|
||||
Добавлена скорость огня
|
||||
Переключение на новый/выбранный режим при редактировании
|
||||
Отправка времени из сервиса (для АР)
|
||||
Выключение по таймеру теперь плавное
|
||||
Добавлен рассвет
|
||||
|
||||
// мигает 8:
|
||||
// красным - не смог подключиться к АР
|
||||
// зелёным - смог подключиться к АР
|
||||
// жёлтым - создал свою АП
|
||||
// бирюзовым - успешно обновился на новую версию
|
||||
// синим - обновился на ту же версию
|
||||
// розовым - сброс всех настроек (первый запуск)
|
||||
TODO:
|
||||
плавная смена режимов
|
||||
Аккуратнее со светомузыкой!
|
||||
4 клика вкл выкл смену?
|
||||
Mqtt?
|
||||
Базовый пак
|
||||
Предложения Серёги крутского
|
||||
Убрать аплод?
|
||||
Огонь 2018/2020?
|
||||
Взять огонь отсюда https://community.alexgyver.ru/threads/wifi-lampa-budilnik-obsuzhdenie-proshivki-ot-gunner47.2418/page-72#post-33652
|
||||
Вернуть искры
|
||||
Эффект погода https://it4it.club/topic/40-esp8266-i-parsing-pogodyi-s-openweathermap/
|
||||
Эффект часы
|
||||
*/
|
||||
|
||||
// Generic ESP8266, 4MB (FS:2MB OTA)
|
||||
// ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ! ВНИМАНИЕ!
|
||||
// ДЛЯ КОМПИЛЯЦИИ ПРОШИВКИ ПОД NODEMCU/WEMOS/ESP01/ESP12 ВЫБИРАТЬ
|
||||
// Инструменты/Плата Generic ESP8266
|
||||
// Инструменты/Flash Size 4MB (FS:2MB OTA)
|
||||
// При прошивке с других прошивок лампы поставить: Инструменты/Erase Flash/All Flash Contents
|
||||
// ESP core 2.7.4+ http://arduino.esp8266.com/stable/package_esp8266com_index.json
|
||||
// FastLED 3.4.0+ https://github.com/FastLED/FastLED/releases
|
||||
|
||||
@@ -49,11 +65,12 @@ const char AP_NameChar[] = "GyverLamp2";
|
||||
const char WiFiPassword[] = "12345678";
|
||||
|
||||
// ------------ Прочее -------------
|
||||
#define GL_VERSION 010
|
||||
#define GL_VERSION 011 // код версии прошивки
|
||||
#define EE_TOUT 30000 // таймаут сохранения епром после изменения, мс
|
||||
#define DEBUG_SERIAL // закомментируй чтобы выключить отладку (скорость 115200)
|
||||
#define EE_KEY 44 // ключ сброса WiFi (измени для сброса всех настроек)
|
||||
//#define DEBUG_SERIAL // закомментируй чтобы выключить отладку (скорость 115200)
|
||||
#define EE_KEY 50 // ключ сброса WiFi (измени для сброса всех настроек)
|
||||
#define NTP_UPD_PRD 5 // период обновления времени с NTP сервера, минут
|
||||
//#define SKIP_WIFI // пропустить подключение к вафле (для отладки)
|
||||
|
||||
// ------------ БИЛДЕР -------------
|
||||
//#define MAX_LEDS 1200
|
||||
@@ -82,11 +99,13 @@ const char WiFiPassword[] = "12345678";
|
||||
#include <WiFiUdp.h> // общение по UDP
|
||||
#include <EEPROM.h> // епром
|
||||
#include "ESP8266httpUpdate.h" // OTA
|
||||
#include "mString.h" // стринг билдер
|
||||
|
||||
// ------------------- ДАТА --------------------
|
||||
Config cfg;
|
||||
Preset preset[MAX_PRESETS];
|
||||
Dawn dawn;
|
||||
Palette pal;
|
||||
WiFiServer server(80);
|
||||
WiFiUDP Udp;
|
||||
WiFiUDP ntpUDP;
|
||||
@@ -94,43 +113,48 @@ NTPClient ntp(ntpUDP);
|
||||
CRGB leds[MAX_LEDS];
|
||||
Time now;
|
||||
Button btn(BTN_PIN);
|
||||
timerMillis EEtmr(EE_TOUT), turnoffTmr;
|
||||
timerMillis EEtmr(EE_TOUT), turnoffTmr, connTmr(120000), dawnTmr;
|
||||
TimeRandom trnd;
|
||||
VolAnalyzer vol(A0), low, high;
|
||||
FastFilter phot;
|
||||
|
||||
byte btnClicks = 0, brTicks = 0;
|
||||
unsigned char matrixValue[11][16];
|
||||
bool gotNTP = false;
|
||||
bool gotNTP = false, gotTime = false;
|
||||
void blink8(CRGB color);
|
||||
|
||||
// ------------------- SETUP --------------------
|
||||
void setup() {
|
||||
delay(800);
|
||||
delay(2000); // ждём старта есп
|
||||
memset(matrixValue, 0, sizeof(matrixValue));
|
||||
#ifdef DEBUG_SERIAL
|
||||
Serial.begin(115200);
|
||||
DEBUGLN();
|
||||
#endif
|
||||
EEPROM.begin(512); // старт епром
|
||||
startStrip(); // старт ленты
|
||||
startStrip(); // старт ленты
|
||||
btn.setLevel(digitalRead(BTN_PIN)); // смотрим что за кнопка
|
||||
EE_startup(); // читаем епром
|
||||
#ifndef SKIP_WIFI
|
||||
checkUpdate(); // индикация было ли обновление
|
||||
showRGB(); // показываем ргб
|
||||
showRGB(); // показываем ргб
|
||||
checkGroup(); // показываем или меняем адрес
|
||||
checkButton(); // проверяем кнопку на удержание
|
||||
startWiFi(); // старт вайфай
|
||||
setupTime(); // выставляем время
|
||||
#endif
|
||||
setupADC(); // настраиваем анализ
|
||||
presetRotation(true); // форсировать смену режима
|
||||
}
|
||||
|
||||
void loop() {
|
||||
timeTicker(); // обновляем время
|
||||
#ifndef SKIP_WIFI
|
||||
tryReconnect(); // пробуем переподключиться если WiFi упал
|
||||
yield();
|
||||
parsing(); // ловим данные
|
||||
yield();
|
||||
#endif
|
||||
checkEEupdate(); // сохраняем епром
|
||||
presetRotation(0); // смена режимов по расписанию
|
||||
effectsRoutine(); // мигаем
|
||||
|
@@ -3,7 +3,7 @@ class Time {
|
||||
byte sec = 0;
|
||||
byte min = 0;
|
||||
byte hour = 0;
|
||||
byte day = 0; // пн 0, вт 2.. вс 6
|
||||
byte day = 0;
|
||||
int ms = 0;
|
||||
uint32_t weekMs = 0;
|
||||
uint32_t weekS = 0;
|
||||
|
@@ -17,8 +17,7 @@ void button() {
|
||||
DEBUGLN(btnClicks);
|
||||
switch (btnClicks) {
|
||||
case 1:
|
||||
setPower(!cfg.state);
|
||||
sendToSlaves(0, cfg.state);
|
||||
controlHandler(!cfg.state);
|
||||
break;
|
||||
case 2:
|
||||
changePreset(1);
|
||||
|
@@ -48,18 +48,21 @@ const char *OTAfile[] = {
|
||||
"module_1200.bin",
|
||||
};
|
||||
|
||||
const char *NTPservers[] = {
|
||||
"pool.ntp.org",
|
||||
"europe.pool.ntp.org",
|
||||
"ntp1.stratum2.ru",
|
||||
"ntp2.stratum2.ru",
|
||||
"ntp.msk-ix.ru",
|
||||
const char NTPserver[] = "pool.ntp.org";
|
||||
//"pool.ntp.org"
|
||||
//"europe.pool.ntp.org"
|
||||
//"ntp1.stratum2.ru"
|
||||
//"ntp2.stratum2.ru"
|
||||
//"ntp.msk-ix.ru"
|
||||
|
||||
struct Palette {
|
||||
byte size = 1;
|
||||
byte strip[16 * 3];
|
||||
};
|
||||
|
||||
#define CFG_SIZE 13
|
||||
struct Config {
|
||||
byte GMT = 3; // часовой пояс +13
|
||||
byte NTP = 1; // 1..5 ВЫЧЕСТЬ 1
|
||||
byte bright = 100; // яркость
|
||||
byte adcMode = 1; // режим ацп (1 выкл, 2 ярк, 3 муз)
|
||||
byte minBright = 0; // мин яркость
|
||||
@@ -71,9 +74,11 @@ struct Config {
|
||||
byte maxCur = 5; // макс ток (мА/100)
|
||||
byte workFrom = 0; // часы работы (0,1.. 23)
|
||||
byte workTo = 0; // часы работы (0,1.. 23)
|
||||
int16_t length = 100; // длина ленты
|
||||
int16_t width = 1; // ширина матрицы
|
||||
byte mTurn = 0;
|
||||
byte matrix = 1; // тип матрицы 1.. 8
|
||||
|
||||
int16_t length = 100; // длина ленты
|
||||
int16_t width = 1; // ширина матрицы
|
||||
uint32_t cityID = 1; // city ID
|
||||
|
||||
byte state = 1; // состояние 0 выкл, 1 вкл
|
||||
byte group = 1; // группа девайса (1-10)
|
||||
@@ -82,8 +87,8 @@ struct Config {
|
||||
byte presetAmount = 1; // количество режимов
|
||||
byte manualOff = 0; // выключали вручную?
|
||||
int8_t curPreset = 0; // текущий режим
|
||||
int16_t minLight = 0; // мин освещённость
|
||||
int16_t maxLight = 1023; // макс освещённость
|
||||
int16_t minLight = 0; // мин освещённость
|
||||
int16_t maxLight = 1023;// макс освещённость
|
||||
char ssid[32]; // логин wifi
|
||||
char pass[32]; // пароль wifi
|
||||
byte version = GL_VERSION;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
bool EEcfgFlag = false;
|
||||
bool EEdawnFlag = false;
|
||||
bool EEpresetFlag = false;
|
||||
bool EEpalFlag = false;
|
||||
|
||||
void EE_startup() {
|
||||
// старт епром
|
||||
@@ -8,18 +9,23 @@ void EE_startup() {
|
||||
EEPROM.write(511, EE_KEY);
|
||||
EEPROM.put(0, cfg);
|
||||
EEPROM.put(sizeof(cfg), dawn);
|
||||
EEPROM.put(sizeof(cfg) + sizeof(dawn), preset);
|
||||
EEPROM.put(sizeof(cfg) + sizeof(dawn), pal);
|
||||
EEPROM.put(sizeof(cfg) + sizeof(dawn) + sizeof(pal), preset);
|
||||
EEPROM.commit();
|
||||
blink8(CRGB::Pink);
|
||||
DEBUGLN("First start");
|
||||
}
|
||||
EEPROM.get(0, cfg);
|
||||
EEPROM.get(sizeof(cfg), dawn);
|
||||
EEPROM.get(sizeof(cfg) + sizeof(dawn), preset);
|
||||
EEPROM.get(sizeof(cfg) + sizeof(dawn), pal);
|
||||
EEPROM.get(sizeof(cfg) + sizeof(dawn) + sizeof(pal), preset);
|
||||
|
||||
DEBUG("EEPR size: ");
|
||||
DEBUGLN(sizeof(cfg) + sizeof(dawn) + sizeof(pal) + sizeof(preset));
|
||||
|
||||
// запускаем всё
|
||||
//trnd.setChannel(cfg.group);
|
||||
FastLED.setMaxPowerInVoltsAndMilliamps(STRIP_VOLT, cfg.maxCur * 100);
|
||||
updPal();
|
||||
}
|
||||
|
||||
void EE_updateCfg() {
|
||||
@@ -34,6 +40,10 @@ void EE_updatePreset() {
|
||||
EEpresetFlag = true;
|
||||
EEtmr.restart();
|
||||
}
|
||||
void EE_updatePal() {
|
||||
EEpalFlag = true;
|
||||
EEtmr.restart();
|
||||
}
|
||||
void checkEEupdate() {
|
||||
if (EEtmr.isReady()) {
|
||||
if (EEcfgFlag || EEdawnFlag || EEpresetFlag) {
|
||||
@@ -47,11 +57,16 @@ void checkEEupdate() {
|
||||
EEPROM.put(sizeof(cfg), dawn);
|
||||
DEBUGLN("save dawn");
|
||||
}
|
||||
if (EEpalFlag) {
|
||||
EEpalFlag = false;
|
||||
EEPROM.put(sizeof(cfg) + sizeof(dawn), pal);
|
||||
DEBUGLN("save pal");
|
||||
}
|
||||
if (EEpresetFlag) {
|
||||
EEpresetFlag = false;
|
||||
EEPROM.put(sizeof(cfg) + sizeof(dawn), preset);
|
||||
EEPROM.put(sizeof(cfg) + sizeof(dawn) + sizeof(pal), preset);
|
||||
DEBUGLN("save preset");
|
||||
}
|
||||
}
|
||||
EEPROM.commit();
|
||||
}
|
||||
EEtmr.stop();
|
||||
|
@@ -1,12 +1,30 @@
|
||||
void effectsRoutine() {
|
||||
static timerMillis effTmr(30, true);
|
||||
static byte prevEff = 255;
|
||||
|
||||
if (dawnTmr.running()) {
|
||||
if (effTmr.isReady()) {
|
||||
fill_solid(leds, MAX_LEDS, ColorFromPalette(HeatColors_p, dawnTmr.getLength8(), scaleFF(dawnTmr.getLength8(), dawn.bright), LINEARBLEND));
|
||||
FastLED.show();
|
||||
}
|
||||
if (dawnTmr.isReady()) dawnTmr.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cfg.state && effTmr.isReady()) {
|
||||
int thisLength = getLength();
|
||||
byte thisScale = getScale();
|
||||
int thisWidth = (cfg.deviceType > 1) ? cfg.width : 1;
|
||||
byte thisBright = getBright();
|
||||
|
||||
if (turnoffTmr.running()) thisBright = scaleFF(thisBright, 255 - turnoffTmr.getLength8());
|
||||
if (turnoffTmr.isReady()) {
|
||||
turnoffTmr.stop();
|
||||
setPower(0);
|
||||
return;
|
||||
}
|
||||
FastLED.setBrightness(thisBright);
|
||||
|
||||
FastLED.setBrightness(getBright());
|
||||
if (prevEff != CUR_PRES.effect) {
|
||||
FastLED.clear();
|
||||
prevEff = CUR_PRES.effect;
|
||||
@@ -18,10 +36,10 @@ void effectsRoutine() {
|
||||
FOR_j(0, cfg.length) {
|
||||
FOR_i(0, cfg.width) {
|
||||
leds[getPix(i, j)] = ColorFromPalette(paletteArr[CUR_PRES.palette - 1],
|
||||
inoise8(
|
||||
i * (thisScale / 5) - cfg.width * (thisScale / 5) / 2,
|
||||
j * (thisScale / 5) - cfg.length * (thisScale / 5) / 2,
|
||||
(now.weekMs >> 1) * CUR_PRES.speed / 255),
|
||||
scalePal(inoise8(
|
||||
i * (thisScale / 5) - cfg.width * (thisScale / 5) / 2,
|
||||
j * (thisScale / 5) - cfg.length * (thisScale / 5) / 2,
|
||||
(now.weekMs >> 1) * CUR_PRES.speed / 255)),
|
||||
255, LINEARBLEND);
|
||||
}
|
||||
}
|
||||
@@ -29,12 +47,13 @@ void effectsRoutine() {
|
||||
} else {
|
||||
FOR_i(0, cfg.length) {
|
||||
leds[i] = ColorFromPalette(paletteArr[CUR_PRES.palette - 1],
|
||||
inoise8(i * (thisScale / 5) - cfg.length * (thisScale / 5) / 2,
|
||||
(now.weekMs >> 1) * CUR_PRES.speed / 255),
|
||||
scalePal(inoise8(i * (thisScale / 5) - cfg.length * (thisScale / 5) / 2,
|
||||
(now.weekMs >> 1) * CUR_PRES.speed / 255)),
|
||||
255, LINEARBLEND);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // ==================================== ЦВЕТ ====================================
|
||||
{
|
||||
fill_solid(leds, cfg.length * thisWidth, CHSV(CUR_PRES.color, thisScale, CUR_PRES.min));
|
||||
@@ -47,11 +66,12 @@ void effectsRoutine() {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // ================================= СМЕНА ЦВЕТА =================================
|
||||
{
|
||||
CRGB thisColor = ColorFromPalette(paletteArr[CUR_PRES.palette - 1], (now.weekMs >> 5) * CUR_PRES.speed / 255, CUR_PRES.min, LINEARBLEND);
|
||||
CRGB thisColor = ColorFromPalette(paletteArr[CUR_PRES.palette - 1], scalePal((now.weekMs >> 5) * CUR_PRES.speed / 255), CUR_PRES.min, LINEARBLEND);
|
||||
fill_solid(leds, cfg.length * thisWidth, thisColor);
|
||||
thisColor = ColorFromPalette(paletteArr[CUR_PRES.palette - 1], (now.weekMs >> 5) * CUR_PRES.speed / 255, CUR_PRES.max, LINEARBLEND);
|
||||
thisColor = ColorFromPalette(paletteArr[CUR_PRES.palette - 1], scalePal((now.weekMs >> 5) * CUR_PRES.speed / 255), CUR_PRES.max, LINEARBLEND);
|
||||
if (CUR_PRES.fromCenter) {
|
||||
fillStrip(cfg.length / 2, cfg.length / 2 + thisLength / 2, thisColor);
|
||||
fillStrip(cfg.length / 2 - thisLength / 2, cfg.length / 2, thisColor);
|
||||
@@ -60,6 +80,7 @@ void effectsRoutine() {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // ================================== ГРАДИЕНТ ==================================
|
||||
if (CUR_PRES.fromCenter) {
|
||||
FOR_i(cfg.length / 2, cfg.length) {
|
||||
@@ -67,7 +88,7 @@ void effectsRoutine() {
|
||||
if (CUR_PRES.soundReact == GL_REACT_LEN) bright = (i < cfg.length / 2 + thisLength / 2) ? (CUR_PRES.max) : (CUR_PRES.min);
|
||||
CRGB thisColor = ColorFromPalette(
|
||||
paletteArr[CUR_PRES.palette - 1], // (x*1.9 + 25) / 255 - быстрый мап 0..255 в 0.1..2
|
||||
(i * (thisScale * 1.9 + 25) / cfg.length) + ((now.weekMs >> 3) * (CUR_PRES.speed - 128) / 128),
|
||||
scalePal((i * (thisScale * 1.9 + 25) / cfg.length) + ((now.weekMs >> 3) * (CUR_PRES.speed - 128) / 128)),
|
||||
bright, LINEARBLEND);
|
||||
if (cfg.deviceType > 1) fillRow(i, thisColor);
|
||||
else leds[i] = thisColor;
|
||||
@@ -81,16 +102,41 @@ void effectsRoutine() {
|
||||
if (CUR_PRES.soundReact == GL_REACT_LEN) bright = (i < thisLength) ? (CUR_PRES.max) : (CUR_PRES.min);
|
||||
CRGB thisColor = ColorFromPalette(
|
||||
paletteArr[CUR_PRES.palette - 1], // (x*1.9 + 25) / 255 - быстрый мап 0..255 в 0.1..2
|
||||
(i * (thisScale * 1.9 + 25) / cfg.length) + ((now.weekMs >> 3) * (CUR_PRES.speed - 128) / 128),
|
||||
scalePal((i * (thisScale * 1.9 + 25) / cfg.length) + ((now.weekMs >> 3) * (CUR_PRES.speed - 128) / 128)),
|
||||
bright, LINEARBLEND);
|
||||
if (cfg.deviceType > 1) fillRow(i, thisColor);
|
||||
else leds[i] = thisColor;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: // =================================== ЧАСТИЦЫ ===================================
|
||||
FOR_i(0, cfg.length * cfg.width) leds[i].fadeToBlackBy(70);
|
||||
if (cfg.deviceType > 1) {
|
||||
{
|
||||
uint16_t rndVal = 0;
|
||||
FOR_i(0, thisScale / 8 + 1) {
|
||||
rndVal = rndVal * 2053 + 13849; // random2053 алгоритм
|
||||
int homeX = inoise16(i * 100000000ul + (now.weekMs << 3) * CUR_PRES.speed / 255);
|
||||
homeX = map(homeX, 10000, 55000, 0, cfg.length);
|
||||
int offsX = inoise8(i * 2500 + (now.weekMs >> 1) * CUR_PRES.speed / 255) - 128;
|
||||
offsX = cfg.length / 2 * offsX / 128;
|
||||
int thisX = homeX + offsX;
|
||||
|
||||
if (cfg.deviceType > 1) {
|
||||
int homeY = inoise16(i * 100000000ul + 2000000000ul + (now.weekMs << 3) * CUR_PRES.speed / 255);
|
||||
homeY = map(homeY, 10000, 55000, 0, cfg.width);
|
||||
int offsY = inoise8(i * 2500 + 30000 + (now.weekMs >> 1) * CUR_PRES.speed / 255) - 128;
|
||||
offsY = cfg.length / 2 * offsY / 128;
|
||||
int thisY = homeY + offsY;
|
||||
setPix(thisX, thisY, CHSV(CUR_PRES.rnd ? rndVal : CUR_PRES.color, 255, 255));
|
||||
} else {
|
||||
setLED(thisX, CHSV(CUR_PRES.rnd ? rndVal : CUR_PRES.color, 255, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
FOR_i(0, cfg.length * cfg.width) leds[i].fadeToBlackBy(70);
|
||||
if (cfg.deviceType > 1) {
|
||||
uint16_t rndVal = 0;
|
||||
FOR_i(0, thisScale / 8) {
|
||||
int thisY = inoise16(i * 100000000ul + (now.weekMs << 6) * CUR_PRES.speed / 255);
|
||||
@@ -102,7 +148,7 @@ void effectsRoutine() {
|
||||
if (thisY >= 0 && thisY < cfg.length && thisX >= 0 && thisX < cfg.width)
|
||||
leds[getPix(thisX, thisY)] = CHSV(CUR_PRES.rnd ? rndVal : CUR_PRES.color, 255, 255);
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
uint16_t rndVal = 0;
|
||||
FOR_i(0, thisScale / 8) {
|
||||
int thisPos = inoise16(i * 100000000ul + (now.weekMs << 6) * CUR_PRES.speed / 255);
|
||||
@@ -110,12 +156,13 @@ void effectsRoutine() {
|
||||
rndVal = rndVal * 2053 + 13849; // random2053 алгоритм
|
||||
if (thisPos >= 0 && thisPos < cfg.length) leds[thisPos] = CHSV(CUR_PRES.rnd ? rndVal : CUR_PRES.color, 255, 255);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
break;
|
||||
|
||||
case 6: // ==================================== ОГОНЬ ====================================
|
||||
{
|
||||
if (cfg.deviceType > 1) { // 2D огонь
|
||||
fireRoutine();
|
||||
fireRoutine(CUR_PRES.speed / 2);
|
||||
} else { // 1D огонь
|
||||
static byte heat[MAX_LEDS];
|
||||
CRGBPalette16 gPal;
|
||||
@@ -138,16 +185,21 @@ void effectsRoutine() {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: // ================================== КОНФЕТТИ ==================================
|
||||
FOR_i(0, (thisScale >> 3) + 1) {
|
||||
byte x = random(0, cfg.length * cfg.width);
|
||||
int x = random(0, cfg.length * cfg.width);
|
||||
if (leds[x] == CRGB(0, 0, 0)) leds[x] = CHSV(CUR_PRES.rnd ? random(0, 255) : CUR_PRES.color, 255, 255);
|
||||
}
|
||||
FOR_i(0, cfg.length * cfg.width) {
|
||||
if (leds[i].r >= 10 || leds[i].g >= 10 || leds[i].b >= 10) leds[i].fadeToBlackBy(CUR_PRES.speed / 2);
|
||||
if (leds[i].r >= 10 || leds[i].g >= 10 || leds[i].b >= 10) leds[i].fadeToBlackBy(CUR_PRES.speed / 2 + 1);
|
||||
else leds[i] = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8: // ================================== ПОГОДА ==================================
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// выводим нажатия кнопки
|
||||
@@ -203,6 +255,13 @@ void fillRow(int row, CRGB color) {
|
||||
FOR_i(cfg.width * row, cfg.width * (row + 1)) leds[i] = color;
|
||||
}
|
||||
|
||||
void updPal() {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
paletteArr[0][i] = CRGB(pal.strip[i * 3], pal.strip[i * 3 + 1], pal.strip[i * 3 + 2]);
|
||||
}
|
||||
if (pal.size < 16) paletteArr[0][pal.size] = paletteArr[0][0];
|
||||
}
|
||||
|
||||
void blink8(CRGB color) {
|
||||
FOR_i(0, 3) {
|
||||
fill_solid(leds, 8, color);
|
||||
@@ -214,15 +273,37 @@ void blink8(CRGB color) {
|
||||
}
|
||||
}
|
||||
|
||||
byte scalePal(byte val) {
|
||||
if (CUR_PRES.palette == 1) val = val * pal.size / 16;
|
||||
return val;
|
||||
}
|
||||
|
||||
void setPix(int x, int y, CRGB color) {
|
||||
if (y >= 0 && y < cfg.length && x >= 0 && x < cfg.width) leds[getPix(x, y)] = color;
|
||||
}
|
||||
void setLED(int x, CRGB color) {
|
||||
if (x >= 0 && x < cfg.length) leds[x] = color;
|
||||
}
|
||||
|
||||
// получить номер пикселя в ленте по координатам
|
||||
uint16_t getPix(int x, int y) {
|
||||
if (cfg.mTurn) {
|
||||
byte b = x;
|
||||
x = y;
|
||||
y = b;
|
||||
int matrixW;
|
||||
if (cfg.matrix == 2 || cfg.matrix == 4 || cfg.matrix == 6 || cfg.matrix == 8) matrixW = cfg.length;
|
||||
else matrixW = cfg.width;
|
||||
int thisX, thisY;
|
||||
switch (cfg.matrix) {
|
||||
case 1: thisX = x; thisY = y; break;
|
||||
case 2: thisX = y; thisY = x; break;
|
||||
case 3: thisX = x; thisY = (cfg.length - y - 1); break;
|
||||
case 4: thisX = (cfg.length - y - 1); thisY = x; break;
|
||||
case 5: thisX = (cfg.width - x - 1); thisY = (cfg.length - y - 1); break;
|
||||
case 6: thisX = (cfg.length - y - 1); thisY = (cfg.width - x - 1); break;
|
||||
case 7: thisX = (cfg.width - x - 1); thisY = y; break;
|
||||
case 8: thisX = y; thisY = (cfg.width - x - 1); break;
|
||||
}
|
||||
if ( !(y & 1) || (cfg.deviceType - 2) ) return (y * cfg.width + x); // если чётная строка
|
||||
else return (y * cfg.width + cfg.width - x - 1); // если нечётная строка
|
||||
|
||||
if ( !(thisY & 1) || (cfg.deviceType - 2) ) return (thisY * matrixW + thisX); // чётная строка
|
||||
else return (thisY * matrixW + matrixW - thisX - 1); // нечётная строка
|
||||
}
|
||||
/*
|
||||
целочисленный мап
|
||||
|
@@ -27,10 +27,15 @@ const unsigned char hueMask[11][16] PROGMEM = {
|
||||
|
||||
byte fireLine[100];
|
||||
|
||||
void fireRoutine() {
|
||||
shiftUp();
|
||||
FOR_i(0, cfg.width) fireLine[i] = random(64, 255);
|
||||
drawFrame(30);
|
||||
void fireRoutine(byte speed) {
|
||||
static byte count = 0;
|
||||
if (count >= 100) {
|
||||
shiftUp();
|
||||
FOR_i(0, cfg.width) fireLine[i] = random(64, 255);
|
||||
count = 0;
|
||||
}
|
||||
drawFrame(count);
|
||||
count += speed;
|
||||
}
|
||||
|
||||
void shiftUp() {
|
||||
|
315
firmware/GyverLamp2/mString.h
Normal file
315
firmware/GyverLamp2/mString.h
Normal file
@@ -0,0 +1,315 @@
|
||||
// TODO
|
||||
// защита от переполнения
|
||||
|
||||
char* mUtoa(uint32_t value, char *buffer, bool clear = 1);
|
||||
char* mLtoa(int32_t value, char *buffer, bool clear = 1);
|
||||
char* mFtoa(double value, int8_t decimals, char *buffer);
|
||||
|
||||
char* mUtoa(uint32_t value, char *buffer, bool clear) {
|
||||
buffer += 11;
|
||||
if (clear) *--buffer = 0;
|
||||
do {
|
||||
*--buffer = value % 10 + '0';
|
||||
value /= 10;
|
||||
} while (value != 0);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char* mLtoa(int32_t value, char *buffer, bool clear) {
|
||||
bool minus = value < 0;
|
||||
if (minus) value = -value;
|
||||
buffer = mUtoa(value, buffer, clear);
|
||||
if (minus) *--buffer = '-';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char* mFtoa(double value, int8_t decimals, char *buffer) {
|
||||
int32_t mant = (int32_t)value;
|
||||
value -= mant;
|
||||
uint32_t exp = 1;
|
||||
while (decimals--) exp *= 10;
|
||||
exp *= (float)value;
|
||||
/*buffer += 9;
|
||||
buffer = mUtoa(exp, buffer);
|
||||
--buffer = '.';
|
||||
buffer -= 11;
|
||||
buffer = mLtoa(mant, buffer, 0);*/
|
||||
buffer = ltoa(mant, buffer, DEC);
|
||||
byte len = strlen(buffer);
|
||||
*(buffer + len++) = '.';
|
||||
ltoa(exp, buffer + len++, DEC);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
class mString {
|
||||
public:
|
||||
int size = 0;
|
||||
char* buf;
|
||||
// system*this = buf;
|
||||
uint16_t length() {
|
||||
return strlen(buf);
|
||||
}
|
||||
void clear() {
|
||||
buf[0] = 0;
|
||||
}
|
||||
|
||||
// constructor
|
||||
mString(char* buffer, int newSize) {
|
||||
//*this = buf;
|
||||
buf = buffer;
|
||||
size = newSize;
|
||||
}
|
||||
/*mString (const char c) {
|
||||
init();
|
||||
add(c);
|
||||
}
|
||||
mString (const char* data) {
|
||||
init();
|
||||
add(data);
|
||||
}
|
||||
mString (const __FlashStringHelper *data) {
|
||||
init();
|
||||
add(data);
|
||||
}
|
||||
mString (uint32_t value) {
|
||||
init();
|
||||
add(value);
|
||||
}
|
||||
mString (int32_t value) {
|
||||
init();
|
||||
add(value);
|
||||
}
|
||||
mString (uint16_t value) {
|
||||
init();
|
||||
add(value);
|
||||
}
|
||||
mString (int16_t value) {
|
||||
init();
|
||||
add(value);
|
||||
}
|
||||
mString (uint8_t value) {
|
||||
init();
|
||||
add(value);
|
||||
}
|
||||
mString (int8_t value) {
|
||||
init();
|
||||
add(value);
|
||||
}
|
||||
mString (double value, byte dec = 2) {
|
||||
init();
|
||||
add(value, dec);
|
||||
}*/
|
||||
|
||||
// add
|
||||
mString& add(const char c) {
|
||||
byte len = length();
|
||||
buf[len++] = c;
|
||||
buf[len++] = 0;
|
||||
return *this;
|
||||
}
|
||||
mString& add(const char* data) {
|
||||
/*byte len = length();
|
||||
do {
|
||||
buf[len] = *(data++);
|
||||
} while (buf[len++] != 0);*/
|
||||
strcpy(buf + length(), data);
|
||||
return *this;
|
||||
}
|
||||
mString& add(const __FlashStringHelper *data) {
|
||||
PGM_P p = reinterpret_cast<PGM_P>(data);
|
||||
strcpy_P(buf + length(), p);
|
||||
return *this;
|
||||
/*do {
|
||||
buf[len] = (char)pgm_read_byte_near(p++);
|
||||
} while (buf[len++] != 0);
|
||||
*/
|
||||
}
|
||||
mString& add(uint32_t value) {
|
||||
//char buf[11];
|
||||
//return add(mUtoa(value, buf));
|
||||
utoa(value, buf + length(), DEC);
|
||||
return *this;
|
||||
}
|
||||
mString& add(uint16_t value) {
|
||||
return add((uint32_t)value);
|
||||
}
|
||||
mString& add(uint8_t value) {
|
||||
return add((uint32_t)value);
|
||||
}
|
||||
mString& add(int32_t value) {
|
||||
//char buf[11];
|
||||
//return add(mLtoa(value, buf));
|
||||
ltoa(value, buf + length(), DEC);
|
||||
return *this;
|
||||
}
|
||||
mString& add(int16_t value) {
|
||||
return add((int32_t)value);
|
||||
}
|
||||
mString& add(int8_t value) {
|
||||
return add((int32_t)value);
|
||||
}
|
||||
mString& add(double value, int8_t dec = 2) {
|
||||
char buf[20];
|
||||
return add(mFtoa(value, dec, buf));
|
||||
//dtostrf(value, dec, DEC, buf+length());
|
||||
//return *this;
|
||||
}
|
||||
|
||||
// add +=
|
||||
mString& operator += (const char c) {
|
||||
return add(c);
|
||||
}
|
||||
mString& operator += (const char* data) {
|
||||
return add(data);
|
||||
}
|
||||
mString& operator += (const __FlashStringHelper *data) {
|
||||
return add(data);
|
||||
}
|
||||
mString& operator += (uint32_t value) {
|
||||
return add(value);
|
||||
}
|
||||
mString& operator += (int32_t value) {
|
||||
return add(value);
|
||||
}
|
||||
mString& operator += (uint16_t value) {
|
||||
return add(value);
|
||||
}
|
||||
mString& operator += (int16_t value) {
|
||||
return add(value);
|
||||
}
|
||||
mString& operator += (uint8_t value) {
|
||||
return add(value);
|
||||
}
|
||||
mString& operator += (int8_t value) {
|
||||
return add(value);
|
||||
}
|
||||
mString& operator += (double value) {
|
||||
return add(value);
|
||||
}
|
||||
|
||||
// assign
|
||||
mString& operator = (const char c) {
|
||||
clear();
|
||||
return add(c);
|
||||
}
|
||||
mString& operator = (const char* data) {
|
||||
clear();
|
||||
return add(data);
|
||||
}
|
||||
mString& operator = (const __FlashStringHelper *data) {
|
||||
clear();
|
||||
return add(data);
|
||||
}
|
||||
mString& operator = (uint32_t value) {
|
||||
clear();
|
||||
return add(value);
|
||||
}
|
||||
mString& operator = (int32_t value) {
|
||||
clear();
|
||||
return add(value);
|
||||
}
|
||||
mString& operator = (uint16_t value) {
|
||||
clear();
|
||||
return add(value);
|
||||
}
|
||||
mString& operator = (int16_t value) {
|
||||
clear();
|
||||
return add(value);
|
||||
}
|
||||
mString& operator = (uint8_t value) {
|
||||
clear();
|
||||
return add(value);
|
||||
}
|
||||
mString& operator = (int8_t value) {
|
||||
clear();
|
||||
return add(value);
|
||||
}
|
||||
mString& operator = (double value) {
|
||||
clear();
|
||||
return add(value);
|
||||
}
|
||||
|
||||
// compare
|
||||
bool operator == (const char c) {
|
||||
return (buf[0] == c && buf[1] == 0);
|
||||
}
|
||||
bool operator == (const char* data) {
|
||||
return !strcmp(buf, data);
|
||||
}
|
||||
bool operator == (uint32_t value) {
|
||||
char valBuf[11];
|
||||
return !strcmp(buf, utoa(value, valBuf, DEC));
|
||||
}
|
||||
bool operator == (int32_t value) {
|
||||
char valBuf[11];
|
||||
return !strcmp(buf, ltoa(value, valBuf, DEC));
|
||||
}
|
||||
bool operator == (float value) {
|
||||
char valBuf[20];
|
||||
return !strcmp(buf, mFtoa(value, 2, valBuf));
|
||||
}
|
||||
char operator [] (uint16_t index) const {
|
||||
return (index < size ? buf[index] : 0);
|
||||
}
|
||||
char& operator [] (uint16_t index) {
|
||||
return buf[index];
|
||||
}
|
||||
|
||||
|
||||
// convert & parse
|
||||
uint32_t toInt() {
|
||||
return atoi(buf);
|
||||
}
|
||||
float toFloat() {
|
||||
return atof(buf);
|
||||
}
|
||||
const char* c_str() {
|
||||
return buf;
|
||||
}
|
||||
bool startsWith(const char *data) {
|
||||
return strlen(data) == strspn(buf, data);
|
||||
}
|
||||
|
||||
int indexOf(char ch, uint16_t fromIndex = 0) {
|
||||
if (fromIndex >= length()) return -1;
|
||||
const char* temp = strchr(buf + fromIndex, ch);
|
||||
if (temp == NULL) return -1;
|
||||
return temp - buf;
|
||||
}
|
||||
int parseBytes(byte* data, int len, char div = ',', char ter = NULL) {
|
||||
int b = 0, c = 0;
|
||||
data[b] = 0;
|
||||
while (true) {
|
||||
if (buf[c] == div) {
|
||||
b++;
|
||||
c++;
|
||||
if (b == len) return b;
|
||||
data[b] = 0;
|
||||
continue;
|
||||
}
|
||||
if (buf[c] == ter || b == len) return b + 1;
|
||||
data[b] *= 10;
|
||||
data[b] += buf[c] - '0';
|
||||
c++;
|
||||
}
|
||||
}
|
||||
int parseInts(int* data, int len, char div = ',', char ter = NULL) {
|
||||
int b = 0, c = 0;
|
||||
data[b] = 0;
|
||||
while (true) {
|
||||
if (buf[c] == div) {
|
||||
b++;
|
||||
c++;
|
||||
if (b == len) return b;
|
||||
data[b] = 0;
|
||||
continue;
|
||||
}
|
||||
if (buf[c] == ter || b == len) return b + 1;
|
||||
data[b] *= 10;
|
||||
data[b] += buf[c] - '0';
|
||||
c++;
|
||||
}
|
||||
}
|
||||
private:
|
||||
|
||||
};
|
@@ -1,6 +1,8 @@
|
||||
#include <FastLED.h> // лента
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/
|
||||
|
||||
CRGBPalette16 customPal;
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Fire_gp ) {
|
||||
0, 0, 0, 0,
|
||||
128, 255, 0, 0,
|
||||
@@ -221,6 +223,7 @@ DEFINE_GRADIENT_PALETTE ( aurora_gp ) {
|
||||
};
|
||||
|
||||
CRGBPalette16 paletteArr[] = {
|
||||
customPal,
|
||||
HeatColors_p,
|
||||
Fire_gp,
|
||||
LavaColors_p,
|
||||
|
@@ -9,35 +9,47 @@ void parsing() {
|
||||
|
||||
buf[n] = NULL;
|
||||
DEBUGLN(buf); // пакет вида <ключ>,<канал>,<тип>,<дата1>,<дата2>...
|
||||
mString pars(buf, sizeof(buf));
|
||||
if (!pars.startsWith(GL_KEY)) return; // не наш ключ
|
||||
byte keyLen = strlen(GL_KEY);
|
||||
|
||||
byte keyLen = strchr(buf, ',') - buf; // indexof
|
||||
if (strncmp(buf, GL_KEY, keyLen)) return; // не наш ключ
|
||||
|
||||
byte data[MAX_PRESETS * PRES_SIZE + keyLen];
|
||||
byte data[MAX_PRESETS * PRES_SIZE + 5];
|
||||
memset(data, 0, MAX_PRESETS * PRES_SIZE + keyLen);
|
||||
int count = 0;
|
||||
char *str, *p = buf + keyLen; // сдвиг до даты
|
||||
char *ssid, *pass;
|
||||
uint32_t city = 0;
|
||||
uint16_t stripL, stripW;
|
||||
while ((str = strtok_r(p, ",", &p)) != NULL) {
|
||||
data[count++] = atoi(str);
|
||||
if (count == 4) ssid = str;
|
||||
if (count == 5) pass = str;
|
||||
uint32_t thisInt = atoi(str);
|
||||
data[count++] = (byte)thisInt;
|
||||
if (data[1] == 0) {
|
||||
if (count == 4) ssid = str;
|
||||
if (count == 5) pass = str;
|
||||
}
|
||||
if (data[1] == 1) {
|
||||
if (count == 16) stripL = thisInt;
|
||||
if (count == 17) stripW = thisInt;
|
||||
if (count == 18) city = thisInt;
|
||||
}
|
||||
}
|
||||
|
||||
// широковещательный запрос времени для local устройств в сети AP лампы
|
||||
if (data[0] == 0 && cfg.WiFimode && !gotNTP) {
|
||||
now.hour = data[1];
|
||||
now.min = data[2];
|
||||
now.day = data[1];
|
||||
now.hour = data[2];
|
||||
now.min = data[3];
|
||||
now.sec = data[4];
|
||||
now.setMs(0);
|
||||
}
|
||||
|
||||
if (data[0] != cfg.group) return; // не наш адрес, выходим
|
||||
|
||||
switch (data[1]) { // тип 0 - control, 1 - config, 2 - effects, 3 - dawn
|
||||
switch (data[1]) { // тип 0 - control, 1 - config, 2 - effects, 3 - dawn, 4 - from master, 5 - palette
|
||||
case 0: DEBUGLN("Control");
|
||||
switch (data[2]) {
|
||||
case 0: setPower(0); break; // выкл
|
||||
case 1: setPower(1); break; // вкл
|
||||
case 0: controlHandler(0); break; // выкл
|
||||
case 1: controlHandler(1); break; // вкл
|
||||
case 2: cfg.minLight = phot.getRaw(); break; // мин яркость
|
||||
case 3: cfg.maxLight = phot.getRaw(); break; // макс яркость
|
||||
case 4: changePreset(-1); break; // пред пресет
|
||||
@@ -54,12 +66,16 @@ void parsing() {
|
||||
case 12: if (gotNTP) { // OTA обновление, если есть интернет
|
||||
cfg.update = 1;
|
||||
EE_updCfg();
|
||||
delay(100);
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
char OTA[60];
|
||||
strcpy(OTA, OTAhost);
|
||||
strcpy(OTA + strlen(OTAhost), OTAfile[data[3]]);
|
||||
mString ota(OTA, 60);
|
||||
ota.clear();
|
||||
ota += OTAhost;
|
||||
ota += OTAfile[data[3]];
|
||||
DEBUG("Update to ");
|
||||
DEBUGLN(OTA);
|
||||
delay(100);
|
||||
ESPhttpUpdate.update(OTA);
|
||||
} break;
|
||||
case 13: // выключить через
|
||||
@@ -77,15 +93,14 @@ void parsing() {
|
||||
FOR_i(0, CFG_SIZE) {
|
||||
*((byte*)&cfg + i) = data[i + 2]; // загоняем в структуру
|
||||
}
|
||||
cfg.mTurn = data[21];
|
||||
cfg.length = data[17] | (data[16] << 8); // склеиваем
|
||||
cfg.width = data[20] | (data[19] << 8); // склеиваем
|
||||
cfg.length = stripL;
|
||||
cfg.width = stripW;
|
||||
cfg.cityID = city;
|
||||
|
||||
if (cfg.length > MAX_LEDS) cfg.length = MAX_LEDS;
|
||||
if (cfg.deviceType == GL_TYPE_STRIP) cfg.width = 1;
|
||||
if (cfg.length * cfg.width > MAX_LEDS) cfg.width = MAX_LEDS / cfg.length;
|
||||
ntp.setTimeOffset((cfg.GMT - 13) * 3600);
|
||||
ntp.setPoolServerName(NTPservers[cfg.NTP - 1]);
|
||||
FastLED.setMaxPowerInVoltsAndMilliamps(STRIP_VOLT, cfg.maxCur * 100);
|
||||
if (cfg.adcMode == GL_ADC_BRI) switchToPhot();
|
||||
else if (cfg.adcMode == GL_ADC_MIC) switchToMic();
|
||||
@@ -100,6 +115,7 @@ void parsing() {
|
||||
*((byte*)&preset + j * PRES_SIZE + i) = data[j * PRES_SIZE + i + 3]; // загоняем в структуру
|
||||
}
|
||||
}
|
||||
if (!cfg.rotation) setPreset(data[cfg.presetAmount * PRES_SIZE + 3] - 1);
|
||||
EE_updatePreset();
|
||||
presetRotation(true); // форсировать смену режима
|
||||
break;
|
||||
@@ -121,9 +137,25 @@ void parsing() {
|
||||
EE_updateCfg();
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: DEBUGLN("Palette");
|
||||
FOR_i(0, 1 + 16 * 3) {
|
||||
*((byte*)&pal + i) = data[i + 2]; // загоняем в структуру
|
||||
}
|
||||
updPal();
|
||||
EE_updatePal();
|
||||
break;
|
||||
|
||||
case 6: DEBUGLN("Time");
|
||||
if (!cfg.WiFimode) { // если мы AP
|
||||
now.day = data[2];
|
||||
now.hour = data[3];
|
||||
now.min = data[4];
|
||||
}
|
||||
gotTime = true;
|
||||
break;
|
||||
}
|
||||
FastLED.clear(); // на всякий случай
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,18 +163,19 @@ void sendToSlaves(byte data1, byte data2) {
|
||||
if (cfg.role == GL_MASTER) {
|
||||
IPAddress ip = WiFi.localIP();
|
||||
ip[3] = 255;
|
||||
char reply[20] = GL_KEY;
|
||||
byte keylen = strlen(GL_KEY);
|
||||
reply[keylen++] = ',';
|
||||
reply[keylen++] = cfg.group + '0';
|
||||
reply[keylen++] = ',';
|
||||
reply[keylen++] = '4';
|
||||
reply[keylen++] = ',';
|
||||
reply[keylen++] = data1 + '0';
|
||||
reply[keylen++] = ',';
|
||||
itoa(data2, reply + (keylen++), DEC);
|
||||
|
||||
DEBUG("Sending: ");
|
||||
char reply[20];
|
||||
mString packet(reply, sizeof(reply));
|
||||
packet.clear();
|
||||
packet += GL_KEY;
|
||||
packet += ',';
|
||||
packet += cfg.group;
|
||||
packet += ",4,";
|
||||
packet += data1;
|
||||
packet += ',';
|
||||
packet += data2;
|
||||
|
||||
DEBUG("Sending to Slaves: ");
|
||||
DEBUGLN(reply);
|
||||
|
||||
FOR_i(0, 3) {
|
||||
|
@@ -30,14 +30,29 @@ void setPreset(byte pres) {
|
||||
}
|
||||
}
|
||||
|
||||
void setPower(bool state) {
|
||||
void controlHandler(bool state) {
|
||||
if (turnoffTmr.running()) {
|
||||
turnoffTmr.stop();
|
||||
DEBUGLN("stop off timer");
|
||||
return;
|
||||
}
|
||||
if (dawnTmr.running()) {
|
||||
dawnTmr.stop();
|
||||
DEBUGLN("stop dawn timer");
|
||||
return;
|
||||
}
|
||||
if (state) cfg.manualOff = 0;
|
||||
if (cfg.state && !state) cfg.manualOff = 1;
|
||||
setPower(state);
|
||||
}
|
||||
|
||||
void setPower(bool state) {
|
||||
cfg.state = state;
|
||||
if (!state) {
|
||||
delay(100); // чтобы пролететь мин. частоту обновления
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
}
|
||||
sendToSlaves(0, cfg.state);
|
||||
DEBUGLN(state ? "Power on" : "Power off");
|
||||
}
|
||||
|
@@ -135,6 +135,7 @@ void setupLocal() {
|
||||
delay(50);
|
||||
}
|
||||
if (connect) {
|
||||
connTmr.stop();
|
||||
blink8(CRGB::Green);
|
||||
server.begin();
|
||||
DEBUG("Connected! Local IP: ");
|
||||
@@ -147,6 +148,7 @@ void setupLocal() {
|
||||
failCount++;
|
||||
tmr = millis();
|
||||
if (failCount >= 3) {
|
||||
connTmr.restart(); // попробуем позже
|
||||
setupAP();
|
||||
return;
|
||||
/*DEBUGLN("Reboot to AP!");
|
||||
@@ -172,5 +174,13 @@ void checkUpdate() {
|
||||
DEBUG("Update to current");
|
||||
}
|
||||
cfg.update = 0;
|
||||
EE_updCfg();
|
||||
}
|
||||
}
|
||||
|
||||
void tryReconnect() {
|
||||
if (connTmr.isReady()) {
|
||||
DEBUGLN("Reconnect");
|
||||
setupLocal();
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
void setupTime() {
|
||||
ntp.setUpdateInterval(NTP_UPD_PRD / 2 * 60000ul); // меньше в два раза, ибо апдейт вручную
|
||||
ntp.setTimeOffset((cfg.GMT - 13) * 3600);
|
||||
ntp.setPoolServerName(NTPservers[cfg.NTP - 1]);
|
||||
ntp.setPoolServerName(NTPserver);
|
||||
if (cfg.WiFimode) {
|
||||
// если подключены - запрашиваем время с сервера
|
||||
ntp.begin();
|
||||
@@ -16,8 +16,7 @@ void timeTicker() {
|
||||
updateTime(); // обновляем время
|
||||
sendTimeToSlaves(); // отправляем время слейвам
|
||||
trnd.update(now.hour, now.min, now.sec); // обновляем рандомайзер
|
||||
if (gotNTP) checkWorkTime(); // проверяем расписание, если подключены к Интернет
|
||||
checkTurnoff(); // проверяем таймер отключения
|
||||
if (gotNTP || gotTime) checkWorkTime(); // проверяем расписание, если знаем время
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,68 +25,68 @@ void updateTime() {
|
||||
now.sec = ntp.getSeconds();
|
||||
now.min = ntp.getMinutes();
|
||||
now.hour = ntp.getHours();
|
||||
now.day = ntp.getDay();
|
||||
now.day = (now.day == 0) ? 6 : (now.day - 1); // перевод из вс0 в пн0
|
||||
now.day = ntp.getDay(); // вс 0, сб 6
|
||||
now.weekMs = now.getWeekS() * 1000ul + ntp.getMillis();
|
||||
now.setMs(ntp.getMillis());
|
||||
if (now.min % NTP_UPD_PRD == 0 && now.sec == 0) {
|
||||
// берём время с интернета каждую NTP_UPD_PRD минуту, ставим флаг что данные с NTP получены, значит мы онлайн
|
||||
if (ntp.update() && !gotNTP) gotNTP = true;
|
||||
}
|
||||
checkDawn();
|
||||
} else { // если нет
|
||||
now.tick(); // тикаем своим счётчиком
|
||||
}
|
||||
}
|
||||
|
||||
void sendTimeToSlaves() {
|
||||
if (!cfg.WiFimode) { // если мы AP
|
||||
if (!cfg.WiFimode) { // если мы AP
|
||||
static byte prevSec = 0;
|
||||
if (prevSec != now.sec) { // новая секунда
|
||||
prevSec = now.sec;
|
||||
if (now.min % 1 == 0 && now.sec == 0) sendTime(); // ровно каждые 5 мин отправляем время
|
||||
if (now.min % 5 == 0 && now.sec == 0) sendTime(); // ровно каждые 5 мин отправляем время
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkTurnoff() {
|
||||
if (turnoffTmr.isReady()) {
|
||||
turnoffTmr.stop();
|
||||
setPower(0);
|
||||
void checkDawn() {
|
||||
if (now.sec == 0 && dawn.state[now.day] && !dawnTmr.running()) { // рассвет включен но не запущен
|
||||
int dawnMinute = dawn.hour[now.day] * 60 + dawn.minute[now.day] - dawn.time;
|
||||
if (dawnMinute < 0) dawnMinute += 1440;
|
||||
if (dawnMinute == now.hour * 60 + now.min) {
|
||||
DEBUGLN("dawn start");
|
||||
dawnTmr.setInterval(dawn.time * 60000ul);
|
||||
dawnTmr.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkWorkTime() {
|
||||
if (!isWorkTime(now.hour, cfg.workFrom, cfg.workTo)) {
|
||||
if (cfg.state) {
|
||||
cfg.state = false;
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
}
|
||||
} else {
|
||||
if (!cfg.state && !cfg.manualOff) {
|
||||
cfg.state = true;
|
||||
}
|
||||
static byte prevState = 2; // для первого запуска
|
||||
byte curState = isWorkTime(now.hour, cfg.workFrom, cfg.workTo);
|
||||
if (prevState != curState) { // переключение расписания
|
||||
prevState = curState;
|
||||
if (curState && !cfg.state && !cfg.manualOff) setPower(1); // нужно включить, а лампа выключена и не выключалась вручную
|
||||
if (!curState && cfg.state) setPower(0); // нужно выключить, а лампа включена
|
||||
}
|
||||
}
|
||||
|
||||
void sendTime() {
|
||||
IPAddress ip = WiFi.localIP();
|
||||
ip[3] = 255;
|
||||
char reply[20] = GL_KEY;
|
||||
byte keylen = strlen(GL_KEY);
|
||||
reply[keylen++] = ',';
|
||||
reply[keylen++] = 0 + '0';
|
||||
reply[keylen++] = ',';
|
||||
char hours[4];
|
||||
itoa(now.hour, hours, DEC);
|
||||
strncpy(reply + keylen, hours, 3);
|
||||
keylen += strlen(hours);
|
||||
reply[keylen++] = ',';
|
||||
char mins[4];
|
||||
itoa(now.min, mins, DEC);
|
||||
strncpy(reply + keylen, mins, 3);
|
||||
keylen += strlen(mins);
|
||||
reply[keylen++] = NULL;
|
||||
char reply[25] = GL_KEY;
|
||||
mString packet(reply, sizeof(reply));
|
||||
packet.clear();
|
||||
packet += GL_KEY;
|
||||
packet += ',';
|
||||
packet += 0;
|
||||
packet += ',';
|
||||
packet += now.day;
|
||||
packet += ',';
|
||||
packet += now.hour;
|
||||
packet += ',';
|
||||
packet += now.min;
|
||||
packet += ',';
|
||||
packet += now.sec;
|
||||
|
||||
DEBUG("Sending time: ");
|
||||
DEBUGLN(reply);
|
||||
|
@@ -12,7 +12,6 @@ class timerMillis {
|
||||
}
|
||||
boolean isReady() {
|
||||
if (_active && millis() - _tmr >= _interval) {
|
||||
//_tmr += _interval;
|
||||
reset();
|
||||
return true;
|
||||
}
|
||||
@@ -28,6 +27,12 @@ class timerMillis {
|
||||
void stop() {
|
||||
_active = false;
|
||||
}
|
||||
bool running() {
|
||||
return _active;
|
||||
}
|
||||
byte getLength8() {
|
||||
return (millis() - _tmr) * 255ul / _interval;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t _tmr = 0;
|
||||
|
Reference in New Issue
Block a user