mirror of
https://github.com/AlexGyver/GyverLamp2.git
synced 2025-08-08 09:01:06 +03:00
add
This commit is contained in:
45
firmware/GyverLamp2_v0.7b/Button.h
Normal file
45
firmware/GyverLamp2_v0.7b/Button.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#define BTN_DEB 100
|
||||
#define BTN_HOLD 800
|
||||
|
||||
// (пин, инверт), инверт 1 - для pullup, 0 - для pulldown
|
||||
|
||||
class Button {
|
||||
public:
|
||||
Button (byte pin) : _pin(pin) {
|
||||
pinMode(_pin, INPUT_PULLUP);
|
||||
}
|
||||
void setLevel(bool inv) {
|
||||
_inv = inv;
|
||||
}
|
||||
void tick() {
|
||||
uint32_t deb = millis() - _tmr;
|
||||
if (state()) {
|
||||
if (_flag && deb > BTN_HOLD) _hold = 1;
|
||||
if (!_flag && deb > BTN_DEB) _flag = 1;
|
||||
} else {
|
||||
if (_flag) {
|
||||
_flag = _hold = 0;
|
||||
if (deb < BTN_HOLD) _click = 1;
|
||||
}
|
||||
_tmr = millis();
|
||||
}
|
||||
}
|
||||
bool state() {
|
||||
return (digitalRead(_pin) ^ _inv);
|
||||
}
|
||||
bool isHold() {
|
||||
return _hold;
|
||||
}
|
||||
bool isClick() {
|
||||
if (_click) {
|
||||
_click = 0;
|
||||
return 1;
|
||||
} return 0;
|
||||
}
|
||||
private:
|
||||
const byte _pin;
|
||||
bool _inv = 1;
|
||||
uint32_t _tmr = 0;
|
||||
bool _flag = 0, _click = 0, _hold = 0;
|
||||
};
|
72
firmware/GyverLamp2_v0.7b/FFT_C.h
Normal file
72
firmware/GyverLamp2_v0.7b/FFT_C.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#define FFT_SIZE 64 // размер выборки (кратно степени 2)
|
||||
|
||||
static float sinF[] = {0.0, -1.0, -0.707107, -0.382683, -0.195090, -0.098017, -0.049068, -0.024541, -0.012272, -0.006136};
|
||||
|
||||
void FFT(int* AVal, int* FTvl) {
|
||||
int i, j, m, Mmax, Istp, count = 0;
|
||||
float Tmpr, Tmpi, Tmvl[FFT_SIZE * 2];
|
||||
float Wpr, Wr, Wi;
|
||||
|
||||
for (i = 0; i < FFT_SIZE * 2; i += 2) {
|
||||
Tmvl[i] = 0;
|
||||
Tmvl[i + 1] = AVal[i / 2];
|
||||
}
|
||||
|
||||
i = j = 1;
|
||||
while (i < FFT_SIZE * 2) {
|
||||
if (j > i) {
|
||||
Tmpr = Tmvl[i];
|
||||
Tmvl[i] = Tmvl[j];
|
||||
Tmvl[j] = Tmpr;
|
||||
Tmpr = Tmvl[i + 1];
|
||||
Tmvl[i + 1] = Tmvl[j + 1];
|
||||
Tmvl[j + 1] = Tmpr;
|
||||
}
|
||||
i = i + 2;
|
||||
m = FFT_SIZE;
|
||||
while ((m >= 2) && (j > m)) {
|
||||
j = j - m;
|
||||
m = m >> 1;
|
||||
}
|
||||
j = j + m;
|
||||
}
|
||||
|
||||
Mmax = 2;
|
||||
while (FFT_SIZE * 2 > Mmax) {
|
||||
Wpr = sinF[count + 1] * sinF[count + 1] * 2;
|
||||
Istp = Mmax * 2;
|
||||
Wr = 1;
|
||||
Wi = 0;
|
||||
m = 1;
|
||||
|
||||
while (m < Mmax) {
|
||||
i = m;
|
||||
m = m + 2;
|
||||
Tmpr = Wr;
|
||||
Tmpi = Wi;
|
||||
Wr += -Tmpr * Wpr - Tmpi * sinF[count];
|
||||
Wi += Tmpr * sinF[count] - Tmpi * Wpr;
|
||||
|
||||
while (i < FFT_SIZE * 2) {
|
||||
j = i + Mmax;
|
||||
Tmpr = Wr * Tmvl[j] - Wi * Tmvl[j - 1];
|
||||
Tmpi = Wi * Tmvl[j] + Wr * Tmvl[j - 1];
|
||||
|
||||
Tmvl[j] = Tmvl[i] - Tmpr;
|
||||
Tmvl[j - 1] = Tmvl[i - 1] - Tmpi;
|
||||
Tmvl[i] = Tmvl[i] + Tmpr;
|
||||
Tmvl[i - 1] = Tmvl[i - 1] + Tmpi;
|
||||
i = i + Istp;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
Mmax = Istp;
|
||||
}
|
||||
for (i = 0; i < FFT_SIZE; i++) {
|
||||
j = i * 2;
|
||||
FTvl[i] = (int)(Tmvl[j] * Tmvl[j] + Tmvl[j + 1] * Tmvl[j + 1]) >> 18;
|
||||
}
|
||||
}
|
||||
// по мотивам https://ru.wikibooks.org/wiki/%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D0%BE%D0%B2/%D0%91%D1%8B%D1%81%D1%82%D1%80%D0%BE%D0%B5_%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%A4%D1%83%D1%80%D1%8C%D0%B5
|
55
firmware/GyverLamp2_v0.7b/FastFilter.h
Normal file
55
firmware/GyverLamp2_v0.7b/FastFilter.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
|
||||
#define FF_SCALE 0
|
||||
|
||||
#define FF_PASS_MAX 1
|
||||
#define FF_PASS_MIN 2
|
||||
|
||||
class FastFilter {
|
||||
public:
|
||||
void setK(byte k) {
|
||||
_k1 = k;
|
||||
_k2 = 32 - k;
|
||||
}
|
||||
void setDt(int dt) {
|
||||
_dt = dt;
|
||||
}
|
||||
void setPass(byte pass) {
|
||||
_pass = pass;
|
||||
}
|
||||
void setRaw(int raw) {
|
||||
_raw = raw;
|
||||
}
|
||||
void setFil(int fil) {
|
||||
_raw_f = fil;
|
||||
}
|
||||
bool checkPass(int val) {
|
||||
if (_pass == FF_PASS_MAX && val > _raw_f) {
|
||||
_raw_f = val;
|
||||
return 1;
|
||||
} else if (_pass == FF_PASS_MIN && val < _raw_f) {
|
||||
_raw_f = val;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void compute() {
|
||||
if (_dt == 0 || millis() - _tmr >= _dt) {
|
||||
_tmr = millis();
|
||||
_raw_f = (_k1 * _raw_f + _k2 * _raw) >> 5;
|
||||
}
|
||||
}
|
||||
long getFil() {
|
||||
return _raw_f;
|
||||
}
|
||||
long getRaw() {
|
||||
return _raw;
|
||||
}
|
||||
private:
|
||||
uint32_t _tmr = 0;
|
||||
int _dt = 0;
|
||||
byte _k1 = 20, _k2 = 12;
|
||||
byte _pass = 0;
|
||||
int _raw_f = 0, _raw = 0;
|
||||
};
|
105
firmware/GyverLamp2_v0.7b/GyverLamp2_v0.7b.ino
Normal file
105
firmware/GyverLamp2_v0.7b/GyverLamp2_v0.7b.ino
Normal file
@@ -0,0 +1,105 @@
|
||||
// LOLIN(WEMOS) D1 R2 & mini
|
||||
// ESP core 2.7.4+ http://arduino.esp8266.com/stable/package_esp8266com_index.json
|
||||
// FastLED 3.4.0+ https://github.com/FastLED/FastLED/releases
|
||||
|
||||
// ---------- Настройки -----------
|
||||
#define MAX_PRESETS 20 // макс количество режимов (не более 30)
|
||||
#define GL_KEY "GL" // ключ сети
|
||||
|
||||
// ------------ Кнопка -------------
|
||||
#define BTN_PIN 4 // пин кнопки GPIO4 (D2). Или 0 для схемы с ESP-01 !!
|
||||
#define USE_BTN 1 // 1 использовать кнопку, 0 нет
|
||||
|
||||
// ------------ Лента -------------
|
||||
#define STRIP_PIN 2 // пин ленты GPIO2 (D4)
|
||||
#define MAX_LEDS 512 // макс. светодиодов
|
||||
#define STRIP_CHIP WS2812 // чип ленты
|
||||
#define STRIP_COLOR GRB // порядок цветов в ленте
|
||||
#define STRIP_VOLT 5 // напряжение ленты, V
|
||||
/*
|
||||
WS2811, GBR, 12V
|
||||
WS2812, GRB, 5V
|
||||
WS2813, GRB, 5V
|
||||
WS2815, GRB, 12V
|
||||
WS2818, RGB, 12V
|
||||
*/
|
||||
|
||||
// ------------ WiFi AP ------------
|
||||
const char AP_NameChar[] = "GyverLamp2";
|
||||
const char WiFiPassword[] = "12345678";
|
||||
|
||||
// ------------ Прочее -------------
|
||||
#define MIC_VCC D6 // питание микрофона
|
||||
#define PHOT_VCC D5 // питание фоторезистора
|
||||
#define EE_TOUT 303000 // таймаут сохранения епром после изменения, мс
|
||||
#define DEBUG_SERIAL // закомментируй чтобы выключить отладку (скорость 115200)
|
||||
#define EE_KEY 40 // ключ сброса WiFi (измени для сброса всех настроек)
|
||||
#define NTP_UPD_PRD 5 // период обновления времени с NTP сервера, минут
|
||||
|
||||
// ---------- БИБЛИОТЕКИ -----------
|
||||
#include "data.h" // данные
|
||||
#include "Time.h" // часы
|
||||
#include "TimeRandom.h" // случайные числа по времени
|
||||
#include "FastRandom.h" // быстрый рандом
|
||||
#include "Button.h" // библа кнопки
|
||||
#include "palettes.h" // палитры
|
||||
#include "NTPClient-Gyver.h" // сервер времени (модиф)
|
||||
#include "timerMillis.h" // таймер миллис
|
||||
#include "VolAnalyzer.h" // анализатор громкости
|
||||
#include "FFT_C.h" // фурье
|
||||
#include <FastLED.h> // лента
|
||||
#include <ESP8266WiFi.h> // базовая либа есп
|
||||
#include <WiFiUdp.h> // общение по UDP
|
||||
#include <EEPROM.h> // епром
|
||||
#include "ESP8266httpUpdate.h" // OTA
|
||||
|
||||
// ------------------- ДАТА --------------------
|
||||
Config cfg;
|
||||
Preset preset[MAX_PRESETS];
|
||||
Dawn dawn;
|
||||
WiFiServer server(80);
|
||||
WiFiUDP Udp;
|
||||
WiFiUDP ntpUDP;
|
||||
NTPClient ntp(ntpUDP);
|
||||
CRGB leds[MAX_LEDS];
|
||||
Time now;
|
||||
Button btn(BTN_PIN);
|
||||
timerMillis EEtmr(EE_TOUT), turnoffTmr;
|
||||
TimeRandom trnd;
|
||||
VolAnalyzer vol(A0), low, high;
|
||||
FastFilter phot;
|
||||
|
||||
byte btnClicks = 0, brTicks = 0;
|
||||
unsigned char matrixValue[11][16];
|
||||
bool gotNTP = false;
|
||||
|
||||
// ------------------- SETUP --------------------
|
||||
void setup() {
|
||||
memset(matrixValue, 0, sizeof(matrixValue));
|
||||
#ifdef DEBUG_SERIAL
|
||||
Serial.begin(115200);
|
||||
DEBUGLN();
|
||||
#endif
|
||||
EEPROM.begin(512); // старт епром
|
||||
startStrip(); // показываем РГБ
|
||||
btn.setLevel(digitalRead(BTN_PIN)); // смотрим что за кнопка
|
||||
EE_startup(); // читаем епром
|
||||
checkGroup(); // показываем или меняем адрес
|
||||
checkButton(); // проверяем кнопку на удержание
|
||||
startWiFi(); // старт вайфай
|
||||
setupTime(); // выставляем время
|
||||
setupADC(); // настраиваем анализ
|
||||
}
|
||||
|
||||
void loop() {
|
||||
timeTicker(); // обновляем время
|
||||
yield();
|
||||
parsing(); // ловим данные
|
||||
yield();
|
||||
checkEEupdate(); // сохраняем епром
|
||||
presetRotation(); // смена режимов
|
||||
effectsRoutine(); // мигаем
|
||||
yield();
|
||||
button(); // проверяем кнопку
|
||||
checkAnalog(); // чтение звука и датчика
|
||||
}
|
192
firmware/GyverLamp2_v0.7b/NTPClient-Gyver.cpp
Normal file
192
firmware/GyverLamp2_v0.7b/NTPClient-Gyver.cpp
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
* Copyright (c) 2015 by Fabrice Weinberg
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "NTPClient-Gyver.h"
|
||||
|
||||
NTPClient::NTPClient(UDP& udp) {
|
||||
this->_udp = &udp;
|
||||
}
|
||||
|
||||
NTPClient::NTPClient(UDP& udp, long timeOffset) {
|
||||
this->_udp = &udp;
|
||||
this->_timeOffset = timeOffset;
|
||||
}
|
||||
|
||||
NTPClient::NTPClient(UDP& udp, const char* poolServerName) {
|
||||
this->_udp = &udp;
|
||||
this->_poolServerName = poolServerName;
|
||||
}
|
||||
|
||||
NTPClient::NTPClient(UDP& udp, const char* poolServerName, long timeOffset) {
|
||||
this->_udp = &udp;
|
||||
this->_timeOffset = timeOffset;
|
||||
this->_poolServerName = poolServerName;
|
||||
}
|
||||
|
||||
NTPClient::NTPClient(UDP& udp, const char* poolServerName, long timeOffset, unsigned long updateInterval) {
|
||||
this->_udp = &udp;
|
||||
this->_timeOffset = timeOffset;
|
||||
this->_poolServerName = poolServerName;
|
||||
this->_updateInterval = updateInterval;
|
||||
}
|
||||
|
||||
void NTPClient::begin() {
|
||||
this->begin(NTP_DEFAULT_LOCAL_PORT);
|
||||
}
|
||||
|
||||
void NTPClient::begin(int port) {
|
||||
this->_port = port;
|
||||
|
||||
this->_udp->begin(this->_port);
|
||||
|
||||
this->_udpSetup = true;
|
||||
}
|
||||
|
||||
bool NTPClient::forceUpdate() {
|
||||
#ifdef DEBUG_NTPClient
|
||||
Serial.println("Update from NTP Server");
|
||||
#endif
|
||||
|
||||
this->sendNTPPacket();
|
||||
|
||||
// Wait till data is there or timeout...
|
||||
byte timeout = 0;
|
||||
int cb = 0;
|
||||
do {
|
||||
delay ( 10 );
|
||||
cb = this->_udp->parsePacket();
|
||||
if (timeout > 100) return false; // timeout after 1000 ms
|
||||
timeout++;
|
||||
} while (cb == 0);
|
||||
|
||||
this->_lastUpdate = millis() - (10 * (timeout + 1)); // Account for delay in reading the time
|
||||
|
||||
this->_udp->read(this->_packetBuffer, NTP_PACKET_SIZE);
|
||||
|
||||
unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]);
|
||||
unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]);
|
||||
|
||||
/// добавлено AlexGyver
|
||||
uint32_t frac = (uint32_t) _packetBuffer[44] << 24
|
||||
| (uint32_t) _packetBuffer[45] << 16
|
||||
| (uint32_t) _packetBuffer[46] << 8
|
||||
| (uint32_t) _packetBuffer[47] << 0;
|
||||
uint16_t mssec = ((uint64_t) frac * 1000) >> 32;
|
||||
//https://arduino.stackexchange.com/questions/49567/synching-local-clock-usign-ntp-to-milliseconds
|
||||
_lastUpdate -= mssec;
|
||||
/// добавлено AlexGyver
|
||||
|
||||
// combine the four bytes (two words) into a long integer
|
||||
// this is NTP time (seconds since Jan 1 1900):
|
||||
unsigned long secsSince1900 = highWord << 16 | lowWord;
|
||||
|
||||
this->_currentEpoc = secsSince1900 - SEVENZYYEARS;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NTPClient::update() {
|
||||
if ((millis() - this->_lastUpdate >= this->_updateInterval) // Update after _updateInterval
|
||||
|| this->_lastUpdate == 0) { // Update if there was no update yet.
|
||||
if (!this->_udpSetup) this->begin(); // setup the UDP client if needed
|
||||
return this->forceUpdate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long NTPClient::getEpochTime() const {
|
||||
return this->_timeOffset + // User offset
|
||||
this->_currentEpoc + // Epoc returned by the NTP server
|
||||
((millis() - this->_lastUpdate) / 1000); // Time since last update
|
||||
}
|
||||
|
||||
int NTPClient::getDay() const {
|
||||
return (((this->getEpochTime() / 86400L) + 4 ) % 7); //0 is Sunday
|
||||
}
|
||||
int NTPClient::getHours() const {
|
||||
return ((this->getEpochTime() % 86400L) / 3600);
|
||||
}
|
||||
int NTPClient::getMinutes() const {
|
||||
return ((this->getEpochTime() % 3600) / 60);
|
||||
}
|
||||
int NTPClient::getSeconds() const {
|
||||
return (this->getEpochTime() % 60);
|
||||
}
|
||||
int NTPClient::getMillis() const {
|
||||
return ((millis() - this->_lastUpdate) % 1000);
|
||||
}
|
||||
int NTPClient::getMillisLastUpd() const {
|
||||
return (millis() - this->_lastUpdate);
|
||||
}
|
||||
|
||||
String NTPClient::getFormattedTime() const {
|
||||
unsigned long rawTime = this->getEpochTime();
|
||||
unsigned long hours = (rawTime % 86400L) / 3600;
|
||||
String hoursStr = hours < 10 ? "0" + String(hours) : String(hours);
|
||||
|
||||
unsigned long minutes = (rawTime % 3600) / 60;
|
||||
String minuteStr = minutes < 10 ? "0" + String(minutes) : String(minutes);
|
||||
|
||||
unsigned long seconds = rawTime % 60;
|
||||
String secondStr = seconds < 10 ? "0" + String(seconds) : String(seconds);
|
||||
|
||||
return hoursStr + ":" + minuteStr + ":" + secondStr;
|
||||
}
|
||||
|
||||
void NTPClient::end() {
|
||||
this->_udp->stop();
|
||||
|
||||
this->_udpSetup = false;
|
||||
}
|
||||
|
||||
void NTPClient::setTimeOffset(int timeOffset) {
|
||||
this->_timeOffset = timeOffset;
|
||||
}
|
||||
|
||||
void NTPClient::setUpdateInterval(unsigned long updateInterval) {
|
||||
this->_updateInterval = updateInterval;
|
||||
}
|
||||
|
||||
void NTPClient::setPoolServerName(const char* poolServerName) {
|
||||
this->_poolServerName = poolServerName;
|
||||
}
|
||||
|
||||
void NTPClient::sendNTPPacket() {
|
||||
// set all bytes in the buffer to 0
|
||||
memset(this->_packetBuffer, 0, NTP_PACKET_SIZE);
|
||||
// Initialize values needed to form NTP request
|
||||
// (see URL above for details on the packets)
|
||||
this->_packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
this->_packetBuffer[1] = 0; // Stratum, or type of clock
|
||||
this->_packetBuffer[2] = 6; // Polling Interval
|
||||
this->_packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
// 8 bytes of zero for Root Delay & Root Dispersion
|
||||
this->_packetBuffer[12] = 49;
|
||||
this->_packetBuffer[13] = 0x4E;
|
||||
this->_packetBuffer[14] = 49;
|
||||
this->_packetBuffer[15] = 52;
|
||||
|
||||
// all NTP fields have been given values, now
|
||||
// you can send a packet requesting a timestamp:
|
||||
this->_udp->beginPacket(this->_poolServerName, 123); //NTP requests are to port 123
|
||||
this->_udp->write(this->_packetBuffer, NTP_PACKET_SIZE);
|
||||
this->_udp->endPacket();
|
||||
}
|
102
firmware/GyverLamp2_v0.7b/NTPClient-Gyver.h
Normal file
102
firmware/GyverLamp2_v0.7b/NTPClient-Gyver.h
Normal file
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
// добавлена синхронизация обнвления по миллисекундам
|
||||
// добавлен вывод миллисекунд
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#include <Udp.h>
|
||||
|
||||
#define SEVENZYYEARS 2208988800UL
|
||||
#define NTP_PACKET_SIZE 48
|
||||
#define NTP_DEFAULT_LOCAL_PORT 1337
|
||||
|
||||
class NTPClient {
|
||||
private:
|
||||
UDP* _udp;
|
||||
bool _udpSetup = false;
|
||||
|
||||
const char* _poolServerName = "pool.ntp.org"; // Default time server
|
||||
int _port = NTP_DEFAULT_LOCAL_PORT;
|
||||
long _timeOffset = 0;
|
||||
|
||||
unsigned long _updateInterval = 60000; // In ms
|
||||
|
||||
unsigned long _currentEpoc = 0; // In s
|
||||
unsigned long _lastUpdate = 0; // In ms
|
||||
|
||||
byte _packetBuffer[NTP_PACKET_SIZE];
|
||||
|
||||
void sendNTPPacket();
|
||||
|
||||
public:
|
||||
NTPClient(UDP& udp);
|
||||
NTPClient(UDP& udp, long timeOffset);
|
||||
NTPClient(UDP& udp, const char* poolServerName);
|
||||
NTPClient(UDP& udp, const char* poolServerName, long timeOffset);
|
||||
NTPClient(UDP& udp, const char* poolServerName, long timeOffset, unsigned long updateInterval);
|
||||
|
||||
/**
|
||||
* Set time server name
|
||||
*
|
||||
* @param poolServerName
|
||||
*/
|
||||
void setPoolServerName(const char* poolServerName);
|
||||
|
||||
/**
|
||||
* Starts the underlying UDP client with the default local port
|
||||
*/
|
||||
void begin();
|
||||
|
||||
/**
|
||||
* Starts the underlying UDP client with the specified local port
|
||||
*/
|
||||
void begin(int port);
|
||||
|
||||
/**
|
||||
* This should be called in the main loop of your application. By default an update from the NTP Server is only
|
||||
* made every 60 seconds. This can be configured in the NTPClient constructor.
|
||||
*
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
bool update();
|
||||
|
||||
/**
|
||||
* This will force the update from the NTP Server.
|
||||
*
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
bool forceUpdate();
|
||||
|
||||
int getDay() const;
|
||||
int getHours() const;
|
||||
int getMinutes() const;
|
||||
int getSeconds() const;
|
||||
int getMillis() const;
|
||||
int getMillisLastUpd() const;
|
||||
|
||||
/**
|
||||
* Changes the time offset. Useful for changing timezones dynamically
|
||||
*/
|
||||
void setTimeOffset(int timeOffset);
|
||||
|
||||
/**
|
||||
* Set the update interval to another frequency. E.g. useful when the
|
||||
* timeOffset should not be set in the constructor
|
||||
*/
|
||||
void setUpdateInterval(unsigned long updateInterval);
|
||||
|
||||
/**
|
||||
* @return time formatted like `hh:mm:ss`
|
||||
*/
|
||||
String getFormattedTime() const;
|
||||
|
||||
/**
|
||||
* @return time in seconds since Jan. 1, 1970
|
||||
*/
|
||||
unsigned long getEpochTime() const;
|
||||
|
||||
/**
|
||||
* Stops the underlying UDP client
|
||||
*/
|
||||
void end();
|
||||
};
|
58
firmware/GyverLamp2_v0.7b/Time.h
Normal file
58
firmware/GyverLamp2_v0.7b/Time.h
Normal file
@@ -0,0 +1,58 @@
|
||||
class Time {
|
||||
public:
|
||||
byte sec = 0;
|
||||
byte min = 0;
|
||||
byte hour = 0;
|
||||
byte day = 0; // пн 0, вт 2.. вс 6
|
||||
int ms = 0;
|
||||
uint32_t weekMs = 0;
|
||||
uint32_t weekS = 0;
|
||||
|
||||
int getMs() {
|
||||
return (millis() - tmr);
|
||||
}
|
||||
void setMs(int ms) {
|
||||
tmr = millis() + ms;
|
||||
}
|
||||
uint32_t getWeekS() {
|
||||
return day * 86400ul + hour * 3600ul + min * 60 + sec;
|
||||
}
|
||||
bool newSec() {
|
||||
if (prevSec != sec) {
|
||||
prevSec = sec;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool newMin() {
|
||||
if (prevMin != min) {
|
||||
prevMin = min;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void tick() {
|
||||
ms = millis() - tmr;
|
||||
if (ms >= 1000) {
|
||||
tmr += 1000;
|
||||
if (++sec >= 60) {
|
||||
sec = 0;
|
||||
if (++min >= 60) {
|
||||
min = 0;
|
||||
if (++hour >= 24) {
|
||||
hour = 0;
|
||||
if (++day >= 7) {
|
||||
day = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
weekMs = getWeekS() * 1000ul + millis() - tmr;
|
||||
}
|
||||
private:
|
||||
uint32_t tmr;
|
||||
byte prevSec = 0;
|
||||
byte prevMin = 0;
|
||||
};
|
122
firmware/GyverLamp2_v0.7b/VolAnalyzer.h
Normal file
122
firmware/GyverLamp2_v0.7b/VolAnalyzer.h
Normal file
@@ -0,0 +1,122 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include "FastFilter.h"
|
||||
|
||||
class VolAnalyzer {
|
||||
public:
|
||||
VolAnalyzer (int pin = -1) {
|
||||
volF.setDt(20);
|
||||
volF.setPass(FF_PASS_MAX);
|
||||
maxF.setPass(FF_PASS_MAX);
|
||||
setVolK(25);
|
||||
setAmpliK(31);
|
||||
if (pin != -1) setPin(pin);
|
||||
}
|
||||
void setPin(int pin) {
|
||||
_pin = pin;
|
||||
pinMode(_pin, INPUT);
|
||||
}
|
||||
void setDt(int dt) {
|
||||
_dt = dt;
|
||||
}
|
||||
void setPeriod(int period) {
|
||||
_period = period;
|
||||
}
|
||||
void setVolDt(int volDt) {
|
||||
volF.setDt(volDt);
|
||||
}
|
||||
void setAmpliDt(int ampliDt) {
|
||||
_ampliDt = ampliDt;
|
||||
}
|
||||
void setWindow(int window) {
|
||||
_window = window;
|
||||
}
|
||||
void setVolK(byte k) {
|
||||
volF.setK(k);
|
||||
}
|
||||
void setAmpliK(byte k) {
|
||||
maxF.setK(k);
|
||||
minF.setK(k);
|
||||
}
|
||||
void setVolMin(int scale) {
|
||||
_volMin = scale;
|
||||
}
|
||||
void setVolMax(int scale) {
|
||||
_volMax = scale;
|
||||
}
|
||||
void setTrsh(int trsh) {
|
||||
_trsh = trsh;
|
||||
}
|
||||
bool tick(int thisRead = -1) {
|
||||
volF.compute();
|
||||
if (millis() - tmr4 >= _ampliDt) { // период сглаживания амплитуды
|
||||
tmr4 = millis();
|
||||
maxF.setRaw(maxs);
|
||||
minF.setRaw(mins);
|
||||
maxF.compute();
|
||||
minF.compute();
|
||||
maxs = 0;
|
||||
mins = 1023;
|
||||
}
|
||||
if (_period == 0 || millis() - tmr1 >= _period) { // период между захватом сэмплов
|
||||
if (_dt == 0 || micros() - tmr2 >= _dt) { // период выборки
|
||||
tmr2 = micros();
|
||||
if (thisRead == -1) thisRead = analogRead(_pin);
|
||||
if (thisRead > max) max = thisRead; // ищем максимум
|
||||
if (!_first) {
|
||||
_first = 1;
|
||||
maxF.setFil(thisRead);
|
||||
minF.setFil(thisRead);
|
||||
}
|
||||
if (++count >= _window) { // выборка завершена
|
||||
tmr1 = millis();
|
||||
raw = max;
|
||||
if (max > maxs) maxs = max; // максимумы среди максимумов
|
||||
if (max < mins) mins = max; // минимумы реди максимумов
|
||||
maxF.checkPass(max); // проверка выше максимума
|
||||
if (getMax() - getMin() < _trsh) max = 0; // если окно громкости меньше порого то 0
|
||||
else max = constrain(map(max, getMin(), getMax(), _volMin, _volMax), _volMin, _volMax); // перевод в громкость
|
||||
volF.setRaw(max); // фильтр столбика громкости
|
||||
if (volF.checkPass(max)) _pulse = 1; // проверка выше максимума
|
||||
max = count = 0;
|
||||
return true; // выборка завершена
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int getRaw() {
|
||||
return raw;
|
||||
}
|
||||
int getVol() {
|
||||
return volF.getFil();
|
||||
}
|
||||
int getMin() {
|
||||
return minF.getFil();
|
||||
}
|
||||
int getMax() {
|
||||
return maxF.getFil();
|
||||
}
|
||||
bool getPulse() {
|
||||
if (_pulse) {
|
||||
_pulse = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
int _pin;
|
||||
int _dt = 600; // 600 мкс между сэмплами достаточно для музыки
|
||||
int _period = 5; // 5 мс между выборами достаточно
|
||||
int _ampliDt = 150;
|
||||
int _window = 20; // при таком размере окна получаем длительность оцифровки 12 мс, вполне хватает
|
||||
uint32_t tmr1 = 0, tmr2 = 0, tmr3 = 0, tmr4 = 0;
|
||||
int raw = 0;
|
||||
int max = 0, count = 0;
|
||||
int maxs = 0, mins = 1023;
|
||||
int _volMin = 0, _volMax = 100, _trsh = 30;
|
||||
bool _pulse = 0, _first = 0;
|
||||
FastFilter minF, maxF, volF;
|
||||
};
|
106
firmware/GyverLamp2_v0.7b/analog.ino
Normal file
106
firmware/GyverLamp2_v0.7b/analog.ino
Normal file
@@ -0,0 +1,106 @@
|
||||
void setupADC() {
|
||||
low.setDt(0);
|
||||
low.setPeriod(0);
|
||||
low.setWindow(0);
|
||||
high.setDt(0);
|
||||
high.setPeriod(0);
|
||||
high.setWindow(0);
|
||||
|
||||
vol.setVolK(20);
|
||||
low.setVolK(20);
|
||||
high.setVolK(20);
|
||||
|
||||
vol.setTrsh(50);
|
||||
low.setTrsh(50);
|
||||
high.setTrsh(50);
|
||||
|
||||
vol.setVolMin(0);
|
||||
low.setVolMin(0);
|
||||
high.setVolMin(0);
|
||||
|
||||
vol.setVolMax(255);
|
||||
low.setVolMax(255);
|
||||
high.setVolMax(255);
|
||||
|
||||
phot.setDt(80);
|
||||
phot.setK(31);
|
||||
}
|
||||
|
||||
|
||||
void checkAnalog() {
|
||||
if (cfg.state) {
|
||||
switch (cfg.adcMode) {
|
||||
case GL_ADC_NONE: break;
|
||||
case GL_ADC_BRI: checkPhot(); break;
|
||||
case GL_ADC_MIC: checkMusic(); break;
|
||||
case GL_ADC_BOTH:
|
||||
{
|
||||
static timerMillis tmr(1000, 1);
|
||||
if (tmr.isReady()) {
|
||||
switchToPhot();
|
||||
phot.setRaw(analogRead(A0));
|
||||
switchToMic();
|
||||
} else {
|
||||
checkMusic();
|
||||
}
|
||||
phot.compute();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkMusic() {
|
||||
if (CUR_PRES.soundMode > 1) {
|
||||
if (CUR_PRES.soundMode == GL_MUS_VOL) { // громкость
|
||||
vol.tick();
|
||||
} else { // частоты
|
||||
int raw[FFT_SIZE], spectr[FFT_SIZE];
|
||||
for (int i = 0; i < FFT_SIZE; i++) raw[i] = analogRead(A0);
|
||||
FFT(raw, spectr);
|
||||
int low_raw = 0;
|
||||
int high_raw = 0;
|
||||
for (int i = 0; i < FFT_SIZE / 2; i++) {
|
||||
spectr[i] = (spectr[i] * (i + 2)) >> 1;
|
||||
if (i < 2) low_raw += spectr[i];
|
||||
else high_raw += spectr[i];
|
||||
}
|
||||
low.tick(low_raw);
|
||||
high.tick(high_raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkPhot() {
|
||||
static timerMillis tmr(1000, true);
|
||||
if (tmr.isReady()) phot.setRaw(analogRead(A0));
|
||||
phot.compute();
|
||||
}
|
||||
|
||||
byte getSoundVol() {
|
||||
switch (CUR_PRES.soundMode) {
|
||||
case GL_MUS_VOL: return vol.getVol();
|
||||
case GL_MUS_LOW: return low.getVol();
|
||||
case GL_MUS_HIGH: return high.getVol();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void switchToMic() {
|
||||
digitalWrite(PHOT_VCC, 0);
|
||||
pinMode(PHOT_VCC, INPUT);
|
||||
pinMode(MIC_VCC, OUTPUT);
|
||||
digitalWrite(MIC_VCC, 1);
|
||||
}
|
||||
void switchToPhot() {
|
||||
digitalWrite(MIC_VCC, 0);
|
||||
pinMode(MIC_VCC, INPUT);
|
||||
pinMode(PHOT_VCC, OUTPUT);
|
||||
digitalWrite(PHOT_VCC, 1);
|
||||
}
|
||||
void disableADC() {
|
||||
digitalWrite(PHOT_VCC, 0);
|
||||
pinMode(PHOT_VCC, INPUT);
|
||||
digitalWrite(MIC_VCC, 0);
|
||||
pinMode(MIC_VCC, INPUT);
|
||||
}
|
63
firmware/GyverLamp2_v0.7b/button.ino
Normal file
63
firmware/GyverLamp2_v0.7b/button.ino
Normal file
@@ -0,0 +1,63 @@
|
||||
#define CLICKS_TOUT 800
|
||||
|
||||
void button() {
|
||||
#if (USE_BTN == 1)
|
||||
static bool flag = 0, holdFlag = 0, brDir = 0;
|
||||
static timerMillis stepTmr(80, true);
|
||||
static uint32_t tmr = 0;
|
||||
|
||||
btn.tick();
|
||||
|
||||
if (btn.isClick()) {
|
||||
btnClicks++;
|
||||
tmr = millis();
|
||||
}
|
||||
if (btnClicks > 0 && millis() - tmr > CLICKS_TOUT) {
|
||||
DEBUG("clicks: ");
|
||||
DEBUGLN(btnClicks);
|
||||
switch (btnClicks) {
|
||||
case 1:
|
||||
setPower(!cfg.state);
|
||||
sendToSlaves(0, cfg.state);
|
||||
break;
|
||||
case 2:
|
||||
changePreset(1);
|
||||
sendToSlaves(1, cfg.curPreset);
|
||||
break;
|
||||
case 3:
|
||||
changePreset(-1);
|
||||
sendToSlaves(1, cfg.curPreset);
|
||||
break;
|
||||
case 5:
|
||||
cfg.role = 0;
|
||||
break;
|
||||
case 6:
|
||||
cfg.role = 1;
|
||||
break;
|
||||
}
|
||||
EE_updateCfg();
|
||||
btnClicks = 0;
|
||||
}
|
||||
|
||||
if (cfg.state && btn.isHold()) {
|
||||
if (stepTmr.isReady()) {
|
||||
holdFlag = true;
|
||||
int temp = cfg.bright;
|
||||
temp += brDir ? 5 : -5;
|
||||
temp = constrain(temp, 0, 255);
|
||||
cfg.bright = temp;
|
||||
brTicks = cfg.bright / 25;
|
||||
}
|
||||
} else {
|
||||
if (holdFlag) {
|
||||
holdFlag = false;
|
||||
brDir = !brDir;
|
||||
brTicks = 0;
|
||||
DEBUG("Bright set to: ");
|
||||
DEBUGLN(cfg.bright);
|
||||
sendToSlaves(2, cfg.bright);
|
||||
EE_updateCfg();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
104
firmware/GyverLamp2_v0.7b/data.h
Normal file
104
firmware/GyverLamp2_v0.7b/data.h
Normal file
@@ -0,0 +1,104 @@
|
||||
// -------------- ВНУТР. КОНСТАНТЫ ---------------
|
||||
#define GL_ADC_NONE 1
|
||||
#define GL_ADC_BRI 2
|
||||
#define GL_ADC_MIC 3
|
||||
#define GL_ADC_BOTH 4
|
||||
#define GL_TYPE_STRIP 1
|
||||
#define GL_TYPE_ZIG 2
|
||||
#define GL_TYPE_PARAL 3
|
||||
#define GL_MUS_NONE 1
|
||||
#define GL_MUS_VOL 2
|
||||
#define GL_MUS_LOW 3
|
||||
#define GL_MUS_HIGH 4
|
||||
#define GL_REACT_BRI 1
|
||||
#define GL_REACT_SCL 2
|
||||
#define GL_REACT_LEN 3
|
||||
#define GL_SLAVE 0
|
||||
#define GL_MASTER 1
|
||||
|
||||
// ------------------- МАКРО --------------------
|
||||
#ifdef DEBUG_SERIAL
|
||||
#define DEBUGLN(x) Serial.println(x)
|
||||
#define DEBUG(x) Serial.print(x)
|
||||
#else
|
||||
#define DEBUGLN(x)
|
||||
#define DEBUG(x)
|
||||
#endif
|
||||
|
||||
#define FOR_i(x,y) for (int i = (x); i < (y); i++)
|
||||
#define FOR_j(x,y) for (int j = (x); j < (y); j++)
|
||||
#define CUR_PRES preset[cfg.curPreset]
|
||||
|
||||
byte scaleFF(byte x, byte b) {
|
||||
return ((uint16_t)x * (b + 1)) >> 8;
|
||||
}
|
||||
int mapFF(byte x, byte min, byte max) {
|
||||
return (((max - min) * x + (min << 8) + 1) >> 8);
|
||||
}
|
||||
|
||||
const char OTAhost[] = "http://ota.alexgyver.ru/GL2_latest.bin";
|
||||
|
||||
const char *NTPservers[] = {
|
||||
"pool.ntp.org",
|
||||
"europe.pool.ntp.org",
|
||||
"ntp1.stratum2.ru",
|
||||
"ntp2.stratum2.ru",
|
||||
"ntp.msk-ix.ru",
|
||||
};
|
||||
|
||||
#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; // мин яркость
|
||||
byte maxBright = 255; // макс яркость
|
||||
byte rotation = 0; // смена режимов: 0 ручная, 1 авто
|
||||
byte rotRnd = 0; // тип автосмены: 0 в порядке, 1 рандом
|
||||
byte rotPeriod = 1; // период смены (1,5..)
|
||||
byte deviceType = 1; // 1 лента, 2 зигзаг, 3 параллел
|
||||
byte maxCur = 5; // макс ток (мА/100)
|
||||
byte workFrom = 0; // часы работы (0,1.. 23)
|
||||
byte workTo = 0; // часы работы (0,1.. 23)
|
||||
|
||||
int length = 100; // длина ленты
|
||||
int width = 1; // ширина матрицы
|
||||
|
||||
byte state = 1; // состояние 0 выкл, 1 вкл
|
||||
byte group = 1; // группа девайса (1-10)
|
||||
byte role = 0; // 0 slave, 1 master
|
||||
byte WiFimode = 0; // 0 AP, 1 local
|
||||
byte presetAmount = 1; // количество режимов
|
||||
byte manualOff = 0; // выключали вручную?
|
||||
int8_t curPreset = 0; // текущий режим
|
||||
int minLight = 0; // мин освещённость
|
||||
int maxLight = 1023; // макс освещённость
|
||||
char ssid[16]; // логин wifi
|
||||
char pass[16]; // пароль wifi
|
||||
};
|
||||
|
||||
#define PRES_SIZE 13
|
||||
struct Preset {
|
||||
byte effect = 1; // тип эффекта (1,2...) ВЫЧЕСТЬ 1
|
||||
byte fadeBright = 0; // флаг на свою яркость (0/1)
|
||||
byte bright = 100; // своя яркость (0.. 255)
|
||||
byte soundMode = 1; // тип звука (1,2...) ВЫЧЕСТЬ 1
|
||||
byte soundReact = 1; // реакция на звук (1,2...) ВЫЧЕСТЬ 1
|
||||
byte min = 0; // мин сигнал светомузыки (0.. 255)
|
||||
byte max = 0; // макс сигнал светомузыки (0.. 255)
|
||||
byte speed = 10; // скорость (0.. 255)
|
||||
byte palette = 1; // палитра (1,2...) ВЫЧЕСТЬ 1
|
||||
byte scale = 1; // масштаб (0.. 255)
|
||||
byte fromCenter = 0; // эффект из центра (0/1)
|
||||
byte color = 0; // цвет (0.. 255)
|
||||
byte rnd = 0; // случайный (0/1)
|
||||
};
|
||||
|
||||
struct Dawn {
|
||||
byte state[7] = {0, 0, 0, 0, 0, 0, 0}; // (1/0)
|
||||
byte hour[7] = {0, 0, 0, 0, 0, 0, 0}; // (0.. 59)
|
||||
byte minute[7] = {0, 0, 0, 0, 0, 0, 0}; // (0.. 59)
|
||||
byte bright = 100; // (0.. 255)
|
||||
byte time = 1; // (5,10,15,20..)
|
||||
};
|
68
firmware/GyverLamp2_v0.7b/eeprom.ino
Normal file
68
firmware/GyverLamp2_v0.7b/eeprom.ino
Normal file
@@ -0,0 +1,68 @@
|
||||
bool EEcfgFlag = false;
|
||||
bool EEdawnFlag = false;
|
||||
bool EEpresetFlag = false;
|
||||
|
||||
void EE_startup() {
|
||||
// старт епром
|
||||
if (EEPROM.read(511) != EE_KEY) {
|
||||
EEPROM.write(511, EE_KEY);
|
||||
EEPROM.put(0, cfg);
|
||||
EEPROM.put(sizeof(cfg), dawn);
|
||||
EEPROM.put(sizeof(cfg) + sizeof(dawn), preset);
|
||||
EEPROM.commit();
|
||||
DEBUGLN("First start");
|
||||
}
|
||||
EEPROM.get(0, cfg);
|
||||
EEPROM.get(sizeof(cfg), dawn);
|
||||
EEPROM.get(sizeof(cfg) + sizeof(dawn), preset);
|
||||
|
||||
// запускаем всё
|
||||
trnd.setChannel(cfg.group);
|
||||
FastLED.setMaxPowerInVoltsAndMilliamps(STRIP_VOLT, cfg.maxCur * 100);
|
||||
}
|
||||
|
||||
void EE_updateCfg() {
|
||||
EEcfgFlag = true;
|
||||
EEtmr.restart();
|
||||
}
|
||||
void EE_updateDawn() {
|
||||
EEdawnFlag = true;
|
||||
EEtmr.restart();
|
||||
}
|
||||
void EE_updatePreset() {
|
||||
EEpresetFlag = true;
|
||||
EEtmr.restart();
|
||||
}
|
||||
void checkEEupdate() {
|
||||
if (EEtmr.isReady()) {
|
||||
if (EEcfgFlag || EEdawnFlag || EEpresetFlag) {
|
||||
if (EEcfgFlag) {
|
||||
EEcfgFlag = false;
|
||||
EEPROM.put(0, cfg);
|
||||
DEBUGLN("save cfg");
|
||||
}
|
||||
if (EEdawnFlag) {
|
||||
EEdawnFlag = false;
|
||||
EEPROM.put(sizeof(cfg), dawn);
|
||||
DEBUGLN("save dawn");
|
||||
}
|
||||
if (EEpresetFlag) {
|
||||
EEpresetFlag = false;
|
||||
EEPROM.put(sizeof(cfg) + sizeof(dawn), preset);
|
||||
DEBUGLN("save preset");
|
||||
}
|
||||
EEPROM.commit();
|
||||
}
|
||||
EEtmr.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void EE_updCfgRst() {
|
||||
EE_updCfg();
|
||||
delay(100);
|
||||
ESP.restart();
|
||||
}
|
||||
void EE_updCfg() {
|
||||
EEPROM.put(0, cfg);
|
||||
EEPROM.commit();
|
||||
}
|
219
firmware/GyverLamp2_v0.7b/effects.ino
Normal file
219
firmware/GyverLamp2_v0.7b/effects.ino
Normal file
@@ -0,0 +1,219 @@
|
||||
void effectsRoutine() {
|
||||
static timerMillis effTmr(30, true);
|
||||
if (cfg.state && effTmr.isReady()) {
|
||||
FastLED.setBrightness(getBright());
|
||||
|
||||
int thisLength = getLength();
|
||||
byte thisScale = getScale();
|
||||
int thisWidth = (cfg.deviceType > 1) ? cfg.width : 1;
|
||||
|
||||
switch (CUR_PRES.effect) {
|
||||
case 1: // =================================== ПЕРЛИН ===================================
|
||||
FastLED.clear();
|
||||
if (cfg.deviceType > 1) {
|
||||
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),
|
||||
255, LINEARBLEND);
|
||||
}
|
||||
}
|
||||
|
||||
} 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),
|
||||
255, LINEARBLEND);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: // ==================================== ЦВЕТ ====================================
|
||||
FastLED.clear();
|
||||
{
|
||||
fill_solid(leds, cfg.length * thisWidth, CHSV(CUR_PRES.color, thisScale, CUR_PRES.min));
|
||||
CRGB thisColor = CHSV(CUR_PRES.color, thisScale, CUR_PRES.max);
|
||||
if (CUR_PRES.fromCenter) {
|
||||
fillStrip(cfg.length / 2, cfg.length / 2 + thisLength / 2, thisColor);
|
||||
fillStrip(cfg.length / 2 - thisLength / 2, cfg.length / 2, thisColor);
|
||||
} else {
|
||||
fillStrip(0, thisLength, thisColor);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3: // ================================= СМЕНА ЦВЕТА =================================
|
||||
FastLED.clear();
|
||||
{
|
||||
CRGB thisColor = ColorFromPalette(paletteArr[CUR_PRES.palette - 1], (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);
|
||||
if (CUR_PRES.fromCenter) {
|
||||
fillStrip(cfg.length / 2, cfg.length / 2 + thisLength / 2, thisColor);
|
||||
fillStrip(cfg.length / 2 - thisLength / 2, cfg.length / 2, thisColor);
|
||||
} else {
|
||||
fillStrip(0, thisLength, thisColor);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4: // ================================== ГРАДИЕНТ ==================================
|
||||
FastLED.clear();
|
||||
if (CUR_PRES.fromCenter) {
|
||||
FOR_i(cfg.length / 2, cfg.length) {
|
||||
byte bright = 255;
|
||||
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),
|
||||
bright, LINEARBLEND);
|
||||
if (cfg.deviceType > 1) fillRow(i, thisColor);
|
||||
else leds[i] = thisColor;
|
||||
}
|
||||
if (cfg.deviceType > 1) FOR_i(0, cfg.length / 2) fillRow(i, leds[(cfg.length - i)*cfg.width - 1]);
|
||||
else FOR_i(0, cfg.length / 2) leds[i] = leds[cfg.length - i - 1];
|
||||
|
||||
} else {
|
||||
FOR_i(0, cfg.length) {
|
||||
byte bright = 255;
|
||||
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),
|
||||
bright, LINEARBLEND);
|
||||
if (cfg.deviceType > 1) fillRow(i, thisColor);
|
||||
else leds[i] = thisColor;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5: // =================================== ЧАСТИЦЫ ===================================
|
||||
//FastLED.clear();
|
||||
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);
|
||||
thisY = map(thisY, 20000, 45000, 0, cfg.length);
|
||||
int thisX = inoise16(i * 100000000ul + 2000000000ul + (now.weekMs << 6) * CUR_PRES.speed / 255);
|
||||
thisX = map(thisX, 20000, 45000, 0, cfg.width);
|
||||
rndVal = rndVal * 2053 + 13849; // random2053 алгоритм
|
||||
|
||||
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 {
|
||||
uint16_t rndVal = 0;
|
||||
FOR_i(0, thisScale / 8) {
|
||||
int thisPos = inoise16(i * 100000000ul + (now.weekMs << 6) * CUR_PRES.speed / 255);
|
||||
thisPos = map(thisPos, 20000, 45000, 0, cfg.length);
|
||||
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: // ==================================== ОГОНЬ ====================================
|
||||
FastLED.clear();
|
||||
{
|
||||
if (cfg.deviceType > 1) { // 2D огонь
|
||||
fireRoutine();
|
||||
} else { // 1D огонь
|
||||
static byte heat[MAX_LEDS];
|
||||
CRGBPalette16 gPal;
|
||||
if (CUR_PRES.color < 5) gPal = HeatColors_p;
|
||||
else gPal = CRGBPalette16(CRGB::Black, CHSV(CUR_PRES.color, 255, 255), CRGB::White);
|
||||
if (CUR_PRES.fromCenter) thisLength /= 2;
|
||||
|
||||
for (int i = 0; i < thisLength; i++) heat[i] = qsub8(heat[i], random8(0, ((((255 - thisScale) / 2 + 20) * 10) / thisLength) + 2));
|
||||
for (int k = thisLength - 1; k >= 2; k--) heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
|
||||
if (random8() < 120 ) {
|
||||
int y = random8(7);
|
||||
heat[y] = qadd8(heat[y], random8(160, 255));
|
||||
}
|
||||
if (CUR_PRES.fromCenter) {
|
||||
for (int j = 0; j < thisLength; j++) leds[cfg.length / 2 + j] = ColorFromPalette(gPal, scale8(heat[j], 240));
|
||||
FOR_i(0, cfg.length / 2) leds[i] = leds[cfg.length - i - 1];
|
||||
} else {
|
||||
for (int j = 0; j < thisLength; j++) leds[j] = ColorFromPalette(gPal, scale8(heat[j], 240));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7: // ================================== КОНФЕТТИ ==================================
|
||||
FOR_i(0, thisScale >> 3) {
|
||||
byte 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);
|
||||
else leds[i] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// выводим нажатия кнопки
|
||||
if (btnClicks > 0) fill_solid(leds, btnClicks, CRGB::White);
|
||||
if (brTicks > 0) fill_solid(leds, brTicks, CRGB::Cyan);
|
||||
FastLED.show();
|
||||
}
|
||||
}
|
||||
|
||||
byte getBright() {
|
||||
int maxBr = cfg.bright;
|
||||
byte fadeBr = 255;
|
||||
if (CUR_PRES.fadeBright) fadeBr = CUR_PRES.bright; // ограничен вручную
|
||||
|
||||
if (cfg.adcMode == GL_ADC_BRI || cfg.adcMode == GL_ADC_BOTH) { // ----> датчик света
|
||||
maxBr = constrain(phot.getFil(), cfg.minLight, cfg.maxLight);
|
||||
maxBr = map(maxBr, cfg.minLight, cfg.maxLight, cfg.minBright, cfg.maxBright);
|
||||
} else if (cfg.adcMode > 2 && // ----> ацп мик
|
||||
CUR_PRES.soundMode > 1 && // светомузыка вкл
|
||||
CUR_PRES.soundReact == GL_REACT_BRI) { // режим яркости
|
||||
fadeBr = mapFF(getSoundVol(), CUR_PRES.min, CUR_PRES.max);
|
||||
}
|
||||
return scaleFF(maxBr, fadeBr);
|
||||
}
|
||||
|
||||
int getLength() {
|
||||
if (cfg.adcMode > 2 // ацп мик
|
||||
&& CUR_PRES.soundMode > 1 // светомузыка вкл
|
||||
&& CUR_PRES.soundReact == GL_REACT_LEN // режим длины
|
||||
) return mapFF(getSoundVol(), 0, cfg.length);
|
||||
else return cfg.length;
|
||||
}
|
||||
|
||||
byte getScale() {
|
||||
if (cfg.adcMode > 2 // ацп мик
|
||||
&& CUR_PRES.soundMode > 1 // светомузыка вкл
|
||||
&& CUR_PRES.soundReact == GL_REACT_SCL // режим масштаба
|
||||
) return mapFF(getSoundVol(), CUR_PRES.min, CUR_PRES.max);
|
||||
else return CUR_PRES.scale;
|
||||
}
|
||||
|
||||
void fillStrip(int from, int to, CRGB color) {
|
||||
if (cfg.deviceType > 1) {
|
||||
FOR_i(from, to) {
|
||||
FOR_j(0, cfg.width) leds[getPix(j, i)] = color;
|
||||
}
|
||||
} else {
|
||||
FOR_i(from, to) leds[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
void fillRow(int row, CRGB color) {
|
||||
FOR_i(cfg.width * row, cfg.width * (row + 1)) leds[i] = color;
|
||||
}
|
||||
|
||||
// получить номер пикселя в ленте по координатам
|
||||
uint16_t getPix(int x, int y) {
|
||||
if ( !(y & 1) || (cfg.deviceType - 2) ) return (y * cfg.width + x); // если чётная строка
|
||||
else return (y * cfg.width + cfg.width - x - 1); // если нечётная строка
|
||||
}
|
||||
/*
|
||||
целочисленный мап
|
||||
y = ( (y1 - y2) * x + (x1y2 - x2y1) ) / (x1-x2)
|
||||
y = ( (y2 - y1) * x + 255 * y1 ) / 255
|
||||
(x + 128) / 255 -> 0.5-2
|
||||
(x*5 + 51) / 255 -> 0.2-5
|
||||
(x*1.9 + 25) / 255 -> 0.1-1
|
||||
*/
|
25
firmware/GyverLamp2_v0.7b/fastRandom.h
Normal file
25
firmware/GyverLamp2_v0.7b/fastRandom.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef FastRandom_h
|
||||
#define FastRandom_h
|
||||
#include <Arduino.h>
|
||||
|
||||
class FastRandom {
|
||||
public:
|
||||
// установить сид
|
||||
void setSeed(uint16_t seed) {
|
||||
_seed = seed;
|
||||
}
|
||||
uint16_t get() {
|
||||
_seed = (_seed * 2053ul) + 13849;
|
||||
return _seed;
|
||||
}
|
||||
uint16_t get(uint16_t max) {
|
||||
return ((uint32_t)max * get()) >> 16;
|
||||
}
|
||||
uint16_t get(uint16_t min, uint16_t max) {
|
||||
return (get(max - min) + min);
|
||||
}
|
||||
private:
|
||||
uint16_t _seed;
|
||||
};
|
||||
|
||||
#endif
|
83
firmware/GyverLamp2_v0.7b/fire2D.ino
Normal file
83
firmware/GyverLamp2_v0.7b/fire2D.ino
Normal file
@@ -0,0 +1,83 @@
|
||||
const unsigned char valueMask[11][16] PROGMEM = {
|
||||
{8 , 0 , 0 , 0 , 0 , 0 , 0 , 8 , 8 , 0 , 0 , 0 , 0 , 0 , 0 , 8 },
|
||||
{16 , 0 , 0 , 0 , 0 , 0 , 0 , 16 , 16 , 0 , 0 , 0 , 0 , 0 , 0 , 16 },
|
||||
{32 , 0 , 0 , 0 , 0 , 0 , 0 , 32 , 32 , 0 , 0 , 0 , 0 , 0 , 0 , 32 },
|
||||
{64 , 0 , 0 , 0 , 0 , 0 , 0 , 64 , 64 , 0 , 0 , 0 , 0 , 0 , 0 , 64 },
|
||||
{96 , 32 , 0 , 0 , 0 , 0 , 32 , 96 , 96 , 32 , 0 , 0 , 0 , 0 , 32 , 96 },
|
||||
{128, 64 , 32 , 0 , 0 , 32 , 64 , 128, 128, 64 , 32 , 0 , 0 , 32 , 64 , 128},
|
||||
{160, 96 , 64 , 32 , 32 , 64 , 96 , 160, 160, 96 , 64 , 32 , 32 , 64 , 96 , 160},
|
||||
{192, 128, 96 , 64 , 64 , 96 , 128, 192, 192, 128, 96 , 64 , 64 , 96 , 128, 192},
|
||||
{255, 160, 128, 96 , 96 , 128, 160, 255, 255, 160, 128, 96 , 96 , 128, 160, 255},
|
||||
{255, 192, 160, 128, 128, 160, 192, 255, 255, 192, 160, 128, 128, 160, 192, 255},
|
||||
{255, 220, 185, 150, 150, 185, 220, 255, 255, 220, 185, 150, 150, 185, 220, 255},
|
||||
};
|
||||
const unsigned char hueMask[11][16] PROGMEM = {
|
||||
{8 , 16, 32, 36, 36, 32, 16, 8 , 8 , 16, 32, 36, 36, 32, 16, 8 },
|
||||
{5 , 14, 29, 31, 31, 29, 14, 5 , 5 , 14, 29, 31, 31, 29, 14, 5 },
|
||||
{1 , 11, 19, 25, 25, 22, 11, 1 , 1 , 11, 19, 25, 25, 22, 11, 1 },
|
||||
{1 , 8 , 13, 19, 25, 19, 8 , 1 , 1 , 8 , 13, 19, 25, 19, 8 , 1 },
|
||||
{1 , 8 , 13, 16, 19, 16, 8 , 1 , 1 , 8 , 13, 16, 19, 16, 8 , 1 },
|
||||
{1 , 5 , 11, 13, 13, 13, 5 , 1 , 1 , 5 , 11, 13, 13, 13, 5 , 1 },
|
||||
{1 , 5 , 11, 11, 11, 11, 5 , 1 , 1 , 5 , 11, 11, 11, 11, 5 , 1 },
|
||||
{0 , 1 , 5 , 8 , 8 , 5 , 1 , 0 , 0 , 1 , 5 , 8 , 8 , 5 , 1 , 0 },
|
||||
{0 , 0 , 1 , 5 , 5 , 1 , 0 , 0 , 0 , 0 , 1 , 5 , 5 , 1 , 0 , 0 },
|
||||
{0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 },
|
||||
{0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 },
|
||||
};
|
||||
|
||||
byte fireLine[100];
|
||||
|
||||
void fireRoutine() {
|
||||
shiftUp();
|
||||
FOR_i(0, cfg.width) fireLine[i] = random(64, 255);
|
||||
drawFrame(30);
|
||||
}
|
||||
|
||||
void shiftUp() {
|
||||
for (int y = cfg.length - 1; y > 0; y--) {
|
||||
for (int x = 0; x < cfg.width; x++) {
|
||||
int newX = x;
|
||||
if (x > 15) newX = x - 15;
|
||||
if (y > 10) continue;
|
||||
matrixValue[y][newX] = matrixValue[y - 1][newX];
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = 0; x < cfg.width; x++) {
|
||||
int newX = x;
|
||||
if (x > 15) newX = x - 15;
|
||||
matrixValue[0][newX] = fireLine[newX];
|
||||
}
|
||||
}
|
||||
|
||||
void drawFrame(int pcnt) {
|
||||
int nextv;
|
||||
for (int y = cfg.length - 1; y > 0; y--) {
|
||||
for (byte x = 0; x < cfg.width; x++) {
|
||||
int newX = x;
|
||||
if (x > 15) newX = x - 15;
|
||||
if (y < 11) {
|
||||
nextv =
|
||||
(((100.0 - pcnt) * matrixValue[y][newX]
|
||||
+ pcnt * matrixValue[y - 1][newX]) / 100.0)
|
||||
- pgm_read_byte(&(valueMask[y][newX]));
|
||||
|
||||
leds[getPix(x, y)] = CHSV(
|
||||
CUR_PRES.color * 2.5 + pgm_read_byte(&(hueMask[y][newX])), // H
|
||||
255, // S
|
||||
(uint8_t)max(0, nextv) // V
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = 0; x < cfg.width; x++) {
|
||||
int newX = x;
|
||||
if (x > 15) newX = x - 15;
|
||||
leds[getPix(newX, 0)] = CHSV(
|
||||
CUR_PRES.color * 2.5 + pgm_read_byte(&(hueMask[0][newX])), // H
|
||||
255, // S
|
||||
(uint8_t)(((100.0 - pcnt) * matrixValue[0][newX] + pcnt * fireLine[newX]) / 100.0) // V
|
||||
);
|
||||
}
|
||||
}
|
249
firmware/GyverLamp2_v0.7b/palettes.h
Normal file
249
firmware/GyverLamp2_v0.7b/palettes.h
Normal file
@@ -0,0 +1,249 @@
|
||||
#include <FastLED.h> // лента
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Fire_gp ) {
|
||||
0, 0, 0, 0,
|
||||
128, 255, 0, 0,
|
||||
224, 255, 255, 0,
|
||||
255, 255, 255, 255
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Sunset_Real_gp ) {
|
||||
0, 120, 0, 0,
|
||||
22, 179, 22, 0,
|
||||
51, 255, 104, 0,
|
||||
85, 167, 22, 18,
|
||||
135, 100, 0, 103,
|
||||
198, 16, 0, 130,
|
||||
255, 0, 0, 160
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( dkbluered_gp ) {
|
||||
0, 1, 0, 4,
|
||||
8, 1, 0, 13,
|
||||
17, 1, 0, 29,
|
||||
25, 1, 0, 52,
|
||||
33, 1, 0, 83,
|
||||
42, 1, 0, 123,
|
||||
51, 1, 0, 174,
|
||||
59, 1, 0, 235,
|
||||
68, 1, 2, 255,
|
||||
76, 4, 17, 255,
|
||||
84, 16, 45, 255,
|
||||
93, 37, 82, 255,
|
||||
102, 69, 127, 255,
|
||||
110, 120, 168, 255,
|
||||
119, 182, 217, 255,
|
||||
127, 255, 255, 255,
|
||||
135, 255, 217, 184,
|
||||
144, 255, 168, 123,
|
||||
153, 255, 127, 73,
|
||||
161, 255, 82, 40,
|
||||
170, 255, 45, 18,
|
||||
178, 255, 17, 5,
|
||||
186, 255, 2, 1,
|
||||
195, 234, 0, 1,
|
||||
204, 171, 0, 1,
|
||||
212, 120, 0, 1,
|
||||
221, 79, 0, 1,
|
||||
229, 48, 0, 1,
|
||||
237, 26, 0, 1,
|
||||
246, 12, 0, 1,
|
||||
255, 4, 0, 1
|
||||
};
|
||||
DEFINE_GRADIENT_PALETTE( Optimus_Prime_gp ) {
|
||||
0, 5, 16, 18,
|
||||
25, 5, 16, 18,
|
||||
51, 7, 25, 39,
|
||||
76, 8, 38, 71,
|
||||
102, 64, 99, 106,
|
||||
127, 194, 189, 151,
|
||||
153, 182, 63, 42,
|
||||
178, 167, 6, 2,
|
||||
204, 100, 3, 1,
|
||||
229, 53, 1, 1,
|
||||
255, 53, 1, 1
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( warmGrad_gp ) {
|
||||
0, 252, 252, 172,
|
||||
25, 239, 255, 61,
|
||||
53, 247, 45, 17,
|
||||
76, 197, 82, 19,
|
||||
96, 239, 255, 61,
|
||||
124, 83, 4, 1,
|
||||
153, 247, 45, 17,
|
||||
214, 23, 15, 17,
|
||||
255, 1, 1, 1
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( coldGrad_gp ) {
|
||||
0, 66, 186, 192,
|
||||
43, 1, 22, 71,
|
||||
79, 2, 104, 142,
|
||||
117, 66, 186, 192,
|
||||
147, 2, 104, 142,
|
||||
186, 1, 22, 71,
|
||||
224, 2, 104, 142,
|
||||
255, 4, 27, 28
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( hotGrad_gp ) {
|
||||
0, 157, 21, 2,
|
||||
35, 229, 244, 16,
|
||||
73, 255, 44, 7,
|
||||
107, 142, 7, 1,
|
||||
153, 229, 244, 16,
|
||||
206, 142, 7, 1,
|
||||
255, 135, 36, 0
|
||||
};
|
||||
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( pinkGrad_gp ) {
|
||||
0, 249, 32, 145,
|
||||
28, 208, 1, 7,
|
||||
43, 249, 1, 19,
|
||||
56, 126, 152, 10,
|
||||
73, 234, 23, 84,
|
||||
89, 224, 45, 119,
|
||||
107, 232, 127, 158,
|
||||
127, 244, 13, 89,
|
||||
150, 188, 6, 52,
|
||||
175, 177, 70, 14,
|
||||
221, 194, 1, 8,
|
||||
255, 112, 0, 1
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( comfy_gp ) {
|
||||
0, 255, 255, 45,
|
||||
43, 208, 93, 1,
|
||||
137, 224, 1, 242,
|
||||
181, 159, 1, 29,
|
||||
255, 63, 4, 68
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( cyperpunk_gp ) {
|
||||
0, 3, 6, 72,
|
||||
38, 12, 50, 188,
|
||||
109, 217, 35, 1,
|
||||
135, 242, 175, 12,
|
||||
178, 161, 32, 87,
|
||||
255, 24, 6, 108
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( girl_gp ) {
|
||||
0, 103, 1, 10,
|
||||
33, 109, 1, 12,
|
||||
76, 159, 5, 48,
|
||||
119, 175, 55, 103,
|
||||
127, 175, 55, 103,
|
||||
178, 159, 5, 48,
|
||||
221, 109, 1, 12,
|
||||
255, 103, 1, 10
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( xmas_gp ) {
|
||||
0, 0, 12, 0,
|
||||
40, 0, 55, 0,
|
||||
66, 1, 117, 2,
|
||||
77, 1, 84, 1,
|
||||
81, 0, 55, 0,
|
||||
119, 0, 12, 0,
|
||||
153, 42, 0, 0,
|
||||
181, 121, 0, 0,
|
||||
204, 255, 12, 8,
|
||||
224, 121, 0, 0,
|
||||
244, 42, 0, 0,
|
||||
255, 42, 0, 0
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( acid_gp ) {
|
||||
0, 0, 12, 0,
|
||||
61, 153, 239, 112,
|
||||
127, 0, 12, 0,
|
||||
165, 106, 239, 2,
|
||||
196, 167, 229, 71,
|
||||
229, 106, 239, 2,
|
||||
255, 0, 12, 0
|
||||
};
|
||||
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( blueSmoke_gp ) {
|
||||
0, 0, 0, 0,
|
||||
12, 1, 1, 3,
|
||||
53, 8, 1, 22,
|
||||
80, 4, 6, 89,
|
||||
119, 2, 25, 216,
|
||||
145, 7, 10, 99,
|
||||
186, 15, 2, 31,
|
||||
233, 2, 1, 5,
|
||||
255, 0, 0, 0
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( gummy_gp ) {
|
||||
0, 8, 47, 5,
|
||||
31, 77, 122, 6,
|
||||
63, 249, 237, 7,
|
||||
95, 232, 51, 1,
|
||||
127, 215, 0, 1,
|
||||
159, 47, 1, 3,
|
||||
191, 1, 7, 16,
|
||||
223, 52, 22, 6,
|
||||
255, 239, 45, 1,
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( leo_gp ) {
|
||||
0, 0, 0, 0,
|
||||
16, 0, 0, 0,
|
||||
32, 0, 0, 0,
|
||||
18, 0, 0, 0,
|
||||
64, 16, 8, 0,
|
||||
80, 80, 40, 0,
|
||||
96, 16, 8, 0,
|
||||
112, 0, 0, 0,
|
||||
128, 0, 0, 0,
|
||||
144, 0, 0, 0,
|
||||
160, 0, 0, 0,
|
||||
176, 0, 0, 0,
|
||||
192, 0, 0, 0,
|
||||
208, 0, 0, 0,
|
||||
224, 0, 0, 0,
|
||||
240, 0, 0, 0,
|
||||
255, 0, 0, 0,
|
||||
};
|
||||
|
||||
DEFINE_GRADIENT_PALETTE ( aurora_gp ) {
|
||||
0, 17, 177, 13, //Greenish
|
||||
64, 121, 242, 5, //Greenish
|
||||
128, 25, 173, 121, //Turquoise
|
||||
192, 250, 77, 127, //Pink
|
||||
255, 171, 101, 221 //Purple
|
||||
};
|
||||
|
||||
CRGBPalette16 paletteArr[] = {
|
||||
HeatColors_p,
|
||||
Fire_gp,
|
||||
LavaColors_p,
|
||||
PartyColors_p,
|
||||
RainbowColors_p,
|
||||
RainbowStripeColors_p,
|
||||
CloudColors_p,
|
||||
OceanColors_p,
|
||||
ForestColors_p,
|
||||
Sunset_Real_gp,
|
||||
dkbluered_gp,
|
||||
Optimus_Prime_gp,
|
||||
warmGrad_gp,
|
||||
coldGrad_gp,
|
||||
hotGrad_gp,
|
||||
pinkGrad_gp,
|
||||
comfy_gp,
|
||||
cyperpunk_gp,
|
||||
girl_gp,
|
||||
xmas_gp,
|
||||
acid_gp,
|
||||
blueSmoke_gp,
|
||||
gummy_gp,
|
||||
leo_gp,
|
||||
aurora_gp,
|
||||
};
|
143
firmware/GyverLamp2_v0.7b/parsing.ino
Normal file
143
firmware/GyverLamp2_v0.7b/parsing.ino
Normal file
@@ -0,0 +1,143 @@
|
||||
void parsing() {
|
||||
if (Udp.parsePacket()) {
|
||||
static uint32_t tmr = 0;
|
||||
static char buf[UDP_TX_PACKET_MAX_SIZE + 1];
|
||||
|
||||
int n = Udp.read(buf, UDP_TX_PACKET_MAX_SIZE);
|
||||
if (millis() - tmr < 500) return; // принимаем посылки не чаще 2 раз в секунду
|
||||
tmr = millis();
|
||||
|
||||
buf[n] = NULL;
|
||||
DEBUGLN(buf); // пакет вида <ключ>,<канал>,<тип>,<дата1>,<дата2>...
|
||||
|
||||
byte keyLen = strlen(GL_KEY);
|
||||
if (!strncmp(buf, GL_KEY, keyLen)) { // парсим если это наша "сеть"
|
||||
byte data[MAX_PRESETS * PRES_SIZE + keyLen];
|
||||
memset(data, 0, 30);
|
||||
int count = 0;
|
||||
char *str, *p = buf + keyLen; // сдвиг до даты
|
||||
char *ssid, *pass;
|
||||
while ((str = strtok_r(p, ",", &p)) != NULL) {
|
||||
data[count++] = atoi(str);
|
||||
if (count == 4) ssid = str;
|
||||
if (count == 5) pass = str;
|
||||
}
|
||||
|
||||
// широковещательный запрос времени для local устройств в сети AP лампы
|
||||
if (data[0] == 0 && cfg.WiFimode && !gotNTP) {
|
||||
now.hour = data[1];
|
||||
now.min = data[2];
|
||||
now.setMs(0);
|
||||
}
|
||||
|
||||
if (data[0] != cfg.group) return; // не наш адрес, выходим
|
||||
|
||||
switch (data[1]) { // тип 0 - control, 1 - config, 2 - effects, 3 - dawn
|
||||
case 0: DEBUGLN("Control");
|
||||
switch (data[2]) {
|
||||
case 0: setPower(0); break; // выкл
|
||||
case 1: setPower(1); break; // вкл
|
||||
case 2: cfg.minLight = phot.getRaw(); break; // мин яркость
|
||||
case 3: cfg.maxLight = phot.getRaw(); break; // макс яркость
|
||||
case 4: changePreset(-1); break; // пред пресет
|
||||
case 5: changePreset(1); break; // след пресет
|
||||
case 6: setPreset(data[3] - 1); break; // конкретный пресет data[3]
|
||||
case 7: cfg.WiFimode = data[3]; EE_updCfgRst(); break; // смена режима WiFi
|
||||
case 8: cfg.role = data[3]; break; // смена роли
|
||||
case 9: cfg.group = data[3]; break; // смена группы
|
||||
case 10: // установка настроек WiFi
|
||||
strcpy(cfg.ssid, ssid);
|
||||
strcpy(cfg.pass, pass);
|
||||
break;
|
||||
case 11: EE_updCfgRst(); break; // рестарт
|
||||
case 12: if (gotNTP) { // OTA обновление, если есть интернет
|
||||
delay(100);
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
ESPhttpUpdate.update(OTAhost);
|
||||
} break;
|
||||
case 13: // выключить через
|
||||
if (data[3] == 0) turnoffTmr.stop();
|
||||
else {
|
||||
turnoffTmr.setInterval((uint32_t)data[3] * 60000ul);
|
||||
turnoffTmr.restart();
|
||||
}
|
||||
break;
|
||||
}
|
||||
EE_updCfg();
|
||||
break;
|
||||
|
||||
case 1: DEBUGLN("Config");
|
||||
FOR_i(0, CFG_SIZE) {
|
||||
*((byte*)&cfg + i) = data[i + 2]; // загоняем в структуру
|
||||
}
|
||||
cfg.length = data[17] | (data[16] << 8); // склеиваем
|
||||
cfg.width = data[20] | (data[19] << 8); // склеиваем
|
||||
if (cfg.deviceType == GL_TYPE_STRIP) cfg.width = 1;
|
||||
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();
|
||||
else disableADC();
|
||||
EE_updCfg();
|
||||
break;
|
||||
|
||||
case 2: DEBUGLN("Preset");
|
||||
cfg.presetAmount = data[2]; // кол-во режимов
|
||||
FOR_j(0, cfg.presetAmount) {
|
||||
FOR_i(0, PRES_SIZE) {
|
||||
*((byte*)&preset + j * PRES_SIZE + i) = data[j * PRES_SIZE + i + 3]; // загоняем в структуру
|
||||
}
|
||||
}
|
||||
EE_updatePreset();
|
||||
break;
|
||||
|
||||
case 3: DEBUGLN("Dawn");
|
||||
FOR_i(0, (2 + 3 * 7)) {
|
||||
*((byte*)&dawn + i) = data[i + 2]; // загоняем в структуру
|
||||
}
|
||||
EE_updateDawn();
|
||||
break;
|
||||
|
||||
case 4: DEBUGLN("From master");
|
||||
if (cfg.role == GL_SLAVE) {
|
||||
switch (data[2]) {
|
||||
case 0: setPower(data[3]); break; // вкл выкл
|
||||
case 1: setPreset(data[3]); break; // пресет
|
||||
case 2: cfg.bright = data[3]; break; // яркость
|
||||
}
|
||||
EE_updateCfg();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: ");
|
||||
DEBUGLN(reply);
|
||||
|
||||
FOR_i(0, 3) {
|
||||
Udp.beginPacket(ip, 8888);
|
||||
Udp.write(reply);
|
||||
Udp.endPacket();
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
}
|
43
firmware/GyverLamp2_v0.7b/presetManager.ino
Normal file
43
firmware/GyverLamp2_v0.7b/presetManager.ino
Normal file
@@ -0,0 +1,43 @@
|
||||
void presetRotation() {
|
||||
if (cfg.rotation && now.newMin()) { // если автосмена и новая минута
|
||||
if (cfg.rotRnd) { // случайная
|
||||
cfg.curPreset = trnd.fromMin(cfg.rotPeriod, cfg.presetAmount);
|
||||
DEBUG("Rnd changed to ");
|
||||
DEBUGLN(cfg.curPreset);
|
||||
} else { // по порядку
|
||||
cfg.curPreset = ((trnd.getMin() / cfg.rotPeriod) % cfg.presetAmount);
|
||||
DEBUG("In order changed to ");
|
||||
DEBUGLN(cfg.curPreset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void changePreset(int dir) {
|
||||
if (!cfg.rotation) { // ручная смена
|
||||
cfg.curPreset += dir;
|
||||
if (cfg.curPreset >= cfg.presetAmount) cfg.curPreset = 0;
|
||||
if (cfg.curPreset < 0) cfg.curPreset = cfg.presetAmount - 1;
|
||||
DEBUG("Preset changed to ");
|
||||
DEBUGLN(cfg.curPreset);
|
||||
}
|
||||
}
|
||||
|
||||
void setPreset(byte pres) {
|
||||
if (!cfg.rotation) { // ручная смена
|
||||
cfg.curPreset = constrain(pres, 0, cfg.presetAmount - 1);
|
||||
DEBUG("Preset set to ");
|
||||
DEBUGLN(cfg.curPreset);
|
||||
}
|
||||
}
|
||||
|
||||
void setPower(bool state) {
|
||||
if (state) cfg.manualOff = 0;
|
||||
if (cfg.state && !state) cfg.manualOff = 1;
|
||||
cfg.state = state;
|
||||
if (!state) {
|
||||
delay(100); // чтобы пролететь мин. частоту обновления
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
}
|
||||
DEBUGLN(state ? "Power on" : "Power off");
|
||||
}
|
170
firmware/GyverLamp2_v0.7b/startup.ino
Normal file
170
firmware/GyverLamp2_v0.7b/startup.ino
Normal file
@@ -0,0 +1,170 @@
|
||||
void checkButton() {
|
||||
#if (USE_BTN == 1)
|
||||
DEBUGLN(cfg.WiFimode ? "local mode" : "AP mode");
|
||||
if (btn.isHold()) { // кнопка зажата
|
||||
FastLED.clear();
|
||||
byte count = 0;
|
||||
bool state = 0;
|
||||
|
||||
while (btn.state()) { // пока зажата кнопка
|
||||
fill_solid(leds, constrain(count, 0, 8), CRGB::Red);
|
||||
count++;
|
||||
if (count == 9) { // на счёт 9 поднимаем яркость и флаг
|
||||
FastLED.setBrightness(120);
|
||||
state = 1;
|
||||
} else if (count == 16) { // на счёт 16 опускаем флаг выходим
|
||||
state = 0;
|
||||
break;
|
||||
}
|
||||
FastLED.show();
|
||||
delay(300);
|
||||
}
|
||||
if (state) {
|
||||
DEBUGLN("change mode");
|
||||
cfg.WiFimode = !cfg.WiFimode;
|
||||
EEPROM.put(0, cfg);
|
||||
EEPROM.commit();
|
||||
delay(100);
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
FastLED.setBrightness(50);
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
#endif
|
||||
}
|
||||
|
||||
void checkGroup() {
|
||||
fill_solid(leds, cfg.group, (cfg.WiFimode) ? (CRGB::Blue) : (CRGB::Green));
|
||||
FastLED.show();
|
||||
uint32_t tmr = millis();
|
||||
bool flag = 0;
|
||||
while (millis() - tmr < 3000) {
|
||||
#if (USE_BTN == 1)
|
||||
btn.tick();
|
||||
if (btn.isClick()) {
|
||||
if (++cfg.group > 10) cfg.group = 1;
|
||||
FastLED.clear();
|
||||
fill_solid(leds, cfg.group, (cfg.WiFimode) ? (CRGB::Blue) : (CRGB::Green));
|
||||
FastLED.show();
|
||||
flag = 1;
|
||||
tmr = millis();
|
||||
}
|
||||
if (btn.isHold()) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
yield();
|
||||
}
|
||||
if (flag) {
|
||||
EEPROM.put(0, cfg);
|
||||
EEPROM.commit();
|
||||
delay(100);
|
||||
ESP.reset();
|
||||
}
|
||||
DEBUG("group: ");
|
||||
DEBUGLN(cfg.group);
|
||||
DEBUG("role: ");
|
||||
DEBUGLN(cfg.role);
|
||||
}
|
||||
|
||||
void startStrip() {
|
||||
delay(500);
|
||||
FastLED.addLeds<STRIP_CHIP, STRIP_PIN, STRIP_COLOR>(leds, MAX_LEDS).setCorrection(TypicalLEDStrip);
|
||||
FastLED.setMaxPowerInVoltsAndMilliamps(STRIP_VOLT, 500);
|
||||
FastLED.setBrightness(50);
|
||||
leds[0] = CRGB::Red;
|
||||
leds[1] = CRGB::Green;
|
||||
leds[2] = CRGB::Blue;
|
||||
FastLED.show();
|
||||
FastLED.clear();
|
||||
delay(1500);
|
||||
}
|
||||
|
||||
void startWiFi() {
|
||||
if (!cfg.WiFimode) setupAP(); // режим точки доступа
|
||||
else setupLocal(); // подключаемся к точке
|
||||
|
||||
DEBUG("UDP port: ");
|
||||
DEBUGLN(8888);
|
||||
Udp.begin(8888);
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
}
|
||||
|
||||
void setupAP() {
|
||||
fill_solid(leds, 8, CRGB::Yellow);
|
||||
FastLED.show();
|
||||
delay(500);
|
||||
WiFi.disconnect();
|
||||
WiFi.mode(WIFI_AP);
|
||||
delay(100);
|
||||
WiFi.softAP(AP_NameChar, WiFiPassword);
|
||||
server.begin();
|
||||
DEBUGLN("Setting AP Mode");
|
||||
DEBUG("AP IP: ");
|
||||
DEBUGLN(WiFi.softAPIP());
|
||||
delay(500);
|
||||
}
|
||||
|
||||
void setupLocal() {
|
||||
if (cfg.ssid[0] == NULL && cfg.pass[0] == NULL) {
|
||||
DEBUGLN("WiFi not configured");
|
||||
setupAP();
|
||||
} else {
|
||||
DEBUGLN("Connecting to AP...");
|
||||
WiFi.softAPdisconnect();
|
||||
WiFi.disconnect();
|
||||
WiFi.mode(WIFI_STA);
|
||||
delay(100);
|
||||
uint32_t tmr = millis();
|
||||
bool connect = false;
|
||||
int8_t count = 0, dir = 1;
|
||||
byte failCount = 0;
|
||||
while (1) {
|
||||
WiFi.begin(cfg.ssid, cfg.pass);
|
||||
while (millis() - tmr < 10000) {
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
connect = true;
|
||||
break;
|
||||
}
|
||||
FastLED.clear();
|
||||
leds[count] = CRGB::Yellow;
|
||||
FastLED.show();
|
||||
count += dir;
|
||||
if (count >= 7 || count <= 0) dir *= -1;
|
||||
delay(50);
|
||||
}
|
||||
if (connect) {
|
||||
fill_solid(leds, 8, CRGB::Green);
|
||||
FastLED.show();
|
||||
server.begin();
|
||||
DEBUG("Connected! Local IP: ");
|
||||
DEBUGLN(WiFi.localIP());
|
||||
delay(500);
|
||||
return;
|
||||
} else {
|
||||
DEBUGLN("Failed!");
|
||||
FOR_i(0, 3) {
|
||||
fill_solid(leds, 8, CRGB::Red);
|
||||
FastLED.show();
|
||||
delay(300);
|
||||
FastLED.clear();
|
||||
FastLED.show();
|
||||
delay(300);
|
||||
}
|
||||
failCount++;
|
||||
tmr = millis();
|
||||
if (failCount >= 3) {
|
||||
setupAP();
|
||||
return;
|
||||
/*DEBUGLN("Reboot to AP!");
|
||||
cfg.WiFimode = 0;
|
||||
EE_updCfg();
|
||||
delay(100);
|
||||
ESP.restart();*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
108
firmware/GyverLamp2_v0.7b/time.ino
Normal file
108
firmware/GyverLamp2_v0.7b/time.ino
Normal file
@@ -0,0 +1,108 @@
|
||||
void setupTime() {
|
||||
ntp.setUpdateInterval(NTP_UPD_PRD / 2 * 60000ul); // меньше в два раза, ибо апдейт вручную
|
||||
ntp.setTimeOffset((cfg.GMT - 13) * 3600);
|
||||
ntp.setPoolServerName(NTPservers[cfg.NTP - 1]);
|
||||
if (cfg.WiFimode) {
|
||||
// если подключены - запрашиваем время с сервера
|
||||
ntp.begin();
|
||||
if (ntp.update() && !gotNTP) gotNTP = true;
|
||||
}
|
||||
}
|
||||
|
||||
// сохраняет счёт времени после обрыва связи
|
||||
void timeTicker() {
|
||||
static timerMillis tmr(10, true);
|
||||
if (tmr.isReady()) {
|
||||
updateTime(); // обновляем время
|
||||
sendTimeToSlaves(); // отправляем время слейвам
|
||||
trnd.update(now.hour, now.min, now.sec); // обновляем рандомайзер
|
||||
if (gotNTP) checkWorkTime(); // проверяем расписание, если подключены к Интернет
|
||||
checkTurnoff(); // проверяем таймер отключения
|
||||
}
|
||||
}
|
||||
|
||||
void updateTime() {
|
||||
if (cfg.WiFimode && WiFi.status() == WL_CONNECTED) { // если вайфай подключен
|
||||
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.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;
|
||||
}
|
||||
} else { // если нет
|
||||
now.tick(); // тикаем своим счётчиком
|
||||
}
|
||||
}
|
||||
|
||||
void sendTimeToSlaves() {
|
||||
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 мин отправляем время
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkTurnoff() {
|
||||
if (turnoffTmr.isReady()) {
|
||||
turnoffTmr.stop();
|
||||
setPower(0);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
DEBUG("Sending time: ");
|
||||
DEBUGLN(reply);
|
||||
Udp.beginPacket(ip, 8888);
|
||||
Udp.write(reply);
|
||||
Udp.endPacket();
|
||||
}
|
||||
|
||||
bool isWorkTime(byte t, byte from, byte to) {
|
||||
if (from == to) return 1;
|
||||
else if (from < to) {
|
||||
if (t >= from && t < to) return 1;
|
||||
else return 0;
|
||||
} else {
|
||||
if (t >= from || t < to) return 1;
|
||||
else return 0;
|
||||
}
|
||||
}
|
68
firmware/GyverLamp2_v0.7b/timeRandom.h
Normal file
68
firmware/GyverLamp2_v0.7b/timeRandom.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef TimeRandom_h
|
||||
#define TimeRandom_h
|
||||
#include <Arduino.h>
|
||||
|
||||
class TimeRandom {
|
||||
public:
|
||||
// установить канал (по умолч 0)
|
||||
void setChannel(byte channel) {
|
||||
_c = channel;
|
||||
}
|
||||
|
||||
// обновить ЧМС
|
||||
void update(byte h, byte m, byte s) {
|
||||
_h = h;
|
||||
_m = m;
|
||||
_s = s;
|
||||
}
|
||||
|
||||
// количество секунд с начала суток
|
||||
uint32_t getSec() {
|
||||
return (_h * 3600ul + _m * 60 + _s);
|
||||
}
|
||||
|
||||
// количество минут с начала суток
|
||||
uint32_t getMin() {
|
||||
return (_h * 60 + _m);
|
||||
}
|
||||
|
||||
// случайное число, обновляется каждые every секунд
|
||||
uint16_t fromSec(int every) {
|
||||
uint16_t s = getSec() / every;
|
||||
uint16_t val = (uint16_t)(_c + 1) * (_h + 1) * (_m + 1) * (s + 1);
|
||||
for (uint16_t i = 0; i < s & 0b1111; i++) val = (val * 2053ul) + 13849;
|
||||
return val;
|
||||
}
|
||||
|
||||
// случайное число от 0 до max, обновляется каждые every секунд
|
||||
uint16_t fromSec(byte every, uint16_t max) {
|
||||
return ((uint32_t)max * fromSec(every)) >> 16;
|
||||
}
|
||||
|
||||
// случайное число от min до max, обновляется каждые every секунд
|
||||
uint16_t fromSec(byte every, uint16_t min, uint16_t max) {
|
||||
return (fromSec(every, max - min) + min);
|
||||
}
|
||||
|
||||
// случайное число, обновляется каждые every минут
|
||||
uint16_t fromMin(int every) {
|
||||
uint16_t m = getMin() / every;
|
||||
uint16_t val = (uint16_t)(_c + 1) * (_h + 1) * (m + 1);
|
||||
for (uint16_t i = 0; i < m & 0b1111; i++) val = (val * 2053ul) + 13849;
|
||||
return val;
|
||||
}
|
||||
|
||||
// случайное число от 0 до max, обновляется каждые every минут
|
||||
uint16_t fromMin(byte every, uint16_t max) {
|
||||
return ((uint32_t)max * fromMin(every)) >> 16;
|
||||
}
|
||||
|
||||
// случайное число от min до max, обновляется каждые every минут
|
||||
uint16_t fromMin(byte every, uint16_t min, uint16_t max) {
|
||||
return (fromMin(every, max - min) + min);
|
||||
}
|
||||
private:
|
||||
byte _h = 0, _m = 0, _s = 0, _c = 0;
|
||||
};
|
||||
|
||||
#endif
|
36
firmware/GyverLamp2_v0.7b/timerMillis.h
Normal file
36
firmware/GyverLamp2_v0.7b/timerMillis.h
Normal file
@@ -0,0 +1,36 @@
|
||||
class timerMillis {
|
||||
public:
|
||||
timerMillis() {}
|
||||
timerMillis(uint32_t interval, bool active = false) {
|
||||
_interval = interval;
|
||||
reset();
|
||||
if (active) restart();
|
||||
else stop();
|
||||
}
|
||||
void setInterval(uint32_t interval) {
|
||||
_interval = (interval == 0) ? 1 : interval;
|
||||
}
|
||||
boolean isReady() {
|
||||
if (_active && millis() - _tmr >= _interval) {
|
||||
//_tmr += _interval;
|
||||
reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void reset() {
|
||||
_tmr = millis();
|
||||
}
|
||||
void restart() {
|
||||
reset();
|
||||
_active = true;
|
||||
}
|
||||
void stop() {
|
||||
_active = false;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t _tmr = 0;
|
||||
uint32_t _interval = 0;
|
||||
boolean _active = false;
|
||||
};
|
Reference in New Issue
Block a user