|
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 |
|
@@ -1124,7 +1140,7 @@ void ClockWork::loop(struct tm &tm) {
|
1124 | 1140 | //--------------------------------------------
|
1125 | 1141 | // Auto Brightness Logic
|
1126 | 1142 | //--------------------------------------------
|
1127 |
| - if (G.autoBrightEnabled) { |
| 1143 | + if (G.autoBrightEnabled == 1) { |
1128 | 1144 | loopAutoBrightLogic();
|
1129 | 1145 | }
|
1130 | 1146 |
|
@@ -1304,13 +1320,12 @@ void ClockWork::loop(struct tm &tm) {
|
1304 | 1320 | config["command"] = "autoBright";
|
1305 | 1321 | if (G.param1 == 0) {
|
1306 | 1322 | 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; |
1309 | 1326 | }
|
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; |
1314 | 1329 | serializeJson(config, str);
|
1315 | 1330 | webSocket.sendTXT(G.client_nr, str, strlen(str));
|
1316 | 1331 | break;
|
|
0 commit comments