#!/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('SETTINGS:LOG:FREQ') is None: redSrv0.set('SETTINGS:LOG:FREQ', 100) if redSrv0.get('SETTINGS:DECIMALS:COUNT') is None: redSrv0.set('SETTINGS:DECIMALS:COUNT',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', 0) if redSrv0.get('SETTINGS:SMOOTHING:FACTOR') is None: redSrv0.set('SETTINGS:SMOOTHING:FACTOR', 10) 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 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') den = abs(float(v1)-float(v2)) if(den < 0.01): den = 0.01 # calcolo il valore risultante pulito (senza correzioni) XVal = (float(v2)/float(den)) redSrv0.set('RTDATA:VALUE:RAW',round(XVal,decimalsCount)) # Smoothing EWMA valori "grezzi"" strValInRaw = XVal # EWMAx RAW RILEGGO DA REDIS vecchio valore oldValRaw = float(redSrv0.get('RTDATA:VALUE:SMRAW')) if(oldValRaw == 0): oldValRaw = 0.01 # se variazione < 50% smooth, altrimenti usa il valore nuovo if((abs(XVal - oldValRaw) / oldValRaw) < 0.5): # effettuo smoothing valore eFact = 3 strValInRaw = (XVal/eFact) + (oldValRaw * (eFact-1) / eFact) redSrv0.set('RTDATA:VALUE:SMRAW',round(strValInRaw,decimalsCount)) # applicazione correzioni (costanti k1*x^2, k2*x e offset) newValue = (float(k1)*float(XVal)*float(XVal))+(float(k2)*float(XVal))+float(offset) redSrv0.set('RTDATA:VALUE:REAL',round(newValue,decimalsCount)) # Smoothing EWMA valori corretti (fattori k1 k2) strValIn = newValue # EWMA: RILEGGO DA REDIS vecchio valore oldVal = float(redSrv0.get('RTDATA:VALUE:SMOOTHED')) if(oldVal == 0): oldVal = 0.01 # se variazione < 50% smooth, altrimenti usa il valore nuovo if((abs(newValue - oldVal) / oldVal) < 0.5): # effettuo smoothing valore eFact = 3 strValIn = (newValue/eFact) + (oldVal * (eFact-1) / eFact) redSrv0.set('RTDATA:VALUE:SMOOTHED',round(strValIn,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) # 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.0): 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()