Added ssl and plato

This commit is contained in:
Magnus Persson 2022-01-18 23:01:10 +01:00
parent 10163f3aa7
commit ddb34e129d
27 changed files with 556 additions and 315 deletions

View File

@ -86,19 +86,20 @@
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordion"> <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordion">
<div class="card-body"> <div class="card-body">
<form action="/api/formula" method="post"> <form action="/api/formula" method="post">
<input type="text" name="gravity-format" id="gravity-format" hidden>
<input type="text" name="id" id="id" hidden> <input type="text" name="id" id="id" hidden>
<div class="row mb-3"> <div class="row mb-3">
Here you can create your gravity formula by entering angles/tilt and the corresponding gravity (SG). These values Here you can create your gravity formula by entering angles/tilt and the corresponding gravity. These values
will be saved for future use. Angles with 0 (zero) will be skipped. The values below will be used to check the will be saved for future use. Angles with 0 (zero) will be skipped. The values below will be used to check the
formula and if the deviation is more than 1.5 SG then the forumla will be rejected. On the bottom of the page you can formula and if the deviation is more than 1.5SG / 0.38P on any of the provided points then the forumla will be
see a graph over the entered values + values calcualated by the formula. rejected. On the bottom of the page you can see a graph over the entered values + values calcualated by the formula.
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-2 col-form-label">#:</label> <label class="col-sm-2 col-form-label">#:</label>
<label class="col-sm-4 col-form-label">Angle/Tilt:</label> <label class="col-sm-4 col-form-label">Angle/Tilt:</label>
<label class="col-sm-4 col-form-label">Gravity (SG):</label> <label class="col-sm-4 col-form-label" id="gravity-header">Gravity (SG):</label>
</div> </div>
<div class="form-group row"> <div class="form-group row">
@ -107,7 +108,7 @@
<input type="number" min="0" max="90" step="0.001" class="form-control" name="a1" id="a1"> <input type="number" min="0" max="90" step="0.001" class="form-control" name="a1" id="a1">
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<input type="number" min="1" max="2" step="0.0001" class="form-control" name="g1" id="g1"> <input type="number" min="0" max="26" step="0.0001" class="form-control" name="g1" id="g1">
</div> </div>
</div> </div>
@ -117,7 +118,7 @@
<input type="number" min="0" max="90" step="0.001" class="form-control" name="a2" id="a2"> <input type="number" min="0" max="90" step="0.001" class="form-control" name="a2" id="a2">
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<input type="number" min="1" max="2" step="0.0001" class="form-control" name="g2" id="g2"> <input type="number" min="0" max="26" step="0.0001" class="form-control" name="g2" id="g2">
</div> </div>
</div> </div>
@ -127,7 +128,7 @@
<input type="number" min="0" max="90" step="0.001" class="form-control" name="a3" id="a3"> <input type="number" min="0" max="90" step="0.001" class="form-control" name="a3" id="a3">
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<input type="number" min="1" max="2" step="0.0001" class="form-control" name="g3" id="g3"> <input type="number" min="0" max="26" step="0.0001" class="form-control" name="g3" id="g3">
</div> </div>
</div> </div>
@ -137,7 +138,7 @@
<input type="number" min="0" max="90" step="0.001" class="form-control" name="a4" id="a4"> <input type="number" min="0" max="90" step="0.001" class="form-control" name="a4" id="a4">
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<input type="number" min="1" max="2" step="0.0001" class="form-control" name="g4" id="g4"> <input type="number" min="0" max="26" step="0.0001" class="form-control" name="g4" id="g4">
</div> </div>
</div> </div>
@ -147,7 +148,7 @@
<input type="number" min="0" max="90" step="0.001" class="form-control" name="a5" id="a5"> <input type="number" min="0" max="90" step="0.001" class="form-control" name="a5" id="a5">
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<input type="number" min="1" max="2" step="0.0001" class="form-control" name="g5" id="g5"> <input type="number" min="0" max="26" step="0.0001" class="form-control" name="g5" id="g5">
</div> </div>
</div> </div>
@ -233,28 +234,40 @@
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
g1.onchange = setFourNumberDecimal g1.onchange = setGravityDecimal
g2.onchange = setFourNumberDecimal g2.onchange = setGravityDecimal
g3.onchange = setFourNumberDecimal g3.onchange = setGravityDecimal
g4.onchange = setFourNumberDecimal g4.onchange = setGravityDecimal
g5.onchange = setFourNumberDecimal g5.onchange = setGravityDecimal
a1.onchange = setTwoNumberDecimal a1.onchange = setAngleDecimal
a2.onchange = setTwoNumberDecimal a2.onchange = setAngleDecimal
a3.onchange = setTwoNumberDecimal a3.onchange = setAngleDecimal
a4.onchange = setTwoNumberDecimal a4.onchange = setAngleDecimal
a5.onchange = setTwoNumberDecimal a5.onchange = setAngleDecimal
window.onload = getConfig; window.onload = getConfig;
setButtonDisabled( true ); setButtonDisabled( true );
function setTwoNumberDecimal(event) { function convertToPlato(sg) {
return 259-(259/sg);
}
function convertToSG(plato) {
return 259/(259-plato);
}
function setAngleDecimal(event) {
this.value = parseFloat(this.value).toFixed(2); this.value = parseFloat(this.value).toFixed(2);
populateChart(); populateChart();
} }
function setFourNumberDecimal(event) { function setGravityDecimal(event) {
this.value = parseFloat(this.value).toFixed(4); if(isPlato())
this.value = parseFloat(this.value).toFixed(1);
else
this.value = parseFloat(this.value).toFixed(4);
populateChart(); populateChart();
} }
@ -267,6 +280,10 @@
chartDataCalc.push( { x: parseFloat(a), y: parseFloat(g) }); chartDataCalc.push( { x: parseFloat(a), y: parseFloat(g) });
} }
function isPlato() {
return $("#gravity-format").text() == "P";
}
function populateChart() { function populateChart() {
chartDataCalc.length = 0 chartDataCalc.length = 0
@ -278,6 +295,10 @@
formula=formula.replaceAll( "tilt^2", angle+"*"+angle ); formula=formula.replaceAll( "tilt^2", angle+"*"+angle );
formula=formula.replaceAll( "tilt", angle ); formula=formula.replaceAll( "tilt", angle );
var g = eval( formula ); var g = eval( formula );
if(isPlato())
g = convertToPlato(g);
populateChartCalc( i, g ); populateChartCalc( i, g );
} }
@ -314,6 +335,23 @@
$("#id").val(cfg["id"]); $("#id").val(cfg["id"]);
$("#angle").text(cfg["angle"]); $("#angle").text(cfg["angle"]);
$("#formula").text(cfg["gravity-formula"]); $("#formula").text(cfg["gravity-formula"]);
$("#gravity-format").text(cfg["gravity-format"]); // Sets the variable used by isPlato()
if(isPlato()) {
$("#gravity-header").text("Gravity (Plato):");
$("#g1").val( parseFloat(cfg["g1"]).toFixed(1) );
$("#g2").val( parseFloat(cfg["g2"]).toFixed(1) );
$("#g3").val( parseFloat(cfg["g3"]).toFixed(1) );
$("#g4").val( parseFloat(cfg["g4"]).toFixed(1) );
$("#g5").val( parseFloat(cfg["g5"]).toFixed(1) );
} else {
$("#gravity-header").text("Gravity (SG):");
$("#g1").val( parseFloat(cfg["g1"]).toFixed(4) );
$("#g2").val( parseFloat(cfg["g2"]).toFixed(4) );
$("#g3").val( parseFloat(cfg["g3"]).toFixed(4) );
$("#g4").val( parseFloat(cfg["g4"]).toFixed(4) );
$("#g5").val( parseFloat(cfg["g5"]).toFixed(4) );
}
$("#a1").val( parseFloat(cfg["a1"]).toFixed(2) ); $("#a1").val( parseFloat(cfg["a1"]).toFixed(2) );
$("#a2").val( parseFloat(cfg["a2"]).toFixed(2) ); $("#a2").val( parseFloat(cfg["a2"]).toFixed(2) );
@ -321,11 +359,9 @@
$("#a4").val( parseFloat(cfg["a4"]).toFixed(2) ); $("#a4").val( parseFloat(cfg["a4"]).toFixed(2) );
$("#a5").val( parseFloat(cfg["a5"]).toFixed(2) ); $("#a5").val( parseFloat(cfg["a5"]).toFixed(2) );
$("#g1").val( parseFloat(cfg["g1"]).toFixed(4) ); if( cfg["error"]!="" ) {
$("#g2").val( parseFloat(cfg["g2"]).toFixed(4) ); showError(cfg["error"]);
$("#g3").val( parseFloat(cfg["g3"]).toFixed(4) ); }
$("#g4").val( parseFloat(cfg["g4"]).toFixed(4) );
$("#g5").val( parseFloat(cfg["g5"]).toFixed(4) );
populateChart(); populateChart();
}) })

File diff suppressed because one or more lines are too long

View File

@ -270,8 +270,25 @@
<div class="card-body"> <div class="card-body">
<form action="/api/config/gravity" method="post"> <form action="/api/config/gravity" method="post">
<input type="text" name="id" id="id3" hidden> <input type="text" name="id" id="id3" hidden>
<fieldset class="form-group row">
<legend class="col-form-label col-sm-2 float-sm-left pt-0">Gravity Format:</legend>
<div class="col-sm-4">
<div class="form-check">
<input class="form-check-input" type="radio" name="gravity-format" id="gravity-format-g" value="G" checked>
<label class="form-check-label" for="gravity-format-g">
SG
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="gravity-format" id="gravity-format-p" value="P">
<label class="form-check-label" for="gravity-format-p">
Plato
</label>
</div>
</div>
</fieldset>
<div class="form-group row"> <div class="form-group row">
<label for="gravity-formula" class="col-sm-2 col-form-label">Formula</label> <label for="gravity-formula" class="col-sm-2 col-form-label">Formula (SG)</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="text" maxlength="200" class="form-control" name="gravity-formula" id="gravity-formula"> <input type="text" maxlength="200" class="form-control" name="gravity-formula" id="gravity-formula">
</div> </div>
@ -416,10 +433,10 @@
$("#id3").val(cfg["id"]); $("#id3").val(cfg["id"]);
$("#id4").val(cfg["id"]); $("#id4").val(cfg["id"]);
$("#mdns").val(cfg["mdns"]); $("#mdns").val(cfg["mdns"]);
if( cfg["temp-format"] == "C" ) if( cfg["temp-format"] == "C" ) $("#temp-format-c").click();
$("#temp-format-c").click(); else $("#temp-format-f").click();
else if( cfg["gravity-format"] == "G" ) $("#gravity-format-g").click();
$("#temp-format-f").click(); else $("#gravity-format-p").click();
$("#ota-url").val(cfg["ota-url"]); $("#ota-url").val(cfg["ota-url"]);
$("#http-push").val(cfg["http-push"]); $("#http-push").val(cfg["http-push"]);
$("#http-push2").val(cfg["http-push2"]); $("#http-push2").val(cfg["http-push2"]);

File diff suppressed because one or more lines are too long

View File

