class Main(): def __init__(self): self.commans = (Play(), Variable(), Speech(), Info()) #, Sinoptik()) self.db = DBConnector() # Очищаем список команд. Список не актуален. self.db.IUD("delete from core_execute") self.last_processed_ID = -1 self.db.commit() self.run() def run(self): while True: try: for row in self.db.select("select ID, COMMAND " " from core_execute " " where ID > %s " "order by ID" % (self.last_processed_ID)): print(str(row[1], "utf-8")) for c in str(row[1], "utf-8").split("\n"): self.execute(c.strip()) self.last_processed_ID = row[0] time.sleep(0.1) # Дергаем секундный таймер, может кому пригодится for cmd in self.commans: cmd.time_handler() except mysql.connector.Error as e: self.execute('speech("пропала связь с базой", "alarm")') time.sleep(10) def execute(self, command): print("[%s] выполняется %s" % (time.strftime("%d-%m-%Y %H:%M"), command)) for cmd in self.commans: if cmd.check_comm(self.db, command): break
class VideoAlerts: def __init__(self, host, port): self.camIds = [166, 167, 168, 169] self.host = host self.port = port self.sessionID = "" self.bs = bytearray() self.bbs = bytearray(4) self.db = DBConnector() def run(self): while True: try: self.sock = socket.socket() self.sock.connect((self.host, self.port)) self._send_login() self._send_empty() i = 0 while True: res = self.sock.recv(10240) if res != b'': res = res[20::].decode("cp1251") for line in res.split('\n'): try: a = json.loads(line) if a['Name'] == "AlarmInfo": c = a['AlarmInfo'] if c['Event'] == 'VideoMotion': var_v = 0 if c['Status'] == 'Start': var_v = 1 cam = c['Channel'] var_id = self.camIds[cam] self._print( "Замечено движение на камере %s (статус %s)" % (cam + 1, var_v)) self.db.IUD( "call CORE_SET_VARIABLE(%s, %s, null)" % (var_id, var_v)) self.db.commit() except Exception as e: #print("{}".format(e)) pass if i >= 5: i = -1 self._send_empty() i += 1 else: break time.sleep(0.2) except Exception as e: print("{}".format(e)) time.sleep(1) try: self.sock.close() except: print('error') def _send_pack(self, data): s = b'\xff' + self.bbs + data + b'\n' self.sock.sendall(s) #print("CLIENT: ", s) res = self.sock.recv(10240) #print("SERVER: ", res) return res def _send_login(self): data = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x03d\x00\x00\x00{ "EncryptType" : "MD5", "LoginType" : "DVRIP-Web", "PassWord" : "tlJwpbo6", "UserName" : "admin" }' res = self._send_pack(data) res = res[20::].decode("cp1251").replace("\n", "").replace(chr(0), "") a = json.loads(res) self.sessionID = a['SessionID'] self.bs = bytearray(self.sessionID, "cp1251") self.bbs = self._sessIdtoHex(self.sessionID) def _send_empty(self): data = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdc\x05,\x00\x00\x00{ "Name" : "", "SessionID" : "' + self.bs + b'" }' self._send_pack(data) #print("PING") def _decodeHex(self, s): if s in '0123456789': return int(s) elif s == 'a': return 10 elif s == 'b': return 11 elif s == 'c': return 12 elif s == 'd': return 13 elif s == 'e': return 14 else: return 15 def _sessIdtoHex(self, s): res = bytearray(4) s = s[2::] for i in range(4): b1 = s[i * 2] b2 = s[i * 2 + 1] res[i] = (self._decodeHex(b1.lower()) << 4) + self._decodeHex( b2.lower()) return res def _print(self, text): print("[%s] %s" % (time.strftime("%d-%m-%Y %H:%M:%S"), text))
class Main(): def __init__(self): self.db = DBConnector() self.termostats = [] self._add_termostat(50, 49, "В хозяйской спальне") #Спальня №3 self._add_termostat(47, 46, "В детской спальне") #Спальня №2 self._add_termostat(44, 43, "В гостевой спальне") #Спальня №1 self._add_termostat(60, 59, "В гостинной") #Гостинная self._add_termostat(66, 65, "В кухне") #Кухня # ID, CHANNEL, VALUE self.BMP280_VARS = [[150, "t", None], [151, "p", None]] self.bmp280_drv = None self.bmp280_init() self.cam_alerts = [] self._load_cam_alerts() self.run() def bmp280_init(self): addr = 0x76 for i in range(2): addr += i try: self.bmp280_drv = BMP280(addr) print("BMP280 OK: %s" % (hex(addr))) except: print("BMP280 ERROR: %s" % (hex(addr))) def run(self): termostats_time_step = 0 bmp280_time_step = 0 clear_db_mem_time_ignore = False boiler_term = None while True: relIds = [] relIds_named = [] for keys in self.db.select("select CORE_GET_LAST_CHANGE_ID()"): if keys[0] - 1 > self.db.lastVarChangeID: # c.ID, c.VARIABLE_ID, c.VALUE, v.APP_CONTROL, v.GROUP_ID for row in self.db.variable_changes(): if row[3] == 1: # Слежение за светом relIds += [str(row[1]), ","] if row[3] == 3: # Слежение за розетками relIds_named += [str(row[1]), ","] elif row[ 3] == 8: # Слежение за пиродатчиками (камерами) try: cam_num = self.cam_alerts.index(row[1]) + 1 if row[2] == 1: self._add_command( 'speech("Замечено движение на камере %s", "notify")' % (cam_num)) except: pass elif row[3] == 4: #Термометры for r in self.termostats: if r[2] == row[1]: r[3] = row[2] # критические температуры if row[1] == 95 and row[2] > 55: # Дымоход self._add_command( 'speech("Температура дымохода %s градусов", "alarm")' % (round(row[2]))) if row[1] == 93: boiler_term = row[2] if row[2] > 55: # Подача котла self._add_command( 'speech("Температура котла %s градусов", "alarm")' % (round(row[2]))) elif row[2] >= 45 and row[2] <= 48: self._add_command( 'speech("Котел холодный", "notify")') # ----------------------- elif row[3] == 5: #Термостаты for r in self.termostats: if r[0] == row[1]: r[1] = row[2] elif row[1] == 163 and row[2] == 1: self._add_command( 'speech("Прозвенел звон*ок на воротах")') if len(relIds) > 0: for row in self.db.select( "select v.APP_CONTROL, c.NAME, p.NAME, v.VALUE " " from core_variables v, core_variable_controls c, plan_parts p " " where v.ID in (%s) " " and v.APP_CONTROL = c.ID " " and v.GROUP_ID = p.ID " " order by v.ID" % ("".join(relIds[:-1]), )): s = [ str(row[2], "utf-8"), ". ", str(row[1], "utf-8"), " " ] if row[3]: s += ["включен"] else: s += ["выключен"] self._add_command('speech("%s", "notify")' % "".join(s).lower()) if len(relIds_named) > 0: for row in self.db.select( "select v.COMM, v.VALUE " " from core_variables v " " where v.ID in (%s) " % ("".join(relIds_named[:-1]), )): comm = str(row[0], "utf-8") s = [comm, " "] if comm[-1::].upper() == "А": if row[1]: s += ["включена"] else: s += ["выключена"] else: if row[1]: s += ["включен"] else: s += ["выключен"] self._add_command('speech("%s", "notify")' % "".join(s).lower()) if termostats_time_step == 0: termostats_time_step = round(15 * 60 / 0.2) if boiler_term != None and boiler_term > 30: for t in self.termostats: if t[3] > t[1] + 0.2: # Перегрели self._add_command('speech("%s жарко", "notify")' % (t[4])) elif t[3] < t[1] - 0.2 and t[ 3] > t[1] - 1: # Переостудили self._add_command( 'speech("%s холодно", "notify")' % (t[4])) termostats_time_step -= 1 if bmp280_time_step == 0: bmp280_time_step = round(60 / 0.2) self._check_bmp280() bmp280_time_step -= 1 # ------------------------------------------- if datetime.datetime.now().hour == 4: if not clear_db_mem_time_ignore: clear_db_mem_time_ignore = True self.clear_mem_db() self.clear_values() else: clear_db_mem_time_ignore = False # ------------------------------------------- time.sleep(0.2) def _add_termostat(self, tst_id, trm_id, title): # Зачитка стартовых значений for rec in self.db.select( "select VALUE from core_variables where ID = %s" % (tst_id)): tst_val = rec[0] for rec in self.db.select( "select VALUE from core_variables where ID = %s" % (trm_id)): trm_val = rec[0] # --------------------------- self.termostats += [[tst_id, tst_val, trm_id, trm_val, title]] def _check_bmp280(self): try: res = self.bmp280_drv.get_data() t = res["t"] p = res["p"] for var in self.BMP280_VARS: if var[2] != res[var[1]]: var[2] = res[var[1]] self.db.IUD("call CORE_SET_VARIABLE(%s, %s, null)" % (var[0], var[2])) self.db.commit() except Exception as e: self.bmp280_init() print(e) def _add_command(self, command): print("[%s] %s" % (time.strftime("%d-%m-%Y %H:%M"), command)) """ if self.get_quiet_time() and alarm == False: try: command.index("speech(") command = "speech(\"\")" except: pass """ self.db.IUD("insert into core_execute (COMMAND) values ('%s')" % command) self.db.commit() def get_quiet_time(self): for rec in self.db.select( "select VALUE from core_variables where NAME = 'QUIET_TIME'"): if rec[0]: return True return False def _load_cam_alerts(self): self.cam_alerts = [] for rec in self.db.select( "select NAME, ALERT_VAR_ID from plan_video order by ORDER_NUM" ): self.cam_alerts += [rec[1]] def _clear_mem_db_table(self, table, space=100): for rec in self.db.select("select MAX(ID) from %s" % (table)): if rec[0]: max_id = rec[0] - space self.db.IUD("delete from %s where ID < %s" % (table, max_id)) self.db.commit() def clear_mem_db(self): try: self._clear_mem_db_table("app_control_exe_queue") self._clear_mem_db_table("app_control_queue") self._clear_mem_db_table("app_control_sess") self._clear_mem_db_table("core_execute") self._clear_mem_db_table("core_variable_changes_mem") print("[%s] CLEAR MEM TABLES" % (time.strftime("%d-%m-%Y %H:%M"))) except Exception as e: print(e) def clear_values(self): try: subprocess.call( 'python3 /home/pyhome/server/watcher/clear_values_15.py', shell=True) except: pass
if row[2] == prev_var_id: if row[3] - prev_var_time < 600 and check_values( values, row): # Если часто, то вкидываем на просмотр values += [row] else: if len(values) > 2: f1, f2 = values[:2] l1, l2 = values[-2:] drop_ids = [] for r in values: if r[0] != f2[0] and r[0] != l1[0]: drop_ids += [str(r[0]), ","] d = "".join(drop_ids[:-1]) db.IUD("delete from core_variable_changes where ID in (%s)" % (d)) v_f, v_l = f1[1] + (f2[1] - f1[1]) / 2, l1[1] + (l2[1] - l1[1]) / 2 db.IUD( "update core_variable_changes set VALUE = %s where ID = %s" % (v_f, f2[0])) db.IUD( "update core_variable_changes set VALUE = %s where ID = %s" % (v_l, l1[0])) db.commit() values = [row] prev_var_time = row[3] prev_var_value = row[1]
class Main(): def __init__(self): self.db = DBConnector() self.db.IUD("update core_scheduler set ACTION_DATETIME = NULL") self.db.commit() print("-- Предстоящие задачи --") for row in self.db.select( "select ID, COMM, ACTION, ACTION_DATETIME, INTERVAL_TIME_OF_DAY, INTERVAL_DAY_OF_TYPE, INTERVAL_TYPE, ENABLE from core_scheduler" ): next_time = self.parse_time(None, str(row[4], "utf-8"), str(row[5], "utf-8"), row[6]) enable = "" if row[7] == 0: enable = " [НЕ ВЫПОЛНЯТЬ!!!]" print("[%s] %s %s" % (datetime.datetime.fromtimestamp(next_time), str(row[1], "utf-8"), enable)) print("------------------------") self.check_time() self.run() def check_time(self): now = datetime.datetime.now().timestamp() for row in self.db.select( "select ID, COMM, ACTION, ACTION_DATETIME, INTERVAL_TIME_OF_DAY, INTERVAL_DAY_OF_TYPE, INTERVAL_TYPE, ENABLE from core_scheduler" ): next_time = None if row[3] == None: # Это обнуленная дата - будет перещитана в холостую относительно текущей next_time = self.parse_time(None, str(row[4], "utf-8"), str(row[5], "utf-8"), row[6]) elif row[3].timestamp( ) <= now: # Это дата, что пришла для выполнения. Выполняем и перещитываем. next_time = self.parse_time(row[3].timestamp(), str(row[4], "utf-8"), str(row[5], "utf-8"), row[6]) if row[7]: # Проверка на Выполнять/Не выполнять self.execute(str(row[1], "utf-8"), str(row[2], "utf-8")) if row[6] == 4: # Одноразовая задача выполнена. Удаляем ее запись. self.db.IUD("delete from core_scheduler where ID = %s" % (row[0])) self.db.commit() if next_time != None: #self.db.IUD("update core_scheduler set ACTION_DATETIME = FROM_UNIXTIME(%s) where ID = %s" % (next_time, row[0])) d_s = datetime.datetime.fromtimestamp(next_time).strftime( "%Y-%m-%d %H:%M:%S") self.db.IUD( "update core_scheduler set ACTION_DATETIME = '%s' where ID = %s" % (d_s, row[0])) self.db.commit() def calc_suntime(self, d, sun_type): st = GetSunTime(d // (24 * 3600), 49.697287, 34.354388, 90.8333333333333, (-time.altzone // 3600) - 1, sun_type) hour = math.trunc(st) minutes = round((st - hour) * 60) return (hour * 60 + minutes) * 60 def parese_sun_delta(self, comm): """ SUNRISE - 1 SUNRISE - 1:03 SUNRISE - 1:03:02 """ s = comm s = s.replace("SUNSET", "") s = s.replace("SUNRISE", "") s = s.replace(" ", "") try: is_minus = s[0] == "-" except: is_minus = False s = s.replace("-", "") a = s.split(":") h, m, s = 0, 0, 0 try: if len(a) > 0: h = int(a[0]) if len(a) > 1: m = int(a[1]) if len(a) > 2: s = int(a[2]) except: pass res = h * 3600 + m * 60 + s if is_minus: res = -res return res def parse_time(self, action_datetime, time_of_day, day_of_type, int_type): if action_datetime == None: action_datetime = datetime.datetime.now().timestamp() now = datetime.datetime.now() now = datetime.datetime(now.year, now.month, now.day) times = [] dates = [] time_type = "" try: time_of_day.upper().index("SUNRISE") time_type = "Sunrise" except: pass try: time_of_day.upper().index("SUNSET") time_type = "Sunset" except: pass if time_type == "Sunrise" or time_type == "Sunset": """ Это особый случай блуждающего времени. Сборка даты/времени выполняется здесь отдельно и дальше код не пойдет. """ sun_delta = self.parese_sun_delta(time_of_day.upper()) d1 = now.timestamp() d2 = now.timestamp() + 24 * 3600 dt = [ d1 + self.calc_suntime(d1, time_type) + sun_delta, d2 + self.calc_suntime(d2, time_type) + sun_delta ] dt.sort() # Проверяем какая дата из расписания готова к выполнению for d in dt: if d > action_datetime: return d return None else: # Получаем список времени в секундах for t in time_of_day.split(","): m = t.split(":") hour = int(m[0].strip()) * 60 minutes = 0 try: minutes = int(m[1].strip()) except: pass sec = 0 try: sec = int(m[2].strip()) except: pass s = hour + minutes times += [s * 60 + sec] if int_type == 0: # Сегодняшняя дата и завтрашняя dates += [now.timestamp(), now.timestamp() + 24 * 3600] elif int_type == 1: # Получаем дату понедельника этой недели в секундах dw = now.timestamp() - now.weekday() * 24 * 3600 # Получаем дату понедельника следующей недели в секундах dw_next = dw + 7 * 24 * 3600 w = ["пн", "вт", "ср", "чт", "пт", "сб", "вс"] for d in day_of_type.split(","): s = w.index(d.strip().lower()) dates += [dw + (s * 24 * 3600)] dates += [dw_next + (s * 24 * 3600)] elif int_type == 2: # Получаем 1 число этого месяца в секундах m = datetime.datetime(now.year, now.month, 1).timestamp() # Получаем 1 число следующего месяца в секундах if now.month < 12: m_next = datetime.datetime(now.year, now.month, 1).timestamp() else: m_next = datetime.datetime(now.year + 1, 1, 1).timestamp() for d in day_of_type.split(","): s = int(d.strip()) dates += [m + (s * 24 * 3600)] dates += [m_next + (s * 24 * 3600)] elif int_type == 3 or int_type == 4: # Ежегодно или Только один раз for d in day_of_type.split(","): m = d.split("-") s = datetime.datetime(now.year, int(m[1].strip()), int(m[0].strip())).timestamp() dates += [s] s_next = datetime.datetime(now.year + 1, int(m[1].strip()), int(m[0].strip())).timestamp() dates += [s_next] dt = [] # Собираем дату и время расписания в одно for tim in times: if len(dates) > 0: for dat in dates: dt += [dat + tim] dt.sort() # Проверяем какая дата из расписания готова к выполнению for d in dt: if d > action_datetime: return d return None def execute(self, comm, action): self.db.IUD("insert into core_execute (COMMAND) values ('%s')" % (action)) self.db.commit() print("[%s] Произошло событие \"%s\"" % (time.strftime("%d-%m-%Y %H:%M"), comm)) print(" и запрошена команда %s" % (action)) def run(self): while True: self.check_time() time.sleep(1)