Data Logger using Raspberry Pi Scott Cairns 1817523


Appendix E Source code for logger.py Program



Download 200.65 Kb.
Page12/12
Date31.07.2017
Size200.65 Kb.
#25490
1   ...   4   5   6   7   8   9   10   11   12

Appendix E Source code for logger.py Program


This appendix contains the source code for the logger.py file which is the main program which allows data logging.
#**********************************************************************************************************#

# Name: project.py #

# Description: Python program for the Data Logger #

# OS: Raspbian #

# Author: Scott Cairns #

# Notes: If any errors occur, ensure that installation guide has been followed properly #

#**********************************************************************************************************#

import os # used for terminal commands

import time # get timestamp to put on files and gpio

import datetime # used for timestamp

import RPi.GPIO as gpio # access to the GPIO

import spidev # for A/D converters

import multiprocessing # for threading/multiprocessing

import eeml # Markup language for COSM

from evdev import UInput, ecodes as e # Imitating a key event

import signal # for killing task

import termios # for key presses

import thread # for key presses thread


# reload spi drivers prevent spi failures

import subprocess

unload_spi = subprocess.Popen('sudo rmmod spi_bcm2708', shell=True, stdout=subprocess.PIPE)

start_spi = subprocess.Popen('sudo modprobe spi_bcm2708', shell=True, stdout=subprocess.PIPE)


# set up GPIO pins for 3 input (buttons) and 3 output (LEDs)

gpio.setmode(gpio.BCM) # Sets to BM mode which allows you to use visual pin number

gpio.setwarnings(False) # Sometimes 'channel already in use' warning shows, this disables it

redLED = 17 # variable to hold GPIO pin number for red LED

greenLED = 22 # GPIO pin number for green LED

yellowLED = 18 # GPIO pin number for yellow LED

gpio.setup(yellowLED, gpio.OUT) # GPIO ID for yellow LED (single image)

gpio.setup(redLED, gpio.OUT) # GPIO ID for red LED (stop recording)

gpio.setup(greenLED, gpio.OUT) # GPIO ID for green LED

gpio.setup(23, gpio.IN, pull_up_down=gpio.PUD_UP) # Set up button on Gertboard

gpio.setup(24, gpio.IN, pull_up_down=gpio.PUD_UP) # Set up button on Gertboard

gpio.setup(25, gpio.IN, pull_up_down=gpio.PUD_UP) # Set up button on Gertboard


# set all GPIO LEDs to be disabled by default except red

gpio.output(yellowLED, False)

gpio.output(redLED, True) # True to show it's not recording

gpio.output(greenLED, False)


# boolean to hold value if recording or not

recording = False


# variable to hold the recording method (store or stream)

method = "store"


# variable to hold the current detected key press

keyDetect = ''


# variable to hold whether we're looking for key presses or not

# (prevent it being called thousands of times)

keyRun = False
# Variables for using in console warning using ANSI escaped sequences

green = '\033[92m' # colour code for green

blue = '\033[94m' # colour code for blue

yellow = '\033[93m' # colour code for yellow

red = '\033[91m' # colour code for red

endc = '\033[0m' # end of console warning


# variable to hold the connection method (if remotely connected linux sets the 'DISPLAY'

# environment variable (such as localhost:10.0) if not then returns Empty variable ('None')

conVar = os.environ.get('DISPLAY')

if (conVar != None): # if connection method isn't 'None' ie remotely connected

conMethod = "remote" # set the method to 'remote'

print yellow + 'INFO: As you are remotely connected you can overwrite buttons' + endc # print info

print yellow + 'Key 1 = GPIO #23 (Record), Key 2 = GPIO #24 (Stop record), Key 3 = GPIO #25 (Capture)' + endc # print info

else: # if it's not remotely connected

conMethod = "local" # set method to 'local'
# COSM info - allows real time graphing over the internet

temp_api_key = 'R-TZoaYnOUWVnf-s_mLMHwL3LQeSAKxZY0tNdThiS0I2VT0g' # API key for COSM - Temp

temp_api_feed = 117505 # Feed ID for COSM - Temp

