Teleinfoserial mysql.c

De MicElectroLinGenMet.

(Redirigé depuis Teleinfomysql-wrt54gl.c)

Origine page Interface téléinfo. piloté par un WRT54GL

Voir la table MySql Téléinfo: Structure de la table Teleinfo



/*       teleinfoserial_mysql.c										*/
/* Version pour PC et wrt54gl										*/
/* Lecture données Téléinfo et enregistre données sur base mysql vesta si ok sinon dans fichier csv.	*/
/* Connexion par le port série du Wrt54gl (Console désactivée dans inittab.)				*/
/* Vérification checksum données téléinfo et boucle de 3 essais si erreurs.				*/
/* Par domos78 at free point fr										*/
 
/*
Paramètres à adapter: 
- Port série à modifier en conséquence avec SERIALPORT.
- Nombre de valeurs à relever: NB_VALEURS + tableaux "etiquettes" et "poschecksum" à modifier selon abonnement (ici triphasé heures creuses).
- Paramètres Mysql (Serveur, Base, table et login/password)
- Autorisé le serveur MySql à accepter les connexions distantes pour le Wrt54gl.
 
Compilation PC:  
- gcc -Wall teleinfoserial_mysql.c -o teleinfoserial_mysql -lmysqlclient
 
Compilation wrt54gl: 
- avec le SDK (OpenWrt-SDK-Linux).
 
Résultat pour les données importantes dans la base MySql du serveur distant:
dan@vesta:~$ bin/listdatateleinfo.sh
timestamp       date            heure           hchp    hchc    ptec    inst1   inst2   inst3   papp
1222265525      24/09/2008      16:12:05        8209506 8026019 HP      1       0       1       460
1222265464      24/09/2008      16:11:04        8209499 8026019 HP      1       0       1       460
1222265405      24/09/2008      16:10:05        8209493 8026019 HP      1       0       1       390
1222265344      24/09/2008      16:09:04        8209487 8026019 HP      1       0       1       390
1222265284      24/09/2008      16:08:04        8209481 8026019 HP      1       0       1       390
1222265225      24/09/2008      16:07:05        8209476 8026019 HP      1       0       1       390
1222265164      24/09/2008      16:06:04        8209470 8026019 HP      1       0       1       390
1222265105      24/09/2008      16:05:05        8209464 8026019 HP      1       0       1       390
 
Résultat en mode DEBUG:
root@wrt54gl:~# ./teleinfoserial_mysql
----- 2008-10-12 15:59:52 -----
ADCO='70060936xxxx'
OPTARIF='HC..'
ISOUSC='20'
HCHP='008444126'
HCHC='008228815'
PTEC='HP'
IINST1='002'
IINST2='000'
IINST3='001'
IMAX1='011'
IMAX2='020'
IMAX3='019'
PMAX='07470'
PAPP='00610'
HHPHC='E'
MOTDETAT='000000'
PPOT='00'
ADIR1=''
ADIR2=''
ADIR3=''
*/
 
//-----------------------------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <syslog.h>
#include <termios.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <mysql/mysql.h>
 
// Define port serie
#define BAUDRATE B1200
#define SERIALPORT "/dev/tts/0"
 
// Define mysql
#define MYSQL_HOST "SQLSERVEUR"
#define MYSQL_DB "BASE"
#define MYSQL_TABLE "TABLE"
#define MYSQL_LOGIN "SQLLOGIN"
#define MYSQL_PWD "SQLPASSWD"
 
// Fichier local au Wrt4gl/PC + fichier trame pour debug.
#define DATACSV "/tmp/teleinfosql.csv"
#define TRAMELOG "/tmp/teleinfotrame."
 
// Active mode debug.
#define DEBUG
 
//-----------------------------------------------------------------------------
 
// Déclaration pour le port série.
int             fdserial ;
struct termios  termiosteleinfo ;
 
// Déclaration pour les données.
char ch[2] ;
char car_prec ;
char message[512] ;
char* match;
int id ;
char datateleinfo[512] ;
 
