Added ssl and plato
This commit is contained in:
parent
10163f3aa7
commit
ddb34e129d
@ -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
@ -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
@ -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
|
||||||
|
@ -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">×</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">×</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>
|
@ -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
|
||||||
|
51
src/calc.cpp
51
src/calc.cpp
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
23
src/main.cpp
23
src/main.cpp
@ -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");
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
46
src/wifi.cpp
46
src/wifi.cpp
@ -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];
|
||||||
|
22
src/wifi.hpp
22
src/wifi.hpp
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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 |
@ -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`
|
||||||
|
|
||||||
|
@ -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
|
||||||
------
|
------
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user