teleinfo linky mode standard

les autres capteurs : Sondes Météo, switches
js-martin
Messages : 459
Enregistré le : 22 mars 2015, 22:08
Contact :

Re: teleinfo linky mode standard

Message par js-martin » 14 juil. 2018, 19:25

Bon, finalement j'ai pris ton code qui m'a fait gagné beaucoup de temps. Merci ;)

Chez moi, il plantait régulièrement (il faut dire que j'ai pas mal de lignes en erreur, je pense que mon dongle usb a du mal à suivre).

Donc, j'ai pris ton code, supprimé les trames EAST et SINSTS (qui seront toujours à zéro pour moi) et je le rends à usage unique : il prend 10 secondes pour récupérer 2-3 trames EAIT (total production) + SINSTI (production instantanée) et il s'arrête juste après avoir mis à jour domoticz.

Dans la contable, je lui fais faire une mise à jour toutes les 2 minutes.

Enedis devrait me repasser en mode historique (je ne sais pas si c'est une bonne idée).

ton code saccagé :

Code : Tout sélectionner

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <limits.h>
#include <sys/time.h>
#include <curl/curl.h>


//--------------------------------------------------
// DONNEES A MODIFIER EN FONCTION DE LA CONFIGURATION SOUHAITEE
//--------------------------------------------------
// Port Serie et Baud Rate
// Délimiteur (normalement 0x09 à 9600 bauds et 0x20 à 1200 bauds)
// Requête JSON pour Domoticz (CHANGER LE IDX AVEC LE NUMERO DE DEVICE)
//--------------------------------------------------
const char* SERIAL_PORT = "/dev/ttyUSB0";
const speed_t BAUD_RATE = B9600;
const char DEMILITER = 0x09;
const char* JSON_HEADER = "http://192.168.1.40:8080/json.htm?type=command&param=udevice&idx=735&nvalue=0&svalue=";
//--------------------------------------------------



/* Number of consecutive characters to read (max = 255) */
const unsigned int BUFFER_SIZE = 255;
/* Max number of characters in one line (<= BUFFER SIZE) */
const unsigned int MAX_LINE_SIZE = 150;
/* Min number of characters in one line (<= MAX_LINE_SIZE) */
const unsigned int MIN_LINE_SIZE = 5;

typedef struct {
	unsigned int EAST;
	unsigned int EAIT;
	unsigned int SINSTS;
	unsigned int SINSTI;
} Teleinfo;

typedef struct {
	int value;
	unsigned int elapsed_seconds;
} DomoticzDevice;


Teleinfo teleinfo = { .EAST = 0, .EAIT = 0, .SINSTS = 0, .SINSTI = 0 };
DomoticzDevice EDF = { .value = 0, .elapsed_seconds = 0 };

unsigned int send_message = 0; 
struct timeval tv1; struct timezone tz1;
struct timeval tv2; struct timezone tz2;

int set_interface_attribs(int fd, int speed)
{
    struct termios tty;

    if (tcgetattr(fd, &tty) < 0)
    {
        printf("Error from tcgetattr: %s\n", strerror(errno));
        return -1;
    }

    cfsetospeed(&tty, (speed_t)speed);
    cfsetispeed(&tty, (speed_t)speed);

    tty.c_cflag |= (CLOCAL | CREAD);    /* ignore modem controls */
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS7;         /* 7-bit characters */
    tty.c_cflag |= PARENB;     /* parity enabled & even */
    tty.c_cflag &= ~CSTOPB;     /* 1 stop bit */
    tty.c_cflag &= ~CRTSCTS;    /* no hardware flowcontrol */

    /* setup for non-canonical mode */
    tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
    tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    tty.c_oflag &= ~OPOST;

    /* read characters, with max delay of half second to receive a char */
    tty.c_cc[VMIN] = BUFFER_SIZE;
    tty.c_cc[VTIME] = 5;

    if (tcsetattr(fd, TCSANOW, &tty) != 0) 
    {
        printf("Error from tcsetattr: %s\n", strerror(errno));
        return -1;
    }
    return 0;
}

int isCheckSumOk(char* line)
{
	unsigned int checksum_expected = 0;
	unsigned int checksum_real = 0;
	unsigned int i;

	checksum_expected = line[strlen(line) - 1];
	for (i = 0; i <= strlen(line) - 2; i++)
	{
		checksum_real += line[i];
	}
	checksum_real = (checksum_real & 0x3F) + 0x20;

	if (checksum_expected != checksum_real)
	{
		//printf("ERROR --> Checksum failed on line: \"%s\"\n", line);
		unsigned char *p;
		unsigned int linelen = strlen(line);
		for (p = line; linelen-- > 0; p++)
			//printf(" 0x%x", *p);
		//printf("\n");
		return -1;
	}

	return 0;
}

int strToUL(char* str)
{
	unsigned int val = 0;
	char *endptr;
	errno = 0;
	val = strtoul(str, &endptr, 10);
	if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0)) 
	{
		printf("ERROR --> Cannot convert to ul the string: \"%s\"\n", str);
		return -1;
	}
	else if (endptr == str)
	{
		printf("ERROR --> Cannot convert to ul an empty string: \"%s\"\n", str);
		return -1;
	}
	return (int)val;
}

