Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BH1750 ambient light sensor #408

Merged
merged 8 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions include/EEPROMAnything.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ void read() {
Serial.printf("MQTT_Topic : %s\n", G.mqtt.topic);
Serial.printf("MQTT_Port : %u\n", G.mqtt.port);

Serial.printf("autoLdrEnabled : %u\n", G.autoLdrEnabled);
Serial.printf("autoLdrBright : %u\n", G.autoLdrBright);
Serial.printf("autoLdrDark : %u\n", G.autoLdrDark);
Serial.printf("autoBrightEnabled : %u\n", G.autoBrightEnabled);
Serial.printf("autoBrightOffset : %u\n", G.autoBrightOffset);
Serial.printf("autoBrightSlope : %u\n", G.autoBrightSlope);
Serial.printf("Uhrtype : %u\n", G.transitionDuration);
Serial.printf("transitionType : %u\n", G.transitionType);
Serial.printf("transitionDuration : %u\n", G.transitionSpeed);
Expand Down
12 changes: 6 additions & 6 deletions include/Uhr.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ struct GLOBAL {

OpenWeatherMapData openWeatherMap;

uint8_t autoLdrEnabled;
uint8_t autoLdrBright;
uint8_t autoLdrDark;
uint8_t autoBrightEnabled;
uint8_t autoBrightOffset;
uint8_t autoBrightSlope;
uint8_t transitionType;
uint8_t transitionDuration;
uint8_t transitionSpeed;
Expand All @@ -146,7 +146,7 @@ struct GLOBAL {
GLOBAL G = {};

// LDR
uint8_t ldrVal = 100;
float ledGain = 100;

uint8_t _second = 0;
uint8_t _secondFrame = 0;
Expand Down Expand Up @@ -241,7 +241,7 @@ enum CommandWords {
COMMAND_SET_WIFI_AND_RESTART = 99,
COMMAND_RESET = 100,
COMMAND_SET_BOOT = 101,
COMMAND_SET_AUTO_LDR = 102,
COMMAND_SET_AUTO_BRIGHT = 102,
COMMAND_SET_LAYOUT_VARIANT = 103,
COMMAND_SET_MQTT_HA_DISCOVERY = 104,

Expand All @@ -252,7 +252,7 @@ enum CommandWords {
COMMAND_REQUEST_CONFIG_VALUES = 200,
COMMAND_REQUEST_COLOR_VALUES = 201,
COMMAND_REQUEST_WIFI_LIST = 202,
COMMAND_REQUEST_AUTO_LDR = 203,
COMMAND_REQUEST_AUTO_BRIGHT = 203,
COMMAND_REQUEST_TRANSITION = 204,
COMMAND_REQUEST_MQTT_VALUES = 205,
COMMAND_REQUEST_BIRTHDAYS = 206,
Expand Down
13 changes: 11 additions & 2 deletions include/clockWork.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,21 @@ class ClockWork {
private:
uint16_t countMillisSpeed = 0;
uint32_t previousMillis = 0;
enum class stateBH1750Type {
toBeInitialized = 0,
Initialized = 1,
cannotBeInitialized = 2,
};
stateBH1750Type stateBH1750 = stateBH1750Type::toBeInitialized;
float lux = 0.0;
uint16 adcValue0Lux = 10; // Hier wird der niedrigste LDR-ADC Wert getrackt, für eine dynamische offset korrektur bei 0 LUX

private:
//------------------------------------------------------------------------------
// Helper Functions
//------------------------------------------------------------------------------
void loopLdrLogic();
void initBH1750Logic();
void loopAutoBrightLogic();
uint32_t num32BitWithOnesAccordingToColumns();
bool isRomanLanguage();

Expand Down Expand Up @@ -52,7 +61,7 @@ class ClockWork {
void clearClockByProgInit();

public:
ClockWork() = default;
//ClockWork() = default;
~ClockWork() = default;

//------------------------------------------------------------------------------
Expand Down
99 changes: 71 additions & 28 deletions include/clockWork.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,78 @@
#include "clockWork.h"
#include "openwmap.h"
#include <Arduino.h>
#include <BH1750.h>

OpenWMap weather;
BH1750 lightMeter(0x23);

//------------------------------------------------------------------------------
// Helper Functions
//------------------------------------------------------------------------------

void ClockWork::loopLdrLogic() {
int16_t lux = analogRead(A0); // Range 0-1023
uint8_t ldrValOld = ldrVal;

if (G.autoLdrEnabled) {
lux /= 4;
uint16_t minimum = min(G.autoLdrBright, G.autoLdrDark);
uint16_t maximum = max(G.autoLdrBright, G.autoLdrDark);
if (lux >= maximum)
lux = maximum;
if (lux <= minimum)
lux = minimum;
if (G.autoLdrDark == G.autoLdrBright) {
// map() //Would crash with division by zero
ldrVal = 100;
// Automatic Brightness Control (enabled/dieabled by G.autoBrightEnabled)
// 1. Measure ambient light with high resolution sensor BH1750, if available. If not, use legacy LDR.
// 2. Derive the ledGain for the LEDs 0.0 - 100.0%
// 3. When ledGain changed, execute led.set()
// Inputs: autoBrightSlope, autoBrightOffset 0-255
// Outputs:
// lux = Ambient light [LUX]
// ledGain = gain for the the LEDs: 0.0-100.0% (Gain means n % of the configured brightness: effectBri)
void ClockWork::loopAutoBrightLogic() {
float ledGainOld = ledGain;
if (stateBH1750 == stateBH1750Type::toBeInitialized) {
initBH1750Logic();
}
if (G.autoBrightEnabled) {
if (stateBH1750 == stateBH1750Type::Initialized) {
// Using BH1750 for ambient light measurement which directly provides the LUX value with high resolution!
if (lightMeter.measurementReady())
lux = lightMeter.readLightLevel(); // 0.0-54612.5 LUX
} else {
ldrVal = map(lux, G.autoLdrDark, G.autoLdrBright, 10, 100);
// Using legacy LDR for ambient light measurement
// Electrical circuit = voltage divider: 3.3V--LDR-->ADC<--220 Ohm--GND
uint16 adcValue = analogRead(A0); // Read out ADC, pin TOUT = 0.0V - 1.0V = adcValue 0-1023
// Track lowest ADC value for offest correction at 0 LUX
if (adcValue < adcValue0Lux)
adcValue0Lux = adcValue;
float ldrValue = adcValue - adcValue0Lux;
// Derive LUX value from ldrValue via a second degree polinomial.
// The polinomial was derived using an Excel trend line, see LDR-Calibration.xlsx
const float x2 = 0.0427;
const float x1 = 2.679;
const float x0 = 10.857;
lux = x2 * ldrValue * ldrValue + x1 * ldrValue + x0;
}

// Based on the LUX value derive the gain for the LEDs 0.0 - 100.0%
// Interpretation of autoBrightSlope+1=aBS: aBS=1 -> slope=1/16x, aBS=16 -> slope=1x, aBS=256 -> slope=16x,
// When autoBrightOffset=0, and aBS=16 then ledGain should reach 100.0% at 500.0 LUX.
ledGain = (lux * (float)(G.autoBrightSlope+1)) / 80.0;
// Add autoBrightOffset 0-255
ledGain += ((uint16)100*(uint16)G.autoBrightOffset)/(uint16)255;
if (ledGain > 100.0) ledGain = 100.0;
}
if (ldrValOld != ldrVal) {
if (ledGainOld != ledGain) {
led.set();
}
}

// Ambient Light Sensor BH1750
// Initialize the I2C bus using SCL and SDA pins
// (BH1750 library doesn't do this automatically)
void ClockWork::initBH1750Logic() {
Wire.begin(D4,D3);
// begin returns a boolean that can be used to detect setup problems.
if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
Serial.println("BH1750 initialized. Using this sensor for ambient light measurement.");
stateBH1750 = stateBH1750Type::Initialized;
} else {
Serial.println("BH1750 initialisation error. Using legacy LDR for ambient light measurement");
stateBH1750 = stateBH1750Type::cannotBeInitialized;
}
}


//------------------------------------------------------------------------------

iUhrType *ClockWork::getPointer(uint8_t type) {
Expand Down Expand Up @@ -943,10 +984,10 @@ void ClockWork::loop(struct tm &tm) {
}

//--------------------------------------------
// LDR Routine
// Auto Brightness Logic
//--------------------------------------------
if (G.autoLdrEnabled) {
loopLdrLogic();
if (G.autoBrightEnabled) {
loopAutoBrightLogic();
}

if (G.prog == COMMAND_IDLE && G.conf == 0) {
Expand Down Expand Up @@ -1044,7 +1085,7 @@ void ClockWork::loop(struct tm &tm) {
config["bootLedSweep"] = G.bootLedSweep;
config["bootShowWifi"] = G.bootShowWifi;
config["bootShowIP"] = G.bootShowIP;
config["autoLdrEnabled"] = G.autoLdrEnabled;
config["autoBrightEnabled"] = G.autoBrightEnabled;
config["isRomanLanguage"] = isRomanLanguage();
config["hasDreiviertel"] = usedUhrType->hasDreiviertel();
config["hasZwanzig"] = usedUhrType->hasZwanzig();
Expand Down Expand Up @@ -1101,15 +1142,17 @@ void ClockWork::loop(struct tm &tm) {
break;
}

case COMMAND_REQUEST_AUTO_LDR: {
case COMMAND_REQUEST_AUTO_BRIGHT: {
DynamicJsonDocument config(1024);
config["command"] = "autoLdr";
config["command"] = "autoBright";
if (G.param1 == 0) {
config["autoLdrEnabled"] = G.autoLdrEnabled;
config["autoLdrBright"] = G.autoLdrBright;
config["autoLdrDark"] = G.autoLdrDark;
config["autoBrightEnabled"] = G.autoBrightEnabled;
config["autoBrightOffset"] = G.autoBrightOffset;
config["autoBrightSlope"] = G.autoBrightSlope;
}
config["autoLdrValue"] = map(analogRead(A0), 0, 1023, 0, 255);
//Original: config["autoBrightSensor"] = map(analogRead(A0), 0, 1023, 0, 255);
config["autoBrightSensor"] = (int)lux;
config["autoBrightGain"] = (int)ledGain;
serializeJson(config, str);
webSocket.sendTXT(G.client_nr, str, strlen(str));
break;
Expand Down Expand Up @@ -1154,7 +1197,7 @@ void ClockWork::loop(struct tm &tm) {

case COMMAND_SET_MINUTE:
case COMMAND_SET_BRIGHTNESS:
case COMMAND_SET_AUTO_LDR:
case COMMAND_SET_AUTO_BRIGHT:
case COMMAND_SET_LANGUAGE_VARIANT:
case COMMAND_SET_WHITETYPE:
case COMMAND_SET_TIME_MANUAL: {
Expand Down
2 changes: 1 addition & 1 deletion include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@
*
* Valid values [0 ... 255]
*/
#define SERNR 33
#define SERNR 58
//--------------------------------------------------------------------------
// Toggle Serial DEBUG Output
//--------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions include/led.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ void Led::resetFrontMatrixBuffer() {

float Led::setBrightnessAuto(float val) {
// G.hh contains time-dependent brightness values in %.
return (val * ldrVal) / 100.f;
return (val * ledGain) / 100.f;
}

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -156,7 +156,7 @@ void Led::getColorbyPositionWithAppliedBrightness(HsbColor &color,
uint8_t manBrightnessSetting = 100;
getCurrentManualBrightnessSetting(manBrightnessSetting);

if (G.autoLdrEnabled) {
if (G.autoBrightEnabled) {
color.B = setBrightnessAuto(color.B);
} else {
color.B *= manBrightnessSetting / 100.f;
Expand Down
10 changes: 5 additions & 5 deletions include/webPageAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,10 +360,10 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload,

//------------------------------------------------------------------------------

case COMMAND_SET_AUTO_LDR: {
G.autoLdrEnabled = split(payload, 3);
G.autoLdrBright = split(payload, 6);
G.autoLdrDark = split(payload, 9);
case COMMAND_SET_AUTO_BRIGHT: {
G.autoBrightEnabled = split(payload, 3);
G.autoBrightOffset = split(payload, 6);
G.autoBrightSlope = split(payload, 9);
break;
}

Expand Down Expand Up @@ -561,7 +561,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload,

//------------------------------------------------------------------------------

case COMMAND_REQUEST_AUTO_LDR: {
case COMMAND_REQUEST_AUTO_BRIGHT: {

G.param1 = split(payload, 3);
G.client_nr = num;
Expand Down
1 change: 1 addition & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ lib_deps =
adafruit/RTClib@^1.11.2
knolleary/PubSubClient@^2.8.0
https://github.com/tzapu/WiFiManager#v2.0.17
claws/BH1750@^1.3.0
extra_scripts = pre:extra_scripts.py
8 changes: 4 additions & 4 deletions src/Wortuhr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,9 @@ void setup() {
G.bootShowWifi = true;
G.bootShowIP = BOOT_SHOWIP;

G.autoLdrEnabled = 0;
G.autoLdrBright = 100;
G.autoLdrDark = 10;
G.autoBrightEnabled = 0;
G.autoBrightOffset = 100;
G.autoBrightSlope = 10;
G.transitionType = 0; // Transition::NO_TRANSITION;
G.transitionDuration = 2;
G.transitionSpeed = 30;
Expand Down Expand Up @@ -433,7 +433,7 @@ void loop() {
httpServer.handleClient();

webSocket.loop();

//------------------------------------------------
// MQTT
//------------------------------------------------
Expand Down
11 changes: 7 additions & 4 deletions webpage/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ <h2 data-i18next="settings.manual-time.h2"></h2>
<h2 data-i18next="settings.brightness.h2"></h2>
<form class="pure-form pure-form-aligned">
<div class="pure-control-group">
<label for="auto-ldr-enabled" data-i18next="settings.brightness.mode"></label><select id="auto-ldr-enabled" size="1">
<label for="auto-bright-enabled" data-i18next="settings.brightness.mode"></label><select id="auto-bright-enabled" size="1">
<option value="1" data-i18next="settings.brightness.automatic"></option>
<option value="0" data-i18next="settings.brightness.manual"></option>
</select>
Expand Down Expand Up @@ -665,14 +665,17 @@ <h2 data-i18next="settings.brightness.h2"></h2>
<div class="specific-layout-brightness-auto">
<br>
<div class="pure-control-group">
<label for="auto-ldr-value" data-i18next="settings.brightness.ldr-value"></label><input id="auto-ldr-value" type="text" value=" " readonly>
<label for="auto-bright-sensor" data-i18next="settings.brightness.value-sensor"></label><input id="auto-bright-sensor" type="text" value=" " readonly>
<label for="auto-bright-gain" data-i18next="settings.brightness.value-gain"></label><input id="auto-bright-gain" type="text" value=" " readonly>
</div>
<br>
<legend data-i18next="settings.brightness.help-offset"></legend>
<div class="pure-control-group">
<label for="auto-ldr-bright" data-i18next="settings.brightness.value-bright"></label><input id="auto-ldr-bright" type="number" min="0" max="255">
<label for="auto-bright-offset" data-i18next="settings.brightness.value-offset"></label><input id="auto-bright-offset" type="number" min="0" max="255">
</div>
<legend data-i18next="settings.brightness.help-slope"></legend>
<div class="pure-control-group">
<label for="auto-ldr-dark" data-i18next="settings.brightness.value-dark"></label><input id="auto-ldr-dark" type="number" min="0" max="255">
<label for="auto-bright-slope" data-i18next="settings.brightness.value-slope"></label><input id="auto-bright-slope" type="number" min="0" max="255">
</div>
<!-- Specific Brightness-automatic End-->
</div>
Expand Down
11 changes: 8 additions & 3 deletions webpage/language/de.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,14 @@ let TRANSLATION_DE_DE = {
"eighteen-to-twenty": "18:00 – 19:59",
"twenty-to-twenty-two": "20:00 – 21:59",
"twenty-two-to-zero": "22:00 – 23:59",
"ldr-value": "Aktuelle Helligkeit vom Fotowiderstand (LDR)",
"value-bright": "Wert „Hell“ (0 – 255)",
"value-dark": "Wert „Dunkel“ (0 – 255)"
"value-sensor": "Licht Sensor [Lux]",
"value-gain": "LED Gain [%]",
"help-offset": "Konfiguration des Helligkeitsoffsets: Sie bestimmt die minimale Helligkeit der LEDs bei 0 Lux Umgebungslicht:\n" +
"0=LEDs aus, n=LED Helligkeit ist n/255, 255=LEDs haben immer die maximale Helligkeit",
"value-offset": "Offset (0–255)",
"help-slope": "Konfiguration der Steilheit: Sie bestimmt den Grad der LED-Helligkeitsänderung bei Änderung des Umgebungslichts.\n" +
"0=schwache LED-Helligkeitsänderung, 16=neutrale LED-Helligkeitsänderung, 255=starke LED-Helligkeitsänderung",
"value-slope": "Steilheit (0–255)"
},
"hostname": {
"h2": "Hostname",
Expand Down
6 changes: 3 additions & 3 deletions webpage/language/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,9 @@ let TRANSLATION_EN_US = {
"eighteen-to-twenty": "18:00 – 19:59",
"twenty-to-twenty-two": "20:00 – 21:59",
"twenty-two-to-zero": "22:00 – 23:59",
"ldr-value": "Current Brightness from the Photoresistor (LDR)",
"value-bright": "Value “Bright” (0 – 255)",
"value-dark": "Value “Dark” (0 – 255)"
"value-sensor": "Current Brightness from the Photoresistor (LDR)",
"value-offset": "Value “Bright” (0 – 255)",
"value-slope": "Value “Dark” (0 – 255)"
},
"hostname": {
"h2": "Hostname",
Expand Down
6 changes: 3 additions & 3 deletions webpage/language/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,9 @@ let TRANSLATION_ES = {
"eighteen-to-twenty": "18:00 – 19:59",
"twenty-to-twenty-two": "20:00 – 21:59",
"twenty-two-to-zero": "22:00 – 23:59",
"ldr-value": "Brillo actual del fotorresistor (LDR)",
"value-bright": "Valor „Brillante“ (0 – 255)",
"value-dark": "Valor „Oscuro“ (0 – 255)"
"value-sensor": "Brillo actual del fotorresistor (LDR)",
"value-offset": "Valor „Brillante“ (0 – 255)",
"value-slope": "Valor „Oscuro“ (0 – 255)"
},
"hostname": {
"h2": "Hostname",
Expand Down
Loading
Loading