44import redis
55import threading
66import sys
7+ import os
78import RPi .GPIO as GPIO
89from picamera import PiCamera
910sys .path .append ('..' )
@@ -17,6 +18,7 @@ class CameraWorker():
1718 def __init__ (self , config , main_thread_running , system_ready , camera_available ):
1819 #self.config = {**config, **self.config}
1920 self .config = config
21+ self .pending_reset = False
2022
2123 #Events
2224 self .main_thread_running = main_thread_running
@@ -40,26 +42,42 @@ def __init__(self, config, main_thread_running, system_ready, camera_available):
4042 def init (self ):
4143 try :
4244 self .camera = PiCamera (resolution = (self .resolutionX , self .resolutionY ))
45+ # Below we calibrate the camera for consistent imaging
46+ camera .framerate = 30
47+ # Wait for the automatic gain control to settle
48+ time .sleep (2 )
49+ # Now fix the values
50+ camera .shutter_speed = camera .exposure_speed
51+ camera .exposure_mode = 'off'
52+ g = camera .awb_gains
53+ camera .awb_mode = 'off'
54+ camera .awb_gains = g
4355 except :
4456 self .camera = PiCamera ()
45- #camera.start_preview()
57+
58+ #Pubsub Listeners
59+ self .pubsub = variables .r .pubsub ()
60+ self .pubsub .subscribe (** {self .topic : self .handleEvent })
61+
4662 print ('Camera Worker...\t \t \t \033 [1;32m Ready\033 [0;0m' )
4763 return
4864
4965 def run (self ):
5066 t = threading .Thread (target = self .work , args = ())
5167 t .start ()
68+ self .listener = threading .Thread (target = self .listen , args = ())
69+ self .listener .start ()
5270 print ('Camera Worker...\t \t \t \033 [1;32m Running\033 [0;0m' )
5371 return t
5472
5573 def wait (self ):
5674 # Calculate the delay
5775 try :
58- next_time = (datetime .datetime .now () + datetime .timedelta (hours = self .hours , minutes = self .minutes , seconds = self .seconds )).replace (microsecond = 0 )
76+ self . next_time = (datetime .datetime .now () + datetime .timedelta (hours = self .hours , minutes = self .minutes , seconds = self .seconds )).replace (microsecond = 0 )
5977 except :
6078 #Default every hour
61- next_time = (datetime .datetime .now () + datetime .timedelta (hours = 1 )).replace (minute = 0 , second = 0 , microsecond = 0 )
62- delay = (next_time - datetime .datetime .now ()).seconds
79+ self . next_time = (datetime .datetime .now () + datetime .timedelta (hours = 1 )).replace (minute = 0 , second = 0 , microsecond = 0 )
80+ delay = (self . next_time - datetime .datetime .now ()).seconds
6381 time .sleep (delay )
6482
6583 def elapsedTime (self ):
@@ -70,24 +88,63 @@ def resetElapsedTime(self):
7088 self .time_start = time .perf_counter ()
7189 pass
7290
91+ def handleEvent (self , message ):
92+ data = message ['data' ]
93+ decoded_message = None
94+ if data is not None :
95+ try :
96+ if isinstance (data , dict ):
97+ decoded_message = data
98+ elif isinstance (data .decode ('utf-8' ), str ):
99+ temp = json .loads (data .decode ('utf-8' ))
100+ decoded_message = temp
101+ if decoded_message ['event' ] == 'Timelapse' :
102+ print ("Camera Signaled for Reset" )
103+ camera_available .clear ()
104+ self .pending_reset = True
105+ except :
106+ print ('Error Handling Event for Camera' )
107+
108+ def listen (self ):
109+ while self .main_thread_running .is_set ():
110+ if self .system_ready .is_set ():
111+ if self .camera_available .is_set ():
112+ self .pubsub .get_message ()
113+ time .sleep (1 )
114+ else :
115+ delay = (self .next_time - datetime .datetime .now ()).seconds + 15
116+ time .sleep (delay ) #wait 15 seconds after next scheduled picture
117+ self .camera_available .set ()
118+ else :
119+ time .sleep (2 )
120+ return
121+
73122 def work (self ):
74123 self .resetElapsedTime ()
75124 while self .main_thread_running .is_set ():
76125 if self .system_ready .is_set ():
77126 if self .camera_available .is_set ():
78127 # try:
79128 for i , filename in enumerate (self .camera .capture_continuous (self .path + 'mudpi-{counter:05d}.jpg' )):
129+ if not self .camera_available .is_set ():
130+ if self .pending_reset :
131+ try :
132+ os .remove (filename ) #cleanup previous file
133+ self .pending_reset = False
134+ except :
135+ print ("Error During Camera Reset Cleanup" )
136+ break ;
80137 message = {'event' :'StateChanged' , 'data' :filename }
81138 variables .r .set ('last_camera_image' , filename )
82139 variables .r .publish (self .topic , json .dumps (message ))
83140 print ('Image Captured \033 [1;36m%s\033 [0;0m' % filename )
84141 self .wait ()
85- if not self .camera_available .is_set ():
86- break ;
87142 # except:
88143 # print("Camera Worker \t\033[1;31m Unexpected Error\033[0;0m")
89144 # time.sleep(30)
90-
145+ else :
146+ time .sleep (1 )
147+ self .resetElapsedTime ()
91148 else :
92149 #System not ready camera should be off
93150 time .sleep (1 )
@@ -97,4 +154,6 @@ def work(self):
97154
98155 #This is only ran after the main thread is shut down
99156 self .camera .close ()
157+ self .listener .join ()
158+ self .pubsub .close ()
100159 print ("Camera Worker Shutting Down...\t \t \033 [1;32m Complete\033 [0;0m" )
0 commit comments