light_api_key = '_Ea8XluPFqxAv3IQF-Zhk_3VqBySAKwrZGxXT0hPQTREOD0g' # API key for COSM - Light

light_api_feed = 117510 # Feed ID for COSM - Light

temp_api_url = '/v2/feeds/{feednum}.xml'.format(feednum = temp_api_feed) # API URL

light_api_url = '/v2/feeds/{feednum}.xml'.format(feednum = light_api_feed) # API URL

# https://cosm.com/users/scottrpi - shows both feeds

# https://cosm.com/feeds/117510 - shows feed for light sensor

# https://cosm.com/feeds/117505 - shows feed for temp sensor


# Function to obtain the Analog to Digital conversion and return the value

def get_adc(channel):

spi = spidev.SpiDev() # use spidev python wrapper to communicate with SPI port

spi.open(0,0) # open channel 0 (ADC is on SPI channel 0 (CE0 / GPIO8)

#r = spi.xfer2([1,(3)<<4,0])

#adc_val = ((r[1]&3) << 8) + r[2]

if (channel == 0): # Channel 0 (actual AC1) is the Light sensor

# Send start bit, sgl/diff, odd/sign, MSBF

# channel = 0 sends 0000 0001 1000 0000 0000 0000

# channel = 1 sends 0000 0001 1100 0000 0000 0000

# sgl/diff = 1; odd/sign = channel; MSBF = 0

r = spi.xfer2([1,(2+channel)<<6,0])

# spi.xfer2 returns same number of 8 bit bytes

# as sent. In this case, 3 - 8 bit bytes are returned

# We must then parse out the correct 10 bit byte from

# the 24 bits returned. The following line discards

# all bits but the 10 data bits from the center of

# the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX

adc_val = ((r[1]&31) << 6) + (r[2] >> 2)

if (channel == 1): # Channel 1 (Actual AC0) is the Temp sensor

# Send start bit, sgl/diff, odd/sign, MSBF

# channel = 0 sends 0000 0001 1000 0000 0000 0000

# channel = 1 sends 0000 0001 1100 0000 0000 0000

# sgl/diff = 1; odd/sign = channel; MSBF = 0

r = spi.xfer2([1,(2+channel)<<6,0])

# spi.xfer2 returns same number of 8 bit bytes

# as sent. In this case, 3 - 8 bit bytes are returned

# We must then parse out the correct 10 bit byte from

# the 24 bits returned. The following line discards

# all bits but the 10 data bits from the center of

# the last 2 bytes: XXXX XXXX - XXXX DDDD - DDDD DDXX

adc_val = ((r[1]&31) << 6) + (r[2] >> 2)

return adc_val

# Function to request the digital value from temperature sensor and record it and graph it

def recordTemp():

try:


while 1: # Loop

timeInt = time.time() # Get current timestamp as an integer

timeStr = datetime.datetime.fromtimestamp(timeInt).strftime('%Y-%m-%d %H:%M:%S') # Convert it to a string

reading = get_adc(1) # get temp sensor digital reading

c_temp = (((reading * (3300.0 / 1024.0)) - 100.0) / 10.0) - 40.0 # Calculate temp in C

f_temp = ( c_temp * 9.0 / 5.0) + 32 # Calculate temp in F

c_temp = "%.1f" % c_temp # set C temp to 1 decimal place

f_temp = "%.1f" % f_temp # set F temp to 1 decimal place

print "Temperature: ", c_temp, "C", f_temp, "F" # print the temperatures into terminal

f = open('/home/pi/Desktop/logger/temperatures.txt', 'a') # Opens file 'temperatures' with method A for append

f.write("Time: " + timeStr + " Temperature: " + c_temp + "C " + f_temp + "F\n") # write temp to file

f.close() # close file once finished the write

#pac = eeml.Pachube(temp_api_url, temp_api_key) # using markup language to connect to COSM (previously Pachube)

#pac.update([eeml.Data(0, c_temp, unit=eeml.Celsius())]) # set the data and use Celsius unit

#pac.put() # do it

time.sleep(30) # Only record the temperatures every 30 seconds

return;

