Skip to content

Commit

Permalink
Fix #1 Add possibility to set serial param at launch
Browse files Browse the repository at this point in the history
  • Loading branch information
syberalexis committed Dec 2, 2020
1 parent e4ad784 commit c942f77
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 66 deletions.
14 changes: 12 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ empty :=
PROJECT_NAME := linky-exporter
DIST_FOLDER := dist
TAG_NAME := $(shell git tag -l --contains HEAD | head -n1)
GOOS ?= $(shell go version | awk '{print $4}' | cut -d'/' -f1)
GOARCH ?= $(shell go version | awk '{print $4}' | cut -d'/' -f2)
GOOSARCH := $(shell go version | cut -d' ' -f4)
GOOS ?= $(shell echo ${GOOSARCH} | cut -d'/' -f1)
GOARCH ?= $(shell echo ${GOOSARCH} | cut -d'/' -f2)
VERSION ?= $(subst v,$(empty),$(TAG_NAME))

ifeq ($(GOARCH), arm)
Expand All @@ -25,3 +26,12 @@ clean:

version:
echo $(VERSION)

info:
echo "PROJECT_NAME = $(PROJECT_NAME)"
echo "DIST_FOLDER = $(DIST_FOLDER)"
echo "TAG_NAME = $(TAG_NAME)"
echo "GOOSARCH = $(GOOSARCH)"
echo "GOOS = $(GOOS)"
echo "GOARCH = $(GOARCH)"
echo "VERSION = $(VERSION)"
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Download binary from [releases page](https://github.com/syberalexis/linky-export

Example :
```bash
curl -L https://github.com/syberalexis/linky-exporter/releases/download/v1.0.1/linky-exporter-1.0.1-linux-amd64 -o /usr/local/bin/linky-exporter
curl -L https://github.com/syberalexis/linky-exporter/releases/download/v2.0.0/linky-exporter-2.0.0-linux-amd64 -o /usr/local/bin/linky-exporter
chmod +x /usr/local/bin/linky-exporter
/usr/local/bin/linky-exporter
```
Expand Down Expand Up @@ -71,7 +71,10 @@ Flags:
-a, --address="0.0.0.0" Listen address
-b, --baud=1200 Baud rate
-d, --device="/dev/serial0" Device to read
--parity="ParityNone" Serial parity
-p, --port=9901 Listen port
--size=7 Serial frame size
--stopbits="Stop1" Serial stopbits
```


Expand Down
23 changes: 16 additions & 7 deletions cmd/linky-exporter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@ package main

import (
"fmt"
"os"
"path/filepath"

"github.com/pkg/errors"
"github.com/prometheus/common/log"
"github.com/syberalexis/linky-exporter/pkg/core"
"gopkg.in/alecthomas/kingpin.v2"
"os"
"path/filepath"
)

var (
version = "dev"
defaultPort = 9901
defaultAddress = "0.0.0.0"
defaultDevice = "/dev/serial0"
defaultBaudRate = 1200
version = "dev"
defaultPort = 9901
defaultAddress = "0.0.0.0"
defaultDevice = "/dev/serial0"
defaultBaudRate = 1200
defaultFrameSize = 7
defaultParity = "ParityNone"
defaultStopBits = "Stop1"
)

// Linky-exporter command main
Expand All @@ -32,7 +36,12 @@ func main() {
app.Flag("address", "Listen address").Default(fmt.Sprintf("%s", defaultAddress)).Short('a').StringVar(&exporter.Address)
app.Flag("baud", "Baud rate").Default(fmt.Sprintf("%d", defaultBaudRate)).Short('b').IntVar(&exporter.BaudRate)
app.Flag("device", "Device to read").Default(fmt.Sprintf("%s", defaultDevice)).Short('d').StringVar(&exporter.Device)
app.Flag("parity", "Serial parity").Default(fmt.Sprintf("%s", defaultParity)).
HintOptions("ParityNone", "N", "ParityOdd", "O", "ParityEven", "E", "ParityMark", "M", "ParitySpace", "S").StringVar(&exporter.Parity)
app.Flag("port", "Listen port").Default(fmt.Sprintf("%d", defaultPort)).Short('p').IntVar(&exporter.Port)
app.Flag("size", "Serial frame size").Default(fmt.Sprintf("%d", defaultFrameSize)).IntVar(&exporter.FrameSize)
app.Flag("stopbits", "Serial stopbits").Default(fmt.Sprintf("%s", defaultStopBits)).
HintOptions("Stop1", "1", "Stop1Half", "15", "Stop2", "2").StringVar(&exporter.StopBits)

// Parsing
args, err := app.Parse(os.Args[1:])
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ go 1.14
require (
github.com/pkg/errors v0.8.1
github.com/prometheus/client_golang v1.5.1
github.com/prometheus/common v0.9.1
github.com/sirupsen/logrus v1.5.0
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
google.golang.org/api v0.24.0
google.golang.org/api v0.24.0 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6
)
105 changes: 56 additions & 49 deletions pkg/collectors/linky-collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,62 @@ package collectors

import (
"bufio"
"strconv"
"strings"

"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
"github.com/tarm/serial"
"strconv"
"strings"
)

// LinkyCollector object to describe and collect metrics
type LinkyCollector struct {
device string
baudRate int
device string
baudRate int
frameSize byte
parity serial.Parity
stopBits serial.StopBits
index *prometheus.Desc
power *prometheus.Desc
intensity *prometheus.Desc
intensity *prometheus.Desc
intensitySubscribed *prometheus.Desc
intensityMax *prometheus.Desc
tomorrowBlue *prometheus.Desc
tomorrowWhite *prometheus.Desc
tomorrowRed *prometheus.Desc
hoursGroup *prometheus.Desc
hoursGroup *prometheus.Desc
}

// Internal linky values object to each metrics
type linkyValues struct {
adco string // 'ADCO': '2000..', # Identification de compteur
optarif string // 'OPTARIF': 'HC..', # option tarifaire
base uint64 // 'BASE': '040177099', # index tarif de base
imax uint16 // 'IMAX': '007', # intensité max
hchc uint64 // 'HCHC': '040177099', # index heure creuse en Wh
iinst int16 // 'IINST': '005', # Intensité instantanée en A
papp uint16 // 'PAPP': '01289', # puissance Apparente, en VA
hhphc string // 'HHPHC': 'A', # Horaire Heures Pleines Heures Creuses
isousc uint16 // 'ISOUSC': '45', # Intensité souscrite en A
hchp uint64 // 'HCHP': '040177099', # index heure pleine en Wh
ptec string // 'PTEC': 'HP..' # Période tarifaire en cours
hpjb uint64 // 'HPJB': '040177099', # index heures creuses jours bleus en wh
hcjb uint64 // 'HCJB': '040177099', # index heures pleines jours bleus en wh
hpjw uint64 // 'HPJW': '040177099', # index heures creuses jours blancs en wh
hcjw uint64 // 'HCJW': '040177099', # index heures pleines jours blancs en wh
hpjr uint64 // 'HPJR': '040177099', # index heures creuses jours rouges en wh
hcjr uint64 // 'HCJR': '040177099', # index heures pleines jours rouges en wh
demain string // 'DEMAIN': 'BLAN' # Couleur du lendemain
adco string // 'ADCO': '2000..', # Identification de compteur
optarif string // 'OPTARIF': 'HC..', # option tarifaire
base uint64 // 'BASE': '040177099', # index tarif de base
imax uint16 // 'IMAX': '007', # intensité max
hchc uint64 // 'HCHC': '040177099', # index heure creuse en Wh
iinst int16 // 'IINST': '005', # Intensité instantanée en A
papp uint16 // 'PAPP': '01289', # puissance Apparente, en VA
hhphc string // 'HHPHC': 'A', # Horaire Heures Pleines Heures Creuses
isousc uint16 // 'ISOUSC': '45', # Intensité souscrite en A
hchp uint64 // 'HCHP': '040177099', # index heure pleine en Wh
ptec string // 'PTEC': 'HP..' # Période tarifaire en cours
hpjb uint64 // 'HPJB': '040177099', # index heures creuses jours bleus en wh
hcjb uint64 // 'HCJB': '040177099', # index heures pleines jours bleus en wh
hpjw uint64 // 'HPJW': '040177099', # index heures creuses jours blancs en wh
hcjw uint64 // 'HCJW': '040177099', # index heures pleines jours blancs en wh
hpjr uint64 // 'HPJR': '040177099', # index heures creuses jours rouges en wh
hcjr uint64 // 'HCJR': '040177099', # index heures pleines jours rouges en wh
demain string // 'DEMAIN': 'BLAN' # Couleur du lendemain
}

// NewLinkyCollector method to construct LinkyCollector
func NewLinkyCollector(device string, baudRate int) *LinkyCollector {
func NewLinkyCollector(device string, baudRate int, frameSize byte, parity serial.Parity, stopBits serial.StopBits) *LinkyCollector {
return &LinkyCollector{
device: device,
baudRate: baudRate,
device: device,
baudRate: baudRate,
frameSize: frameSize,
parity: parity,
stopBits: stopBits,
index: prometheus.NewDesc("linky_index_watthours_total",
"Index en Wh",
[]string{"idcompteur", "tarif", "periode"}, nil,
Expand Down Expand Up @@ -84,9 +91,9 @@ func NewLinkyCollector(device string, baudRate int) *LinkyCollector {
[]string{"idcompteur", "tarif"}, nil,
),
hoursGroup: prometheus.NewDesc("linky_hours_group_info",
"Groupe horaire (tarif Tempo ou HPHC)",
[]string{"idcompteur", "tarif", "groupe"}, nil,
),
"Groupe horaire (tarif Tempo ou HPHC)",
[]string{"idcompteur", "tarif", "groupe"}, nil,
),
}
}

Expand Down Expand Up @@ -131,38 +138,38 @@ func (collector *LinkyCollector) Collect(ch chan<- prometheus.Metric) {
ch <- prometheus.MustNewConstMetric(collector.hoursGroup, prometheus.GaugeValue, 1, values.adco, tarif, values.hhphc)
switch strings.ToLower(values.ptec) {
case "th..":
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.base), values.adco, tarif, "-" )
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.base), values.adco, tarif, "-")
case "hc..":
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hchc), values.adco, tarif, "HC" )
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hchc), values.adco, tarif, "HC")
case "hp..":
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hchp), values.adco, tarif, "HP" )
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hchp), values.adco, tarif, "HP")
case "hcjb":
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hcjb), values.adco, tarif, "HCJB" )
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hcjb), values.adco, tarif, "HCJB")
case "hcjw":
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hcjw), values.adco, tarif, "HCJW" )
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hcjw), values.adco, tarif, "HCJW")
case "hcjr":
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hcjr), values.adco, tarif, "HCJR" )
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hcjr), values.adco, tarif, "HCJR")
case "hpjb":
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hpjb), values.adco, tarif, "HPJB" )
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hpjb), values.adco, tarif, "HPJB")
case "hpjw":
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hpjw), values.adco, tarif, "HPJW" )
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hpjw), values.adco, tarif, "HPJW")
case "hpjr":
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hpjr), values.adco, tarif, "HPJR" )
ch <- prometheus.MustNewConstMetric(collector.index, prometheus.CounterValue, float64(values.hpjr), values.adco, tarif, "HPJR")
default:
}
switch strings.ToLower(values.demain) {
case "bleu":
ch <- prometheus.MustNewConstMetric(collector.tomorrowBlue, prometheus.GaugeValue, 1, values.adco, tarif )
ch <- prometheus.MustNewConstMetric(collector.tomorrowWhite, prometheus.GaugeValue, 0, values.adco, tarif )
ch <- prometheus.MustNewConstMetric(collector.tomorrowRed, prometheus.GaugeValue, 0, values.adco, tarif )
ch <- prometheus.MustNewConstMetric(collector.tomorrowBlue, prometheus.GaugeValue, 1, values.adco, tarif)
ch <- prometheus.MustNewConstMetric(collector.tomorrowWhite, prometheus.GaugeValue, 0, values.adco, tarif)
ch <- prometheus.MustNewConstMetric(collector.tomorrowRed, prometheus.GaugeValue, 0, values.adco, tarif)
case "blan":
ch <- prometheus.MustNewConstMetric(collector.tomorrowBlue, prometheus.GaugeValue, 0, values.adco, tarif )
ch <- prometheus.MustNewConstMetric(collector.tomorrowWhite, prometheus.GaugeValue, 1, values.adco, tarif )
ch <- prometheus.MustNewConstMetric(collector.tomorrowRed, prometheus.GaugeValue, 0, values.adco, tarif )
ch <- prometheus.MustNewConstMetric(collector.tomorrowBlue, prometheus.GaugeValue, 0, values.adco, tarif)
ch <- prometheus.MustNewConstMetric(collector.tomorrowWhite, prometheus.GaugeValue, 1, values.adco, tarif)
ch <- prometheus.MustNewConstMetric(collector.tomorrowRed, prometheus.GaugeValue, 0, values.adco, tarif)
case "roug":
ch <- prometheus.MustNewConstMetric(collector.tomorrowBlue, prometheus.GaugeValue, 0, values.adco, tarif )
ch <- prometheus.MustNewConstMetric(collector.tomorrowWhite, prometheus.GaugeValue, 0, values.adco, tarif )
ch <- prometheus.MustNewConstMetric(collector.tomorrowRed, prometheus.GaugeValue, 1, values.adco, tarif )
ch <- prometheus.MustNewConstMetric(collector.tomorrowBlue, prometheus.GaugeValue, 0, values.adco, tarif)
ch <- prometheus.MustNewConstMetric(collector.tomorrowWhite, prometheus.GaugeValue, 0, values.adco, tarif)
ch <- prometheus.MustNewConstMetric(collector.tomorrowRed, prometheus.GaugeValue, 1, values.adco, tarif)
}
} else {
log.Errorf("Unable to read telemetry information : %s", err)
Expand All @@ -171,7 +178,7 @@ func (collector *LinkyCollector) Collect(ch chan<- prometheus.Metric) {

// Read information from serial port
func (collector *LinkyCollector) readSerial(linkyValues *linkyValues) error {
c := &serial.Config{Name: collector.device, Baud: collector.baudRate, Size: 7, Parity: serial.ParityNone, StopBits: serial.Stop1}
c := &serial.Config{Name: collector.device, Baud: collector.baudRate, Size: collector.frameSize, Parity: collector.parity, StopBits: collector.stopBits}
stream, err := serial.OpenPort(c)
if err != nil {
log.Fatal(err)
Expand Down
67 changes: 61 additions & 6 deletions pkg/core/linky-exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,82 @@ package core

import (
"fmt"
"net/http"
"os"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
log "github.com/sirupsen/logrus"
"github.com/syberalexis/linky-exporter/pkg/collectors"
"net/http"
"github.com/tarm/serial"
)

// LinkyExporter object to run exporter server and expose metrics
type LinkyExporter struct {
Address string
Port int
Device string
BaudRate int
Address string
Port int
Device string
BaudRate int
FrameSize int
Parity string
StopBits string
}

// Run method to run http exporter server
func (exporter *LinkyExporter) Run() {
log.Info(fmt.Sprintf("Beginning to serve on port :%d", exporter.Port))

prometheus.MustRegister(collectors.NewLinkyCollector(exporter.Device, exporter.BaudRate))
prometheus.MustRegister(collectors.NewLinkyCollector(exporter.Device, exporter.BaudRate,
byte(exporter.FrameSize), parseParity(exporter.Parity), parseStopBits(exporter.StopBits)))
http.Handle("/metrics", promhttp.Handler())

log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", exporter.Address, exporter.Port), nil))
}

func parseParity(value string) (parity serial.Parity) {
switch value {
case "ParityNone", "N":
parity = serial.ParityNone
break
case "ParityOdd", "O":
parity = serial.ParityOdd
break
case "ParityEven", "E":
parity = serial.ParityEven
break
case "ParityMark", "M":
parity = serial.ParityMark
break
case "ParitySpace", "S":
parity = serial.ParitySpace
break
default:
_, err := fmt.Fprintln(os.Stderr, "Impossible to parse Parity named", value)
if err != nil {
log.Error(err)
}
os.Exit(3)
}
return
}

func parseStopBits(value string) (stopBits serial.StopBits) {
switch value {
case "Stop1", "1":
stopBits = serial.Stop1
break
case "Stop1Half", "15":
stopBits = serial.Stop1Half
break
case "Stop2", "2":
stopBits = serial.Stop2
break
default:
_, err := fmt.Fprintln(os.Stderr, "Impossible to parse StopBits named", value)
if err != nil {
log.Error(err)
}
os.Exit(3)
}
return
}

0 comments on commit c942f77

Please sign in to comment.