gravitymon/html/config.htm
2023-02-04 13:30:13 +01:00

1024 lines
51 KiB
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://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<style>
.row-margin-10 { margin-top: 1.0em; }
</style>
</head>
<body class="py-4">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<!-- START MENU -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="/index.htm">Beer Gravity Monitor</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/index.htm">Home</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Configuration
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Configuration</a></li>
<li><a class="dropdown-item" href="/format.htm">Format editor</a></li>
<li><a class="dropdown-item" href="/test.htm">Test push</a></li>
<li><a class="dropdown-item" href="/firmware.htm">Upload firmware</a></li>
</ul>
</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>
<div class="spinner-border text-light" id="spinner" role="status"></div>
</div>
</nav>
<!-- START MAIN INDEX -->
<div class="container row-margin-10">
<div class="alert alert-success alert-dismissible hide fade d-none" role="alert" id="alert">
<div id="alert-msg"></div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<div class="alert alert-warning alert-dismissible hide fade d-none" role="alert" id="warning-sleep">
<div>A sleep-interval of less than 300s will reduce battery life, consider using 900s</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<div class="alert alert-warning alert-dismissible hide fade d-none" role="alert" id="warning-gyro">
<div>When using the gyro temperature use a sleep-interval that is greater than 300s for accurate readings</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<script type="text/javascript">
function showError( msg ) {
$('#alert').removeClass('alert-success').addClass('alert-danger').removeClass('hide').addClass('show').removeClass('d-none');
$('#alert-msg').text( msg );
}
function showSuccess( msg ) {
$('#alert').addClass('alert-success').removeClass('alert-danger').removeClass('hide').addClass('show').removeClass('d-none');
$('#alert-msg').text( msg );
}
$("#alert-btn").click(function(e){
$('#alert').addClass('hide').removeClass('show').addClass('d-none');
});
function showWarningSleep() {
$('#warning-sleep').removeClass('d-none').addClass('show').removeClass('hide');
}
function hideWarningSleep() {
$('#warning-sleep').addClass('d-none').removeClass('show').addClass('hide');
}
function showWarningGyro() {
$('#warning-gyro').removeClass('d-none').addClass('show').removeClass('hide');
}
function hideWarningGyro() {
$('#warning-gyro').addClass('d-none').removeClass('show').addClass('hide');
}
</script>
<div class="accordion" id="accordion">
<div class="accordion-item">
<h2 class="accordion-header" id="headingDevice">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseDevice" aria-expanded="true" aria-controls="collapseDevice">
<b>Device settings</b>
</button>
</h2>
<div id="collapseDevice" class="accordion-collapse collapse show" aria-labelledby="headingDevice" data-bs-parent="#accordion">
<div class="accordion-body">
<input type="text" name="runtime-average" id="runtime-average" hidden>
<input type="text" name="platform" id="platform" hidden>
<input type="text" name="voltage-factor-calc" id="voltage-factor-calc" hidden>
<form action="/api/config/device" method="post">
<input type="text" name="id" id="id1" hidden>
<div class="row mb-3">
<label for="mdns" class="col-sm-2 col-form-label">Device name</label>
<div class="col-sm-3">
<input type="text" maxlength="63" class="form-control" name="mdns" id="mdns" placeholder="gravmon" data-bs-toggle="tooltip" title="Name of the device. Will be used for identifying the device when pushing data and on the local network.">
</div>
</div>
<div class="row mb-3">
<fieldset class="form-group row">
<legend class="col-form-label col-sm-2 float-sm-left pt-0">Temperature Format</legend>
<div class="col-sm-4">
<div class="form-check">
<input class="form-check-input" type="radio" name="temp-format" id="temp-format-c" value="C" checked data-bs-toggle="tooltip" title="Temperature format used with displaying data">
<label class="form-check-label" for="temp-format-c">Celsius</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="temp-format" id="temp-format-f" value="F" data-bs-toggle="tooltip" title="Temperature format used with displaying data">
<label class="form-check-label" for="temp-format-f">Fahrenheit</label>
</div>
</div>
</fieldset>
</div>
<div class="row mb-3">
<label for="sleep-interval" class="col-sm-2 col-form-label">Interval (seconds)</label>
<div class="col-sm-2">
<input type="number" min="10" max="3600" class="form-control" name="sleep-interval" id="sleep-interval" placeholder="300" data-bs-toggle="tooltip" title="The number of seconds that the device will sleep between gravity readings. Recommended value is 300s">
</div>
<label for="sleep-interval" class="col-sm-4 col-form-label" id="sleep-interval-info"></label>
</div>
<div class="row mb-3">
<div class="col-sm-4 offset-sm-2">
<button type="submit" class="btn btn-primary" id="device-btn" data-bs-toggle="tooltip" title="Save changes in this section">Save</button>
</div>
</div>
</form>
<hr class="my-2">
<div class="row mb-3">
<label class="col-sm-2 col-form-label">Wifi</label>
<div class="col-sm-2">
<label class="col-sm-4 col-form-label" id="wifi-ssid"></label>
</div>
</div>
<div class="row mb-3">
<label class="col-sm-2 col-form-label">Wifi 2</label>
<div class="col-sm-2">
<label class="col-sm-4 col-form-label" id="wifi-ssid2"></label>
</div>
</div>
<hr class="my-2">
<div class="row mb-3">
<label for="calibrate-btn" class="col-sm-2 col-form-label">Current calibration</label>
<label for="calibrate-btn" class="col-sm-2 col-form-label" id="gyro-calibration-data">Loading...</label>
<label for="gyro-calibration-data" class="col-sm-2 col-form-label" id="angle">Loading...</label>
<div class="col-sm-8 offset-sm-2">
<button type="button" class="btn btn-warning" id="calibrate-btn" data-bs-toggle="tooltip" title="Perform a calibration. The device should be flat on a surface (90 degrees) with the battery down">Calibrate device</button>
</div>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingPush">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePush" aria-expanded="false" aria-controls="collapsePush">
<b>Push settings</b>
</button>
</h2>
<div id="collapsePush" class="accordion-collapse collapse" aria-labelledby="headingPush" data-bs-parent="#accordion">
<div class="accordion-body">
<form action="/api/config/push" method="post">
<input type="text" name="id" id="id2" hidden>
<input type="text" name="section" value="collapsePush" hidden>
<input type="text" name="http-push-h1" id="http-push-h1" hidden>
<input type="text" name="http-push-h2" id="http-push-h2" hidden>
<input type="text" name="http-push2-h1" id="http-push2-h1" hidden>
<input type="text" name="http-push2-h2" id="http-push2-h2" hidden>
<div class="row mb-3">
<label for="http-push" class="col-sm-2 col-form-label">HTTP 1 (POST)</label>
<div class="col-sm-8">
<input type="url" maxlength="120" class="form-control" name="http-push" id="http-push" placeholder="http://www.internet.com/path" data-bs-toggle="tooltip" title="URL to push target, use format http://servername.com/resource (Supports http and https)">
</div>
<div class="col-sm-2">
<button type="button" class="btn btn-secondary" data-field1="#http-push-h1" data-field2="#http-push-h2" data-bs-toggle="modal" data-bs-target="#modal-http" data-bs-toggle="tooltip" title="Edit the http headers for data format and authentication">Headers</button>
</div>
</div>
<div class="row mb-3">
<label for="http-push2" class="col-sm-2 col-form-label">HTTP 2 (POST)</label>
<div class="col-sm-8">
<input type="url" maxlength="120" class="form-control" name="http-push2" id="http-push2" placeholder="http://www.internet.com/path" data-bs-toggle="tooltip" title="URL to push target, use format http://servername.com/resource (Supports http and https)">
</div>
<div class="col-sm-2">
<button type="button" class="btn btn-secondary" data-field1="#http-push2-h1" data-field2="#http-push2-h2" data-bs-toggle="modal" data-bs-target="#modal-http" data-bs-toggle="tooltip" title="Edit the http headers for data format and authentication">Headers</button>
</div>
</div>
<div class="row mb-3">
<label for="token" class="col-sm-2 col-form-label">Token</label>
<div class="col-sm-4">
<input type="text" maxlength="50" class="form-control" name="token" id="token" data-bs-toggle="tooltip" title="Token can be used in the format template as a variable, some services use this for authentication">
</div>
</div>
<div class="row mb-3">
<label for="http-push3" class="col-sm-2 col-form-label">HTTP 3 (GET)</label>
<div class="col-sm-8">
<input type="url" maxlength="120" class="form-control" name="http-push3" id="http-push3" placeholder="http://www.internet.com/path" data-bs-toggle="tooltip" title="URL to push target, use format http://servername.com/resource (Supports http and https). Do not add the query string, that will be added via the format template">
</div>
</div>
<div class="row mb-3">
<label for="token2" class="col-sm-2 col-form-label">Token 2</label>
<div class="col-sm-4">
<input type="text" maxlength="50" class="form-control" name="token2" id="token2" data-bs-toggle="tooltip" title="Token can be used in the format template as a variable, some services use this for authentication">
</div>
</div>
<div class="row mb-3">
<div class="col-sm-8 offset-sm-2">
<button type="submit" class="btn btn-primary" id="push-btn" data-bs-toggle="tooltip" title="Save changes in this section">Save</button>
<button type="button" class="btn btn-secondary" id="format-btn" data-bs-toggle="tooltip" title="Open up the format editor to change data format posted">Format editor</button>
<button type="button" class="btn btn-secondary" id="test-btn" data-bs-toggle="tooltip" title="Test posting data to defined push targets">Test Push</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingPush2">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePush2" aria-expanded="false" aria-controls="collapsePush2">
<b>Push settings (2)</b>
</button>
</h2>
<div id="collapsePush2" class="accordion-collapse collapse" aria-labelledby="headingPush2" data-bs-parent="#accordion">
<div class="accordion-body">
<form action="/api/config/push" method="post">
<input type="text" name="id" id="id5" hidden>
<input type="text" name="section" value="collapsePush2" hidden>
<div class="row mb-3">
<label for="influxdb2-push" class="col-sm-2 col-form-label">InfluxDB v2 URL</label>
<div class="col-sm-8">
<input type="url" maxlength="40" class="form-control" name="influxdb2-push" placeholder="http://www.internet.com" id="influxdb2-push" data-bs-toggle="tooltip" title="URL to push target, use format http://servername.com (Supports http and https)">
</div>
</div>
<div class="row mb-3">
<label for="influxdb2-org" class="col-sm-2 col-form-label">InfluxDB v2 Org</label>
<div class="col-sm-4">
<input type="text" maxlength="50" class="form-control" name="influxdb2-org" id="influxdb2-org" data-bs-toggle="tooltip" title="Identifier to what organisation to use">
</div>
</div>
<div class="row mb-3">
<label for="influxdb2-bucket" class="col-sm-2 col-form-label">InfluxDB v2 Bucket ID</label>
<div class="col-sm-4">
<input type="text" maxlength="50" class="form-control" name="influxdb2-bucket" id="influxdb2-bucket" data-bs-toggle="tooltip" title="Identifier for the data bucket to use">
</div>
</div>
<div class="row mb-3">
<label for="influxdb2-auth" class="col-sm-2 col-form-label">InfluxDB v2 Auth Token</label>
<div class="col-sm-4">
<input type="text" maxlength="100" class="form-control" name="influxdb2-auth" id="influxdb2-auth" data-bs-toggle="tooltip" title="Authentication token for accessing data bucket">
</div>
</div>
<hr class="my-2">
<div class="row mb-3">
<label for="mqtt-push" class="col-sm-2 col-form-label">MQTT Server</label>
<div class="col-sm-4">
<input type="text" maxlength="40" class="form-control" name="mqtt-push" id="mqtt-push" placeholder="www.internet.com" data-bs-toggle="tooltip" title="Name of server to connect to, use format servername.com">
</div>
</div>
<div class="row mb-3">
<label for="mqtt-topic" class="col-sm-2 col-form-label">MQTT Port</label>
<div class="col-sm-4">
<input type="number" min="1" max="65535" class="form-control" name="mqtt-port" id="mqtt-port" placeholder="1883" data-bs-toggle="tooltip" title="Port number to use, 1883 is standard. Ports higher than 8000 will assume to use SSL">
</div>
</div>
<div class="row mb-3">
<label for="mqtt-user" class="col-sm-2 col-form-label">MQTT User</label>
<div class="col-sm-4">
<input type="text" maxlength="20" class="form-control" name="mqtt-user" id="mqtt-user" data-bs-toggle="tooltip" title="Username to use. Leave blank if authentication is disabled">
</div>
</div>
<div class="row mb-3">
<label for="mqtt-pass" class="col-sm-2 col-form-label">MQTT Password</label>
<div class="col-sm-4">
<input type="text" maxlength="20" class="form-control" name="mqtt-pass" id="mqtt-pass" data-bs-toggle="tooltip" title="Password to use. Leave blank if authentication is disabled">
</div>
</div>
<div class="row mb-3">
<div class="col-sm-8 offset-sm-2">
<button type="submit" class="btn btn-primary" id="push-btn2" data-bs-toggle="tooltip" title="Save changes in this section">Save</button>
<button type="button" class="btn btn-secondary" id="format-btn2" data-bs-toggle="tooltip" title="Open up the format editor to change data format posted">Format editor</button>
<button type="button" class="btn btn-secondary" id="test-btn2" data-bs-toggle="tooltip" title="Test posting data to defined push targets">Test Push</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingGravity">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseGravity" aria-expanded="false" aria-controls="collapseGravity">
<b>Gravity Settings</b>
</button>
</h2>
<div id="collapseGravity" class="accordion-collapse collapse" aria-labelledby="headingGravity" data-bs-parent="#accordion">
<div class="accordion-body">
<form action="/api/config/gravity" method="post">
<input type="text" name="id" id="id3" hidden>
<div class="row mb-3">
<fieldset class="form-group row">
<label for="gravity-format" class="col-sm-2 col-form-label">Gravity Format</label>
<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 data-bs-toggle="tooltip" title="Present gravity in SG format">
<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" checked data-bs-toggle="tooltip" title="Present gravity in Plato format">
<label class="form-check-label" for="gravity-format-p">Plato</label>
</div>
</div>
</fieldset>
</div>
<div class="row mb-3">
<label for="gravity-formula" class="col-sm-2 col-form-label">Formula</label>
<div class="col-sm-10">
<input type="text" maxlength="200" class="form-control" name="gravity-formula" id="gravity-formula" placeholder="0.0*tilt^2+0.01*tilt+0.2" checked data-bs-toggle="tooltip" title="Formula used to convert angle to gravity">
</div>
</div>
<div class="row mb-3">
<div class="col-sm-3 offset-sm-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="gravity-temp-adjustment" id="gravity-temp-adjustment" checked data-bs-toggle="tooltip" title="Adjust the calculated gravity based on the current temperature. Assumes that calibration is done using 20C / 68F">
<label class="form-check-label" for="gravity-temp-adjustment">Temperature adjust gravity</label>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-sm-4 offset-sm-2">
<button type="submit" class="btn btn-primary" id="gravity-btn" data-bs-toggle="tooltip" title="Save changes in this section">Save</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingHardware">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseHardware" aria-expanded="false" aria-controls="collapseHardware">
<b>Hardware Settings</b>
</button>
</h2>
<div id="collapseHardware" class="accordion-collapse collapse" aria-labelledby="headingHardware" data-bs-parent="#accordion">
<div class="accordion-body">
<form action="/api/config/hardware" method="post">
<input type="text" name="id" id="id4" hidden>
<div class="row mb-3">
<label for="voltage-factor" class="col-sm-2 col-form-label">Voltage factor</label>
<div class="col-sm-2">
<input type="number" step=".01" class="form-control" name="voltage-factor" id="voltage-factor" placeholder="1.59" data-bs-toggle="tooltip" title="Factor used to calculate the battery voltage. Can vary depending on the R2 value">
</div>
<div class="col-sm-2">
<label for="voltage-factor" class="col-sm-3 col-form-label" id="battery">Loading...</label>
</div>
<div class="col-sm-1">
<button type="button" class="btn btn-secondary" id="volt-factor-btn" data-bs-toggle="tooltip" title="Calcualte the voltage factor based on measured battery voltage">Calculate</button>
</div>
<div class="col-sm-2">
<input type="number" step=".01" class="form-control" name="measured-voltage" id="measured-voltage" placeholder="" data-bs-toggle="tooltip" title="Enter the measured battery voltage to calcualte the factor">
</div>
</div>
<div class="row mb-3">
<label for="voltage-config" class="col-sm-2 col-form-label">Config voltage</label>
<div class="col-sm-2">
<input type="number" step=".01" min="3.00" max="6.00" class="form-control" name="voltage-config" id="voltage-config" placeholder="4.16" data-bs-toggle="tooltip" title="Over this level the device will always go into configuration mode, some batteries might have a higher voltage when fully charged">
</div>
</div>
<div class="row mb-3">
<label for="temp-adjustment-value" class="col-sm-2 col-form-label">Temp Sensor Adj</label>
<div class="col-sm-2">
<input type="number" step=".1" class="form-control" name="temp-adjustment-value" id="temp-adjustment-value" placeholder="0" data-bs-toggle="tooltip" title="This value will be added to the sensor value in case the sensor dont show the correct temperature">
</div>
</div>
<div class="row mb-3">
<div class="col-sm-4 offset-sm-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="gyro-temp" id="gyro-temp" data-bs-toggle="tooltip" title="Use the temperature sensor in the gyro instead of DS18B20, require 300s update interval to be accurate">
<label class="form-check-label" for="gyro-temp">Use gyro temperature</label>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-sm-4 offset-sm-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="storage-sleep" id="storage-sleep" data-bs-toggle="tooltip" title="If enabled and the device is placed on its cap (less than 5 degress) it will go into sleep for 2000 minutes">
<label class="form-check-label" for="storage-sleep">Enable storage mode when placed on cap</label>
</div>
</div>
</div>
<div class="row mb-3">
<label class="col-sm-2 col-form-label" for="ble">Bluetooth tilt color:</label>
<div class="col-sm-2">
<select class="form-select" id="ble" name="ble" disabled data-bs-toggle="tooltip" title="Select the BLE token to be used when sending data over bluetooth">
<option value="">-not active-</option>
<option value="red">red</option>
<option value="green">green</option>
<option value="black">black</option>
<option value="purple">purple</option>
<option value="orange">orange</option>
<option value="blue">blue</option>
<option value="yellow">yellow</option>
<option value="pink">pink</option>
</select>
</div>
</div>
<div class="row mb-3" id="ota-hide">
<label for="ota-url" class="col-sm-2 col-form-label">OTA base URL</label>
<div class="col-sm-8">
<input type="url" maxlength="90" class="form-control" name="ota-url" id="ota-url" placeholder="http://www.local.com/path/" data-bs-toggle="tooltip" title="Base URL to where firmware and version.json file can be found. Needs to end with '/', example: http://www.mysite.com/firmware/">
</div>
</div>
<div class="row mb-3">
<div class="col-sm-4 offset-sm-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="gravitymon-com" id="gravitymon-com" data-bs-toggle="tooltip" title="If enabled gravitymon.com will be checked for new versions.">
<label class="form-check-label" for="gravitymon-com">OTA from gravitymon.com</label>
</div>
</div>
</div>
<script>
$("#volt-factor-btn").click(function(e) {
var f = $("#voltage-factor-calc").val();
var mv = parseFloat( $("#measured-voltage").val() );
if( isNaN(mv) ) {
showError("You need to enter a measured voltage in order to calculate the factor");
return;
}
var vf = mv / f;
$("#voltage-factor").val( parseFloat(vf).toFixed(2) );
});
</script>
<script>
var gravitymonUrl = "https://www.gravitymon.com/firmware/";
$("#gravitymon-com").click(function(e){
var b = $("#gravitymon-com").is(":checked");
if ( b ) {
$("#ota-url").val(gravitymonUrl);
$('#ota-hide').hide();
} else {
$('#ota-hide').show();
}
});
</script>
<div class="row mb-3">
<div class="col-sm-8 offset-sm-2">
<button type="submit" class="btn btn-primary" id="hardware-btn" data-bs-toggle="tooltip" title="Save changes in this section">Save</button>
<button type="button" class="btn btn-secondary" id="firmware-btn" checked data-bs-toggle="tooltip" title="Manually upload a new firmware version to the device">Upload firmware</button>
</div>
</div>
</form>
<div class="row mb-3">
<div class="col-sm-8 offset-sm-2">
</div>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingAdvanced">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvanced" aria-expanded="false" aria-controls="collapseAdvanced">
<b>Advanced Software Settings (use with caution)</b>
</button>
</h2>
<div id="collapseAdvanced" class="accordion-collapse collapse" aria-labelledby="headingAdvanced" data-bs-parent="#accordion">
<div class="accordion-body">
<div class="row mb-3">
<div class="col-sm-4">
<div class="form-check">
<input checked class="form-check-input" type="checkbox" name="adv-config" id="adv-config" data-bs-toggle="tooltip" title="Enable the advanced software settings.">
<label class="form-check-label" for="adv-config">Disable advanced software settings</label>
</div>
</div>
</div>
<form action="/api/config/advanced" method="post">
<input type="text" name="id" id="id6" hidden>
<div class="row mb-3">
<label for="gyro-read-count" class="col-sm-3 col-form-label">Gyro reads:</label>
<div class="col-sm-3">
<input disabled type="number" min="10" max="100" class="form-control" name="gyro-read-count" id="gyro-read-count" placeholder="50" checked data-bs-toggle="tooltip" title="How many times should we read the gyro to get an accurate angle. More reads = better accuracy but higher battery drain">
</div>
<div class="col-sm-5">(10-100) - default 50</div>
</div>
<div class="row mb-3">
<label for="gyro-moving-threashold" class="col-sm-3 col-form-label">Gyro moving theashold</label>
<div class="col-sm-3">
<input disabled type="number" min="50" max="1000" class="form-control" name="gyro-moving-threashold" id="gyro-moving-threashold" placeholder="500" checked data-bs-toggle="tooltip" title="How much deviation between gyro reads are acceptable in order to regard this as a valid angle">
</div>
<div class="col-sm-5">(50-1000) - default 500</div>
</div>
<div class="row mb-3">
<label for="formula-max-deviation" class="col-sm-3 col-form-label">Formula max deviation (SG)</label>
<div class="col-sm-3">
<input disabled type="number" step=".1" min="1" max="10" class="form-control" name="formula-max-deviation" id="formula-max-deviation" placeholder="3" checked data-bs-toggle="tooltip" title="When validating the derived formula this is the maximum accepted deviation for the supplied values">
</div>
<div class="col-sm-5">(1 - 10) - default 3 SG</div>
</div>
<div class="row mb-3">
<div class="col-sm-3 offset-sm-3">
<div class="form-check">
<input disabled class="form-check-input" type="checkbox" class="form-control" name="ignore-low-angles" id="ignore-low-angles" data-bs-toggle="tooltip" title="When active, angles below water will be ignored. Note! Angle must be defined under calibration, first field.">
<label class="form-check-label" for="ignore-low-angles">Ignore angles below water</label>
</div>
</div>
<div class="col-sm-5" name="water-angle" id="water-angle"></div>
</div>
<div class="row mb-3">
<label for="formula-calibration-temp" class="col-sm-3 col-form-label">Gravity calibration temp</label>
<div class="col-sm-3">
<input disabled type="number" step=".01" min="0" max="100" class="form-control" name="formula-calibration-temp" id="formula-calibration-temp" placeholder="20" checked data-bs-toggle="tooltip" title="Calibration temperature, used in temperatur correction formula, default 20C/68F">
</div>
<div class="col-sm-5">(0 - 100) - default 20C/68F</div>
</div>
<hr>
<div class="row mb-3">
<label for="tempsensor-resolution" class="col-sm-3 col-form-label">DS18B20 resolution (bits)</label>
<div class="col-sm-3">
<input disabled type="number" min="9" max="12" class="form-control" name="tempsensor-resolution" id="tempsensor-resolution" placeholder="9" checked data-bs-toggle="tooltip" title="Resolution when reading the DS18B20 temperature sensor, higher resolution give better accuracy but takes longer">
</div>
<div class="col-sm-5">(9 - 12) - default 9 bits</div>
</div>
<hr>
<div class="row mb-3">
<label for="wifi-connect-timeout" class="col-sm-3 col-form-label">Wifi connect timeout (s)</label>
<div class="col-sm-3">
<input disabled type="number" min="1" max="60" class="form-control" name="wifi-connect-timeout" id="wifi-connect-timeout" placeholder="20" checked data-bs-toggle="tooltip" title="Max time waiting for a wifi connection before going back to sleep">
</div>
<div class="col-sm-5">(1 - 60) - default 20 s</div>
</div>
<div class="row mb-3">
<label for="wifi-portal-timeout" class="col-sm-3 col-form-label">Wifi portal timeout (s)</label>
<div class="col-sm-3">
<input disabled type="number" min="10" max="240" class="form-control" name="wifi-portal-timeout" id="wifi-portal-timeout" placeholder="120" checked data-bs-toggle="tooltip" title="Max time the wifi portal is active before existing">
</div>
<div class="col-sm-5">(10 - 240) - default 120 s</div>
</div>
<hr>
<div class="row mb-3">
<label for="int-http1" class="col-sm-3 col-form-label">Skip interval - HTTP 1 (POST):</label>
<div class="col-sm-3">
<input disabled type="number" min="0" max="5" class="form-control" name="int-http1" id="int-http1" placeholder="0" checked data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
</div>
<div class="col-sm-5">(0 - 5) - default 0</div>
</div>
<div class="row mb-3">
<label for="int-http2" class="col-sm-3 col-form-label">Skip interval - HTTP 2 (POST)</label>
<div class="col-sm-3">
<input disabled type="number" min="0" max="5" class="form-control" name="int-http2" id="int-http2" placeholder="0" data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
</div>
<div class="col-sm-5">(0 - 5) - default 0</div>
</div>
<div class="row mb-3">
<label for="int-http3" class="col-sm-3 col-form-label">Skip interval - HTTP 3 (GET)</label>
<div class="col-sm-3">
<input disabled type="number" min="0" max="5" class="form-control" name="int-http3" id="int-http3" placeholder="0" data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
</div>
<div class="col-sm-5">(0 - 5) - default 0</div>
</div>
<div class="row mb-3">
<label for="int-influx" class="col-sm-3 col-form-label">Skip interval - InfluxDB v2</label>
<div class="col-sm-3">
<input disabled type="number" min="0" max="5" class="form-control" name="int-influx" id="int-influx" placeholder="0" data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
</div>
<div class="col-sm-5">(0 - 5) - default 0</div>
</div>
<div class="row mb-3">
<label for="int-mqtt" class="col-sm-3 col-form-label">Skip interval - MQTT</label>
<div class="col-sm-3">
<input disabled type="number" min="0" max="5" class="form-control" name="int-mqtt" id="int-mqtt" placeholder="0" data-bs-toggle="tooltip" title="Defines how many sleep cycles to skip between pushing data to this target, 1 = every second cycle">
</div>
<div class="col-sm-5">(0 - 5) - default 0</div>
</div>
<div class="row mb-3">
<div class="col-sm-8 offset-sm-3">
<button type="submit" class="btn btn-primary" id="advanced-btn" data-bs-toggle="tooltip" title="Save changes in this section">Save</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modal-http" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="modal-header" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-header">Define HTTP headers</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<label for="http-header" class="col-form-label">Header 1 (Header: value)</label>
<input type="text" maxlength="100" class="form-control" id="header1" oninput="checkHeader(this)" placeholder="Content-Type: application/json" data-bs-toggle="tooltip" title="Set a http headers, empty string is skipped">
<label for="http-header" class="col-form-label">Header 2 (Header: value)</label>
<input type="text" maxlength="100" class="form-control" id="header2" oninput="checkHeader(this)" data-bs-toggle="tooltip" title="Set a http headers, empty string is skipped">
<input type="text" id="field1" hidden>
<input type="text" id="field2" hidden>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" data-bs-toggle="tooltip" title="Close dialog, press the save button in the section to save data">Close</button>
</div>
</div>
</div>
</div>
<script>
$('#modal-http').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget)
var field1 = button.data('field1')
var field2 = button.data('field2')
var modal = $(this)
modal.find('.modal-body #header1').val($(field1).val())
modal.find('.modal-body #header2').val($(field2).val())
modal.find('.modal-body #field1').val(field1)
modal.find('.modal-body #field2').val(field2)
})
$('#modal-http').on('hide.bs.modal', function (event) {
console.log("2")
var modal = $(this)
field1 = modal.find('.modal-body #field1').val()
field2 = modal.find('.modal-body #field2').val()
$(field1).val(modal.find('.modal-body #header1').val())
$(field2).val(modal.find('.modal-body #header2').val())
})
function checkHeader(input) {
console.log( input.value );
if (input.value != "" && input.value.indexOf(":") == -1) {
$("#btn-close").prop("disabled", true);
$(input).removeClass("is-valid").addClass("is-invalid");
} else {
$("#btn-close").prop("disabled", false);
$(input).removeClass("is-invalid").addClass("is-valid");
}
}
</script>
<script type="text/javascript">
window.onload = getConfig;
setButtonDisabled( true );
// Opens the targetet according (if URL has #collapseXXX)
$(document).ready(function () {
if(location.hash != null && location.hash != ""){
$('.collapse').removeClass('in');
$(location.hash + '.collapse').collapse('show');
}
});
// Trigger the calibration
$("#calibrate-btn").click(function(e){
console.log( "Calibrating..." );
$.ajax( {
type: "POST",
url: "/api/calibrate",
data: { id: $("#id1").val() },
success: function(result) { showSuccess('Calibration of device was completed successfully.'); getConfig(); },
error: function(result) { showError('Unable to calibrate device.'); }
} );
});
$("#firmware-btn").click(function(e){
window.location.href = "/firmware.htm";
});
// Open the format editor
$("#format-btn").click(function(e){
window.location.href = "/format.htm";
});
// Open the format editor
$("#format-btn2").click(function(e){
window.location.href = "/format.htm";
});
$("#test-btn").click(function(e){
window.location.href = "/test.htm";
});
$("#test-btn2").click(function(e){
window.location.href = "/test.htm";
});
function estimateBatteryLife(interval, rt) {
// ESP8266 consumes between 140-170mA when WIFI is on. Deep sleep is 20uA.
// MPU-6050 consumes 4mA
// DS18B20 consumes 1mA
// For this estimation we use an average of 160mA
var pwrActive = 160; // mA per hour (120-170 mA)
var pwrSleep = 15; // mA per day (include all pheripials as well)
var batt = 2200; // mA
var ble = false;
var wifi = true;
var platform = $("#platform").val();
if($("#ble").val() != "")
ble = true;
if($("#http-push").val() == "" && $("#http-push2").val() == "" && $("#http-push3").val() == "" && $("#influxdb2-push").val() == "" && $("#mqtt-push").val() == "")
wifi = false;
console.log( "Connection options: BLE=" + (ble?"on":"off") + " WIFI=" + (wifi?"on":"off") );
if(platform == "esp32" && wifi) {
var pwrActive = 320; // mA per hour (260-379 mA)
} else if(platform == "esp32" && !wifi) {
var pwrActive = 160;
} else if(platform == "esp32c3" && wifi) {
var pwrActive = 320; // mA per hour (290-350 mA)
} else if(platform == "esp32c3" && !wifi) {
var pwrActive = 160;
} else if(platform == "esp32s2" && wifi) {
var pwrActive = 280; // mA per hour (260-300 mA)
} else if(platform == "esp32s2" && !wifi) {
var pwrActive = 160;
} else if(platform == "esp32lite" && wifi) {
var pwrActive = 330; // mA per hour (260-379 mA)
} else if(platform == "esp32lite" && !wifi) {
var pwrActive = 160;
}
console.log( "Estimated power per hour = " + pwrActive.toString() + "mA on platform = " + platform);
if(rt<1) rt = 2;
// The deep sleep will consume approx 1mA per day.
var powerPerDay = (24*3600)/(interval+rt)*(rt/3600)*pwrActive + pwrSleep;
return batt/powerPerDay;
}
function updateSleepInfo() {
var i = parseInt($("#sleep-interval").val());
var rt = parseInt($("#runtime-average").val());
var j = 0;
console.log("Average runtime " + $("#runtime-average").val() )
if( rt>0 ) {
j = estimateBatteryLife(i, rt);
}
var t1 = Math.floor(i/60) + " m " + (i%60) + " s";
var t2 = Math.floor(j/7) + " weeks " + Math.floor(j%7) + " days";
if( j )
$("#sleep-interval-info").text( t1 + " - Estimated runtime: " + t2);
else
$("#sleep-interval-info").text( t1 );
hideWarningGyro();
if(i>0 && i<300) {
if( $("#gyro-temp").is(":checked") )
showWarningGyro();
showWarningSleep();
} else {
hideWarningSleep();
}
}
// Trigger the calibration and show warnings if needed
$("#sleep-interval").keyup(updateSleepInfo);
$("#gyro-temp").change(updateSleepInfo);
function setButtonDisabled( b ) {
$("#device-btn").prop("disabled", b);
$("#calibrate-btn").prop("disabled", b);
$("#push-btn").prop("disabled", b);
$("#format-btn").prop("disabled", b);
$("#test-btn").prop("disabled", b);
$("#gravity-btn").prop("disabled", b);
$("#hardware-btn").prop("disabled", b);
$("#push-btn2").prop("disabled", b);
$("#format-btn2").prop("disabled", b);
$("#test-btn2").prop("disabled", b);
$("#advanced-btn").prop("disabled", b);
checkAdvancedSection();
}
$("#adv-config").click(function(e){
checkAdvancedSection();
});
function checkAdvancedSection() {
var b = $("#adv-config").is(":checked");
$("#advanced-btn").prop("disabled", b);
$("#gyro-read-count").prop("disabled", b);
$("#gyro-moving-threashold").prop("disabled", b);
$("#formula-max-deviation").prop("disabled", b);
$("#wifi-portal-timeout").prop("disabled", b);
$("#wifi-connect-timeout").prop("disabled", b);
$("#formula-calibration-temp").prop("disabled", b);
$("#int-http1").prop("disabled", b);
$("#int-http2").prop("disabled", b);
$("#int-http3").prop("disabled", b);
$("#int-influx").prop("disabled", b);
$("#int-mqtt").prop("disabled", b);
$("#tempsensor-resolution").prop("disabled", b);
$("#ignore-low-angles").prop("disabled", b);
}
// Get the advanced values from the API
function getAdvancedConfig() {
setButtonDisabled( true );
var url = "/api/config/advanced";
//var url = "/test/adv.json";
$('#spinner').show();
$.getJSON(url, function (cfg) {
console.log( cfg );
$("#gyro-read-count").val(cfg["gyro-read-count"]);
$("#gyro-moving-threashold").val(cfg["gyro-moving-threashold"]);
$("#formula-max-deviation").val(cfg["formula-max-deviation"]);
$("#wifi-portal-timeout").val(cfg["wifi-portal-timeout"]);
$("#wifi-connect-timeout").val(cfg["wifi-connect-timeout"]);
$("#tempsensor-resolution").val(cfg["tempsensor-resolution"]);
$("#ignore-low-angles").prop( "checked", cfg["ignore-low-angles"] );
$("#formula-calibration-temp").val(cfg["formula-calibration-temp"]);
$("#int-http1").val(cfg["int-http1"]);
$("#int-http2").val(cfg["int-http2"]);
$("#int-http3").val(cfg["int-http3"]);
$("#int-influx").val(cfg["int-influx"]);
$("#int-mqtt").val(cfg["int-mqtt"]);
if ( cfg["gyro-read-count"] != 50 || cfg["gyro-moving-threashold"] != 500 || cfg["formula-max-deviation"] != 3 || cfg["wifi-portal-timeout"] != 120 || cfg["wifi-connect-timeout"] != 20 || cfg["tempsensor-resolution"] != 9 ||
cfg["int-http1"] != 0 || cfg["int-http2"] != 0 || cfg["int-http3"] != 0 || cfg["int-influx"] != 0 || cfg["int-mqtt"] != 0 || cfg["ignore-low-angles"] != false || (cfg["formula-calibration-temp"] != 20 && cfg["formula-calibration-temp"] != 68)) {
$("#adv-config").attr("checked", false );
}
})
.fail(function () {
showError('Unable to get data from the device.');
})
.always(function() {
$('#spinner').hide();
setButtonDisabled( false );
});
}
// Get the configuration values from the API
function getConfig() {
setButtonDisabled( true );
var url = "/api/config";
//var url = "/test/config.json";
$('#spinner').show();
$.getJSON(url, function (cfg) {
console.log( cfg );
if(cfg["platform"]=="esp32" || cfg["platform"]=="esp32c3" || cfg["platform"]=="esp32lite") {
$('#ble').prop('disabled', false);
$("#ble").val(cfg["ble"]);
}
if(cfg["platform"]=="esp32lite") {
$('#gyro-temp').prop('disabled', true);
}
$("#id1").val(cfg["id"]);
$("#id2").val(cfg["id"]);
$("#id3").val(cfg["id"]);
$("#id4").val(cfg["id"]);
$("#id5").val(cfg["id"]);
$("#id6").val(cfg["id"]);
$("#mdns").val(cfg["mdns"]);
if( cfg["temp-format"] == "C" ) $("#temp-format-c").click();
else $("#temp-format-f").click();
if( cfg["gravity-format"] == "G" ) $("#gravity-format-g").click();
else $("#gravity-format-p").click();
$("#ota-url").val(cfg["ota-url"]);
if( cfg["ota-url"] == gravitymonUrl) {
$("#gravitymon-com").prop( "checked", true );
$("#ota-hide").hide();
}
$("#token").val(cfg["token"]);
$("#token2").val(cfg["token2"]);
$("#http-push").val(cfg["http-push"]);
$("#http-push-h1").val(cfg["http-push-h1"]);
$("#http-push-h2").val(cfg["http-push-h2"]);
$("#http-push2").val(cfg["http-push2"]);
$("#http-push2-h1").val(cfg["http-push2-h1"]);
$("#http-push2-h2").val(cfg["http-push2-h2"]);
$("#http-push3").val(cfg["http-push3"]);
$("#influxdb2-push").val(cfg["influxdb2-push"]);
$("#influxdb2-org").val(cfg["influxdb2-org"]);
$("#influxdb2-bucket").val(cfg["influxdb2-bucket"]);
$("#influxdb2-auth").val(cfg["influxdb2-auth"]);
$("#mqtt-push").val(cfg["mqtt-push"]);
$("#mqtt-port").val(cfg["mqtt-port"]);
$("#mqtt-user").val(cfg["mqtt-user"]);
$("#mqtt-pass").val(cfg["mqtt-pass"]);
$("#sleep-interval").val(cfg["sleep-interval"]);
$("#voltage-factor").val(cfg["voltage-factor"]);
$("#voltage-config").val(cfg["voltage-config"]);
$("#gravity-formula").val(cfg["gravity-formula"]);
$("#temp-adjustment-value").val(cfg["temp-adjustment-value"]);
$("#gravity-temp-adjustment").prop( "checked", cfg["gravity-temp-adjustment"] );
$("#gyro-temp").prop( "checked", cfg["gyro-temp"] );
$("#storage-sleep").prop( "checked", cfg["storage-sleep"] );
$("#gyro-calibration-data").text( cfg["gyro-calibration-data"]["ax"] + "," + cfg["gyro-calibration-data"]["ay"] + "," + cfg["gyro-calibration-data"]["az"] + "," + cfg["gyro-calibration-data"]["gx"] + "," + cfg["gyro-calibration-data"]["gy"] + "," + cfg["gyro-calibration-data"]["gz"] );
$("#battery").text(cfg["battery"] + " V");
$("#angle").text(cfg["angle"]);
$("#runtime-average").val(cfg["runtime-average"]);
$("#water-angle").text( "(Water angle: " + cfg["formula-calculation-data"]["a1"] + ") - default off");
$("#wifi-ssid").text(cfg["wifi-ssid"]);
$("#wifi-ssid2").text(cfg["wifi-ssid2"]);
$("#platform").val(cfg["platform"]);
$("#voltage-factor-calc").val( cfg["battery"] / cfg["voltage-factor"] );
//$("#gravity").text(cfg["gravity"] + " SG");
})
.fail(function () {
showError('Unable to get data from the device.');
})
.always(function() {
//$('#spinner').hide();
//setButtonDisabled( false );
updateSleepInfo();
getAdvancedConfig();
});
}
</script>
<!-- START FOOTER -->
<div class="container themed-container bg-primary text-light row-margin-10">(C) Copyright 2021-22 Magnus Persson</div>
</body>
</html>