Merge branch 'BME280-Enhancements' of https://github.com/albarlow/WLED into BME280-Enhancements
This commit is contained in:
commit
d8d01ac353
@ -1,36 +1,60 @@
|
|||||||
Hello! I have written a v2 usermod for the BME280/BMP280 sensor based on the [existing v1 usermod](https://github.com/Aircoookie/WLED/blob/master/usermods/Wemos_D1_mini%2BWemos32_mini_shield/usermod_bme280.cpp). It is not just a refactor, there are many changes which I made to fit my use case, and I hope they will fit the use cases of others as well! Most notably, this usermod is *just* for the BME280 and does not control a display like in the v1 usermod designed for the WeMos shield.
|
# Usermod BME280
|
||||||
|
This Usermod is designed to read a `BME280` or `BMP280` sensor and output the following:
|
||||||
|
- Temperature
|
||||||
|
- Humidity (`BME280` only)
|
||||||
|
- Pressure
|
||||||
|
- Heat Index (`BME280` only)
|
||||||
|
- Dew Point (`BME280` only)
|
||||||
|
|
||||||
- Requires libraries `BME280@~3.0.0` (by [finitespace](https://github.com/finitespace/BME280)) and `Wire`. Please add these under `lib_deps` in your `platform.ini` (or `platform_override.ini`).
|
Configuration is all completed via the Usermod menu. There are no settings to set in code! The following settings can be configured in the Usermod Menu:
|
||||||
- Data is published over MQTT so make sure you've enabled the MQTT sync interface.
|
- Temperature Decimals (number of decimal places to output)
|
||||||
|
- Humidity Decimals
|
||||||
|
- Pressure Decimals
|
||||||
|
- Temperature Interval (how many seconds between reads of temperature and humidity)
|
||||||
|
- Pressure Interval
|
||||||
|
- Publish Always (turn off to only publish changes, on to publish whether or not value changed)
|
||||||
|
- Use Celsius (turn off to use Farenheit)
|
||||||
|
- Home Assistant Discovery (turn on to sent MQTT Discovery entries for Home Assistant)
|
||||||
|
- SCL/SDA GPIO Pins
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
- Libraries
|
||||||
|
- `BME280@~3.0.0` (by [finitespace](https://github.com/finitespace/BME280))
|
||||||
|
- `Wire`
|
||||||
|
- These must be added under `lib_deps` in your `platform.ini` (or `platform_override.ini`).
|
||||||
|
- Data is published over MQTT - make sure you've enabled the MQTT sync interface.
|
||||||
- This usermod also writes to serial (GPIO1 on ESP8266). Please make sure nothing else listening on the serial TX pin of your board will get confused by log messages!
|
- This usermod also writes to serial (GPIO1 on ESP8266). Please make sure nothing else listening on the serial TX pin of your board will get confused by log messages!
|
||||||
|
|
||||||
To enable, compile with `USERMOD_BME280` defined (i.e. `platformio_override.ini`)
|
In addition to outputting via MQTT, you can read the values from the Info Screen on the dashboard page of the device's web interface.
|
||||||
|
|
||||||
|
Methods also exist to read the read/calculated values from other WLED modules through code.
|
||||||
|
- `getTemperatureC()`
|
||||||
|
- `getTemperatureF()`
|
||||||
|
- `getHumidity()`
|
||||||
|
- `getPressure()`
|
||||||
|
- `getDewPointC()`
|
||||||
|
- `getDewPointF()`
|
||||||
|
- `getHeatIndexC()`
|
||||||
|
- `getHeatIndexF()`
|
||||||
|
|
||||||
|
# Complilation
|
||||||
|
|
||||||
|
To enable, compile with `USERMOD_BME280` defined (e.g. in `platformio_override.ini`)
|
||||||
```ini
|
```ini
|
||||||
|
[env:usermod_bme280_d1_mini]
|
||||||
|
extends = env:d1_mini
|
||||||
build_flags =
|
build_flags =
|
||||||
${common.build_flags_esp8266}
|
${common.build_flags_esp8266}
|
||||||
-D USERMOD_BME280
|
-D USERMOD_BME280
|
||||||
```
|
lib_deps =
|
||||||
or define `USERMOD_BME280` in `my_config.h`
|
${esp8266.lib_deps}
|
||||||
```c++
|
BME280@~3.0.0
|
||||||
#define USERMOD_BME280
|
Wire
|
||||||
```
|
```
|
||||||
|
|
||||||
Changes include:
|
|
||||||
- Adjustable measure intervals
|
|
||||||
- Temperature and pressure have separate intervals due to pressure not frequently changing at any constant altitude
|
|
||||||
- Adjustment of number of decimal places in published sensor values
|
|
||||||
- Separate adjustment for temperature, humidity and pressure values
|
|
||||||
- Values are rounded to the specified number of decimal places
|
|
||||||
- Pressure measured in units of hPa instead of Pa
|
|
||||||
- Calculation of heat index (apparent temperature) and dew point
|
|
||||||
- These, along with humidity measurements, are disabled if the sensor is a BMP280
|
|
||||||
- 16x oversampling of sensor during measurement
|
|
||||||
- Values are only published if they are different from the previous value
|
|
||||||
- Values are published on startup (continually until the MQTT broker acknowledges a successful publication)
|
|
||||||
|
|
||||||
Adjustments are made through preprocessor definitions at the start of the class definition.
|
# MQTT
|
||||||
|
MQTT topics are as follows (`<deviceTopic>` is set in MQTT section of Sync Setup menu):
|
||||||
MQTT topics are as follows:
|
|
||||||
Measurement type | MQTT topic
|
Measurement type | MQTT topic
|
||||||
--- | ---
|
--- | ---
|
||||||
Temperature | `<deviceTopic>/temperature`
|
Temperature | `<deviceTopic>/temperature`
|
||||||
@ -38,3 +62,29 @@ Humidity | `<deviceTopic>/humidity`
|
|||||||
Pressure | `<deviceTopic>/pressure`
|
Pressure | `<deviceTopic>/pressure`
|
||||||
Heat index | `<deviceTopic>/heat_index`
|
Heat index | `<deviceTopic>/heat_index`
|
||||||
Dew point | `<deviceTopic>/dew_point`
|
Dew point | `<deviceTopic>/dew_point`
|
||||||
|
|
||||||
|
If you are using Home Assistant, and `Home Assistant Discovery` is turned on, Home Assistant should automatically detect a new device, provided you have the MQTT integration installed. The device is seperate from the main WLED device and will contain sensors for Pressure, Humidity, Temperature, Dew Point and Heat Index.
|
||||||
|
|
||||||
|
# Revision History
|
||||||
|
Jul 2022
|
||||||
|
- Added Home Assistant Discovery
|
||||||
|
- Added API interface to output data
|
||||||
|
- Removed compile-time variables
|
||||||
|
- Added usermod menu interface
|
||||||
|
- Added value outputs to info screen
|
||||||
|
- Updated `readme.md`
|
||||||
|
- Registered usermod
|
||||||
|
- Implemented PinManager for usermod
|
||||||
|
- Implemented reallocation of pins without reboot
|
||||||
|
|
||||||
|
Apr 2021
|
||||||
|
- Added `Publish Always` option
|
||||||
|
|
||||||
|
Dec 2020
|
||||||
|
- Ported to V2 Usermod format
|
||||||
|
- Customisable `measure intervals`
|
||||||
|
- Customisable number of `decimal places` in published sensor values
|
||||||
|
- Pressure measured in units of hPa instead of Pa
|
||||||
|
- Calculation of heat index (apparent temperature) and dew point
|
||||||
|
- `16x oversampling` of sensor during measurement
|
||||||
|
- Values only published if they are different from the previous value
|
@ -1,3 +1,6 @@
|
|||||||
|
// force the compiler to show a warning to confirm that this file is included
|
||||||
|
#warning **** Included USERMOD_BME280 version 2.0 ****
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
@ -9,43 +12,30 @@
|
|||||||
class UsermodBME280 : public Usermod
|
class UsermodBME280 : public Usermod
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// User-defined configuration
|
|
||||||
#define Celsius // Show temperature mesaurement in Celcius. Comment out for Fahrenheit
|
|
||||||
#define TemperatureDecimals 1 // Number of decimal places in published temperaure values
|
|
||||||
#define HumidityDecimals 2 // Number of decimal places in published humidity values
|
|
||||||
#define PressureDecimals 2 // Number of decimal places in published pressure values
|
|
||||||
#define TemperatureInterval 5 // Interval to measure temperature (and humidity, dew point if available) in seconds
|
|
||||||
#define PressureInterval 300 // Interval to measure pressure in seconds
|
|
||||||
#define PublishAlways 0 // Publish values even when they have not changed
|
|
||||||
|
|
||||||
// Sanity checks
|
// NOTE: Do not implement any compile-time variables, anything the user needs to configure
|
||||||
#if !defined(TemperatureDecimals) || TemperatureDecimals < 0
|
// should be configurable from the Usermod menu using the methods below
|
||||||
#define TemperatureDecimals 0
|
// key settings set via usermod menu
|
||||||
#endif
|
unsigned long TemperatureDecimals = 0; // Number of decimal places in published temperaure values
|
||||||
#if !defined(HumidityDecimals) || HumidityDecimals < 0
|
unsigned long HumidityDecimals = 0; // Number of decimal places in published humidity values
|
||||||
#define HumidityDecimals 0
|
unsigned long PressureDecimals = 0; // Number of decimal places in published pressure values
|
||||||
#endif
|
unsigned long TemperatureInterval = 5; // Interval to measure temperature (and humidity, dew point if available) in seconds
|
||||||
#if !defined(PressureDecimals) || PressureDecimals < 0
|
unsigned long PressureInterval = 300; // Interval to measure pressure in seconds
|
||||||
#define PressureDecimals 0
|
bool PublishAlways = false; // Publish values even when they have not changed
|
||||||
#endif
|
bool UseCelsius = true; // Use Celsius for Reporting
|
||||||
#if !defined(TemperatureInterval) || TemperatureInterval < 0
|
bool HomeAssistantDiscovery = false; // Publish Home Assistant Device Information
|
||||||
#define TemperatureInterval 1
|
|
||||||
#endif
|
|
||||||
#if !defined(PressureInterval) || PressureInterval < 0
|
|
||||||
#define PressureInterval TemperatureInterval
|
|
||||||
#endif
|
|
||||||
#if !defined(PublishAlways)
|
|
||||||
#define PublishAlways 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32 // ESP32 boards
|
// set the default pins based on the architecture, these get overridden by Usermod menu settings
|
||||||
uint8_t SCL_PIN = 22;
|
#ifdef ARDUINO_ARCH_ESP32 // ESP32 boards
|
||||||
uint8_t SDA_PIN = 21;
|
#define HW_PIN_SCL 22
|
||||||
#else // ESP8266 boards
|
#define HW_PIN_SDA 21
|
||||||
uint8_t SCL_PIN = 5;
|
#else // ESP8266 boards
|
||||||
uint8_t SDA_PIN = 4;
|
#define HW_PIN_SCL 5
|
||||||
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
#define HW_PIN_SDA 4
|
||||||
#endif
|
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
||||||
|
#endif
|
||||||
|
int8_t ioPin[2] = {HW_PIN_SCL, HW_PIN_SDA}; // I2C pins: SCL, SDA...defaults to Arch hardware pins but overridden at setup()
|
||||||
|
bool initDone = false;
|
||||||
|
|
||||||
// BME280 sensor settings
|
// BME280 sensor settings
|
||||||
BME280I2C::Settings settings{
|
BME280I2C::Settings settings{
|
||||||
@ -75,6 +65,7 @@ private:
|
|||||||
float sensorHeatIndex;
|
float sensorHeatIndex;
|
||||||
float sensorDewPoint;
|
float sensorDewPoint;
|
||||||
float sensorPressure;
|
float sensorPressure;
|
||||||
|
String tempScale;
|
||||||
// Track previous sensor values
|
// Track previous sensor values
|
||||||
float lastTemperature;
|
float lastTemperature;
|
||||||
float lastHumidity;
|
float lastHumidity;
|
||||||
@ -82,43 +73,122 @@ private:
|
|||||||
float lastDewPoint;
|
float lastDewPoint;
|
||||||
float lastPressure;
|
float lastPressure;
|
||||||
|
|
||||||
|
// MQTT topic strings for publishing Home Assistant discovery topics
|
||||||
|
bool mqttInitialized = false;
|
||||||
|
String mqttTemperatureTopic = "";
|
||||||
|
String mqttHumidityTopic = "";
|
||||||
|
String mqttPressureTopic = "";
|
||||||
|
String mqttHeatIndexTopic = "";
|
||||||
|
String mqttDewPointTopic = "";
|
||||||
|
|
||||||
// Store packet IDs of MQTT publications
|
// Store packet IDs of MQTT publications
|
||||||
uint16_t mqttTemperaturePub = 0;
|
uint16_t mqttTemperaturePub = 0;
|
||||||
uint16_t mqttPressurePub = 0;
|
uint16_t mqttPressurePub = 0;
|
||||||
|
|
||||||
|
// Read the BME280/BMP280 Sensor (which one runs depends on whether Celsius or Farenheit being set in Usermod Menu)
|
||||||
void UpdateBME280Data(int SensorType)
|
void UpdateBME280Data(int SensorType)
|
||||||
{
|
{
|
||||||
float _temperature, _humidity, _pressure;
|
float _temperature, _humidity, _pressure;
|
||||||
#ifdef Celsius
|
|
||||||
|
if (UseCelsius) {
|
||||||
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
|
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
|
||||||
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Celsius);
|
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Celsius);
|
||||||
#else
|
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
||||||
|
|
||||||
|
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
|
||||||
|
|
||||||
|
sensorTemperature = _temperature;
|
||||||
|
sensorHumidity = _humidity;
|
||||||
|
sensorPressure = _pressure;
|
||||||
|
tempScale = "°C";
|
||||||
|
if (sensorType == 1)
|
||||||
|
{
|
||||||
|
sensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
|
||||||
|
sensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
BME280::TempUnit tempUnit(BME280::TempUnit_Fahrenheit);
|
BME280::TempUnit tempUnit(BME280::TempUnit_Fahrenheit);
|
||||||
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Fahrenheit);
|
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Fahrenheit);
|
||||||
#endif
|
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
||||||
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
|
||||||
|
|
||||||
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
|
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
|
||||||
|
|
||||||
sensorTemperature = _temperature;
|
sensorTemperature = _temperature;
|
||||||
sensorHumidity = _humidity;
|
sensorHumidity = _humidity;
|
||||||
sensorPressure = _pressure;
|
sensorPressure = _pressure;
|
||||||
if (sensorType == 1)
|
tempScale = "°F";
|
||||||
{
|
if (sensorType == 1)
|
||||||
sensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
|
{
|
||||||
sensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
|
sensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
|
||||||
|
sensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Procedure to define all MQTT discovery Topics
|
||||||
|
void _mqttInitialize()
|
||||||
|
{
|
||||||
|
mqttTemperatureTopic = String(mqttDeviceTopic) + "/temperature";
|
||||||
|
mqttPressureTopic = String(mqttDeviceTopic) + "/pressure";
|
||||||
|
mqttHumidityTopic = String(mqttDeviceTopic) + "/humidity";
|
||||||
|
mqttHeatIndexTopic = String(mqttDeviceTopic) + "/heat_index";
|
||||||
|
mqttDewPointTopic = String(mqttDeviceTopic) + "/dew_point";
|
||||||
|
|
||||||
|
if (HomeAssistantDiscovery) {
|
||||||
|
_createMqttSensor(F("Temperature"), mqttTemperatureTopic, F("temperature"), tempScale);
|
||||||
|
_createMqttSensor(F("Pressure"), mqttPressureTopic, F("pressure"), F("hPa"));
|
||||||
|
_createMqttSensor(F("Humidity"), mqttHumidityTopic, F("humidity"), F("%"));
|
||||||
|
_createMqttSensor(F("HeatIndex"), mqttHeatIndexTopic, F("temperature"), tempScale);
|
||||||
|
_createMqttSensor(F("DewPoint"), mqttDewPointTopic, F("temperature"), tempScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an MQTT Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
|
||||||
|
void _createMqttSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement)
|
||||||
|
{
|
||||||
|
String t = String("homeassistant/sensor/") + mqttClientID + "/" + name + "/config";
|
||||||
|
|
||||||
|
StaticJsonDocument<600> doc;
|
||||||
|
|
||||||
|
doc[F("name")] = String(serverDescription) + " " + name;
|
||||||
|
doc[F("state_topic")] = topic;
|
||||||
|
doc[F("unique_id")] = String(mqttClientID) + name;
|
||||||
|
if (unitOfMeasurement != "")
|
||||||
|
doc[F("unit_of_measurement")] = unitOfMeasurement;
|
||||||
|
if (deviceClass != "")
|
||||||
|
doc[F("device_class")] = deviceClass;
|
||||||
|
doc[F("expire_after")] = 1800;
|
||||||
|
|
||||||
|
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
|
||||||
|
device[F("name")] = serverDescription;
|
||||||
|
device[F("identifiers")] = "wled-sensor-" + String(mqttClientID);
|
||||||
|
device[F("manufacturer")] = F("WLED");
|
||||||
|
device[F("model")] = F("FOSS");
|
||||||
|
device[F("sw_version")] = versionString;
|
||||||
|
|
||||||
|
String temp;
|
||||||
|
serializeJson(doc, temp);
|
||||||
|
Serial.println(t);
|
||||||
|
Serial.println(temp);
|
||||||
|
|
||||||
|
mqtt->publish(t.c_str(), 0, true, temp.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Wire.begin(SDA_PIN, SCL_PIN);
|
bool HW_Pins_Used = (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA); // note whether architecture-based hardware SCL/SDA pins used
|
||||||
|
PinOwner po = PinOwner::UM_BME280; // defaults to being pinowner for SCL/SDA pins
|
||||||
|
PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } }; // allocate pins
|
||||||
|
if (HW_Pins_Used) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
||||||
|
if (!pinManager.allocateMultiplePins(pins, 2, po)) { sensorType=0; return; }
|
||||||
|
|
||||||
|
Wire.begin(ioPin[1], ioPin[0]);
|
||||||
|
|
||||||
if (!bme.begin())
|
if (!bme.begin())
|
||||||
{
|
{
|
||||||
sensorType = 0;
|
sensorType = 0;
|
||||||
Serial.println("Could not find BME280I2C sensor!");
|
Serial.println(F("Could not find BME280I2C sensor!"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -126,24 +196,25 @@ public:
|
|||||||
{
|
{
|
||||||
case BME280::ChipModel_BME280:
|
case BME280::ChipModel_BME280:
|
||||||
sensorType = 1;
|
sensorType = 1;
|
||||||
Serial.println("Found BME280 sensor! Success.");
|
Serial.println(F("Found BME280 sensor! Success."));
|
||||||
break;
|
break;
|
||||||
case BME280::ChipModel_BMP280:
|
case BME280::ChipModel_BMP280:
|
||||||
sensorType = 2;
|
sensorType = 2;
|
||||||
Serial.println("Found BMP280 sensor! No Humidity available.");
|
Serial.println(F("Found BMP280 sensor! No Humidity available."));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sensorType = 0;
|
sensorType = 0;
|
||||||
Serial.println("Found UNKNOWN sensor! Error!");
|
Serial.println(F("Found UNKNOWN sensor! Error!"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
initDone=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
// BME280 sensor MQTT publishing
|
// BME280 sensor MQTT publishing
|
||||||
// Check if sensor present and MQTT Connected, otherwise it will crash the MCU
|
// Check if sensor present and MQTT Connected, otherwise it will crash the MCU
|
||||||
if (sensorType != 0 && mqtt != nullptr)
|
if (sensorType != 0 && WLED_MQTT_CONNECTED)
|
||||||
{
|
{
|
||||||
// Timer to fetch new temperature, humidity and pressure data at intervals
|
// Timer to fetch new temperature, humidity and pressure data at intervals
|
||||||
timer = millis();
|
timer = millis();
|
||||||
@ -157,6 +228,12 @@ public:
|
|||||||
float temperature = roundf(sensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
float temperature = roundf(sensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||||
float humidity, heatIndex, dewPoint;
|
float humidity, heatIndex, dewPoint;
|
||||||
|
|
||||||
|
if (WLED_MQTT_CONNECTED && !mqttInitialized)
|
||||||
|
{
|
||||||
|
_mqttInitialize();
|
||||||
|
mqttInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
// If temperature has changed since last measure, create string populated with device topic
|
// If temperature has changed since last measure, create string populated with device topic
|
||||||
// from the UI and values read from sensor, then publish to broker
|
// from the UI and values read from sensor, then publish to broker
|
||||||
if (temperature != lastTemperature || PublishAlways)
|
if (temperature != lastTemperature || PublishAlways)
|
||||||
@ -213,4 +290,173 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* API calls te enable data exchange between WLED modules
|
||||||
|
*/
|
||||||
|
inline float getTemperatureC() {
|
||||||
|
if (UseCelsius) {
|
||||||
|
return (float)roundf(sensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||||
|
} else {
|
||||||
|
return (float)roundf(sensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals) * 1.8f + 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
inline float getTemperatureF() {
|
||||||
|
if (UseCelsius) {
|
||||||
|
return ((float)roundf(sensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals) -32) * 0.56f;
|
||||||
|
} else {
|
||||||
|
return (float)roundf(sensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline float getHumidity() {
|
||||||
|
return (float)roundf(sensorHumidity * pow(10, HumidityDecimals));
|
||||||
|
}
|
||||||
|
inline float getPressure() {
|
||||||
|
return (float)roundf(sensorPressure * pow(10, PressureDecimals));
|
||||||
|
}
|
||||||
|
inline float getDewPointC() {
|
||||||
|
if (UseCelsius) {
|
||||||
|
return (float)roundf(sensorDewPoint * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||||
|
} else {
|
||||||
|
return (float)roundf(sensorDewPoint * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals) * 1.8f + 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline float getDewPointF() {
|
||||||
|
if (UseCelsius) {
|
||||||
|
return ((float)roundf(sensorDewPoint * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals) -32) * 0.56f;
|
||||||
|
} else {
|
||||||
|
return (float)roundf(sensorDewPoint * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline float getHeatIndexC() {
|
||||||
|
if (UseCelsius) {
|
||||||
|
return (float)roundf(sensorHeatIndex * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||||
|
} else {
|
||||||
|
return (float)roundf(sensorHeatIndex * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals) * 1.8f + 32;
|
||||||
|
}
|
||||||
|
}inline float getHeatIndexF() {
|
||||||
|
if (UseCelsius) {
|
||||||
|
return ((float)roundf(sensorHeatIndex * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals) -32) * 0.56f;
|
||||||
|
} else {
|
||||||
|
return (float)roundf(sensorHeatIndex * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish Sensor Information to Info Page
|
||||||
|
void addToJsonInfo(JsonObject &root)
|
||||||
|
{
|
||||||
|
JsonObject user = root[F("u")];
|
||||||
|
if (user.isNull()) user = root.createNestedObject(F("u"));
|
||||||
|
|
||||||
|
if (sensorType==0) //No Sensor
|
||||||
|
{
|
||||||
|
// if we sensor not detected, let the user know
|
||||||
|
JsonArray temperature_json = user.createNestedArray(F("BME/BMP280 Sensor"));
|
||||||
|
temperature_json.add(F("Not Found"));
|
||||||
|
}
|
||||||
|
else if (sensorType==2) //BMP280
|
||||||
|
{
|
||||||
|
|
||||||
|
JsonArray temperature_json = user.createNestedArray("Temperature");
|
||||||
|
JsonArray pressure_json = user.createNestedArray("Pressure");
|
||||||
|
temperature_json.add(roundf(sensorTemperature * pow(10, TemperatureDecimals)));
|
||||||
|
temperature_json.add(tempScale);
|
||||||
|
pressure_json.add(roundf(sensorPressure * pow(10, PressureDecimals)));
|
||||||
|
pressure_json.add(F("hPa"));
|
||||||
|
}
|
||||||
|
else if (sensorType==1) //BME280
|
||||||
|
{
|
||||||
|
JsonArray temperature_json = user.createNestedArray("Temperature");
|
||||||
|
JsonArray humidity_json = user.createNestedArray("Humidity");
|
||||||
|
JsonArray pressure_json = user.createNestedArray("Pressure");
|
||||||
|
JsonArray heatindex_json = user.createNestedArray("Heat Index");
|
||||||
|
JsonArray dewpoint_json = user.createNestedArray("Dew Point");
|
||||||
|
temperature_json.add(roundf(sensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals));
|
||||||
|
temperature_json.add(tempScale);
|
||||||
|
humidity_json.add(roundf(sensorHumidity * pow(10, HumidityDecimals)));
|
||||||
|
humidity_json.add(F("%"));
|
||||||
|
pressure_json.add(roundf(sensorPressure * pow(10, PressureDecimals)));
|
||||||
|
pressure_json.add(F("hPa"));
|
||||||
|
heatindex_json.add(roundf(sensorHeatIndex * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals));
|
||||||
|
heatindex_json.add(tempScale);
|
||||||
|
dewpoint_json.add(roundf(sensorDewPoint * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals));
|
||||||
|
dewpoint_json.add(tempScale);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save Usermod Config Settings
|
||||||
|
void addToConfig(JsonObject& root)
|
||||||
|
{
|
||||||
|
JsonObject top = root.createNestedObject(F("BME280/BMP280"));
|
||||||
|
top[F("TemperatureDecimals")] = TemperatureDecimals;
|
||||||
|
top[F("HumidityDecimals")] = HumidityDecimals;
|
||||||
|
top[F("PressureDecimals")] = PressureDecimals;
|
||||||
|
top[F("TemperatureInterval")] = TemperatureInterval;
|
||||||
|
top[F("PressureInterval")] = PressureInterval;
|
||||||
|
top[F("PublishAlways")] = PublishAlways;
|
||||||
|
top[F("UseCelsius")] = UseCelsius;
|
||||||
|
top[F("HomeAssistantDiscovery")] = HomeAssistantDiscovery;
|
||||||
|
JsonArray io_pin = top.createNestedArray(F("pin"));
|
||||||
|
for (byte i=0; i<2; i++) io_pin.add(ioPin[i]);
|
||||||
|
top[F("help4Pins")] = F("SCL,SDA"); // help for Settings page
|
||||||
|
DEBUG_PRINTLN(F("BME280 config saved."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Usermod Config Settings
|
||||||
|
bool readFromConfig(JsonObject& root)
|
||||||
|
{
|
||||||
|
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
||||||
|
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
|
||||||
|
|
||||||
|
|
||||||
|
int8_t newPin[2]; for (byte i=0; i<2; i++) newPin[i] = ioPin[i]; // prepare to note changed pins
|
||||||
|
|
||||||
|
JsonObject top = root[F("BME280/BMP280")];
|
||||||
|
if (top.isNull()) {
|
||||||
|
DEBUG_PRINT(F("BME280/BMP280"));
|
||||||
|
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool configComplete = !top.isNull();
|
||||||
|
|
||||||
|
// A 3-argument getJsonValue() assigns the 3rd argument as a default value if the Json value is missing
|
||||||
|
configComplete &= getJsonValue(top[F("TemperatureDecimals")], TemperatureDecimals, 1);
|
||||||
|
configComplete &= getJsonValue(top[F("HumidityDecimals")], HumidityDecimals, 0);
|
||||||
|
configComplete &= getJsonValue(top[F("PressureDecimals")], PressureDecimals, 0);
|
||||||
|
configComplete &= getJsonValue(top[F("TemperatureInterval")], TemperatureInterval, 30);
|
||||||
|
configComplete &= getJsonValue(top[F("PressureInterval")], PressureInterval, 30);
|
||||||
|
configComplete &= getJsonValue(top[F("PublishAlways")], PublishAlways, false);
|
||||||
|
configComplete &= getJsonValue(top[F("UseCelsius")], UseCelsius, true);
|
||||||
|
configComplete &= getJsonValue(top[F("HomeAssistantDiscovery")], HomeAssistantDiscovery, false);
|
||||||
|
for (byte i=0; i<2; i++) configComplete &= getJsonValue(top[F("pin")][i], newPin[i], ioPin[i]);
|
||||||
|
|
||||||
|
DEBUG_PRINT(FPSTR(F("BME280/BMP280")));
|
||||||
|
if (!initDone) {
|
||||||
|
// first run: reading from cfg.json
|
||||||
|
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
||||||
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
|
} else {
|
||||||
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
|
// changing parameters from settings page
|
||||||
|
bool pinsChanged = false;
|
||||||
|
for (byte i=0; i<2; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; } // check if any pins changed
|
||||||
|
if (pinsChanged) { //if pins changed, deallocate old pins and allocate new ones
|
||||||
|
PinOwner po = PinOwner::UM_BME280;
|
||||||
|
if (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
||||||
|
pinManager.deallocateMultiplePins((const uint8_t *)ioPin, 2, po); // deallocate pins
|
||||||
|
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
|
return !top[F("pin")].isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
return configComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t getId() {
|
||||||
|
return USERMOD_ID_BME280;
|
||||||
|
}
|
||||||
};
|
};
|
@ -76,6 +76,7 @@
|
|||||||
#define USERMOD_ID_WORDCLOCK 27 //Usermod "usermod_v2_word_clock.h"
|
#define USERMOD_ID_WORDCLOCK 27 //Usermod "usermod_v2_word_clock.h"
|
||||||
#define USERMOD_ID_MY9291 28 //Usermod "usermod_MY9291.h"
|
#define USERMOD_ID_MY9291 28 //Usermod "usermod_MY9291.h"
|
||||||
#define USERMOD_ID_SI7021_MQTT_HA 29 //Usermod "usermod_si7021_mqtt_ha.h"
|
#define USERMOD_ID_SI7021_MQTT_HA 29 //Usermod "usermod_si7021_mqtt_ha.h"
|
||||||
|
#define USERMOD_ID_BME280 30 //Usermod "usermod_bme280.h
|
||||||
|
|
||||||
//Access point behavior
|
//Access point behavior
|
||||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||||
|
@ -53,7 +53,8 @@ enum struct PinOwner : uint8_t {
|
|||||||
// #define USERMOD_ID_ELEKSTUBE_IPS // 0x10 // Usermod "usermod_elekstube_ips.h" -- Uses quite a few pins ... see Hardware.h and User_Setup.h
|
// #define USERMOD_ID_ELEKSTUBE_IPS // 0x10 // Usermod "usermod_elekstube_ips.h" -- Uses quite a few pins ... see Hardware.h and User_Setup.h
|
||||||
// #define USERMOD_ID_SN_PHOTORESISTOR // 0x11 // Usermod "usermod_sn_photoresistor.h" -- Uses hard-coded pin (PHOTORESISTOR_PIN == A0), but could be easily updated to use pinManager
|
// #define USERMOD_ID_SN_PHOTORESISTOR // 0x11 // Usermod "usermod_sn_photoresistor.h" -- Uses hard-coded pin (PHOTORESISTOR_PIN == A0), but could be easily updated to use pinManager
|
||||||
UM_RGBRotaryEncoder = USERMOD_RGB_ROTARY_ENCODER, // 0x16 // Usermod "rgb-rotary-encoder.h"
|
UM_RGBRotaryEncoder = USERMOD_RGB_ROTARY_ENCODER, // 0x16 // Usermod "rgb-rotary-encoder.h"
|
||||||
UM_QuinLEDAnPenta = USERMOD_ID_QUINLED_AN_PENTA // 0x17 // Usermod "quinled-an-penta.h"
|
UM_QuinLEDAnPenta = USERMOD_ID_QUINLED_AN_PENTA, // 0x17 // Usermod "quinled-an-penta.h"
|
||||||
|
UM_BME280 = USERMOD_ID_BME280 // 0x18 // Usermod "usermod_bme280.h -- Uses "standard" HW_I2C pins
|
||||||
};
|
};
|
||||||
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");
|
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user