pulsante spegnimento, inserimento data e ora

This commit is contained in:
Marco Locatelli
2021-04-23 12:06:47 +02:00
parent 448955d263
commit 5e95a9e92a
11 changed files with 147 additions and 165 deletions
+6
View File
@@ -0,0 +1,6 @@
2021-04-21 00:25:00.636728 Program end. Ctrl+C from user
2021-04-21 00:43:00.683259 Caught error: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
2021-04-21 00:46:17.711533 Caught error: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
2021-04-22 15:03:04.132682 Caught error: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
2021-04-22 15:04:27.913191 Caught error: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
2021-04-22 15:34:13.724625 Caught error: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
+1 -1
View File
@@ -36,7 +36,7 @@ if redSrv0.get('SETTINGS:LOG:STATUS') is None:
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")
redSrv0.set('SETTINGS:FOLDER:CURRENT', "")
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)
+1 -98
View File
@@ -1,98 +1 @@
2021-03-29 09:58:47.508544 Program end. Ctrl+C from user
2021-03-29 09:58:49.419906 Program end. Ctrl+C from user
2021-03-29 10:06:36.805375 Program end. Ctrl+C from user
2021-03-29 10:16:34.873420 Program end. Ctrl+C from user
2021-03-29 11:31:02.367011 Program end. Ctrl+C from user
2021-03-29 11:36:21.793976 Program end. Ctrl+C from user
2021-03-29 11:36:32.642389 Program end. Ctrl+C from user
2021-03-29 11:36:39.298257 Program end. Ctrl+C from user
2021-03-29 11:37:09.962049 Program end. Ctrl+C from user
2021-03-29 12:26:08.253892 Program end. Ctrl+C from user
2021-03-29 12:34:34.762399 Program end. Ctrl+C from user
2021-03-29 12:35:59.824375 Program end. Ctrl+C from user
2021-03-29 12:41:24.933798 Program end. Ctrl+C from user
2021-03-29 12:43:32.139821 Program end. Ctrl+C from user
2021-03-29 12:45:05.686145 Program end. Ctrl+C from user
2021-03-29 12:46:23.743580 Program end. Ctrl+C from user
2021-03-29 12:53:23.943793 Program end. Ctrl+C from user
2021-03-29 13:04:38.212360 Program end. Ctrl+C from user
2021-03-29 13:11:50.548529 Program end. Ctrl+C from user
2021-03-29 13:12:03.872367 Program end. Ctrl+C from user
2021-03-29 13:12:47.701751 Program end. Ctrl+C from user
2021-03-29 14:49:22.191222 Program end. Ctrl+C from user
2021-03-29 15:04:18.258773 Program end. Ctrl+C from user
2021-03-30 08:54:50.480755 Program end. Ctrl+C from user
2021-03-30 08:55:09.628193 Program end. Ctrl+C from user
2021-03-30 08:57:11.032414 Program end. Ctrl+C from user
2021-03-30 08:57:17.269880 Caught error: can only concatenate str (not "bytes") to str
2021-03-30 08:58:02.637416 Caught error: can only concatenate str (not "bytes") to str
2021-03-30 08:59:26.917913 Caught error: can only concatenate str (not "bytes") to str
2021-03-30 09:00:48.338924 Caught error: can only concatenate str (not "bytes") to str
2021-03-30 09:01:36.599414 Caught error: can only concatenate str (not "bytes") to str
2021-03-30 09:02:03.091920 Caught error: can only concatenate str (not "bytes") to str
2021-03-30 09:02:58.740174 Program end. Ctrl+C from user
2021-03-30 09:10:26.654282 Program end. Ctrl+C from user
2021-03-30 09:10:32.675386 Caught error: strftime() argument 1 must be str, not builtin_function_or_method
2021-03-30 09:11:57.923154 Caught error: module 'datetime' has no attribute 'now'
2021-03-30 09:13:27.237961 Caught error: module 'datetime' has no attribute 'now'
2021-03-30 09:13:53.044379 Caught error: module 'datetime' has no attribute 'now'
2021-03-30 09:15:12.159821 Caught error: module 'datetime' has no attribute 'now'
2021-03-30 09:22:00.948297 Program end. Ctrl+C from user
2021-03-30 09:22:22.153029 Caught error: name 'lastExec' is not defined
2021-03-30 09:22:44.387098 Caught error: unsupported operand type(s) for -: 'float' and 'datetime.timedelta'
2021-03-30 09:24:50.404856 Caught error: sleep length must be non-negative
2021-03-30 09:29:44.893036 Program end. Ctrl+C from user
2021-03-30 09:30:40.621197 Program end. Ctrl+C from user
2021-03-30 09:30:56.786784 Program end. Ctrl+C from user
2021-03-30 09:31:13.197526 Program end. Ctrl+C from user
2021-03-30 09:31:24.975494 Program end. Ctrl+C from user
2021-03-30 09:31:59.845816 Program end. Ctrl+C from user
2021-03-30 10:27:37.838338 Program end. Ctrl+C from user
2021-03-30 10:34:02.215293 Program end. Ctrl+C from user
2021-03-30 10:35:17.726550 Program end. Ctrl+C from user
2021-03-30 10:37:02.170879 Program end. Ctrl+C from user
2021-03-30 10:40:44.353305 Program end. Ctrl+C from user
2021-03-30 10:42:47.689947 Program end. Ctrl+C from user
2021-03-30 10:53:33.297267 Program end. Ctrl+C from user
2021-03-30 11:38:38.717298 Program end. Ctrl+C from user
2021-03-30 11:46:56.641430 Program end. Ctrl+C from user
2021-03-30 14:19:38.149124 Program end. Ctrl+C from user
2021-03-30 14:20:54.350302 Program end. Ctrl+C from user
2021-03-30 22:03:03.117436 Program end. Ctrl+C from user
2021-03-30 22:12:28.454778 Program end. Ctrl+C from user
2021-03-30 22:13:02.315239 Program end. Ctrl+C from user
2021-03-31 09:34:15.961409 Program end. Ctrl+C from user
2021-03-31 10:17:45.300938 Program end. Ctrl+C from user
2021-03-31 11:27:00.292142 Caught error: invalid literal for int() with base 10: b''
2021-03-31 11:27:00.785487 Caught error: invalid literal for int() with base 10: b''
2021-03-31 11:28:44.547015 Caught error: invalid literal for int() with base 10: b''
2021-03-31 11:29:27.065961 Caught error: invalid literal for int() with base 10: b''
2021-03-31 11:32:52.310001 Caught error: invalid literal for int() with base 10: b''
2021-03-31 11:37:57.102044 Caught error: invalid literal for int() with base 10: b''
2021-03-31 12:52:46.545088 Program end. Ctrl+C from user
2021-03-31 12:55:07.891601 Caught error: unsupported operand type(s) for -: 'datetime.datetime' and 'str'
2021-03-31 12:55:31.352004 Caught error: unsupported operand type(s) for -: 'datetime.datetime' and 'str'
2021-03-31 13:00:46.530922 Program end. Ctrl+C from user
2021-03-31 13:22:12.133149 Program end. Ctrl+C from user
2021-04-01 10:28:30.317253 Caught error: Error while reading from socket: (104, 'Connection reset by peer')
2021-04-01 14:19:28.128726 Program end. Ctrl+C from user
2021-04-01 14:28:52.849487 Program end. Ctrl+C from user
2021-04-01 14:31:27.497836 Program end. Ctrl+C from user
2021-04-01 14:52:01.713444 Caught error: name 'ADS1256' is not defined
2021-04-01 15:10:59.667675 Caught error: name 'fileSave' is not defined
2021-04-01 15:20:07.442727 Caught error: name 'now' is not defined
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.
2021-04-09 09:35:39.271878 Caught error: Error 111 connecting to 127.0.0.1:6379. Connection refused.
2021-04-12 09:44:47.671178 Caught error: Error while reading from socket: (104, 'Connection reset by peer')
2021-04-14 11:56:16.891671 Caught error: Error 111 connecting to 127.0.0.1:6379. Connection refused.
2021-04-16 11:01:11.178539 Caught error: unsupported operand type(s) for /: 'str' and 'int'
2021-04-16 11:06:50.122850 Caught error: unsupported operand type(s) for /: 'str' and 'int'
2021-04-16 14:22:54.029457 Caught error: unsupported operand type(s) for /: 'str' and 'int'
2021-04-16 14:24:04.609002 Caught error: unsupported operand type(s) for /: 'str' and 'int'
2021-04-16 14:44:34.419407 Caught error: Error 111 connecting to 127.0.0.1:6379. Connection refused.
2021-04-19 17:55:54.666011 Caught error: 'str' object cannot be interpreted as an integer
2021-04-19 21:20:16.907473 Caught error: Error 111 connecting to 127.0.0.1:6379. Connection refused.
2021-04-19 21:32:14.973023 Caught error: Error while reading from socket: (104, 'Connection reset by peer')
2021-04-21 00:26:09.976858 Caught error: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
+35 -19
View File
@@ -21,7 +21,7 @@ def getRedisVal(redisKey):
return redSrv0.get(redisKey).decode('utf-8')
#assegno director log per file di debug
LOG_path = "/home/pi/Flythis/logger/log/"
LOG_path = "/home/pi/Flythis/"
#intervallo in millisecondi fra un campionamento e il successivo
startingSampleFreq = 250
@@ -31,23 +31,35 @@ redSrv0.set(redSampleFreq,startingSampleFreq)
#se non c'è un valore nei campi di redis, popolo il db
redSrv0.set('SETTINGS:DECIMALS:COUNT',3)
redSrv0.set('SETTINGS:LOG:STATUS',0)
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")
redSrv0.set('SETTINGS:FOLDER:CURRENT', "")
if redSrv0.get('SETTINGS:SELECTED_CH') is None:
redSrv0.set('SETTINGS:SELECTED_CH',0)
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)
if redSrv0.get('SETTINGS:IN:MIN:'+str(numCh)) is None:
redSrv0.set('SETTINGS:IN:MIN:'+str(numCh),0)
if redSrv0.get('SETTINGS:OUT:MAX:'+str(numCh)) is None:
redSrv0.set('SETTINGS:OUT:MAX:'+str(numCh),100)
if redSrv0.get('SETTINGS:OUT:MIN:'+str(numCh)) is None:
redSrv0.set('SETTINGS:OUT:MIN:'+str(numCh),0)
if redSrv0.get('SETTINGS:UNIT:MEASURE:'+str(numCh)) is None:
redSrv0.set('SETTINGS:UNIT:MEASURE:'+str(numCh),"-")
if redSrv0.get('SETTINGS:CHANNEL:A') is None:
redSrv0.set('SETTINGS:CHANNEL:A',0)
if redSrv0.get('SETTINGS:CHANNEL:B') is None:
redSrv0.set('SETTINGS:CHANNEL:B',1)
if redSrv0.get('RTDATA:SESSION:NAME') is None:
redSrv0.set('RTDATA:SESSION:NAME',"")
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)
if redSrv0.get('SETTINGS:IN:MIN:'+str(numCh)) is None:
redSrv0.set('SETTINGS:IN:MIN:'+str(numCh),0)
if redSrv0.get('SETTINGS:OUT:MAX:'+str(numCh)) is None:
redSrv0.set('SETTINGS:OUT:MAX:'+str(numCh),100)
if redSrv0.get('SETTINGS:OUT:MIN:'+str(numCh)) is None:
redSrv0.set('SETTINGS:OUT:MIN:'+str(numCh),0)
if redSrv0.get('SETTINGS:UNIT:MEASURE:'+str(numCh)) is None:
redSrv0.set('SETTINGS:UNIT:MEASURE:'+str(numCh),"-")
if redSrv0.get('RTDATA:CH:'+str(numCh)) is None:
redSrv0.set('RTDATA:CH:'+str(numCh),1)
if redSrv0.get('RTDATA:OUT:'+str(numCh)) is None:
redSrv0.set('RTDATA:OUT:'+str(numCh),1)
# init oggetto lettura da
try:
@@ -120,26 +132,30 @@ try:
#eccezione da ctrl+c in terminale e chiusura
except KeyboardInterrupt:
lastLog = datetime.datetime.now()
print (str(lastLog)+" Program End. Ctrl+C from user\r\n")
now = datetime.datetime.now()
dateFormat ="%d/%m/%Y %H:%M:%S"
lastLog = now.strftime(dateFormat)
print (str(lastLog)+" FTSampler End. Ctrl+C from user\r\n")
try:
logFile = open(LOG_path+"PyLog.txt", "a")
except FileNotFoundError:
print("Creating new PyLog.txt")
logFile = open(LOG_path+"PyLog.txt", "w+")
logFile.write(str(lastLog)+" Program end. Ctrl+C from user\r\n")
logFile.write(str(lastLog)+" FTSampler end. Ctrl+C from user\r\n")
logFile.close()
exit()
#eccezione da errore e chiusura
except Exception as errorMessage:
lastLog = datetime.datetime.now()
print(str(lastLog)+" Caught error " + str(errorMessage)+"\r\n")
now = datetime.datetime.now()
dateFormat ="%d/%m/%Y %H:%M:%S"
lastLog = now.strftime(dateFormat)
print(str(lastLog)+" FTSampler: caught error " + str(errorMessage)+"\r\n")
try:
logFile = open(LOG_path+"PyLog.txt", "a")
except FileNotFoundError:
print("Creating new PyLog.txt")
logFile = open(LOG_path+"PyLog.txt", "w+")
logFile.write(str(lastLog)+" Caught error: "+str(errorMessage)+"\r\n")
logFile.write(str(lastLog)+" FTSampler: caught error: "+str(errorMessage)+"\r\n")
logFile.close()
exit()
+28 -6
View File
@@ -108,7 +108,8 @@ def api_channels_all():
'ChRealMin' : getRedisVal('SETTINGS:OUT:MIN:'+str(numCh)),
'LastSessionName' : getRedisVal('RTDATA:SESSION:NAME'),
'GateOpen': getRedisVal('RTDATA:GATE_OPEN'),
'CurrentWorkFolder' : getRedisVal('SETTINGS:FOLDER:CURRENT')
'CurrentWorkFolder' : getRedisVal('SETTINGS:FOLDER:CURRENT'),
'RealDateStatus' : getRedisVal('SETTINGS:TIME:REAL')
}
# restituisce in formato json i dati letti da redis
return jsonify(channelsData)
@@ -256,11 +257,31 @@ def data_delete():
redSrv0.set('SETTINGS:FOLDER:CURRENT', "")
return redirect("/logger")
@flaskApp.route("/api/v1/setup/dateTime", methods=['POST'])
def insertDateTime():
#funzione inserimento data e ora
newDateTime = request.form['dateTimeInput']
if newDateTime == "":
return redirect("/settings")
else:
workedDateTime = datetime.strptime(newDateTime, '%Y-%m-%dT%H:%M')
#formato per salvare data YYYYmmdd
formatDate = "%Y%m%d"
newDate = workedDateTime.strftime(formatDate)
#formato per salvare time hh.mm
formatTime = "%H:%M"
newTime = workedDateTime.strftime(formatTime)
#imposto data e time su raspberry:
os.system("sudo date +%Y%m%d -s " + str(newDate))
os.system("sudo date +%T -s " + str(newTime))
redSrv0.set('SETTINGS:TIME:REAL',1)
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)
redSrv0.set('SETTINGS:PASSWORD:CURRENT', currentPassword, ex=60)
return redirect("/settings")
@flaskApp.route("/api/v1/setup/saveInMin", methods=['PUT'])
@@ -356,11 +377,12 @@ def resetSetup():
# rimando in settings
return redirect("/settings")
@flaskApp.route("/api/v1/setup/FTPowerOff", methods=['POST'])
@flaskApp.route("/api/v1/setup/poweroff", methods=['PUT'])
#spegne il sistema
def FTShutdown():
os.system("sudo shutdown -h +1")
#spegne il sistema dopo 1 minuto
return redirect("/")
redSrv0.set('SETTINGS:TIME:REAL',0)
os.system("sudo shutdown -h now")
#spegne il sistema
#dichiaro host ipv4 (ottenuto sopra utilizzando il modulo socket)
if __name__ == "__main__":
+4
View File
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-power" viewBox="0 0 16 16">
<path d="M7.5 1v7h1V1h-1z"/>
<path d="M3 8.812a4.999 4.999 0 0 1 2.578-4.375l-.485-.874A6 6 0 1 0 11 3.616l-.501.865A5 5 0 1 1 3 8.812z"/>
</svg>

