11 lines
17 KiB
HTML
11 lines
17 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:1em}</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><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="/config.htm">Configuration</a></li><li><a class="dropdown-item" href="#">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-ha"><div>Home Assistant device configuration detected in MQTT format. These messages will be posted when format is saved and not during gravity measurement.</div><button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button></div><script type="text/javascript">function showError(s){$("#alert").removeClass("alert-success").addClass("alert-danger").removeClass("hide").addClass("show").removeClass("d-none"),$("#alert-msg").text(s)}function showSuccess(s){$("#alert").addClass("alert-success").removeClass("alert-danger").removeClass("hide").addClass("show").removeClass("d-none"),$("#alert-msg").text(s)}function showWarningHomeAssistant(){$("#warning-ha").removeClass("d-none").addClass("show").removeClass("hide")}function hideWarningHomeAssistant(){$("#warning-ha").addClass("d-none").removeClass("show").addClass("hide")}$("#alert-btn").click(function(s){$("#alert").addClass("hide").removeClass("show").addClass("d-none")})</script><div class="accordion" id="accordion"><div class="accordion-item"><h2 class="accordion-header" id="headingFormat"><button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFormat" aria-expanded="true" aria-controls="collapseFormat"><b>Push Format Templates</b></button></h2><div id="collapseFormat" class="accordion-collapse collapse show" aria-labelledby="headingFormat" data-bs-parent="#accordion"><div class="accordion-body"><input type="text" name="id" id="id" hidden> <input type="text" name="http-1" id="http-1" hidden> <input type="text" name="http-2" id="http-2" hidden> <input type="text" name="http-3" id="http-3" hidden> <input type="text" name="influxdb" id="influxdb" hidden> <input type="text" name="mqtt" id="mqtt" hidden><div class="row mb-3"><label for="push-target" class="col-sm-2 col-form-label">Push target:</label> <select class="custom-select col-sm-4" required name="push-target" id="push-target" data-bs-toggle="tooltip" title="Select the push target to edit format template for"><option value="http-1">HTTP option 1 (post)</option><option value="http-2">HTTP option 2 (post)</option><option value="http-3">HTTP option 3 (get)</option><option value="influxdb">Influx DB</option><option value="mqtt">MQTT</option></select></div><div class="row mb-3"><div class="col-sm-12"><textarea rows="10" class="form-control" name="format" id="format">
|
|
</textarea></div></div><script>let formatTemplates = [
|
|
{ "id": "GravityMon-Post", "format": "%7B%20%22name%22%20%3A%20%22%24%7Bmdns%7D%22%2C%20%22ID%22%3A%20%22%24%7Bid%7D%22%2C%20%22token%22%20%3A%20%22%24%7Btoken%7D%22%2C%20%22interval%22%3A%20%24%7Bsleep-interval%7D%2C%20%22temperature%22%3A%20%24%7Btemp%7D%2C%20%22temp_units%22%3A%20%22%24%7Btemp-unit%7D%22%2C%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%20%22angle%22%3A%20%24%7Bangle%7D%2C%20%22battery%22%3A%20%24%7Bbattery%7D%2C%20%22RSSI%22%3A%20%24%7Brssi%7D%2C%20%22corr-gravity%22%3A%20%24%7Bcorr-gravity%7D%2C%20%22gravity-unit%22%3A%20%22%24%7Bgravity-unit%7D%22%2C%20%22run-time%22%3A%20%24%7Brun-time%7D%7D" },
|
|
{ "id": "GravityMon-Get", "format": "%3Fname%3D%24%7Bmdns%7D%26id%3D%24%7Bid%7D%26token%3D%24%7Btoken2%7D%26interval%3D%24%7Bsleep-interval%7D%26temperature%3D%24%7Btemp%7D%26%0Atemp-units%3D%24%7Btemp-unit%7D%26gravity%3D%24%7Bgravity%7D%26angle%3D%24%7Bangle%7D%26battery%3D%24%7Bbattery%7D%26rssi%3D%24%7Brssi%7D%26%0Acorr-gravity%3D%24%7Bcorr-gravity%7D%26gravity-unit%3D%24%7Bgravity-unit%7D%26run-time%3D%24%7Brun-time%7D" },
|
|
{ "id": "iSpindle-Post", "format": "%7B%20%22name%22%20%3A%20%22%24%7Bmdns%7D%22%2C%20%22ID%22%3A%20%22%24%7Bid%7D%22%2C%20%22token%22%20%3A%20%22%24%7Btoken%7D%22%2C%20%22interval%22%3A%20%24%7Bsleep-interval%7D%2C%20%22temperature%22%3A%20%24%7Btemp%7D%2C%20%22temp_units%22%3A%20%22%24%7Btemp-unit%7D%22%2C%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%20%22angle%22%3A%20%24%7Bangle%7D%2C%20%22battery%22%3A%20%24%7Bbattery%7D%2C%20%22RSSI%22%3A%20%24%7Brssi%7D%7D" },
|
|
{ "id": "BrewFatherCustom-Post", "format": "%7B%20%20%20%22name%22%3A%20%22%24%7Bmdns%7D%22%2C%20%20%20%22temp%22%3A%20%24%7Btemp%7D%2C%20%20%20%22aux_temp%22%3A%200%2C%20%20%20%22ext_temp%22%3A%200%2C%20%20%20%22temp_unit%22%3A%20%22%24%7Btemp-unit%7D%22%2C%20%20%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%20%20%20%22gravity_unit%22%3A%20%22%24%7Bgravity-unit%7D%22%2C%20%20%20%22pressure%22%3A%200%2C%20%20%20%22pressure_unit%22%3A%20%22PSI%22%2C%20%20%20%22ph%22%3A%200%2C%20%20%20%22bpm%22%3A%200%2C%20%20%20%22comment%22%3A%20%22%22%2C%20%20%20%22beer%22%3A%20%22%22%2C%20%20%20%22battery%22%3A%20%24%7Bbattery%7D%7D" },
|
|
{ "id": "iSpindle-Mqtt", "format": "ispindel%2F%24%7Bmdns%7D%2Ftilt%3A%24%7Bangle%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Ftemperature%3A%24%7Btemp%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Ftemp_units%3A%24%7Btemp-unit%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Fbattery%3A%24%7Bbattery%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Fgravity%3A%24%7Bgravity%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2Finterval%3A%24%7Bsleep-interval%7D%7C%0Aispindel%2F%24%7Bmdns%7D%2FRSSI%3A%24%7Brssi%7D%7C" },
|
|
{ "id": "HomeAssistant-Mqtt", "format": "gravmon%2F%24%7Bmdns%7D%2Ftemperature%3A%24%7Btemp%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Fgravity%3A%24%7Bgravity%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Frssi%3A%24%7Brssi%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Ftilt%3A%24%7Btilt%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Fbattery%3A%24%7Bbattery%7D%7C%0A" },
|
|
{ "id": "HomeAssistant-Mqtt2", "format": "gravmon%2F%24%7Bmdns%7D%2Ftemperature%3A%24%7Btemp%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Fgravity%3A%24%7Bgravity%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Frssi%3A%24%7Brssi%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Ftilt%3A%24%7Btilt%7D%7C%0Agravmon%2F%24%7Bmdns%7D%2Fbattery%3A%24%7Bbattery%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Ftemperature%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_temp%22%2C%22name%22%3A%22temperature%22%2C%22dev_cla%22%3A%22temperature%22%2C%22unit_of_meas%22%3A%22%24%7Btemp-unit%7D%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Ftemperature%22%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Fgravity%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_grav%22%2C%22name%22%3A%22gravity%22%2C%22dev_cla%22%3A%22temperature%22%2C%22unit_of_meas%22%3A%22%20%24%7Bgravity-unit%7D%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Fgravity%22%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Frssi%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_rssi%22%2C%22name%22%3A%22rssi%22%2C%22dev_cla%22%3A%22signal_strength%22%2C%22unit_of_meas%22%3A%22dBm%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Frssi%22%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Ftilt%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_tilt%22%2C%22name%22%3A%22tilt%22%2C%22dev_cla%22%3A%22temperature%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Ftilt%22%7D%7C%0Ahomeassistant%2Fsensor%2Fgravmon_%24%7Bid%7D%2Fbattery%2Fconfig%3A%7B%22dev%22%3A%7B%22name%22%3A%22%24%7Bmdns%7D%22%2C%22mdl%22%3A%22gravmon%22%2C%22sw%22%3A%22%24%7Bapp-ver%7D%22%2C%22ids%22%3A%22%24%7Bid%7D%22%7D%2C%22uniq_id%22%3A%22%24%7Bid%7D_batt%22%2C%22name%22%3A%22battery%22%2C%22dev_cla%22%3A%22voltage%22%2C%22unit_of_meas%22%3A%22V%22%2C%22stat_t%22%3A%22gravmon%2F%24%7Bmdns%7D%2Fbattery%22%7D%7C%0A" },
|
|
{ "id": "Brewblox-Mqtt", "format": "brewcast%2Fhistory%3A%7B%22key%22%3A%22%24%7Bmdns%7D%22%2C%22data%22%3A%7B%22Temperature%5BdegC%5D%22%3A%20%24%7Btemp-c%7D%2C%22Temperature%5BdegF%5D%22%3A%20%24%7Btemp-f%7D%2C%22Battery%5BV%5D%22%3A%24%7Bbattery%7D%2C%22Tilt%5Bdeg%5D%22%3A%24%7Bangle%7D%2C%22Rssi%5BdBm%5D%22%3A%24%7Brssi%7D%2C%22SG%22%3A%24%7Bgravity-sg%7D%2C%22Plato%22%3A%24%7Bgravity-plato%7D%7D%7D%7C" },
|
|
{ "id": "UBIDots-Post", "format": "%7B%0A%20%20%20%22temperature%22%3A%20%24%7Btemp%7D%2C%0A%20%20%20%22gravity%22%3A%20%24%7Bgravity%7D%2C%0A%20%20%20%22angle%22%3A%20%24%7Bangle%7D%2C%0A%20%20%20%22battery%22%3A%20%24%7Bbattery%7D%2C%0A%20%20%20%22rssi%22%3A%20%24%7Brssi%7D%0A%7D" } ];</script><div class="row mb-3"><div class="col-sm-2"><button class="btn btn-primary" id="format-btn" data-bs-toggle="tooltip" title="Save the format template, saving an empty form will reset the template to default">Save</button> <button class="btn btn-secondary" id="test-btn" data-bs-toggle="tooltip" title="Apply device data to template to see how it works">Test</button></div><select class="custom-select col-sm-4" required name="predefined" id="predefined" data-bs-toggle="tooltip" title="Select a pre-defined format template"><option value="iSpindle-Post">iSpindle (POST)</option><option value="GravityMon-Post">GravityMon (POST)</option><option value="iSpindle-Mqtt">iSpindle (MQTT)</option><option value="HomeAssistant-Mqtt">Home Assistant (MQTT)</option><option value="HomeAssistant-Mqtt2">Home Assistant - Auto register sensor (MQTT)</option><option value="UBIDots-Post">UBIdots (POST)</option><option value="BrewFatherCustom-Post">Brewfather - Custom Endpoint (POST)</option><option value="iSpindle-Post">Brewfather - iSpindle Endpoint (POST)</option><option value="GravityMon-Get">GravityMon (GET)</option><option value="Brewblox-Mqtt">BrewBlox (MQTT)</option></select><div class="col-sm-4"><button class="btn btn-secondary" id="copy-btn" data-bs-toggle="tooltip" title="Copy the selected format template to the selected push target">Copy format</button> <button class="btn btn-secondary" id="clear-btn" data-bs-toggle="tooltip" title="Clear the current format template">Clear format</button></div></div><hr class="my-2"><pre class="card-preview" id="preview" name="preview"></pre></div></div></div></div></div><script type="text/javascript">function postHomeAssistant(e){if(e){console.log("Current format is mqtt, running post tests to register device."),$("#spinner").show(),setButtonDisabled(!0);var t="/api/test/push";t+="?id="+$("#id").val()+"&format=mqtt",$.getJSON(t,function(e){console.log(e);e.code;var t=e.success;e.enabled;t?showSuccess("Format stored successfully. Home Assistant Device Registration Successful."):showError("Format stored successfully. Home Assistant Device Registration Failed!")}).fail(function(){showError("Format stored successfully. Home Assistant Device Registration Failed!")}).always(function(){$("#spinner").hide(),setButtonDisabled(!1),getConfig()})}else getConfig()}function setButtonDisabled(e){$("#format-btn").prop("disabled",e),$("#test-btn").prop("disabled",e),$("#copy-btn").prop("disabled",e),$("#clear-btn").prop("disabled",e)}function selectFormat(){var e="#"+$("#push-target").val();console.log(e),e=decodeURIComponent($(e).val()),console.log(e),e=e.replaceAll("|","|\n"),console.log(e),$("#format").val(e),$("#preview").text("")}function getConfig(){setButtonDisabled(!0);var e="/api/config/format";$("#spinner").show(),$.getJSON(e,function(e){console.log(e),$("#id").val(e.id),$("#http-1").val(e["http-1"]),$("#http-2").val(e["http-2"]),$("#http-3").val(e["http-3"]),$("#influxdb").val(e.influxdb),$("#mqtt").val(e.mqtt),selectFormat()}).fail(function(){showError("Unable to get data from the device.")}).always(function(){$("#spinner").hide(),setButtonDisabled(!1)})}window.onload=getConfig,setButtonDisabled(!0),$(document).ready(function(){null!=location.hash&&""!=location.hash&&($(".collapse").removeClass("in"),$(location.hash+".collapse").collapse("show"))}),$("#push-target").change(function(e){console.log(e),selectFormat()}),$("#copy-btn").click(function(e){var l=$("#predefined").val();formatTemplates.forEach(function(e,t){e.id==l&&$("#format").val(decodeURIComponent(e.format))})}),$("#clear-btn").click(function(e){$("#format").val("")}),$("#format-btn").click(function(e){$("#spinner").show(),setButtonDisabled(!0);var t=$("#format").val(),l=!1;hideWarningHomeAssistant(),"mqtt"==$("#push-target").val()&&-1!=t.search("homeassistant/sensor/")&&(console.log("Current format is mqtt, it contains topics for Home Assistant device registration."),showWarningHomeAssistant(),l=!0),t=t.replaceAll("\n","");var a="id="+$("#id").val()+"&"+$("#push-target").val()+"="+encodeURIComponent(t);console.log(a),$.ajax({type:"POST",url:"/api/config/format",data:a,success:function(e){showSuccess("Format stored successfully."),postHomeAssistant(l)},error:function(e){showError("Unable to store format."),$("#spinner").hide()},always:function(){$("#spinner").hide(),setButtonDisabled(!1)}})}),$("#test-btn").click(function(e){var t="/api/status";$("#spinner").show(),$.getJSON(t,function(e){console.log(e);var t=$("#format").val();if(t="C"==e["temp-format"]?t.replaceAll("${temp}",e["temp-c"]):t.replaceAll("${temp}",e["temp-f"]),"G"==e["gravity-format"]){var l=e.gravity;t=t.replaceAll("${gravity-sg}",l),t=t.replaceAll("${corr-gravity-sg}",l);var a=259-(259-l);t=t.replaceAll("${gravity-plato}",a),t=t.replaceAll("${corr-gravity-plato}",a)}else{a=e.gravity;t=t.replaceAll("${gravity-plato}",a),t=t.replaceAll("${corr-gravity-plato}",a);l=259/(259-a);t=t.replaceAll("${gravity-sg}",l),t=t.replaceAll("${corr-gravity-sg}",l)}t=t.replaceAll("${mdns}",e.mdns),t=t.replaceAll("${id}",e.id),t=t.replaceAll("${sleep-interval}",e["sleep-interval"]),t=t.replaceAll("${token}",e.token),t=t.replaceAll("${token2}",e.token2),t=t.replaceAll("${temp-c}",e["temp-c"]),t=t.replaceAll("${temp-f}",e["temp-f"]),t=t.replaceAll("${temp-unit}",e["temp-format"]),t=t.replaceAll("${battery}",e.battery),t=t.replaceAll("${rssi}",e.rssi),t=t.replaceAll("${run-time}",e["runtime-average"]),t=t.replaceAll("${gravity}",e.gravity),t=t.replaceAll("${gravity-unit}",e["gravity-format"]),t=t.replaceAll("${corr-gravity}",e.gravity),t=t.replaceAll("${angle}",e.angle),t=t.replaceAll("${tilt}",e.angle),t=t.replaceAll("${app-ver}",e["app-ver"]),t=t.replaceAll("${app-build}",e["app-build"]);try{var o=JSON.parse(t);t=JSON.stringify(o,null,2)}catch(e){console.log("Not a JSON object!")}$("#preview").text(t)}).fail(function(){showError("Unable to get data from the device.")}).always(function(){$("#spinner").hide()})})</script><!-- START FOOTER --><div class="container themed-container bg-primary text-light row-margin-10">(C) Copyright 2021-22 Magnus Persson</div></body></html> |