Async temperature usermod (#1178)
* Change Temperature usermod to use async reading to avoid blocking * Fix comparison on wait time * Add * Simplify logic in the loop method * Optimize calls to minimize latency, inform user how long till first measurement * disable usermod if sensor not found * Added debug statements on init, update readme * fix spelling error of celsius
This commit is contained in:
parent
63d92381ee
commit
57421d2392
13
usermods/Temperature/platformio_override.ini
Normal file
13
usermods/Temperature/platformio_override.ini
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
; Options
|
||||||
|
; -------
|
||||||
|
; USERMOD_DALLASTEMPERATURE - define this to have this user mod included wled00\usermods_list.cpp
|
||||||
|
; USERMOD_DALLASTEMPERATURE_CELSIUS - define this to report temperatures in degrees celsius, otherwise fahrenheit will be reported
|
||||||
|
; USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - the number of milliseconds between measurements, defaults to 60 seconds
|
||||||
|
; USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT - the number of milliseconds after boot to take first measurement, defaults to 20 seconds
|
||||||
|
;
|
||||||
|
[env:d1_mini_usermod_dallas_temperature_C]
|
||||||
|
extends = env:d1_mini
|
||||||
|
build_flags = ${common.build_flags_esp8266} -D USERMOD_DALLASTEMPERATURE -D USERMOD_DALLASTEMPERATURE_CELSIUS
|
||||||
|
lib_deps = ${env.lib_deps}
|
||||||
|
milesburton/DallasTemperature@^3.9.0
|
||||||
|
OneWire@~2.3.5
|
@ -5,11 +5,18 @@ This usermod will read from an attached DS18B20 temperature sensor (as available
|
|||||||
The temperature is displayed both in the Info section of the web UI as well as published to the `/temperature` MQTT topic if enabled.
|
The temperature is displayed both in the Info section of the web UI as well as published to the `/temperature` MQTT topic if enabled.
|
||||||
This usermod will be expanded with support for different sensor types in the future.
|
This usermod will be expanded with support for different sensor types in the future.
|
||||||
|
|
||||||
|
If temperature sensor is not detected during boot, this usermod will be disabled.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Copy `usermod_temperature.h` to the wled00 directory.
|
Copy the example `platformio_override.ini` to the root directory. This file should be placed in the same directory as `platformio.ini`.
|
||||||
Uncomment the corresponding lines in `usermods_list.cpp` and compile!
|
|
||||||
If this is the only v2 usermod you plan to use, you can alternatively replace `usermods_list.h` in wled00 with the one in this folder.
|
### Define Your Options
|
||||||
|
|
||||||
|
* `USERMOD_DALLASTEMPERATURE` - define this to have this user mod included wled00\usermods_list.cpp
|
||||||
|
* `USERMOD_DALLASTEMPERATURE_CELSIUS` - define this to report temperatures in degrees celsious, otherwise fahrenheit will be reported
|
||||||
|
* `USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL` - the number of milliseconds between measurements, defaults to 60 seconds
|
||||||
|
* `USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 20 seconds
|
||||||
|
|
||||||
## Project link
|
## Project link
|
||||||
|
|
||||||
@ -17,7 +24,10 @@ If this is the only v2 usermod you plan to use, you can alternatively replace `u
|
|||||||
|
|
||||||
### PlatformIO requirements
|
### PlatformIO requirements
|
||||||
|
|
||||||
You might have to uncomment `DallasTemperature@~3.8.0`,`OneWire@~2.3.5 under` `[common]` section in `platformio.ini`:
|
If you are using `platformio_override.ini`, you should be able to refresh the task list and see your custom task, for example `env:d1_mini_usermod_dallas_temperature_C`.
|
||||||
|
|
||||||
|
|
||||||
|
If you are not using `platformio_override.ini`, you might have to uncomment `DallasTemperature@~3.8.0`,`OneWire@~2.3.5 under` `[common]` section in `platformio.ini`:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
# platformio.ini
|
# platformio.ini
|
||||||
@ -38,3 +48,11 @@ lib_deps_external =
|
|||||||
OneWire@~2.3.5
|
OneWire@~2.3.5
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Change Log
|
||||||
|
|
||||||
|
2020-09-12
|
||||||
|
* Changed to use async, non-blocking implementation
|
||||||
|
* Do not report low temperatures that indicate an error to mqtt
|
||||||
|
* Disable plugin if temperature sensor not detected
|
||||||
|
* Report the number of seconds until the first read in the info screen instead of sensor error
|
@ -11,61 +11,156 @@
|
|||||||
#define TEMPERATURE_PIN 14
|
#define TEMPERATURE_PIN 14
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TEMP_CELSIUS // Comment out for Fahrenheit
|
// the frequency to check temperature, 1 minute
|
||||||
|
#ifndef USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL
|
||||||
|
#define USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL 60000
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MEASUREMENT_INTERVAL 60000 //1 Minute
|
// how many seconds after boot to take first measurement, 20 seconds
|
||||||
|
#ifndef USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT
|
||||||
|
#define USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT 20000
|
||||||
|
#endif
|
||||||
|
|
||||||
OneWire oneWire(TEMPERATURE_PIN);
|
OneWire oneWire(TEMPERATURE_PIN);
|
||||||
DallasTemperature sensor(&oneWire);
|
DallasTemperature sensor(&oneWire);
|
||||||
|
|
||||||
class UsermodTemperature : public Usermod {
|
class UsermodTemperature : public Usermod {
|
||||||
private:
|
private:
|
||||||
//set last reading as "40 sec before boot", so first reading is taken after 20 sec
|
// The device's unique 64-bit serial code stored in on-board ROM.
|
||||||
unsigned long lastMeasurement = UINT32_MAX - 40000;
|
// Reading directly from the sensor device address is faster than
|
||||||
float temperature = 0.0f;
|
// reading from index. When reading by index, DallasTemperature
|
||||||
public:
|
// must first look up the device address at the specified index.
|
||||||
void getReading() {
|
DeviceAddress sensorDeviceAddress;
|
||||||
sensor.requestTemperatures();
|
// set last reading as "40 sec before boot", so first reading is taken after 20 sec
|
||||||
#ifdef TEMP_CELSIUS
|
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT);
|
||||||
temperature = sensor.getTempCByIndex(0);
|
// last time requestTemperatures was called
|
||||||
#else
|
// used to determine when we can read the sensors temperature
|
||||||
temperature = sensor.getTempFByIndex(0);
|
// we have to wait at least 93.75 ms after requestTemperatures() is called
|
||||||
#endif
|
unsigned long lastTemperaturesRequest;
|
||||||
|
float temperature = -100; // default to -100, DS18B20 only goes down to -50C
|
||||||
|
// indicates requestTemperatures has been called but the sensor measurement is not complete
|
||||||
|
bool waitingForConversion = false;
|
||||||
|
// flag to indicate we have finished the first getTemperature call
|
||||||
|
// allows this library to report to the user how long until the first
|
||||||
|
// measurement
|
||||||
|
bool getTemperatureComplete = false;
|
||||||
|
// flag set at startup if DS18B20 sensor not found, avoids trying to keep getting
|
||||||
|
// temperature if flashed to a board without a sensor attached
|
||||||
|
bool disabled = false;
|
||||||
|
|
||||||
|
void requestTemperatures() {
|
||||||
|
// there is requestTemperaturesByAddress however it
|
||||||
|
// appears to do more work,
|
||||||
|
// TODO: measure exection time difference
|
||||||
|
sensor.requestTemperatures();
|
||||||
|
lastTemperaturesRequest = millis();
|
||||||
|
waitingForConversion = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getTemperature() {
|
||||||
|
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
|
||||||
|
temperature = sensor.getTempC(sensorDeviceAddress);
|
||||||
|
#else
|
||||||
|
temperature = sensor.getTempF(sensorDeviceAddress);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lastMeasurement = millis();
|
||||||
|
waitingForConversion = false;
|
||||||
|
getTemperatureComplete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
sensor.begin();
|
sensor.begin();
|
||||||
sensor.setResolution(9);
|
|
||||||
|
// get the unique 64-bit serial code stored in on-board ROM
|
||||||
|
// if getAddress returns false, the sensor was not found
|
||||||
|
disabled = !sensor.getAddress(sensorDeviceAddress, 0);
|
||||||
|
|
||||||
|
if (!disabled) {
|
||||||
|
DEBUG_PRINTLN("Dallas Temperature found");
|
||||||
|
// set the resolution for this specific device
|
||||||
|
sensor.setResolution(sensorDeviceAddress, 9, true);
|
||||||
|
// do not block waiting for reading
|
||||||
|
sensor.setWaitForConversion(false);
|
||||||
|
} else {
|
||||||
|
DEBUG_PRINTLN("Dallas Temperature not found");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (millis() - lastMeasurement > MEASUREMENT_INTERVAL)
|
if (disabled) {
|
||||||
|
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 < USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL)
|
||||||
{
|
{
|
||||||
getReading();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we are due for a measurement, if we are not already waiting
|
||||||
|
// for a conversion to complete, then make a new request for temps
|
||||||
|
if (!waitingForConversion)
|
||||||
|
{
|
||||||
|
requestTemperatures();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we were waiting for a conversion to complete, have we waited log enough?
|
||||||
|
if (now - lastTemperaturesRequest >= 94 /* 93.75ms per the datasheet */)
|
||||||
|
{
|
||||||
|
getTemperature();
|
||||||
|
|
||||||
if (WLED_MQTT_CONNECTED) {
|
if (WLED_MQTT_CONNECTED) {
|
||||||
char subuf[38];
|
char subuf[38];
|
||||||
strcpy(subuf, mqttDeviceTopic);
|
strcpy(subuf, mqttDeviceTopic);
|
||||||
strcat(subuf, "/temperature");
|
if (-100 <= temperature) {
|
||||||
mqtt->publish(subuf, 0, true, String(temperature).c_str());
|
// dont publish super low temperature as the graph will get messed up
|
||||||
|
// the DallasTemperature library returns -127C or -196.6F when problem
|
||||||
|
// reading the sensor
|
||||||
|
strcat(subuf, "/temperature");
|
||||||
|
mqtt->publish(subuf, 0, true, String(temperature).c_str());
|
||||||
|
} else {
|
||||||
|
// publish something else to indicate status?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lastMeasurement = millis();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addToJsonInfo(JsonObject& root) {
|
void addToJsonInfo(JsonObject& root) {
|
||||||
|
// dont add temperature to info if we are disabled
|
||||||
|
if (disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
JsonObject user = root["u"];
|
JsonObject user = root["u"];
|
||||||
if (user.isNull()) user = root.createNestedObject("u");
|
if (user.isNull()) user = root.createNestedObject("u");
|
||||||
|
|
||||||
JsonArray temp = user.createNestedArray("Temperature");
|
JsonArray temp = user.createNestedArray("Temperature");
|
||||||
if (temperature == DEVICE_DISCONNECTED_C) {
|
|
||||||
|
if (!getTemperatureComplete) {
|
||||||
|
// if we haven't read the sensor yet, let the user know
|
||||||
|
// that we are still waiting for the first measurement
|
||||||
|
temp.add((USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT - millis()) / 1000);
|
||||||
|
temp.add(" sec until read");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temperature <= -100) {
|
||||||
temp.add(0);
|
temp.add(0);
|
||||||
temp.add(" Sensor Error!");
|
temp.add(" Sensor Error!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
temp.add(temperature);
|
temp.add(temperature);
|
||||||
#ifdef TEMP_CELSIUS
|
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
|
||||||
temp.add("°C");
|
temp.add("°C");
|
||||||
#else
|
#else
|
||||||
temp.add("°F");
|
temp.add("°F");
|
||||||
|
@ -9,7 +9,10 @@
|
|||||||
* \/ \/ \/
|
* \/ \/ \/
|
||||||
*/
|
*/
|
||||||
//#include "usermod_v2_example.h"
|
//#include "usermod_v2_example.h"
|
||||||
#include "usermod_temperature.h"
|
#ifdef USERMOD_DALLASTEMPERATURE
|
||||||
|
#include "../usermods/Temperature/usermod_temperature.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
//#include "usermod_v2_empty.h"
|
//#include "usermod_v2_empty.h"
|
||||||
|
|
||||||
void registerUsermods()
|
void registerUsermods()
|
||||||
@ -20,6 +23,9 @@ void registerUsermods()
|
|||||||
* \/ \/ \/
|
* \/ \/ \/
|
||||||
*/
|
*/
|
||||||
//usermods.add(new MyExampleUsermod());
|
//usermods.add(new MyExampleUsermod());
|
||||||
|
#ifdef USERMOD_DALLASTEMPERATURE
|
||||||
usermods.add(new UsermodTemperature());
|
usermods.add(new UsermodTemperature());
|
||||||
|
#endif
|
||||||
|
|
||||||
//usermods.add(new UsermodRenameMe());
|
//usermods.add(new UsermodRenameMe());
|
||||||
}
|
}
|
@ -10,7 +10,9 @@
|
|||||||
* \/ \/ \/
|
* \/ \/ \/
|
||||||
*/
|
*/
|
||||||
//#include "usermod_v2_example.h"
|
//#include "usermod_v2_example.h"
|
||||||
//#include "usermod_temperature.h"
|
#ifdef USERMOD_DALLASTEMPERATURE
|
||||||
|
#include "../usermods/Temperature/usermod_temperature.h"
|
||||||
|
#endif
|
||||||
//#include "usermod_v2_empty.h"
|
//#include "usermod_v2_empty.h"
|
||||||
|
|
||||||
void registerUsermods()
|
void registerUsermods()
|
||||||
@ -21,6 +23,8 @@ void registerUsermods()
|
|||||||
* \/ \/ \/
|
* \/ \/ \/
|
||||||
*/
|
*/
|
||||||
//usermods.add(new MyExampleUsermod());
|
//usermods.add(new MyExampleUsermod());
|
||||||
//usermods.add(new UsermodTemperature());
|
#ifdef USERMOD_DALLASTEMPERATURE
|
||||||
|
usermods.add(new UsermodTemperature());
|
||||||
|
#endif
|
||||||
//usermods.add(new UsermodRenameMe());
|
//usermods.add(new UsermodRenameMe());
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user