Go in industrial projects

Does anyone intrested in implementation of industrial communication protocols in go?

It can be used for automation projects, web based scadas, data acquisition systems, iot devices etc.

I have some experience and want to start an open source project.

go ahead and start doing it :slight_smile: It’s easier to find contributors to an existing project

Can i take some architectural ideas from you ? :slight_smile:

yeah, what do you need to know?

Thank you, i have a couple of industrial communication clients. i want to collect them in a library. Is this a good practice?

package main

import "fmt"

type Client interface {
	Connect()
}

type TcpClient struct {
	IpAddress string
	Port      int
}

type ModbusTcpClient struct {
	TcpClient
	UnitIndentifier int
}

func (c ModbusTcpClient) Connect() {
	fmt.Println("connect method for modbus tcp client", c)
}

type IsoOnTcpClient struct {
	TcpClient
	Rack int
	Slot int
}

func (c IsoOnTcpClient) Connect() {
	fmt.Println("connect method for iso on tcp client", c)
}

func NewModbusTcpClient(ipAddress string, port, unitIdentifier int) Client {
	c := ModbusTcpClient{
		UnitIndentifier: unitIdentifier,
	}
	c.IpAddress = ipAddress
	c.Port = port
	return c
}

func NewIsoOnTcpClient(ipAddress string, port, rack, slot int) Client {
	c := IsoOnTcpClient{
		Rack: rack,
		Slot: slot,
	}
	c.IpAddress = ipAddress
	c.Port = port
	return c
}

func main() {
	mtc := NewModbusTcpClient("1.2.3.4", 5, 6)
	mtc.Connect()

	iotc := NewIsoOnTcpClient("7.8.9.10", 11, 12, 13)
	iotc.Connect()
}

looks good for me, at least from what I can see.

I think the following (composite pattern) will be unnecessary since there is only two clients and eight different functions.

package main

import "fmt"

const (
	ModbusTcpClient = 1
	IsoOnTcpClient  = 2
)

type Connector interface {
	Connect()
}

type TcpConnector struct {
	IpAddress string
	Port      int
}

//iso on tcp
type IsoOnTcpConnector struct {
	TcpConnector
	Rack int
	Slot int
}

func (c *IsoOnTcpConnector) Connect() {
	fmt.Println("connect method for iso on tcp client")
}

//modbus tcp
type ModbusTcpConnector struct {
	TcpConnector
	UnitIdentifier int
}

func (c *ModbusTcpConnector) Connect() {
	fmt.Println("connect method for modbus tcp client")
}

type Configuration struct {
	Type           int
	IpAddress      string
	Port           int
	UnitIdentifier int
	Rack           int
	Slot           int
}

type Client struct {
	Connector
}

func New(c *Configuration) *Client {
	switch c.Type {
	case ModbusTcpClient:
		mtc := &ModbusTcpConnector{
			UnitIdentifier: c.UnitIdentifier,
		}
		mtc.IpAddress = c.IpAddress
		mtc.Port = c.Port
		return &Client{
			mtc,
		}
	case IsoOnTcpClient:
		iotc := &IsoOnTcpConnector{
			Rack: c.Rack,
			Slot: c.Slot,
		}
		iotc.IpAddress = c.IpAddress
		iotc.Port = c.Port
		return &Client{
			iotc,
		}
	default:
		return nil
	}
}

func main() {
	mtc := New(&Configuration{
		Type:           ModbusTcpClient,
		IpAddress:      "1.2.3.4",
		Port:           502,
		UnitIdentifier: 0,
	})
	mtc.Connect()

	iotc := New(&Configuration{
		Type:      IsoOnTcpClient,
		IpAddress: "1.2.3.4",
		Port:      102,
		Rack:      0,
		Slot:      1,
	})
	iotc.Connect()
}

the question is if other clients will have similar configuration. You should follow open-closed principle. Right now, when a new type will come you have to edit New(c) function.

I’d keep them separate: NewModbusTcp() and NewIsoOnTcpClient(). What they really have in common is the Connect() function but right now I cannot see any use case for Connector interface so I’d drop it. At least for now.

Thank you, i understand.

Hello,

I could make some time and quite complete the project which you guided me about the architecture.

If you have time, i’ll be glad if you check even only the usage part.

https://github.com/ermanimer/ict/blob/master/README.md#usage

Best regards