Commit 9f3b92dc authored by remi.clement@inrae.fr's avatar remi.clement@inrae.fr
Browse files

big merge

Showing with 599 additions and 12852 deletions
+599 -12852
# OhmPi # OhmPi
Development of a low-cost multi-electrodes resistivimeter for electrical resistivity mesaurement for lab applications, based on raspberry board Development of a low-cost multi-electrodes resistivity meter for electrical resistivity mesaurement for lab applications, based on raspberry board
## Installation ## Installation
......
import logging
from paho.mqtt.client import MQTTv31 from paho.mqtt.client import MQTTv31
# OhmPi configuration # OhmPi configuration
...@@ -12,15 +14,21 @@ OHMPI_CONFIG = { ...@@ -12,15 +14,21 @@ OHMPI_CONFIG = {
'integer': 2, # Max value 10 # TODO: Explain what this is... 'integer': 2, # Max value 10 # TODO: Explain what this is...
'version': 2, 'version': 2,
'max_elec': 64, 'max_elec': 64,
'board_address': {'A': 0x72, 'B': 0x73, 'M': 0x70, 'N': 0x71} # def. {'A': 0x76, 'B': 0x71, 'M': 0x74, 'N': 0x70} 'board_address': {'A': 0x72, 'B': 0x73, 'M': 0x70, 'N': 0x71}, # def. {'A': 0x76, 'B': 0x71, 'M': 0x74, 'N': 0x70}
#'board_address': {'A': 0x76, 'B': 0x71, 'M': 0x74, 'N': 0x70} # def. {'A': 0x76, 'B': 0x71, 'M': 0x74, 'N': 0x70} #'board_address': {'A': 0x70, 'B': 0x71, 'M': 0x72, 'N': 0x73}, # def. {'A': 0x76, 'B': 0x71, 'M': 0x74, 'N': 0x70}
} 'settings': 'ohmpi_settings.json',
'board_version': '22.11',
} # TODO: add a dictionary with INA models and associated gain values
CONTROL_CONFIG = {
'tcp_port': 5555,
'interface': 'http_interface.py' # 'mqtt_interface'
}
# Execution logging configuration # Execution logging configuration
EXEC_LOGGING_CONFIG = { EXEC_LOGGING_CONFIG = {
'debug_mode': True, 'logging_level': logging.DEBUG,
'logging_to_console': False, 'logging_to_console': True,
'file_name': 'ohmpi_log', 'file_name': 'exec.log',
'max_bytes': 262144, 'max_bytes': 262144,
'backup_count': 30, 'backup_count': 30,
'when': 'd', 'when': 'd',
...@@ -29,8 +37,9 @@ EXEC_LOGGING_CONFIG = { ...@@ -29,8 +37,9 @@ EXEC_LOGGING_CONFIG = {
# Data logging configuration # Data logging configuration
DATA_LOGGING_CONFIG = { DATA_LOGGING_CONFIG = {
'file_name': 'data_log', 'logging_level': logging.INFO,
'logging_to_console': False, 'logging_to_console': True,
'file_name': 'data.log',
'max_bytes': 16777216, 'max_bytes': 16777216,
'backup_count': 1024, 'backup_count': 1024,
'when': 'd', 'when': 'd',
...@@ -39,7 +48,7 @@ DATA_LOGGING_CONFIG = { ...@@ -39,7 +48,7 @@ DATA_LOGGING_CONFIG = {
# State of Health logging configuration # State of Health logging configuration
SOH_LOGGING_CONFIG = { SOH_LOGGING_CONFIG = {
'file_name': 'soh_log', 'file_name': 'soh.log',
'logging_to_console': True, 'logging_to_console': True,
'max_bytes': 16777216, 'max_bytes': 16777216,
'backup_count': 1024, 'backup_count': 1024,
...@@ -49,35 +58,34 @@ SOH_LOGGING_CONFIG = { ...@@ -49,35 +58,34 @@ SOH_LOGGING_CONFIG = {
# MQTT logging configuration parameters # MQTT logging configuration parameters
MQTT_LOGGING_CONFIG = { MQTT_LOGGING_CONFIG = {
'hostname': 'raspberrypi.local', 'hostname':'ohmpy.umons.ac.be',
'port': 1883, 'port': 1883,
'qos': 0, 'qos': 2,
'retain': False, 'retain': False,
'keepalive': 60, 'keepalive': 60,
'will': None, 'will': None,
'auth': None, 'auth': { 'username': 'mqtt_user', 'password': 'mqtt_password' },
'tls': None, 'tls': None,
'protocol': MQTTv31, 'protocol': MQTTv31,
'transport': 'tcp', 'transport': 'tcp',
'client_id': f'ohmpi_sn_{OHMPI_CONFIG["id"]}', 'client_id': f'{OHMPI_CONFIG["id"]}',
'ctrl_topic': f'ctrl_ohmpi_sn_{OHMPI_CONFIG["id"]}', 'exec_topic': f'ohmpi_{OHMPI_CONFIG["id"]}/exec',
'exec_topic': f'exec_ohmpi_sn_{OHMPI_CONFIG["id"]}', 'data_topic': f'ohmpi_{OHMPI_CONFIG["id"]}/data',
'data_topic': f'data_ohmpi_sn_{OHMPI_CONFIG["id"]}', 'soh_topic': f'ohmpi_{OHMPI_CONFIG["id"]}/soh'
'soh_topic': f'soh_ohmpi_sn_{OHMPI_CONFIG["id"]}'
} }
# MQTT command configuration parameters # MQTT control configuration parameters
MQTT_CONTROL_CONFIG = { MQTT_CONTROL_CONFIG = {
'hostname': 'ohmpy.umons.ac.be', 'hostname': 'ohmpy.umons.ac.be',
'port': 1883, 'port': 1883,
'qos': 0, 'qos': 2,
'retain': False, 'retain': False,
'keepalive': 60, 'keepalive': 60,
'will': None, 'will': None,
'auth': None, 'auth': { 'username': 'mqtt_user', 'password': 'mqtt_password' },
'tls': None, 'tls': None,
'protocol': MQTTv31, 'protocol': MQTTv31,
'transport': 'tcp', 'transport': 'tcp',
'client_id': f'ohmpi_sn_{OHMPI_CONFIG["id"]}', 'client_id': f'{OHMPI_CONFIG["id"]}',
'cmd_topic': f'cmd_ohmpi_sn_{OHMPI_CONFIG["id"]}' 'ctrl_topic': f'ohmpi_{OHMPI_CONFIG["id"]}/ctrl'
} }
...@@ -29,7 +29,7 @@ OhmPi project ...@@ -29,7 +29,7 @@ OhmPi project
+----------------------------------+-----------------------------------+-------------------------------+ +----------------------------------+-----------------------------------+-------------------------------+
| .. image:: logo_inrae.jpg | .. image:: logo_univ_gustave.png | .. image:: logo_ilvo.png | | .. image:: logo_inrae.jpg | .. image:: logo_univ_gustave.png | .. image:: logo_ilvo.png |
+----------------------------------+-----------------------------------+-------------------------------+ +----------------------------------+-----------------------------------+-------------------------------+
| .. image:: logo_univ_mons.png | .. image:: ige.png | | | .. image:: logo_univ_mons.png | .. image:: ige.png | .. image:: logo-iris.jpg |
+----------------------------------+-----------------------------------+-------------------------------+ +----------------------------------+-----------------------------------+-------------------------------+
...@@ -66,4 +66,4 @@ to the near surface scientific community. ...@@ -66,4 +66,4 @@ to the near surface scientific community.
.. note:: .. note::
Everyone willing to get involved is welcome in OhmPi Project!. Everyone willing to get involved is welcome in OhmPi Project!.
\ No newline at end of file
doc/source/Ohmpi_V2_00/step_n_2/a/schema_measurement_board.jpg

1 MB

...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
<div class='container'> <div class='container'>
<h1>OhmPi Acquisition Board</h1> <h1>OhmPi Acquisition Board</h1>
<!-- nb stacks, on-time --> <!-- nb stacks, on-time -->
<button id="setConfigBtn" type="button" class="btn btn-secondary" data-toggle="modal" data-target="#exampleModal">Settings</button> <button id="update_settingsBtn" type="button" class="btn btn-secondary" data-toggle="modal" data-target="#exampleModal">Settings</button>
<button id='startBtn' type="button" class="btn btn-primary">Start</button> <button id='startBtn' type="button" class="btn btn-primary">Start</button>
<button id='stopBtn' type="button" class="btn btn-warning">Stop</button> <button id='stopBtn' type="button" class="btn btn-warning">Stop</button>
<!-- upload button for csv which display the table ABMN --> <!-- upload button for csv which display the table ABMN -->
...@@ -113,7 +113,7 @@ ...@@ -113,7 +113,7 @@
<div class="col-sm-10"> <div class="col-sm-10">
<input type="number" class="form-control" id="elecSpacing", value="1"> <input type="number" class="form-control" id="elecSpacing", value="1">
</div> </div>
</div> </div>
</form> </form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
...@@ -139,11 +139,10 @@ ...@@ -139,11 +139,10 @@
let interv = null // hold interval for automatic data retrieval let interv = null // hold interval for automatic data retrieval
let quads = [] // available quadrupoles for time-serie figure let quads = [] // available quadrupoles for time-serie figure
let squads = [] // selected quadrupoles for time-serie figure let squads = [] // selected quadrupoles for time-serie figure
let elecSpacing = 1 // m
// useful functions // useful functions
function sendCommand(query, callback=null) { function sendCommand(query, callback=null) {
// dic in the form: {'command': X, ...} as JSON // dic in the form: {'cmd': X, ...} as JSON
if (callback == null) { if (callback == null) {
function callback(x) { function callback(x) {
console.log('default callback:', x) console.log('default callback:', x)
...@@ -160,12 +159,11 @@ ...@@ -160,12 +159,11 @@
xhr.open('POST', serverUrl) xhr.open('POST', serverUrl)
xhr.setRequestHeader('Content-Type', 'application/json') xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(query) xhr.send(query)
console.log('sendCommand:', query)
} }
// start button // start button
function startBtnFunc() { function startBtnFunc() {
sendCommand('{"command": "start"}', function(x) { sendCommand('{"cmd": "start"}', function(x) {
console.log(x['status']) console.log(x['status'])
if (x['status'] == 'running') { if (x['status'] == 'running') {
output.innerHTML = 'Status: measuring...' output.innerHTML = 'Status: measuring...'
...@@ -177,10 +175,9 @@ ...@@ -177,10 +175,9 @@
// stop button // stop button
function stopBtnFunc() { function stopBtnFunc() {
sendCommand('{"command": "stop"}', function(x) { sendCommand('{"cmd": "stop"}', function(x) {
output.innerHTML = 'Status: ' + x['status'] output.innerHTML = 'Status: ' + x['status']
clearInterval(interv) clearInterval(interv)
document.getElementById('dataRetrievalCheck').checked = false
getData() getData()
}) })
} }
...@@ -192,19 +189,18 @@ ...@@ -192,19 +189,18 @@
// collect values from modal // collect values from modal
let formVals = {} let formVals = {}
for (let field of ['nbElectrodes', 'injectionDuration', for (let field of ['nbElectrodes', 'injectionDuration',
'nbMeasurements', 'sequenceDelay', 'nbStack', 'elecSpacing']) { 'nbMeasurements', 'sequenceDelay', 'nbStack']) {
formVals[field] = document.getElementById(field).value formVals[field] = document.getElementById(field).value
} }
console.log(formVals) console.log(formVals)
elecSpacing = formVals['elecSpacing']
// define callback to send settigs to Pi // define callback to send settigs to Pi
function configCallback() { function configCallback() {
sendCommand(JSON.stringify({ sendCommand(JSON.stringify({
'command': 'setConfig', 'cmd': 'update_settings',
'config': formVals 'config': formVals
}), function(x) { }), function(x) {
console.log('setconfig:', x) console.log('update_settings', x)
}) })
} }
...@@ -235,69 +231,45 @@ ...@@ -235,69 +231,45 @@
saveConfigBtn.addEventListener('click', saveConfigBtnFunc) saveConfigBtn.addEventListener('click', saveConfigBtnFunc)
// make pseudo plot // make pseudo plot
var trace = {} var trace = {
let layout = {} x: [],
let tdata = [] y: [],
let layout2 = {} mode: 'markers',
let rsdata = [] marker: {
let rslayout = {} size: 40,
color: [],
// initialize all plots colorbar: {
function initPlots() { title: 'App. res. [Ohm.m]',
trace = { cmin: 0,
x: [], cmax: 100,
y: [], }
mode: 'markers', }
marker: { }
size: 40, let layout = {
color: [], title: 'Pseudo-section',
colorbar: { yaxis: {
title: 'App. res. [Ohm.m]', title: 'Pseudo-depth',
cmin: 0, autorange: 'reversed'
cmax: 100, },
} xaxis: {
} title: 'X'
} }
layout = {
title: 'Pseudo-section',
yaxis: {
title: 'Pseudo-depth',
autorange: 'reversed'
},
xaxis: {
title: 'X'
}
} }
Plotly.newPlot('gd', [trace], layout) Plotly.newPlot('gd', [trace], layout)
// make time-serie plot // make time-serie plot
tdata = [] let tdata = []
layout2 = { let layout2 = {
title: 'Time-serie', title: 'Time-serie',
yaxis: { yaxis: {
title: 'App. res. [Ohm.m]' title: 'App. res. [Ohm.m]'
}, },
xaxis: { xaxis: {
title: 'Sampling time' title: 'Sampling time'
} }
} }
Plotly.newPlot('ts', tdata, layout2) 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()
// add trace to time-serie plot // add trace to time-serie plot
function addTraceBtnFunc() { function addTraceBtnFunc() {
...@@ -329,36 +301,28 @@ ...@@ -329,36 +301,28 @@
let surveyName = el['target'].value let surveyName = el['target'].value
let df = data[surveyName] let df = data[surveyName]
if (df != undefined) { 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 // let's assume electrodes are 1 m distance
// compute pseudo-depth (assume no topo) // compute pseudo-depth (assume no topo)
// compute app res (assumping flat, line survey) // compute app res (assumping flat, line survey)
let xpos = [] let xpos = []
let ypos = [] let ypos = []
let app = [] let app = []
for (let i = 0; i < df['a'].length; i++) { for (let i = 0; i < a.length; i++) {
let a = df['a'][i] let ab = (a[i] + b[i])/2
let b = df['b'][i] let mn = (m[i] + n[i])/2
let m = df['m'][i]
let n = df['n'][i]
// let's sort the electrodes AB are the two left, MN, the two right
// TODO not sure this is correct, resipy code is much more complex here
let abmn = [a, b, m, n]
abmn = abmn.sort((a, b) => a - b)
a = abmn[0]
b = abmn[1]
m = abmn[2]
n = abmn[3]
let ab = (a + b)/2
let mn = (m + n)/2
let dist = Math.abs(ab - mn) let dist = Math.abs(ab - mn)
xpos.push((Math.min(ab, mn) + dist/2)*elecSpacing) xpos.push(Math.min(ab, mn) + dist/2)
ypos.push((Math.sqrt(2)/2*dist)*elecSpacing) ypos.push(Math.sqrt(2)/2*dist)
let am = Math.abs(a - m)*elecSpacing let am = Math.abs(a[i] - m[i])
let bm = Math.abs(b - m)*elecSpacing let bm = Math.abs(b[i] - m[i])
let an = Math.abs(a - n)*elecSpacing let an = Math.abs(a[i] - n[i])
let bn = Math.abs(a - n)*elecSpacing let bn = Math.abs(a[i] - n[i])
let K = (2*Math.PI)/((1/am)-(1/an)-(1/an)+(1/bn)) let K = (2*Math.PI)/((1/am)-(1/an)-(1/an)+(1/bn))
app.push(df['rho'][i]*K) app.push(df['rho'][i]*-K)
} }
console.log(app) console.log(app)
// update the trace and redraw the figure // update the trace and redraw the figure
...@@ -372,10 +336,22 @@ ...@@ -372,10 +336,22 @@
} }
let surveySelect = document.getElementById('surveySelect') 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 // run RS check
function rsBtnFunc() { function rsBtnFunc() {
sendCommand('{"command": "rsCheck"}', function (res) { sendCommand('{"cmd": "rsCheck"}', function (res) {
// update the bar plot // update the bar plot
rsdata.push({ rsdata.push({
x: res['data']['AB'], x: res['data']['AB'],
...@@ -400,7 +376,7 @@ ...@@ -400,7 +376,7 @@
// getData // getData
function getData() { function getData() {
sendCommand(JSON.stringify({ sendCommand(JSON.stringify({
'command': 'getData', 'cmd': 'getData',
'surveyNames': Object.keys(data).slice(0, -1) 'surveyNames': Object.keys(data).slice(0, -1)
// last survey is often partial so we download it again // last survey is often partial so we download it again
}), function(ddic) { }), function(ddic) {
...@@ -439,14 +415,8 @@ ...@@ -439,14 +415,8 @@
surveySelectFunc({'target': surveySelect}) surveySelectFunc({'target': surveySelect})
// update list of quadrupoles if any // update list of quadrupoles if any
let idiff = false if (quads.length == 0) {
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') console.log('updating list of quadrupoles')
quads = []
let df = data[surveyNames[0]] let df = data[surveyNames[0]]
let quadSelect = document.getElementById('quadSelect') let quadSelect = document.getElementById('quadSelect')
quadSelect.innerHTML = '' quadSelect.innerHTML = ''
...@@ -517,22 +487,20 @@ ...@@ -517,22 +487,20 @@
// checkbox interaction for data download // checkbox interaction for data download
function dataRetrievalCheckFunc(x) { function dataRetrievalCheckFunc(x) {
if (x['target'].checked == true) { if (x['target'].checked == true) {
interv = setInterval(getData, 1000) // every 1s interv = setInterval(getData, 1000) // every 5s
} else { } else {
clearInterval(interv) clearInterval(interv)
} }
} }
let dataRetrievalCheck = document.getElementById('dataRetrievalCheck') let dataRetrievalCheck = document.getElementById('dataRetrievalCheck')
dataRetrievalCheck.addEventListener('change', dataRetrievalCheckFunc) dataRetrievalCheck.addEventListener('change', dataRetrievalCheckFunc)
// remove data // remove data
function removeDataBtnFunc() { function removeDataBtnFunc() {
sendCommand('{"command": "removeData"}',function(x) { sendCommand('{"cmd": "removeData"}',function(x) {
data = {} data = {}
output.innerHTML = 'Status: ' + x['status'] + ' (all data cleared)' output.innerHTML = 'Status: ' + x['status'] + ' (all data cleared)'
console.log('all data removed') console.log('all data removed')
initPlots() // reset all plots
}) })
} }
let removeDataBtn = document.getElementById('removeDataBtn') let removeDataBtn = document.getElementById('removeDataBtn')
...@@ -540,7 +508,7 @@ ...@@ -540,7 +508,7 @@
// shutdown Pi // shutdown Pi
function shutdownBtnFunc() { function shutdownBtnFunc() {
sendCommand('{"command": "shutdown"}', function(x) { sendCommand('{"cmd": "shutdown"}', function(x) {
console.log('shuting down...') console.log('shuting down...')
}) })
} }
...@@ -549,7 +517,7 @@ ...@@ -549,7 +517,7 @@
// restart Pi // restart Pi
function restartBtnFunc() { function restartBtnFunc() {
sendCommand('{"command": "restart"}', function(x) { sendCommand('{"cmd": "restart"}', function(x) {
console.log('rebooting...') console.log('rebooting...')
}) })
} }
...@@ -558,7 +526,7 @@ ...@@ -558,7 +526,7 @@
// invert data // invert data
// function invertBtnFunc() { // function invertBtnFunc() {
// sendCommand('{"command": "invert"}', function(x) { // sendCommand('{"cmd": "invert"}', function(x) {
// console.log('inversion results', x) // console.log('inversion results', x)
// }) // })
// } // }
...@@ -567,7 +535,7 @@ ...@@ -567,7 +535,7 @@
// download data // download data
function downloadBtnFunc() { function downloadBtnFunc() {
sendCommand('{"command": "download"}', function(x) { sendCommand('{"cmd": "download"}', function(x) {
let dwl = document.getElementById('download') let dwl = document.getElementById('download')
dwl.setAttribute('href', serverUrl + '/data.zip') dwl.setAttribute('href', serverUrl + '/data.zip')
dwl.setAttribute('download', 'data.zip') dwl.setAttribute('download', 'data.zip')
......
import json import json
from config import EXEC_LOGGING_CONFIG, DATA_LOGGING_CONFIG, MQTT_LOGGING_CONFIG from config import EXEC_LOGGING_CONFIG, DATA_LOGGING_CONFIG, MQTT_LOGGING_CONFIG, MQTT_CONTROL_CONFIG
from os import path, mkdir, statvfs from os import path, mkdir, statvfs
from time import gmtime from time import gmtime
import logging import logging
from mqtt_logger import MQTTHandler from mqtt_logger import MQTTHandler
from compressed_sized_timed_rotating_logger import CompressedSizedTimedRotatingFileHandler from compressed_sized_timed_rotating_logger import CompressedSizedTimedRotatingFileHandler
import sys
def setup_loggers(mqtt=True): def setup_loggers(mqtt=True):
...@@ -12,7 +13,7 @@ def setup_loggers(mqtt=True): ...@@ -12,7 +13,7 @@ def setup_loggers(mqtt=True):
log_path = path.join(path.dirname(__file__), 'logs') log_path = path.join(path.dirname(__file__), 'logs')
if not path.isdir(log_path): if not path.isdir(log_path):
mkdir(log_path) mkdir(log_path)
exec_log_filename = path.join(log_path, 'msg_log') exec_log_filename = path.join(log_path, EXEC_LOGGING_CONFIG['file_name'])
exec_logger = logging.getLogger('exec_logger') exec_logger = logging.getLogger('exec_logger')
# SOH logging setup # SOH logging setup
...@@ -23,16 +24,9 @@ def setup_loggers(mqtt=True): ...@@ -23,16 +24,9 @@ def setup_loggers(mqtt=True):
data_path = path.join(base_path, 'data') data_path = path.join(base_path, 'data')
if not path.isdir(data_path): if not path.isdir(data_path):
mkdir(data_path) mkdir(data_path)
data_log_filename = path.join(data_path, 'data_log') data_log_filename = path.join(data_path, DATA_LOGGING_CONFIG['file_name'])
data_logger = logging.getLogger('data_logger') data_logger = logging.getLogger('data_logger')
# Debug and logging
debug = EXEC_LOGGING_CONFIG['debug_mode']
if debug:
logging_level = logging.DEBUG
else:
logging_level = logging.INFO
# Set message logging format and level # Set message logging format and level
log_format = '%(asctime)-15s | %(process)d | %(levelname)s: %(message)s' log_format = '%(asctime)-15s | %(process)d | %(levelname)s: %(message)s'
logging_to_console = EXEC_LOGGING_CONFIG['logging_to_console'] logging_to_console = EXEC_LOGGING_CONFIG['logging_to_console']
...@@ -46,15 +40,27 @@ def setup_loggers(mqtt=True): ...@@ -46,15 +40,27 @@ def setup_loggers(mqtt=True):
exec_formatter.datefmt = '%Y/%m/%d %H:%M:%S UTC' exec_formatter.datefmt = '%Y/%m/%d %H:%M:%S UTC'
exec_handler.setFormatter(exec_formatter) exec_handler.setFormatter(exec_formatter)
exec_logger.addHandler(exec_handler) exec_logger.addHandler(exec_handler)
exec_logger.setLevel(logging_level) exec_logger.setLevel(EXEC_LOGGING_CONFIG['logging_level'])
if logging_to_console: if logging_to_console:
exec_logger.addHandler(logging.StreamHandler()) print(f'logging exec ? {logging_to_console}') # TODO: delete this line
console_exec_handler = logging.StreamHandler(sys.stdout)
console_exec_handler.setLevel(EXEC_LOGGING_CONFIG['logging_level'])
console_exec_handler.setFormatter(exec_formatter)
exec_logger.addHandler(console_exec_handler)
if mqtt: if mqtt:
mqtt_msg_handler = MQTTHandler(MQTT_LOGGING_CONFIG['hostname'], MQTT_LOGGING_CONFIG['exec_topic']) mqtt_settings = MQTT_LOGGING_CONFIG.copy()
mqtt_msg_handler.setLevel(logging_level) [mqtt_settings.pop(i) for i in ['client_id', 'exec_topic', 'data_topic', 'soh_topic']]
mqtt_msg_handler.setFormatter(exec_formatter) mqtt_settings.update({'topic':MQTT_LOGGING_CONFIG['exec_topic']})
exec_logger.addHandler(mqtt_msg_handler) # TODO: handle the case of MQTT broker down or temporarily unavailable
try:
mqtt_exec_handler = MQTTHandler(**mqtt_settings)
mqtt_exec_handler.setLevel(EXEC_LOGGING_CONFIG['logging_level'])
mqtt_exec_handler.setFormatter(exec_formatter)
exec_logger.addHandler(mqtt_exec_handler)
except:
mqtt = False
# Set data logging format and level # Set data logging format and level
log_format = '%(asctime)-15s | %(process)d | %(levelname)s: %(message)s' log_format = '%(asctime)-15s | %(process)d | %(levelname)s: %(message)s'
...@@ -70,25 +76,32 @@ def setup_loggers(mqtt=True): ...@@ -70,25 +76,32 @@ def setup_loggers(mqtt=True):
data_formatter.datefmt = '%Y/%m/%d %H:%M:%S UTC' data_formatter.datefmt = '%Y/%m/%d %H:%M:%S UTC'
data_handler.setFormatter(exec_formatter) data_handler.setFormatter(exec_formatter)
data_logger.addHandler(data_handler) data_logger.addHandler(data_handler)
data_logger.setLevel(logging_level) data_logger.setLevel(DATA_LOGGING_CONFIG['logging_level'])
if logging_to_console: if logging_to_console:
data_logger.addHandler(logging.StreamHandler()) console_data_handler = logging.StreamHandler(sys.stdout)
console_data_handler.setLevel(DATA_LOGGING_CONFIG['logging_level'])
console_data_handler.setFormatter(exec_formatter)
data_logger.addHandler(console_data_handler)
if mqtt: if mqtt:
mqtt_data_handler = MQTTHandler(MQTT_LOGGING_CONFIG['hostname'], MQTT_LOGGING_CONFIG['data_topic']) mqtt_settings = MQTT_LOGGING_CONFIG.copy()
mqtt_data_handler.setLevel(logging_level) [mqtt_settings.pop(i) for i in ['client_id', 'exec_topic', 'data_topic', 'soh_topic']]
mqtt_settings.update({'topic': MQTT_LOGGING_CONFIG['data_topic']})
mqtt_data_handler = MQTTHandler(**mqtt_settings)
mqtt_data_handler.setLevel(DATA_LOGGING_CONFIG['logging_level'])
mqtt_data_handler.setFormatter(data_formatter) mqtt_data_handler.setFormatter(data_formatter)
data_logger.addHandler(mqtt_data_handler) data_logger.addHandler(mqtt_data_handler)
try: try:
init_logging(exec_logger, data_logger, logging_level, log_path, data_log_filename) init_logging(exec_logger, data_logger, EXEC_LOGGING_CONFIG['logging_level'], log_path, data_log_filename)
except Exception as err: except Exception as err:
print(f'ERROR: Could not initialize logging!\n{err}') print(f'ERROR: Could not initialize logging!\n{err}')
finally: finally:
return exec_logger, exec_log_filename, data_logger, data_log_filename, logging_level return exec_logger, exec_log_filename, data_logger, data_log_filename, EXEC_LOGGING_CONFIG['logging_level']
def init_logging(exec_logger, data_logger, logging_level, log_path, data_log_filename): def init_logging(exec_logger, data_logger, exec_logging_level, log_path, data_log_filename):
""" This is the init sequence for the logging system """ """ This is the init sequence for the logging system """
init_logging_status = True init_logging_status = True
...@@ -97,7 +110,7 @@ def init_logging(exec_logger, data_logger, logging_level, log_path, data_log_fil ...@@ -97,7 +110,7 @@ def init_logging(exec_logger, data_logger, logging_level, log_path, data_log_fil
exec_logger.info('*** NEW SESSION STARTING ***') exec_logger.info('*** NEW SESSION STARTING ***')
exec_logger.info('****************************') exec_logger.info('****************************')
exec_logger.info('') exec_logger.info('')
exec_logger.info('Logging level: %s' % logging_level) exec_logger.info('Logging level: %s' % exec_logging_level)
try: try:
st = statvfs('.') st = statvfs('.')
available_space = st.f_bavail * st.f_frsize / 1024 / 1024 available_space = st.f_bavail * st.f_frsize / 1024 / 1024
...@@ -109,7 +122,8 @@ def init_logging(exec_logger, data_logger, logging_level, log_path, data_log_fil ...@@ -109,7 +122,8 @@ def init_logging(exec_logger, data_logger, logging_level, log_path, data_log_fil
# TODO Add OhmPi settings # TODO Add OhmPi settings
config_dict = {'execution logging configuration': json.dumps(EXEC_LOGGING_CONFIG, indent=4), config_dict = {'execution logging configuration': json.dumps(EXEC_LOGGING_CONFIG, indent=4),
'data logging configuration': json.dumps(DATA_LOGGING_CONFIG, indent=4), 'data logging configuration': json.dumps(DATA_LOGGING_CONFIG, indent=4),
'mqtt logging configuration': json.dumps(MQTT_LOGGING_CONFIG, indent=4)} 'mqtt logging configuration': json.dumps(MQTT_LOGGING_CONFIG, indent=4),
'mqtt control configuration': json.dumps(MQTT_CONTROL_CONFIG, indent=4)}
for k, v in config_dict.items(): for k, v in config_dict.items():
exec_logger.info(f'{k}:\n{v}') exec_logger.info(f'{k}:\n{v}')
exec_logger.info('') exec_logger.info('')
......
This diff is collapsed.
...@@ -51,8 +51,11 @@ class MQTTHandler(logging.Handler): ...@@ -51,8 +51,11 @@ class MQTTHandler(logging.Handler):
cleanly. cleanly.
""" """
msg = self.format(record) msg = self.format(record)
publish.single(self.topic, msg, self.qos, self.retain, try:
publish.single(self.topic, msg, self.qos, self.retain,
hostname=self.hostname, port=self.port, hostname=self.hostname, port=self.port,
client_id=self.client_id, keepalive=self.keepalive, client_id=self.client_id, keepalive=self.keepalive,
will=self.will, auth=self.auth, tls=self.tls, will=self.will, auth=self.auth, tls=self.tls,
protocol=self.protocol, transport=self.transport) protocol=self.protocol, transport=self.transport)
except Exception as e:
pass # TODO log in exec ?
This diff is collapsed.
{
"nb_electrodes": 64,
"injection_duration":0.2,
"nbr_meas": 100,
"sequence_delay": 1,
"nb_stack": 1,
"export_path": "data/measurement.csv"
}
...@@ -7,4 +7,6 @@ adafruit-circuitpython-tca9548a ...@@ -7,4 +7,6 @@ adafruit-circuitpython-tca9548a
adafruit-circuitpython-mcp230xx adafruit-circuitpython-mcp230xx
gpiozero gpiozero
termcolor termcolor
pyzmq pyzmq
\ No newline at end of file pandas
pyzmq
#!bin/bash #!bin/bash
source ./ohmpy/bin/activate cd /home/pi/OhmPi
python webserver.py
source /home/pi/OhmPi/ohmpy/bin/activate
python ohmpi.py
...@@ -9,9 +9,9 @@ n = a + 2 ...@@ -9,9 +9,9 @@ n = a + 2
seq = np.c_[a, b, m, n] seq = np.c_[a, b, m, n]
k = OhmPi(idps=True) k = OhmPi(idps=True)
k.pardict['injection_duration'] = 0.5 k.settings['injection_duration'] = 0.5
k.pardict['nb_stack'] = 1 k.settings['nb_stack'] = 1
k.pardict['nbr_meas'] = 1 k.settings['nbr_meas'] = 1
#k.sequence = seq #k.sequence = seq
#k.reset_mux() #k.reset_mux()
#k.switch_mux_on([4, 7, 5, 6]) #k.switch_mux_on([4, 7, 5, 6])
...@@ -24,8 +24,8 @@ k.pardict['nbr_meas'] = 1 ...@@ -24,8 +24,8 @@ k.pardict['nbr_meas'] = 1
#k.rs_check(tx_volt=12) #k.rs_check(tx_volt=12)
# x = [] # x = []
for i in range(5): for i in range(1):
out = k.run_measurement(injection_duration=0.5, nb_stack=5, strategy='vmin', tx_volt=5, autogain=True) out = k.run_measurement(injection_duration=0.5, nb_stack=2, strategy='vmin', tx_volt=5, autogain=True)
#x.append(out['R [ohm]']) #x.append(out['R [ohm]'])
k.append_and_save('out.csv', out) k.append_and_save('out.csv', out)
......
from http.server import SimpleHTTPRequestHandler, HTTPServer
import time
import os
import json
from ohmpi import OhmPi
import threading
import pandas as pd
import shutil
#hostName = "raspberrypi.local" # works for AP-STA
#hostName = "192.168.50.1" # fixed IP in AP-STA mode
hostName = "0.0.0.0" # for AP mode (not AP-STA)
serverPort = 8080
# https://gist.github.com/MichaelCurrie/19394abc19abd0de4473b595c0e37a3a
with open('ohmpi_param.json') as json_file:
pardict = json.load(json_file)
ohmpi = OhmPi(pardict, sequence='dd.txt')
#ohmpi = OhmPi(pardict, sequence='dd16s0no8.txt')
class MyServer(SimpleHTTPRequestHandler):
# because we use SimpleHTTPRequestHandler, we do not need to implement
# the do_GET() method (if we use the BaseHTTPRequestHandler, we would need to)
# def do_GET(self):
# # normal get for wepages (not so secure!)
# print(self.command)
# print(self.headers)
# print(self.request)
# self.send_response(200)
# self.send_header("Content-type", "text/html")
# self.end_headers()
# with open(os.path.join('.', self.path[1:]), 'r') as f:
# self.wfile.write(bytes(f.read(), "utf-8"))
def do_POST(self):
global ohmpiThread, status, run
dic = json.loads(self.rfile.read(int(self.headers['Content-Length'])))
rdic = {}
if dic['command'] == 'start':
ohmpi.measure()
elif dic['command'] == 'stop':
ohmpi.stop()
elif dic['command'] == 'getData':
# get all .csv file in data folder
fnames = [fname for fname in os.listdir('data/') if fname[-4:] == '.csv']
ddic = {}
for fname in fnames:
if (fname.replace('.csv', '') not in dic['surveyNames']
and fname != 'readme.txt'
and '_rs' not in fname):
df = pd.read_csv('data/' + fname)
ddic[fname.replace('.csv', '')] = {
'a': df['A'].tolist(),
'b': df['B'].tolist(),
'm': df['M'].tolist(),
'n': df['N'].tolist(),
'rho': df['R [ohm]'].tolist(),
}
rdic['data'] = ddic
elif dic['command'] == 'removeData':
shutil.rmtree('data')
os.mkdir('data')
elif dic['command'] == 'setConfig':
ohmpi.stop()
cdic = dic['config']
ohmpi.pardict['nb_electrodes'] = int(cdic['nbElectrodes'])
ohmpi.pardict['injection_duration'] = float(cdic['injectionDuration'])
ohmpi.pardict['nbr_meas'] = int(cdic['nbMeasurements'])
ohmpi.pardict['nb_stack'] = int(cdic['nbStack'])
ohmpi.pardict['sequence_delay'] = int(cdic['sequenceDelay'])
if cdic['sequence'] != '':
with open('sequence.txt', 'w') as f:
f.write(cdic['sequence'])
ohmpi.read_quad('sequence.txt')
print('new sequence set.')
print('setConfig', ohmpi.pardict)
elif dic['command'] == 'invert':
pass
elif dic['command'] == 'getResults':
pass
elif dic['command'] == 'rsCheck':
ohmpi.rs_check()
fnames = sorted([fname for fname in os.listdir('data/') if fname[-7:] == '_rs.csv'])
df = pd.read_csv('data/' + fnames[-1])
ddic = {
'AB': (df['A'].astype('str') + '-' + df['B'].astype(str)).tolist(),
'res': df['RS [kOhm]'].tolist()
}
rdic['data'] = ddic
elif dic['command'] == 'download':
shutil.make_archive('data', 'zip', 'data')
elif dic['command'] == 'shutdown':
print('shutting down...')
os.system('shutdown now -h')
elif dic['command'] == 'restart':
print('shutting down...')
os.system('reboot')
else:
# command not found
rdic['response'] = 'command not found'
rdic['status'] = ohmpi.status
self.send_response(200)
self.send_header('Content-Type', 'text/json')
self.end_headers()
self.wfile.write(bytes(json.dumps(rdic), 'utf8'))
if __name__ == "__main__":
webServer = HTTPServer((hostName, serverPort), MyServer)
print("Server started http://%s:%s" % (hostName, serverPort))
try:
webServer.serve_forever()
except KeyboardInterrupt:
pass
webServer.server_close()
print("Server stopped.")
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment