Rechercher sur ce site...

Suivre les données télé-info de EDF dans Grafana

Hello,

Je vous propose de suivre votre consommation grâce aux données télé-info d'EDF recueilli. Je ne vais pas vous expliquer comment récupérer les données, mais plutôt vous aidez à les afficher dans Grafana dont voici un aperçu.

 

 

Prérequis :

  • La récupération des données fonctionne, voir tuto http://www.magdiblog.fr/gpio/teleinfo-edf-suivi-conso-de-votre-compteur-electrique/
  • Avoir monté une solution de supervision Grafana/Prometheus.

C'est partie pour l'intégration :

Installer le package xinetd qui va permettre d'afficher la page web :

apt update
apt install xinetd

On place le fichier de conf xinetd dans le repertoire /etc/xinetd.d/

cd /etc/xinetd.d/
curl -k -O https://raw.githubusercontent.com/jbsky/jbsky/master/script/edf/etc/edf

Le fichier de config xinetd téléchargé :

service edf-expose-metric
{
  type = unlisted
  port = 10111
  socket_type = stream
  wait = no
  user = root
  server = /usr/local/bin/httpwrapper
  server_args = /usr/local/bin/edf-expose-metric
  disable = no
  only_from = 0.0.0.0
  log_type = FILE /dev/null
  protocol = TCP
}

Ensuite, on place les 3 scripts suivants dans le répertoire /usr/local/bin/

cd /usr/local/bin/
curl -k -O https://raw.githubusercontent.com/jbsky/jbsky/master/script/edf/bin/edf-teleinfo
curl -k -O https://raw.githubusercontent.com/jbsky/jbsky/master/script/edf/bin/edf-expose-metric
curl -k -O https://raw.githubusercontent.com/jbsky/jbsky/master/script/edf/bin/httpwrapper
chmod +x /usr/local/bin/{httpwrapper,edf-teleinfo,edf-expose-metric}

Le 1er qui est lancé par /etc/init.d/edf est en écoute sur le dev, ici à configurer par le votre, alimente au fur et à mesure que des infos sont lues dans un fichier /tmp.

#!/bin/bash
TMPFILE=/tmp/edf
DEV=/dev/ttyUSB0
stty -F ${DEV} 1200 sane evenp parenb cs7 -crtscts

cat > ${TMPFILE} <<EOF
HCHP
HCHC
MOTDETAT
ISOUSC
OPTARIF
ADCO
PAPP
HHPHC
PTEC
IINST
IMAX
EOF
function readdev(){
while read TYPE VALUE CHECKSUM;do

	case "$TYPE" in

HCHP)sed -i  "s/HCHP.*/HCHP=$VALUE/g" ${TMPFILE} ;;
HCHC)sed -i  "s/HCHC.*/HCHC=$VALUE/g" ${TMPFILE} ;;
MOTDETAT)sed -i  "s/MOTDETAT.*/MOTDETAT=$VALUE/g" ${TMPFILE} ;;
ISOUSC)sed -i  "s/ISOUSC.*/ISOUSC=$VALUE/g" ${TMPFILE} ;;
OPTARIF)sed -i  "s/OPTARIF.*/OPTARIF=$VALUE/g" ${TMPFILE} ;;
ADCO)sed -i  "s/ADCO.*/ADCO=$VALUE/g" ${TMPFILE} ;;
PAPP)sed -i  "s/PAPP.*/PAPP=$VALUE/g" ${TMPFILE} ;;
HHPHC)sed -i  "s/HHPHC.*/HHPHC=$VALUE/g" ${TMPFILE} ;;
PTEC)sed -i  "s/PTEC.*/PTEC=$VALUE/g" ${TMPFILE} ;;
IINST)sed -i  "s/IINST.*/IINST=$VALUE/g" ${TMPFILE} ;;
IMAX)sed -i  "s/IMAX.*/IMAX=$VALUE/g" ${TMPFILE} ;;
	esac

done < ${DEV}
}
readdev

Le 2e script va afficher les métriques, si vous avez lancé le 1er script, celui-ci devrait afficher les données recueillies.

#!/bin/bash
# printMetric name description type value
function printMetric {
    echo "# HELP $1 $2"
    echo "# TYPE $1 $3"
    echo "$1 $4"
}
. /tmp/edf

printMetric "Heures_pleines" "HCHP" "COUNTER" "$HCHP"
printMetric "Heures_creuses" "HCHC" "COUNTER" "$HCHC"
printMetric "Mot_d_etat" "MOTDETAT" "GAUGE" "$MOTDETAT"
printMetric "Intensite_souscrite_I" "ISOUSC" "GAUGE" "$ISOUSC"
#printMetric "Option_tarifaire" "OPTARIF" "GAUGE" "$OPTARIF"
printMetric "Identifiant_du_compteur" "ADCO" "GAUGE" "$ADCO"

printMetric "Puissance_apparente_VA" "PPAP" "GAUGE" "$PAPP"
#printMetric "Groupe_horaire_si_option" "HHPHC" "GAUGE" "$HHPHC"
#printMetric "Periode_tarifaire_en_cours" "PTEC" "GAUGE" "$PTEC"

if [[ "${PTEC}" == "HP.." ]];then
	printMetric "Periode_tarifaire_en_cours_HP" "PTEC" "GAUGE" "1"
	printMetric "Periode_tarifaire_en_cours_HC" "PTEC" "GAUGE" "0"
