Beispiel #1
0
 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;
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 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);
Beispiel #4
0
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);
Beispiel #5
0
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);
Beispiel #6
0
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
Beispiel #7
0
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();
Beispiel #8
0
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);
Beispiel #9
0
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);
Beispiel #10
0
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);
Beispiel #11
0
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]);
Beispiel #12
0
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);
Beispiel #13
0
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)
Beispiel #14
0
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'));
Beispiel #15
0
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
Beispiel #16
0
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)
Beispiel #17
0
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]);
Beispiel #18
0
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);
Beispiel #19
0
class KNXManager:
    """
    KNX management class
    """
    def __init__(self, slave_keys):
        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:
            return self.sql.update_room_device_option_resp(json_obj, daemon_id);
        elif int(json_obj['type']) == KNX_WRITE_SHORT:
            return self.sql.update_room_device_option_write_short(json_obj, daemon_id);
        elif int(json_obj['type']) == KNX_WRITE_LONG:
            return self.sql.update_room_device_option_write_long(json_obj, daemon_id);

    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, json_obj, dev, hostname):
        """
        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(dev['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": str(dev['addr_dst']),
                "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, json_obj, dev, hostname):
        """
        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.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]);

    def send_knx_write_long_to_slave(self, json_obj, dev, hostname):
        """
        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": 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]);

    def send_knx_write_short_to_slave(self, json_obj, dev, hostname):
        """
        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": str(dev['addr_dst']),
                "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]);
    
    def send_on(self, json_obj, dev, hostname):
        """
        Ask to close all the speed fan before open another
        """
        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;
    
    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;
    
    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;

    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(255*int(json_obj['data']['value'])/100)
            }
        );
        self.send_json_obj_to_slave(json_str, sock, hostname, self.aes_slave_keys[hostname]);
Beispiel #20
0
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);
Beispiel #21
0
class Trigger:

    def __init__(self, daemon):
        self.logger = Logger(False, LOG_FILE);
        self.sql = MasterSql();
        self.daemon = daemon;
        self.triggers_list = '';
        self.update_triggers_list();

    def update_triggers_list(self):
        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);
        self.triggers_list = res;
        self.logger.debug(res);

    def get_trigger_info(self, id_trigger):
        triggers_list = self.triggers_list;
        trigger = [];
        for condition in triggers_list:
            if (condition[0] == id_trigger):
                trigger.append(condition);
        return trigger;

    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 == True):
            return 1;
        return 0;

    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;

    def test_equ(self, val_device, val_condition):
        if (val_device == val_condition):
            return True;
        return 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;

    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;

    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
            };
        res = functab[str(condition[3])](device_state[2], condition[4]);
        return res;
