Usermod settings v2

- added POST field parsing
- simpler handling in readFromConfig()
This commit is contained in:
Blaz Kristan
2021-06-27 15:32:33 +02:00
parent 0ae0f40628
commit 9e8aadb750
12 changed files with 400 additions and 433 deletions

View File

@@ -17,11 +17,6 @@
#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
class UsermodTemperature : public Usermod {
private:
@@ -32,9 +27,12 @@ class UsermodTemperature : public Usermod {
int8_t temperaturePin = TEMPERATURE_PIN;
// measurement unit (true==°C, false==°F)
bool degC = true;
// using parasite power on the sensor
bool parasite = false;
// how often do we read from sensor?
unsigned long readingInterval = USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL;
// 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);
unsigned long lastMeasurement = UINT32_MAX - USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL;
// 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
@@ -42,37 +40,32 @@ class UsermodTemperature : public Usermod {
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 readTemperature call
// allows this library to report to the user how long until the first
// measurement
bool readTemperatureComplete = 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;
bool enabled = true;
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _readInterval[];
static const char _parasite[];
//Dallas sensor quick (& dirty) reading. Credit to - Author: Peter Scargill, August 17th, 2013
int16_t readDallas() {
float readDallas() {
byte i;
byte data[2];
int16_t result; // raw data from sensor
oneWire->reset();
oneWire->write(0xCC); // skip ROM
oneWire->write(0xBE); // read (temperature) from EEPROM
int16_t result; // raw data from sensor
if (!oneWire->reset()) return -127.0f; // send reset command and fail fast
oneWire->skip(); // skip ROM
oneWire->write(0xBE); // read (temperature) from EEPROM
for (i=0; i < 2; i++) data[i] = oneWire->read(); // first 2 bytes contain temperature
for (i=2; i < 8; i++) oneWire->read(); // read unused bytes
result = (data[1]<<8) | data[0];
result >>= 4; // 9-bit precision accurate to 1°C (/16)
if (data[1]&0x80) result |= 0xF000; // fix negative value
//if (data[0]&0x08) ++result;
result = (data[1]<<4) | (data[0]>>4); // we only need whole part, we will add fraction when returning
if (data[1]&0x80) result |= 0xFF00; // fix negative value
oneWire->reset();
oneWire->write(0xCC); // skip ROM
oneWire->write(0x44,0); // request new temperature reading (without parasite power)
return result;
oneWire->skip(); // skip ROM
oneWire->write(0x44,parasite); // request new temperature reading (without parasite power)
return (float)result + ((data[0]&0x0008) ? 0.5f : 0.0f);
}
void requestTemperatures() {
@@ -86,7 +79,6 @@ class UsermodTemperature : public Usermod {
temperature = readDallas();
lastMeasurement = millis();
waitingForConversion = false;
readTemperatureComplete = true;
DEBUG_PRINTF("Read temperature %2.1f.\n", temperature);
}
@@ -118,23 +110,23 @@ class UsermodTemperature : public Usermod {
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
if (!pinManager.allocatePin(temperaturePin,false)) {
temperaturePin = -1; // allocation failed
disabled = true;
enabled = false;
DEBUG_PRINTLN(F("Temperature pin allocation failed."));
} else {
if (!disabled) {
if (enabled) {
// config says we are enabled
oneWire = new OneWire(temperaturePin);
if (!oneWire->reset())
disabled = true; // resetting 1-Wire bus yielded an error
enabled = false; // resetting 1-Wire bus yielded an error
else
while ((disabled=!findSensor()) && retries--) delay(25); // try to find sensor
while ((enabled=findSensor()) && retries--) delay(25); // try to find sensor
}
}
initDone = true;
}
void loop() {
if (disabled || strip.isUpdating()) return;
if (!enabled || strip.isUpdating()) return;
unsigned long now = millis();
@@ -189,7 +181,7 @@ class UsermodTemperature : public Usermod {
*/
void addToJsonInfo(JsonObject& root) {
// dont add temperature to info if we are disabled
if (disabled) return;
if (!enabled) return;
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
@@ -197,14 +189,6 @@ class UsermodTemperature : public Usermod {
JsonArray temp = user.createNestedArray(FPSTR(_name));
//temp.add(F("Loaded."));
if (!readTemperatureComplete) {
// 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!"));
@@ -239,51 +223,44 @@ class UsermodTemperature : public Usermod {
void addToConfig(JsonObject &root) {
// we add JSON object: {"Temperature": {"pin": 0, "degC": true}}
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
top[FPSTR(_enabled)] = !disabled;
top[FPSTR(_enabled)] = enabled;
top["pin"] = temperaturePin; // usermodparam
top["degC"] = degC; // usermodparam
top[FPSTR(_readInterval)] = readingInterval / 1000;
top[FPSTR(_parasite)] = parasite;
DEBUG_PRINTLN(F("Temperature config saved."));
}
/**
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
*
* The function should return true if configuration was successfully loaded or false if there was no configuration.
*/
bool readFromConfig(JsonObject &root) {
// we look for JSON object: {"Temperature": {"pin": 0, "degC": true}}
JsonObject top = root[FPSTR(_name)];
int8_t newTemperaturePin = temperaturePin;
bool configComplete = true;
if (!top.isNull() && top["pin"] != nullptr) {
if (top[FPSTR(_enabled)].is<bool>()) {
disabled = !top[FPSTR(_enabled)].as<bool>();
} else {
String str = top[FPSTR(_enabled)]; // checkbox -> off or on
disabled = (bool)(str=="off"); // off is guaranteed to be present
}
newTemperaturePin = min(39,max(-1,top["pin"].as<int>()));
if (top["degC"].is<bool>()) {
// reading from cfg.json
degC = top["degC"].as<bool>();
} else {
// new configuration from set.cpp
String str = top["degC"]; // checkbox -> off or on
degC = (bool)(str!="off"); // off is guaranteed to be present
}
readingInterval = min(120,max(10,top[FPSTR(_readInterval)].as<int>())) * 1000; // convert to ms
DEBUG_PRINTLN(F("Temperature config (re)loaded."));
} else {
DEBUG_PRINTLN(F("No config found. (Using defaults.)"));
configComplete = false;
JsonObject top = root[FPSTR(_name)];
if (top.isNull()) {
DEBUG_PRINT(FPSTR(_name));
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
return false;
}
enabled = top[FPSTR(_enabled)] | enabled;
newTemperaturePin = top["pin"] | newTemperaturePin;
degC = top["degC"] | degC;
readingInterval = top[FPSTR(_readInterval)] | readingInterval/1000;
readingInterval = min(120,max(10,(int)readingInterval)) * 1000; // convert to ms
parasite = top[FPSTR(_parasite)] | parasite;
DEBUG_PRINT(FPSTR(_name));
if (!initDone) {
// first run: reading from cfg.json
temperaturePin = newTemperaturePin;
DEBUG_PRINTLN(F(" config loaded."));
} else {
// changing parameters from settings page
// changing paramters from settings page
if (newTemperaturePin != temperaturePin) {
// deallocate pin and release memory
delete oneWire;
@@ -292,8 +269,10 @@ class UsermodTemperature : public Usermod {
// initialise
setup();
}
DEBUG_PRINTLN(F(" config (re)loaded."));
}
return configComplete;
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
return !top[FPSTR(_parasite)].isNull();
}
uint16_t getId()
@@ -305,4 +284,5 @@ class UsermodTemperature : public Usermod {
// strings to reduce flash memory usage (used more than twice)
const char UsermodTemperature::_name[] PROGMEM = "Temperature";
const char UsermodTemperature::_enabled[] PROGMEM = "enabled";
const char UsermodTemperature::_readInterval[] PROGMEM = "read-interval-s";
const char UsermodTemperature::_readInterval[] PROGMEM = "read-interval-s";
const char UsermodTemperature::_parasite[] PROGMEM = "parasite-pwr";