From 5ea494e6451c27b15b59330c78453fbbc34467b3 Mon Sep 17 00:00:00 2001 From: Vincent BENOIT Date: Tue, 15 Nov 2022 11:06:04 +0100 Subject: [PATCH] =?UTF-8?q?copie=20d'une=20base=20de=20donn=C3=A9es=20vier?= =?UTF-8?q?ge=20et=20conforme=20si=20elle=20n'existe=20pas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/intercom.py | 173 ++++++++++++++++++++++++++++-------------------- 1 file changed, 102 insertions(+), 71 deletions(-) diff --git a/src/intercom.py b/src/intercom.py index 459dba0..72a440c 100644 --- a/src/intercom.py +++ b/src/intercom.py @@ -3,7 +3,7 @@ # @author: benoit.vince84@free.fr # @date: Septembre 2022 -# @brief: Programme Intercom à partir du module GSM du GNSS_HAT +# @brief: Programme Intercom à partir du module GSM ################################################################### # Importation de modules externes # @@ -16,8 +16,9 @@ import RPi.GPIO as GPIO from datetime import datetime, date import calendar import json -from jsonschema import validate +import jsonschema import socket +import shutil from signal import signal, SIGINT from threading import Thread from apscheduler.schedulers.background import BackgroundScheduler @@ -26,54 +27,65 @@ from apscheduler.schedulers.background import BackgroundScheduler # Class et Methods # def validate_json(json_data={}, logger=None): - ''' Validate json by schema + ''' Validate json database by schema :param json_data: json data loaded :param logger: - werkzeug context + logger object - :return int: - 0 => If validates with 2.0 - 1 => otherwise + :return bool: + True if OK, otherwise False ''' + if not isinstance(logger, log.Logger): + return False if not isinstance(json_data, dict): logger.error("error parameter, expecting dict, get {}".format(type(json_data))) return False - if not isinstance(logger, log.Logger): - logger.error("error parameter, expecting logging.Logger, get {}".format(type(logger))) - return False ret = True try: with open(os.path.join('/home/pi', 'db.json.schema'), 'r') as f: schema=json.load(f) - try: - validate(instance=json_data, schema=schema) - except jsonschema.exceptions.ValidationError as e: - logger.error("Validator error") - ret = False - except jsonschema.exceptions.SchemaError as e: - logger.error("Schema error") - ret = False except FileNotFoundError as e: logger.error("Impossible d'ouvrir le fichier de validation ({})".format(e)) ret = False + + try: + jsonschema.validate(instance=json_data, schema=schema) + except jsonschema.exceptions.ValidationError as e: + logger.error("Erreur de validation de la base de données : {}".format(e)) + ret = False + except jsonschema.exceptions.SchemaError as e: + logger.error("Erreur de schéma : {}".format(e)) + ret = False return ret def get_conf(logger=None): ''' Get configuration + :param logger: + logger object + :return dict: Configuration dictionnary ''' if not isinstance(logger, log.Logger): - logger.error("error parameter, expecting logging.Logger, get {}".format(type(logger))) return None config = None + + # copy database if not exists + if not os.path.exists(os.path.join("/etc/kineintercom", "db.json")): + logger.warning("Le fichier de la base de données n'existe pas ...") + try: + shutil.copyfile(os.path.join("/usr/share/kineintercom", "database_origin.json"), + os.path.join("/etc/kineintercom", "db.json")) + except PermissionError as e: + logger.error("Erreur de permission: {}".format(e)) + return None try: with open(os.path.join("/etc/kineintercom", "db.json"), 'r') as f: try: @@ -100,7 +112,7 @@ def send_at_cmd(cmd='', timeout=0.0, serObj=None, logger=None): :param serObj: serial object - :param log: + :param logger: logger object :return int: @@ -121,7 +133,7 @@ def send_at_cmd(cmd='', timeout=0.0, serObj=None, logger=None): try: if timeout > 0.0: - serObj.timeout = timeout + serObj.timeout = timeout + 0.1 else: serObj.timeout = None serObj.write(bytes(cmd+'\r', 'utf-8')) @@ -129,19 +141,12 @@ def send_at_cmd(cmd='', timeout=0.0, serObj=None, logger=None): out = '' outlst = [] while serObj.in_waiting > 0: - #c = serObj.read(1).decode('utf-8', 'replace') - #if c == '\r' or c == '\n': - # if out != '': - # outlst.append(out) - # out = '' - #else: - # out += c - # remove \r and \n chars from out string out += serObj.read_until().decode('utf-8', 'replace').replace('\r','').replace('\n','') if out != '': outlst.append(out) out = '' + time.sleep(timeout) logger.debug("Reponse: {}".format(outlst)) if 'OK' in outlst: return 0, outlst @@ -162,16 +167,23 @@ def send_at_cmd(cmd='', timeout=0.0, serObj=None, logger=None): def set_sim_pin(serObj=None, pin_actif=False, code_pin="", logger=None): ''' Set SIM PIN if necessary + + AT+CPIN= : Enter PIN (response READY: MT is not pending for any password) + :param serObj: serial object - :param config: - dictionary config object from JSON database + :param pin_actif: + attribute from dictionary config object + + :param code_pin: + attribute from dictionary config object :param log: logger object :return bool: + True if OK, otherwise False ''' if not isinstance(logger, log.Logger): return False @@ -196,28 +208,30 @@ def set_sim_pin(serObj=None, pin_actif=False, code_pin="", logger=None): elif ret == 1: logger.warning("Timeout avec la commande AT: {}".format('AT+CPIN?')) else: - if rsp[1].split('+CPIN: ')[1] == 'SIM PIN': - logger.info('SIM verrouillée ...') - # Must enter SIM PIN - if not pin_actif: - logger.error("Configuration en conflit avec la réponse du module GSM") - return False - else: - # Enter the SIM PIN configured in database - ret, rsp = send_at_cmd(cmd='AT+CPIN='+code_pin, - timeout=0.0, - serObj=serObj, - logger=logger) - if ret == 2: - logger.error("Erreur avec la commande AT: {}".format('AT+CPIN=')) - return False - elif ret == 1: - logger.warning("Timeout avec la commande AT: {}".format('AT+CPIN=')) - else: - logger.info("code PIN saisi ...") - elif rsp[1].split('+CPIN: ')[1] == 'READY': - # SIM PIN already notified - logger.info('SIM déverrouillée ...') + for item in rsp: + if item.startswith('+CPIN:'): + if item.split('+CPIN: ')[1] == 'SIM PIN': + logger.info('SIM verrouillée ...') + # Must enter SIM PIN + if not pin_actif: + logger.error("Configuration en conflit avec la réponse du module GSM") + return False + else: + # Enter the SIM PIN configured in database + ret, _ = send_at_cmd(cmd='AT+CPIN='+code_pin, + timeout=2.0, + serObj=serObj, + logger=logger) + if ret == 2: + logger.error("Erreur avec la commande AT: {}".format('AT+CPIN=')) + return False + elif ret == 1: + logger.warning("Timeout avec la commande AT: {}".format('AT+CPIN=')) + else: + logger.info("code PIN validé ...") + elif item.split('+CPIN: ')[1] == 'READY': + # SIM PIN already notified + logger.info('SIM déverrouillée ...') return True @@ -227,15 +241,11 @@ def init_gsm_com(serObj=None, config={}, logger=None): AT : test command ATE1 : AT+CMEE=2 : - AT+CPIN? : Enter PIN (response READY: MT is not pending for any password - AT+CREG? : Network registration - return the status of result code - AT+CSQ : AT+CLTS=1 : AT+CMGF=1 : Set the format of messages to Text mode AT+CLIP=1 : The calling line identifty (CLI) of calling party when receiving a mobile terminated call AT+VTD=1 : Tone Duration (in 1/10 seconds) - ATS0=2 : Set Number of Ring before Automatically Answering the call :param serObj: serial object @@ -247,6 +257,7 @@ def init_gsm_com(serObj=None, config={}, logger=None): logger object :return bool: + True if OK, otherwise False ''' if not isinstance(logger, log.Logger): return False @@ -288,11 +299,11 @@ def update_gsm_com(serObj=None, config={}, logger=None): :param config: dictionary config object from JSON database - :param log: + :param logger: logger object :return bool: - True if ok, otherwise False + True if OK, otherwise False ''' if not isinstance(logger, log.Logger): return False @@ -322,7 +333,7 @@ def info_gsm_com(serObj=None, config={}, logger=None): :param config: dictionary config object from JSON database - :param log: + :param logger: logger object :return bool: @@ -442,22 +453,21 @@ def verify_caller(buf="", num="", logger=None): :param num: Caller phone number - :param log: + :param logger: logger object :return bool: True if authorized, False otherwise ''' + if not isinstance(logger, log.Logger): + return False, "" if not isinstance(buf, str): logger.error("error parameter, expecting str, get {}".format(type(buf))) return False, "" if not isinstance(num, str): logger.error("error parameter, expecting str, get {}".format(type(num))) return False, "" - if not isinstance(logger, log.Logger): - logger.error("error parameter, expecting logging.Logger, get {}".format(type(logger))) - return False, "" outlst = buf[7:].split(',') logger.debug("=> {}".format(outlst)) @@ -469,6 +479,12 @@ def verify_caller(buf="", num="", logger=None): def listener(sock, logger): ''' Thread socket listener + + :param sock: + socket object + + :param logger: + logger object ''' global FLAG_CONF_UPDATE @@ -509,13 +525,13 @@ def listener(sock, logger): logger.debug("Fin du serveur de communication") return -def verify_open_hours(conf=None, logger=None): +def verify_open_hours(conf={}, logger=None): ''' Verify if GSM HAT must be opened with conf hours :param conf: configuration object - :param log: + :param logger: logger object :return bool: @@ -523,6 +539,9 @@ def verify_open_hours(conf=None, logger=None): ''' if not isinstance(logger, log.Logger): return False + if not isinstance(conf, dict): + logger.error("error parameter, expecting dict, get {}".format(type(conf))) + return False flag = False my_date = date.today() @@ -542,6 +561,9 @@ def verify_open_hours(conf=None, logger=None): def init_module(): ''' initialisation of GNSS/GPS/GSM HAT Module + + :return bool: + True if OK, otherwise False ''' try: GPIO.setmode(GPIO.BOARD) @@ -553,6 +575,9 @@ def init_module(): def setup_module(): ''' Setup module (Set/Reset) + + :return bool: + True if OK, otherwise False ''' while True: try: @@ -565,9 +590,18 @@ def setup_module(): #GPIO.cleanup() return True -def cron_verify_hours(op=None, config=None, logger=None): +def cron_verify_hours(op='', config=None, logger=None): ''' cron job to check opened or closed hours ''' + if not isinstance(logger, log.Logger): + return + if not isinstance(config, dict): + logger.error("error parameter, expecting dict, get {}".format(type(config))) + return + if not isinstance(op, str): + logger.error("error parameter, expecting str, get {}".format(type(op))) + return + global GSM_MODULE_STATE global GSM_MODULE_INIT_STATE if op == 'Horaires': @@ -678,7 +712,7 @@ def main(): hl = log.FileHandler(os.path.join('/var/log/KineIntercom','Intercom.log')) fl.setLevel(log.DEBUG) hl.setLevel(log.INFO) - formatter = log.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + formatter = log.Formatter('%(asctime)s - %(funcName)s - %(levelname)s - %(message)s') fl.setFormatter(formatter) hl.setFormatter(formatter) logger.addHandler(fl) @@ -773,9 +807,6 @@ def main(): else: GSM_MODULE_INIT_STATE = True - sys.exit(0) - - # Retreive GSM infos logger.info('Récupération des infos du module ...') ret = info_gsm_com(serObj=ser, config=config, logger=logger)