Bug fixes gravitycorr + option to use gyro temp
This commit is contained in:
parent
876718602f
commit
c1c325a2bc
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,7 +1,8 @@
|
||||
.pio/*
|
||||
.vscode/*
|
||||
*.map
|
||||
docs/*
|
||||
test/*.md
|
||||
test/env/*
|
||||
test/*.py
|
||||
TODO.md
|
||||
TODO.md
|
||||
|
49
README.md
49
README.md
@ -2,7 +2,7 @@
|
||||
|
||||
I started this project out of curiosity for how a motion sensor is working and since I like to brew beer this was the result. This software can be used with iSpindle hardware and utilizes the same hardware configuration. No code has been reused from the iSpindle project.
|
||||
|
||||
### TODO
|
||||
## TODO
|
||||
|
||||
* Add support for Plato in device (today it assumes that formula is in SG).
|
||||
* Add support for converting between SG/Plato in device.
|
||||
@ -11,25 +11,25 @@ I started this project out of curiosity for how a motion sensor is working and s
|
||||
* Add support for https web server (will require certificates to be created as part of build process)
|
||||
* Add iSpindle 3D print cradle + small PCB (what I use for my builds)
|
||||
* Validate max sleep time to 70 min (max time for ESP)
|
||||
* Check how much movement there is during fermentack (check run time) if we should go into sleep mode for a shorter time...
|
||||
* Validate the power consumption of the device using amp meter (integrated and/or separate)
|
||||
* Add option to use temperature readings from motion sensor (longer battery life)
|
||||
* Testing, Testing and more testing......
|
||||
|
||||
# Functionallity
|
||||
|
||||
I have made a few differnt design decision compared to the standard iSpindle software.
|
||||
I have made a few different design decision compared to the standard iSpindle software.
|
||||
|
||||
* All configuration options have been moved to a web gui and is accesible without using the double reset function. You only need to use this for changing the WIFI configuration. The web gui can be accessed when either the device is laying flat on a surface (90 degress) or it's beeing charged. The benefits is that it's easier to change settings and also read the angle/tilt when doing calibration. You can also change the forumla and directly see the new calculated result.
|
||||
* The device operate in two modes, __always-on__ or __deep-sleep__. Always on can be triggered in two ways: Connected to charger and the power is over 4.1V or the device is lying flat (angle is approx 90 degrees).
|
||||
|
||||
* The software also has built in OTA support so new versions can be downloaded from a local webserver (when connected to power)
|
||||
* Configuration options have been moved to a web gui and is accesible when the device is in __always-on__ mode. The Wifi portal only need to be used for changing WIFI network.
|
||||
|
||||
* Temperature calibration of DS18B20 sensor so you can adjust the temperature sensor readings.
|
||||
* The software also has built in OTA support so new versions can be downloaded from a local webserver and checks are done during startup and the device is in __always-on__ mode.
|
||||
|
||||
* Automatic temperature gravity calculation to adjust for a lower temperature in the fermentation vessels. Useful if you are fermenting at lower temperatures. It's possible to build this into the normal gravity formula but this is an easier option. Just make sure that the calibration is done at 20°C.
|
||||
* Temperature calibration has been added for the DS18B20 sensor so you can adjust the temperature sensor readings if there is a need. When the device is in __always-on__ mode the temperature will rise in the container so the value will increase and not reflect the temperature for the surronding the container.
|
||||
|
||||
* The software will read the motion sensor 50 times and use the average to calculate the angle. If the readings show that the device is moving it will wait a few seconds and retry the operation again to make sure that no invalid angles should be reported. The downside is that the device will remain running if it's moving and draw more power. For normal fermentation this should not be an issue.
|
||||
* There is an option to automatically correct the gravity calculation based on the temperature. Useful if you are fermenting at lower temperatures. It's possible to build this into the normal gravity formula but this is an easier option. Just make sure that the calibration is done at 20°C.
|
||||
|
||||
## Integrations / Sending data
|
||||
|
||||
In this version the software supports sending data to standad HTTP endpoint and Brewfather. These are the ones I use so more can be added on request.
|
||||
* The software will read the motion sensor 50 times and use the average to calculate the angle. If the readings show that the device is moving it will wait a few seconds and retry the operation again to make sure that no invalid angles should be reported. If the device is unsuccesful to get a valid angle within 10s it will go to sleep for 60s and then retry again (TODO: This will be adjusted after more testing).
|
||||
|
||||
## Configuration
|
||||
|
||||
@ -39,7 +39,7 @@ Configuration is accessed by entering the URL for the device, this will be the m
|
||||
|
||||
http://gravmon.local/
|
||||
|
||||
The main page shows the device readings; gravity, angle, temperature and battery charge. If the checkbox is active then the device will never go into sleep mode. This is useful if you are collecting angle/tilt for calibration. If this is unchecked the device will go into sleep mode and the web UI is no longer accesible.
|
||||
The main page shows the device readings; gravity, angle, temperature and battery charge. If the checkbox is active then the device will never go into sleep mode. This is useful if you are collecting angle/tilt for calibration. If this is unchecked the device will change mode as explained before.
|
||||
|
||||

|
||||
|
||||
@ -55,15 +55,13 @@ The device page shows the device settings and software versions.
|
||||
|
||||
http://gravmon.local/config.htm
|
||||
|
||||
This page is divided into several categories of settings. The first one contains device settings, mDNS name, temperature format, and gyro calibration data. The interval setting is the amount of time the device will be in sleep mode between readings (interval is in seconds).
|
||||
* This page is divided into several categories of settings. The first one contains device settings, mDNS name, temperature format, sleep interval and gyro calibration data. The interval setting is the amount of time the device will be in sleep mode between readings (interval is in seconds). To simplify this you can also see the conversion to minutes / seconds next to the input field.
|
||||
|
||||
Calibration needs to be done or the device will not work correctly. Place the device flat on a surface with gyro up and press the calibrate button when it's stable.
|
||||
|
||||
__TODO: Update image for config settings.__
|
||||
* Calibration needs to be done or the device will not work correctly. Place the device flat on a surface with gyro up and press the calibrate button when it's stable. If no calibration data exist the device will not enter sleep-mode.
|
||||
|
||||

|
||||
|
||||
The second section contains the push settings, two URL's for http posts, Brewfather and settings for InfluxDB v2.
|
||||
* The second section contains the push settings, two URL's for http posts, Brewfather and settings for InfluxDB v2.
|
||||
|
||||
### This is the format used for standard http posts.
|
||||
```
|
||||
@ -100,18 +98,19 @@ The second section contains the push settings, two URL's for http posts, Brewfat
|
||||
```
|
||||
measurement,host=<mdns>,device=<id>,temp-format=<C|F>,gravity-format=SG gravity=1.0004,angle=45.45,temp=20.1,battery=3.96,rssi=-18
|
||||
```
|
||||
|
||||
__TODO: Update image for push settings.__
|
||||
|
||||

|
||||
|
||||
The third section contains the gravity options, formlua and option for temperature correcting gravity.
|
||||
* The third section contains the gravity formula and also option for doing temperature compensation. The calibration formula uses two keywords, temp and tilt. Temperature is in the selected device format.
|
||||
|
||||
* Gravity formula is compatible with standard iSpindle formulas so any existing calculation option can be used. I use the tool fermentrack for controlling my fermentation and I use this tool for calculating gravity. The formula can handle two keywords, __tilt__ and __temp__. This is an example of a formula; __0.00145*tilt^3+0.1445*tilt^2+0.00179*tilt+0.9436__
|
||||
|
||||

|
||||
* This is the formula used for temperature calibration (temp is in F). Cal = 20C.
|
||||
```
|
||||
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))
|
||||
```
|
||||

|
||||
|
||||
The fouth section contains the hardware options, voltage factor for calculating the battery charge, temperature sensor adjustment and OTA base URL.
|
||||
* Hardware settings contain settings for temperature sensor adjustment, voltage factor (to calulate the battery level) and OTA URL.
|
||||
|
||||
* For the OTA to work, place the following files (version.json + firmware.bin) at the location that you pointed out in OTA URL. If the version number in the json file is newer than in the code the update will be done during startup.
|
||||
|
||||
@ -129,7 +128,7 @@ Contents version.json
|
||||
|
||||
# Building a device
|
||||
|
||||
Not yet complete.
|
||||
See the iSpindle documentation for building a device.
|
||||
|
||||
# Compiling the software
|
||||
|
||||
@ -142,3 +141,5 @@ You can set the SSID and PWD as presets through platformio.ini by adding the set
|
||||
-D USER_SSID=\""\"" // =\""myssid\""
|
||||
-D USER_SSID_PWD=\""\"" // =\""mypwd\""
|
||||
```
|
||||
|
||||
There are more options in teh platform.ini file that enable/disable additional functions for logging level, pushing performance data to InfluxDB and more. If i get the time I will add some documentation around these.
|
BIN
img/config1.png
BIN
img/config1.png
Binary file not shown.
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 13 KiB |
BIN
img/config2.png
BIN
img/config2.png
Binary file not shown.
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 19 KiB |
@ -22,6 +22,7 @@ build_unflags =
|
||||
build_flags = #-O0 -Wl,-Map,output.map
|
||||
-D BAUD=${common_env_data.monitor_speed}
|
||||
-D ACTIVATE_OTA
|
||||
-D USE_GYRO_TEMP # If this is enabled the DS18 will not be used, temp is read from the gyro.
|
||||
#-D DEBUG_ESP_HTTP_CLIENT
|
||||
#-D DEBUG_ESP_HTTP_SERVER
|
||||
#-D DEBUG_ESP_PORT=Serial
|
||||
|
@ -64,17 +64,18 @@ double calculateGravity( double angle, double temp ) {
|
||||
//
|
||||
// Do a standard gravity temperature correction. This is a simple way to adjust for differnt worth temperatures
|
||||
//
|
||||
double gravityTemperatureCorrection( double gravity, double temp, 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);
|
||||
#endif
|
||||
|
||||
double tempF = convertCtoF( temp );
|
||||
double calTempF = convertCtoF(calTemp);
|
||||
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))";
|
||||
|
||||
// Store variable names and pointers.
|
||||
te_variable vars[] = {{"gravity", &gravity}, {"temp", &tempF}, {"cal", &calTempF}};
|
||||
te_variable vars[] = {{"gravity", &gravity}, {"temp", &temp}, {"cal", &calTempF}};
|
||||
|
||||
int err;
|
||||
// Compile the expression with variables.
|
||||
|
@ -29,7 +29,7 @@ SOFTWARE.
|
||||
|
||||
// Functions
|
||||
double calculateGravity( double angle, double temp );
|
||||
double gravityTemperatureCorrection( double gravity, double temp, double calTemp = 20 );
|
||||
double gravityTemperatureCorrection( double gravity, double temp, char tempFormat, double calTemp = 20 );
|
||||
|
||||
#endif // _CALC_H
|
||||
|
||||
|
@ -48,10 +48,10 @@ SOFTWARE.
|
||||
#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 (iSpindle format)
|
||||
#define CFG_PARAM_PUSH_INFLUXDB2_ORG "influxdb2-org" // URL (iSpindle format)
|
||||
#define CFG_PARAM_PUSH_INFLUXDB2_BUCKET "influxdb2-bucket" // URL (iSpindle format)
|
||||
#define CFG_PARAM_PUSH_INFLUXDB2_AUTH "influxdb2-auth" // 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
|
||||
|
@ -67,7 +67,7 @@ class GyroSensor {
|
||||
void calibrateSensor();
|
||||
|
||||
double getAngle() { return angle; };
|
||||
double getSensorTempC() { return sensorTemp; };
|
||||
float getSensorTempC() { return sensorTemp; };
|
||||
bool isConnected() { return sensorConnected; };
|
||||
bool hasValue() { return validValue; };
|
||||
void enterSleep();
|
||||
|
@ -52,6 +52,9 @@ void printBuildOptions() {
|
||||
#ifdef SKIP_SLEEPMODE
|
||||
"SKIP_SLEEP "
|
||||
#endif
|
||||
#ifdef USE_GYRO_TEMP
|
||||
"GYRO_TEMP "
|
||||
#endif
|
||||
#ifdef EMBED_HTML
|
||||
"EMBED_HTML "
|
||||
#endif
|
||||
|
@ -197,7 +197,7 @@ void loop() {
|
||||
#endif
|
||||
if( myConfig.isGravityTempAdj() ) {
|
||||
LOG_PERF_START("loop-gravity-corr");
|
||||
gravity = gravityTemperatureCorrection( gravity, temp); // Use default correction temperature of 20C
|
||||
gravity = gravityTemperatureCorrection( gravity, temp, myConfig.getTempFormat() ); // Use default correction temperature of 20C
|
||||
LOG_PERF_STOP("loop-gravity-corr");
|
||||
#if LOG_LEVEL==6
|
||||
Log.verbose(F("Main: Temp adjusted gravity=%F." CR), gravity );
|
||||
|
@ -24,6 +24,7 @@ SOFTWARE.
|
||||
#include "tempsensor.h"
|
||||
#include "helper.h"
|
||||
#include "config.h"
|
||||
#include "gyro.h"
|
||||
#include <onewire.h>
|
||||
#include <DallasTemperature.h>
|
||||
#include <Wire.h>
|
||||
@ -35,11 +36,13 @@ float convertCtoF( float t ) {
|
||||
return (t * 1.8 ) + 32.0;
|
||||
}
|
||||
|
||||
#if !defined( USE_GYRO_TEMP )
|
||||
OneWire myOneWire(D6);
|
||||
DallasTemperature mySensors(&myOneWire);
|
||||
TempSensor myTempSensor;
|
||||
|
||||
#define TEMPERATURE_PRECISION 9
|
||||
#endif
|
||||
|
||||
TempSensor myTempSensor;
|
||||
|
||||
//
|
||||
// Setup temp sensors
|
||||
@ -51,6 +54,10 @@ void TempSensor::setup() {
|
||||
return;
|
||||
#endif
|
||||
|
||||
#if defined( USE_GYRO_TEMP )
|
||||
Log.notice(F("TSEN: Using temperature from gyro." CR));
|
||||
#else
|
||||
// This code is used to read the DS18 temp sensor
|
||||
if( mySensors.getDS18Count() )
|
||||
return;
|
||||
|
||||
@ -63,6 +70,7 @@ void TempSensor::setup() {
|
||||
Log.notice(F("TSEN: Found %d sensors." CR), mySensors.getDS18Count());
|
||||
mySensors.setResolution(TEMPERATURE_PRECISION);
|
||||
}
|
||||
#endif
|
||||
|
||||
float t = myConfig.getTempSensorAdj();
|
||||
|
||||
@ -81,20 +89,30 @@ void TempSensor::setup() {
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieving value from sensor
|
||||
// Retrieving value from sensor, value is in Celcius
|
||||
//
|
||||
float TempSensor::getValue() {
|
||||
float c = 0;
|
||||
|
||||
#if defined( SIMULATE_TEMP )
|
||||
return 21;
|
||||
#endif
|
||||
|
||||
#if defined( USE_GYRO_TEMP )
|
||||
//LOG_PERF_START("temp-get");
|
||||
float c = myGyro.getSensorTempC();
|
||||
//LOG_PERF_STOP("temp-get");
|
||||
hasSensor = true;
|
||||
return c;
|
||||
#if LOG_LEVEL==6
|
||||
Log.verbose(F("TSEN: Reciving temp value for gyro sensor %F C." CR), c);
|
||||
#endif
|
||||
#else
|
||||
// Read the sensors
|
||||
//LOG_PERF_START("temp-request");
|
||||
mySensors.requestTemperatures();
|
||||
//LOG_PERF_STOP("temp-request");
|
||||
|
||||
float c = 0;
|
||||
|
||||
if( mySensors.getDS18Count() >= 1) {
|
||||
//LOG_PERF_START("temp-get");
|
||||
c = mySensors.getTempCByIndex(0);
|
||||
@ -107,6 +125,7 @@ float TempSensor::getValue() {
|
||||
}
|
||||
|
||||
return c;
|
||||
#endif
|
||||
}
|
||||
|
||||
// EOF
|
@ -88,9 +88,12 @@ void webHandleConfig() {
|
||||
double temp = myTempSensor.getValueCelcius();
|
||||
double gravity = calculateGravity( angle, temp );
|
||||
|
||||
doc[ CFG_PARAM_ANGLE ] = reduceFloatPrecision( angle);
|
||||
doc[ CFG_PARAM_GRAVITY ] = reduceFloatPrecision( gravityTemperatureCorrection( gravity, temp ), 4);
|
||||
doc[ CFG_PARAM_BATTERY ] = reduceFloatPrecision( myBatteryVoltage.getVoltage());
|
||||
doc[ CFG_PARAM_ANGLE ] = reduceFloatPrecision( angle);
|
||||
if( myConfig.isGravityTempAdj() )
|
||||
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());
|
||||
|
||||
#if LOG_LEVEL==6
|
||||
serializeJson(doc, Serial);
|
||||
@ -224,15 +227,18 @@ void webHandleStatus() {
|
||||
double temp = myTempSensor.getValueCelcius();
|
||||
double gravity = calculateGravity( angle, temp );
|
||||
|
||||
doc[ CFG_PARAM_ID ] = myConfig.getID();
|
||||
doc[ CFG_PARAM_ANGLE ] = reduceFloatPrecision( angle);
|
||||
doc[ CFG_PARAM_GRAVITY ] = reduceFloatPrecision( gravityTemperatureCorrection( gravity, temp ), 4);
|
||||
doc[ CFG_PARAM_TEMP_C ] = reduceFloatPrecision( temp, 1);
|
||||
doc[ CFG_PARAM_TEMP_F ] = reduceFloatPrecision( myTempSensor.getValueFarenheight(), 1);
|
||||
doc[ CFG_PARAM_BATTERY ] = reduceFloatPrecision( myBatteryVoltage.getVoltage());
|
||||
doc[ CFG_PARAM_TEMPFORMAT ] = String( myConfig.getTempFormat() );
|
||||
doc[ CFG_PARAM_SLEEP_MODE ] = sleepModeAlwaysSkip;
|
||||
doc[ CFG_PARAM_RSSI ] = WiFi.RSSI();
|
||||
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);
|
||||
else
|
||||
doc[ CFG_PARAM_GRAVITY ] = reduceFloatPrecision( gravity, 4);
|
||||
doc[ CFG_PARAM_TEMP_C ] = reduceFloatPrecision( temp, 1);
|
||||
doc[ CFG_PARAM_TEMP_F ] = reduceFloatPrecision( myTempSensor.getValueFarenheight(), 1);
|
||||
doc[ CFG_PARAM_BATTERY ] = reduceFloatPrecision( myBatteryVoltage.getVoltage());
|
||||
doc[ CFG_PARAM_TEMPFORMAT ] = String( myConfig.getTempFormat() );
|
||||
doc[ CFG_PARAM_SLEEP_MODE ] = sleepModeAlwaysSkip;
|
||||
doc[ CFG_PARAM_RSSI ] = WiFi.RSSI();
|
||||
#if LOG_LEVEL==6
|
||||
serializeJson(doc, Serial);
|
||||
Serial.print( CR );
|
||||
|
Loading…
Reference in New Issue
Block a user