2022-11-09 08:57:56 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"flag"
|
|
|
|
"log"
|
2025-01-21 15:35:44 +01:00
|
|
|
"math"
|
2022-11-09 08:57:56 +01:00
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
|
2025-01-21 15:35:44 +01:00
|
|
|
"actshad.dev/modbus"
|
2022-11-09 08:57:56 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
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"},
|
|
|
|
}
|
|
|
|
|
2025-01-21 15:35:44 +01:00
|
|
|
logger log.Logger = *log.Default()
|
|
|
|
config_path string
|
|
|
|
config_cache = config{
|
2022-11-09 08:57:56 +01:00
|
|
|
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() {
|
2025-01-21 15:35:44 +01:00
|
|
|
logger.SetFlags(log.Llongfile | log.Ltime)
|
2022-11-09 08:57:56 +01:00
|
|
|
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()
|
|
|
|
|
2025-01-21 15:35:44 +01:00
|
|
|
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)
|
2022-11-09 08:57:56 +01:00
|
|
|
|
2025-01-21 15:35:44 +01:00
|
|
|
err := handler.Connect()
|
|
|
|
if err != nil {
|
|
|
|
logger.Panic(err)
|
|
|
|
}
|
|
|
|
defer handler.Close()
|
|
|
|
modbus_client := modbus.NewClient(handler)
|
2022-11-09 08:57:56 +01:00
|
|
|
|
|
|
|
for {
|
2025-01-21 15:35:44 +01:00
|
|
|
for key, register := range sdm_registers {
|
|
|
|
res, err := modbus_client.ReadInputRegisters(register.Address, 2)
|
2022-11-09 08:57:56 +01:00
|
|
|
if err != nil {
|
2025-01-21 15:35:44 +01:00
|
|
|
logger.Printf("Could not read from %s (%s)", key, err)
|
2022-11-09 08:57:56 +01:00
|
|
|
continue
|
|
|
|
}
|
2025-01-21 15:35:44 +01:00
|
|
|
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)
|
2022-11-09 08:57:56 +01:00
|
|
|
}
|
2025-01-21 15:35:44 +01:00
|
|
|
time.Sleep(time.Second)
|
2022-11-09 08:57:56 +01:00
|
|
|
}
|
|
|
|
}
|