#!/usr/bin/env python
# coding: latin-1
# vim: ts=4 sw=4 ai

# Load the Accelerometer library
from XLoBorg import *
#from MPU9150 import *

from os import system, mkdir, chown
from time import asctime, strftime, sleep
import RPi.GPIO as GPIO
import datetime
from multiprocessing import Process, Event, Value, Lock

LIGHT = 4 # GPIO of the light

# Tell the library to disable diagnostic printouts
printFunction = NoPrint

# Start the XLoBorg module (sets up devices)
Init()
ins = outs = 0
GPIO.setmode(GPIO.BCM)
GPIO.setup(LIGHT, GPIO.OUT)
GPIO.output(LIGHT, False)

SAMPLES = 5 # Number of samples to trigger action
SAMPLETIME = 0.1 # Time between samples

def camera(tilt, dy, mn, yr, lock):
	while True:
		cat_evt.wait()
		if end_evt.is_set():
			break
		with lock: # (yr, mn, dy better not change while we do this)
			dirname = "%02d%02d%02d/" % (yr.value, mn.value, dy.value)
		filename = strftime("%y%m%d-%H%M%S")
		if tilt.value > 0.0:
			inout = "_I.jpg"
		else:
			inout = "_O.jpg"
		GPIO.output(LIGHT, True)
		i = 0
		while cat_evt.is_set() or i < 3:
			i = i + 1	
			system("raspistill -w 640 -h 480 -q 50 -t 10 \
				-o %s-%02d%s" % (dirname + filename, i, inout))
			chown("%s-%02d%s" % (dirname + filename, i, inout), 1000, 1000)
		GPIO.output(LIGHT, False)

# Create shared variables for communication between processes
tilt = Value('f', 0.0) # catflap tilt value
dy = Value('i', 0) # Day, month, year of start of an event
mn = Value('i', 0)
yr = Value('i', 0)

# Create a lock for synchronisation
lock = Lock()

cat_evt = Event()
end_evt = Event()

proc = Process(target=camera, args=(tilt, dy, mn, yr, lock))
proc.start()

tracing = False

ins = outs = 0
more = 0 # Extension of prev event
peeping = 0 # Flap open just enough to sniff
ending = 0 # Count to avoid spurious end of event
intruder = False
x = y = z = 0.0

# Main code starts here
try:
	while True:

		# Create directory for the day
		with lock:
			dy.value = datetime.date.today().day
			mn.value = datetime.date.today().month
			yr.value = datetime.date.today().year - 2000
		dirname = "%02d%02d%02d" % (yr.value, mn.value, dy.value)
		try:
			mkdir(dirname)
			chown(dirname, 1000, 1000)
		except:
			dirname = dirname + "/"

		# Read and display the raw magnetometer readings
		(x, y, z) = ReadAccelerometer()
#		print "xyz = %2.2f %2.2f %2.2f" % (x, y, z)
		tilt.value = z

		# Detect an entry or exit

		# Sometimes the first sample or two are in the wrong sense. Reset.
		if ins > 0 and ins <= 2 and z < 0.0 \
		  or (outs > 0 and outs <= 2 and z > 0.0):
			ins = 0
			outs = 0

		# Detect catflap at least 25 degrees open either way:
		if z > 0.43:
			ins += 1
			outs = 0
		elif z < -0.43:
			outs += 1
			ins = 0

		# Detect foreign cat peeping in
		#   But note that if ins > 30 he's just left his tail in the catflap
		if z > 0.2 and z < 0.43 and ins < 30:
			peeping += 1

		# Detect an intruder
		if peeping == 20 or ins + peeping == 60:
			if not intruder:
				intruder = True
				logfile = open(dirname + "catflap.txt", "a")
				chown(dirname + "catflap.txt", 1000, 1000)
				logfile.write("%s Intruder! peeping = %3d ins = %3d\n" % (asctime(), peeping, ins))
				logfile.close()

		# We have an entry or exit if at least SAMPLES readings > 25 degrees
		if ins == SAMPLES or outs == SAMPLES:
			logfile = open(dirname + "catflap.txt", "a")
			chown(dirname + "catflap.txt", 1000, 1000)
			if ins == SAMPLES:
				logfile.write("%s In\n" %asctime())
			else:
				logfile.write("%s Out\n" %asctime())
			logfile.close()
			more = 0
#			logfile = open(dirname + "catflap.txt", "a")
#			logfile.write("%s Setting cat_evt\n" %asctime())
#			logfile.close()
			cat_evt.set()

		# End of event if catflap < 15 degrees
		if abs(z) >= 0.26:
			ending = 0
		else:
			# Intruder? continue event for 5 secs and sound warning after 2 secs
			if intruder and more < 50:
				more += 1
				if more == 20: # Give him 2 secs to think he's safe!
					system("mpg321 catwarning.mp3 2>/dev/null &")
					logfile = open(dirname + "catflap.txt", "a")
					chown(dirname + "catflap.txt", 1000, 1000)
					logfile.write("%s Yowl!\n" % (asctime(),))
					logfile.close()

			else:
			   # Count to 3 samples before accepting end of event
			   if ending < 3:
			       ending += 1
			   else:
					if ins > 0 and ins < SAMPLES:
						logfile = open(dirname + "catflap.txt", "a")
						chown(dirname + "catflap.txt", 1000, 1000)
						logfile.write("%s (Transitory In)  %5d\n" % (asctime(), ins))
						logfile.close()
					elif outs > 0 and outs < SAMPLES:
						logfile = open(dirname + "catflap.txt", "a")
						chown(dirname + "catflap.txt", 1000, 1000)
						logfile.write("%s (Transitory Out) %5d\n" % (asctime(), outs))
						logfile.close()
					ins = outs = peeping = more = ending = 0
					intruder = False
	#				logfile = open(dirname + "catflap.txt", "a")
	#				logfile.write("%s Clearing cat_evt\n" %asctime())
	#				logfile.close()
					cat_evt.clear()

		# Record x/y/z in cattrace.csv starting
		#   when abs(z) > 0.2(12 degrees) until < 0.1 (6 degrees)
		if not tracing and abs(z) > 0.2:
			tracing = True
			tracecount = 0.0
			tracefile = open(dirname + "cattrace.csv", "a")
			tracefile.write("%s\n" % asctime())
		if tracing:
			tracefile.write('%03.1f, %+01.4f, %+01.4f, %+01.4f, %3d, %3d, %2d, %3d, %3d\n' % (tracecount, x, y, z, ins, outs, intruder, peeping, more))
			tracecount += SAMPLETIME
		if tracing and abs(z) < 0.1 and more == 0 and ending == 0:
			tracing = False
			tracefile.write("\n")
			tracefile.close()

		sleep(SAMPLETIME)

except KeyboardInterrupt:
	GPIO.cleanup()
	end_evt.set()
	cat_evt.set()
	proc.join()
