You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/11/09 15:37:31 UTC
[plc4x] branch feature/plc4go updated (cb235b9 -> da01c44)
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a change to branch feature/plc4go
in repository https://gitbox.apache.org/repos/asf/plc4x.git.
from cb235b9 - Implemented the connection establishment of KNX connection and PING operation
new 2f615be - Implemented a first version of the subscription API
new da01c44 - Started implementing discovery for KNX
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
plc4go/cmd/main/drivers/knxnetip_test.go | 20 +-
plc4go/internal/plc4go/knxnetip/KnxNetIpDriver.go | 6 +
.../plc4go/model/DefaultPlcSubscriptionRequest.go | 210 ++++++++++-----------
plc4go/pkg/plc4go/model/plc_subscription_event.go | 11 ++
.../pkg/plc4go/model/plc_subscription_request.go | 21 ++-
5 files changed, 150 insertions(+), 118 deletions(-)
[plc4x] 01/02: - Implemented a first version of the subscription API
Posted by cd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch feature/plc4go
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit 2f615be3bee9507fc8bab00f25b192fe361593e2
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon Nov 9 16:37:01 2020 +0100
- Implemented a first version of the subscription API
---
plc4go/cmd/main/drivers/knxnetip_test.go | 20 +-
.../plc4go/model/DefaultPlcSubscriptionRequest.go | 210 ++++++++++-----------
plc4go/pkg/plc4go/model/plc_subscription_event.go | 11 ++
.../pkg/plc4go/model/plc_subscription_request.go | 21 ++-
4 files changed, 144 insertions(+), 118 deletions(-)
diff --git a/plc4go/cmd/main/drivers/knxnetip_test.go b/plc4go/cmd/main/drivers/knxnetip_test.go
index 09e63be..6104e46 100644
--- a/plc4go/cmd/main/drivers/knxnetip_test.go
+++ b/plc4go/cmd/main/drivers/knxnetip_test.go
@@ -20,12 +20,15 @@ package drivers
import (
"encoding/hex"
+ "fmt"
"plc4x.apache.org/plc4go/v0/internal/plc4go/knxnetip"
"plc4x.apache.org/plc4go/v0/internal/plc4go/knxnetip/readwrite/model"
"plc4x.apache.org/plc4go/v0/internal/plc4go/transports/udp"
"plc4x.apache.org/plc4go/v0/internal/plc4go/utils"
"plc4x.apache.org/plc4go/v0/pkg/plc4go"
+ apiModel "plc4x.apache.org/plc4go/v0/pkg/plc4go/model"
"testing"
+ "time"
)
func KnxNetIp(t *testing.T) {
@@ -52,6 +55,7 @@ func TestKnxNetIpPlc4goDriver(t *testing.T) {
// Get a connection to a remote PLC
crc := driverManager.GetConnection("knxnet-ip://192.168.42.11")
+ //crc := driverManager.GetConnection("knxnet-ip://-discover-")
// Wait for the driver to connect (or not)
connectionResult := <-crc
@@ -75,9 +79,16 @@ func TestKnxNetIpPlc4goDriver(t *testing.T) {
defer connection.Close()
// Prepare a read-request
+ pollingInterval, err := time.ParseDuration("5s")
+ if err != nil {
+ t.Errorf("invalid format")
+ t.Fail()
+ return
+ }
srb := connection.SubscriptionRequestBuilder()
srb.AddChangeOfStateItem("field1", "*/*/*")
- srb.AddChangeOfStateItem("field2", "holding-register:3:REAL")
+ srb.AddCyclicItem("field2", "holding-register:3:REAL", pollingInterval)
+ srb.AddItemHandler(knxEventHandler)
subscriptionRequest, err := srb.Build()
if err != nil {
t.Errorf("error preparing subscription-request: %s", connectionResult.Err.Error())
@@ -128,3 +139,10 @@ func TestKnxNetIpPlc4goDriver(t *testing.T) {
fmt.Printf("\n\nResult field2: %d\n", wrr.Response.GetResponseCode("field2"))*/
}
+func knxEventHandler(event apiModel.PlcSubscriptionEvent) {
+ for _, fieldName := range event.GetFieldNames() {
+ if event.GetResponseCode(fieldName) == apiModel.PlcResponseCode_OK {
+ fmt.Printf("Got update for field %s with value %s", fieldName, event.GetValue(fieldName).GetString())
+ }
+ }
+}
\ No newline at end of file
diff --git a/plc4go/internal/plc4go/model/DefaultPlcSubscriptionRequest.go b/plc4go/internal/plc4go/model/DefaultPlcSubscriptionRequest.go
index 1abb1a4..53dd8b8 100644
--- a/plc4go/internal/plc4go/model/DefaultPlcSubscriptionRequest.go
+++ b/plc4go/internal/plc4go/model/DefaultPlcSubscriptionRequest.go
@@ -19,64 +19,85 @@
package model
import (
- "encoding/xml"
- "errors"
- values2 "plc4x.apache.org/plc4go/v0/internal/plc4go/model/values"
- "plc4x.apache.org/plc4go/v0/internal/plc4go/spi"
- "plc4x.apache.org/plc4go/v0/pkg/plc4go/model"
- "plc4x.apache.org/plc4go/v0/pkg/plc4go/values"
+ "encoding/xml"
+ "errors"
+ "plc4x.apache.org/plc4go/v0/internal/plc4go/spi"
+ "plc4x.apache.org/plc4go/v0/pkg/plc4go/model"
+ "time"
+)
+
+type SubscriptionType uint8
+
+const (
+ SUBSCRIPTION_CYCLIC SubscriptionType = 0x01
+ SUBSCRIPTION_CHANGE_OF_STATE SubscriptionType = 0x02
+ SUBSCRIPTION_EVENT SubscriptionType = 0x03
)
type DefaultPlcSubscriptionRequestBuilder struct {
- subscriber spi.PlcSubscriber
- fieldHandler spi.PlcFieldHandler
- valueHandler spi.PlcValueHandler
- queries map[string]string
- values map[string]interface{}
+ subscriber spi.PlcSubscriber
+ fieldHandler spi.PlcFieldHandler
+ valueHandler spi.PlcValueHandler
+ eventHandler model.PlcSubscriptionEventHandler
+ queries map[string]string
+ types map[string]SubscriptionType
+ intervals map[string]time.Duration
}
func NewDefaultPlcSubscriptionRequestBuilder(fieldHandler spi.PlcFieldHandler, valueHandler spi.PlcValueHandler, subscriber spi.PlcSubscriber) *DefaultPlcSubscriptionRequestBuilder {
- return &DefaultPlcSubscriptionRequestBuilder{
+ return &DefaultPlcSubscriptionRequestBuilder{
subscriber: subscriber,
- fieldHandler: fieldHandler,
- valueHandler: valueHandler,
- queries: map[string]string{},
- values: map[string]interface{}{},
- }
+ fieldHandler: fieldHandler,
+ valueHandler: valueHandler,
+ queries: map[string]string{},
+ }
+}
+
+func (m *DefaultPlcSubscriptionRequestBuilder) AddCyclicItem(name string, query string, interval time.Duration) {
+ m.queries[name] = query
+ m.types[name] = SUBSCRIPTION_CYCLIC
+ m.intervals[name] = interval
+}
+
+func (m *DefaultPlcSubscriptionRequestBuilder) AddChangeOfStateItem(name string, query string) {
+ m.queries[name] = query
+ m.types[name] = SUBSCRIPTION_CHANGE_OF_STATE
}
-func (m *DefaultPlcSubscriptionRequestBuilder) AddItem(name string, query string, value interface{}) {
- m.queries[name] = query
- m.values[name] = value
+func (m *DefaultPlcSubscriptionRequestBuilder) AddEventItem(name string, query string) {
+ m.queries[name] = query
+ m.types[name] = SUBSCRIPTION_EVENT
+}
+
+func (m *DefaultPlcSubscriptionRequestBuilder) AddItemHandler(eventHandler model.PlcSubscriptionEventHandler) {
+ m.eventHandler = eventHandler
}
func (m *DefaultPlcSubscriptionRequestBuilder) Build() (model.PlcSubscriptionRequest, error) {
- fields := make(map[string]model.PlcField)
- values := make(map[string]values.PlcValue)
- for name, query := range m.queries {
- field, err := m.fieldHandler.ParseQuery(query)
- if err != nil {
- return nil, errors.New("Error parsing query: " + query + ". Got error: " + err.Error())
- }
- fields[name] = field
- value, err := m.valueHandler.NewPlcValue(field, m.values[name])
- if err != nil {
- return nil, errors.New("Error parsing value of type: " + field.GetTypeName() + ". Got error: " + err.Error())
- }
- values[name] = value
- }
- return DefaultPlcSubscriptionRequest{
- fields: fields,
- values: values,
- subscriber: m.subscriber,
- }, nil
+ fields := make(map[string]model.PlcField)
+ for name, query := range m.queries {
+ field, err := m.fieldHandler.ParseQuery(query)
+ if err != nil {
+ return nil, errors.New("Error parsing query: " + query + ". Got error: " + err.Error())
+ }
+ fields[name] = field
+ }
+ return DefaultPlcSubscriptionRequest{
+ fields: fields,
+ types: m.types,
+ intervals: m.intervals,
+ subscriber: m.subscriber,
+ eventHandler: m.eventHandler,
+ }, nil
}
type DefaultPlcSubscriptionRequest struct {
- fields map[string]model.PlcField
- values map[string]values.PlcValue
- subscriber spi.PlcSubscriber
- model.PlcSubscriptionRequest
+ fields map[string]model.PlcField
+ types map[string]SubscriptionType
+ intervals map[string]time.Duration
+ eventHandler model.PlcSubscriptionEventHandler
+ subscriber spi.PlcSubscriber
+ model.PlcSubscriptionRequest
}
func (m DefaultPlcSubscriptionRequest) Execute() <-chan model.PlcSubscriptionRequestResult {
@@ -84,77 +105,50 @@ func (m DefaultPlcSubscriptionRequest) Execute() <-chan model.PlcSubscriptionReq
}
func (m DefaultPlcSubscriptionRequest) GetFieldNames() []string {
- var fieldNames []string
- for fieldName, _ := range m.fields {
- fieldNames = append(fieldNames, fieldName)
- }
- return fieldNames
+ var fieldNames []string
+ for fieldName, _ := range m.fields {
+ fieldNames = append(fieldNames, fieldName)
+ }
+ return fieldNames
}
func (m DefaultPlcSubscriptionRequest) GetField(name string) model.PlcField {
- return m.fields[name]
+ return m.fields[name]
+}
+
+func (m DefaultPlcSubscriptionRequest) GetType(name string) SubscriptionType {
+ return m.types[name]
}
-func (m DefaultPlcSubscriptionRequest) GetValue(name string) values.PlcValue {
- return m.values[name]
+func (m DefaultPlcSubscriptionRequest) GetInterval(name string) time.Duration {
+ return m.intervals[name]
}
func (m DefaultPlcSubscriptionRequest) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
- if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: "PlcSubscriptionRequest"}}); err != nil {
- return err
- }
-
- if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: "fields"}}); err != nil {
- return err
- }
- for fieldName, field := range m.fields {
- value := m.values[fieldName]
- if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: fieldName}}); err != nil {
- return err
- }
- if err := e.EncodeElement(field, xml.StartElement{Name: xml.Name{Local: "field"}}); err != nil {
- return err
- }
- switch value.(type) {
- case values2.PlcList:
- listValue, ok := value.(values2.PlcList)
- if !ok {
- return errors.New("couldn't cast PlcValue to PlcList")
- }
- for _, subValue := range listValue.Values {
- if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: "value"}}); err != nil {
- return err
- }
- if !subValue.IsString() {
- return errors.New("value not serializable to string")
- }
- e.EncodeToken(xml.CharData(subValue.GetString()))
- if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: "value"}}); err != nil {
- return err
- }
- }
- default:
- if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: "value"}}); err != nil {
- return err
- }
- if !value.IsString() {
- return errors.New("value not serializable to string")
- }
- e.EncodeToken(xml.CharData(value.GetString()))
- if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: "value"}}); err != nil {
- return err
- }
- }
- if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: fieldName}}); err != nil {
- return err
- }
- }
- if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: "fields"}}); err != nil {
- return err
- }
-
- if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: "PlcSubscriptionRequest"}}); err != nil {
- return err
- }
- return nil
+ if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: "PlcSubscriptionRequest"}}); err != nil {
+ return err
+ }
+
+ if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: "fields"}}); err != nil {
+ return err
+ }
+ for fieldName, field := range m.fields {
+ if err := e.EncodeToken(xml.StartElement{Name: xml.Name{Local: fieldName}}); err != nil {
+ return err
+ }
+ if err := e.EncodeElement(field, xml.StartElement{Name: xml.Name{Local: "field"}}); err != nil {
+ return err
+ }
+ if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: fieldName}}); err != nil {
+ return err
+ }
+ }
+ if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: "fields"}}); err != nil {
+ return err
+ }
+
+ if err := e.EncodeToken(xml.EndElement{Name: xml.Name{Local: "PlcSubscriptionRequest"}}); err != nil {
+ return err
+ }
+ return nil
}
diff --git a/plc4go/pkg/plc4go/model/plc_subscription_event.go b/plc4go/pkg/plc4go/model/plc_subscription_event.go
index 773175b..50ae9b8 100644
--- a/plc4go/pkg/plc4go/model/plc_subscription_event.go
+++ b/plc4go/pkg/plc4go/model/plc_subscription_event.go
@@ -17,3 +17,14 @@
// under the License.
//
package model
+
+import "plc4x.apache.org/plc4go/v0/pkg/plc4go/values"
+
+type PlcSubscriptionEvent interface {
+ GetRequest() PlcSubscriptionRequest
+ GetFieldNames() []string
+ GetResponseCode(name string) PlcResponseCode
+ GetValue(name string) values.PlcValue
+ PlcResponse
+}
+
diff --git a/plc4go/pkg/plc4go/model/plc_subscription_request.go b/plc4go/pkg/plc4go/model/plc_subscription_request.go
index 6b3c398..1c5b96c 100644
--- a/plc4go/pkg/plc4go/model/plc_subscription_request.go
+++ b/plc4go/pkg/plc4go/model/plc_subscription_request.go
@@ -20,20 +20,23 @@ package model
import "time"
+type PlcSubscriptionEventHandler func(event PlcSubscriptionEvent)
+
type PlcSubscriptionRequestBuilder interface {
- AddCyclicItem(name string, query string, interval time.Duration)
- AddChangeOfStateItem(name string, query string)
- AddEventItem(name string, query string)
- Build() (PlcSubscriptionRequest, error)
+ AddCyclicItem(name string, query string, interval time.Duration)
+ AddChangeOfStateItem(name string, query string)
+ AddEventItem(name string, query string)
+ AddItemHandler(handler PlcSubscriptionEventHandler)
+ Build() (PlcSubscriptionRequest, error)
}
type PlcSubscriptionRequestResult struct {
- Request PlcSubscriptionRequest
- Response PlcSubscriptionResponse
- Err error
+ Request PlcSubscriptionRequest
+ Response PlcSubscriptionResponse
+ Err error
}
type PlcSubscriptionRequest interface {
- Execute() <-chan PlcSubscriptionRequestResult
- PlcRequest
+ Execute() <-chan PlcSubscriptionRequestResult
+ PlcRequest
}
[plc4x] 02/02: - Started implementing discovery for KNX
Posted by cd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch feature/plc4go
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit da01c447f60836dba0dafa18aaa4b2020a982d80
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon Nov 9 16:37:21 2020 +0100
- Started implementing discovery for KNX
---
plc4go/internal/plc4go/knxnetip/KnxNetIpDriver.go | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/plc4go/internal/plc4go/knxnetip/KnxNetIpDriver.go b/plc4go/internal/plc4go/knxnetip/KnxNetIpDriver.go
index 6ccdc84..7a30edc 100644
--- a/plc4go/internal/plc4go/knxnetip/KnxNetIpDriver.go
+++ b/plc4go/internal/plc4go/knxnetip/KnxNetIpDriver.go
@@ -56,6 +56,12 @@ func (m KnxNetIpDriver) CheckQuery(query string) error {
}
func (m KnxNetIpDriver) GetConnection(transportUrl url.URL, transports map[string]transports.Transport, options map[string][]string) <-chan plc4go.PlcConnectionConnectResult {
+ // If the host is set to "discover", use the KNX discovery mechanism
+ if transportUrl.Host == "-discover-" {
+ // Multicast address every KNX gateway is required to respond to.
+ transportUrl.Host = "224.0.23.12"
+ }
+
// Get an the transport specified in the url
transport, ok := transports[transportUrl.Scheme]
if !ok {