class Valve(): def __init__(self,valve_name,usbConnectHandler): #log.setLevel(logging.INFO) self.config_handler = ConfigManager() self.alarm_mgr_handler = AlertManager() matchObj = re.findall(r'\d', valve_name, 1) valve_id = int(matchObj[0]) self.vlv_id = valve_id self.vlv_name = valve_name self.vlv_board_pin_relay = int(self.config_handler.getConfigParam(self.vlv_name,"OutBoardPin")) self.vlv_status = G_UNKNOWN self.vlv_prevstatus = G_UNKNOWN self.vlv_lightstatus = "" self.vlv_prevlightstatus = "" self.vlv_light_list = {} #Dict of lights. key = color GREEN RED WHITE self.vlv_start_time = time.time() self.vlv_update_time=time.time() self.vlv_open_time = None self.vlv_manualopen_time = None self.vlv_manual_mode = False self.vlv_error_time = None self.vlv_last_alert_time = 0 self.vlv_last_sev1_alert_time = 0 self.vlv_last_cmd_sent_time = None self.vlv_last_cmd_trigger_time = None self.vlv_next_auto_cmd_allowed_time = time.time() + float(self.config_handler.getConfigParam("VALVE_MANAGER", "VALVE_MANAGER_LOOP_TIMEOUT")) self.vlv_next_manual_cmd_allowed_time = time.time() + float(self.config_handler.getConfigParam("VALVE_MANAGER", "VALVE_MANAGER_LOOP_TIMEOUT")) self.vlv_lock_time=None self.seconds_between_alerts=float(self.config_handler.getConfigParam("ALERT", "TimeBetweenAlerts")) self.vlv_alert_light_time = None self.auto_force_close_valve = False self.vlv_force_lock = False self.vlv_add_alert_time_by_type = {} #Key is Alert type, data is time() self.valve_properties = None valveconfigfilename = self.config_handler.getConfigParam("INTERNAL", "VALVE_CONFIG_DEFINITION_FILE") self.loadValveConfig(valveconfigfilename) self.nbrfault=0 self.vlv_statusEventList=[] self.usbConnectHandler=usbConnectHandler self.initBoardPinModeOutput(int(self.config_handler.getConfigParam(self.vlv_name,"OutBoardPin"))) tmplog = "Valve Serial Device: %s pin %d" % (self.usbConnectHandler.connection.device, int(self.config_handler.getConfigParam(self.vlv_name,"OutBoardPin"))) log.info(tmplog) #Force close on startup self.vlv_close_time = time.time() self.triggerValve("close") def loadValveConfig(self,valveconfigfilename): try: valveconfigfilename = self.config_handler.getConfigParam("INTERNAL", "VALVE_CONFIG_DEFINITION_FILE") valvesConfigJSON = {} #loadValveConfig(self.valveconfigfilename) f=open(valveconfigfilename) valvesConfigJSON=json.load(f) f.close() key_list = valvesConfigJSON.keys() for keysv in key_list: #Delete other keys, must be a better way ! if keysv != self.vlv_name: pass else: self.valve_properties = valvesConfigJSON[keysv] print(self.valve_properties) pass except IOError: log.error("Config file " + valveconfigfilename + " does not exist ! ") log.error("Exiting...") os._exit(-1) except Exception: traceback.print_exc() log.error("Exiting...") os._exit(-1) def isValveOpen(self,mything,myservice,myid): return self.vlv_status==G_OPEN def startLightFlash(self,color): key=self.vlv_name+"_"+color if (key in self.vlv_light_list): # log.info("Green startFlashLight started !!!") self.vlv_light_list[key].startFlashLight() def stopLightFlash(self, color): key = self.vlv_name + "_" + color if (key in self.vlv_light_list): # log.info("Green startFlashLight started !!!") self.vlv_light_list[key].stopFlashLight() def turnOnLight(self, color): key = self.vlv_name + "_" + color if (key in self.vlv_light_list): # log.info("Green startFlashLight started !!!") self.vlv_light_list[key].turnOnLight() def turnOffLight(self, color): key = self.vlv_name + "_" + color if (key in self.vlv_light_list): # log.info("Green startFlashLight started !!!") self.vlv_light_list[key].turnOffLight() def addAlert(self, id, device,extratxt=""): self.vlv_last_alert_time = time.time() status_text="request for Alert %s %s %s" %(id, device,extratxt) if (id in self.vlv_add_alert_time_by_type): lastalerttime = self.vlv_add_alert_time_by_type[id] if ( time.time() >(lastalerttime+self.seconds_between_alerts)): try: del self.vlv_add_alert_time_by_type[id] except KeyError: pass log.info("%s can now be sent again for %s!" %(id,device)) else: log.debug("Skip %s" % status_text) else: self.vlv_add_alert_time_by_type[id]=time.time() status_text = self.alarm_mgr_handler.addAlert(id, device, extratxt) log.warning(status_text) return status_text def determineValveOpenClosedStatus(self): #log.debug("Valve Determine Status called !") valve_status_text=self.vlv_name+":"+self.vlv_status logstr="" do_print_status=False if (self.vlv_prevstatus != self.vlv_status): self.vlv_update_time = time.time() do_print_status = True self.vlv_prevstatus = self.vlv_status if (do_print_status == True): self.printStatus() return (valve_status_text) def updateSensor(self): #Nothing to check here ! Weather API @Todo try: status_text="OK" # self.tid,self.module,self.device,self.status,self.text) except Exception: self.auto_force_close_valve = True sensor_status_text = self.addAlert("HW101", self.vlv_name ) resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]",self.vlv_name ,self.vlv_status,status_text) return resp def lock(self): tmptxt="" if self.vlv_force_lock==False: tmptxt="%s Valve Lock down requested" % (self.vlv_name) self.vlv_force_lock = True self.vlv_lock_time=time.time() else: self.vlv_force_lock = False tmptxt="%s Valve UnLock requested" % (self.vlv_name) # self.vlv_lock_time=None log.info(tmptxt) # resp = CommmandQResponse(time.time() * 1000000, "[DeviceManager] " + self.determineValveOpenClosedStatus()) # self.tid,self.module,self.device,self.status,self.text) mod="[DeviceManager]" stat="[STATUS]" str0 = self.determineValveOpenClosedStatus().split(':') dev=str0[0] if str0.__len__() >1: stat=str0[1] resp = CommmandQResponse(time.time() * 1000000, mod, dev, stat,"") return (resp) def status(self): log.debug("Valve status called !") self.updateSensor() rsptxt=self.getCmdQResponseStatusStr() #resp = CommmandQResponse(time.time() * 1000000, "[DeviceManager] " + self.determineValveOpenClosedStatus()) # self.tid,self.module,self.device,self.status,self.text) mod="[DeviceManager]" stat="[STATUS]" str0 = self.determineValveOpenClosedStatus().split(':') dev=str0[0] if str0.__len__() >1: stat=str0[1] resp = CommmandQResponse(time.time() * 1000000, mod, dev, stat,rsptxt) return (resp) def getCmdQResponseStatusStr(self): resp_json=None try: rspstr={} if self.vlv_open_time != None: rspstr[G_OPEN]=GarageUtil.getTimePrintOut(self,time.time()-self.vlv_open_time) else: rspstr[G_OPEN]="" if self.vlv_close_time != None and self.vlv_open_time != None: rspstr[G_CLOSED] = GarageUtil.getTimePrintOut(self,time.time()-self.vlv_close_time) else: rspstr[G_CLOSED]="" if self.vlv_error_time != None: rspstr[G_ERROR] = GarageUtil.getTimePrintOut(self,time.time()-self.vlv_close_time) else: rspstr[G_ERROR]="Check!" if self.vlv_lock_time !=None: rspstr[G_LOCK] = GarageUtil.getTimePrintOut(self,time.time()-self.vlv_lock_time) else: rspstr[G_LOCK] = "" resp_json = json.dumps(rspstr) except Exception: log.error("Bug handling of getCmdQResponseStatusStr JSON convert") traceback.print_exc() resp_json="Error!" return json.dumps(resp_json) def clear(self): # resp = CommmandQResponse(time.time()*1000000, "Valve alarm cleared" ) resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]", "", "", "Valve alarm cleared") return (resp) def addLight(self, key,lightobj): self.vlv_light_list[key]=lightobj self.initBoardPinModeOutput(self.vlv_light_list[key].board_pin_id) self.turnOffLight(key) log.debug(str(lightobj)) pass def initBoardPinModeOutput(self, pin): log.info("Init Board Pin %d Mode Output %s" % (pin, self.vlv_name)) self.usbConnectHandler.pinMode(pin, self.usbConnectHandler.OUTPUT) self.s_update_time = time.time() def initBoardPinModeInput(self, pin): log.info("Init Board Pin %d Mode Input %s" % (pin, self.vlv_name)) self.usbConnectHandler.pinMode(pin, self.usbConnectHandler.INPUT) self.s_update_time=time.time() def manualopen(self): try: status_text = "ManualOpen" self.alarm_mgr_handler.clearAlertDevice("VALVE_COMMAND", self.vlv_name,"called from manualopen()") self.addAlert("VO003", self.vlv_name, " Manually opened") self.vlv_manualopen_time=time.time() self.vlv_open_time = time.time() self.vlv_manual_mode = True #self.triggerValve("open") self.open() resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]", "", "", status_text) log.debug(status_text) return resp except Exception: traceback.print_exc() logstr = "open() Valve %s Status = %s Fatal Exception" % (self.vlv_name, self.vlv_status) log.error(logstr) os._exit(-1) # resp=CommmandQResponse(0, status_text) #resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]", "", "", status_text) #log.debug(status_text) #return resp def open(self): status_text="Open" self.alarm_mgr_handler.clearAlertDevice("VALVE_COMMAND", self.vlv_name, "from open()") try: self.vlv_open_time=time.time() if self.vlv_force_lock == False: if (self.vlv_status == G_CLOSED ): if time.time() > self.vlv_next_manual_cmd_allowed_time: self.alarm_mgr_handler.clearAlertDevice("VALVE_OPEN", self.vlv_name,"from open() / "+self.printStatus(True)) self.triggerValve("open") status_text=self.addAlert("VTO01", self.vlv_name) self.vlv_next_manual_cmd_allowed_time = time.time() + float(self.config_handler.getConfigParam("VALVE_COMMON", "TimeBetweenButtonManualPressed")) # self.startLightFlash('GREEN') else: # open denied. Too early to retry! self.vlv_manual_mode = False status_text = self.addAlert("VTO02", self.vlv_name) else: # open denied. current status is " + self.vlv_status status_text = self.addAlert("VTO03", self.vlv_name, self.vlv_status) else: #Lock! status_text = self.addAlert("VTO04", self.vlv_name, self.vlv_status) self.vlv_last_cmd_trigger_time=time.time() except Exception: traceback.print_exc() logstr = "open() Valve %s Status = %s Fatal Exception" % (self.vlv_name, self.vlv_status) log.error(logstr) os._exit(-1) # resp=CommmandQResponse(0, status_text) resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]", "", "", status_text) log.debug(status_text) return resp def close(self): logtxt = self.vlv_name +" " status_text = "Close" try: # if time.time() >= (self.vlv_close_time+ 2*float(self.config_handler.getConfigParam("NOTIFICATION_MANAGER", "NOTIFICATION_MANAGER_LOOP_TIMEOUT"))): #Dont clear alarm right away. give time to notification manager # self.alarm_mgr_handler.clearAlertDevice("VALVE_OPEN", self.vlv_name) # self.alarm_mgr_handler.clearAlertDevice("VALVE_COMMAND", self.vlv_name) # self.vlv_last_sev1_alert_time = time.time() # if To avoid misleading logs. Valve will be closed regardless if self.vlv_manual_mode == True and self.auto_force_close_valve == False: logtxt = logtxt + "Close Manual " log.info(logtxt) if time.time() > self.vlv_next_manual_cmd_allowed_time: # close. valve normal path! status_text = self.addAlert("VTC01", self.vlv_name) self.vlv_next_manual_cmd_allowed_time = time.time() + float(self.config_handler.getConfigParam("VALVE_COMMON", "TimeBetweenButtonManualPressed")) else: # Closing to often. closing anyways. Could indicate a GUI bug ! #if self.vlv_status != G_CLOSED and time.time() > (self.vlv_start_time+30): self.alarm_mgr_handler.clearAlertDevice("VALVE_COMMAND", self.vlv_name,"from close()") status_text = self.addAlert("VTC02", self.vlv_name, "from close()") if self.vlv_status != G_OPEN: # and time.time() > (self.vlv_start_time+30): #hard coded msg, dont wan to see on startup # already closed ! # Avoid on startup #self.alarm_mgr_handler.clearAlertDevice("VALVE_COMMAND", self.vlv_name) status_text = self.addAlert("VTC03", self.vlv_name,self.vlv_status) else: logtxt = logtxt + "close() Auto " log.debug(logtxt) self.vlv_close_time = time.time() self.triggerValve("close") self.vlv_last_cmd_trigger_time=time.time() self.vlv_manual_mode = False #reset manual mode to false except Exception: traceback.print_exc() logstr = "close() Valve %s Status = %s Fatal Exception" % (self.vlv_name, self.vlv_status) log.error(logstr) os._exit(-1) # resp=CommmandQResponse(0, status_text) resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]", "", "", status_text) log.debug(status_text) return resp ''' return True if OK, False if problem. OS exit if fatal ! ''' def triggerValve(self,cmd="close"): logtxt=self.vlv_name+" "+cmd+" triggerValve " #ValveManager Check Policy will not call this because status os LOCKOPEN and OPEN in this mode ! valve_cmd = None if self.valve_properties["TimeProperties"]["reverse_hi_low"] == "False": valve_cmd = self.usbConnectHandler.LOW else: valve_cmd = self.usbConnectHandler.HIGH try: if (cmd == "open"): #self.vlv_open_time = time.time() if (self.vlv_force_lock): logtxt = logtxt + "Trigger valve open refused because of Manual Override" else: if self.valve_properties["TimeProperties"]["reverse_hi_low"] == "False": valve_cmd = self.usbConnectHandler.HIGH else: valve_cmd = self.usbConnectHandler.LOW self.vlv_status=G_OPEN elif cmd == "close": #self.vlv_close_time = time.time() self.vlv_manual_mode = False #Manual Mode disbaled by close if self.valve_properties["TimeProperties"]["reverse_hi_low"] == "False": valve_cmd = self.usbConnectHandler.LOW else: valve_cmd = self.usbConnectHandler.HIGH self.vlv_status = G_CLOSED else: self.vlv_status = G_ERROR logtxt = logtxt + "Error with triggerValve command" status_text = self.addAlert("SW101", self.vlv_name) self.usbConnectHandler.digitalWrite(self.vlv_board_pin_relay, valve_cmd) self.vlv_next_auto_cmd_allowed_time = time.time() + float(self.config_handler.getConfigParam("VALVE_COMMON", "TimeBeforeAutoRetryClose")) self.vlv_next_manual_cmd_allowed_time = time.time() + float(self.config_handler.getConfigParam("VALVE_COMMON", "TimeBetweenButtonManualPressed")) self.vlv_last_cmd_sent_time=time.time() log.debug(logtxt) except Exception: log.error("triggerValve Open or Close fatal error !") traceback.print_exc() os._exit(-1) return True def printStatus(self, silent=False): logstr = "%s:%s " % (self.vlv_name, self.vlv_status) if self.vlv_update_time != None: printut = datetime.datetime.fromtimestamp(self.vlv_update_time).strftime("%Y%m%d-%H%M%S") else: printut = "None" if self.vlv_open_time != None: printot = datetime.datetime.fromtimestamp(self.vlv_open_time).strftime("%Y%m%d-%H%M%S") else: printot = "None" if self.vlv_manualopen_time != None: printmot = datetime.datetime.fromtimestamp(self.vlv_manualopen_time).strftime("%Y%m%d-%H%M%S") else: printmot = "None" if self.vlv_close_time != None: printct = datetime.datetime.fromtimestamp(self.vlv_close_time).strftime("%Y%m%d-%H%M%S") else: printct = "None" if self.vlv_error_time != None: printerrt = datetime.datetime.fromtimestamp(self.vlv_error_time).strftime("%Y%m%d-%H%M%S") else: printerrt = "None" if self.vlv_last_alert_time != None: printlast = datetime.datetime.fromtimestamp(self.vlv_last_alert_time).strftime("%Y%m%d-%H%M%S") else: printlast = "None" try: logstr = logstr + "updte=" + printut + " opn=" + printot + " clse=" + printct + " mopn="+printmot+" err=" + printerrt + " Alert=" + printlast if silent == False: log.info(logstr) except Exception: log.error("Time Stamp print error ?!? print to stdout ") print(logstr) return logstr def getAllLightStatus(self): all_light_status = "" for color in sorted({"GREEN", "RED", "WHITE"}): key_dev_color = self.vlv_name + "_" + color if key_dev_color in self.vlv_light_list: light_status = color[0] if self.vlv_light_list[key_dev_color].getLightStatus() == "ON": all_light_status += light_status.lower() elif self.vlv_light_list[key_dev_color].getLightStatus() == "FLASH": all_light_status += light_status.upper() else: all_light_status += "-" else: log.debug("%s %s light defined yet" % (color,self.vlv_name)) return all_light_status def test(self): self.initBoardPinModeOutput(self.vlv_board_pin_relay) logbuf = "Arduino Init Pin=%d" % self.vlv_board_pin_relay log.info(logbuf) for n in range(0, 1): self.usbConnectHandler.digitalWrite(self.vlv_board_pin_relay, self.usbConnectHandler.HIGH) log.info("ON") sleep(3) self.usbConnectHandler.digitalWrite(self.vlv_board_pin_relay, self.usbConnectHandler.LOW) log.info("OFF") sleep(2) n += 1 resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]", "", "", "test!") return resp def get_serialdevicename(self): return self.usbConnectHandler.connection.device def get_vlv_name(self): return self.vlv_name
class ValveManager(): def __init__(self): #log.setLevel(logging.INFO) log.info("ValveManager Starting") self.valve_manager_start_time = time.time() self.config_handler = ConfigManager() self.alarm_mgr_handler = AlertManager() self.notif_mgr_handler = NotificationManager() self.email_sender = self.config_handler.getConfigParam( "EMAIL_ACCOUNT_INFORMATION", "USER") self.email_recipient = self.config_handler.getConfigParam( "EMAIL_ACCOUNT_INFORMATION", "RECIPIENTLISTINFO") self.weather_mgr_handler = WeatherManager() self.isRainForecast = False self.isRainForecastPrev = False self.ValveOpenTriggerCriticalElapsedTime = float( self.config_handler.getConfigParam( "VALVE_COMMON", "ValveOpenTriggerCriticalElapsedTime")) self.ValveOpenTriggerWarningElapsedTime = float( self.config_handler.getConfigParam( "VALVE_COMMON", "ValveOpenTriggerWarningElapsedTime")) self.ValveHardwareResponseTime = float( self.config_handler.getConfigParam("VALVE_COMMON", "ValveHardwareResponseTime")) self.cherryweb_server_last_run_time = time.time() self.gm_add_alert_time_by_type = {} #Key is Alert type, data is time() self.seconds_between_alerts = float( self.config_handler.getConfigParam("ALERT", "TimeBetweenAlerts")) self.vlv_add_alert_time_by_type = { } #Key is Alert type, data is time() self.error_message_count = 0 self.valve_last_info_log = {} #use as heart beat ! self.last_schedule_process_time = { } #Avoid closing the valve at every loop self.endtime_null = "19990101-00:00:00" self.weekdays_name = [ 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY' ] self.valve_run_end_time_dict = {} #Track end time for valve self.last_alert_closed_sev3_checkvalvepolicy = { } #Avoid closing the valve at every loop self.last_alert_open_sev3_checkvalvepolicy = { } #Avoid closing the valve at every loop self.default_language = self.config_handler.getConfigParam( "NOTIFICATION_COMMON", "DEFAULT_LANGUAGE") self.valveconfigfilename = self.config_handler.getConfigParam( "INTERNAL", "VALVE_CONFIG_DEFINITION_FILE") self.valvesConfigJSON = {} self.valves_by_id = {} self.loadValveConfig(self.valveconfigfilename) def loadValveConfig(self, valveconfigfilename): try: f = open(self.valveconfigfilename) self.valvesConfigJSON = json.load(f) #self.valvesConfigJSON=json.dumps(tmpcfg, indent=2, sort_keys=True) f.close() self.processValveConfig() except IOError: log.error("Config file " + self.valveconfigfilename + " does not exist ! ") log.error("Exiting...") os._exit(-1) except Exception: traceback.print_exc() log.error("Exiting...") os._exit(-1) def processValveConfig(self): try: valve_ordered_array = [] for keysv in self.valvesConfigJSON: id = self.valvesConfigJSON[keysv]["TimeProperties"]["id"] self.valves_by_id[ id] = keysv #hash to sort valve by id. No lamda working! for id in sorted(self.valves_by_id, key=int): keysv = self.valves_by_id[id] valve_ordered_array.append(keysv) valve_ordered_array_length = len(valve_ordered_array) for vlvidx in range(valve_ordered_array_length): keysv = valve_ordered_array[vlvidx] keysvprevious = None logtxt = keysv + " " cfg_start_time_field = self.valvesConfigJSON[keysv][ "TimeProperties"]["start_time"] cfg_duration_field = self.valvesConfigJSON[keysv][ "TimeProperties"]["duration"] cfg_calendar_field = self.valvesConfigJSON[keysv][ "TimeProperties"]["calendar"] previous_cfg_start_time_field = None previous_cfg_duration_field = None previous_cfg_calendar_field = None previous_cfg_duration_field_array = None previous_cfg_duration_field_array_len = 0 previous_cfg_calendar_field_array = None previous_cfg_calendar_field_array_len = 0 previous_flag = False if cfg_start_time_field == "PREVIOUS": previous_flag = True logtxt = " PREVIOUS keyword found." log.debug(logtxt) if vlvidx == 0: log.error(keysv + " Cannot be set to previous with id") log.error(keysv + "Config error for cfg_start_time in " + self.valveconfigfilename) os._exit(-1) keysvprevious = valve_ordered_array[vlvidx - 1] previous_cfg_start_time_field = self.valvesConfigJSON[ keysvprevious]["TimeProperties"]["start_time"] previous_cfg_duration_field = self.valvesConfigJSON[ keysvprevious]["TimeProperties"]["duration"] previous_cfg_calendar_field = self.valvesConfigJSON[ keysvprevious]["TimeProperties"]["calendar"] previous_cfg_duration_field_array = previous_cfg_duration_field.split( ',') previous_cfg_duration_field_array_len = len( previous_cfg_duration_field_array) previous_cfg_calendar_field_array = previous_cfg_calendar_field.split( ',') previous_cfg_calendar_field_array_len = len( previous_cfg_calendar_field_array) logtxt = str( vlvidx ) + ") PREVIOUS value for " + keysvprevious + " from " + keysv + " st=" + previous_cfg_start_time_field log.debug(logtxt) if previous_flag == True: cfg_start_time_field_array = previous_cfg_start_time_field.split( ',') else: cfg_start_time_field_array = cfg_start_time_field.split( ',') cfg_start_time_field_array_len = len( cfg_start_time_field_array) cfg_duration_field_array = cfg_duration_field.split(',') cfg_duration_field_array_len = len(cfg_duration_field_array) cfg_calendar_field_array = cfg_calendar_field.split(',') cfg_calendar_field_array_len = len(cfg_calendar_field_array) if (cfg_start_time_field_array_len != cfg_duration_field_array_len or cfg_start_time_field_array_len != cfg_calendar_field_array_len): # Different valve configs, only use 1st entry by default. logtxt = logtxt + " - Different valve configs, start_time, calendar or duration array len unequal (" + str(cfg_start_time_field_array_len) \ + "/"+str(cfg_duration_field_array_len) + "/"+str(cfg_calendar_field_array_len) +") " log.debug(logtxt) if (cfg_start_time_field_array_len <= 0 or cfg_duration_field_array_len <= 0): logtxt = logtxt + "start_time & duration array len unequal (" + str(cfg_start_time_field_array_len) + "/"+str(cfg_duration_field_array_len) \ + "/"+str(cfg_calendar_field_array_len) +") " raise Exception(logtxt) logtxt2 = keysv + " " + " previous_flag:" + str(previous_flag) logtxt2 = " cfg_start_time_field:" + cfg_start_time_field + " cfg_duration_field:" + str( cfg_duration_field ) + " cfg_calendar_field:" + cfg_calendar_field for idx in range(cfg_start_time_field_array_len ): #Look in json field separated by commas cfg_start_time = cfg_start_time_field_array[idx] if idx > 0: if (cfg_duration_field_array_len - 1) < idx: # cfg_duration = 0 cfg_duration_field = self.valvesConfigJSON[keysv][ "TimeProperties"]["duration"] cfg_duration_field = cfg_duration_field + ",0" cfg_duration_field_array = cfg_duration_field.split( ',') cfg_duration_field_array_len = len( cfg_duration_field_array) self.valvesConfigJSON[keysv]["TimeProperties"][ "duration"] = cfg_duration_field # else: # cfg_duration = cfg_duration_field_array[idx] if (cfg_calendar_field_array_len - 1) < idx: # cfg_calendar = 0 cfg_calendar_field = self.valvesConfigJSON[keysv][ "TimeProperties"]["calendar"] cfg_calendar_field = cfg_calendar_field + ",OFF" cfg_calendar_field_array = cfg_calendar_field.split( ',') cfg_calendar_field_array_len = len( cfg_calendar_field_array) self.valvesConfigJSON[keysv]["TimeProperties"][ "calendar"] = cfg_calendar_field # else: # cfg_duration = cfg_duration_field_array[idx] if previous_flag == True: # If previous start time is previous + duration if previous_cfg_duration_field_array_len == cfg_start_time_field_array_len: previous_cfg_duration = previous_cfg_duration_field_array[ idx] else: previous_cfg_duration = 0 log.error( "previous_flag=True with previous_cfg_duration_array len > idx" ) now = datetime.datetime.now() tmpstartdatetime = now.strftime("%Y%m%d") + "-" start_datetime_str = tmpstartdatetime + cfg_start_time + ":00" # 0s to remove ambiguity logtxt = logtxt + " start_datetime #" + str( idx) + "=" + start_datetime_str log.debug(logtxt) start_datetime_init = datetime.datetime.strptime( start_datetime_str, "%Y%m%d-%H:%M:%S") start_datetime = start_datetime_init + datetime.timedelta( minutes=int(previous_cfg_duration)) start_datetime_str = start_datetime.strftime("%H:%M") if idx > 0: start_datetime_str = self.valvesConfigJSON[keysv][ "TimeProperties"][ "start_time"] + "," + start_datetime_str self.valvesConfigJSON[keysv]["TimeProperties"][ "start_time"] = start_datetime_str cfg_start_time_field = self.valvesConfigJSON[keysv][ "TimeProperties"]["start_time"] cfg_duration_field = self.valvesConfigJSON[keysv][ "TimeProperties"]["duration"] log.debug( str(idx) + ">processValveConfig " + keysv + " st=" + cfg_start_time_field + " dur=" + cfg_duration_field + " id=" + id) self.valve_last_info_log[keysv] = time.time() + float( self.config_handler.getConfigParam( "VALVE_MANAGER", "VALVE_DISPLAY_OPEN_STATUS_INTERVAL")) self.last_schedule_process_time[keysv] = time.time( ) # Initial time for schedule self.last_alert_closed_sev3_checkvalvepolicy[ keysv] = time.time() - float( self.config_handler.getConfigParam( "INTERNAL", "LOG_SEVERITY3_REPEAT_INTERVAL") ) # Initial time for schedule self.last_alert_open_sev3_checkvalvepolicy[keysv] = time.time( ) - float( self.config_handler.getConfigParam( "INTERNAL", "LOG_SEVERITY3_REPEAT_INTERVAL") ) # Initial time for schedule #os._exit(-1) except Exception: traceback.print_exc() log.error("Exiting...") os._exit(-1) emailsub = "Valve Config Summary" emailstr = "*** " + emailsub + " ***\n" log.info(emailstr) for vlvidx in range(valve_ordered_array_length): #Print summary keysv = valve_ordered_array[vlvidx] cfg_start_time_field = self.valvesConfigJSON[keysv][ "TimeProperties"]["start_time"] cfg_duration_field = self.valvesConfigJSON[keysv][ "TimeProperties"]["duration"] cfg_calendar_field = self.valvesConfigJSON[keysv][ "TimeProperties"]["calendar"] logtxt = keysv + " start_time:" + cfg_start_time_field + " duration:" + str( cfg_duration_field) + " calendar:" + cfg_calendar_field log.info(logtxt) emailstr = emailstr + logtxt + "\n" #os._exit(-1) try: self.notif_mgr_handler.send_email(self.email_sender, self.email_recipient, emailstr, emailsub) except Exception: traceback.print_exc() errtxt = self.email_sender + " " + self.email_recipient + " " + emailstr + " " + emailsub log.error(errtxt) #os._exit(-1) def monitor(self): self.dev_manager_handler = DeviceManager() self.deviceList = self.dev_manager_handler.deviceList i = 0 lastlogprint = time.time() while (True): self.isRainForecast = self.weather_mgr_handler.isRainForecasted() logstr = "is Rain Forecasted Direct: " + str(self.isRainForecast) log.debug(logstr) if time.time() > (self.valve_manager_start_time + 60): if cherrypy.engine.state == cherrypy.engine.states.STARTED: if i % 1000 == 0: log.debug("Cherrypy Web Server Thread Running") self.cherryweb_server_last_run_time = time.time() else: log.error("Cherrypy Web Server Thread Dead") if (time.time() > (self.cherryweb_server_last_run_time + 120)): log.error( "Cherrypy Web server thread not running, force exit of valve processes for crontab restart !" ) os._exit(-1) elif (time.time() > (self.cherryweb_server_last_run_time + 30)): # 15sec to allow for cherry pi web server to start log.error( "Cherrypy Web server thread not running, sending alert SW001 !" ) # status_text = self.alarm_mgr_handler.addAlert("SW001", "RASPBERRY_PI") status_text = self.addAlert( "SW001", "RASPBERRY_PI", "Cherrypy Web server thread not running") log.error(status_text) else: if i % 5 == 0: log.debug( "Cherrypy Web server thread monitoring off for 1 min after ValveManager thread startup" ) for key in self.deviceList: sensor_status_str = "" obj = self.deviceList[key] if isinstance(obj, Valve): obj.updateSensor() obj.determineValveOpenClosedStatus() self.ScheduleValve(obj) self.checkValvePolicy(obj) if log.isEnabledFor(logging.DEBUG) and i % 10000 == 0: tmplog = "%s Device: %s" % (obj.get_vlv_name(), obj.get_serialdevicename()) log.info(tmplog) self.alarm_mgr_handler.processAlerts() if i % 10000 == 0 or time.time() > (lastlogprint + float( self.config_handler.getConfigParam( "VALVE_MANAGER", "VALVE_DISPLAY_ALL_STATUS_INTERVAL"))): log.info("** valveManager heart beat %d **" % (i)) lastlogprint = time.time() self.dev_manager_handler.listDevices() self.alarm_mgr_handler.status() if self.isRainForecastPrev != self.isRainForecast: #For a print on rain forecast change logstr = "is Rain Forecasted: " + str(self.isRainForecast) self.isRainForecastPrev = self.isRainForecast log.info(logstr) sleep( float( self.config_handler.getConfigParam( "VALVE_MANAGER", "VALVE_MANAGER_LOOP_TIMEOUT"))) i = i + 1 pass def getWeekdays(self, day): i = self.weekdays_name.index(day) # get the index of the selected day return i ################################################# # Is this a day to run ################################################# def isDayRun(self, vname, cal, idx): caldx = 0 #Take calendar 0 i.e. 1st element of array as default. # calendar: OFF,EVEN,MONDAY,EVERYDAY calname = "OFF" isdayrun = False dt = datetime.datetime.today() wd = datetime.datetime.today().weekday() cal_array = cal.split(',') nbrcal = len(cal_array) if (idx <= (nbrcal - 1)): calname = cal_array[idx].upper() else: calname = cal_array[0].upper() if calname == None or calname == "OFF": log.debug(vname + " OFF") isdayrun = False elif calname == "EVERYDAY": isdayrun = True elif calname == "EVEN": if dt.day % 2 == 0: isdayrun = True elif calname == "ODD": if dt.day % 2 == 1: isdayrun = True elif calname in self.weekdays_name: day = self.getWeekdays(calname) if (day == wd): isdayrun = True tmplog = vname + " #" + str( idx) + " Weekday check " + calname + " day=" + str( day) + " wd=" + str(wd) + " " + str(isdayrun) log.debug(tmplog) else: log.error("Unsupported Calendar Name:'" + calname + "' for " + vname) isdayrun = False tmplog = vname + " #" + str(idx) + " isdayrun=" + str( isdayrun) + " cal=" + cal + " nbr calendars=" + str(nbrcal) log.debug(tmplog) return isdayrun ################################################# # Schedule valvle method ################################################# def ScheduleValve(self, vlv: Valve): logtxt = "ScheduleValve: " + vlv.vlv_name + " " + vlv.vlv_status + " " logtxt2 = logtxt now = datetime.datetime.now() motime = "None" try: if time.time() < ( self.last_schedule_process_time[vlv.vlv_name] + float( self.config_handler.getConfigParam( "VALVE_COMMON", "SCHEDULE_CHECK_INTERVAL_MIN"))): return logtxt #last_alert_closed_sev3_checkvalvepolicy updated in check policy if time.time() > ( self.last_alert_closed_sev3_checkvalvepolicy[vlv.vlv_name] + float( self.config_handler.getConfigParam( "INTERNAL", "LOG_SEVERITY3_REPEAT_INTERVAL"))): log.debug(logtxt) self.last_schedule_process_time[vlv.vlv_name] = time.time() # debug messages & events handling start if vlv.vlv_manual_mode == True: if vlv.vlv_manualopen_time != None: motime = datetime.datetime.fromtimestamp( vlv.vlv_manualopen_time).strftime("%Y%m%d-%H%M%S") logtxt = logtxt + "Skip Scheduler. Manual Mode enabled " log.debug(logtxt) return logtxt logtxt2 = logtxt2 + "Manual Force Status:%s - Last Manual Open Time:%s" % ( vlv.auto_force_close_valve, motime) + " - " if time.time() > ( self.last_alert_closed_sev3_checkvalvepolicy[vlv.vlv_name] + float( self.config_handler.getConfigParam( "INTERNAL", "LOG_SEVERITY3_REPEAT_INTERVAL"))): log.debug(logtxt2) # debug tmpstartdatetime = now.strftime("%Y%m%d") + "-" if vlv.auto_force_close_valve == True: #Skip scheduling logtxt = logtxt + " auto_force_close_valve enabled. Skip Scheduling." log.debug(logtxt) vlv.vlv_manual_mode = False self.vlv_close_time = time.time() vlv.triggerValve("close") vlv.close() return logtxt except Exception: vlv.addAlert("SW002", vlv.vlv_name, " Error force closing") raise Exception("Bloc Messages & events or Auto Force Close") return try: if vlv.vlv_name in self.valvesConfigJSON: cfg_start_time = self.valvesConfigJSON[ vlv.vlv_name]["TimeProperties"]["start_time"] cfg_duration = self.valvesConfigJSON[ vlv.vlv_name]["TimeProperties"]["duration"] cfg_calendar = self.valvesConfigJSON[ vlv.vlv_name]["TimeProperties"]["calendar"] cfg_current_weather_ignore = self.valvesConfigJSON[ vlv.vlv_name]["TimeProperties"]["current_weather_ignore"] valve_enable = False cfg_start_time_array = cfg_start_time.split(',') cfg_start_time_array_len = len(cfg_start_time_array) cfg_duration_array = cfg_duration.split(',') cfg_duration_array_len = len(cfg_duration_array) if (cfg_start_time_array_len != cfg_duration_array_len): logtxt = logtxt + "start_time & duration array len unequal (" + str( cfg_start_time_array_len) + "/" + str( cfg_duration_array_len) + ")" raise Exception(logtxt) logtxtvalvetimetrigger = "" for idx in range(cfg_start_time_array_len): isdayrun = self.isDayRun(vlv.vlv_name, cfg_calendar, idx) logtxt2 = vlv.vlv_name + " #" + str( idx) + ">" + "start_time:" + cfg_start_time_array[ idx] + " dur:" + cfg_duration_array[idx] start_datetime_str = tmpstartdatetime + cfg_start_time_array[ idx] + ":00" #0s to remove ambiguity # logtxt = logtxt + " start_datetime #"+str(idx)+"=" + start_datetime_str start_datetime = datetime.datetime.strptime( start_datetime_str, "%Y%m%d-%H:%M:%S") end_datetime = start_datetime + datetime.timedelta( minutes=int(cfg_duration_array[idx])) start_datetime_str2 = start_datetime.strftime( "%Y%m%d-%H:%M:%S") end_datetime_str2 = end_datetime.strftime( "%Y%m%d-%H:%M:%S") isRainForecastOverride = self.isRainForecast if self.isRainForecast == True and cfg_current_weather_ignore == "True": isRainForecastOverride = False logtxt2 = logtxt2 + " Override Rain forcast! " if (isRainForecastOverride == False and isdayrun == True and now >= start_datetime and now <= end_datetime): logtxt2 = logtxt2 + " Turn VALVE_ON" valve_enable = valve_enable | True logtxtvalvetimetrigger = logtxtvalvetimetrigger + start_datetime.strftime( "%d-%Hh%Mm") + " to " + end_datetime.strftime( "%d-%Hh%Mm") else: logtxt2 = logtxt2 + " Turn VALVE_OFF" valve_enable = valve_enable | False if time.time() > ( self.last_alert_closed_sev3_checkvalvepolicy[ vlv.vlv_name] + float( self.config_handler.getConfigParam( "INTERNAL", "LOG_SEVERITY3_REPEAT_INTERVAL"))): logtxt2 = logtxt2 + " [s=" + start_datetime_str2 + ", e=" + end_datetime_str2 + "] " log.debug(logtxt2) #end for idx if (valve_enable): if vlv.vlv_status != G_OPEN: if self.isRainForecast == True and cfg_current_weather_ignore == "True": logtxtOver = vlv.vlv_name + " Override Rain forcast, " + G_OPEN + "!" log.info(logtxtOver) vlv.open() logtxt = logtxt + "Open " + logtxtvalvetimetrigger else: logtxt = logtxt + "Already Open " + logtxtvalvetimetrigger else: if vlv.vlv_status != G_CLOSED: vlv.close() logtxt = logtxt + "Closed" else: logtxt = logtxt + "Already Closed" if time.time() > (self.last_alert_closed_sev3_checkvalvepolicy[ vlv.vlv_name] + float( self.config_handler.getConfigParam( "INTERNAL", "LOG_SEVERITY3_REPEAT_INTERVAL"))): log.debug(logtxt) else: logtxt = logtxt + " not defined in " + self.valveconfigfilename log.error(logtxt) raise Exception(logtxt) except Exception: traceback.print_exc() vlv.auto_force_close_valve = True vlv.vlv_manual_mode = False #self.alarm_mgr_handler.clearAlertDevice("VALVE_COMMAND", vlv.vlv_name) #self.alarm_mgr_handler.clearAlertDevice("VALVE_OPEN", vlv.vlv_name) status_text = vlv.addAlert("SW002", vlv.vlv_name, logtxt) vlv.vlv_last_alert_time = time.time() log.error(status_text) #Do all to close! self.vlv_close_time = time.time() vlv.triggerValve("close") vlv.close() # Display Status at fixed interval if vlv.vlv_status != G_CLOSED and time.time( ) > self.valve_last_info_log[vlv.vlv_name]: # limit number of logs ! log.info(logtxt) self.valve_last_info_log[vlv.vlv_name] = time.time() + float( self.config_handler.getConfigParam( "VALVE_MANAGER", "VALVE_DISPLAY_OPEN_STATUS_INTERVAL")) #Valve policy should take precedence over schedule in case something goes wrong def checkValvePolicy(self, vlv: Valve): logtxt = " checkValvePolicy: " + vlv.vlv_name + " " tmpstr = "" try: # This is how the open time threasholds are defined. refopentime is there to ensure opentime non null value. # ------- <opentimewarning>----<opentimeredcritical>--<opentimefinal>----<opentimelightingstop> refopentime = time.time() if vlv.vlv_open_time != None: refopentime = vlv.vlv_open_time opentimehw = refopentime + float(self.ValveHardwareResponseTime) opentimecritical = refopentime + float( self.ValveOpenTriggerCriticalElapsedTime) opentimewarning = refopentime + float( self.ValveOpenTriggerWarningElapsedTime) event_active_time = refopentime + float( 30) #Alarm hardocoded 30 sec if vlv.vlv_status == G_OPEN: #Locked Status is LOCKOPEN ! Don't allow auto close on lock open. if (vlv.vlv_open_time != None): #Is there an open time stamp ? if time.time() > opentimecritical: logtxt = logtxt + " Open Time Exceeded " log.debug(logtxt) # self.alarm_mgr_handler.clearAlertDevice("VALVE_COMMAND", vlv.vlv_name) # self.alarm_mgr_handler.clearAlertDevice("VALVE_OPEN", vlv.vlv_name) if (time.time() > vlv.vlv_last_alert_time \ + float(self.config_handler.getConfigParam("INTERNAL", "LOG_SEVERITY1_REPEAT_INTERVAL"))): log.critical(logtxt) self.alarm_mgr_handler.clearAlertID( "VO001", vlv.vlv_name) self.alarm_mgr_handler.clearAlertID( "VO002", vlv.vlv_name) self.alarm_mgr_handler.clearAlertID( "VO003", vlv.vlv_name) status_text = self.addAlert("VO001", vlv.vlv_name, logtxt) log.debug(status_text) vlv.vlv_last_alert_time = time.time() self.vlv_manual_mode = False vlv.auto_force_close_valve = True #disable scheduler for some time because of manual mode to false and auto close impacts self.last_schedule_process_time[ vlv.vlv_name] = time.time() + 90 vlv.close() elif time.time() > opentimewarning: logtxt = logtxt + " Open Time Warning!" log.debug(logtxt) #self.alarm_mgr_handler.clearAlertDevice("VALVE_COMMAND", vlv.vlv_name) #self.alarm_mgr_handler.clearAlertDevice("VALVE_OPEN", vlv.vlv_name) if (time.time() > vlv.vlv_last_alert_time \ + float(self.config_handler.getConfigParam("INTERNAL", "LOG_SEVERITY2_REPEAT_INTERVAL"))): log.warning(logtxt) self.last_alert_open_sev3_checkvalvepolicy[ vlv.vlv_name] = time.time() status_text = self.addAlert("VO002", vlv.vlv_name) vlv.vlv_last_alert_time = time.time() log.debug(status_text) #self.vlv_manual_mode = False elif time.time() > opentimehw: if time.time() > ( self.last_alert_open_sev3_checkvalvepolicy[ vlv.vlv_name] + float( self.config_handler.getConfigParam( "INTERNAL", "LOG_SEVERITY3_REPEAT_INTERVAL"))): logtxt = logtxt + " open HW time expired. nothing to do. OK! " log.debug(logtxt) self.last_alert_open_sev3_checkvalvepolicy[ vlv.vlv_name] = time.time() else: logtxt = logtxt + vlv.vlv_status + " " + tmpstr if time.time() > (self.last_alert_open_sev3_checkvalvepolicy[ vlv.vlv_name] + float( self.config_handler.getConfigParam( "INTERNAL", "LOG_SEVERITY3_REPEAT_INTERVAL"))): log.debug(logtxt) self.last_alert_open_sev3_checkvalvepolicy[ vlv.vlv_name] = time.time() if vlv.vlv_status == G_CLOSED: if time.time() >= ( vlv.vlv_close_time + 2 * float( self.config_handler.getConfigParam( "NOTIFICATION_MANAGER", "NOTIFICATION_MANAGER_LOOP_TIMEOUT")) ): # Dont clear alarm right away. give time to notification manager self.alarm_mgr_handler.clearAlertDevice( "VALVE_OPEN", vlv.vlv_name, logtxt + " G_CLOSED") self.alarm_mgr_handler.clearAlertDevice( "VALVE_COMMAND", vlv.vlv_name, logtxt + " G_CLOSED") logtxt = logtxt + " G_CLOSED. clearAlertDevice/VALVE_COMMAND/VALVE_OPEN Alert." if time.time() > ( self.last_alert_closed_sev3_checkvalvepolicy[ vlv.vlv_name] + float( self.config_handler.getConfigParam( "INTERNAL", "LOG_SEVERITY3_REPEAT_INTERVAL")) ): #reduce load, dont clear forever log.debug(logtxt) #vlv.vlv_last_alert_time = time.time() self.last_alert_closed_sev3_checkvalvepolicy[ vlv.vlv_name] = time.time() except Exception: traceback.print_exc() vlv.auto_force_close_valve = True status_text = vlv.addAlert("SW101", vlv.vlv_name) vlv.vlv_last_alert_time = time.time() log.error(status_text) self.vlv_close_time = time.time() vlv.triggerValve("close") vlv.close() sleep(5) os._exit(-1) def addAlert(self, id, device, extratxt=""): self.vlv_last_alert_time = time.time() status_text = "request for Alert %s %s %s" % (id, device, extratxt) try: self.vlv_add_alert_time_by_type[id] = time.time() status_text = self.alarm_mgr_handler.addAlert(id, device, extratxt) log.warning(status_text) except Exception: traceback.print_exc() logtxt = "ValveManager AddAlert Exception:" + str( traceback.format_list( traceback.extract_stack())) + " sys.excInfo:" + str( sys.exc_info()) log.error(logtxt) return status_text
class GarageManager(): def __init__(self): #log.setLevel(logging.INFO) log.info("GarageManager Starting") self.garage_manager_start_time=time.time() self.config_handler = ConfigManager() self.alarm_mgr_handler = AlertManager() self.GarageOpenTriggerWarningElapsedTime = float(self.config_handler.getConfigParam("GARAGE_COMMON","GarageOpenTriggerWarningElapsedTime")) self.GarageOpenTriggerCloseDoorElapsedTime = float(self.config_handler.getConfigParam("GARAGE_COMMON","GarageOpenTriggerCloseDoorElapsedTime")) self.LightGarageOpenTriggerCloseDoorPreWarningBeforeClose = float(self.config_handler.getConfigParam("GARAGE_COMMON","LightGarageOpenTriggerCloseDoorPreWarningBeforeClose")) self.cherryweb_server_last_run_time = time.time() self.gm_add_alert_time_by_type = {} #Key is Alert type, data is time() self.seconds_between_alerts=float(self.config_handler.getConfigParam("ALERT", "TimeBetweenAlerts")) self.g_add_alert_time_by_type = {} #Key is Alert type, data is time() self.error_message_count = 0 def monitor(self): self.dev_manager_handler = DeviceManager() self.deviceList=self.dev_manager_handler.deviceList i=0 while (True): if time.time() > (self.garage_manager_start_time+60): if cherrypy.engine.state == cherrypy.engine.states.STARTED: log.debug("Cherrypy Web Server Thread Running") self.cherryweb_server_last_run_time = time.time() else: log.error("Cherrypy Web Server Thread Dead") if (time.time() > (self.cherryweb_server_last_run_time + 120) ): log.error("Cherrypy Web server thread not running, force exit of garage processes for crontab restart !") os._exit(-1) elif (time.time() > (self.cherryweb_server_last_run_time + 30) ): # 15sec to allow for cherry pi web server to start log.error("Cherrypy Web server thread not running, sending alert SW001 !") # status_text = self.alarm_mgr_handler.addAlert("SW001", "RASPBERRY_PI") status_text = self.addAlert("SW001", "RASPBERRY_PI","Cherrypy Web server thread not running") log.error(status_text) else: log.debug("Cherrypy Web server thread monitoring off for 1 min after GarageManager thread startup") for key in self.deviceList: sensor_status_str = "" obj = self.deviceList[key] if isinstance(obj, GarageDoor): obj.updateSensor() obj.determineGarageDoorOpenClosedStatus() self.checkGaragePolicy(obj) if log.isEnabledFor(logging.DEBUG) or i % 100000 == 0: tmplog = "%s Device: %s" % (obj.get_g_name(), obj.get_serialdevicename()) log.info(tmplog) # else: # if self.error_message_count % 1000 == 0: # log.info("No Garage configured!") # self.error_message_count = self.error_message_count + 1 self.alarm_mgr_handler.processAlerts() if log.isEnabledFor(logging.DEBUG) or i%10000==0: log.info("** garageManager heart beat %d **" % (i)) self.dev_manager_handler.listDevices() self.alarm_mgr_handler.status() sleep(float(self.config_handler.getConfigParam("GARAGE_MANAGER","GARAGE_MANAGER_LOOP_TIMEOUT"))) i=i+1 pass #Warpper for add alert def addAlert(self, id, device,extratxt=""): self.g_last_alert_time = time.time() status_text="request for Alert %s %s %s" %(id, device,extratxt) if (id in self.gm_add_alert_time_by_type): lastalerttime = self.g_add_alert_time_by_type[id] if ( time.time() >(lastalerttime+self.seconds_between_alerts)): self.gm_add_alert_time_by_type.remove(id) log.info("%s can now be sent again for %s!" %(id,device)) else: log.debug("Skip %s" % status_text) else: self.gm_add_alert_time_by_type[id]=time.time() status_text = self.alarm_mgr_handler.addAlert(id, device, extratxt) log.warning(status_text) return status_text def checkGaragePolicy(self,gd: GarageDoor ): try: # This is how the open time threasholds are defined. refopentime is there to ensure opentime non null value. # ------- <opentimewarning>----<opentimeredcritical>--<opentimefinal>----<opentimelightingstop> refopentime = time.time() if gd.g_open_time != None: refopentime = gd.g_open_time opentimefinal = refopentime + float(self.GarageOpenTriggerCloseDoorElapsedTime) opentimeredcritical = refopentime + opentimefinal - self.LightGarageOpenTriggerCloseDoorPreWarningBeforeClose opentimewarning = refopentime + float(self.GarageOpenTriggerWarningElapsedTime) if gd.g_status == G_OPEN: #Locked Status is LOCKOPEN ! Don't allow auto close on lock open. remain_time_before_next_command_allowed = gd.g_next_auto_cmd_allowed_time - time.time() #datetime.datetime.fromtimestamp(time.time()).strftime("%Y%m%d-%H%M%S") if remain_time_before_next_command_allowed > 0: tmpstr="checkGaragePolicy %s open=%s Allowed Next_Manual_Cmd=%s Next_Auto_Cmd=%s --> Remain=%d sec" % (gd.g_name, \ # datetime.datetime.fromtimestamp(time.time()).strftime("%Y%m%d-%H%M%S"),\ datetime.datetime.fromtimestamp(gd.g_open_time).strftime("%Y%m%d-%H%M%S"), \ datetime.datetime.fromtimestamp(gd.g_next_manual_cmd_allowed_time).strftime("%Y%m%d-%H%M%S"), \ datetime.datetime.fromtimestamp(gd.g_next_auto_cmd_allowed_time).strftime("%Y%m%d-%H%M%S"), \ remain_time_before_next_command_allowed) if (int(time.time())%60==0 ): log.info(tmpstr ) if (gd.g_open_time != None): #Is there an open time stamp ? if time.time() > opentimefinal: # " GARAGE OPEN TIME EXPIRED ALERT" #status_text = gd.g_name + " " + self.alarm_magr_handler.alertTable["G0001"]["text"] self.alarm_mgr_handler.clearAlertDevice("GARAGE_COMMAND", gd.g_name," from checkGaragePolicy() G_OPEN opentimefinal") self.alarm_mgr_handler.clearAlertDevice("GARAGE_OPEN", gd.g_name, " from checkGaragePolicy() G_OPEN opentimefinal") status_text = gd.addAlert("GO001", gd.g_name) gd.g_last_alert_time = time.time() log.debug(status_text) #close door when timer expires! if gd.g_next_auto_cmd_allowed_time != None and time.time() > gd.g_next_auto_cmd_allowed_time: gd.g_next_auto_cmd_allowed_time = time.time() + float(self.config_handler.getConfigParam("GARAGE_COMMON", "TimeBeforeAutoRetryCloseDoor")) tmpstr = "checkGaragePolicy triggerGarageDoor %s Next Auto Cmd Allowed Time=%s --> Remain=%d sec" % (gd.g_name, \ datetime.datetime.fromtimestamp(gd.g_next_auto_cmd_allowed_time).strftime("%Y%m%d-%H%M%S"), \ remain_time_before_next_command_allowed) log.info(tmpstr) if (gd.g_auto_force_ignore_garage_open_close_cmd == False and gd.g_manual_force_lock_garage_open_close_cmd==False): gd.triggerGarageDoor() # return True is No Manual Overide else: tmpstr = "checkGaragePolicy %s Automatic triggerGarageDoor not allowed" % (gd.g_name) log.info(tmpstr) elif time.time() > opentimeredcritical : # and time.time() < (gd.g_open_time + self.GarageOpenTriggerCloseDoorElapsedTime) : #LightGarageOpenTriggerCloseDoorPreWarningBeforeClose gd.startLightFlash('RED') gd.stopLightFlash('GREEN') gd.stopLightFlash('WHITE') gd.turnOffLight('GREEN') gd.turnOffLight('WHITE') elif time.time() > opentimewarning: # status_text = gd.g_name + " GARAGE OPEN TIME WARNING ALERT" # self.alarm_magr_handler.addAlert(CommmandQResponse(0, status_text)) self.alarm_mgr_handler.clearAlertDevice("GARAGE_COMMAND", gd.g_name," from checkGaragePolicy() G_OPEN opentimewarning") self.alarm_mgr_handler.clearAlertDevice("GARAGE_OPEN", gd.g_name, " from checkGaragePolicy() G_OPEN opentimewarning") status_text = gd.addAlert("GO002", gd.g_name) gd.g_last_alert_time = time.time() log.debug(status_text) gd.startLightFlash('GREEN') else: gd.turnOnLight('GREEN') gd.turnOnLight('WHITE') gd.stopLightFlash('RED') gd.turnOffLight('RED') if (gd.g_status == G_LOCKOPEN): #Alert in this case every GarageLockOpenTriggerAlarmElapsedTime if (gd.g_lock_time!=None and time.time() > (gd.g_lock_time + float(self.config_handler.getConfigParam("GARAGE_COMMON","GarageLockOpenTriggerAlarmElapsedTime")))): self.alarm_mgr_handler.clearAlertDevice("GARAGE_COMMAND", gd.g_name, "from checkGaragePolicy() G_LOCKOPEN") self.alarm_mgr_handler.clearAlertDevice("GARAGE_OPEN", gd.g_name," from checkGaragePolicy() G_LOCKLOPEN") status_text = gd.addAlert("GLO01", gd.g_name) gd.startLightFlash('WHITE') gd.startLightFlash('RED') gd.startLightFlash('GREEN') gd.g_last_alert_time = time.time() log.debug(status_text) gd.g_lock_time = time.time() else: gd.stopLightFlash('WHITE') gd.stopLightFlash('RED') gd.stopLightFlash('GREEN') gd.turnOnLight('WHITE') gd.turnOnLight('GREEN') gd.turnOnLight('RED') if (gd.g_status.find(G_CLOSED)>=0): if (gd.g_close_time != None): #Is there an open time stamp ? # Manage specific case for light when GarageManager was restarted, door lock but door not opened ! close_white_light_delay=120 opentimelightingstop = gd.g_close_time + close_white_light_delay #Change light status during the close_white_light_delay period and a little more! if time.time() <= (gd.g_close_time + (close_white_light_delay+float(self.config_handler.getConfigParam("GARAGE_COMMON","GarageDoorAssumedClosedTime"))) ): log.debug("%s Turn off all lights!" % gd.g_name) gd.stopLightFlash('WHITE') if time.time() > opentimelightingstop: gd.turnOffLight('WHITE') else: gd.turnOnLight('WHITE') gd.turnOffLight('GREEN') gd.turnOffLight('RED') gd.stopLightFlash('GREEN') gd.stopLightFlash('RED') except Exception: traceback.print_exc() gd.g_auto_force_ignore_garage_open_close_cmd=True # status_text=gd.g_name + " CLOSE BY COMMAND DISABLED" # self.alarm_magr_handler.addAlert(CommmandQResponse(0, status_text)) self.alarm_mgr_handler.clearAlertDevice("GARAGE_COMMAND", gd.g_name) self.alarm_mgr_handler.clearAlertDevice("GARAGE_OPEN", gd.g_name) status_text = gd.addAlert("GCD01", gd.g_name) gd.g_last_alert_time = time.time() log.debug(status_text) sleep(5) os._exit(-1) def addAlert(self, id, device,extratxt=""): self.g_last_alert_time = time.time() status_text="request for Alert %s %s %s" %(id, device,extratxt) if (id in self.g_add_alert_time_by_type): lastalerttime = self.g_add_alert_time_by_type[id] if ( time.time() >(lastalerttime+self.seconds_between_alerts)): try: del self.g_add_alert_time_by_type[id] except KeyError: pass log.info("%s can now be sent again for %s!" %(id,device)) else: log.debug("Skip %s" % status_text) else: self.g_add_alert_time_by_type[id]=time.time() status_text = self.alarm_mgr_handler.addAlert(id, device, extratxt) log.warning(status_text) return status_text
class GarageDoor(): def __init__(self, garage_name, usbConnectHandler): #log.setLevel(logging.INFO) self.config_handler = ConfigManager() self.alarm_mgr_handler = AlertManager() matchObj = re.findall(r'\d', garage_name, 1) garage_id = int(matchObj[0]) self.g_id = garage_id self.g_name = garage_name self.g_board_pin_relay = int( self.config_handler.getConfigParam(self.g_name, "GarageBoardPin")) self.g_status = G_UNKNOWN self.g_prevstatus = G_UNKNOWN self.g_lightstatus = "" self.g_prevlightstatus = "" self.g_sensor_props = {} self.g_light_list = {} #Dict of lights. key = color GREEN RED WHITE self.g_update_time = time.time() self.g_open_time = None self.g_close_time = None self.g_error_time = None self.g_sensor_error_time = None self.g_last_alert_time = None self.g_last_cmd_sent_time = None self.g_last_cmd_trigger_time = None self.g_next_auto_cmd_allowed_time = time.time() + float( self.config_handler.getConfigParam("GARAGE_MANAGER", "GARAGE_MANAGER_LOOP_TIMEOUT")) self.g_next_manual_cmd_allowed_time = time.time() + float( self.config_handler.getConfigParam("GARAGE_MANAGER", "GARAGE_MANAGER_LOOP_TIMEOUT")) self.g_lock_time = None self.seconds_between_alerts = float( self.config_handler.getConfigParam("ALERT", "TimeBetweenAlerts")) self.g_alert_light_time = None self.g_auto_force_ignore_garage_open_close_cmd = False self.g_manual_force_lock_garage_open_close_cmd = False self.g_add_alert_time_by_type = {} #Key is Alert type, data is time() self.nbrfault = 0 self.g_statusEventList = [] self.usbConnectHandler = usbConnectHandler self.initBoardPinModeOutput( int( self.config_handler.getConfigParam(self.g_name, "GarageBoardPin"))) tmplog = "Garage Serial Device: %s pin %d" % ( self.usbConnectHandler.connection.device, int( self.config_handler.getConfigParam(self.g_name, "GarageBoardPin"))) log.info(tmplog) def isGarageOpen(self, mything, myservice, myid): return self.g_status == G_OPEN def startLightFlash(self, color): key = self.g_name + "_" + color if (key in self.g_light_list): # log.info("Green startFlashLight started !!!") self.g_light_list[key].startFlashLight() def stopLightFlash(self, color): key = self.g_name + "_" + color if (key in self.g_light_list): # log.info("Green startFlashLight started !!!") self.g_light_list[key].stopFlashLight() def turnOnLight(self, color): key = self.g_name + "_" + color if (key in self.g_light_list): # log.info("Green startFlashLight started !!!") self.g_light_list[key].turnOnLight() def turnOffLight(self, color): key = self.g_name + "_" + color if (key in self.g_light_list): # log.info("Green startFlashLight started !!!") self.g_light_list[key].turnOffLight() def addAlert(self, id, device, extratxt=""): self.g_last_alert_time = time.time() status_text = "request for Alert %s %s %s" % (id, device, extratxt) if (id in self.g_add_alert_time_by_type): lastalerttime = self.g_add_alert_time_by_type[id] if (time.time() > (lastalerttime + self.seconds_between_alerts)): try: del self.g_add_alert_time_by_type[id] except KeyError: pass log.info("%s can now be sent again for %s!" % (id, device)) else: log.debug("Skip %s" % status_text) else: self.g_add_alert_time_by_type[id] = time.time() status_text = self.alarm_mgr_handler.addAlert(id, device, extratxt) log.warning(status_text) return status_text def updateSensor(self): sensor_status_text = "" try: for sensor in self.g_sensor_props: self.g_sensor_props[sensor].s_update_time = time.time() read_status = self.usbConnectHandler.digitalRead( self.g_sensor_props[sensor].board_pin_id) self.g_sensor_props[sensor].status = S_SENSOR_STATUS_LIST[ read_status] #0=open 1=closed sensor_status_text = sensor_status_text + "%s/%s/%s " % ( self.g_name, sensor, S_SENSOR_STATUS_LIST[read_status]) log.debug("Sensor %s Status = %d" % (sensor, read_status)) resp = self.determineGarageDoorOpenClosedStatus() except Exception: self.g_auto_force_ignore_garage_open_close_cmd = True sensor_status_text = self.addAlert("HW001", self.g_name + "_" + sensor) status_text = self.addAlert("GCD01", self.g_name) # self.tid,self.module,self.device,self.status,self.text) resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]", self.g_name + "_" + sensor, S_ERROR, status_text) # os._exit(6) return resp def determineGarageDoorOpenClosedStatus(self): log.debug("GarageDoor dertermine Door Open Closed Status called !") sensorkey0 = "[UNKNOWN]" sensor_status_text = self.g_name + ":" + G_UNKNOWN logstr = "" do_print_status = False ''' Check garage status. Garage status g_status value based on sensor value if all sensors report the same''' for i, sensor in enumerate(self.g_sensor_props): logstr = "%d Garage %d Sensor %s Status = %s" % ( i, self.g_id, sensor, self.g_sensor_props[sensor].status) if i == 0: #keep track of 1st sensor, not necessarely in order to see all are the same sensorkey0 = sensor else: if (self.g_sensor_props[sensor].status == self.g_sensor_props[sensorkey0].status): self.g_status = self.g_sensor_props[sensor].status if (S_ERROR in self.g_statusEventList): self.g_statusEventList.remove(S_ERROR) # self.stopLightFlash('RED') # self.stopLightFlash('WHITE') # self.stopLightFlash('GREEN') for sensorkey in self.g_sensor_props: sensordevname = self.g_name + "_" + sensorkey self.alarm_mgr_handler.clearAlertDevice( "SENSOR", sensordevname, "from determineGarageDoorOpenClosedStatus") self.nbrfault = 0 self.g_sensor_error_time = None else: self.g_sensor_props[sensor].status = S_ERROR self.g_sensor_props[sensor].s_update_time = time.time() logstr = " %d Garage %d Sensor %s Status = %s" % ( i, self.g_id, sensor, S_WARNING) if (S_ERROR not in self.g_statusEventList): self.g_statusEventList.append(S_ERROR) self.g_sensor_error_time = time.time() #log.warning(logstr) self.nbrfault = self.nbrfault + 1 # if self.nbrfault>float(self.config_handler.getConfigParam("GARAGE_MANAGER", "SENSOR_DEFECT_ASSESSMENT_TIME")): if self.g_sensor_error_time != None and \ time.time() > (self.g_sensor_error_time + (float(self.config_handler.getConfigParam("GARAGE_MANAGER", "SENSOR_DEFECT_ASSESSMENT_TIME")))): # sensor_status_text = "Garage " + self.g_name + " Sensor " + S_ERROR self.g_sensor_props[sensor].status = S_ERROR self.g_status = G_ERROR sensor_status_text = self.addAlert( "GS001", self.g_name + "_" + sensor) self.g_auto_force_ignore_garage_open_close_cmd = True status_text = self.addAlert("GCD01", self.g_name) self.startLightFlash('RED') self.startLightFlash('GREEN') self.startLightFlash('WHITE') #Overide Garage but keep Sensor status upto date if self.g_manual_force_lock_garage_open_close_cmd == True: #Strip LOCK in case already there self.g_status = self.g_status.replace(G_LOCK, "") self.g_status = G_LOCK + self.g_status logstr = "Garage %s Status = %s" % (self.g_id, self.g_status) if self.g_lock_time != None and time.time( ) > self.g_lock_time + float( self.config_handler.getConfigParam( "ALERT", "AlertDefaultClearInterval")): self.alarm_mgr_handler.clearAlertID("GTO04", self.g_name) log.debug(logstr) if (self.g_prevstatus != self.g_status): self.g_update_time = time.time() sensor_status_text = self.g_name + ":" + self.g_status log_status_text = self.g_name + " change from " + self.g_prevstatus + " to " + self.g_status log.info(log_status_text) # Check if previously locked but same status if ("LOCK" in self.g_prevstatus and "LOCK" in self.g_status): #or ("LOCK" in self.g_status and "LOCK" not in self.g_prevstatus): self.g_open_time = time.time() self.g_close_time = time.time() self.g_lock_time = time.time() log_status_text = self.g_name + " Reset open/close timers " + "PrevStatus:" + self.g_prevstatus + " Status:" + self.g_status log.info(log_status_text) self.g_prevstatus = self.g_status if self.g_status == G_OPEN: self.g_open_time = time.time() elif self.g_status == G_CLOSED or self.g_status == G_LOCKCLOSED: # self.g_auto_force_ignore_garage_open_close_cmd = False self.g_close_time = time.time() # Clear all alarms when all sensors are OK since garage is closed. self.alarm_mgr_handler.clearAlertDevice( "GARAGE_OPEN", self.g_name, "from determineGarageDoorOpenClosedStatus()") self.alarm_mgr_handler.clearAlertID("GLO01", self.g_name) self.alarm_mgr_handler.clearAlertID("HW002", self.g_name) for sensorkey in self.g_sensor_props: sensordevname = self.g_name + "_" + sensorkey self.alarm_mgr_handler.clearAlertDevice( "SENSOR", sensordevname) elif self.g_status == G_ERROR: tmpstrerr = self.g_name + ":" + self.g_status + " ERROR status" log.info(tmpstrerr) self.g_error_time = time.time() # self.startLightFlash('RED') #self.printStatus() do_print_status = True else: # Status no change # In case of previous garage error state and if garage is currently closed # --> Check if garage is closed and auto close was disabled # --> Check if enough time has passed to see if auto close can be re-enabled log.debug(self.g_name + "status no change !") if (self.g_status.find(G_CLOSED)>=0 and self.g_error_time!=None \ and self.g_auto_force_ignore_garage_open_close_cmd==True \ and (time.time() > (self.g_error_time + float(self.config_handler.getConfigParam("GARAGE_COMMON", "GarageDoorAssumedClosedTime") ) ) ) ): if (time.time() > (self.g_close_time + float( self.config_handler.getConfigParam( "GARAGE_COMMON", "GarageDoorAssumedClosedTime")))): self.g_auto_force_ignore_garage_open_close_cmd = False self.alarm_mgr_handler.clearAlertID("GCD01", self.g_name) log.info( self.g_name + " assumed closed. Garage back to auto close mode!") else: #here the status is set when the status didnt change sensor_status_text = self.g_name + ":" + self.g_status # log.info(sensor_status_text) # Send HW error # --> if current time is greater then last command sent time + some time # --> and if last command trigger time is greater then last update status change + some time # --> and garage is not manually locked if self.g_update_time != None and self.g_last_cmd_sent_time != None and self.g_last_cmd_trigger_time !=None \ and self.g_manual_force_lock_garage_open_close_cmd == False \ and time.time() > (self.g_last_cmd_sent_time + float(self.config_handler.getConfigParam("GARAGE_COMMON", "GarageElapsedTimeForStatusChange")))\ and self.g_last_cmd_trigger_time > (self.g_update_time+float(self.config_handler.getConfigParam("GARAGE_COMMON", "GarageElapsedTimeForStatusChange"))): self.alarm_mgr_handler.clearAlertDevice( "GARAGE_COMMAND", self.g_name, "determineGarageDoorOpenClosedStatus() before HW002") status_text = self.addAlert("HW002", self.g_name) self.g_update_time = time.time() if self.g_status == G_OPEN and self.g_open_time != None and time.time( ) > (self.g_open_time + 15): self.alarm_mgr_handler.clearAlertID("GTO01", self.g_name) if self.g_status.find( G_CLOSED) >= 0 and self.g_close_time != None and time.time( ) > (self.g_close_time + 15): self.alarm_mgr_handler.clearAlertID("GTC01", self.g_name) #Trigger a print status on light changes self.g_lightstatus = self.getAllLightStatus() if self.g_lightstatus != self.g_prevlightstatus: do_print_status = True self.g_prevlightstatus = self.g_lightstatus if (do_print_status == True): self.printStatus() return (sensor_status_text) def lock(self): tmptxt = "" if self.g_manual_force_lock_garage_open_close_cmd == False: tmptxt = "%s Garage Lock down requested" % (self.g_name) self.g_manual_force_lock_garage_open_close_cmd = True self.g_lock_time = time.time() else: self.g_manual_force_lock_garage_open_close_cmd = False tmptxt = "%s Garage UnLock requested" % (self.g_name) self.g_lock_time = None # self.g_lock_time=None log.info(tmptxt) # resp = CommmandQResponse(time.time() * 1000000, "[DeviceManager] " + self.determineGarageDoorOpenClosedStatus()) # self.tid,self.module,self.device,self.status,self.text) mod = "[DeviceManager]" stat = "[STATUS]" str0 = self.determineGarageDoorOpenClosedStatus().split(':') dev = str0[0] if str0.__len__() > 1: stat = str0[1] resp = CommmandQResponse(time.time() * 1000000, mod, dev, stat, "") return (resp) def status(self): log.debug("GarageDoor status called !") self.updateSensor() rsptxt = self.getCmdQResponseStatusStr() #resp = CommmandQResponse(time.time() * 1000000, "[DeviceManager] " + self.determineGarageDoorOpenClosedStatus()) # self.tid,self.module,self.device,self.status,self.text) mod = "[DeviceManager]" stat = "[STATUS]" str0 = self.determineGarageDoorOpenClosedStatus().split(':') dev = str0[0] if str0.__len__() > 1: stat = str0[1] resp = CommmandQResponse(time.time() * 1000000, mod, dev, stat, rsptxt) return (resp) def getCmdQResponseStatusStr(self): resp_json = None try: rspstr = {} if self.g_open_time != None: rspstr[G_OPEN] = GarageUtil.getTimePrintOut( self, time.time() - self.g_open_time) else: rspstr[G_OPEN] = "" if self.g_close_time != None and self.g_open_time != None: rspstr[G_CLOSED] = GarageUtil.getTimePrintOut( self, time.time() - self.g_close_time) else: rspstr[G_CLOSED] = "" if self.g_error_time != None: rspstr[G_ERROR] = GarageUtil.getTimePrintOut( self, time.time() - self.g_close_time) else: rspstr[G_ERROR] = "Check!" if self.g_lock_time != None: rspstr[G_LOCK] = GarageUtil.getTimePrintOut( self, time.time() - self.g_lock_time) else: rspstr[G_LOCK] = "" resp_json = json.dumps(rspstr) except Exception: log.error("Bug handling of getCmdQResponseStatusStr JSON convert") traceback.print_exc() resp_json = "Error!" return json.dumps(resp_json) def clear(self): # resp = CommmandQResponse(time.time()*1000000, "Garage alarm cleared" ) resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]", "", "", "Garage alarm cleared") return (resp) def addSensor(self, key, sensor_props): self.g_sensor_props[key] = sensor_props self.initBoardPinModeInput(self.g_sensor_props[key].board_pin_id) log.debug(str(sensor_props)) self.s_update_time = time.time() pass def addLight(self, key, lightobj): self.g_light_list[key] = lightobj self.initBoardPinModeOutput(self.g_light_list[key].board_pin_id) self.turnOffLight(key) log.debug(str(lightobj)) pass def initBoardPinModeOutput(self, pin): log.info("Init Board Pin %d Mode Output %s" % (pin, self.g_name)) self.usbConnectHandler.pinMode(pin, self.usbConnectHandler.OUTPUT) self.s_update_time = time.time() def initBoardPinModeInput(self, pin): log.info("Init Board Pin %d Mode Input %s" % (pin, self.g_name)) self.usbConnectHandler.pinMode(pin, self.usbConnectHandler.INPUT) self.s_update_time = time.time() def open(self): status_text = "Open" self.alarm_mgr_handler.clearAlertDevice("GARAGE_COMMAND", self.g_name, "from open() 1") try: if self.g_manual_force_lock_garage_open_close_cmd == False: if (self.g_status == G_CLOSED): if time.time() > self.g_next_manual_cmd_allowed_time: # status_text+=" open. Trigger garage door !" self.alarm_mgr_handler.clearAlertDevice( "GARAGE_OPEN", self.g_name, "from open() 2") self.triggerGarageDoor() status_text = self.addAlert("GTO01", self.g_name) self.g_next_manual_cmd_allowed_time = time.time( ) + float( self.config_handler.getConfigParam( "GARAGE_COMMON", "TimeBetweenButtonManualPressed")) # self.startLightFlash('GREEN') else: # open denied. Too early to retry! status_text = self.addAlert("GTO02", self.g_name) else: # open denied. current status is " + self.g_status status_text = self.addAlert("GTO03", self.g_name, self.g_status) else: #Lock! status_text = self.addAlert("GTO04", self.g_name, self.g_status) self.g_last_cmd_trigger_time = time.time() except Exception: traceback.print_exc() logstr = "open() Garage %s Status = %s Fatal Exception" % ( self.g_name, self.g_status) log.error(logstr) os._exit(-1) # resp=CommmandQResponse(0, status_text) resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]", "", "", status_text) log.warning(status_text) return resp def manualopen(self): self.open() status_text = "manualopen" resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]", "", "", status_text) log.debug(status_text) return resp def close(self): status_text = "Close" try: if self.g_auto_force_ignore_garage_open_close_cmd == True: status_text = self.g_name + " " + self.alarm_mgr_handler.alertFileListJSON[ "Fr"]["GCD01"]["text"] + " " # log.warning(status_text) else: if (self.g_status == G_OPEN and self.g_manual_force_lock_garage_open_close_cmd == False): if time.time() > self.g_next_manual_cmd_allowed_time: # close. Trigger garage door ! self.alarm_mgr_handler.clearAlertDevice( "GARAGE_COMMAND", self.g_name, "from close() 1") status_text = self.addAlert("GTC01", self.g_name) self.triggerGarageDoor() self.g_next_manual_cmd_allowed_time = time.time( ) + float( self.config_handler.getConfigParam( "GARAGE_COMMON", "TimeBetweenButtonManualPressed")) # self.startLightFlash('RED') else: # status_text += "close denied. Too early to retry!" self.alarm_mgr_handler.clearAlertDevice( "GARAGE_COMMAND", self.g_name, "from close() 2") status_text = self.addAlert("GTC02", self.g_name) else: # status_text += "close denied. current status is " + self.g_status self.alarm_mgr_handler.clearAlertDevice( "GARAGE_COMMAND", self.g_name, "from close() 3") status_text = self.addAlert("GTC03", self.g_name, self.g_status) self.g_last_cmd_trigger_time = time.time() except Exception: traceback.print_exc() logstr = "close() Garage %s Status = %s Fatal Exception" % ( self.g_name, self.g_status) log.error(logstr) os._exit(-1) # resp=CommmandQResponse(0, status_text) resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]", "", "", status_text) log.warning(status_text) return resp ''' return True if OK, False if problem. OS exit if fatal ! ''' def triggerGarageDoor(self): #GarageManager Check Policy will not call this because status os LOCKOPEN and OPEN in this mode ! if (self.g_manual_force_lock_garage_open_close_cmd): logtxt = "Trigger garage Door refused because of Manual Override" log.error(logtxt) return False try: self.usbConnectHandler.digitalWrite(self.g_board_pin_relay, self.usbConnectHandler.HIGH) log.debug(self.g_name + " Press button!") sleep( float( self.config_handler.getConfigParam( "GARAGE_COMMON", "TimeToKeepButtonPressedMilliSec")) / 1000) self.usbConnectHandler.digitalWrite(self.g_board_pin_relay, self.usbConnectHandler.LOW) log.debug(self.g_name + " Release button!") sleep( float( self.config_handler.getConfigParam( "GARAGE_COMMON", "TimeToKeepButtonPressedMilliSec")) / 1000) self.g_next_auto_cmd_allowed_time = time.time() + float( self.config_handler.getConfigParam( "GARAGE_COMMON", "TimeBeforeAutoRetryCloseDoor")) self.g_next_manual_cmd_allowed_time = time.time() + float( self.config_handler.getConfigParam( "GARAGE_COMMON", "TimeBetweenButtonManualPressed")) self.g_last_cmd_sent_time = time.time() log.info("%s Open/Close door button pressed" % (self.g_name)) except Exception: log.error("triggerGarageDoor Open or Close button problem !") traceback.print_exc() os._exit(-1) return True def printStatus(self): logstr = "%s:%s " % (self.g_name, self.g_status) sensor_status_str = "" all_light_status = self.getAllLightStatus() for sensor in self.g_sensor_props: sensor_status_str = sensor_status_str + sensor + "=" + self.g_sensor_props[ sensor].status + " " if self.g_update_time != None: printut = datetime.datetime.fromtimestamp( self.g_update_time).strftime("%Y%m%d-%H%M%S") else: printut = "None" if self.g_open_time != None: printot = datetime.datetime.fromtimestamp( self.g_open_time).strftime("%Y%m%d-%H%M%S") else: printot = "None" if self.g_close_time != None: printct = datetime.datetime.fromtimestamp( self.g_close_time).strftime("%Y%m%d-%H%M%S") else: printct = "None" if self.g_lock_time != None: printlock = datetime.datetime.fromtimestamp( self.g_lock_time).strftime("%Y%m%d-%H%M%S") else: printlock = "None" if self.g_error_time != None: printerrt = datetime.datetime.fromtimestamp( self.g_error_time).strftime("%Y%m%d-%H%M%S") else: printerrt = "None" if self.g_last_alert_time != None: printlast = datetime.datetime.fromtimestamp( self.g_last_alert_time).strftime("%Y%m%d-%H%M%S") else: printlast = "None" try: logstr = logstr + sensor_status_str + "updte=" + printut + " opn=" + printot + " clse=" + printct + " lock=" + printlock + " err=" + printerrt + " Alert=" + printlast + " Lights:" + all_light_status log.info(logstr) except Exception: log.error("Time Stamp print error ?!? print to stdout ") print(logstr) def getAllLightStatus(self): all_light_status = "" for color in sorted({"GREEN", "RED", "WHITE"}): key_dev_color = self.g_name + "_" + color if key_dev_color in self.g_light_list: light_status = color[0] if self.g_light_list[key_dev_color].getLightStatus() == "ON": all_light_status += light_status.lower() elif self.g_light_list[key_dev_color].getLightStatus( ) == "FLASH": all_light_status += light_status.upper() else: all_light_status += "-" else: log.debug("%s %s light defined yet" % (color, self.g_name)) return all_light_status def test(self): self.initBoardPinModeOutput(self.g_board_pin_relay) logbuf = "Arduino Init Pin=%d" % self.g_board_pin_relay log.info(logbuf) for n in range(0, 1): self.usbConnectHandler.digitalWrite(self.g_board_pin_relay, self.usbConnectHandler.HIGH) log.info("ON") sleep(3) self.usbConnectHandler.digitalWrite(self.g_board_pin_relay, self.usbConnectHandler.LOW) log.info("OFF") sleep(2) n += 1 resp = CommmandQResponse(time.time() * 1000000, "[MESSAGE]", "", "", "test!") return resp def get_serialdevicename(self): return self.usbConnectHandler.connection.device def get_g_name(self): return self.g_name