def get_free_photos(dir, camera_config, logger): freedir = dir + "free/" if not os.path.exists(freedir): try: os.mkdir(freedir) except Exception as e: logger.warning(whoami() + str(e)) return [] filelist = [f for f in os.listdir(freedir)] for f in filelist: try: os.remove(freedir + f) except Exception as e: logger.warning(whoami() + str(e)) urllist = [(c["name"], c["photo_url"], c["user"], c["password"]) for c in camera_config] freephotolist = [] for cname, url, user, pw in urllist: try: request = urllib.request.Request(url) base64string = base64.b64encode( bytes('%s:%s' % (user, pw), 'ascii')) request.add_header("Authorization", "Basic %s" % base64string.decode('utf-8')) result = urllib.request.urlopen(request, timeout=3) image = np.asarray(bytearray(result.read()), dtype="uint8") image = cv2.imdecode(image, cv2.IMREAD_COLOR) datestr = datetime.datetime.now().strftime("%d%m%Y-%H:%M:%S") photoname = freedir + cname + "_" + datestr + ".jpg" cv2.imwrite(photoname, image) freephotolist.append(photoname) except Exception as e: logger.warning(whoami() + str(e)) return freephotolist
def copy_redis_to_cameras_cfg(self): self.logger.debug(whoami() + "copying redis camera data to config ...") cameras = self.getp("g3_cameras") for i, c in enumerate(cameras, start=1): cstr = "CAMERA" + str(i) self.cfg[cstr]["ACTIVE"] = "yes" if c[0] else "no" self.cfg[cstr]["NAME"] = c[1] self.cfg[cstr]["STREAM_URL"] = c[2] self.cfg[cstr]["PHOTO_URL"] = c[3] self.cfg[cstr]["REBOOT_URL"] = c[4] self.cfg[cstr]["PTZ_MODE"] = c[5] self.cfg[cstr]["PTZ_RIGHT_URL"] = c[6] self.cfg[cstr]["PTZ_LEFT_URL"] = c[7] self.cfg[cstr]["PTZ_UP_URL"] = c[8] self.cfg[cstr]["PTZ_DOWN_URL"] = c[9] self.cfg[cstr]["MIN_AREA_RECT"] = str(c[10]) self.cfg[cstr]["HOG_SCALE"] = str(c[11]) self.cfg[cstr]["HOG_THRESH"] = str(c[12]) self.cfg[cstr]["MOG2_SENSITIVITY"] = str(c[13]) self.cfg[cstr]["USER"] = str(c[14]) self.cfg[cstr]["PASSWORD"] = str(c[15]) # write to cfg_file cfg_file = self.dirs["main"] + "guck3.config" try: with open(cfg_file, "w") as f: self.cfg.write(f) except Exception as e: self.logger.error(whoami() + str(e) + ", cannot write redis to config file!") return -1 self.logger.debug(whoami() + "... redis camera data copied to config!") return 1
def userlogin(): if request.method == "GET": app.logger.info(whoami() + ": new user starting to log in ...") userloginform = models.UserLoginForm(request.form) return render_template( "login.html", userloginform=userloginform, userauth=flask_login.current_user.is_authenticated) else: userloginform = models.UserLoginForm(request.form) email = userloginform.email.data pw = userloginform.password.data app.logger.info(whoami() + ": user trying to log in - " + email) try: correct_pw = USERS[email] except Exception: app.logger.warning(whoami() + ": user log in failed - " + email) return redirect(url_for("index")) if pw == correct_pw: app.logger.info(whoami() + ": user logged in - " + email) try: user = User() user.id = email flask_login.login_user(user) except Exception: pass return render_template("index.html") app.logger.warning(whoami() + ": user log in failed- " + email) return redirect(url_for('index'))
def stop(self): if not self.active or not self.running: return self.logger.debug(whoami() + "stopping telegram bot") self.send_message_all("Stopping GUCK3 telegram bot, this may take a while ...") self.updater.stop() self.logger.info(whoami() + "telegram bot stopped!") self.running = False
def run(self): if not self.active or not self.isok: self.startup_completed = True return self.startup_cam() self.startup_completed = True if not self.isok or not self.active or not self.mpp: return self.running = True while self.running and self.isok and self.active: t_query = time.time() try: self.parent_pipe.send("query") except Exception as e: self.logger.warning(whoami() + str(e) + ": error in communication with camera " + self.cname) self.running = False self.isok = False break while True: cond1 = self.running cond2 = self.parent_pipe.poll() if not cond1 or cond2: break time.sleep(0.01) if cond1 and not cond2: # stopped and no poll break ret, frame0, rects, tx = self.parent_pipe.recv() self.tx = tx t_reply = time.time() with self.lock: self.fpslist.append(1 / (t_reply - t_query)) self.isok = ret if not cond1: break if not self.isok: self.logger.warning(whoami() + ": error in communication with camera " + self.cname) self.running = False break if ret: if self.frame is not None: self.oldframe = self.frame.copy() else: self.oldframe = None self.frame = frame0.copy() self.newframe = False if self.frame is not None and self.oldframe is not None: if np.bitwise_xor(self.frame, self.oldframe).any(): self.newframe = True self.rects = rects self.shutdown() self.shutdown_completed = True
def get_config(self): t = self.cfgr.get_telegram() if t["active"].lower() == "no": return False, None, None try: token = t["token"] chatids = json.loads(t["chatids"]) self.logger.debug(whoami() + "got config for active telegram bot") except Exception as e: self.logger.debug(whoami() + str(e) + "telegram config error, setting telegram to inactive!") return False, None, None return True, token, chatids
def __init__(self, ccfg, dirs, mp_loggerqueue, logger): Thread.__init__(self) self.daemon = True self.ccfg = ccfg self.parent_pipe, self.child_pipe = mp.Pipe() self.mpp = None self.outvideo = None self.ymax = -1 self.xmax = -1 self.dirs = dirs self.is_recording = False self.recordfile = None self.frame = None self.oldframe = None self.rects = [] self.tx = None self.shutdown_completed = False self.running = False self.newframe = False self.cnn_classified_list = [] self.fpslist = [] self.lock = Lock() self.startup_completed = False self.logger = logger self.mp_loggerqueue = mp_loggerqueue try: self.isok = True self.cname = ccfg["name"] self.active = ccfg["active"] self.stream_url = ccfg["stream_url"] self.photo_url = ccfg["photo_url"] self.reboot_url = ccfg["reboot_url"] self.ptz_mode = ccfg["ptz_mode"] self.ptz_right_url = ccfg["ptz_right_url"] self.ptz_left_url = ccfg["ptz_left_url"] self.ptz_up_url = ccfg["ptz_up_url"] self.ptz_down_url = ccfg["ptz_down_url"] self.min_area_rect = ccfg["min_area_rect"] self.hog_scale = ccfg["hog_scale"] self.hog_thresh = ccfg["hog_thresh"] self.mog2_sensitivity = ccfg["mog2_sensitivity"] except Exception as e: self.logger.error(whoami() + str(e)) try: self.fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D') except Exception: self.logger.error(whoami() + "Cannot get fourcc, no recording possible") self.fourcc = None
def get_cnn_classification(self, camera): if (not self.active) or not (camera.active and camera.frame is not None) or\ (len(camera.rects) == 0 or self.RESNETMODEL is None): return [] try: self.logger.debug(whoami() + "performing resnet classification with " + str(len(camera.rects)) + " opencv detections ...") img0 = self.image_loader(camera.frame.copy()) pred = self.RESNETMODEL([img0])[0] boxes = pred["boxes"].to("cpu").tolist() labels = pred["labels"].to("cpu").tolist() scores = pred["scores"].to("cpu").tolist() cnn_classified_list = [] for x, y, w, h in camera.rects: r2 = (x, y, x + w, y + h) for i, label in enumerate(labels): if label != 1 or scores[i] < 0.5: continue box = boxes[i] x1_det = int(box[0]) y1_det = int(box[1]) x2_det = int(box[2]) y2_det = int(box[3]) x_det_w = x2_det - x1_det y_det_h = y2_det - y1_det r1 = (x1_det, y1_det, x2_det, y2_det) overlapArea, ratio1, ratio2 = self.overlap_rects(r1, r2) if (ratio1 > 0.5 or ratio2 > 0.5): self.logger.info(" Human detected with score " + str(scores[i]) + " and overlap " + str(ratio1) + " / " + str(ratio2)) cnn_classified_list.append( (x1_det, y1_det, x_det_w, y_det_h)) self.logger.info(whoami() + "!! CLASSIFIED !!") else: self.logger.info("Detection refused with score " + str(scores[i]) + " and ratios " + str(ratio1) + " / " + str(ratio2) + " !") camera.cnn_classified_list = cnn_classified_list except Exception as e: self.logger.error(whoami() + str(e) + ": ResNet classification error!") camera.cnn_classified_list = [] return
def stop_recording(self): if self.outvideo: self.outvideo.release() self.outvideo = None self.is_recording = False self.logger.debug(whoami() + "camera " + self.cname + " recording stopped")
def send_photo(self, photopath): if not self.active: return for c in self.chatids: try: self.bot.send_photo(chat_id=c, photo=open(photopath, "rb")) except Exception as e: self.logger.warning(whoami() + str(e) + ": chat_id " + str(c))
def send_message_all(self, text): if not self.active: return for c in self.chatids: try: self.bot.send_message(chat_id=c, text=text) except Exception as e: self.logger.warning(whoami() + str(e) + ": chat_id " + str(c))
def run(self): if not self.active: return self.logger.debug(whoami() + "starting keyboard thread") self.running = True instruction = ">> Enter '?' or 'help' for help" print(instruction) while self.running: mpp_inputto = mp.Process(target=input_to, args=(self.fn, 1, self.kbqueue, )) mpp_inputto.start() msg = self.kbqueue.get() mpp_inputto.join() if self.running and msg: reply = GeneralMsgHandler(msg, "kbd", self.state_data, self.mp_loggerqueue) print(reply) print(instruction) self.logger.debug(whoami() + "keyboard thread stopped!")
def user_loader(email): if email not in USERS: return try: user = User() user.id = email except Exception as e: app.logger.warning(whoami() + str(e)) return user
def insert_photodata(self, photonames): photodata = self.getp("g3_photodata") try: for p in photonames: photodata.insert(0, p) if len(photodata) > 50: del photodata[-1] self.setp("g3_photodata", photodata) except Exception as e: self.logger.error(whoami() + str(e) + ", cannot insert photodata!")
def __init__(self, dirs, cfgr, logger): self.logger = logger self.active = False self.cfgr = cfgr self.dirs = dirs with warnings.catch_warnings(): warnings.simplefilter("ignore") self.device = torch.device( "cuda" if torch.cuda.is_available() else "cpu") try: self.RESNETMODEL = torchvision.models.detection.maskrcnn_resnet50_fpn( pretrained=True).to(self.device) self.RESNETMODEL.eval() self.active = True self.logger.info(whoami() + "Torchvision Resnet initialized!") except Exception as e: self.logger.error(whoami() + str(e) + ": cannot init Torchvision Resnet!") self.RESNETMODEL = None
def stop(self): if self.shutdown_completed and not self.mpp: self.logger.warning(whoami() + self.cname + " shutdown already completed, exiting ...") return 1 elif self.shutdown_completed and self.mpp: self.logger.warning(whoami() + self.cname + " shutdown only half completed, aborting !!!") return -1 self.logger.debug(whoami() + "setting stop for " + self.cname) self.running = False t0 = time.time() while not self.shutdown_completed and time.time() - t0 < 10: time.sleep(0.1) if not self.shutdown_completed: self.logger.error(whoami() + self.cname + " shutdown sequence timed out, aborting !!!!") else: self.logger.debug(whoami() + "shutdown completed for " + self.cname)
def copy_cameras_to_redis(self): self.logger.debug(whoami() + "copying camera data to redis ...") self.setp("g3_cameras", []) cameralist = [] idx = 1 while True: str0 = "CAMERA" + str(idx) try: assert self.cfg[str0]["NAME"] active = True if self.cfg[str0]["ACTIVE"].lower( ) == "yes" else False camera_name = self.cfg[str0]["NAME"] stream_url = self.cfg[str0]["STREAM_URL"] photo_url = self.cfg[str0]["PHOTO_URL"] user = self.cfg[str0]["USER"] password = self.cfg[str0]["PASSWORD"] reboot_url = self.cfg[str0]["REBOOT_URL"] ptz_mode = self.cfg[str0]["PTZ_MODE"].lower() if ptz_mode not in ["start", "startstop", "none"]: ptz_mode = "none" ptz_right_url = self.cfg[str0]["PTZ_RIGHT_URL"] ptz_left_url = self.cfg[str0]["PTZ_LEFT_URL"] ptz_up_url = self.cfg[str0]["PTZ_UP_URL"] ptz_down_url = self.cfg[str0]["PTZ_DOWN_URL"] min_area_rect = int(self.cfg[str0]["MIN_AREA_RECT"]) hog_scale = float(self.cfg[str0]["HOG_SCALE"]) hog_thresh = float(self.cfg[str0]["HOG_THRESH"]) mog2_sensitivity = float(self.cfg[str0]["MOG2_SENSITIVITY"]) cameralist.append( (active, camera_name, stream_url, photo_url, reboot_url, ptz_mode, ptz_right_url, ptz_left_url, ptz_up_url, ptz_down_url, min_area_rect, hog_scale, hog_thresh, mog2_sensitivity, user, password)) except Exception: break idx += 1 if idx == 1: self.copyok = False return self.setp("g3_cameras", cameralist) self.logger.debug(whoami() + " ... camera data copied to redis!")
def handler(self, update, context): msg = update.message.text.lower() reply = GeneralMsgHandler(msg, "tgram", self.state_data, self.mp_loggerqueue) update.message.reply_text(reply) if reply.startswith("collecting photo snapshots"): imglist = get_free_photos(self.state_data.DIRS["photo"], self.state_data.CAMERA_CONFIG, self.logger) if imglist: for photo_name in imglist: try: self.bot.send_photo(chat_id=update.effective_chat.id, photo=open(photo_name, "rb")) except Exception as e: self.logger.warning(whoami() + str(e))
def run_nest(ns_outqueue, ns_inqueue, dirs, cfg, mp_loggerqueue): global TERMINATED setproctitle("g3." + os.path.basename(__file__)) logger = mplogging.setup_logger(mp_loggerqueue, __file__) logger.info(whoami() + "starting ...") sh = SigHandler_ns(logger) signal.signal(signal.SIGINT, sh.sighandler_ns) signal.signal(signal.SIGTERM, sh.sighandler_ns) try: nest_token = cfg["NEST"]["TOKEN"] nest_api_url = "https://developer-api.nest.com" nest = Nest_sse(nest_token, nest_api_url, "STATUS", logger) nest.start() except Exception: logger.error(whoami() + "cannot start nest, exiting ...") ns_outqueue.put("NOOK") sys.exit() ns_outqueue.put("OK") while not TERMINATED: time.sleep(0.02) try: cmd = ns_inqueue.get_nowait() if cmd == "stop": break elif cmd == "get_status": nest_status = nest.fetch() ns_outqueue.put(nest_status) except (queue.Empty, EOFError): continue except Exception: continue clear_all_queues([ns_inqueue, ns_outqueue]) logger.info(whoami() + "... exited!")
def start(self): if not self.active: return -1 self.logger.debug(whoami() + "starting telegram handler") self.logger.debug(whoami() + "telegram token & chat ids: " + str(self.token) + " / " + str(self.chatids)) try: self.updater = Updater(self.token, use_context=True) self.dp = self.updater.dispatcher self.bot = self.updater.bot self.dp.add_handler(MessageHandler(Filters.text, self.handler)) self.updater.start_polling() self.running = True self.send_message_all("GUCK3 telegram bot started!") self.send_message_all(">> Enter '?' or 'help' for help") self.logger.info(whoami() + "telegram handler/bot started!") return 1 except Exception as e: self.logger.warning(whoami() + str(e) + "cannot start telegram bot, setting to inactive!") self.token = None self.chatids = None self.active = False return -1
def start_recording(self): if not self.active or not self.isok: return None if not self.fourcc: self.is_recording = False self.logger.debug( whoami() + "camera " + self.cname + " no recording possible due to missing fourcc/codec!") if self.outvideo: try: self.outvideo.release() except Exception: pass now = datetime.now() datestr = now.strftime("%d%m%Y-%H:%M:%S") self.recordfile = self.dirs[ "video"] + self.cname + "_" + datestr + ".avi" self.outvideo = cv2.VideoWriter(self.recordfile, self.fourcc, 10.0, (self.xmax, self.ymax)) self.is_recording = True self.logger.debug(whoami() + "camera " + self.cname + " recording started: " + self.recordfile)
def shutdown(self): self.logger.debug(whoami() + "camera " + self.cname + " starting shutdown initialize") if self.outvideo: self.outvideo.release() self.logger.debug(whoami() + "camera " + self.cname + " recording stopped") try: self.parent_pipe.send("stop") t0 = time.time() polled = False while not polled and time.time() - t0 < 10: polled = self.parent_pipe.poll() time.sleep(0.05) if polled: ret, _ = self.parent_pipe.recv() self.mpp.join(5) if self.mpp.is_alive(): os.kill(self.mpp.pid, signal.SIGKILL) else: if self.mpp: if self.mpp.is_alive(): os.kill(self.mpp.pid, signal.SIGKILL) except Exception: if self.mpp: if self.mpp.is_alive(): os.kill(self.mpp.pid, signal.SIGKILL) self.mpp = None self.logger.debug(whoami() + "camera " + self.cname + " mpp stopped!") try: cv2.destroyWindow(self.cname) except Exception: pass self.stop_recording() self.frame = None self.logger.debug(whoami() + "camera " + self.cname + " shutdown finished!") return 1
def insert_update_userdata(self, username, lasttm, active, no_newdetections, photolist): try: userdata, user_in_userdata = self.user_in_userdata(username) if not user_in_userdata: userdata[username] = {} userdata[username]["lastttm"] = lasttm userdata[username]["active"] = active userdata[username]["no_newdetections"] = no_newdetections userdata[username]["photolist"] = photolist self.setp("g3_userdata", userdata) self.setp("g3_userdata_last_updated", time.time()) except Exception as e: self.logger.warning(whoami() + str(e))
def startup_cam(self): if not self.active or not self.isok: return None self.mpp = mp.Process(target=mpcam.run_cam, args=( self.ccfg, self.child_pipe, self.mp_loggerqueue, )) self.mpp.start() try: self.parent_pipe.send("query_cam_status") self.isok, self.ymax, self.xmax = self.parent_pipe.recv() except Exception: self.isok = False self.active = False if self.isok: self.logger.debug(whoami() + "camera " + self.cname + " started!") else: self.logger.debug(whoami() + "camera " + self.cname + " out of function, not started!") self.mpp.join() self.mpp = None return self.mpp
def beforerequest(): try: user0 = flask_login.current_user.get_id() g.user = user0 if user0 is not None: userdata, user_in_userdata = RED.user_in_userdata(user0) if not userdata or not user_in_userdata: RED.insert_update_userdata(user0, time.time(), True, 0, []) else: RED.insert_update_userdata(user0, time.time(), True, userdata[user0]["no_newdetections"], userdata[user0]["photolist"]) except Exception as e: app.logger.info(whoami() + str(e)) pass
def copy_users_to_redis(self): self.setp("g3_users", {}) idx = 1 users = {} while True: str0 = "USER" + str(idx) try: username = self.cfg[str0]["USERNAME"] password = self.cfg[str0]["PASSWORD"] users[username] = password except Exception: break idx += 1 if idx == 1: self.copyok = False return self.setp("g3_users", users) self.logger.debug(whoami() + "user data copied to db")
def run_cameras(pd_outqueue, pd_inqueue, dirs, cfg, mp_loggerqueue): global TERMINATED setproctitle("g3." + os.path.basename(__file__)) # tf.get_logger().setLevel('INFO') # tf.autograph.set_verbosity(1) logger = mplogging.setup_logger(mp_loggerqueue, __file__) logger.info(whoami() + "starting ...") sh = SigHandler_pd(logger) signal.signal(signal.SIGINT, sh.sighandler_pd) signal.signal(signal.SIGTERM, sh.sighandler_pd) cfgr = ConfigReader(cfg) camera_config = cfgr.get_cameras() options = cfgr.get_options() cameras = [] for c in camera_config: camera = Camera(c, dirs, mp_loggerqueue, logger) cameras.append(camera) startup_cams(cameras) logger.info(whoami() + "all cameras started!") tgram_active = False kbd_active = False pd_in_cmd, pd_in_param = pd_inqueue.get() if pd_in_cmd == "tgram_active": tgram_active = pd_in_param elif pd_in_cmd == "kbd_active": kbd_active = pd_in_param if not camera_config or not cameras: logger.error(whoami() + "cannot get correct config for cameras, exiting ...") pd_outqueue.put(("error:config", None)) sys.exit() else: pd_outqueue.put(("allok", None)) torchresnet = TorchResNet(dirs, cfgr, logger) try: showframes = (options["showframes"].lower() == "yes") except Exception: logger.warning( whoami() + "showframes not set in config, setting to default False!") showframes = False lastdetection_tt = 0 while not TERMINATED: time.sleep(0.02) mainmsglist = [] for c in cameras: mainmsg = "status" mainparams = (c.cname, c.frame, c.get_fps(), c.isok, c.active, c.tx) if c.active and c.isok: try: if c.newframe: torchresnet.get_cnn_classification(c) c.draw_detections(cnn=True) mainparams = (c.cname, c.frame, c.get_fps(), c.isok, c.active, c.tx) if showframes: cv2.imshow(c.cname, c.frame) c.write_record() new_detections = c.get_new_detections() if new_detections and time.time( ) - lastdetection_tt > 3: lastdetection_tt = time.time() mainmsg = "detection" c.clear_new_detections() except Exception as e: logger.warning(whoami() + str(e)) mainmsglist.append((mainmsg, mainparams)) # send to __main__.py pd_outqueue.put(mainmsglist) if showframes: cv2.waitKey(1) & 0xFF try: cmd, param = pd_inqueue.get_nowait() logger.debug(whoami() + "received " + cmd) if cmd == "stop": break elif cmd == "record on": start_all_recordings(cameras) elif cmd == "record off": stop_all_recordings(cameras) except (queue.Empty, EOFError): continue except Exception: continue shutdown_cams(cameras) clear_all_queues([pd_inqueue, pd_outqueue]) logger.info(whoami() + "... exited!")
def main(cfg, dirs, inqueue, outqueue, loggerqueue): global RED global USERS global DIRS global app global maincomm setproctitle("g3." + os.path.basename(__file__)) DIRS = dirs log_handler = logging.FileHandler(dirs["logs"] + "webflask.log", mode="w") log_handler.setFormatter( logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s')) app.logger.removeHandler(default_handler) app.logger.setLevel(logging.DEBUG) app.logger.addHandler(log_handler) app.logger.info(whoami() + "starting ...") RED = RedisAPI(REDISCLIENT, dirs, cfg, app.logger) if not RED.copyok: app.logger.error(whoami() + ": cannot init redis, exiting") outqueue.put("False") else: outqueue.put("True") USERS = RED.get_users() # start communicator thread maincomm = MainCommunicator(inqueue, outqueue, app, RED) maincomm.start() try: certfile = cfg["OPTIONS"]["CERTFILE"] keyfile = cfg["OPTIONS"]["KEYFILE"] options = { 'bind': '%s:%s' % ('0.0.0.0', '8000'), 'certfile': certfile, 'keyfile': keyfile, 'capture_output': True, 'debug': True, 'graceful_timeout': 10, 'worker_class': 'gevent', 'workers': 1 } app.logger.info(whoami() + ": binding gunicorn to https!") except Exception: options = { 'bind': '%s:%s' % ('0.0.0.0', '8000'), 'capture_output': True, 'debug': True, 'graceful_timeout': 10, 'worker_class': 'gevent', 'workers': 1 } app.logger.warning(whoami() + ": binding gunicorn to http!") signal.signal(signal.SIGFPE, sighandler) # nicht die feine englische / faut de mieux StandaloneApplication(app, options).run()
def userlogout(): userid = flask_login.current_user.get_id() app.logger.info(whoami() + ": user logging out - " + userid) flask_login.logout_user() return redirect(url_for("index"))
def shutdown(self): global TERMINATED TERMINATED = True self.logger.debug(whoami() + "got signal, exiting ...")