index-mqtt.html 26.37 KiB
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf8"/>
    <title>OhmPi Acquisition Board</title>
    <link rel="shortcut icon" type="image/jpg" href="logo_ohmpi.jpg"/>
    <!-- dependencies (need to be local as no internet in AP mode)-->
    <script src="js/plotly-basic-2.8.3.min.js"></script>
    <script src="js/jquery-3.4.1.min.js"></script>
    <link type="text/css" href="css/bootstrap.min.css" rel="stylesheet">
	<!-- <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> -->
	<!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous"> -->
    <!-- <script src="js/danfojs/bundle.min.js"></script> -->
    <!-- <script src="js/mqtt.min.js"></script> -->
    <script src="js/paho/paho-mqtt.js"></script>
</head>
<body>
    <div class='container'>
        <h1>OhmPi Acquisition Board</h1>
        <!-- nb stacks, on-time -->
        <button id="update_settingsBtn" type="button" class="btn btn-secondary" data-toggle="modal" data-target="#exampleModal">Settings</button>
        <button id='runBtn' type="button" class="btn btn-primary">&#9654</button>
        <button id='stopBtn' type="button" class="btn btn-warning">&#9724</button>
        <!-- upload button for csv which display the table ABMN -->
        <button id="removeDataBtn" type="button" class="btn btn-danger">Clear data</button>
        <button id="getDataBtn" type="button" class="btn btn-info">Get data</button>
        <div class="form-check">
            <input id="dataRetrievalCheck" class="form-check-input" type="checkbox" value="">
            <label class="form-check-label" for="dataRetrievalCheck">
                Automaticaly get data every 1 secondStart
            </label>
        </div>
        <div id='output'>Status: idle</div>
        <!-- Pseudo section -->
        <select id='surveySelect' class='custom-select'>
        </select>
        <input id="cmin" type="number" value="0"/>
        <input id="cmax" type="number" value="150"/>
        <button id="capplyBtn" type="button" class="btn btn-info">Apply</button>
        <div id="gd"></div>
        <div class="mb3 row">
            <label for="quadSelect">Quadrupole:</label>
            <div class="col-sm-10">
                <select id='quadSelect' class='custom-select'></select>    
            </div>
        </div>
        <!-- trace figure -->
        <button id="addTraceBtn" type="button" class="btn btn-info">Add trace</button>
        <button id="removeTracesBtn" type="button" class="btn btn-info">Remove all traces</button>    
        <div id="ts"></div>
        <!-- RS check -->
        <button id="rsBtn" type="button" class="btn btn-info">Check contact resistance</button>
        <button id="rsClearBtn" type="button" class="btn btn-info">Clear plot</button>
        <div id="rs"></div>
        <!-- Additional buttons -->
        <button id="downloadBtn" type="button" class="btn btn-primary">Download data</button>
        <!-- <button id="invertBtn" type="button" class="btn btn-primary">Invert</button> -->
        <a id="download"></a>
        <!-- Modal for configuration -->
        <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
            <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                <h5 class="modal-title" id="exampleModalLabel">OhmPi configuration</h5>
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">&times;</span> </button> </div> <div class="modal-body"> <form> <div class="form-group row"> <label for="nbElectrodes" class="col-sm-2 col-form-label">Nb electrodes</label> <div class="col-sm-10"> <input type="number" class="form-control-number" id="nbElectrodes" value="64"> </div> </div> <div class="form-group row"> <label for="injectionDuration" class="col-sm-2 col-form-label">Injection duration [s]</label> <div class="col-sm-10"> <input type="number" class="form-control-number" id="injectionDuration" value="0.2"> </div> </div> <div class="form-group row"> <label for="nbMeasurements" class="col-sm-2 col-form-label">Nb Measurements</label> <div class="col-sm-10"> <input type="number" class="form-control-number" id="nbMeasurements" value="1"> </div> </div> <div class="form-group row"> <label for="sequenceDelay" class="col-sm-2 col-form-label">Sequence delay [s]</label> <div class="col-sm-10"> <input type="number" class="form-control-number" id="sequenceDelay" value="100"> </div> </div> <div class="form-group row"> <label for="nbStack" class="col-sm-2 col-form-label">Nb stack</label> <div class="col-sm-10"> <input type="number" class="form-control-number" id="nbStack" value="1"> </div> </div> <div class="form-group row"> <label for="sequence" class="col-sm-2 col-form-label">Sequence</label> <div class="col-sm-10"> <input type="file" class="form-control" id="sequence"> </div> </div> <div class="form-group row"> <label for="elecSpacing" class="col-sm-2 col-form-label">Electrode spacing [m]</label> <div class="col-sm-10"> <input type="number" class="form-control" id="elecSpacing", value="1"> </div> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> <button id="saveConfigBtn" type="button" data-dismiss="modal" class="btn btn-primary">Save</button> </div> </div> </div> </div> <button id="restartBtn" type="button" class="btn btn-danger">Restart</button> <button id="shutdownBtn" type="button" class="btn btn-danger">Shutdown</button> <footer>v0.2.0</footer> </div> <script type="text/javascript"> //let serverUrl = 'http://10.3.141.1:8080' //let serverUrl = 'http://0.0.0.0:8080' //let serverUrl = 'http://localhost:8080' let serverUrl = 'http://' + window.location.host console.log('serverUrl =', serverUrl) let output = document.getElementById('output') let data = {} // hold data of all surveys
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
let interv = null // hold interval for automatic data retrieval let quads = [] // available quadrupoles for time-serie figure let squads = [] // selected quadrupoles for time-serie figure let commands = {} // store commands and their id let callbacks = {} // store callback (might not be needed) // function with MQTT let topic = 'ohmpi_0001' // we could change this through a drop-down to connect to a different ohmpi let topic_ctrl = topic + '/ctrl' let topic_exec = topic + '/exec' let topic_data = topic + '/data' let hostname = location.hostname let port = 9001 let clientId = 'ohmpi_0001_html' let message = null let msg = '' // create client client = new Paho.MQTT.Client(hostname, port, clientId); client.onConnectionLost = onConnectionLost; client.onMessageArrived = onMessageArrived; client.connect({onSuccess:onConnect}); function onConnect() { console.log("onConnect") client.subscribe(topic_data) client.subscribe(topic_exec) // send welcome message message = new Paho.MQTT.Message("Hello from index.html") message.destinationName = topic_ctrl client.send(message) } function onConnectionLost(responseObject) { if (responseObject.errorCode !== 0) console.log("onConnectionLost:" + responseObject.errorMessage) } function onMessageArrived(message) { console.log("onMessageArrived:" + message.payloadString) try { let payload = message.payloadString if (message.topic == topic_data) { // process data msg = payload // for accessing the variable from the console console.log('DATA', payload) let ddic = JSON.parse(payload.split('INFO:')[1]) // check cmd_id is any processData(ddic) // usually these don't have a cmd_id so we are not sure when } else if (message.topic == topic_exec) { // display it in the log console.log('EXEC LOG:', payload) } // let response = JSON.parse(message.payloadString) // console.log('response=', response) // // check ID of message against our dictionnary of callback // let cmd_id = response['cmd_id'] // if (callbacks.hasOwnProperty(cmd_id)) { // console.log('++ execute callback') // callbacks[cmd_id](response['content']) // execute callback // } } catch (e) { console.log(e) }
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
// client.disconnect() } // useful functions function generateUniqSerial() { return 'xxxx-xxxx-xxx-xxxx'.replace(/[x]/g, (c) => { const r = Math.floor(Math.random() * 16); return r.toString(16); }); } // sending commands to the OhmPi function sendCommand(query, callback=null) { // dic in the form: {'cmd': X, ...} as JSON if (callback == null) { function callback(x) { console.log('default callback:', x) } } /* let xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState == 4) { if (xhr.status == 200) { callback(JSON.parse(xhr.response)) } } } xhr.open('POST', serverUrl) xhr.setRequestHeader('Content-Type', 'application/json') xhr.send(query) */ // generate a unique command id to be associated with the commands let uuid = generateUniqSerial() commands[uuid] = query callbacks[uuid] = callback // store the callback to be processed later when message arrives let payload = '{"cmd_id": "' + uuid + '",' + query.slice(1) console.log('sendCommand()', payload) message = new Paho.MQTT.Message(payload) message.destinationName = topic_ctrl client.send(message) } // run button function runBtnFunc() { sendCommand('{"cmd": "run_multiple_sequences"}', function(x) { console.log(x['status']) if (x['status'] == 'running') { output.innerHTML = 'Status: measuring...' } }) } let runBtn = document.getElementById('runBtn') runBtn.addEventListener('click', runBtnFunc) // interrupt button function stopBtnFunc() { sendCommand('{"cmd": "interrupt"}', function(x) { output.innerHTML = 'Status: ' + x['status'] clearInterval(interv) getData() }) } let stopBtn = document.getElementById('stopBtn') stopBtn.addEventListener('click', stopBtnFunc) // set configuration function saveConfigBtnFunc() {
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
// collect values from modal let formVals = {} for (let field of ['nbElectrodes', 'injectionDuration', 'nbMeasurements', 'sequenceDelay', 'nbStack']) { formVals[field] = document.getElementById(field).value } console.log(formVals) // define callback to send settings to Pi function configCallback() { sendCommand(JSON.stringify({ 'cmd': 'update_settings', 'kwargs': { 'config': formVals } }), function(x) { console.log('update_settings', x) }) } // deal with the potential file containing the sequence // https://stackoverflow.com/questions/19038919/is-it-possible-to-upload-a-text-file-to-input-in-html-js if (!window.FileReader) { alert('Your browser is not supported'); return false; } let input = document.getElementById('sequence') if (input.files.length) { const reader = new FileReader() reader.readAsText(input.files[0]) reader.addEventListener('load', () => { formVals['sequence'] = reader.result console.log('file==', reader.result) configCallback() }, false) } else { console.log('no sequence uploaded') formVals['sequence'] = '' configCallback() } } let saveConfigBtn = document.getElementById('saveConfigBtn') saveConfigBtn.addEventListener('click', saveConfigBtnFunc) // make pseudo plot var trace = { x: [], y: [], mode: 'markers', marker: { size: 40, color: [], colorbar: { title: 'App. res. [Ohm.m]', cmin: 0, cmax: 100, } } } let layout = { title: 'Pseudo-section', yaxis: { title: 'Pseudo-depth', autorange: 'reversed' }, xaxis: { title: 'X' }