int sendUrl(char* url)
{
	int ret = -1;
    CURL *curl;
    CURLcode res;
    curl = curl_easy_init();
    if (curl)
    {
        curl_easy_setopt(curl, CURLOPT_URL, url);
		curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); //Prevent "longjmp causes uninitialized stack frame" bug
		curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "deflate");
		curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60);
        //curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
        //curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
        res = curl_easy_perform(curl);
        if(res != CURLE_OK)
        {
			printf("ERROR --> Cannot send curl url: \"%s\"\n", url);
        }
        else
        {
			ret = 0;
		}

        curl_easy_cleanup(curl);
    }
    else
    {
		printf("ERROR --> Cannot init curl\n");
	}
	return ret;
}

int processLine(char* line)
{
	char label [MAX_LINE_SIZE];
	char elem1 [MAX_LINE_SIZE];
	char elem2 [MAX_LINE_SIZE];
	int val;
	unsigned int start = 0;
	unsigned int i = 0;
	// Find next elem
	label[0] = '\0';
	for (i = start; i <= strlen(line) - 2; i++)
	{
		// Find the delimiter
		if (line[i] == DEMILITER)
		{
			memcpy(label, &line[start], i-start);
			label[i-start] = '\0';
			break;
		}
	}
	// Find next elem
	start = i+1;
	elem1[0] = '\0';
	for (i = start; i <= strlen(line) - 2; i++)
	{
		// Find the delimiter
		if (line[i] == DEMILITER)
		{
			memcpy(elem1, &line[start], i-start);
			elem1[i-start] = '\0';
			break;
		}
	}
	// Find next elem
	start = i+1;
	elem2[0] = '\0';
	for (i = start; i <= strlen(line) - 2; i++)
	{
		// Find the delimiter
		if (line[i] == DEMILITER)
		{
			memcpy(elem2, &line[start], i-start);
			elem2[i-start] = '\0';
			break;
		}
	}

	//printf("DEBUG --> New line: %s - %s - %s\n", label, elem1, elem2);
	// Save value
//	if(strcmp(label, "EAST") == 0) {
//		val = strToUL(elem1);
//		if (val != -1) teleinfo.EAST = (unsigned int)val;
//		else return -1;
//	} else 
        if(strcmp(label, "EAIT") == 0) {
		val = strToUL(elem1);
		if (val != -1) teleinfo.EAIT = (unsigned int)val;
		else return -1;
	}
//	else if(strcmp(label, "SINSTS") == 0) {
//		val = strToUL(elem1);
//		if (val != -1) teleinfo.SINSTS = (unsigned int)val;
//		else return -1;
//	}
	else if(strcmp(label, "SINSTI") == 0) {
		val = strToUL(elem1);
		if (val != -1) teleinfo.SINSTI = (unsigned int)val;
		else return -1;
	}
}

