UNPKG

bt-seneca-msc

Version:

A pure Javascript API for the Seneca Multi Smart Calibrator (MSC) device, using web bluetooth.

307 lines (288 loc) 12.4 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Seneca MSC</title> <script src="./dist/bt-seneca-msc.js"></script> <!-- CSS only --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous"> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> </head> <body> <h2>API commands</h2> <div class="container container-md"> <div class="row"> <div class="col"> <div class="container d-grid gap-3"> <div class="row"> <div class="col"> <button id="startBt" class="btn btn-primary">Pair(false)</button> <button id="startBt2" class="btn btn-primary">Pair(true)</button> </div> <div class="col"> <div id="resultPair"></div> </div> </div> <div class="row"> <div class="col"> <button id="stopBt" class="btn btn-primary">Stop()</button> </div> <div class="col"> <div id="resultStop"></div> </div> </div> <div class="row"> <div class="col"> <button id="getState" class="btn btn-primary">GetState()</button> </div> <div class="col"> <div id="resultGetState"></div> </div> </div> </div> </div> <div class="col"> <div class="container d-grid gap-3"> <div class="col"> <div class="row"> <label for="new_command_id">Command type</label> <select id="new_command_id" class="form-control"></select> </div> <div class="row"> <label for="new_command_sp" id="setpoint1_desc">Setpoint 1</label> <input type="number" id="new_command_sp" class="form-control" /> </div> <div class="row"> <label for="new_command_sp2" id="setpoint2_desc">Setpoint 2</label> <input type="number" id="new_command_sp2" class="form-control" /> </div> <div class="row"> <input type="button" id="executeBtn" value="Execute(command)" class="btn btn-primary"> <div id="resultExecute"></div> </div> </div> </div> </div> <div class="col"> <div class="container d-grid gap-3"> <div class="row"> <input type="button" id="traceBtn" value="Loglevel: debug" onclick="MSC.log.setLevel(MSC.log.levels.TRACE);" class="btn btn-info"> </div> <div class="row"> <input type="button" id="defaultLog" value="Loglevel: info" onclick="MSC.log.setLevel(MSC.log.levels.INFO);" class="btn btn-info"> </div> <div class="row"> <input type="button" id="defaultLog" value="Loglevel: default" onclick="MSC.log.setLevel(MSC.log.levels.WARN);" class="btn btn-info"> </div> </div> </div> </div> <div class="row"> <div class="col"> <input type="button" id="jsonTraces" value="Test modbus traces" class="btn btn-info"> <div id="jsonTestTraces"></div> </div> </div> </div> <h2>GetState()</h2> <div class="container"> <div class="row"> <div class="col col-md"> <table id="state" class="table table-striped"> <tr> <td>Overall status</td> <td> <div id="overall"></div> </td> </tr> <tr> <td>Detailed status</td> <td> <div id="status"></div> </td> </tr> <tr> <td>Meter mode</td> <td> <div id="mode"></div> </td> </tr> <tr> <td>Last setpoint</td> <td> <div id="sp"></div> </td> </tr> <tr> <td>Last measure</td> <td> <div id="meas"></div> </td> </tr> <tr> <td>Bluetooth info</td> <td> <div id="btinfo"></div> </td> </tr> <tr> <td>Meter serial number</td> <td> <div id="serial"></div> </td> </tr> <tr> <td>Meter battery (V)</td> <td> <div id="battery"></div> </td> </tr> <tr> <td>Stats</td> <td> <div id="stats"></div> </td> </tr> </table> </div> <div class="col col-sm"> <img src="./docs/msc.jpg" alt="Seneca MSC" width="400" /> </div> </div> </div> <script> // Event listeners $("#jsonTraces").click(async () => { var trace = MSC.GetJsonTraces(); $("#jsonTestTraces").text(trace); }); $("#startBt").click(async () => { $("#resultPair").text("Pending..."); var res = await MSC.Pair(false); $("#resultPair").text("Result PAIR(false): " + res); }); $("#startBt2").click(async () => { $("#resultPair").text("Pending..."); var res = await MSC.Pair(true); $("#resultPair").text("Result PAIR(true): " + res); }); $("#stopBt").click(async () => { $("#resultStop").text("Pending..."); var state = await MSC.GetState(); if (state.ready) var stop = await MSC.Execute(new MSC.Command(MSC.CommandType.OFF)); // Stop the meter first var res = await MSC.Stop(); // Then close interface $("#resultStop").text("Result STOP: " + res); }); $("#executeBtn").click(async () => { await addRequest(); }); $("#getState").click(async () => { $("#resultGetState").text("Pending..."); var res = await MSC.GetState(); $("#resultGetState").text("Result GetState: " + res); }); // Called to enable/disable setpoints depending on commands function configureSetpoints(ctype) { // Create a temporary command const command = new MSC.Command(ctype); // Get the default setpoint for this command type const setpoints = command.defaultSetpoint(); switch (Object.keys(setpoints).length) { case 0: $("#new_command_sp").addClass('d-none'); $("#new_command_sp2").addClass('d-none'); $("#setpoint1_desc").addClass('d-none'); $("#setpoint2_desc").addClass('d-none'); $("#setpoint1_desc").text('Setpoint 1'); $("#setpoint2_desc").text('Setpoint 2'); break; case 1: $("#new_command_sp").removeClass('d-none'); $("#new_command_sp2").addClass('d-none'); $("#setpoint1_desc").text(Object.keys(setpoints)[0]); $("#setpoint1_desc").removeClass('d-none'); $("#setpoint2_desc").addClass('d-none'); break; case 2: $("#new_command_sp").removeClass('d-none'); $("#new_command_sp2").removeClass('d-none'); $("#setpoint1_desc").text(Object.keys(setpoints)[0]); $("#setpoint2_desc").text(Object.keys(setpoints)[1]); $("#setpoint1_desc").removeClass('d-none'); $("#setpoint2_desc").removeClass('d-none'); break; default: throw new Error("Not handled:" + setpoints.length); } } $("#new_command_id").change(() => { const value = $("#new_command_id").val(); configureSetpoints(value); }); // Fill the command select items with available commands var select = $("#new_command_id"); for (var i in MSC.CommandType) { // Will enumerate keys // Skip reserved commands var cmd = new MSC.Command(MSC.CommandType[i]); if (!cmd.isValid()) continue; var opt = $("<option>").val(MSC.CommandType[i]).text(i); select.append(opt); } configureSetpoints($("#new_command_id").val()); function dumpArray(arr) { var elem = ""; for (var key in arr) { elem += key + " = " + arr[key] + "<br/>"; } return elem; } async function addRequest() { var type = parseInt($("#new_command_id").val()); var setpoint1 = $("#new_command_sp").val(); var setpoint2 = $("#new_command_sp2").val(); var comm; if ($("#new_command_sp").hasClass('d-none')) { comm = MSC.Command.CreateNoSP(type); } else if ($("#new_command_sp2").hasClass('d-none')) { comm = MSC.Command.CreateOneSP(type, setpoint1); } else { comm = MSC.Command.CreateTwoSP(type, setpoint1, setpoint2); } $("#resultExecute").text("Pending..."); var res = await MSC.Execute(comm); $("#resultExecute").text("Result : " + res); } async function updateStatus() { var mstate = await MSC.GetState(); $("#overall").text("ready:" + mstate.ready + ", initializing:" + mstate.initializing); $("#status").text(mstate.status); $("#sp").html(dumpArray(mstate.lastSetpoint)); $("#meas").html(dumpArray(mstate.lastMeasure)); $("#btinfo").text(mstate.deviceName); $("#serial").text(mstate.deviceSerial); var description = ""; for (let x in MSC.CommandType) { if (MSC.CommandType[x] === mstate.deviceMode) { description = x; break; } } $("#mode").text(mstate.deviceMode + " (" + description + ")"); $("#battery").text(mstate.batteryLevel); $("#stats").html(dumpArray(mstate.stats)); setTimeout(updateStatus, 500); } setTimeout(updateStatus, 500); </script> </body> </html>