except KeyboardInterrupt: # Ctrl C on keyboard



os.system("reset") # Reset terminal to prevent hidden characters after program ends

gpio.cleanup() # reset GPIO ports if KeyboardInterrupt

# Function to request the digital value from light sensor and record it and graph it

def recordLight():

try:

while 1: # Loop



timeInt = time.time() # Get current timestamp as an integer

timeStr = datetime.datetime.fromtimestamp(timeInt).strftime('%Y-%m-%d %H:%M:%S') # Convert it to a string

reading = get_adc(0) # get light sensor digital reading

print "Light: ", reading # print light sensor reading

light = reading # set light to the return variable

light = "%.1f" % light # set light reading to 1 decimal place

f = open('/home/pi/Desktop/logger/light.txt', 'a') # Opens file 'light.txt' with method a for append

f.write("Time: " + timeStr + " Light: " + light + "\n") # write light info to file

f.close() # Close file once finished writing

#pac = eeml.Pachube(light_api_url, light_api_key) # using markup language to connect to COSM (previously Pachube)

#pac.update([eeml.Data(0, light)]) # run update, don't set a data type as it's just raw number

#pac.put() # do it

time.sleep(30) # Record light every 30 seconds

return;


except KeyboardInterrupt: # Ctrl C on keyboard

os.system("reset") # Reset terminal to prevent hidden characters after program ends

gpio.cleanup() # reset GPIO ports if KeyboardInterrupt

# Function to set variables required for recording and start the recording

def startRecord(method):

try:


# set up the variables required for the recording

serverConf = "/etc/ffserver.conf" # path to the ffserver config

logLevel = "error" # logging level, quiet, panic, fatal, error, warning, info, verbose, debug

rframeRate = "1" # Frame rate in Hz (for saving/recording)

sframeRate = "30" # Frame rate in Hz (for streaming)

frameSize = "352x288" # Set frame size in width x height (640x480, 352x288, 320x240, 176x144, 160x120 supported)

fileFormat = "video4linux2" # output format

inputName = "/dev/video0" # Input type, video0 for camera

outLocation = "http://localhost:8001/webcam.ffm" # Output location, over network

timeInt = time.time() # Get current timestamp as an integer

timeStr = datetime.datetime.fromtimestamp(timeInt).strftime('%Y-%m-%d~%H:%M:%S') # Convert it to a string

outLocationSave = "/home/pi/Desktop/logger/webcam-%s.avi" %timeStr

# Output location, in this case save under /home/pi/ with name 'webcam-timestamp.mpg'

vSync = "1" # video sync (make sure no duplicate frames etc

aSync = "1" # audio sync to fix wait at start

aFormat = "alsa" # format for audio: oss or alsa

aChannel = "1" # audio channels

aInput = "hw:1,0" # input device for audio (sound card #1 sub #0)

# Run terminal command to run ffserver and ffmpeg

#os.system("ffserver -f " + serverConf + " & ffmpeg -v " + logLevel +

# " -r " + frameRate + " -s " + frameSize + " -f " + fileFormat +

# " -i " + inputName + " -vcodec mjpeg -f alsa -ac 1 -ar 48000 -i hw:1,0 " + outLocation + " " + outLocationSave)

p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE) # check open processes

out, err = p.communicate() # record them in 'out'

for line in out.splitlines(): # check each line

if 'ffmpeg' in line: # if ffmpeg is in it

print red + "Attempting to kill ffmpeg - May cause audio issues with last save" + endc

time.sleep(2) # show warning for 2 seconds before continuing

pid = int(line.split(None, 1)[0]) # get the process ID

os.kill(pid, signal.SIGKILL) # send kill signal

if (method == "store"): # if the selected method is to store it to the SD card (video + audio)

# print "Recording has started - Storing to SD card" # print appropriate message

# os.system("ffmpeg -v " + logLevel + " -r " + frameRate + " -s " + frameSize + " -f " + fileFormat +

# " -i " + inputName + " -f alsa -ac 1 -i hw:1,0 " + " " + outLocationSave)

