# pir2A.py A40 global g_pir2AVer g_pir2AVer="A40" # this is the code module containing most of the #python3 code for the PiR2 system #pi # NB the ioDeviceArray is defined in pir2Data.py # # pg LIST OF MODULES # 1 List of Modules # 2 list of globals # 2 identifyTask() # 3 initializeTask() # 7 createLogCopy() # 7 createNewEmptyLogTask() # 8 queuehelloTask() # 8 helloTask() # 8 manageTasks() # 9 appendToLog() # 11 acquire_procTemp() # 12 osCommand() # 13 getControl_fromOwner() # 14 control_fromOwner() # 16 pir2_performAorC # 18 control_audioTV() # 18 control_piArea # 18 acquire_piSN # 18 acquire_piIP # 19 displayHeader() # 19 displayLog() # 20 unixTime() # 21 askVerbose() # 21 openLog2() # 21 informUserWait() # 22 isLogAvailable() # 25 piR2_findStrInArray() # 25 piR2_ioDeviceAttribute() # 25 piR2_attrFromStr() # 27 sortableDateTime() # 29 pir2_convertMIC_ControlTask() # 30 pir2versions() import pir2Data # NB pir2Data defines contents of (and array sizes) # pir2A.g_numioDevices # pir2A.g_ioDeviceArray[i] # pir2A.g_fileArray[i] import time import os import subprocess # NB in Python, # A global variable (eg g_AA) needs to be declared as global # in every module (ie in every function that references it) # in this library. # Other modules not in this library (eg PiR2main.py) must # reference these global variables with a prefix eg PiR2.g_AA # to show where the variable can. These references can be # to "read" or "write" the variable. # Arrays must have all their elements defined before being referenced. # list of global variables # global g_firstRecId # global g_helloTaskNumber # global g_isPythonVersion3Str # global g_ioDeviceArray # global g_isAddingNewLine # global g_lastRecId # global g_piIPStr # global g_piSN_Str # global g_piAreaStr # global g_startTime[] # global g_startTimeArray[] # global g_taskArray[] # global g_pir2AVer # global g_pir2mainVer # global g_pir2DataVer # global g_pir2VersionsVer # global g_validateLogVer # global g_pir1AVer # global g_globalTestVer # global g_sDateTimeVer def identifyTask(): print("***************************") print("* PiR2 controller by D@CC *") print("* pir2A.py v"+g_pir2AVer+" *") print("* (c) Silver Software *") print("* from MehInControl.com *") print("* Version 0.2 2019GJul19 *") print("***************************") # Purpose # This python3 software is the main module of the PiR2 controller. It # normally runs on a Raspberry Pi equipped with a PiR2 controller board. # although it will run without the PiR2 controller board. This # function identifies the PiR2 software. The functions defined and # used by the PiR2 software are all defined in the pir2A.py library # which must be imported into the piR2main.py module. # # PiR2 libraries used by the PiR2 controller software: # pir2Data.py # # Non-PiR2 libraries used by the PiR2 controller software: # (imported in piR2_main.py) # from os import system, name # from time import sleep # from subprocess import call ??? # import os # return #end def identifyTask() def initializeTask(fileArray): # @ purpose To initialize everything necessary # # @param0 array fileArray which is g_fileArray # @returns nothing # # LEXICAL CONVENTIONS # conditional variables begin with is... # string variables end with ...Str # list variables end with ...Array # count variables begin with num... # task functions end with ...Task # global variables begin with g_..... # #end etc follows each if, while or for compound statement # doh=0 is a null statement eg after an else: null global g_startTimeArray global g_helloTaskNumber global g_taskArray #print('fileArray[0]:',fileArray[0],":") #print('fileArray[1]:',fileArray[1],":") #exit() #define g_ioDeviceArray array as global but no elements # just out global g_ioDeviceArray print("**************************************************") print("begin PiR2 initialization") # The number of tasks defined is 1 # create the taskQueue g_startTime=[0,1,2] #define each task in the PiR2 system #define the first task g_helloTaskNumber=0 g_taskArray=[0,1,2] g_taskArray[g_helloTaskNumber]="helloTask" #define other globals global g_lastRecId g_lastRecId=0 #define fileArray array as global but no elements # passed in: g_fileArray as fileArray # defines global g_fileArray only because it uses it #g_fileArray=[0,1,2,3,4] #g_fileArray[0]="/home/pi/Desktop/PiR2/files/PiR2_Log" #g_fileArray[1]="/home/pi/Desktop/PiR2/files/PiR2_Log.txt" #g_fileArray[2]="/home/pi/Desktop/PiR2/files/commandResult.txt" #g_fileArray[3]="/home/pi/Desktop/PiR2/Audio/" #g_fileArray[4]="/home/pi/Downloads/PiR2_Control_" # +piSN+"_txt.html" import os #if there is no log file, create it logFileNameWoTXT=fileArray[0] #logFileNameWoTXT="/home/pi/Desktop/PiR2/files/PiR2_Log" logFileName=logFileNameWoTXT+".txt" if os.path.exists(logFileName) and os.path.getsize(logFileName) >0: #non-empty Log file exists print("Log file exists") #print("HIT ENTER TO CONTINUE") #aStr=input() #get id of last log record logF=open(logFileName,"r") i=0 #new improved file read algorithm #in initializeTask recStr="na" lastRecStr="na" prevRecStr="na" numNulls=0 #get piSN global g_piSN g_piSN=acquire_piSN() #remove trailing \n if it exists #g_piSN.rstrip() print("new piSN:"+g_piSN+":") isVerbose=True #where should this be defined???? while True: # ends when BREAK is encountered #print("Read next record.") #prevRec=recStr recStr=logF.readline() lenStr=len(recStr) if (not recStr): #test if EOF break #if EOF then BREAK out of WHILE LOOP #end if if lenStr==1 : #indicates a Null record (only \n) numNulls+=1 if numNulls==1 : if isVerbose==True: print("WARNING-First Null record is #:",i) #end if else: i+=1 if(i==1) : firstRecStr=recStr #end if prevRecStr=lastRecStr lastRecStr=recStr #end if #end while logF.close() #get id of first record # split records into parts by commas result=firstRecStr.split(",") global g_firstRecId g_firstRecId=int(result[0]) #print ("First RecordID:"+str(g_firstRecId)+":") # get id of last record #print ("Last Record:",lastRecStr) #remove any white space (before or after) lastRecStr=lastRecStr.rstrip() lastRecStr=lastRecStr.lstrip() numCol=lastRecStr.find(",") print("numCol:",numCol) if numCol==-1 : lastRecStr=prevRecStr lastRecStr=lastRecStr.rstrip() lastRecStr=lastRecStr.lstrip() numCol=lastRecStr.find(",") #end if #print(ord(lastRecStr[0:1])) #print(ord(lastRecStr[1:2])) #print(ord(lastRecStr[2:3])) #print(ord(lastRecStr[3:4])) print("numCol:",numCol) print ("Last Record:",lastRecStr) print ("lenLastRecord",len(lastRecStr)) #if lastRecStr=="" : # lastRecStr=secondLastRecStr #end if result=lastRecStr.split(",") print("result:",result) #initialize the last record id #global g_lastRecId g_lastRecId=int(result[0]) print ("Last RecordID:"+str(g_lastRecId)+":") print("HIT ENTER TO CONTINUE:") #print("Creating PiR2_Log_id-id:") createLogCopy(g_firstRecId,g_lastRecId,logFileName,logFileNameWoTXT) #now replace the old log file logFileNameNew=logFileName #print("Creating 2 rec. log:"+logFileNameNew+":") logF=open(logFileNameNew,"w") lastRecStrWnewline=lastRecStr if g_isAddingNewLine==True : lastRecStrWnewline=lastRecStrWnewline+"\n" #end if logF.write(lastRecStrWnewline) logF.close() #begin with a last record of old log file #****************************************** unitsStr=" " #Control... parameters: pir2A.g_ioDeviceArray,pir2A.g_prevValueArray, \ #pir2A.g_isAddingNewLine #then a record defining the piSN (even if record begins with "SN" instead print("Before call appendToLog from InitializeTask") appendToLog(g_piSN_Str,"A",unixTime(),"piSN",g_piSN,unitsStr, \ g_ioDeviceArray,g_prevValueArray,g_isAddingNewLine,fileArray) print("Created a 2 rec. log with g_piSN:"+g_piSN+":") #print("HIT ENTER TO CONTINUE:") #aStr=input() else: #no log exists #initialize a new log file with a recordID of 0 etc recStr="need to create it" createNewEmptyLogTask(logFileName,recStr,"SN",-1,unixTime(),fileArray) #end if # the helloTask is not yet queued to start g_startTime[g_helloTaskNumber]=0 #return #end def initializeTask() def createLogCopy(idRecFirst,idRecLast,logFileName,logFileNameWoTXT): #print("Creating PiR2_Log_id-id:") logFileNameCopy=logFileNameWoTXT logFileNameCopy=logFileNameCopy+"_"+str(idRecFirst) lastIdToWriteStr=str(idRecLast-1) if (idRecLast<=idRecFirst): print("NOT writing an empty Log append file") exit() else: logFileNameCopy=logFileNameCopy+"-"+lastIdToWriteStr+".txt" logF=open(logFileName,"r") logCopyF=open(logFileNameCopy,"w+") lastIdToBeWrittenStr=str(idRecLast-1) writtenIdStr=str(idRecFirst) iCnt=0 while writtenIdStrfiles/resultStr.txt") # strip off any trailing new line (ie line feed) resultStr=resultStr.rstrip() resultStr=resultStr[5:9] else: resultStr="49.8" # same format as after editing from vcgencmd #end if #print("resultStr: "+resultStr) return resultStr #end if #end def acquire_procTemp() def osCommand(commandStr): # @purpose: to issue a system command and return the result # @param1: str commandStr eg: "vcgencmd measure_temp" # @returns: str commandResultStr eg: "temp=36.9'C" from subprocess import call #import os from os import system, name, remove from time import sleep #print("osCommand received commandStr:"+commandStr) commandResultStr="none" global g_fileArray #commandRFileName=g_fileArray[2] commandRFileName="/home/pi/Desktop/PiR2/files/commandResult.txt" # name is not a function, but a special variable if name == 'nt': _ =system('cls') else: if (commandStr=="clear"): print("before clear") _= system("clear") print("after clear") else: if (False): # in case no file exists, appending something will create it # for sure fh=open(commandRFileName, "a") fh.write("any") fh.close() # now remove it remove(commandRFileName) #endif # save result in txt file saveOutputStr=" >"+commandRFileName revisedCommandStr=commandStr+saveOutputStr #print("revisedCommandStr:"+revisedCommandStr) #invoke system command _= system(revisedCommandStr) fh=open(commandRFileName, "r") # read the result of the command commandResultStr=fh.readline() fh.close() #end if return commandResultStr #end if #end def osCommand() def getControl_fromOwner(array,prevValueArray,g_isAddingNewLine,fileArray): # @purpose: accept and log a fromOwner command (containing a ":") # to display the log (comments have no ":") # @param0 array g_ioDeviceArray as defined in pir2Data.py # @param1 str fromOwnerValueStr eg "acquire:piSN" # @param2 array prevValueArray eg # eg2 "piArea:GreatRoom" # @param3 array fileArray eg g_fileArray # @returns nothing ################################################################ # maybe move these to the initialize routine ???????? global g_piSN_Str g_piSN_Str=acquire_piSN() #this works #print("piSN:"+g_piSN_Str+":") # but don't display the piSN while testing ################################################################ g_piSN_Str="SN" #should get the unitsStr from the ioDevice array unitStr="" ######################################## #a=input("after acquire_piSN(): Hit Enter") ################################################################ global g_piIPStr g_piIPStr=acquire_piIP() #this works, #print("piIP:"+g_piIPStr+":") #a=input("after acquire_piIP(): Hit Enter") global g_isPythonVersion3Str g_isPythonVersion3Str="True" posColon=0 colonStr=":" fromOwnerValueStr=colonStr while (fromOwnerValueStr.find(colonStr) != -1): global g_lastRecId #print("g_lastRecId:"+str(g_lastRecId)+":") print("Enter a fromOwner command eg piArea:Great_Room ") fromOwnerValueStr=input(" or Return(<-) to monitor the Log:") #print("fromOwnerValueStr:"+fromOwnerValueStr) #log1Str=g_piSN_Str+","+"C" #log2Str="fromOwner"+","+fromOwnerValueStr+","+unitsStr if fromOwnerValueStr =="" : doh=0 #null statement #do not append it else: #unitsStr=piR2_ioDeviceAttribute(array,"fromOwner","unitsUsed") #print("unitsStr:"+unitsStr) ##################################################################### #from line 555 of piR2A unitsStr="" # append to log the "fromOwner" value #print("about to append to Log fromOwner") appendToLog(g_piSN_Str,"C",unixTime(),"fromOwner",fromOwnerValueStr, \ unitsStr,array,prevValueArray,g_isAddingNewLine,fileArray) # end if if (fromOwnerValueStr.find(colonStr) != -1): #print("found a colon") #if it has a ":" in the reply #process the control_fromOwner command control_fromOwner(array,fromOwnerValueStr,prevValueArray) ##################################################################### else: doh=0 #fall through to test the while again #end if #end while return #end def getControl_fromOwner() def control_fromOwner(array,fromOwnerValueStr,prevValueArray): # @purpose: to process the control commands received # via the MIC Control file (wrapped in html tags) # @param0 array g_ioDeviceArray as defined in pir2Data.py # @param1 str fromOwnerValueStr eg "acquire:piSN" # @param2 array prevValueArray eg # eg2 "piArea:BedRoom" # @returns nothing colonStr=":" parts=fromOwnerValueStr.split(colonStr) #print("parts:",parts) part0=parts[0] if part0=="acquire": ioDeviceFromOwner=parts[1] ioValueFromOwner="" #no value from Owner when acquiring data isAcquire=True else: # eg "acquire:piSN" ioDeviceFromOwner=parts[0] ioValueFromOwner=parts[1] #print("ioValueFromOwner:"+ioValueFromOwner+":") ioValue=parts[1] #print("ioValue:"+ioValue) isAcquire=False #end if # now perform the requested action and then # append to log the info received fromOwner # but only if it is a valid ioDevice name # g_ioDeviceArray is defined in the mainprogram # eg ioDeviceFromOwner is "piArea" # if ioDevice is not defined, the line below will return "" ioDeviceRec=piR2_findStrInArray(array, \ "|nameDevice|"+ioDeviceFromOwner+"|") if ioDeviceRec == "" : print("WARNING: ioDevice:"+ioDeviceFromOwner+" is not yet Defined") #so don't process it else: # it exists, so process it now acStr="C" if isAcquire==True: acStr="A" #actually perform the Acquire or Control action ioValueToLog=pir2_performAorC(array,ioDeviceRec,ioDeviceFromOwner, \ ioValueFromOwner,acStr) # get the units unitsStr=piR2_ioDeviceAttribute(array,ioDeviceFromOwner,"unitsUsed") #print("unitsStr:"+unitsStr) # now write it to the log appendToLog(g_piSN_Str,acStr,unixTime(),ioDeviceFromOwner,ioValueToLog, \ unitsStr,array,prevValueArray,g_isAddingNewLine,g_fileArray) # clear this "fromOwner reply" fromOwnerValueStr=colonStr #print("clear the fromOwner reply") #end if return #end def control_fromOwner() def pir2_performAorC(array,ioDeviceRec,ioDeviceFromOwner,ioValueFromOwner,acStr): # @Purpose to perform the "acquire" or "control" function that # was requested by the Owner # @param0 array g_ioDeviceArray as defined in pir2Data.py # @param1 record ioDeviceRec row of above arrayfor ioDevice # @param2 str ioDeviceFromOwner eg piSN the exact ioDevice name # @param3 str ioValueFromOwner eg alarm.wav # @param4 str acStr eg "A" A:Acquire or C:Control # # returns str ioValueToLog eg 192.168.0.10 #print("ioDeviceRec:"+ioDeviceRec+" is Defined") if acStr=="A": #print("isAcquire:True") #acStr="A" ioValueToLog="unassigned" if ioDeviceFromOwner=="piArea": ioValueToLog=g_piAreaStr #end if if ioDeviceFromOwner=="piSN": #get the actual piSN not the g_piSN_Str # which contains "SN" during testing ioValueToLog=acquire_piSN() #end if if ioDeviceFromOwner=="piIP": ioValueToLog=g_piIPStr #end if if ioDeviceFromOwner=="lastRecId": ioValueToLog=str(g_lastRecId) #end if if ioDeviceFromOwner=="logA": ioValueToLog=g_logAStr #end if else: ioValueToLog=ioValueFromOwner #acStr="C" #unitsStr="" #print("ioDeviceRec:"+ioDeviceRec) #look up the unitsUsed unitsStr=piR2_ioDeviceAttribute(array,ioDeviceFromOwner,"unitsUsed") #print("unitsStr:"+unitsStr) #print("invoking the Control action:"+ioDeviceFromOwner) #now invoke the Control (before logging it) # do this only for physical (not data) devices if ioDeviceFromOwner=="audioTV": control_audioTV(ioValueFromOwner) #end if #use the ioDevice defined by the Owner if ioDeviceFromOwner=="piArea": control_piArea(ioValueFromOwner) #end if #end if return ioValueToLog #end def pir2_performAorC() def control_audioTV(soundByteMp3OrWav): global g_fileArray audioFolder=g_fileArray[3] #audioFolder="/home/pi/Desktop/PiR2/Audio/" commandStr="omxplayer "+audioFolder+soundByteMp3OrWav #print("commandStr:"+commandStr+":") osCommand(commandStr) #print("after commandStr") return #end def control_audioTV() def control_piArea(roomNameStr): global g_piAreaStr #print("Before g_piAreaStr definition") g_piAreaStr=roomNameStr #print("g_piAreaStr:"+g_piAreaStr+":") return #end def control_piArea() def acquire_piSN(): commandStr="grep Serial /proc/cpuinfo" piSN_Str=osCommand(commandStr) #print("piSN_Str:"+piSN_Str+":") #piSN_Str=piSN_Str.rstrip() #print("piSN_Str:"+piSN_Str+":") piSN_Str=piSN_Str[12:34] #remove any trailing \n, if it exists piSN_Str=piSN_Str.rstrip() #print("piSN_Str:"+piSN_Str+":") return piSN_Str #end def acquire_piSN() def acquire_piIP(): commandStr="ifconfig | grep inet" piIP_Str=osCommand(commandStr) #print("piIP_Str:"+piIP_Str+":") piIP_Str=piIP_Str[20:39] #print("piIP_Str:"+piIP_Str+":") piIP_Str=piIP_Str.rstrip() #print("piIP_Str:"+piIP_Str+":") piIP_Str=piIP_Str.rstrip(" Bcast:") #print("piIP_Str:"+piIP_Str+":") return piIP_Str #end def acquire_piIP() def displayHeader(dateInStr): # @Purpose To display the refreshing log header # @Param0 str dateInStr "2019GJul23" # @returns nothing global g_pir2AVer global g_piAreaStr global g_piIPStr global g_piSN # display the log header #print("g_piAreaStr:"+g_piAreaStr+":") # g_piArea Str="This_Room" recStr="piArea:"+g_piAreaStr #print(recStr) #print("g_piIPStr:"+g_piIPStr+":") # g_piIPStr="192.192.192.192" recStr="piIP:"+g_piIPStr+" piSN:"+g_piSN+"." print(recStr,) recStr="Log date: ["+dateInStr+"] v:"+g_pir2AVer print(recStr) print(" id# SN ac hh:mm:ss.xxx ioDevice Value Units") #end #end def displayHeader() def displayLog(): # @purpose display the log file # @param0 none # @returns nothing global g_fileArray log=open(g_fileArray[1],"r") #log=open("/home/pi/Desktop/PiR2/files/PiR2_Log.txt","r") #count the records numRecs=0 for x in log: numRecs += 1 #end for log.close() logArray=[0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5] numActualRecords = numRecs #***************************** #print("logCount:",str(numActualRecords)) # read the Log file again # saving the displayable records in the logArray logFileName=g_fileArray[1] #logFileName="/home/pi/Desktop/PiR2/files/PiR2_Log.txt" log=open(logFileName,"r") numToDisplay=24 for x in range(numActualRecords): recStr = log.readline() if (x> (numActualRecords-numToDisplay-1)): y=numActualRecords-x-1 #print("y:",y,":",recStr.rstrip()) logArray[y]=recStr.rstrip() #end if #end for log.close() y=1 #print(y, logArray[y]) # now display the saved displayable records # range(24) actually means 0,1,2,.... 23 for y in range(numToDisplay): #print(y,":",logArray[y],) print(logArray[y],) #end for print("***") #end def displayLog() def unixTime(): # @Purpose to return the current time as unix time string # @param0 nothing # @returns str tStr eg 1234567890.123 import time rFloat=time.time() #print("rFloat:",rFloat) x=str(rFloat).find(".") #print("x:",x) tStr=str(rFloat) tStr=tStr[0:14] #print("tStr:",tStr) return tStr #end def unixTime() def askVerbose(isQuerying): # @Purpose To ask the user if verbose interactions should be used # @param cond isQuerying eg True (will stop & ask user) # @returns cond isVerboseResult eg True # if called with False, it will not ask anything # and will stay in NOT verbose mode isVerboseResult=False if isQuerying==True: isVerboseResult=True a=input("For NOT verbose,hit Enter: ") if a=="": isVerboseResult=False #end if #end if return isVerboseResult #end def askVerbose(): def openLog2(isVerbose,logFileName,errorMessageStr): # @Purpose Tries to open the specified file # NB Program stops if this fails # @param0 cond isVerbose eg True # @param1 str logFileName eg "/home/pi/Desktop/PiR2/files/PiR2_Log.txt" # @param2 str errorMessageStr eg eg "ERRORxxx-Bad File Name:" # @returns file handle eg log if not(os.path.exists(logFileName) and (os.path.getsize(logFileName)>0)): # NB File is not available print(errorMessageStr) exit() else: log= open(logFileName, "r") if isVerbose==True: print("Opened file name:",logFileName) #end if return log #end def openLog2() def informUserWait(isVerbose,secondsDt,countBy5): # @param1 cond isVerbose eg True # @param2 int secondsDt eg 1 # @param3 int countBy5 eg 20 # # @returns nothing # Now wait 20 seconds and check to see if Log File length has changed if isVerbose==True: print("monitoring Log use for 20 seconds (is it growing?)") #end if i=0 for j in range(int(countBy5/5)): for k in range(int(countBy5/5)): i+=1 if g_isPythonVersion3Str=="True" : endStr='end=" "' else: endStr="2." #end if if isVerbose==True: print(".", endStr) time.sleep(secondsDt) #end for i+=1 print (".") time.sleep(secondsDt) #end for return #end def informUserWait() def isLogAvailable(logFileName): # @Purpose to check if the log file is available # ie not already being used by another running process # @param0 str logFileName eg "....PiR2_Log.txt" # @returns cond isQuerying eg True if Log file is available # ie not active (ie not in use) # called from pir2main.py # @param none # #logFileName="/home/pi/Desktop/PiR2/files/PiR2_Log.txt" # True means "ask the user if verbose info is wanted" ####################################################### # This can be set False to NOT ask the user ####################################################### isQuerying=True # ask user who will # hit return for non-verbose isVerbose =askVerbose(isQuerying) print("Watching (20 sec) to see if log file is available. . . :") import os numNulls=0 # return True if Log doesn't exist yet if os.path.exists(logFileName) and os.path.getsize(logFileName) >0: #non-empty Log file exists log=openLog2(isVerbose,logFileName,"ERROR-Bad File Name:") #NB size is the total size of the file (in bytes) size=os.path.getsize(logFileName) i=0 # in isLogAvailable recStr="na" #prevRec="na" while (True): prevRec=recStr #recStr has no trailing \n (New Line) recStr=log.readline() #recStr as read always has trailing \n lenStr=len(recStr) if (not recStr ): #test if eof break #out of the while NB BREAK OUT OF THE WHILE LOOP #end if #if i==0 : # print("i:"+str(i)) #end if i=i+1 #count the records if lenStr==1 : #if it only has the \n numNulls+=1 if numNulls==1: #mention only the first one if isVerbose==True: print("WARNING: first null record is #:",i) #end if else: #recStr=recStr[0:lenStr-1] #strip trailing \n (New Line) recStr=recStr.rstrip() #strip trailing \n (New Line) # and any spaces (unfortunately) lenStr=len(recStr) # revise lenStr #print(i,",",lenStr,",",recStr) #end if #end while ie until isEof=True (accomplished by the "break") lenStr=len(recStr) if isVerbose==True: print("last Log record:",prevRec) log.close() lenLogFile=i #as counted in the while loop if isVerbose==True: print("log file had ",lenLogFile," records.") avgRecLen=int(size/lenLogFile) if isVerbose==True: print("avgRecLen=",avgRecLen) if numNulls>0: if isVerbose==True: print("WARNING-Total # of Null records:", \ numNulls) #end if informUserWait(isVerbose,1,20) #20 seconds in 1 second intervals log=openLog2(isVerbose,logFileName,"ERROR011-File disappeared...doh:") newSize=os.path.getsize(logFileName) log.close() if newSize>size : numRecs=int((newSize/avgRecLen)+0.5) if isVerbose==True: print("Log now has ",numRecs,"records.") if isVerbose==True: print("Log file is IN USE") returnTruthValue= False else: # log file is not in use, ie available returnTruthValue= True #end if else: # log file is empty or doesn't exist yet ####################################################### returnTruthValue= True ####MUST INVESTIGATE #### ####################################################### return returnTruthValue #end def isLogAvailable() def piR2_findStrInArray(array,typeandtextStr): #This function returns the first matching list # in the passed array # or a null string # @purpose to provide the list of attributes for a specified ioNameDevice # from an array of all the PiR2 ioDevices. # The ioNameDevice is unique for each row of the array # eg find and return the full list of attributes for the # ioDevice whose "nameDevice" is "procTemp" # @param1 array array eg g_ioDeviceArray # @param2 str ioNameDevice eg "|nameDevice|procTemp|" # @returns list array[n] eg |id|0001| |ioCode|A002| ...|KER|0| # #array is passed in #number of rows in the Array is the height (ie len(array) ) global g_ioDeviceArray returnList="" if typeandtextStr !="": height=len(array) #print("height: ",height) foundThisRecordNumber=-1 for x in range(height): #strRec=array[x]) if type(array[x])==str: found=array[x].find(typeandtextStr) if found !=-1: foundThisRecordNumber=x #end if #end if #end for if foundThisRecordNumber != -1: returnList=array[foundThisRecordNumber] #endif return returnList #end def piR2_findStrInArray() def piR2_ioDeviceAttribute(array,ioNameDevice,attributeName): # @purpose to provide the attribute value for a specified atributeName # for a specified ioNameDevice # from an array of all the PiR2 ioDevices. # The ioNameDevice is unique for each row of the array # eg find and return "d'C" as unitsUsed for procTemp # @param0 array array eg g_ioDeviceArray # @param1 str ioNameDevice eg procTemp # @param2 str attributeName eg unitsUsed # # @returns str result eg d'C (for procTemp) # #print("DEBUG: In piR2_ioDeviceAttribute") # array is g_ioDeviceArray #print("ioNameDevice:"+ioNameDevice) #print("attributeName:"+attributeName) searchForStr="|nameDevice|"+ioNameDevice+"|" #print("searchForStr:"+searchForStr) # ioAttribues is a python "list" of all the attributes ioAttributes=piR2_findStrInArray(array,searchForStr) data=ioAttributes.split() #print("data:",data) yesStr="|yesStr|empty|" for attribute in data: #print(attribute) aPos=attribute.find("|"+attributeName+"|") if aPos>-1: yesStr=attribute #endif #end for #print(yesStr) parts=yesStr.split("|") result=parts[2] #print("result:",result) #print(result) #return the result return result #end def piR2_ioDeviceAttribute() def piR2_attrFromStr(anyStr,attrNameStr): # @purpose to provide the value of a specified attribute for a # PiR2 ioDevice in a string which contains a list of # all the attributes for one specific PiR2 ioDevice # eg |unitsUsed|d'C| where unitsUsed is the attribute # and d'C is the value of this attribute of the # procTemp ioDevice # @param0 str anyStr eg |anAttr|anyValue| .. |nameDevice|procTemp| # @param1 str attrNameStr eg nameDevice # # @returns str result eg procTemp # workStr=anyStr+" " beg=workStr.find("|"+attrNameStr+"|") #print("beg:",beg) end=workStr.find(" ",beg) #print("end:",end) attrStr=workStr[beg:end] #print("attrStr:",attrStr) parts=attrStr.split("|") #print("parts:",parts) rStr=parts[2] #print("rStr:",rStr) return rStr #end def piR2_attrFromStr() def sortableDateTime(timeIn): # @purpose: to return dkcc sortable date & time w msec & Time Zone # Also: the columns will remain unchanged # eg time is 02:04 not 2:4 # @param1 str timeIn eg "1561500618.3098228" # @returns str resultStr eg "2019FJun03 21:46:11.740 EDT" #print("timeIn:"+timeIn+":") import time; timeG=timeIn timeGStr=timeIn parts=timeGStr.split(".") #print("parts[0]:"+parts[0]) #print("parts[1]:"+parts[1]) timeInt=int(parts[0]) tfrStr="."+parts[1] #keep only 3 digits of decimal (msec) #print("tfrStr1:"+tfrStr+":") tfrStr=tfrStr+"000" #print("tfrStr2:"+tfrStr+":") tfrStr=tfrStr[0:4] ################################################################### # must prefix single digit seconds with a "0" to be sortable ################################################################### #print("tfrStr3:"+tfrStr+":") tGStr=time.strftime("%a, %d %b %Y %H:%M:%S %Z") #print("strftime,timeG:"+tGStr+":") monthIntStr=time.strftime("%m") monthInt=int(monthIntStr) alphabetStr="ABCDEFGHIJKL" #first 12 letters monthLetter=alphabetStr[monthInt-1:monthInt] #print("monthLetter:"+monthLetter+":") #################################################################### tFStr=time.strftime("%Y"+monthLetter+"%b%d %H:%M:%S"+tfrStr+" %Z") # must prefix single digit numbers with a "0" to be sortable # #################################################################### resultStr=tFStr return resultStr #end def sortableDateTime() def pir2_convertMIC_ControlTask(array,prevValueArray, g_isAddingNewLine,fileArray): #@ Purpose: 1. to look for (very often, ie every minute) # the presence of an incoming MIC control file # 2. to convert the control file coming from MIC (in # its html wrapper) into a proper text file format # including the piSN and unixTime # 3. to actually invoke each control command # eg1 "audioTV:alarm.wav" # eg2 "acquire:All" # @param0 array array pir2A.g_ioDeviceArray # @param1 array prevValueArray pir2A.g_prevValueArray # @param2 bool g_isAddingNewLine pir2A.g_isAddingNewLine # # @Returns: int resultInt eg2 # count of control command lines # (which is usually 0) # # NB this task should be run more often than once per minute #global g_fileArray fileNameMIC_Control=fileArray[4]+acquire_piSN()+"_txt.html" #print('C file name:',fileNameMIC_Control) fileNameMIC_test="/home/pi/Downloads/PiR2_Control_00000045db9ca6_txt.html" #if fileNameMIC_Control != fileNameMIC_test : # print('ERROR991:C file name:',fileNameMIC_Control) #end if # import os resultInt=0 numNulls=0 i=0 if os.path.exists(fileNameMIC_Control) and os.path.getsize(fileNameMIC_Control) >0: # process the incoming MIC Control file print("NOTICE: An incoming MIC Control file exists.") fc=open(fileNameMIC_Control) while True: # ends when BREAK is encountered recStr=fc.readline() lenStr=len(recStr) if (not recStr): #test if EOF break #if EOF then BREAK out of the WHILE LOOP #end if #print("recStr:",recStr) if lenStr==1 : #indicates a Null record (only \n) numNulls +=1 else: #print("after NullCheck, recStr:",recStr) i+=1 # strip white space from beginning and end controlStr=recStr.strip() isControlCmd=True if len(controlStr)==0: isControlCmd=False firstChar=recStr[0:1] if firstChar.find("<")>-1: isControlCmd=False if isControlCmd : #does this string begin with an html tag ("<") #here #print("cmd recStr:",recStr) #process the command resultInt+=1 #print("Control Command is:"+controlStr) piSN_Str=g_piSN_Str #piSN_Str=acquire_piSN() #create the outgoing controlRecord ending with a New Line #controlRecord=piSN_Str+","+unixTime()+","+controlStr+"\n" #print("PiR2 Control Record:"+controlRecord+":") #copied similar code from line 555 of piR2A # to fix ********************UnitsStr****** unitsStr="" # append to log the "fromOwner" value #print("about to append to Log fromOwner") fromOwnerValueStr="a:" appendToLog(piSN_Str,"C",unixTime(),"fromOwner",controlStr, \ unitsStr,array,prevValueArray,g_isAddingNewLine,g_fileArray) colonStr=":" #array=array(1,2,3) #prevValueArray=array(1,2,3) if (controlStr.find(colonStr) != -1): #print("found a colon") #if it has a ":" in the reply #process the control_fromOwner command control_fromOwner(array,controlStr,prevValueArray) #end if #end if #end if #process the next record #end while #print("encountered EOF on MIC Control file") fc.close() import os # delete the Control file that came from MIC os.remove(fileNameMIC_Control) #print("deleted:",fileNameMIC_Control) else: print("NOTICE: no incoming MIC Control file was found.") #end if print("ctrl-Z to exit!") #print("returning:",resultInt) # return the number of commands found return resultInt #end def pir2_convertMIC_ControlTask def pir2versions(): #global g_pir2AVer #g_pir2AVer="v40" global g_pir2mainVer g_pir2mainVer="v40" global g_pir2DataVer g_pir2DataVer="A40" global g_pir2VersionsVer g_pir2VersionsVer="A03" global g_validateLogVer g_validateLogVer="A02" global g_pir1AVer g_pir1AVer="A01" global g_globalTestVer g_globalTestVer="A01" global g_sDateTimeVer g_sDateTimeVer="A01" print('piR2 modules, as of 2019GJul19 :') print(' g_pir2AVer:',g_pir2AVer,":") print(' g_pir2mainVer:',g_pir2mainVer,":") print(' g_pir2DataVer:',g_pir2DataVer,":") print(' g_pir2VersionsVer:',g_pir2VersionsVer,":") print(' g_validateLogVer:',g_validateLogVer,":") print(' g_pir1AVerVer:',g_g_pir1AVer,":") print(' g_globalTestVer:',g_globalTestVer,":") print(' g_sDateTimeVer:',g_sDateTimeVer,":") print("end") return #end def pir2versions.py A03 # /FLA42/PiR2/python/pir2A.py _A40 # /r/PiR2/python/pir2A.py #end piR2A.py