konimarti / opc

OPC DA client in Golang for monitoring and analyzing process data based on Windows COM.
MIT License
237 stars 85 forks source link

Issues with read-write synchronization and event notification #26

Closed GhostCakeMaker closed 4 years ago

GhostCakeMaker commented 4 years ago

I have some questions, as follows:

  1. It seems that the Read and Write methods you provided are not synchronized. I have done some tests. image

  2. And you don't seem to have provided the DataChanged event.

konimarti commented 4 years ago

@GhostCakeMaker thanks for your feedback.

Regarding your first issue, please provide some more data and information. Did you double-check that the OPC tag you want to write to allows a write operation? The following example with the Graybox OPC server demonstrates the read/write methods:

package main

import (
    "fmt"

    "github.com/konimarti/opc"
)

func main() {
    client, err := opc.NewConnection(
        "Graybox.Simulator",
        []string{"localhost"},
        []string{"storage.numeric.reg01"},
    )
    defer client.Close()

    if err != nil {
        panic(err)
    }

    // read reg01
    fmt.Println(client.ReadItem("storage.numeric.reg01"))

    // write to reg01
    fmt.Println(client.Write("storage.numeric.reg01", 66666))

    // read reg01 again
    fmt.Println(client.ReadItem("storage.numeric.reg01"))
}

And it produceds the following, correct output (manually initialized to 77777):

{77777 216 2019-12-20 08:58:36 +0000 UTC}
<nil>
{66666 216 2019-12-20 08:58:44 +0000 UTC}

Regarding your second point, if you would like to add this feature, please feel free to send me your pull request.

GhostCakeMaker commented 4 years ago

package main / OPC DA操作库: github.com/konimarti/opc 测试发现,读写都是异步的 没有实现DataChanged事件 */ import ( "fmt" "github.com/konimarti/opc" )

func main() { browser, := opc.CreateBrowser("Matrikon.OPC.Simulation.1", []string{"localhost"}) fmt.Println(browser.Name) //opc.PrettyPrint(browser) client, := opc.NewConnection("Matrikon.OPC.Simulation.1", []string{"localhost"}, []string{"Bucket Brigade.GoLang.Name"}) defer func() { client.Close() if err := recover(); err != nil { fmt.Println(err) } }() ReadAllPrint(client) randInt := "77777" errMsg := client.Write("Bucket Brigade.GoLang.Name", randInt) fmt.Println("WRITE value:",randInt,"result:",errMsg) //time.Sleep(500 * time.Millisecond) ReadAllPrint(client) }

func ReadAllPrint(conn opc.Connection) { itemMap := conn.Read() for _, v := range itemMap { fmt.Println("READ value:", v.Value, "quality:", v.Quality, "timestamp:", v.Timestamp, "good:", v.Good()) } }

konimarti commented 4 years ago

I don't have a Matrikon OPC server installed to test it and I don't know how your tag "Bucket Brigade.GoLang.Name" is defined. The best is to test it with the known tags on the Graybox OPC server, so we share the same starting point. Did you try the example from above with Graybox?

GhostCakeMaker commented 4 years ago

For the first question, I used the Gray Opc you provided, which seems to be ok,but good is false. image However, the second question, DataChanged event do you provide again?

konimarti commented 4 years ago

@GhostCakeMaker thanks for confirming that it works. The OPC quality value of 216 is "good - local override, value forced" according to the standard. I will change the code accordingly, so that it also returns true when Good() is called. The DataChanged functionality is not implemented; however, if you want to add it, please feel free to do so. I'd appreciate it.