After

Width:  |  Height:  |  Size: 273 B

+6 -4
View File
@@ -4,20 +4,23 @@
<main>
<script>
var intTime=500;
$("#Div0").hide();
var intTime=300;
var timeout = setTimeout(dataRefresh, intTime);
function dataRefresh() {
// scarico i dati aggioranti
$.ajax({url: "/api/v1/channels/all", success: function(result){
$("#ServerTime").html(result.timeSrv);
if(result.RealDateStatus == "0")
{
$("#Div0").show();
}
}});
timeout = setTimeout(dataRefresh, intTime);
};
</script>
<div class="container-fluid">
<div class="card my-2">
<div class="card-header">
<h4>FT Logger</h4>
@@ -28,6 +31,5 @@
Analog/Digital logger software
</div>
</div>
</div>
</main>
{% endblock %}
+24 -3
View File
@@ -4,7 +4,8 @@
<main>
<script>
var intTime=500;
$("#Div0").hide();
var intTime=300;
var timeout = setTimeout(dataRefresh, intTime);
@@ -12,12 +13,26 @@
// scarico i dati aggioranti
$.ajax({url: "/api/v1/channels/all", success: function(result){
$("#ServerTime").html(result.timeSrv);
// if(result.RealDateStatus == "0")
// {
// $("#Div0").show();
// }
}});
timeout = setTimeout(dataRefresh, intTime);
};
//funzione deleteData: chiamata per eliminare il contenuto della cartella /data
function powerOff(){
var R = confirm("Spegnere il sistema?");
if (R == true){
$.ajax({
type: 'PUT'
,url: "/api/v1/setup/poweroff"
,data: ""
})};
};
</script>
<div class="container-fluid text-center">
<div class="row">
<div class="col-12">
<a href="logger" class="btn btn-block btn-primary text-uppercase mt-4">Logger</a>
@@ -35,6 +50,12 @@
<a href="about" class="btn btn-block btn-primary text-uppercase">About</a>
</div>
</div>
</div>
<div class="row">
<div class="col-4"></div>
<button type="button" class="btn btn-danger col-4 my-4" onclick="powerOff()">
<img src="../static/img/power.svg" height="36" width="36"> <br> POWER OFF </button>
</div>
<div class="col-4"></div>
</div>
</main>
{% endblock %}
+18
View File
@@ -44,8 +44,26 @@
<!--contenuto della pagina main-->
<div id="main">
<div class="container-fluid">
<div id="Div0">
<div class="card col-12 my-2">
<div class="row card-header">
<strong>Data e ora</strong>
</div>
<div class="card-body">
<form class="col-12" method="POST" action="/api/v1/setup/dateTime">
<div class="row input-group my-2">
<label for="dateTimeInput" class="input-group-text col-3">Data e Ora: &nbsp;</label>
<input type="datetime-local" class="col-6" id="dateTimeInput" name="dateTimeInput">
<input type="submit" value="Conferma" class="btn btn-success col-3">
</div>
</form>
</div>
</div>
</div>
{% block content %}
{% endblock %}
</div>
</div>
<!--fine contenuto main, inizio footer (data, ora, logo)-->
+20 -11
View File
@@ -4,6 +4,7 @@
<main>
<script type="text/javascript">
$("#Div0").hide();
var intTime=300;
var intTimeSlow=2000;
@@ -32,6 +33,16 @@
$("#ServerTime").html(result.timeSrv);
$("#LastSessionName").html(result.LastSessionName);
$("#CurrentFolder").html(result.CurrentWorkFolder);
if(result.GateOpen == "0")
{
$("#WarnCanc").hide();
}
else if(result.GateOpen == "1")
{
$("#WarnCanc").show();
}
// Se ho una current folder assegnata, la mostro e mostro contenuto. Altrimenti mostro elenco cartelle.
if(result.CurrentWorkFolder == "")
{
@@ -54,24 +65,24 @@
{
$("#btnStart").show();
$("#btnStop").hide();
}
}
else if(result.Status == "1")
{
$("#btnStart").hide();
$("#btnStop").show();
}
if(result.GateOpen == "1")
// se real date status non è stato inserito, mostro div0 che lo chiede
if(result.RealDateStatus == "0")
{
$("#divWarnCanc").show();
}
else
{
$("#divWarnCanc").hide();
$("#Div0").show();
}
//scarico unità di misura dei canali mostrati
$("#UniMisuA").html(result.UniMeasure[result.ChA]);
$("#UniMisuB").html(result.UniMeasure[result.ChB]);
}});
// A ogni giro di data refresh fix di tabella cartelle e tabella file
@@ -278,9 +289,8 @@
}
</script>
<div class="container-fluid">
<div class="row my-2">
<div class="col-12 alert alert-danger text-center" id="divWarnCanc">
<div class="col-12 alert alert-danger text-center" name="WarnCanc" id="WarnCanc">
<h3>CANCELLO APERTO</h3>
</div>
</div>
@@ -373,6 +383,5 @@
</div>
</div>
</div>
</div>
</main>
{% endblock %}
+4 -23
View File
@@ -5,7 +5,7 @@
<script type="text/javascript">
var intTime=300;
refreshInput();
refreshInput();
var timeout = setTimeout(dataRefresh, intTime);
var timeoutSetting = setTimeout(refreshSettings, intTime);
@@ -137,7 +137,6 @@
};
</script>
<div class="container-fluid">
<div id="Div1">
<div class="card my-2 col-12">
<div class="row card-header">
@@ -146,9 +145,9 @@
<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="password" class=" form-control" id="PasswordForm" name="PasswordForm"></input>
<input type="submit" value="LOGIN" class="btn btn-success"></input>
<span class="input-group-text col-3">Password: &nbsp;</span>
<input type="password" class=" form-control col-6" id="PasswordForm" name="PasswordForm"></input>
<input type="submit" value="Login" class="btn btn-success col-3"></input>
</div>
</form>
</div>
@@ -362,24 +361,6 @@
</form>
</div>
</div>
<div class="card my-2 col-12">
<div class="row card-header">
<i class="fas fa-table mr-1"></i>
<strong>System Power Off</strong>
</div>
<div class="card-body mb-4">
<form method="POST" action="/api/v1/setup/FTPowerOff">
<div class="row text-center">
<div class="col-2"></div>
<div class="col-8">
<input type="submit" value="SHUTDOWN SYSTEM" class="btn btn-danger btn-block mt-2" onclick="alert('Power off in 60 seconds')"></input>
</div>
<div class="col-2"></div>
</div>
</form>
</div>
</div>
</div>
</div>
</main>
{% endblock %}