-
Notifications
You must be signed in to change notification settings - Fork 20
/
dimmertask.ino
185 lines (158 loc) · 6.89 KB
/
dimmertask.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
volatile bool moonUpdate = true;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR _moonISR()
{
portENTER_CRITICAL_ISR(&timerMux);
moonUpdate = true;
portEXIT_CRITICAL_ISR(&timerMux);
}
void IRAM_ATTR dimmerTask ( void * pvParameters )
{
const TickType_t dimmerTaskdelayTime = 1000 / UPDATE_FREQ_LEDS / portTICK_PERIOD_MS;
if ( defaultTimersLoaded() ) ESP_LOGI( TAG, "Default timers loaded." );
else {
ESP_LOGI( TAG, "No timers loaded." );
setEmptyTimers();
}
/* setup pwm on leds */
channel[ 0 ].pin = LED0_PIN;
channel[ 1 ].pin = LED1_PIN;
channel[ 2 ].pin = LED2_PIN;
channel[ 3 ].pin = LED3_PIN;
channel[ 4 ].pin = LED4_PIN;
for ( uint8_t num = 0; num < NUMBER_OF_CHANNELS; num++ ) {
char NVSKeyName[32];
snprintf( NVSKeyName, sizeof( NVSKeyName ), "channelname%i", num );
snprintf( channel[ num ].name, sizeof( channel[ num ].name ), preferences.getString( NVSKeyName, "channelname" ).c_str() );
snprintf( NVSKeyName, sizeof( NVSKeyName ), "channelcolor%i", num );
snprintf( channel[ num ].color, sizeof( channel[ num ].color ), preferences.getString( NVSKeyName, "#fffe7a" ).c_str() );
snprintf( NVSKeyName, sizeof( NVSKeyName ), "channelminimum%i", num );
channel[ num ].fullMoonLevel = preferences.getFloat( NVSKeyName, 0 );
ledcAttachPin( channel[num].pin, num);
}
setupDimmerPWMfrequency( preferences.getDouble( "pwmfrequency", LEDC_MAXIMUM_FREQ ),
preferences.getUInt( "pwmdepth", LEDC_NUMBER_OF_BIT ) );
hw_timer_t * moonTimer = timerBegin( HWTIMER1_MOON, 80, true );
timerAttachInterrupt( moonTimer, &_moonISR, true );
timerAlarmWrite( moonTimer, 1000000 * 10, true );
timerAlarmEnable( moonTimer );
leds.setState( LIGHTS_AUTO );
TickType_t xLastWakeTime = xTaskGetTickCount();
ESP_LOGI( TAG, "Lights running after %i ms.", millis() );
while (1) {
if ( moonUpdate ) {
moonData = moonPhase.getPhase();
ESP_LOGI( TAG, "Moon phase updated: %i degrees %.6f%% lit", moonData.angle, moonData.percentLit * 100 );
portENTER_CRITICAL(&timerMux);
moonUpdate = false;
portEXIT_CRITICAL(&timerMux);
}
lightState_t currentState = leds.state();
if ( currentState != LIGHTS_AUTO ) {
uint16_t pwmValue = ( currentState == LIGHTS_OFF ) ? 0 : ledcMaxValue;
float percentage = ( pwmValue == 0 ) ? 0 : 100;
for ( uint8_t num = 0; num < NUMBER_OF_CHANNELS; num++ ) {
channel[num].currentPercentage = percentage;
ledcWrite( num, pwmValue );
}
while ( leds.state() == currentState ) delay( dimmerTaskdelayTime );
}
else {
struct timeval microSecondTime;
gettimeofday( µSecondTime, NULL );
struct tm localTime;
localtime_r( µSecondTime.tv_sec, &localTime );
suseconds_t milliSecondsToday = ( localTime.tm_hour * 3600000U ) +
( localTime.tm_min * 60000U ) +
( localTime.tm_sec * 1000U ) +
( microSecondTime.tv_usec / 1000U );
if ( milliSecondsToday ) { /* to solve flashing at 00:00:000 due to the fact that the first timer has no predecessor */
for ( uint8_t num = 0; num < NUMBER_OF_CHANNELS; num++ ) {
uint8_t thisTimer = 0;
while ( channel[num].timer[thisTimer].time * 1000U < milliSecondsToday )
thisTimer++;
float newPercentage;
/* only do a lot of float math if really neccesary */
if ( channel[num].timer[thisTimer].percentage != channel[num].timer[thisTimer - 1].percentage ) {
newPercentage = mapFloat( milliSecondsToday,
channel[num].timer[thisTimer - 1].time * 1000U,
channel[num].timer[thisTimer].time * 1000U,
channel[num].timer[thisTimer - 1].percentage,
channel[num].timer[thisTimer].percentage );
}
else {
/* timers are equal so no math neccesary */
newPercentage = channel[num].timer[thisTimer].percentage;
}
/* calculate moon light */
if ( newPercentage < ( channel[num].fullMoonLevel * moonData.percentLit ) )
newPercentage = channel[num].fullMoonLevel * moonData.percentLit;
/* done, set the channel */
channel[num].currentPercentage = newPercentage;
ledcWrite( num, mapFloat( channel[num].currentPercentage,
0,
100,
0,
ledcMaxValue ) );
}
}
}
vTaskDelayUntil( &xLastWakeTime, dimmerTaskdelayTime );
}
}
bool defaultTimersLoaded() {
//find 'default.aqu' on selected storage and if present load the timerdata from this file
//return true on success
//return false on error
if ( !FFat.exists( defaultTimerFile ) ) {
return false;
}
File f = FFat.open( defaultTimerFile, "r" );
if ( !f.available() ) {
ESP_LOGI( TAG, "Error opening default timer file. [%s]", defaultTimerFile );
return false;
}
byte currentTimer = 0;
uint8_t chan;
//String data;
while ( f.position() < f.size() ) {
String data = f.readStringUntil( '\n' );
if ( 0 == data.indexOf( "[" ) ) {
chan = data.substring( 1, 3 ).toInt();
currentTimer = 0;
}
else if ( currentTimer < MAX_TIMERS - 1 ) {
channel[chan].timer[currentTimer].time = data.substring( 0, data.indexOf(",") ).toInt();
channel[chan].timer[currentTimer].percentage = data.substring( data.indexOf(",") + 1 ).toInt();
currentTimer++;
channel[chan].numberOfTimers = currentTimer;
}
}
f.close();
//add the 24:00 timers ( copy of timer percentage no: 0 )
for (chan = 0; chan < NUMBER_OF_CHANNELS; chan++ ) {
channel[chan].timer[channel[chan].numberOfTimers].time = 86400;
channel[chan].timer[channel[chan].numberOfTimers].percentage = channel[chan].timer[0].percentage;
currentTimer++;
channel[chan].numberOfTimers = currentTimer;
}
return true;
}
void setEmptyTimers() {
for ( uint8_t num = 0; num < NUMBER_OF_CHANNELS; num++) {
channel[num].timer[0] = {0, 0};
channel[num].timer[1] = {86400, 0};
channel[num].numberOfTimers = 1;
}
}
void setupDimmerPWMfrequency( const double frequency, const uint8_t numberOfBits ) {
/* Setup timers and pwm bit depth */
for ( uint8_t num = 0; num < NUMBER_OF_CHANNELS; num++ ) {
ledcActualFrequency = ledcSetup( num, frequency, numberOfBits );
}
ledcMaxValue = ( 0x00000001 << numberOfBits ) - 1;
ledcNumberOfBits = numberOfBits;
ESP_LOGI( TAG, "PWM frequency set to %.2f kHz.", ledcActualFrequency / 1000);
ESP_LOGI( TAG, "PWM bit depth set to %i bits.", ledcNumberOfBits);
ESP_LOGI( TAG, "Maximum raw value set to 0x%x or %i decimal.", ledcMaxValue, ledcMaxValue);
}