Applied precommit cpp checks

This commit is contained in:
Magnus Persson 2022-01-07 10:13:08 +01:00
parent 88bd971b73
commit ed53182c29
22 changed files with 3780 additions and 3439 deletions

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,20 +21,21 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "src/calc.h"
#include <tinyexpr.h>
#include <config.h>
#include <curveFitting.h>
#include "src/helper.h"
#include "src/config.h"
#include "src/tempsensor.h"
#include <tinyexpr.h>
#include <calc.hpp>
#include <helper.hpp>
#include <tempsensor.hpp>
#define FORMULA_MAX_DEVIATION 1.5
//
// Use values to derive a formula
//
int createFormula(RawFormulaData& fd, char *formulaBuffer, int formulaBufferSize, int order) {
int createFormula(RawFormulaData &fd, char *formulaBuffer,
int formulaBufferSize, int order) {
int noAngles = 0;
// Check how many valid values we have got
@ -46,33 +47,40 @@ int createFormula(RawFormulaData& fd, char *formulaBuffer, int formulaBufferSize
noAngles = 3;
#if LOG_LEVEL == 6
Log.verbose(F("CALC: Trying to create formula using order = %d, found %d angles" CR), order, noAngles);
Log.verbose(
F("CALC: Trying to create formula using order = %d, found %d angles" CR),
order, noAngles);
#endif
if (!noAngles) {
Log.error(F("CALC: Not enough values for deriving formula" CR));
return ERR_FORMULA_NOTENOUGHVALUES;
} else {
double coeffs[order + 1];
int ret = fitCurve(order, noAngles, fd.a, fd.g, sizeof(coeffs)/sizeof(double), coeffs);
int ret = fitCurve(order, noAngles, fd.a, fd.g,
sizeof(coeffs) / sizeof(double), coeffs);
// Returned value is 0 if no error
if (ret == 0) {
#if LOG_LEVEL == 6
Log.verbose(F("CALC: Finshied processing data points." CR));
#endif
// Print the formula based on 'order'
if (order == 4) {
snprintf(formulaBuffer, formulaBufferSize, "%.8f*tilt^4+%.8f*tilt^3+%.8f*tilt^2+%.8f*tilt+%.8f", coeffs[0], coeffs[1], coeffs[2], coeffs[3], coeffs[4]);
snprintf(formulaBuffer, formulaBufferSize,
"%.8f*tilt^4+%.8f*tilt^3+%.8f*tilt^2+%.8f*tilt+%.8f",
coeffs[0], coeffs[1], coeffs[2], coeffs[3], coeffs[4]);
} else if (order == 3) {
snprintf(formulaBuffer, formulaBufferSize, "%.8f*tilt^3+%.8f*tilt^2+%.8f*tilt+%.8f", coeffs[0], coeffs[1], coeffs[2], coeffs[3]);
snprintf(formulaBuffer, formulaBufferSize,
"%.8f*tilt^3+%.8f*tilt^2+%.8f*tilt+%.8f", coeffs[0], coeffs[1],
coeffs[2], coeffs[3]);
} else if (order == 2) {
snprintf(formulaBuffer, formulaBufferSize, "%.8f*tilt^2+%.8f*tilt+%.8f", coeffs[0], coeffs[1], coeffs[2]);
snprintf(formulaBuffer, formulaBufferSize, "%.8f*tilt^2+%.8f*tilt+%.8f",
coeffs[0], coeffs[1], coeffs[2]);
} else { // order == 1
snprintf(formulaBuffer, formulaBufferSize, "%.8f*tilt+%.8f", coeffs[0], coeffs[1]);
snprintf(formulaBuffer, formulaBufferSize, "%.8f*tilt+%.8f", coeffs[0],
coeffs[1]);
}
#if LOG_LEVEL == 6
@ -82,15 +90,13 @@ int createFormula(RawFormulaData& fd, char *formulaBuffer, int formulaBufferSize
bool valid = true;
for (int i = 0; i < 5; i++) {
if ( fd.a[i] == 0 && valid )
break;
if (fd.a[i] == 0 && valid) break;
double g = calculateGravity(fd.a[i], 0, formulaBuffer);
double dev = (g - fd.g[i]) < 0 ? (fd.g[i] - g) : (g - fd.g[i]);
// If the deviation is more than 2 degress we mark it as failed.
if ( dev*1000 > FORMULA_MAX_DEVIATION )
valid = false;
if (dev * 1000 > FORMULA_MAX_DEVIATION) valid = false;
}
if (!valid) {
@ -108,7 +114,8 @@ int createFormula(RawFormulaData& fd, char *formulaBuffer, int formulaBufferSize
}
//
// Calculates gravity according to supplied formula, compatible with iSpindle/Fermentrack formula
// Calculates gravity according to supplied formula, compatible with
// iSpindle/Fermentrack formula
//
double calculateGravity(double angle, double temp, const char *tempFormula) {
const char *formula = myConfig.getGravityFormula();
@ -121,12 +128,12 @@ double calculateGravity(double angle, double temp, const char *tempFormula) {
}
#if LOG_LEVEL == 6
Log.verbose(F("CALC: Calculating gravity for angle %F, temp %F." CR), angle, temp);
Log.verbose(F("CALC: Calculating gravity for angle %F, temp %F." CR), angle,
temp);
Log.verbose(F("CALC: Formula %s." CR), formula);
#endif
if ( strlen(formula) == 0 )
return 0.0;
if (strlen(formula) == 0) return 0.0;
// Store variable names and pointers.
te_variable vars[] = {{"tilt", &angle}, {"temp", &temp}};
@ -150,20 +157,28 @@ double calculateGravity(double angle, double temp, const char *tempFormula) {
}
//
// Do a standard gravity temperature correction. This is a simple way to adjust for differnt worth temperatures
// Do a standard gravity temperature correction. This is a simple way to adjust
// for differnt worth temperatures
//
double gravityTemperatureCorrection(double gravity, double temp, char tempFormat, double calTemp) {
double gravityTemperatureCorrection(double gravity, double temp,
char tempFormat, double calTemp) {
#if LOG_LEVEL == 6
Log.verbose(F("CALC: Adjusting gravity based on temperature, gravity %F, temp %F, calTemp %F." CR), gravity, temp, calTemp);
Log.verbose(F("CALC: Adjusting gravity based on temperature, gravity %F, "
"temp %F, calTemp %F." CR),
gravity, temp, calTemp);
#endif
if ( tempFormat == 'C')
temp = convertCtoF(temp);
if (tempFormat == 'C') temp = convertCtoF(temp);
double calTempF = convertCtoF(calTemp); // calTemp is in C
const char* formula = "gravity*((1.00130346-0.000134722124*temp+0.00000204052596*temp^2-0.00000000232820948*temp^3)/(1.00130346-0.000134722124*cal+0.00000204052596*cal^2-0.00000000232820948*cal^3))";
const char *formula =
"gravity*((1.00130346-0.000134722124*temp+0.00000204052596*temp^2-0."
"00000000232820948*temp^3)/"
"(1.00130346-0.000134722124*cal+0.00000204052596*cal^2-0."
"00000000232820948*cal^3))";
// Store variable names and pointers.
te_variable vars[] = {{"gravity", &gravity}, {"temp", &temp}, {"cal", &calTempF}};
te_variable vars[] = {
{"gravity", &gravity}, {"temp", &temp}, {"cal", &calTempF}};
int err;
// Compile the expression with variables.
@ -179,7 +194,9 @@ double gravityTemperatureCorrection(double gravity, double temp, char tempFormat
return g;
}
Log.error(F("CALC: Failed to parse expression %d, no correction has been made." CR), err);
Log.error(
F("CALC: Failed to parse expression %d, no correction has been made." CR),
err);
return gravity;
}

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,12 +21,12 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef SRC_CALC_H_
#define SRC_CALC_H_
#ifndef SRC_CALC_HPP_
#define SRC_CALC_HPP_
// Includes
#include "src/helper.h"
#include "src/config.h"
#include <config.hpp>
#include <helper.hpp>
#define ERR_FORMULA_NOTENOUGHVALUES -1
#define ERR_FORMULA_INTERNAL -2
@ -34,9 +34,11 @@ SOFTWARE.
// Functions
double calculateGravity(double angle, double temp, const char *tempFormula = 0);
double gravityTemperatureCorrection(double gravity, double temp, char tempFormat, double calTemp = 20);
int createFormula(RawFormulaData& fd, char *formulaBuffer, int formulaBufferSize, int order);
double gravityTemperatureCorrection(double gravity, double temp,
char tempFormat, double calTemp = 20);
int createFormula(RawFormulaData &fd, char *formulaBuffer,
int formulaBufferSize, int order);
#endif // SRC_CALC_H_
#endif // SRC_CALC_HPP_
// EOF

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,10 +21,11 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "src/config.h"
#include "src/helper.h"
#include <LittleFS.h>
#include <config.hpp>
#include <helper.hpp>
Config myConfig;
//
@ -33,13 +34,14 @@ Config myConfig;
Config::Config() {
// Assiging default values
char buf[30];
snprintf(&buf[0], sizeof(buf) "%6x", (unsigned int) ESP.getChipId());
snprintf(&buf[0], sizeof(buf), "%6x", (unsigned int)ESP.getChipId());
id = String(&buf[0]);
snprintf(&buf[0], sizeof(buf), "" WIFI_MDNS "%s", getID());
mDNS = String(&buf[0]);
#if LOG_LEVEL == 6 && !defined(CFG_DISABLE_LOGGING)
Log.verbose(F("CFG : Created config for %s (%s)." CR), id.c_str(), mDNS.c_str() );
Log.verbose(F("CFG : Created config for %s (%s)." CR), id.c_str(),
mDNS.c_str());
#endif
setTempFormat('C');
@ -54,7 +56,8 @@ Config::Config() {
}
//
// Populate the json document with all configuration parameters (used in both web and saving to file)
// Populate the json document with all configuration parameters (used in both
// web and saving to file)
//
void Config::createJson(DynamicJsonDocument& doc) {
doc[CFG_PARAM_MDNS] = getMDNS();
@ -71,7 +74,8 @@ void Config::createJson(DynamicJsonDocument& doc) {
doc[CFG_PARAM_PUSH_INFLUXDB2_BUCKET] = getInfluxDb2PushBucket();
doc[CFG_PARAM_PUSH_INFLUXDB2_AUTH] = getInfluxDb2PushToken();
doc[CFG_PARAM_SLEEP_INTERVAL] = getSleepInterval();
// doc[ CFG_PARAM_PUSH_INTERVAL ] = getSleepInterval(); // TODO: @deprecated
// doc[ CFG_PARAM_PUSH_INTERVAL ] = getSleepInterval(); //
// TODO: @deprecated
doc[CFG_PARAM_VOLTAGEFACTOR] = getVoltageFactor();
doc[CFG_PARAM_GRAVITY_FORMULA] = getGravityFormula();
doc[CFG_PARAM_GRAVITY_FORMAT] = String(getGravityFormat());
@ -149,7 +153,8 @@ bool Config::loadFile() {
#endif
if (!LittleFS.exists(CFG_FILENAME)) {
Log.error(F("CFG : Configuration file does not exist " CFG_FILENAME "." CR));
Log.error(
F("CFG : Configuration file does not exist " CFG_FILENAME "." CR));
return false;
}
@ -160,7 +165,8 @@ bool Config::loadFile() {
return false;
}
Log.notice(F("CFG : Size of configuration file=%d bytes." CR), configFile.size() );
Log.notice(F("CFG : Size of configuration file=%d bytes." CR),
configFile.size());
DynamicJsonDocument doc(CFG_JSON_BUFSIZE);
DeserializationError err = deserializeJson(doc, configFile);
@ -171,21 +177,18 @@ bool Config::loadFile() {
configFile.close();
if (err) {
Log.error(F("CFG : Failed to parse " CFG_FILENAME " file, Err: %s, %d." CR), err.c_str(), doc.capacity());
Log.error(F("CFG : Failed to parse " CFG_FILENAME " file, Err: %s, %d." CR),
err.c_str(), doc.capacity());
return false;
}
#if LOG_LEVEL == 6
Log.verbose(F("CFG : Parsed configuration file." CR));
#endif
if ( !doc[ CFG_PARAM_OTA ].isNull() )
setOtaURL(doc[ CFG_PARAM_OTA ]);
if ( !doc[ CFG_PARAM_MDNS ].isNull() )
setMDNS(doc[ CFG_PARAM_MDNS ] );
if ( !doc[ CFG_PARAM_SSID ].isNull() )
setWifiSSID(doc[ CFG_PARAM_SSID ]);
if ( !doc[ CFG_PARAM_PASS ].isNull() )
setWifiPass(doc[ CFG_PARAM_PASS ]);
if (!doc[CFG_PARAM_OTA].isNull()) setOtaURL(doc[CFG_PARAM_OTA]);
if (!doc[CFG_PARAM_MDNS].isNull()) setMDNS(doc[CFG_PARAM_MDNS]);
if (!doc[CFG_PARAM_SSID].isNull()) setWifiSSID(doc[CFG_PARAM_SSID]);
if (!doc[CFG_PARAM_PASS].isNull()) setWifiPass(doc[CFG_PARAM_PASS]);
if (!doc[CFG_PARAM_TEMPFORMAT].isNull()) {
String s = doc[CFG_PARAM_TEMPFORMAT];
setTempFormat(s.charAt(0));
@ -207,7 +210,8 @@ bool Config::loadFile() {
if (!doc[CFG_PARAM_SLEEP_INTERVAL].isNull())
setSleepInterval(doc[CFG_PARAM_SLEEP_INTERVAL].as<int>());
if (!doc[CFG_PARAM_PUSH_INTERVAL].isNull()) // TODO: @deprecated
setSleepInterval(doc[ CFG_PARAM_PUSH_INTERVAL ].as<int>()); // TODO: @deprecated
setSleepInterval(
doc[CFG_PARAM_PUSH_INTERVAL].as<int>()); // TODO: @deprecated
if (!doc[CFG_PARAM_VOLTAGEFACTOR].isNull())
setVoltageFactor(doc[CFG_PARAM_VOLTAGEFACTOR].as<float>());
if (!doc[CFG_PARAM_GRAVITY_FORMULA].isNull())
@ -302,14 +306,18 @@ void Config::debug() {
Log.verbose(F("CFG : VoltageFactor; %F." CR), getVoltageFactor());
Log.verbose(F("CFG : Gravity formula; '%s'." CR), getGravityFormula());
Log.verbose(F("CFG : Gravity format; '%c'." CR), getGravityFormat());
Log.verbose(F("CFG : Gravity temp adj; %s." CR), isGravityTempAdj()?"true":"false" );
Log.verbose(F("CFG : Gravity temp adj; %s." CR),
isGravityTempAdj() ? "true" : "false");
Log.verbose(F("CFG : Push brewfather; '%s'." CR), getBrewfatherPushUrl());
Log.verbose(F("CFG : Push http; '%s'." CR), getHttpPushUrl());
Log.verbose(F("CFG : Push http2; '%s'." CR), getHttpPushUrl2());
Log.verbose(F("CFG : InfluxDb2; '%s', '%s', '%s', '%s'." CR), getInfluxDb2PushUrl(), getInfluxDb2PushOrg(),
Log.verbose(F("CFG : InfluxDb2; '%s', '%s', '%s', '%s'." CR),
getInfluxDb2PushUrl(), getInfluxDb2PushOrg(),
getInfluxDb2PushBucket(), getInfluxDb2PushToken());
// Log.verbose(F("CFG : Accel offset\t%d\t%d\t%d" CR), gyroCalibration.ax, gyroCalibration.ay, gyroCalibration.az );
// Log.verbose(F("CFG : Gyro offset \t%d\t%d\t%d" CR), gyroCalibration.gx, gyroCalibration.gy, gyroCalibration.gz );
// Log.verbose(F("CFG : Accel offset\t%d\t%d\t%d" CR), gyroCalibration.ax,
// gyroCalibration.ay, gyroCalibration.az ); Log.verbose(F("CFG : Gyro offset
// \t%d\t%d\t%d" CR), gyroCalibration.gx, gyroCalibration.gy,
// gyroCalibration.gz );
#endif
}

View File

@ -1,230 +0,0 @@
/*
MIT License
Copyright (c) 2021 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef SRC_CONFIG_H_
#define SRC_CONFIG_H_
// Includes
#include <stdlib.h>
#include "src/helper.h"
#include <Arduino.h>
#include <ArduinoJson.h>
// defintions
#define CFG_JSON_BUFSIZE 3192
#define CFG_APPNAME "GravityMon " // Name of firmware
#define CFG_FILENAME "/gravitymon.json" // Name of config file
#define WIFI_DEFAULT_SSID "GravityMon" // Name of created SSID
#define WIFI_DEFAULT_PWD "password" // Password for created SSID
#define WIFI_MDNS "gravitymon" // Prefix for MDNS name
#define WIFI_PORTAL_TIMEOUT 120 // Number of seconds until the config portal is closed
// These are used in API + Savefile
#define CFG_PARAM_ID "id"
#define CFG_PARAM_MDNS "mdns" // Device name
#define CFG_PARAM_OTA "ota-url" // Base URL for OTA
#define CFG_PARAM_SSID "wifi-ssid" // WIFI
#define CFG_PARAM_PASS "wifi-pass" // WIFI
#define CFG_PARAM_PUSH_BREWFATHER "brewfather-push" // URL (brewfather format)
#define CFG_PARAM_PUSH_HTTP "http-push" // URL (iSpindle format)
#define CFG_PARAM_PUSH_HTTP2 "http-push2" // URL (iSpindle format)
#define CFG_PARAM_PUSH_INFLUXDB2 "influxdb2-push" // URL
#define CFG_PARAM_PUSH_INFLUXDB2_ORG "influxdb2-org" // URL
#define CFG_PARAM_PUSH_INFLUXDB2_BUCKET "influxdb2-bucket" // URL
#define CFG_PARAM_PUSH_INFLUXDB2_AUTH "influxdb2-auth" // URL
#define CFG_PARAM_SLEEP_INTERVAL "sleep-interval" // Sleep interval
// TODO: @deprecated setting
#define CFG_PARAM_PUSH_INTERVAL "push-interval" // Time between push
#define CFG_PARAM_TEMPFORMAT "temp-format" // C or F
#define CFG_PARAM_VOLTAGEFACTOR "voltage-factor" // Factor to calculate the battery voltage
#define CFG_PARAM_GRAVITY_FORMULA "gravity-formula" // Formula for calculating gravity
#define CFG_PARAM_GRAVITY_FORMAT "gravity-format" // Gravity format G or P
#define CFG_PARAM_GRAVITY_TEMP_ADJ "gravity-temp-adjustment" // True/False. Adjust gravity for temperature
#define CFG_PARAM_TEMP_ADJ "temp-adjustment-value" // Correction value for temp sensor
#define CFG_PARAM_GYRO_CALIBRATION "gyro-calibration-data" // READ ONLY
#define CFG_PARAM_FORMULA_DATA "formula-calculation-data" // Raw data for the formula calculation
// These are used in API's
#define CFG_PARAM_APP_NAME "app-name"
#define CFG_PARAM_APP_VER "app-ver"
#define CFG_PARAM_ANGLE "angle"
#define CFG_PARAM_GRAVITY "gravity"
#define CFG_PARAM_TEMP_C "temp-c"
#define CFG_PARAM_TEMP_F "temp-f"
#define CFG_PARAM_BATTERY "battery"
#define CFG_PARAM_SLEEP_MODE "sleep-mode"
#define CFG_PARAM_RSSI "rssi"
// Used for holding sensordata or sensoroffsets
struct RawGyroData {
int16_t ax; // Raw Acceleration
int16_t ay;
int16_t az;
int16_t gx; // Raw Position
int16_t gy;
int16_t gz;
int16_t temp; // Only for information (temperature of chip)
};
// Used for holding formulaData (used for calculating formula on device)
struct RawFormulaData {
double a[5];
double g[5];
};
// Main configuration class
class Config {
private:
bool saveNeeded;
// Device configuration
String id;
String mDNS;
String otaURL;
char tempFormat; // C, F
float voltageFactor;
float tempSensorAdj; // This value will be added to the read sensor value
int sleepInterval;
// Wifi Config
String wifiSSID;
String wifiPASS;
// Push target settings
String brewfatherPushUrl; // URL For brewfather
String httpPushUrl; // URL 1 for standard http
String httpPushUrl2; // URL 2 for standard http
String influxDb2Url; // URL for InfluxDB v2
String influxDb2Org; // Organisation for InfluxDB v2
String influxDb2Bucket; // Bucket for InfluxDB v2
String influxDb2Token; // Auth Token for InfluxDB v2
// Gravity and temperature calculations
String gravityFormula;
bool gravityTempAdj; // true, false
char gravityFormat; // G, P
// Gyro calibration data
RawGyroData gyroCalibration; // Holds the gyro calibration constants (6 * int16_t)
RawFormulaData formulaData; // Used for creating formula
void debug();
void formatFileSystem();
public:
Config();
const char* getID() { return id.c_str(); }
const char* getMDNS() { return mDNS.c_str(); }
void setMDNS(String s) { mDNS = s; saveNeeded = true; }
const char* getOtaURL() { return otaURL.c_str(); }
void setOtaURL(String s) { otaURL = s; saveNeeded = true; }
bool isOtaActive() { return otaURL.length() ? true : false; }
const char* getWifiSSID() { return wifiSSID.c_str(); }
void setWifiSSID(String s) { wifiSSID = s; saveNeeded = true; }
const char* getWifiPass() { return wifiPASS.c_str(); }
void setWifiPass(String s) { wifiPASS = s; saveNeeded = true; }
// Brewfather
const char* getBrewfatherPushUrl() { return brewfatherPushUrl.c_str(); }
void setBrewfatherPushUrl(String s) { brewfatherPushUrl = s; saveNeeded = true; }
bool isBrewfatherActive() { return brewfatherPushUrl.length()?true:false; }
// Standard HTTP
const char* getHttpPushUrl() { return httpPushUrl.c_str(); }
void setHttpPushUrl(String s) { httpPushUrl = s; saveNeeded = true; }
bool isHttpActive() { return httpPushUrl.length()?true:false; }
const char* getHttpPushUrl2() { return httpPushUrl2.c_str(); }
void setHttpPushUrl2(String s) { httpPushUrl2 = s; saveNeeded = true; }
bool isHttpActive2() { return httpPushUrl2.length()?true:false; }
// InfluxDB2
const char* getInfluxDb2PushUrl() { return influxDb2Url.c_str(); }
void setInfluxDb2PushUrl(String s) { influxDb2Url = s; saveNeeded = true; }
bool isInfluxDb2Active() { return influxDb2Url.length()?true:false; }
const char* getInfluxDb2PushOrg() { return influxDb2Org.c_str(); }
void setInfluxDb2PushOrg(String s) { influxDb2Org = s; saveNeeded = true; }
const char* getInfluxDb2PushBucket() { return influxDb2Bucket.c_str(); }
void setInfluxDb2PushBucket(String s) { influxDb2Bucket = s; saveNeeded = true; }
const char* getInfluxDb2PushToken() { return influxDb2Token.c_str(); }
void setInfluxDb2PushToken(String s) { influxDb2Token = s; saveNeeded = true; }
int getSleepInterval() { return sleepInterval; }
void setSleepInterval(int v) { sleepInterval = v; saveNeeded = true; }
void setSleepInterval(String s) { sleepInterval = s.toInt(); saveNeeded = true; }
char getTempFormat() { return tempFormat; }
void setTempFormat(char c) { tempFormat = c; saveNeeded = true; }
bool isTempC() { return tempFormat == 'C' ? false : true; }
bool isTempF() { return tempFormat == 'F' ? false : true; }
float getVoltageFactor() { return voltageFactor; }
void setVoltageFactor(float f) { voltageFactor = f; saveNeeded = true; }
void setVoltageFactor(String s) { voltageFactor = s.toFloat(); saveNeeded = true; }
float getTempSensorAdj() { return tempSensorAdj; }
void setTempSensorAdj(float f) { tempSensorAdj = f; saveNeeded = true; }
void setTempSensorAdj(String s) { tempSensorAdj = s.toFloat(); saveNeeded = true; }
const char* getGravityFormula() { return gravityFormula.c_str(); }
void setGravityFormula(String s) { gravityFormula = s; saveNeeded = true; }
bool isGravityTempAdj() { return gravityTempAdj; }
void setGravityTempAdj(bool b) { gravityTempAdj = b; saveNeeded = true; }
char getGravityFormat() { return gravityFormat; }
void setGravityFormat(char c) { gravityFormat = c; saveNeeded = true; }
bool isGravitySG() { return gravityFormat == 'G' ? false : true; }
bool isGravityPlato() { return gravityFormat == 'P' ? false : true; }
const RawGyroData& getGyroCalibration() { return gyroCalibration; }
void setGyroCalibration(const RawGyroData &r) { gyroCalibration = r; saveNeeded = true; }
const RawFormulaData& getFormulaData() { return formulaData; }
void setFormulaData(const RawFormulaData &r) { formulaData = r; saveNeeded = true; }
// IO functions
void createJson(DynamicJsonDocument& doc);
bool saveFile();
bool loadFile();
void checkFileSystem();
bool isSaveNeeded() { return saveNeeded; }
void setSaveNeeded() { saveNeeded = true; }
};
// Global instance created
extern Config myConfig;
#endif // SRC_CONFIG_H_
// EOF

309
src/config.hpp Normal file
View File

@ -0,0 +1,309 @@
/*
MIT License
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef SRC_CONFIG_HPP_
#define SRC_CONFIG_HPP_
// Includes
#include <Arduino.h>
#include <ArduinoJson.h>
#include <stdlib.h>
#include <helper.hpp>
// defintions
#define CFG_JSON_BUFSIZE 3192
#define CFG_APPNAME "GravityMon " // Name of firmware
#define CFG_FILENAME "/gravitymon.json" // Name of config file
#define WIFI_DEFAULT_SSID "GravityMon" // Name of created SSID
#define WIFI_DEFAULT_PWD "password" // Password for created SSID
#define WIFI_MDNS "gravitymon" // Prefix for MDNS name
#define WIFI_PORTAL_TIMEOUT \
120 // Number of seconds until the config portal is closed
// These are used in API + Savefile
#define CFG_PARAM_ID "id"
#define CFG_PARAM_MDNS "mdns" // Device name
#define CFG_PARAM_OTA "ota-url" // Base URL for OTA
#define CFG_PARAM_SSID "wifi-ssid" // WIFI
#define CFG_PARAM_PASS "wifi-pass" // WIFI
#define CFG_PARAM_PUSH_BREWFATHER "brewfather-push" // URL (brewfather format)
#define CFG_PARAM_PUSH_HTTP "http-push" // URL (iSpindle format)
#define CFG_PARAM_PUSH_HTTP2 "http-push2" // URL (iSpindle format)
#define CFG_PARAM_PUSH_INFLUXDB2 "influxdb2-push" // URL
#define CFG_PARAM_PUSH_INFLUXDB2_ORG "influxdb2-org" // URL
#define CFG_PARAM_PUSH_INFLUXDB2_BUCKET "influxdb2-bucket" // URL
#define CFG_PARAM_PUSH_INFLUXDB2_AUTH "influxdb2-auth" // URL
#define CFG_PARAM_SLEEP_INTERVAL "sleep-interval" // Sleep interval
// TODO: @deprecated setting
#define CFG_PARAM_PUSH_INTERVAL "push-interval" // Time between push
#define CFG_PARAM_TEMPFORMAT "temp-format" // C or F
#define CFG_PARAM_VOLTAGEFACTOR \
"voltage-factor" // Factor to calculate the battery voltage
#define CFG_PARAM_GRAVITY_FORMULA \
"gravity-formula" // Formula for calculating gravity
#define CFG_PARAM_GRAVITY_FORMAT "gravity-format" // Gravity format G or P
#define CFG_PARAM_GRAVITY_TEMP_ADJ \
"gravity-temp-adjustment" // True/False. Adjust gravity for temperature
#define CFG_PARAM_TEMP_ADJ \
"temp-adjustment-value" // Correction value for temp sensor
#define CFG_PARAM_GYRO_CALIBRATION "gyro-calibration-data" // READ ONLY
#define CFG_PARAM_FORMULA_DATA \
"formula-calculation-data" // Raw data for the formula calculation
// These are used in API's
#define CFG_PARAM_APP_NAME "app-name"
#define CFG_PARAM_APP_VER "app-ver"
#define CFG_PARAM_ANGLE "angle"
#define CFG_PARAM_GRAVITY "gravity"
#define CFG_PARAM_TEMP_C "temp-c"
#define CFG_PARAM_TEMP_F "temp-f"
#define CFG_PARAM_BATTERY "battery"
#define CFG_PARAM_SLEEP_MODE "sleep-mode"
#define CFG_PARAM_RSSI "rssi"
// Used for holding sensordata or sensoroffsets
struct RawGyroData {
int16_t ax; // Raw Acceleration
int16_t ay;
int16_t az;
int16_t gx; // Raw Position
int16_t gy;
int16_t gz;
int16_t temp; // Only for information (temperature of chip)
};
// Used for holding formulaData (used for calculating formula on device)
struct RawFormulaData {
double a[5];
double g[5];
};
// Main configuration class
class Config {
private:
bool saveNeeded;
// Device configuration
String id;
String mDNS;
String otaURL;
char tempFormat; // C, F
float voltageFactor;
float tempSensorAdj; // This value will be added to the read sensor value
int sleepInterval;
// Wifi Config
String wifiSSID;
String wifiPASS;
// Push target settings
String brewfatherPushUrl; // URL For brewfather
String httpPushUrl; // URL 1 for standard http
String httpPushUrl2; // URL 2 for standard http
String influxDb2Url; // URL for InfluxDB v2
String influxDb2Org; // Organisation for InfluxDB v2
String influxDb2Bucket; // Bucket for InfluxDB v2
String influxDb2Token; // Auth Token for InfluxDB v2
// Gravity and temperature calculations
String gravityFormula;
bool gravityTempAdj; // true, false
char gravityFormat; // G, P
// Gyro calibration data
RawGyroData
gyroCalibration; // Holds the gyro calibration constants (6 * int16_t)
RawFormulaData formulaData; // Used for creating formula
void debug();
void formatFileSystem();
public:
Config();
const char* getID() { return id.c_str(); }
const char* getMDNS() { return mDNS.c_str(); }
void setMDNS(String s) {
mDNS = s;
saveNeeded = true;
}
const char* getOtaURL() { return otaURL.c_str(); }
void setOtaURL(String s) {
otaURL = s;
saveNeeded = true;
}
bool isOtaActive() { return otaURL.length() ? true : false; }
const char* getWifiSSID() { return wifiSSID.c_str(); }
void setWifiSSID(String s) {
wifiSSID = s;
saveNeeded = true;
}
const char* getWifiPass() { return wifiPASS.c_str(); }
void setWifiPass(String s) {
wifiPASS = s;
saveNeeded = true;
}
// Brewfather
const char* getBrewfatherPushUrl() { return brewfatherPushUrl.c_str(); }
void setBrewfatherPushUrl(String s) {
brewfatherPushUrl = s;
saveNeeded = true;
}
bool isBrewfatherActive() {
return brewfatherPushUrl.length() ? true : false;
}
// Standard HTTP
const char* getHttpPushUrl() { return httpPushUrl.c_str(); }
void setHttpPushUrl(String s) {
httpPushUrl = s;
saveNeeded = true;
}
bool isHttpActive() { return httpPushUrl.length() ? true : false; }
const char* getHttpPushUrl2() { return httpPushUrl2.c_str(); }
void setHttpPushUrl2(String s) {
httpPushUrl2 = s;
saveNeeded = true;
}
bool isHttpActive2() { return httpPushUrl2.length() ? true : false; }
// InfluxDB2
const char* getInfluxDb2PushUrl() { return influxDb2Url.c_str(); }
void setInfluxDb2PushUrl(String s) {
influxDb2Url = s;
saveNeeded = true;
}
bool isInfluxDb2Active() { return influxDb2Url.length() ? true : false; }
const char* getInfluxDb2PushOrg() { return influxDb2Org.c_str(); }
void setInfluxDb2PushOrg(String s) {
influxDb2Org = s;
saveNeeded = true;
}
const char* getInfluxDb2PushBucket() { return influxDb2Bucket.c_str(); }
void setInfluxDb2PushBucket(String s) {
influxDb2Bucket = s;
saveNeeded = true;
}
const char* getInfluxDb2PushToken() { return influxDb2Token.c_str(); }
void setInfluxDb2PushToken(String s) {
influxDb2Token = s;
saveNeeded = true;
}
int getSleepInterval() { return sleepInterval; }
void setSleepInterval(int v) {
sleepInterval = v;
saveNeeded = true;
}
void setSleepInterval(String s) {
sleepInterval = s.toInt();
saveNeeded = true;
}
char getTempFormat() { return tempFormat; }
void setTempFormat(char c) {
tempFormat = c;
saveNeeded = true;
}
bool isTempC() { return tempFormat == 'C' ? false : true; }
bool isTempF() { return tempFormat == 'F' ? false : true; }
float getVoltageFactor() { return voltageFactor; }
void setVoltageFactor(float f) {
voltageFactor = f;
saveNeeded = true;
}
void setVoltageFactor(String s) {
voltageFactor = s.toFloat();
saveNeeded = true;
}
float getTempSensorAdj() { return tempSensorAdj; }
void setTempSensorAdj(float f) {
tempSensorAdj = f;
saveNeeded = true;
}
void setTempSensorAdj(String s) {
tempSensorAdj = s.toFloat();
saveNeeded = true;
}
const char* getGravityFormula() { return gravityFormula.c_str(); }
void setGravityFormula(String s) {
gravityFormula = s;
saveNeeded = true;
}
bool isGravityTempAdj() { return gravityTempAdj; }
void setGravityTempAdj(bool b) {
gravityTempAdj = b;
saveNeeded = true;
}
char getGravityFormat() { return gravityFormat; }
void setGravityFormat(char c) {
gravityFormat = c;
saveNeeded = true;
}
bool isGravitySG() { return gravityFormat == 'G' ? false : true; }
bool isGravityPlato() { return gravityFormat == 'P' ? false : true; }
const RawGyroData& getGyroCalibration() { return gyroCalibration; }
void setGyroCalibration(const RawGyroData& r) {
gyroCalibration = r;
saveNeeded = true;
}
const RawFormulaData& getFormulaData() { return formulaData; }
void setFormulaData(const RawFormulaData& r) {
formulaData = r;
saveNeeded = true;
}
// IO functions
void createJson(DynamicJsonDocument& doc);
bool saveFile();
bool loadFile();
void checkFileSystem();
bool isSaveNeeded() { return saveNeeded; }
void setSaveNeeded() { saveNeeded = true; }
};
// Global instance created
extern Config myConfig;
#endif // SRC_CONFIG_HPP_
// EOF

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,8 +21,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "gyro.h"
#include "helper.h"
#include <gyro.hpp>
#include <helper.hpp>
GyroSensor myGyro;
@ -31,7 +31,8 @@ GyroSensor myGyro;
#define SENSOR_READ_COUNT 50
#define SENSOR_READ_DELAY 3150 // us, empirical, to hold sampling to 200 Hz
#define GYRO_SHOW_MINMAX // Will calculate the min/max values when doing calibration
#define GYRO_SHOW_MINMAX // Will calculate the min/max values when doing
// calibration
// #define GYRO_CALIBRATE_STARTUP // Will calibrate sensor at startup
//
@ -42,14 +43,14 @@ bool GyroSensor::setup() {
Log.verbose(F("GYRO: Setting up hardware." CR));
#endif
Wire.begin(D3, D4);
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having
// compilation difficulties
accelgyro.initialize();
if (!accelgyro.testConnection()) {
Log.error(F("GYRO: Failed to connect to MPU6050 (gyro)." CR));
sensorConnected = false;
} else {
#if !defined(GYRO_DISABLE_LOGGING)
Log.notice(F("GYRO: Connected to MPU6050 (gyro)." CR));
#endif
@ -57,11 +58,13 @@ bool GyroSensor::setup() {
// Configure the sensor
accelgyro.setTempSensorEnabled(true);
//accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_2); // Set in .initalize()
//accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_250); // Set in .initalize()
// accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_2); // Set in
// .initalize() accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_250); //
// Set in .initalize()
accelgyro.setDLPFMode(MPU6050_DLPF_BW_5);
#if defined(GYRO_USE_INTERRUPT)
// Alternative method to read data, let the MPU signal when sampling is done.
// Alternative method to read data, let the MPU signal when sampling is
// done.
accelgyro.setRate(17);
accelgyro.setInterruptDrive(1);
accelgyro.setInterruptMode(1);
@ -74,7 +77,8 @@ bool GyroSensor::setup() {
calibrateSensor();
#endif
// Once we have calibration values stored we just apply them from the config.
// Once we have calibration values stored we just apply them from the
// config.
calibrationOffset = myConfig.getGyroCalibration();
applyCalibration();
}
@ -94,11 +98,13 @@ void GyroSensor::enterSleep() {
//
// Do a number of reads to get a more stable value.
//
void GyroSensor::readSensor(RawGyroData &raw, const int noIterations, const int delayTime) {
void GyroSensor::readSensor(RawGyroData &raw, const int noIterations,
const int delayTime) {
RawGyroDataL average = {0, 0, 0, 0, 0, 0};
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
Log.verbose(F("GYRO: Reading sensor with %d iterations %d us delay." CR), noIterations, delayTime );
Log.verbose(F("GYRO: Reading sensor with %d iterations %d us delay." CR),
noIterations, delayTime);
#endif
// Set some initial values
@ -110,7 +116,6 @@ void GyroSensor::readSensor(RawGyroData &raw, const int noIterations, const int
max = min;
#endif
for (int cnt = 0; cnt < noIterations; cnt++) {
#if defined(GYRO_USE_INTERRUPT)
while (accelgyro.getIntDataReadyStatus() == 0) {
delayMicroseconds(1);
@ -165,12 +170,19 @@ void GyroSensor::readSensor(RawGyroData &raw, const int noIterations, const int
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
#if defined(GYRO_SHOW_MINMAX)
Log.verbose(F("GYRO: Min \t%d\t%d\t%d\t%d\t%d\t%d\t%d." CR), min.ax, min.ay, min.az, min.gx, min.gy, min.gz, min.temp );
Log.verbose(F("GYRO: Max \t%d\t%d\t%d\t%d\t%d\t%d\t%d." CR), max.ax, max.ay, max.az, max.gx, max.gy, max.gz, max.temp );
Log.verbose(F("GYRO: Min \t%d\t%d\t%d\t%d\t%d\t%d\t%d." CR), min.ax,
min.ay, min.az, min.gx, min.gy, min.gz, min.temp);
Log.verbose(F("GYRO: Max \t%d\t%d\t%d\t%d\t%d\t%d\t%d." CR), max.ax,
max.ay, max.az, max.gx, max.gy, max.gz, max.temp);
#endif
Log.verbose(F("GYRO: Average\t%d\t%d\t%d\t%d\t%d\t%d\t%d." CR), raw.ax, raw.ay, raw.az, raw.gx, raw.gy, raw.gz, raw.temp );
//Log.verbose(F("GYRO: Result \t%d\t%d\t%d\t%d\t%d\t%d." CR), average.ax/noIterations, average.ay/noIterations, average.az/noIterations,
// average.gx/noIterations, average.gy/noIterations, average.gz/noIterations );
Log.verbose(F("GYRO: Average\t%d\t%d\t%d\t%d\t%d\t%d\t%d." CR), raw.ax,
raw.ay, raw.az, raw.gx, raw.gy, raw.gz, raw.temp);
// Log.verbose(F("GYRO: Result \t%d\t%d\t%d\t%d\t%d\t%d." CR),
// average.ax/noIterations, average.ay/noIterations, average.az/noIterations,
// average.gx/noIterations,
// average.gy/noIterations,
// average.gz/noIterations
// );
#endif
}
@ -184,17 +196,18 @@ float GyroSensor::calculateAngle(RawGyroData &raw) {
// Smooth out the readings to we can have a more stable angle/tilt.
// ------------------------------------------------------------------------------------------------------------
// Accelerometer full scale range of +/- 2g with Sensitivity Scale Factor of 16,384 LSB(Count)/g.
// Gyroscope full scale range of +/- 250 °/s with Sensitivity Scale Factor of 131 LSB (Count)/°/s.
float ax = ((float) raw.ax)/16384,
ay = ((float) raw.ay)/16384,
az = ((float) raw.az)/16384;
// Accelerometer full scale range of +/- 2g with Sensitivity Scale Factor of
// 16,384 LSB(Count)/g. Gyroscope full scale range of +/- 250 °/s with
// Sensitivity Scale Factor of 131 LSB (Count)/°/s.
float ax = (static_cast<float>(raw.ax)) / 16384,
ay = (static_cast<float>(raw.ay)) / 16384,
az = (static_cast<float>(raw.az)) / 16384;
// Source: https://www.nxp.com/docs/en/application-note/AN3461.pdf
float v = (acos(ay / sqrt(ax * ax + ay * ay + az * az)) * 180.0 / PI);
// Log.notice(F("GYRO: angle = %F." CR), v );
//double v = (acos( raw.az / sqrt( raw.ax*raw.ax + raw.ay*raw.ay + raw.az*raw.az ) ) *180.0 / PI);
//Log.notice(F("GYRO: angle = %F." CR), v );
// double v = (acos( raw.az / sqrt( raw.ax*raw.ax + raw.ay*raw.ay +
// raw.az*raw.az ) ) *180.0 / PI); Log.notice(F("GYRO: angle = %F." CR), v );
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
Log.verbose(F("GYRO: angle = %F." CR), v);
@ -212,8 +225,10 @@ bool GyroSensor::isSensorMoving(RawGyroData &raw) {
int x = abs(raw.gx), y = abs(raw.gy), z = abs(raw.gz);
if( x>SENSOR_MOVING_THREASHOLD || y>SENSOR_MOVING_THREASHOLD || z>SENSOR_MOVING_THREASHOLD ) {
Log.notice(F("GYRO: Movement detected (%d)\t%d\t%d\t%d." CR), SENSOR_MOVING_THREASHOLD, x, y, z);
if (x > SENSOR_MOVING_THREASHOLD || y > SENSOR_MOVING_THREASHOLD ||
z > SENSOR_MOVING_THREASHOLD) {
Log.notice(F("GYRO: Movement detected (%d)\t%d\t%d\t%d." CR),
SENSOR_MOVING_THREASHOLD, x, y, z);
return true;
}
@ -228,12 +243,14 @@ bool GyroSensor::read() {
Log.verbose(F("GYRO: Getting new gyro position." CR));
#endif
if( !sensorConnected )
return false;
if (!sensorConnected) return false;
readSensor( lastGyroData, SENSOR_READ_COUNT, SENSOR_READ_DELAY ); // Last param is unused if GYRO_USE_INTERRUPT is defined.
readSensor(lastGyroData, SENSOR_READ_COUNT,
SENSOR_READ_DELAY); // Last param is unused if GYRO_USE_INTERRUPT
// is defined.
// If the sensor is unstable we return false to signal we dont have valid value
// If the sensor is unstable we return false to signal we dont have valid
// value
if (isSensorMoving(lastGyroData)) {
#if !defined(GYRO_DISABLE_LOGGING)
Log.notice(F("GYRO: Sensor is moving." CR));
@ -243,16 +260,16 @@ bool GyroSensor::read() {
validValue = true;
angle = calculateAngle(lastGyroData);
#if !defined(GYRO_DISABLE_LOGGING)
Log.notice(F("GYRO: Sensor values %d,%d,%d\t%F" CR), lastGyroData.ax, lastGyroData.ay, lastGyroData.az, angle );
Log.notice(F("GYRO: Sensor values %d,%d,%d\t%F" CR), lastGyroData.ax,
lastGyroData.ay, lastGyroData.az, angle);
#endif
}
sensorTemp = ((float) lastGyroData.temp) / 340 + 36.53;
sensorTemp = (static_cast<float>(lastGyroData.temp)) / 340 + 36.53;
// The first read value is close to the DS18 value according to my tests, if more reads are
// done then the gyro temp will increase to much
if( initialSensorTemp == INVALID_TEMPERATURE )
initialSensorTemp = sensorTemp;
// The first read value is close to the DS18 value according to my tests, if
// more reads are done then the gyro temp will increase to much
if (initialSensorTemp == INVALID_TEMPERATURE) initialSensorTemp = sensorTemp;
return validValue;
}
@ -262,8 +279,10 @@ bool GyroSensor::read() {
//
void GyroSensor::dumpCalibration() {
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
Log.verbose(F("GYRO: Accel offset\t%d\t%d\t%d" CR), calibrationOffset.ax, calibrationOffset.ay, calibrationOffset.az );
Log.verbose(F("GYRO: Gyro offset \t%d\t%d\t%d" CR), calibrationOffset.gx, calibrationOffset.gy, calibrationOffset.gz );
Log.verbose(F("GYRO: Accel offset\t%d\t%d\t%d" CR), calibrationOffset.ax,
calibrationOffset.ay, calibrationOffset.az);
Log.verbose(F("GYRO: Gyro offset \t%d\t%d\t%d" CR), calibrationOffset.gx,
calibrationOffset.gy, calibrationOffset.gz);
#endif
}
@ -275,7 +294,9 @@ void GyroSensor::applyCalibration() {
Log.verbose(F("GYRO: Applying calibration offsets to sensor." CR));
#endif
if( ( calibrationOffset.ax + calibrationOffset.ay + calibrationOffset.az + calibrationOffset.gx + calibrationOffset.gy + calibrationOffset.gz ) == 0 ) {
if ((calibrationOffset.ax + calibrationOffset.ay + calibrationOffset.az +
calibrationOffset.gx + calibrationOffset.gy + calibrationOffset.gz) ==
0) {
Log.error(F("GYRO: No valid calibraion values exist, aborting." CR));
return;
}
@ -322,24 +343,38 @@ void GyroSensor::calibrateSensor() {
//
void GyroSensor::debug() {
#if LOG_LEVEL == 6 && !defined(GYRO_DISABLE_LOGGING)
Log.verbose(F("GYRO: Debug - Clock src %d." CR), accelgyro.getClockSource() );
Log.verbose(F("GYRO: Debug - Clock src %d." CR),
accelgyro.getClockSource());
Log.verbose(F("GYRO: Debug - Device ID %d." CR), accelgyro.getDeviceID());
Log.verbose(F("GYRO: Debug - DHPF Mode %d." CR), accelgyro.getDHPFMode());
Log.verbose(F("GYRO: Debug - DMP on %s." CR), accelgyro.getDMPEnabled()?"on":"off" );
Log.verbose(F("GYRO: Debug - Acc range %d." CR), accelgyro.getFullScaleAccelRange() );
Log.verbose(F("GYRO: Debug - Gyr range %d." CR), accelgyro.getFullScaleGyroRange() );
Log.verbose(F("GYRO: Debug - Int %s." CR), accelgyro.getIntEnabled()?"on":"off" );
Log.verbose(F("GYRO: Debug - Clock %d." CR), accelgyro.getMasterClockSpeed() );
Log.verbose(F("GYRO: Debug - DMP on %s." CR),
accelgyro.getDMPEnabled() ? "on" : "off");
Log.verbose(F("GYRO: Debug - Acc range %d." CR),
accelgyro.getFullScaleAccelRange());
Log.verbose(F("GYRO: Debug - Gyr range %d." CR),
accelgyro.getFullScaleGyroRange());
Log.verbose(F("GYRO: Debug - Int %s." CR),
accelgyro.getIntEnabled() ? "on" : "off");
Log.verbose(F("GYRO: Debug - Clock %d." CR),
accelgyro.getMasterClockSpeed());
Log.verbose(F("GYRO: Debug - Rate %d." CR), accelgyro.getRate());
Log.verbose(F("GYRO: Debug - Gyro range %d." CR), accelgyro.getFullScaleGyroRange() );
// Log.verbose(F("GYRO: Debug - I2C bypass %s." CR), accelgyro.getI2CBypassEnabled()?"on":"off" );
// Log.verbose(F("GYRO: Debug - I2C master %s." CR), accelgyro.getI2CMasterModeEnabled()?"on":"off" );
Log.verbose(F("GYRO: Debug - Acc FactX %d." CR), accelgyro.getAccelXSelfTestFactoryTrim() );
Log.verbose(F("GYRO: Debug - Acc FactY %d." CR), accelgyro.getAccelYSelfTestFactoryTrim() );
Log.verbose(F("GYRO: Debug - Acc FactZ %d." CR), accelgyro.getAccelZSelfTestFactoryTrim() );
Log.verbose(F("GYRO: Debug - Gyr FactX %d." CR), accelgyro.getGyroXSelfTestFactoryTrim() );
Log.verbose(F("GYRO: Debug - Gyr FactY %d." CR), accelgyro.getGyroYSelfTestFactoryTrim() );
Log.verbose(F("GYRO: Debug - Gyr FactZ %d." CR), accelgyro.getGyroZSelfTestFactoryTrim() );
Log.verbose(F("GYRO: Debug - Gyro range %d." CR),
accelgyro.getFullScaleGyroRange());
// Log.verbose(F("GYRO: Debug - I2C bypass %s." CR),
// accelgyro.getI2CBypassEnabled()?"on":"off" ); Log.verbose(F("GYRO: Debug -
// I2C master %s." CR), accelgyro.getI2CMasterModeEnabled()?"on":"off" );
Log.verbose(F("GYRO: Debug - Acc FactX %d." CR),
accelgyro.getAccelXSelfTestFactoryTrim());
Log.verbose(F("GYRO: Debug - Acc FactY %d." CR),
accelgyro.getAccelYSelfTestFactoryTrim());
Log.verbose(F("GYRO: Debug - Acc FactZ %d." CR),
accelgyro.getAccelZSelfTestFactoryTrim());
Log.verbose(F("GYRO: Debug - Gyr FactX %d." CR),
accelgyro.getGyroXSelfTestFactoryTrim());
Log.verbose(F("GYRO: Debug - Gyr FactY %d." CR),
accelgyro.getGyroYSelfTestFactoryTrim());
Log.verbose(F("GYRO: Debug - Gyr FactZ %d." CR),
accelgyro.getGyroZSelfTestFactoryTrim());
switch (accelgyro.getFullScaleAccelRange()) {
case 0:
@ -356,12 +391,18 @@ void GyroSensor::debug() {
break;
}
Log.verbose(F("GYRO: Debug - Acc OffX %d\t%d." CR), accelgyro.getXAccelOffset(), calibrationOffset.az );
Log.verbose(F("GYRO: Debug - Acc OffY %d\t%d." CR), accelgyro.getYAccelOffset(), calibrationOffset.ay );
Log.verbose(F("GYRO: Debug - Acc OffZ %d\t%d." CR), accelgyro.getZAccelOffset(), calibrationOffset.az );
Log.verbose(F("GYRO: Debug - Gyr OffX %d\t%d." CR), accelgyro.getXGyroOffset(), calibrationOffset.gx );
Log.verbose(F("GYRO: Debug - Gyr OffY %d\t%d." CR), accelgyro.getYGyroOffset(), calibrationOffset.gy );
Log.verbose(F("GYRO: Debug - Gyr OffZ %d\t%d." CR), accelgyro.getZGyroOffset(), calibrationOffset.gz );
Log.verbose(F("GYRO: Debug - Acc OffX %d\t%d." CR),
accelgyro.getXAccelOffset(), calibrationOffset.az);
Log.verbose(F("GYRO: Debug - Acc OffY %d\t%d." CR),
accelgyro.getYAccelOffset(), calibrationOffset.ay);
Log.verbose(F("GYRO: Debug - Acc OffZ %d\t%d." CR),
accelgyro.getZAccelOffset(), calibrationOffset.az);
Log.verbose(F("GYRO: Debug - Gyr OffX %d\t%d." CR),
accelgyro.getXGyroOffset(), calibrationOffset.gx);
Log.verbose(F("GYRO: Debug - Gyr OffY %d\t%d." CR),
accelgyro.getYGyroOffset(), calibrationOffset.gy);
Log.verbose(F("GYRO: Debug - Gyr OffZ %d\t%d." CR),
accelgyro.getZGyroOffset(), calibrationOffset.gz);
#endif
}

View File

@ -1,87 +0,0 @@
/*
MIT License
Copyright (c) 2021 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef _GYRO_H
#define _GYRO_H
#define I2CDEV_IMPLEMENTATION I2CDEV_ARDUINO_WIRE
//#define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_SBWIRE
// Includes
#include <Arduino.h>
#include "MPU6050.h"
#include "config.h"
// Classes
struct RawGyroDataL { // Used for average multiple readings
long ax; // Raw Acceleration
long ay;
long az;
long gx; // Raw Position
long gy;
long gz;
long temp; // Only for information (temperature of chip)
};
#define INVALID_TEMPERATURE -273
class GyroSensor {
private:
MPU6050 accelgyro;
bool sensorConnected = false;
bool validValue = false;
float angle = 0;
float sensorTemp = 0;
float initialSensorTemp = INVALID_TEMPERATURE;
RawGyroData calibrationOffset;
RawGyroData lastGyroData;
void debug();
void applyCalibration();
void dumpCalibration();
void readSensor(RawGyroData &raw, const int noIterations = 100, const int delayTime = 1);
bool isSensorMoving(RawGyroData &raw);
float calculateAngle(RawGyroData &raw);
public:
bool setup();
bool read();
void calibrateSensor();
const RawGyroData& getLastGyroData() { return lastGyroData; }
float getAngle() { return angle; };
float getSensorTempC() { return sensorTemp; };
float getInitialSensorTempC() { return initialSensorTemp; };
bool isConnected() { return sensorConnected; };
bool hasValue() { return validValue; };
void enterSleep();
};
// Global instance created
extern GyroSensor myGyro;
#endif // _GYRO_H
// EOF

89
src/gyro.hpp Normal file
View File

@ -0,0 +1,89 @@
/*
MIT License
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef SRC_GYRO_HPP_
#define SRC_GYRO_HPP_
#define I2CDEV_IMPLEMENTATION I2CDEV_ARDUINO_WIRE
// #define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_SBWIRE
// Includes
#include <Arduino.h>
#include <MPU6050.h>
#include <config.hpp>
// Classes
struct RawGyroDataL { // Used for average multiple readings
int32_t ax; // Raw Acceleration
int32_t ay;
int32_t az;
int32_t gx; // Raw Position
int32_t gy;
int32_t gz;
int32_t temp; // Only for information (temperature of chip)
};
#define INVALID_TEMPERATURE -273
class GyroSensor {
private:
MPU6050 accelgyro;
bool sensorConnected = false;
bool validValue = false;
float angle = 0;
float sensorTemp = 0;
float initialSensorTemp = INVALID_TEMPERATURE;
RawGyroData calibrationOffset;
RawGyroData lastGyroData;
void debug();
void applyCalibration();
void dumpCalibration();
void readSensor(RawGyroData &raw, const int noIterations = 100,
const int delayTime = 1);
bool isSensorMoving(RawGyroData &raw);
float calculateAngle(RawGyroData &raw);
public:
bool setup();
bool read();
void calibrateSensor();
const RawGyroData &getLastGyroData() { return lastGyroData; }
float getAngle() { return angle; }
float getSensorTempC() { return sensorTemp; }
float getInitialSensorTempC() { return initialSensorTemp; }
bool isConnected() { return sensorConnected; }
bool hasValue() { return validValue; }
void enterSleep();
};
// Global instance created
extern GyroSensor myGyro;
#endif // SRC_GYRO_HPP_
// EOF

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,12 +21,13 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "helper.h"
#include "config.h"
#include "gyro.h"
#include "tempsensor.h"
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <config.hpp>
#include <gyro.hpp>
#include <helper.hpp>
#include <tempsensor.hpp>
SerialDebug mySerial;
BatteryVoltage myBatteryVoltage;
@ -36,7 +37,9 @@ BatteryVoltage myBatteryVoltage;
//
void printHeap() {
#if LOG_LEVEL == 6
Log.verbose(F("HELP: Heap %d kb, HeapFrag %d %%, FreeSketch %d kb." CR), ESP.getFreeHeap()/1024, ESP.getHeapFragmentation(), ESP.getFreeSketchSpace()/1024 );
Log.verbose(F("HELP: Heap %d kb, HeapFrag %d %%, FreeSketch %d kb." CR),
ESP.getFreeHeap() / 1024, ESP.getHeapFragmentation(),
ESP.getFreeSketchSpace() / 1024);
#endif
}
@ -68,13 +71,14 @@ void printBuildOptions() {
#ifdef ACTIVATE_OTA
"OTA "
#endif
CR), CFG_APPVER, LOG_LEVEL );
CR),
CFG_APPVER, LOG_LEVEL);
}
//
// Configure serial debug output
//
SerialDebug::SerialDebug(const long serialSpeed) {
SerialDebug::SerialDebug(const int32 serialSpeed) {
// Start serial with auto-detected rate (default to defined BAUD)
Serial.flush();
Serial.begin(serialSpeed);
@ -89,7 +93,7 @@ SerialDebug::SerialDebug(const long serialSpeed) {
//
void printTimestamp(Print* _logOutput, int _logLevel) {
char c[12];
sprintf(c, "%10lu ", millis());
snprintf(c, sizeof(c), "%10lu ", millis());
_logOutput->print(c);
}
@ -97,12 +101,15 @@ void printTimestamp(Print* _logOutput, int _logLevel) {
// Read and calculate the battery voltage
//
void BatteryVoltage::read() {
// The analog pin can only handle 3.3V maximum voltage so we need to reduce the voltage (from max 5V)
// The analog pin can only handle 3.3V maximum voltage so we need to reduce
// the voltage (from max 5V)
float factor = myConfig.getVoltageFactor(); // Default value is 1.63
int v = analogRead(A0);
batteryLevel = ((3.3 / 1023) * v) * factor;
#if LOG_LEVEL == 6
Log.verbose(F("BATT: Reading voltage level. Factor=%F Value=%d, Voltage=%F." CR), factor, v, batteryLevel );
Log.verbose(
F("BATT: Reading voltage level. Factor=%F Value=%d, Voltage=%F." CR),
factor, v, batteryLevel);
#endif
}
@ -115,8 +122,7 @@ PerfLogging myPerfLogging;
//
void PerfLogging::clear() {
// Clear the measurements
if( first == 0 )
return;
if (first == 0) return;
PerfEntry* pe = first;
@ -147,10 +153,9 @@ void PerfLogging::stop( const char* key ) {
if (pe != 0) {
pe->end = millis();
unsigned long t = pe->end - pe->start;
uint32_t t = pe->end - pe->start;
if( t > pe->max )
pe->max = t;
if (t > pe->max) pe->max = t;
}
}
@ -161,7 +166,8 @@ void PerfLogging::print() {
PerfEntry* pe = first;
while (pe != 0) {
//Log.notice( F("PERF: %s=%l ms (%l, %l)" CR), pe->key, (pe->end - pe->start), pe->start, pe->end );
// Log.notice( F("PERF: %s=%l ms (%l, %l)" CR), pe->key, (pe->end -
// pe->start), pe->start, pe->end );
Log.notice(F("PERF: %s %lms" CR), pe->key, pe->max);
pe = pe->next;
}
@ -171,14 +177,14 @@ void PerfLogging::print() {
// Push collected performance data to influx (use influx configuration)
//
void PerfLogging::pushInflux() {
if( !myConfig.isInfluxDb2Active() )
return;
if (!myConfig.isInfluxDb2Active()) return;
WiFiClient client;
HTTPClient http;
String serverPath = String(myConfig.getInfluxDb2PushUrl()) + "/api/v2/write?org=" +
String(myConfig.getInfluxDb2PushOrg()) + "&bucket=" +
String(myConfig.getInfluxDb2PushBucket());
String serverPath =
String(myConfig.getInfluxDb2PushUrl()) +
"/api/v2/write?org=" + String(myConfig.getInfluxDb2PushOrg()) +
"&bucket=" + String(myConfig.getInfluxDb2PushBucket());
http.begin(client, serverPath);
@ -190,15 +196,16 @@ void PerfLogging::pushInflux() {
// ------------------------------------------------------------------------------------------
PerfEntry* pe = first;
char buf[100];
sprintf( &buf[0], "perf,host=%s,device=%s ", myConfig.getMDNS(), myConfig.getID() );
snprintf(&buf[0], sizeof(buf), "perf,host=%s,device=%s ", myConfig.getMDNS(),
myConfig.getID());
body += &buf[0];
while (pe != 0) {
if (pe->max) {
if (pe->next)
sprintf( &buf[0], "%s=%ld,", pe->key, pe->max);
snprintf(&buf[0], sizeof(buf), "%s=%u,", pe->key, pe->max);
else
sprintf( &buf[0], "%s=%ld", pe->key, pe->max);
snprintf(&buf[0], sizeof(buf), "%s=%u", pe->key, pe->max);
body += &buf[0];
}
@ -207,10 +214,15 @@ void PerfLogging::pushInflux() {
// Create the payload with debug data for validating sensor stability
// ------------------------------------------------------------------------------------------
sprintf( &buf[0], "\ndebug,host=%s,device=%s ", myConfig.getMDNS(), myConfig.getID() );
snprintf(&buf[0], sizeof(buf), "\ndebug,host=%s,device=%s ",
myConfig.getMDNS(), myConfig.getID());
body += &buf[0];
sprintf( &buf[0], "angle=%.4f,gyro-ax=%d,gyro-ay=%d,gyro-az=%d,gyro-temp=%.2f,ds-temp=%.2f", myGyro.getAngle(), myGyro.getLastGyroData().ax,
myGyro.getLastGyroData().ay, myGyro.getLastGyroData().az, myGyro.getSensorTempC(), myTempSensor.getTempC() );
snprintf(
&buf[0], sizeof(buf),
"angle=%.4f,gyro-ax=%d,gyro-ay=%d,gyro-az=%d,gyro-temp=%.2f,ds-temp=%.2f",
myGyro.getAngle(), myGyro.getLastGyroData().ax,
myGyro.getLastGyroData().ay, myGyro.getLastGyroData().az,
myGyro.getSensorTempC(), myTempSensor.getTempC());
body += &buf[0];
// Log.notice(F("PERF: data %s." CR), body.c_str() );
@ -226,9 +238,12 @@ void PerfLogging::pushInflux() {
int httpResponseCode = http.POST(body);
if (httpResponseCode == 204) {
Log.notice(F("PERF: InfluxDB2 push performance data successful, response=%d" CR), httpResponseCode);
Log.notice(
F("PERF: InfluxDB2 push performance data successful, response=%d" CR),
httpResponseCode);
} else {
Log.error(F("PERF: InfluxDB2 push performance data failed, response=%d" CR), httpResponseCode);
Log.error(F("PERF: InfluxDB2 push performance data failed, response=%d" CR),
httpResponseCode);
}
http.end();
@ -237,7 +252,8 @@ void PerfLogging::pushInflux() {
#endif // COLLECT_PERFDATA
//
// Convert float to formatted string with n decimals. Buffer should be at least 10 chars.
// Convert float to formatted string with n decimals. Buffer should be at least
// 10 chars.
//
char* convertFloatToString(float f, char* buffer, int dec) {
dtostrf(f, 6, dec, buffer);

View File

@ -1,156 +0,0 @@
/*
MIT License
Copyright (c) 2021 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef _HELPER_H
#define _HELPER_H
// Includes
#include <ArduinoLog.h>
// Sleep mode
void deepSleep(int t);
// Show build options
void printBuildOptions();
// Float to String
char* convertFloatToString( float f, char* buf, int dec = 2);
float reduceFloatPrecision( float f, int dec = 2 );
// Logging via serial
void printTimestamp(Print* _logOutput, int _logLevel);
void printNewline(Print* _logOutput);
void printHeap();
// Classes
class SerialDebug {
public:
SerialDebug(const long serialSpeed = 115200L);
static Logging* getLog() { return &Log; };
};
class BatteryVoltage {
private:
float batteryLevel;
public:
void read();
float getVoltage() { return batteryLevel; };
};
#if defined( COLLECT_PERFDATA )
class PerfLogging {
private:
struct PerfEntry {
unsigned long start; // millis()
unsigned long end; // millis()
unsigned long max; // max time in ms
const char* key; // measurement
PerfEntry* next; // Next in the linked list
float mA; // Power consumption
float V; // Power consumption
};
PerfEntry* first = 0;
bool measurePower = false;
PerfEntry* find( const char* k ) {
if( first == 0 )
return 0;
PerfEntry* pe = first;
while( strcmp( k, pe->key ) != 0 ) {
if( pe->next == 0 )
return 0;
pe = pe->next;
}
return pe;
};
PerfEntry* add( const char* k ) {
if( first == 0 ) {
first = new PerfEntry();
first->key = k;
first->next = 0;
first->max = 0;
return first;
}
PerfEntry* pe = first;
while( strcmp( k, pe->key ) != 0 ) {
if( pe->next == 0 ) {
pe->next = new PerfEntry();
pe->next->key = k;
pe->next->max = 0;
pe->next->next = 0;
return pe->next;
}
pe = pe->next;
}
return pe;
};
public:
void clear();
void start( const char* key );
void stop( const char* key );
void print();
void pushInflux();
};
extern PerfLogging myPerfLogging;
// Use these to collect performance data from various parts of the code
#define LOG_PERF_START(s) myPerfLogging.start(s)
#define LOG_PERF_STOP(s) myPerfLogging.stop(s)
//#define LOG_PERF_PRINT() myPerfLogging.print()
#define LOG_PERF_PRINT()
#define LOG_PERF_CLEAR() myPerfLogging.clear()
#define LOG_PERF_PUSH() myPerfLogging.pushInflux()
#else
// These will disable the performance collection function
#define LOG_PERF_START(s)
#define LOG_PERF_STOP(s)
#define LOG_PERF_PRINT()
#define LOG_PERF_CLEAR()
#define LOG_PERF_PUSH()
#endif // COLLECT_PERFDATA
// Global instance created
extern SerialDebug mySerial;
extern BatteryVoltage myBatteryVoltage;
#endif // _HELPER_H
// EOF

153
src/helper.hpp Normal file
View File

@ -0,0 +1,153 @@
/*
MIT License
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef SRC_HELPER_HPP_
#define SRC_HELPER_HPP_
// Includes
#include <ArduinoLog.h>
// Sleep mode
void deepSleep(int t);
// Show build options
void printBuildOptions();
// Float to String
char* convertFloatToString(float f, char* buf, int dec = 2);
float reduceFloatPrecision(float f, int dec = 2);
// Logging via serial
void printTimestamp(Print* _logOutput, int _logLevel);
void printNewline(Print* _logOutput);
void printHeap();
// Classes
class SerialDebug {
public:
explicit SerialDebug(const int32 serialSpeed = 115200L);
static Logging* getLog() { return &Log; }
};
class BatteryVoltage {
private:
float batteryLevel;
public:
void read();
float getVoltage() { return batteryLevel; }
};
#if defined(COLLECT_PERFDATA)
class PerfLogging {
private:
struct PerfEntry {
uint32_t start; // millis()
uint32_t end; // millis()
uint32_t max; // max time in ms
const char* key; // measurement
PerfEntry* next; // Next in the linked list
float mA; // Power consumption
float V; // Power consumption
};
PerfEntry* first = 0;
bool measurePower = false;
PerfEntry* find(const char* k) {
if (first == 0) return 0;
PerfEntry* pe = first;
while (strcmp(k, pe->key) != 0) {
if (pe->next == 0) return 0;
pe = pe->next;
}
return pe;
}
PerfEntry* add(const char* k) {
if (first == 0) {
first = new PerfEntry();
first->key = k;
first->next = 0;
first->max = 0;
return first;
}
PerfEntry* pe = first;
while (strcmp(k, pe->key) != 0) {
if (pe->next == 0) {
pe->next = new PerfEntry();
pe->next->key = k;
pe->next->max = 0;
pe->next->next = 0;
return pe->next;
}
pe = pe->next;
}
return pe;
}
public:
void clear();
void start(const char* key);
void stop(const char* key);
void print();
void pushInflux();
};
extern PerfLogging myPerfLogging;
// Use these to collect performance data from various parts of the code
#define LOG_PERF_START(s) myPerfLogging.start(s)
#define LOG_PERF_STOP(s) myPerfLogging.stop(s)
// #define LOG_PERF_PRINT() myPerfLogging.print()
#define LOG_PERF_PRINT()
#define LOG_PERF_CLEAR() myPerfLogging.clear()
#define LOG_PERF_PUSH() myPerfLogging.pushInflux()
#else
// These will disable the performance collection function
#define LOG_PERF_START(s)
#define LOG_PERF_STOP(s)
#define LOG_PERF_PRINT()
#define LOG_PERF_CLEAR()
#define LOG_PERF_PUSH()
#endif // COLLECT_PERFDATA
// Global instance created
extern SerialDebug mySerial;
extern BatteryVoltage myBatteryVoltage;
#endif // SRC_HELPER_HPP_
// EOF

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,16 +21,17 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "helper.h"
#include "gyro.h"
#include "config.h"
#include "wifi.h"
#include "webserver.h"
#include "calc.h"
#include "tempsensor.h"
#include "pushtarget.h"
#include <LittleFS.h>
#include <calc.hpp>
#include <config.hpp>
#include <gyro.hpp>
#include <helper.hpp>
#include <pushtarget.hpp>
#include <tempsensor.hpp>
#include <webserver.hpp>
#include <wifi.hpp>
// Settings for double reset detector.
#define ESP8266_DRD_USE_RTC true
#define DRD_TIMEOUT 2
@ -44,11 +45,13 @@ const int interval = 1000; // ms, time to wait between changes
bool sleepModeAlwaysSkip = true; // Web interface can override normal behaviour
#else
const int interval = 200; // ms, time to wait between changes to output
bool sleepModeAlwaysSkip = false; // Web interface can override normal behaviour
bool sleepModeAlwaysSkip =
false; // Web interface can override normal behaviour
#endif
unsigned long loopMillis = 0; // Used for main loop to run the code every _interval_
unsigned long runtimeMillis; // Used to calculate the total time since start/wakeup
unsigned long stableGyroMillis; // Used to calculate the total time since last stable gyro reading
uint32_t loopMillis = 0; // Used for main loop to run the code every _interval_
uint32_t runtimeMillis; // Used to calculate the total time since start/wakeup
uint32_t stableGyroMillis; // Used to calculate the total time since last
// stable gyro reading
bool sleepModeActive = false;
bool goToSleep = false;
int loopCounter = 0;
@ -57,7 +60,6 @@ int loopCounter = 0;
// Check if we should be in sleep mode
//
void checkSleepMode(float angle, float volt) {
#if defined(SKIP_SLEEPMODE)
sleepModeActive = false;
Log.verbose(F("MAIN: Skipping sleep mode (SKIP_SLEEPMODE is defined)." CR));
@ -67,8 +69,11 @@ void checkSleepMode( float angle, float volt ) {
const RawGyroData &g = myConfig.getGyroCalibration();
// Will not enter sleep mode if: no calibration data
if( g.ax==0 && g.ay==0 && g.az==0 && g.gx==0 && g.gy==0 && g.gz==0 ) {
Log.notice(F("MAIN: Missing calibration data, so forcing webserver to be active." CR) );
if (g.ax == 0 && g.ay == 0 && g.az == 0 && g.gx == 0 && g.gy == 0 &&
g.gz == 0) {
Log.notice(
F("MAIN: Missing calibration data, so forcing webserver to be "
"active." CR));
sleepModeAlwaysSkip = true;
}
@ -79,11 +84,14 @@ void checkSleepMode( float angle, float volt ) {
}
// Will not enter sleep mode if: charger is connected
sleepModeActive = (volt<4.15 && (angle>85 && angle<95)) || (volt>4.15) ? false : true;
sleepModeActive = (volt < 4.15 && (angle > 85 && angle < 95)) || (volt > 4.15)
? false
: true;
// sleep mode active when flat
// sleepModeActive = ( angle<85 && angle>5 ) ? true : false;
Log.notice(F("MAIN: Deep sleep mode %s (angle=%F volt=%F)." CR), sleepModeActive ? "true":"false", angle, volt );
Log.notice(F("MAIN: Deep sleep mode %s (angle=%F volt=%F)." CR),
sleepModeActive ? "true" : "false", angle, volt);
}
//
@ -100,7 +108,8 @@ void setup() {
Log.verbose(F("Main: Reset reason %s." CR), ESP.getResetInfo().c_str());
#endif
// Main startup
Log.notice(F("Main: Started setup for %s." CR), String( ESP.getChipId(), HEX).c_str() );
Log.notice(F("Main: Started setup for %s." CR),
String(ESP.getChipId(), HEX).c_str());
printBuildOptions();
LOG_PERF_START("main-config-load");
@ -113,25 +122,28 @@ void setup() {
ESP.wdtEnable(interval * 2);
if (dt) {
Log.notice(F("Main: Detected doubletap on reset. Reset reason=%s" CR), ESP.getResetReason().c_str());
Log.notice(F("Main: Detected doubletap on reset. Reset reason=%s" CR),
ESP.getResetReason().c_str());
}
#ifdef SKIP_SLEEPMODE
// If we are running in debug more we skip this part. makes is hard to debug in case of crash/watchdog reset
// If we are running in debug more we skip this part. makes is hard to debug
// in case of crash/watchdog reset
dt = false;
#endif
LOG_PERF_START("main-wifi-connect");
myWifi.connect( dt ); // This will return false if unable to connect to wifi, will be handled in loop()
myWifi.connect(dt); // This will return false if unable to connect to wifi,
// will be handled in loop()
LOG_PERF_STOP("main-wifi-connect");
LOG_PERF_START("main-temp-setup");
myTempSensor.setup();
LOG_PERF_STOP("main-temp-setup");
//LOG_PERF_START("main-gyro-setup"); // Takes less than 5ms, so skip this measurment
if( !myGyro.setup() )
Log.error(F("Main: Failed to initialize the gyro." CR));
// LOG_PERF_START("main-gyro-setup"); // Takes less than 5ms, so skip this
// measurment
if (!myGyro.setup()) Log.error(F("Main: Failed to initialize the gyro." CR));
// LOG_PERF_STOP("main-gyro-setup");
LOG_PERF_START("main-gyro-read");
@ -152,7 +164,8 @@ void setup() {
LOG_PERF_STOP("main-wifi-ota");
#endif
if (!sleepModeActive) {
//LOG_PERF_START("main-webserver-setup"); // Takes less than 4ms , so skip this measurment
// LOG_PERF_START("main-webserver-setup"); // Takes less than 4ms , so
// skip this measurment
myWebServer.setupWebServer();
// LOG_PERF_STOP("main-webserver-setup");
}
@ -160,7 +173,8 @@ void setup() {
LOG_PERF_STOP("main-setup");
Log.notice(F("Main: Setup completed." CR));
stableGyroMillis = millis(); // Put it here so we dont include time for wifi connection
stableGyroMillis =
millis(); // Put it here so we dont include time for wifi connection
}
//
@ -169,7 +183,7 @@ void setup() {
void loop() {
drd->loop();
if( sleepModeActive || abs( (long) (millis() - loopMillis)) > interval ) {
if (sleepModeActive || abs((int32_t)(millis() - loopMillis)) > interval) {
float angle = 0;
float volt = myBatteryVoltage.getVoltage();
// float sensorTemp = 0;
@ -181,7 +195,8 @@ void loop() {
// Process the sensor values and push data to targets.
// ------------------------------------------------------------------------------------------------
// If we dont get any readings we just skip this and try again the next interval.
// If we dont get any readings we just skip this and try again the next
// interval.
//
if (myGyro.hasValue()) {
angle = myGyro.getAngle(); // Gyro angle
@ -192,31 +207,38 @@ void loop() {
float temp = myTempSensor.getTempC();
LOG_PERF_STOP("loop-temp-read");
//LOG_PERF_START("loop-gravity-calc"); // Takes less than 2ms , so skip this measurment
// LOG_PERF_START("loop-gravity-calc"); // Takes less than 2ms , so skip
// this measurment
float gravity = calculateGravity(angle, temp);
// LOG_PERF_STOP("loop-gravity-calc");
//LOG_PERF_START("loop-gravity-corr"); // Takes less than 2ms , so skip this measurment
// Use default correction temperature of 20C
float corrGravity = gravityTemperatureCorrection( gravity, temp, myConfig.getTempFormat() );
// LOG_PERF_START("loop-gravity-corr"); // Takes less than 2ms , so skip
// this measurment Use default correction temperature of 20C
float corrGravity =
gravityTemperatureCorrection(gravity, temp, myConfig.getTempFormat());
// LOG_PERF_STOP("loop-gravity-corr");
#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING)
Log.verbose(F("Main: Sensor values gyro angle=%F, temp=%F, gravity=%F, corr=%F." CR), angle, temp, gravity, corrGravity );
Log.verbose(F("Main: Sensor values gyro angle=%F, temp=%F, gravity=%F, "
"corr=%F." CR),
angle, temp, gravity, corrGravity);
#endif
// Limit the printout when sleep mode is not active.
if (loopCounter % 10 == 0 || sleepModeActive) {
Log.notice(F("Main: angle=%F, temp=%F, gravity=%F, corrGravity=%F, batt=%F." CR), angle, temp, gravity, corrGravity ,volt );
Log.notice(F("Main: angle=%F, temp=%F, gravity=%F, corrGravity=%F, "
"batt=%F." CR),
angle, temp, gravity, corrGravity, volt);
}
LOG_PERF_START("loop-push");
myPushTarget.send( angle, gravity, corrGravity, temp, (millis()-runtimeMillis)/1000, sleepModeActive ); // Force the transmission if we are going to sleep
myPushTarget.send(
angle, gravity, corrGravity, temp, (millis() - runtimeMillis) / 1000,
sleepModeActive); // Force the transmission if we are going to sleep
LOG_PERF_STOP("loop-push");
// If we have completed the update lets go to sleep
if( sleepModeActive )
goToSleep = true;
if (sleepModeActive) goToSleep = true;
} else {
Log.error(F("Main: No gyro value." CR));
}
@ -227,20 +249,26 @@ void loop() {
int sleepInterval = myConfig.getSleepInterval();
// If we didnt get a wifi connection, we enter sleep for a short time to conserve battery.
// If we didnt get a wifi connection, we enter sleep for a short time to
// conserve battery.
// ------------------------------------------------------------------------------------------------
//
if (!myWifi.isConnected()) { // no connection to wifi
Log.notice(F("MAIN: No connection to wifi established, sleeping for 60s." CR) );
Log.notice(
F("MAIN: No connection to wifi established, sleeping for 60s." CR));
sleepInterval = 60; // 60s
goToSleep = true;
}
// If the sensor is moving and we are not getting a clear reading, we enter sleep for a short time to conserve battery.
// If the sensor is moving and we are not getting a clear reading, we enter
// sleep for a short time to conserve battery.
// ------------------------------------------------------------------------------------------------
//
if( sleepModeActive && ((millis()-stableGyroMillis)>10000L) ) { // 10s since last stable gyro reading
Log.notice(F("MAIN: Unable to get a stable reading for 10s, sleeping for 60s." CR) );
if (sleepModeActive && ((millis() - stableGyroMillis) >
10000L)) { // 10s since last stable gyro reading
Log.notice(
F("MAIN: Unable to get a stable reading for 10s, sleeping for "
"60s." CR));
sleepInterval = 60; // 60s
goToSleep = true;
}
@ -249,7 +277,9 @@ void loop() {
// ------------------------------------------------------------------------------------------------
//
if (goToSleep && !sleepModeAlwaysSkip) {
Log.notice(F("MAIN: Entering deep sleep for %d s, run time %l s, battery=%F V." CR), sleepInterval, (millis()-runtimeMillis)/1000, volt );
Log.notice(F("MAIN: Entering deep sleep for %d s, run time %l s, "
"battery=%F V." CR),
sleepInterval, (millis() - runtimeMillis) / 1000, volt);
LittleFS.end();
myGyro.enterSleep();
drd->stop();
@ -269,13 +299,16 @@ void loop() {
myGyro.read();
LOG_PERF_STOP("loop-gyro-read");
//LOG_PERF_START("loop-batt-read"); // Takes less than 2ms , so skip this measurment
// LOG_PERF_START("loop-batt-read"); // Takes less than 2ms , so skip this
// measurment
myBatteryVoltage.read();
// LOG_PERF_STOP("loop-batt-read");
loopMillis = millis();
// #if LOG_LEVEL==6 && !defined( MAIN_DISABLE_LOGGING )
Log.verbose(F("Main: Heap %d kb FreeSketch %d kb HeapFrag %d %%." CR), ESP.getFreeHeap()/1024, ESP.getFreeSketchSpace()/1024, ESP.getHeapFragmentation() );
Log.verbose(F("Main: Heap %d kb FreeSketch %d kb HeapFrag %d %%." CR),
ESP.getFreeHeap() / 1024, ESP.getFreeSketchSpace() / 1024,
ESP.getHeapFragmentation());
// #endif
}

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,22 +21,25 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "pushtarget.h"
#include "config.h"
#include "gyro.h" // For testing the tempsensor in the gyro
#include <config.h>
#include <gyro.hpp>
#include <pushtarget.hpp>
PushTarget myPushTarget;
//
// Send the pressure value
//
void PushTarget::send(float angle, float gravity, float corrGravity, float temp, float runTime, bool force ) {
unsigned long timePassed = abs( (long) (millis() - ms) );
unsigned long interval = myConfig.getSleepInterval()*1000;
void PushTarget::send(float angle, float gravity, float corrGravity, float temp,
float runTime, bool force) {
uint32_t timePassed = abs((int32_t)(millis() - ms));
uint32_t interval = myConfig.getSleepInterval() * 1000;
if ((timePassed < interval) && !force) {
#if LOG_LEVEL == 6 && !defined(PUSH_DISABLE_LOGGING)
Log.verbose(F("PUSH: Timer has not expired %l vs %l." CR), timePassed, interval );
Log.verbose(F("PUSH: Timer has not expired %l vs %l." CR), timePassed,
interval);
#endif
return;
}
@ -55,13 +58,15 @@ void PushTarget::send(float angle, float gravity, float corrGravity, float temp,
if (myConfig.isHttpActive()) {
LOG_PERF_START("push-http");
sendHttp( myConfig.getHttpPushUrl(), angle, gravity, corrGravity, temp, runTime );
sendHttp(myConfig.getHttpPushUrl(), angle, gravity, corrGravity, temp,
runTime);
LOG_PERF_STOP("push-http");
}
if (myConfig.isHttpActive2()) {
LOG_PERF_START("push-http2");
sendHttp( myConfig.getHttpPushUrl2(), angle, gravity, corrGravity, temp, runTime );
sendHttp(myConfig.getHttpPushUrl2(), angle, gravity, corrGravity, temp,
runTime);
LOG_PERF_STOP("push-http2");
}
@ -75,27 +80,35 @@ void PushTarget::send(float angle, float gravity, float corrGravity, float temp,
//
// Send to influx db v2
//
void PushTarget::sendInfluxDb2(float angle, float gravity, float corrGravity, float temp, float runTime) {
void PushTarget::sendInfluxDb2(float angle, float gravity, float corrGravity,
float temp, float runTime) {
#if !defined(PUSH_DISABLE_LOGGING)
Log.notice(F("PUSH: Sending values to influxdb2 angle=%F, gravity=%F, temp=%F." CR), angle, gravity, temp );
Log.notice(
F("PUSH: Sending values to influxdb2 angle=%F, gravity=%F, temp=%F." CR),
angle, gravity, temp);
#endif
WiFiClient client;
HTTPClient http;
String serverPath = String(myConfig.getInfluxDb2PushUrl()) + "/api/v2/write?org=" +
String(myConfig.getInfluxDb2PushOrg()) + "&bucket=" +
String(myConfig.getInfluxDb2PushBucket());
String serverPath =
String(myConfig.getInfluxDb2PushUrl()) +
"/api/v2/write?org=" + String(myConfig.getInfluxDb2PushOrg()) +
"&bucket=" + String(myConfig.getInfluxDb2PushBucket());
http.begin(client, serverPath);
// Create body for influxdb2
char buf[1024];
sprintf( &buf[0], "measurement,host=%s,device=%s,temp-format=%c,gravity-format=%s "
"gravity=%.4f,corr-gravity=%.4f,angle=%.2f,temp=%.2f,battery=%.2f,rssi=%d,temp2=%.2f\n",
snprintf(
&buf[0], sizeof(buf),
"measurement,host=%s,device=%s,temp-format=%c,gravity-format=%s "
"gravity=%.4f,corr-gravity=%.4f,angle=%.2f,temp=%.2f,battery=%.2f,rssi=%"
"d,temp2=%.2f\n",
// TODO: Add support for plato format
myConfig.getMDNS(), myConfig.getID(), myConfig.getTempFormat(), "SG",
myConfig.isGravityTempAdj() ? corrGravity : gravity,
corrGravity, angle, temp, myBatteryVoltage.getVoltage(), WiFi.RSSI(), myGyro.getSensorTempC() ); // For comparing gyro tempsensor vs DSB1820
myConfig.isGravityTempAdj() ? corrGravity : gravity, corrGravity, angle,
temp, myBatteryVoltage.getVoltage(), WiFi.RSSI(),
myGyro.getSensorTempC()); // For comparing gyro tempsensor vs DSB1820
#if LOG_LEVEL == 6 && !defined(PUSH_DISABLE_LOGGING)
Log.verbose(F("PUSH: url %s." CR), serverPath.c_str());
@ -108,9 +121,11 @@ void PushTarget::sendInfluxDb2(float angle, float gravity, float corrGravity, fl
int httpResponseCode = http.POST(&buf[0]);
if (httpResponseCode == 204) {
Log.notice(F("PUSH: InfluxDB2 push successful, response=%d" CR), httpResponseCode);
Log.notice(F("PUSH: InfluxDB2 push successful, response=%d" CR),
httpResponseCode);
} else {
Log.error(F("PUSH: InfluxDB2 push failed, response=%d" CR), httpResponseCode);
Log.error(F("PUSH: InfluxDB2 push failed, response=%d" CR),
httpResponseCode);
}
http.end();
@ -119,17 +134,19 @@ void PushTarget::sendInfluxDb2(float angle, float gravity, float corrGravity, fl
//
// Send data to brewfather
//
void PushTarget::sendBrewfather(float angle, float gravity, float corrGravity, float temp ) {
void PushTarget::sendBrewfather(float angle, float gravity, float corrGravity,
float temp) {
#if !defined(PUSH_DISABLE_LOGGING)
Log.notice(F("PUSH: Sending values to brewfather angle=%F, gravity=%F, temp=%F." CR), angle, gravity, temp );
Log.notice(
F("PUSH: Sending values to brewfather angle=%F, gravity=%F, temp=%F." CR),
angle, gravity, temp);
#endif
DynamicJsonDocument doc(300);
//
// {
// "name": "YourDeviceName", // Required field, this will be the ID in Brewfather
// "temp": 20.32,
// "aux_temp": 15.61, // Fridge Temp
// "name": "YourDeviceName", // Required field, this will be the ID in
// Brewfather "temp": 20.32, "aux_temp": 15.61, // Fridge Temp
// "ext_temp": 6.51, // Room Temp
// "temp_unit": "C", // C, F, K
// "gravity": 1.042,
@ -148,7 +165,8 @@ void PushTarget::sendBrewfather(float angle, float gravity, float corrGravity, f
doc["temp_unit"] = String(myConfig.getTempFormat());
doc["battery"] = reduceFloatPrecision(myBatteryVoltage.getVoltage(), 2);
// TODO: Add support for plato format
doc["gravity"] = reduceFloatPrecision( myConfig.isGravityTempAdj() ? corrGravity : gravity, 4 );
doc["gravity"] = reduceFloatPrecision(
myConfig.isGravityTempAdj() ? corrGravity : gravity, 4);
doc["gravity_unit"] = myConfig.isGravitySG() ? "G" : "P";
WiFiClient client;
@ -169,9 +187,11 @@ void PushTarget::sendBrewfather(float angle, float gravity, float corrGravity, f
int httpResponseCode = http.POST(json);
if (httpResponseCode == 200) {
Log.notice(F("PUSH: Brewfather push successful, response=%d" CR), httpResponseCode);
Log.notice(F("PUSH: Brewfather push successful, response=%d" CR),
httpResponseCode);
} else {
Log.error(F("PUSH: Brewfather push failed, response=%d" CR), httpResponseCode);
Log.error(F("PUSH: Brewfather push failed, response=%d" CR),
httpResponseCode);
}
http.end();
@ -180,9 +200,12 @@ void PushTarget::sendBrewfather(float angle, float gravity, float corrGravity, f
//
// Send data to http target
//
void PushTarget::sendHttp( String serverPath, float angle, float gravity, float corrGravity, float temp, float runTime ) {
void PushTarget::sendHttp(String serverPath, float angle, float gravity,
float corrGravity, float temp, float runTime) {
#if !defined(PUSH_DISABLE_LOGGING)
Log.notice(F("PUSH: Sending values to http angle=%F, gravity=%F, temp=%F." CR), angle, gravity, temp );
Log.notice(
F("PUSH: Sending values to http angle=%F, gravity=%F, temp=%F." CR),
angle, gravity, temp);
#endif
DynamicJsonDocument doc(256);
@ -195,7 +218,8 @@ void PushTarget::sendHttp( String serverPath, float angle, float gravity, float
doc["temperature"] = reduceFloatPrecision(temp, 1);
doc["temp-units"] = String(myConfig.getTempFormat());
// TODO: Add support for plato format
doc["gravity"] = reduceFloatPrecision( myConfig.isGravityTempAdj() ? corrGravity : gravity, 4 );
doc["gravity"] = reduceFloatPrecision(
myConfig.isGravityTempAdj() ? corrGravity : gravity, 4);
doc["corr-gravity"] = reduceFloatPrecision(corrGravity, 4);
doc["angle"] = reduceFloatPrecision(angle, 2);
doc["battery"] = reduceFloatPrecision(myBatteryVoltage.getVoltage(), 2);
@ -222,7 +246,8 @@ void PushTarget::sendHttp( String serverPath, float angle, float gravity, float
int httpResponseCode = http.POST(json);
if (httpResponseCode == 200) {
Log.notice(F("PUSH: HTTP push successful, response=%d" CR), httpResponseCode);
Log.notice(F("PUSH: HTTP push successful, response=%d" CR),
httpResponseCode);
} else {
Log.error(F("PUSH: HTTP push failed, response=%d" CR), httpResponseCode);
}

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,33 +21,37 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef _PUSHTARGET_H
#define _PUSHTARGET_H
#ifndef SRC_PUSHTARGET_HPP_
#define SRC_PUSHTARGET_HPP_
// Includes
#include "helper.h"
#include <Arduino.h>
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <helper.hpp>
// Classes
class PushTarget {
private:
unsigned long ms; // Used to check that we do not post to often
uint32_t ms; // Used to check that we do not post to often
void sendBrewfather(float angle, float gravity, float corrGravity, float temp );
void sendHttp(String serverPath, float angle, float gravity, float corrGravity, float temp, float runTime);
void sendInfluxDb2(float angle, float gravity, float corrGravity, float temp, float runTime);
void sendBrewfather(float angle, float gravity, float corrGravity,
float temp);
void sendHttp(String serverPath, float angle, float gravity,
float corrGravity, float temp, float runTime);
void sendInfluxDb2(float angle, float gravity, float corrGravity, float temp,
float runTime);
public:
PushTarget() { ms = millis(); }
void send(float angle, float gravity, float corrGravity, float temp, float runTime, bool force = false );
void send(float angle, float gravity, float corrGravity, float temp,
float runTime, bool force = false);
};
extern PushTarget myPushTarget;
#endif // _PUSHTARGET_H
#endif // SRC_PUSHTARGET_HPP_
// EOF

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,20 +21,19 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "tempsensor.h"
#include "helper.h"
#include "config.h"
#include "gyro.h"
#include <onewire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <onewire.h>
#include <config.hpp>
#include <gyro.hpp>
#include <helper.hpp>
#include <tempsensor.hpp>
//
// Conversion between C and F
//
float convertCtoF( float t ) {
return (t * 1.8 ) + 32.0;
}
float convertCtoF(float t) { return (t * 1.8) + 32.0; }
#if !defined(USE_GYRO_TEMP)
OneWire myOneWire(D6);
@ -48,7 +47,6 @@ TempSensor myTempSensor;
// Setup temp sensors
//
void TempSensor::setup() {
#if defined(SIMULATE_TEMP)
hasSensors = true;
return;
@ -64,7 +62,8 @@ void TempSensor::setup() {
if (mySensors.getDS18Count()) {
#if !defined(TSEN_DISABLE_LOGGING)
Log.notice(F("TSEN: Found %d temperature sensor(s)." CR), mySensors.getDS18Count());
Log.notice(F("TSEN: Found %d temperature sensor(s)." CR),
mySensors.getDS18Count());
#endif
mySensors.setResolution(TEMPERATURE_PRECISION);
}
@ -82,7 +81,8 @@ void TempSensor::setup() {
}
#if LOG_LEVEL == 6 && !defined(TSEN_DISABLE_LOGGING)
Log.verbose(F("TSEN: Adjustment values for temp sensor %F C, %F F." CR), tempSensorAdjC, tempSensorAdjF );
Log.verbose(F("TSEN: Adjustment values for temp sensor %F C, %F F." CR),
tempSensorAdjC, tempSensorAdjF);
#endif
}
@ -95,8 +95,8 @@ float TempSensor::getValue() {
#endif
#if defined(USE_GYRO_TEMP)
// When using the gyro temperature only the first read value will be accurate so we will use this for processing.
//LOG_PERF_START("temp-get");
// When using the gyro temperature only the first read value will be accurate
// so we will use this for processing. LOG_PERF_START("temp-get");
float c = myGyro.getInitialSensorTempC();
// LOG_PERF_STOP("temp-get");
hasSensor = true;

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,8 +21,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef _TEMPSENSOR_H
#define _TEMPSENSOR_H
#ifndef SRC_TEMPSENSOR_HPP_
#define SRC_TEMPSENSOR_HPP_
// definitions
float convertCtoF(float t);
@ -37,14 +37,14 @@ class TempSensor {
public:
void setup();
bool isSensorAttached() { return hasSensor; };
bool isSensorAttached() { return hasSensor; }
float getTempC() { return getValue() + tempSensorAdjC; }
float getTempF() { return convertCtoF(getValue()) + tempSensorAdjF; };
float getTempF() { return convertCtoF(getValue()) + tempSensorAdjF; }
};
// Global instance created
extern TempSensor myTempSensor;
#endif // _TEMPSENSOR_H
#endif // SRC_TEMPSENSOR_HPP_
// EOF

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,15 +21,16 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "webserver.h"
#include "config.h"
#include "helper.h"
#include "gyro.h"
#include "calc.h"
#include "tempsensor.h"
#include <ArduinoJson.h>
#include <LittleFS.h>
#include <calc.hpp>
#include <config.hpp>
#include <gyro.hpp>
#include <helper.hpp>
#include <tempsensor.hpp>
#include <webserver.hpp>
WebServer myWebServer; // My wrapper class fr webserver functions
extern bool sleepModeActive;
extern bool sleepModeAlwaysSkip;
@ -74,7 +75,9 @@ void WebServer::webHandleConfig() {
doc[CFG_PARAM_ANGLE] = reduceFloatPrecision(angle);
if (myConfig.isGravityTempAdj())
doc[ CFG_PARAM_GRAVITY ] = reduceFloatPrecision( gravityTemperatureCorrection( gravity, temp, myConfig.getTempFormat() ), 4);
doc[CFG_PARAM_GRAVITY] = reduceFloatPrecision(
gravityTemperatureCorrection(gravity, temp, myConfig.getTempFormat()),
4);
else
doc[CFG_PARAM_GRAVITY] = reduceFloatPrecision(gravity, 4);
doc[CFG_PARAM_BATTERY] = reduceFloatPrecision(myBatteryVoltage.getVoltage());
@ -125,23 +128,29 @@ void WebServer::webHandleUploadFile() {
String f = upload.filename;
bool validFilename = false;
if( f.equalsIgnoreCase("index.min.htm") || f.equalsIgnoreCase("device.min.htm") || f.equalsIgnoreCase("calibration.min.htm") ||
f.equalsIgnoreCase("config.min.htm") || f.equalsIgnoreCase("about.min.htm") ) {
if (f.equalsIgnoreCase("index.min.htm") ||
f.equalsIgnoreCase("device.min.htm") ||
f.equalsIgnoreCase("calibration.min.htm") ||
f.equalsIgnoreCase("config.min.htm") ||
f.equalsIgnoreCase("about.min.htm")) {
validFilename = true;
}
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.debug(F("WEB : webServer callback for /api/upload, receiving file %s, valid=%s." CR), f.c_str(), validFilename?"yes":"no");
Log.debug(F("WEB : webServer callback for /api/upload, receiving file %s, "
"valid=%s." CR),
f.c_str(), validFilename ? "yes" : "no");
#endif
if (upload.status == UPLOAD_FILE_START) {
Log.notice(F("WEB : Start upload." CR));
if( validFilename )
uploadFile = LittleFS.open( f, "w");
if (validFilename) uploadFile = LittleFS.open(f, "w");
} else if (upload.status == UPLOAD_FILE_WRITE) {
Log.notice(F("WEB : Writing upload." CR));
if (uploadFile)
uploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file
uploadFile.write(
upload.buf,
upload.currentSize); // Write the received bytes to the file
} else if (upload.status == UPLOAD_FILE_END) {
Log.notice(F("WEB : Finish upload." CR));
if (uploadFile) {
@ -165,7 +174,8 @@ void WebServer::webHandleCalibrate() {
Log.notice(F("WEB : webServer callback for /api/calibrate." CR));
if (!id.equalsIgnoreCase(myConfig.getID())) {
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID());
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(),
myConfig.getID());
server->send(400, "text/plain", "Invalid ID.");
LOG_PERF_STOP("webserver-api-calibrate");
return;
@ -209,7 +219,9 @@ void WebServer::webHandleStatus() {
doc[CFG_PARAM_ID] = myConfig.getID();
doc[CFG_PARAM_ANGLE] = reduceFloatPrecision(angle);
if (myConfig.isGravityTempAdj())
doc[ CFG_PARAM_GRAVITY ] = reduceFloatPrecision( gravityTemperatureCorrection( gravity, temp, myConfig.getTempFormat() ), 4);
doc[CFG_PARAM_GRAVITY] = reduceFloatPrecision(
gravityTemperatureCorrection(gravity, temp, myConfig.getTempFormat()),
4);
else
doc[CFG_PARAM_GRAVITY] = reduceFloatPrecision(gravity, 4);
doc[CFG_PARAM_TEMP_C] = reduceFloatPrecision(temp, 1);
@ -238,7 +250,8 @@ void WebServer::webHandleClearWIFI() {
Log.notice(F("WEB : webServer callback for /api/clearwifi." CR));
if (!id.compareTo(myConfig.getID())) {
server->send(200, "text/plain", "Clearing WIFI credentials and doing reset...");
server->send(200, "text/plain",
"Clearing WIFI credentials and doing reset...");
delay(1000);
WiFi.disconnect(); // Clear credentials
ESP.reset();
@ -256,14 +269,16 @@ void WebServer::webHandleStatusSleepmode() {
Log.notice(F("WEB : webServer callback for /api/status/sleepmode." CR));
if (!id.equalsIgnoreCase(myConfig.getID())) {
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID());
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(),
myConfig.getID());
server->send(400, "text/plain", "Invalid ID.");
LOG_PERF_STOP("webserver-api-sleepmode");
return;
}
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : sleep-mode=%s." CR), server->arg( CFG_PARAM_SLEEP_MODE ).c_str() );
Log.verbose(F("WEB : sleep-mode=%s." CR),
server->arg(CFG_PARAM_SLEEP_MODE).c_str());
#endif
if (server->arg(CFG_PARAM_SLEEP_MODE).equalsIgnoreCase("true"))
@ -283,14 +298,17 @@ void WebServer::webHandleConfigDevice() {
Log.notice(F("WEB : webServer callback for /api/config/device." CR));
if (!id.equalsIgnoreCase(myConfig.getID())) {
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID());
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(),
myConfig.getID());
server->send(400, "text/plain", "Invalid ID.");
LOG_PERF_STOP("webserver-api-config-device");
return;
}
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : mdns=%s, temp-format=%s." CR), server->arg( CFG_PARAM_MDNS ).c_str(), server->arg( CFG_PARAM_TEMPFORMAT ).c_str() );
Log.verbose(F("WEB : mdns=%s, temp-format=%s." CR),
server->arg(CFG_PARAM_MDNS).c_str(),
server->arg(CFG_PARAM_TEMPFORMAT).c_str());
#endif
myConfig.setMDNS(server->arg(CFG_PARAM_MDNS).c_str());
@ -311,26 +329,33 @@ void WebServer::webHandleConfigPush() {
Log.notice(F("WEB : webServer callback for /api/config/push." CR));
if (!id.equalsIgnoreCase(myConfig.getID())) {
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID());
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(),
myConfig.getID());
server->send(400, "text/plain", "Invalid ID.");
LOG_PERF_STOP("webserver-api-config-push");
return;
}
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : http=%s,%s, bf=%s influx2=%s, %s, %s, %s." CR), server->arg( CFG_PARAM_PUSH_HTTP ).c_str(),
server->arg( CFG_PARAM_PUSH_HTTP2 ).c_str(), server->arg( CFG_PARAM_PUSH_BREWFATHER ).c_str(),
server->arg( CFG_PARAM_PUSH_INFLUXDB2 ).c_str(), server->arg( CFG_PARAM_PUSH_INFLUXDB2_ORG ).c_str(),
server->arg( CFG_PARAM_PUSH_INFLUXDB2_BUCKET ).c_str(), server->arg( CFG_PARAM_PUSH_INFLUXDB2_AUTH ).c_str()
);
Log.verbose(F("WEB : http=%s,%s, bf=%s influx2=%s, %s, %s, %s." CR),
server->arg(CFG_PARAM_PUSH_HTTP).c_str(),
server->arg(CFG_PARAM_PUSH_HTTP2).c_str(),
server->arg(CFG_PARAM_PUSH_BREWFATHER).c_str(),
server->arg(CFG_PARAM_PUSH_INFLUXDB2).c_str(),
server->arg(CFG_PARAM_PUSH_INFLUXDB2_ORG).c_str(),
server->arg(CFG_PARAM_PUSH_INFLUXDB2_BUCKET).c_str(),
server->arg(CFG_PARAM_PUSH_INFLUXDB2_AUTH).c_str());
#endif
myConfig.setHttpPushUrl(server->arg(CFG_PARAM_PUSH_HTTP).c_str());
myConfig.setHttpPushUrl2(server->arg(CFG_PARAM_PUSH_HTTP2).c_str());
myConfig.setBrewfatherPushUrl(server->arg(CFG_PARAM_PUSH_BREWFATHER).c_str());
myConfig.setInfluxDb2PushUrl(server->arg(CFG_PARAM_PUSH_INFLUXDB2).c_str());
myConfig.setInfluxDb2PushOrg( server->arg( CFG_PARAM_PUSH_INFLUXDB2_ORG ).c_str() );
myConfig.setInfluxDb2PushBucket( server->arg( CFG_PARAM_PUSH_INFLUXDB2_BUCKET ).c_str() );
myConfig.setInfluxDb2PushToken( server->arg( CFG_PARAM_PUSH_INFLUXDB2_AUTH ).c_str() );
myConfig.setInfluxDb2PushOrg(
server->arg(CFG_PARAM_PUSH_INFLUXDB2_ORG).c_str());
myConfig.setInfluxDb2PushBucket(
server->arg(CFG_PARAM_PUSH_INFLUXDB2_BUCKET).c_str());
myConfig.setInfluxDb2PushToken(
server->arg(CFG_PARAM_PUSH_INFLUXDB2_AUTH).c_str());
myConfig.saveFile();
server->sendHeader("Location", "/config.htm#collapseTwo", true);
server->send(302, "text/plain", "Push config updated");
@ -346,18 +371,23 @@ void WebServer::webHandleConfigGravity() {
Log.notice(F("WEB : webServer callback for /api/config/gravity." CR));
if (!id.equalsIgnoreCase(myConfig.getID())) {
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID());
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(),
myConfig.getID());
server->send(400, "text/plain", "Invalid ID.");
LOG_PERF_STOP("webserver-api-config-gravity");
return;
}
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : formula=%s, temp-corr=%s." CR), server->arg( CFG_PARAM_GRAVITY_FORMULA ).c_str(), server->arg( CFG_PARAM_GRAVITY_TEMP_ADJ ).c_str() );
Log.verbose(F("WEB : formula=%s, temp-corr=%s." CR),
server->arg(CFG_PARAM_GRAVITY_FORMULA).c_str(),
server->arg(CFG_PARAM_GRAVITY_TEMP_ADJ).c_str());
#endif
myConfig.setGravityFormula(server->arg(CFG_PARAM_GRAVITY_FORMULA).c_str());
myConfig.setGravityTempAdj( server->arg( CFG_PARAM_GRAVITY_TEMP_ADJ ).equalsIgnoreCase( "on" ) ? true:false);
myConfig.setGravityTempAdj(
server->arg(CFG_PARAM_GRAVITY_TEMP_ADJ).equalsIgnoreCase("on") ? true
: false);
myConfig.saveFile();
server->sendHeader("Location", "/config.htm#collapseThree", true);
server->send(302, "text/plain", "Gravity config updated");
@ -373,14 +403,18 @@ void WebServer::webHandleConfigHardware() {
Log.notice(F("WEB : webServer callback for /api/config/hardware." CR));
if (!id.equalsIgnoreCase(myConfig.getID())) {
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID());
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(),
myConfig.getID());
server->send(400, "text/plain", "Invalid ID.");
LOG_PERF_STOP("webserver-api-config-hardware");
return;
}
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : vf=%s, tempadj=%s, ota=%s." CR), server->arg( CFG_PARAM_VOLTAGEFACTOR ).c_str(), server->arg( CFG_PARAM_TEMP_ADJ ).c_str(), server->arg( CFG_PARAM_OTA ).c_str() );
Log.verbose(F("WEB : vf=%s, tempadj=%s, ota=%s." CR),
server->arg(CFG_PARAM_VOLTAGEFACTOR).c_str(),
server->arg(CFG_PARAM_TEMP_ADJ).c_str(),
server->arg(CFG_PARAM_OTA).c_str());
#endif
myConfig.setVoltageFactor(server->arg(CFG_PARAM_VOLTAGEFACTOR).toFloat());
@ -403,8 +437,10 @@ void WebServer::webHandleFormulaRead() {
const RawFormulaData& fd = myConfig.getFormulaData();
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : %F %F %F %F %F." CR), fd.a[0], fd.a[1], fd.a[2], fd.a[3], fd.a[4] );
Log.verbose(F("WEB : %F %F %F %F %F." CR), fd.g[0], fd.g[1], fd.g[2], fd.g[3], fd.g[4] );
Log.verbose(F("WEB : %F %F %F %F %F." CR), fd.a[0], fd.a[1], fd.a[2], fd.a[3],
fd.a[4]);
Log.verbose(F("WEB : %F %F %F %F %F." CR), fd.g[0], fd.g[1], fd.g[2], fd.g[3],
fd.g[4]);
#endif
doc[CFG_PARAM_ID] = myConfig.getID();
@ -418,7 +454,8 @@ void WebServer::webHandleFormulaRead() {
doc[CFG_PARAM_GRAVITY_FORMULA] = "Not enough values to create formula.";
break;
case ERR_FORMULA_UNABLETOFFIND:
doc[ CFG_PARAM_GRAVITY_FORMULA ] = "Unable to find an accurate formula based on input.";
doc[CFG_PARAM_GRAVITY_FORMULA] =
"Unable to find an accurate formula based on input.";
break;
default:
doc[CFG_PARAM_GRAVITY_FORMULA] = myConfig.getGravityFormula();
@ -457,15 +494,21 @@ void WebServer::webHandleFormulaWrite() {
Log.notice(F("WEB : webServer callback for /api/formula/post." CR));
if (!id.equalsIgnoreCase(myConfig.getID())) {
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID());
Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(),
myConfig.getID());
server->send(400, "text/plain", "Invalid ID.");
LOG_PERF_STOP("webserver-api-formula-write");
return;
}
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : angles=%F,%F,%F,%F,%F." CR), server->arg( "a1" ).toFloat(), server->arg( "a2" ).toFloat(), server->arg( "a3" ).toFloat(), server->arg( "a4" ).toFloat(), server->arg( "a5" ).toFloat() );
Log.verbose(F("WEB : gravity=%F,%F,%F,%F,%F." CR), server->arg( "g1" ).toFloat(), server->arg( "g2" ).toFloat(), server->arg( "g3" ).toFloat(), server->arg( "g4" ).toFloat(), server->arg( "g5" ).toFloat() );
Log.verbose(F("WEB : angles=%F,%F,%F,%F,%F." CR), server->arg("a1").toFloat(),
server->arg("a2").toFloat(), server->arg("a3").toFloat(),
server->arg("a4").toFloat(), server->arg("a5").toFloat());
Log.verbose(F("WEB : gravity=%F,%F,%F,%F,%F." CR),
server->arg("g1").toFloat(), server->arg("g2").toFloat(),
server->arg("g3").toFloat(), server->arg("g4").toFloat(),
server->arg("g5").toFloat());
#endif
RawFormulaData fd;
@ -484,23 +527,25 @@ void WebServer::webHandleFormulaWrite() {
int e;
char buf[100];
e = createFormula( fd, &buf[0], 2 );
e = createFormula(fd, &buf[0], sizeof(buf), 2);
if (e) {
// If we fail with order=2 try with 3
Log.warning(F("WEB : Failed to find formula with order 3." CR), e);
e = createFormula( fd, &buf[0], 3 );
e = createFormula(fd, &buf[0], sizeof(buf), 3);
}
if (e) {
// If we fail with order=3 try with 4
Log.warning(F("WEB : Failed to find formula with order 4." CR), e);
e = createFormula( fd, &buf[0], 4 );
e = createFormula(fd, &buf[0], sizeof(buf), 4);
}
if (e) {
// If we fail with order=4 then we mark it as failed
Log.error(F("WEB : Unable to find formula based on provided values err=%d." CR), e );
Log.error(
F("WEB : Unable to find formula based on provided values err=%d." CR),
e);
lastFormulaCreateError = e;
} else {
// Save the formula as succesful
@ -546,7 +591,8 @@ bool WebServer::checkHtmlFile( HtmlFile item ) {
Log.verbose(F("WEB : Checking for file %s." CR), fn);
#endif
// TODO: We might need to add more checks here like zero file size etc. But for now we only check if the file exist.
// TODO: We might need to add more checks here like zero file size etc. But
// for now we only check if the file exist.
return LittleFS.exists(fn);
}
@ -554,8 +600,7 @@ bool WebServer::checkHtmlFile( HtmlFile item ) {
//
// Handler for page not found
//
void WebServer::webHandlePageNotFound()
{
void WebServer::webHandlePageNotFound() {
Log.error(F("WEB : URL not found %s received." CR), server->uri().c_str());
server->send(404, "text/plain", F("URL not found"));
}
@ -577,21 +622,27 @@ bool WebServer::setupWebServer() {
server->on("/index.htm", std::bind(&WebServer::webReturnIndexHtm, this));
server->on("/device.htm", std::bind(&WebServer::webReturnDeviceHtm, this));
server->on("/config.htm", std::bind(&WebServer::webReturnConfigHtm, this));
server->on("/calibration.htm", std::bind(&WebServer::webReturnCalibrationHtm, this) );
server->on("/calibration.htm",
std::bind(&WebServer::webReturnCalibrationHtm, this));
server->on("/about.htm", std::bind(&WebServer::webReturnAboutHtm, this));
#else
// Show files in the filessytem at startup
FSInfo fs;
LittleFS.info(fs);
Log.notice( F("WEB : File system Total=%d, Used=%d." CR), fs.totalBytes, fs.usedBytes );
Log.notice(F("WEB : File system Total=%d, Used=%d." CR), fs.totalBytes,
fs.usedBytes);
Dir dir = LittleFS.openDir("/");
while (dir.next()) {
Log.notice( F("WEB : File=%s, %d bytes" CR), dir.fileName().c_str(), dir.fileSize() );
Log.notice(F("WEB : File=%s, %d bytes" CR), dir.fileName().c_str(),
dir.fileSize());
}
// Check if the html files exist, if so serve them, else show the static upload page.
if( checkHtmlFile( HTML_INDEX ) && checkHtmlFile( HTML_DEVICE ) && checkHtmlFile( HTML_CONFIG ) && checkHtmlFile( HTML_ABOUT ) ) {
// Check if the html files exist, if so serve them, else show the static
// upload page.
if (checkHtmlFile(HTML_INDEX) && checkHtmlFile(HTML_DEVICE) &&
checkHtmlFile(HTML_CONFIG) && checkHtmlFile(HTML_CALIBRATION) &&
checkHtmlFile(HTML_ABOUT)) {
Log.notice(F("WEB : All html files exist, starting in normal mode." CR));
server->serveStatic("/", LittleFS, "/index.min.htm");
@ -601,7 +652,8 @@ bool WebServer::setupWebServer() {
server->serveStatic("/about.htm", LittleFS, "/about.min.htm");
server->serveStatic("/calibration.htm", LittleFS, "/calibration.min.htm");
// Also add the static upload view in case we we have issues that needs to be fixed.
// Also add the static upload view in case we we have issues that needs to
// be fixed.
server->on("/upload.htm", std::bind(&WebServer::webReturnUploadHtm, this));
} else {
Log.error(F("WEB : Missing html files, starting with upload UI." CR));
@ -610,22 +662,49 @@ bool WebServer::setupWebServer() {
#endif
// Dynamic content
server->on("/api/config", HTTP_GET, std::bind(&WebServer::webHandleConfig, this) ); // Get config.json
server->on("/api/device", HTTP_GET, std::bind(&WebServer::webHandleDevice, this)); // Get device.json
server->on("/api/formula", HTTP_GET, std::bind(&WebServer::webHandleFormulaRead, this)); // Get formula.json (calibration page)
server->on("/api/formula", HTTP_POST, std::bind(&WebServer::webHandleFormulaWrite, this)); // Get formula.json (calibration page)
server->on("/api/calibrate", HTTP_POST, std::bind(&WebServer::webHandleCalibrate, this)); // Run calibration routine (param id)
server->on("/api/factory", HTTP_GET, std::bind(&WebServer::webHandleFactoryReset, this)); // Reset the device
server->on("/api/status", HTTP_GET, std::bind(&WebServer::webHandleStatus, this)); // Get the status.json
server->on("/api/clearwifi", HTTP_GET, std::bind(&WebServer::webHandleClearWIFI, this)); // Clear wifi settings
server->on("/api/upload", HTTP_GET, std::bind(&WebServer::webHandleUpload, this)); // Get upload.json
server->on("/api/config", HTTP_GET,
std::bind(&WebServer::webHandleConfig, this)); // Get config.json
server->on("/api/device", HTTP_GET,
std::bind(&WebServer::webHandleDevice, this)); // Get device.json
server->on("/api/formula", HTTP_GET,
std::bind(&WebServer::webHandleFormulaRead,
this)); // Get formula.json (calibration page)
server->on("/api/formula", HTTP_POST,
std::bind(&WebServer::webHandleFormulaWrite,
this)); // Get formula.json (calibration page)
server->on("/api/calibrate", HTTP_POST,
std::bind(&WebServer::webHandleCalibrate,
this)); // Run calibration routine (param id)
server->on(
"/api/factory", HTTP_GET,
std::bind(&WebServer::webHandleFactoryReset, this)); // Reset the device
server->on(
"/api/status", HTTP_GET,
std::bind(&WebServer::webHandleStatus, this)); // Get the status.json
server->on(
"/api/clearwifi", HTTP_GET,
std::bind(&WebServer::webHandleClearWIFI, this)); // Clear wifi settings
server->on("/api/upload", HTTP_GET,
std::bind(&WebServer::webHandleUpload, this)); // Get upload.json
server->on("/api/upload", HTTP_POST, std::bind(&WebServer::webReturnOK, this), std::bind(&WebServer::webHandleUploadFile, this)); // File upload data
server->on("/api/status/sleepmode", HTTP_POST, std::bind(&WebServer::webHandleStatusSleepmode, this)); // Change sleep mode
server->on("/api/config/device", HTTP_POST, std::bind(&WebServer::webHandleConfigDevice, this)); // Change device settings
server->on("/api/config/push", HTTP_POST, std::bind(&WebServer::webHandleConfigPush, this)); // Change push settings
server->on("/api/config/gravity", HTTP_POST, std::bind(&WebServer::webHandleConfigGravity, this)); // Change gravity settings
server->on("/api/config/hardware", HTTP_POST, std::bind(&WebServer::webHandleConfigHardware, this)); // Change hardware settings
server->on(
"/api/upload", HTTP_POST, std::bind(&WebServer::webReturnOK, this),
std::bind(&WebServer::webHandleUploadFile, this)); // File upload data
server->on("/api/status/sleepmode", HTTP_POST,
std::bind(&WebServer::webHandleStatusSleepmode,
this)); // Change sleep mode
server->on("/api/config/device", HTTP_POST,
std::bind(&WebServer::webHandleConfigDevice,
this)); // Change device settings
server->on("/api/config/push", HTTP_POST,
std::bind(&WebServer::webHandleConfigPush,
this)); // Change push settings
server->on("/api/config/gravity", HTTP_POST,
std::bind(&WebServer::webHandleConfigGravity,
this)); // Change gravity settings
server->on("/api/config/hardware", HTTP_POST,
std::bind(&WebServer::webHandleConfigHardware,
this)); // Change hardware settings
server->onNotFound(std::bind(&WebServer::webHandlePageNotFound, this));
server->begin();

View File

@ -1,100 +0,0 @@
/*
MIT License
Copyright (c) 2021 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef _WEBSERVER_H
#define _WEBSERVER_H
// Include
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <incbin.h>
// Binary resouces
#if defined( EMBED_HTML )
INCBIN_EXTERN(IndexHtm);
INCBIN_EXTERN(DeviceHtm);
INCBIN_EXTERN(ConfigHtm);
INCBIN_EXTERN(CalibrationHtm);
INCBIN_EXTERN(AboutHtm);
#else
INCBIN_EXTERN(UploadHtm);
#endif
// classes
class WebServer {
private:
ESP8266WebServer *server = 0;
File uploadFile;
int lastFormulaCreateError = 0;
void webHandleConfig();
void webHandleFormulaWrite();
void webHandleFormulaRead();
void webHandleConfigHardware();
void webHandleConfigGravity();
void webHandleConfigPush();
void webHandleConfigDevice();
void webHandleStatusSleepmode();
void webHandleClearWIFI();
void webHandleStatus();
void webHandleFactoryReset();
void webHandleCalibrate();
void webHandleUploadFile();
void webHandleUpload();
void webHandleDevice();
void webHandlePageNotFound();
// Inline functions.
void webReturnOK() { server->send(200); }
#if defined( EMBED_HTML )
void webReturnIndexHtm() { server->send_P(200, "text/html", (const char*) gIndexHtmData, gIndexHtmSize ); }
void webReturnDeviceHtm() { server->send_P(200, "text/html", (const char*) gDeviceHtmData, gDeviceHtmSize ); }
void webReturnConfigHtm() { server->send_P(200, "text/html", (const char*) gConfigHtmData, gConfigHtmSize ); }
void webReturnCalibrationHtm() { server->send_P(200, "text/html", (const char*) gCalibrationHtmData, gCalibrationHtmSize ); }
void webReturnAboutHtm() { server->send_P(200, "text/html", (const char*) gAboutHtmData, gAboutHtmSize ); }
#else
void webReturnUploadHtm() { server->send_P(200, "text/html", (const char*) gUploadHtmData, gUploadHtmSize ); }
#endif
public:
enum HtmlFile {
HTML_INDEX = 0,
HTML_DEVICE = 1,
HTML_CONFIG = 2,
HTML_ABOUT = 3,
HTML_CALIBRATION = 4
};
bool setupWebServer();
void loop();
bool checkHtmlFile( HtmlFile item );
const char* getHtmlFileName( HtmlFile item );
};
// Global instance created
extern WebServer myWebServer;
#endif // _WEBSERVER_H
// EOF

116
src/webserver.hpp Normal file
View File

@ -0,0 +1,116 @@
/*
MIT License
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef SRC_WEBSERVER_HPP_
#define SRC_WEBSERVER_HPP_
// Include
#include <ESP8266WebServer.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <incbin.h>
// Binary resouces
#if defined(EMBED_HTML)
INCBIN_EXTERN(IndexHtm);
INCBIN_EXTERN(DeviceHtm);
INCBIN_EXTERN(ConfigHtm);
INCBIN_EXTERN(CalibrationHtm);
INCBIN_EXTERN(AboutHtm);
#else
INCBIN_EXTERN(UploadHtm);
#endif
// classes
class WebServer {
private:
ESP8266WebServer* server = 0;
File uploadFile;
int lastFormulaCreateError = 0;
void webHandleConfig();
void webHandleFormulaWrite();
void webHandleFormulaRead();
void webHandleConfigHardware();
void webHandleConfigGravity();
void webHandleConfigPush();
void webHandleConfigDevice();
void webHandleStatusSleepmode();
void webHandleClearWIFI();
void webHandleStatus();
void webHandleFactoryReset();
void webHandleCalibrate();
void webHandleUploadFile();
void webHandleUpload();
void webHandleDevice();
void webHandlePageNotFound();
// Inline functions.
void webReturnOK() { server->send(200); }
#if defined(EMBED_HTML)
void webReturnIndexHtm() {
server->send_P(200, "text/html", (const char*)gIndexHtmData, gIndexHtmSize);
}
void webReturnDeviceHtm() {
server->send_P(200, "text/html", (const char*)gDeviceHtmData,
gDeviceHtmSize);
}
void webReturnConfigHtm() {
server->send_P(200, "text/html", (const char*)gConfigHtmData,
gConfigHtmSize);
}
void webReturnCalibrationHtm() {
server->send_P(200, "text/html", (const char*)gCalibrationHtmData,
gCalibrationHtmSize);
}
void webReturnAboutHtm() {
server->send_P(200, "text/html", (const char*)gAboutHtmData, gAboutHtmSize);
}
#else
void webReturnUploadHtm() {
server->send_P(200, "text/html", (const char*)gUploadHtmData,
gUploadHtmSize);
}
#endif
public:
enum HtmlFile {
HTML_INDEX = 0,
HTML_DEVICE = 1,
HTML_CONFIG = 2,
HTML_ABOUT = 3,
HTML_CALIBRATION = 4
};
bool setupWebServer();
void loop();
bool checkHtmlFile(HtmlFile item);
const char* getHtmlFileName(HtmlFile item);
};
// Global instance created
extern WebServer myWebServer;
#endif // SRC_WEBSERVER_HPP_
// EOF

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,54 +21,62 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "wifi.h"
#include "config.h"
#include "helper.h"
#include "gyro.h"
#include "calc.h"
#include "tempsensor.h"
#include <ArduinoJson.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <WiFiManager.h>
#include <ESP8266mDNS.h>
#include <LittleFS.h>
#include <WiFiManager.h>
#include <incbin.h>
#include <calc.hpp>
#include <config.hpp>
#include <gyro.hpp>
#include <helper.hpp>
#include <tempsensor.hpp>
#include <wifi.hpp>
Wifi myWifi;
const char *userSSID = USER_SSID;
const char *userPWD = USER_SSID_PWD;
//
// Connect to last known access point or create one if connection is not working.
// Connect to last known access point or create one if connection is not
// working.
//
bool Wifi::connect(bool showPortal) {
WiFi.persistent(true);
WiFi.mode(WIFI_STA);
if (!strlen(myConfig.getWifiSSID())) {
Log.info(F("WIFI: No SSID seams to be stored, forcing portal to start." CR));
Log.info(
F("WIFI: No SSID seams to be stored, forcing portal to start." CR));
showPortal = true;
} else {
//Log.info(F("WIFI: Using SSID=%s and %s." CR), myConfig.getWifiSSID(), myConfig.getWifiPass() );
//Log.info(F("WIFI: Using SSID=%s and %s." CR), myConfig.getWifiSSID(), "*****" );
// Log.info(F("WIFI: Using SSID=%s and %s." CR), myConfig.getWifiSSID(),
// myConfig.getWifiPass()); Log.info(F("WIFI: Using SSID=%s and %s." CR),
// myConfig.getWifiSSID(), "*****");
}
if (strlen(userSSID) == 0 && showPortal) {
#if LOG_LEVEL == 6
Log.verbose(F("WIFI: Connecting to WIFI via connection manager (portal=%s)." CR), showPortal?"true":"false");
Log.verbose(
F("WIFI: Connecting to WIFI via connection manager (portal=%s)." CR),
showPortal ? "true" : "false");
#endif
WiFiManager myWifiManager;
Log.notice(F("WIFI: Starting wifi portal." CR));
myWifiManager.setDebugOutput(true);
myWifiManager.setClass("invert");
myWifiManager.setConfigPortalTimeout(120); // Keep it open for 120 seconds
bool f = myWifiManager.startConfigPortal( WIFI_DEFAULT_SSID, WIFI_DEFAULT_PWD );
bool f =
myWifiManager.startConfigPortal(WIFI_DEFAULT_SSID, WIFI_DEFAULT_PWD);
if (f) {
//Log.notice(F("WIFI: Success got values from WIFI portal=%s,%s." CR), myWifiManager.getWiFiSSID(), myWifiManager.getWiFiPass() );
Log.notice(F("WIFI: Success got values from WIFI portal=%s,%s." CR), myWifiManager.getWiFiSSID(), "*****" );
// Log.notice(F("WIFI: Success got values from WIFI portal=%s,%s." CR),
// myWifiManager.getWiFiSSID(), myWifiManager.getWiFiPass() );
Log.notice(F("WIFI: Success got values from WIFI portal=%s,%s." CR),
myWifiManager.getWiFiSSID(), "*****");
myConfig.setWifiSSID(myWifiManager.getWiFiSSID());
myConfig.setWifiPass(myWifiManager.getWiFiPass());
myConfig.saveFile();
@ -82,13 +90,16 @@ bool Wifi::connect( bool showPortal ) {
// Connect to wifi
int i = 0;
//Log.notice(F("WIFI: Connecting to WIFI, mode=%d,persistent=%d,fhy=%d ." CR), WiFi.getMode(), WiFi.getPersistent(), WiFi.getPhyMode() );
// Log.notice(F("WIFI: Connecting to WIFI, mode=%d,persistent=%d,fhy=%d ."
// CR), WiFi.getMode(), WiFi.getPersistent(), WiFi.getPhyMode() );
WiFi.mode(WIFI_STA);
if (strlen(userSSID)) {
Log.notice(F("WIFI: Connecting to wifi using hardcoded settings %s." CR), userSSID);
Log.notice(F("WIFI: Connecting to wifi using hardcoded settings %s." CR),
userSSID);
WiFi.begin(userSSID, userPWD);
} else {
Log.notice(F("WIFI: Connecting to wifi using stored settings %s." CR), myConfig.getWifiSSID());
Log.notice(F("WIFI: Connecting to wifi using stored settings %s." CR),
myConfig.getWifiSSID());
WiFi.begin(myConfig.getWifiSSID(), myConfig.getWifiPass());
}
@ -99,7 +110,8 @@ bool Wifi::connect( bool showPortal ) {
Serial.print(".");
if (i++ > 100) { // Try for 20 seconds.
Log.error(F("WIFI: Failed to connect to wifi %d, aborting %s." CR), WiFi.status(), getIPAddress().c_str() );
Log.error(F("WIFI: Failed to connect to wifi %d, aborting %s." CR),
WiFi.status(), getIPAddress().c_str());
WiFi.disconnect();
return connectedFlag; // Return to main that we have failed to connect.
}
@ -112,7 +124,8 @@ bool Wifi::connect( bool showPortal ) {
}
//
// This will erase the stored credentials and forcing the WIFI manager to AP mode.
// This will erase the stored credentials and forcing the WIFI manager to AP
// mode.
//
bool Wifi::disconnect() {
Log.notice(F("WIFI: Erasing stored WIFI credentials." CR));
@ -142,7 +155,9 @@ bool Wifi::updateFirmware() {
switch (ret) {
case HTTP_UPDATE_FAILED:
Log.error(F("WIFI: OTA update failed %d, %s." CR), ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
Log.error(F("WIFI: OTA update failed %d, %s." CR),
ESPhttpUpdate.getLastError(),
ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
break;
@ -177,7 +192,8 @@ void Wifi::downloadFile(const char *fname) {
f.close();
Log.notice(F("WIFI: Downloaded file %s." CR), fname);
} else {
Log.error(F("WIFI: Failed to download file, respone=%d" CR), httpResponseCode);
Log.error(F("WIFI: Failed to download file, respone=%d" CR),
httpResponseCode);
}
http.end();
}
@ -213,7 +229,8 @@ bool Wifi::checkFirmwareVersion() {
Log.error(F("WIFI: Failed to parse version.json, %s" CR), err);
} else {
#if LOG_LEVEL == 6
Log.verbose(F("WIFI: Project %s version %s." CR), (const char*) ver["project"], (const char*) ver["version"]);
Log.verbose(F("WIFI: Project %s version %s." CR),
(const char *)ver["project"], (const char *)ver["version"]);
#endif
int newVer[3];
int curVer[3];
@ -221,16 +238,18 @@ bool Wifi::checkFirmwareVersion() {
if (parseFirmwareVersionString(newVer, (const char *)ver["version"])) {
if (parseFirmwareVersionString(curVer, CFG_APPVER)) {
#if LOG_LEVEL == 6
Log.verbose(F("WIFI: OTA checking new=%d.%d.%d cur=%d.%d.%d" CR), newVer[0], newVer[1], newVer[2], curVer[0], curVer[1], curVer[2] );
Log.verbose(F("WIFI: OTA checking new=%d.%d.%d cur=%d.%d.%d" CR),
newVer[0], newVer[1], newVer[2], curVer[0], curVer[1],
curVer[2]);
#endif
// Compare major version
if( newVer[0] > curVer[0] )
newFirmware = true;
if (newVer[0] > curVer[0]) newFirmware = true;
// Compare minor version
if (newVer[0] == curVer[0] && newVer[1] > curVer[1])
newFirmware = true;
// Compare patch version
if( newVer[0] == curVer[0] && newVer[1] == curVer[1] && newVer[2] > curVer[2] )
if (newVer[0] == curVer[0] && newVer[1] == curVer[1] &&
newVer[2] > curVer[2])
newFirmware = true;
}
}
@ -249,11 +268,13 @@ bool Wifi::checkFirmwareVersion() {
}
}
} else {
Log.error(F("WIFI: OTA error checking version.json, response=%d" CR), httpResponseCode);
Log.error(F("WIFI: OTA error checking version.json, response=%d" CR),
httpResponseCode);
}
http.end();
#if LOG_LEVEL == 6
Log.verbose(F("WIFI: OTA found new version %s." CR), newFirmware?"true":"false");
Log.verbose(F("WIFI: OTA found new version %s." CR),
newFirmware ? "true" : "false");
#endif
return newFirmware;
}
@ -270,7 +291,8 @@ bool Wifi::parseFirmwareVersionString( int (&num)[3], const char *version ) {
char *p = &temp[0];
int i = 0;
strcpy( &temp[0], version );
// strcpy(&temp[0], version);
snprintf(&temp[0], sizeof(temp), "%s", version);
while ((s = strtok_r(p, ".", &p)) != NULL) {
num[i++] = atoi(s);

View File

@ -1,7 +1,7 @@
/*
MIT License
Copyright (c) 2021 Magnus
Copyright (c) 2021-22 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -21,8 +21,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef _WIFI_H
#define _WIFI_H
#ifndef SRC_WIFI_HPP_
#define SRC_WIFI_HPP_
// Include
#include <ESP8266WiFi.h>
@ -42,8 +42,8 @@ class Wifi {
// WIFI
bool connect(bool showPortal = false);
bool disconnect();
bool isConnected() { return connectedFlag; };
String getIPAddress() { return WiFi.localIP().toString(); };
bool isConnected() { return connectedFlag; }
String getIPAddress() { return WiFi.localIP().toString(); }
// OTA
bool updateFirmware();
@ -53,6 +53,6 @@ class Wifi {
// Global instance created
extern Wifi myWifi;
#endif // _WIFI_H
#endif // SRC_WIFI_HPP_
// EOF