@ -123,13 +123,19 @@
console.log( cfg ); console.log( cfg );
$("#id").text(cfg["id"]); $("#id").text(cfg["id"]);
$("#angle").text(cfg["angle"]); $("#angle").text(cfg["angle"]);
$("#gravity").text(cfg["gravity"] + " SG");
if( cfg["gravity-format"] == "G")
$("#gravity").text(cfg["gravity"] + " SG");
else
$("#gravity").text(cfg["gravity"] + " °P");
$("#battery").text(cfg["battery"] + " V"); $("#battery").text(cfg["battery"] + " V");
if( cfg["temp-format"] == "C") if( cfg["temp-format"] == "C")
$("#temp").text(cfg["temp-c"] + " C"); $("#temp").text(cfg["temp-c"] + " C");
else else
$("#temp").text(cfg["temp-f"] + " F"); $("#temp").text(cfg["temp-f"] + " F");
//console.log(cfg["sleep-mode"] );
if( cfg["sleep-mode"] ) if( cfg["sleep-mode"] )
$("#sleep-mode").attr("checked", true ); $("#sleep-mode").attr("checked", true );
else else

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="description" content=""><title>Beer Gravity Monitor</title><link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"><script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script><script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" crossorigin="anonymous"></script></head><body class="py-4"><!-- START MENU --><nav class="navbar navbar-expand-sm navbar-dark bg-primary"><a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbar"><ul class="navbar-nav mr-auto"><li class="nav-item active"><a class="nav-link" href="/index.htm">Home <span class="sr-only">(current)</span></a></li><li class="nav-item"><a class="nav-link" href="/device.htm">Device</a></li><li class="nav-item"><a class="nav-link" href="/config.htm">Configuration</a></li><li class="nav-item"><a class="nav-link" href="/calibration.htm">Calibration</a></li><li class="nav-item"><a class="nav-link" href="/about.htm">About</a></li></ul><div class="spinner-border text-light" id="spinner" role="status"></div></div></nav><!-- START MAIN INDEX --><div class="container"><hr class="my-4"><div class="alert alert-success alert-dismissible fade hide show d-none" role="alert" id="alert"><div id="alert-msg">...</div><button type="button" id="alert-btn" class="close" aria-label="Close"><span aria-hidden="true">&times;</span></button></div><script type="text/javascript">function showError(s){$(".alert").removeClass("alert-success").addClass("alert-danger").removeClass("d-none").addClass("show"),$("#alert-msg").text(s)}function showSuccess(s){$(".alert").addClass("alert-success").removeClass("alert-danger").removeClass("d-none").addClass("show"),$("#alert-msg").text(s)}$("#alert-btn").click(function(s){$(".alert").addClass("d-none").removeClass("show")})</script><div class="" id="id" hidden></div><div class="row mb-3"><div class="col-md-8 themed-grid-col bg-light">Gravity:</div><div class="col-md-4 themed-grid-col bg-light" id="gravity">Loading...</div></div><div class="row mb-3"><div class="col-md-8 themed-grid-col bg-light">Temperature:</div><div class="col-md-4 themed-grid-col bg-light" id="temp">Loading...</div></div><div class="row mb-3"><div class="col-md-8 themed-grid-col bg-light">Angle/Tilt:</div><div class="col-md-4 themed-grid-col bg-light" id="angle">Loading...</div></div><div class="row mb-3"><div class="col-md-8 themed-grid-col bg-light">Battery:</div><div class="col-md-4 themed-grid-col bg-light" id="battery">Loading...</div></div><div class="row mb-3"><div class="col-md-12 px-md-5 themed-grid-col bg-light custom-control custom-checkbox"><input type="checkbox" class="custom-control-input" name="sleep-mode" id="sleep-mode" disabled> <label class="custom-control-label" for="sleep-mode">Do not enter sleep mode when floating (check this if you are collecting angles/tilt for calibration).</label></div></div><hr class="my-4"></div><script type="text/javascript">function getStatus(){var e="/api/status";$("#spinner").show(),$.getJSON(e,function(e){console.log(e),$("#id").text(e.id),$("#angle").text(e.angle),$("#gravity").text(e.gravity+" SG"),$("#battery").text(e.battery+" V"),"C"==e["temp-format"]?$("#temp").text(e["temp-c"]+" C"):$("#temp").text(e["temp-f"]+" F"),e["sleep-mode"]?$("#sleep-mode").attr("checked",!0):$("#sleep-mode").attr("checked",!1),$("#sleep-mode").removeAttr("disabled")}).fail(function(){showError("Unable to get data from the device.")}).always(function(){$("#spinner").hide()})}function start(){setInterval(getStatus,3e3)}window.onload=start,$("#sleep-mode").click(function(e){console.log("Blocking sleep mode = "+$("#sleep-mode").is(":checked")),$.ajax({type:"POST",url:"/api/status/sleepmode",data:{id:$("#id").text(),"sleep-mode":$("#sleep-mode").is(":checked")},success:function(e){},error:function(e){showError("Could not update sleep mode for device.")}})})</script><!-- START FOOTER --><div class="container-fluid themed-container bg-primary text-light">(C) Copyright 2021-22 Magnus Persson</div></body></html> <!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="description" content=""><title>Beer Gravity Monitor</title><link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"><script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script><script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" crossorigin="anonymous"></script></head><body class="py-4"><!-- START MENU --><nav class="navbar navbar-expand-sm navbar-dark bg-primary"><a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbar"><ul class="navbar-nav mr-auto"><li class="nav-item active"><a class="nav-link" href="/index.htm">Home <span class="sr-only">(current)</span></a></li><li class="nav-item"><a class="nav-link" href="/device.htm">Device</a></li><li class="nav-item"><a class="nav-link" href="/config.htm">Configuration</a></li><li class="nav-item"><a class="nav-link" href="/calibration.htm">Calibration</a></li><li class="nav-item"><a class="nav-link" href="/about.htm">About</a></li></ul><div class="spinner-border text-light" id="spinner" role="status"></div></div></nav><!-- START MAIN INDEX --><div class="container"><hr class="my-4"><div class="alert alert-success alert-dismissible fade hide show d-none" role="alert" id="alert"><div id="alert-msg">...</div><button type="button" id="alert-btn" class="close" aria-label="Close"><span aria-hidden="true">&times;</span></button></div><script type="text/javascript">function showError(s){$(".alert").removeClass("alert-success").addClass("alert-danger").removeClass("d-none").addClass("show"),$("#alert-msg").text(s)}function showSuccess(s){$(".alert").addClass("alert-success").removeClass("alert-danger").removeClass("d-none").addClass("show"),$("#alert-msg").text(s)}$("#alert-btn").click(function(s){$(".alert").addClass("d-none").removeClass("show")})</script><div class="" id="id" hidden></div><div class="row mb-3"><div class="col-md-8 themed-grid-col bg-light">Gravity:</div><div class="col-md-4 themed-grid-col bg-light" id="gravity">Loading...</div></div><div class="row mb-3"><div class="col-md-8 themed-grid-col bg-light">Temperature:</div><div class="col-md-4 themed-grid-col bg-light" id="temp">Loading...</div></div><div class="row mb-3"><div class="col-md-8 themed-grid-col bg-light">Angle/Tilt:</div><div class="col-md-4 themed-grid-col bg-light" id="angle">Loading...</div></div><div class="row mb-3"><div class="col-md-8 themed-grid-col bg-light">Battery:</div><div class="col-md-4 themed-grid-col bg-light" id="battery">Loading...</div></div><div class="row mb-3"><div class="col-md-12 px-md-5 themed-grid-col bg-light custom-control custom-checkbox"><input type="checkbox" class="custom-control-input" name="sleep-mode" id="sleep-mode" disabled> <label class="custom-control-label" for="sleep-mode">Do not enter sleep mode when floating (check this if you are collecting angles/tilt for calibration).</label></div></div><hr class="my-4"></div><script type="text/javascript">function getStatus(){var e="/api/status";$("#spinner").show(),$.getJSON(e,function(e){console.log(e),$("#id").text(e.id),$("#angle").text(e.angle),"G"==e["gravity-format"]?$("#gravity").text(e.gravity+" SG"):$("#gravity").text(e.gravity+" °P"),$("#battery").text(e.battery+" V"),"C"==e["temp-format"]?$("#temp").text(e["temp-c"]+" C"):$("#temp").text(e["temp-f"]+" F"),e["sleep-mode"]?$("#sleep-mode").attr("checked",!0):$("#sleep-mode").attr("checked",!1),$("#sleep-mode").removeAttr("disabled")}).fail(function(){showError("Unable to get data from the device.")}).always(function(){$("#spinner").hide()})}function start(){setInterval(getStatus,3e3)}window.onload=start,$("#sleep-mode").click(function(e){console.log("Blocking sleep mode = "+$("#sleep-mode").is(":checked")),$.ajax({type:"POST",url:"/api/status/sleepmode",data:{id:$("#id").text(),"sleep-mode":$("#sleep-mode").is(":checked")},success:function(e){},error:function(e){showError("Could not update sleep mode for device.")}})})</script><!-- START FOOTER --><div class="container-fluid themed-container bg-primary text-light">(C) Copyright 2021-22 Magnus Persson</div></body></html>

View File

@ -27,19 +27,14 @@ build_flags =
#-D DEBUG_ESP_HTTP_SERVER #-D DEBUG_ESP_HTTP_SERVER
#-D DEBUG_ESP_PORT=Serial #-D DEBUG_ESP_PORT=Serial
#-D DEBUG_ESP_WIFI #-D DEBUG_ESP_WIFI
#-D DEBUG_ESP_SSL
#-D DEBUG_ESP_CORE #-D DEBUG_ESP_CORE
#-D SKIP_SLEEPMODE #-D SKIP_SLEEPMODE
-D CFG_DISABLE_LOGGING # Turn off verbose logging for some of the parts (too much will cause a crash) but also add space
-D GYRO_DISABLE_LOGGING
-D PUSH_DISABLE_LOGGING
-D TSEN_DISABLE_LOGGING
-D WEB_DISABLE_LOGGING
-D MAIN_DISABLE_LOGGING
-D USE_LITTLEFS=true -D USE_LITTLEFS=true
-D EMBED_HTML # If this is not used the html files needs to be on the file system (can be uploaded) -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=\""\"" # =\""myssid\""
-D USER_SSID_PWD=\""\"" # =\""mypwd\"" -D USER_SSID_PWD=\""\"" # =\""mypwd\""
-D CFG_APPVER="\"0.6.0\"" -D CFG_APPVER="\"0.6.1\""
lib_deps = # Switched to forks for better version control. lib_deps = # Switched to forks for better version control.
# Using local copy of this library # Using local copy of this library
#https://github.com/jrowberg/i2cdevlib.git#<document> #https://github.com/jrowberg/i2cdevlib.git#<document>
@ -65,20 +60,26 @@ extra_scripts =
script/create_versionjson.py script/create_versionjson.py
build_unflags = build_unflags =
${common_env_data.build_unflags} ${common_env_data.build_unflags}
# -D MAIN_DISABLE_LOGGING
-D WEB_DISABLE_LOGGING
-D PUSH_DISABLE_LOGGING
build_flags = build_flags =
${common_env_data.build_flags} ${common_env_data.build_flags}
-D PIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS #-D PIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS
#-D SKIP_SLEEPMODE #-D SKIP_SLEEPMODE
-D DOUBLERESETDETECTOR_DEBUG=true #-D DOUBLERESETDETECTOR_DEBUG=true
-D COLLECT_PERFDATA # This option will collect runtime data for a few defined methods to measure time, dumped to serial and/or influxdb -D COLLECT_PERFDATA # This option will collect runtime data for a few defined methods to measure time, dumped to serial and/or influxdb
-D LOG_LEVEL=6 # Maximum log level for the debug build. -D LOG_LEVEL=6 # Maximum log level for the debug build.
-D CFG_DISABLE_LOGGING # Turn off verbose/notice logging to reduce size and dont overload uart.
-D GYRO_DISABLE_LOGGING
-D CALC_DISABLE_LOGGING
-D HELPER_DISABLE_LOGGING
-D PUSH_DISABLE_LOGGING
-D TSEN_DISABLE_LOGGING
-D WIFI_DISABLE_LOGGING
-D WEB_DISABLE_LOGGING
-D MAIN_DISABLE_LOGGING
lib_deps = lib_deps =
${common_env_data.lib_deps} ${common_env_data.lib_deps}
board = ${common_env_data.board} board = ${common_env_data.board}
#build_type = debug # Using debug type crashes my devkit... #build_type = debug
build_type = release build_type = release
board_build.filesystem = littlefs board_build.filesystem = littlefs
monitor_filters = esp8266_exception_decoder monitor_filters = esp8266_exception_decoder

View File

