# pir2A.py A470 global g_pir2AVer g_pir2AVer="A72" #By D@CC #on 2024AJan22 # this is the code module containing most of the #python3 code for the PiR2 system #pi # NB 1. the ioDeviceArray is defined in pir2Data.py # 2. the first program is pir2Main.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 acquire_pushButton() # 31 acquire_digIn0() # 31 control_redLED() # 31 control_digOut0() # 31 pir2_initGPIO() # 33 init_I2C_Bus() # 34 acquire_tempId00() # 34 control_imageTV() # 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 global g_RPiGPIO g_RPiGPIO="RPi.GPIO" # change this for gpiozero #Do NOT change the next statement if g_RPiGPIO=="RPi.GPIO": #72 import RPi.GPIO as GPIO #72 else: #72 import RPi7GPIO as GPIO #72 #if end #72 def unity(func): #72 #by D@CC on 2024AJan18 #Purpose: return "constants" such as GPIO.BCM, GPIO.HIGH etc #strReturn=func() try: strReturn=func() except: strReturn=True finally: pass #try end if strReturn=="GPIO.PUD_UP": return strReturn #if end if strReturn=="GPIO.HIGH": strReturn=func(parm=True) if strReturn=="GPIO.LOW" : strReturn=func(parm=False) return strReturn #/unity.py def testGPIO(g_ledR_pin): #ledR_pin=27 GPIO.setmode(GPIO.BCM) GPIO.setup(g_ledR_pin,GPIO.OUT) GPIO.output(g_ledR_pin,GPIO.HIGH) time.sleep(1) GPIO.output(g_ledR_pin,GPIO.LOW) time.sleep(1) #end def import smbus # 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 # globat g_piOS_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) MIC180RR 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(isVerbose, 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" # defines logical GPIO #s for GPIO pins # (not the actual pin numbers themselves) global g_btn_pin g_btn_pin=22 #was 27 in A46 global g_ledR_pin g_ledR_pin=27 #was 18 in A46 global g_diC_pin g_diC_pin=18 #was 17 in A46 global g_di0_pin g_di0_pin=22 #was 23 in A46 global g_do0_pin g_do0_pin=17 #initialize the GPIO pins isPiR2=pir2_initGPIO(isVerbose, g_btn_pin, g_ledR_pin, g_di0_pin, \ g_do0_pin, g_diC_pin) if (isPiR2==False) : print("Error- program should have stopped earlier") # end if # defines I2C Bus & device address #s global g_tempId00bus g_tempId00bus=1 global g_tempId00addr g_tempId00addr=0x0048 # initialize the I2C devices BusA=init_I2C_Bus(g_tempId00bus) 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+":") #get g_piOS_Str global g_piOS_Str g_piOS_Str = acquire_piOS() 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(), \ g_isAddingNewLine,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:") print('idRecFirst:',idRecFirst,":") print('idRecLast:',idRecLast,":") 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"): doh=0 #null statement 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" # display pin #s sp6=" " print(" GPIO pins deviceNames") print("g_di0_pin ",g_di0_pin, "piSN") print("g_do0_pin ",g_do0_pin, "procTemp") print("g_diC_pin ",g_diC_pin, "pushButton") print("g_ledR_pin",g_ledR_pin, "redLED") print(sp6,sp6,sp6, "piOS") print(sp6,sp6,sp6, "piArea") print(sp6,sp6,sp6, "piIP") print(sp6,sp6,sp6, "digOut0") print(sp6,sp6,sp6, "digIn0") print(sp6,sp6,sp6, "tempId00") print(sp6,sp6,sp6, "toOwner") print(sp6,sp6,sp6, "ambTemp") print(sp6,sp6,sp6, "ambTemp1") print(sp6,sp6,sp6, "ambTemp2") print(sp6,sp6,sp6, "audioTV:alarm.wav") print(sp6,sp6,sp6, "imageTV:PiR2_Clock.jpg") print(sp6,sp6,sp6, "logA:155 kg") print(sp6,sp6,sp6, "piButton(fut)") print(sp6,sp6,sp6, "ambLight(fut)") print(sp6,sp6,sp6, "ambHum(fut)") print(sp6,sp6,sp6, "ambAirpr(fut)") print(sp6,sp6,sp6, "digLight(fut)") print(sp6,sp6,sp6, "piModel(fut)") print(sp6,sp6,sp6, "piRam(fut)") print(sp6,sp6,sp6, "usbAmps0(fut)") print(sp6,sp6,sp6, "emailOut0(fut)") print(sp6,sp6,sp6, "emailOut1(fut)") print(sp6,sp6,sp6, "digMains(fut)") 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 acquire:pushButton ") print(" or audioTV:alarm.wav ") print(" or logA:1 ") 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 #null statement #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 #print("in control_fromOwner") 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) print("ioValueToLog:",ioValueToLog,":") # 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 # @param5 obj busA eg 1 for tempId00 bus (TMP102) # # returns str ioValueToLog eg 192.168.0.10 #print("ioDeviceRec:"+ioDeviceRec+" is Defined") #print("in performAorC") if acStr=="A": #print("isAcquire:True") #print("in pir2_performAorC todo A") #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=="piOS": ioValueToLog=g_piOS_Str #end if if ioDeviceFromOwner=="lastRecId": ioValueToLog=str(g_lastRecId) #end if if ioDeviceFromOwner=="logA": ioValueToLog=g_logAStr #end if if ioDeviceFromOwner=="pushButton": #print("g_btn_pin:",g_btn_pin) ioValueToLog=acquire_pushButton(g_btn_pin) #end if if ioDeviceFromOwner=="digIn0": #print("g_di0_pin:",g_di0_pin) ioValueToLog=acquire_digIn0(g_di0_pin) #end if if ioDeviceFromOwner=="tempId00": print("g_tempId00addr:",hex(g_tempId00addr)) busA=init_I2C_Bus(g_tempId00bus) ioValueToLog=acquire_tempId00(busA,g_tempId00addr," C") #end if else: #print("in pir2_performAorC todo C") 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 if ioDeviceFromOwner=="redLED": #print("before redLED, pin:",g_ledR_pin) #a=input('pause') control_redLED(g_ledR_pin,ioValueFromOwner) #end if if ioDeviceFromOwner=="digOut0": #print("before digOut0, do0_pin:",g_do0_pin) #a=input('pause') control_digOut0(g_do0_pin,ioValueFromOwner,HIGH,LOW,g_RPIGPIO) #end if if ioDeviceFromOwner=="imageTV": #print("before imageTV, image:",ioValueFromOwner) #a=input('pause') control_imageTV(ioValueFromOwner, "", 5) #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="aplay "+audioFolder+soundByteMp3OrWav #72 #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+":") ipCol=piIP_Str.find("inet")+5 #print("ipCol:",ipCol,":") ipEnd=ipCol+12 #print("ipEnd:",ipEnd,":") #print("piIP_Str:"+piIP_Str+":") piIP_Str=piIP_Str[ipCol:ipEnd] #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 acquire_piOS(): commandStr="uname -a" piOS_Str=osCommand(commandStr) print("piOS_Str:"+piOS_Str+":") ipCol=piOS_Str.find("#") print("ipCol:",ipCol,":") piOS_Str=piOS_Str[0:ipCol] #remove any trailing \n, if it exists piOS_Str=piOS_Str.rstrip() print("piOS_Str:"+piOS_Str+":") #a=input("pause") return piOS_Str #end def acquire_piOS() 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 g_piSN = acquire_piSN() # display the log header #print("g_piAreaStr:"+g_piAreaStr+":") # g_piArea Str="This_Room" recStr="piArea:"+g_piAreaStr+": piOS:"+g_piOS_Str+":" print(recStr) #g_piIPStr = acquire_piSN() #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(isVerbose,logFileName): # @Purpose to check if the log file is available # ie not already being used by another running process # @param0 cond isVerbose False for minimum dialog # @param1 str logFileName eg "....PiR2_Log.txt" # @returns cond isQuerying eg True if Log file is available # ie not active (ie not in use) # @usedBy pir2main.py # @param none # #logFileName="/home/pi/Desktop/PiR2/files/PiR2_Log.txt" ################################################################ # isQuerying=True means "ask the user if verbose info is wanted" # This can be set False to Never ask the user ################################################################ #moved to pir2main.py #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 # it might be necessary to install the rpi.gpio software # sudo apt-get update # pip install rpi.gpio def acquire_pushButton(btn_pin): # @purpose: to sense if the pushButton is down # @param0: unused # returns str 1 if button is down (else 0) #GPIO.setmode(GPIO.BCM) #print("@2.1596 in acquire_PB, btn_pin:",btn_pin) #GPIO.setup(btn_pin,unity(GPIO.IN)) #72 by calling program #print("@2.1598 after GPIO.setup") if GPIO.input(btn_pin) : downInt=0 else: downInt=1 # end if print("acquire_PB, returning downInt:",downInt) #a=input() return str(downInt) # end def def acquire_digIn0(di0_pin): # Digital Input line 0 # @purpose: to sense if the di0 is down # @param0: unused # returns str 1 if button is down (else 0) if GPIO.input(di0_pin) : downInt=1 else: downInt=0 # end if return str(downInt) # end def def control_redLED(ledR_pin,onOne): # @purpose: to turn the Red Led on or off # @param0: int onOne 1 to turn it ON (0 to turn it OFF) # @returns: nothing #print("in control_redLED, pin:",ledR_pin) #print("onOne:",onOne) #a=input("pause in redLED") if (onOne=="1"): #a=input("before GPIO 1") #import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) GPIO.setup(ledR_pin,GPIO.OUT) GPIO.output(ledR_pin,GPIO.HIGH) #a=input("after GPIO redLED HIGH") # end if if (onOne=="0"): #a=input("before GPIO 0") #import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) GPIO.setup(ledR_pin,GPIO.OUT) GPIO.output(ledR_pin,GPIO.LOW) #a=input("after GPIO redLED LOW") # end if return # end def def control_digOut0(do0_pin,onOne,HIGH,LOW,RPiXGPIO): #72 # Digital Output line 0 # @purpose: to turn the do0 on or off (on = 3.3v) # @param0: pin (# for RPi.GPIO, object for RPi7GPIO) # @param1: int onOne 1 to turn it ON (0 to turn it OFF) # @param2: HIGH: # @param3: LOW # @param4: RPiGPIO (aka global) # returns nothing #print("@2.1668 in control_digOut0, do0_pin,onOne:",do0_pin,",",onOne) #GPIO.setup(do0_pin,GPIO.OUT) #72 must do in calling routine if (onOne==True): STATE=HIGH else: STATE=LOW #if end #print("@2.1680,RPiXGPIO:",RPiXGPIO) #72 display which RPi?GPIO is being used #print("@2.1681,do0_pin:",do0_pin) GPIO.output(do0_pin,STATE) #72 return # end def def pir2_initGPIO(isVerbose,btn_pin, ledR_pin, di0_pin, do0_pin,diC_pin): # @purpose to initialize the GPIO pins # @param0 bool isVerbose False to minimize user dialog # @param1 int btn_pin GPIO pin of pushButton # @param2 int ledR_pin GPIO pin of redLED # @param3 int di0_pin GPIO pin of digIn0 # @param4 int do0_pin GPIO pin of digOut0 # @param5 int diC_pin GPIO pin of digInVC (not controlable) # returns bool isPiR2 False if PiR2 does not exist import RPi.GPIO as GPIO import pir2A # GPIO setup GPIO.setmode(GPIO.BCM) #print("diC_pin:",diC_pin) # setup and enable the internal pull-up resistors # (and the internal resistors (300ohm) on the Output pins GPIO.setup(btn_pin,GPIO.IN,GPIO.PUD_UP) GPIO.setup(ledR_pin,GPIO.OUT) GPIO.setup(do0_pin,GPIO.OUT) GPIO.setup(di0_pin,GPIO.IN,GPIO.PUD_UP) GPIO.setup(diC_pin,GPIO.OUT) # set diC_pin as a source of 3v3 volts for di0_pin # This offers the protection of a internal 300 ohm # resistor so that the 3v3 Voltage source is not # used directly as a voltage source for the di0_pin # Note that di0 is on the pi's hardware pin 16. # For testing, it can be connected to either # hardware pin 14 which is ground # or hardware pin 12 which outputs 3.3v through # the internal 300 ohm resistor. # if a simple reed switch (ie a set of external # contacts) is used to sense an open door, the # 2 contacts should be connected to pins 12 and 16. # The following statement provides 3v3 on the diC_pin # through the internal 300 ohm resistor. #global g_diC_pin #done in the calling program #g_diC_pin=17 #a=input("before diC") GPIO.output(diC_pin,GPIO.HIGH) #a=input("after diC") if (isVerbose): #test to see if the PiR2 controller is connected if GPIO.input(btn_pin) : downInt=0 else: downInt=1 # end if #print("downInt:",downInt) print("To continue, press the PiR2 pushButton within 5 sec") isPiR2=False downIntNew="0" timeStart=time.time() #print("Start:',timeStart) while downIntNew=="0" : if time.time()>timeStart+5.0 : # time is up if isPiR2==False : print("pushButton was not pressed . . .") print("but saw ctrl-c, Conclusion: . . .") print("ERROR031:No PiR2 controller is connected.") print("This test showed the push button always Up") print("It looks like no PiR2 controller is connected.") ##################################################### #GPIO.cleanup() ##################################################### return #end if else: # time is not yet up #check the button again and again #acquire always returns a string downIntNew=acquire_pushButton(btn_pin) #print("downIntNew:",downIntNew) if downIntNew=="1" : #button was pressed within 5 sec. print("saw pushButton down") isPiR2=True break #out of the while # end if # end if # end while if isPiR2==True: # now test the PiR2 print("pushButton is initially Up") print("red LED will be on for 4 seconds") print("") control_redLED(ledR_pin,"1") #on when GPIO.HIGH time.sleep(4) control_redLED(ledR_pin,"0") #off when GPIO.LOW #end if else: #if not verbose . . . presume PiR2 is connected isPiR2=True #end if return isPiR2 # end def pir2_initGPIO def init_I2C_Bus(I2C_BUS_Number) : # @purpose to initialize a specific I2C_BUS # @param0 int I2C_BUS_Number eg 1 # bus # 1 uses GPIO2 and GPIO3 on the Raspberry Pi # @returns obj busA eg the object assigned to this I2C bus if I2C_BUS_Number !=1 : print("ERROR041-invalid bus number for I2C TMP102 (tempIdxx) iodevice") exit() else: busA=smbus.SMBus(I2C_BUS_Number) # end if return busA # end def def acquire_tempId00(busA,DEVICE_ADDRESS,unitsStr) : # @purpose to read the temp of this device on this bus in these units # @param0 obj busA created in the init_tempBus(I2C_BUS) method # @param1 int DEVICE_ADDRESS eg 0x48 for the first TMP102 iodevice # TMP102 is factory hardwired to 0x48 # @param2 str unitsStr eg " C" for Centigrade (or " F" for Fahr) # @returns str returnValue eg 20.0 for Centigrade # # this routine also converts the temp into the requested units # temp_registerInt=0 #print("@2.1818, DEVICE_ADDRESS:",DEVICE_ADDRESS) temp_reg_12bit=busA.read_word_data(DEVICE_ADDRESS,temp_registerInt) #eg temp_reg_12bit of 61459 is returned temp_loByte=(temp_reg_12bit & 0xff00) >>8 temp_hiByte=(temp_reg_12bit & 0x00ff) # convert to temp from page 6 of datasheet tempInt=((( temp_hiByte * 256) + temp_loByte) >>4 ) # handle negative temperatures if tempInt > 0x7ff : tempInt=tempInt - 4096 # end if #convert to Centigrade first temp_C=float(tempInt) * 0.0625 returnValueFloat=temp_C if unitsStr ==" F" or unitsStr==" f": temp_F=temp_C * 9/5 + 32 returnValueFloat=temp_F # end if if unitsStr !=" C" and unitsStr!=" F" and unitsStr!=" c" and unitsStr!=" f" : print("WARNING: bad units requested:",unitsStr,": returning C units") # end if #must return a string not a float return str(returnValueFloat) # end def def control_imageTV(imageNameStr, folderStr, displaySecsCnt) : # @purpose To display an image on the TV HDMI for a number of seconds # this uses the python fbi method and the pir2.osCommand() # @param0 str imageNameStr name of image (jpg or png or tif etc) # including the .jpg etc # @param1 str folderStr usually "" indicating that the # image is in PiR2/images folder # if not null the folder must be fully # specified eg "/home/pi/Desktop/PiR2/images/" # @param2 int displaySecCnt the time duration to display the image # (after this time, screen returns to python) # @returns bool returnValueBool True if displayed ok, else False #displaySecsCnt=timeSecInt #seconds #print("Now display an image for ", displaySecsCnt," secs.") #print("@1852 into control_imageTV") #72 if folderStr == "" : folderStr="/home/pi/Desktop/PiR2/images/" else : if folderStr[0:1] != "/" : prefixStr="/" else : prefixStr="" # end if lenStr=len(folderStr) if folderStr[lenStr-1:lenStr] != "/" : suffixStr="/" else : suffixStr="" # end if folderStr=prefixStr+folderStr+suffixStr # end if imgStr=imageNameStr #imgStr="t.jpg" extraWait=2 time.sleep(displaySecsCnt+extraWait) if False : #72 # to install fbi use terminal to: # >>> sudo apt-get update # >>> sudo apt-get -y install fbi cmdStr="sudo fbi -T 1 -d /dev/fb0 -a -1 -t "+str(displaySecsCnt)+" " # without sudo, permission is denied # -T 1 is tty1 # -d "dev/fb0" is the ??? # -a -1 is ?? # -t is the time(sec) to display a photo (usually of a slide show) # followed by the fullPath/fileName # # python stripped off the trailing space above. . . doh # so I added it in below (2 spaces would also work) cmdwoImgStr=" "+cmdStr+folderStr cmdStr=cmdwoImgStr+imgStr else: #72 # try sxiv cmdStr=" nsxiv "+folderStr+imgStr #if end #testing #print("cmdStr:",cmdStr,":") #a=input("next") #print("@1878, cmdStr:",cmdStr) #72 osCommand(cmdStr) # if extraWait<=1 Raspian hangs, needs a reboot # if extraWait=2 it works fine # no known error checks/tests have been included returnValue=True return returnValue #end control_imageTV() def pir2versions(): #global g_pir2AVer # g_pir2AVer="v46" global g_pir2mainVer g_pir2mainVer="v46" global g_pir2DataVer g_pir2DataVer="v45" 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" global g_test_TMP102Ver g_test_TMP102Ver="A03" 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(' g_test_TMP102Ver:',g_test_TMP102Ver,":") print("end") return #end def pir2versions.py A03 # /FLA42/PiR2/python/pir2A.py _A46 # /r/PiR2/python/pir2A.py #end piR2A.py