#!/usr/bin/python from flask import Flask, render_template, jsonify, request import time from datetime import datetime from flask.wrappers import Request import redis import os, glob import json from werkzeug.utils import redirect import os.path, time from distutils.dir_util import copy_tree import shutil from gpiozero import LED import FTL.FTLog import logging FTL.FTLog.Write(" FTServer started") #silenzio i logger logging.getLogger('werkzeug').disabled = True os.environ['WERKZEUG_RUN_MAIN'] = 'true' #definisco il led led = LED(26) #assegno ipv4 statico ipv4 = '10.10.10.210' #ipv4 = '10.74.82.210' #definisco directory /data dataDir='/home/pi/data/' #configurazione per lavorare su server redis locale REDIS_PORT = 6379 REDIS_HOST = '127.0.0.1' redSrv0 = redis.Redis( host=REDIS_HOST, port=REDIS_PORT, db=0) #funzione per leggere e decodificare da redis def getRedisVal(redisKey): 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 @flaskApp.route("/") #funzione main: passa al template home il titolo def main(): channelsData = { 'title' : 'Home' } #assegno il template html di riferimento return render_template('home.html', **channelsData) @flaskApp.route("/logger") #funzione logger, route a pagina /logger def logger(): channelsData = { 'title' : 'Logger' } #assegno il template html di riferimento return render_template('logger.html', **channelsData) @flaskApp.route("/settings") #funzione setup, route a pagina /setup def setup(): channelsData = { 'title' : 'Settings', } #assegno il template html di riferimento return render_template('settings.html', **channelsData) @flaskApp.route("/about") #funzione about, route a pagina /about def about(): channelsData = { 'title' : 'About' } #assegno il template html di riferimento return render_template('about.html', **channelsData) # 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') # check exe time vs sample time exeWarning = getRedisVal('SETTINGS:WARNING:EXETIME') displayWarning = 0 if exeWarning == "1": displayWarning = 1 elif exeWarning == "0": displayWarning = 0 #check demon warning denZero = getRedisVal('RTDATA:WARNING:DENOMZERO') displayDenomWarning = 0 if denZero == "1": displayDenomWarning = 1 elif denZero == "0": displayDenomWarning = 0 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] OUTMAX = [0,0,0,0,0,0,0,0] UNIMISURA = [0,0,0,0,0,0,0,0] for numCh in range(0,8,+1): CH[numCh] = getRedisVal('RTDATA:CH:'+str(numCh)) OUT[numCh] = getRedisVal('RTDATA:OUT:'+str(numCh)) OUTMIN[numCh] = getRedisVal('SETTINGS:OUT:MIN:'+str(numCh)) OUTMAX[numCh] = getRedisVal('SETTINGS:OUT:MAX:'+str(numCh)) UNIMISURA[numCh] = getRedisVal('SETTINGS:UNIT:MEASURE:'+str(numCh)) channelsData = { 'timeSrv' : getRedisVal('RTDATA:TIME:SRV'), 'WriteFreq' : getRedisVal('SETTINGS:WRITE:FREQ'), 'DecimalsCount' : getRedisVal('SETTINGS:DECIMALS:COUNT'), 'DecimalsDisplay' : getRedisVal('SETTINGS:DECIMALS:DISPLAY'), 'Status' : getRedisVal('SETTINGS:LOG:STATUS'), 'Channels': CH, 'Outs': OUT, 'Outmin': OUTMIN, 'Outmax': OUTMAX, 'UniMeasure' : UNIMISURA, 'CalcUMeasure' : getRedisVal('RTDATA:VALUE:UMEASURE'), 'ChA' : getRedisVal('SETTINGS:CHANNEL:A'), 'ChB' : getRedisVal('SETTINGS:CHANNEL:B'), 'ChScaleMax' : getRedisVal('SETTINGS:IN:MAX:'+str(numCh)), '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'), 'GateOpen': getRedisVal('RTDATA:GATE_OPEN'), 'CurrentWorkFolder' : getRedisVal('SETTINGS:FOLDER:CURRENT'), 'RealDateStatus' : getRedisVal('SETTINGS:TIME:REAL'), 'SelPowerChannel' : getRedisVal('SETTINGS:POWER:CH'), 'SmoothFact' : getRedisVal('SETTINGS:SMOOTHING:FACTOR'), 'EFact' : getRedisVal('SETTINGS:SMOOTHING:EFACT'), 'LogFreq' : getRedisVal('SETTINGS:LOG:FREQ'), 'SelProcessing' : getRedisVal('SETTINGS:SMOOTHING:FUNCTION'), 'ResultValue' : getRedisVal('RTDATA:VALUE:SMOOTHED'), 'RealValue' : getRedisVal('RTDATA:VALUE:SMRAW'), 'Crono' : getRedisVal('SETTINGS:LOG:CRONO'), 'DisplayAlert' : displayWarning, 'DisplayDenomAlert' : displayDenomWarning, 'EwmaEnab' : (redSrv0.get('RTDATA:EWMA:VETO') is None) } # restituisce in formato json i dati letti da redis return jsonify(channelsData) # definisco una NUOVA route a cui rispondere su chiamta in metodo GET x restituire dati aggiornati @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',"") # on load 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 legge direttamente da redis, ritorna jsonify result = { 'numCh' : numCh, 'CostanteK1' : getRedisVal('RTDATA:VALUE:K1CONST'), 'CostanteK2' : getRedisVal('RTDATA:VALUE:K2CONST'), 'Offset' : getRedisVal('RTDATA:VALUE:OFFSET'), 'CalcUMeasure' : getRedisVal('RTDATA:VALUE:UMEASURE'), 'SmoothFact' : getRedisVal('SETTINGS:SMOOTHING:FACTOR'), 'EFact' : getRedisVal('SETTINGS:SMOOTHING:EFACT'), 'ChanThresh' : getRedisVal('SETTINGS:POWER:THRESH'), 'timeSrv' : getRedisVal('RTDATA:TIME:SRV'), 'LogFreq' : getRedisVal('SETTINGS:LOG:FREQ'), 'DecimalsCount' : getRedisVal('SETTINGS:DECIMALS:COUNT'), 'DecimalsDisplay' : getRedisVal('SETTINGS:DECIMALS:DISPLAY'), 'WriteFreq' : getRedisVal('SETTINGS:WRITE:FREQ'), 'TimeBeforeWrite' : getRedisVal('SETTINGS:LOG:WAITIME'), 'CurrIn' : getRedisVal('RTDATA:CH:'+str(numCh)), 'CurrOut' : getRedisVal('RTDATA:OUT:'+str(numCh)), '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)), 'UniMisura' : getRedisVal('SETTINGS:UNIT:MEASURE:'+str(numCh)), 'CurrentWorkFolder' : getRedisVal('SETTINGS:FOLDER:CURRENT'), 'MinUptime' : getRedisVal('SETTINGS:POWER:UPTIME'), '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/folders/list", methods=['GET']) def api_get_folders(): folderList = os.listdir(dataDir) lista = [] idx=0 # for item in sorted(data): for item in folderList: current = {"Elenco Cartelle": item} lista.append(current) idx=idx+1 return jsonify(folderTable = lista) # elenco file nella directory @flaskApp.route("/api/v1/files/list", methods=['GET']) def api_get_files(): currentFolder = getRedisVal('SETTINGS:FOLDER:CURRENT') workingDirectory = (dataDir+currentFolder) if workingDirectory == dataDir: return "OK" else: 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(workingDirectory+"/"+item))) # Transforming the time object to a timestamp T_stamp = time.strftime("%Y-%m-%d %H:%M:%S", t_obj) current = {"Nome": item, "Size (bytes)": os.path.getsize(workingDirectory+"/"+item), "Data creazione":T_stamp} lista.append(current) idx=idx+1 return jsonify(fileTable = lista) # Route di comando x LOG: start e stop @flaskApp.route("/api/v1/log/start", methods=['PUT']) #funzione start_log: scrive su redis LOG:STATUS -> 1 def start_log(): currentFolder = getRedisVal('SETTINGS:FOLDER:CURRENT') workingDirectory = (dataDir+currentFolder) if workingDirectory != dataDir: redSrv0.set('SETTINGS:LOG:STATUS', 1) redSrv0.set('RTDATA:EWMA:VETO', 1) redSrv0.expire('RTDATA:EWMA:VETO', 2) #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) + ".txt" redSrv0.set('RTDATA:SESSION:NAME', nameDate) led.on() return "OK" else: redSrv0.set('SETTINGS:FOLDER:CURRENT', "Default") currentFolder = getRedisVal('SETTINGS:FOLDER:CURRENT') workingDirectory = (dataDir+currentFolder) os.mkdir(workingDirectory) redSrv0.set('SETTINGS:LOG:STATUS', 1) redSrv0.set('RTDATA:EWMA:VETO', 1) redSrv0.expire('RTDATA:EWMA:VETO', 2) #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) + ".txt" redSrv0.set('RTDATA:SESSION:NAME', nameDate) led.on() return "OK" @flaskApp.route("/api/v1/log/stop", methods=['PUT']) def stop_log(): #funzione stop_log: scrive su redis LOG:STATUS -> 0 redSrv0.set('SETTINGS:LOG:STATUS', 0) redSrv0.set('SETTINGS:LOG:WAITER', 0) redSrv0.set('RTDATA:SESSION:NAME', "") led.off() return "OK" @flaskApp.route("/api/v1/data/navigate", methods=['PUT']) def data_navigate(): #funzione torna in /data if(getRedisVal('SETTINGS:LOG:STATUS') == "0"): redSrv0.set('SETTINGS:FOLDER:CURRENT',"") return redirect("/logger") else: return redirect("/logger") @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 """ scriptUnmount = """ sync /bin/umount /mnt/USB """ 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) os.system("bash -c '%s'" % scriptUnmount) 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) if dataDir == workingDirectory: return redirect("/logger") else: if(getRedisVal('SETTINGS:LOG:STATUS') == "0"): shutil.rmtree(workingDirectory) redSrv0.set('SETTINGS:FOLDER:CURRENT', "") return redirect("/logger") else: 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=3600) return redirect("/settings") @flaskApp.route("/api/v1/setup/setupValues", methods=['PUT']) def setupValues(): redSrv0.set('SETTINGS:SMOOTHING:FACTOR', 100) redSrv0.set('SETTINGS:LOG:FREQ', 10) redSrv0.save() return redirect("/settings") @flaskApp.route("/api/v1/setup/workingValues", methods=['PUT']) def workingValues(): redSrv0.set('SETTINGS:SMOOTHING:FACTOR', 25) redSrv0.set('SETTINGS:LOG:FREQ', 20) redSrv0.save() return redirect("/settings") @flaskApp.route("/api/v1/setup/saveInMin", methods=['PUT']) def setupInMin(): # devo leggere il channel attualmente selezionato indCh = getRedisVal('SETTINGS:SELECTED_CH') currChVal = redSrv0.get('RTDATA:CH:'+ str(indCh)) redSrv0.set('SETTINGS:IN:MIN:'+ str(indCh), currChVal) redSrv0.save() return redirect("/settings") @flaskApp.route("/api/v1/setup/saveInMax", methods=['PUT']) def setupInMax(): # devo leggere il channel attualmente selezionato indCh = getRedisVal('SETTINGS:SELECTED_CH') currChVal = redSrv0.get('RTDATA:CH:'+ str(indCh)) redSrv0.set('SETTINGS:IN:MAX:'+ str(indCh), currChVal) redSrv0.save() return redirect("/settings") @flaskApp.route("/api/v1/setup/selectChannelA/", methods=['PUT']) def selectChannelA(numChA): redSrv0.set('SETTINGS:CHANNEL:A', numChA) redSrv0.save() return "OK" @flaskApp.route("/api/v1/setup/selectChannelB/", methods=['PUT']) def selectChannelB(numChB): redSrv0.set('SETTINGS:CHANNEL:B', numChB) redSrv0.save() return "OK" @flaskApp.route("/api/v1/setup/selectChannel/", methods=['PUT']) def setChannel(numCh): redSrv0.set('SETTINGS:SELECTED_CH', numCh) redSrv0.save() return redirect("/settings") @flaskApp.route("/api/v1/setup/selectPowerChannel/", methods=['PUT']) def setPowerChannel(numPowerCh): redSrv0.set('SETTINGS:POWER:CH', numPowerCh) redSrv0.save() return "OK" @flaskApp.route("/api/v1/setup/calcMeasureUnit", methods=['POST']) def VUnitMeasure(): CMeasureUnit = request.form['CalcUMeasure'] redSrv0.set('RTDATA:VALUE:UMEASURE', CMeasureUnit) redSrv0.save() return redirect("/settings") @flaskApp.route("/api/v1/setup/selectProcessing/", methods=['PUT']) def setProcessing(processingType): redSrv0.set('SETTINGS:SMOOTHING:FUNCTION', processingType) redSrv0.save() return "OK" @flaskApp.route("/api/v1/threshold", methods=['POST']) def setPowerThreshold(): powerThreshold = request.form['ChanThresh'] redSrv0.set('SETTINGS:POWER:THRESH', powerThreshold) minUptime = request.form['MinUptime'] redSrv0.set('SETTINGS:POWER:UPTIME', minUptime) redSrv0.save() # rimando in settings return redirect("/settings") @flaskApp.route("/api/v1/smoothFact", methods=['POST']) def setSmoothFact(): smoothingFactor = request.form['SmoothFact'] redSrv0.set('SETTINGS:SMOOTHING:FACTOR', smoothingFactor) redSrv0.save() # rimando in settings return redirect("/settings") @flaskApp.route("/api/v1/eFact", methods=['POST']) def setEFact(): eFactor = request.form['EFact'] redSrv0.set('SETTINGS:SMOOTHING:EFACT', eFactor) redSrv0.save() # rimando in settings return redirect("/settings") @flaskApp.route("/api/v1/frequency", methods=['POST']) def setWriteFrequency(): #funzione set frequenza scrive su redis LOG:FREQ prendendolo dall'input in pagina html con nome LogFreq newLogFrequency = request.form['LogFreq'] redSrv0.set('SETTINGS:LOG:FREQ', newLogFrequency) newWriteFrequency = request.form['WriteFreq'] redSrv0.set('SETTINGS:WRITE:FREQ', newWriteFrequency) timeBeforeWrite = request.form['TimeBeforeWrite'] redSrv0.set('SETTINGS:LOG:WAITIME', timeBeforeWrite) redSrv0.save() # rimando in settings return redirect("/settings") @flaskApp.route("/api/v1/decimalsCount", methods=['POST']) def setDecimalsCount(): #funzione set decimali per i calcoli, scrive su SETTINGS:DECIMALS:COUNT newDecimalsCount = request.form['DecimalsCount'] redSrv0.set('SETTINGS:DECIMALS:COUNT', newDecimalsCount) redSrv0.save() # rimando in settings return redirect("/settings") @flaskApp.route("/api/v1/decimalsDisplay", methods=['POST']) def setDecimalsDisplay(): #funzione set decimali da mostrare, scrive su SETTINGS:DECIMALS:DISPLAY newDecimalsDisplay = request.form['DecimalsDisplay'] redSrv0.set('SETTINGS:DECIMALS:DISPLAY', newDecimalsDisplay) redSrv0.save() # rimando in settings return redirect("/settings") @flaskApp.route("/api/v1/kconst", methods=['POST']) def setKConst(): #scrive su redis la costante K newK1Const = request.form['K1Const'] redSrv0.set('RTDATA:VALUE:K1CONST', newK1Const) newK2Const = request.form['K2Const'] redSrv0.set('RTDATA:VALUE:K2CONST', newK2Const) newOffset = request.form['Offset'] redSrv0.set('RTDATA:VALUE:OFFSET', newOffset) redSrv0.save() # 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/scale", methods=['POST']) def setScale(): indexCh = getRedisVal('SETTINGS:SELECTED_CH') inputMin = request.form['MinIn'] redSrv0.set('SETTINGS:IN:MIN:'+ str(indexCh), inputMin) inputMax = request.form['MaxIn'] redSrv0.set('SETTINGS:IN:MAX:'+ str(indexCh), inputMax) scaleMin = request.form['MinOut'] redSrv0.set('SETTINGS:OUT:MIN:'+ str(indexCh), scaleMin) scaleMax = request.form['MaxOut'] redSrv0.set('SETTINGS:OUT:MAX:'+ str(indexCh), scaleMax) uniMisura = request.form['UniMisura'] redSrv0.set('SETTINGS:UNIT:MEASURE:'+ str(indexCh), uniMisura) redSrv0.save() # rimando in settings return redirect("/settings") @flaskApp.route("/api/v1/setup/resetSettings", methods=['POST']) def resetSetup(): FTL.FTLog.Write(" FTServer asked redis flushall") os.system("sudo redis-cli flushall") return redirect("/logger") @flaskApp.route("/api/v1/setup/poweroff", methods=['PUT']) def FTShutdown(): redSrv0.set('SETTINGS:TIME:REAL',0) FTL.FTLog.Write(" FTServer asked a shutdown") redSrv0.set('SETTINGS:POWER:OFF',1) #spegne il sistema #dichiaro host ipv4 (ottenuto sopra utilizzando il modulo socket) if __name__ == "__main__": FTL.FTLog.Write(" FTServer starting Flask Hosting!") flaskApp.run(host=ipv4, port=80, debug=True)