Skip to content

Commit a562f1d

Browse files
authored
Merge branch 'ESPWortuhr:main' into Add-options-for-vertical,-extra-led-and-meander-layout
2 parents 538ed10 + a1eef35 commit a562f1d

File tree

19 files changed

+358
-202
lines changed

19 files changed

+358
-202
lines changed

include/EEPROMAnything.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,9 @@ void read() {
7676
Serial.printf("MQTT_Port : %u\n", G.mqtt.port);
7777

7878
Serial.printf("autoBrightEnabled : %u\n", G.autoBrightEnabled);
79-
Serial.printf("autoBrightOffset : %u\n", G.autoBrightOffset);
80-
Serial.printf("autoBrightSlope : %u\n", G.autoBrightSlope);
79+
Serial.printf("autoBrightMin : %u\n", G.autoBrightMin);
80+
Serial.printf("autoBrightMax : %u\n", G.autoBrightMax);
81+
Serial.printf("autoBrightPeak : %u\n", G.autoBrightPeak);
8182
Serial.printf("Uhrtype : %u\n", G.transitionDuration);
8283
Serial.printf("transitionType : %u\n", G.transitionType);
8384
Serial.printf("transitionDuration : %u\n", G.transitionSpeed);

include/Uhr.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@ struct GLOBAL {
137137
OpenWeatherMapData openWeatherMap;
138138

139139
uint8_t autoBrightEnabled;
140-
uint8_t autoBrightOffset;
141-
uint8_t autoBrightSlope;
140+
uint8_t autoBrightMin;
141+
uint8_t autoBrightMax;
142+
uint16_t autoBrightPeak;
142143
uint8_t transitionType;
143144
uint8_t transitionDuration;
144145
uint8_t transitionSpeed;
@@ -155,7 +156,7 @@ struct GLOBAL {
155156
GLOBAL G = {};
156157

157158
// LDR
158-
float ledGain = 100;
159+
float ledGain = DEFAULT_BRIGHTNESS;
159160

160161
uint8_t _second = 0;
161162
uint8_t _secondFrame = 0;

include/clockWork.h

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,12 @@ class ClockWork {
66
private:
77
uint16_t countMillisSpeed = 0;
88
uint32_t previousMillis = 0;
9-
enum class stateBH1750Type {
10-
toBeInitialized = 0,
11-
Initialized = 1,
12-
cannotBeInitialized = 2,
13-
};
14-
stateBH1750Type stateBH1750 = stateBH1750Type::toBeInitialized;
15-
float lux = 0.0;
16-
uint16_t adcValue0Lux =
17-
10; // Hier wird der niedrigste LDR-ADC Wert getrackt,
18-
// für eine dynamische offset korrektur bei 0 LUX
9+
uint32_t lux = 0;
1910

2011
private:
2112
//------------------------------------------------------------------------------
2213
// Helper Functions
2314
//------------------------------------------------------------------------------
24-
void initBH1750Logic();
2515
void loopAutoBrightLogic();
2616
uint32_t num32BitWithOnesAccordingToColumns();
2717
bool isRomanLanguage();

include/clockWork.hpp

Lines changed: 81 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -5,84 +5,100 @@
55
#include "clockWork.h"
66
#include "openwmap.h"
77
#include <Arduino.h>
8+
#if AUTOBRIGHT_USE_BH1750
89
#include <BH1750.h>
10+
BH1750 lightMeter(0x23);
11+
bool bh1750Initialized;
12+
#endif
913

1014
OpenWMap weather;
11-
BH1750 lightMeter(0x23);
1215

1316
//------------------------------------------------------------------------------
1417
// Helper Functions
1518
//------------------------------------------------------------------------------
1619

17-
// Automatic Brightness Control (enabled/dieabled by G.autoBrightEnabled)
18-
// 1. Measure ambient light with high resolution sensor BH1750, if available. If
19-
// not, use legacy LDR.
20+
// Automatic Brightness Control (enabled/disabled by G.autoBrightEnabled)
21+
// 1. Measure ambient light with high resolution sensor BH1750, if available.
22+
// If not, use legacy LDR.
2023
// 2. Derive the ledGain for the LEDs 0.0 - 100.0%
21-
// 3. When ledGain changed, execute led.set()
22-
// Inputs: autoBrightSlope, autoBrightOffset 0-255
24+
// 3. When ledGain changed, set parametersChanged = true
25+
// Inputs:
26+
// G.autoBrightEnabled, G.autoBrightMin, G.autoBrightMax, G.autoBrightPeak
27+
// AUTOBRIGHT_LDR_RESBRIGHT, AUTOBRIGHT_LDR_RESDARK, AUTOBRIGHT_LDR_RESDIVIDER
2328
// Outputs:
2429
// lux = Ambient light [LUX]
2530
// ledGain = gain for the the LEDs: 0.0-100.0% (Gain means n % of the
26-
// configured brightness: effectBri)
31+
// configured brightness: effectBri)
2732
void ClockWork::loopAutoBrightLogic() {
33+
if (G.autoBrightEnabled != 1)
34+
return;
35+
36+
if (G.autoBrightMin == G.autoBrightMax) {
37+
// If min and max are identical, nothing needs to be measured...
38+
// Besides: map() would crash with division by zero in this case
39+
ledGain = G.autoBrightMax;
40+
return;
41+
}
42+
2843
float ledGainOld = ledGain;
29-
if (stateBH1750 == stateBH1750Type::toBeInitialized) {
30-
initBH1750Logic();
31-
}
32-
if (G.autoBrightEnabled) {
33-
if (stateBH1750 == stateBH1750Type::Initialized) {
34-
// Using BH1750 for ambient light measurement which directly
35-
// provides the LUX value with high resolution!
36-
if (lightMeter.measurementReady())
37-
lux = lightMeter.readLightLevel(); // 0.0-54612.5 LUX
38-
} else {
39-
// Using legacy LDR for ambient light measurement
40-
// Electrical circuit = voltage divider: 3.3V--LDR-->ADC<--220
41-
// Ohm--GND
42-
uint16_t adcValue = analogRead(
43-
A0); // Read out ADC, pin TOUT = 0.0V - 1.0V = adcValue 0-1023
44-
// Track lowest ADC value for offest correction at 0 LUX
45-
if (adcValue < adcValue0Lux)
46-
adcValue0Lux = adcValue;
47-
float ldrValue = adcValue - adcValue0Lux;
48-
// Derive LUX value from ldrValue via a second degree polinomial.
49-
// The polinomial was derived using an Excel trend line, see
50-
// LDR-Calibration.xlsx
51-
const float x2 = 0.0427;
52-
const float x1 = 2.679;
53-
const float x0 = 10.857;
54-
lux = x2 * ldrValue * ldrValue + x1 * ldrValue + x0;
44+
float luxNow = -1.0;
45+
46+
#if AUTOBRIGHT_USE_BH1750
47+
if (bh1750Initialized && lightMeter.measurementReady()) {
48+
luxNow = lightMeter.readLightLevel(); // 0.0-54612.5 LUX
49+
}
50+
#endif
51+
52+
#if AUTOBRIGHT_USE_LDR
53+
// only use LDR, if no value from BH1750 is available
54+
if (luxNow < 0) {
55+
uint16_t adcValue = analogRead(A0); // Range 0-1023 (1024 on overflow)
56+
57+
// The lux value is considerably misrepresented upwards at ADC values
58+
// above 980. As 980 with an LDR5528 corresponds to approx. 1500 lux,
59+
// but usually no more than 1000 lux are reached indoors even on sunny
60+
// days, a fixed upper measurement limit of 980 is set here.
61+
// Regardless of this, a maximum value of 1023 has to be applied in
62+
// any case in order to avoid division by zero (analogRead is 0-1024)!
63+
if (adcValue > 980) {
64+
adcValue = 980;
5565
}
5666

57-
// Based on the LUX value derive the gain for the LEDs 0.0 - 100.0%
58-
// Interpretation of autoBrightSlope+1=aBS: aBS=1 -> slope=1/16x, aBS=16
59-
// -> slope=1x, aBS=256 -> slope=16x, When autoBrightOffset=0, and
60-
// aBS=16 then ledGain should reach 100.0% at 500.0 LUX.
61-
ledGain = (lux * (float)(G.autoBrightSlope + 1)) / 80.0;
62-
// Add autoBrightOffset 0-255
63-
ledGain +=
64-
((uint16_t)100 * (uint16_t)G.autoBrightOffset) / (uint16_t)255;
65-
if (ledGain > 100.0)
66-
ledGain = 100.0;
67+
luxNow = (adcValue * AUTOBRIGHT_LDR_RESDARK * 10) /
68+
(AUTOBRIGHT_LDR_RESBRIGHT * AUTOBRIGHT_LDR_RESDIVIDER *
69+
(1024 - adcValue));
6770
}
68-
if (ledGainOld != ledGain) {
69-
parametersChanged = true;
71+
#endif
72+
73+
// If luxNow is still negative, no data could be retrieved from BH1750 or
74+
// LDR. We return to preserve the previous ledGain (potentially default).
75+
// Otherwise we may end up in a blinking light...
76+
if (luxNow < 0) {
77+
return;
7078
}
71-
}
7279

73-
// Ambient Light Sensor BH1750
74-
// Initialize the I2C bus using SCL and SDA pins
75-
// (BH1750 library doesn't do this automatically)
76-
void ClockWork::initBH1750Logic() {
77-
// begin returns a boolean that can be used to detect setup problems.
78-
if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
79-
Serial.println("BH1750 initialized. Using this sensor for ambient "
80-
"light measurement.");
81-
stateBH1750 = stateBH1750Type::Initialized;
82-
} else {
83-
Serial.println("BH1750 initialisation error. Using legacy LDR for "
84-
"ambient light measurement");
85-
stateBH1750 = stateBH1750Type::cannotBeInitialized;
80+
// Even in HIGH_RES_MODE, the BH1750 only has a precision of 1 lux. The
81+
// decimal point values supplied by the library should therefore be
82+
// considered as 'noise' and their use makes little to no sense.
83+
// Also: in order to not trigger parametersChanged more often than
84+
// necessary, the value gets rounded.
85+
lux = round(luxNow);
86+
87+
ledGain = map(lux, 0, G.autoBrightPeak, G.autoBrightMin, G.autoBrightMax);
88+
89+
// Ensure ledGain meets the defined limits.
90+
uint16_t minimum = min(G.autoBrightMin, G.autoBrightMax);
91+
uint16_t maximum = max(G.autoBrightMin, G.autoBrightMax);
92+
93+
if (ledGain >= maximum) {
94+
ledGain = maximum;
95+
}
96+
if (ledGain <= minimum) {
97+
ledGain = minimum;
98+
}
99+
100+
if (ledGainOld != ledGain) {
101+
parametersChanged = true;
86102
}
87103
}
88104

@@ -1124,7 +1140,7 @@ void ClockWork::loop(struct tm &tm) {
11241140
//--------------------------------------------
11251141
// Auto Brightness Logic
11261142
//--------------------------------------------
1127-
if (G.autoBrightEnabled) {
1143+
if (G.autoBrightEnabled == 1) {
11281144
loopAutoBrightLogic();
11291145
}
11301146

@@ -1304,13 +1320,12 @@ void ClockWork::loop(struct tm &tm) {
13041320
config["command"] = "autoBright";
13051321
if (G.param1 == 0) {
13061322
config["autoBrightEnabled"] = G.autoBrightEnabled;
1307-
config["autoBrightOffset"] = G.autoBrightOffset;
1308-
config["autoBrightSlope"] = G.autoBrightSlope;
1323+
config["autoBrightMin"] = G.autoBrightMin;
1324+
config["autoBrightMax"] = G.autoBrightMax;
1325+
config["autoBrightPeak"] = G.autoBrightPeak;
13091326
}
1310-
// Original: config["autoBrightSensor"] = map(analogRead(A0), 0, 1023,
1311-
// 0, 255);
1312-
config["autoBrightSensor"] = (int)lux;
1313-
config["autoBrightGain"] = (int)ledGain;
1327+
config["autoBrightSensor"] = (uint32_t)lux;
1328+
config["autoBrightGain"] = (uint8_t)ledGain;
13141329
serializeJson(config, str);
13151330
webSocket.sendTXT(G.client_nr, str, strlen(str));
13161331
break;

include/config.h

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,18 @@
178178
* NeutralWhite (4300K) or ColdWhite (6500K)), in the case of RGB just leave it
179179
* at NeutralWhite. With DEFAULT_HUE it is possible to define the hue value
180180
* of the default color scheme. Use https://colorizer.org to get a hue value
181-
* of your choice.
181+
* of your choice. DEFAULT_BRIGHTNESS defines the default brightness (percent)
182+
* of the LEDs, if no other value is defined yet.
182183
*
183184
* Valid values for DEFAULT_LEDTYPE [Brg, Grb, Rgb, Rbg, Gbr, Grbw]
184185
* Valid values for WHITE_LEDTYPE [WarmWhite, NeutralWhite, ColdWhite]
185186
* Valid values for DEFAULT_HUE [integer 0-255]
187+
* Valid values for DEFAULT_BRIGHTNESS [one of these: 0, 20, 40, 60, 80, 100]
186188
*/
187189
#define DEFAULT_LEDTYPE Brg
188190
#define WHITE_LEDTYPE WhiteType::NeutralWhite
189191
#define DEFAULT_HUE 120
192+
#define DEFAULT_BRIGHTNESS 100
190193

191194
//--------------------------------------------------------------------------
192195
// Define Build Type
@@ -210,6 +213,46 @@
210213
*/
211214
#define DEFAULT_BUILDTYPE BuildTypeDef::Normal
212215

216+
//--------------------------------------------------------------------------
217+
// Specify settings for automatic brightness control
218+
//--------------------------------------------------------------------------
219+
/*
220+
* The wordclock offers the option to automatically adjust the LED
221+
* brightness to the ambient light. Either an LDR or a BH1750 module is
222+
* used for this purpose. If both measurement methods are activated and the
223+
* corresponding hardware is available and functional, the BH1750 is the
224+
* preferred choice.
225+
*
226+
* By setting AUTOBRIGHT_USE_LDR or AUTOBRIGHT_USE_BH1750 to false, the
227+
* respective variant will be disabled and the program code on the
228+
* microcontroller can thus be reduced. If both modes are deactivated,
229+
* the option for automatic brightness control in the web interface is no
230+
* longer available.
231+
*
232+
* For the LDR variant, a voltage divider with an LDR (R1) and a resistor R2
233+
* is used. As LDR a type 5528 and as R2 a 10k resistor is recommended. In
234+
* case of a different configuration, it is necessary to adjust these
235+
* values accordingly:
236+
* AUTOBRIGHT_LDR_RESBRIGHT resistance of the LDR in bright environment
237+
* (10 lux) in KΩ
238+
* AUTOBRIGHT_LDR_RESDARK resistance of the LDR in a dark environment
239+
* (0 lux) in KΩ
240+
* AUTOBRIGHT_LDR_RESDIVIDER resistance of the divider resistor (R2) in KΩ
241+
*
242+
* Valid values:
243+
* AUTOBRIGHT_USE_BH1750 [true, false]
244+
* AUTOBRIGHT_USE_LDR [true, false]
245+
* AUTOBRIGHT_LDR_RESBRIGHT [number]
246+
* AUTOBRIGHT_LDR_RESDARK [number]
247+
* AUTOBRIGHT_LDR_RESDIVIDER [number]
248+
*/
249+
#define AUTOBRIGHT_USE_BH1750 true
250+
#define AUTOBRIGHT_USE_LDR true
251+
252+
#define AUTOBRIGHT_LDR_RESBRIGHT 15
253+
#define AUTOBRIGHT_LDR_RESDARK 1000
254+
#define AUTOBRIGHT_LDR_RESDIVIDER 10
255+
213256
//--------------------------------------------------------------------------
214257
// Define External Realtime Clock
215258
//--------------------------------------------------------------------------

include/led.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ uint8_t Led::getCurrentManualBrightnessSetting() {
146146
} else if (_hour < 24) {
147147
return G.h22;
148148
} else {
149-
return 100;
149+
return DEFAULT_BRIGHTNESS;
150150
}
151151
}
152152

@@ -155,7 +155,7 @@ uint8_t Led::getCurrentManualBrightnessSetting() {
155155
HsbColor Led::getColorbyPositionWithAppliedBrightness(ColorPosition position) {
156156
HsbColor color = G.color[position];
157157

158-
if (G.autoBrightEnabled) {
158+
if (G.autoBrightEnabled == 1) {
159159
color.B = setBrightnessAuto(color.B);
160160
} else {
161161
color.B *= getCurrentManualBrightnessSetting() / 100.f;

include/webPageAdapter.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,6 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload,
296296
G.transitionSpeed = split(payload, 9);
297297
G.transitionColorize = split(payload, 12);
298298
G.transitionDemo = split(payload, 15);
299-
;
300299
break;
301300
}
302301

@@ -362,8 +361,23 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload,
362361

363362
case COMMAND_SET_AUTO_BRIGHT: {
364363
G.autoBrightEnabled = split(payload, 3);
365-
G.autoBrightOffset = split(payload, 6);
366-
G.autoBrightSlope = split(payload, 9);
364+
G.autoBrightMin = split(payload, 6);
365+
G.autoBrightMax = split(payload, 9);
366+
G.autoBrightPeak = split(payload, 12, 4);
367+
368+
if (G.autoBrightMin < 0)
369+
G.autoBrightMin = 0;
370+
if (G.autoBrightMin > 100)
371+
G.autoBrightMin = 100;
372+
if (G.autoBrightMax < 10)
373+
G.autoBrightMax = 10;
374+
if (G.autoBrightMax > 100)
375+
G.autoBrightMax = 100;
376+
if (G.autoBrightPeak < 10)
377+
G.autoBrightPeak = 10;
378+
if (G.autoBrightPeak > 1500)
379+
G.autoBrightPeak = 1500;
380+
367381
break;
368382
}
369383

0 commit comments

Comments
 (0)