Beispiel #22
0
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])
Beispiel #23
0
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 Domoleaf 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.db_username = self._parser.getValueFromSection(MASTER_CONF_MYSQL_SECTION, MASTER_CONF_MYSQL_USER_ENTRY);
        self.db_passwd = self._parser.getValueFromSection(MASTER_CONF_MYSQL_SECTION, MASTER_CONF_MYSQL_PASSWORD_ENTRY);
        self.db_dbname = self._parser.getValueFromSection(MASTER_CONF_MYSQL_SECTION, MASTER_CONF_MYSQL_DB_NAME_ENTRY);
        self.get_aes_slave_keys(0);
        self.reload_camera(None, None, 0);
        self._scanner = Scanner();
        self.hostlist = [];
        self.hostlist.append(Host('', '127.0.0.1', socket.gethostname().upper()));
        self.knx_manager = KNXManager(self.aes_slave_keys);
        self.enocean_manager = EnOceanManager(self.aes_slave_keys);
        self.reload_d3config(None, None, 0);
        self.trigger = Trigger(self);
        self.scenario = Scenario(self);
        self.schedule = Schedule(self);
        self.calcLogs = CalcLogs(self);

        self.functions = {
              1 : self.knx_manager.send_knx_write_short_to_slave,
              2 : self.knx_manager.send_knx_write_long_to_slave,
              3 : self.knx_manager.send_knx_write_speed_fan,
              4 : self.knx_manager.send_knx_write_temp,
              5 : IP_IRManager().send_to_gc,
              6 : self.knx_manager.send_on,
              7 : self.knx_manager.send_to_thermostat,
              8 : self.knx_manager.send_clim_mode,
              9 : HttpReq().http_action,
             10 : self.upnp_audio,
             11 : self.knx_manager.send_knx_write_percent,
             12 : self.knx_manager.send_off,
             13 : self.knx_manager.send_knx_write_short_to_slave_r,
        };
        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_MODIF_DATETIME               : self.modif_datetime,
            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_CHECK_USB                    : self.check_usb,
            DATA_BACKUP_DB_CREATE_USB         : self.backup_db_create_usb,
            DATA_BACKUP_DB_REMOVE_USB         : self.backup_db_remove_usb,
            DATA_BACKUP_DB_LIST_USB           : self.backup_db_list_usb,
            DATA_BACKUP_DB_RESTORE_USB        : self.backup_db_restore_usb,
            DATA_SMARTCMD_LAUNCH              : self.smartcmd_launch,
            DATA_TRIGGERS_LIST_UPDATE         : self.triggers_list_update,
            DATA_SCHEDULES_LIST_UPDATE        : self.schedules_list_update,
            DATA_SCENARIOS_LIST_UPDATE        : self.scenarios_list_update,
            DATA_CHECK_ALL_SCHEDULES          : self.check_schedules,
            DATA_CALC_LOGS                    : self.launch_calc_logs,
            DATA_CHECK_UPDATES                : self.check_updates,
            DATA_UPDATE                       : self.update,
            DATA_SEND_ALIVE                   : self.send_request,
            DATA_SEND_TECH                    : self.send_tech,
            DATA_SEND_INTERFACES              : self.send_interfaces,
            DATA_SHUTDOWN_D3                  : self.shutdown_d3,
            DATA_REBOOT_D3                    : self.reboot_d3,
            DATA_WIFI_UPDATE                  : self.wifi_update,
            DATA_REMOTE_SQL                   : self.remote_sql
        };

    def get_aes_slave_keys(self, db):
        """
        Get the secretkeys of each slave daemon stored in database
        """
        query = "SELECT serial, secretkey FROM daemon";
        res = self.sql.mysql_handler_personnal_query(query, db);
        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];

    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.IPPROTO_TCP, socket.TCP_NODELAY, 1);
        self.cmd_connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1);
        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 domoleaf 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();
        myname = socket.gethostname();
        try:
            name = socket.gethostbyaddr(addr[0])[0]
        except socket.error as serr:
            name = 'localhost'
        if name == 'localhost':
            name = myname
        name = name.split('.')[0];
        r = SlaveReceiver(new_connection, name, self);
        r.start();

    def parse_data(self, data, connection, daemon_id, db):
        """
        Once data are received whether from domoleaf or slave, the function of the packet_type in data is called.
        """
        json_obj = json.JSONDecoder().decode(data);
        json_obj['daemon_id'] = daemon_id;
        if json_obj['packet_type'] in self.data_function.keys():
            self.data_function[json_obj['packet_type']](json_obj, connection, db);
        else:
            frameinfo = getframeinfo(currentframe());

    def check_updates(self, json_obj, connection, db):
        query = 'SELECT configuration_value FROM configuration WHERE configuration_id=4';
        actual_version = self.sql.mysql_handler_personnal_query(query, db);
        if not actual_version:
            self.logger.error("CHECK_UPDATE : No Master Version");
            return;
        query = 'UPDATE configuration SET configuration_value="" WHERE configuration_id=13';
        self.sql.mysql_handler_personnal_query(query, db);
        p = call(['dpkg', '--configure', '-a'])
        p = Popen(['apt-get', 'update'], stdin=PIPE, stdout=PIPE, stderr=PIPE, bufsize=-1);
        output, error = p.communicate();
        p = Popen(['apt-show-versions',  '-u', 'domomaster'], stdin=PIPE, stdout=PIPE, stderr=PIPE, bufsize=-1);
        output, error = p.communicate();
        if not p.returncode:
            tab = output.decode("utf-8").split(" ");
            version = tab[-1].rsplit("\n")[0];
        else:
            version = actual_version[0][0];
        query = ''.join(['UPDATE configuration SET configuration_value="', version, '" WHERE configuration_id=13']);
        self.sql.mysql_handler_personnal_query(query, db);

    def update(self, json_obj, connection, db):
        call(['apt-get', 'update']);
        p = Popen("DEBIAN_FRONTEND=noninteractive apt-get install domomaster domoslave -y ",
              shell=True, stdin=None, stdout=False, stderr=False,executable="/bin/bash");
        output, error = p.communicate();
        hostname = socket.gethostname();
        if '.' in hostname:
            hostname = hostname.split('.')[0];
        version = os.popen("dpkg-query -W -f='${Version}\n' domomaster").read().split('\n')[0];
        query = ''.join(['UPDATmon SET version="', version, '" WHERE name="', hostname, '"' ]);
        self.sql.mysql_handler_personnal_query(query, db);
        query = ''.join(['UPDATE configuration SET configuration_value="', version, '" WHERE configuration_id=4']);
        self.sql.mysql_handler_personnal_query(query, db);
        json_obj['data'].append(hostname);
        port = self._parser.getValueFromSection('connect', 'port');
        for host in self.hostlist:
            if (host._Hostname.startswith('MD3') or host._Hostname.startswith('SD3')) and host._Hostname not in json_obj['data']:
                sock = socket.create_connection((host._IpAddr, port));
                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 = ''.join(['UPDATE daemon SET version="', version, '" WHERE name="', host._Hostname, '"']);
                self.sql.mysql_handler_personnal_query(query, db);
                sock.close();

    def backup_db_create_local(self, json_obj, connection, db):
        path = '/etc/domoleaf/sql/backup/';
        filename = 'domoleaf_backup_';
        t = str(time.time());
        if '.' in t:
            t = t.split('.')[0];
        filename += t+'.sql';
        os.system("mysqldump --defaults-file=/etc/mysql/debian.cnf domoleaf > "+path+filename);
        os.system('cd '+path+' && tar -czf '+filename+'.tar.gz'+' '+filename);
        os.system('rm '+path+filename);

    def backup_db_remove_local(self, json_obj, connection, db):
        filename = ''.join(['/etc/domoleaf/sql/backup/domoleaf_backup_', str(json_obj['data']), '.sql.tar.gz']);
        if str(json_obj['data'][0]) == '.' or str(json_obj['data'][0]) == '/':
            self.logger.error('The filename is corrupted. Aborting database file removing.')
            return;
        try:
            os.stat(filename);
        except Exception as e:
            try:
                filename = filename.split('.tar.gz')[0];
                os.stat(filename);
            except Exception as e:
                self.logger.error("The database file to remove does not exists.")
                self.logger.error(e)
                return;
        os.remove(filename);

    def backup_db_list_local(self, json_obj, connection, db):
        json_obj = [];
        append = json_obj.append;
        backup_list = os.listdir('/etc/domoleaf/sql/backup/')
        for f in backup_list:
            s = os.stat('/etc/domoleaf/sql/backup/'+f);
            if '.sql' in f:
                g = f.split('.sql')[0];
                append({"name": g, "size": s.st_size});
        json_sorted = sorted(json_obj, key=lambda json_obj: json_obj['name'], reverse=True);
        json_str = json.JSONEncoder().encode(json_sorted);
        connection.send(bytes(json_str, 'utf-8'));

    def backup_db_restore_local(self, json_obj, connection, db):
        path = '/etc/domoleaf/sql/backup/';
        filename = ''.join(['domoleaf_backup_', str(json_obj['data']), '.sql.tar.gz']);
        if json_obj['data'][0] == '.' or json_obj['data'][0] == '/':
            self.logger.error('The filename is corrupted. Aborting database restoring.')
            return;
        try:
            os.stat(path+filename);
            os.system('cd '+path+' && tar -xzf '+filename);
            os.system('mysql --defaults-file=/etc/mysql/debian.cnf domoleaf < '+path+filename.split('.tar.gz')[0]);
            os.system('rm '+path+filename.split('.tar.gz')[0]);
            return;
        except Exception as e:
            try:
                filename = filename.split('.tar.gz')[0];
                os.stat(path+filename);
            except Exception as e:
                self.logger.error("The database file to restore does not exists.");
                self.logger.error(e);
                return;
        os.system('mysql --defaults-file=/etc/mysql/debian.cnf domoleaf < '+path+filename);

    def check_usb(self, json_obj, connection, db):
        try:
            sdx1 = glob.glob('/dev/sd?1')[0];
        except Exception as e:
            return;
        if not (os.path.exists(sdx1)):
            json_obj = 0;
        else:
            json_obj = 1;
        json_str = json.JSONEncoder().encode(json_obj);
        connection.send(bytes(json_str, 'utf-8'));

    def backup_db_list_usb(self, json_obj, connection, db):
        json_obj = [];
        append = json_obj.append
        sdx1 = glob.glob('/dev/sd?1')[0];
        if not (os.path.exists(sdx1)):
            return;
        os.system('mount '+sdx1+' /etc/domoleaf/mnt');
        os.system('mkdir -p /etc/domoleaf/mnt/backup');
        backup_list = os.listdir('/etc/domoleaf/mnt/backup/')
        for f in backup_list:
            s = os.stat('/etc/domoleaf/mnt/backup/'+f);
            if '.sql' in f:
                g = f.split('.sql')[0];
                append({"name": g, "size": s.st_size});
        os.system('umount /etc/domoleaf/mnt');
        json_sorted = sorted(json_obj, key=lambda json_obj: json_obj['name'], reverse=True);
        json_str = json.JSONEncoder().encode(json_sorted);
        connection.send(bytes(json_str, 'utf-8'));

    def backup_db_remove_usb(self, json_obj, connection, db):
        filename = ''.join(['/etc/domoleaf/mnt/backup/domoleaf_backup_', str(json_obj['data']), '.sql.tar.gz']);
        if str(json_obj['data'][0]) == '.' or str(json_obj['data'][0]) == '/':
            self.logger.error('The filename is corrupted. Aborting database file removing.')
            return;
        sdx1 = glob.glob('/dev/sd?1')[0];
        if not (os.path.exists(sdx1)):
            return;
        os.system('mount '+sdx1+' /etc/domoleaf/mnt');
        path = '/etc/domoleaf/mnt/backup/';
        try:
            os.stat(filename);
        except Exception as e:
            try:
                filename = filename.split('.tar.gz')[0];
                os.stat(filename);
            except Exception as e:
                self.logger.error("The database file to remove does not exists.")
                self.logger.error(e)
                os.system('umount /etc/domoleaf/mnt');
                return;
        os.remove(filename);
        os.system('umount /etc/domoleaf/mnt');

    def backup_db_restore_usb(self, json_obj, connection, db):
        path = '/etc/domoleaf/mnt/backup/';
        filename = ''.join(['domoleaf_backup_', str(json_obj['data']), '.sql']);
        if json_obj['data'][0] == '.' or json_obj['data'][0] == '/':
            self.logger.error('The filename is corrupted. Aborting database restoring.')
            return;
        sdx1 = glob.glob('/dev/sd?1')[0];
        if not (os.path.exists(sdx1)):
            return;
        os.system('mount '+sdx1+' /etc/domoleaf/mnt');
        try:
            os.stat(path+filename);
            os.system('cp '+path+filename+' /tmp/ && umount /etc/domoleaf/mnt && cd /tmp/');
            os.system('mysql --defaults-file=/etc/mysql/debian.cnf domoleaf < /tmp/'+filename);
            os.remove('/tmp/'+filename);
            return;
        except Exception as e:
            try:
                filename += '.tar.gz';
                os.stat(path+filename);
                os.system('cp '+path+filename+' /tmp/ && umount /etc/domoleaf/mnt && cd /tmp/ && tar -xzf '+filename);
            except Exception as e:
                self.logger.error("The database file to restore does not exists.");
                self.logger.error(e);
                os.system('umount /etc/domoleaf/mnt');
                return;
        os.system('umount /etc/domoleaf/mnt');
        os.system('mysql --defaults-file=/etc/mysql/debian.cnf domoleaf < /tmp/'+filename.split('.tar.gz')[0]);
        os.remove('/tmp/'+filename);
        os.remove('/tmp/'+filename.split('.tar.gz')[0]);

    def backup_db_create_usb(self, json_obj, connection, db):
        sdx1 = glob.glob('/dev/sd?1')[0];
        if not (os.path.exists(sdx1)):
            return;
        os.system('mount '+sdx1+' /etc/domoleaf/mnt');
        path = '/etc/domoleaf/mnt/backup/';
        filename = 'domoleaf_backup_';
        os.system('mkdir -p '+path);
        t = str(time.time());
        if '.' in t:
            t = t.split('.')[0];
        filename += t+'.sql';
        os.system("mysqldump --defaults-file=/etc/mysql/debian.cnf domoleaf > "+path+filename);
        os.system('cd '+path+' && tar -czf '+filename+'.tar.gz'+' '+filename);
        os.system('rm '+path +filename);
        os.system('umount /etc/domoleaf/mnt');

    def monitor_knx(self, json_obj, connection, db):
        """
        Callback called each time a monitor_knx packet is received.
        Updates room_device_option values in the database and check scenarios.
        """
        daemon_id = self.sql.update_knx_log(json_obj, db);
        doList = self.knx_manager.update_room_device_option(daemon_id, json_obj, db);
        if doList:
            self.scenario.setValues(self.get_global_state(db), self.trigger, self.schedule, connection, doList);
            self.scenario.start();
        connection.close();

    def knx_write_short(self, json_obj, connection, db):
        """
        Callback called each time a knx_write_short packet is received.
        Updates room_device_option values in the database.
        """
        daemons = self.sql.get_daemons(db);
        slave_name = self.get_slave_name(json_obj, daemons);
        if slave_name is None:
            connection.close();
            return None;
        dev = {}
        dev["addr_dst"] = json_obj['data']['addr']
        slave_name = slave_name.split('.')[0];
        self.knx_manager.send_knx_write_short_to_slave(json_obj, dev, slave_name);
        connection.close();
        return None;

    def knx_write_long(self, json_obj, connection, db):
        """
        Callback called each time a knx_write_long packet is received.
        Updates room_device_option values in the database.
        """
        daemons = self.sql.get_daemons(db);
        slave_name = self.get_slave_name(json_obj, daemons);
        if slave_name is None:
            connection.close();
            return None;
        dev = {}
        dev["addr_dst"] = json_obj['data']['addr']
        slave_name = slave_name.split('.')[0];
        self.knx_manager.send_knx_write_long_to_slave(json_obj, dev, slave_name);
        connection.close();
        return None;

    def knx_read(self, json_obj, connection, db):
        """
        Callback called each time a knx_read packet is received.
        """
        daemons = self.sql.get_daemons(db);
        slave_name = self.get_slave_name(json_obj, daemons);
        if slave_name is None:
            return None;
        slave_name = slave_name.split('.')[0];
        self.knx_manager.send_knx_read_request_to_slave(slave_name, json_obj);
        connection.close();

    def monitor_ip(self, json_obj, connection, db):
        """
        Callback called each time a monitor_ip packet is received.
        A new local network scan is performed and the result stored in the database
        """
        self.scanner.scan();
        self.sql.insert_hostlist_in_db(self.scanner._HostList, db);
        self.hostlist = self.scanner._HostList;
        connection.close();

    def monitor_bluetooth(self, json_obj, connection, db):
        """
        TODO
        """
        connection.close();
        return None;

    def monitor_enocean(self, json_obj, connection, db):
        """
        Callback called each time a monitor_enocean packet is received.
        Stores the data in enocean_log table.
        """
        daemon_id = self.sql.update_enocean_log(json_obj, db);
        doList = self.enocean_manager.update_room_device_option(daemon_id, json_obj, db);
        connection.close();
        if doList:
            self.scenario.setValues(self.get_global_state(db), self.trigger, self.schedule, connection, doList);
            self.scenario.start();
        return None;

    def send_to_device(self, json_obj, connection, db):
        """
        Retrieves the good device in the database and builds the request to send.
        """
        hostname = '';
        dm = DeviceManager(int(json_obj['data']['room_device_id']), int(json_obj['data']['option_id']), DEBUG_MODE);
        dev = dm.load_from_db(db);
        if dev is None:
            connection.close();
            return ;
        if 'daemon_name' in dev:
            for host in self.hostlist:
                if dev['daemon_name'] == host._Hostname:
                    hostname = host._Hostname;
                    break;
        function_writing = int(dev['function_writing']);
        if (function_writing > 0):
            try:
                self.functions[function_writing](json_obj, dev, hostname);
            except Exception as e:
                self.logger.error(e);
        connection.close();

    def upnp_audio(self, json_obj, dev, hostname):
        cmd = UpnpAudio(dev['addr'], int(dev['plus1']));
        cmd.action(json_obj);

    def get_ip_ifname(self, ifname):
        """
        Retrieves network interface name from IP address.
        """
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM);
        try:
            res = socket.inet_ntoa(fcntl.ioctl(s.fileno(),
                                               0x8915,
                                               struct.pack('256s', bytes(ifname, 'utf-8')))[20:24]);
            return res;
        except Exception as e:
            frameinfo = getframeinfo(currentframe());
            self.logger.error('in get_ip_ifname: '+str(e));
            return None;

    def cron_upnp(self, json_obj, connection, db):
        """
        Callback called each time a cron_upnp packet is received.
        """
        local_ip = self.get_ip_ifname("eth0");
        if local_ip is None:
            connection.close();
            return None;
        query = "SELECT configuration_id, configuration_value FROM configuration";
        res = self.sql.mysql_handler_personnal_query(query);
        actions = json_obj['data'];
        for act in actions:
            if act['action'] == 'open':
                for r in res:
                    if int(r[0]) == int(act['configuration_id']):
                        if int(r[0]) == 1:
                            call(["upnpc", "-a", local_ip, str(r[1]), "80", act['protocol']]);
                        elif int(r[0]) == 2:
                            call(["upnpc", "-a", local_ip, str(r[1]), "443", act['protocol']]);
            elif act['action'] == 'close':
                for r in res:
                    if int(r[0]) == int(act['configuration_id']):
                        call(["upnpc", "-d", str(r[1]), act['protocol']]);

    def reload_camera(self, json_obj, connection, db):
        """
        Generation of the file devices.conf located in /etc/domoleaf by default.
        """
        camera_file = open(CAMERA_CONF_FILE, 'w');
        query = "SELECT room_device_id, addr, plus1 FROM room_device WHERE protocol_id = 6";
        res = self.sql.mysql_handler_personnal_query(query, db);
        for r in res:
            ip = str(r[1]);
            if r[1] and utils.is_valid_ip(ip):
                camera_file.write("location /device/"+str(r[0]));
                camera_file.write("/ {\n")
                camera_file.write("\tproxy_buffering off;\n")
                camera_file.write("\tproxy_pass http://"+ip);
                if str(r[2]).isdigit():
                    camera_file.write(":"+str(r[2])+"/;\n}\n\n");
                else:
                    camera_file.write(":/;\n}\n\n");
        camera_file.close();
        call(["service", "nginx", "restart"]);

    def reload_d3config(self, json_obj, connection, db):
        """
        Loads port config. Reading in database and storing.
        """
        query = "SELECT configuration_id, configuration_value FROM configuration";
        res = self.sql.mysql_handler_personnal_query(query, db);
        for r in res:
            self.d3config[str(r[0])] = r[1];

    def check_slave(self, json_obj, connection, db):
        """
        Asks "check_slave" to the slave described in json_obj and waits for answer.
        """
        query = ''.join(["SELECT serial, secretkey FROM daemon WHERE daemon_id=", str(json_obj['data']['daemon_id'])]);
        res = self.sql.mysql_handler_personnal_query(query, db);
        if res is None or not res:
            self.logger.error('in check_slave: No daemon for id '+str(json_obj['data']['daemon_id']));
            connection.close();
            return ;
        elif len(res) > 1:
            self.logger.error('in check_slave: Too much daemons for id '+str(json_obj['data']['daemon_id']));
            connection.close();
            return ;
        hostname = res[0][0];
        self_hostname = socket.gethostname();
        if hostname == self_hostname:
            ip = '127.0.0.1';
        else:
            ip = '';
            for h in self.hostlist:
                if hostname in h._Hostname.upper():
                    ip = h._IpAddr;
        if not ip:
            self.logger.error('in check_slave: '+hostname+' not in hostlist. Try perform network scan again.');
            connection.close();
            return ;
        port = self._parser.getValueFromSection('connect', 'port');
        sock = socket.create_connection((ip, port));
        if '.' in self_hostname:
            self_hostname = self_hostname.split('.')[0];
        aes_IV = AESManager.get_IV();
        aes_key = self.get_secret_key(hostname);
        obj_to_send = ''.join(['{"packet_type": "check_slave", "sender_name": "', self_hostname, '"}']);
        encode_obj = AES.new(aes_key, AES.MODE_CBC, aes_IV);
        spaces = 16 - len(obj_to_send) % 16;
        sock.send(bytes(aes_IV, 'utf-8') + encode_obj.encrypt(obj_to_send + (spaces * ' ')));
        rlist, wlist, elist = select.select([sock], [], [], SELECT_TIMEOUT * 10);
        val = '0';
        version = '';
        interface_knx = '';
        interface_enocean = '';
        data = sock.recv(4096);
        if data:
            decrypt_IV = data[:16].decode();
            decode_obj = AES.new(res[0][1], AES.MODE_CBC, decrypt_IV);
            data2 = decode_obj.decrypt(data[16:]).decode();
            resp = json.JSONDecoder().decode(data2);
            if str(self.aes_slave_keys[hostname]) == str(resp['aes_pass']):
                val = '1';
                version = resp['version'];
                interface_knx = resp['interface_knx'];
                interface_enocean = resp['interface_enocean'];
            connection.send(bytes(version, 'utf-8'));
        connection.close();
        query = ''.join(['UPDATE daemon SET validation=', val, ', version="', version, '" WHERE serial="', hostname, '"']);
        self.sql.mysql_handler_personnal_query(query, db);
        query = ''.join(['UPDATE daemon_protocol SET interface="', interface_knx, '" WHERE daemon_id="', str(json_obj['data']['daemon_id']), '" AND protocol_id="1"']);
        self.sql.mysql_handler_personnal_query(query, db);
        query = ''.join(['UPDATE daemon_protocol SET interface="', interface_enocean, '" WHERE daemon_id="', str(json_obj['data']['daemon_id']), '" AND protocol_id="2"']);
        self.sql.mysql_handler_personnal_query(query, db);
        sock.close();

    def get_secret_key(self, hostname):
        """
        Retrieves the secretkey of 'hostname' in the database.
        """
        query = ''.join(['SELECT serial, secretkey FROM daemon WHERE serial = \'', hostname, '\'']);
        res = self.sql.mysql_handler_personnal_query(query);
        for r in res:
            if r[0] == hostname:
                return str(r[1]);

    def send_mail(self, json_obj, connection, db):
        """
        Callback called each time a send_mail packet is received.
        The parameters are stored in 'json_obj'.
        """
        try:
            from_addr = formataddr((self.d3config['6'], self.d3config['5']));
            host = self.d3config['7'];
            secure = self.d3config['8']
            port = self.d3config['9'];
            username = self.d3config['10'];
            password = self.d3config['11'];
            msg = MIMEMultipart();
            mdr = json_obj['data']['object'];
            msg['Subject'] = json_obj['data']['object'];
            msg['From'] = from_addr;
            msg['To'] = json_obj['data']['destinator'];
            msg.attach(MIMEText(json_obj['data']['message']));
            server = smtplib.SMTP(host, port);
            if (secure == 2):
                server.ehlo();
                server.starttls();
                server.ehlo();
            if not username and not password:
                server.login(self.d3config['5'], username);
            server.sendmail(from_addr, json_obj['data']['destinator'], msg.as_string());
            server.quit();
            connection.close();
        except Exception as e:
            self.logger.error('Error for sending mail');
            self.logger.error(e);
            connection.send(bytes('Error', 'utf-8'));
            connection.close();

    def modif_datetime(self, json_obj, connection, db):
        os.system('date --set '+json_obj['data'][0]);
        os.system('date --set '+json_obj['data'][1]);

    def get_slave_name(self, json_obj, daemons):
        """
        Retrieves the hostname of the daemon described by 'json_obj' in the 'daemons' list.
        """
        daemon_found = False;
        slave_name = '';
        for d in daemons:
            if int(json_obj['data']['daemon']) == int(d[0]):
                daemon_found = True;
                slave_name = str(d[2]);
                break;
        if daemon_found is False:
            frameinfo = getframeinfo(currentframe());
            self.logger.error('in get_slave_name: '+str(json_obj['data']['daemon']));
            return None;
        if str(json_obj['data']['addr']).count('/') != 2:
            frameinfo = getframeinfo(currentframe());
            self.logger.error('in get_slave_name: '+str(json_obj['data']['addr']));
            return None;
        return slave_name;

    def reload_web_server(self):
        """
        Call "service reload nginx"
        """
        self.logger.debug('Reloading web server...');
        call(["service", "nginx", "reload"]);
        self.logger.debug('[ OK ] Done reloading web server.');

    def smartcmd_launch(self, json_obj, connection, db):
        s = Smartcommand(self, int(json_obj['data']))
        s.setValues(connection);
        s.start();

    def triggers_list_update(self, json_obj, connection, db):
        self.trigger.update_triggers_list(db);

    def schedules_list_update(self, json_obj, connection, db):
        self.schedule.update_schedules_list(db);

    def scenarios_list_update(self, json_obj, connection, db):
        self.scenario.update_scenarios_list(db);

    def check_schedules(self, json_obj, connection, db):
        self.schedule.check_all_schedules(connection);

    def launch_calc_logs(self, json_obj, connection, db):
        try:
            self.calcLogs.sort_logs(connection, db);
        except Exception as e:
            self.logger.error(e);

    def get_global_state(self, db):
        query = 'SELECT room_device_id, option_id, opt_value FROM room_device_option';
        res = self.sql.mysql_handler_personnal_query(query, db);
        filtered = [];
        append = filtered.append;
        for elem in res:
            if elem[2]:
                append(elem);
        global_state = [];
        if filtered:
            global_state = filtered;
        else:
            global_state = '';
        return global_state;

    def send_tech(self, json_obj, connection, db):
        query = 'SELECT configuration_value FROM configuration WHERE configuration_id=1';
        http = self.sql.mysql_handler_personnal_query(query, db);
        query = 'SELECT configuration_value FROM configuration WHERE configuration_id=2';
        ssl = self.sql.mysql_handler_personnal_query(query, db);
        json_obj['info']['http'] = http[0][0];
        json_obj['info']['ssl']  = ssl[0][0];
        self.send_request(json_obj, connection, db)

    def send_request(self, json_obj, connection, db):
        if self._parser.getValueFromSection('greenleaf', 'commercial') == "1":
            admin_addr = self._parser.getValueFromSection('greenleaf', 'admin_addr')
            hostname = socket.gethostname()
            GLManager.SendRequest(str(json_obj), admin_addr, self.get_secret_key(hostname))

    def send_interfaces(self, json_obj, connection, db):
        query = ''.join(["SELECT serial, secretkey FROM daemon WHERE daemon_id=", str(json_obj['data']['daemon_id'])]);
        res = self.sql.mysql_handler_personnal_query(query, db);
        if res is None or not res:
            self.logger.error('in send_interfaces: No daemon for id '+str(json_obj['data']['daemon_id']));
            connection.close();
            return ;
        elif len(res) > 1:
            self.logger.error('in send_interfaces: Too much daemons for id '+str(json_obj['data']['daemon_id']));
            connection.close();
            return ;
        hostname = res[0][0];
        ip = '';
        for h in self.hostlist:
            if hostname in h._Hostname.upper():
                ip = h._IpAddr;
        if not ip:
            self.logger.error('in send_interfaces: '+hostname+' not in hostlist. Try perform network scan again.');
            connection.close();
            return ;
        port = self._parser.getValueFromSection('connect', 'port');
        sock = socket.create_connection((ip, port));
        self_hostname = socket.gethostname();
        if '.' in self_hostname:
            self_hostname = self_hostname.split('.')[0];
        aes_IV = AESManager.get_IV();
        aes_key = self.get_secret_key(hostname);
        obj_to_send = json.JSONEncoder().encode(
            {
                "packet_type": "send_interfaces", 
                "sender_name": self_hostname,
                "interface_knx": json_obj['data']['interface_knx'],
                "interface_EnOcean": json_obj['data']['interface_EnOcean'],
                "interface_arg_knx": json_obj['data']['interface_arg_knx'],
                "interface_arg_EnOcean": json_obj['data']['interface_arg_EnOcean'],
                "daemon_knx": json_obj['data']['daemon_knx']
            }
        );
        encode_obj = AES.new(aes_key, AES.MODE_CBC, aes_IV);
        spaces = 16 - len(obj_to_send) % 16;
        sock.send(bytes(aes_IV, 'utf-8') + encode_obj.encrypt(obj_to_send + (spaces * ' ')));
        rlist, wlist, elist = select.select([sock], [], [], SELECT_TIMEOUT * 300);
        re = '';
        data = sock.recv(4096);
        if data:
            decrypt_IV = data[:16].decode();
            host = None;
            for h in self.hostlist:
                if h._IpAddr == ip:
                    host = h;
            decode_obj = AES.new(res[0][1], AES.MODE_CBC, decrypt_IV);
            data2 = decode_obj.decrypt(data[16:]).decode();
            resp = json.JSONDecoder().decode(data2);
            hostname = host._Hostname;
            if '.' in host._Hostname:
                hostname = host._Hostname.split('.')[0];
            if str(self.aes_slave_keys[hostname]) == str(resp['aes_pass']):
                re = '1';
            connection.send(bytes(re, 'utf-8'));
        connection.close();
        sock.close();

    def shutdown_d3(self, json_obj, connection, db):
        """
        Asks "shutdown_d3" to the slave described in json_obj for shutdown daemon.
        """
        query = ''.join(["SELECT serial, secretkey FROM daemon WHERE daemon_id=", str(json_obj['data']['daemon_id'])]);
        res = self.sql.mysql_handler_personnal_query(query, db);
        if res is None or not res:
            self.logger.error('in shutdown_d3: No daemon for id '+str(json_obj['data']['daemon_id']));
            connection.close();
            return ;
        elif len(res) > 1:
            self.logger.error('in shutdown_d3: Too much daemons for id '+str(json_obj['data']['daemon_id']));
            connection.close();
            return ;
        hostname = res[0][0];
        ip = '';
        for h in self.hostlist:
            if hostname in h._Hostname.upper():
                ip = h._IpAddr;
        if not ip:
            self.logger.error('in shutdown_d3: '+hostname+' not in hostlist. Try perform network scan again.');
            connection.close();
            return ;
        port = self._parser.getValueFromSection('connect', 'port');
        sock = socket.create_connection((ip, port));
        self_hostname = socket.gethostname();
        if '.' in self_hostname:
            self_hostname = self_hostname.split('.')[0];
        aes_IV = AESManager.get_IV();
        aes_key = self.get_secret_key(hostname);
        obj_to_send = ''.join(['{"packet_type": "shutdown_d3", "sender_name": "', self_hostname, '"}']);
        encode_obj = AES.new(aes_key, AES.MODE_CBC, aes_IV);
        spaces = 16 - len(obj_to_send) % 16;
        sock.send(bytes(aes_IV, 'utf-8') + encode_obj.encrypt(obj_to_send + (spaces * ' ')));
        connection.close();
        sock.close();

    def reboot_d3(self, json_obj, connection, db):
        """
        Asks "reboot_d3" to the slave described in json_obj for reboot daemon.
        """
        query = ''.join(["SELECT serial, secretkey FROM daemon WHERE daemon_id=", str(json_obj['data']['daemon_id'])]);
        res = self.sql.mysql_handler_personnal_query(query, db);
        if res is None or not res:
            self.logger.error('in reboot_d3: No daemon for id '+str(json_obj['data']['daemon_id']));
            connection.close();
            return ;
        elif len(res) > 1:
            self.logger.error('in reboot_d3: Too much daemons for id '+str(json_obj['data']['daemon_id']));
            connection.close();
            return ;
        hostname = res[0][0];
        ip = '';
        for h in self.hostlist:
            if hostname in h._Hostname.upper():
                ip = h._IpAddr;
        if not ip:
            self.logger.error('in reboot_d3: '+hostname+' not in hostlist. Try perform network scan again.');
            connection.close();
            return ;
        port = self._parser.getValueFromSection('connect', 'port');
        sock = socket.create_connection((ip, port));
        self_hostname = socket.gethostname();
        if '.' in self_hostname:
            self_hostname = self_hostname.split('.')[0];
        aes_IV = AESManager.get_IV();
        aes_key = self.get_secret_key(hostname);
        obj_to_send = ''.join(['{"packet_type": "reboot_d3", "sender_name": "', self_hostname, '"}']);
        encode_obj = AES.new(aes_key, AES.MODE_CBC, aes_IV);
        spaces = 16 - len(obj_to_send) % 16;
        sock.send(bytes(aes_IV, 'utf-8') + encode_obj.encrypt(obj_to_send + (spaces * ' ')));
        connection.close();
        sock.close();

    def wifi_update(self, json_obj, connection, db):
        """
        Send "wifi_update" to the slave described in json_obj for update the wifi configuration.
        """
        query = ''.join(["SELECT serial, secretkey FROM daemon WHERE daemon_id=", str(json_obj['data']['daemon_id'])]);
        res = self.sql.mysql_handler_personnal_query(query, db);
        if res is None or not res:
            self.logger.error('in wifi_update: No daemon for id '+str(json_obj['data']['daemon_id']));
            connection.close();
            return ;
        elif len(res) > 1:
            self.logger.error('in wifi_update: Too much daemons for id '+str(json_obj['data']['daemon_id']));
            connection.close();
            return ;
        hostname = res[0][0];
        ip = '';
        for h in self.hostlist:
            if hostname in h._Hostname.upper():
                ip = h._IpAddr;
        if not ip:
            self.logger.error('in wifi_update: '+hostname+' not in hostlist. Try perform network scan again.');
            connection.close();
            return ;
        port = self._parser.getValueFromSection('connect', 'port');
        sock = socket.create_connection((ip, port));
        self_hostname = socket.gethostname();
        if '.' in self_hostname:
            self_hostname = self_hostname.split('.')[0];
        aes_IV = AESManager.get_IV();
        aes_key = self.get_secret_key(hostname);
        obj_to_send = ''.join(['{"packet_type": "wifi_update", "sender_name": "', str(self_hostname),
              '", "ssid": "', str(json_obj['data']['ssid']), '", "password": "******", "security": "', str(json_obj['data']['security']),
              '", "mode": "', str(json_obj['data']['mode']), '"}']);
        encode_obj = AES.new(aes_key, AES.MODE_CBC, aes_IV);
        spaces = 16 - len(obj_to_send) % 16;
        sock.send(bytes(aes_IV, 'utf-8') + encode_obj.encrypt(obj_to_send + (spaces * ' ')));
        rlist, wlist, elist = select.select([sock], [], [], SELECT_TIMEOUT * 300);
        re = '';
        for s in rlist:
            data = sock.recv(4096);
            if not data:
                continue;
            decrypt_IV = data[:16].decode();
            host = None;
            for h in self.hostlist:
                if h._IpAddr == ip:
                    host = h;
            decode_obj = AES.new(res[0][1], AES.MODE_CBC, decrypt_IV);
            data2 = decode_obj.decrypt(data[16:]).decode();
            resp = json.JSONDecoder().decode(data2);
            hostname = host._Hostname;
            if '.' in host._Hostname:
                hostname = host._Hostname.split('.')[0];
            if str(self.aes_slave_keys[hostname]) == str(resp['aes_pass']):
                re = '1';
            connection.send(bytes(re, 'utf-8'));
        connection.close();
        sock.close();
    
    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;
