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) } }