else
	printMetric "Periode_tarifaire_en_cours_HP" "PTEC" "GAUGE" "0"
	printMetric "Periode_tarifaire_en_cours_HC" "PTEC" "GAUGE" "1"
fi
printMetric "Intensite_instantanee_A" "IINST" "GAUGE" "$IINST"
printMetric "Intensite_maximale_A" "IMAX" "GAUGE" "$IMAX"

HCHP=005594895
HCHC=005702480
MOTDETAT=000000
ISOUSC=30
OPTARIF=HC..
ADCO=000000000000
PAPP=00460
HHPHC=C
PTEC=HP..
IINST=002
IMAX=034

Le dernier est le httpwrapper, en gros, ça va rajouter un header afin que n'importe quel navigateur considère les données du 2e script comme une page web.

#!/bin/bash
# small http wrapper for bash scripts via xinetd

ulimit -n 20480
ulimit -l 512

#root='/opt/metrics.d/'
file="$1"
mime='text/plain'

#cd $root

if [ -f "$file" ]; then
  #$root
  $file > /tmp/.$$.output

  size=$(stat -c "%s" "/tmp/.$$.output")

  printf 'HTTP/1.1 200 OK\r\nDate: %s\r\nContent-Length: %s\r\nContent-Type: %s\r\nConnection: close\r\n\r\n' "$(date)" "$size" "$mime"

  cat /tmp/.$$.output

  sleep 1
  rm -f /tmp/.$$.output
  exit 0
fi

exit 1

Pour la partie lancement de service de la collecte des infos dans le fichier tmp, il faut encore un script à placer dans /etc/init.d/

Malheureusement, même si j'ai un fichier systemd dans le dépot, je n'ai pas réussit à démarrer le service sans qu'il me ramène un code erreur à 2, si quelqu'un à la solution, je suis preneur, bien entendu.

cd /etc/init.d/
curl -k -O https://raw.githubusercontent.com/jbsky/jbsky/master/script/edf/init.d/edf-teleinfo
chmod +x /etc/init.d/edf-teleinfo
#! /bin/sh
### BEGIN INIT INFO
# Provides:          skeleton
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Example initscript
# Description:       This file should be used to construct scripts to be
#                    placed in /etc/init.d.
### END INIT INFO

# Author: Foo Bar <foobar@baz.org>
#
# Please remove the "Author" lines above and replace them
# with your own name if you copy and modify this script.

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Teleinfo edf capture"
NAME=edf-teleinfo
DAEMON=/usr/local/bin/$NAME
DAEMON_ARGS=""
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
        # Return
        #   0 if daemon has been started
        #   1 if daemon was already running
        #   2 if daemon could not be started
        start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
                || return 1
        start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
                $DAEMON_ARGS \
                || return 2
        # Add code here, if necessary, that waits for the process to be ready
        # to handle requests from services started subsequently which depend
                # on this one.  As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
        # Return
        #   0 if daemon has been stopped
        #   1 if daemon was already stopped
        #   2 if daemon could not be stopped
        #   other if a failure occurred
        start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
        RETVAL="$?"
        [ "$RETVAL" = 2 ] && return 2
        # Wait for children to finish too if this is a daemon that forks
        # and if the daemon is only ever run from this initscript.
        # If the above conditions are not satisfied then add some other code
        # that waits for the process to drop all resources that could be
        # needed by services started subsequently.  A last resort is to
        # sleep for some time.
        start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
        [ "$?" = 2 ] && return 2
        # Many daemons don't delete their pidfiles when they exit.
        rm -f $PIDFILE
        return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
        #
        # If the daemon can reload its configuration without
        # restarting (for example, when it is sent a SIGHUP),
        # then implement that here.
        #
        start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
        return 0
}

case "$1" in
  start)
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
        do_start
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
  stop)
        [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
        do_stop
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
  status)
       status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
       ;;
  #reload|force-reload)
        #
        # If do_reload() is not implemented then leave this commented out
        # and leave 'force-reload' as an alias for 'restart'.
        #
        #log_daemon_msg "Reloading $DESC" "$NAME"
        #do_reload
        #log_end_msg $?
        #;;
  restart|force-reload)
        #
        # If the "reload" option is implemented then remove the
        # 'force-reload' alias
        #
        log_daemon_msg "Restarting $DESC" "$NAME"
        do_stop
        case "$?" in
          0|1)
                do_start
                case "$?" in
                        0) log_end_msg 0 ;;
                        1) log_end_msg 1 ;; # Old process is still running
                        *) log_end_msg 1 ;; # Failed to start
                esac
                ;;
          *)
                # Failed to stop
                log_end_msg 1
                ;;
        esac
        ;;
  *)
        echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
        exit 3
        ;;
esac

Reste à démarrer l'histoire!

systemctl restart xinetd
systemctl enable edf-teleinfo
systemctl start edf-teleinfo

Logiquement, le port 10111 doit être en écoute :

lsof -i -n -P |grep 10111

doit ramener une ligne.

=> http://192.168.X.Y:10111

Attention, un test avec le navigateur est aussi nécessaire.

Si vos données s'affiche, y a plus qu'à configurer dans Prometheus, pas de difficulté apparente, ajouter ce qui suit dans le fichier prometheus.yml.

 - job_name: 'edf'
static_configs:
- targets: ['192.168.X.Y:10111']

Étape finale, le board grafana est disponible à l'URL suivante :

https://grafana.com/grafana/dashboards/11675

Sources :

Exporting Prometheus Metrics with Bash Scripts

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.