os.system("ffmpeg -v " + logLevel + " -r " + rframeRate + " -s " + frameSize + " -f " + fileFormat +

" -vsync " + vSync + " -i " + inputName + " -f " + aFormat + " -ar 8000 -ac " + aChannel + " -async " +

aSync + " -i " + aInput + " " + outLocationSave)

elif (method == "stream"): # if the selected method is to strream it over network (video only)

print "Recording has started - Streaming across network" # print appropriate message

os.system("ffserver -f " + serverConf + " & ffmpeg -v " + logLevel +

" -r " + sframeRate + " -s " + frameSize + " -f " + fileFormat +

" -i " + inputName + " " + outLocation)

return;

except KeyboardInterrupt: # Ctrl C on keyboard



os.system("reset") # Reset terminal to prevent hidden characters after program ends

gpio.cleanup() # reset GPIO ports if KeyboardInterrupt

# Function to end the processes / recording

def stopRecord(recording):

try:

if (recording == True): # if recording has started



if (p1.is_alive()): # If process 1 (recordTemp) is alive

p1.terminate() # terminate process

if (p2.is_alive()): # If process 2 (recordLight) is alive

p2.terminate() # terminate process

if (p3.is_alive()): # If process 3 (startRecord) is alive

p3.terminate() # terminate process

# Imitate a key press, only works if running script from device (remote connection requires pressing q)

if (conMethod == "local"): # only do it if actually on the device

ui = UInput() # create new uinput

ui.write(e.EV_KEY,e.KEY_Q, 1) # key Q press down

ui.write(e.EV_KEY,e.KEY_Q, 0) # key Q press up

ui.syn() # do it

ui.close() # close uinput

print "Recorded finished" # print appropriate message

else: # if recording hasn't started

print "Recording has not yet started" # print appropriate message

return;

except KeyboardInterrupt: # Ctrl C on keyboard



os.system("reset") # Reset terminal to prevent hidden characters after program ends

gpio.cleanup() # reset GPIO ports if KeyboardInterrupt


# Function to set variables for an image and execute it

def singleImg():

frameSize = "352x288" # Set frame size in width x height

inputName = "/dev/video0" # Input type, video0 for camera

timeInt = time.time() # Get current timestamp as an integer

timeStr = datetime.datetime.fromtimestamp(timeInt).strftime('%Y-%m-%d~%H:%M:%S') # Convert it to a string

picOut = "/home/pi/Desktop/logger/image-%s.jpg" % timeStr # Output location for single image timestamp attached
p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE) # check open processes

out, err = p.communicate() # record them in 'out'

for line in out.splitlines(): # check each line

if 'ffmpeg' in line: # if ffmpeg is in it

print red + "Attempting to kill ffmpeg - May cause audio issues with last save" + endc

time.sleep(2)

pid = int(line.split(None, 1)[0]) # get the process ID

os.kill(pid, signal.SIGKILL) # send kill signal

# Run terminal command which will take a single image and save it to picOut

os.system("fswebcam -r " + frameSize + " -d " + inputName + " " + picOut)

return;

def keyPress():



try:

term = open("/dev/tty", "r") # /dev/tty is the terminal for the current process, open in reading mode

fd = term.fileno() # returns integer file desciptor

old = termios.tcgetattr(fd) # return list containing tty attributes for file descriptor

new = termios.tcgetattr(fd) # return list containing tty attributes for file descriptor

new[3] &= ~termios.ICANON & ~termios.ECHO # canonical mode and echo input characters

termios.tcsetattr(fd, termios.TCSANOW, new) # sets the parameters associated with terminal, TCSANOW = immediately

key = None # current key isn't set

try: # try

key = os.read(fd, 1) # read key press

finally: # always execute this before leaving try statement

termios.tcsetattr(fd, termios.TCSAFLUSH, old) # set attrs again this time after all output is written to object has fd has been trasmitted

term.close() # close the file
global keyDetect # allow overwriting of variable outside function

global keyRun # allow overwriting of variable outside function

if key == '1': # if key pressed is '1'

keyDetect = '1' # then set it to 1

elif key == '2': # if key is '2'

keyDetect = '2' # set to 2

elif key == '3': # if key is '3'