/// Constantes/Variables à changées suivant abonnement, Nombre de valeurs, voir tableau "etiquettes", 20 pour abonnement tri heures creuse.
#define NB_VALEURS 20
char etiquettes[NB_VALEURS][16] = {"ADCO", "OPTARIF", "ISOUSC", "HCHP", "HCHC", "PTEC", "IINST1", "IINST2", "IINST3", "IMAX1", "IMAX2", "IMAX3", "PMAX", "PAPP", "HHPHC", "MOTDETAT", "PPOT", "ADIR1", "ADIR2" ,"ADIR3"} ;
// Fin Constantes/variables à changées suivant abonnement.
 
char 	valeurs[NB_VALEURS][18] ;
char 	checksum[255] ;
int 	res ;
int	no_essais = 1 ;
int	nb_essais = 3 ;
int	erreur_checksum = 0 ;
 
// Déclaration pour la date.
time_t 		td;
struct 	tm 	*dc;
char		sdate[12];
char		sheure[10];
char		timestamp[11];
 
/*------------------------------------------------------------------------------*/
/* Init port rs232								*/
/*------------------------------------------------------------------------------*/
int initserie(void)
// Mode Non-Canonical Input Processing, Attend 1 caractère ou time-out(avec VMIN et VTIME).
{
	int device ;
 
        // Ouverture de la liaison serie (Nouvelle version de config.)
        if ( (device=open(SERIALPORT, O_RDWR | O_NOCTTY)) == -1 ) 
	{
                syslog(LOG_ERR, "Erreur ouverture du port serie %s !", SERIALPORT);
                exit(1) ;
        }
 
        tcgetattr(device,&termiosteleinfo) ;				// Lecture des parametres courants.
 
	cfsetispeed(&termiosteleinfo, BAUDRATE) ;			// Configure le débit en entrée/sortie.
	cfsetospeed(&termiosteleinfo, BAUDRATE) ;
 
	termiosteleinfo.c_cflag |= (CLOCAL | CREAD) ;			// Active réception et mode local.
 
	// Format série "7E1"
	termiosteleinfo.c_cflag |= PARENB  ;				// Active 7 bits de donnees avec parite pair.
	termiosteleinfo.c_cflag &= ~PARODD ;
	termiosteleinfo.c_cflag &= ~CSTOPB ;
	termiosteleinfo.c_cflag &= ~CSIZE ;
	termiosteleinfo.c_cflag |= CS7 ;
 
	termiosteleinfo.c_iflag |= (INPCK | ISTRIP) ;			// Mode de control de parité.
 
	termiosteleinfo.c_cflag &= ~CRTSCTS ;				// Désactive control de flux matériel.
 
	termiosteleinfo.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;	// Mode non-canonique (mode raw) sans echo.
 
	termiosteleinfo.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL) ;	// Désactive control de flux logiciel, conversion 0xOD en 0x0A.
 
	termiosteleinfo.c_oflag &= ~OPOST ;				// Pas de mode de sortie particulier (mode raw).
 
	termiosteleinfo.c_cc[VTIME] = 80 ;  				// time-out à ~8s.
	termiosteleinfo.c_cc[VMIN]  = 0 ;   				// 1 car. attendu.
 
	tcflush(device, TCIFLUSH) ;					// Efface les données reçues mais non lues.
        tcsetattr(device,TCSANOW,&termiosteleinfo) ;			// Sauvegarde des nouveaux parametres
	return device ;
}
 
/*------------------------------------------------------------------------------*/
/* Lecture données téléinfo sur port série					*/
/*------------------------------------------------------------------------------*/
void LiTrameSerie(int device)
{
// (0d 03 02 0a => Code fin et début trame)
	tcflush(device, TCIFLUSH) ;			// Efface les données non lus en entrée.
	message[0]='\0' ;
	memset(valeurs, 0x00, sizeof(valeurs)) ; 
 
	do
	{
		car_prec = ch[0] ;
		res = read(device, ch, 1) ;
		if (! res)
		{	
			syslog(LOG_ERR, "Erreur pas de réception début données Téléinfo !\n") ;
			close(device);
			exit(1) ;
		}
	 }
	while ( ! (ch[0] == 0x02 && car_prec == 0x03) ) ;	// Attend code fin suivi de début trame téléinfo .
 
	do
	{
		res = read(device, ch, 1) ;
		if (! res)
		{	
			syslog(LOG_ERR, "Erreur pas de réception fin données Téléinfo !\n") ;
			close(device);
			exit(1) ;
		}
		ch[1] ='\0' ;
		strcat(message, ch) ;
	}
	while (ch[0] != 0x03) ;				// Attend code fin trame téléinfo.
}
 
