a69dcfc49d
Avoid buffer overflows with longer mqtt topics mqtDeviceTopic in wled.h is defined with a size of 33, so this should be set to 45 to accommodate the additional 12 characters - /temperature
174 lines
5.8 KiB
C++
174 lines
5.8 KiB
C++
#pragma once
|
|
|
|
#include "wled.h"
|
|
|
|
#include <DallasTemperature.h> //DS18B20
|
|
|
|
//Pin defaults for QuinLed Dig-Uno
|
|
#ifndef TEMPERATURE_PIN
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
#define TEMPERATURE_PIN 18
|
|
#else //ESP8266 boards
|
|
#define TEMPERATURE_PIN 14
|
|
#endif
|
|
#endif
|
|
|
|
// the frequency to check temperature, 1 minute
|
|
#ifndef USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL
|
|
#define USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL 60000
|
|
#endif
|
|
|
|
// 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);
|
|
DallasTemperature sensor(&oneWire);
|
|
|
|
class UsermodTemperature : public Usermod {
|
|
private:
|
|
// The device's unique 64-bit serial code stored in on-board ROM.
|
|
// Reading directly from the sensor device address is faster than
|
|
// reading from index. When reading by index, DallasTemperature
|
|
// must first look up the device address at the specified index.
|
|
DeviceAddress sensorDeviceAddress;
|
|
// set last reading as "40 sec before boot", so first reading is taken after 20 sec
|
|
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT);
|
|
// last time requestTemperatures was called
|
|
// used to determine when we can read the sensors temperature
|
|
// we have to wait at least 93.75 ms after requestTemperatures() is called
|
|
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() {
|
|
if (strip.isUpdating()) return;
|
|
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
|
|
temperature = sensor.getTempC(sensorDeviceAddress);
|
|
#else
|
|
temperature = sensor.getTempF(sensorDeviceAddress);
|
|
#endif
|
|
|
|
lastMeasurement = millis();
|
|
waitingForConversion = false;
|
|
getTemperatureComplete = true;
|
|
}
|
|
|
|
public:
|
|
|
|
|
|
void setup() {
|
|
sensor.begin();
|
|
|
|
// 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(F("Dallas Temperature found"));
|
|
// set the resolution for this specific device
|
|
sensor.setResolution(sensorDeviceAddress, 9, true);
|
|
// do not block waiting for reading
|
|
sensor.setWaitForConversion(false);
|
|
// allocate pin & prevent other use
|
|
if (!pinManager.allocatePin(TEMPERATURE_PIN,false))
|
|
disabled = true;
|
|
} else {
|
|
DEBUG_PRINTLN(F("Dallas Temperature not found"));
|
|
}
|
|
}
|
|
|
|
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 < USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL) 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) {
|
|
char subuf[45];
|
|
strcpy(subuf, mqttDeviceTopic);
|
|
if (-100 <= temperature) {
|
|
// 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_P(subuf, PSTR("/temperature"));
|
|
mqtt->publish(subuf, 0, true, String(temperature).c_str());
|
|
} else {
|
|
// publish something else to indicate status?
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void addToJsonInfo(JsonObject& root) {
|
|
// dont add temperature to info if we are disabled
|
|
if (disabled) return;
|
|
|
|
JsonObject user = root[F("u")];
|
|
if (user.isNull()) user = root.createNestedObject(F("u"));
|
|
|
|
JsonArray temp = user.createNestedArray(F("Temperature"));
|
|
|
|
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(F(" sec until read"));
|
|
return;
|
|
}
|
|
|
|
if (temperature <= -100) {
|
|
temp.add(0);
|
|
temp.add(F(" Sensor Error!"));
|
|
return;
|
|
}
|
|
|
|
temp.add(temperature);
|
|
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
|
|
temp.add(F("°C"));
|
|
#else
|
|
temp.add(F("°F"));
|
|
#endif
|
|
}
|
|
|
|
uint16_t getId()
|
|
{
|
|
return USERMOD_ID_TEMPERATURE;
|
|
}
|
|
};
|