Test version for fermentation

This commit is contained in:
Magnus 2021-04-07 20:16:40 +02:00
parent 7f782ad7bd
commit 876718602f
11 changed files with 146 additions and 73 deletions

3
.gitignore vendored
View File

@ -3,4 +3,5 @@
*.map
test/*.md
test/env/*
test/*.py
test/*.py
TODO.md

View File

@ -7,9 +7,11 @@ I started this project out of curiosity for how a motion sensor is working and s
* Add support for Plato in device (today it assumes that formula is in SG).
* Add support for converting between SG/Plato in device.
* Add support for Blynk as endpoint
* Add support for https connections (push)
* Add support for https connections (push) - [need to reduce memory usage for this to work, gets out of memory error]
* 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...
# Functionallity
@ -96,11 +98,7 @@ The second section contains the push settings, two URL's for http posts, Brewfat
### This is the format for InfluxDB v2
```
gravity,host=<mdns>,device=<id>,format=SG value=1.0004
angle,host=<mdns>,device=<id> value=45.45
temp,host=<mdns>,device=<id>,format=<C|F> value=20.1
battery,host=<mdns>,device=<id> value=3.96
rssi,host=<mdns>,device=<id> value=-18
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.__

Binary file not shown.

Binary file not shown.

View File

@ -21,10 +21,14 @@ board = d1_mini
build_unflags =
build_flags = #-O0 -Wl,-Map,output.map
-D BAUD=${common_env_data.monitor_speed}
-D ACTIVATE_OTA
-D ACTIVATE_OTA
#-D DEBUG_ESP_HTTP_CLIENT
#-D DEBUG_ESP_HTTP_SERVER
#-D DEBUG_ESP_PORT=Serial
#-D SKIP_SLEEPMODE
#-D DOUBLERESETDETECTOR_DEBUG true
-D USE_LITTLEFS=true
-D EMBED_HTML
-D EMBED_HTML # If this is not used the html files needs to be on the file system (can be uploaded)
-D USER_SSID=\""\"" # =\""myssid\""
-D USER_SSID_PWD=\""\"" # =\""mypwd\""
-D CFG_APPVER="\"0.3.5\""
@ -38,6 +42,7 @@ lib_deps =
https://github.com/bblanchon/ArduinoJson
https://github.com/PaulStoffregen/OneWire
https://github.com/milesburton/Arduino-Temperature-Control-Library
https://github.com/wollewald/INA219_WE # For measuring power consumption
[env:gravity-debug]
upload_speed = ${common_env_data.upload_speed}

View File

@ -52,7 +52,7 @@ bool GyroSensor::setup() {
Log.notice(F("GYRO: Connected to MPU6050 (gyro)." CR));
sensorConnected = true;
// Configure ethe sensor
// Configure the sensor
accelgyro.setTempSensorEnabled(true);
accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_250);
@ -91,6 +91,7 @@ void GyroSensor::readSensor(RawGyroData &raw, const int noIterations, const int
#if LOG_LEVEL==6
Log.verbose(F("GYRO: Reading sensor with %d iterations %d us delay." CR), noIterations, delayTime );
#endif
// Set some initial values
#if defined( GYRO_SHOW_MINMAX )
RawGyroData min, max;
@ -99,7 +100,6 @@ void GyroSensor::readSensor(RawGyroData &raw, const int noIterations, const int
min.temp = accelgyro.getTemperature();
max = min;
#endif
for(int cnt = 0; cnt < noIterations ; cnt ++) {
accelgyro.getRotation( &raw.gx, &raw.gy, &raw.gz );
accelgyro.getAcceleration( &raw.ax, &raw.ay, &raw.az );

View File

@ -26,6 +26,10 @@ SOFTWARE.
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#if defined( COLLECT_PERFDATA )
#include <INA219_WE.h> // For measuring power consumption
#endif
SerialDebug mySerial;
BatteryVoltage myBatteryVoltage;
@ -95,27 +99,64 @@ void BatteryVoltage::read() {
#endif
}
#if defined( COLLECT_PERFDATA )
PerfLogging myPerfLogging;
INA219_WE ina219(0x40); // For measuring power consumption
//
// Initialize
//
PerfLogging::PerfLogging() {
if( ina219.init() )
measurePower = true;
Log.notice( F("PERF: Performance logging enabled. Power sensor %s" CR), measurePower?"found":"not found");
}
//
// Initialize
//
void PerfLogging::readPowerSensor(PerfEntry *pe) {
pe->mA = 0;
pe->V = 0;
if( !measurePower )
return;
if( ina219.getOverflow() )
Log.error( F("PERF: Voltage sensor overflow detected." CR));
/*
shuntVoltage_mV = ina219.getShuntVoltage_mV();
busVoltage_V = ina219.getBusVoltage_V();
current_mA = ina219.getCurrent_mA();
power_mW = ina219.getBusPower();
loadVoltage_V = busVoltage_V + (shuntVoltage_mV/1000);
*/
pe->mA = ina219.getCurrent_mA();
pe->V = ina219.getBusVoltage_V() + (ina219.getShuntVoltage_mV()/1000);
}
//
// Clear the current cache
//
void PerfLogging::clear() {
// Clear the measurements
if( first == 0 )
return;
PerfEntry* pe = first;
do {
PerfEntry* p = pe;
pe->max = 0;
pe->start = 0;
pe->end = 0;
pe->mA = 0;
pe->V = 0;
pe = pe->next;
delete p;
} while( pe != 0 );
first = 0;
}
//
@ -137,8 +178,10 @@ void PerfLogging::stop( const char* key ) {
unsigned long t = pe->end - pe->start;
if( t > pe->max )
if( t > pe->max )
pe->max = t;
readPowerSensor( pe );
}
}
@ -175,11 +218,19 @@ void PerfLogging::pushInflux() {
String body;
PerfEntry* pe = first;
char buf[100];
sprintf( &buf[0], "perf,host=%s,device=%s ", myConfig.getMDNS(), myConfig.getID() );
body += &buf[0];
while( pe != 0 ) {
char buf[100];
sprintf( &buf[0], "%s,host=%s,device=%s value=%ld\n", pe->key, myConfig.getMDNS(), myConfig.getID(), pe->max);
body += &buf[0];
if( pe->max ) {
if( pe->next )
sprintf( &buf[0], "%s=%ld,", pe->key, pe->max);
else
sprintf( &buf[0], "%s=%ld", pe->key, pe->max);
body += &buf[0];
}
pe = pe->next;
}

View File

@ -66,10 +66,15 @@ class PerfLogging {
unsigned long end; // millis()
unsigned long max; // max time in ms
const char* key; // measurement
PerfEntry* next; //
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 )
@ -112,7 +117,10 @@ class PerfLogging {
return pe;
};
void readPowerSensor(PerfEntry* pe);
public:
PerfLogging();
void clear();
void start( const char* key );
void stop( const char* key );

View File

@ -35,7 +35,6 @@ SOFTWARE.
#define ESP8266_DRD_USE_RTC true
#define DRD_TIMEOUT 2
#define DRD_ADDRESS 0
#define DOUBLERESETDETECTOR_DEBUG true
#include <ESP_DoubleResetDetector.h>
DoubleResetDetector *drd;
@ -47,10 +46,12 @@ bool sleepModeAlwaysSkip = true; // Web interface can override normal
const int interval = 200; // ms, time to wait between changes to output
bool sleepModeAlwaysSkip = false; // Web interface can override normal behaviour
#endif
unsigned long lastMillis = 0;
unsigned long startMillis;
bool sleepModeActive = false;
int loopCounter = 0;
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
bool sleepModeActive = false;
bool goToSleep = false;
int loopCounter = 0;
//
// Check if we should be in sleep mode
@ -78,7 +79,7 @@ void checkSleepMode( float angle, float volt ) {
}
// Will not enter sleep mode if: charger is connected
sleepModeActive = (volt<4.15 && angle>85) || (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;
@ -93,7 +94,7 @@ void checkSleepMode( float angle, float volt ) {
void setup() {
LOG_PERF_START("run-time");
LOG_PERF_START("main-setup");
startMillis = millis();
runtimeMillis = millis();
drd = new DoubleResetDetector(DRD_TIMEOUT, DRD_ADDRESS);
bool dt = drd->detectDoubleReset();
@ -118,10 +119,10 @@ void setup() {
LOG_PERF_STOP("main-temp-setup");
// Setup Gyro
LOG_PERF_START("main-gyro-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_STOP("main-gyro-setup");
//LOG_PERF_STOP("main-gyro-setup");
if( dt )
Log.notice(F("Main: Detected doubletap on reset." CR));
@ -148,16 +149,15 @@ void setup() {
LOG_PERF_STOP("main-wifi-ota");
#endif
if( !sleepModeActive ) {
LOG_PERF_START("main-webserver-setup");
//LOG_PERF_START("main-webserver-setup"); // Takes less than 4ms , so skip this measurment
myWebServer.setupWebServer();
LOG_PERF_STOP("main-webserver-setup");
//LOG_PERF_STOP("main-webserver-setup");
}
}
LOG_PERF_STOP("main-setup");
LOG_PERF_PRINT(); // Dump data to serial
LOG_PERF_PUSH(); // Dump data to influx
Log.notice(F("Main: Setup completed." CR));
stableGyroMillis = millis(); // Put it here so we dont include time for wifi connection
}
//
@ -166,26 +166,31 @@ void setup() {
void loop() {
drd->loop();
if( sleepModeActive || abs(millis() - lastMillis) > interval ) {
float angle = 90;
if( sleepModeActive || abs(millis() - loopMillis) > interval ) {
float angle = 0;
float volt = myBatteryVoltage.getVoltage();
float sensorTemp = 0;
loopCounter++;
#if LOG_LEVEL==6
Log.verbose(F("Main: Entering main loop." CR) );
#endif
// 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( myGyro.hasValue() ) {
angle = myGyro.getAngle(); // Gyro angle
sensorTemp = myGyro.getSensorTempC(); // Temp in the Gyro
stableGyroMillis = millis(); // Reset timer
LOG_PERF_START("loop-temp-read");
float temp = myTempSensor.getValueCelcius(); // The code is build around using C for temp.
LOG_PERF_STOP("loop-temp-read");
LOG_PERF_START("loop-gravity-calc");
//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_STOP("loop-gravity-calc");
#if LOG_LEVEL==6
Log.verbose(F("Main: Sensor values gyro angle=%F gyro temp=%F, temp=%F, gravity=%F." CR), angle, sensorTemp, temp, gravity );
@ -202,49 +207,62 @@ void loop() {
// Limit the printout when sleep mode is not active.
if( loopCounter%10 == 0 || sleepModeActive ) {
Log.notice(F("Main: gyro angle=%F, gyro temp=%F, DS18B20 temp=%F, gravity=%F, batt=%F." CR), angle, sensorTemp, temp, gravity, volt );
LOG_PERF_PRINT();
}
unsigned long runTime = millis() - startMillis;
LOG_PERF_START("loop-push");
myPushTarget.send( angle, gravity, temp, runTime/1000, sleepModeActive ); // Force the transmission if we are going to sleep
myPushTarget.send( angle, gravity, 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;
} else {
Log.error(F("Main: No gyro value." CR) );
}
if( sleepModeActive ) {
unsigned long runTime = millis() - startMillis;
// Enter sleep mode...
Log.notice(F("MAIN: Entering deep sleep for %d s, run time %l s, battery=%F V." CR), myConfig.getSleepInterval(), runTime/1000, volt );
LittleFS.end();
myGyro.enterSleep();
drd->stop();
LOG_PERF_STOP("run-time");
LOG_PERF_PUSH();
LOG_PERF_PRINT();
delay(100);
deepSleep( myConfig.getSleepInterval() );
}
#if LOG_LEVEL==6
Log.verbose(F("Main: Sleep mode not active." CR) );
#endif
int sleepInterval = myConfig.getSleepInterval();
// 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) );
sleepInterval = 60; // 60s
goToSleep = true;
}
// Enter sleep mode if the conditions are right
// ------------------------------------------------------------------------------------------------
//
if( goToSleep ) {
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();
LOG_PERF_STOP("run-time");
LOG_PERF_PUSH();
delay(100);
deepSleep( sleepInterval );
}
// If we are running in normal mode we just continue
// ------------------------------------------------------------------------------------------------
// Do these checks if we are running in normal mode (not sleep mode)
//
checkSleepMode( angle, volt );
LOG_PERF_START("loop-gyro-read");
myGyro.read();
LOG_PERF_STOP("loop-gyro-read");
LOG_PERF_START("loop-batt-read");
//LOG_PERF_START("loop-batt-read"); // Takes less than 2ms , so skip this measurment
myBatteryVoltage.read();
LOG_PERF_STOP("loop-batt-read");
//LOG_PERF_STOP("loop-batt-read");
lastMillis = millis();
loopMillis = millis();
#if LOG_LEVEL==6
Log.verbose(F("Main: Heap %d kb FreeSketch %d kb." CR), ESP.getFreeHeap()/1024, ESP.getFreeSketchSpace()/1024 );
Log.verbose(F("Main: HeapFrag %d %%." CR), ESP.getHeapFragmentation() );

View File

@ -23,6 +23,7 @@ SOFTWARE.
*/
#include "pushtarget.h"
#include "config.h"
#include "gyro.h" // For testing the tempsensor in the gyro
PushTarget myPushTarget;
@ -86,17 +87,11 @@ void PushTarget::sendInfluxDb2(float angle, float gravity, float temp, float run
// Create body for influxdb2
char buf[1024];
sprintf( &buf[0], "gravity,host=%s,device=%s,format=%s value=%.4f\n"
"angle,host=%s,device=%s value=%.2f\n"
"temp,host=%s,device=%s,format=%c value=%.1f\n"
"battery,host=%s,device=%s value=%.2f\n"
"rssi,host=%s,device=%s value=%d\n",
sprintf( &buf[0], "measurement,host=%s,device=%s,temp-format=%c,gravity-format=%s "
"gravity=%.4f,angle=%.2f,temp=%.2f,battery=%.2f,rssi=%d,temp2=%.2f\n",
// TODO: Add support for plato format
myConfig.getMDNS(), myConfig.getID(), "SG", gravity,
myConfig.getMDNS(), myConfig.getID(), angle,
myConfig.getMDNS(), myConfig.getID(), myConfig.getTempFormat(), temp,
myConfig.getMDNS(), myConfig.getID(), myBatteryVoltage.getVoltage(),
myConfig.getMDNS(), myConfig.getID(), WiFi.RSSI() );
myConfig.getMDNS(), myConfig.getID(), myConfig.getTempFormat(), "SG",
gravity, angle, temp, myBatteryVoltage.getVoltage(), WiFi.RSSI(), myGyro.getSensorTempC() ); // For comparing gyro tempsensor vs DSB1820
#if LOG_LEVEL==6
Log.verbose(F("PUSH: url %s." CR), serverPath.c_str());
@ -115,7 +110,6 @@ void PushTarget::sendInfluxDb2(float angle, float gravity, float temp, float run
}
http.end();
}
//

View File

@ -21,7 +21,6 @@ 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.
*/
//#define DEBUG_ESP_HTTP_SERVER
#include "webserver.h"
#include "config.h"
#include "helper.h"
@ -31,7 +30,6 @@ SOFTWARE.
#include <ArduinoJson.h>
#include <incbin.h>
#include <ESP8266WiFi.h>
//#define DEBUG_ESP_HTTP_SERVER
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <LittleFS.h>