def __init__(self, slave_keys): ## Logger object for formatting and printing logs self.logger = Logger(DEBUG_MODE, LOG_FILE); ## SQL object for managing database self.sql = MasterSql(); self._parser = DaemonConfigParser('/etc/domoleaf/master.conf'); ## Object containing AES keys for encrypted communications self.aes_slave_keys = slave_keys;
def __init__(self, daemon): ## Logger object for formatting and printing logs self.logger = Logger(False, LOG_FILE) ## SQL object for managing database self.sql = MasterSql() ## Instance of the slave daemon self.daemon = daemon ## Trigger list self.triggers_list = '' self.update_triggers_list()
def __init__(self, daemon): Thread.__init__(self) ## Logger object for formatting and printing logs self.logger = Logger(False, LOG_FILE) ## SQL object for managing slave daemon database self.sql = MasterSql() ## Instance of the slave daemon self.daemon = daemon ## List of scenarios self.scenarios_list = {} self.update_scenarios_list()
def remote_sql(self, json_obj, connection): """ Execute sql command from configurator """ db = MasterSql(); req = json_obj['data'].split(';'); for item in req: if item != '': db.mysql_handler_personnal_query(item); connection.close(); return;
def __init__(self, slave_keys): ## Logger object for formatting and printing self.logger = Logger(DEBUG_MODE, LOG_FILE) ## SQL manager for the master daemon self.sql = MasterSql() self._parser = DaemonConfigParser('/etc/domoleaf/master.conf') ## Object containing the AES keys for encrypted communications self.aes_slave_keys = slave_keys ## Array containing functions associated with IDs self.functions_transform = { 0: utils.convert_none, 4: utils.eno_onoff }
def __init__(self, daemon): ## The logger used for formating and printing self.logger = Logger(False, LOG_FILE); self.logger.debug('Init CalcLogs'); ## SQL manager self.sql = MasterSql(); ## The instance of the slave daemon self.daemon = daemon; ## List of the devices self.devices_list = {}; self.devices_list_update();
class EnOceanManager: ## The constructor. # # @param slave_keys The aes keys of the slaves. def __init__(self, slave_keys): ## Logger object for formatting and printing self.logger = Logger(DEBUG_MODE, LOG_FILE); ## SQL manager for the master daemon self.sql = MasterSql(); self._parser = DaemonConfigParser('/etc/domoleaf/master.conf'); ## Object containing the AES keys for encrypted communications self.aes_slave_keys = slave_keys; ## Array containing functions associated with IDs self.functions_transform = { 0: utils.convert_none, 4: utils.eno_onoff }; ## Updates the table room_device_option with EnOcean values. # # @param daemon_id The ID of the daemon. # @param json_obj JSON object containing the source address of the EnOcean device. # @param db The database handler. # # @return The result of the query. def update_room_device_option(self, daemon_id, json_obj, db): query = ''.join(["SELECT room_device_option.option_id, room_device.room_device_id, addr_plus, function_answer, room_device_option.dpt_id ", "FROM room_device_option JOIN room_device ON room_device_option.room_device_id=room_device.room_device_id ", "JOIN dpt_optiondef ON dpt_optiondef.option_id=room_device_option.option_id AND ", "dpt_optiondef.protocol_id=room_device.protocol_id AND dpt_optiondef.dpt_id=room_device_option.dpt_id ", "WHERE daemon_id=", str(daemon_id), " AND room_device_option.addr=\"", str(json_obj['src_addr']), "\""]); res = self.sql.mysql_handler_personnal_query(query, db); result = [] append = result.append if not res: query = ''.join(["SELECT room_device_option.option_id, room_device.room_device_id, addr_plus, function_answer, room_device_option.dpt_id ", "FROM room_device_option JOIN room_device ON room_device_option.room_device_id=room_device.room_device_id ", "JOIN dpt_optiondef ON dpt_optiondef.option_id=room_device_option.option_id AND ", "dpt_optiondef.protocol_id=room_device.protocol_id AND dpt_optiondef.dpt_id=room_device_option.dpt_id ", "WHERE daemon_id=", str(daemon_id), " AND room_device_option.addr_plus=\"", str(json_obj['src_addr']), "\""]); res = self.sql.mysql_handler_personnal_query(query, db); for r in res: val = self.functions_transform[r[3]](int(json_obj['value']), r[4]); if val is not None: append(r) up = ''.join(["UPDATE room_device_option SET opt_value=\"", str(val), "\" WHERE room_device_id=", str(r[1]), " AND option_id=\"", str(r[0]), "\""]); self.sql.mysql_handler_personnal_query(up, db); return result
def __init__(self, daemon): self.logger = Logger(False, LOG_FILE); self.sql = MasterSql(); self.daemon = daemon; self.schedules_list = ''; self.full_schedules_list = ''; self.update_schedules_list();
class SlaveReceiver(Thread): def __init__(self, connection, hostname, daemon): """ Threaded class for reading from a slave and send the data to the treatment function """ Thread.__init__(self); self.connection = connection; self.daemon = daemon; self.connected_host = hostname; self.sql = MasterSql(); def run(self): """ Thread run function overload """ res = self.sql.mysql_handler_personnal_query('SELECT serial, secretkey FROM daemon WHERE serial=\'' + self.connected_host + '\''); aes_key = ''; for r in res: if r[0] == self.connected_host: aes_key = r[1]; break; if aes_key == '': return None; data = self.connection.recv(MasterDaemon.MAX_DATA_LENGTH); decrypt_IV = data[:16].decode(); decode_obj = AES.new(aes_key, AES.MODE_CBC, decrypt_IV); data2 = decode_obj.decrypt(data[16:]).decode(); flag = False; obj = data2; self.daemon.parse_data(obj, self.connection);
def __init__(self, daemon): self.logger = Logger(False, LOG_FILE); self.logger.debug('Init CalcLogs'); self.sql = MasterSql(); self.daemon = daemon; self.devices_list = {}; self.devices_list_update();
class Smartcommand: def __init__(self, daemon, smartcmd_id = 0): self.logger = Logger(False, LOG_FILE); self.logger.info('Started SMARTCMD'); self.smartcmd_id = smartcmd_id; self.sql = MasterSql(); self.daemon = daemon; def launch_smartcmd(self, json_obj, connection): if (self.smartcmd_id == 0): self.logger.error('Invalid Smartcommand'); return; query = 'SELECT room_device_id, option_id, option_value, time_lapse FROM smartcommand_elems WHERE smartcommand_id ="'+ str(self.smartcmd_id) +'" ORDER BY exec_id'; res = self.sql.mysql_handler_personnal_query(query); delay_color = 0; for r in res: obj = {}; obj['sync'] = 0; data = {}; data['room_device_id'] = r[0]; data['option_id'] = r[1]; data['value'] = r[2]; obj['data'] = data; obj['packet_type'] = 'smartcmd_launch'; delay = r[3]; if (data['option_id'] == 392 or data['option_id'] == 393 or data['option_id'] == 394): delay_color = delay_color + 1; if (delay > 0 and delay_color <= 1): time.sleep(delay); if (delay_color >= 3): delay_color = 0; self.daemon.send_to_device(obj, connection);
def __init__(self, daemon): Thread.__init__(self); self.logger = Logger(False, LOG_FILE); self.sql = MasterSql(); self.daemon = daemon; self.scenarios_list = {}; self.update_scenarios_list();
class Scenario: def __init__(self, daemon): self.logger = Logger(False, LOG_FILE); self.sql = MasterSql(); self.daemon = daemon; self.scenarios_list = {}; self.update_scenarios_list(); def get_scenarios_tab(self, scenarios): scenarios_tab = {}; self.logger.debug('\n\nGETTING SCENARIOS TAB\n'); for d in scenarios: scHash = str(d[4])+'_'+str(d[5]) if (scHash not in scenarios_tab): scenarios_tab[scHash] = []; scenarios_tab[scHash].append(d) return scenarios_tab; def update_scenarios_list(self): self.logger.debug('UPDATING SCENARIOS'); query = ('SELECT id_scenario, trigger_events_conditions.id_trigger, id_schedule, ' 'id_smartcmd, trigger_events_conditions.room_device_id, id_option ' 'FROM trigger_events_conditions ' 'JOIN scenarios_list ' 'ON trigger_events_conditions.id_trigger=scenarios_list.id_trigger ' 'WHERE activated = 1 && scenarios_list.id_trigger IS NOT NULL ' 'ORDER BY id_scenario'); scenarios_list = self.sql.mysql_handler_personnal_query(query); self.logger.debug('S LIST = ' + str(scenarios_list) + '\n'); self.scenarios_list = self.get_scenarios_tab(scenarios_list); self.logger.debug('S TAB = ' + str(self.scenarios_list) + '\n\n\n'); def check_all_scenarios(self, global_state, trigger, schedule, connection, doList): self.logger.debug('CHECKING ALL SCENARIOS'); self.logger.debug('SCENARIOS LIST = '); self.logger.debug(self.scenarios_list); self.logger.debug('\n'); for do in doList: slist = self.scenarios_list[str(do[1])+'_'+str(do[0])]; self.logger.debug('SLIST = '); self.logger.debug(slist); for scenario in slist: self.logger.error(scenario); self.logger.debug('Scenario : ' + str(scenario) + '\n\n'); if trigger.test_trigger(scenario[1], global_state) == 1: self.logger.debug('Trigger OK'); if (scenario[2] is None or scenario[2] is not None and schedule.test_schedule(scenario[2]) == 1): self.launch_scenario(scenario[3], connection); def launch_scenario(self, id_smartcmd, connection): self.logger.debug('LAUNCH !!!'); jsonString = json.JSONEncoder().encode({ "data": id_smartcmd }); data = json.JSONDecoder().decode(jsonString); self.daemon.smartcmd_launch(data, connection);
class EnOceanManager: """ KNX management class """ def __init__(self, slave_keys): self.logger = Logger(DEBUG_MODE, LOG_FILE); self.sql = MasterSql(); self._parser = DaemonConfigParser('/etc/domoleaf/master.conf'); self.aes_slave_keys = slave_keys; self.functions_transform = { 0: utils.convert_none, 4: utils.eno_onoff }; def update_room_device_option(self, daemon_id, json_obj): """ Update of the table room_device_option with EnOcean value """ query = "SELECT room_device_option.option_id, room_device.room_device_id, addr_plus, function_answer, room_device_option.dpt_id "; query += "FROM room_device_option "; query += "JOIN room_device ON room_device_option.room_device_id=room_device.room_device_id "; query += "JOIN dpt_optiondef ON dpt_optiondef.option_id=room_device_option.option_id AND "; query += "dpt_optiondef.protocol_id=room_device.protocol_id AND dpt_optiondef.dpt_id=room_device_option.dpt_id "; query += "WHERE daemon_id=" + str(daemon_id) + " AND room_device_option.addr=\""; query += str(json_obj['src_addr']) + "\""; res = self.sql.mysql_handler_personnal_query(query); result = [] if len(res) == 0: query = "SELECT room_device_option.option_id, room_device.room_device_id, addr_plus, function_answer, room_device_option.dpt_id "; query += "FROM room_device_option "; query += "JOIN room_device ON room_device_option.room_device_id=room_device.room_device_id "; query += "JOIN dpt_optiondef ON dpt_optiondef.option_id=room_device_option.option_id AND "; query += "dpt_optiondef.protocol_id=room_device.protocol_id AND dpt_optiondef.dpt_id=room_device_option.dpt_id "; query += "WHERE daemon_id=" + str(daemon_id) + " AND room_device_option.addr_plus=\""; query += str(json_obj['src_addr']) + "\""; res = self.sql.mysql_handler_personnal_query(query); for r in res: val = self.functions_transform[r[3]](int(json_obj['value']), r[4]); if val is not None: result.append(r) up = "UPDATE room_device_option SET opt_value=\"" + str(val) up += "\" WHERE room_device_id=" + str(r[1]) + " AND option_id=\"" + str(r[0]) + "\""; self.sql.mysql_handler_personnal_query(up); return result
def __init__(self, slave_keys): self.logger = Logger(DEBUG_MODE, LOG_FILE); self.sql = MasterSql(); self._parser = DaemonConfigParser('/etc/domoleaf/master.conf'); self.aes_slave_keys = slave_keys; self.functions_transform = { 0: utils.convert_none, 4: utils.eno_onoff };
def __init__(self, connection, hostname, daemon): """ Threaded class for reading from a slave and send the data to the treatment function """ Thread.__init__(self); self.connection = connection; self.daemon = daemon; self.connected_host = hostname; self.sql = MasterSql();
def __init__(self, connection, hostname, daemon): ## Logger object for formatting and printing logs self.logger = Logger(log_flag, LOG_FILE); Thread.__init__(self); ## Connection object for communications self.connection = connection; ## Instance of Master daemon self.daemon = daemon; ## The hostname of the system self.connected_host = hostname.upper(); ## SQL object for managing master database self.sql = MasterSql(); ## Username for login to the database self.db_username = daemon.db_username; ## Password for login to the database self.db_passwd = daemon.db_passwd; ## Database name for login to the database self.db_dbname = daemon.db_dbname;
def __init__(self, daemon): ## Logger object for formatting and printing logs self.logger = Logger(False, LOG_FILE); ## SQL object for managing database self.sql = MasterSql(); ## Instance of the slave daemon self.daemon = daemon; ## Trigger list self.triggers_list = ''; self.update_triggers_list();
class SlaveReceiver(Thread): ## The constructor. # # @param connection Connection object used to communicate. # @param hostname The hostname. # @param daemon The MasterDaemon with the adapted treatment functions. def __init__(self, connection, hostname, daemon): ## Logger object for formatting and printing logs self.logger = Logger(log_flag, LOG_FILE); Thread.__init__(self); ## Connection object for communications self.connection = connection; ## Instance of Master daemon self.daemon = daemon; ## The hostname of the system self.connected_host = hostname.upper(); ## SQL object for managing master database self.sql = MasterSql(); ## Username for login to the database self.db_username = daemon.db_username; ## Password for login to the database self.db_passwd = daemon.db_passwd; ## Database name for login to the database self.db_dbname = daemon.db_dbname; ## Thread run function overload. # # @return None def run(self): ## Database handler to query master database self.db = MysqlHandler(self.db_username, self.db_passwd, self.db_dbname); self.logger.error('SELECT serial, secretkey, daemon_id FROM daemon WHERE serial=\''+self.connected_host+'\''); res = self.sql.mysql_handler_personnal_query('SELECT serial, secretkey, daemon_id FROM daemon WHERE serial=\''+self.connected_host+'\'', self.db); aes_key = ''; for r in res: if r[0] == self.connected_host: aes_key = r[1]; daemon_id = r[2]; break; if not aes_key: return None; try: data = self.connection.recv(MasterDaemon.MAX_DATA_LENGTH); decrypt_IV = data[:16].decode(); decode_obj = AES.new(aes_key, AES.MODE_CBC, decrypt_IV); data2 = decode_obj.decrypt(data[16:]).decode(); flag = False; obj = data2; self.daemon.parse_data(obj, self.connection, daemon_id, self.db); except Exception as e: self.logger.error(e); self.db.close();
def __init__(self, log_flag): self.logger = Logger(log_flag, LOG_FILE); self.logger.info('Started Greenleaf Master Daemon'); self.d3config = {}; self.aes_slave_keys = {}; self.aes_master_key = None; self.connected_clients = {}; self.sql = MasterSql(); self._parser = DaemonConfigParser(MASTER_CONF_FILE); self.get_aes_slave_keys(); self.reload_camera(None, None); self.scanner = Scanner(HOSTS_CONF); self.scanner.scan(False); self.hostlist = self.scanner._HostList; self.sql.insert_hostlist_in_db(self.scanner._HostList); self.knx_manager = KNXManager(self.aes_slave_keys); self.reload_d3config(None, None); self.protocol_function = { PROTOCOL_KNX : KNXManager.protocol_knx, PROTOCOL_ENOCEAN : self.protocol_enocean, PROTOCOL_IP : self.protocol_ip }; self.upnp_function = { UPNP_PLAY : self.upnp_set_play, UPNP_PAUSE : self.upnp_set_pause, UPNP_NEXT : self.upnp_set_next, UPNP_PREVIOUS : self.upnp_set_prev, UPNP_STOP : self.upnp_set_stop, UPNP_VOLUME_UP : self.upnp_set_volume_up, UPNP_VOLUME_DOWN : self.upnp_set_volume_down, UPNP_SET_VOLUME : self.upnp_set_volume }; self.enocean_function = {}; self.data_function = { DATA_MONITOR_KNX : self.monitor_knx, DATA_MONITOR_IP : self.monitor_ip, DATA_MONITOR_ENOCEAN : self.monitor_enocean, DATA_MONITOR_BLUETOOTH : self.monitor_bluetooth, DATA_KNX_READ : self.knx_read, DATA_KNX_WRITE_S : self.knx_write_short, DATA_KNX_WRITE_L : self.knx_write_long, DATA_SEND_TO_DEVICE : self.send_to_device, DATA_CRON_UPNP : self.cron_upnp, DATA_SEND_MAIL : self.send_mail, DATA_CHECK_SLAVE : self.check_slave, DATA_RELOAD_CAMERA : self.reload_camera, DATA_RELOAD_D3CONFIG : self.reload_d3config, DATA_BACKUP_DB_CREATE_LOCAL : self.backup_db_create_local, DATA_BACKUP_DB_REMOVE_LOCAL : self.backup_db_remove_local, DATA_BACKUP_DB_LIST_LOCAL : self.backup_db_list_local, DATA_BACKUP_DB_RESTORE_LOCAL : self.backup_db_restore_local, DATA_UPDATE : self.update };
def __init__(self, slave_keys): self.knx_function = { OPTION_ON_OFF : self.send_knx_write_short_to_slave, OPTION_VAR : self.send_knx_write_long_to_slave, OPTION_UP_DOWN : self.send_knx_write_short_to_slave, OPTION_OPEN_CLOSE : self.send_knx_write_short_to_slave, OPTION_STOP_UP_DOWN : self.send_knx_write_short_to_slave, OPTION_TEMPERATURE_W: self.send_knx_write_temp }; self.sql = MasterSql(); self._parser = DaemonConfigParser('/etc/greenleaf/master.conf'); self.aes_slave_keys = slave_keys;
def __init__(self, daemon): ## Logger object for formatting and printing logs self.logger = Logger(False, LOG_FILE) ## SQL object for managing slave database self.sql = MasterSql() ## Instance of the slave daemon self.daemon = daemon ## Schedule list self.schedules_list = "" ## Full schedule list self.full_schedules_list = "" self.update_schedules_list(0)
def __init__(self, slave_keys): ## Logger object for formatting and printing self.logger = Logger(DEBUG_MODE, LOG_FILE); ## SQL manager for the master daemon self.sql = MasterSql(); self._parser = DaemonConfigParser('/etc/domoleaf/master.conf'); ## Object containing the AES keys for encrypted communications self.aes_slave_keys = slave_keys; ## Array containing functions associated with IDs self.functions_transform = { 0: utils.convert_none, 4: utils.eno_onoff };
class Scenario(Thread): def __init__(self, daemon): Thread.__init__(self); self.logger = Logger(False, LOG_FILE); self.sql = MasterSql(); self.daemon = daemon; self.scenarios_list = {}; self.update_scenarios_list(); def setValues(self, global_state, trigger, schedule, connection, doList): self.global_state = global_state; self.trigger = trigger; self.schedule = schedule; self.connection = connection; self.doList = doList; def run(self): check_all_scenarios(self); def get_scenarios_tab(self, scenarios): scenarios_tab = {}; self.logger.debug('\n\nGETTING SCENARIOS TAB\n'); for d in scenarios: scHash = ''.join([str(d[4]), '_', str(d[5])]); if scHash not in scenarios_tab: scenarios_tab[scHash] = []; scenarios_tab[scHash].append(d) return scenarios_tab; def update_scenarios_list(self, db=0): self.logger.debug('UPDATING SCENARIOS'); query = ''.join(['SELECT id_scenario, trigger_events_conditions.id_trigger, id_schedule, ', 'id_smartcmd, trigger_events_conditions.room_device_id, id_option ', 'FROM trigger_events_conditions ', 'JOIN scenarios_list ', 'ON trigger_events_conditions.id_trigger=scenarios_list.id_trigger ', 'WHERE activated = 1 && scenarios_list.id_trigger IS NOT NULL ', 'ORDER BY id_scenario']); scenarios_list = self.sql.mysql_handler_personnal_query(query, db); self.logger.debug('S LIST = '+str(scenarios_list)+'\n'); self.scenarios_list = self.get_scenarios_tab(scenarios_list); self.logger.debug('S TAB = '+str(self.scenarios_list)+'\n\n\n'); def launch_scenario(self, id_smartcmd, connection): self.logger.debug('LAUNCH !!!'); jsonString = json.JSONEncoder().encode({ "data": id_smartcmd }); data = json.JSONDecoder().decode(jsonString); self.daemon.smartcmd_launch(data, connection);
class Smartcommand: def __init__(self, daemon, smartcmd_id = 0): self.logger = Logger(False, LOG_FILE); self.logger.debug('Started SMARTCMD'); self.smartcmd_id = smartcmd_id; self.sql = MasterSql(); self.daemon = daemon; def launch_smartcmd(self, json_obj, connection): if (self.smartcmd_id == 0): self.logger.error('Invalid Smartcommand'); return; tab_except_http = [356, 357, 358, 359, 360, 361]; query = ('SELECT smartcommand_elems.room_device_id, option_value, ' ' smartcommand_elems.option_id, time_lapse, opt_value, ' ' device_id ' 'FROM smartcommand_elems ' 'JOIN room_device_option ON room_device_option.room_device_id=smartcommand_elems.room_device_id AND room_device_option.option_id=smartcommand_elems.option_id ' 'JOIN room_device ON room_device.room_device_id=smartcommand_elems.room_device_id ' 'WHERE smartcommand_id ="'+ str(self.smartcmd_id) +'" ' 'ORDER BY exec_id'); res = self.sql.mysql_handler_personnal_query(query); delay_color = 0; for r in res: obj = {}; obj['sync'] = 0; data = {}; data['room_device_id'] = r[0]; data['value'] = r[1]; data['option_id'] = r[2]; data['action'] = r[1]; if r[5] == 86: data['value'] = r[4] elif data['option_id'] in tab_except_http: data['value'] = ''; obj['data'] = data; obj['packet_type'] = 'smartcmd_launch'; delay = r[3]; if (data['option_id'] == 392 or data['option_id'] == 393 or data['option_id'] == 394): delay_color = delay_color + 1; if (delay > 0 and delay_color <= 1): time.sleep(delay); if (delay_color >= 3): delay_color = 0; self.daemon.send_to_device(obj, connection);
def __init__(self, daemon, smartcmd_id=0): Thread.__init__(self) ## Logger object for formatting and printing logs self.logger = Logger(LOG_FLAG, LOG_FILE) self.logger.debug('Started SMARTCMD') ## The ID of the smart command self.smartcmd_id = smartcmd_id ## SQL object for managing database self.sql = MasterSql() ## Instance of the slave daemon self.daemon = daemon ## Array of option code for which the data is not important self.tab_except_http = [356, 357, 358, 359, 360, 361] ## Username to connect to the database self.db_username = daemon.db_username ## Password to connect to the database self.db_passwd = daemon.db_passwd ## Database name on which connect self.db_dbname = daemon.db_dbname
def __init__(self, slave_keys): self.knx_function = { OPTION_ON_OFF : self.send_knx_write_short_to_slave, OPTION_VAR : self.send_knx_write_long_to_slave, OPTION_UP_DOWN : self.send_knx_write_short_to_slave, OPTION_OPEN_CLOSE : self.send_knx_write_short_to_slave, OPTION_STOP_UP_DOWN : self.send_knx_write_short_to_slave, OPTION_SPEED_FAN_0 : self.send_knx_write_speed_fan, OPTION_SPEED_FAN_1 : self.send_knx_write_speed_fan, OPTION_SPEED_FAN_2 : self.send_knx_write_speed_fan, OPTION_SPEED_FAN_3 : self.send_knx_write_speed_fan, OPTION_SPEED_FAN_4 : self.send_knx_write_speed_fan, OPTION_SPEED_FAN_5 : self.send_knx_write_speed_fan, OPTION_SPEED_FAN_6 : self.send_knx_write_speed_fan, OPTION_TEMPERATURE_W: self.send_knx_write_temp, OPTION_COLOR_R : self.send_knx_write_long_to_slave, OPTION_COLOR_G : self.send_knx_write_long_to_slave, OPTION_COLOR_B : self.send_knx_write_long_to_slave, OPTION_COLOR_W : self.send_knx_write_long_to_slave }; self.logger = Logger(True, LOG_FILE); self.sql = MasterSql(); self._parser = DaemonConfigParser('/etc/domoleaf/master.conf'); self.aes_slave_keys = slave_keys;
class Scenario(Thread): ## The constructor. # # @param daemon The daemon which instanciated this class. def __init__(self, daemon): Thread.__init__(self) ## Logger object for formatting and printing logs self.logger = Logger(False, LOG_FILE) ## SQL object for managing slave daemon database self.sql = MasterSql() ## Instance of the slave daemon self.daemon = daemon ## List of scenarios self.scenarios_list = {} self.update_scenarios_list() ## Sets values of a scenario. # # @param global_state The new global state. # @param trigger The new trigger. # @param schedule The new schedule. # @param connection The new connection. # @param doList The new doList. # @return None def setValues(self, global_state, trigger, schedule, connection, doList): ## Global state object self.global_state = global_state ## The trigger for the scenario self.trigger = trigger ## The schedule for the scenario self.schedule = schedule ## The connection to something self.connection = connection ## The do list self.doList = doList ## Starts the thread. # # @return None def run(self): check_all_scenarios(self) ## Gets scenarios from a list. # # @param scenarios The scenarios list. # # @return An array of scenarios. def get_scenarios_tab(self, scenarios): scenarios_tab = {} self.logger.debug('\n\nGETTING SCENARIOS TAB\n') for d in scenarios: scHash = ''.join([str(d[4]), '_', str(d[5])]) if scHash not in scenarios_tab: scenarios_tab[scHash] = [] scenarios_tab[scHash].append(d) return scenarios_tab ## Updates the list of scenarios in database. # # @param db The database handler (default 0). # @return None def update_scenarios_list(self, db=0): self.logger.debug('UPDATING SCENARIOS') query = ''.join([ 'SELECT id_scenario, trigger_events_conditions.id_trigger, id_schedule, ', 'id_smartcmd, trigger_events_conditions.room_device_id, id_option ', 'FROM trigger_events_conditions ', 'JOIN scenarios_list ', 'ON trigger_events_conditions.id_trigger=scenarios_list.id_trigger ', 'WHERE activated = 1 && scenarios_list.id_trigger IS NOT NULL ', 'ORDER BY id_scenario' ]) scenarios_list = self.sql.mysql_handler_personnal_query(query, db) self.logger.debug('S LIST = ' + str(scenarios_list) + '\n') self.scenarios_list = self.get_scenarios_tab(scenarios_list) self.logger.debug('S TAB = ' + str(self.scenarios_list) + '\n\n\n') ## Starts a scenario. # # @param id_smartcmd ID of the smartcommand launching the scenario. # @param connection The connection used to communicate. # @return None def launch_scenario(self, id_smartcmd, connection): self.logger.debug('LAUNCH !!!') jsonString = json.JSONEncoder().encode({"data": id_smartcmd}) data = json.JSONDecoder().decode(jsonString) self.daemon.smartcmd_launch(data, connection)
class EnOceanManager: ## The constructor. # # @param slave_keys The aes keys of the slaves. def __init__(self, slave_keys): ## Logger object for formatting and printing self.logger = Logger(DEBUG_MODE, LOG_FILE) ## SQL manager for the master daemon self.sql = MasterSql() self._parser = DaemonConfigParser('/etc/domoleaf/master.conf') ## Object containing the AES keys for encrypted communications self.aes_slave_keys = slave_keys ## Array containing functions associated with IDs self.functions_transform = { 0: utils.convert_none, 4: utils.eno_onoff } ## Updates the table room_device_option with EnOcean values. # # @param daemon_id The ID of the daemon. # @param json_obj JSON object containing the source address of the EnOcean device. # @param db The database handler. # # @return The result of the query. def update_room_device_option(self, daemon_id, json_obj, db): query = ''.join([ "SELECT room_device_option.option_id, room_device.room_device_id, addr_plus, function_answer, room_device_option.dpt_id ", "FROM room_device_option JOIN room_device ON room_device_option.room_device_id=room_device.room_device_id ", "JOIN dpt_optiondef ON dpt_optiondef.option_id=room_device_option.option_id AND ", "dpt_optiondef.protocol_id=room_device.protocol_id AND dpt_optiondef.dpt_id=room_device_option.dpt_id ", "WHERE daemon_id=", str(daemon_id), " AND room_device_option.addr=\"", str(json_obj['src_addr']), "\"" ]) res = self.sql.mysql_handler_personnal_query(query, db) result = [] append = result.append if not res: query = ''.join([ "SELECT room_device_option.option_id, room_device.room_device_id, addr_plus, function_answer, room_device_option.dpt_id ", "FROM room_device_option JOIN room_device ON room_device_option.room_device_id=room_device.room_device_id ", "JOIN dpt_optiondef ON dpt_optiondef.option_id=room_device_option.option_id AND ", "dpt_optiondef.protocol_id=room_device.protocol_id AND dpt_optiondef.dpt_id=room_device_option.dpt_id ", "WHERE daemon_id=", str(daemon_id), " AND room_device_option.addr_plus=\"", str(json_obj['src_addr']), "\"" ]) res = self.sql.mysql_handler_personnal_query(query, db) for r in res: val = self.functions_transform[r[3]](int(json_obj['value']), r[4]) if val is not None: append(r) up = ''.join([ "UPDATE room_device_option SET opt_value=\"", str(val), "\" WHERE room_device_id=", str(r[1]), " AND option_id=\"", str(r[0]), "\"" ]) self.sql.mysql_handler_personnal_query(up, db) return result
class KNXManager: ## The constructor. # # @param slave_keys Array containing the AES keys of all the slaves. # @return None def __init__(self, slave_keys): ## Logger object for formatting and printing logs self.logger = Logger(DEBUG_MODE, LOG_FILE); ## SQL object for managing database self.sql = MasterSql(); self._parser = DaemonConfigParser('/etc/domoleaf/master.conf'); ## Object containing AES keys for encrypted communications self.aes_slave_keys = slave_keys; ## Updates room_device_option table in database to set new values of the device described by json_obj. # # @param daemon_id The ID of a slave daemon. # @param json_obj JSON object containing the values to update. # @param db The database handler. # # @return The result of the query. def update_room_device_option(self, daemon_id, json_obj, db): if int(json_obj['type']) == KNX_RESPONSE: return self.sql.update_room_device_option_resp(json_obj, daemon_id, db); elif int(json_obj['type']) == KNX_WRITE_SHORT: return self.sql.update_room_device_option_write_short(json_obj, daemon_id, db); elif int(json_obj['type']) == KNX_WRITE_LONG: return self.sql.update_room_device_option_write_long(json_obj, daemon_id, db); ## Sends a JSON object to a slave daemon. # # @param json_str The data to send. # @param sock The socket used to send the data. # @param hostname The hostname of the slave daemon. # @param aes_key The AES key of the slave daemon to encrypt data. # @return None def send_json_obj_to_slave(self, json_str, sock, hostname, aes_key): hostname_key = ''; if '.' in hostname: hostname_key = hostname.split('.')[0]; else: hostname_key = hostname; AES.key_size = 32; aes_IV = AESManager.get_IV(); encode_obj = AES.new(aes_key, AES.MODE_CBC, aes_IV); spaces = 16 - len(json_str) % 16; data2 = encode_obj.encrypt(json_str + (spaces * ' ')); sock.send(bytes(aes_IV, 'utf-8') + data2); ## Changes the speed value of a fan. # # @param json_obj JSON object containing the values to write. # @param dev Object containing informations about the device. # @param hostname The hostname of the slave to who send the packet. # @return None def send_knx_write_speed_fan(self, json_obj, dev, hostname): port = self._parser.getValueFromSection('connect', 'port'); sock = socket.create_connection((hostname, port)); if not port: sys.exit(4); if json_obj['data']['value'] == '1': query = ''.join(['SELECT option_id, addr, dpt_id FROM room_device_option WHERE room_device_id=', str(dev['room_device_id']), ' AND option_id IN(400, 401, 402, 403, 404, 405, 406) AND status=1']); res = self.sql.mysql_handler_personnal_query(query); for line in res: if str(line[2]) == "51" and str(line[0]) == str(json_obj['data']['option_id']): val = str(line[0]).split('40')[1]; json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_long", "addr_to_send": line[1], "value": val } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); return; elif str(line[2]) == "2" and str(line[0]) != str(json_obj['data']['option_id']): json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_short", "addr_to_send": line[1], "value": "0" } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_short", "addr_to_send": str(dev['addr_dst']), "value": json_obj['data']['value'] } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); sock.close(); ## Converts absolute value of temperature (Celsius) in 2 hexadecimal values for sending to KNX device. # # @param json_obj JSON object containing the values to write. # @param dev Object describing the KNX device to who send the packet. # @param hostname The hostname of the slave daemon to who send the packet. # @return None def send_knx_write_temp(self, json_obj, dev, hostname): port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); val_str = json_obj['data']['value']; if ',' in val_str: val_str = val_str.replace(',', '.') value = utils.convert_temperature_reverse(float(val_str)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_temp", "addr_to_send": str(dev['addr_dst']), "value": value[0] + ' ' + value[1] } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); sock.close(); ## Builds a "long write" request and sends it to "hostname". # # @param json_obj JSON object containing the new values. # @param dev The device to who send the request. # @param hostname The slave daemon to who send the packet. # @return None def send_knx_write_long_to_slave(self, json_obj, dev, hostname): port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_long", "addr_to_send": str(dev['addr_dst']), "value": hex(int(json_obj['data']['value'])) } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); sock.close(); ## Builds a "short read" request and sends it to "hostname". # # @param json_obj JSON object containing the new values. # @param dev The device to who send the request. # @param hostname The hostname of the slave daemon to who send the packet. # @return None def send_knx_write_short_to_slave(self, json_obj, dev, hostname): port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_short", "addr_to_send": str(dev['addr_dst']), "value": json_obj['data']['value'] } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); sock.close(); ## Changes the value to send when it is supposed to be inverted and sends the packet to the slave. # # @param json_obj JSON object to change before sending. # @param dev The device to who send the request. # @param hostname The hostname of the slave daemon to who send the packet. # @return None. def send_knx_write_short_to_slave_reverse(self, json_obj, dev, hostname): json_obj['data']['value'] = (int(json_obj['data']['value']) + 1) % 2; self.send_knx_write_short_to_slave(json_obj, dev, hostname); ## Builds a "short read" request and sends it to the slave "hostname". # # @param hostname The slave daemon to who send the read request. # @param json_obj JSON object containing the data to send. # @return None def send_knx_read_request_to_slave(self, hostname, json_obj): port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_read_request", "addr_to_read": json_obj['data']['addr'] } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); sock.close(); ## Asks to send a "on" packet to a device. # # @param json_obj JSON object containing the new values. # @param dev The KNX device. # @param hostname The hostname of the slave daemon. # @return None def send_on(self, json_obj, dev, hostname): port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_short", "addr_to_send": str(dev['addr_dst']), "value": "1" } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); sock.close(); return; ## Asks to send a "off" packet to a device. # # @param json_obj JSON object containing the new values. # @param dev The KNX device. # @param hostname The hostname of the slave daemon. # @return None def send_off(self, json_obj, dev, hostname): port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_short", "addr_to_send": str(dev['addr_dst']), "value": "0" } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); sock.close(); return; ## Sends the new value of the temperature to thermostat. # # @param json_obj JSON object containing the new values. # @param dev The KNX device. # @param hostname The hostname of the slave daemon. # @return None def send_to_thermostat(self, json_obj, dev, hostname): port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); if json_obj['data']['option_id'] == '412': val = 1; elif json_obj['data']['option_id'] == '413': val = 2; elif json_obj['data']['option_id'] == '414': val = 4; elif json_obj['data']['option_id'] == '415': val = 8; elif json_obj['data']['option_id'] == '416': val = 16; elif json_obj['data']['option_id'] == '417': val = 32; else: val = 0 if val > 0: json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_long", "addr_to_send": hex(int(dev['addr_dst'])), "value": val } ); sock = socket.create_connection((hostname, port)); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); sock.close(); return; ## Sends the new mode of the air conditioner. # # @param json_obj JSON object containing the new values. # @param dev The KNX device. # @param hostname The hostname of the slave daemon. # @return None def send_clim_mode(self, json_obj, dev, hostname): if json_obj['data']['option_id'] == '425': #Auto val = 0 elif json_obj['data']['option_id'] == '426': #Heat val = 1 elif json_obj['data']['option_id'] == '427': #Morning Warmup val = 2 elif json_obj['data']['option_id'] == '428': #Cool val = 3 elif json_obj['data']['option_id'] == '429': #Night Purge val = 4 elif json_obj['data']['option_id'] == '430': #Precool val = 5 elif json_obj['data']['option_id'] == '431': #Off val = 6 elif json_obj['data']['option_id'] == '432': #Test val = 7 elif json_obj['data']['option_id'] == '433': #Emergency Heat val = 8 elif json_obj['data']['option_id'] == '434': #Fan only val = 9 elif json_obj['data']['option_id'] == '435': #Free Cool val = 10 elif json_obj['data']['option_id'] == '436': #Ice val = 11 else: val = -1 if val >= 0: json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_long", "addr_to_send": str(dev['addr_dst']), "value": hex(int(val)) } ); sock = socket.create_connection((hostname, port)); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); sock.close(); return; ## Sends a value converted in percentages. # # @param json_obj Not used here. # @param dev Object describing the KNX device. # @param hostname Hostname of the slave daemon to who sent the packet. # @return None def send_knx_write_percent(self, json_obj, dev, hostname): port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_long", "addr_to_send": str(dev['addr_dst']), "value": hex(int(255*int(json_obj['data']['value'])/100)) } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); sock.close();
class Trigger: ## The constructor. # # @param daemon The daemon object which instanciated this class. def __init__(self, daemon): ## Logger object for formatting and printing logs self.logger = Logger(False, LOG_FILE) ## SQL object for managing database self.sql = MasterSql() ## Instance of the slave daemon self.daemon = daemon ## Trigger list self.triggers_list = '' self.update_triggers_list() ## Updates the trigger list. # # @param db The database handler (default 0). # @return None def update_triggers_list(self, db=0): self.logger.debug('Updating Triggers') query = ( 'SELECT trigger_events_list.id_trigger, ' 'trigger_events_conditions.room_device_id, ' 'trigger_events_conditions.id_option, trigger_events_conditions.operator, trigger_events_conditions.value ' 'FROM trigger_events_list ' 'JOIN trigger_events_conditions ' 'ON trigger_events_list.id_trigger = trigger_events_conditions.id_trigger ' 'ORDER BY trigger_events_list.id_trigger') res = self.sql.mysql_handler_personnal_query(query, db) self.triggers_list = res self.logger.debug(res) ## Retrieves the trigger informations from its ID. # # @param id_trigger ID of the trigger. # # @return Array containing trigger informations. def get_trigger_info(self, id_trigger): triggers_list = self.triggers_list trigger = [] append = trigger.append for condition in triggers_list: if (condition[0] == id_trigger): append(condition) return trigger ## Tests all the conditions in a trigger from its ID. # # @param id_trigger The ID of the trigger. # @param global_state Global state. # # @return 1 if the conditions are verified, else 0. def test_trigger(self, id_trigger, global_state): trigger = self.get_trigger_info(id_trigger) res = True for condition in trigger: res = res and self.test_condition(condition, global_state) if res: return 1 return 0 ## Gets a device state. # # @param room_device_id ID of the device. # @param option_id Option ID of the device. # @param global_state Global state. # # @return The state of the device. def get_device_state(self, room_device_id, option_id, global_state): device_state = [] for elem in global_state: if elem[0] == room_device_id and elem[1] == option_id: device_state = elem return device_state return device_state ## Tests the equivalence between the value of a device and the value of a condition. # # @param val_device Value to test. # @param val_condition Value compared. # # @return True if the values are equal, else False. def test_equ(self, val_device, val_condition): if (val_device == val_condition): return True return False ## Tests the superiority or the equivalence between the value of a device and the value of a condition. # # @param val_device Value to test. # @param val_condition Value compared. # # @return True if val_device >= val_condition, else False. def test_sup_equ(self, val_device, val_condition): val_device = float(val_device) val_condition = float(val_condition) if (val_device >= val_condition): return True return False ## Tests the inferiority or the equivalence between the value of a device and the value of a condition. # # @param val_device Value to test. # @param val_condition Value compared. # # @return True if val_device <= val_condition, else False. def test_inf_equ(self, val_device, val_condition): val_device = float(val_device) val_condition = float(val_condition) if (val_device <= val_condition): return True return False ## Tests multiple conditions. # # @param condition Condition to test. # @param global_state Global state. # # @return Function to test def test_condition(self, condition, global_state): device_state = self.get_device_state(condition[1], condition[2], global_state) if not device_state: self.logger.error('No Device State') return False self.logger.debug(device_state) functab = { "0": self.test_equ, "1": self.test_sup_equ, "2": self.test_inf_equ } return functab[str(condition[3])](device_state[2], condition[4])
class CalcLogs: ## The constructor. # # @param daemon The slave daemon which initialized this class instance. def __init__(self, daemon): ## The logger used for formating and printing self.logger = Logger(False, LOG_FILE); self.logger.debug('Init CalcLogs'); ## SQL manager self.sql = MasterSql(); ## The instance of the slave daemon self.daemon = daemon; ## List of the devices self.devices_list = {}; self.devices_list_update(); ## Updates the device list. # # Queries the database to fetch room_device and room_device_option. # The result is stored in a class variable. # # @return none def devices_list_update(self): self.logger.debug('Updating Logs'); query = ('SELECT room_device.daemon_id, room_device_option.addr_plus, room_device_option.addr, ' 'room_device.room_device_id, room_device_option.option_id, room_device.name ' 'FROM room_device ' 'JOIN room_device_option ' 'ON room_device.room_device_id = room_device_option.room_device_id ' 'WHERE daemon_id IS NOT NULL ' 'ORDER BY room_device_id'); res = self.sql.mysql_handler_personnal_query(query); self.devices_list = self.get_tab_devices_list(res); ## Stores the device list in an array and returns it. # # @param res Array containing all informations about room_device and room_device_option. # # @return An array containing informations about the devices, with daemon_id as index. def get_tab_devices_list(self, res): tab = {}; for r in res: daemon_id = r[0]; addr_plus = r[1]; addr = r[2]; if daemon_id not in tab: tab[daemon_id] = {}; if addr_plus: if daemon_id in tab and addr_plus not in tab[daemon_id]: tab[daemon_id][addr_plus] = []; r = r[3:]; tab[daemon_id][addr_plus].append(r); else: if daemon_id in tab and addr not in tab[daemon_id]: tab[daemon_id][addr] = []; r = r[3:]; tab[daemon_id][addr].append(r); return tab; ## Stores only the logs of specific devices. # # @return an array containing the logs. def get_only_good_logs(self, res): tab = []; tab_append = tab.append; self.logger.debug(self.devices_list); for r in res: if (r[1] in self.devices_list[r[0]]): self.logger.debug(r); log = []; log_append = log.append; log_append(r[2]); log_append(r[3]); log_append(self.devices_list[r[0]][r[1]][0][0]); log_append(self.devices_list[r[0]][r[1]][0][1]); log_append(r[4]); log_append(r[5]); log_append(r[1]); log_append(r[0]); tab_append(log); return tab; ## Gets the devices for which logs will be done. # # @param res Array containing all the room devices informations. # # @return An array containing the room devices for who the logs will be done. def get_good_time_range(self, res): end_tr = time.time() - TIME_BEFORE_TIME_TO_CALC - 1; init_tr = end_tr - TIME_RANGE_TO_CALC + 1; tab = []; append = tab.append; for r in res: if (r[0] <= end_tr): append(r); return (tab); ## Cuts the logs array. # # @param tab The array to cut. # # @return The cut dictionnary. def cut_tab(self, tab): cut_tab = {}; cut_dict = {}; for log in tab: device_id = log[2]; option_id = log[3]; if (device_id not in cut_tab): cut_tab[device_id] = {}; if (option_id not in cut_tab[device_id]): cut_tab[device_id][option_id] = []; cut_tab[device_id][option_id].append(log); for device in cut_tab: cut_dict[device] = {}; for option in cut_tab[device]: cut_dict[device][option] = []; for log in cut_tab[device][option]: cut_dict[device][option].append(log); return cut_dict; ## Calculates average values of some data logged. # # @param dictlogs Array containing the logs. # # @return An array containing the average values calculated. def calc_average_values(self, dictlogs): dictaverage = {}; for time_r in dictlogs: dictaverage[time_r] = {}; for device in dictlogs[time_r]: dictaverage[time_r][device] = {}; for option in dictlogs[time_r][device]: dictaverage[time_r][device][option] = []; t0 = -1; t1 = 0; avg = 0; avg_elem = []; append = avg_elem.append; val = 0; for elem in dictlogs[time_r][device][option]: if (t0 == -1): t0 = elem[0]; val = elem[1]; append(t0); else: t1 = elem[0]; avg += (t1 - t0) * val; t0 = t1; val = elem[1]; append(int(avg / TIME_INTERVAL)); append(device); append(option); dictaverage[time_r][device][option].append(avg_elem); return (dictaverage); ## Gets all the logs from the database. # # @param db The database handler. # # @return An array containing all the logs of the database. def get_logs(self, db): query = ('SELECT daemon_id, addr_dest, t_date, knx_value, type, addr_src ' 'FROM knx_log ' 'ORDER BY t_date'); return self.sql.mysql_handler_personnal_query(query, db); ## Cuts a dictionnay depending on the time. # # @param dictlogs The array to cut. # # @return An array of the logs corresponding the right time range. def cut_dict_time(self, dictlogs): end_tr = time.time() - TIME_BEFORE_TIME_TO_CALC - 1; init_tr = end_tr - TIME_RANGE_TO_CALC + 1; init = init_tr; end = init + TIME_INTERVAL - 1; dicttime = {}; tmpdict = {}; n = int(TIME_RANGE_TO_CALC / TIME_INTERVAL); for time_r in range(n): dicttime[time_r] = {}; tmpdict[time_r] = {}; for device in dictlogs: dicttime[time_r][device] = {}; tmpdict[time_r][device] = {}; for option in dictlogs[device]: dicttime[time_r][device][option] = []; tmpdict[time_r][device][option] = []; first = tmpdict[time_r][device][option]; if (not first): first = list(dictlogs[device][option][0]); first[0] = init; last = list(first); dicttime[time_r][device][option].append(first); for log in dictlogs[device][option]: date = log[0]; if (date >= init and date <= end): dicttime[time_r][device][option].append(log); last = list(log); if (date > end): break; last[0] = end + 1; dicttime[time_r][device][option].append(last); tmpdict[time_r][device][option] = list(last); init += TIME_INTERVAL; end += TIME_INTERVAL; return dicttime; ## Inserts a graphic log in the database. # # @param dictlogs Dictionnay containing all the logs. # @param db The database handler. # @return none def save_graph_logs(self, dictlogs, db): query = ('INSERT INTO graphic_log ' '(date, value, room_device_id, option_id) ' 'VALUES '); for time_r in dictlogs: for device in dictlogs[time_r]: for option in dictlogs[time_r][device]: for log in dictlogs[time_r][device][option]: query += '('+str(log[0])+', '+str(log[1])+', '+str(log[2])+', '+str(log[3])+'), '; query = query[:-2]; res = self.sql.mysql_handler_personnal_query(query, db); ## Deletes the KNX logs from the database. # # @param dictlogs Dictionnay containing all the logs for all devices. # @param db The database handler. # @return none def delete_knx_logs(self, dictlogs, db): end_tr = time.time() - TIME_BEFORE_TIME_TO_CALC; last_logs = []; append = last_logs.append; for device in dictlogs: for option in dictlogs[device]: log = dictlogs[device][option][-1]; append(log); query = ('DELETE FROM knx_log ' 'WHERE t_date < ' + str(end_tr)); res = self.sql.mysql_handler_personnal_query(query, db); query = ('DELETE FROM enocean_log ' 'WHERE t_date < ' + str(end_tr)); res = self.sql.mysql_handler_personnal_query(query, db); query = ('INSERT INTO knx_log ' '(type, addr_src, addr_dest, knx_value, t_date, daemon_id) ' 'VALUES '); for log in last_logs: query += ('( '+str(log[4])+', '+'\''+str(log[5])+'\', '+ '\''+str(log[6])+'\', '+str(log[1])+', '+ str(log[0])+', '+str(log[7])+'), '); query = query[:-2]; res = self.sql.mysql_handler_personnal_query(query, db); ## Sorts the logs by calling multiple function to print only the wanted logs. # # @param connection Not used here. # @param db The database handler. # @return none def sort_logs(self, connection, db): self.logger.debug('\n\nSorting Logs : \n'); try: logs = self.get_logs(db); if not logs: return; tablogs = self.get_only_good_logs(logs); self.logger.debug('TABLOGS 1 :\n'+str(tablogs)+'\n'); tablogs = self.get_good_time_range(tablogs); if not tablogs: return; self.logger.debug('TABLOGS 2 :\n'+str(tablogs)+'\n'); dictlogs = self.cut_tab(tablogs); if not dictlogs: return; self.logger.debug('DICTLOGS :\n'+str(dictlogs)+'\n'); dictlogstime = self.cut_dict_time(dictlogs); dictlogstime = self.calc_average_values(dictlogstime); if not dictlogstime: return; self.logger.debug('DICTLOGSTIME :\n'+str(dictlogstime)+'\n'); self.logger.debug('Save Graph Logs\n'); self.save_graph_logs(dictlogstime, db); self.logger.debug('Delete Logs\n'); self.delete_knx_logs(dictlogs, db); self.logger.debug('OK\n\n'); except Exception as e: self.logger.error(e);
class MasterDaemon: """ Main class of the master daemon It provides communication between master and slave boxes and a part of the database management """ def __init__(self, log_flag): self.logger = Logger(log_flag, LOG_FILE); self.logger.info('Started Greenleaf Master Daemon'); self.d3config = {}; self.aes_slave_keys = {}; self.aes_master_key = None; self.connected_clients = {}; self.sql = MasterSql(); self._parser = DaemonConfigParser(MASTER_CONF_FILE); self.get_aes_slave_keys(); self.reload_camera(None, None); self.scanner = Scanner(HOSTS_CONF); self.scanner.scan(False); self.hostlist = self.scanner._HostList; self.sql.insert_hostlist_in_db(self.scanner._HostList); self.knx_manager = KNXManager(self.aes_slave_keys); self.reload_d3config(None, None); self.protocol_function = { PROTOCOL_KNX : KNXManager.protocol_knx, PROTOCOL_ENOCEAN : self.protocol_enocean, PROTOCOL_IP : self.protocol_ip }; self.upnp_function = { UPNP_PLAY : self.upnp_set_play, UPNP_PAUSE : self.upnp_set_pause, UPNP_NEXT : self.upnp_set_next, UPNP_PREVIOUS : self.upnp_set_prev, UPNP_STOP : self.upnp_set_stop, UPNP_VOLUME_UP : self.upnp_set_volume_up, UPNP_VOLUME_DOWN : self.upnp_set_volume_down, UPNP_SET_VOLUME : self.upnp_set_volume }; self.enocean_function = {}; self.data_function = { DATA_MONITOR_KNX : self.monitor_knx, DATA_MONITOR_IP : self.monitor_ip, DATA_MONITOR_ENOCEAN : self.monitor_enocean, DATA_MONITOR_BLUETOOTH : self.monitor_bluetooth, DATA_KNX_READ : self.knx_read, DATA_KNX_WRITE_S : self.knx_write_short, DATA_KNX_WRITE_L : self.knx_write_long, DATA_SEND_TO_DEVICE : self.send_to_device, DATA_CRON_UPNP : self.cron_upnp, DATA_SEND_MAIL : self.send_mail, DATA_CHECK_SLAVE : self.check_slave, DATA_RELOAD_CAMERA : self.reload_camera, DATA_RELOAD_D3CONFIG : self.reload_d3config, DATA_BACKUP_DB_CREATE_LOCAL : self.backup_db_create_local, DATA_BACKUP_DB_REMOVE_LOCAL : self.backup_db_remove_local, DATA_BACKUP_DB_LIST_LOCAL : self.backup_db_list_local, DATA_BACKUP_DB_RESTORE_LOCAL : self.backup_db_restore_local, DATA_UPDATE : self.update }; def get_aes_slave_keys(self): """ Get the secretkeys of each slave daemon stored in database """ query = "SELECT serial, secretkey FROM daemon"; res = self.sql.mysql_handler_personnal_query(query); self_hostname = socket.gethostname(); for r in res: if SLAVE_NAME_PREFIX in r[0] or 'MD3' in r[0]: self.aes_slave_keys[r[0]] = r[1]; elif self_hostname == r[0]: self.aes_slave_keys[r[0]] = r[1]; self.aes_master_key = r[1]; print(self.aes_slave_keys) def stop(self): """ Stops the daemon and closes sockets """ flag = False; while not flag: flag = True; for client in self.connected_clients.values(): flag = False; client.close(); break; self.slave_connection.close(); sys.exit(0); def run(self): """ Initialization of the connections and accepting incomming communications """ self.slave_connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM); self.cmd_connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM); self.slave_connection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1); self.cmd_connection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1); s_port = self._parser.getValueFromSection(MASTER_CONF_LISTEN_SECTION, MASTER_CONF_LISTEN_PORT_SLAVE_ENTRY); c_port = self._parser.getValueFromSection(MASTER_CONF_LISTEN_SECTION, MASTER_CONF_LISTEN_PORT_CMD_ENTRY); if not s_port: frameinfo = getframeinfo(currentframe()); self.logger.error('in run: No slave listening port defined in ' + MASTER_CONF_FILE); sys.exit(1); if not c_port: frameinfo = getframeinfo(currentframe()); self.logger.error('in run: No command listening port defined in ' + MASTER_CONF_FILE); sys.exit(1); self.slave_connection.bind(('', int(s_port))); self.slave_connection.listen(MAX_SLAVES); self.cmd_connection.bind(('', int(c_port))); self.cmd_connection.listen(MAX_CMDS); self.loop(); def loop(self): """ Main loop. Waits for new connections. """ self.run = True; while self.run: try: rlist, wlist, elist = select.select([self.slave_connection], [], [], SELECT_TIMEOUT); for connection in rlist: self.accept_new_slave_connection(connection); rlist, wlist, elist = select.select([self.cmd_connection], [], [], SELECT_TIMEOUT); for connection in rlist: self.accept_new_cmd_connection(connection); except KeyboardInterrupt as e: frameinfo = getframeinfo(currentframe()); self.logger.info('in loop: Keyboard interrupt: leaving program'); print("[ MASTER DAEMON " + frameinfo.filename + ":" + str(frameinfo.lineno) + " ]: Keyboard Interrupt"); self.stop(); sys.exit(0); except ValueError as e: frameinfo = getframeinfo(currentframe()); self.logger.error('in loop: Value error: ' + str(e)); print("[ MASTER DAEMON " + frameinfo.filename + ":" + str(frameinfo.lineno) + "]: Value Error"); print(e); pass; def accept_new_cmd_connection(self, connection): """ Gets new mastercommand connections and threads the treatment. """ new_connection, addr = connection.accept(); r = CommandReceiver(new_connection, self); r.start(); def accept_new_slave_connection(self, connection): """ Gets new slave connections and threads the treatment. """ new_connection, addr = connection.accept(); for host in self.hostlist: if addr[0] == host._IpAddr: hostname = host._Hostname.split('.')[0]; r = SlaveReceiver(new_connection, hostname, self); r.start(); def parse_data(self, data, connection): """ Once data are received whether from mastercommand or slave, the function of the packet_type in data is called. """ json_obj = json.JSONDecoder().decode(data); if json_obj['packet_type'] in self.data_function.keys(): self.data_function[json_obj['packet_type']](json_obj, connection); else: frameinfo = getframeinfo(currentframe()); def update(self, json_obj, connection): call(['apt-get', 'update']); call(['apt-get', 'install', 'glmaster', 'glslave', '-y']); hostname = socket.gethostname(); if '.' in hostname: hostname = hostname.split('.')[0]; version_file = open('/etc/greenleaf/.glmaster.version', 'r'); if not version_file: self.logger.error("File not found: /etc/greenleaf/.glmaster.version"); print("File not found: /etc/greenleaf/.glmaster.version"); return; version = version_file.read(); if '\n' in version: version = version.split('\n')[0]; query = 'UPDATE daemon SET version="' + version + '" WHERE name="' + hostname + '"'; self.sql.mysql_handler_personnal_query(query); query = 'UPDATE configuration SET configuration_value="' + version + '" WHERE configuration_id=4'; self.sql.mysql_handler_personnal_query(query); json_obj['data'].append(hostname); port = self._parser.getValueFromSection('connect', 'port'); for host in self.hostlist: sock = socket.create_connection((host._IpAddr, port)); if host._Hostname.startswith('MD3') or host._Hostname.startswith('SD3') and host._Hostname not in json_obj['data']: json_str = json.JSONEncoder().encode(json_obj); sock.send(bytes(json_str, 'utf-8')); data = sock.recv(4096); decrypt_IV = data[:16].decode(); decode_obj = AES.new(self.aes_master_key, AES.MODE_CBC, decrypt_IV); data2 = decode_obj.decrypt(data[16:]).decode(); version = data2['new_version']; query = 'UPDATE daemon SET version="' + version + '" WHERE name="' + host._Hostname + '"'; self.sql.mysql_handler_personnal_query(query); def backup_db_create_local(self, json_obj, connection): filename = '/etc/greenleaf/sql/backup/mastercommand_backup_'; t = str(time.time()); if '.' in t: t = t.split('.')[0]; filename += t; filename += '.sql'; os.popen("mysqldump --defaults-file=/etc/mysql/debian.cnf mastercommand > " + filename); def backup_db_remove_local(self, json_obj, connection): filename = '/etc/greenleaf/sql/backup/'; filename += json_obj; filename += '.sql'; if json_obj[0] == '.' or json_obj[0] == '/': print('The filename is corrupted. Aborting database file removing.') return; try: os.stat(filename); except Exception as e: print("The database file to remove does not exists.") print(e) return; os.remove(filename); def backup_db_list_local(self, json_obj, connection): json_obj = []; backup_list = os.listdir('/etc/greenleaf/sql/backup/') for f in backup_list: s = os.stat('/etc/greenleaf/sql/backup/' + f); if '.sql' in f: f = f.split('.sql')[0]; json_obj.append({"name": f, "size": s.st_size}); json_sorted = sorted(json_obj, key=lambda json_obj: json_obj['name']); json_str = json.JSONEncoder().encode(json_sorted); connection.send(bytes(json_str, 'utf-8'));
class KNXManager: """ KNX management class """ def __init__(self, slave_keys): self.knx_function = { OPTION_ON_OFF : self.send_knx_write_short_to_slave, OPTION_VAR : self.send_knx_write_long_to_slave, OPTION_UP_DOWN : self.send_knx_write_short_to_slave, OPTION_OPEN_CLOSE : self.send_knx_write_short_to_slave, OPTION_STOP_UP_DOWN : self.send_knx_write_short_to_slave, OPTION_SPEED_FAN_0 : self.send_knx_write_speed_fan, OPTION_SPEED_FAN_1 : self.send_knx_write_speed_fan, OPTION_SPEED_FAN_2 : self.send_knx_write_speed_fan, OPTION_SPEED_FAN_3 : self.send_knx_write_speed_fan, OPTION_SPEED_FAN_4 : self.send_knx_write_speed_fan, OPTION_SPEED_FAN_5 : self.send_knx_write_speed_fan, OPTION_SPEED_FAN_6 : self.send_knx_write_speed_fan, OPTION_TEMPERATURE_W: self.send_knx_write_temp, OPTION_COLOR_R : self.send_knx_write_long_to_slave, OPTION_COLOR_G : self.send_knx_write_long_to_slave, OPTION_COLOR_B : self.send_knx_write_long_to_slave, OPTION_COLOR_W : self.send_knx_write_long_to_slave }; self.logger = Logger(True, LOG_FILE); self.sql = MasterSql(); self._parser = DaemonConfigParser('/etc/domoleaf/master.conf'); self.aes_slave_keys = slave_keys; def update_room_device_option(self, daemon_id, json_obj): """ Update room_device_option table in database to set new values of the device described by 'json_obj' """ if int(json_obj['type']) == KNX_RESPONSE: self.sql.update_room_device_option_resp(json_obj, daemon_id); elif int(json_obj['type']) == KNX_WRITE_SHORT: self.sql.update_room_device_option_write_short(json_obj, daemon_id); elif int(json_obj['type']) == KNX_WRITE_LONG: self.sql.update_room_device_option_write_long(json_obj, daemon_id); def protocol_knx(self, json_obj, dev, hostname): """ KNX protocol data treatment function """ new_obj = { "data": { "addr": str(dev['addr_dst']), "value": str(json_obj['data']['value']), "option_id": str(json_obj['data']['option_id']), "room_device_id": str(dev['room_device_id']), } }; self.knx_function[int(json_obj['data']['option_id'])](hostname, new_obj); def send_json_obj_to_slave(self, json_str, sock, hostname, aes_key, close_flag = True): """ Send 'json_obj' to 'hostname' via 'sock' """ hostname_key = ''; if '.' in hostname: hostname_key = hostname.split('.')[0]; else: hostname_key = hostname; AES.key_size = 32; aes_IV = AESManager.get_IV(); encode_obj = AES.new(aes_key, AES.MODE_CBC, aes_IV); spaces = 16 - len(json_str) % 16; data2 = encode_obj.encrypt(json_str + (spaces * ' ')); sock.send(bytes(aes_IV, 'utf-8') + data2); if close_flag == True: sock.close(); def send_knx_write_speed_fan(self, hostname, json_obj): """ Ask to close all the speed fan before open another """ port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); if json_obj['data']['value'] == '1': query = 'SELECT option_id, addr, dpt_id '; query += 'FROM room_device_option '; query += 'WHERE room_device_id=' + str(json_obj['data']['room_device_id']) + ' AND '; query += 'option_id IN(400, 401, 402, 403, 404, 405, 406) AND status=1'; res = self.sql.mysql_handler_personnal_query(query); for line in res: if str(line[2]) == "51" and str(line[0]) == str(json_obj['data']['option_id']): sock = socket.create_connection((hostname, port)); val = str(line[0]).split('40')[1]; json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_long", "addr_to_send": line[1], "value": val } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); sock.close(); return; if str(line[2]) == "2" and str(line[0]) != str(json_obj['data']['option_id']): sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_short", "addr_to_send": line[1], "value": "0" } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); sock.close(); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_short", "addr_to_send": json_obj['data']['addr'], "value": json_obj['data']['value'] } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); def send_knx_write_temp(self, hostname, json_obj): """ Converts absolute value of temperature (Celsius) in 2 hexadecimal values for sending to KNX device """ port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); val_str = json_obj['data']['value']; if '.' in val_str: val_str = val_str.split('.')[0]; value = utils.convert_temperature_reverse(int(val_str)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_temp", "addr_to_send": json_obj['data']['addr'], "value": value[0] + ' ' + value[1] } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); def send_knx_write_long_to_slave(self, hostname, json_obj): """ Constructs long write request and sends it to 'hostname' """ port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_long", "addr_to_send": json_obj['data']['addr'], "value": hex(int(json_obj['data']['value'])) } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); def send_knx_write_short_to_slave(self, hostname, json_obj): """ Constructs short write request and sends it to 'hostname' """ port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_short", "addr_to_send": json_obj['data']['addr'], "value": json_obj['data']['value'] } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); def send_knx_read_request_to_slave(self, hostname, json_obj): """ Constructs short read request and sends it to 'hostname' """ port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_read_request", "addr_to_read": json_obj['data']['addr'] } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]);
class Schedule: def __init__(self, daemon): self.logger = Logger(False, LOG_FILE); self.sql = MasterSql(); self.daemon = daemon; self.schedules_list = ''; self.full_schedules_list = ''; self.update_schedules_list(); def update_schedules_list(self): self.logger.debug('Updating Schedules'); query = ('SELECT trigger_schedules_list.id_schedule, id_smartcmd, ' 'months, weekdays, days, hours, mins ' 'FROM scenarios_list ' 'JOIN trigger_schedules_list ON scenarios_list.id_schedule = trigger_schedules_list.id_schedule ' 'WHERE scenarios_list.id_schedule IS NOT NULL && id_trigger IS NULL && activated = 1 ' 'ORDER BY id_scenario '); res = self.sql.mysql_handler_personnal_query(query); self.schedules_list = res; query = ('SELECT trigger_schedules_list.id_schedule, id_smartcmd, ' 'months, weekdays, days, hours, mins ' 'FROM scenarios_list ' 'JOIN trigger_schedules_list ON scenarios_list.id_schedule = trigger_schedules_list.id_schedule ' 'WHERE scenarios_list.id_schedule IS NOT NULL && activated = 1 ' 'ORDER BY id_scenario '); res = self.sql.mysql_handler_personnal_query(query); self.full_schedules_list = res; def get_schedule_infos(self, id_schedule): schedules_list = self.full_schedules_list; for schedule in schedules_list: if (schedule[0] == id_schedule): return (schedule[2], schedule[3], schedule[4], schedule[5], schedule[6]); return 0; def check_all_schedules(self, connection): schedules_list = self.schedules_list; for schedule in schedules_list: if self.test_schedule(schedule[0]) == 1: self.launch_scenario(schedule[1], connection); def test_schedule(self, id_schedule): if not self.full_schedules_list: return 0; months, weekdays, days, hours, mins = self.get_schedule_infos(id_schedule); now = datetime.datetime.now(); curr_month = int(now.month) - 1; curr_weekday = int(now.strftime('%w')); curr_day = int(now.day) - 1; curr_hour = int(now.hour); curr_min = int(now.minute); months = list("{0:b}".format(int(months)).zfill(12)); weekdays = list("{0:b}".format(int(weekdays)).zfill(7)); days = list("{0:b}".format(int(days)).zfill(31)); hours = list("{0:b}".format(int(hours)).zfill(24)); mins = list(mins); if (int(months[curr_month]) == 1 and int(weekdays[curr_weekday]) == 1 and int(days[curr_day]) == 1 and int(hours[curr_hour]) == 1 and int(mins[curr_min]) == 1): return 1; return 0; def launch_scenario(self, id_smartcmd, connection): jsonString = json.JSONEncoder().encode({ "data": id_smartcmd }); data = json.JSONDecoder().decode(jsonString); self.daemon.smartcmd_launch(data, connection);
class KNXManager: """ KNX management class """ def __init__(self, slave_keys): self.knx_function = { OPTION_ON_OFF : self.send_knx_write_short_to_slave, OPTION_VAR : self.send_knx_write_long_to_slave, OPTION_UP_DOWN : self.send_knx_write_short_to_slave, OPTION_OPEN_CLOSE : self.send_knx_write_short_to_slave, OPTION_STOP_UP_DOWN : self.send_knx_write_short_to_slave, OPTION_TEMPERATURE_W: self.send_knx_write_temp }; self.sql = MasterSql(); self._parser = DaemonConfigParser('/etc/greenleaf/master.conf'); self.aes_slave_keys = slave_keys; def update_room_device_option(self, daemon_id, json_obj): """ Update room_device_option table in database to set new values of the device described by 'json_obj' """ if int(json_obj['type']) == KNX_RESPONSE: self.sql.update_room_device_option_resp(json_obj, daemon_id); elif int(json_obj['type']) == KNX_WRITE_SHORT: self.sql.update_room_device_option_write_short(json_obj, daemon_id); elif int(json_obj['type']) == KNX_WRITE_LONG: self.sql.update_room_device_option_write_long(json_obj, daemon_id); def protocol_knx(self, json_obj, dev, hostname): """ KNX protocol data treatment function """ new_obj = { "data": { "addr": str(dev['addr_dst']), "value": str(json_obj['data']['value']) } }; self.knx_function[int(json_obj['data']['option_id'])](hostname, new_obj); def send_json_obj_to_slave(self, json_str, sock, hostname, aes_key, close_flag = True): """ Send 'json_obj' to 'hostname' via 'sock' """ hostname_key = ''; if '.' in hostname: hostname_key = hostname.split('.')[0]; else: hostname_key = hostname; AES.key_size = 32; aes_IV = AESManager.get_IV(); encode_obj = AES.new(aes_key, AES.MODE_CBC, aes_IV); data2 = encode_obj.encrypt(json_str + (176 - len(json_str)) * ' '); sock.send(bytes(aes_IV, 'utf-8') + data2); if close_flag == True: sock.close(); def send_knx_write_temp(self, hostname, json_obj): """ Converts absolute value of temperature (Celsius) in 2 hexadecimal values for sending to KNX device """ port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); val_str = json_obj['data']['value']; if '.' in val_str: val_str = val_str.split('.')[0]; value = utils.convert_temperature_reverse(int(val_str)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_temp", "addr_to_send": json_obj['data']['addr'], "value": value[0] + ' ' + value[1] } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); def send_knx_write_long_to_slave(self, hostname, json_obj): """ Constructs long write request and sends it to 'hostname' """ port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_long", "addr_to_send": json_obj['data']['addr'], "value": hex(int(json_obj['data']['value'])) } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); def send_knx_write_short_to_slave(self, hostname, json_obj): """ Constructs short write request and sends it to 'hostname' """ port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_write_short", "addr_to_send": json_obj['data']['addr'], "value": json_obj['data']['value'] } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]); def send_knx_read_request_to_slave(self, hostname, json_obj): """ Constructs short read request and sends it to 'hostname' """ port = self._parser.getValueFromSection('connect', 'port'); if not port: sys.exit(4); sock = socket.create_connection((hostname, port)); json_str = json.JSONEncoder().encode( { "packet_type": "knx_read_request", "addr_to_read": json_obj['data']['addr'] } ); self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]);
class CalcLogs: def __init__(self, daemon): self.logger = Logger(False, LOG_FILE); self.logger.debug('Init CalcLogs'); self.sql = MasterSql(); self.daemon = daemon; self.devices_list = {}; self.devices_list_update(); def devices_list_update(self): self.logger.debug('Updating Logs'); query = ('SELECT room_device.daemon_id, room_device_option.addr_plus, room_device_option.addr, ' 'room_device.room_device_id, room_device_option.option_id, room_device.name ' 'FROM room_device ' 'JOIN room_device_option ' 'ON room_device.room_device_id = room_device_option.room_device_id ' 'WHERE daemon_id IS NOT NULL ' 'ORDER BY room_device_id'); res = self.sql.mysql_handler_personnal_query(query); self.devices_list = res; self.devices_list = self.get_tab_devices_list(res); def get_tab_devices_list(self, res): tab = {}; for r in res: daemon_id = r[0]; addr_plus = r[1]; addr = r[2]; if daemon_id not in tab: tab[daemon_id] = {}; if addr_plus: if daemon_id in tab and addr_plus not in tab[daemon_id]: tab[daemon_id][addr_plus] = []; r = r[3:]; tab[daemon_id][addr_plus].append(r); else: if daemon_id in tab and addr not in tab[daemon_id]: tab[daemon_id][addr] = []; r = r[3:]; tab[daemon_id][addr].append(r); return tab; def get_only_good_logs(self, res): tab = []; tab_append = tab.append self.logger.debug(self.devices_list); for r in res: if (r[1] in self.devices_list[r[0]]): self.logger.debug(r); log = []; log_append = log.append; log_append(r[2]); log_append(r[3]); log_append(self.devices_list[r[0]][r[1]][0][0]); log_append(self.devices_list[r[0]][r[1]][0][1]); log_append(r[4]); log_append(r[5]); log_append(r[1]); log_append(r[0]); tab_append(log); return tab; def get_good_time_range(self, res): end_tr = time.time() - TIME_BEFORE_TIME_TO_CALC - 1; init_tr = end_tr - TIME_RANGE_TO_CALC + 1; #self.logger.debug('NOW = '+ time.strftime("%d %m %Y %H:%M:%S", time.localtime(now))); tab = []; append = tab.append; for r in res: if (r[0] <= end_tr): append(r); return (tab); def cut_tab(self, tab): cut_tab = {}; cut_dict = {}; for log in tab: device_id = log[2]; option_id = log[3]; if (device_id not in cut_tab): cut_tab[device_id] = {}; if (option_id not in cut_tab[device_id]): cut_tab[device_id][option_id] = []; cut_tab[device_id][option_id].append(log); for device in cut_tab: cut_dict[device] = {}; for option in cut_tab[device]: cut_dict[device][option] = []; for log in cut_tab[device][option]: cut_dict[device][option].append(log); return cut_dict; def calc_average_values(self, dictlogs): dictaverage = {}; for time_r in dictlogs: dictaverage[time_r] = {}; for device in dictlogs[time_r]: dictaverage[time_r][device] = {}; for option in dictlogs[time_r][device]: dictaverage[time_r][device][option] = []; t0 = -1; t1 = 0; avg = 0; avg_elem = []; append = avg_elem.append; val = 0; for elem in dictlogs[time_r][device][option]: if (t0 == -1): t0 = elem[0]; val = elem[1]; append(t0); else: t1 = elem[0]; avg += (t1 - t0) * val; t0 = t1; val = elem[1]; append(int(avg / TIME_INTERVAL)); append(device); append(option); dictaverage[time_r][device][option].append(avg_elem); return (dictaverage); def get_logs(self, db): query = ('SELECT daemon_id, addr_dest, t_date, knx_value, type, addr_src ' 'FROM knx_log ' 'ORDER BY t_date'); return self.sql.mysql_handler_personnal_query(query, db); def cut_dict_time(self, dictlogs): end_tr = time.time() - TIME_BEFORE_TIME_TO_CALC - 1; init_tr = end_tr - TIME_RANGE_TO_CALC + 1; init = init_tr; end = init + TIME_INTERVAL - 1; dicttime = {}; tmpdict = {}; n = int(TIME_RANGE_TO_CALC / TIME_INTERVAL); for time_r in range(n): dicttime[time_r] = {}; tmpdict[time_r] = {}; for device in dictlogs: dicttime[time_r][device] = {}; tmpdict[time_r][device] = {}; for option in dictlogs[device]: dicttime[time_r][device][option] = []; tmpdict[time_r][device][option] = []; first = tmpdict[time_r][device][option]; if (not first): first = list(dictlogs[device][option][0]); first[0] = init; last = list(first); dicttime[time_r][device][option].append(first); for log in dictlogs[device][option]: date = log[0]; if (date >= init and date <= end): dicttime[time_r][device][option].append(log); last = list(log); if (date > end): break; last[0] = end + 1; dicttime[time_r][device][option].append(last); tmpdict[time_r][device][option] = list(last); init += TIME_INTERVAL; end += TIME_INTERVAL; return dicttime; def save_graph_logs(self, dictlogs, db): query = ('INSERT INTO graphic_log ' '(date, value, room_device_id, option_id) ' 'VALUES '); for time_r in dictlogs: for device in dictlogs[time_r]: for option in dictlogs[time_r][device]: for log in dictlogs[time_r][device][option]: query += '('+str(log[0])+', '+str(log[1])+', '+str(log[2])+', '+str(log[3])+'), '; query = query[:-2]; res = self.sql.mysql_handler_personnal_query(query, db); def delete_knx_logs(self, dictlogs, db): end_tr = time.time() - TIME_BEFORE_TIME_TO_CALC; last_logs = []; append = last_logs.append; for device in dictlogs: for option in dictlogs[device]: log = dictlogs[device][option][-1]; append(log); query = ('DELETE FROM knx_log ' 'WHERE t_date < ' + str(end_tr)); res = self.sql.mysql_handler_personnal_query(query, db); query = ('DELETE FROM enocean_log ' 'WHERE t_date < ' + str(end_tr)); res = self.sql.mysql_handler_personnal_query(query, db); query = ('INSERT INTO knx_log ' '(type, addr_src, addr_dest, knx_value, t_date, daemon_id) ' 'VALUES '); for log in last_logs: query += ('( '+str(log[4])+', '+'\''+str(log[5])+'\', '+ '\''+str(log[6])+'\', '+str(log[1])+', '+ str(log[0])+', '+str(log[7])+'), '); query = query[:-2]; res = self.sql.mysql_handler_personnal_query(query, db); def sort_logs(self, connection, db): self.logger.debug('\n\nSorting Logs : \n'); try: logs = self.get_logs(db); #self.logger.debug('LOGS :\n' + str(logs) + '\n'); if not logs: return; tablogs = self.get_only_good_logs(logs); self.logger.debug('TABLOGS 1 :\n'+str(tablogs)+'\n'); tablogs = self.get_good_time_range(tablogs); if not tablogs: return; self.logger.debug('TABLOGS 2 :\n'+str(tablogs)+'\n'); dictlogs = self.cut_tab(tablogs); if not dictlogs: return; self.logger.debug('DICTLOGS :\n'+str(dictlogs)+'\n'); dictlogstime = self.cut_dict_time(dictlogs); dictlogstime = self.calc_average_values(dictlogstime); if not dictlogstime: return; self.logger.debug('DICTLOGSTIME :\n'+str(dictlogstime)+'\n'); self.logger.debug('Save Graph Logs\n'); self.save_graph_logs(dictlogstime, db); self.logger.debug('Delete Logs\n'); self.delete_knx_logs(dictlogs, db); self.logger.debug('OK\n\n'); except Exception as e: self.logger.error(e);
def __init__(self): ## Logger object for formatting and printing logs self.logger = Logger(False, LOG_FILE); ## SQL object for managing database self.sql = MasterSql();
class CalcLogs: def __init__(self, daemon): self.logger = Logger(False, LOG_FILE); self.logger.debug('Init CalcLogs'); self.sql = MasterSql(); self.daemon = daemon; self.devices_list = {}; self.devices_list_update(); def devices_list_update(self): self.logger.debug('Updating Logs'); query = ('SELECT room_device.daemon_id, room_device_option.addr_plus, room_device_option.addr, ' 'room_device.room_device_id, room_device_option.option_id, room_device.name ' 'FROM room_device ' 'JOIN room_device_option ' 'ON room_device.room_device_id = room_device_option.room_device_id ' 'WHERE daemon_id IS NOT NULL ' 'ORDER BY room_device_id'); res = self.sql.mysql_handler_personnal_query(query); self.devices_list = res; self.devices_list = self.get_tab_devices_list(res); def get_tab_devices_list(self, res): tab = {}; for r in res: daemon_id = r[0]; addr_plus = r[1]; addr = r[2]; if (daemon_id not in tab): tab[daemon_id] = {}; if (addr_plus): if (daemon_id in tab and addr_plus not in tab[daemon_id]): tab[daemon_id][addr_plus] = []; r = r[3:]; tab[daemon_id][addr_plus].append(r); else: if (daemon_id in tab and addr not in tab[daemon_id]): tab[daemon_id][addr] = []; r = r[3:]; tab[daemon_id][addr].append(r); return tab; def get_only_good_logs(self, res): tab = []; self.logger.debug(self.devices_list); for r in res: if (r[1] in self.devices_list[r[0]]): self.logger.debug(r); log = []; log.append(r[2]); log.append(r[3]); log.append(self.devices_list[r[0]][r[1]][0][0]); log.append(self.devices_list[r[0]][r[1]][0][1]); log.append(r[4]); log.append(r[5]); log.append(r[1]); log.append(r[0]); tab.append(log); return tab; def get_good_time_range(self, res): now = time.time(); #now = TEST_TIMESTAMP; end_tr = now - TIME_BEFORE_TIME_TO_CALC - 1; init_tr = end_tr - TIME_RANGE_TO_CALC + 1; #self.logger.debug('NOW = '+ time.strftime("%d %m %Y %H:%M:%S", time.localtime(now))); tab = []; for r in res: date = r[0]; if (date <= end_tr): tab.append(r); return (tab); def cut_tab(self, tab): cut_tab = {}; cut_dict = {}; for log in tab: device_id = log[2]; option_id = log[3]; if (device_id not in cut_tab): cut_tab[device_id] = {}; if (option_id not in cut_tab[device_id]): cut_tab[device_id][option_id] = []; cut_tab[device_id][option_id].append(log); for device in cut_tab: cut_dict[device] = {}; for option in cut_tab[device]: cut_dict[device][option] = []; for log in cut_tab[device][option]: cut_dict[device][option].append(log); return cut_dict; def calc_average_values(self, dictlogs): dictaverage = {}; for time_r in dictlogs: dictaverage[time_r] = {}; for device in dictlogs[time_r]: dictaverage[time_r][device] = {}; for option in dictlogs[time_r][device]: dictaverage[time_r][device][option] = []; t0 = -1; t1 = 0; avg = 0; avg_elem = []; val = 0; for elem in dictlogs[time_r][device][option]: if (t0 == -1): t0 = elem[0]; val = elem[1]; avg_elem.append(t0); else: t1 = elem[0]; avg = avg + (t1 - t0) * val; t0 = t1; val = elem[1]; avg_elem.append(int(avg / TIME_INTERVAL)); avg_elem.append(device); avg_elem.append(option); dictaverage[time_r][device][option].append(avg_elem); return (dictaverage); def get_logs(self, test): if (test == 0): query = ('SELECT daemon_id, addr_dest, t_date, knx_value, type, addr_src ' 'FROM knx_log ' 'ORDER BY t_date'); res = self.sql.mysql_handler_personnal_query(query); else: res = self.get_test_logs(); return res; def cut_dict_time(self, dictlogs): now = time.time(); #now = TEST_TIMESTAMP; end_tr = now - TIME_BEFORE_TIME_TO_CALC - 1; init_tr = end_tr - TIME_RANGE_TO_CALC + 1; init = init_tr; end = init + TIME_INTERVAL - 1; dicttime = {}; tmpdict = {}; n = int(TIME_RANGE_TO_CALC / TIME_INTERVAL); for time_r in range(n): dicttime[time_r] = {}; tmpdict[time_r] = {}; for device in dictlogs: dicttime[time_r][device] = {}; tmpdict[time_r][device] = {}; for option in dictlogs[device]: dicttime[time_r][device][option] = []; tmpdict[time_r][device][option] = []; first = tmpdict[time_r][device][option]; if (not first): first = list(dictlogs[device][option][0]); first[0] = init; last = list(first); dicttime[time_r][device][option].append(first); for log in dictlogs[device][option]: date = log[0]; if (date >= init and date <= end): dicttime[time_r][device][option].append(log); last = list(log); if (date > end): break; last[0] = end + 1; dicttime[time_r][device][option].append(last); tmpdict[time_r][device][option] = list(last); init = init + TIME_INTERVAL; end = end + TIME_INTERVAL; return dicttime; def save_graph_logs(self, dictlogs): query = ('INSERT INTO graphic_log ' '(date, value, room_device_id, option_id) ' 'VALUES '); for time_r in dictlogs: for device in dictlogs[time_r]: for option in dictlogs[time_r][device]: for log in dictlogs[time_r][device][option]: query += '(' + str(log[0]) + ', '; query += str(log[1]) + ', '; query += str(log[2]) + ', '; query += str(log[3]) + '), '; query = query[:-2]; res = self.sql.mysql_handler_personnal_query(query); def delete_knx_logs(self, dictlogs): now = time.time(); #now = TEST_TIMESTAMP; end_tr = now - TIME_BEFORE_TIME_TO_CALC; last_logs = []; for device in dictlogs: for option in dictlogs[device]: log = dictlogs[device][option][-1]; last_logs.append(log); query = ('DELETE FROM knx_log ' 'WHERE t_date < ' + str(end_tr)); res = self.sql.mysql_handler_personnal_query(query); query = ('DELETE FROM enocean_log ' 'WHERE t_date < ' + str(end_tr)); res = self.sql.mysql_handler_personnal_query(query); query = ('INSERT INTO knx_log ' '(type, addr_src, addr_dest, knx_value, t_date, daemon_id) ' 'VALUES '); for log in last_logs: query += '( ' + str(log[4]) + ', '; query += '\'' + str(log[5]) + '\', '; query += '\'' + str(log[6]) + '\', '; query += str(log[1]) + ', '; query += str(log[0]) + ', '; query += str(log[7]) + '), '; query = query[:-2]; res = self.sql.mysql_handler_personnal_query(query); def sort_logs(self, connection): self.logger.debug('\n\nSorting Logs : \n'); try: logs = self.get_logs(0); #self.logger.debug('LOGS :\n' + str(logs) + '\n'); if not logs: return; tablogs = self.get_only_good_logs(logs); self.logger.debug('TABLOGS 1 :\n' + str(tablogs) + '\n'); tablogs = self.get_good_time_range(tablogs); if not tablogs: return; self.logger.debug('TABLOGS 2 :\n' + str(tablogs) + '\n'); dictlogs = self.cut_tab(tablogs); if not dictlogs: return; self.logger.debug('DICTLOGS :\n' + str(dictlogs) + '\n'); dictlogstime = self.cut_dict_time(dictlogs); dictlogstime = self.calc_average_values(dictlogstime); if not dictlogstime: return; self.logger.debug('DICTLOGSTIME :\n' + str(dictlogstime) + '\n'); self.logger.debug('Save Graph Logs\n'); self.save_graph_logs(dictlogstime); self.logger.debug('Delete Logs\n'); self.delete_knx_logs(dictlogs); self.logger.debug('OK\n\n'); except Exception as e: self.logger.error(e); def get_test_logs(self): res = [(1, '0/0/12', 1448268700, 1), (1, '0/1/23', 1448268800, 3515), (1, '0/0/14', 1448268850, 255), (1, '0/0/17', 1448268860, 1), (1, '0/1/1', 1448268900, 1786), (1, '0/1/1', 1448270540, 1786), (1, '0/1/1', 1448270661, 1788), (1, '0/1/23', 1448270719, 3548), (1, '0/1/1', 1448270781, 1790), (1, '0/1/1', 1448270901, 1792), (1, '0/1/1', 1448271141, 1796), (1, '0/0/12', 1448271148, 1), (1, '0/0/14', 1448271152, 255), (1, '0/1/23', 1448271155, 3598), (1, '0/0/17', 1448271160, 1), (1, '0/0/19', 1448271163, 255), (1, '0/1/23', 1448271167, 3398), (1, '0/0/12', 1448271173, 0), (1, '0/0/14', 1448271175, 0), (1, '0/0/12', 1448271179, 0), (1, '0/0/17', 1448271181, 0), (1, '0/0/19', 1448271184, 0), (1, '0/0/17', 1448271188, 0), (1, '0/0/12', 1448271229, 1), (1, '0/0/14', 1448271232, 255), (1, '0/0/17', 1448271235, 1), (1, '0/0/19', 1448271238, 251), (1, '0/0/19', 1448271241, 255), (1, '0/0/12', 1448271245, 0), (1, '0/0/14', 1448271247, 0), (1, '0/0/17', 1448271251, 0), (1, '0/0/19', 1448271253, 0), (1, '0/0/12', 1448271257, 1), (1, '0/0/14', 1448271259, 204), (1, '0/1/1', 1448271262, 1802), (1, '0/0/12', 1448271265, 1), (1, '0/0/14', 1448271268, 255), (1, '0/0/14', 1448271273, 59), (1, '0/0/14', 1448271274, 58), (1, '0/0/17', 1448271281, 1), (1, '0/0/19', 1448271284, 255), (1, '0/1/1', 1448271381, 1806), (1, '0/1/1', 1448271501, 1812), (1, '0/1/1', 1448271621, 1816), (1, '0/1/1', 1448271741, 1824), (1, '0/1/1', 1448272011, 1830), (1, '0/1/23', 1448272062, 3398), (1, '0/1/1', 1448272101, 1834), (1, '0/1/1', 1448272222, 1834), (1, '0/1/1', 1448272295, 1824), (1, '0/1/1', 1448272415, 1822), (1, '0/1/1', 1448272535, 1822), (1, '0/1/1', 1448272655, 1824), (1, '0/1/1', 1448272775, 1824), (1, '0/1/1', 1448272911, 1830), (1, '0/1/23', 1448272963, 3398), (1, '0/1/1', 1448273015, 1836), (1, '0/1/1', 1448273135, 1838), (1, '0/1/1', 1448273255, 1842), (1, '0/1/1', 1448273375, 1844), (1, '0/1/1', 1448273495, 1850), (1, '0/1/1', 1448273615, 1852), (1, '0/1/1', 1448273735, 1856), (1, '0/1/1', 1448273856, 1856), (1, '0/1/23', 1448273863, 3398), (1, '0/1/1', 1448273976, 1858), (1, '0/1/1', 1448274096, 1864), (1, '0/1/1', 1448274216, 1866), (1, '0/1/1', 1448274336, 1870), (1, '0/1/1', 1448274456, 1874), (1, '0/1/1', 1448274576, 1876), (1, '0/1/1', 1448274712, 1882), (1, '0/1/23', 1448274764, 3398), (1, '0/1/24', 1448274767, 3423), (1, '0/1/1', 1448274816, 1884), (1, '0/1/1', 1448274936, 1886), (1, '0/1/1', 1448275056, 1888), (1, '0/1/1', 1448275176, 1892), (1, '0/1/1', 1448275296, 1892), (1, '0/1/1', 1448275416, 1896), (1, '0/1/6', 1448275519, 0), (1, '0/1/8', 1448275522, 0)]; return (res);