Skip to content

Commit b89f718

Browse files
authored
Merge pull request wled#2257 from calebmah/bh1750-usermod
Add BH1750 usermod
2 parents 849aa64 + 2ebb837 commit b89f718

File tree

5 files changed

+232
-0
lines changed

5 files changed

+232
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; Options
2+
; -------
3+
; USERMOD_BH1750 - define this to have this user mod included wled00\usermods_list.cpp
4+
; USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL - the max number of milliseconds between measurements, defaults to 10000ms
5+
; USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL - the min number of milliseconds between measurements, defaults to 500ms
6+
; USERMOD_BH1750_FIRST_MEASUREMENT_AT - the number of milliseconds after boot to take first measurement, defaults to 10 seconds
7+
; USERMOD_BH1750_OFFSET_VALUE - the offset value to report on, defaults to 1
8+
;
9+
[env:usermod_BH1750_d1_mini]
10+
extends = env:d1_mini
11+
build_flags =
12+
${common.build_flags_esp8266}
13+
-D USERMOD_BH1750
14+
lib_deps =
15+
${env.lib_deps}
16+
claws/BH1750 @ ^1.2.0

usermods/BH1750_v2/readme.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# BH1750 usermod
2+
3+
This usermod will read from an ambient light sensor like the BH1750 sensor.
4+
The luminance is displayed both in the Info section of the web UI as well as published to the `/luminance` MQTT topic if enabled.
5+
6+
## Installation
7+
8+
Copy the example `platformio_override.ini` to the root directory. This file should be placed in the same directory as `platformio.ini`.
9+
10+
### Define Your Options
11+
12+
* `USERMOD_BH1750` - define this to have this user mod included wled00\usermods_list.cpp
13+
* `USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL` - the max number of milliseconds between measurements, defaults to 10000ms
14+
* `USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL` - the min number of milliseconds between measurements, defaults to 500ms
15+
* `USERMOD_BH1750_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 10 seconds
16+
* `USERMOD_BH1750_OFFSET_VALUE` - the offset value to report on, defaults to 1
17+
18+
All parameters can be configured at runtime using Usermods settings page.
19+
20+
### PlatformIO requirements
21+
22+
If you are using `platformio_override.ini`, you should be able to refresh the task list and see your custom task, for example `env:usermod_BH1750_d1_mini`.
23+
24+
## Change Log
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#pragma once
2+
3+
#include "wled.h"
4+
#include <Wire.h>
5+
#include <BH1750.h>
6+
7+
// the max frequency to check photoresistor, 10 seconds
8+
#ifndef USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL
9+
#define USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL 10000
10+
#endif
11+
12+
// the min frequency to check photoresistor, 500 ms
13+
#ifndef USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL
14+
#define USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL 500
15+
#endif
16+
17+
// how many seconds after boot to take first measurement, 10 seconds
18+
#ifndef USERMOD_BH1750_FIRST_MEASUREMENT_AT
19+
#define USERMOD_BH1750_FIRST_MEASUREMENT_AT 10000
20+
#endif
21+
22+
// only report if differance grater than offset value
23+
#ifndef USERMOD_BH1750_OFFSET_VALUE
24+
#define USERMOD_BH1750_OFFSET_VALUE 1
25+
#endif
26+
27+
class Usermod_BH1750 : public Usermod
28+
{
29+
private:
30+
int8_t offset = USERMOD_BH1750_OFFSET_VALUE;
31+
32+
unsigned long maxReadingInterval = USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL;
33+
unsigned long minReadingInterval = USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL;
34+
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL - USERMOD_BH1750_FIRST_MEASUREMENT_AT);
35+
unsigned long lastSend = UINT32_MAX - (USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL - USERMOD_BH1750_FIRST_MEASUREMENT_AT);
36+
// flag to indicate we have finished the first readLightLevel call
37+
// allows this library to report to the user how long until the first
38+
// measurement
39+
bool getLuminanceComplete = false;
40+
41+
// flag set at startup
42+
bool disabled = false;
43+
44+
// strings to reduce flash memory usage (used more than twice)
45+
static const char _name[];
46+
static const char _enabled[];
47+
static const char _maxReadInterval[];
48+
static const char _minReadInterval[];
49+
static const char _offset[];
50+
51+
BH1750 lightMeter;
52+
float lastLux = -1000;
53+
54+
bool checkBoundSensor(float newValue, float prevValue, float maxDiff)
55+
{
56+
return isnan(prevValue) || newValue <= prevValue - maxDiff || newValue >= prevValue + maxDiff || (newValue == 0.0 && prevValue > 0.0);
57+
}
58+
59+
public:
60+
void setup()
61+
{
62+
Wire.begin();
63+
lightMeter.begin();
64+
}
65+
66+
void loop()
67+
{
68+
if (disabled || strip.isUpdating())
69+
return;
70+
71+
unsigned long now = millis();
72+
73+
// check to see if we are due for taking a measurement
74+
// lastMeasurement will not be updated until the conversion
75+
// is complete the the reading is finished
76+
if (now - lastMeasurement < minReadingInterval)
77+
{
78+
return;
79+
}
80+
81+
bool shouldUpdate = now - lastSend > maxReadingInterval;
82+
83+
float lux = lightMeter.readLightLevel();
84+
lastMeasurement = millis();
85+
getLuminanceComplete = true;
86+
87+
if (shouldUpdate || checkBoundSensor(lux, lastLux, offset))
88+
{
89+
lastLux = lux;
90+
lastSend = millis();
91+
if (WLED_MQTT_CONNECTED)
92+
{
93+
char subuf[45];
94+
strcpy(subuf, mqttDeviceTopic);
95+
strcat_P(subuf, PSTR("/luminance"));
96+
mqtt->publish(subuf, 0, true, String(lux).c_str());
97+
}
98+
else
99+
{
100+
DEBUG_PRINTLN("Missing MQTT connection. Not publishing data");
101+
}
102+
}
103+
}
104+
105+
void addToJsonInfo(JsonObject &root)
106+
{
107+
JsonObject user = root[F("u")];
108+
if (user.isNull())
109+
user = root.createNestedObject(F("u"));
110+
111+
JsonArray lux_json = user.createNestedArray(F("Luminance"));
112+
113+
if (!getLuminanceComplete)
114+
{
115+
// if we haven't read the sensor yet, let the user know
116+
// that we are still waiting for the first measurement
117+
lux_json.add((USERMOD_BH1750_FIRST_MEASUREMENT_AT - millis()) / 1000);
118+
lux_json.add(F(" sec until read"));
119+
return;
120+
}
121+
122+
lux_json.add(lastLux);
123+
lux_json.add(F(" lx"));
124+
}
125+
126+
uint16_t getId()
127+
{
128+
return USERMOD_ID_BH1750;
129+
}
130+
131+
/**
132+
* addToConfig() (called from set.cpp) stores persistent properties to cfg.json
133+
*/
134+
void addToConfig(JsonObject &root)
135+
{
136+
// we add JSON object.
137+
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
138+
top[FPSTR(_enabled)] = !disabled;
139+
top[FPSTR(_maxReadInterval)] = maxReadingInterval;
140+
top[FPSTR(_minReadInterval)] = minReadingInterval;
141+
top[FPSTR(_offset)] = offset;
142+
143+
DEBUG_PRINTLN(F("Photoresistor config saved."));
144+
}
145+
146+
/**
147+
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
148+
*/
149+
bool readFromConfig(JsonObject &root)
150+
{
151+
// we look for JSON object.
152+
JsonObject top = root[FPSTR(_name)];
153+
if (top.isNull())
154+
{
155+
DEBUG_PRINT(FPSTR(_name));
156+
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
157+
return false;
158+
}
159+
160+
disabled = !(top[FPSTR(_enabled)] | !disabled);
161+
maxReadingInterval = (top[FPSTR(_maxReadInterval)] | maxReadingInterval); // ms
162+
minReadingInterval = (top[FPSTR(_minReadInterval)] | minReadingInterval); // ms
163+
offset = top[FPSTR(_offset)] | offset;
164+
DEBUG_PRINT(FPSTR(_name));
165+
DEBUG_PRINTLN(F(" config (re)loaded."));
166+
167+
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
168+
return true;
169+
}
170+
};
171+
172+
// strings to reduce flash memory usage (used more than twice)
173+
const char Usermod_BH1750::_name[] PROGMEM = "BH1750";
174+
const char Usermod_BH1750::_enabled[] PROGMEM = "enabled";
175+
const char Usermod_BH1750::_maxReadInterval[] PROGMEM = "max-read-interval-ms";
176+
const char Usermod_BH1750::_minReadInterval[] PROGMEM = "min-read-interval-ms";
177+
const char Usermod_BH1750::_offset[] PROGMEM = "offset-lx";
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include "wled.h"
2+
/*
3+
* Register your v2 usermods here!
4+
*/
5+
#ifdef USERMOD_BH1750
6+
#include "../usermods/BH1750_v2/usermod_BH1750.h"
7+
#endif
8+
9+
void registerUsermods()
10+
{
11+
#ifdef USERMOD_BH1750
12+
usermods.add(new Usermod_BH1750());
13+
#endif
14+
}

wled00/const.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#define USERMOD_ID_SN_PHOTORESISTOR 17 //Usermod "usermod_sn_photoresistor.h"
6161
#define USERMOD_ID_BATTERY_STATUS_BASIC 18 //Usermod "usermod_v2_battery_status_basic.h"
6262
#define USERMOD_ID_PWM_FAN 19 //Usermod "usermod_PWM_fan.h"
63+
#define USERMOD_ID_BH1750 20 //Usermod "usermod_bh1750.h"
6364

6465
//Access point behavior
6566
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot

0 commit comments

Comments
 (0)