|
5 | 5 | #include "clockWork.h" |
6 | 6 | #include "openwmap.h" |
7 | 7 | #include <Arduino.h> |
| 8 | +#if AUTOBRIGHT_USE_BH1750 |
8 | 9 | #include <BH1750.h> |
| 10 | +BH1750 lightMeter(0x23); |
| 11 | +bool bh1750Initialized; |
| 12 | +#endif |
9 | 13 |
|
10 | 14 | OpenWMap weather; |
11 | | -BH1750 lightMeter(0x23); |
12 | 15 |
|
13 | 16 | //------------------------------------------------------------------------------ |
14 | 17 | // Helper Functions |
15 | 18 | //------------------------------------------------------------------------------ |
16 | 19 |
|
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. |
20 | 23 | // 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 |
23 | 28 | // Outputs: |
24 | 29 | // lux = Ambient light [LUX] |
25 | 30 | // ledGain = gain for the the LEDs: 0.0-100.0% (Gain means n % of the |
26 | | -// configured brightness: effectBri) |
| 31 | +// configured brightness: effectBri) |
27 | 32 | 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 | + |
28 | 43 | 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; |
55 | 65 | } |
56 | 66 |
|
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)); |
67 | 70 | } |
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; |
70 | 78 | } |
71 | | -} |
72 | 79 |
|
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; |
86 | 102 | } |
87 | 103 | } |
88 | 104 |
|
@@ -1210,7 +1226,7 @@ void ClockWork::loop(struct tm &tm) { |
1210 | 1226 | //-------------------------------------------- |
1211 | 1227 | // Auto Brightness Logic |
1212 | 1228 | //-------------------------------------------- |
1213 | | - if (G.autoBrightEnabled) { |
| 1229 | + if (G.autoBrightEnabled == 1) { |
1214 | 1230 | loopAutoBrightLogic(); |
1215 | 1231 | } |
1216 | 1232 |
|
@@ -1390,13 +1406,12 @@ void ClockWork::loop(struct tm &tm) { |
1390 | 1406 | config["command"] = "autoBright"; |
1391 | 1407 | if (G.param1 == 0) { |
1392 | 1408 | config["autoBrightEnabled"] = G.autoBrightEnabled; |
1393 | | - config["autoBrightOffset"] = G.autoBrightOffset; |
1394 | | - config["autoBrightSlope"] = G.autoBrightSlope; |
| 1409 | + config["autoBrightMin"] = G.autoBrightMin; |
| 1410 | + config["autoBrightMax"] = G.autoBrightMax; |
| 1411 | + config["autoBrightPeak"] = G.autoBrightPeak; |
1395 | 1412 | } |
1396 | | - // Original: config["autoBrightSensor"] = map(analogRead(A0), 0, 1023, |
1397 | | - // 0, 255); |
1398 | | - config["autoBrightSensor"] = (int)lux; |
1399 | | - config["autoBrightGain"] = (int)ledGain; |
| 1413 | + config["autoBrightSensor"] = (uint32_t)lux; |
| 1414 | + config["autoBrightGain"] = (uint8_t)ledGain; |
1400 | 1415 | serializeJson(config, str); |
1401 | 1416 | webSocket.sendTXT(G.client_nr, str, strlen(str)); |
1402 | 1417 | break; |
|
0 commit comments