int main()
{
    //freopen("out.txt", "a", stdout);
    int fd;
    int wlen;
    unsigned char line[MAX_LINE_SIZE];
    unsigned int linelen = 0;
    unsigned int pos = 0;
    fd = open(SERIAL_PORT, O_RDONLY | O_NOCTTY | O_SYNC);
    if (fd < 0)
    {
        printf("Error opening %s: %s\n", SERIAL_PORT, strerror(errno));
        return -1;
    }

	/* Get current time */
	gettimeofday(&tv1, &tz1);
	gettimeofday(&tv2, &tz2);

    /* Open serial port */
    set_interface_attribs(fd, BAUD_RATE);

    /* Receive characters */
    do
    {
        unsigned char buf[BUFFER_SIZE];
        int rdlen;
        int first_line = 1;

        rdlen = read(fd, buf, sizeof(buf) - 1);
        if (rdlen > 0)
        {
			int i = 0;
			while (i < rdlen)
			{
				// Discard all special characters
				const char c = buf[i];
				if (((c >= 0x00) && (c <= 0x01)) || ((c >= 0x04) && (c <= 0x08)))
				{
					//printf("DEBUG --> Char 0x%x discarded in line: \"%s\"\n", c, line);
					i++;
					continue;
				}

				// Get character
				line[pos] = c;

				// If line ending is found
				if (((c >= 0x02) && (c <= 0x03)) || ((c >= 0x0a) && (c <= 0x0f)))
				{
					// Close string
					line[pos] = 0;
					linelen = pos;
					pos = 0;

					// Discard first line as it may be truncated
					if (first_line)
					{
						first_line = 0;
					}
					// Discard lines too small
					else if (linelen < MIN_LINE_SIZE)
					{
						// Nothing to do
                        //printf("WARNING --> Line discarded because too small: \"%s\"\n", line);
					}
					// Discard incoherent lines
					else if (line[linelen-2] != DEMILITER)
					{
						//printf("ERROR --> Ending delimiter not found on line: \"%s\"\n", line);
					}
					else
					{
#ifdef DISPLAY_LINE_STRING
						//printf("Read %d: \"%s\"\n", linelen, line);
#endif
#ifdef DISPLAY_LINE_HEX
						unsigned char *p;
						//printf("Read %d:", linelen);
						for (p = line; linelen-- > 0; p++)
							//printf(" 0x%x", *p);
						//printf("\n");
#endif
						// Verify checksum
						if (isCheckSumOk(line) == 0)
						{
							//printf("SUCCESS --> Checksum OK on line: \"%s\"\n", line);
							processLine(line);
						}
					}
				}

				else if (pos == sizeof(line) - 1)
				{
					// Close string
					line[pos] = 0;
					linelen = pos;
					pos = 0;

					printf("ERROR: no new line read in line: \"%s\"\n", line);
				}

				else if (pos == sizeof(buf) - 1)
				{
					// Close string
					line[pos] = 0;
					linelen = pos;
					pos = 0;

					printf("ERROR: no new line read in buffer: \"%s\"\n", buf);
				}

				else
				{
					pos++;
				}

				i++;
			}

#ifdef DISPLAY_BUFFER_STRING
            buf[rdlen] = 0;
            printf("Read %d: \"%s\"\n", rdlen, buf);
#endif
#ifdef DISPLAY_BUFFER_HEX
            unsigned char *p;
            printf("Read %d:", rdlen);
            for (p = buf; rdlen-- > 0; p++)
                printf(" 0x%x", *p);
            printf("\n");
#endif
        }
        else if (rdlen < 0)
        {
            printf("Error from read: %d: %s\n", rdlen, strerror(errno));
        }


		/* Check if it's time to send a message to Domoticz */
		if (send_message)
		{
			send_message = 0;

			//Calculate values to send
			//int SINST = (int)(teleinfo.SINSTS) - (int)(teleinfo.SINSTI);
                        int SINST =  (int)(teleinfo.SINSTI);
			char SINST_str[12]; sprintf(SINST_str, "%d", SINST);

			//int EAT = (int)(teleinfo.EAST) - (int)(teleinfo.EAIT);
                        int EAT =  (int)(teleinfo.EAIT);
			char EAT_str[12]; sprintf(EAT_str, "%d", EAT);

			//Construction of message to send
			char message [1000];
			strcpy(message, JSON_HEADER);
			strcat(message, SINST_str);
			strcat(message, ";");
			strcat(message, EAT_str);
			//Send message
			if(sendUrl(message) == 0)
			{
				printf("DEBUG --> New message sent: \"%s\"\n", message);
                                exit(0);
			}
		}
		else
		{
			gettimeofday(&tv2, &tz2);
			if((tv2.tv_sec - tv1.tv_sec) >= 10)
			{
				send_message = 1;
				tv1.tv_sec = tv2.tv_sec;
			}
		}

        /* sleep and repeat read */
        //sleep(1);
    } while (1);
}


