#!/usr/bin/python from array import * import os import math import time import datetime import ADS1256 import redis import FTL.FTLog import numpy as np FTL.FTLog.Write(" FTSampler started") #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') #definizioni variabili redSamPer='SETTINGS:LOG:EXETIME' redSampleFreq = 'SETTINGS:LOG:FREQ' #se non c'è un valore nei campi di redis, popolo il db redSrv0.set('SETTINGS:LOG:STATUS', 0) redSrv0.set('SETTINGS:POWER:OFF', 0) if redSrv0.get('SETTINGS:WARNING:EXETIME') is None: redSrv0.set('SETTINGS:WARNING:EXETIME', 0) if redSrv0.get('RTDATA:EWMA:VETO') is None: redSrv0.set('RTDATA:EWMA:VETO', 0) if redSrv0.get('SETTINGS:LOG:FREQ') is None: redSrv0.set('SETTINGS:LOG:FREQ', 20) if redSrv0.get('SETTINGS:DECIMALS:COUNT') is None: redSrv0.set('SETTINGS:DECIMALS:COUNT', 3) if redSrv0.get('SETTINGS:DECIMALS:DISPLAY') is None: redSrv0.set('SETTINGS:DECIMALS:DISPLAY', 1) if redSrv0.get('RTDATA:VALUE:K1CONST') is None: redSrv0.set('RTDATA:VALUE:K1CONST', 0) if redSrv0.get('RTDATA:VALUE:K2CONST') is None: redSrv0.set('RTDATA:VALUE:K2CONST', 1) if redSrv0.get('RTDATA:VALUE:OFFSET') is None: redSrv0.set('RTDATA:VALUE:OFFSET', 0) if redSrv0.get('SETTINGS:POWER:UPTIME') is None: redSrv0.set('SETTINGS:POWER:UPTIME', 300) if redSrv0.get('SETTINGS:POWER:CH') is None: redSrv0.set('SETTINGS:POWER:CH', 10) if redSrv0.get('RTDATA:VALUE:UMEASURE') is None: redSrv0.set('RTDATA:VALUE:UMEASURE', "kOhm") if redSrv0.get('SETTINGS:LOG:EXETIME') is None: redSrv0.set('SETTINGS:LOG:EXETIME', 1) if redSrv0.get('RTDATA:VALUE:SMOOTHED') is None: redSrv0.set('RTDATA:VALUE:SMOOTHED', 1) if redSrv0.get('RTDATA:VALUE:RAW') is None: redSrv0.set('RTDATA:VALUE:RAW', 1) if redSrv0.get('RTDATA:VALUE:REAL') is None: redSrv0.set('RTDATA:VALUE:REAL', 1) if redSrv0.get('RTDATA:VALUE:SMRAW') is None: redSrv0.set('RTDATA:VALUE:SMRAW', 1) if redSrv0.get('SETTINGS:POWER:THRESH') is None: redSrv0.set('SETTINGS:POWER:THRESH', 0) if redSrv0.get('SETTINGS:SMOOTHING:FUNCTION') is None: redSrv0.set('SETTINGS:SMOOTHING:FUNCTION', 2) if redSrv0.get('SETTINGS:SMOOTHING:FACTOR') is None: redSrv0.set('SETTINGS:SMOOTHING:FACTOR', 25) if redSrv0.get('SETTINGS:SMOOTHING:EFACT') is None: redSrv0.set('SETTINGS:SMOOTHING:EFACT', 3) 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', "") if redSrv0.get('SETTINGS:SELECTED_CH') is None: redSrv0.set('SETTINGS:SELECTED_CH', 0) if redSrv0.get('SETTINGS:CHANNEL:A') is None: redSrv0.set('SETTINGS:CHANNEL:A', 2) if redSrv0.get('SETTINGS:CHANNEL:B') is None: redSrv0.set('SETTINGS:CHANNEL:B', 3) 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),"V") 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) # calcola la media (colonna x colonna) dei valori ricevuti def calcMean(dataArray): outValues = [0.0] * 8 smoothFunction= int(getRedisVal('SETTINGS:SMOOTHING:FUNCTION')) smoothFact= int(getRedisVal('SETTINGS:SMOOTHING:FACTOR')) # verifico il TIPO di Smoothing richiesto: 0 none, 1 media semplice, 2 RMS if (smoothFunction == 1): # effettuo calcolo media mobile outValues = np.sum(dataArray, axis=0) / smoothFact elif (smoothFunction == 2): # calcolo i quadrati outValues = np.sqrt(np.sum(np.square(dataArray), axis=0) / smoothFact) else: # nessuno smooting, passa il primo dei sample acquisiti outValues = dataArray[0] # restituisco valori calcolati return outValues #funzione salva time+data di log e otto valori su redis def redisSave(CHvalues): decimalsCount = int(getRedisVal('SETTINGS:DECIMALS:COUNT')) redLastLog = 'RTDATA:TIME:LOG' dateFormat ="%d/%m/%Y %H:%M:%S" rawLastLog = datetime.datetime.now() lastLog = rawLastLog.strftime(dateFormat) redSrv0.set(redLastLog,str(lastLog)) for chIndex in range(0,8,+1): redAreaIn = 'RTDATA:CH:'+str(chIndex) redAreaOut = 'RTDATA:OUT:'+str(chIndex) strValIn = float("%.4f" % (CHvalues[chIndex])) #salvo valore IN filtrato redSrv0.set(redAreaIn,round(strValIn,decimalsCount)) # salvo i valori scalati in OUT roundedOut = round(scaleVal(CHvalues[chIndex], chIndex), decimalsCount) redSrv0.set(redAreaOut,roundedOut) #funzione di gestione dei valori grezzi di ingresso dei canali x taratura min/MAX def setupScale(CHvalues): decimalsCount = int(getRedisVal('SETTINGS:DECIMALS:COUNT')) redLastLog = 'RTDATA:TIME:LOG' dateFormat ="%d/%m/%Y %H:%M:%S" rawLastLog = datetime.datetime.now() lastLog = rawLastLog.strftime(dateFormat) redSrv0.set(redLastLog,str(lastLog)) for chIndex in range(0,8,+1): redAreaIn = 'RTDATA:CH:'+str(chIndex) redAreaOut = 'RTDATA:OUT:'+str(chIndex) strValIn = float("%.4f" % (CHvalues[chIndex])) #salvo valore IN filtrato redSrv0.set(redAreaIn,round(strValIn,decimalsCount)) # salvo i valori scalati in OUT roundedOut = round(scaleVal(CHvalues[chIndex], chIndex), decimalsCount) redSrv0.set(redAreaOut,roundedOut) #funzione di refresh valori scalati def scaleVal(inValue, chIndex): #rileggo da redis i valori min/max secondo chIndex chInMin = float(0) if (redSrv0.get('SETTINGS:IN:MIN:'+str(chIndex)) != 0): chInMin = float(redSrv0.get('SETTINGS:IN:MIN:'+str(chIndex))) chInMax = float(3.3) if (redSrv0.get('SETTINGS:IN:MAX:'+str(chIndex)) != 100): chInMax = float(redSrv0.get('SETTINGS:IN:MAX:'+str(chIndex))) chOutMin = float(0) if (redSrv0.get('SETTINGS:OUT:MIN:'+str(chIndex)) != 0): chOutMin = float(redSrv0.get('SETTINGS:OUT:MIN:'+str(chIndex))) chOutMax = float(1000) if (redSrv0.get('SETTINGS:OUT:MAX:'+str(chIndex)) != 100): chOutMax = float(redSrv0.get('SETTINGS:OUT:MAX:'+str(chIndex))) # check denom zero deltaOut = (chOutMax - chOutMin) deltaIn = (chInMax - chInMin) if(deltaIn==0): deltaIn = 1 # calcolo scalato outVal = chOutMin + ((inValue-chInMin) * (deltaOut / deltaIn)) return outVal def checkPowerOff(): powerChannel = getRedisVal('SETTINGS:POWER:CH') if(int(powerChannel) < 10): #controllo che non ci sia già una richiesta di spegnimento if(getRedisVal('SETTINGS:POWER:OFF')=="0"): limitVal = float(getRedisVal('SETTINGS:POWER:THRESH')) actVal = float(getRedisVal('RTDATA:CH:' + str(powerChannel))) #controllo che il valore letto sia inferiore al valore impostato di soglia if(actVal < limitVal): #controllo che il sistema abbia superato l'uptime minimo impostato su redis UptimePower = getRedisVal('SETTINGS:POWER:UPTIME') sysUptime = os.popen("awk '{print $1}' /proc/uptime").readline() if float(sysUptime) > float(UptimePower): # chiedo spegnimento redSrv0.set('SETTINGS:POWER:OFF',1) def calculateValue(): # funzione per calcolare valore risultante (B/A-B) decimalsCount = int(getRedisVal('SETTINGS:DECIMALS:COUNT')) ch1 = getRedisVal('SETTINGS:CHANNEL:A') ch2 = getRedisVal('SETTINGS:CHANNEL:B') v1 = getRedisVal('RTDATA:OUT:' + ch1) v2 = getRedisVal('RTDATA:OUT:' + ch2) k1 = getRedisVal('RTDATA:VALUE:K1CONST') k2 = getRedisVal('RTDATA:VALUE:K2CONST') offset = getRedisVal('RTDATA:VALUE:OFFSET') eFact = int(getRedisVal('SETTINGS:SMOOTHING:EFACT')) # check val min di 1 x denom EWMA... if(eFact < 1): eFact = 1 # fix valore minimo denominatore den = abs(float(v1)-float(v2)) if(den < 0.05): den = 0.05 redSrv0.set('RTDATA:WARNING:DENOMZERO', 1) else: redSrv0.set('RTDATA:WARNING:DENOMZERO', 0) # calcolo il valore risultante RealTime pulito (senza correzioni) XVal = (float(v2)/float(den)) redSrv0.set('RTDATA:VALUE:RAW',round(XVal,decimalsCount)) # # correzione fattore di scala K2 su cifre significative # corrDecCount = decimalsCount - int(round(math.log(float(k2),10),0)) # if (corrDecCount < 0): # corrDecCount = 0 # applicazione correzioni (costanti k1*x^2, k2*x e offset) in RT YVal = (float(k1)*float(XVal)*float(XVal))+(float(k2)*float(XVal))+float(offset) # redSrv0.set('RTDATA:VALUE:REAL',round(YVal,corrDecCount)) redSrv0.set('RTDATA:VALUE:REAL',round(YVal,decimalsCount)) # procedo SOLO SE il veto EWMA non è presente... eVeto = getRedisVal('RTDATA:EWMA:VETO') if (redSrv0.get('RTDATA:EWMA:VETO') is None): # Smoothing EWMA valori "grezzi" (= medio sul passato) --> ottengo valori "X filtrati" # RILEGGO DA REDIS vecchio valore XValOld = float(redSrv0.get('RTDATA:VALUE:SMRAW')) XValEwma = (XVal/eFact) + (XValOld * (eFact-1) / eFact) else: # NON faccio nulla XValEwma = XVal # salvo XVal! redSrv0.set('RTDATA:VALUE:SMRAW',round(XValEwma,decimalsCount)) # applicazione correzioni (costanti k1*x^2, k2*x e offset) sul valore "X filtrato" YValEwma = (float(k1)*float(XValEwma)*float(XValEwma))+(float(k2)*float(XValEwma))+float(offset) # redSrv0.set('RTDATA:VALUE:SMOOTHED',round(YValEwma,corrDecCount)) redSrv0.set('RTDATA:VALUE:SMOOTHED',round(YValEwma,decimalsCount)) # init array smoothFact= int(getRedisVal('SETTINGS:SMOOTHING:FACTOR')) initArray = [0.0] * 8 meanValues = [0.0] * 8 dataBox = np.array([initArray] * smoothFact) redisTime = 'RTDATA:TIME:SRV' # init oggetto lettura Digital Analog try: CH = ADS1256.ADS1256() CH.ADS1256_init() #ciclo principale while(1): # update freq campionamento da redis sampleFreq = getRedisVal(redSampleFreq) smoothFact= int(getRedisVal('SETTINGS:SMOOTHING:FACTOR')) dataBox = np.array([initArray] * smoothFact) now = datetime.datetime.now() dateFormat ="%d/%m/%Y %H:%M:%S" lastLog = now.strftime(dateFormat) redSrv0.set(redisTime,str(lastLog)) for counter in range(0,smoothFact,+1): # leggo gli 8 valori CHvalue = CH.ADS1256_GetAll() floatArray = np.array(CHvalue, dtype=float) dataBox[counter] = floatArray*float(5.0/0x7fffff) # calcolo e scrittura ogni NUM PERIOD cicli if counter == (smoothFact-1): # faccio gli smoothing colonna x colonna meanValues = calcMean(dataBox) #salvo valori redisSave(meanValues) #verifica se sono in fase di salvataggio min/max x taratura valori ingresso setupScale(meanValues) # controllo soglia spegnimento checkPowerOff() # calcolo il valore k*[V2/(V1-V2)] + offset calculateValue() # riporto ultima esecuzione ad adesso endExec = datetime.datetime.now() # calcolo il delta time dovuto alle esecuzioni delta = endExec - now # attesa viene fatta sempre waitTime = (int(sampleFreq)*smoothFact)/1000 - delta.microseconds/1000000 if(waitTime < 0.001): redSrv0.set('SETTINGS:WARNING:EXETIME',1) else: redSrv0.set('SETTINGS:WARNING:EXETIME',0) if(waitTime < 0.001): waitTime = 0.001 # vera attesa time.sleep(waitTime) #eccezione da ctrl+c in terminale e chiusura except KeyboardInterrupt: FTL.FTLog.Write(" FTSampler stopped by Ctrl+C") exit() #eccezione da errore e chiusura except Exception as errorMessage: FTL.FTLog.Write(str(" FTSampler stopped: " + errorMessage)) exit()