#!/usr/bin/env python #-*- coding: iso8859-15 -*- ########################################################## # CONFIG SENALES v1.0 # ########################################################## # Autor: Juan Miguel Taboada Godoy # # Fecha: Malaga, 03 de agosto de 2006 # # Descripción: Fichero de configuración de senales # # Versión: 2006080300 # # # # Codigo fuente bajo licencia GNU/GPL # # Centrologic (Computational Logistic Center) # # http://www.centrologic.com - info@centrologic.com # ########################################################## # Librerias import MySQLdb import md5 # Get autoid {{{1 def autoid(db,name,debug=False): # Get database data (sql_host,sql_port,sql_socket,sql_user,sql_passwd,sql_db,sql_table)=db # Get composed name of signal md5check=md5.new(name).hexdigest() # Conecto a la BD if (debug): print "AUTOID: Abriendo la conexion SQL" try: # Control sobre autodetección del socket if (sql_socket=="auto"): # MySQL socket por defecto if (debug): print " Conectando con socket autoconfigurado (BDconnection)" BDconnection = MySQLdb.connect(host=sql_host,port=sql_port, user=sql_user, passwd=sql_passwd, db=sql_db) else: # MySQL socket definido en la configuración if (debug): print " Conectando con socket manual (BDconnection)" BDconnection = MySQLdb.connect(host=sql_host,port=sql_port, user=sql_user, passwd=sql_passwd, db=sql_db, unix_socket=sql_socket) # Activo el cursor if (debug): print " Cargando cursor (BD)" BD = BDconnection.cursor() except MySQLdb.OperationalError, message: raise IOError,"DB_MYSQL ERROR: Error número %d al conectar a la Base de Datos:\n%s" % (message[0],message[1]) # Creo y envío el query de consulta a la base de datos if (debug): print " Consultando ID (BD)" query="SELECT * FROM ids WHERE md5='%s'" % (md5check) if ((BD==None) or (BDconnection==None)): raise IOError,"DB_MYSQL: Se intentó un QUERY pero el sistema no esta correctamente conectado a la Base de Datos (%s)" % (query) try: BD.execute(query) DBresult=BD.rowcount except MySQLdb.OperationalError, message: raise IOError,"DB_MYSQL OPERATIONAL ERROR: Error %d: %s\n(QUERY: %s)" % (message[0],message[1],query) # Compruebo si hubo resultado, si no lo hubo, inserto el registro en la BD y vuelvo a consultar if (DBresult==0): if (debug): print " Insertando ID (BD)" # No hubo resultados de la busqueda, inserto el nuevo registro try: query="INSERT INTO ids (md5) VALUES ('%s')" % (md5check) BD.execute(query) except MySQLdb.OperationalError, message: # Error en la operación raise IOError,"DB_MYSQL OPERATIONAL ERROR: Error %d: %s\n(QUERY: %s)" % (message[0],message[1],query) # Creo y envio el query de consulta a la base de datos if (debug): print " Consultando de nuevo ID (BD)" query="SELECT * FROM ids WHERE md5='%s'" % (md5check) try: BD.execute(query) DBresult=BD.rowcount except MySQLdb.OperationalError, message: raise IOError,"DB_MYSQL OPERATIONAL ERROR: Error %d: %s\n(QUERY: %s)" % (message[0],message[1],query) # Extraigo el valor todos=BD.fetchall() unico=todos[0] id=unico[0] # Desconecto de la BD if (debug): print "AUTOID: Desconectando de la Base de Datos" try: if (BD!=None): if (debug): print " Cerrando cursor de la Base de Datos (BD)" BD.close() if (BDconnection!=None): if (debug): print " Cerrando conexion a la Base de Datos (BDconnection)" BDconnection.close() except Exception,e: raise IOError,"DB_MYSQL ERROR: al cerrar la conexión a la Base de Datos: %s" % (e[1]) # Devuelvo el valor return id # }}}1 # Clase para la gestión de señales ## Gestor de senales class SENALES: # Constructor ## Constructor: reconoce los Telemandos: \n ## - pesyr ## - momentum ## - netstatistics ## - web ## - advantech ## \param self - def __init__(self): # Datos de conexion a la Base de datos sql_host="localhost"# SQL: Host sql_port=3306 # SQL: Puerto sql_socket="auto" # SQL: Socket sql_user="likindoy" sql_passwd="likindoyclave" sql_db="likindoy_test" sql_table="ids" self.__db=(sql_host,sql_port,sql_socket,sql_user,sql_passwd,sql_db,sql_table) # Inicializa la lista de la clase self.__lista=[] # Inicializa el diccionario de filtros de la clase self.__filter={} self.__filter['enBD']=None # Inicializa el comprobador de datos self.__validIDs=True self.__validIDs_error=None # All config ## \internal ## \param self - ## \param confirmation Confirmation that we say to the library we know what we are doing def allconfig(self,confirmation=""): if (confirmation=="I know what I am doing"): dict={} dict["senales"]=self.__lista return dict else: raise IOError,"You can not get the list of signals without confirmation. Check source code for more information!" # Filter ## \internal ## \param self - ## \param enBD True, False or None (to limit or not limit the list of signals with enBD field) def filter(self,enBD=None): # Set filters self.__filter['enBD']=enBD ## \internal ## \param self - ## \param confirmation Confirmation that we say to the library we know what we are doing def list(self,confirmation=""): if (confirmation=="I know what I am doing"): return self.__lista else: raise IOError,"You can not get the list of signals without confirmation. Check source code for more information!" # Indica al sistema que los IDs no van a ser usados ## Indica al sistema que los IDs no van a ser usados ## \param self - def not_using_IDs(self): # Actualiza el valor de valid IDs a True self.__validIDs=True # Añade un elemento a la lista de la clase de señales (es un simple contenedor) ## Inserta una senal en la lista ## \param self - ## \param idsenal Valor numerico entero que indica el ID de la senal en la Base de Datos (no puede ser None, ni haber sido declarado anteriormente). Especialmente no se recomienda cambiar este numero una vez realizada una carga a la Base de Datos, debido a que este numero representa la relacion entre el conector fisico en el telemando y la linea logica en la grafica. Hacer cambios corrompe la Base de Datos si no se sabe lo que se hace. ## \param name Valor Alfanumerico que representan el nombre de la senal (no puede ser None, ni contener el caracter espacio, ni el caracter ':', ni haber sido declarado anteriormente) ## \param telemando Valor Alfanumerico que representa el nombre del Telemando ## \param descripcion Cadena de texto que representa la descripcion del Telemando ## \param enBD Indica si la senal debe cargarse a la BD o no ## \param conector Conector al que se relaciona esta senal (Ej: "ea0med","ea",cobertura,...)\n ## - En PESYR: \n ## - "ed": Entrada digital \n ## - "ea": Entrada analogica \n ## - "sd": Salida digutal o por rele \n ## - "be": Bits especiales \n ## - Bit 0: Alimentandose de bateria interna \n ## - Bit 1: Llave de servicio esta bloqueando la terminal \n ## - Bit 2: Modem mal configurado o baja cobertura \n ## - En SIGNALS: tiene el formato "XY:Z" \n ## - "X": Puede ser "ed", "sd", "ea" o "sa" \n ## - "Y": Pueder ser vacio (valor original), "med" (valor medio), "max" (valor maximo) o "min" (valor minimo). Las senales digitales no permiten "med", "max" o "min", por lo que este campo no se usa en las senales digitales. \n ## - "Z": Es la posicion de memoria en el Automatata \n ## - Excepciones en PESYR: Los telemandos de tipo L3 son distintos a los L6 en el numero de entradas digitales. \n ## - L3: Su numero de serie comienza con IA y siguen el esquema de numeracion 4xxxx. Estos Telemandos tienen 16 entradas digitales y sus entradas estan nombradas segun el siguiente patron:\n ## El bit 0 es llamado en el software de PESYR: 0 \n ## El bit 1 es llamado en el software de PESYR: 1 \n ## ... \n ## El bit 7 es llamado en el software de PESYR: 7 \n ## El bit 8 es llamado en el software de PESYR: A \n ## ... \n ## El bit 14 es llamado en el software de PESYR: G \n ## El bit 15 es llamado en el software de PESYR: H \n ## \n ## - L6: Su numero de serie comienza con IB y siguen el esquema de numeracion 5xxxx. Estos Telemandos tienen 8 entradas digitales y sus entradas estan nombradas segun el siguiente patron:\n ## El bit 0 es llamado en el software de PESYR: A \n ## El bit 1 es llamado en el software de PESYR: B \n ## ... \n ## El bit 6 es llamado en el software de PESYR: G \n ## El bit 8 es llamado en el software de PESYR: H.\n ## \n ## - Deduccion: Cuando hablamos del bit C depende de si estamos hablando de un L3 (que seria el bit 10) o si hablamos de un L6 (que seria el bit 2). Este error es un problema de diseno en el software de PESYR y no se ha solucionado en Grafista pues seria inducir un error en Grafista tambien, es por esta razon que se explica aqui su funcionamiento, para que el usuario conozca que el software esta cometiendo el error en el nombramiento. ## \param tiposenal Indica si la senal es 'a' analogica o 'd' digital ## \param frecuencia Frecuencia de muestreo de la senal (en segundos) ## \param param1 PESYR: En senales digitales indica a que bit responde la senal (por defecto es el bit 0)\n ## MOMENTUM: En senales analogicas indica el rango logico que se usara para convertir la senal fisica recibida del automata ## \param param2 PESYR: En senales digitales indica el algoritmo de conversion de cadenas a series de bits (por defecto es 'hex')\n ## MOMENTUM: En senales analogicas indica al rango fisico recibido del automata para hacer la conversion fisico-logica ## \exception IOError Cuando se produce algun error def add(self,idsenal,name,telemando,descripcion,enBD,conector,tiposenal,frecuencia,param1=None,param2=None): # Control de errores if (idsenal==None): raise IOError,"ID es nulo. Encontrado en telemando '%s' senal '%s'." % (telemando,name) if (type(idsenal)!=type(1)): raise IOError,"ID no es un numero. Encontrado en telemando '%s' senal '%s'." % (telemando,name) if (name==None): raise IOError,"El ID de la senal es nulo. Encontrado en telemando '%s'." % (telemando) if (len(name.split(" "))>1): raise IOError,"El ID de la senal no puede contener el caracter espacio. Encontrado '%s' en telemando '%s'." % (name,telemando) if (len(name.split(":"))>1): raise IOError,"El ID de la senal no puede contener el caracter ':'. Encontrado '%s' en telemando '%s'." % (name,telemando) # Obtengo el id real del telemando (si ningun ID anterior fallo y tengo acceso a la base de datos) validID=True isAutoID=False if (self.__validIDs): # Si todos los IDs son validos, intento obtener el ID if (idsenal==0): try: idsenal=autoid(self.__db,name) isAutoID=True except Exception,error: # El ID no es valido validID=False # Anoto que se van a almacenar IDs no validos en la lista self.__validIDs=False # Anoto el error producido al obtener el AutoID self.__validIDs_error=error else: # Si algun ID no es valido, validID=(idsenal!=0) # Busco el id del telemando if (validID): # Dejo el ID recibido id=idsenal else: # Si el ID no es valido lo pongo a None id=-1 # Comprueba que no existe el ID ni el ALFANUM for elemento in self.__lista: # Si el ID es valido lo compruebo if ((validID) and (elemento[0]==id)): raise IOError,"El ID '%s' ya ha sido declarado anteriormente (primer parametro)" % (idsenal) # Compruebo el ALFANUM if (elemento[1]==name): raise IOError,"El ALFANUM '%s' ya ha sido declarado anteriormente (segundo parametro)" % (name) # Carga los datos a la lista self.__lista.append((id,name,telemando,descripcion,enBD,tiposenal,conector,param1,param2,frecuencia)) # Busca una senal en la lista y la devuelve ## \internal ## Busca una senal en la lista de senales (es necesario el id o el nombre) ## \param self - ## \param id Identificador de la senal (valor numerico entero) ## \param nombre Nombre de la senal (valor alfanumerico) ## \return Devuelve una tupla con los datos encontrados sobre una senal def search(self,id=None,nombre=None): # Compruebo si todos los IDs son correctos if (not self.__validIDs): raise IOError,"ERROR: Se han almacenado IDs no validos en la lista. ERROR: %s" % (self.__validIDs_error) # Si no hay nada que buscar if ((id==None) and (nombre==None)): # Devuelve que no se encontro nada return (None,None,None,None,None,None,None,None) # Busca la senal por el ID for senal in self.__lista: # Recojo los datos (senalid,name,telemando,descripcion,enBD,tiposenal,conector,param1,param2,frecuencia)=senal # Control de filtros if ((self.__filter['enBD']==None) or (self.__filter['enBD']==enBD)): # Si el ID o el NOMBRE son encontrados if (((id!=None) and (id==senalid)) or ((nombre!=None) and (nombre==name))): # Devuelve el par encontrado return (senalid,name,telemando,descripcion,tiposenal,conector,param1,param2) # No encontrado return (None,None,None,None,None,None,None,None) # Busca una senal en la lista y devuelve su frecuencia ## \internal ## Busca una senal en la lista de senales y devuelve su frecuencia (es necesario el id o el nombre) ## \param self - ## \param id Identificador de la senal (valor numerico entero) ## \param nombre Nombre de la senal (valor alfanumerico) ## \return Devuelve la frecuencia de muestreo (en segundos) de una senal def search_freq(self,id=None,nombre=None): # Compruebo si todos los IDs son correctos if (not self.__validIDs): raise IOError,"ERROR: Se han almacenado IDs no validos en la lista. ERROR: %s" % (self.__validIDs_error) # Si no hay nada que buscar if ((id==None) and (nombre==None)): # Devuelve que no se encontro nada return None # Busca la senal por el ID for senal in self.__lista: # Recojo los datos (senalid,name,telemando,descripcion,enBD,tiposenal,conector,param1,param2,frecuencia)=senal # Control de filtros if ((self.__filter['enBD']==None) or (self.__filter['enBD']==enBD)): # Si el ID o el NOMBRE son encontrados if (((id!=None) and (id==senalid)) or ((nombre!=None) and (nombre==name))): # Devuelve el par encontrado return frecuencia # No encontrado return None # Busca las senales de un Telemando ## \internal ## Devuelve una lista de senales de un Telemando concreto ## \param self - ## \param telemando Valor Alfanumerico del Telemando ## \return Lista de senales que pertenencen a un Telemando concreto def search_tele(self,telemando=None): # Compruebo si todos los IDs son correctos if (not self.__validIDs): raise IOError,"ERROR: Se han almacenado IDs no validos en la lista. ERROR: %s" % (self.__validIDs_error) # Inicializo valores lista=[] # Si no hay nada que buscar if (telemando==None): # Devuelve que no se encontro nada return lista # Busca la senal por el ID for senal in self.__lista: # Recojo los datos (senalid,name,senaltelemando,descripcion,enBD,tiposenal,conector,param1,param2,frecuencia)=senal # Control de filtros if ((self.__filter['enBD']==None) or (self.__filter['enBD']==enBD)): # Si el telemando existe if (telemando==senaltelemando): # Devuelve el par encontrado lista.append((senalid,name,senaltelemando,descripcion,tiposenal,conector,param1,param2)) # No encontrado return lista # ### EXCEPCIONES ### ################################# # EXCEPTION CLASSES {{{1 # Excepciones básicas # Except (General Exception) {{{2 class Except(Exception): def __init__(self,string): self.string=string def __str__(self): return self.string #}}}2 # IOError (Error de entrada/salida) {{{2 class IOError(Exception): def __init__(self,string): self.string=string def __str__(self): return self.string # }}}2 # ConnectionError (Error de conexion) {{{2 class ConnectionError(Exception): def __init__(self,string): self.string=string def __str__(self): return self.string # }}}2 # }}}1 # Creo el objeto para que sea usado s=SENALES()