powercollect/main.go
Thomas Klaehn db50b3271a Companion device for perinode-modbusbridge
Signed-off-by: Thomas Klaehn <thomas.klaehn@perinet.io>
2025-01-21 15:35:44 +01:00

112 lines
2.8 KiB
Go

package main
import (
"encoding/json"
"flag"
"log"
"math"
"os"
"strconv"
"time"
"actshad.dev/modbus"
)
type sdm630Register struct {
Address uint16
Unit string
}
type config struct {
RtuAddress int `json:"rtu_address"`
SampleRate int `json:"sample_rate"`
ModbusHost string `json:"modbus_host"`
ModbusPort int `json:"modbus_port"`
InfluxdbHost string `json:"influxdb_host"`
InfluxdbPort int `json:"influxdb_port"`
InfluxdbToken string `json:"influxdb_token"`
}
var (
// SDM630 input registers
sdm_registers = map[string]sdm630Register{
"L1Voltage": {0x00, "V"},
"L2Voltage": {0x02, "V"},
"L3Voltage": {0x04, "V"},
"L1Current": {0x06, "A"},
"L2Current": {0x08, "A"},
"L3Current": {0x0A, "A"},
"L1PowerW": {0x0C, "W"},
"L2PowerW": {0x0E, "W"},
"L3PowerW": {0x10, "W"},
"L1PhaseAngle": {0x24, "°"},
"L2PhaseAngle": {0x26, "°"},
"L3PhaseAngle": {0x28, "°"},
"TotalImport": {0x48, "kWh"},
"TotalExport": {0x4A, "kWh"},
}
logger log.Logger = *log.Default()
config_path string
config_cache = config{
RtuAddress: 1, // modbus device slave address (0x01)
SampleRate: 1, // sec
ModbusHost: "", // hostname of the modbus tcp to rtu bridge
ModbusPort: 502, // port of the modbus tcp to rtu bridge
InfluxdbHost: "", // hostname of the influxdb server
InfluxdbPort: 8086, // port of the influxdb server
InfluxdbToken: "", // access token for the influx db
}
)
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 init() {
logger.SetFlags(log.Llongfile | log.Ltime)
logger.Println("Starting")
}
func main() {
flag.StringVar(&config_path, "c", "./config/config.json", "Specify path to find the config file. Default is ./config/config.json")
flag.Parse()
read_config()
tmp := config_cache.ModbusHost + ":" + strconv.Itoa(config_cache.ModbusPort)
handler := modbus.NewTCPClientHandler(tmp)
// handler.Timeout = 500 * time.Millisecond
handler.Timeout = 500 * time.Second
handler.SlaveId = byte(config_cache.RtuAddress)
err := handler.Connect()
if err != nil {
logger.Panic(err)
}
defer handler.Close()
modbus_client := modbus.NewClient(handler)
for {
for key, register := range sdm_registers {
res, err := modbus_client.ReadInputRegisters(register.Address, 2)
if err != nil {
logger.Printf("Could not read from %s (%s)", key, err)
continue
}
var ieee754 uint32 = (uint32(res[0])<<24 + (uint32(res[1]) << 16) + (uint32(res[2]) << 8) + uint32(res[3]))
result := math.Float32frombits(ieee754)
logger.Printf("%s: %f %s\n", key, result, register.Unit)
}
time.Sleep(time.Second)
}
}