Installation Curl sur Raspberry :

Code : Tout sélectionner

sudo apt-get install libcurl4-openssl-dev
Compilation :

Code : Tout sélectionner

sudo cc driver_teleinfo.c -lcurl
Modifié en dernier par js-martin le 26 juil. 2018, 18:55, modifié 3 fois.
Domotisation de : mes compteurs EDF, solaire, eau / mon alarme / ma Chaudière Viessamnn / mon congel / ma sonnette. Matériels : Pi2 - RFXTrx433e - Zwave+ Aeotec, ampoules Hue - Détecteur et prises Fibaro - Capteurs Oregon - présentation installation => lien

Disable adblock

This site is supported by ads and donations.
If you see this text you are blocking our ads.
Please consider a Donation to support the site.


js-martin
Messages : 459
Enregistré le : 22 mars 2015, 22:08
Contact :

Re: teleinfo linky mode standard

Message par js-martin » 16 juil. 2018, 11:35

Finalement, je vais garder le mode standard car je vois que la solution est stable.

Il faudrait modifier le code de Domoticz pour simplifier les choses (et ne pas passer par ce programme d'adaptation).

S'il y a des personnes qui souhaitent faire le support du Linky dans Domoticz, voici un extrait de trames du compteur (j'ai juste modifié mon numéro de PRM):

Code : Tout sélectionner

