diff --git a/README.md b/README.md
index 25aeda550050520c27e9e0c7312d34fe0b2b9538..243403d4ef388883a3e09fbc844d2e7e3958e256 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,8 @@ We strongly recommend users to create a virtual environment to run the code and
 *  you should run you code within the virtual environment
 *  to leave the virtual environment simply type: `deactivate`
 
+To enable to Python module, we need to add the 'ohmpi' folder to the python path. This can be done by `source .env` or manually by adding `export PYTHONPATH=$PYTHONPATH:/home/<username>/OhmPi` to /home/<username>/.bashrc.
+
 ## First run with four electrodes
 
 In the examples folder, you will find the code "simple_measurement.py".
diff --git a/index-mqtt.html b/index-mqtt.html
deleted file mode 100755
index 070d4fe13ea81700590c04d23493fbab8dcb512a..0000000000000000000000000000000000000000
--- a/index-mqtt.html
+++ /dev/null
@@ -1,654 +0,0 @@
-<!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>
-                <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
-        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)
-            }
-            // 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() {
-            // 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'
-            }
-
-        }
-        Plotly.newPlot('gd', [trace], layout)
-
-        // make time-serie plot
-        let tdata = []
-        let layout2 = {
-            title: 'Time-serie',
-            yaxis: {
-                title: 'App. res. [Ohm.m]'
-            },
-            xaxis: {
-                title: 'Sampling time'
-            }
-        }
-        Plotly.newPlot('ts', tdata, layout2)
-
-        // add trace to time-serie plot
-        function addTraceBtnFunc() {
-            let val = document.getElementById('quadSelect').value
-            squads.push(val.split(', '))
-            tdata.push({
-                x: [],
-                y: [],
-                name: val,
-                type: 'scatter'
-            })
-            Plotly.newPlot('ts', tdata, layout2)
-            getData()
-        }
-        let addTraceBtn = document.getElementById('addTraceBtn')
-        addTraceBtn.addEventListener('click', addTraceBtnFunc)
-
-        // remove all traces from time-serie plot
-        function removeTracesBtnFunc() {
-            squads = []
-            tdata = []            
-            Plotly.newPlot('ts', tdata, layout2)
-        }
-        let removeTracesBtn = document.getElementById('removeTracesBtn')
-        removeTracesBtn.addEventListener('click', removeTracesBtnFunc)
-
-        // callback function to draw the plot
-        function surveySelectFunc(el) {
-            let surveyName = el['target'].value
-            let df = data[surveyName]
-            if (df != undefined) {
-                let a = df['a']
-                let b = df['b']
-                let m = df['m']
-                let n = df['n']
-                // let's assume electrodes are 1 m distance
-                // compute pseudo-depth (assume no topo)
-                // compute app res (assumping flat, line survey)
-                let xpos = []
-                let ypos = []
-                let app = []
-                for (let i = 0; i < a.length; i++) {
-                    let ab = (a[i] + b[i])/2
-                    let mn = (m[i] + n[i])/2
-                    let dist = Math.abs(ab - mn)
-                    xpos.push(Math.min(ab, mn) + dist/2)
-                    ypos.push(Math.sqrt(2)/2*dist)
-                    let am = Math.abs(a[i] - m[i])
-                    let bm = Math.abs(b[i] - m[i])
-                    let an = Math.abs(a[i] - n[i])
-                    let bn = Math.abs(a[i] - n[i])
-                    let K = (2*Math.PI)/((1/am)-(1/an)-(1/an)+(1/bn))
-                    app.push(df['rho'][i]*-K)
-                }
-                console.log(app)
-                // update the trace and redraw the figure
-                trace['x'] = xpos
-                trace['y'] = ypos
-                trace['marker']['color'] = app
-                trace['marker']['cmax'] = document.getElementById('cmax').value
-                trace['marker']['cmin'] = document.getElementById('cmin').value
-                Plotly.redraw('gd')
-            }
-        }
-        let surveySelect = document.getElementById('surveySelect')
-
-        // bar chart for contact resistance
-        let rsdata = []
-        let rslayout = {
-            title: 'Contact resistances',
-            yaxis: {
-                title: 'Resistance [kOhm]'
-            },
-            xaxis: {
-                title: 'Consecutive electrodes'
-            }
-        }
-        Plotly.newPlot('rs', rsdata, rslayout)
-        
-        // run RS check
-        function rsBtnFunc() {
-            sendCommand('{"cmd": "rsCheck"}', function (res) {
-                // update the bar plot
-                rsdata.push({
-                x: res['data']['AB'],
-                y: res['data']['res'],
-                name: 'RS',
-                type: 'bar'
-                })
-                Plotly.redraw('rs')
-            })
-        }
-        let rsBtn = document.getElementById('rsBtn')
-        rsBtn.addEventListener('click', rsBtnFunc)
-        
-        // clear RS graph
-        function rsClearBtnFunc() {
-            rsdata = []
-            Plotly.newPlot('rs', rsdata, rslayout)
-        }
-        let rsClearBtn = document.getElementById('rsClearBtn')
-        rsClearBtn.addEventListener('click', rsClearBtnFunc)
-        
-        // getData
-        function getData() {
-            sendCommand(JSON.stringify({
-                'cmd': 'get_data',
-                'survey_names': Object.keys(data).slice(0, -1)
-                // last survey is often partial so we download it again
-            }), console.log('processData(ddic)')
-            )
-        }
-
-        // processData
-        function processData(ddic) {
-            // update status
-            output.innerHTML = 'Status: ' + ddic['status']
-
-            // update data dic with new data
-            data = { // destructuring assignement (magic! :o)
-                ...data,
-                ...ddic['data'] // value from second dic are preferred
-            }
-            
-            // dropdown with number of surveys and +++
-            let surveyNames = Object.keys(data).sort()
-
-            // remove listener as we will replace the choices
-            surveySelect.removeEventListener('change', surveySelectFunc)
-            surveySelect.innerHTML = ''  // clearing all child nodes
-
-            // add choices again
-            for (let surveyName of surveyNames) {
-                let option = document.createElement('option')
-                option.innerText = surveyName
-                option.value = surveyName
-                surveySelect.appendChild(option)
-            }
-
-            // listener again
-            surveySelect.addEventListener('change', surveySelectFunc)
-            
-            // plot last one by default
-            surveySelect.value = surveyNames[surveyNames.length - 1]
-            
-            // call the function directly
-            // (as progammatically chaging the value does not trigger the event)
-            surveySelectFunc({'target': surveySelect})
-
-            // update list of quadrupoles if any
-            if (quads.length == 0) {
-                console.log('updating list of quadrupoles')
-                let df = data[surveyNames[0]]
-                let quadSelect = document.getElementById('quadSelect')
-                quadSelect.innerHTML = ''
-                for (let i = 0; i < df['a'].length; i++) {
-                    quad = [df['a'][i], df['b'][i], df['m'][i], df['n'][i]]
-                    quads.push(quad)
-                    let option = document.createElement('option')
-                    option.value = quad.join(', ')
-                    option.innerText = quad.join(', ')
-                    quadSelect.appendChild(option)
-                }
-                console.log('quads=', quads)
-            }
-
-            // update time-serie figure
-            if (squads.length > 0) {
-
-                // transform all surveyNames to datetime
-                let xt = []
-                for (surveyName of surveyNames) {
-                    let a = surveyName.split('_').slice(-1)[0]
-                    xt.push(a.slice(0, 4) + '-' 
-                        + a.slice(4, 6) + '-' 
-                        + a.slice(6, 8) + ' '
-                        + a.slice(9, 11) + ':'
-                        + a.slice(11, 13) + ':'
-                        + a.slice(13, 15))
-                }
-                //console.log(xt)
-
-                // create one new trace per selected quadrupole
-                for (let k = 0; k < squads.length; k++) {
-                    squad = squads[k]
-                    let x = []
-                    let y = []
-                    for (let i = 0; i < surveyNames.length; i++) {
-                        df = data[surveyNames[i]]
-                        for (let j = 0; j < df['a'].length; j++) {
-                            if (df['a'][j] == squad[0]
-                            && df['b'][j] == squad[1]
-                            && df['m'][j] == squad[2]
-                            && df['n'][j] == squad[3]) {
-                                y.push(df['rho'][j])
-                                x.push(xt[i])
-                                break
-                            }
-                        }
-                    }
-
-                    // update trace dictionnary
-                    tdata[k]['x'] = x
-                    tdata[k]['y'] = y
-                }
-                //console.log(tdata)
-                Plotly.redraw('ts')
-            }
-        }
-
-        let getDataBtn = document.getElementById('getDataBtn')
-        getDataBtn.addEventListener('click', getData)
-        
-        // apply new colorscale
-        let capplyBtn = document.getElementById('capplyBtn')
-        capplyBtn.addEventListener('click', function() {
-            surveySelectFunc({'target': surveySelect})
-        })
-        
-        // checkbox interaction for data download
-        function dataRetrievalCheckFunc(x) {
-            if (x['target'].checked == true) {
-                interv = setInterval(getData, 1000) // every 5s
-            } else {
-                clearInterval(interv)
-            }             
-        }
-        let dataRetrievalCheck = document.getElementById('dataRetrievalCheck')
-        dataRetrievalCheck.addEventListener('change', dataRetrievalCheckFunc)
-
-        // remove data
-        function removeDataBtnFunc() {
-            sendCommand('{"cmd": "removeData"}',function(x) {
-                data = {}
-                output.innerHTML = 'Status: ' + x['status'] + ' (all data cleared)'
-                console.log('all data removed')
-            })
-        }
-        let removeDataBtn = document.getElementById('removeDataBtn')
-        removeDataBtn.addEventListener('click', removeDataBtnFunc)
-
-        // shutdown Pi
-        function shutdownBtnFunc() {
-            sendCommand('{"cmd": "shutdown"}', function(x) {
-                console.log('shuting down...')
-            })
-        }
-        let shutdownBtn = document.getElementById('shutdownBtn')
-        shutdownBtn.addEventListener('click', shutdownBtnFunc)
-        
-        // restart Pi
-        function restartBtnFunc() {
-            sendCommand('{"cmd": "restart"}', function(x) {
-                console.log('rebooting...')
-            })
-        }
-        let restartBtn = document.getElementById('restartBtn')
-        restartBtn.addEventListener('click', restartBtnFunc)
-        
-        // invert data
-        // function invertBtnFunc() {
-        //     sendCommand('{"cmd": "invert"}', function(x) {
-        //         console.log('inversion results', x)
-        //     })
-        // }
-        // let invertBtn = document.getElementById('invertBtn')
-        // invertBtn.addEventListener('click', invertBtnFunc)
-
-        // download data
-        function downloadBtnFunc() {
-            sendCommand('{"cmd": "download"}', function(x) {
-                let dwl = document.getElementById('download')
-                dwl.setAttribute('href', serverUrl + '/data.zip')
-                dwl.setAttribute('download', 'data.zip')
-                dwl.click()
-            })
-        }
-        let downloadBtn = document.getElementById('downloadBtn')
-        downloadBtn.addEventListener('click', downloadBtnFunc)
-
-
-    </script>
-    
-    <!-- Boostrap scripts (at the end of the page for faster loading time)-->
-	<script src="js/bootstrap.bundle.min.js"></script>
-    <!-- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script> -->
-</body>
-</html>
diff --git a/index.html b/index.html
deleted file mode 100644
index b334d18b47d1f8ab64e32028a15fac4c0b513d7e..0000000000000000000000000000000000000000
--- a/index.html
+++ /dev/null
@@ -1,704 +0,0 @@
-<!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> -->
-</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 second
-            </label>
-        </div>
-        <div id='output'>Status: idle</div>
-        
-        <!-- Pseudo section -->
-        <select id='surveySelect' class='custom-select'>
-        </select>
-        <input id="cmin" type="number" value=""/>
-        <input id="cmax" type="number" value=""/>
-        <button id="capplyBtn" type="button" class="btn btn-info">Apply</button>
-        <div id="gd"></div>
-        <div id="hoverinfo" style="margin-left:80px;"></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="getRsBtn" type="button" class="btn btn-info">Get 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 settings -->
-        <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 settings</h5>
-                <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
-        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 elecSpacing = 1 // 1 m
-
-        // useful functions
-        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)
-        }
-
-        // run button
-        function runBtnFunc() {
-            sendCommand('{"cmd": "run_multiple_sequences"}', function(x) {
-                console.log(x['ohmpi_status'])
-                if (x['ohmpi_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['ohmpi_status']
-                clearInterval(interv)
-                getData()
-            })
-        }
-        let stopBtn = document.getElementById('stopBtn')
-        stopBtn.addEventListener('click', stopBtnFunc)
-
-        // set configuration
-        function saveSettingsBtnFunc() {
-            // collect values from modal
-            let formVals = {}
-            formVals['nb_electrodes'] = parseInt(document.getElementById('nbElectrodes').value)
-            formVals['injection_duration'] = parseFloat(document.getElementById('injectionDuration').value)
-            formVals['nb_meas'] = parseInt(document.getElementById('nbMeasurements').value)
-            formVals['sequence_delay'] = parseInt(document.getElementById('sequenceDelay').value)
-            formVals['nb_stack'] = parseInt(document.getElementById('nbStack').value)
-            formVals['elec_spacing'] = parseFloat(document.getElementById('elecSpacing').value)
-            console.log(formVals)
-            elecSpacing = formVals['elec_spacing']
-            
-            // define callback to send settigs to Pi
-            function settingsCallback() {
-                sendCommand(JSON.stringify({
-                    'cmd': 'update_settings',
-                    '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)
-                    settingsCallback()
-                }, false)
-            } else {
-                console.log('no sequence uploaded')
-                formVals['sequence'] = ''
-                settingsCallback()
-            } 
-            
-            
-        }
-        let saveConfigBtn = document.getElementById('saveConfigBtn')
-        saveConfigBtn.addEventListener('click', saveSettingsBtnFunc)
-
-        // make pseudo plot
-        var trace = {}
-        let layout = {}
-        let tdata = []
-        let layout2 = {}
-        let rsdata = []
-        let rslayout = {}
-        
-        // initialize all plots
-        function initPlots() {
-			trace = {
-				x: [],
-				y: [],
-				mode: 'markers',
-				marker: {
-					size: 40,
-					color: [],
-					colorbar: {
-						title: 'App. res. [Ohm.m]',
-						cmin: 0,
-						cmax: 100,
-					}
-				}
-			}
-			layout = {
-				title: 'Pseudo-section',
-				yaxis: {
-					title: 'Pseudo-depth',
-					autorange: 'reversed'
-				},
-				xaxis: {
-					title: 'X'
-				}
-
-			}
-			Plotly.newPlot('gd', [trace], layout)
-
-			// make time-serie plot
-			tdata = []
-			layout2 = {
-				title: 'Time-serie',
-				yaxis: {
-					title: 'App. res. [Ohm.m]'
-				},
-				xaxis: {
-					title: 'Sampling time'
-				}
-			}
-			Plotly.newPlot('ts', tdata, layout2)
-			
-			// bar chart for contact resistance
-			rsdata = []
-			rslayout = {
-				title: 'Contact resistances',
-				yaxis: {
-					title: 'Resistance [kOhm]'
-				},
-				xaxis: {
-					title: 'Consecutive electrodes'
-				}
-			}
-			Plotly.newPlot('rs', rsdata, rslayout)
-		}
-		initPlots()
-
-        // hover function
-        var hoverInfo = document.getElementById('hoverinfo')
-        document.getElementById('gd').on('plotly_hover', function(data){
-            var infotext = data.points.map(function(d){
-              return (Math.round(d.data.marker.color[d.pointIndex], 2) + ' Ohm.m');
-            });
-            hoverInfo.innerHTML = infotext.join('<br/>');
-        })
-         .on('plotly_unhover', function(data){
-            hoverInfo.innerHTML = '';
-        });
-
-        // add trace to time-serie plot
-        function addTraceBtnFunc() {
-            let val = document.getElementById('quadSelect').value
-            squads.push(val.split(', '))
-            tdata.push({
-                x: [],
-                y: [],
-                name: val,
-                type: 'scatter'
-            })
-            Plotly.newPlot('ts', tdata, layout2)
-            getData()
-        }
-        let addTraceBtn = document.getElementById('addTraceBtn')
-        addTraceBtn.addEventListener('click', addTraceBtnFunc)
-
-        // remove all traces from time-serie plot
-        function removeTracesBtnFunc() {
-            squads = []
-            tdata = []            
-            Plotly.newPlot('ts', tdata, layout2)
-        }
-        let removeTracesBtn = document.getElementById('removeTracesBtn')
-        removeTracesBtn.addEventListener('click', removeTracesBtnFunc)
-
-        // callback function to draw the plot
-        function surveySelectFunc(el) {
-            let surveyName = el['target'].value
-            let df = data[surveyName]
-            if (df != undefined) {
-                // let's assume electrodes are 1 m distance
-                // compute pseudo-depth (assume no topo)
-                // compute app res (assumping flat, line survey)
-                let xpos = []
-                let ypos = []
-                let app = []
-                for (let i = 0; i < df['a'].length; i++) {
-                    let a = df['a'][i]
-                    let b = df['b'][i]
-                    let m = df['m'][i]
-                    let n = df['n'][i]
-                    
-                    // compute geometric factor assuming flat 2D surface
-                    let am = Math.abs(a - m)*elecSpacing
-                    let bm = Math.abs(b - m)*elecSpacing
-                    let an = Math.abs(a - n)*elecSpacing
-                    let bn = Math.abs(b - n)*elecSpacing
-                    let K = 2*Math.PI/((1/am)-(1/bm)-(1/an)+(1/bn))
-                    app.push(df['rho'][i]*K)
-                    //console.log(K) // same as resipy for the wenner case
-                
-                    // computing pseudo-depth assuming 2D flat array
-                    // let's sort the electrodes AB are the two left, MN, the two right
-                    let abmn = [a, b, m, n]
-                    abmn = abmn.sort((a, b) => a - b)
-                    let ab = (abmn[0] + abmn[1])/2
-                    let mn = (abmn[2] + abmn[3])/2
-                    let dist = Math.abs(ab - mn)
-                    xpos.push((Math.min(ab, mn) + dist/2)*elecSpacing)
-                    ypos.push((Math.sqrt(2)/2*dist)*elecSpacing)
-                    
-                    /*
-                           lookupDict = dict(zip(self.elec['label'], np.arange(self.elec.shape[0]))) 
-        array = self.df[['a','b','m','n']].replace(lookupDict).values.astype(int)
-        elecm = self.elec[['x','y','z']].values.astype(float).copy() # electrode matrix - should be array of floats so np.inf work properly
-            
-        ### first determine if measurements are nested ###
-        #find mid points of AB 
-        AB = (elecm[array[:,0]] + elecm[array[:,1]]) / 2 # mid points of AB 
-        MN = (elecm[array[:,2]] + elecm[array[:,3]]) / 2 # mid points of MN 
-        ABrad = np.sqrt(np.sum((elecm[array[:,0]] - AB)**2,axis=1)) # radius of AB circle 
-        MNrad = np.sqrt(np.sum((elecm[array[:,2]] - MN)**2,axis=1)) # radius of MN circle 
-        
-        Amn = np.sqrt(np.sum((elecm[array[:,0]] - MN)**2,axis=1)) # distance of A to mid point of MN 
-        Bmn = np.sqrt(np.sum((elecm[array[:,1]] - MN)**2,axis=1)) # distance of B to mid point of MN 
-        Nab = np.sqrt(np.sum((elecm[array[:,2]] - AB)**2,axis=1)) # distance of N to mid point of AB 
-        Mab = np.sqrt(np.sum((elecm[array[:,3]] - AB)**2,axis=1)) # distance of M to mid point of AB
-        
-        iABinMN = (Amn < MNrad) & (Bmn < MNrad)
-        iMNinAB = (Nab < ABrad) & (Mab < ABrad)
-        inested = iABinMN | iMNinAB #if AB encompasses MN or MN encompasses AB 
-                       
-        # so it will never be taken as minimium
-        elecm[self.elec['remote'].values,:] = np.inf
-        
-        # compute midpoint position of AB and MN dipoles
-        elecx = elecm[:,0]
-        elecy = elecm[:,1]
-
-        #CURRENT ELECTRODE MIDPOINTS 
-        caddx = np.abs(elecx[array[:,0]]-elecx[array[:,1]])/2
-        caddy = np.abs(elecy[array[:,0]]-elecy[array[:,1]])/2
-        caddx[np.isinf(caddx)] = 0 
-        caddy[np.isinf(caddy)] = 0        
-        cmiddlex = np.min([elecx[array[:,0]], elecx[array[:,1]]], axis=0) + caddx
-        cmiddley = np.min([elecy[array[:,0]], elecy[array[:,1]]], axis=0) + caddy
-        
-        #POTENTIAL ELECTRODE MIDPOINTS
-        paddx = np.abs(elecx[array[:,2]]-elecx[array[:,3]])/2
-        paddy = np.abs(elecy[array[:,2]]-elecy[array[:,3]])/2
-        paddx[np.isinf(paddx)] = 0 
-        paddy[np.isinf(paddy)] = 0 
-        pmiddlex = np.min([elecx[array[:,2]], elecx[array[:,3]]], axis=0) + paddx
-        pmiddley = np.min([elecy[array[:,2]], elecy[array[:,3]]], axis=0) + paddy
-
-        
-        # for non-nested measurements
-        xposNonNested  = np.min([cmiddlex, pmiddlex], axis=0) + np.abs(cmiddlex-pmiddlex)/2
-        yposNonNested  = np.min([cmiddley, pmiddley], axis=0) + np.abs(cmiddley-pmiddley)/2
-        pcdist = np.sqrt((cmiddlex-pmiddlex)**2 + (cmiddley-pmiddley)**2)
-
-        # zposNonNested = np.sqrt(2)/2*pcdist
-        zposNonNested = pcdist/4
-
-        if np.all(cmiddley-pmiddley == 0):
-            zposNonNested = 0.25*pcdist
-        else: # for 3D arrays where there are mid-line measurements, this works closer to inversion results
-            zposNonNested = np.sqrt(2)/2*pcdist
-        
-        # for nested measurements use formula of Dalhin 2006
-        xposNested = np.zeros(len(pmiddlex))
-        yposNested = np.zeros(len(pmiddlex))
-        outerElec1 = np.zeros((len(pmiddlex), 2)) # position of one electrode of outer dipole
-        outerElec2 = np.zeros((len(pmiddlex), 2)) # position of one electrode of outer dipole
-        # innerMid = np.zeros((len(pmiddlex), 2)) # middle of inner dipole
-        if np.sum(iMNinAB) > 0:
-            xposNested[iMNinAB] = pmiddlex[iMNinAB]
-            yposNested[iMNinAB] = pmiddley[iMNinAB]
-            outerElec1[iMNinAB] = np.c_[elecx[array[iMNinAB,0]], elecy[array[iMNinAB,0]]]
-            outerElec2[iMNinAB] = np.c_[elecx[array[iMNinAB,1]], elecy[array[iMNinAB,1]]]
-
-        if np.sum(iABinMN) > 0:
-            xposNested[iABinMN] = cmiddlex[iABinMN]
-            yposNested[iABinMN] = cmiddley[iABinMN]
-            outerElec1[iABinMN] = np.c_[elecx[array[iABinMN,2]], elecy[array[iABinMN,2]]]
-            outerElec2[iABinMN] = np.c_[elecx[array[iABinMN,3]], elecy[array[iABinMN,3]]]
-      
-        innerMid = np.c_[pmiddlex, pmiddley] # always use potential dipole
-        
-        apdist = np.sqrt(np.sum((outerElec1-innerMid)**2, axis=1))
-        bpdist = np.sqrt(np.sum((outerElec2-innerMid)**2, axis=1))
-        zposNested  = np.min([apdist, bpdist], axis=0)/3
-        
-        xpos = np.zeros_like(pmiddlex)
-        ypos = np.zeros_like(pmiddlex)
-        zpos = np.zeros_like(pmiddlex)
-        
-        xpos[~inested] = xposNonNested[~inested]
-        xpos[inested] = xposNested[inested]
-        
-        ypos[~inested] = yposNonNested[~inested]
-        ypos[inested] = yposNested[inested]
-        
-        zpos[~inested] = zposNonNested[~inested]
-        zpos[inested] = zposNested[inested]
-
-                    */
-                  }
-                //console.log(app)
-                // update the trace and redraw the figure
-                trace['x'] = xpos
-                trace['y'] = ypos
-                trace['marker']['color'] = app
-                trace['marker']['cmax'] = document.getElementById('cmax').value
-                trace['marker']['cmin'] = document.getElementById('cmin').value
-                Plotly.redraw('gd')
-            }
-        }
-        let surveySelect = document.getElementById('surveySelect')
-        
-        // run RS check
-        function rsBtnFunc() {
-            sendCommand('{"cmd": "rsCheck"}', function (a) {})
-        }
-        let rsBtn = document.getElementById('rsBtn')
-        rsBtn.addEventListener('click', rsBtnFunc)
-
-        // get RS check data
-        function getRsBtnFunc() {
-            sendCommand('{"cmd": "getRsCheck"}', function(res) {
-                // update the bar plot
-                rsdata.push({
-                x: res['data']['AB'],
-                y: res['data']['res'],
-                name: 'RS',
-                type: 'bar'
-                })
-                Plotly.redraw('rs')
-            })
-        }
-        let getRsBtn = document.getElementById('getRsBtn')
-        getRsBtn.addEventListener('click', getRsBtnFunc)
-        
-        // clear RS graph
-        function rsClearBtnFunc() {
-            rsdata = []
-            Plotly.newPlot('rs', rsdata, rslayout)
-        }
-        let rsClearBtn = document.getElementById('rsClearBtn')
-        rsClearBtn.addEventListener('click', rsClearBtnFunc)
-        
-        // getData
-        function getData() {
-            let surveyNames = []
-            sendCommand(JSON.stringify({
-                'cmd': 'getData',
-                'surveyNames': surveyNames
-                // last survey is often partial so we download it again
-            }), function(ddic) {
-                // update status
-                //output.innerHTML = 'Status: ' + ddic['status']
-
-                // update data dic with new data
-                data = { // destructuring assignement (magic! :o)
-                    ...data,
-                    ...ddic['data'] // value from second dic are preferred
-                }
-                
-                // dropdown with number of surveys
-                surveyNames = Object.keys(data).sort()
-
-                // remove listener as we will replace the choices
-                surveySelect.removeEventListener('change', surveySelectFunc)
-                surveySelect.innerHTML = ''  // clearing all child nodes
-
-                // add choices again
-                for (let surveyName of surveyNames) {
-                    let option = document.createElement('option')
-                    option.innerText = surveyName
-                    option.value = surveyName
-                    surveySelect.appendChild(option)
-                }
-
-                // listener again
-                surveySelect.addEventListener('change', surveySelectFunc)
-                
-                // plot last one by default
-                surveySelect.value = surveyNames[surveyNames.length - 1]
-                
-                // call the function directly
-                // (as progammatically chaging the value does not trigger the event)
-                surveySelectFunc({'target': surveySelect})
-
-                // update list of quadrupoles if any
-                let idiff = false
-                if (data[surveyNames[0]] != undefined) {
-                    idiff = quads.length != data[surveyNames[0]]['a'].length
-                } 
-                //console.log('idiff=', idiff, quads.length, data[surveyNames[0]]['a'].length)
-                if (((quads.length == 0) | idiff) & (data[surveyNames[0]] != undefined)){
-                    console.log('updating list of quadrupoles')
-                    quads = []
-                    let df = data[surveyNames[0]]
-                    let quadSelect = document.getElementById('quadSelect')
-                    quadSelect.innerHTML = ''
-                    for (let i = 0; i < df['a'].length; i++) {
-                        quad = [df['a'][i], df['b'][i], df['m'][i], df['n'][i]]
-                        quads.push(quad)
-                        let option = document.createElement('option')
-                        option.value = quad.join(', ')
-                        option.innerText = quad.join(', ')
-                        quadSelect.appendChild(option)
-                    }
-                    console.log('quads=', quads)
-                }
-                
-                // update time-serie figure
-                if (squads.length > 0) {
-
-                    // transform all surveyNames to datetime
-                    let xt = []
-                    for (surveyName of surveyNames) {
-                        let a = surveyName.split('_').slice(-1)[0]
-                        xt.push(a.slice(0, 4) + '-' 
-                            + a.slice(4, 6) + '-' 
-                            + a.slice(6, 8) + ' '
-                            + a.slice(9, 11) + ':'
-                            + a.slice(11, 13) + ':'
-                            + a.slice(13, 15))
-                    }
-                    //console.log(xt)
-
-                    // create one new trace per selected quadrupole
-                    for (let k = 0; k < squads.length; k++) {
-                        squad = squads[k]
-                        let x = []
-                        let y = []
-                        for (let i = 0; i < surveyNames.length; i++) {
-                            df = data[surveyNames[i]]
-                            for (let j = 0; j < df['a'].length; j++) {
-                                if (df['a'][j] == squad[0]
-                                && df['b'][j] == squad[1]
-                                && df['m'][j] == squad[2]
-                                && df['n'][j] == squad[3]) {
-                                    y.push(df['rho'][j])
-                                    x.push(xt[i])
-                                    break
-                                }
-                            }
-                        }
-
-                        // update trace dictionnary
-                        tdata[k]['x'] = x
-                        tdata[k]['y'] = y
-                    }
-                    //console.log(tdata)
-                    Plotly.redraw('ts')
-                }
-            })
-        }
-        let getDataBtn = document.getElementById('getDataBtn')
-        getDataBtn.addEventListener('click', getData)
-        
-        // apply new colorscale
-        let capplyBtn = document.getElementById('capplyBtn')
-        capplyBtn.addEventListener('click', function() {
-            surveySelectFunc({'target': surveySelect})
-        })
-
-        // checkbox interaction for data download
-        function dataRetrievalCheckFunc(x) {
-            if (x['target'].checked == true) {
-                interv = setInterval(getData, 1000) // every 5s
-            } else {
-                clearInterval(interv)
-            }             
-        }
-        let dataRetrievalCheck = document.getElementById('dataRetrievalCheck')
-        dataRetrievalCheck.addEventListener('change', dataRetrievalCheckFunc)
-
-        // remove data
-        function removeDataBtnFunc() {
-            sendCommand('{"cmd": "removeData"}',function(x) {
-                data = {}
-                output.innerHTML = 'Status: ' + x['ohmpi_status'] + ' (all data cleared)'
-                console.log('all data removed')
-                initPlots() // reset all plots
-            })
-        }
-        let removeDataBtn = document.getElementById('removeDataBtn')
-        removeDataBtn.addEventListener('click', removeDataBtnFunc)
-
-        // shutdown Pi
-        function shutdownBtnFunc() {
-            sendCommand('{"cmd": "shutdown"}', function(x) {
-                console.log('shuting down...')
-            })
-        }
-        let shutdownBtn = document.getElementById('shutdownBtn')
-        shutdownBtn.addEventListener('click', shutdownBtnFunc)
-        
-        // restart Pi
-        function restartBtnFunc() {
-            sendCommand('{"cmd": "restart"}', function(x) {
-                console.log('rebooting...')
-            })
-        }
-        let restartBtn = document.getElementById('restartBtn')
-        restartBtn.addEventListener('click', restartBtnFunc)
-        
-        // invert data
-        // function invertBtnFunc() {
-        //     sendCommand('{"cmd": "invert"}', function(x) {
-        //         console.log('inversion results', x)
-        //     })
-        // }
-        // let invertBtn = document.getElementById('invertBtn')
-        // invertBtn.addEventListener('click', invertBtnFunc)
-
-        // download data
-        function downloadBtnFunc() {
-            sendCommand('{"cmd": "download"}', function(x) {
-                let dwl = document.getElementById('download')
-                dwl.setAttribute('href', serverUrl + '/data.zip')
-                dwl.setAttribute('download', 'data.zip')
-                dwl.click()
-            })
-        }
-        let downloadBtn = document.getElementById('downloadBtn')
-        downloadBtn.addEventListener('click', downloadBtnFunc)
-
-
-    </script>
-    
-    <!-- Boostrap scripts (at the end of the page for faster loading time)-->
-	<script src="js/bootstrap.bundle.min.js"></script>
-    <!-- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script> -->
-</body>
-</html>
diff --git a/ohmpi/config.py b/ohmpi/config.py
index 8bd970d8096ec3515ced1a1c9d11ea5e2aeabbc7..0763f48ca2240311e01b281a1eea9571c324defd 100644
--- a/ohmpi/config.py
+++ b/ohmpi/config.py
@@ -1,7 +1,7 @@
 import logging
 from ohmpi.utils import get_platform
 
-from paho.mqtt.client import MQTTv31  # noqa
+from paho.mqtt.client import MQTTv31
 
 _, on_pi = get_platform()
 # DEFINE THE ID OF YOUR OhmPi
@@ -18,34 +18,25 @@ OHMPI_CONFIG = {
 }
 
 HARDWARE_CONFIG = {
-    'ctl': {'model': 'raspberry_pi'},
-    'pwr': {'model': 'pwr_batt', 'voltage': 12., 'interface_name': 'none'},
-    'tx':  {'model': 'mb_2023_0_X',
-             'voltage_max': 12.,  # Maximum voltage supported by the TX board [V]
-             'adc_voltage_max': 4800.,  # Maximum voltage read by the current ADC on the TX board [mA]
-             'r_shunt': 2.,  # Shunt resistance in Ohms
-             'interface_name': 'i2c',
+    'ctl': {'model' : 'dummy_ctl'
+                   },
+    'tx' : {'model' : 'dummy_tx',
+             'current_max': 4800 / 50 / 2,  # Maximum current mA
+             'r_shunt': 2,  # Shunt resistance in Ohms
+             'low_battery': 12.  # Volts
             },
-    'rx':  {'model': 'mb_2023_0_X',
-            'coef_p2': 2.50,  # slope for conversion for ADS, measurement in V/V
-            'sampling_rate': 50.,  # number of samples per second
-            'interface_name': 'i2c',
+    'rx' : {'model': 'dummy_rx',
             },
-    'mux':  # default properties given in config are system properties that will be
-            # overwritten by properties defined in each the board dict below.
-            # if defined in board specs, values out of specs will be bounded to remain in specs
-            # omitted properties in config will be set to board specs default values if they exist
-            {'boards': {},
-             'default': {'interface_name': 'i2c',
-                         'voltage_max': 100.,
-                         'current_max': 3.}
-             }
+    'mux': {'model' : 'dummy_mux',
+             'max_elec': 64,
+             'voltage_max' : 100,
+             'current_max' : 3
+            }
 }
-
 # SET THE LOGGING LEVELS, MQTT BROKERS AND MQTT OPTIONS ACCORDING TO YOUR NEEDS
 # Execution logging configuration
 EXEC_LOGGING_CONFIG = {
-    'logging_level': logging.DEBUG,  # TODO: set logging level back to INFO
+    'logging_level': logging.INFO,
     'log_file_logging_level': logging.DEBUG,
     'logging_to_console': True,
     'file_name': f'exec{logging_suffix}.log',
@@ -69,8 +60,8 @@ DATA_LOGGING_CONFIG = {
 # State of Health logging configuration (For a future release)
 SOH_LOGGING_CONFIG = {
     'logging_level': logging.INFO,
-    'logging_to_console': True,
     'log_file_logging_level': logging.DEBUG,
+    'logging_to_console': True,
     'file_name': f'soh{logging_suffix}.log',
     'max_bytes': 16777216,
     'backup_count': 1024,
diff --git a/ohmpi/hardware_system.py b/ohmpi/hardware_system.py
index 8b698406576473dac523e3b0e9dd80e5ead33d08..8af099205b20b6d7b652869f86a73b60c168e2cf 100644
--- a/ohmpi/hardware_system.py
+++ b/ohmpi/hardware_system.py
@@ -167,6 +167,22 @@ class OhmPiHardware:
         self._start_time = None  # time of the beginning of a readings acquisition
         self._pulse = 0  # pulse number
         self.exec_logger.event(f'OhmPiHardware\tinit\tend\t{datetime.datetime.utcnow()}')
+        self._pwr_state = 'off'
+
+    @property
+    def pwr_state(self):
+        return self._pwr_state
+
+    @pwr_state.setter
+    def pwr_state(self, state):
+        if state == 'on':
+            self.tx.pwr_state = 'on'
+            self._pwr_state = 'on'
+            self.exec_logger.debug(f'{self.model} cannot be switched on')
+        elif state == 'off':
+            self.tx.pwr_state = 'off'
+            self._pwr_state = 'off'
+            self.exec_logger.debug(f'{self.model} cannot be switched off')
 
     def _clear_values(self):
         self.readings = np.array([])
@@ -420,8 +436,8 @@ class OhmPiHardware:
                         append=False):
         self.exec_logger.event(f'OhmPiHardware\tvab_square_wave\tbegin\t{datetime.datetime.utcnow()}')
         switch_pwr_off, switch_tx_pwr_off = False, False
-        if self.tx.pwr_state == 'off':
-            self.tx.pwr_state = 'on'
+        if self.pwr_state == 'off':
+            self.pwr_state = 'on'
             switch_tx_pwr_off = True
         # if self.tx.pwr.pwr_state == 'off':
         #     self.tx.pwr.pwr_state = 'on'
@@ -442,7 +458,7 @@ class OhmPiHardware:
         if switch_pwr_off:
             self.tx.pwr.pwr_state = 'off'
         if switch_tx_pwr_off:
-            self.tx.pwr_state = 'off'
+            self.pwr_state = 'off'
 
     def _vab_pulse(self, vab=None, duration=1., sampling_rate=None, polarity=1, append=False):
         """ Gets VMN and IAB from a single voltage pulse
@@ -466,8 +482,8 @@ class OhmPiHardware:
 
     def _vab_pulses(self, vab, durations, sampling_rate, polarities=None, append=False):
         switch_pwr_off, switch_tx_pwr_off = False, False
-        if self.tx.pwr_state == 'off':
-            self.tx.pwr_state = 'on'
+        if self.pwr_state == 'off':
+            self.pwr_state = 'on'
             switch_pwr_off = True
         n_pulses = len(durations)
         self.exec_logger.debug(f'n_pulses: {n_pulses}')
@@ -492,7 +508,8 @@ class OhmPiHardware:
         if switch_pwr_off:
             self.tx.pwr.pwr_state = 'off'
         if switch_tx_pwr_off:
-            self.tx.pwr_state = 'off'
+            self.pwr_state = 'off'
+    
     def switch_mux(self, electrodes, roles=None, state='off', **kwargs):
         """Switches on multiplexer relays for given quadrupole.
 
diff --git a/ohmpi/ohmpi.py b/ohmpi/ohmpi.py
index 8798b9162573632827e48d3226c5076960e79b78..fc70ef7b90f7e25a0758813c794c16d06a7346f5 100644
--- a/ohmpi/ohmpi.py
+++ b/ohmpi/ohmpi.py
@@ -451,6 +451,12 @@ class OhmPi(object):
         cmd_id : str, optional
             Unique command identifier
         """
+        # check pwr is on, if not, let's turn it on
+        switch_power_off = False
+        if self._hw.pwr_state == 'off':
+            self._hw.pwr_state = 'on'
+            switch_power_off = True
+
         self.exec_logger.debug('Starting measurement')
         self.exec_logger.debug('Waiting for data')
 
@@ -532,6 +538,11 @@ class OhmPi(object):
         else:
             self.exec_logger.info(f'Skipping {quad}')
         self.switch_mux_off(quad, cmd_id)
+
+        # if power was off before measurement, let's turn if off
+        if switch_power_off:
+            self._hw.pwr_state = 'off'
+
         return d
 
     def run_multiple_sequences(self, cmd_id=None, sequence_delay=None, nb_meas=None, **kwargs):  # NOTE : could be renamed repeat_sequence
@@ -588,6 +599,8 @@ class OhmPi(object):
         cmd_id : str, optional
             Unique command identifier
         """
+        # switch power on
+        self._hw.pwr_state = 'on'
         self.status = 'running'
         self.exec_logger.debug(f'Status: {self.status}')
         self.exec_logger.debug(f'Measuring sequence: {self.sequence}')
@@ -669,7 +682,7 @@ class OhmPi(object):
             self.append_and_save(filename, acquired_data)
             self.exec_logger.debug(f'quadrupole {i + 1:d}/{n:d}')
 
-        # self.switch_dps('off')
+        self._hw.pwr_state = 'off'
         self.status = 'idle'
 
     def run_sequence_async(self, cmd_id=None, **kwargs):