gasmeter/main.go
2023-01-13 08:27:47 +01:00

238 lines
5.4 KiB
Go

package main
import (
"context"
"encoding/binary"
"encoding/json"
"flag"
"log"
"math"
"os"
"path"
"strconv"
"time"
"periph.io/x/conn/v3/i2c"
"periph.io/x/conn/v3/i2c/i2creg"
"periph.io/x/conn/v3/mmr"
"periph.io/x/host/v3"
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
)
type config struct {
DataStorage string `json:"data_storage"`
InfluxdbHost string `json:"influxdb_host"`
InfluxdbPort int `json:"influxdb_port"`
InfluxdbToken string `json:"influxdb_token"`
TriggerLevel float64 `json:"trigger_level"`
TriggerHysterese float64 `json:"trigger_hysterese"`
StepWidth float64 `json:"step_width"`
Zustandszahl float64 `json:"zustandszahl"`
BrennwertHS float64 `json:"brennwert_hs"`
}
type data struct {
Unit string `json:"unit"`
Value float64 `json:"value"`
}
type sample struct {
Volume data `json:"volume"`
Power data `json:"power"`
}
var (
logger log.Logger = *log.Default()
config_path string
config_cache = config{
DataStorage: "",
InfluxdbHost: "",
InfluxdbPort: 0,
InfluxdbToken: "",
TriggerLevel: 0.0,
TriggerHysterese: 0.0,
StepWidth: 0.0,
Zustandszahl: 0.0,
BrennwertHS: 0.0,
}
)
func read_config() {
data, err := os.ReadFile(config_path)
if err != nil {
logger.Printf("Unable to read %s", config_path)
return
}
err = json.Unmarshal(data, &config_cache)
if err != nil {
logger.Print("Unable to evaluate config data")
return
}
}
func main() {
// file, err := os.OpenFile("log.txt", os.O_WRONLY|os.O_CREATE, 0644)
// if err != nil {
// logger.Println(err)
// }
// defer file.Close()
// logger.SetOutput(file)
logger.SetPrefix("Gas: ")
logger.Println("Starting")
flag.StringVar(&config_path, "c", "./config/config.json", "Specify path to find the config file. Default is ./config/config.json")
flag.Parse()
read_config()
trigger_state := false
old_state := false
var gas sample
// Create data storage directory
dir := path.Dir(config_cache.DataStorage)
err := os.MkdirAll(dir, os.ModePerm)
if err != nil {
logger.Fatal(err)
}
// Try reading stored value
data, err := os.ReadFile(config_cache.DataStorage)
if err != nil {
log.Print(err)
gas.Volume.Unit = "m³"
gas.Volume.Value = 0.0
gas.Power.Unit = "kW/h"
gas.Power.Value = 0.0
} else {
err = json.Unmarshal(data, &gas)
if err != nil {
logger.Print(err)
}
}
last_value := gas.Volume.Value
// prepare influx connection
influxdb_url := "http://" + config_cache.InfluxdbHost + ":" + strconv.Itoa(config_cache.InfluxdbPort)
client := influxdb2.NewClient(influxdb_url, config_cache.InfluxdbToken)
// always close client at the end
defer client.Close()
// get non-blocking write client
writeAPI := client.WriteAPIBlocking("tkl", "home")
ctx := context.Background()
// Int I2C system
if _, err := host.Init(); err != nil {
logger.Fatal(err)
}
bus, err := i2creg.Open("")
if err != nil {
logger.Fatal(err)
}
defer bus.Close()
i2c_dev := i2c.Dev{
Bus: bus,
Addr: 0x0d,
}
mem_dev := mmr.Dev8{
Conn: &i2c_dev,
Order: binary.BigEndian,
}
err = mem_dev.WriteUint8(0x09, 0x1d)
if err != nil {
logger.Fatal("unable to write to reg 0x09")
}
for { // ever
var raw [6]uint8
var i uint8
for i = 0; i < 6; i++ {
res, err := mem_dev.ReadUint8(i)
if err != nil {
logger.Print("unable to read from reg 0")
continue
}
raw[i] = res
}
var mag_x int16
mag_x = int16(raw[0])
mag_x |= int16(raw[1]) << 8
fmag_x := float64(mag_x)
var mag_y int16
mag_y = int16(raw[2])
mag_y |= int16(raw[3]) << 8
fmag_y := float64(mag_y)
var mag_z int16
mag_z = int16(raw[4])
mag_z |= int16(raw[5]) << 8
fmag_z := float64(mag_z)
mag := math.Sqrt(fmag_x*fmag_x + fmag_y*fmag_y + fmag_z*fmag_z)
logger.Printf("mag: %f\n\n", mag)
old_state = trigger_state
if mag > config_cache.TriggerLevel+config_cache.TriggerHysterese {
trigger_state = true
} else if mag < config_cache.TriggerLevel-config_cache.TriggerHysterese {
trigger_state = false
}
if !old_state && trigger_state {
gas.Volume.Value += config_cache.StepWidth
}
logger.Printf("Volume: %f %s\n", gas.Volume.Value, gas.Volume.Unit)
gas.Power.Value = gas.Volume.Value * config_cache.BrennwertHS * config_cache.Zustandszahl
logger.Printf("Power: %f %s\n", gas.Power.Value, gas.Power.Unit)
if last_value != gas.Volume.Value {
last_value = gas.Volume.Value
file, err := os.OpenFile(config_cache.DataStorage, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
log.Print(err)
} else {
res, err := json.Marshal(gas)
if err != nil {
logger.Print(err)
} else {
file.Write(res)
}
file.Close()
}
point := influxdb2.NewPointWithMeasurement("gas")
point.AddTag("sensor", "gasmeter")
point.AddField("volume", gas.Volume.Value)
point.AddField("unit", gas.Volume.Unit)
point.SetTime(time.Now())
err = writeAPI.WritePoint(ctx, point)
if err != nil {
logger.Print(err.Error())
}
point = influxdb2.NewPointWithMeasurement("gas")
point.AddTag("sensor", "gasmeter")
point.AddField("power", gas.Power.Value)
point.AddField("unit", gas.Power.Unit)
point.SetTime(time.Now())
err = writeAPI.WritePoint(ctx, point)
if err != nil {
logger.Print(err.Error())
}
err = writeAPI.Flush(ctx)
if err != nil {
logger.Print(err.Error())
continue
}
}
time.Sleep(time.Millisecond * 1000)
}
}