
About PLC4Go
PLC4Go
is a sub-project of PLC4X
with implementations based on Go
.
One of PLC4X’s core principals is, that an application using PLC4X should be independent of the PLC or protocol being used.
When addressing a resource on a remote there are two parts that are dependent on the protocol and the type of PLC:
-
Addressing the PLC itself
-
Addressing a resource on the PLC
Providing this independence to addressing the PLC itself is completely handled by the PlcDriverManager
the application requests a connection from.
Hereby the design of the url string
passed to the getConnection
method is greatly inspired by JDBC
.
The protocol prefix of the url specifies the type of driver being used.
For example, when connecting to a Siemens PLC using the S7/Step7 Protocol, the url: s7://192.42.0.98/1/2
causes the driver manager to create a S7 connection instance.
The part behind the :
is hereby used by the driver implementation to configure that particular connection.
For a S7 connection, for example, this is IP address/host name
/rack number
/slot number
. For different types of connections this url structure will greatly differ.
As mentioned above, the second platform dependent information is the address of resources on a PLC.
The format of an address greatly depends on the type of connection. Therefore parseAddress
is one of the only methods defined in the PlcConnection
interface any connection has to implement.
This method returns an object implementing the Address
interface which then can be used by the same connection to identify remote resources.

Usage
Below code example connects to a remote Siemens S7 PLC using the S7/Step7 protocol and then reads the state of the inputs
and outputs
from this.
func HellpPlc4go() {
driverManager := plc4go.NewPlcDriverManager()
driverManager.RegisterDriver(modbus.NewModbusDriver())
driverManager.RegisterTransport(tcp.NewTcpTransport())
// Get a connection to a remote PLC
crc := driverManager.GetConnection("modbus-tcp://192.168.23.30")
// Wait for the driver to connect (or not)
connectionResult := <-crc
if connectionResult.Err != nil {
t.Errorf("error connecting to PLC: %s", connectionResult.Err.Error())
return
}
connection := connectionResult.Connection
// Try to ping the remote device (This block is just optional)
pingResultChannel := connection.Ping()
pingResult := <-pingResultChannel
if pingResult.Err != nil {
t.Errorf("couldn't ping device: %s", pingResult.Err.Error())
return
}
// Make sure the connection is closed at the end
defer connection.Close()
// Prepare a read-request
readRequest, err := connection.ReadRequestBuilder().
AddItem("field1", "holding-register:1:REAL").
AddItem("field2", "holding-register:3:REAL").
Build()
if err != nil {
t.Errorf("error preparing read-request: %s", connectionResult.Err.Error())
return
}
// Execute a read-request
rrc := readRequest.Execute()
// Wait for the response to finish
rrr := <-rrc
if rrr.Err != nil {
t.Errorf("error executing read-request: %s", rrr.Err.Error())
return
}
// Do something with the response
value := rrr.Response.GetValue("field")
// Do something sensible with the information
fmt.Printf("\n\nResult: %f\n", value)
}