diff --git a/main.go b/main.go index 3372625..392b0fc 100644 --- a/main.go +++ b/main.go @@ -20,7 +20,7 @@ import ( var ( httpAddr = flag.String("http-addr", ":9455", "Address to listen on") inverterAddr = flag.String("inverter-addr", "192.168.86.33:502", "Address of inverter") - scrapeInterval = flag.Duration("scrape-interval", 5*time.Second, "Period of modbus scraping loop") + scrapeInterval = flag.Duration("scrape-interval", 15*time.Second, "Period of modbus scraping loop") registerGauges = make(map[uint16]prometheus.Gauge) @@ -73,6 +73,21 @@ func statusHandler(w http.ResponseWriter, r *http.Request) { http.Error(w, "not implemented", http.StatusNotFound) } +func readRegs(client modbus.Client, start, qty uint16) { + data, err := client.ReadInputRegisters(5000, 50) + if err != nil { + die("Couldn't read input registers %d-%d: %v", start+1, start+qty, err) + } + for addr, reg := range sungrowInputRegs { + if addr <= start || addr > start+qty { + continue + } + val := reg.read(data[(addr-start-1)*2:]) + //fmt.Printf("%s: %v %s\n", reg.name, val, reg.unit) + registerGauges[addr].Set(val) + } +} + func main() { flag.Parse() scrapeIntervalGauge.Set(float64(*scrapeInterval)) @@ -118,19 +133,8 @@ func main() { for { start := time.Now() scrapeStart.SetToCurrentTime() - d0, err := client.ReadInputRegisters(5000, 100) - if err != nil { - die("Couldn't read input registers 5001-5100: %v", err) - } - d1, err := client.ReadInputRegisters(5100, 50) - if err != nil { - die("Couldn't read input registers 5101-5149: %v", err) - } - data := append(d0, d1...) - for addr, reg := range sungrowInputRegs { - //fmt.Printf("%s: %v %s\n", reg.name, val, reg.unit) - registerGauges[addr].Set(reg.read(data[(addr-5001)*2:])) - } + readRegs(client, 5000, 50) + readRegs(client, 5100, 50) scrapeEnd.SetToCurrentTime() scrapeDuration.Set(time.Since(start).Seconds()) scrapeCounter.Inc() diff --git a/sungrow.go b/sungrow.go index e5838dc..e02f6f9 100644 --- a/sungrow.go +++ b/sungrow.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "net" + "sync" ) const ( @@ -40,10 +41,11 @@ func getKey(conn io.ReadWriter) ([]byte, error) { // sungrowConn wraps a regular TCP connection with funky Sungrow encryption. type sungrowConn struct { net.Conn - block cipher.Block fifo *bytes.Buffer - txid uint16 + + mu sync.Mutex + txid uint16 } func (c *sungrowConn) Write(msg []byte) (int, error) { @@ -51,7 +53,10 @@ func (c *sungrowConn) Write(msg []byte) (int, error) { return c.Conn.Write(msg) } + c.mu.Lock() c.txid = binary.BigEndian.Uint16(msg[:2]) + c.mu.Unlock() + c.fifo.Truncate(0) bs := c.block.BlockSize() @@ -76,6 +81,7 @@ func (c *sungrowConn) Read(out []byte) (int, error) { if c.block == nil { return c.Conn.Read(out) } + if c.fifo.Len() > 0 { return c.fifo.Read(out) } @@ -95,7 +101,9 @@ func (c *sungrowConn) Read(out []byte) (int, error) { for cp := pkt; len(cp) > 0; cp = cp[bs:] { c.block.Decrypt(cp, cp) } + c.mu.Lock() binary.BigEndian.PutUint16(pkt, c.txid) + c.mu.Unlock() c.fifo.Write(pkt[:pktlen]) return c.fifo.Read(out) } diff --git a/sungrow_map.go b/sungrow_map.go index d04ab2a..fb72216 100644 --- a/sungrow_map.go +++ b/sungrow_map.go @@ -36,6 +36,7 @@ var sungrowInputRegs = map[uint16]*register{ 5035: {"power_factor", s16, 0.001, ""}, 5036: {"frequency", u16, 0.1, "Hz"}, 5049: {"nominal_reactive_power", s16, 0.1, "kVA"}, + 5113: {"daily_running_time", u16, 1, "m"}, 5144: {"total_power_yield_2", u32, 0.1, "kWh"}, 5148: {"frequency_2", u16, 0.01, "Hz"},