diff --git a/usermods/BH1750_v2/platformio_override.ini b/usermods/BH1750_v2/platformio_override.ini new file mode 100644 index 00000000..7b981e50 --- /dev/null +++ b/usermods/BH1750_v2/platformio_override.ini @@ -0,0 +1,16 @@ +; Options +; ------- +; USERMOD_BH1750 - define this to have this user mod included wled00\usermods_list.cpp +; USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL - the max number of milliseconds between measurements, defaults to 10000ms +; USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL - the min number of milliseconds between measurements, defaults to 500ms +; USERMOD_BH1750_FIRST_MEASUREMENT_AT - the number of milliseconds after boot to take first measurement, defaults to 10 seconds +; USERMOD_BH1750_OFFSET_VALUE - the offset value to report on, defaults to 1 +; +[env:usermod_BH1750_d1_mini] +extends = env:d1_mini +build_flags = + ${common.build_flags_esp8266} + -D USERMOD_BH1750 +lib_deps = + ${env.lib_deps} + claws/BH1750 @ ^1.2.0 diff --git a/usermods/BH1750_v2/readme.md b/usermods/BH1750_v2/readme.md new file mode 100644 index 00000000..9496dc02 --- /dev/null +++ b/usermods/BH1750_v2/readme.md @@ -0,0 +1,24 @@ +# BH1750 usermod + +This usermod will read from an ambient light sensor like the BH1750 sensor. +The luminance is displayed both in the Info section of the web UI as well as published to the `/luminance` MQTT topic if enabled. + +## Installation + +Copy the example `platformio_override.ini` to the root directory. This file should be placed in the same directory as `platformio.ini`. + +### Define Your Options + +* `USERMOD_BH1750` - define this to have this user mod included wled00\usermods_list.cpp +* `USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL` - the max number of milliseconds between measurements, defaults to 10000ms +* `USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL` - the min number of milliseconds between measurements, defaults to 500ms +* `USERMOD_BH1750_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 10 seconds +* `USERMOD_BH1750_OFFSET_VALUE` - the offset value to report on, defaults to 1 + +All parameters can be configured at runtime using Usermods settings page. + +### PlatformIO requirements + +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`. + +## Change Log diff --git a/usermods/BH1750_v2/usermod_bh1750.h b/usermods/BH1750_v2/usermod_bh1750.h new file mode 100644 index 00000000..fb0b1c5a --- /dev/null +++ b/usermods/BH1750_v2/usermod_bh1750.h @@ -0,0 +1,177 @@ +#pragma once + +#include "wled.h" +#include +#include + +// the max frequency to check photoresistor, 10 seconds +#ifndef USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL +#define USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL 10000 +#endif + +// the min frequency to check photoresistor, 500 ms +#ifndef USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL +#define USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL 500 +#endif + +// how many seconds after boot to take first measurement, 10 seconds +#ifndef USERMOD_BH1750_FIRST_MEASUREMENT_AT +#define USERMOD_BH1750_FIRST_MEASUREMENT_AT 10000 +#endif + +// only report if differance grater than offset value +#ifndef USERMOD_BH1750_OFFSET_VALUE +#define USERMOD_BH1750_OFFSET_VALUE 1 +#endif + +class Usermod_BH1750 : public Usermod +{ +private: + int8_t offset = USERMOD_BH1750_OFFSET_VALUE; + + unsigned long maxReadingInterval = USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL; + unsigned long minReadingInterval = USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL; + unsigned long lastMeasurement = UINT32_MAX - (USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL - USERMOD_BH1750_FIRST_MEASUREMENT_AT); + unsigned long lastSend = UINT32_MAX - (USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL - USERMOD_BH1750_FIRST_MEASUREMENT_AT); + // flag to indicate we have finished the first readLightLevel call + // allows this library to report to the user how long until the first + // measurement + bool getLuminanceComplete = false; + + // flag set at startup + bool disabled = false; + + // strings to reduce flash memory usage (used more than twice) + static const char _name[]; + static const char _enabled[]; + static const char _maxReadInterval[]; + static const char _minReadInterval[]; + static const char _offset[]; + + BH1750 lightMeter; + float lastLux = -1000; + + bool checkBoundSensor(float newValue, float prevValue, float maxDiff) + { + return isnan(prevValue) || newValue <= prevValue - maxDiff || newValue >= prevValue + maxDiff || (newValue == 0.0 && prevValue > 0.0); + } + +public: + void setup() + { + Wire.begin(); + lightMeter.begin(); + } + + void loop() + { + if (disabled || strip.isUpdating()) + return; + + unsigned long now = millis(); + + // check to see if we are due for taking a measurement + // lastMeasurement will not be updated until the conversion + // is complete the the reading is finished + if (now - lastMeasurement < minReadingInterval) + { + return; + } + + bool shouldUpdate = now - lastSend > maxReadingInterval; + + float lux = lightMeter.readLightLevel(); + lastMeasurement = millis(); + getLuminanceComplete = true; + + if (shouldUpdate || checkBoundSensor(lux, lastLux, offset)) + { + lastLux = lux; + lastSend = millis(); + if (WLED_MQTT_CONNECTED) + { + char subuf[45]; + strcpy(subuf, mqttDeviceTopic); + strcat_P(subuf, PSTR("/luminance")); + mqtt->publish(subuf, 0, true, String(lux).c_str()); + } + else + { + DEBUG_PRINTLN("Missing MQTT connection. Not publishing data"); + } + } + } + + void addToJsonInfo(JsonObject &root) + { + JsonObject user = root[F("u")]; + if (user.isNull()) + user = root.createNestedObject(F("u")); + + JsonArray lux_json = user.createNestedArray(F("Luminance")); + + if (!getLuminanceComplete) + { + // if we haven't read the sensor yet, let the user know + // that we are still waiting for the first measurement + lux_json.add((USERMOD_BH1750_FIRST_MEASUREMENT_AT - millis()) / 1000); + lux_json.add(F(" sec until read")); + return; + } + + lux_json.add(lastLux); + lux_json.add(F(" lx")); + } + + uint16_t getId() + { + return USERMOD_ID_BH1750; + } + + /** + * addToConfig() (called from set.cpp) stores persistent properties to cfg.json + */ + void addToConfig(JsonObject &root) + { + // we add JSON object. + JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname + top[FPSTR(_enabled)] = !disabled; + top[FPSTR(_maxReadInterval)] = maxReadingInterval; + top[FPSTR(_minReadInterval)] = minReadingInterval; + top[FPSTR(_offset)] = offset; + + DEBUG_PRINTLN(F("Photoresistor config saved.")); + } + + /** + * readFromConfig() is called before setup() to populate properties from values stored in cfg.json + */ + bool readFromConfig(JsonObject &root) + { + // we look for JSON object. + JsonObject top = root[FPSTR(_name)]; + if (top.isNull()) + { + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + return false; + } + + disabled = !(top[FPSTR(_enabled)] | !disabled); + maxReadingInterval = (top[FPSTR(_maxReadInterval)] | maxReadingInterval); // ms + minReadingInterval = (top[FPSTR(_minReadInterval)] | minReadingInterval); // ms + offset = top[FPSTR(_offset)] | offset; + DEBUG_PRINT(FPSTR(_name)); + DEBUG_PRINTLN(F(" config (re)loaded.")); + + // use "return !top["newestParameter"].isNull();" when updating Usermod with new features + return true; + } +}; + +// strings to reduce flash memory usage (used more than twice) +const char Usermod_BH1750::_name[] PROGMEM = "BH1750"; +const char Usermod_BH1750::_enabled[] PROGMEM = "enabled"; +const char Usermod_BH1750::_maxReadInterval[] PROGMEM = "max-read-interval-ms"; +const char Usermod_BH1750::_minReadInterval[] PROGMEM = "min-read-interval-ms"; +const char Usermod_BH1750::_offset[] PROGMEM = "offset-lx"; diff --git a/usermods/BH1750_v2/usermods_list.cpp b/usermods/BH1750_v2/usermods_list.cpp new file mode 100644 index 00000000..6e914df5 --- /dev/null +++ b/usermods/BH1750_v2/usermods_list.cpp @@ -0,0 +1,14 @@ +#include "wled.h" +/* + * Register your v2 usermods here! + */ +#ifdef USERMOD_BH1750 +#include "../usermods/BH1750_v2/usermod_BH1750.h" +#endif + +void registerUsermods() +{ +#ifdef USERMOD_BH1750 + usermods.add(new Usermod_BH1750()); +#endif +} diff --git a/wled00/const.h b/wled00/const.h index 9348911e..770a6de2 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -60,6 +60,7 @@ #define USERMOD_ID_SN_PHOTORESISTOR 17 //Usermod "usermod_sn_photoresistor.h" #define USERMOD_ID_BATTERY_STATUS_BASIC 18 //Usermod "usermod_v2_battery_status_basic.h" #define USERMOD_ID_PWM_FAN 19 //Usermod "usermod_PWM_fan.h" +#define USERMOD_ID_BH1750 20 //Usermod "usermod_bh1750.h" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot