Merge remote-tracking branch 'origin/develop'

This commit is contained in:
Samuele E. Locatelli
2021-04-08 21:35:59 +02:00
8 changed files with 399 additions and 258 deletions
+14 -5
View File
@@ -3,6 +3,8 @@
import time
import datetime
import redis
import os
import os.path
#configurazione per lavorare su server redis locale
REDIS_PORT = 6379
@@ -14,7 +16,10 @@ redSrv0 = redis.Redis(
#funzione per leggere e decodificare da redis
def getRedisVal(redisKey):
return redSrv0.get(redisKey).decode('utf-8')
if redSrv0.get(redisKey) is None:
return redSrv0.get(redisKey)
else:
return redSrv0.get(redisKey).decode('utf-8')
#assegno directory per file di data output
DATA_path = "/home/pi/data/"
@@ -30,6 +35,8 @@ if redSrv0.get('SETTINGS:LOG:STATUS') is None:
redSrv0.set('SETTINGS:LOG:STATUS',0)
if redSrv0.get('SETTINGS:SELECTED_CH') is None:
redSrv0.set('SETTINGS:SELECTED_CH',0)
if redSrv0.get('SETTINGS:FOLDER:CURRENT') is None:
redSrv0.set('SETTINGS:FOLDER:CURRENT', "default")
for numCh in range(0,8,+1):
if redSrv0.get('SETTINGS:IN:MAX:'+str(numCh)) is None:
redSrv0.set('SETTINGS:IN:MAX:'+str(numCh),100)
@@ -42,15 +49,17 @@ if redSrv0.get('SETTINGS:SELECTED_CH') is None:
#funzione salva time+data e otto valori letti su file (SE LOG è 1)
def fileSave():
currentFolder = getRedisVal('SETTINGS:FOLDER:CURRENT')
workingDirectory = (DATA_path+currentFolder)
#dò un nome al nuovo file
dataFileName = getRedisVal('RTDATA:SESSION:NAME')
dateFormat ="%d/%m/%Y %H:%M:%S"
rawLastLog = datetime.datetime.now()
lastLog = rawLastLog.strftime(dateFormat)
try:
outFile = open(DATA_path+"/"+dataFileName, "a")
outFile = open(workingDirectory+"/"+dataFileName, "a")
except FileNotFoundError:
print("Creating new data.csv")
outFile = open(DATA_path+"/"+dataFileName, "w+")
outFile = open(workingDirectory+"/"+dataFileName, "w+")
outFile.write("# LOG started at " + str(lastLog))
# dichiaro una stringa in cui accumulo i valori
csvRow = str(lastLog) +","
@@ -64,7 +73,7 @@ def fileSave():
outFile.write(csvRow +"\r\n")
outFile.close()
#ciclo principale, salva time attuale e se LOG:STATUS è 1 fa il ciclo principale
#ciclo principale, salva time attuale e se LOG:STATUS è 1 fa fileSave()
while(1):
now = datetime.datetime.now()
# solo se su redis LOG è 1 eseguo il ciclo principale
+1
View File
@@ -84,3 +84,4 @@
2021-04-01 15:20:08.570454 Caught error: name 'now' is not defined
2021-04-01 15:21:11.244154 Caught error: name 'now' is not defined
2021-04-02 09:27:42.781175 Caught error: Connection closed by server.
2021-04-08 11:19:48.305652 Caught error: Error 111 connecting to 127.0.0.1:6379. Connection refused.
+12 -9
View File
@@ -16,21 +16,26 @@ redSrv0 = redis.Redis(
#funzione per leggere e decodificare da redis
def getRedisVal(redisKey):
return redSrv0.get(redisKey).decode('utf-8')
if redSrv0.get(redisKey) is None:
return redSrv0.get(redisKey)
else:
return redSrv0.get(redisKey).decode('utf-8')
#assegno director: log per file di debug e data per file output
#assegno director log per file di debug
LOG_path = "/home/pi/Flythis/logger/log/"
DATA_path = "/home/pi/data/"
startingSampleFreq = 250
#intervallo in millisecondi fra un campionamento e il successivo
startingSampleFreq = 250
redSampleFreq = 'SETTINGS:LOG:FREQ'
redSrv0.set(redSampleFreq,startingSampleFreq)
#se non c'è un valore nei campi di redis, popolo il db
redSrv0.set('SETTINGS:LOG:STATUS',0)
redisTime = 'RTDATA:TIME:SRV'
if redSrv0.get('SETTINGS:PASSWORD:CURRENT') is None:
redSrv0.set('SETTINGS:PASSWORD:CURRENT',"-")
if redSrv0.get('SETTINGS:FOLDER:CURRENT') is None:
redSrv0.set('SETTINGS:FOLDER:CURRENT', "default")
if redSrv0.get('SETTINGS:SELECTED_CH') is None:
redSrv0.set('SETTINGS:SELECTED_CH',0)
for numCh in range(0,8,+1):
@@ -86,17 +91,15 @@ try:
outVal = chOutMin + ((inValue-chInMin) * (deltaOut / deltaIn))
return outVal
#ciclo principale, salva time attuale e se LOG:STATUS è 1 fa il ciclo principale
#ciclo principale
while(1):
now = datetime.datetime.now()
redSrv0.set(redisTime,str(now))
#print(logStatus)
# solo se su redis LOG è 1 eseguo il ciclo principale
CHvalue = CH.ADS1256_GetAll()
redisSave(CHvalue)
# riporto ultima esecuzione ad adesso
endExec = datetime.datetime.now()
# calcolo il delta dovuto alle esecuzioni
# calcolo il delta time dovuto alle esecuzioni
delta = endExec - now
waitTime = int(redSrv0.get(redSampleFreq)) / 1000 - delta.microseconds/1000000
if(waitTime < 0.1):
+105 -34
View File
@@ -4,16 +4,19 @@ from flask import Flask, render_template, jsonify, request
from datetime import datetime
from flask.wrappers import Request
import redis
import os
import os, glob
import json
from werkzeug.utils import redirect
import os.path, time
#from pathlib import Path
#from stat import S_ISREG, ST_CTIME, ST_MODE
from distutils.dir_util import copy_tree
import shutil
#assegno ipv4 statico
ipv4 = '10.74.83.210'
#definisco directory /data
dataDir='/home/pi/data/'
#configurazione per lavorare su server redis locale
REDIS_PORT = 6379
REDIS_HOST = '127.0.0.1'
@@ -24,7 +27,10 @@ redSrv0 = redis.Redis(
#funzione per leggere e decodificare da redis
def getRedisVal(redisKey):
return redSrv0.get(redisKey).decode('utf-8')
if redSrv0.get(redisKey) is None:
return redSrv0.get(redisKey)
else:
return redSrv0.get(redisKey).decode('utf-8')
flaskApp = Flask(__name__)
flaskApp.config['JSON_SORT_KEYS'] = False
@@ -70,12 +76,10 @@ def about():
#assegno il template html di riferimento
return render_template('about.html', **channelsData)
# definisco una NUOVA route a cui rispondere su chiamta in metodo GET x restituire dati aggiornati
# funzione api_channels_all: legge direttamente da redis, ritorna jsonify
@flaskApp.route("/api/v1/channels/all", methods=['GET'])
def api_channels_all():
numCh = getRedisVal('SETTINGS:SELECTED_CH')
#funzione api_channels_all: legge direttamente da redis, ritorna jsonify
CH = [0,0,0,0,0,0,0,0]
OUT = [0,0,0,0,0,0,0,0]
OUTMIN = [0,0,0,0,0,0,0,0]
@@ -85,7 +89,6 @@ def api_channels_all():
OUT[numCh] = getRedisVal('RTDATA:OUT:'+str(numCh))
OUTMIN[numCh] = getRedisVal('SETTINGS:OUT:MIN:'+str(numCh))
OUTMAX[numCh] = getRedisVal('SETTINGS:OUT:MAX:'+str(numCh))
channelsData = {
'timeSrv' : getRedisVal('RTDATA:TIME:SRV'),
'timeLog' : getRedisVal('RTDATA:TIME:LOG'),
@@ -102,7 +105,8 @@ def api_channels_all():
'ChScaleMin' : getRedisVal('SETTINGS:IN:MIN:'+str(numCh)),
'ChRealMax' : getRedisVal('SETTINGS:OUT:MAX:'+str(numCh)),
'ChRealMin' : getRedisVal('SETTINGS:OUT:MIN:'+str(numCh)),
'LastSessionName' : getRedisVal('RTDATA:SESSION:NAME')
'LastSessionName' : getRedisVal('RTDATA:SESSION:NAME'),
'CurrentWorkFolder' : getRedisVal('SETTINGS:FOLDER:CURRENT')
}
# restituisce in formato json i dati letti da redis
return jsonify(channelsData)
@@ -111,6 +115,21 @@ def api_channels_all():
@flaskApp.route("/api/v1/channels/current", methods=['GET'])
def api_channels_current():
numCh = getRedisVal('SETTINGS:SELECTED_CH')
savedPwd = getRedisVal('SETTINGS:PASSWORD:CURRENT')
if savedPwd is None:
redSrv0.set('SETTINGS:PASSWORD:CURRENT',"")
# tutto false
showDiv1 = 0
showDiv2 = 0
showDiv3 = 0
if savedPwd == "":
showDiv1 = 1
elif savedPwd == "viaZavaritt":
showDiv3 = 1
elif savedPwd == "viaZavaritt152":
showDiv2 = 1
showDiv3 = 1
#funzione api_channels_all: legge direttamente da redis, ritorna jsonify
result = {
'numCh' : numCh,
@@ -123,34 +142,29 @@ def api_channels_current():
'MaxOut' : getRedisVal('SETTINGS:OUT:MAX:'+str(numCh)),
'MinOut' : getRedisVal('SETTINGS:OUT:MIN:'+str(numCh)),
'MaxIn' : getRedisVal('SETTINGS:IN:MAX:'+str(numCh)),
'MinIn' : getRedisVal('SETTINGS:IN:MIN:'+str(numCh))
'MinIn' : getRedisVal('SETTINGS:IN:MIN:'+str(numCh)),
'CurrentWorkFolder' : getRedisVal('SETTINGS:FOLDER:CURRENT'),
'ShowDiv01' : showDiv1,
'ShowDiv02' : showDiv2,
'ShowDiv03' : showDiv3,
}
# restituisce in formato json i dati letti da redis
return jsonify(result)
# elenco file nella directory
@flaskApp.route("/api/v1/files/list", methods=['GET'])
def api_get_files():
dataDir='/home/pi/data/'
fileList = os.listdir(dataDir)
# #all entries in the directory w/ stats
# data = (os.path.join(dataDir, fn) for fn in os.listdir(dataDir))
# data = ((os.stat(path), path) for path in data)
# # regular files, insert creation date
# data = ((stat[ST_CTIME], path)
# for stat, path in data if S_ISREG(stat[ST_MODE]))
currentFolder = getRedisVal('SETTINGS:FOLDER:CURRENT')
workingDirectory = (dataDir+currentFolder)
fileList = os.listdir(workingDirectory)
lista = []
idx=0
# for item in sorted(data):
for item in fileList:
t_obj = time.strptime(time.ctime(os.path.getctime(dataDir+item)))
t_obj = time.strptime(time.ctime(os.path.getctime(workingDirectory+"/"+item)))
# Transforming the time object to a timestamp
# of ISO 8601 format
T_stamp = time.strftime("%Y-%m-%d %H:%M:%S", t_obj)
current = {"name": item,"size": os.path.getsize(dataDir+item), "date":T_stamp}
# current = {"name": item,"size": os.path.getsize(dataDir+item), "date":time.ctime(os.path.getctime(dataDir+item))}
current = {"name": item,"size": os.path.getsize(workingDirectory+"/"+item), "date":T_stamp}
lista.append(current)
idx=idx+1
return jsonify(fileTable = lista)
@@ -158,16 +172,21 @@ def api_get_files():
# Route di comando x LOG: start e stop
@flaskApp.route("/api/v1/log/start", methods=['PUT'])
def start_log():
#funzione start_log: scrive su redis LOG:STATUS -> 1
redSrv0.set('SETTINGS:LOG:STATUS', 1)
#data e time ora
lastDate = datetime.now()
#formato per data time nomefile: YYYYddmm_HMS
format = "%Y%m%d_%H%M%S"
#format date e time adando strftime()
nameDate = lastDate.strftime(format) + ".csv"
redSrv0.set('RTDATA:SESSION:NAME', nameDate)
return "OK"
currentFolder = getRedisVal('SETTINGS:FOLDER:CURRENT')
workingDirectory = (dataDir+currentFolder)
if os.path.isdir(workingDirectory) is True:
#funzione start_log: scrive su redis LOG:STATUS -> 1
redSrv0.set('SETTINGS:LOG:STATUS', 1)
#data e time ora
lastDate = datetime.now()
#formato per data time nomefile: YYYYddmm_HMS
format = "%Y%m%d_%H%M%S"
#format date e time adando strftime()
nameDate = lastDate.strftime(format) + ".csv"
redSrv0.set('RTDATA:SESSION:NAME', nameDate)
return "OK"
else:
return "OK"
@flaskApp.route("/api/v1/log/stop", methods=['PUT'])
def stop_log():
@@ -176,6 +195,45 @@ def stop_log():
redSrv0.set('RTDATA:SESSION:NAME', "-")
return "OK"
@flaskApp.route("/api/v1/data/export", methods=['PUT'])
def data_export():
#funzione dataExport: copia
currentFolder = getRedisVal('SETTINGS:FOLDER:CURRENT')
workingDirectory = (dataDir+currentFolder)
scriptMount = """
if [ -a /dev/sd[a-z]1 ]
then
/bin/mount /dev/sd[a-z]1 /mnt/USB
else
/bin/mount /dev/sd[a-z] /mnt/USB
fi
"""
os.system("bash -c '%s'" % scriptMount)
usbDrive='/mnt/USB/'
dataDestination = (usbDrive+currentFolder)
if os.path.isdir(dataDestination) is True:
copy_tree(workingDirectory, dataDestination)
else:
os.mkdir(dataDestination)
copy_tree(workingDirectory, dataDestination)
return redirect("/logger")
@flaskApp.route("/api/v1/data/delete", methods=['PUT'])
def data_delete():
#funzione dataDelete: cancella
currentFolder = getRedisVal('SETTINGS:FOLDER:CURRENT')
workingDirectory = (dataDir+currentFolder)
shutil.rmtree(workingDirectory)
redSrv0.set('SETTINGS:FOLDER:CURRENT', "not set")
return redirect("/logger")
@flaskApp.route("/api/v1/setup/passwordInput", methods=['POST'])
def insertPassword():
#funzione inserimento password
currentPassword = request.form['PasswordForm']
redSrv0.set('SETTINGS:PASSWORD:CURRENT', currentPassword, ex=5*60)
return redirect("/settings")
@flaskApp.route("/api/v1/setup/saveInMin", methods=['PUT'])
def setupInMin():
# devo leggere il channel attualmente selezionato
@@ -221,6 +279,19 @@ def setWriteFrequency():
# rimando in settings
return redirect("/settings")
@flaskApp.route("/api/v1/setup/workingtree", methods=['POST'])
def setWorkingTree():
#funzione set directory scrive su redis il testo preso dall'input in settings
newWorkFolder = request.form['NewFolder']
redSrv0.set('SETTINGS:FOLDER:CURRENT', newWorkFolder)
currentFolder = getRedisVal('SETTINGS:FOLDER:CURRENT')
workingDirectory = (dataDir+currentFolder)
if os.path.isdir(workingDirectory) is True:
return redirect("/logger")
else:
os.mkdir(workingDirectory)
return redirect("/logger")
@flaskApp.route("/api/v1/scaleout", methods=['POST'])
def setScale():
indexCh = getRedisVal('SETTINGS:SELECTED_CH')
+4 -12
View File
@@ -6,24 +6,16 @@
var intTime=2000;
</script>
<div class="container-fluid py-2">
<div class="card mb-4">
<div class="card my-2">
<div class="card-header">
<i class="fas fa-table mr-1"></i>
About Analogger
<h4>Steamware Srl</h4>
</div>
<div class="card-body">
<div class="row">
<h4>Steamware Srl</h4>
FT Logger Software 2021
</div>
<div class="row">
<p>Analog and Digital reader and logger software</p>
</div>
<div class="row">
<p>Version 0.2.1</p>
</div>
<div class="row">
<p>Last Patched:<br>
02/04/2021</p>
Analog and Digital reader and logger software
</div>
</div>
</div>
+2 -2
View File
@@ -4,8 +4,8 @@
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="FlyThis" />
<meta name="author" content="MarcoLoca" />
<meta name="description" content="FlyThisLogger" />
<meta name="author" content="Marco&Samu Loca" />
<title>{{ title }}</title>
<link rel="shortcut icon" href="../static/img/steam.ico">
<link rel="stylesheet" href="../static/css/bootstrap.min.css">
+84 -38
View File
@@ -3,10 +3,13 @@
{% block content %}
<main>
<script type="text/javascript">
var intTime=200;
// fix visualizzazioni
fixDisplay();
fixFileTable();
// avvio timer
var timeout = setTimeout(dataRefresh, intTime);
var fileTable = [
@@ -42,9 +45,9 @@
$("#LoggerTime").html(result.timeLog);
$("#ServerTime").html(result.timeSrv);
$("#LastSessionName").html(result.LastSessionName);
$("#CurrentFolder").html(result.CurrentWorkFolder);
}});
timeout = setTimeout(dataRefresh, intTime);
};
@@ -93,8 +96,11 @@
,url: "/api/v1/log/start"
,data: ""
})
// fix file
$("#btnStart").hide();
$("#btnStop").show();
// fix table
fixFileTable();
dataRefresh()
};
// Funzione stopLog: fa chiamata per settare a 0 il LOG:STATUS
@@ -104,11 +110,43 @@
,url: "/api/v1/log/stop"
,data: ""
})
// fix file
$("#btnStart").show();
$("#btnStop").hide();
// fix table
fixFileTable();
};
//funzione exportData: chiamata per copiare e incollare il contenuto della cartella /data
function exportData(){
$.ajax({
type: 'PUT'
,url: "/api/v1/data/export"
,data: ""
})
// fix table
fixFileTable();
};
//funzione deleteData: chiamata per eliminare il contenuto della cartella /data
function deleteData(){
var R = confirm("Confermi di voler eliminare la cartella attuale e il suo contenuto?");
if (R == true){
$.ajax({
type: 'PUT'
,url: "/api/v1/data/delete"
,data: ""
})
fixDisplay();
fixFileTable();
dataRefresh();
}
else{
fixDisplay();
fixFileTable();
dataRefresh();
}
};
function fixFileTable(){
// scarico i dati aggioranti
$.ajax({url: "/api/v1/files/list", success: function(result){
@@ -117,9 +155,8 @@
UpdateFileTable(fileTable);
}});
}
function UpdateFileTable(fileTable) {
// EXTRACT VALUE FOR HTML HEADER.
var col = [];
for (var i = 0; i < fileTable.length; i++) {
@@ -129,20 +166,18 @@
}
}
}
// CREATE DYNAMIC TABLE.
var table = document.createElement("table");
// CREATE HTML TABLE HEADER ROW USING THE EXTRACTED HEADERS ABOVE.
var tr = table.insertRow(-1); // TABLE ROW.
// TABLE ROW.
var tr = table.insertRow(-1);
// TABLE HEADER.
for (var i = 0; i < col.length; i++) {
var th = document.createElement("th"); // TABLE HEADER.
var th = document.createElement("th");
th.innerHTML = col[i];
tr.appendChild(th);
}
// ADD JSON DATA TO THE TABLE AS ROWS.
for (var i = 0; i < fileTable.length; i++) {
tr = table.insertRow(-1);
@@ -151,15 +186,14 @@
tabCell.innerHTML = fileTable[i][col[j]];
}
}
// FINALLY ADD THE NEWLY CREATED TABLE WITH JSON DATA TO A CONTAINER.
var divContainer = document.getElementById("showData");
divContainer.innerHTML = "";
divContainer.appendChild(table);
}
// fix file
UpdateFileTable(fileTable);
</script>
<div class="container-fluid">
<div class="row my-2">
@@ -174,9 +208,6 @@
<div class="col">
<strong>OUT <span id="OutputA"></span></strong>
</div>
<!-- <div class="col">
# <span id="ChannelA"></span>
</div> -->
</div>
</div>
</div>
@@ -192,39 +223,46 @@
<div class="col">
<strong>OUT <span id="OutputB"></span></strong>
</div>
<!-- <div class="col">
# <span id="ChannelB"></span>
</div> -->
</div>
</div>
</div>
</div>
</div>
<div class="table-info text-center py-2 row">
<div class="table-secondary text-center py-2 m-2 row">
<!-- <div class="text-center my-2 row"> -->
<div class="col-6">
<button type="button" class="btn btn-success btn-block" onclick="startLog()">Start Log</button>
<button id="btnStart" type="button" class="btn btn-success btn-block" onclick="startLog()">Start Log</button>
</div>
<div class="col-6">
<button type="button" class="btn btn-danger btn-block" onclick="stopLog()">Stop Log</button>
</div>
<div class="col-6">
<strong>Logger period: </strong> <span id="LogFrequency"></span> ms
</div>
<div class="col-6">
<strong>File Write period: </strong> <span id="WriteFrequency"></span> ms
<button id="btnStop" type="button" class="btn btn-warning btn-block" onclick="stopLog()">Stop Log</button>
</div>
</div>
<div class="card mb-4">
<div class="card-header">
<div class="row">
<div class="col-3">
<b>Record Log</b>
<div class="card my-2 col-12">
<div class="row card-header">
<strong>Folder salvataggio file. Attuale: &nbsp; </strong> <h5><span class="badge badge-warning" id="CurrentFolder"></span></h5>
</div>
<div class="row card-body">
<form class="col-12" method="POST" action="/api/v1/setup/workingtree">
<div class="row input-group my-2">
<span class="col-3 input-group-text">Insert new: &nbsp;</span>
<input type="text" class="col-7 form-control" id="NewFolder" name="NewFolder"></input>
<input type="submit" value="SET" class="btn btn-success btn-block col-2"></input>
</div>
<div class="col-9">
<div class="input-group-text">
<span>Current Session: &nbsp;</span> <span id="LastSessionName"></span>
</div>
</form>
</div>
</div>
<div class="card my-2">
<div class="card-header">
<b>Elenco registrazioni</b>
<div class="input-group-text my-2">
<span>Sessione attuale: &nbsp;</span> <span id="LastSessionName"></span>
</div>
<div class="row mt-2">
<div class="col-6">
<button type="button" class="btn btn-primary btn-block" onclick="exportData()">Esporta Cartella</button>
</div>
<div class="col-6">
<button type="button" class="btn btn-danger btn-block" onclick="deleteData()">Cancella Cartella</button>
</div>
</div>
</div>
@@ -232,6 +270,14 @@
<p class="text-center" id="showData"></p>
</div>
</div>
<!-- <div class="table-warning text-center my-60 row">
<div class="col-6">
<strong>Logger period: </strong> <span id="LogFrequency"></span> ms
</div>
<div class="col-6">
<strong>File Write period: </strong> <span id="WriteFrequency"></span> ms
</div>
</div> -->
</div>
</main>
{% endblock %}
+177 -158
View File
@@ -10,7 +10,6 @@
// carico la prima volta i dati
function refreshInput() {
// scarico i dati aggioranti
$.ajax({url: "/api/v1/channels/current", success: function(result){
// compilo i dati scaricati
$("#CurrIn").html(result.CurrIn);
@@ -24,11 +23,22 @@
$("#MaxOut").val(result.MaxOut);
$("#MinIn").html(result.MinIn);
$("#MaxIn").html(result.MaxIn);
$("#CurrentFolder").html(result.CurrentWorkFolder);
// inizio nascondendo div2 e div3
$("#Div2").hide();
$("#Div3").hide();
if(result.ShowDiv02 == "1")
{
$("#Div2").show();
}
if(result.ShowDiv03 == "1")
{
$("#Div3").show();
}
}});
}
function refreshSettings() {
// scarico i dati aggioranti
$.ajax({url: "/api/v1/channels/current", success: function(result){
// compilo i dati scaricati
$("#CurrIn").html(result.CurrIn);
@@ -78,7 +88,7 @@
}
})
};
function saveMax(){
$.ajax({
type: 'PUT'
@@ -122,187 +132,196 @@
</script>
<div class="container-fluid">
<div class="row mx-1 my-2">
<div class="card col-6">
<div id="Div1">
<div class="card my-2 col-12">
<div class="row card-header">
<div class="col-6">
<strong>Channel A</strong>
</div>
<div class="col-6">
<div class="form-group">
<select class="form-control" id="SelChannelA" onchange="setChannelA(this)">
<option>0</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
</select>
</div>
</div>
<strong>Autenticazione utente</strong>
</div>
<div class="card-body text-center">
Original: <span id="ChannelA"></span>
<br>
<strong>Scaled: <span id="OutputA"></span>
</strong>
</div>
</div>
<div class="card col-6">
<div class="row card-header">
<div class="col-6">
<strong>Channel B</strong>
</div>
<div class="col-6">
<div class="form-group">
<select class="form-control" id="SelChannelB" onchange="setChannelB(this)">
<option>0</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
</select>
</div>
</div>
</div>
<div class="card-body text-center">
Original: <span id="ChannelB"></span>
<br>
<strong>Scaled: <span id="OutputB"></span>
</strong>
<div class="card-body">
<form class="col-12" method="POST" action="/api/v1/setup/passwordInput">
<div class="row input-group my-2">
<span class="input-group-text">Password: &nbsp;</span>
<input type="text" class=" form-control" id="PasswordForm" name="PasswordForm"></input>
<input type="submit" value="LOGIN" class="btn btn-success"></input>
</div>
</form>
</div>
</div>
</div>
<div class="card mb-4">
<div class="card-header">
<div class="row">
<div class="col-4">
<i class="fas fa-table mr-1"></i>
<strong>Channel Setup</strong>
<div class="row" id="Div2">
<div class="col-6">
<div class="card my-2">
<div class="card-header">
<strong>Canale A</strong>
<div class="form-group">
<select class="form-control" id="SelChannelA" onchange="setChannelA(this)">
<option>0</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
</select>
</div>
</div>
<div class="col-4 text-right">
<div class="card-body text-center">
Nativo: <span id="ChannelA"></span>
<br>
<strong>Scalato: <span id="OutputA"></span>
</strong>
</div>
</div>
</div>
<div class="col-6">
<div class="card my-2">
<div class="card-header">
<strong>Canale B</strong>
<div class="form-group">
<select class="form-control" id="SelChannelB" onchange="setChannelB(this)">
<option>0</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
</select>
</div>
</div>
<div class="card-body text-center">
Nativo: <span id="ChannelB"></span>
<br>
<strong>Scalato: <span id="OutputB"></span>
</strong>
</div>
</div>
</div>
</div>
<div id="Div3">
<div class="card my-2 col-12">
<div class="row card-header">
<div class="col-5">
<i class="fas fa-table mr-1"></i>
<strong>Impostazioni scala canale</strong>
</div>
<div class="col-3 text-right">
<label for="sel1"> Channel n°</label>
</div>
<div class="col-4 text-right">
<div class="form-group">
<select class="form-control" id="ddlChannels" onchange="setChannel(this)">
<option>0</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>0</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
</select>
</div>
</div>
</div>
</div>
<h5>
<div class="card-body text-center">
<div class="card-body row text-center">
<div class="col-2"></div>
<div class="col-8">
<div class="row">
<div class="col-4">MIN</div>
<div class="col-4">Current</div>
<div class="col-4">MAX</div>
</div>
</div>
<div class="col-2"></div>
</div>
<div class="card-body row text-center">
<div class="col-2">IN</div>
<div class="col-8">
<div class="row">
<div class="col-4"><span class="badge badge-secondary text-center" id="MinIn">000</span></div>
<div class="col-4"><span class="badge badge-warning text-center" id="CurrIn">000</span></div>
<div class="col-4"><span class="badge badge-info text-center" id="MaxIn">000</span></div>
</div>
</div>
<div class="col-2"></div>
</div>
<div class="card-body row text-center">
<div class="col-2"></div>
<div class="col-8">
<div class="row">
<div class="col-4"><button type="button" class="btn btn-secondary btn-block" onclick="saveMin()">Save Min</button></div>
<div class="col-4"></div>
<div class="col-4"><button type="button" class="btn btn-info btn-block" onclick="saveMax()">Save Max</button></div>
</div>
</div>
<div class="col-2"></div>
</div>
<form method="POST" action="/api/v1/scaleout">
<div class="card-body h5 text-center">
<div class="card-body row text-center">
<div class="col-2 text-center">OUT</div>
<div class="col-2"></div>
<div class="col-8">
<div class="row">
<div class="col-4">
<input type="number" class="form-control text-center" id="MinOut" name="MinOut"></input>
</div>
<div class="col-4"><span class="badge badge-warning" id="CurrOut">{{ Out0 }}</span></div>
<div class="col-4">
<input type="number" class="form-control text-center" id="MaxOut" name="MaxOut"></input>
</div>
<div class="col-4">MIN</div>
<div class="col-4">Attuale</div>
<div class="col-4">MAX</div>
</div>
</div>
<div class="col-2">
</div>
<div class="col-2"></div>
</div>
<div class="row text-center">
<div class="col-2"></div>
<div class="col-8">
<div class="row">
<input type="submit" value="SET OUTPUT SCALE" class="btn btn-success btn-block mx-2 my-2"></input>
<div class="card-body row text-center">
<div class="col-2">IN</div>
<div class="col-8">
<div class="row">
<div class="col-4"><span class="badge badge-secondary text-center" id="MinIn">000</span></div>
<div class="col-4"><span class="badge badge-warning text-center" id="CurrIn">000</span></div>
<div class="col-4"><span class="badge badge-info text-center" id="MaxIn">000</span></div>
</div>
</div>
<div class="col-2"></div>
</div>
<div class="col-2"></div>
<div class="card-body row text-center">
<div class="col-2"></div>
<div class="col-8">
<div class="row">
<div class="col-4"><button type="button" class="btn btn-secondary btn-block" onclick="saveMin()">Save Min</button></div>
<div class="col-4"></div>
<div class="col-4"><button type="button" class="btn btn-info btn-block" onclick="saveMax()">Save Max</button></div>
</div>
</div>
<div class="col-2"></div>
</div>
<form method="POST" action="/api/v1/scaleout">
<div class="card-body row text-center">
<div class="col-2 text-center">OUT</div>
<div class="col-8">
<div class="row">
<div class="col-4">
<input type="number" class="form-control text-center" id="MinOut" name="MinOut"></input>
</div>
<div class="col-4"><span class="badge badge-warning" id="CurrOut">{{ Out0 }}</span></div>
<div class="col-4">
<input type="number" class="form-control text-center" id="MaxOut" name="MaxOut"></input>
</div>
</div>
</div>
<div class="col-2">
</div>
</div>
<div class="row text-center">
<div class="col-2"></div>
<div class="col-8">
<div class="row">
<input type="submit" value="SET OUTPUT SCALE" class="btn btn-success btn-block mt-2"></input>
</div>
</div>
<div class="col-2"></div>
</div>
</form>
</div>
</form>
</div>
</h5>
</div>
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-table mr-1"></i>
<strong>Impostazioni Timer</strong>
<div class="card my-2 col-12">
<div class="row card-header">
<i class="fas fa-table mr-1"></i>
<strong>Impostazioni Timer</strong>
</div>
<div class="card-body row">
<form class="col-12" method="POST" action="/api/v1/frequency">
<div class="input-group my-2">
<span class="col-8 input-group-text">Periodo di campionamento (ms): &nbsp;</span>
<input type="number" class="col-4 form-control" id="LogFreq" name="LogFreq"></input>
</div>
<div class="input-group my-2">
<span class="col-8 input-group-text">Periodo di scrittura (ms): &nbsp;</span>
<input type="number" class="col-4 form-control" id="WriteFreq" name="WriteFreq"></input>
<br>
<input type="submit" value="SET" class="btn btn-success btn-block mt-2"></input>
</div>
</form>
</div>
</div>
<div class="card-body row">
<form class="col-12" method="POST" action="/api/v1/frequency">
<div class="input-group my-2">
<span class="col-8 input-group-text">Periodo di campionamento (ms): &nbsp;</span>
<input type="number" class="col-4 form-control" id="LogFreq" name="LogFreq"></input>
</div>
<div class="input-group my-2">
<span class="col-8 input-group-text">Periodo di scrittura (ms): &nbsp;</span>
<input type="number" class="col-4 form-control" id="WriteFreq" name="WriteFreq"></input>
<br>
<input type="submit" value="SET" class="btn btn-success btn-block my-2"></input>
</div>
</form>
</div>
</div>
<div class="card my-2">
<div class="card-header">
<i class="fas fa-table mr-1"></i>
<strong>Reset settings to defaults</strong>
</div>
<div class="card-body">
<form method="POST" action="api/v1/setup/resetSettings">
<div class="row">
<div class="col-2"></div>
<input type="submit" class="col-8 btn btn-danger btn-block my-2" value="RESET SETTINGS"></input>
<div class="col-2"></div>
</div>
</form>
<div class="card my-2 col-12">
<div class="row card-header">
<i class="fas fa-table mr-1"></i>
<strong>Reset impostazioni predefinite</strong>
</div>
<div class="card-body mb-4">
<form method="POST" action="/api/v1/setup/resetSettings">
<div class="row">
<div class="col-2"></div>
<input type="submit" class="col-8 btn btn-danger btn-block my-2" value="RESET SETTINGS"></input>
<div class="col-2"></div>
</div>
</form>
</div>
</div>
</div>
</div>