Beispiel #24
0
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();
Beispiel #25
0
class Schedule:

    ## The constructor
    #
    # @param daemon The daemon instanciating the class.
    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)

    ## Updates the schedule list from the database.
    #
    # @param db The database handler.
    # @return None
    def update_schedules_list(self, db):
        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 "
        )
        if not db:
            self.schedules_list = self.sql.mysql_handler_personnal_query(query)
        else:
            self.schedules_list = self.sql.mysql_handler_personnal_query(query, db)
        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 "
        )
        if not db:
            self.full_schedules_list = self.sql.mysql_handler_personnal_query(query)
        else:
            self.full_schedules_list = self.sql.mysql_handler_personnal_query(query, db)

    ## Retrieves schedule informations from its ID.
    #
    # @param id_schedule The ID of the schedule.
    #
    # @return Array containing the informations of the wanted schedule.
    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

    ## Tests the schedules and starts a scenario if the test is valid.
    #
    # @param connection Connection object.
    # @return None
    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)

    ## Tests if the schedule has to be started.
    #
    # @param id_schedule The ID of the schedule to test.
    #
    # @return 1 if the schedule has to be started, else 0.
    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

    ## Starts a scenario in the smart command.
    #
    # @param id_smartcmd The ID of the smartcommand from which start the scenario.
    # @param connection Connection object.
    # @return None
    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, 0)