keyDetect = '3' # set to 3

elif key == 'Q': # if key is 'Q'

print 'Please try again' # print message to try again

else: # otherwise

print 'Unusable key detected' # print to show unusuable key

keyRun = False # set it to false as it's not longer running

except KeyboardInterrupt: # Ctrl C on keyboard

os.system("reset") # Reset terminal to prevent hidden characters after program ends

gpio.cleanup() # reset GPIO ports if KeyboardInterrupt

try:

time.sleep(1) # prevent some misreading buttons during start up



print "Python Program loaded, press a button to continue"

while 1: # Infinite loop

if (((gpio.input(23) == False) or (keyDetect == '1')) and (recording == False)): # if record button is pressed and not recording, record

if (conMethod == "remote"): # give warning if remotely connected

print yellow + "INFO: As remotely connected you must press Q to end the webcam stream" + endc

print yellow + "WARNING: When ending the stream, it may take a few minutes depending on the length of recording" + endc

time.sleep(2) # give time to read the info

gpio.output(redLED, False) # disable the red LED

gpio.output(greenLED, True) # enable the LED to show it's recording (green)

recording = True # Set recording variable to true

p1 = multiprocessing.Process(target=recordTemp) # create a process with target as recordTemp

p2 = multiprocessing.Process(target=recordLight) # create a process with target as recordLight

p3 = multiprocessing.Process(target=startRecord, args=(method,)) # create a process with target as startRecord taking 'method' variable as param

p3.start() # Start process to startRecord

time.sleep(2) # wait a few seconds

p1.start() # Start process to recordTemp

time.sleep(3) # wait a few seconds

p2.start() # Start process to recordLight

keyDetect = '' # Reset keyDetect

time.sleep(1) # prevent button from being detected several times with 1 press

if (((gpio.input(23) == False) or (keyDetect == '1')) and (recording == True)): # if record button is pressed and recording, stop

gpio.output(greenLED, False) # disable the LED to show it's recording (green)

gpio.output(redLED, True) # enable the LED to show it's not recording (red)

stopRecord(recording); # Call the stopRecord function (pass recording boolean)

recording = False # Set recording variable to false

keyDetect = '' # reset keyDetect

time.sleep(1) # prevent button from being detected several times with 1 press

if (((gpio.input(24) == False) or (keyDetect == '2')) and (method == "store")): # if switch button is pressed and current method is store

method = "stream" # change method to stream

print "Recording method has changed to stream - The recording will be streamed across the network" # print appropriate message

keyDetect = '' # reset keyDetect

time.sleep(1) # sleep for 1 second

if (((gpio.input(24) == False) or (keyDetect == '2')) and (method == "stream")): # if switch button is pressed and current method is stream

method = "store" # change method to store

print "Recording method has changed to store - The recording will be saved to the SD card" # print appropriate message

keyDetect = '' # reset keyDetect

time.sleep(1) # sleep for 1 second

if ((gpio.input(25) == False) or (keyDetect == '3')):

gpio.output(yellowLED, True) # enable LED for short duration to show it's taken image (yellow)

time.sleep(1) # sleep for one second

gpio.output(yellowLED, False) # disable LED again

singleImg(); # Call the singleImg function

keyDetect = '' # reset keyDetect

time.sleep(1) # prevent button from being detected several times with 1 press

if ((conMethod == "remote") and (keyRun == False)): # if remotely connected start function to allow key detection

time.sleep(1) # allow time for q to be pressed

thread.start_new_thread( keyPress, ())

keyRun = True # set it to true so it won't call this statement each loop

except KeyboardInterrupt: # Ctrl C on keyboard

os.system("reset") # Reset terminal to prevent hidden characters after program ends

gpio.cleanup() # reset GPIO ports if KeyboardInterrupt

gpio.cleanup() # reset GPIO ports if exit



os.system("reset") # Reset terminal to prevent hidden characters after program ends


Directory: ~aka

Download 200.65 Kb.

Share with your friends:
1   ...   4   5   6   7   8   9   10   11   12




The database is protected by copyright ©ininet.org 2024
send message

    Main page