@ -29,7 +29,7 @@ SOFTWARE.
#include <helper.hpp> #include <helper.hpp>
#include <tempsensor.hpp> #include <tempsensor.hpp>
#define FORMULA_MAX_DEVIATION 1.5 #define FORMULA_MAX_DEVIATION 1.6
// //
// Use values to derive a formula // Use values to derive a formula
@ -46,7 +46,7 @@ int createFormula(RawFormulaData &fd, char *formulaBuffer,
else if (fd.a[0] > 0 && fd.a[1] > 0 && fd.a[2] > 0) else if (fd.a[0] > 0 && fd.a[1] > 0 && fd.a[2] > 0)
noAngles = 3; noAngles = 3;
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
Log.verbose( Log.verbose(
F("CALC: Trying to create formula using order = %d, found %d angles" CR), F("CALC: Trying to create formula using order = %d, found %d angles" CR),
order, noAngles); order, noAngles);
@ -62,7 +62,7 @@ int createFormula(RawFormulaData &fd, char *formulaBuffer,
// Returned value is 0 if no error // Returned value is 0 if no error
if (ret == 0) { if (ret == 0) {
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
Log.verbose(F("CALC: Finshied processing data points." CR)); Log.verbose(F("CALC: Finshied processing data points." CR));
#endif #endif
@ -83,7 +83,7 @@ int createFormula(RawFormulaData &fd, char *formulaBuffer,
coeffs[1]); coeffs[1]);
} }
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
Log.verbose(F("CALC: Formula: %s" CR), formulaBuffer); Log.verbose(F("CALC: Formula: %s" CR), formulaBuffer);
#endif #endif
@ -96,7 +96,14 @@ int createFormula(RawFormulaData &fd, char *formulaBuffer,
double dev = (g - fd.g[i]) < 0 ? (fd.g[i] - g) : (g - fd.g[i]); 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 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) {
#if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
char s[10];
snprintf(&s[0], sizeof(s), "%.8f", dev);
Log.verbose(F("CALC: Deviation is: %s" CR), &s[0]);
#endif
valid = false;
}
} }
if (!valid) { if (!valid) {
@ -121,13 +128,13 @@ double calculateGravity(double angle, double temp, const char *tempFormula) {
const char *formula = myConfig.getGravityFormula(); const char *formula = myConfig.getGravityFormula();
if (tempFormula != 0) { if (tempFormula != 0) {
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
Log.verbose(F("CALC: Using temporary formula." CR)); Log.verbose(F("CALC: Using temporary formula." CR));
#endif #endif
formula = tempFormula; formula = tempFormula;
} }
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
Log.verbose(F("CALC: Calculating gravity for angle %F, temp %F." CR), angle, Log.verbose(F("CALC: Calculating gravity for angle %F, temp %F." CR), angle,
temp); temp);
Log.verbose(F("CALC: Formula %s." CR), formula); Log.verbose(F("CALC: Formula %s." CR), formula);
@ -146,8 +153,10 @@ double calculateGravity(double angle, double temp, const char *tempFormula) {
double g = te_eval(expr); double g = te_eval(expr);
te_free(expr); te_free(expr);
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
Log.verbose(F("CALC: Calculated gravity is %F." CR), g); char s[10];
snprintf(&s[0], sizeof(s), "%.8f", g);
Log.verbose(F("CALC: Calculated gravity is %s." CR), &s[0]);
#endif #endif
return g; return g;
} }
@ -158,18 +167,20 @@ double calculateGravity(double angle, double temp, const char *tempFormula) {
// //
// Do a standard gravity temperature correction. This is a simple way to adjust // Do a standard gravity temperature correction. This is a simple way to adjust
// for differnt worth temperatures // for differnt worth temperatures. This function uses C as temperature.
// //
double gravityTemperatureCorrection(double gravity, double temp, // Source: https://homebrewacademy.com/hydrometer-temperature-correction/
char tempFormat, double calTemp) { //
#if LOG_LEVEL == 6 double gravityTemperatureCorrectionC(double gravity, double tempC,
double calTempC) {
#if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
Log.verbose(F("CALC: Adjusting gravity based on temperature, gravity %F, " Log.verbose(F("CALC: Adjusting gravity based on temperature, gravity %F, "
"temp %F, calTemp %F." CR), "temp %F, calTemp %F." CR),
gravity, temp, calTemp); gravity, tempC, calTempC);
#endif #endif
// float tempF = convertCtoF(tempC);
// float calTempF = convertCtoF(calTempC);
if (tempFormat == 'C') temp = convertCtoF(temp);
double calTempF = convertCtoF(calTemp); // calTemp is in C
const char *formula = const char *formula =
"gravity*((1.00130346-0.000134722124*temp+0.00000204052596*temp^2-0." "gravity*((1.00130346-0.000134722124*temp+0.00000204052596*temp^2-0."
"00000000232820948*temp^3)/" "00000000232820948*temp^3)/"
@ -178,7 +189,7 @@ double gravityTemperatureCorrection(double gravity, double temp,
// Store variable names and pointers. // Store variable names and pointers.
te_variable vars[] = { te_variable vars[] = {
{"gravity", &gravity}, {"temp", &temp}, {"cal", &calTempF}}; {"gravity", &gravity}, {"temp", &tempC}, {"cal", &calTempC}};
int err; int err;
// Compile the expression with variables. // Compile the expression with variables.
@ -188,8 +199,10 @@ double gravityTemperatureCorrection(double gravity, double temp,
double g = te_eval(expr); double g = te_eval(expr);
te_free(expr); te_free(expr);
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(CALC_DISABLE_LOGGING)
Log.verbose(F("CALC: Corrected gravity is %F." CR), g); char s[10];
snprintf(&s[0], sizeof(s), "%.8f", g);
Log.verbose(F("CALC: Corrected gravity is %s." CR), &s[0]);
#endif #endif
return g; return g;
} }

View File

@ -26,16 +26,16 @@ SOFTWARE.
// Includes // Includes
#include <config.hpp> #include <config.hpp>
#include <helper.hpp>
#define ERR_FORMULA_NOTENOUGHVALUES -1 #define ERR_FORMULA_NOTENOUGHVALUES -1
#define ERR_FORMULA_INTERNAL -2 #define ERR_FORMULA_INTERNAL -2
#define ERR_FORMULA_UNABLETOFFIND -3 #define ERR_FORMULA_UNABLETOFFIND -3
// Functions // Functions
double calculateGravity(double angle, double temp, const char *tempFormula = 0); double calculateGravity(double angle, double tempC,
double gravityTemperatureCorrection(double gravity, double temp, const char *tempFormula = 0);
char tempFormat, double calTemp = 20); double gravityTemperatureCorrectionC(double gravity, double tempC,
double calTempC = 20);
int createFormula(RawFormulaData &fd, char *formulaBuffer, int createFormula(RawFormulaData &fd, char *formulaBuffer,
int formulaBufferSize, int order); int formulaBufferSize, int order);

View File

@ -48,7 +48,7 @@ Config::Config() {
setGravityFormat('G'); setGravityFormat('G');
setSleepInterval(900); // 15 minutes setSleepInterval(900); // 15 minutes
setVoltageFactor(1.59); // Conversion factor for battery setVoltageFactor(1.59); // Conversion factor for battery
setTempSensorAdj(0.0); setTempSensorAdjC(0.0);
setGravityTempAdj(false); setGravityTempAdj(false);
gyroCalibration = {0, 0, 0, 0, 0, 0}; gyroCalibration = {0, 0, 0, 0, 0, 0};
formulaData = {{0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}}; formulaData = {{0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}};
@ -82,7 +82,7 @@ void Config::createJson(DynamicJsonDocument& doc) {
doc[CFG_PARAM_VOLTAGEFACTOR] = getVoltageFactor(); doc[CFG_PARAM_VOLTAGEFACTOR] = getVoltageFactor();
doc[CFG_PARAM_GRAVITY_FORMULA] = getGravityFormula(); doc[CFG_PARAM_GRAVITY_FORMULA] = getGravityFormula();
doc[CFG_PARAM_GRAVITY_FORMAT] = String(getGravityFormat()); doc[CFG_PARAM_GRAVITY_FORMAT] = String(getGravityFormat());
doc[CFG_PARAM_TEMP_ADJ] = getTempSensorAdj(); doc[CFG_PARAM_TEMP_ADJ] = getTempSensorAdjC();
doc[CFG_PARAM_GRAVITY_TEMP_ADJ] = isGravityTempAdj(); doc[CFG_PARAM_GRAVITY_TEMP_ADJ] = isGravityTempAdj();
doc[CFG_PARAM_GYRO_TEMP] = isGyroTemp(); doc[CFG_PARAM_GYRO_TEMP] = isGyroTemp();
@ -239,7 +239,7 @@ bool Config::loadFile() {
setGravityFormat(s.charAt(0)); setGravityFormat(s.charAt(0));
} }
if (!doc[CFG_PARAM_TEMP_ADJ].isNull()) if (!doc[CFG_PARAM_TEMP_ADJ].isNull())
setTempSensorAdj(doc[CFG_PARAM_TEMP_ADJ].as<float>()); setTempSensorAdjC(doc[CFG_PARAM_TEMP_ADJ].as<float>());
if (!doc[CFG_PARAM_GYRO_CALIBRATION]["ax"].isNull()) if (!doc[CFG_PARAM_GYRO_CALIBRATION]["ax"].isNull())
gyroCalibration.ax = doc[CFG_PARAM_GYRO_CALIBRATION]["ax"]; gyroCalibration.ax = doc[CFG_PARAM_GYRO_CALIBRATION]["ax"];
@ -318,7 +318,7 @@ void Config::debug() {
Log.verbose(F("CFG : Sleep interval; %d." CR), getSleepInterval()); Log.verbose(F("CFG : Sleep interval; %d." CR), getSleepInterval());
Log.verbose(F("CFG : OTA; '%s'." CR), getOtaURL()); Log.verbose(F("CFG : OTA; '%s'." CR), getOtaURL());
Log.verbose(F("CFG : Temp Format; %c." CR), getTempFormat()); Log.verbose(F("CFG : Temp Format; %c." CR), getTempFormat());
Log.verbose(F("CFG : Temp Adj; %F." CR), getTempSensorAdj()); Log.verbose(F("CFG : Temp Adj; %F." CR), getTempSensorAdjC());
Log.verbose(F("CFG : VoltageFactor; %F." CR), getVoltageFactor()); Log.verbose(F("CFG : VoltageFactor; %F." CR), getVoltageFactor());
Log.verbose(F("CFG : Gravity formula; '%s'." CR), getGravityFormula()); Log.verbose(F("CFG : Gravity formula; '%s'." CR), getGravityFormula());
Log.verbose(F("CFG : Gravity format; '%c'." CR), getGravityFormat()); Log.verbose(F("CFG : Gravity format; '%c'." CR), getGravityFormat());

View File

@ -89,6 +89,7 @@ SOFTWARE.
#define CFG_PARAM_BATTERY "battery" #define CFG_PARAM_BATTERY "battery"
#define CFG_PARAM_SLEEP_MODE "sleep-mode" #define CFG_PARAM_SLEEP_MODE "sleep-mode"
#define CFG_PARAM_RSSI "rssi" #define CFG_PARAM_RSSI "rssi"
#define CFG_PARAM_ERROR "error"
// Used for holding sensordata or sensoroffsets // Used for holding sensordata or sensoroffsets
struct RawGyroData { struct RawGyroData {
@ -118,41 +119,40 @@ class Config {
String id; String id;
String mDNS; String mDNS;
String otaURL; String otaURL;
char tempFormat; // C, F char tempFormat;
float voltageFactor; float voltageFactor;
float tempSensorAdj; // This value will be added to the read sensor value float tempSensorAdjC;
int sleepInterval; int sleepInterval;
bool gyroTemp; // Experimental feature bool gyroTemp;
// Wifi Config // Wifi Config
String wifiSSID; String wifiSSID;
String wifiPASS; String wifiPASS;
// Push target settings // Push target settings
String brewfatherPushUrl; // URL For brewfather String brewfatherPushUrl;
String httpPushUrl; // URL 1 for standard http String httpPushUrl;
String httpPushUrl2; // URL 2 for standard http String httpPushUrl2;
String influxDb2Url; // URL for InfluxDB v2 String influxDb2Url;
String influxDb2Org; // Organisation for InfluxDB v2 String influxDb2Org;
String influxDb2Bucket; // Bucket for InfluxDB v2 String influxDb2Bucket;
String influxDb2Token; // Auth Token for InfluxDB v2 String influxDb2Token;
String mqttUrl; // Server name String mqttUrl;
String mqttTopic; String mqttTopic;
String mqttUser; String mqttUser;
String mqttPass; String mqttPass;
// Gravity and temperature calculations // Gravity and temperature calculations
String gravityFormula; String gravityFormula;
bool gravityTempAdj; // true, false bool gravityTempAdj;
char gravityFormat; // G, P char gravityFormat;
// Gyro calibration data // Gyro calibration and formula calculation data
RawGyroData RawGyroData gyroCalibration;
gyroCalibration; // Holds the gyro calibration constants (6 * int16_t) RawFormulaData formulaData;
RawFormulaData formulaData; // Used for creating formula
void debug(); void debug();
void formatFileSystem(); void formatFileSystem();
@ -273,11 +273,13 @@ class Config {
char getTempFormat() { return tempFormat; } char getTempFormat() { return tempFormat; }
void setTempFormat(char c) { void setTempFormat(char c) {
tempFormat = c; if (c == 'C' || c == 'F') {
saveNeeded = true; tempFormat = c;
saveNeeded = true;
}
} }
bool isTempC() { return tempFormat == 'C' ? false : true; } bool isTempC() { return tempFormat == 'C'; }
bool isTempF() { return tempFormat == 'F' ? false : true; } bool isTempF() { return tempFormat == 'F'; }
float getVoltageFactor() { return voltageFactor; } float getVoltageFactor() { return voltageFactor; }
void setVoltageFactor(float f) { void setVoltageFactor(float f) {
@ -289,13 +291,17 @@ class Config {
saveNeeded = true; saveNeeded = true;
} }
float getTempSensorAdj() { return tempSensorAdj; } float getTempSensorAdjC() { return tempSensorAdjC; }
void setTempSensorAdj(float f) { void setTempSensorAdjC(float f) {
tempSensorAdj = f; tempSensorAdjC = f;
saveNeeded = true; saveNeeded = true;
} }
void setTempSensorAdj(String s) { void setTempSensorAdjC(String s) {
tempSensorAdj = s.toFloat(); tempSensorAdjC = s.toFloat();
saveNeeded = true;
}
void setTempSensorAdjF(String s) {
tempSensorAdjC = convertFtoC(s.toFloat());
saveNeeded = true; saveNeeded = true;
} }
@ -313,11 +319,13 @@ class Config {
char getGravityFormat() { return gravityFormat; } char getGravityFormat() { return gravityFormat; }
void setGravityFormat(char c) { void setGravityFormat(char c) {
gravityFormat = c; if (c == 'G' || c == 'P') {
saveNeeded = true; gravityFormat = c;
saveNeeded = true;
}
} }
bool isGravitySG() { return gravityFormat == 'G' ? false : true; } bool isGravitySG() { return gravityFormat == 'G'; }
bool isGravityPlato() { return gravityFormat == 'P' ? false : true; } bool isGravityPlato() { return gravityFormat == 'P'; }
const RawGyroData& getGyroCalibration() { return gyroCalibration; } const RawGyroData& getGyroCalibration() { return gyroCalibration; }
void setGyroCalibration(const RawGyroData& r) { void setGyroCalibration(const RawGyroData& r) {

View File

@ -24,19 +24,39 @@ SOFTWARE.
#include <ESP8266HTTPClient.h> #include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <config.hpp>
#include <gyro.hpp> #include <gyro.hpp>
#include <helper.hpp> #include <helper.hpp>
#include <tempsensor.hpp> #include <tempsensor.hpp>
#include <wifi.hpp>
SerialDebug mySerial; SerialDebug mySerial;
BatteryVoltage myBatteryVoltage; BatteryVoltage myBatteryVoltage;
//
// Convert sg to plato
//
double convertToPlato(double sg) { return 259 - (259 / sg); }
//
// Convert plato to sg
//
double convertToSG(double plato) { return 259 / (259 - plato); }
//
// Conversion to F
//
float convertCtoF(float c) { return (c * 1.8) + 32.0; }
//
// Conversion to C
//
float convertFtoC(float f) { return (f - 32.0) / 1.8; }
// //
// Print the heap information. // Print the heap information.
// //
void printHeap() { void printHeap() {
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(HELPER_DISABLE_LOGGING)
Log.verbose(F("HELP: Heap %d kb, HeapFrag %d %%, FreeSketch %d kb." CR), Log.verbose(F("HELP: Heap %d kb, HeapFrag %d %%, FreeSketch %d kb." CR),
ESP.getFreeHeap() / 1024, ESP.getHeapFragmentation(), ESP.getFreeHeap() / 1024, ESP.getHeapFragmentation(),
ESP.getFreeSketchSpace() / 1024); ESP.getFreeSketchSpace() / 1024);
@ -47,7 +67,7 @@ void printHeap() {
// Enter deep sleep for the defined duration (Argument is seconds) // Enter deep sleep for the defined duration (Argument is seconds)
// //
void deepSleep(int t) { void deepSleep(int t) {
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(HELPER_DISABLE_LOGGING)
Log.verbose(F("HELP: Entering sleep mode for %ds." CR), t); Log.verbose(F("HELP: Entering sleep mode for %ds." CR), t);
#endif #endif
uint32_t wake = t * 1000000; uint32_t wake = t * 1000000;
@ -106,7 +126,7 @@ void BatteryVoltage::read() {
float factor = myConfig.getVoltageFactor(); // Default value is 1.63 float factor = myConfig.getVoltageFactor(); // Default value is 1.63
int v = analogRead(A0); int v = analogRead(A0);
batteryLevel = ((3.3 / 1023) * v) * factor; batteryLevel = ((3.3 / 1023) * v) * factor;
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(HELPER_DISABLE_LOGGING)
Log.verbose( Log.verbose(
F("BATT: Reading voltage level. Factor=%F Value=%d, Voltage=%F." CR), F("BATT: Reading voltage level. Factor=%F Value=%d, Voltage=%F." CR),
factor, v, batteryLevel); factor, v, batteryLevel);
@ -177,14 +197,13 @@ void PerfLogging::print() {
void PerfLogging::pushInflux() { void PerfLogging::pushInflux() {
if (!myConfig.isInfluxDb2Active()) return; if (!myConfig.isInfluxDb2Active()) return;
WiFiClient client;
HTTPClient http; HTTPClient http;
String serverPath = String serverPath =
String(myConfig.getInfluxDb2PushUrl()) + String(myConfig.getInfluxDb2PushUrl()) +
"/api/v2/write?org=" + String(myConfig.getInfluxDb2PushOrg()) + "/api/v2/write?org=" + String(myConfig.getInfluxDb2PushOrg()) +
"&bucket=" + String(myConfig.getInfluxDb2PushBucket()); "&bucket=" + String(myConfig.getInfluxDb2PushBucket());
http.begin(client, serverPath); http.begin(myWifi.getWifiClient(), serverPath);
// Create body for influxdb2, format used // Create body for influxdb2, format used
// key,host=mdns value=0.0 // key,host=mdns value=0.0
@ -225,7 +244,7 @@ void PerfLogging::pushInflux() {
// Log.notice(F("PERF: data %s." CR), body.c_str() ); // Log.notice(F("PERF: data %s." CR), body.c_str() );
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(HELPER_DISABLE_LOGGING)
Log.verbose(F("PERF: url %s." CR), serverPath.c_str()); Log.verbose(F("PERF: url %s." CR), serverPath.c_str());
Log.verbose(F("PERF: data %s." CR), body.c_str()); Log.verbose(F("PERF: data %s." CR), body.c_str());
#endif #endif
@ -236,15 +255,18 @@ void PerfLogging::pushInflux() {
int httpResponseCode = http.POST(body); int httpResponseCode = http.POST(body);
if (httpResponseCode == 204) { if (httpResponseCode == 204) {
#if !defined(HELPER_DISABLE_LOGGING)
Log.notice( Log.notice(
F("PERF: InfluxDB2 push performance data successful, response=%d" CR), F("PERF: InfluxDB2 push performance data successful, response=%d" CR),
httpResponseCode); httpResponseCode);
#endif
} else { } else {
Log.error(F("PERF: InfluxDB2 push performance data failed, response=%d" CR), Log.error(F("PERF: InfluxDB2 push performance data failed, response=%d" CR),
httpResponseCode); httpResponseCode);
} }
http.end(); http.end();
myWifi.closeWifiClient();
} }
#endif // COLLECT_PERFDATA #endif // COLLECT_PERFDATA

View File

@ -33,6 +33,12 @@ void deepSleep(int t);
// Show build options // Show build options
void printBuildOptions(); void printBuildOptions();
// Data conversion
double convertToPlato(double sg);
double convertToSG(double plato);
float convertCtoF(float c);
float convertFtoC(float f);
// Float to String // Float to String
char* convertFloatToString(float f, char* buf, int dec = 2); char* convertFloatToString(float f, char* buf, int dec = 2);
float reduceFloatPrecision(float f, int dec = 2); float reduceFloatPrecision(float f, int dec = 2);

View File

@ -63,14 +63,18 @@ void checkSleepMode(float angle, float volt) {
if (!g.ax && !g.ay && !g.az && !g.gx && !g.gy && !g.gz) { if (!g.ax && !g.ay && !g.az && !g.gx && !g.gy && !g.gz) {
// Will not enter sleep mode if: no calibration data // Will not enter sleep mode if: no calibration data
#if !defined(MAIN_DISABLE_LOGGING)
Log.notice( Log.notice(
F("MAIN: Missing calibration data, so forcing webserver to be " F("MAIN: Missing calibration data, so forcing webserver to be "
"active." CR)); "active." CR));
#endif
runMode = RunMode::configurationMode; runMode = RunMode::configurationMode;
} else if (sleepModeAlwaysSkip) { } else if (sleepModeAlwaysSkip) {
// Check if the flag from the UI has been set, the we force configuration // Check if the flag from the UI has been set, the we force configuration
// mode. // mode.
#if !defined(MAIN_DISABLE_LOGGING)
Log.notice(F("MAIN: Sleep mode disabled from web interface." CR)); Log.notice(F("MAIN: Sleep mode disabled from web interface." CR));
#endif
runMode = RunMode::configurationMode; runMode = RunMode::configurationMode;
} else if ((volt < 4.15 && (angle > 85 && angle < 95)) || (volt > 4.15)) { } else if ((volt < 4.15 && (angle > 85 && angle < 95)) || (volt > 4.15)) {
runMode = RunMode::configurationMode; runMode = RunMode::configurationMode;
@ -80,14 +84,18 @@ void checkSleepMode(float angle, float volt) {
switch (runMode) { switch (runMode) {
case RunMode::configurationMode: case RunMode::configurationMode:
#if !defined(MAIN_DISABLE_LOGGING)
Log.notice(F("MAIN: run mode CONFIG (angle=%F volt=%F)." CR), angle, Log.notice(F("MAIN: run mode CONFIG (angle=%F volt=%F)." CR), angle,
volt); volt);
#endif
break; break;
case RunMode::wifiSetupMode: case RunMode::wifiSetupMode:
break; break;
case RunMode::gravityMode: case RunMode::gravityMode:
#if !defined(MAIN_DISABLE_LOGGING)
Log.notice(F("MAIN: run mode GRAVITY (angle=%F volt=%F)." CR), angle, Log.notice(F("MAIN: run mode GRAVITY (angle=%F volt=%F)." CR), angle,
volt); volt);
#endif
break; break;
} }
} }
@ -207,22 +215,21 @@ bool loopReadGravity() {
stableGyroMillis = millis(); // Reset timer stableGyroMillis = millis(); // Reset timer
LOG_PERF_START("loop-temp-read"); LOG_PERF_START("loop-temp-read");
float temp = myTempSensor.getTempC(myConfig.isGyroTemp()); float tempC = myTempSensor.getTempC(myConfig.isGyroTemp());
LOG_PERF_STOP("loop-temp-read"); LOG_PERF_STOP("loop-temp-read");
float gravity = calculateGravity(angle, temp); float gravity = calculateGravity(angle, tempC);
float corrGravity = float corrGravity = gravityTemperatureCorrectionC(gravity, tempC);
gravityTemperatureCorrection(gravity, temp, myConfig.getTempFormat());
#if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(MAIN_DISABLE_LOGGING)
Log.verbose(F("Main: Sensor values gyro angle=%F, temp=%F, gravity=%F, " Log.verbose(F("Main: Sensor values gyro angle=%F, temp=%FC, gravity=%F, "
"corr=%F." CR), "corr_gravity=%F." CR),
angle, temp, gravity, corrGravity); angle, tempC, gravity, corrGravity);
#endif #endif
LOG_PERF_START("loop-push"); LOG_PERF_START("loop-push");
// Force the transmission if we are going to sleep // Force the transmission if we are going to sleep
myPushTarget.send(angle, gravity, corrGravity, temp, myPushTarget.send(angle, gravity, corrGravity, tempC,
(millis() - runtimeMillis) / 1000, (millis() - runtimeMillis) / 1000,
runMode == RunMode::gravityMode ? true : false); runMode == RunMode::gravityMode ? true : false);
LOG_PERF_STOP("loop-push"); LOG_PERF_STOP("loop-push");

View File

@ -21,19 +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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include <ESP8266HTTPClient.h>
#include <MQTT.h> #include <MQTT.h>
#include <config.hpp> #include <config.hpp>
#include <gyro.hpp> #include <gyro.hpp>
#include <pushtarget.hpp> #include <pushtarget.hpp>
#include <wifi.hpp>
PushTarget myPushTarget; PushTarget myPushTarget;
// //
// Send the pressure value // Send the data to targets
// //
void PushTarget::send(float angle, float gravity, float corrGravity, float temp, void PushTarget::send(float angle, float gravity, float corrGravity,
float runTime, bool force) { float tempC, float runTime, bool force) {
uint32_t timePassed = abs((int32_t)(millis() - ms)); uint32_t timePassed = abs((int32_t)(millis() - ms));
uint32_t interval = myConfig.getSleepInterval() * 1000; uint32_t interval = myConfig.getSleepInterval() * 1000;
@ -45,41 +47,37 @@ void PushTarget::send(float angle, float gravity, float corrGravity, float temp,
return; return;
} }
#if LOG_LEVEL == 6 && !defined(PUSH_DISABLE_LOGGING)
Log.verbose(F("PUSH: Sending data." CR));
#endif
ms = millis(); ms = millis();
if (myConfig.isBrewfatherActive()) { if (myConfig.isBrewfatherActive()) {
LOG_PERF_START("push-brewfather"); LOG_PERF_START("push-brewfather");
sendBrewfather(angle, gravity, corrGravity, temp); sendBrewfather(angle, gravity, corrGravity, tempC);
LOG_PERF_STOP("push-brewfather"); LOG_PERF_STOP("push-brewfather");
} }
if (myConfig.isHttpActive()) { if (myConfig.isHttpActive()) {
LOG_PERF_START("push-http"); LOG_PERF_START("push-http");
sendHttp(myConfig.getHttpPushUrl(), angle, gravity, corrGravity, temp, sendHttp(myConfig.getHttpPushUrl(), angle, gravity, corrGravity, tempC,
runTime); runTime);
LOG_PERF_STOP("push-http"); LOG_PERF_STOP("push-http");
} }
if (myConfig.isHttpActive2()) { if (myConfig.isHttpActive2()) {
LOG_PERF_START("push-http2"); LOG_PERF_START("push-http2");
sendHttp(myConfig.getHttpPushUrl2(), angle, gravity, corrGravity, temp, sendHttp(myConfig.getHttpPushUrl2(), angle, gravity, corrGravity, tempC,
runTime); runTime);
LOG_PERF_STOP("push-http2"); LOG_PERF_STOP("push-http2");
} }
if (myConfig.isInfluxDb2Active()) { if (myConfig.isInfluxDb2Active()) {
LOG_PERF_START("push-influxdb2"); LOG_PERF_START("push-influxdb2");
sendInfluxDb2(angle, gravity, corrGravity, temp, runTime); sendInfluxDb2(angle, gravity, corrGravity, tempC, runTime);
LOG_PERF_STOP("push-influxdb2"); LOG_PERF_STOP("push-influxdb2");
} }
if (myConfig.isMqttActive()) { if (myConfig.isMqttActive()) {
LOG_PERF_START("push-mqtt"); LOG_PERF_START("push-mqtt");
sendMqtt(angle, gravity, corrGravity, temp, runTime); sendMqtt(angle, gravity, corrGravity, tempC, runTime);
LOG_PERF_STOP("push-mqtt"); LOG_PERF_STOP("push-mqtt");
} }
} }
@ -88,32 +86,43 @@ void PushTarget::send(float angle, float gravity, float corrGravity, float temp,
// Send to influx db v2 // Send to influx db v2
// //
void PushTarget::sendInfluxDb2(float angle, float gravity, float corrGravity, void PushTarget::sendInfluxDb2(float angle, float gravity, float corrGravity,
float temp, float runTime) { float tempC, float runTime) {
#if !defined(PUSH_DISABLE_LOGGING) #if !defined(PUSH_DISABLE_LOGGING)
Log.notice( Log.notice(
F("PUSH: Sending values to influxdb2 angle=%F, gravity=%F, temp=%F." CR), F("PUSH: Sending values to influxdb2 angle=%F, gravity=%F, temp=%F." CR),
angle, gravity, temp); angle, gravity, tempC);
#endif #endif
WiFiClient client;
HTTPClient http; HTTPClient http;
String serverPath = String serverPath =
String(myConfig.getInfluxDb2PushUrl()) + String(myConfig.getInfluxDb2PushUrl()) +
"/api/v2/write?org=" + String(myConfig.getInfluxDb2PushOrg()) + "/api/v2/write?org=" + String(myConfig.getInfluxDb2PushOrg()) +
"&bucket=" + String(myConfig.getInfluxDb2PushBucket()); "&bucket=" + String(myConfig.getInfluxDb2PushBucket());
http.begin(client, serverPath); http.begin(myWifi.getWifiClient(), serverPath);
float temp = myConfig.isTempC() ? tempC : convertCtoF(tempC);
gravity = myConfig.isGravityTempAdj() ? corrGravity : gravity;
// Create body for influxdb2 // Create body for influxdb2
char buf[1024]; char buf[1024];
snprintf(&buf[0], sizeof(buf), if (myConfig.isGravitySG()) {
"measurement,host=%s,device=%s,temp-format=%c,gravity-format=%s " snprintf(&buf[0], sizeof(buf),
"gravity=%.4f,corr-gravity=%.4f,angle=%.2f,temp=%.2f,battery=%.2f," "measurement,host=%s,device=%s,temp-format=%c,gravity-format=%s "
"rssi=%d\n", "gravity=%.4f,corr-gravity=%.4f,angle=%.2f,temp=%.2f,battery=%.2f,"
// TODO: Add support for plato format "rssi=%d\n",
myConfig.getMDNS(), myConfig.getID(), myConfig.getTempFormat(), "SG", myConfig.getMDNS(), myConfig.getID(), myConfig.getTempFormat(),
myConfig.isGravityTempAdj() ? corrGravity : gravity, corrGravity, "G", gravity, corrGravity, angle, temp,
angle, temp, myBatteryVoltage.getVoltage(), WiFi.RSSI()); myBatteryVoltage.getVoltage(), WiFi.RSSI());
} else {
snprintf(&buf[0], sizeof(buf),
"measurement,host=%s,device=%s,temp-format=%c,gravity-format=%s "
"gravity=%.1f,corr-gravity=%.1f,angle=%.2f,temp=%.2f,battery=%.2f,"
"rssi=%d\n",
myConfig.getMDNS(), myConfig.getID(), myConfig.getTempFormat(),
"G", convertToPlato(gravity), convertToPlato(corrGravity), angle,
convertCtoF(temp), myBatteryVoltage.getVoltage(), WiFi.RSSI());
}
#if LOG_LEVEL == 6 && !defined(PUSH_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(PUSH_DISABLE_LOGGING)
Log.verbose(F("PUSH: url %s." CR), serverPath.c_str()); Log.verbose(F("PUSH: url %s." CR), serverPath.c_str());
@ -134,17 +143,18 @@ void PushTarget::sendInfluxDb2(float angle, float gravity, float corrGravity,
} }
http.end(); http.end();
myWifi.closeWifiClient();
} }
// //
// Send data to brewfather // Send data to brewfather
// //
void PushTarget::sendBrewfather(float angle, float gravity, float corrGravity, void PushTarget::sendBrewfather(float angle, float gravity, float corrGravity,
float temp) { float tempC) {
#if !defined(PUSH_DISABLE_LOGGING) #if !defined(PUSH_DISABLE_LOGGING)
Log.notice( Log.notice(F("PUSH: Sending values to brewfather angle=%F, gravity=%F, "
F("PUSH: Sending values to brewfather angle=%F, gravity=%F, temp=%F." CR), "corr-gravity=%F, temp=%F." CR),
angle, gravity, temp); angle, gravity, corrGravity, tempC);
#endif #endif
DynamicJsonDocument doc(300); DynamicJsonDocument doc(300);
@ -165,21 +175,26 @@ void PushTarget::sendBrewfather(float angle, float gravity, float corrGravity,
// "battery": 4.98 // "battery": 4.98
// } // }
// //
float temp = myConfig.isTempC() ? tempC : convertCtoF(tempC);
doc["name"] = myConfig.getMDNS(); doc["name"] = myConfig.getMDNS();
doc["temp"] = reduceFloatPrecision(temp, 1); doc["temp"] = reduceFloatPrecision(temp, 1);
doc["temp_unit"] = String(myConfig.getTempFormat()); doc["temp_unit"] = String(myConfig.getTempFormat());
doc["battery"] = reduceFloatPrecision(myBatteryVoltage.getVoltage(), 2); doc["battery"] = reduceFloatPrecision(myBatteryVoltage.getVoltage(), 2);
// TODO: Add support for plato format if (myConfig.isGravitySG()) {
doc["gravity"] = reduceFloatPrecision( doc["gravity"] = reduceFloatPrecision(
myConfig.isGravityTempAdj() ? corrGravity : gravity, 4); myConfig.isGravityTempAdj() ? corrGravity : gravity, 4);
} else {
doc["gravity"] = reduceFloatPrecision(
convertToPlato(myConfig.isGravityTempAdj() ? corrGravity : gravity), 1);
}
doc["gravity_unit"] = myConfig.isGravitySG() ? "G" : "P"; doc["gravity_unit"] = myConfig.isGravitySG() ? "G" : "P";
WiFiClient client;
HTTPClient http; HTTPClient http;
String serverPath = myConfig.getBrewfatherPushUrl(); String serverPath = myConfig.getBrewfatherPushUrl();
// Your Domain name with URL path or IP address with path // Your Domain name with URL path or IP address with path
http.begin(client, serverPath); http.begin(myWifi.getWifiClient(), serverPath);
String json; String json;
serializeJson(doc, json); serializeJson(doc, json);
#if LOG_LEVEL == 6 && !defined(PUSH_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(PUSH_DISABLE_LOGGING)
@ -200,6 +215,7 @@ void PushTarget::sendBrewfather(float angle, float gravity, float corrGravity,
} }
http.end(); http.end();
myWifi.closeWifiClient();
} }
// //
@ -207,24 +223,31 @@ void PushTarget::sendBrewfather(float angle, float gravity, float corrGravity,
// //
void PushTarget::createIspindleFormat(DynamicJsonDocument &doc, float angle, void PushTarget::createIspindleFormat(DynamicJsonDocument &doc, float angle,
float gravity, float corrGravity, float gravity, float corrGravity,
float temp, float runTime) { float tempC, float runTime) {
float temp = myConfig.isTempC() ? tempC : convertCtoF(tempC);
// Use iSpindle format for compatibility // Use iSpindle format for compatibility
doc["name"] = myConfig.getMDNS(); doc["name"] = myConfig.getMDNS();
doc["ID"] = myConfig.getID(); doc["ID"] = myConfig.getID();
doc["token"] = "gravmon"; doc["token"] = "gravitmon";
doc["interval"] = myConfig.getSleepInterval(); doc["interval"] = myConfig.getSleepInterval();
doc["temperature"] = reduceFloatPrecision(temp, 1); doc["temperature"] = reduceFloatPrecision(temp, 1);
doc["temp-units"] = String(myConfig.getTempFormat()); doc["temp-units"] = String(myConfig.getTempFormat());
// TODO: Add support for plato format if (myConfig.isGravitySG()) {
doc["gravity"] = reduceFloatPrecision( doc["gravity"] = reduceFloatPrecision(
myConfig.isGravityTempAdj() ? corrGravity : gravity, 4); myConfig.isGravityTempAdj() ? corrGravity : gravity, 4);
doc["corr-gravity"] = reduceFloatPrecision(corrGravity, 4); doc["corr-gravity"] = reduceFloatPrecision(corrGravity, 4);
} else {
doc["gravity"] = reduceFloatPrecision(
convertToPlato(myConfig.isGravityTempAdj() ? corrGravity : gravity), 1);
doc["corr-gravity"] = reduceFloatPrecision(convertToPlato(corrGravity), 1);
}
doc["angle"] = reduceFloatPrecision(angle, 2); doc["angle"] = reduceFloatPrecision(angle, 2);
doc["battery"] = reduceFloatPrecision(myBatteryVoltage.getVoltage(), 2); doc["battery"] = reduceFloatPrecision(myBatteryVoltage.getVoltage(), 2);
doc["rssi"] = WiFi.RSSI(); doc["rssi"] = WiFi.RSSI();
// Some additional information // Some additional information
doc["gravity-units"] = "SG"; doc["gravity-unit"] = myConfig.isGravitySG() ? "G" : "P";
doc["run-time"] = reduceFloatPrecision(runTime, 2); doc["run-time"] = reduceFloatPrecision(runTime, 2);
} }
@ -232,21 +255,26 @@ void PushTarget::createIspindleFormat(DynamicJsonDocument &doc, float angle,
// Send data to http target // Send data to http target
// //
void PushTarget::sendHttp(String serverPath, float angle, float gravity, void PushTarget::sendHttp(String serverPath, float angle, float gravity,
float corrGravity, float temp, float runTime) { float corrGravity, float tempC, float runTime) {
#if !defined(PUSH_DISABLE_LOGGING) #if !defined(PUSH_DISABLE_LOGGING)
Log.notice( Log.notice(F("PUSH: Sending values to http angle=%F, gravity=%F, "
F("PUSH: Sending values to http angle=%F, gravity=%F, temp=%F." CR), "corr-gravity=%F, temp=%F." CR),
angle, gravity, temp); angle, gravity, corrGravity, tempC);
#endif #endif
DynamicJsonDocument doc(256); DynamicJsonDocument doc(256);
createIspindleFormat(doc, angle, gravity, corrGravity, temp, runTime); createIspindleFormat(doc, angle, gravity, corrGravity, tempC, runTime);
WiFiClient client;
HTTPClient http; HTTPClient http;
// Your Domain name with URL path or IP address with path if (serverPath.startsWith("https://")) {
http.begin(client, serverPath); myWifi.getWifiClientSecure().setInsecure();
Log.notice(F("PUSH: HTTP, SSL enabled without validation." CR));
http.begin(myWifi.getWifiClientSecure(), serverPath);
} else {
http.begin(myWifi.getWifiClient(), serverPath);
}
String json; String json;
serializeJson(doc, json); serializeJson(doc, json);
#if LOG_LEVEL == 6 && !defined(PUSH_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(PUSH_DISABLE_LOGGING)
@ -266,26 +294,36 @@ void PushTarget::sendHttp(String serverPath, float angle, float gravity,
} }
http.end(); http.end();
myWifi.closeWifiClient();
} }
// //
// Send data to http target // Send data to http target
// //
void PushTarget::sendMqtt(float angle, float gravity, float corrGravity, void PushTarget::sendMqtt(float angle, float gravity, float corrGravity,
float temp, float runTime) { float tempC, float runTime) {
#if !defined(PUSH_DISABLE_LOGGING) #if !defined(PUSH_DISABLE_LOGGING)
Log.notice( Log.notice(F("PUSH: Sending values to mqtt angle=%F, gravity=%F, "
F("PUSH: Sending values to mqtt angle=%F, gravity=%F, temp=%F." CR), "corr-gravity=%F, temp=%F." CR),
angle, gravity, temp); angle, gravity, corrGravity, tempC);
#endif #endif
DynamicJsonDocument doc(256); DynamicJsonDocument doc(256);
createIspindleFormat(doc, angle, gravity, corrGravity, temp, runTime); createIspindleFormat(doc, angle, gravity, corrGravity, tempC, runTime);
WiFiClient client;
MQTTClient mqtt(512); // Maximum message size MQTTClient mqtt(512); // Maximum message size
String url = myConfig.getMqttUrl();
if (url.endsWith(":8883")) {
// Allow secure channel, but without certificate validation
myWifi.getWifiClientSecure().setInsecure();
Log.notice(F("PUSH: MQTT, SSL enabled without validation." CR));
url.replace(":8883", "");
mqtt.begin(url.c_str(), 8883, myWifi.getWifiClientSecure());
} else {
mqtt.begin(myConfig.getMqttUrl(), myWifi.getWifiClient());
}
mqtt.begin(myConfig.getMqttUrl(), client);
mqtt.connect(myConfig.getMDNS(), myConfig.getMqttUser(), mqtt.connect(myConfig.getMDNS(), myConfig.getMqttUser(),
myConfig.getMqttPass()); myConfig.getMqttPass());
@ -306,6 +344,7 @@ void PushTarget::sendMqtt(float angle, float gravity, float corrGravity,
} }
mqtt.disconnect(); mqtt.disconnect();
myWifi.closeWifiClient();
} }
// EOF // EOF

View File

@ -27,8 +27,6 @@ SOFTWARE.
// Includes // Includes
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <helper.hpp> #include <helper.hpp>
@ -38,15 +36,15 @@ class PushTarget {
uint32_t 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, void sendBrewfather(float angle, float gravity, float corrGravity,
float temp); float tempC);
void sendHttp(String serverPath, float angle, float gravity, void sendHttp(String serverPath, float angle, float gravity,
float corrGravity, float temp, float runTime); float corrGravity, float tempC, float runTime);
void sendInfluxDb2(float angle, float gravity, float corrGravity, float temp, void sendInfluxDb2(float angle, float gravity, float corrGravity, float tempC,
float runTime); float runTime);
void sendMqtt(float angle, float gravity, float corrGravity, float temp, void sendMqtt(float angle, float gravity, float corrGravity, float tempC,
float runTime); float runTime);
void createIspindleFormat(DynamicJsonDocument &doc, float angle, void createIspindleFormat(DynamicJsonDocument &doc, float angle,
float gravity, float corrGravity, float temp, float gravity, float corrGravity, float tempC,
float runTime); float runTime);
public: public:

View File

@ -30,11 +30,6 @@ SOFTWARE.
#include <helper.hpp> #include <helper.hpp>
#include <tempsensor.hpp> #include <tempsensor.hpp>
//
// Conversion between C and F
//
float convertCtoF(float t) { return (t * 1.8) + 32.0; }
OneWire myOneWire(D6); OneWire myOneWire(D6);
DallasTemperature mySensors(&myOneWire); DallasTemperature mySensors(&myOneWire);
#define TEMPERATURE_PRECISION 9 #define TEMPERATURE_PRECISION 9
@ -63,20 +58,12 @@ void TempSensor::setup() {
mySensors.setResolution(TEMPERATURE_PRECISION); mySensors.setResolution(TEMPERATURE_PRECISION);
} }
float t = myConfig.getTempSensorAdj();
// Set the temp sensor adjustment values // Set the temp sensor adjustment values
if (myConfig.isTempC()) { tempSensorAdjC = myConfig.getTempSensorAdjC();
tempSensorAdjF = t * 1.8; // Convert the adjustment value to C
tempSensorAdjC = t;
} else {
tempSensorAdjF = t;
tempSensorAdjC = t * 0.556; // Convert the adjustent value to F
}
#if LOG_LEVEL == 6 && !defined(TSEN_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(TSEN_DISABLE_LOGGING)
Log.verbose(F("TSEN: Adjustment values for temp sensor %F C, %F F." CR), Log.verbose(F("TSEN: Adjustment values for temp sensor %F C." CR),
tempSensorAdjC, tempSensorAdjF); tempSensorAdjC);
#endif #endif
} }
@ -101,7 +88,9 @@ float TempSensor::getValue(bool useGyro) {
// If we dont have sensors just return 0 // If we dont have sensors just return 0
if (!mySensors.getDS18Count()) { if (!mySensors.getDS18Count()) {
Log.error(F("TSEN: No temperature sensors found. Skipping read." CR)); #if !defined(TSEN_DISABLE_LOGGING)
Log.notice(F("TSEN: No temperature sensors found. Skipping read." CR));
#endif
return -273; return -273;
} }

View File

@ -25,13 +25,11 @@ SOFTWARE.
#define SRC_TEMPSENSOR_HPP_ #define SRC_TEMPSENSOR_HPP_
// definitions // definitions
float convertCtoF(float t);
// classes // classes
class TempSensor { class TempSensor {
private: private:
bool hasSensor = false; bool hasSensor = false;
float tempSensorAdjF = 0;
float tempSensorAdjC = 0; float tempSensorAdjC = 0;
float getValue(bool useGyro); float getValue(bool useGyro);
@ -41,9 +39,6 @@ class TempSensor {
float getTempC(bool useGyro = false) { float getTempC(bool useGyro = false) {
return getValue(useGyro) + tempSensorAdjC; return getValue(useGyro) + tempSensorAdjC;
} }
float getTempF(bool useGyro = false) {
return convertCtoF(getValue(useGyro)) + tempSensorAdjF;
}
}; };
// Global instance created // Global instance created

View File

@ -72,16 +72,23 @@ void WebServer::webHandleConfig() {
doc[CFG_PARAM_PASS] = ""; // dont show the wifi password doc[CFG_PARAM_PASS] = ""; // dont show the wifi password
double angle = myGyro.getAngle(); double angle = myGyro.getAngle();
double temp = myTempSensor.getTempC(myConfig.isGyroTemp()); double tempC = myTempSensor.getTempC(myConfig.isGyroTemp());
double gravity = calculateGravity(angle, temp); double gravity = calculateGravity(angle, tempC);
doc[CFG_PARAM_ANGLE] = reduceFloatPrecision(angle); doc[CFG_PARAM_ANGLE] = reduceFloatPrecision(angle);
if (myConfig.isGravityTempAdj()) doc[CFG_PARAM_GRAVITY_FORMAT] = String(myConfig.getGravityFormat());
doc[CFG_PARAM_GRAVITY] = reduceFloatPrecision(
gravityTemperatureCorrection(gravity, temp, myConfig.getTempFormat()), if (myConfig.isGravityTempAdj()) {
4); gravity =
else gravityTemperatureCorrectionC(gravity, tempC, myConfig.getTempFormat());
}
if (myConfig.isGravityPlato()) {
doc[CFG_PARAM_GRAVITY] = reduceFloatPrecision(convertToPlato(gravity), 1);
} else {
doc[CFG_PARAM_GRAVITY] = reduceFloatPrecision(gravity, 4); doc[CFG_PARAM_GRAVITY] = reduceFloatPrecision(gravity, 4);
}
doc[CFG_PARAM_BATTERY] = reduceFloatPrecision(myBatteryVoltage.getVoltage()); doc[CFG_PARAM_BATTERY] = reduceFloatPrecision(myBatteryVoltage.getVoltage());
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
@ -215,22 +222,24 @@ void WebServer::webHandleStatus() {
DynamicJsonDocument doc(256); DynamicJsonDocument doc(256);
double angle = myGyro.getAngle(); double angle = myGyro.getAngle();
double temp = myTempSensor.getTempC(myConfig.isGyroTemp()); double tempC = myTempSensor.getTempC(myConfig.isGyroTemp());
double gravity = calculateGravity(angle, temp); double gravity = calculateGravity(angle, tempC);
doc[CFG_PARAM_ID] = myConfig.getID(); doc[CFG_PARAM_ID] = myConfig.getID();
doc[CFG_PARAM_ANGLE] = reduceFloatPrecision(angle); doc[CFG_PARAM_ANGLE] = reduceFloatPrecision(angle);
if (myConfig.isGravityTempAdj()) if (myConfig.isGravityTempAdj()) {
doc[CFG_PARAM_GRAVITY] = reduceFloatPrecision( gravity = gravityTemperatureCorrectionC(gravity, tempC); //
gravityTemperatureCorrection(gravity, temp, myConfig.getTempFormat()), }
4); if (myConfig.isGravityPlato()) {
else doc[CFG_PARAM_GRAVITY] = reduceFloatPrecision(convertToPlato(gravity), 1);
} else {
doc[CFG_PARAM_GRAVITY] = reduceFloatPrecision(gravity, 4); doc[CFG_PARAM_GRAVITY] = reduceFloatPrecision(gravity, 4);
doc[CFG_PARAM_TEMP_C] = reduceFloatPrecision(temp, 1); }
doc[CFG_PARAM_TEMP_F] = doc[CFG_PARAM_TEMP_C] = reduceFloatPrecision(tempC, 1);
reduceFloatPrecision(myTempSensor.getTempF(myConfig.isGyroTemp()), 1); doc[CFG_PARAM_TEMP_F] = reduceFloatPrecision(convertCtoF(tempC), 1);
doc[CFG_PARAM_BATTERY] = reduceFloatPrecision(myBatteryVoltage.getVoltage()); doc[CFG_PARAM_BATTERY] = reduceFloatPrecision(myBatteryVoltage.getVoltage());
doc[CFG_PARAM_TEMPFORMAT] = String(myConfig.getTempFormat()); doc[CFG_PARAM_TEMPFORMAT] = String(myConfig.getTempFormat());
doc[CFG_PARAM_GRAVITY_FORMAT] = String(myConfig.getGravityFormat());
doc[CFG_PARAM_SLEEP_MODE] = sleepModeAlwaysSkip; doc[CFG_PARAM_SLEEP_MODE] = sleepModeAlwaysSkip;
doc[CFG_PARAM_RSSI] = WiFi.RSSI(); doc[CFG_PARAM_RSSI] = WiFi.RSSI();
@ -280,8 +289,7 @@ void WebServer::webHandleStatusSleepmode() {
} }
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : sleep-mode=%s." CR), Log.verbose(F("WEB : %s." CR), getRequestArguments().c_str());
server->arg(CFG_PARAM_SLEEP_MODE).c_str());
#endif #endif
if (server->arg(CFG_PARAM_SLEEP_MODE).equalsIgnoreCase("true")) if (server->arg(CFG_PARAM_SLEEP_MODE).equalsIgnoreCase("true"))
@ -309,9 +317,7 @@ void WebServer::webHandleConfigDevice() {
} }
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : mdns=%s, temp-format=%s." CR), Log.verbose(F("WEB : %s." CR), getRequestArguments().c_str());
server->arg(CFG_PARAM_MDNS).c_str(),
server->arg(CFG_PARAM_TEMPFORMAT).c_str());
#endif #endif
myConfig.setMDNS(server->arg(CFG_PARAM_MDNS).c_str()); myConfig.setMDNS(server->arg(CFG_PARAM_MDNS).c_str());
@ -339,14 +345,7 @@ void WebServer::webHandleConfigPush() {
return; return;
} }
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : http=%s,%s, bf=%s influx2=%s, %s, %s, %s." CR), Log.verbose(F("WEB : %s." CR), getRequestArguments().c_str());
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 #endif
myConfig.setHttpPushUrl(server->arg(CFG_PARAM_PUSH_HTTP).c_str()); myConfig.setHttpPushUrl(server->arg(CFG_PARAM_PUSH_HTTP).c_str());
@ -369,6 +368,25 @@ void WebServer::webHandleConfigPush() {
LOG_PERF_STOP("webserver-api-config-push"); LOG_PERF_STOP("webserver-api-config-push");
} }
//
// Get string with all received arguments. Used for debugging only.
//
String WebServer::getRequestArguments() {
String debug;
for (int i = 0; i < server->args(); i++) {
if (!server->argName(i).equals(
"plain")) { // this contains all the arguments, we dont need that.
if (debug.length()) debug += ", ";
debug += server->argName(i);
debug += "=";
debug += server->arg(i);
}
}
return debug;
}
// //
// Update gravity settings. // Update gravity settings.
// //
@ -386,11 +404,10 @@ void WebServer::webHandleConfigGravity() {
} }
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : formula=%s, temp-corr=%s." CR), Log.verbose(F("WEB : %s." CR), getRequestArguments().c_str());
server->arg(CFG_PARAM_GRAVITY_FORMULA).c_str(),
server->arg(CFG_PARAM_GRAVITY_TEMP_ADJ).c_str());
#endif #endif
myConfig.setGravityFormat(server->arg(CFG_PARAM_GRAVITY_FORMAT).charAt(0));
myConfig.setGravityFormula(server->arg(CFG_PARAM_GRAVITY_FORMULA).c_str()); myConfig.setGravityFormula(server->arg(CFG_PARAM_GRAVITY_FORMULA).c_str());
myConfig.setGravityTempAdj( myConfig.setGravityTempAdj(
server->arg(CFG_PARAM_GRAVITY_TEMP_ADJ).equalsIgnoreCase("on") ? true server->arg(CFG_PARAM_GRAVITY_TEMP_ADJ).equalsIgnoreCase("on") ? true
@ -418,15 +435,15 @@ void WebServer::webHandleConfigHardware() {
} }
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : vf=%s, tempadj=%s, ota=%s gyrotemp=%s." CR), Log.verbose(F("WEB : %s." CR), getRequestArguments().c_str());
server->arg(CFG_PARAM_VOLTAGEFACTOR).c_str(),
server->arg(CFG_PARAM_TEMP_ADJ).c_str(),
server->arg(CFG_PARAM_OTA).c_str(),
server->arg(CFG_PARAM_GYRO_TEMP).c_str());
#endif #endif
myConfig.setVoltageFactor(server->arg(CFG_PARAM_VOLTAGEFACTOR).toFloat()); myConfig.setVoltageFactor(server->arg(CFG_PARAM_VOLTAGEFACTOR).toFloat());
myConfig.setTempSensorAdj(server->arg(CFG_PARAM_TEMP_ADJ).toFloat()); if (myConfig.isTempC()) {
myConfig.setTempSensorAdjC(server->arg(CFG_PARAM_TEMP_ADJ));
} else {
myConfig.setTempSensorAdjF(server->arg(CFG_PARAM_TEMP_ADJ));
}
myConfig.setOtaURL(server->arg(CFG_PARAM_OTA).c_str()); myConfig.setOtaURL(server->arg(CFG_PARAM_OTA).c_str());
myConfig.setGyroTemp( myConfig.setGyroTemp(
server->arg(CFG_PARAM_GYRO_TEMP).equalsIgnoreCase("on") ? true : false); server->arg(CFG_PARAM_GYRO_TEMP).equalsIgnoreCase("on") ? true : false);
@ -447,24 +464,24 @@ void WebServer::webHandleFormulaRead() {
const RawFormulaData& fd = myConfig.getFormulaData(); const RawFormulaData& fd = myConfig.getFormulaData();
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #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], Log.verbose(F("WEB : %s." CR), getRequestArguments().c_str());
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 #endif
doc[CFG_PARAM_ID] = myConfig.getID(); doc[CFG_PARAM_ID] = myConfig.getID();
doc[CFG_PARAM_ANGLE] = reduceFloatPrecision(myGyro.getAngle()); doc[CFG_PARAM_ANGLE] = reduceFloatPrecision(myGyro.getAngle());
doc[CFG_PARAM_GRAVITY_FORMAT] = String(myConfig.getGravityFormat());
doc[CFG_PARAM_GRAVITY_FORMULA] = "";
doc[CFG_PARAM_ERROR] = "";
switch (lastFormulaCreateError) { switch (lastFormulaCreateError) {
case ERR_FORMULA_INTERNAL: case ERR_FORMULA_INTERNAL:
doc[CFG_PARAM_GRAVITY_FORMULA] = "Internal error creating formula."; doc[CFG_PARAM_ERROR] = "Internal error creating formula.";
break; break;
case ERR_FORMULA_NOTENOUGHVALUES: case ERR_FORMULA_NOTENOUGHVALUES:
doc[CFG_PARAM_GRAVITY_FORMULA] = "Not enough values to create formula."; doc[CFG_PARAM_ERROR] = "Not enough values to create formula.";
break; break;
case ERR_FORMULA_UNABLETOFFIND: case ERR_FORMULA_UNABLETOFFIND:
doc[CFG_PARAM_GRAVITY_FORMULA] = doc[CFG_PARAM_ERROR] =
"Unable to find an accurate formula based on input."; "Unable to find an accurate formula based on input.";
break; break;
default: default:
@ -478,11 +495,19 @@ void WebServer::webHandleFormulaRead() {
doc["a4"] = reduceFloatPrecision(fd.a[3], 2); doc["a4"] = reduceFloatPrecision(fd.a[3], 2);
doc["a5"] = reduceFloatPrecision(fd.a[4], 2); doc["a5"] = reduceFloatPrecision(fd.a[4], 2);
doc["g1"] = reduceFloatPrecision(fd.g[0], 4); if (myConfig.isGravityPlato()) {
doc["g2"] = reduceFloatPrecision(fd.g[1], 4); doc["g1"] = reduceFloatPrecision(convertToPlato(fd.g[0]), 1);
doc["g3"] = reduceFloatPrecision(fd.g[2], 4); doc["g2"] = reduceFloatPrecision(convertToPlato(fd.g[1]), 1);
doc["g4"] = reduceFloatPrecision(fd.g[3], 4); doc["g3"] = reduceFloatPrecision(convertToPlato(fd.g[2]), 1);
doc["g5"] = reduceFloatPrecision(fd.g[4], 4); doc["g4"] = reduceFloatPrecision(convertToPlato(fd.g[3]), 1);
doc["g5"] = reduceFloatPrecision(convertToPlato(fd.g[4]), 1);
} else {
doc["g1"] = reduceFloatPrecision(fd.g[0], 4);
doc["g2"] = reduceFloatPrecision(fd.g[1], 4);
doc["g3"] = reduceFloatPrecision(fd.g[2], 4);
doc["g4"] = reduceFloatPrecision(fd.g[3], 4);
doc["g5"] = reduceFloatPrecision(fd.g[4], 4);
}
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
serializeJson(doc, Serial); serializeJson(doc, Serial);
@ -512,13 +537,7 @@ void WebServer::webHandleFormulaWrite() {
} }
#if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING)
Log.verbose(F("WEB : angles=%F,%F,%F,%F,%F." CR), server->arg("a1").toFloat(), Log.verbose(F("WEB : %s." CR), getRequestArguments().c_str());
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 #endif
RawFormulaData fd; RawFormulaData fd;
@ -527,11 +546,21 @@ void WebServer::webHandleFormulaWrite() {
fd.a[2] = server->arg("a3").toDouble(); fd.a[2] = server->arg("a3").toDouble();
fd.a[3] = server->arg("a4").toDouble(); fd.a[3] = server->arg("a4").toDouble();
fd.a[4] = server->arg("a5").toDouble(); fd.a[4] = server->arg("a5").toDouble();
fd.g[0] = server->arg("g1").toDouble();
fd.g[1] = server->arg("g2").toDouble(); if (myConfig.isGravityPlato()) {
fd.g[2] = server->arg("g3").toDouble(); fd.g[0] = convertToSG(server->arg("g1").toDouble());
fd.g[3] = server->arg("g4").toDouble(); fd.g[1] = convertToSG(server->arg("g2").toDouble());
fd.g[4] = server->arg("g5").toDouble(); fd.g[2] = convertToSG(server->arg("g3").toDouble());
fd.g[3] = convertToSG(server->arg("g4").toDouble());
fd.g[4] = convertToSG(server->arg("g5").toDouble());
} else {
fd.g[0] = server->arg("g1").toDouble();
fd.g[1] = server->arg("g2").toDouble();
fd.g[2] = server->arg("g3").toDouble();
fd.g[3] = server->arg("g4").toDouble();
fd.g[4] = server->arg("g5").toDouble();
}
myConfig.setFormulaData(fd); myConfig.setFormulaData(fd);
int e; int e;
@ -727,9 +756,8 @@ bool WebServer::setupWebServer() {
// called from main loop // called from main loop
// //
void WebServer::loop() { void WebServer::loop() {
// Dont put serial debug output in this call
server->handleClient();
MDNS.update(); MDNS.update();
server->handleClient();
} }
// EOF // EOF

View File

@ -65,6 +65,8 @@ class WebServer {
void webHandleDevice(); void webHandleDevice();
void webHandlePageNotFound(); void webHandlePageNotFound();
String getRequestArguments();
// Inline functions. // Inline functions.
void webReturnOK() { server->send(200); } void webReturnOK() { server->send(200); }
#if defined(EMBED_HTML) #if defined(EMBED_HTML)

View File

@ -110,6 +110,8 @@ String WifiConnection::getIPAddress() { return WiFi.localIP().toString(); }
// Additional method to detect double reset. // Additional method to detect double reset.
// //
bool WifiConnection::isDoubleResetDetected() { bool WifiConnection::isDoubleResetDetected() {
if (strlen(userSSID))
return false; // Ignore this if we have hardcoded settings.
return myDRD->detectDoubleReset(); return myDRD->detectDoubleReset();
} }
@ -230,11 +232,17 @@ bool WifiConnection::updateFirmware() {
Log.verbose(F("WIFI: Updating firmware." CR)); Log.verbose(F("WIFI: Updating firmware." CR));
#endif #endif
WiFiClient client;
String serverPath = myConfig.getOtaURL(); String serverPath = myConfig.getOtaURL();
serverPath += "firmware.bin"; serverPath += "firmware.bin";
HTTPUpdateResult ret;
HTTPUpdateResult ret = ESPhttpUpdate.update(client, serverPath); if (serverPath.startsWith("https://")) {
myWifi.getWifiClientSecure().setInsecure();
Log.notice(F("WIFI: OTA, SSL enabled without validation." CR));
ret = ESPhttpUpdate.update(myWifi.getWifiClientSecure(), serverPath);
} else {
ret = ESPhttpUpdate.update(myWifi.getWifiClient(), serverPath);
}
switch (ret) { switch (ret) {
case HTTP_UPDATE_FAILED: case HTTP_UPDATE_FAILED:
@ -257,16 +265,21 @@ bool WifiConnection::updateFirmware() {
// Download and save file // Download and save file
// //
void WifiConnection::downloadFile(const char *fname) { void WifiConnection::downloadFile(const char *fname) {
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING)
Log.verbose(F("WIFI: Download file %s." CR), fname); Log.verbose(F("WIFI: Download file %s." CR), fname);
#endif #endif
WiFiClient client;
HTTPClient http; HTTPClient http;
String serverPath = myConfig.getOtaURL(); String serverPath = myConfig.getOtaURL();
serverPath += fname; serverPath += fname;
// Your Domain name with URL path or IP address with path if (serverPath.startsWith("https://")) {
http.begin(client, serverPath); myWifi.getWifiClientSecure().setInsecure();
Log.notice(F("WIFI: OTA, SSL enabled without validation." CR));
http.begin(myWifi.getWifiClientSecure(), serverPath);
} else {
http.begin(myWifi.getWifiClient(), serverPath);
}
int httpResponseCode = http.GET(); int httpResponseCode = http.GET();
if (httpResponseCode == 200) { if (httpResponseCode == 200) {
@ -279,22 +292,28 @@ void WifiConnection::downloadFile(const char *fname) {
httpResponseCode); httpResponseCode);
} }
http.end(); http.end();
myWifi.closeWifiClient();
} }
// //
// Check what firmware version is available over OTA // Check what firmware version is available over OTA
// //
bool WifiConnection::checkFirmwareVersion() { bool WifiConnection::checkFirmwareVersion() {
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING)
Log.verbose(F("WIFI: Checking if new version exist." CR)); Log.verbose(F("WIFI: Checking if new version exist." CR));
#endif #endif
WiFiClient client;
HTTPClient http; HTTPClient http;
String serverPath = myConfig.getOtaURL(); String serverPath = myConfig.getOtaURL();
serverPath += "version.json"; serverPath += "version.json";
// Your Domain name with URL path or IP address with path // Your Domain name with URL path or IP address with path
http.begin(client, serverPath); if (serverPath.startsWith("https://")) {
myWifi.getWifiClientSecure().setInsecure();
Log.notice(F("WIFI: OTA, SSL enabled without validation." CR));
http.begin(myWifi.getWifiClientSecure(), serverPath);
} else {
http.begin(myWifi.getWifiClient(), serverPath);
}
// Send HTTP GET request // Send HTTP GET request
int httpResponseCode = http.GET(); int httpResponseCode = http.GET();
@ -303,7 +322,7 @@ bool WifiConnection::checkFirmwareVersion() {
Log.notice(F("WIFI: Found version.json, response=%d" CR), httpResponseCode); Log.notice(F("WIFI: Found version.json, response=%d" CR), httpResponseCode);
String payload = http.getString(); String payload = http.getString();
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING)
Log.verbose(F("WIFI: Payload %s." CR), payload.c_str()); Log.verbose(F("WIFI: Payload %s." CR), payload.c_str());
#endif #endif
DynamicJsonDocument ver(300); DynamicJsonDocument ver(300);
@ -311,7 +330,7 @@ bool WifiConnection::checkFirmwareVersion() {
if (err) { if (err) {
Log.error(F("WIFI: Failed to parse version.json, %s" CR), err); Log.error(F("WIFI: Failed to parse version.json, %s" CR), err);
} else { } else {
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING)
Log.verbose(F("WIFI: Project %s version %s." CR), Log.verbose(F("WIFI: Project %s version %s." CR),
(const char *)ver["project"], (const char *)ver["version"]); (const char *)ver["project"], (const char *)ver["version"]);
#endif #endif
@ -320,7 +339,7 @@ bool WifiConnection::checkFirmwareVersion() {
if (parseFirmwareVersionString(newVer, (const char *)ver["version"])) { if (parseFirmwareVersionString(newVer, (const char *)ver["version"])) {
if (parseFirmwareVersionString(curVer, CFG_APPVER)) { if (parseFirmwareVersionString(curVer, CFG_APPVER)) {
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING)
Log.verbose(F("WIFI: OTA checking new=%d.%d.%d cur=%d.%d.%d" CR), 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], newVer[0], newVer[1], newVer[2], curVer[0], curVer[1],
curVer[2]); curVer[2]);
@ -355,6 +374,7 @@ bool WifiConnection::checkFirmwareVersion() {
httpResponseCode); httpResponseCode);
} }
http.end(); http.end();
myWifi.closeWifiClient();
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6
Log.verbose(F("WIFI: OTA found new version %s." CR), Log.verbose(F("WIFI: OTA found new version %s." CR),
newFirmware ? "true" : "false"); newFirmware ? "true" : "false");
@ -367,7 +387,7 @@ bool WifiConnection::checkFirmwareVersion() {
// //
bool WifiConnection::parseFirmwareVersionString(int (&num)[3], bool WifiConnection::parseFirmwareVersionString(int (&num)[3],
const char *version) { const char *version) {
#if LOG_LEVEL == 6 #if LOG_LEVEL == 6 && !defined(WIFI_DISABLE_LOGGING)
Log.verbose(F("WIFI: Parsing version number string %s." CR), version); Log.verbose(F("WIFI: Parsing version number string %s." CR), version);
#endif #endif
char temp[80]; char temp[80];

View File

@ -26,16 +26,24 @@ SOFTWARE.
// Include // Include
#include <Arduino.h> #include <Arduino.h>
#include <ESP8266WiFi.h>
// tcp cleanup, to avoid memory crash.
struct tcp_pcb;
extern struct tcp_pcb* tcp_tw_pcbs;
extern "C" void tcp_abort(struct tcp_pcb* pcb);
// classes // classes
class WifiConnection { class WifiConnection {
private: private:
// WIFI // WIFI
WiFiClient _client;
WiFiClientSecure _secureClient;
// OTA // OTA
bool newFirmware = false; bool newFirmware = false;
bool parseFirmwareVersionString(int (&num)[3], const char *version); bool parseFirmwareVersionString(int (&num)[3], const char* version);
void downloadFile(const char *fname); void downloadFile(const char* fname);
void connectAsync(); void connectAsync();
bool waitForConnection(int maxTime = 20); bool waitForConnection(int maxTime = 20);
@ -53,6 +61,16 @@ class WifiConnection {
void startPortal(); void startPortal();
void loop(); void loop();
WiFiClient& getWifiClient() { return _client; }
WiFiClientSecure& getWifiClientSecure() { return _secureClient; }
void closeWifiClient() {
_client.stopAll();
_secureClient.stopAll();
// Cleanup memory allocated by open tcp connetions.
while (tcp_tw_pcbs) tcp_abort(tcp_tw_pcbs);
}
// OTA // OTA
bool updateFirmware(); bool updateFirmware();
bool checkFirmwareVersion(); bool checkFirmwareVersion();

View File

@ -83,19 +83,9 @@ This is a list of C++ defines that is used to enable/disable functions in the co
* - ACTIVATE_OTA * - ACTIVATE_OTA
- Enables the OTA functionallity in the code - Enables the OTA functionallity in the code
* - SKIP_SLEEPMODE * - SKIP_SLEEPMODE
- THe device never goes into sleep mode, useful when developing. - The device never goes into sleep mode, useful when developing.
* - CFG_DISABLE_LOGGING * - xxx_DISABLE_LOGGING
- Done include verbose logging in Config class. Excessive logging may crash device. - Done include verbose logging in the corresponding class. Excessive logging may crash device.
* - GYRO_DISABLE_LOGGING
- Done include verbose logging in Gyro class. Excessive logging may crash device.
* - PUSH_DISABLE_LOGGING
- Done include verbose logging in PushTarget class. Excessive logging may crash device.
* - TSEN_DISABLE_LOGGING
- Done include verbose logging in TempSensor class. Excessive logging may crash device.
* - WEB_DISABLE_LOGGING
- Done include verbose logging in WebServer class. Excessive logging may crash device.
* - MAIN_DISABLE_LOGGING
- Done include verbose logging in Main class. Excessive logging may crash device.
* - USE_LITTLEFS * - USE_LITTLEFS
- Use the new filesystem in Ardurino - Use the new filesystem in Ardurino
* - EMBED_HTML * - EMBED_HTML

View File

@ -12,6 +12,7 @@ One of the following conditions will place the device in ``configuration mode``:
- Placed in horizontal mode 85-90 degrees - Placed in horizontal mode 85-90 degrees
- Charger connected >4.15V - Charger connected >4.15V
Status Status
====== ======
@ -97,22 +98,36 @@ Push Settings
:width: 800 :width: 800
:alt: Push Settings :alt: Push Settings
.. note::
When enabling SSL this will not validate the root CA of the remote service, this is a design decision based on two aspects. Enabling CA validation will take 3-4s extra on each connection which means way less
battery life, so the decision is to prioritize battery life over security. The data transmitted is not really that sensitive anyway so I belive this is a good balance.
* **HTTP URL 1:** * **HTTP URL 1:**
Endpoint to send data via http. Format used Format used :ref:`data-formats-ispindle` Endpoint to send data via http. Format used Format used :ref:`data-formats-ispindle`
If you add the prefix `https://` then the device will use SSL when sending data.
* **HTTP URL 2:** * **HTTP URL 2:**
Endpoint to send data via http. Format used :ref:`data-formats-ispindle` Endpoint to send data via http. Format used :ref:`data-formats-ispindle`
If you add the prefix `https://` then the device will use SSL when sending data.
* **Brewfather URL:** * **Brewfather URL:**
Endpoint to send data via http to brewfather. Format used :ref:`data-formats-brewfather` Endpoint to send data via http to brewfather. Format used :ref:`data-formats-brewfather`
SSL is not supported for this target.
* **Influx DB v2 URL:** * **Influx DB v2 URL:**
Endpoint to send data via http to InfluxDB. Format used :ref:`data-formats-influxdb2` Endpoint to send data via http to InfluxDB. Format used :ref:`data-formats-influxdb2`
SSL is not supported for this target. Raise a issue on github if this is wanted.
* **Influx DB v2 Organisation:** * **Influx DB v2 Organisation:**
Name of organisation in Influx. Name of organisation in Influx.
@ -129,6 +144,8 @@ Push Settings
IP or name of server to send data to. Format used :ref:`data-formats-ispindle` IP or name of server to send data to. Format used :ref:`data-formats-ispindle`
If you add the suffix `:8883` to the server name, then the device will use SSL when sending data.
* **MQTT Topic:** * **MQTT Topic:**
Name of topic to publish sensor readings to, iSpindle format is used. Name of topic to publish sensor readings to, iSpindle format is used.
@ -149,6 +166,10 @@ Gravity Settings
:width: 800 :width: 800
:alt: Gravity Settings :alt: Gravity Settings
* **Gravity format:**
Gravity format can be eihter `SG` or `Plato`. The device will use SG Internally and convert to Plato when displaying data.
* **Gravity formula:** * **Gravity formula:**
Gravity formula is compatible with standard iSpindle formulas so any existing calculation option can be used. You can also use Gravity formula is compatible with standard iSpindle formulas so any existing calculation option can be used. You can also use
@ -159,9 +180,9 @@ Gravity Settings
Will apply a temperature calibration formula to the gravity as a second step. Will apply a temperature calibration formula to the gravity as a second step.
.. warning:: .. warning::
This formula assumes that the calibration has been done at 20C. This formula assumes that the calibration has been done at 20°C / 68°F.
Formula used in temperature correction: Formula used in temperature correction.
:: ::
@ -199,6 +220,8 @@ Hardware Settings
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 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. code the update will be done during startup.
If you have the previx `https://` then the device will use secure transfer without CA validation.
Example; OTA URL (don't forget trailing dash), the name of the file should be firmware.bin Example; OTA URL (don't forget trailing dash), the name of the file should be firmware.bin
.. code-block:: .. code-block::
@ -325,7 +348,7 @@ GET: /api/config/formula
Retrive the data used for formula calculation data via an HTTP GET command. Payload is in JSON format. Retrive the data used for formula calculation data via an HTTP GET command. Payload is in JSON format.
* ``a1``-``a4`` are the angles/tilt readings (up to 5 are currently supported) * ``a1``-``a4`` are the angles/tilt readings (up to 5 are currently supported)
* ``g1``-``g4`` are the corresponding gravity reaadings (in SG) * ``g1``-``g4`` are the corresponding gravity reaadings in SG or Plato depending on the device-format.
.. code-block:: json .. code-block:: json
@ -340,8 +363,9 @@ Retrive the data used for formula calculation data via an HTTP GET command. Payl
"g2": 1.053, "g2": 1.053,
"g3": 1.062, "g3": 1.062,
"g4": 1, "g4": 1,
"g5": 1 "g5": 1,
"gravity-formula": "0.0*tilt^3+0.0*tilt^2+0.0017978*tilt+0.9436", "gravity-format": "G",
"gravity-formula": "0.0*tilt^3+0.0*tilt^2+0.0017978*tilt+0.9436"
} }
@ -350,7 +374,7 @@ POST: /api/config/device
Used to update device settings via an HTTP POST command. Payload is in JSON format. Used to update device settings via an HTTP POST command. Payload is in JSON format.
* ``temp-format`` can be either ``C`` or ``F`` * ``temp-format`` can be either ``C`` (Celcius) or ``F`` (Farenheight)
.. code-block:: json .. code-block:: json
@ -391,6 +415,7 @@ POST: /api/config/gravity
Used to update gravity settings via an HTTP POST command. Payload is in JSON format. Used to update gravity settings via an HTTP POST command. Payload is in JSON format.
* ``gravity-formula`` keywords ``temp`` and ``tilt`` are supported. * ``gravity-formula`` keywords ``temp`` and ``tilt`` are supported.
* ``gravity-format`` can be either ``G`` (SG) or ``P`` (PLATO)
.. note:: .. note::
``gravity-temp-adjustment`` is defined as "on" or "off" when posting since this is the output values ``gravity-temp-adjustment`` is defined as "on" or "off" when posting since this is the output values
@ -401,6 +426,7 @@ Used to update gravity settings via an HTTP POST command. Payload is in JSON for
{ {
"id": "ee1bfc", "id": "ee1bfc",
"gravity-formula": "0.0*tilt^3+0.0*tilt^2+0.0017978*tilt+0.9436", "gravity-formula": "0.0*tilt^3+0.0*tilt^2+0.0017978*tilt+0.9436",
"gravity-format": "P",
"gravity-temp-adjustment": "off" "gravity-temp-adjustment": "off"
} }
@ -500,6 +526,7 @@ present or the API call will fail.
url = "http://" + host + "/api/config/gravity" url = "http://" + host + "/api/config/gravity"
json = { "id": id, json = { "id": id,
"gravity-formula": "", "gravity-formula": "",
"gravity-format": "P",
"gravity-temp-adjustment": "off" # Adjust gravity (on/off) "gravity-temp-adjustment": "off" # Adjust gravity (on/off)
} }
set_config( url, json ) set_config( url, json )
@ -542,6 +569,7 @@ iSpindle format
This is the format used for standard http posts. This is the format used for standard http posts.
* ``corr-gravity`` is an extended parameter containing a temperature corrected gravity reading. * ``corr-gravity`` is an extended parameter containing a temperature corrected gravity reading.
* ``gravity-format`` is an extended parameter containing the gravity format (G or P).
* ``run-time`` is an extended parameter containing the number of seconds the execution took. * ``run-time`` is an extended parameter containing the number of seconds the execution took.
.. code-block:: json .. code-block:: json
@ -554,10 +582,12 @@ This is the format used for standard http posts.
"temperature": 20.5, "temperature": 20.5,
"temp-units": "C", "temp-units": "C",
"gravity": 1.0050, "gravity": 1.0050,
"corr-gravity": 1.0050,
"angle": 45.34, "angle": 45.34,
"battery": 3.67, "battery": 3.67,
"rssi": -12, "rssi": -12,
"corr-gravity": 1.0050,
"gravity-unit": "G",
"run-time": 6 "run-time": 6
} }
@ -567,14 +597,14 @@ This is the format used for standard http posts.
Brewfather format Brewfather format
================= =================
This is the format for Brewfather This is the format for Brewfather. See: `Brewfather API docs <https://docs.brewfather.app/integrations/custom-stream>`_
.. code-block:: json .. code-block:: json
{ {
"name" : "gravmon", "name" : "gravmon",
"temp": 20.5, "temp": 20.5,
"temp-unit": "C", "temp_unit": "C",
"battery": 3.67, "battery": 3.67,
"gravity": 1.0050, "gravity": 1.0050,
"gravity_unit": "G", "gravity_unit": "G",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -7,7 +7,7 @@ Welcome to GravityMon's documentation!
###################################### ######################################
.. note:: .. note::
This documentation reflects **v0.6**. Last updated 2022-01-15 This documentation reflects **v0.7**. Last updated 2022-01-18
GravityMon is a replacement firmare for the iSpindle firmware, it uses the same hardware configuration so GravityMon is a replacement firmare for the iSpindle firmware, it uses the same hardware configuration so
@ -23,9 +23,6 @@ The hardware design comes from the fantastic iSpindle project so that is not cov
My approach to this software is a little different from that the original ispindle firmware. The github repository can My approach to this software is a little different from that the original ispindle firmware. The github repository can
be found here; `GravityMon on Github <https://github.com/mp-se/gravitymon>`_ be found here; `GravityMon on Github <https://github.com/mp-se/gravitymon>`_
.. note:: .. note::
This software is in the early stages even though its more than one year old so if you find issues, please This software is in the early stages even though its more than one year old so if you find issues, please
open a ticket on github. open a ticket on github.
@ -46,6 +43,7 @@ The main differences:
* Visual graph showing how formula will be interpreted * Visual graph showing how formula will be interpreted
* Using the temperature sensor in gyro instead of DS18B20 (faster) * Using the temperature sensor in gyro instead of DS18B20 (faster)
* Built in performance measurements (used to optimise code) * Built in performance measurements (used to optimise code)
* SSL support in standard HTTP and MQTT connections.
For a complete breakdown see the :ref:`functionallity` For a complete breakdown see the :ref:`functionallity`

View File

@ -3,6 +3,24 @@
Releases Releases
######## ########
v0.7.0
------
Development version (dev branch)
* SSL support for HTTP targets (no validation of CA)
* SSL support for MQTT targets (no validation of CA)
* SSL support for OTA (no validation of CA)
* Breaking change: To simplify the internal structure the
temp sensor adjustment is now stored in C. So if you have
enabled this function using F you will need to go into
the configuration and update the factor again.
* Added error handling for calibration page.
TODO:
Update docs, MQTT ssl is enabled using :8883 at end, http targets enables using prefix https://
Note! Brewfather don't support SSL.
v0.6.0 v0.6.0
------ ------