/*------------------------------------------------------------------------------*/
/* Test checksum d'un message (Return 1 si checkum ok)				*/
/*------------------------------------------------------------------------------*/
int checksum_ok(char *etiquette, char *valeur, char checksum) 
{
	unsigned char sum = 32 ;		// Somme des codes ASCII du message + un espace
	int i ;
 
	for (i=0; i < strlen(etiquette); i++) sum = sum + etiquette[i] ;
	for (i=0; i < strlen(valeur); i++) sum = sum + valeur[i] ;
	sum = (sum & 63) + 32 ;
	if ( sum == checksum) return 1 ;	// Return 1 si checkum ok.
	#ifdef DEBUG
		syslog(LOG_INFO, "Checksum lu:%02x   calculé:%02x", checksum, sum) ;
	#endif
	return 0 ;
}
 
/*------------------------------------------------------------------------------*/
/* Recherche valeurs des étiquettes de la liste.				*/
/*------------------------------------------------------------------------------*/
int LitValEtiquettes()
{
	int id ;
	erreur_checksum = 0 ;
 
	for (id=0; id<NB_VALEURS; id++)
	{
		if ( (match = strstr(message, etiquettes[id])) != NULL)
		{
			sscanf(match, "%s %s %s", etiquettes[id], valeurs[id], checksum) ;
			if ( strlen(checksum) > 1 ) checksum[0]=' ' ;	// sscanf ne peux lire le checksum à 0x20 (espace), si longueur checksum > 1 donc c'est un espace.
			if ( ! checksum_ok(etiquettes[id], valeurs[id], checksum[0]) ) 
			{
				syslog(LOG_ERR, "Donnees teleinfo [%s] corrompues (essai %d) !\n", etiquettes[id], no_essais) ;
				erreur_checksum = 1 ;
				return 0 ;
			}
		}
	}
	// Remplace chaine "HP.." ou "HC.." par "HP ou "HC".
	valeurs[5][2] = '\0' ;
	#ifdef DEBUG
	printf("----------------------\n") ; for (id=0; id<NB_VALEURS; id++) printf("%s='%s'\n", etiquettes[id], valeurs[id]) ;
	#endif
	return 1 ;
}
 
/*------------------------------------------------------------------------------*/
/* Test si dépassement intensité						*/
/*------------------------------------------------------------------------------*/
int DepasseCapacite()
{
	//  Test sur les 3 phases (étiquette ADIR1, ADIR2, ADIR3) à remplacer par ADPS pour monophasé.
	if ( (strlen(valeurs[17])) || (strlen(valeurs[18])) || (strlen(valeurs[19])) )
	{
		syslog(LOG_INFO, "Dépassement d'intensité: ADRI1='%s', ADRI2='%s', ADRI3='%s' !", valeurs[17], valeurs[18], valeurs[19]) ;
		return 1 ;
	}
	return 0 ;
}
 
