diff --git a/client.go b/client.go index 27e8498..91885ed 100644 --- a/client.go +++ b/client.go @@ -19,9 +19,10 @@ type Mbclient struct { keepAliveDuration time.Duration timeOut time.Duration wg sync.WaitGroup + registerOffset uint16 } -func New(Address string, Unit uint8, KeepAlive, TimeOut time.Duration) (*Mbclient, error) { +func New(Address string, Unit uint8, KeepAlive, TimeOut time.Duration, registerOffset uint16) (*Mbclient, error) { c := new(Mbclient) c.address = Address @@ -30,6 +31,7 @@ func New(Address string, Unit uint8, KeepAlive, TimeOut time.Duration) (*Mbclien <-c.t.C c.keepAliveDuration = KeepAlive c.timeOut = TimeOut + c.registerOffset = registerOffset return c, nil } @@ -49,7 +51,17 @@ func (m *Mbclient) closeConn() { m.wg.Wait() } -func (m *Mbclient) ReadRegisters(first uint16, numRegs uint16) ([]uint16, error) { +// Reads one or many holding registers (Function code 03) +func (m *Mbclient) ReadHoldingRegisters(first uint16, numRegs uint16) ([]uint16, error) { + return m.readRegisters(3, first, numRegs) +} + +// Reads one or many input registers (Function code 04) +func (m *Mbclient) ReadInputRegisters(first uint16, numRegs uint16) ([]uint16, error) { + return m.readRegisters(4, first, numRegs) +} + +func (m *Mbclient) readRegisters(functionCode uint8, first uint16, numRegs uint16) ([]uint16, error) { var err error // If The timer is expired, conn is closed and needs to be reopened if !m.t.Stop() { @@ -71,11 +83,11 @@ func (m *Mbclient) ReadRegisters(first uint16, numRegs uint16) ([]uint16, error) var mbpayload mbPDU binary.BigEndian.PutUint16(req[0:2], m.transactionCounter) - binary.BigEndian.PutUint16(req[2:4], 0) + binary.BigEndian.PutUint16(req[2:4], 0) // Protocol identifier binary.BigEndian.PutUint16(req[4:6], 6) // Length req[6] = m.unit - req[7] = 3 //FunctionCode - binary.BigEndian.PutUint16(req[8:10], first-1) + req[7] = functionCode + binary.BigEndian.PutUint16(req[8:10], first-m.registerOffset) binary.BigEndian.PutUint16(req[10:12], numRegs) m.conn.SetDeadline(time.Now().Add(5 * time.Second)) @@ -114,7 +126,7 @@ func (m *Mbclient) ReadRegisters(first uint16, numRegs uint16) ([]uint16, error) } err = mbpayload.unMarshal(response) - if mbpayload.functionCode != 3 { + if mbpayload.functionCode != functionCode { m.t.Reset(m.keepAliveDuration) return nil, fmt.Errorf("modbus exception %v req: %x", mbpayload.functionCode&0x7F, req) } diff --git a/client_test.go b/client_test.go index 95091f8..cde0e75 100644 --- a/client_test.go +++ b/client_test.go @@ -7,58 +7,91 @@ import ( "github.com/stretchr/testify/assert" ) +const testNibeHost = "NIBE-06543922346009.solver.nu:502" +const testIAMhost = "IAM_248000012514.solver.nu:502" + +func TestNibeInputRegsters(t *testing.T) { + inputRegs := []uint16{1, 5, 7 /*8,*/, 9, 10, 11, 12, 13, 14, 16 /*26,*/ /*39,*/, 86, 1046, 1083, 1100, 1102, 1104, // S1155 specific + 40 /*46, 48, 50*/ /* 396, 398,*/, 1017 /*1567,*/, 1025, 1028, 1029, 1083, 1087, 1575, 1577 /*1581,*/, 1583, 1585, 1975} // common registers + c, err := New(testNibeHost, 1, 100*time.Millisecond, 5*time.Second, 0) + t.Log("Connect") + assert.NoError(t, err) + for _, reg := range inputRegs { + + res, err := c.ReadInputRegisters(uint16(reg), 1) + assert.NoError(t, err, "Failed to read reg %v", reg) + + if err == nil { + t.Logf("reg: %v res: %v \n", reg, res) + } + time.Sleep(10 * time.Millisecond) + } + + time.Sleep(1 * time.Second) +} + +func TestNibeHoldingRegsters(t *testing.T) { + inputRegs := []uint16{18, 20, 22, 26, 30, 34, 38, 39, 40, 41, 45, 43, 44, 45, 56 /*97, 159,*/, 196, 197, 237} + c, err := New(testNibeHost, 1, 100*time.Millisecond, 5*time.Second, 0) + t.Log("Connect") + assert.NoError(t, err) + for _, reg := range inputRegs { + + res, err := c.ReadHoldingRegisters(uint16(reg), 1) + assert.NoError(t, err, "Failed to read reg %v", reg) + + if err == nil { + t.Logf("reg: %v res: %v \n", reg, res) + } + time.Sleep(10 * time.Millisecond) + } + + time.Sleep(1 * time.Second) +} + func TestReadOneRegisterKeepAlive(t *testing.T) { - c, err := New("IAM_248000012514.solver.nu:502", 1, 100*time.Millisecond, 5*time.Second) + c, err := New(testIAMhost, 1, 100*time.Millisecond, 5*time.Second, 1) t.Log("Connect") assert.NoError(t, err) for n := 0; n < 5; n++ { - res, err := c.ReadRegisters(12401, 2) + res, err := c.ReadHoldingRegisters(12401, 2) assert.NoError(t, err) assert.Len(t, res, 2) t.Log(res) - res, err = c.ReadRegisters(12102, 2) + res, err = c.ReadHoldingRegisters(12102, 2) assert.NoError(t, err) assert.Len(t, res, 2) t.Log(res) - res, err = c.ReadRegisters(12544, 1) - assert.NoError(t, err) - assert.Len(t, res, 1) - t.Log(float32(res[0]) / 10) - - res, err = c.ReadRegisters(12136, 1) - assert.NoError(t, err) - assert.Len(t, res, 1) - t.Log(res) } time.Sleep(1 * time.Second) } func TestReadOneRegisterShortKeepAlive(t *testing.T) { - c, err := New("IAM_248000012514.solver.nu:502", 1, 10*time.Nanosecond, 5*time.Second) + c, err := New(testIAMhost, 1, 10*time.Nanosecond, 5*time.Second, 1) t.Log("Connect") assert.NoError(t, err) for n := 0; n < 5; n++ { - res, err := c.ReadRegisters(12401, 2) + res, err := c.ReadHoldingRegisters(12401, 2) assert.NoError(t, err) assert.Len(t, res, 2) t.Log(res) time.Sleep(100 * time.Millisecond) - res, err = c.ReadRegisters(12102, 2) + res, err = c.ReadHoldingRegisters(12102, 2) assert.NoError(t, err) assert.Len(t, res, 2) t.Log(res) time.Sleep(100 * time.Millisecond) - res, err = c.ReadRegisters(12544, 1) + res, err = c.ReadHoldingRegisters(12544, 1) assert.NoError(t, err) assert.Len(t, res, 1) t.Log(float32(res[0]) / 10) time.Sleep(100 * time.Millisecond) - res, err = c.ReadRegisters(12136, 1) + res, err = c.ReadHoldingRegisters(12136, 1) assert.NoError(t, err) assert.Len(t, res, 1) t.Log(res) @@ -68,25 +101,25 @@ func TestReadOneRegisterShortKeepAlive(t *testing.T) { } func TestReadALot(t *testing.T) { - c, err := New("IAM_248000012514.solver.nu:502", 1, 100*time.Millisecond, 5*time.Second) + c, err := New(testIAMhost, 1, 100*time.Millisecond, 5*time.Second, 1) t.Log("Connect") assert.NoError(t, err) for n := 0; n < 500; n++ { t.Log(n) - _, err := c.ReadRegisters(12401, 2) + _, err := c.ReadHoldingRegisters(12401, 2) if err != nil { t.Log(err) } - _, err = c.ReadRegisters(12102, 2) + _, err = c.ReadHoldingRegisters(12102, 2) if err != nil { t.Log(err) } - _, err = c.ReadRegisters(12544, 1) + _, err = c.ReadHoldingRegisters(12544, 1) if err != nil { t.Log(err) } - _, err = c.ReadRegisters(12136, 1) + _, err = c.ReadHoldingRegisters(12136, 1) if err != nil { t.Log(err) }