/dev $ cat ttyUSBP
EP*PREF 03      B
PCOUP   03      \
SINSTS  00000   F
SMAXSN  E180716063417   00021   9
SMAXSN-1        E180715064903   00023   Y
SINSTI  01258   L
SMAXIN  E180716103316   01423   /
SMAXIN-1        E180715144229   01971   \
CCASN   E180716100000   00000   0
CCASN-1 E180716090000   00000   V
UMOY1   E180716103000   230     +
STGE    002A0301        <
MSG1    PAS DE          MESSAGE                 <
PRM     22246454325444  4
RELAIS  000     B
NTARF   01      N
NJOURF  00      &
NJOURF+1        00      B
PJOURF+1        00008001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE   9
ADSC    031864661664    @
VTIC    02      J
DATE    E180716103423           B
NGTF       PRODUCTEUR           .
LTARF    INDEX NON CONSO        0
EAST    000000000       O
EASF01  000000000       "
EASF02  000000000       #
EASF03  000000000       $
EASF04  000000000       %
EASF05  000000000       &
EASF06  000000000       '
EASF07  000000000       (
EASF08  000000000       )
EASF09  000000000       *
EASF10  000000000       "
EASD01  000000000        
EASD02  000000000       !
EASD03  000000000       "
EASD04  000000000       #
EAIT    000032781       Z
ERQ1    000000000       ;
ERQ2    000000890       M
ERQ3    000002546       N
ERQ4    000000000       >
IRMS1   005     3
URMS1   228     F
PREF    03      B
PCOUP   03      \
SINSTS  00000   F
SMAXSN  E180716063417   00021   9
SMAXSN-1        E180715064903   00023   Y
SINSTI  01253   G
SMAXIN  E180716103316   01423   /
SMAXIN-1        E180715144229   01971   \
CCASN   E180716100000   00000   0
CCASN-1 E180716090000   00000   V
UMOY1   E180716103000   230     +
STGE    002A0301        <
MSG1    PAS DE          MESSAGE                 <
PRM     22246454325444  4
RELAIS  000     B
NTARF   01      N
NJOURF  00      &
NJOURF+1        00      B
PJOURF+1        00008001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE   9
ADSC    031864661664    @
VTIC    02      J
DATE    E180716103424           C
NGTF       PRODUCTEUR           .
LTARF    INDEX NON CONSO        0
EAST    000000000       O
EASF01  000000000       "
EASF02  000000000       #
EASF03  000000000       $
EASF04  000000000       %
EASF05  000000000       &
EASF06  000000000       '
EASF07  000000000       (
EASF08  000000000       )
EASF09  000000000       *
EASF10  000000000       "
EASD01  000000000        
EASD02  000000000       !
EASD03  000000000       "
EASD04  000000000       #
EAIT    000032781       Z
ERQ1    000000000       ;
ERQ2    000000890       M
ERQ3    000002546       N
ERQ4    000000000       >
IRMS1   005     3
URMS1   228     F
PREF    03      B
PCOUP   03      \
SINSTS  00000   F
SMAXSN  E180716063417   00021   9
SMAXSN-1        E180715064903   00023   Y
SINSTI  01249   L
SMAXIN  E180716103316   01423   /
SMAXIN-1        E180715144229   01971   \
CCASN   E180716100000   00000   0
CCASN-1 E180716090000   00000   V
UMOY1   E180716103000   230     +
STGE    002A0301        <
MSG1    PAS DE          MESSAGE                 <
PRM     22246454325444  4
RELAIS  000     B
NTARF   01      N
NJOURF  00      &
NJOURF+1        00      B
PJOURF+1        00008001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE   9
ADSC    031864661664    @
VTIC    02      J
DATE    E180716103426           E
NGTF       PRODUCTEUR           .
LTARF    INDEX NON CONSO        0
EAST    000000000       O
EASF01  000000000       "
EASF02  000000000       #
EASF03  000000000       $
EASF04  000000000       %
EASF05  000000000       &
EASF06  000000000       '
EASF07  000000000       (
EASF08  000000000       )
EASF09  000000000       *
EASF10  000000000       "
EASD01  000000000        
EASD02  000000000       !
EASD03  000000000       "
EASD04  000000000       #
EAIT    000032782       [
ERQ1    000000000       ;
ERQ2    000000890       M
ERQ3    000002546       N
ERQ4    000000000       >
IRMS1   005     3
URMS1   229     G
PREF    03      B
PCOUP   03      \
SINSTS  00000   F
SMAXSN  E180716063417   00021   9
SMAXSN-1        E180715064903   00023   Y
SINSTI  01237   I
SMAXIN  E180716103316   01423   /
SMAXIN-1        E180715144229   01971   \
CCASN   E180716100000   00000   0
CCASN-1 E180716090000   00000   V
UMOY1   E180716103000   230     +
STGE    002A0301        <
MSG1    PAS DE          MESSAGE                 <
PRM     22246454325444  4
RELAIS  000     B
NTARF   01      N
NJOURF  00      &
NJOURF+1        00      B
PJOURF+1        00008001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE   9
ADSC    031864661664    @
VTIC    02      J
DATE    E180716103427           F
NGTF       PRODUCTEUR           .
LTARF    INDEX NON CONSO        0
EAST    000000000       O
EASF01  000000000       "
EASF02  000000000       #
EASF03  000000000       $
EASF04  000000000       %
EASF05  000000000       &
EASF06  000000000       '
EASF07  000000000       (
EASF08  000000000       )
EASF09  000000000       *
EASF10  000000000       "
EASD01  000000000        
EASD02  000000000       !
EASD03  000000000       "
EASD04  000000000       #
EAIT    000032782       [
ERQ1    000000000       ;
ERQ2    000000890       M
Avec les mises à jour, je retrouve un fonctionnement normal :
conso.jpg
conso.jpg (142.21 Kio) Vu 445 fois
prod_j.jpg
prod_j.jpg (81.41 Kio) Vu 445 fois
prod_s.jpg
prod_s.jpg (62.71 Kio) Vu 445 fois

Pour ceux qui se demandent pourquoi je n'avais pas de production, la réponse est ici :

http://forum-photovoltaique.fr/viewtopi ... 49#p442923

Rappel :
Paramètre mode historique

Code : Tout sélectionner

sudo stty -F /dev/ttyUSBC 1200 sane evenp parenb cs7 -crtscts
Paramètre mode Linky standard (pour mon Itron)

Code : Tout sélectionner

sudo stty -F /dev/ttyUSBP 9600 -parodd cs7 -cstopb
Paramètre mode Linky standard (pour le SagemCom)

Code : Tout sélectionner

sudo stty -F /dev/ttyUSBP 9600 -parodd cs7
À mettre dans /etc/rc.local
Domotisation de : mes compteurs EDF, solaire, eau / mon alarme / ma Chaudière Viessamnn / mon congel / ma sonnette. Matériels : Pi2 - RFXTrx433e - Zwave+ Aeotec, ampoules Hue - Détecteur et prises Fibaro - Capteurs Oregon - présentation installation => lien

Répondre