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