diff --git a/succbone/succd/modbus.go b/succbone/succd/modbus.go index 70fa22f..bc7681d 100644 --- a/succbone/succd/modbus.go +++ b/succbone/succd/modbus.go @@ -2,6 +2,7 @@ package main import ( "context" + "net" "time" "github.com/simonvetter/modbus" @@ -35,10 +36,17 @@ func (d *daemon) modbusConnect() error { return nil } +func (d *daemon) modbusRestart() error { + d.modbusClient.Close() + return d.modbusClient.Open() +} + // There are currently two devices connected to the modbus. // The first one (slave 1) is a temperature/humidity sensor. // The second one (slave 2) is a PTA8D08 transmitter -func (d *daemon) modbusUpdate() { +// +// Returns whether modbus should restart (only in case of an underlying network error) +func (d *daemon) modbusUpdate() bool { var err error // Switch to slave 1 (BTA1) @@ -48,6 +56,9 @@ func (d *daemon) modbusUpdate() { var registersBTA1 []uint16 // temperature, humidity registersBTA1, err = d.modbusClient.ReadRegisters(1, 2, modbus.INPUT_REGISTER) if err != nil { + if _, ok := err.(net.Error); ok { + return true + } klog.Warningf("error while reading registers from BTA1 %v", err) } else if len(registersBTA1) != 2 { klog.Warningf("expected two registers from modbus slave 1, but got %d", len(registersBTA1)) @@ -68,6 +79,9 @@ func (d *daemon) modbusUpdate() { var registersKEC2 []uint16 // temperatures dp registersKEC2, err = d.modbusClient.ReadRegisters(0, 3, modbus.HOLDING_REGISTER) if err != nil { + if _, ok := err.(net.Error); ok { + return true + } klog.Warningf("error while reading registers from KEC2 %v", err) } else if len(registersKEC2) != 3 { klog.Warningf("expected three registers from modbus slave 2, but got %d", len(registersKEC2)) @@ -88,6 +102,9 @@ func (d *daemon) modbusUpdate() { digitalInputRegisters, err = d.modbusClient.ReadRegisters(0x81, 8, modbus.HOLDING_REGISTER) if err != nil { + if _, ok := err.(net.Error); ok { + return true + } klog.Warningf("error while reading digital inputs from KEC1 %v", err) } else { // Convert MODBUS words into bools @@ -140,8 +157,13 @@ func (d *daemon) modbusUpdate() { err = d.modbusClient.WriteRegisters(0x01, registerValuesKEC1[:]) if err != nil { + if _, ok := err.(net.Error); ok { + return true + } klog.Warningf("error while updating registers %v", err) } + + return false } // Call modbusUpdate every 100 milliseconds @@ -151,7 +173,16 @@ func (d *daemon) modbusProcess(ctx context.Context) { case <-ctx.Done(): return default: - d.modbusUpdate() + shouldRestart := d.modbusUpdate() + // the modbus library does not reopen the tcp socket in case of + // a connection loss. + if shouldRestart { + klog.Infof("restarting modbus connection...") + err := d.modbusRestart() + if err != nil { + klog.Warningf("failed to restart modbus %v", err) + } + } time.Sleep(time.Millisecond * 100) } }