/*------------------------------------------------------------------------------*/
/* Ecrit les données teleinfo dans base mysql					*/
/*------------------------------------------------------------------------------*/
int writemysqlteleinfo(char data[])
{
	MYSQL mysql ;
	char query[255] ;
 
	/* INIT MYSQL AND CONNECT ----------------------------------------------------*/
	if(!mysql_init(&mysql))
	{
		syslog(LOG_ERR, "Erreur: Initialisation MySQL impossible !") ; 
		return 0 ;
	}
	if(!mysql_real_connect(&mysql, MYSQL_HOST, MYSQL_LOGIN,	MYSQL_PWD, MYSQL_DB, 0, NULL, 0))
	{
		syslog(LOG_ERR, "Erreur connection %d: %s \n", mysql_errno(&mysql), mysql_error(&mysql));
		return 0 ;
	}
 
	sprintf(query, "INSERT INTO %s VALUES (%s)", MYSQL_TABLE, data);
 
	if(mysql_query(&mysql, query))
	{
		syslog(LOG_ERR, "Erreur INSERT %d: \%s \n", mysql_errno(&mysql), mysql_error(&mysql));
		mysql_close(&mysql);
		return 0 ;
	}
	#ifdef DEBUG
	else syslog(LOG_INFO, "Requete MySql ok.") ;
	#endif
	mysql_close(&mysql);
	return 1 ;
}
 
/*------------------------------------------------------------------------------*/
/* Ecrit les données teleinfo dans fichier DATACSV				*/
/*------------------------------------------------------------------------------*/
void writecsvteleinfo(char data[])
{
        /* Ouverture fichier csv */
        FILE *datateleinfo ;
        if ((datateleinfo = fopen(DATACSV, "a")) == NULL)
        {
		syslog(LOG_ERR, "Erreur ouverture fichier teleinfo %s !", DATACSV) ; 
                exit(1);
        }
        fprintf(datateleinfo, "%s\n", data) ;
        fclose(datateleinfo) ;
}
 
#ifdef DEBUG
/*------------------------------------------------------------------------------*/
/* Ecrit la trame teleinfo dans fichier si erreur (pour debugger)		*/
/*------------------------------------------------------------------------------*/
void writetrameteleinfo(char trame[], char ts[])
{
	char nomfichier[255] = TRAMELOG ;
	strcat(nomfichier, ts) ;
        FILE *teleinfotrame ;
        if ((teleinfotrame = fopen(nomfichier, "w")) == NULL)
        {
		syslog(LOG_ERR, "Erreur ouverture fichier teleinfotrame %s !", nomfichier) ;
                exit(1);
        }
        fprintf(teleinfotrame, "%s", trame) ;
        fclose(teleinfotrame) ;
}
#endif
 
/*------------------------------------------------------------------------------*/
/* Main										*/
/*------------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
 openlog("teleinfoserial_mysql", LOG_PID, LOG_USER) ;
 fdserial = initserie() ;
 
 do
 {
	// Lit trame téléinfo.
	LiTrameSerie(fdserial) ;
 
	time(&td) ;                                     //Lit date/heure système.
	dc = localtime(&td) ;
	strftime(sdate,sizeof sdate,"%Y-%m-%d",dc);
	strftime(sheure,sizeof sdate,"%H:%M:%S",dc);
	strftime(timestamp,sizeof timestamp,"%s",dc);
 
	#ifdef DEBUG
	writetrameteleinfo(message, timestamp) ;	// Enregistre trame en mode debug.
	#endif
 
	if ( LitValEtiquettes() ) 			// Lit valeurs des étiquettes de la liste.
	{
		sprintf(datateleinfo,"'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s'", timestamp, sdate, sheure, valeurs[0], valeurs[1], valeurs[2], valeurs[3], valeurs[4], valeurs[5], valeurs[6], valeurs[7], valeurs[8], valeurs[9], valeurs[10], valeurs[11], valeurs[12], valeurs[13], valeurs[14], valeurs[15], valeurs[16], valeurs[17], valeurs[18], valeurs[19]) ;
		if (! writemysqlteleinfo(datateleinfo) ) writecsvteleinfo(datateleinfo) ;		// Si écriture dans base MySql KO, écriture dans fichier csv.
 
		DepasseCapacite() ; 			// Test si etiquette dépassement intensité (log l'information seulement).
	}
	#ifdef DEBUG
	else writetrameteleinfo(message, timestamp) ;	// Si erreur checksum enregistre trame.
	#endif
	no_essais++ ;
 }
 while ( (erreur_checksum) && (no_essais <= nb_essais) ) ;
 
 close(fdserial) ;
 closelog() ;
 exit(0) ;
}



Outils personnels
Administration wiki