class Core(object): '''Implements the core functionality of SimpleSeer - capture - inspect - measure - watch ''' _instance=None class Transition(Exception): def __init__(self, state): self.state = state def __init__(self, config): if Core._instance is not None: assert RuntimeError, 'Only one state machine allowed currently' Core._instance = self self._states = {} self._cur_state = None self._events = Queue() self._clock = util.Clock(1.0, sleep=gevent.sleep) self._config = config self._worker_enabled = None self._worker_checked = None self.config = config #bkcompat for old SeerCore stuff self.cameras = [] self.video_cameras = [] self.log = logging.getLogger(__name__) self._mem_prof_ticker = 0 self._channel_manager = ChannelManager(shareConnection=False) for cinfo in config.cameras: cam = StillCamera(**cinfo) video = cinfo.get('video') if video is not None: cam = VideoCamera(cam, 1.0, **video) cam.start() self.video_cameras.append(cam) self.cameras.append(cam) util.load_plugins() self.reloadInspections() if not self.config.skip_worker_check and not self.config.framebuffer: self.workerCheck(5.0) #wait up to 5s for worker processes if self.config.framebuffer and not self.config.skip_worker_check: log.warn("Framebuffer is active, while worker is enabled. Workers can not handle framebuffer calls, so you should add skip_worker_check: 1 to the config") self.lastframes = deque() self.framecount = 0 self.reset() @classmethod def get(cls): return cls._instance def workerCheck(self, timeout = 0.5, checkinterval = 0.1): result = ping_worker.delay(1) checktime = time.time() self.log.info("checking for worker process") self._worker_checked = checktime while not result.ready(): time.sleep(checkinterval) if time.time() - checktime > timeout: self.log.info("worker check timeout") self._worker_enabled = False return False if result.get() == 2: self.log.info("worker found") self._worker_enabled = True return True else: self._worker_enabled = False return False def reloadInspections(self): i = list(M.Inspection.objects) m = list(M.Measurement.objects) w = list(M.Watcher.objects) self.inspections = i self.measurements = m self.watchers = w def subscribe(self, name): # Create thread that listens for event specified by name # If message received, trigger that event def callback(msg): data = jsondecode(msg.body) self.trigger(name, data) def listener(): self._channel_manager.subscribe(name, callback) gevent.spawn_link_exception(listener) def publish(self, name, data): self._channel_manager.publish(name, data) def get_image(self, width, index, camera): frame = self.lastframes[index][camera] image = frame.image if (width): image = image.scale(width / float(image.width)) s = StringIO() image.save(s, "jpeg", quality=60) return dict( content_type='image/jpeg', data=s.getvalue()) def get_config(self): return self._config.get_config() def reset(self): start = State(self, 'start') self._states = dict(start=start) self._cur_state = start def capture(self, indexes = []): currentframes = [] self.framecount += 1 cameras = self.cameras if len(indexes): cameras = [ self.cameras[i] for i in indexes ] currentframes = [ cam.getFrame() for cam in cameras ] while len(self.lastframes) >= (self._config.max_frames or 30): self.lastframes.popleft() self.lastframes.append(currentframes) new_frame_ids = [] for frame in currentframes: new_frame_ids.append(frame.id) return currentframes """ This is probably not used any more. commenting out to make sure def inspect(self, frames = []): if not len(frames) and not len(self.lastframes): frames = self.capture() elif not len(frames): frames = self.lastframes[-1] for frame in frames: frame.features = [] frame.results = [] for inspection in self.inspections: if inspection.parent: #root parents only continue if inspection.camera and frame.camera != inspection.camera: #this camera, or all cameras if no camera is specified continue feats = inspection.execute(frame.image) frame.features.extend(feats) for m in inspection.measurements: m.execute(frame, feats) for watcher in self.watchers: watcher.check(frame.results) """ def process(self, frame): if self._worker_enabled: async_results = self.process_async(frame) return self.process_async_complete(frame, async_results) frame.features = [] frame.results = [] # all times are in seconds, not ms ct_epoch = int(frame.capturetime.strftime("%s")) for inspection in M.Inspection.objects: if inspection.parent: continue if inspection.camera and inspection.camera != frame.camera: continue if 'interval' in inspection.parameters and not nextInInterval(frame, inspection.parameters['intervalField'], inspection.parameters['interval']): continue features = inspection.execute(frame) frame.features += features for m in inspection.measurements: if 'interval' in m.parameters and not nextInInterval(frame, m.parameters['intervalField'], m.parameters['interval']): continue m.execute(frame, features) def process_async(self, frame): frame.features = [] frame.results = [] frame.save_image() #make sure the image is in gridfs (does nothing if already saved) results_async = [] inspections = list(M.Inspection.objects) #allocate each inspection to a celery task # all times are in seconds, not ms for inspection in M.Inspection.objects: if inspection.parent: continue if inspection.camera and inspection.camera != frame.camera: continue if 'interval' in inspection.parameters and not nextInInterval(frame, inspection.parameters['intervalField'], inspection.parameters['interval']): continue results_async.append(execute_inspection.delay(inspection.id, frame.imgfile.grid_id, frame.metadata)) return results_async def process_async_complete(self, frame, results_async): #note that async results refer to Celery results, and not Frame results results_complete = [] ct_epoch = int(frame.capturetime.strftime("%s")) while not len(results_complete) == len(results_async): new_ready_results = [] for index, r in enumerate(results_async): if not index in results_complete and r.ready(): new_ready_results.append(index) for result_index in new_ready_results: (scvfeatures, inspection_id) = results_async[result_index].get() insp = M.Inspection.objects.get(id=inspection_id) features = [] for scvfeature in scvfeatures: scvfeature.image = frame.image ff = M.FrameFeature() ff.setFeature(scvfeature) ff.inspection = insp.id features.append(ff) frame.features += features #import pdb;pdb.set_trace() for m in insp.measurements: if 'interval' in m.parameters and not nextInInterval(frame, m.parameters['intervalField'], m.parameters['interval']): continue m.execute(frame, features) results_complete += new_ready_results time.sleep(0.2) @property def results(self): ret = [] for frameset in self.lastframes: results = [] for f in frameset: results += [f.results for f in frameset] ret.append(results) return ret """ def get_inspection(self, name): return M.Inspection.objects(name=name).next() def get_measurement(self, name): return M.Measurement.objects(name=name).next() """ def state(self, name): if name in self._states: return self._states[name] s = self._states[name] = State(self, name) return s def trigger(self, name, data=None): self._events.put((name, data)) def step(self): next = self._cur_state = self._cur_state.run() return next def wait(self, name): while True: try: (n,d) = self._events.get(timeout=0.5) if n == name: return (n,d) except Empty: continue self._cur_state.trigger(n,d) def on(self, state_name, event_name): state = self.state(state_name) self.subscribe(event_name) return state.on(event_name) def run(self, audit=False): audit_trail = [] while True: print self._cur_state if self._cur_state is None: break if audit: audit_trail.append(self._cur_state.name) try: self._cur_state = self._cur_state.run() except self.Transition, t: if isinstance(t.state, State): self._cur_state = t.state elif t.state is None: self._cur_state = None else: self._cur_state = self.state(t.state) audit_trail.append(None) return audit_trail