diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml index 8e4007c5..6a41f08d 100644 --- a/.github/workflows/default.yml +++ b/.github/workflows/default.yml @@ -18,18 +18,18 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v5 with: - go-version: ^1.18 + go-version: ^1.21 - name: Build run: go build -v ./... - name: Lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@master with: version: latest skip-pkg-cache: true @@ -37,9 +37,23 @@ jobs: args: --timeout=3m --issues-exit-code=0 ./... - name: Test - run: go test -race -v -coverprofile=coverage.out -covermode=atomic ./... + run: go test -race -v -coverprofile=coverage_temp.out -covermode=atomic ./... + + - name: Remove mocks and cmd from coverage + run: grep -v -e "/eebus-go/mocks/" -e "/eebus-go/cmd/" coverage_temp.out > coverage.out - name: Send coverage - uses: shogo82148/actions-goveralls@v1 + uses: coverallsapp/github-action@v2 + with: + file: coverage.out + + - name: Run Gosec Security Scanner + uses: securego/gosec@master + with: + # we let the report trigger content trigger a failure using the GitHub Security features. + args: '-no-fail -fmt sarif -out results.sarif ./...' + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v3 with: - path-to-profile: coverage.out \ No newline at end of file + # Path to SARIF file relative to the root of the repository + sarif_file: results.sarif \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..dd9bcca0 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,58 @@ +run: + # timeout for analysis, e.g. 30s, 5m, default is 1m + timeout: 5m + + # include test files or not, default is true + tests: true + + # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": + # If invoked with -mod=readonly, the go command is disallowed from the implicit + # automatic updating of go.mod described above. Instead, it fails when any changes + # to go.mod are needed. This setting is most useful to check that go.mod does + # not need updates, such as in a continuous integration and testing system. + # If invoked with -mod=vendor, the go command assumes that the vendor + # directory holds the correct copies of dependencies and ignores + # the dependency descriptions in go.mod. + modules-download-mode: readonly + +# output configuration options +output: + # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" + formats: + - format: colored-line-number + +linters: + enable: + - bodyclose + - errcheck + - errorlint + - gocheckcompilerdirectives + - gochecknoinits + - gochecksumtype + - goconst + - gofmt + - gosimple + - gosec + - govet + - nilerr + - nilnil + - staticcheck + - typecheck + - unused + - whitespace + +issues: + # Excluding configuration per-path, per-linter, per-text and per-source + exclude-rules: + # Exclude some linters from running on tests files. + - path: _test\.go + linters: + - errcheck + - goconst + - gosec + + # checking for errors in defers seldom makes sense... + - source: "^\\s*defer\\s" + linters: + - errcheck + - staticcheck diff --git a/.mockery.yaml b/.mockery.yaml new file mode 100644 index 00000000..d4b533e7 --- /dev/null +++ b/.mockery.yaml @@ -0,0 +1,10 @@ +with-expecter: True +inpackage: false +dir: "{{ .InterfaceDir }}/../mocks" +mockname: "{{.InterfaceName}}" +outpkg: "mocks" +filename: "{{.InterfaceName}}.go" +all: True +packages: + github.com/enbility/eebus-go/api: + github.com/enbility/eebus-go/features: diff --git a/LICENSE b/LICENSE index 311758a5..34e447e7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT license Copyright (c) 2022 Andreas Linde & Timo Vogel +Copyright (c) 2023-2024 Andreas Linde Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 62f2718e..ab25b701 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,32 @@ # eebus-go -[![Build Status](https://github.com/enbility/eebus-go/actions/workflows/default.yml/badge.svg?branch=dev)](https://github.com/enbility/eebus-go/actions/workflows/default.yml/badge.svg?branch=dev) +[![Build Status](https://github.com/enbility/eebus-go/actions/workflows/default.yml/badge.svg?branch=main)](https://github.com/enbility/eebus-go/actions/workflows/default.yml/badge.svg?branch=main) [![GoDoc](https://img.shields.io/badge/godoc-reference-5272B4)](https://godoc.org/github.com/enbility/eebus-go) -[![Coverage Status](https://coveralls.io/repos/github/enbility/eebus-go/badge.svg?branch=dev)](https://coveralls.io/github/enbility/eebus-go?branch=dev) +[![Coverage Status](https://coveralls.io/repos/github/enbility/eebus-go/badge.svg?branch=main)](https://coveralls.io/github/enbility/eebus-go?branch=main) [![Go report](https://goreportcard.com/badge/github.com/enbility/eebus-go)](https://goreportcard.com/report/github.com/enbility/eebus-go) +[![CodeFactor](https://www.codefactor.io/repository/github/enbility/eebus-go/badge)](https://www.codefactor.io/repository/github/enbility/eebus-go) -This library provides a complete foundation for implementing [EEBUS](https://eebus.org) use cases. The use cases define various functional scenarios for different device categories, e.g. energy management systems, charging stations, heat pumps, and more. +This library provides a foundation for implementing [EEBUS](https://eebus.org) use cases in [go](https://golang.org). It uses the SHIP implementation [ship-go](https://github.com/enbility/ship-go) and the SPINE implementation [spine-go](https://github.com/enbility/spine-go). Both repositories started as part of this repository, before they were moved into their own separate repositories and go packages. + +Basic understanding of the EEBUS concepts SHIP and SPINE to use this library is required. Please check the corresponding specifications on the [EEBUS downloads website](https://www.eebus.org/media-downloads/). ## Introduction The supported functionality contains: -- Support for SHIP 1.0.1 -- Support for big parts of SPINE 1.1.1 -- (De-)serialization for EEBUS specific JSON format requirements +- Support for SHIP 1.0.1 via [ship-go](https://github.com/enbility/ship-go) +- Support for SPINE 1.3.0 via [spine-go](https://github.com/enbility/spine-go) - Certificate handling -- mDNS Support, incl. avahi support (recommended) +- mDNS Support, incl. avahi support - Connection (websocket) handling, including reconnection and double connections - Support for handling pairing of devices -Basic understanding of the EEBUS concepts SHIP and SPINE to use this library is required. Please check the corresponding specifications on the [EEBUS downloads website](https://www.eebus.org/media-downloads/). +## Packages -An open source SDK written in go providing the foundation to use EEBUS in your projects. Contains support for SHIP and SPINE communication. +- `api`: global API interface definitions and eebus service configuration +- `features`: provides feature helpers with the local SPINE feature having the client role and the remote SPINE feature being the server for easy access to commonly used functions +- `service`: central package which provides access to SHIP and SPINE. Use this to create the EEBUS service, its configuration and connect to remote EEBUS services +- `util`: package with various useful helper functions ## Usage @@ -85,6 +90,9 @@ If no certfile or keyfile are provided, they are generated and printed in the co - Double connection handling is not implemented according to SHIP 12.2.2. Instead the connection initiated by the higher SKI will be kept. Much simpler and always works - PIN Verification is _NOT_ supported other than SHIP 13.4.4.3.5.1 _"none"_ PIN state is supported! - Access Methods SHIP 13.4.6 only supports the most basic scenario and only works after PIN verification state is completed. +- Supported registration mechanisms (SHIP 5): + - auto accept (without any interaction mechanism!) + - user verification This approach has been tested with: @@ -92,151 +100,11 @@ This approach has been tested with: - Porsche Mobile Charger Connect - SMA Home Energy Manager 2.0 -## Roadmap - Spine specification implementation - -### General request processing - -- [X] Request and process full data -- [ ] Request partial data - - [ ] Delete Selectors - - [ ] Update Selectors - - [ ] Elements -- [ ] Send - - [X] Full data - - [ ] Partial data -- [X] Process partial data - - [X] Delete Selectors - - [X] Update Selectors - - [X] Elements -- [ ] Request types - - [X] Read - - [ ] Send - - [X] Full Request - - [ ] Partial Request - - [ ] Partial Delete - - [X] Receive - - [X] Full Request - - [X] Partial Request - - [X] Partial Delete - - [X] Reply - - [ ] Send - - [X] Full Request - - [ ] Partial Request - - [ ] Partial Delete - - [X] Receive - - [X] Full Request - - [X] Partial Request - - [X] Partial Delete - - [X] Notify - - [ ] Send - - [X] Full Request - - [ ] Partial Request - - [ ] Partial Delete - - [X] Receive - - [X] Full Request - - [X] Partial Request - - [X] Partial Delete - - [X] Write - - [ ] Send - - [X] Full Request - - [ ] Partial Request - - [ ] Partial Delete - - [X] Receive - - [X] Full Request - - [X] Partial Request - - [X] Partial Delete -- [X] Result message handling - - [X] Handle incoming error results - - [X] Handle incoming success results - - [X] Respond with error result when processing failed -- [X] Acknowledgement support - - [X] Request - - [X] Respond -- [x] Use maximum response delay to timeout requests - -### Node Management - -- [ ] Detailed Discovery - - [ ] Read Messages - - [ ] Send - - [X] Full Request - - [ ] Partial Request - - [X] Receive - - [X] Full Request - - [X] Partial Request - - [ ] Reply Messages - - [ ] Send - - [X] Full Request - - [ ] Partial Request - - [X] Receive - - [X] Full Request - - [X] Partial Request - - [ ] Notify Messages - - [ ] Send - - [X] Full Request - - [ ] Partial Request - - [X] Receive - - [X] Full Request - - [X] Partial Request -- [ ] Destination List - - [ ] Request and process full data - - [X] Response full data - - [ ] Request and process partial data - - [ ] Response partial data - - [ ] Notify subscribers -- [ ] Binding - - [ ] Send Requests - - [X] Add Binding - - [ ] Delete Binding - - [X] Receive Requests - - [X] Add Binding - - [X] Delete Binding -- [ ] Subscription - - [ ] Send Requests - - [X] Add Subscription - - [ ] Delete Subscription - - [X] Receive Requests - - [X] Add Subscription - - [X] Delete Subscription - - [X] Notify subscribers -- [ ] Use Case Discovery - - [ ] Read Messages - - [ ] Send - - [X] Full Request - - [ ] Partial Request - - [X] Receive - - [X] Full Request - - [X] Partial Request - - [ ] Reply Messages - - [ ] Send - - [X] Full Request - - [ ] Partial Request - - [X] Receive - - [X] Full Request - - [X] Partial Request - - [ ] Notify Messages - - [ ] Send - - [X] Full Request - - [ ] Partial Request - - [X] Receive - - [X] Full Request - - [X] Partial Request - -### General feature implementation - -- [ ] Hearbeat Support - - [X] Send hearbeats - - [ ] Receive hearbeats - -### Partial, selector, elements support - -All list types do support processing of incoming partial messages, including selectors and elements. Sending partial messages is possible but there is no special support implemented right now. - ## Interfaces ### Verbose logging -Use `SetLogger` on `Service` to set the logger which needs to conform to the `logging.Logging` interface. +Use `SetLogger` on `Service` to set the logger which needs to conform to the `logging.Logging` interface of [ship-go](https://github.com/enbility/ship-go). Example: diff --git a/api/api.go b/api/api.go new file mode 100644 index 00000000..1f06faa2 --- /dev/null +++ b/api/api.go @@ -0,0 +1,105 @@ +package api + +import ( + "github.com/enbility/ship-go/logging" + + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" +) + +//go:generate mockery + +/* Service */ + +// central service interface +// +// implemented by service, used by the eebus service implementation +type ServiceInterface interface { + // setup the service + Setup() error + + // start the service + Start() + + // shutdown the service + Shutdown() + + // set logging interface + SetLogging(logger logging.LoggingInterface) + + // return the configuration + Configuration() *Configuration + + // return the local service details + LocalService() *shipapi.ServiceDetails + + // return the local device + LocalDevice() spineapi.DeviceLocalInterface + + // Passthough functions to HubInterface + + // Provide the current pairing state for a SKI + PairingDetailForSki(ski string) *shipapi.ConnectionStateDetail + + // Defines wether incoming pairing requests should be automatically accepted or not + // + // Default: false + SetAutoAccept(value bool) + + // Returns if the service has auto accept enabled or not + IsAutoAcceptEnabled() bool + + // Returns the Service detail of a remote SKI + RemoteServiceForSKI(ski string) *shipapi.ServiceDetails + + // Sets the SKI as being paired + RegisterRemoteSKI(ski string) + + // Sets the SKI as not being paired + UnregisterRemoteSKI(ski string) + + // Disconnect from a connected remote SKI + DisconnectSKI(ski string, reason string) + + // Cancels the pairing process for a SKI + // + // This should be called while the service is running and the end + // user wants to cancel/disallow an incoming pairing request + CancelPairingWithSKI(ski string) + + // Define wether the user is able to react to an incoming pairing request + // + // Call this with `true` e.g. if the user is currently using a web interface + // where an incoming request can be accepted or denied + // + // Default is set to false, meaning every incoming pairing request will be + // automatically denied + UserIsAbleToApproveOrCancelPairingRequests(allow bool) +} + +// interface for receiving data for specific events from Service +// +// some are passthrough readers, because service needs to coordinate +// everything with SPINE +// +// implemented by the eebus service implementation, used by service +type ServiceReaderInterface interface { + // report a connection to a SKI + RemoteSKIConnected(service ServiceInterface, ski string) + + // report a disconnection to a SKI + RemoteSKIDisconnected(service ServiceInterface, ski string) + + // report all currently visible EEBUS services + VisibleRemoteServicesUpdated(service ServiceInterface, entries []shipapi.RemoteService) + + // Provides the SHIP ID the remote service reported during the handshake process + // This needs to be persisted and passed on for future remote service connections + // when using `PairRemoteService` + ServiceShipIDUpdate(ski string, shipdID string) + + // Provides the current pairing state for the remote service + // This is called whenever the state changes and can be used to + // provide user information for the pairing/connection process + ServicePairingDetailUpdate(ski string, detail *shipapi.ConnectionStateDetail) +} diff --git a/service/types.go b/api/configuration.go similarity index 63% rename from service/types.go rename to api/configuration.go index 4434fe9e..9d5f40c8 100644 --- a/service/types.go +++ b/api/configuration.go @@ -1,87 +1,16 @@ -package service +package api import ( "crypto/tls" "fmt" + "time" - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" + "github.com/enbility/ship-go/mdns" + "github.com/enbility/spine-go/model" ) const defaultPort int = 4711 -// generic service details about the local or any remote service -type ServiceDetails struct { - // This is the SKI of the service - // This needs to be persisted - ski string - - // This is the IPv4 address of the device running the service - // This is optional only needed when this runs with - // zeroconf as mDNS and the remote device is using the latest - // avahi version and thus zeroconf can sometimes not detect - // the IPv4 address and not initiate a connection - ipv4 string - - // shipID is the SHIP identifier of the service - // This needs to be persisted - shipID string - - // The EEBUS device type of the device model - deviceType model.DeviceTypeType - - // Flags if the service auto auto accepts other services - registerAutoAccept bool -} - -// create a new ServiceDetails record with a SKI -func NewServiceDetails(ski string) *ServiceDetails { - service := &ServiceDetails{ - ski: util.NormalizeSKI(ski), // standardize the provided SKI strings - } - - return service -} - -// return the services SKI -func (s *ServiceDetails) SKI() string { - return s.ski -} - -// SHIP ID is the ship identifier of the service -func (s *ServiceDetails) SetShipID(shipId string) { - s.shipID = shipId -} - -// Return the services SHIP ID -func (s *ServiceDetails) ShipID() string { - return s.shipID -} - -func (s *ServiceDetails) SetIPv4(ipv4 string) { - s.ipv4 = ipv4 -} - -func (s *ServiceDetails) IPv4() string { - return s.ipv4 -} - -func (s *ServiceDetails) SetDeviceType(deviceType model.DeviceTypeType) { - s.deviceType = deviceType -} - -func (s *ServiceDetails) DeviceType() model.DeviceTypeType { - return s.deviceType -} - -func (s *ServiceDetails) SetRegisterAutoAccept(auto bool) { - s.registerAutoAccept = auto -} - -func (s *ServiceDetails) RegisterAutoAccept() bool { - return s.registerAutoAccept -} - // defines requires meta information about this service type Configuration struct { // The vendors IANA PEN, optional but highly recommended. @@ -121,6 +50,10 @@ type Configuration struct { // SPINE Protocol Specification 6 featureSet model.NetworkManagementFeatureSetType + // SPINE entity types for each entity that should be created + // Each entity has to have a different type! + entityTypes []model.EntityTypeType + // Network interface to use for the service // Optional, if not set all detected interfaces will be used interfaces []string @@ -131,19 +64,16 @@ type Configuration struct { // The certificate used for the service and its connections, required certificate tls.Certificate - // Wether remote devices should be automatically accepted - // If enabled will automatically search for other services with - // the same setting and automatically connect to them. - // Has to be set on configuring the service! - // TODO: if disabled, user verification needs to be implemented and supported - // the spec defines that this should have a timeout and be activate - // e.g via a physical button - registerAutoAccept bool - // The sites grid voltage // This is useful when e.g. power values are not available and therefor // need to be calculated using the current values voltage float64 + + // The timeout to be used for sending heartbeats + heartbeatTimeout time.Duration + + // Optional set which mDNS providers should be used + mdnsProviderSelection mdns.MdnsProviderSelection } // Setup a Configuration with the required parameters @@ -153,43 +83,55 @@ func NewConfiguration( deviceModel, serialNumber string, deviceType model.DeviceTypeType, + entityTypes []model.EntityTypeType, port int, certificate tls.Certificate, voltage float64, + heartbeatTimeout time.Duration, ) (*Configuration, error) { configuration := &Configuration{ - certificate: certificate, - port: port, - voltage: voltage, + certificate: certificate, + port: port, + voltage: voltage, + heartbeatTimeout: heartbeatTimeout, + mdnsProviderSelection: mdns.MdnsProviderSelectionGoZeroConfOnly, + } + + if port == 0 { + configuration.port = defaultPort } isRequired := "is required" if len(vendorCode) == 0 { return nil, fmt.Errorf("vendorCode %s", isRequired) - } else { - configuration.vendorCode = vendorCode } + configuration.vendorCode = vendorCode + if len(deviceBrand) == 0 { return nil, fmt.Errorf("brand %s", isRequired) - } else { - configuration.deviceBrand = deviceBrand } + configuration.deviceBrand = deviceBrand + if len(deviceModel) == 0 { return nil, fmt.Errorf("model %s", isRequired) - } else { - configuration.deviceModel = deviceModel } + configuration.deviceModel = deviceModel + if len(serialNumber) == 0 { return nil, fmt.Errorf("serialNumber %s", isRequired) - } else { - configuration.deviceSerialNumber = serialNumber } + configuration.deviceSerialNumber = serialNumber + if len(deviceType) == 0 { return nil, fmt.Errorf("deviceType %s", isRequired) - } else { - configuration.deviceType = deviceType } + configuration.deviceType = deviceType + + if len(entityTypes) == 0 { + return nil, fmt.Errorf("entityTypes %s", isRequired) + } + configuration.entityTypes = entityTypes // set default configuration.featureSet = model.NetworkManagementFeatureSetTypeSmart @@ -197,6 +139,22 @@ func NewConfiguration( return configuration, nil } +func (s *Configuration) VendorCode() string { + return s.vendorCode +} + +func (s *Configuration) DeviceBrand() string { + return s.deviceBrand +} + +func (s *Configuration) DeviceModel() string { + return s.deviceModel +} + +func (s *Configuration) DeviceSerialNumber() string { + return s.deviceSerialNumber +} + // define an alternative mDNS and SHIP identifier // usually this is only used when no deviceCode is available or identical to the brand // if this is not set, generated identifier is used @@ -210,18 +168,36 @@ func (s *Configuration) SetAlternateMdnsServiceName(name string) { s.alternateMdnsServiceName = name } +func (s *Configuration) SetMdnsProviderSelection(providerSelection mdns.MdnsProviderSelection) { + s.mdnsProviderSelection = providerSelection +} + +func (s *Configuration) MdnsProviderSelection() mdns.MdnsProviderSelection { + return s.mdnsProviderSelection +} + +func (s *Configuration) DeviceType() model.DeviceTypeType { + return s.deviceType +} + +func (s *Configuration) FeatureSet() model.NetworkManagementFeatureSetType { + return s.featureSet +} + +func (s *Configuration) EntityTypes() []model.EntityTypeType { + return s.entityTypes +} + +func (s *Configuration) Interfaces() []string { + return s.interfaces +} + // define which network interfaces should be considered instead of all existing // expects a list of network interface names func (s *Configuration) SetInterfaces(ifaces []string) { s.interfaces = ifaces } -// define wether this service should announce auto accept -// TODO: this needs to be redesigned! -func (s *Configuration) SetRegisterAutoAccept(auto bool) { - s.registerAutoAccept = auto -} - // generates a standard identifier used for mDNS ID and SHIP ID // Brand-Model-SerialNumber func (s *Configuration) generateIdentifier() string { @@ -254,7 +230,23 @@ func (s *Configuration) MdnsServiceName() string { return s.generateIdentifier() } +func (s *Configuration) Certificate() tls.Certificate { + return s.certificate +} + +func (s *Configuration) Port() int { + return s.port +} + +func (s *Configuration) SetCertificate(cert tls.Certificate) { + s.certificate = cert +} + // return the sites predefined grid voltage func (s *Configuration) Voltage() float64 { return s.voltage } + +func (s *Configuration) HeartbeatTimeout() time.Duration { + return s.heartbeatTimeout +} diff --git a/api/configuration_test.go b/api/configuration_test.go new file mode 100644 index 00000000..6b2e388c --- /dev/null +++ b/api/configuration_test.go @@ -0,0 +1,146 @@ +package api + +import ( + "crypto/tls" + "testing" + "time" + + "github.com/enbility/ship-go/cert" + "github.com/enbility/ship-go/mdns" + spinemodel "github.com/enbility/spine-go/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestConfigurationSuite(t *testing.T) { + suite.Run(t, new(ConfigurationSuite)) +} + +type ConfigurationSuite struct { + suite.Suite +} + +func (s *ConfigurationSuite) Test_Configuration() { + certificate, _ := cert.CreateCertificate("unit", "org", "DE", "CN") + vendor := "vendor" + brand := "brand" + model := "model" + serial := "serial" + port := 4567 + volt := 230.0 + heartbeatTimeout := time.Second * 4 + entityTypes := []spinemodel.EntityTypeType{spinemodel.EntityTypeTypeCEM} + + config, err := NewConfiguration("", brand, model, serial, spinemodel.DeviceTypeTypeEnergyManagementSystem, + entityTypes, 0, certificate, volt, heartbeatTimeout) + + assert.Nil(s.T(), config) + assert.NotNil(s.T(), err) + + config, err = NewConfiguration("", brand, model, serial, spinemodel.DeviceTypeTypeEnergyManagementSystem, + entityTypes, port, certificate, volt, heartbeatTimeout) + + assert.Nil(s.T(), config) + assert.NotNil(s.T(), err) + + config, err = NewConfiguration(vendor, "", model, serial, spinemodel.DeviceTypeTypeEnergyManagementSystem, + entityTypes, port, certificate, 230, heartbeatTimeout) + + assert.Nil(s.T(), config) + assert.NotNil(s.T(), err) + + config, err = NewConfiguration(vendor, brand, "", serial, spinemodel.DeviceTypeTypeEnergyManagementSystem, + entityTypes, port, certificate, 230, heartbeatTimeout) + + assert.Nil(s.T(), config) + assert.NotNil(s.T(), err) + + config, err = NewConfiguration(vendor, brand, model, "", spinemodel.DeviceTypeTypeEnergyManagementSystem, + entityTypes, port, certificate, 230, heartbeatTimeout) + + assert.Nil(s.T(), config) + assert.NotNil(s.T(), err) + + config, err = NewConfiguration(vendor, brand, model, serial, "", + entityTypes, port, certificate, 230, heartbeatTimeout) + + assert.Nil(s.T(), config) + assert.NotNil(s.T(), err) + + config, err = NewConfiguration(vendor, brand, model, serial, spinemodel.DeviceTypeTypeEnergyManagementSystem, + []spinemodel.EntityTypeType{}, port, certificate, 230, heartbeatTimeout) + + assert.Nil(s.T(), config) + assert.NotNil(s.T(), err) + + config, err = NewConfiguration(vendor, brand, model, serial, spinemodel.DeviceTypeTypeEnergyManagementSystem, + entityTypes, port, certificate, 230, heartbeatTimeout) + + assert.NotNil(s.T(), config) + assert.Nil(s.T(), err) + + assert.Equal(s.T(), mdns.MdnsProviderSelectionGoZeroConfOnly, config.MdnsProviderSelection()) + + config.SetMdnsProviderSelection(mdns.MdnsProviderSelectionAvahiOnly) + assert.Equal(s.T(), mdns.MdnsProviderSelectionAvahiOnly, config.MdnsProviderSelection()) + + ifaces := []string{"lo", "eth0"} + config.SetInterfaces(ifaces) + assert.Equal(s.T(), 2, len(config.interfaces)) + + ifacesValue := config.Interfaces() + assert.Equal(s.T(), ifaces, ifacesValue) + + id := config.generateIdentifier() + assert.NotEqual(s.T(), "", id) + + id = config.Identifier() + assert.NotEqual(s.T(), "", id) + + id = config.MdnsServiceName() + assert.NotEqual(s.T(), "", id) + + alternate := "alternate" + + config.SetAlternateIdentifier(alternate) + id = config.Identifier() + assert.Equal(s.T(), alternate, id) + + config.SetAlternateMdnsServiceName(alternate) + id = config.MdnsServiceName() + assert.Equal(s.T(), alternate, id) + + voltage := config.Voltage() + assert.Equal(s.T(), volt, voltage) + + portValue := config.Port() + assert.Equal(s.T(), port, portValue) + + heartbeatValue := config.HeartbeatTimeout() + assert.Equal(s.T(), heartbeatTimeout, heartbeatValue) + + vendorValue := config.VendorCode() + assert.Equal(s.T(), vendor, vendorValue) + + deviceValue := config.DeviceBrand() + assert.Equal(s.T(), brand, deviceValue) + + modelValue := config.DeviceModel() + assert.Equal(s.T(), model, modelValue) + + serialValue := config.DeviceSerialNumber() + assert.Equal(s.T(), serial, serialValue) + + deviceTypeValue := config.DeviceType() + assert.Equal(s.T(), spinemodel.DeviceTypeTypeEnergyManagementSystem, deviceTypeValue) + + entityValues := config.EntityTypes() + assert.Equal(s.T(), entityTypes, entityValues) + featuresetValue := config.FeatureSet() + assert.Equal(s.T(), spinemodel.NetworkManagementFeatureSetTypeSmart, featuresetValue) + + testCert := tls.Certificate{} + config.SetCertificate(testCert) + certValue := config.Certificate() + assert.Equal(s.T(), testCert, certValue) +} diff --git a/features/errors.go b/api/errors.go similarity index 98% rename from features/errors.go rename to api/errors.go index 39f87c29..59200057 100644 --- a/features/errors.go +++ b/api/errors.go @@ -1,4 +1,4 @@ -package features +package api import "errors" diff --git a/cmd/evse/main.go b/cmd/evse/main.go index 73729d09..26f180b9 100644 --- a/cmd/evse/main.go +++ b/cmd/evse/main.go @@ -13,18 +13,22 @@ import ( "syscall" "time" + "github.com/enbility/eebus-go/api" "github.com/enbility/eebus-go/service" - "github.com/enbility/eebus-go/spine/model" + shipapi "github.com/enbility/ship-go/api" + "github.com/enbility/ship-go/cert" + "github.com/enbility/spine-go/model" ) +var remoteSki string + type evse struct { - myService *service.EEBUSService + myService *service.Service } func (h *evse) run() { var err error var certificate tls.Certificate - var remoteSki string if len(os.Args) == 5 { remoteSki = os.Args[2] @@ -35,7 +39,7 @@ func (h *evse) run() { log.Fatal(err) } } else { - certificate, err = service.CreateCertificate("Demo", "Demo", "DE", "Demo-Unit-02") + certificate, err = cert.CreateCertificate("Demo", "Demo", "DE", "Demo-Unit-02") if err != nil { log.Fatal(err) } @@ -60,15 +64,17 @@ func (h *evse) run() { log.Fatal(err) } - configuration, err := service.NewConfiguration( + configuration, err := api.NewConfiguration( "Demo", "Demo", "EVSE", "234567890", - model.DeviceTypeTypeChargingStation, port, certificate, 230) + model.DeviceTypeTypeChargingStation, + []model.EntityTypeType{model.EntityTypeTypeEVSE}, + port, certificate, 230, time.Second*4) if err != nil { log.Fatal(err) } configuration.SetAlternateIdentifier("Demo-EVSE-234567890") - h.myService = service.NewEEBUSService(configuration, h) + h.myService = service.NewService(configuration, h) h.myService.SetLogging(h) if err = h.myService.Setup(); err != nil { @@ -80,20 +86,36 @@ func (h *evse) run() { os.Exit(0) } + h.myService.RegisterRemoteSKI(remoteSki) + h.myService.Start() // defer h.myService.Shutdown() - - remoteService := service.NewServiceDetails(remoteSki) - h.myService.PairRemoteService(remoteService) } // EEBUSServiceHandler -func (h *evse) RemoteSKIConnected(service *service.EEBUSService, ski string) {} +func (h *evse) RemoteSKIConnected(service api.ServiceInterface, ski string) {} + +func (h *evse) RemoteSKIDisconnected(service api.ServiceInterface, ski string) {} + +func (h *evse) VisibleRemoteServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteService) { +} -func (h *evse) RemoteSKIDisconnected(service *service.EEBUSService, ski string) {} +func (h *evse) ServiceShipIDUpdate(ski string, shipdID string) {} -func (h *evse) ReportServiceShipID(ski string, shipdID string) {} +func (h *evse) ServicePairingDetailUpdate(ski string, detail *shipapi.ConnectionStateDetail) { + if ski == remoteSki && detail.State() == shipapi.ConnectionStateRemoteDeniedTrust { + fmt.Println("The remote service denied trust. Exiting.") + h.myService.CancelPairingWithSKI(ski) + h.myService.UnregisterRemoteSKI(ski) + h.myService.Shutdown() + os.Exit(0) + } +} + +func (h *evse) AllowWaitingForTrust(ski string) bool { + return ski == remoteSki +} // main app func usage() { diff --git a/cmd/hems/main.go b/cmd/hems/main.go index 2f61f1e9..354805ec 100644 --- a/cmd/hems/main.go +++ b/cmd/hems/main.go @@ -13,18 +13,22 @@ import ( "syscall" "time" + "github.com/enbility/eebus-go/api" "github.com/enbility/eebus-go/service" - "github.com/enbility/eebus-go/spine/model" + shipapi "github.com/enbility/ship-go/api" + "github.com/enbility/ship-go/cert" + "github.com/enbility/spine-go/model" ) +var remoteSki string + type hems struct { - myService *service.EEBUSService + myService *service.Service } func (h *hems) run() { var err error var certificate tls.Certificate - var remoteSki string if len(os.Args) == 5 { remoteSki = os.Args[2] @@ -35,7 +39,7 @@ func (h *hems) run() { log.Fatal(err) } } else { - certificate, err = service.CreateCertificate("Demo", "Demo", "DE", "Demo-Unit-01") + certificate, err = cert.CreateCertificate("Demo", "Demo", "DE", "Demo-Unit-01") if err != nil { log.Fatal(err) } @@ -60,15 +64,17 @@ func (h *hems) run() { log.Fatal(err) } - configuration, err := service.NewConfiguration( + configuration, err := api.NewConfiguration( "Demo", "Demo", "HEMS", "123456789", - model.DeviceTypeTypeEnergyManagementSystem, port, certificate, 230) + model.DeviceTypeTypeEnergyManagementSystem, + []model.EntityTypeType{model.EntityTypeTypeCEM}, + port, certificate, 230, time.Second*4) if err != nil { log.Fatal(err) } configuration.SetAlternateIdentifier("Demo-HEMS-123456789") - h.myService = service.NewEEBUSService(configuration, h) + h.myService = service.NewService(configuration, h) h.myService.SetLogging(h) if err = h.myService.Setup(); err != nil { @@ -80,20 +86,36 @@ func (h *hems) run() { os.Exit(0) } + h.myService.RegisterRemoteSKI(remoteSki) + h.myService.Start() // defer h.myService.Shutdown() - - remoteService := service.NewServiceDetails(remoteSki) - h.myService.PairRemoteService(remoteService) } // EEBUSServiceHandler -func (h *hems) RemoteSKIConnected(service *service.EEBUSService, ski string) {} +func (h *hems) RemoteSKIConnected(service api.ServiceInterface, ski string) {} + +func (h *hems) RemoteSKIDisconnected(service api.ServiceInterface, ski string) {} + +func (h *hems) VisibleRemoteServicesUpdated(service api.ServiceInterface, entries []shipapi.RemoteService) { +} -func (h *hems) RemoteSKIDisconnected(service *service.EEBUSService, ski string) {} +func (h *hems) ServiceShipIDUpdate(ski string, shipdID string) {} -func (h *hems) ReportServiceShipID(ski string, shipdID string) {} +func (h *hems) ServicePairingDetailUpdate(ski string, detail *shipapi.ConnectionStateDetail) { + if ski == remoteSki && detail.State() == shipapi.ConnectionStateRemoteDeniedTrust { + fmt.Println("The remote service denied trust. Exiting.") + h.myService.CancelPairingWithSKI(ski) + h.myService.UnregisterRemoteSKI(ski) + h.myService.Shutdown() + os.Exit(0) + } +} + +func (h *hems) AllowWaitingForTrust(ski string) bool { + return ski == remoteSki +} // UCEvseCommisioningConfigurationCemDelegate diff --git a/features/api.go b/features/api.go new file mode 100644 index 00000000..edb4db43 --- /dev/null +++ b/features/api.go @@ -0,0 +1,27 @@ +package features + +import ( + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" +) + +// Feature interface were the local feature role is client and the remote feature role is server +type FeatureInterface interface { + // check if there is a subscription to the remote feature + HasSubscription() bool + + // subscribe to the feature of the entity + Subscribe() (*model.MsgCounterType, error) + + // check if there is a binding to the remote feature + HasBinding() bool + + // bind to the feature of the entity + Bind() (*model.MsgCounterType, error) + + // add a callback function to be invoked once a result or reply message for a msgCounter came in + AddResponseCallback(msgCounterReference model.MsgCounterType, function func(msg api.ResponseMessage)) error + + // add a callback function to be invoked once a result came in + AddResultCallback(function func(msg api.ResponseMessage)) +} diff --git a/features/deviceclassification.go b/features/deviceclassification.go index c2f5f9c6..b5fbeb76 100644 --- a/features/deviceclassification.go +++ b/features/deviceclassification.go @@ -1,22 +1,30 @@ package features import ( - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" ) type DeviceClassification struct { - *FeatureImpl + *Feature } -func NewDeviceClassification(localRole, remoteRole model.RoleType, spineLocalDevice *spine.DeviceLocalImpl, entity *spine.EntityRemoteImpl) (*DeviceClassification, error) { - feature, err := NewFeatureImpl(model.FeatureTypeTypeDeviceClassification, localRole, remoteRole, spineLocalDevice, entity) +// Get a new DeviceClassification features helper +// +// - The feature on the local entity has to be of role client +// - The feature on the remote entity has to be of role server +func NewDeviceClassification( + localEntity spineapi.EntityLocalInterface, + remoteEntity spineapi.EntityRemoteInterface) (*DeviceClassification, error) { + feature, err := NewFeature(model.FeatureTypeTypeDeviceClassification, localEntity, remoteEntity) if err != nil { return nil, err } dc := &DeviceClassification{ - FeatureImpl: feature, + Feature: feature, } return dc, nil @@ -29,14 +37,9 @@ func (d *DeviceClassification) RequestManufacturerDetails() (*model.MsgCounterTy // get the current manufacturer details for a remote device entity func (d *DeviceClassification) GetManufacturerDetails() (*model.DeviceClassificationManufacturerDataType, error) { - rData := d.featureRemote.Data(model.FunctionTypeDeviceClassificationManufacturerData) - if rData == nil { - return nil, ErrDataNotAvailable - } - - data := rData.(*model.DeviceClassificationManufacturerDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.DeviceClassificationManufacturerDataType](d.featureRemote, model.FunctionTypeDeviceClassificationManufacturerData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data, nil diff --git a/features/deviceclassification_test.go b/features/deviceclassification_test.go index 48a5c63a..d6c442ac 100644 --- a/features/deviceclassification_test.go +++ b/features/deviceclassification_test.go @@ -1,11 +1,13 @@ -package features +package features_test import ( "testing" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/features" "github.com/enbility/eebus-go/util" + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) @@ -17,21 +19,21 @@ func TestDeviceClassificationSuite(t *testing.T) { type DeviceClassificationSuite struct { suite.Suite - localDevice *spine.DeviceLocalImpl - remoteEntity *spine.EntityRemoteImpl + localEntity spineapi.EntityLocalInterface + remoteEntity spineapi.EntityRemoteInterface - deviceClassification *DeviceClassification + deviceClassification *features.DeviceClassification sentMessage []byte } -var _ spine.SpineDataConnection = (*DeviceClassificationSuite)(nil) +var _ shipapi.ShipConnectionDataWriterInterface = (*DeviceClassificationSuite)(nil) -func (s *DeviceClassificationSuite) WriteSpineMessage(message []byte) { +func (s *DeviceClassificationSuite) WriteShipMessageWithPayload(message []byte) { s.sentMessage = message } func (s *DeviceClassificationSuite) BeforeTest(suiteName, testName string) { - s.localDevice, s.remoteEntity = setupFeatures( + s.localEntity, s.remoteEntity = setupFeatures( s.T(), s, []featureFunctions{ @@ -45,7 +47,7 @@ func (s *DeviceClassificationSuite) BeforeTest(suiteName, testName string) { ) var err error - s.deviceClassification, err = NewDeviceClassification(model.RoleTypeServer, model.RoleTypeClient, s.localDevice, s.remoteEntity) + s.deviceClassification, err = features.NewDeviceClassification(s.localEntity, s.remoteEntity) assert.Nil(s.T(), err) assert.NotNil(s.T(), s.deviceClassification) } @@ -61,7 +63,7 @@ func (s *DeviceClassificationSuite) Test_GetManufacturerDetails() { assert.NotNil(s.T(), err) assert.Nil(s.T(), result) - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.DeviceClassificationManufacturerDataType{ DeviceName: util.Ptr(model.DeviceClassificationStringType("brand")), DeviceCode: util.Ptr(model.DeviceClassificationStringType("brand")), diff --git a/features/deviceconfiguration.go b/features/deviceconfiguration.go index dc63a6ac..8275ba62 100644 --- a/features/deviceconfiguration.go +++ b/features/deviceconfiguration.go @@ -1,31 +1,39 @@ package features import ( - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/api" + "github.com/enbility/eebus-go/util" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" ) type DeviceConfiguration struct { - *FeatureImpl + *Feature } -func NewDeviceConfiguration(localRole, remoteRole model.RoleType, spineLocalDevice *spine.DeviceLocalImpl, entity *spine.EntityRemoteImpl) (*DeviceConfiguration, error) { - feature, err := NewFeatureImpl(model.FeatureTypeTypeDeviceConfiguration, localRole, remoteRole, spineLocalDevice, entity) +// Get a new DeviceConfiguration features helper +// +// - The feature on the local entity has to be of role client +// - The feature on the remote entity has to be of role server +func NewDeviceConfiguration( + localEntity spineapi.EntityLocalInterface, + remoteEntity spineapi.EntityRemoteInterface) (*DeviceConfiguration, error) { + feature, err := NewFeature(model.FeatureTypeTypeDeviceConfiguration, localEntity, remoteEntity) if err != nil { return nil, err } dc := &DeviceConfiguration{ - FeatureImpl: feature, + Feature: feature, } return dc, nil } // request DeviceConfiguration data from a remote entity -func (d *DeviceConfiguration) RequestDescriptions() error { - _, err := d.requestData(model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData, nil, nil) - return err +func (d *DeviceConfiguration) RequestDescriptions() (*model.MsgCounterType, error) { + return d.requestData(model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData, nil, nil) } // request DeviceConfigurationKeyValueListDataType from a remote entity @@ -35,14 +43,9 @@ func (d *DeviceConfiguration) RequestKeyValues() (*model.MsgCounterType, error) // return current descriptions for Device Configuration func (d *DeviceConfiguration) GetDescriptions() ([]model.DeviceConfigurationKeyValueDescriptionDataType, error) { - rData := d.featureRemote.Data(model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData) - if rData == nil { - return nil, ErrDataNotAvailable - } - - data := rData.(*model.DeviceConfigurationKeyValueDescriptionListDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.DeviceConfigurationKeyValueDescriptionListDataType](d.featureRemote, model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data.DeviceConfigurationKeyValueDescriptionData, nil @@ -61,7 +64,7 @@ func (d *DeviceConfiguration) GetDescriptionForKeyId(keyId model.DeviceConfigura } } - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } // returns the description of a provided key name @@ -73,30 +76,42 @@ func (d *DeviceConfiguration) GetDescriptionForKeyName(keyName model.DeviceConfi } for _, item := range descriptions { - if item.KeyId == nil || item.KeyName == nil { - continue - } - if *item.KeyName == keyName { + if item.KeyId != nil && + item.KeyName != nil && + *item.KeyName == keyName { return &item, nil } } - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } // return current values for Device Configuration func (d *DeviceConfiguration) GetKeyValues() ([]model.DeviceConfigurationKeyValueDataType, error) { - rData := d.featureRemote.Data(model.FunctionTypeDeviceConfigurationKeyValueListData) - if rData == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.DeviceConfigurationKeyValueListDataType](d.featureRemote, model.FunctionTypeDeviceConfigurationKeyValueListData) + if err != nil { + return nil, api.ErrDataNotAvailable } - data := rData.(*model.DeviceConfigurationKeyValueListDataType) - if data == nil { - return nil, ErrDataNotAvailable + return data.DeviceConfigurationKeyValueData, nil +} + +// write key values +// returns an error if this failed +func (d *DeviceConfiguration) WriteKeyValues(data []model.DeviceConfigurationKeyValueDataType) (*model.MsgCounterType, error) { + if len(data) == 0 { + return nil, api.ErrMissingData } - return data.DeviceConfigurationKeyValueData, nil + cmd := model.CmdType{ + Function: util.Ptr(model.FunctionTypeDeviceConfigurationKeyValueListData), + Filter: []model.FilterType{*model.NewFilterTypePartial()}, + DeviceConfigurationKeyValueListData: &model.DeviceConfigurationKeyValueListDataType{ + DeviceConfigurationKeyValueData: data, + }, + } + + return d.remoteDevice.Sender().Write(d.featureLocal.Address(), d.featureRemote.Address(), cmd) } // return a pointer value for a given key and value type @@ -116,11 +131,7 @@ func (d *DeviceConfiguration) GetKeyValueForKeyName(keyname model.DeviceConfigur continue } - if desc.KeyName == nil { - continue - } - - if *desc.KeyName == keyname { + if desc.KeyName != nil && *desc.KeyName == keyname { switch valueType { case model.DeviceConfigurationKeyValueTypeTypeBoolean: return item.Value.Boolean, nil @@ -137,10 +148,10 @@ func (d *DeviceConfiguration) GetKeyValueForKeyName(keyname model.DeviceConfigur case model.DeviceConfigurationKeyValueTypeTypeScaledNumber: return item.Value.ScaledNumber, nil default: - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } } } - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } diff --git a/features/deviceconfiguration_test.go b/features/deviceconfiguration_test.go index 22b40e7f..7def2cb4 100644 --- a/features/deviceconfiguration_test.go +++ b/features/deviceconfiguration_test.go @@ -1,12 +1,16 @@ -package features +package features_test import ( "testing" + "time" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/features" "github.com/enbility/eebus-go/util" + shipmocks "github.com/enbility/ship-go/mocks" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" ) @@ -17,23 +21,19 @@ func TestDeviceConfigurationSuite(t *testing.T) { type DeviceConfigurationSuite struct { suite.Suite - localDevice *spine.DeviceLocalImpl - remoteEntity *spine.EntityRemoteImpl + localEntity spineapi.EntityLocalInterface + remoteEntity spineapi.EntityRemoteInterface - deviceConfiguration *DeviceConfiguration - sentMessage []byte -} - -var _ spine.SpineDataConnection = (*DeviceConfigurationSuite)(nil) - -func (s *DeviceConfigurationSuite) WriteSpineMessage(message []byte) { - s.sentMessage = message + deviceConfiguration *features.DeviceConfiguration } func (s *DeviceConfigurationSuite) BeforeTest(suiteName, testName string) { - s.localDevice, s.remoteEntity = setupFeatures( + mockWriter := shipmocks.NewShipConnectionDataWriterInterface(s.T()) + mockWriter.EXPECT().WriteShipMessageWithPayload(mock.Anything).Return().Maybe() + + s.localEntity, s.remoteEntity = setupFeatures( s.T(), - s, + mockWriter, []featureFunctions{ { featureType: model.FeatureTypeTypeDeviceConfiguration, @@ -46,14 +46,15 @@ func (s *DeviceConfigurationSuite) BeforeTest(suiteName, testName string) { ) var err error - s.deviceConfiguration, err = NewDeviceConfiguration(model.RoleTypeServer, model.RoleTypeClient, s.localDevice, s.remoteEntity) + s.deviceConfiguration, err = features.NewDeviceConfiguration(s.localEntity, s.remoteEntity) assert.Nil(s.T(), err) assert.NotNil(s.T(), s.deviceConfiguration) } func (s *DeviceConfigurationSuite) Test_RequestDescriptions() { - err := s.deviceConfiguration.RequestDescriptions() + counter, err := s.deviceConfiguration.RequestDescriptions() assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) } func (s *DeviceConfigurationSuite) Test_RequestKeyValueList() { @@ -114,6 +115,30 @@ func (s *DeviceConfigurationSuite) Test_GetValueForKey() { value, err = s.deviceConfiguration.GetKeyValueForKeyName(model.DeviceConfigurationKeyNameTypePvCurtailmentLimitFactor, model.DeviceConfigurationKeyValueTypeTypeScaledNumber) assert.Nil(s.T(), err) assert.NotNil(s.T(), value) + + value, err = s.deviceConfiguration.GetKeyValueForKeyName(model.DeviceConfigurationKeyNameTypeAzimuth, model.DeviceConfigurationKeyValueTypeTypeDate) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), value) + + value, err = s.deviceConfiguration.GetKeyValueForKeyName(model.DeviceConfigurationKeyNameTypeBatteryType, model.DeviceConfigurationKeyValueTypeTypeDateTime) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), value) + + value, err = s.deviceConfiguration.GetKeyValueForKeyName(model.DeviceConfigurationKeyNameTypeTimeToAcDischargePowerMax, model.DeviceConfigurationKeyValueTypeTypeDuration) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), value) + + value, err = s.deviceConfiguration.GetKeyValueForKeyName(model.DeviceConfigurationKeyNameTypeIncentivesWaitIncentiveWriteable, model.DeviceConfigurationKeyValueTypeTypeTime) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), value) + + value, err = s.deviceConfiguration.GetKeyValueForKeyName(model.DeviceConfigurationKeyNameTypeIncentivesWaitIncentiveWriteable, model.DeviceConfigurationKeyValueTypeType("invalid")) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), value) + + value, err = s.deviceConfiguration.GetKeyValueForKeyName(model.DeviceConfigurationKeyNameType("invalid"), model.DeviceConfigurationKeyValueTypeType("invalid")) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), value) } func (s *DeviceConfigurationSuite) Test_GetValues() { @@ -134,10 +159,33 @@ func (s *DeviceConfigurationSuite) Test_GetValues() { assert.NotNil(s.T(), data) } +func (s *DeviceConfigurationSuite) Test_WriteValues() { + counter, err := s.deviceConfiguration.WriteKeyValues(nil) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), counter) + + data := []model.DeviceConfigurationKeyValueDataType{} + counter, err = s.deviceConfiguration.WriteKeyValues(data) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), counter) + + data = []model.DeviceConfigurationKeyValueDataType{ + { + KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(0)), + Value: &model.DeviceConfigurationKeyValueValueType{ + ScaledNumber: model.NewScaledNumberType(10), + }, + }, + } + counter, err = s.deviceConfiguration.WriteKeyValues(data) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) +} + // helper func (s *DeviceConfigurationSuite) addDescription() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.DeviceConfigurationKeyValueDescriptionListDataType{ DeviceConfigurationKeyValueDescriptionData: []model.DeviceConfigurationKeyValueDescriptionDataType{ { @@ -156,13 +204,33 @@ func (s *DeviceConfigurationSuite) addDescription() { ValueType: util.Ptr(model.DeviceConfigurationKeyValueTypeTypeScaledNumber), Unit: util.Ptr(model.UnitOfMeasurementTypepct), }, + { + KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(3)), + KeyName: util.Ptr(model.DeviceConfigurationKeyNameTypeAzimuth), + ValueType: util.Ptr(model.DeviceConfigurationKeyValueTypeTypeDate), + }, + { + KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(4)), + KeyName: util.Ptr(model.DeviceConfigurationKeyNameTypeBatteryType), + ValueType: util.Ptr(model.DeviceConfigurationKeyValueTypeTypeDateTime), + }, + { + KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(5)), + KeyName: util.Ptr(model.DeviceConfigurationKeyNameTypeTimeToAcDischargePowerMax), + ValueType: util.Ptr(model.DeviceConfigurationKeyValueTypeTypeDuration), + }, + { + KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(6)), + KeyName: util.Ptr(model.DeviceConfigurationKeyNameTypeIncentivesWaitIncentiveWriteable), + ValueType: util.Ptr(model.DeviceConfigurationKeyValueTypeTypeTime), + }, }, } rF.UpdateData(model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData, fData, nil, nil) } func (s *DeviceConfigurationSuite) addData() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.DeviceConfigurationKeyValueListDataType{ DeviceConfigurationKeyValueData: []model.DeviceConfigurationKeyValueDataType{ { @@ -183,6 +251,30 @@ func (s *DeviceConfigurationSuite) addData() { ScaledNumber: model.NewScaledNumberType(50), }, }, + { + KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(3)), + Value: &model.DeviceConfigurationKeyValueValueType{ + Date: model.NewDateType("01.01.2023"), + }, + }, + { + KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(4)), + Value: &model.DeviceConfigurationKeyValueValueType{ + DateTime: model.NewDateTimeTypeFromTime(time.Now()), + }, + }, + { + KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(5)), + Value: &model.DeviceConfigurationKeyValueValueType{ + Duration: model.NewDurationType(time.Second * 4), + }, + }, + { + KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(6)), + Value: &model.DeviceConfigurationKeyValueValueType{ + Time: model.NewTimeType("13:05"), + }, + }, }, } rF.UpdateData(model.FunctionTypeDeviceConfigurationKeyValueListData, fData, nil, nil) diff --git a/features/devicediagnosis.go b/features/devicediagnosis.go index 701cca58..7966d067 100644 --- a/features/devicediagnosis.go +++ b/features/devicediagnosis.go @@ -1,22 +1,32 @@ package features import ( - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "time" + + "github.com/enbility/eebus-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" ) type DeviceDiagnosis struct { - *FeatureImpl + *Feature } -func NewDeviceDiagnosis(localRole, remoteRole model.RoleType, spineLocalDevice *spine.DeviceLocalImpl, entity *spine.EntityRemoteImpl) (*DeviceDiagnosis, error) { - feature, err := NewFeatureImpl(model.FeatureTypeTypeDeviceDiagnosis, localRole, remoteRole, spineLocalDevice, entity) +// Get a new DeviceDiagnosis features helper +// +// - The feature on the local entity has to be of role client +// - The feature on the remote entity has to be of role server +func NewDeviceDiagnosis( + localEntity spineapi.EntityLocalInterface, + remoteEntity spineapi.EntityRemoteInterface) (*DeviceDiagnosis, error) { + feature, err := NewFeature(model.FeatureTypeTypeDeviceDiagnosis, localEntity, remoteEntity) if err != nil { return nil, err } dd := &DeviceDiagnosis{ - FeatureImpl: feature, + Feature: feature, } return dd, nil @@ -29,21 +39,36 @@ func (d *DeviceDiagnosis) RequestState() (*model.MsgCounterType, error) { // get the current diagnosis state for an device entity func (d *DeviceDiagnosis) GetState() (*model.DeviceDiagnosisStateDataType, error) { - rData := d.featureRemote.Data(model.FunctionTypeDeviceDiagnosisStateData) - if rData == nil { - return nil, ErrDataNotAvailable - } - - data := rData.(*model.DeviceDiagnosisStateDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.DeviceDiagnosisStateDataType](d.featureRemote, model.FunctionTypeDeviceDiagnosisStateData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data, nil } -func (d *DeviceDiagnosis) SendState(operatingState *model.DeviceDiagnosisStateDataType) { +func (d *DeviceDiagnosis) SetLocalState(operatingState *model.DeviceDiagnosisStateDataType) { d.featureLocal.SetData(model.FunctionTypeDeviceDiagnosisStateData, operatingState) +} + +// request FunctionTypeDeviceDiagnosisHeartbeatData from a remote device +func (d *DeviceDiagnosis) RequestHeartbeat() (*model.MsgCounterType, error) { + return d.requestData(model.FunctionTypeDeviceDiagnosisHeartbeatData, nil, nil) +} + +// check if the currently available heartbeat data is within a time duration +func (d *DeviceDiagnosis) IsHeartbeatWithinDuration(duration time.Duration) bool { + data, err := spine.RemoteFeatureDataCopyOfType[*model.DeviceDiagnosisHeartbeatDataType](d.featureRemote, model.FunctionTypeDeviceDiagnosisHeartbeatData) + if err != nil || data == nil || data.Timestamp == nil { + return false + } + + timeValue, err := data.Timestamp.GetTime() + if err != nil { + return false + } + + diff := time.Now().UTC().Add(-1 * duration) - _, _ = d.featureLocal.NotifyData(model.FunctionTypeDeviceDiagnosisStateData, nil, nil, false, nil, d.featureRemote) + return diff.Compare(timeValue.Local()) <= 0 } diff --git a/features/devicediagnosis_test.go b/features/devicediagnosis_test.go index 44047f2c..08d0dcff 100644 --- a/features/devicediagnosis_test.go +++ b/features/devicediagnosis_test.go @@ -1,11 +1,14 @@ -package features +package features_test import ( "testing" + "time" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/features" "github.com/enbility/eebus-go/util" + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) @@ -17,21 +20,21 @@ func TestDeviceDiagnosisSuite(t *testing.T) { type DeviceDiagnosisSuite struct { suite.Suite - localDevice *spine.DeviceLocalImpl - remoteEntity *spine.EntityRemoteImpl + localEntity spineapi.EntityLocalInterface + remoteEntity spineapi.EntityRemoteInterface - deviceDiagnosis *DeviceDiagnosis + deviceDiagnosis *features.DeviceDiagnosis sentMessage []byte } -var _ spine.SpineDataConnection = (*DeviceDiagnosisSuite)(nil) +var _ shipapi.ShipConnectionDataWriterInterface = (*DeviceDiagnosisSuite)(nil) -func (s *DeviceDiagnosisSuite) WriteSpineMessage(message []byte) { +func (s *DeviceDiagnosisSuite) WriteShipMessageWithPayload(message []byte) { s.sentMessage = message } func (s *DeviceDiagnosisSuite) BeforeTest(suiteName, testName string) { - s.localDevice, s.remoteEntity = setupFeatures( + s.localEntity, s.remoteEntity = setupFeatures( s.T(), s, []featureFunctions{ @@ -39,17 +42,24 @@ func (s *DeviceDiagnosisSuite) BeforeTest(suiteName, testName string) { featureType: model.FeatureTypeTypeDeviceDiagnosis, functions: []model.FunctionType{ model.FunctionTypeDeviceDiagnosisStateData, + model.FunctionTypeDeviceDiagnosisHeartbeatData, }, }, }, ) var err error - s.deviceDiagnosis, err = NewDeviceDiagnosis(model.RoleTypeServer, model.RoleTypeClient, s.localDevice, s.remoteEntity) + s.deviceDiagnosis, err = features.NewDeviceDiagnosis(s.localEntity, s.remoteEntity) assert.Nil(s.T(), err) assert.NotNil(s.T(), s.deviceDiagnosis) } +func (s *DeviceDiagnosisSuite) Test_RequestHeartbeat() { + counter, err := s.deviceDiagnosis.RequestHeartbeat() + assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) +} + func (s *DeviceDiagnosisSuite) Test_RequestState() { counter, err := s.deviceDiagnosis.RequestState() assert.Nil(s.T(), err) @@ -61,7 +71,7 @@ func (s *DeviceDiagnosisSuite) Test_GetState() { assert.NotNil(s.T(), err) assert.Nil(s.T(), result) - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.DeviceDiagnosisStateDataType{ OperatingState: util.Ptr(model.DeviceDiagnosisOperatingStateTypeNormalOperation), PowerSupplyCondition: util.Ptr(model.PowerSupplyConditionTypeGood), @@ -73,11 +83,41 @@ func (s *DeviceDiagnosisSuite) Test_GetState() { assert.NotNil(s.T(), result) } -func (s *DeviceDiagnosisSuite) Test_SendState() { +func (s *DeviceDiagnosisSuite) Test_SetState() { data := &model.DeviceDiagnosisStateDataType{ OperatingState: util.Ptr(model.DeviceDiagnosisOperatingStateTypeNormalOperation), PowerSupplyCondition: util.Ptr(model.PowerSupplyConditionTypeGood), } - s.deviceDiagnosis.SendState(data) + s.deviceDiagnosis.SetLocalState(data) assert.NotNil(s.T(), s.sentMessage) } + +func (s *DeviceDiagnosisSuite) Test_IsHeartbeatWithinDuration() { + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) + + result := s.deviceDiagnosis.IsHeartbeatWithinDuration(time.Second * 10) + assert.Equal(s.T(), false, result) + + now := time.Now().UTC() + + data := &model.DeviceDiagnosisHeartbeatDataType{ + HeartbeatCounter: util.Ptr(uint64(1)), + HeartbeatTimeout: model.NewDurationType(time.Second * 4), + } + + rF.UpdateData(model.FunctionTypeDeviceDiagnosisHeartbeatData, data, nil, nil) + + result = s.deviceDiagnosis.IsHeartbeatWithinDuration(time.Second * 10) + assert.Equal(s.T(), false, result) + + data.Timestamp = model.NewAbsoluteOrRelativeTimeTypeFromTime(now) + rF.UpdateData(model.FunctionTypeDeviceDiagnosisHeartbeatData, data, nil, nil) + + result = s.deviceDiagnosis.IsHeartbeatWithinDuration(time.Second * 10) + assert.Equal(s.T(), true, result) + + time.Sleep(time.Second * 2) + + result = s.deviceDiagnosis.IsHeartbeatWithinDuration(time.Second * 1) + assert.Equal(s.T(), false, result) +} diff --git a/features/electricalconnection.go b/features/electricalconnection.go index ad6fdf37..0d35e1de 100644 --- a/features/electricalconnection.go +++ b/features/electricalconnection.go @@ -1,39 +1,43 @@ package features import ( - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" ) type ElectricalConnection struct { - *FeatureImpl + *Feature } -func NewElectricalConnection(localRole, remoteRole model.RoleType, spineLocalDevice *spine.DeviceLocalImpl, entity *spine.EntityRemoteImpl) (*ElectricalConnection, error) { - feature, err := NewFeatureImpl(model.FeatureTypeTypeElectricalConnection, localRole, remoteRole, spineLocalDevice, entity) +// Get a new ElectricalConnection features helper +// +// - The feature on the local entity has to be of role client +// - The feature on the remote entity has to be of role server +func NewElectricalConnection( + localEntity spineapi.EntityLocalInterface, + remoteEntity spineapi.EntityRemoteInterface) (*ElectricalConnection, error) { + feature, err := NewFeature(model.FeatureTypeTypeElectricalConnection, localEntity, remoteEntity) if err != nil { return nil, err } e := &ElectricalConnection{ - FeatureImpl: feature, + Feature: feature, } return e, nil } // request ElectricalConnectionDescriptionListDataType from a remote entity -func (e *ElectricalConnection) RequestDescriptions() error { - _, err := e.requestData(model.FunctionTypeElectricalConnectionDescriptionListData, nil, nil) - - return err +func (e *ElectricalConnection) RequestDescriptions() (*model.MsgCounterType, error) { + return e.requestData(model.FunctionTypeElectricalConnectionDescriptionListData, nil, nil) } // request FunctionTypeElectricalConnectionParameterDescriptionListData from a remote entity -func (e *ElectricalConnection) RequestParameterDescriptions() error { - _, err := e.requestData(model.FunctionTypeElectricalConnectionParameterDescriptionListData, nil, nil) - - return err +func (e *ElectricalConnection) RequestParameterDescriptions() (*model.MsgCounterType, error) { + return e.requestData(model.FunctionTypeElectricalConnectionParameterDescriptionListData, nil, nil) } // request FunctionTypeElectricalConnectionPermittedValueSetListData from a remote entity @@ -41,15 +45,16 @@ func (e *ElectricalConnection) RequestPermittedValueSets() (*model.MsgCounterTyp return e.requestData(model.FunctionTypeElectricalConnectionPermittedValueSetListData, nil, nil) } +// request FunctionTypeElectricalConnectionCharacteristicListData from a remote entity +func (e *ElectricalConnection) RequestCharacteristics() (*model.MsgCounterType, error) { + return e.requestData(model.FunctionTypeElectricalConnectionCharacteristicListData, nil, nil) +} + // return list of description for Electrical Connection func (e *ElectricalConnection) GetDescriptions() ([]model.ElectricalConnectionDescriptionDataType, error) { - rData := e.featureRemote.Data(model.FunctionTypeElectricalConnectionDescriptionListData) - if rData == nil { - return nil, ErrMetadataNotAvailable - } - data := rData.(*model.ElectricalConnectionDescriptionListDataType) - if data == nil { - return nil, ErrMetadataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.ElectricalConnectionDescriptionListDataType](e.featureRemote, model.FunctionTypeElectricalConnectionDescriptionListData) + if err != nil { + return nil, api.ErrMetadataNotAvailable } return data.ElectricalConnectionDescriptionData, nil @@ -77,23 +82,37 @@ func (e *ElectricalConnection) GetDescriptionForMeasurementId(measurementId mode return &item, nil } - return nil, ErrMetadataNotAvailable + return nil, api.ErrMetadataNotAvailable } // return parameter descriptions for all Electrical Connections func (e *ElectricalConnection) GetParameterDescriptions() ([]model.ElectricalConnectionParameterDescriptionDataType, error) { - rData := e.featureRemote.Data(model.FunctionTypeElectricalConnectionParameterDescriptionListData) - if rData == nil { - return nil, ErrDataNotAvailable - } - data := rData.(*model.ElectricalConnectionParameterDescriptionListDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.ElectricalConnectionParameterDescriptionListDataType](e.featureRemote, model.FunctionTypeElectricalConnectionParameterDescriptionListData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data.ElectricalConnectionParameterDescriptionData, nil } +// return parameter description for a specific scope +func (e *ElectricalConnection) GetParameterDescriptionForScopeType(scope model.ScopeTypeType) (*model.ElectricalConnectionParameterDescriptionDataType, error) { + desc, err := e.GetParameterDescriptions() + if err != nil { + return nil, err + } + + for _, element := range desc { + if element.ScopeType == nil || *element.ScopeType != scope { + continue + } + + return &element, nil + } + + return nil, api.ErrDataNotAvailable +} + // return parameter description for a specific parameterId func (e *ElectricalConnection) GetParameterDescriptionForParameterId(parameterId model.ElectricalConnectionParameterIdType) (*model.ElectricalConnectionParameterDescriptionDataType, error) { desc, err := e.GetParameterDescriptions() @@ -109,7 +128,7 @@ func (e *ElectricalConnection) GetParameterDescriptionForParameterId(parameterId return &element, nil } - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } // return parameter description for a specific measurementId @@ -127,7 +146,7 @@ func (e *ElectricalConnection) GetParameterDescriptionForMeasurementId(measureme return &element, nil } - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } // return parameter description for a specific measurementId @@ -145,19 +164,14 @@ func (e *ElectricalConnection) GetParameterDescriptionForMeasuredPhase(phase mod return &element, nil } - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } // return permitted values for all Electrical Connections func (e *ElectricalConnection) GetPermittedValueSets() ([]model.ElectricalConnectionPermittedValueSetDataType, error) { - rData := e.featureRemote.Data(model.FunctionTypeElectricalConnectionPermittedValueSetListData) - if rData == nil { - return nil, ErrDataNotAvailable - } - - data := rData.(*model.ElectricalConnectionPermittedValueSetListDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.ElectricalConnectionPermittedValueSetListDataType](e.featureRemote, model.FunctionTypeElectricalConnectionPermittedValueSetListData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data.ElectricalConnectionPermittedValueSetData, nil @@ -178,7 +192,7 @@ func (e *ElectricalConnection) GetPermittedValueSetForParameterId(parameterId mo return &element, nil } - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } // return permitted valueset for a provided measuremnetId @@ -201,7 +215,7 @@ func (e *ElectricalConnection) GetPermittedValueSetForMeasurementId(measurementI return &element, nil } - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } // returns minimum, maximum, default/pause limit values @@ -273,3 +287,36 @@ func (e *ElectricalConnection) AdjustValueToBeWithinPermittedValuesForParameter( return value } + +// return characteristics for a Electrical Connections +func (e *ElectricalConnection) GetCharacteristics() ([]model.ElectricalConnectionCharacteristicDataType, error) { + data, err := spine.RemoteFeatureDataCopyOfType[*model.ElectricalConnectionCharacteristicListDataType](e.featureRemote, model.FunctionTypeElectricalConnectionCharacteristicListData) + if err != nil { + return nil, api.ErrDataNotAvailable + } + + return data.ElectricalConnectionCharacteristicData, nil +} + +// return characteristics for a Electrical Connections +func (e *ElectricalConnection) GetCharacteristicForContextType( + context model.ElectricalConnectionCharacteristicContextType, + cType model.ElectricalConnectionCharacteristicTypeType, +) (*model.ElectricalConnectionCharacteristicDataType, error) { + data, err := e.GetCharacteristics() + if err != nil || data == nil || len(data) == 0 { + return nil, api.ErrDataNotAvailable + } + + for _, item := range data { + if item.CharacteristicId != nil && + item.CharacteristicContext != nil && + *item.CharacteristicContext == context && + item.CharacteristicType != nil && + *item.CharacteristicType == cType { + return &item, nil + } + } + + return nil, api.ErrDataNotAvailable +} diff --git a/features/electricalconnection_test.go b/features/electricalconnection_test.go index 5bbd2280..e26b9dd6 100644 --- a/features/electricalconnection_test.go +++ b/features/electricalconnection_test.go @@ -1,11 +1,13 @@ -package features +package features_test import ( "testing" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/features" "github.com/enbility/eebus-go/util" + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) @@ -17,21 +19,21 @@ func TestElectricalConnectionSuite(t *testing.T) { type ElectricalConnectionSuite struct { suite.Suite - localDevice *spine.DeviceLocalImpl - remoteEntity *spine.EntityRemoteImpl + localEntity spineapi.EntityLocalInterface + remoteEntity spineapi.EntityRemoteInterface - electricalConnection *ElectricalConnection + electricalConnection *features.ElectricalConnection sentMessage []byte } -var _ spine.SpineDataConnection = (*ElectricalConnectionSuite)(nil) +var _ shipapi.ShipConnectionDataWriterInterface = (*ElectricalConnectionSuite)(nil) -func (s *ElectricalConnectionSuite) WriteSpineMessage(message []byte) { +func (s *ElectricalConnectionSuite) WriteShipMessageWithPayload(message []byte) { s.sentMessage = message } func (s *ElectricalConnectionSuite) BeforeTest(suiteName, testName string) { - s.localDevice, s.remoteEntity = setupFeatures( + s.localEntity, s.remoteEntity = setupFeatures( s.T(), s, []featureFunctions{ @@ -41,25 +43,28 @@ func (s *ElectricalConnectionSuite) BeforeTest(suiteName, testName string) { model.FunctionTypeElectricalConnectionDescriptionListData, model.FunctionTypeElectricalConnectionParameterDescriptionListData, model.FunctionTypeElectricalConnectionPermittedValueSetListData, + model.FunctionTypeElectricalConnectionCharacteristicListData, }, }, }, ) var err error - s.electricalConnection, err = NewElectricalConnection(model.RoleTypeServer, model.RoleTypeClient, s.localDevice, s.remoteEntity) + s.electricalConnection, err = features.NewElectricalConnection(s.localEntity, s.remoteEntity) assert.Nil(s.T(), err) assert.NotNil(s.T(), s.electricalConnection) } func (s *ElectricalConnectionSuite) Test_RequestDescriptions() { - err := s.electricalConnection.RequestDescriptions() + counter, err := s.electricalConnection.RequestDescriptions() assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) } func (s *ElectricalConnectionSuite) Test_RequestParameterDescriptions() { - err := s.electricalConnection.RequestParameterDescriptions() + counter, err := s.electricalConnection.RequestParameterDescriptions() assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) } func (s *ElectricalConnectionSuite) Test_RequestPermittedValueSets() { @@ -68,6 +73,12 @@ func (s *ElectricalConnectionSuite) Test_RequestPermittedValueSets() { assert.NotNil(s.T(), counter) } +func (s *ElectricalConnectionSuite) Test_RequestCharacteristics() { + counter, err := s.electricalConnection.RequestCharacteristics() + assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) +} + func (s *ElectricalConnectionSuite) Test_GetDescriptions() { data, err := s.electricalConnection.GetDescriptions() assert.NotNil(s.T(), err) @@ -111,6 +122,28 @@ func (s *ElectricalConnectionSuite) Test_GetParameterDescriptions() { assert.NotNil(s.T(), data) } +func (s *ElectricalConnectionSuite) Test_GetParameterDescriptionForScope() { + data, err := s.electricalConnection.GetParameterDescriptionForScopeType(model.ScopeTypeTypeACPowerTotal) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), data) + + s.addDescription() + + data, err = s.electricalConnection.GetParameterDescriptionForScopeType(model.ScopeTypeTypeACPowerTotal) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), data) + + s.addParamDescriptionPower() + + data, err = s.electricalConnection.GetParameterDescriptionForScopeType(model.ScopeTypeTypeACPowerTotal) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), data) + + data, err = s.electricalConnection.GetParameterDescriptionForScopeType(model.ScopeTypeTypeACCurrent) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), data) +} + func (s *ElectricalConnectionSuite) Test_GetParameterDescriptionForParameterId() { parametertId := model.ElectricalConnectionParameterIdType(1) data, err := s.electricalConnection.GetParameterDescriptionForParameterId(parametertId) @@ -201,6 +234,18 @@ func (s *ElectricalConnectionSuite) Test_GetPermittedValueSets() { assert.NotNil(s.T(), data) } +func (s *ElectricalConnectionSuite) Test_GetPermittedValueSetsEmptyElli() { + data, err := s.electricalConnection.GetPermittedValueSets() + assert.NotNil(s.T(), err) + assert.Nil(s.T(), data) + + s.addPermittedValueSetEmptyElli() + + data, err = s.electricalConnection.GetPermittedValueSets() + assert.Nil(s.T(), err) + assert.NotNil(s.T(), data) +} + func (s *ElectricalConnectionSuite) Test_GetPermittedValueSetForParameterId() { parametertId := model.ElectricalConnectionParameterIdType(1) data, err := s.electricalConnection.GetPermittedValueSetForParameterId(parametertId) @@ -274,10 +319,44 @@ func (s *ElectricalConnectionSuite) Test_AdjustValueToBeWithinPermittedValuesFor assert.Equal(s.T(), value, 0.1) } +func (s *ElectricalConnectionSuite) Test_GetCharacteristics() { + data, err := s.electricalConnection.GetCharacteristics() + assert.NotNil(s.T(), err) + assert.Nil(s.T(), data) + + s.addCharacteristics() + + data, err = s.electricalConnection.GetCharacteristics() + assert.Nil(s.T(), err) + assert.NotNil(s.T(), data) +} + +func (s *ElectricalConnectionSuite) Test_GetCharacteristicForContextType() { + data, err := s.electricalConnection.GetCharacteristicForContextType( + model.ElectricalConnectionCharacteristicContextTypeEntity, + model.ElectricalConnectionCharacteristicTypeTypeEnergyCapacityNominalMax) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), data) + + s.addCharacteristics() + + data, err = s.electricalConnection.GetCharacteristicForContextType( + model.ElectricalConnectionCharacteristicContextTypeEntity, + model.ElectricalConnectionCharacteristicTypeTypeApparentPowerConsumptionNominalMax) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), data) + + data, err = s.electricalConnection.GetCharacteristicForContextType( + model.ElectricalConnectionCharacteristicContextTypeEntity, + model.ElectricalConnectionCharacteristicTypeTypeEnergyCapacityNominalMax) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), data) +} + // helper func (s *ElectricalConnectionSuite) addDescription() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.ElectricalConnectionDescriptionListDataType{ ElectricalConnectionDescriptionData: []model.ElectricalConnectionDescriptionDataType{ { @@ -291,8 +370,26 @@ func (s *ElectricalConnectionSuite) addDescription() { rF.UpdateData(model.FunctionTypeElectricalConnectionDescriptionListData, fData, nil, nil) } +func (s *ElectricalConnectionSuite) addCharacteristics() { + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) + fData := &model.ElectricalConnectionCharacteristicListDataType{ + ElectricalConnectionCharacteristicData: []model.ElectricalConnectionCharacteristicDataType{ + { + ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), + ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(0)), + CharacteristicId: util.Ptr(model.ElectricalConnectionCharacteristicIdType(0)), + CharacteristicContext: util.Ptr(model.ElectricalConnectionCharacteristicContextTypeEntity), + CharacteristicType: util.Ptr(model.ElectricalConnectionCharacteristicTypeTypeEnergyCapacityNominalMax), + Value: model.NewScaledNumberType(98), + Unit: util.Ptr(model.UnitOfMeasurementTypeWh), + }, + }, + } + rF.UpdateData(model.FunctionTypeElectricalConnectionCharacteristicListData, fData, nil, nil) +} + func (s *ElectricalConnectionSuite) addParamDescriptionCurrents() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.ElectricalConnectionParameterDescriptionListDataType{ ElectricalConnectionParameterDescriptionData: []model.ElectricalConnectionParameterDescriptionDataType{ { @@ -371,7 +468,7 @@ func (s *ElectricalConnectionSuite) addParamDescriptionCurrents() { } func (s *ElectricalConnectionSuite) addParamDescriptionPower() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.ElectricalConnectionParameterDescriptionListDataType{ ElectricalConnectionParameterDescriptionData: []model.ElectricalConnectionParameterDescriptionDataType{ { @@ -386,7 +483,7 @@ func (s *ElectricalConnectionSuite) addParamDescriptionPower() { } func (s *ElectricalConnectionSuite) addPermittedValueSet() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.ElectricalConnectionPermittedValueSetListDataType{ ElectricalConnectionPermittedValueSetData: []model.ElectricalConnectionPermittedValueSetDataType{ { @@ -461,3 +558,25 @@ func (s *ElectricalConnectionSuite) addPermittedValueSet() { } rF.UpdateData(model.FunctionTypeElectricalConnectionPermittedValueSetListData, fData, nil, nil) } + +func (s *ElectricalConnectionSuite) addPermittedValueSetEmptyElli() { + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) + fData := &model.ElectricalConnectionPermittedValueSetListDataType{ + ElectricalConnectionPermittedValueSetData: []model.ElectricalConnectionPermittedValueSetDataType{ + { + ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), + ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(0)), + PermittedValueSet: []model.ScaledNumberSetType{}, + }, + { + ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), + ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(1)), + }, + { + ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), + ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(2)), + }, + }, + } + rF.UpdateData(model.FunctionTypeElectricalConnectionPermittedValueSetListData, fData, nil, nil) +} diff --git a/features/feature.go b/features/feature.go index b47e54f2..2af86fb1 100644 --- a/features/feature.go +++ b/features/feature.go @@ -3,84 +3,143 @@ package features import ( "errors" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" ) -type Feature interface { - SubscribeForEntity() error -} - -type FeatureImpl struct { +type Feature struct { featureType model.FeatureTypeType localRole model.RoleType remoteRole model.RoleType - spineLocalDevice *spine.DeviceLocalImpl + spineLocalDevice spineapi.DeviceLocalInterface + localEntity spineapi.EntityLocalInterface - featureLocal spine.FeatureLocal - featureRemote *spine.FeatureRemoteImpl + featureLocal spineapi.FeatureLocalInterface + featureRemote spineapi.FeatureRemoteInterface - device *spine.DeviceRemoteImpl - entity *spine.EntityRemoteImpl + remoteDevice spineapi.DeviceRemoteInterface + remoteEntity spineapi.EntityRemoteInterface } -var _ Feature = (*FeatureImpl)(nil) +var _ FeatureInterface = (*Feature)(nil) + +func NewFeature( + featureType model.FeatureTypeType, + localEntity spineapi.EntityLocalInterface, + remoteEntity spineapi.EntityRemoteInterface) (*Feature, error) { + if localEntity == nil { + return nil, errors.New("local entity is nil") + } + + if remoteEntity == nil { + return nil, errors.New("remote entity is nil") + } -func NewFeatureImpl(featureType model.FeatureTypeType, localRole, remoteRole model.RoleType, spineLocalDevice *spine.DeviceLocalImpl, entity *spine.EntityRemoteImpl) (*FeatureImpl, error) { - f := &FeatureImpl{ + f := &Feature{ featureType: featureType, - localRole: localRole, - remoteRole: remoteRole, - spineLocalDevice: spineLocalDevice, - device: entity.Device(), - entity: entity, + localRole: model.RoleTypeClient, + remoteRole: model.RoleTypeServer, + spineLocalDevice: localEntity.Device(), + localEntity: localEntity, + remoteDevice: remoteEntity.Device(), + remoteEntity: remoteEntity, } var err error - f.featureLocal, f.featureRemote, err = f.getLocalClientAndRemoteServerFeatures() + f.featureLocal, f.featureRemote, err = f.getLocalAndRemoteFeatures() return f, err } -// subscribe to the feature for a the entity -func (f *FeatureImpl) SubscribeForEntity() error { - if _, fErr := f.featureLocal.Subscribe(f.featureRemote.Device(), f.featureRemote.Address()); fErr != nil { - return errors.New(fErr.String()) +// check if there is a subscription to the remote feature +func (f *Feature) HasSubscription() bool { + subscription := f.featureLocal.HasSubscriptionToRemote(f.featureRemote.Address()) + return subscription +} + +// subscribe to the feature of the entity +func (f *Feature) Subscribe() (*model.MsgCounterType, error) { + msgCounter, fErr := f.featureLocal.SubscribeToRemote(f.featureRemote.Address()) + + if fErr != nil { + return nil, errors.New(fErr.String()) + } + + return msgCounter, nil +} + +// unssubscribe to the feature of the entity +func (f *Feature) Unsubscribe() (*model.MsgCounterType, error) { + msgCounter, fErr := f.featureLocal.RemoveRemoteSubscription(f.featureRemote.Address()) + + if fErr != nil { + return nil, errors.New(fErr.String()) + } + + return msgCounter, nil +} + +// check if there is a binding to the remote feature +func (f *Feature) HasBinding() bool { + binding := f.featureLocal.HasBindingToRemote(f.featureRemote.Address()) + return binding +} + +// bind to the feature of the entity +func (f *Feature) Bind() (*model.MsgCounterType, error) { + msgCounter, fErr := f.featureLocal.BindToRemote(f.featureRemote.Address()) + if fErr != nil { + return nil, errors.New(fErr.String()) } - return nil + return msgCounter, nil } -// bind to the feature of a the entity -func (f *FeatureImpl) Bind() error { - if _, fErr := f.featureLocal.Bind(f.featureRemote.Device(), f.featureRemote.Address()); fErr != nil { - return errors.New(fErr.String()) +// remove a binding to the feature of the entity +func (f *Feature) Unbind() (*model.MsgCounterType, error) { + msgCounter, fErr := f.featureLocal.RemoveRemoteBinding(f.featureRemote.Address()) + + if fErr != nil { + return nil, errors.New(fErr.String()) } - return nil + return msgCounter, nil +} + +// add a callback function to be invoked once a result to a msgCounter came in +func (f *Feature) AddResponseCallback( + msgCounterReference model.MsgCounterType, + function func(msg spineapi.ResponseMessage)) error { + return f.featureLocal.AddResponseCallback(msgCounterReference, function) +} + +// add a callback function to be invoked once a result came in +func (f *Feature) AddResultCallback(function func(msg spineapi.ResponseMessage)) { + f.featureLocal.AddResultCallback(function) } // helper method which adds checking if the feature is available and the operation is allowed // selectors and elements are used if specific data should be requested by using // model.FilterType DataSelectors (selectors) and/or DataElements (elements) // both should use the proper data types for the used function -func (f *FeatureImpl) requestData(function model.FunctionType, selectors any, elements any) (*model.MsgCounterType, error) { +func (f *Feature) requestData(function model.FunctionType, selectors any, elements any) (*model.MsgCounterType, error) { if f.featureRemote == nil { - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } fTypes := f.featureRemote.Operations() if _, exists := fTypes[function]; !exists { - return nil, ErrFunctionNotSupported + return nil, api.ErrFunctionNotSupported } - if !fTypes[function].Read { - return nil, ErrOperationOnFunctionNotSupported + if !fTypes[function].Read() { + return nil, api.ErrOperationOnFunctionNotSupported } - msgCounter, fErr := f.featureLocal.RequestData(function, selectors, elements, f.featureRemote) + msgCounter, fErr := f.featureLocal.RequestRemoteData(function, selectors, elements, f.featureRemote) if fErr != nil { return nil, errors.New(fErr.String()) } @@ -89,18 +148,19 @@ func (f *FeatureImpl) requestData(function model.FunctionType, selectors any, el } // internal helper method for getting local and remote feature for a given featureType and a given remoteDevice -func (f *FeatureImpl) getLocalClientAndRemoteServerFeatures() (spine.FeatureLocal, *spine.FeatureRemoteImpl, error) { - if f.entity == nil { - return nil, nil, errors.New("invalid remote entity provided") +func (f *Feature) getLocalAndRemoteFeatures() ( + spineapi.FeatureLocalInterface, + spineapi.FeatureRemoteInterface, + error) { + featureLocal := f.localEntity.FeatureOfTypeAndRole(f.featureType, f.localRole) + if featureLocal == nil { + featureLocal = f.localEntity.FeatureOfTypeAndRole(model.FeatureTypeTypeGeneric, f.localRole) } - - featureLocal := f.spineLocalDevice.FeatureByTypeAndRole(f.featureType, f.localRole) - featureRemote := f.entity.Device().FeatureByEntityTypeAndRole(f.entity, f.featureType, f.remoteRole) - if featureLocal == nil { return nil, nil, errors.New("local feature not found") } + featureRemote := f.remoteEntity.Device().FeatureByEntityTypeAndRole(f.remoteEntity, f.featureType, f.remoteRole) if featureRemote == nil { return nil, nil, errors.New("remote feature not found") } diff --git a/features/feature_test.go b/features/feature_test.go new file mode 100644 index 00000000..b6e57899 --- /dev/null +++ b/features/feature_test.go @@ -0,0 +1,128 @@ +package features_test + +import ( + "testing" + + "github.com/enbility/eebus-go/features" + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestFeatureSuite(t *testing.T) { + suite.Run(t, new(FeatureSuite)) +} + +type FeatureSuite struct { + suite.Suite + + localEntity spineapi.EntityLocalInterface + remoteEntity spineapi.EntityRemoteInterface + + testFeature *features.Feature + sentMessage []byte +} + +var _ shipapi.ShipConnectionDataWriterInterface = (*FeatureSuite)(nil) + +func (s *FeatureSuite) WriteShipMessageWithPayload(message []byte) { + s.sentMessage = message +} + +func (s *FeatureSuite) BeforeTest(suiteName, testName string) { + s.localEntity, s.remoteEntity = setupFeatures( + s.T(), + s, + []featureFunctions{ + { + featureType: model.FeatureTypeTypeAlarm, + functions: []model.FunctionType{ + model.FunctionTypeAlarmListData, + }, + }, + }, + ) + + var err error + s.testFeature, err = features.NewFeature(model.FeatureTypeTypeAlarm, s.localEntity, s.remoteEntity) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), s.testFeature) +} + +func (s *FeatureSuite) Test_NewFeature() { + newFeature, err := features.NewFeature(model.FeatureTypeTypeBill, nil, s.remoteEntity) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), newFeature) + + newFeature, err = features.NewFeature(model.FeatureTypeTypeBill, s.localEntity, nil) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), newFeature) + + newFeature, err = features.NewFeature(model.FeatureTypeTypeBill, s.localEntity, s.remoteEntity) + assert.NotNil(s.T(), err) + assert.NotNil(s.T(), newFeature) + + f := spine.NewFeatureLocal(1, s.localEntity, model.FeatureTypeTypeBill, model.RoleTypeClient) + s.localEntity.AddFeature(f) + + newFeature, err = features.NewFeature(model.FeatureTypeTypeBill, s.localEntity, s.remoteEntity) + assert.NotNil(s.T(), err) + assert.NotNil(s.T(), newFeature) +} + +func (s *FeatureSuite) Test_Subscription() { + subscription := s.testFeature.HasSubscription() + assert.Equal(s.T(), false, subscription) + + counter, err := s.testFeature.Subscribe() + assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) + + subscription = s.testFeature.HasSubscription() + assert.Equal(s.T(), true, subscription) + + counter, err = s.testFeature.Subscribe() + assert.NotNil(s.T(), counter) + assert.Nil(s.T(), err) + + counter, err = s.testFeature.Unsubscribe() + assert.NotNil(s.T(), counter) + assert.Nil(s.T(), err) + + subscription = s.testFeature.HasSubscription() + assert.Equal(s.T(), false, subscription) +} + +func (s *FeatureSuite) Test_Binding() { + binding := s.testFeature.HasBinding() + assert.Equal(s.T(), false, binding) + + counter, err := s.testFeature.Bind() + assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) + + binding = s.testFeature.HasBinding() + assert.Equal(s.T(), true, binding) + + counter, err = s.testFeature.Bind() + assert.NotNil(s.T(), counter) + assert.Nil(s.T(), err) + + counter, err = s.testFeature.Unbind() + assert.NotNil(s.T(), counter) + assert.Nil(s.T(), err) + + binding = s.testFeature.HasBinding() + assert.Equal(s.T(), false, binding) +} + +func (s *FeatureSuite) Test_ResultCallback() { + testFct := func(msg spineapi.ResponseMessage) {} + err := s.testFeature.AddResponseCallback(10, testFct) + assert.Nil(s.T(), err) + + s.testFeature.AddResultCallback(testFct) +} diff --git a/features/helper_test.go b/features/helper_test.go index fc7cf975..357403e0 100644 --- a/features/helper_test.go +++ b/features/helper_test.go @@ -1,9 +1,15 @@ -package features +package features_test import ( - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "encoding/json" + "sync" + "time" + "github.com/enbility/eebus-go/util" + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" "github.com/stretchr/testify/assert" ) @@ -12,19 +18,102 @@ type featureFunctions struct { functions []model.FunctionType } -func setupFeatures(t assert.TestingT, dataCon spine.SpineDataConnection, featureFunctions []featureFunctions) (*spine.DeviceLocalImpl, *spine.EntityRemoteImpl) { - localDevice := spine.NewDeviceLocalImpl("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode", - "TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart) - localEntity := spine.NewEntityLocalImpl(localDevice, model.EntityTypeTypeCEM, spine.NewAddressEntityType([]uint{1})) - localDevice.AddEntity(localEntity) +type WriteMessageHandler struct { + sentMessages [][]byte + + mux sync.Mutex +} + +var _ shipapi.ShipConnectionDataWriterInterface = (*WriteMessageHandler)(nil) + +func (t *WriteMessageHandler) WriteShipMessageWithPayload(message []byte) { + t.mux.Lock() + defer t.mux.Unlock() + + t.sentMessages = append(t.sentMessages, message) +} + +func (t *WriteMessageHandler) LastMessage() []byte { + t.mux.Lock() + defer t.mux.Unlock() + + if len(t.sentMessages) == 0 { + return nil + } + + return t.sentMessages[len(t.sentMessages)-1] +} + +func (t *WriteMessageHandler) MessageWithReference(msgCounterReference *model.MsgCounterType) []byte { + t.mux.Lock() + defer t.mux.Unlock() + + var datagram model.Datagram + + for _, msg := range t.sentMessages { + if err := json.Unmarshal(msg, &datagram); err != nil { + return nil + } + if datagram.Datagram.Header.MsgCounterReference == nil { + continue + } + if uint(*datagram.Datagram.Header.MsgCounterReference) != uint(*msgCounterReference) { + continue + } + if datagram.Datagram.Payload.Cmd[0].ResultData != nil { + continue + } + + return msg + } + + return nil +} + +func (t *WriteMessageHandler) ResultWithReference(msgCounterReference *model.MsgCounterType) []byte { + t.mux.Lock() + defer t.mux.Unlock() + + var datagram model.Datagram + + for _, msg := range t.sentMessages { + if err := json.Unmarshal(msg, &datagram); err != nil { + return nil + } + if datagram.Datagram.Header.MsgCounterReference == nil { + continue + } + if uint(*datagram.Datagram.Header.MsgCounterReference) != uint(*msgCounterReference) { + continue + } + if datagram.Datagram.Payload.Cmd[0].ResultData == nil { + continue + } + + return msg + } + + return nil +} + +func setupFeatures( + t assert.TestingT, + dataCon shipapi.ShipConnectionDataWriterInterface, + featureFunctions []featureFunctions) (spineapi.EntityLocalInterface, spineapi.EntityRemoteInterface) { + localDevice := spine.NewDeviceLocal("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode", + "TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + localEntity := spine.NewEntityLocal(localDevice, model.EntityTypeTypeCEM, spine.NewAddressEntityType([]uint{1})) for i, item := range featureFunctions { - f := spine.NewFeatureLocalImpl(uint(i+1), localEntity, item.featureType, model.RoleTypeServer) + f := spine.NewFeatureLocal(uint(i+1), localEntity, item.featureType, model.RoleTypeClient) localEntity.AddFeature(f) } + localDevice.AddEntity(localEntity) + remoteDeviceName := "remoteDevice" - remoteDevice := spine.NewDeviceRemoteImpl(localDevice, "test", dataCon) + sender := spine.NewSender(dataCon) + remoteDevice := spine.NewDeviceRemote(localDevice, "test", sender) data := &model.NodeManagementDetailedDiscoveryDataType{ DeviceInformation: &model.NodeManagementDetailedDiscoveryDeviceInformationType{ Description: &model.NetworkManagementDeviceDescriptionDataType{ @@ -56,7 +145,7 @@ func setupFeatures(t assert.TestingT, dataCon spine.SpineDataConnection, feature Feature: util.Ptr(model.AddressFeatureType(i + 1)), }, FeatureType: util.Ptr(item.featureType), - Role: util.Ptr(model.RoleTypeClient), + Role: util.Ptr(model.RoleTypeServer), }, } var supportedFcts []model.FunctionPropertyType @@ -80,6 +169,9 @@ func setupFeatures(t assert.TestingT, dataCon spine.SpineDataConnection, feature assert.Nil(t, err) assert.NotNil(t, remoteEntities) assert.NotEqual(t, 0, len(remoteEntities)) + remoteDevice.UpdateDevice(data.DeviceInformation.Description) + + localDevice.AddRemoteDeviceForSki("test", remoteDevice) - return localDevice, remoteEntities[0] + return localEntity, remoteEntities[0] } diff --git a/features/identification.go b/features/identification.go index 0225febf..4d69c325 100644 --- a/features/identification.go +++ b/features/identification.go @@ -1,22 +1,30 @@ package features import ( - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" ) type Identification struct { - *FeatureImpl + *Feature } -func NewIdentification(localRole, remoteRole model.RoleType, spineLocalDevice *spine.DeviceLocalImpl, entity *spine.EntityRemoteImpl) (*Identification, error) { - feature, err := NewFeatureImpl(model.FeatureTypeTypeIdentification, localRole, remoteRole, spineLocalDevice, entity) +// Get a new Identification features helper +// +// - The feature on the local entity has to be of role client +// - The feature on the remote entity has to be of role server +func NewIdentification( + localEntity spineapi.EntityLocalInterface, + remoteEntity spineapi.EntityRemoteInterface) (*Identification, error) { + feature, err := NewFeature(model.FeatureTypeTypeIdentification, localEntity, remoteEntity) if err != nil { return nil, err } i := &Identification{ - FeatureImpl: feature, + Feature: feature, } return i, nil @@ -29,14 +37,9 @@ func (i *Identification) RequestValues() (*model.MsgCounterType, error) { // return current values for Identification func (i *Identification) GetValues() ([]model.IdentificationDataType, error) { - rData := i.featureRemote.Data(model.FunctionTypeIdentificationListData) - if rData == nil { - return nil, ErrDataNotAvailable - } - - data := rData.(*model.IdentificationListDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.IdentificationListDataType](i.featureRemote, model.FunctionTypeIdentificationListData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data.IdentificationData, nil diff --git a/features/identification_test.go b/features/identification_test.go index 37f7942a..b1a97a0e 100644 --- a/features/identification_test.go +++ b/features/identification_test.go @@ -1,11 +1,13 @@ -package features +package features_test import ( "testing" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/features" "github.com/enbility/eebus-go/util" + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) @@ -17,21 +19,21 @@ func TestIdentificationSuite(t *testing.T) { type IdentificationSuite struct { suite.Suite - localDevice *spine.DeviceLocalImpl - remoteEntity *spine.EntityRemoteImpl + localEntity spineapi.EntityLocalInterface + remoteEntity spineapi.EntityRemoteInterface - identification *Identification + identification *features.Identification sentMessage []byte } -var _ spine.SpineDataConnection = (*IdentificationSuite)(nil) +var _ shipapi.ShipConnectionDataWriterInterface = (*IdentificationSuite)(nil) -func (s *IdentificationSuite) WriteSpineMessage(message []byte) { +func (s *IdentificationSuite) WriteShipMessageWithPayload(message []byte) { s.sentMessage = message } func (s *IdentificationSuite) BeforeTest(suiteName, testName string) { - s.localDevice, s.remoteEntity = setupFeatures( + s.localEntity, s.remoteEntity = setupFeatures( s.T(), s, []featureFunctions{ @@ -45,7 +47,7 @@ func (s *IdentificationSuite) BeforeTest(suiteName, testName string) { ) var err error - s.identification, err = NewIdentification(model.RoleTypeServer, model.RoleTypeClient, s.localDevice, s.remoteEntity) + s.identification, err = features.NewIdentification(s.localEntity, s.remoteEntity) assert.Nil(s.T(), err) assert.NotNil(s.T(), s.identification) } @@ -69,7 +71,7 @@ func (s *IdentificationSuite) Test_GetValues() { } func (s *IdentificationSuite) addData() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.IdentificationListDataType{ IdentificationData: []model.IdentificationDataType{ { diff --git a/features/incentivetable.go b/features/incentivetable.go index a39713ca..9e0d7eb7 100644 --- a/features/incentivetable.go +++ b/features/incentivetable.go @@ -1,37 +1,43 @@ package features import ( - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" ) type IncentiveTable struct { - *FeatureImpl + *Feature } -func NewIncentiveTable(localRole, remoteRole model.RoleType, spineLocalDevice *spine.DeviceLocalImpl, entity *spine.EntityRemoteImpl) (*IncentiveTable, error) { - feature, err := NewFeatureImpl(model.FeatureTypeTypeIncentiveTable, localRole, remoteRole, spineLocalDevice, entity) +// Get a new IncentiveTable features helper +// +// - The feature on the local entity has to be of role client +// - The feature on the remote entity has to be of role server +func NewIncentiveTable( + localEntity spineapi.EntityLocalInterface, + remoteEntity spineapi.EntityRemoteInterface) (*IncentiveTable, error) { + feature, err := NewFeature(model.FeatureTypeTypeIncentiveTable, localEntity, remoteEntity) if err != nil { return nil, err } i := &IncentiveTable{ - FeatureImpl: feature, + Feature: feature, } return i, nil } // request FunctionTypeIncentiveTableDescriptionData from a remote entity -func (i *IncentiveTable) RequestDescriptions() error { - _, err := i.requestData(model.FunctionTypeIncentiveTableDescriptionData, nil, nil) - return err +func (i *IncentiveTable) RequestDescriptions() (*model.MsgCounterType, error) { + return i.requestData(model.FunctionTypeIncentiveTableDescriptionData, nil, nil) } // request FunctionTypeIncentiveTableConstraintsData from a remote entity -func (i *IncentiveTable) RequestConstraints() error { - _, err := i.requestData(model.FunctionTypeIncentiveTableConstraintsData, nil, nil) - return err +func (i *IncentiveTable) RequestConstraints() (*model.MsgCounterType, error) { + return i.requestData(model.FunctionTypeIncentiveTableConstraintsData, nil, nil) } // request FunctionTypeIncentiveTableData from a remote entity @@ -43,7 +49,7 @@ func (i *IncentiveTable) RequestValues() (*model.MsgCounterType, error) { // returns an error if this failed func (i *IncentiveTable) WriteValues(data []model.IncentiveTableType) (*model.MsgCounterType, error) { if len(data) == 0 { - return nil, ErrMissingData + return nil, api.ErrMissingData } cmd := model.CmdType{ @@ -52,19 +58,14 @@ func (i *IncentiveTable) WriteValues(data []model.IncentiveTableType) (*model.Ms }, } - return i.featureRemote.Sender().Write(i.featureLocal.Address(), i.featureRemote.Address(), cmd) + return i.remoteDevice.Sender().Write(i.featureLocal.Address(), i.featureRemote.Address(), cmd) } // return current values for Time Series func (i *IncentiveTable) GetValues() ([]model.IncentiveTableType, error) { - rData := i.featureRemote.Data(model.FunctionTypeIncentiveTableData) - if rData == nil { - return nil, ErrDataNotAvailable - } - - data := rData.(*model.IncentiveTableDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.IncentiveTableDataType](i.featureRemote, model.FunctionTypeIncentiveTableData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data.IncentiveTable, nil @@ -74,7 +75,7 @@ func (i *IncentiveTable) GetValues() ([]model.IncentiveTableType, error) { // returns an error if this failed func (i *IncentiveTable) WriteDescriptions(data []model.IncentiveTableDescriptionType) (*model.MsgCounterType, error) { if len(data) == 0 { - return nil, ErrMissingData + return nil, api.ErrMissingData } cmd := model.CmdType{ @@ -83,19 +84,14 @@ func (i *IncentiveTable) WriteDescriptions(data []model.IncentiveTableDescriptio }, } - return i.featureRemote.Sender().Write(i.featureLocal.Address(), i.featureRemote.Address(), cmd) + return i.remoteDevice.Sender().Write(i.featureLocal.Address(), i.featureRemote.Address(), cmd) } // return list of descriptions func (i *IncentiveTable) GetDescriptions() ([]model.IncentiveTableDescriptionType, error) { - rData := i.featureRemote.Data(model.FunctionTypeIncentiveTableDescriptionData) - if rData == nil { - return nil, ErrDataNotAvailable - } - - data := rData.(*model.IncentiveTableDescriptionDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.IncentiveTableDescriptionDataType](i.featureRemote, model.FunctionTypeIncentiveTableDescriptionData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data.IncentiveTableDescription, nil @@ -116,7 +112,7 @@ func (i *IncentiveTable) GetDescriptionsForScope(scope model.ScopeTypeType) ([]m } if len(result) == 0 { - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } return result, nil @@ -124,14 +120,9 @@ func (i *IncentiveTable) GetDescriptionsForScope(scope model.ScopeTypeType) ([]m // return list of constraints func (i *IncentiveTable) GetConstraints() ([]model.IncentiveTableConstraintsType, error) { - rData := i.featureRemote.Data(model.FunctionTypeIncentiveTableConstraintsData) - if rData == nil { - return nil, ErrDataNotAvailable - } - - data := rData.(*model.IncentiveTableConstraintsDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.IncentiveTableConstraintsDataType](i.featureRemote, model.FunctionTypeIncentiveTableConstraintsData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data.IncentiveTableConstraints, nil diff --git a/features/incentivetable_test.go b/features/incentivetable_test.go index 2f5d03b5..c74aab6f 100644 --- a/features/incentivetable_test.go +++ b/features/incentivetable_test.go @@ -1,11 +1,13 @@ -package features +package features_test import ( "testing" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/features" "github.com/enbility/eebus-go/util" + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) @@ -17,21 +19,21 @@ func TestIncentiveTableSuite(t *testing.T) { type IncentiveTableSuite struct { suite.Suite - localDevice *spine.DeviceLocalImpl - remoteEntity *spine.EntityRemoteImpl + localEntity spineapi.EntityLocalInterface + remoteEntity spineapi.EntityRemoteInterface - incentiveTable *IncentiveTable + incentiveTable *features.IncentiveTable sentMessage []byte } -var _ spine.SpineDataConnection = (*IncentiveTableSuite)(nil) +var _ shipapi.ShipConnectionDataWriterInterface = (*IncentiveTableSuite)(nil) -func (s *IncentiveTableSuite) WriteSpineMessage(message []byte) { +func (s *IncentiveTableSuite) WriteShipMessageWithPayload(message []byte) { s.sentMessage = message } func (s *IncentiveTableSuite) BeforeTest(suiteName, testName string) { - s.localDevice, s.remoteEntity = setupFeatures( + s.localEntity, s.remoteEntity = setupFeatures( s.T(), s, []featureFunctions{ @@ -47,19 +49,21 @@ func (s *IncentiveTableSuite) BeforeTest(suiteName, testName string) { ) var err error - s.incentiveTable, err = NewIncentiveTable(model.RoleTypeServer, model.RoleTypeClient, s.localDevice, s.remoteEntity) + s.incentiveTable, err = features.NewIncentiveTable(s.localEntity, s.remoteEntity) assert.Nil(s.T(), err) assert.NotNil(s.T(), s.incentiveTable) } func (s *IncentiveTableSuite) Test_RequestDescriptions() { - err := s.incentiveTable.RequestDescriptions() + counter, err := s.incentiveTable.RequestDescriptions() assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) } func (s *IncentiveTableSuite) Test_RequestConstraints() { - err := s.incentiveTable.RequestConstraints() + counter, err := s.incentiveTable.RequestConstraints() assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) } func (s *IncentiveTableSuite) Test_RequestValues() { @@ -216,7 +220,7 @@ func (s *IncentiveTableSuite) Test_GetConstraints() { // helpers func (s *IncentiveTableSuite) addData() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.IncentiveTableDataType{ IncentiveTable: []model.IncentiveTableType{ @@ -236,7 +240,7 @@ func (s *IncentiveTableSuite) addData() { } func (s *IncentiveTableSuite) addDescription() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.IncentiveTableDescriptionDataType{ IncentiveTableDescription: []model.IncentiveTableDescriptionType{ { @@ -275,7 +279,7 @@ func (s *IncentiveTableSuite) addDescription() { } func (s *IncentiveTableSuite) addConstraints() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.IncentiveTableConstraintsDataType{ IncentiveTableConstraints: []model.IncentiveTableConstraintsType{ { diff --git a/features/loadcontrol.go b/features/loadcontrol.go index feca212f..16d08d14 100644 --- a/features/loadcontrol.go +++ b/features/loadcontrol.go @@ -1,37 +1,44 @@ package features import ( - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/api" + "github.com/enbility/eebus-go/util" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" ) type LoadControl struct { - *FeatureImpl + *Feature } -func NewLoadControl(localRole, remoteRole model.RoleType, spineLocalDevice *spine.DeviceLocalImpl, entity *spine.EntityRemoteImpl) (*LoadControl, error) { - feature, err := NewFeatureImpl(model.FeatureTypeTypeLoadControl, localRole, remoteRole, spineLocalDevice, entity) +// Get a new LoadControl features helper +// +// - The feature on the local entity has to be of role client +// - The feature on the remote entity has to be of role server +func NewLoadControl( + localEntity spineapi.EntityLocalInterface, + remoteEntity spineapi.EntityRemoteInterface) (*LoadControl, error) { + feature, err := NewFeature(model.FeatureTypeTypeLoadControl, localEntity, remoteEntity) if err != nil { return nil, err } lc := &LoadControl{ - FeatureImpl: feature, + Feature: feature, } return lc, nil } // request FunctionTypeLoadControlLimitDescriptionListData from a remote device -func (l *LoadControl) RequestLimitDescriptions() error { - _, err := l.requestData(model.FunctionTypeLoadControlLimitDescriptionListData, nil, nil) - return err +func (l *LoadControl) RequestLimitDescriptions() (*model.MsgCounterType, error) { + return l.requestData(model.FunctionTypeLoadControlLimitDescriptionListData, nil, nil) } // request FunctionTypeLoadControlLimitConstraintsListData from a remote device -func (l *LoadControl) RequestLimitConstraints() error { - _, err := l.requestData(model.FunctionTypeLoadControlLimitConstraintsListData, nil, nil) - return err +func (l *LoadControl) RequestLimitConstraints() (*model.MsgCounterType, error) { + return l.requestData(model.FunctionTypeLoadControlLimitConstraintsListData, nil, nil) } // request FunctionTypeLoadControlLimitListData from a remote device @@ -42,14 +49,9 @@ func (l *LoadControl) RequestLimitValues() (*model.MsgCounterType, error) { // returns the load control limit descriptions // returns an error if no description data is available yet func (l *LoadControl) GetLimitDescriptions() ([]model.LoadControlLimitDescriptionDataType, error) { - rData := l.featureRemote.Data(model.FunctionTypeLoadControlLimitDescriptionListData) - if rData == nil { - return nil, ErrMetadataNotAvailable - } - - data := rData.(*model.LoadControlLimitDescriptionListDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.LoadControlLimitDescriptionListDataType](l.featureRemote, model.FunctionTypeLoadControlLimitDescriptionListData) + if err != nil { + return nil, api.ErrMetadataNotAvailable } return data.LoadControlLimitDescriptionData, nil @@ -72,7 +74,41 @@ func (l *LoadControl) GetLimitDescriptionsForCategory(category model.LoadControl } if len(result) == 0 { - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable + } + + return result, nil +} + +// returns the load control limit descriptions of a provided type, direction and scope +// returns an error if no description data for the category is available +// +// providing an empty string for any of the params, will ignore the value in the request +func (l *LoadControl) GetLimitDescriptionsForTypeCategoryDirectionScope( + limitType model.LoadControlLimitTypeType, + limitCategory model.LoadControlCategoryType, + limitDirection model.EnergyDirectionType, + scope model.ScopeTypeType, +) ([]model.LoadControlLimitDescriptionDataType, error) { + data, err := l.GetLimitDescriptions() + if err != nil || len(data) == 0 { + return nil, err + } + + var result []model.LoadControlLimitDescriptionDataType + + for _, item := range data { + if item.LimitId != nil && + (limitType == "" || (item.LimitType != nil && *item.LimitType == limitType)) && + (limitCategory == "" || (item.LimitCategory != nil && *item.LimitCategory == limitCategory)) && + (limitDirection == "" || (item.LimitDirection != nil && *item.LimitDirection == limitDirection)) && + (scope == "" || (item.ScopeType != nil && *item.ScopeType == scope)) { + result = append(result, item) + } + } + + if len(result) == 0 { + return nil, api.ErrDataNotAvailable } return result, nil @@ -95,7 +131,7 @@ func (l *LoadControl) GetLimitDescriptionsForMeasurementId(measurementId model.M } if len(result) == 0 { - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } return result, nil @@ -105,28 +141,25 @@ func (l *LoadControl) GetLimitDescriptionsForMeasurementId(measurementId model.M // returns an error if this failed func (l *LoadControl) WriteLimitValues(data []model.LoadControlLimitDataType) (*model.MsgCounterType, error) { if len(data) == 0 { - return nil, ErrMissingData + return nil, api.ErrMissingData } cmd := model.CmdType{ + Function: util.Ptr(model.FunctionTypeLoadControlLimitListData), + Filter: []model.FilterType{*model.NewFilterTypePartial()}, LoadControlLimitListData: &model.LoadControlLimitListDataType{ LoadControlLimitData: data, }, } - return l.featureRemote.Sender().Write(l.featureLocal.Address(), l.featureRemote.Address(), cmd) + return l.remoteDevice.Sender().Write(l.featureLocal.Address(), l.featureRemote.Address(), cmd) } // return limit data func (l *LoadControl) GetLimitValues() ([]model.LoadControlLimitDataType, error) { - rData := l.featureRemote.Data(model.FunctionTypeLoadControlLimitListData) - if rData == nil { - return nil, ErrDataNotAvailable - } - - data := rData.(*model.LoadControlLimitListDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.LoadControlLimitListDataType](l.featureRemote, model.FunctionTypeLoadControlLimitListData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data.LoadControlLimitData, nil @@ -145,5 +178,5 @@ func (l *LoadControl) GetLimitValueForLimitId(limitId model.LoadControlLimitIdTy } } - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } diff --git a/features/loadcontrol_test.go b/features/loadcontrol_test.go index 75200e5a..fa6b6928 100644 --- a/features/loadcontrol_test.go +++ b/features/loadcontrol_test.go @@ -1,11 +1,13 @@ -package features +package features_test import ( "testing" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/features" "github.com/enbility/eebus-go/util" + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) @@ -17,21 +19,21 @@ func TestLoadControlSuite(t *testing.T) { type LoadControlSuite struct { suite.Suite - localDevice *spine.DeviceLocalImpl - remoteEntity *spine.EntityRemoteImpl + localEntity spineapi.EntityLocalInterface + remoteEntity spineapi.EntityRemoteInterface - loadControl *LoadControl + loadControl *features.LoadControl sentMessage []byte } -var _ spine.SpineDataConnection = (*LoadControlSuite)(nil) +var _ shipapi.ShipConnectionDataWriterInterface = (*LoadControlSuite)(nil) -func (s *LoadControlSuite) WriteSpineMessage(message []byte) { +func (s *LoadControlSuite) WriteShipMessageWithPayload(message []byte) { s.sentMessage = message } func (s *LoadControlSuite) BeforeTest(suiteName, testName string) { - s.localDevice, s.remoteEntity = setupFeatures( + s.localEntity, s.remoteEntity = setupFeatures( s.T(), s, []featureFunctions{ @@ -47,19 +49,21 @@ func (s *LoadControlSuite) BeforeTest(suiteName, testName string) { ) var err error - s.loadControl, err = NewLoadControl(model.RoleTypeServer, model.RoleTypeClient, s.localDevice, s.remoteEntity) + s.loadControl, err = features.NewLoadControl(s.localEntity, s.remoteEntity) assert.Nil(s.T(), err) assert.NotNil(s.T(), s.loadControl) } func (s *LoadControlSuite) Test_RequestLimitDescription() { - err := s.loadControl.RequestLimitDescriptions() + counter, err := s.loadControl.RequestLimitDescriptions() assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) } func (s *LoadControlSuite) Test_RequestLimitConstraints() { - err := s.loadControl.RequestLimitConstraints() + counter, err := s.loadControl.RequestLimitConstraints() assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) } func (s *LoadControlSuite) Test_RequestLimits() { @@ -96,6 +100,34 @@ func (s *LoadControlSuite) Test_GetLimitDescriptionsForCategory() { assert.NotNil(s.T(), data) } +func (s *LoadControlSuite) Test_GetLimitDescriptionsForTypeDirectionScope() { + data, err := s.loadControl.GetLimitDescriptionsForTypeCategoryDirectionScope( + model.LoadControlLimitTypeTypeSignDependentAbsValueLimit, + model.LoadControlCategoryTypeObligation, + model.EnergyDirectionTypeConsume, + model.ScopeTypeTypeActivePowerLimit) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), data) + + s.addDescription() + + data, err = s.loadControl.GetLimitDescriptionsForTypeCategoryDirectionScope( + model.LoadControlLimitTypeTypeMaxValueLimit, + model.LoadControlCategoryTypeObligation, + model.EnergyDirectionTypeConsume, + model.ScopeTypeTypeActivePowerLimit) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), data) + + data, err = s.loadControl.GetLimitDescriptionsForTypeCategoryDirectionScope( + model.LoadControlLimitTypeTypeSignDependentAbsValueLimit, + model.LoadControlCategoryTypeObligation, + model.EnergyDirectionTypeConsume, + model.ScopeTypeTypeActivePowerLimit) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), data) +} + func (s *LoadControlSuite) Test_GetLimitDescriptionsForMeasurementId() { measurementId := model.MeasurementIdType(0) data, err := s.loadControl.GetLimitDescriptionsForMeasurementId(measurementId) @@ -180,13 +212,16 @@ func (s *LoadControlSuite) Test_GetLimitDataForLimitId() { // helper func (s *LoadControlSuite) addDescription() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.LoadControlLimitDescriptionListDataType{ LoadControlLimitDescriptionData: []model.LoadControlLimitDescriptionDataType{ { - LimitId: util.Ptr(model.LoadControlLimitIdType(0)), - MeasurementId: util.Ptr(model.MeasurementIdType(0)), - LimitCategory: util.Ptr(model.LoadControlCategoryTypeObligation), + LimitId: util.Ptr(model.LoadControlLimitIdType(0)), + MeasurementId: util.Ptr(model.MeasurementIdType(0)), + LimitType: util.Ptr(model.LoadControlLimitTypeTypeSignDependentAbsValueLimit), + LimitCategory: util.Ptr(model.LoadControlCategoryTypeObligation), + LimitDirection: util.Ptr(model.EnergyDirectionTypeConsume), + ScopeType: util.Ptr(model.ScopeTypeTypeActivePowerLimit), }, }, } @@ -194,7 +229,7 @@ func (s *LoadControlSuite) addDescription() { } func (s *LoadControlSuite) addData() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.LoadControlLimitListDataType{ LoadControlLimitData: []model.LoadControlLimitDataType{ { diff --git a/features/measurement.go b/features/measurement.go index 8dacef96..5cba18ea 100644 --- a/features/measurement.go +++ b/features/measurement.go @@ -1,38 +1,43 @@ package features import ( - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" ) type Measurement struct { - *FeatureImpl + *Feature } -func NewMeasurement(localRole, remoteRole model.RoleType, spineLocalDevice *spine.DeviceLocalImpl, entity *spine.EntityRemoteImpl) (*Measurement, error) { - feature, err := NewFeatureImpl(model.FeatureTypeTypeMeasurement, localRole, remoteRole, spineLocalDevice, entity) +// Get a new Measurement features helper +// +// - The feature on the local entity has to be of role client +// - The feature on the remote entity has to be of role server +func NewMeasurement( + localEntity spineapi.EntityLocalInterface, + remoteEntity spineapi.EntityRemoteInterface) (*Measurement, error) { + feature, err := NewFeature(model.FeatureTypeTypeMeasurement, localEntity, remoteEntity) if err != nil { return nil, err } m := &Measurement{ - FeatureImpl: feature, + Feature: feature, } return m, nil } // request FunctionTypeMeasurementDescriptionListData from a remote device -func (m *Measurement) RequestDescriptions() error { - _, err := m.requestData(model.FunctionTypeMeasurementDescriptionListData, nil, nil) - - return err +func (m *Measurement) RequestDescriptions() (*model.MsgCounterType, error) { + return m.requestData(model.FunctionTypeMeasurementDescriptionListData, nil, nil) } // request FunctionTypeMeasurementConstraintsListData from a remote entity -func (m *Measurement) RequestConstraints() error { - _, err := m.requestData(model.FunctionTypeMeasurementConstraintsListData, nil, nil) - return err +func (m *Measurement) RequestConstraints() (*model.MsgCounterType, error) { + return m.requestData(model.FunctionTypeMeasurementConstraintsListData, nil, nil) } // request FunctionTypeMeasurementListData from a remote entity @@ -42,13 +47,9 @@ func (m *Measurement) RequestValues() (*model.MsgCounterType, error) { // return list of descriptions func (m *Measurement) GetDescriptions() ([]model.MeasurementDescriptionDataType, error) { - rData := m.featureRemote.Data(model.FunctionTypeMeasurementDescriptionListData) - if rData == nil { - return nil, ErrMetadataNotAvailable - } - data := rData.(*model.MeasurementDescriptionListDataType) - if data == nil { - return nil, ErrMetadataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.MeasurementDescriptionListDataType](m.featureRemote, model.FunctionTypeMeasurementDescriptionListData) + if err != nil { + return nil, api.ErrMetadataNotAvailable } return data.MeasurementDescriptionData, nil @@ -69,7 +70,7 @@ func (m *Measurement) GetDescriptionsForScope(scope model.ScopeTypeType) ([]mode } if len(result) == 0 { - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } return result, nil @@ -91,22 +92,39 @@ func (m *Measurement) GetDescriptionForMeasurementId(measurementId model.Measure return &item, nil } - return nil, ErrMetadataNotAvailable + return nil, api.ErrMetadataNotAvailable } // return current values for measurements func (m *Measurement) GetValues() ([]model.MeasurementDataType, error) { - rData := m.featureRemote.Data(model.FunctionTypeMeasurementListData) - if rData == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.MeasurementListDataType](m.featureRemote, model.FunctionTypeMeasurementListData) + if err != nil { + return nil, api.ErrMetadataNotAvailable + } + + return data.MeasurementData, nil +} + +// return current values of a measurementId +// +// if nothing is found, it will return an error +func (m *Measurement) GetValueForMeasurementId(id model.MeasurementIdType) (float64, error) { + values, err := m.GetValues() + if err != nil { + return 0, err } - data := rData.(*model.MeasurementListDataType) - if data == nil { - return nil, ErrDataNotAvailable + for _, item := range values { + if item.MeasurementId == nil || item.Value == nil { + continue + } + + if *item.MeasurementId == id { + return item.Value.GetValue(), nil + } } - return data.MeasurementData, nil + return 0, api.ErrDataNotAvailable } // return current values of a defined measurementType, commodityType and scopeType @@ -136,7 +154,7 @@ func (m *Measurement) GetValuesForTypeCommodityScope(measurement model.Measureme } if len(resultSet) == 0 { - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } return resultSet, nil @@ -144,14 +162,9 @@ func (m *Measurement) GetValuesForTypeCommodityScope(measurement model.Measureme // return measurement constraints func (m *Measurement) GetConstraints() ([]model.MeasurementConstraintsDataType, error) { - rData := m.featureRemote.Data(model.FunctionTypeMeasurementConstraintsListData) - if rData == nil { - return nil, ErrMetadataNotAvailable - } - - data := rData.(*model.MeasurementConstraintsListDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.MeasurementConstraintsListDataType](m.featureRemote, model.FunctionTypeMeasurementConstraintsListData) + if err != nil { + return nil, api.ErrMetadataNotAvailable } return data.MeasurementConstraintsData, nil diff --git a/features/measurement_test.go b/features/measurement_test.go index a8c1c377..03d28a96 100644 --- a/features/measurement_test.go +++ b/features/measurement_test.go @@ -1,12 +1,14 @@ -package features +package features_test import ( "testing" "time" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/features" "github.com/enbility/eebus-go/util" + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) @@ -18,21 +20,21 @@ func TestMeasurementSuite(t *testing.T) { type MeasurementSuite struct { suite.Suite - localDevice *spine.DeviceLocalImpl - remoteEntity *spine.EntityRemoteImpl + localEntity spineapi.EntityLocalInterface + remoteEntity spineapi.EntityRemoteInterface - measurement *Measurement + measurement *features.Measurement sentMessage []byte } -var _ spine.SpineDataConnection = (*MeasurementSuite)(nil) +var _ shipapi.ShipConnectionDataWriterInterface = (*MeasurementSuite)(nil) -func (s *MeasurementSuite) WriteSpineMessage(message []byte) { +func (s *MeasurementSuite) WriteShipMessageWithPayload(message []byte) { s.sentMessage = message } func (s *MeasurementSuite) BeforeTest(suiteName, testName string) { - s.localDevice, s.remoteEntity = setupFeatures( + s.localEntity, s.remoteEntity = setupFeatures( s.T(), s, []featureFunctions{ @@ -56,19 +58,21 @@ func (s *MeasurementSuite) BeforeTest(suiteName, testName string) { ) var err error - s.measurement, err = NewMeasurement(model.RoleTypeServer, model.RoleTypeClient, s.localDevice, s.remoteEntity) + s.measurement, err = features.NewMeasurement(s.localEntity, s.remoteEntity) assert.Nil(s.T(), err) assert.NotNil(s.T(), s.measurement) } func (s *MeasurementSuite) Test_RequestDescriptions() { - err := s.measurement.RequestDescriptions() + msgCounter, err := s.measurement.RequestDescriptions() assert.Nil(s.T(), err) + assert.NotNil(s.T(), msgCounter) } func (s *MeasurementSuite) Test_RequestConstraints() { - err := s.measurement.RequestConstraints() + msgCounter, err := s.measurement.RequestConstraints() assert.Nil(s.T(), err) + assert.NotNil(s.T(), msgCounter) } func (s *MeasurementSuite) Test_RequestValues() { @@ -77,6 +81,24 @@ func (s *MeasurementSuite) Test_RequestValues() { assert.NotNil(s.T(), counter) } +func (s *MeasurementSuite) Test_GetValueForMeasurementId() { + measurement := model.MeasurementIdType(0) + + value, err := s.measurement.GetValueForMeasurementId(measurement) + assert.NotNil(s.T(), err) + assert.Equal(s.T(), 0.0, value) + + s.addData() + + value, err = s.measurement.GetValueForMeasurementId(measurement) + assert.Nil(s.T(), err) + assert.Equal(s.T(), 9.0, value) + + value, err = s.measurement.GetValueForMeasurementId(model.MeasurementIdType(100)) + assert.NotNil(s.T(), err) + assert.Equal(s.T(), 0.0, value) +} + func (s *MeasurementSuite) Test_GetValuesForTypeCommodityScope() { measurement := model.MeasurementTypeTypeCurrent commodity := model.CommodityTypeTypeElectricity @@ -151,7 +173,7 @@ func (s *MeasurementSuite) Test_GetValues() { // helper func (s *MeasurementSuite) addDescription() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.MeasurementDescriptionListDataType{ MeasurementDescriptionData: []model.MeasurementDescriptionDataType{ { @@ -173,7 +195,7 @@ func (s *MeasurementSuite) addDescription() { } func (s *MeasurementSuite) addConstraints() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.MeasurementConstraintsListDataType{ MeasurementConstraintsData: []model.MeasurementConstraintsDataType{ { @@ -194,9 +216,9 @@ func (s *MeasurementSuite) addConstraints() { } func (s *MeasurementSuite) addData() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) - t := time.Now() + t := time.Now().UTC() fData := &model.MeasurementListDataType{ MeasurementData: []model.MeasurementDataType{ { diff --git a/features/smartenergymanagementps.go b/features/smartenergymanagementps.go new file mode 100644 index 00000000..8d90a08d --- /dev/null +++ b/features/smartenergymanagementps.go @@ -0,0 +1,63 @@ +package features + +import ( + "github.com/enbility/eebus-go/api" + "github.com/enbility/eebus-go/util" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" +) + +type SmartEnergyManagementPs struct { + *Feature +} + +// Get a new Identification features helper +// +// - The feature on the local entity has to be of role client +// - The feature on the remote entity has to be of role server +func NewSmartEnergyManagementPs( + localEntity spineapi.EntityLocalInterface, + remoteEntity spineapi.EntityRemoteInterface) (*SmartEnergyManagementPs, error) { + feature, err := NewFeature(model.FeatureTypeTypeSmartEnergyManagementPs, localEntity, remoteEntity) + if err != nil { + return nil, err + } + + i := &SmartEnergyManagementPs{ + Feature: feature, + } + + return i, nil +} + +// request FunctionTypeSmartEnergyManagementPsData from a remote entity +func (i *SmartEnergyManagementPs) RequestValues() (*model.MsgCounterType, error) { + return i.requestData(model.FunctionTypeSmartEnergyManagementPsData, nil, nil) +} + +// write SmartEnergyManagementPsData +// returns an error if this failed +func (l *SmartEnergyManagementPs) WriteValues(data *model.SmartEnergyManagementPsDataType) (*model.MsgCounterType, error) { + if data == nil { + return nil, api.ErrMissingData + } + + cmd := model.CmdType{ + Function: util.Ptr(model.FunctionTypeSmartEnergyManagementPsData), + Filter: []model.FilterType{*model.NewFilterTypePartial()}, + SmartEnergyManagementPsData: data, + } + + return l.remoteDevice.Sender().Write(l.featureLocal.Address(), l.featureRemote.Address(), cmd) +} + +// return current values for FunctionTypeSmartEnergyManagementPsData +func (i *SmartEnergyManagementPs) GetValues() (*model.SmartEnergyManagementPsDataType, error) { + data, err := spine.RemoteFeatureDataCopyOfType[*model.SmartEnergyManagementPsDataType](i.featureRemote, model.FunctionTypeSmartEnergyManagementPsData) + if err != nil { + return nil, api.ErrDataNotAvailable + } + + return data, nil +} diff --git a/features/smartenergymanagementps_test.go b/features/smartenergymanagementps_test.go new file mode 100644 index 00000000..fcca328f --- /dev/null +++ b/features/smartenergymanagementps_test.go @@ -0,0 +1,95 @@ +package features_test + +import ( + "testing" + + "github.com/enbility/eebus-go/features" + "github.com/enbility/eebus-go/util" + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestSmartEnergyManagementPsSuite(t *testing.T) { + suite.Run(t, new(SmartEnergyManagementPsSuite)) +} + +type SmartEnergyManagementPsSuite struct { + suite.Suite + + localEntity spineapi.EntityLocalInterface + remoteEntity spineapi.EntityRemoteInterface + + smartenergymgmtps *features.SmartEnergyManagementPs + sentMessage []byte +} + +var _ shipapi.ShipConnectionDataWriterInterface = (*SmartEnergyManagementPsSuite)(nil) + +func (s *SmartEnergyManagementPsSuite) WriteShipMessageWithPayload(message []byte) { + s.sentMessage = message +} + +func (s *SmartEnergyManagementPsSuite) BeforeTest(suiteName, testName string) { + s.localEntity, s.remoteEntity = setupFeatures( + s.T(), + s, + []featureFunctions{ + { + featureType: model.FeatureTypeTypeSmartEnergyManagementPs, + functions: []model.FunctionType{ + model.FunctionTypeSmartEnergyManagementPsData, + }, + }, + }, + ) + + var err error + s.smartenergymgmtps, err = features.NewSmartEnergyManagementPs(s.localEntity, s.remoteEntity) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), s.smartenergymgmtps) +} + +func (s *SmartEnergyManagementPsSuite) Test_RequestValues() { + counter, err := s.smartenergymgmtps.RequestValues() + assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) +} + +func (s *SmartEnergyManagementPsSuite) Test_WriteValues() { + counter, err := s.smartenergymgmtps.WriteValues(nil) + assert.NotNil(s.T(), err) + assert.Nil(s.T(), counter) + + data := &model.SmartEnergyManagementPsDataType{ + NodeScheduleInformation: &model.PowerSequenceNodeScheduleInformationDataType{}, + Alternatives: []model.SmartEnergyManagementPsAlternativesType{}, + } + counter, err = s.smartenergymgmtps.WriteValues(data) + assert.Nil(s.T(), err) + assert.NotNil(s.T(), counter) +} + +func (s *SmartEnergyManagementPsSuite) Test_GetValues() { + value, err := s.smartenergymgmtps.GetValues() + assert.NotNil(s.T(), err) + assert.Nil(s.T(), value) + + s.addData() + + value, err = s.smartenergymgmtps.GetValues() + assert.Nil(s.T(), err) + assert.NotNil(s.T(), value) +} + +func (s *SmartEnergyManagementPsSuite) addData() { + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) + + fData := &model.SmartEnergyManagementPsDataType{ + NodeScheduleInformation: &model.PowerSequenceNodeScheduleInformationDataType{}, + Alternatives: []model.SmartEnergyManagementPsAlternativesType{}, + } + rF.UpdateData(model.FunctionTypeSmartEnergyManagementPsData, fData, nil, nil) +} diff --git a/features/timeseries.go b/features/timeseries.go index 7b3d02c2..b5c9a6fc 100644 --- a/features/timeseries.go +++ b/features/timeseries.go @@ -1,37 +1,43 @@ package features import ( - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" ) type TimeSeries struct { - *FeatureImpl + *Feature } -func NewTimeSeries(localRole, remoteRole model.RoleType, spineLocalDevice *spine.DeviceLocalImpl, entity *spine.EntityRemoteImpl) (*TimeSeries, error) { - feature, err := NewFeatureImpl(model.FeatureTypeTypeTimeSeries, localRole, remoteRole, spineLocalDevice, entity) +// Get a new TimeSeries features helper +// +// - The feature on the local entity has to be of role client +// - The feature on the remote entity has to be of role server +func NewTimeSeries( + localEntity spineapi.EntityLocalInterface, + remoteEntity spineapi.EntityRemoteInterface) (*TimeSeries, error) { + feature, err := NewFeature(model.FeatureTypeTypeTimeSeries, localEntity, remoteEntity) if err != nil { return nil, err } t := &TimeSeries{ - FeatureImpl: feature, + Feature: feature, } return t, nil } // request FunctionTypeTimeSeriesDescriptionListData from a remote entity -func (t *TimeSeries) RequestDescriptions() error { - _, err := t.requestData(model.FunctionTypeTimeSeriesDescriptionListData, nil, nil) - return err +func (t *TimeSeries) RequestDescriptions() (*model.MsgCounterType, error) { + return t.requestData(model.FunctionTypeTimeSeriesDescriptionListData, nil, nil) } // request FunctionTypeTimeSeriesConstraintsListData from a remote entity -func (t *TimeSeries) RequestConstraints() error { - _, err := t.requestData(model.FunctionTypeTimeSeriesConstraintsListData, nil, nil) - return err +func (t *TimeSeries) RequestConstraints() (*model.MsgCounterType, error) { + return t.requestData(model.FunctionTypeTimeSeriesConstraintsListData, nil, nil) } // request FunctionTypeTimeSeriesListData from a remote device @@ -43,7 +49,7 @@ func (t *TimeSeries) RequestValues() (*model.MsgCounterType, error) { // returns an error if this failed func (t *TimeSeries) WriteValues(data []model.TimeSeriesDataType) (*model.MsgCounterType, error) { if len(data) == 0 { - return nil, ErrMissingData + return nil, api.ErrMissingData } cmd := model.CmdType{ @@ -52,19 +58,14 @@ func (t *TimeSeries) WriteValues(data []model.TimeSeriesDataType) (*model.MsgCou }, } - return t.featureRemote.Sender().Write(t.featureLocal.Address(), t.featureRemote.Address(), cmd) + return t.remoteDevice.Sender().Write(t.featureLocal.Address(), t.featureRemote.Address(), cmd) } // return current values for Time Series func (t *TimeSeries) GetValues() ([]model.TimeSeriesDataType, error) { - rData := t.featureRemote.Data(model.FunctionTypeTimeSeriesListData) - if rData == nil { - return nil, ErrDataNotAvailable - } - - data := rData.(*model.TimeSeriesListDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.TimeSeriesListDataType](t.featureRemote, model.FunctionTypeTimeSeriesListData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data.TimeSeriesData, nil @@ -95,19 +96,14 @@ func (t *TimeSeries) GetValueForType(timeSeriesType model.TimeSeriesTypeType) (* return &item, nil } - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } // return list of descriptions func (t *TimeSeries) GetDescriptions() ([]model.TimeSeriesDescriptionDataType, error) { - rData := t.featureRemote.Data(model.FunctionTypeTimeSeriesDescriptionListData) - if rData == nil { - return nil, ErrDataNotAvailable - } - - data := rData.(*model.TimeSeriesDescriptionListDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.TimeSeriesDescriptionListDataType](t.featureRemote, model.FunctionTypeTimeSeriesDescriptionListData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data.TimeSeriesDescriptionData, nil @@ -125,7 +121,7 @@ func (t *TimeSeries) GetDescriptionForId(id model.TimeSeriesIdType) (*model.Time } } - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } func (t *TimeSeries) GetDescriptionForType(timeSeriesType model.TimeSeriesTypeType) (*model.TimeSeriesDescriptionDataType, error) { @@ -140,22 +136,14 @@ func (t *TimeSeries) GetDescriptionForType(timeSeriesType model.TimeSeriesTypeTy } } - return nil, ErrDataNotAvailable + return nil, api.ErrDataNotAvailable } // return current constraints for Time Series func (t *TimeSeries) GetConstraints() ([]model.TimeSeriesConstraintsDataType, error) { - rData := t.featureRemote.Data(model.FunctionTypeTimeSeriesConstraintsListData) - switch constraintsData := rData.(type) { - case *model.TimeSeriesConstraintsListDataType: - if constraintsData == nil { - return nil, ErrDataNotAvailable - } - } - - data := rData.(*model.TimeSeriesConstraintsListDataType) - if data == nil { - return nil, ErrDataNotAvailable + data, err := spine.RemoteFeatureDataCopyOfType[*model.TimeSeriesConstraintsListDataType](t.featureRemote, model.FunctionTypeTimeSeriesConstraintsListData) + if err != nil { + return nil, api.ErrDataNotAvailable } return data.TimeSeriesConstraintsData, nil diff --git a/features/timeseries_test.go b/features/timeseries_test.go index 97c0a107..a396b31d 100644 --- a/features/timeseries_test.go +++ b/features/timeseries_test.go @@ -1,12 +1,14 @@ -package features +package features_test import ( "testing" "time" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/features" "github.com/enbility/eebus-go/util" + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) @@ -18,21 +20,21 @@ func TestTimeSeriesSuite(t *testing.T) { type TimeSeriesSuite struct { suite.Suite - localDevice *spine.DeviceLocalImpl - remoteEntity *spine.EntityRemoteImpl + localEntity spineapi.EntityLocalInterface + remoteEntity spineapi.EntityRemoteInterface - timeSeries *TimeSeries + timeSeries *features.TimeSeries sentMessage []byte } -var _ spine.SpineDataConnection = (*TimeSeriesSuite)(nil) +var _ shipapi.ShipConnectionDataWriterInterface = (*TimeSeriesSuite)(nil) -func (s *TimeSeriesSuite) WriteSpineMessage(message []byte) { +func (s *TimeSeriesSuite) WriteShipMessageWithPayload(message []byte) { s.sentMessage = message } func (s *TimeSeriesSuite) BeforeTest(suiteName, testName string) { - s.localDevice, s.remoteEntity = setupFeatures( + s.localEntity, s.remoteEntity = setupFeatures( s.T(), s, []featureFunctions{ @@ -48,19 +50,21 @@ func (s *TimeSeriesSuite) BeforeTest(suiteName, testName string) { ) var err error - s.timeSeries, err = NewTimeSeries(model.RoleTypeServer, model.RoleTypeClient, s.localDevice, s.remoteEntity) + s.timeSeries, err = features.NewTimeSeries(s.localEntity, s.remoteEntity) assert.Nil(s.T(), err) assert.NotNil(s.T(), s.timeSeries) } func (s *TimeSeriesSuite) Test_RequestDescription() { - err := s.timeSeries.RequestDescriptions() + msgCounter, err := s.timeSeries.RequestDescriptions() assert.Nil(s.T(), err) + assert.NotNil(s.T(), msgCounter) } func (s *TimeSeriesSuite) Test_RequestConstraints() { - err := s.timeSeries.RequestConstraints() + msgCounter, err := s.timeSeries.RequestConstraints() assert.Nil(s.T(), err) + assert.NotNil(s.T(), msgCounter) } func (s *TimeSeriesSuite) Test_RequestValues() { @@ -180,7 +184,7 @@ func (s *TimeSeriesSuite) Test_GetConstraints() { // helpers func (s *TimeSeriesSuite) addData() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.TimeSeriesListDataType{ TimeSeriesData: []model.TimeSeriesDataType{ @@ -210,7 +214,7 @@ func (s *TimeSeriesSuite) addData() { } func (s *TimeSeriesSuite) addDescription() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.TimeSeriesDescriptionListDataType{ TimeSeriesDescriptionData: []model.TimeSeriesDescriptionDataType{ { @@ -227,7 +231,7 @@ func (s *TimeSeriesSuite) addDescription() { } func (s *TimeSeriesSuite) addConstraints() { - rF := s.remoteEntity.Feature(util.Ptr(model.AddressFeatureType(1))) + rF := s.remoteEntity.FeatureOfAddress(util.Ptr(model.AddressFeatureType(1))) fData := &model.TimeSeriesConstraintsListDataType{ TimeSeriesConstraintsData: []model.TimeSeriesConstraintsDataType{ { diff --git a/go.mod b/go.mod index cf80a29d..2dcebb03 100644 --- a/go.mod +++ b/go.mod @@ -1,32 +1,35 @@ module github.com/enbility/eebus-go -go 1.18 +go 1.21.1 require ( + github.com/enbility/ship-go v0.5.0 + github.com/enbility/spine-go v0.5.0 + github.com/stretchr/testify v1.8.4 +) + +require ( + github.com/ahmetb/go-linq/v3 v3.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/google/go-cmp v0.5.9 - github.com/miekg/dns v1.1.52 // indirect + github.com/enbility/zeroconf/v2 v2.0.0-20240210101930-d0004078577b // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/holoplot/go-avahi v0.0.0-20240210093433-b8dc0fc11e7e // indirect + github.com/miekg/dns v1.1.58 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rickb777/date v1.20.5 // indirect github.com/rickb777/plural v1.4.1 // indirect - github.com/stretchr/objx v0.5.0 // indirect - golang.org/x/mod v0.9.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/tools v0.7.0 // indirect + github.com/stretchr/objx v0.5.1 // indirect + gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a // indirect + go.uber.org/mock v0.4.0 // indirect + golang.org/x/mod v0.15.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/tools v0.17.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) -require ( - github.com/ahmetb/go-linq/v3 v3.2.0 - github.com/godbus/dbus/v5 v5.1.0 - github.com/gorilla/websocket v1.5.0 - github.com/holoplot/go-avahi v1.0.1 - github.com/libp2p/zeroconf/v2 v2.2.0 - github.com/rickb777/date v1.20.1 - github.com/stretchr/testify v1.8.2 - gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a -) - retract ( v0.2.2 // Contains retractions only. v0.2.1 // Published accidentally. diff --git a/go.sum b/go.sum index c98cad52..f9865682 100644 --- a/go.sum +++ b/go.sum @@ -3,58 +3,58 @@ github.com/ahmetb/go-linq/v3 v3.2.0/go.mod h1:haQ3JfOeWK8HpVxMtHHEMPVgBKiYyQ+f1/ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/enbility/ship-go v0.5.0 h1:Uqol2XjzDOcvT8HUAE4B/59yqd3mxhpJJ/Q2eDHNGqc= +github.com/enbility/ship-go v0.5.0/go.mod h1:ovyrJE3oPnGT5+eQnOqWut80gFDQ0XHn3ZWU2fHV9xQ= +github.com/enbility/spine-go v0.5.0 h1:3OQBl8gQPW/iuWmwcabmCIXDcFCP0RsDw7uP8BYUmaY= +github.com/enbility/spine-go v0.5.0/go.mod h1:8rXOJ7nTa4qrSRK0PpfavBXMztxi6l+h/IFpIVmHviM= +github.com/enbility/zeroconf/v2 v2.0.0-20240210101930-d0004078577b h1:sg3c6LJ4eWffwtt9SW0lgcIX4Oh274vwdJnNFNNrDco= +github.com/enbility/zeroconf/v2 v2.0.0-20240210101930-d0004078577b/go.mod h1:BjzRRiYX6mWdOgku1xxDE+NsV8PijTby7Q7BkYVdfDU= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/holoplot/go-avahi v1.0.1 h1:XcqR2keL4qWRnlxHD5CAOdWpLFZJ+EOUK0vEuylfvvk= -github.com/holoplot/go-avahi v1.0.1/go.mod h1:qH5psEKb0DK+BRplMfc+RY4VMOlbf6mqfxgpMy6aP0M= -github.com/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q= -github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= -github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.52 h1:Bmlc/qsNNULOe6bpXcUTsuOajd0DzRHwup6D9k1An0c= -github.com/miekg/dns v1.1.52/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= -github.com/onsi/gomega v1.24.0 h1:+0glovB9Jd6z3VR+ScSwQqXVTIfJcGA9UBM8yzQxhqg= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/holoplot/go-avahi v0.0.0-20240210093433-b8dc0fc11e7e h1:XOKmPp6CgtFByseoBaL5Ew9b6NWSie+nr6pMFeO0Tvc= +github.com/holoplot/go-avahi v0.0.0-20240210093433-b8dc0fc11e7e/go.mod h1:WRfsMEGa+MvsfqqKmS7Ye1jrnfRW6kfF/CTP9UMZj0Q= +github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= +github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rickb777/date v1.20.1 h1:7MzSOc42Hbr5UXiQOihAAXoYDoeyzr0Hwvt+hCjBDV4= -github.com/rickb777/date v1.20.1/go.mod h1:9MqjVxT6a/AQTA4nxj9E6G3ksQiMESTn9/9kfE+CvwU= +github.com/rickb777/date v1.20.5 h1:Ybjz7J7ga9ui4VJizQpil0l330r6wkn6CicaoattIxQ= +github.com/rickb777/date v1.20.5/go.mod h1:6BPrm3/aQI0I8jvlD1fAlm/86k5eSeTQ2mR5FEmTnSw= github.com/rickb777/plural v1.4.1 h1:5MMLcbIaapLFmvDGRT5iPk8877hpTPt8Y9cdSKRw9sU= github.com/rickb777/plural v1.4.1/go.mod h1:kdmXUpmKBJTS0FtG/TFumd//VBWsNTD7zOw7x4umxNw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= +github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a h1:DxppxFKRqJ8WD6oJ3+ZXKDY0iMONQDl5UTg2aTyHh8k= gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a/go.mod h1:NREvu3a57BaK0R1+ztrEzHWiZAihohNLQ6trPxlIqZI= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integration_tests/devicediagnosis_test.go b/integration_tests/devicediagnosis_test.go deleted file mode 100644 index 7e8f804f..00000000 --- a/integration_tests/devicediagnosis_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package integrationtests - -import ( - "testing" - - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -const ( - dd_subscriptionRequestCall_recv_file_path = "./testdata/dd_subscriptionRequestCall_recv.json" - dd_subscriptionRequestCall_recv_result_file_path = "./testdata/ec_subscriptionRequestCall_recv_result.json" -) - -func TestDeviceDiagnosisSuite(t *testing.T) { - suite.Run(t, new(DeviceDiagnosisSuite)) -} - -type DeviceDiagnosisSuite struct { - suite.Suite - sut *spine.DeviceLocalImpl - - remoteSki string - - readHandler spine.SpineDataProcessing - writeHandler *WriteMessageHandler -} - -func (s *DeviceDiagnosisSuite) SetupSuite() { -} - -func (s *DeviceDiagnosisSuite) BeforeTest(suiteName, testName string) { - s.sut, s.remoteSki, s.readHandler, s.writeHandler = beforeTest(suiteName, testName, 1, model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeServer) - - // f.AddFunctionType(model.FunctionTypeDeviceDiagnosisHeartbeatData, true, false) - - initialCommunication(s.T(), s.readHandler, s.writeHandler) -} - -func (s *DeviceDiagnosisSuite) AfterTest(suiteName, testName string) { -} - -func (s *DeviceDiagnosisSuite) TestHeartbeatSubscription_RecvNotify() { - // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), dd_subscriptionRequestCall_recv_file_path)) - waitForAck(s.T(), msgCounter, s.writeHandler) - - // Assert - remoteDevice := s.sut.RemoteDeviceForSki(s.remoteSki) - assert.NotNil(s.T(), remoteDevice) - - ddFeature := remoteDevice.FeatureByEntityTypeAndRole( - remoteDevice.Entity(spine.NewAddressEntityType([]uint{1})), - model.FeatureTypeTypeDeviceDiagnosis, - model.RoleTypeClient) - assert.NotNil(s.T(), ddFeature) -} diff --git a/integration_tests/electricalconnection_test.go b/integration_tests/electricalconnection_test.go deleted file mode 100644 index ced18fe9..00000000 --- a/integration_tests/electricalconnection_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package integrationtests - -import ( - "testing" - - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -const ( - ec_permittedvaluesetlistdata_recv_notify_partial_file_path = "./testdata/ec_permittedvaluesetlistdata_recv_notify_partial.json" - ec_descriptionlistdata_recv_reply_file_path = "./testdata/ec_descriptionListData_recv_reply.json" - ec_parameterdescriptionlistdata_recv_reply_file_path = "./testdata/ec_parameterDescriptionListData_recv_reply.json" - ec_subscriptionRequestCall_recv_result_file_path = "./testdata/ec_subscriptionRequestCall_recv_result.json" -) - -func TestElectricalConnectionSuite(t *testing.T) { - suite.Run(t, new(ElectricalConnectionSuite)) -} - -type ElectricalConnectionSuite struct { - suite.Suite - sut *spine.DeviceLocalImpl - - remoteSki string - - readHandler spine.SpineDataProcessing - writeHandler *WriteMessageHandler -} - -func (s *ElectricalConnectionSuite) SetupSuite() { -} - -func (s *ElectricalConnectionSuite) BeforeTest(suiteName, testName string) { - s.sut, s.remoteSki, s.readHandler, s.writeHandler = beforeTest(suiteName, testName, 1, model.FeatureTypeTypeElectricalConnection, model.RoleTypeClient) - initialCommunication(s.T(), s.readHandler, s.writeHandler) -} - -func (s *ElectricalConnectionSuite) AfterTest(suiteName, testName string) { -} - -func (s *ElectricalConnectionSuite) TestDescriptionListData_RecvReply() { - // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), ec_descriptionlistdata_recv_reply_file_path)) - waitForAck(s.T(), msgCounter, s.writeHandler) - - // Assert - remoteDevice := s.sut.RemoteDeviceForSki(s.remoteSki) - assert.NotNil(s.T(), remoteDevice) - - ecFeature := remoteDevice.FeatureByEntityTypeAndRole( - remoteDevice.Entity(spine.NewAddressEntityType([]uint{1, 1})), - model.FeatureTypeTypeElectricalConnection, - model.RoleTypeServer) - assert.NotNil(s.T(), ecFeature) - - fdata := ecFeature.Data(model.FunctionTypeElectricalConnectionDescriptionListData) - if !assert.NotNil(s.T(), fdata) { - return - } - data := fdata.(*model.ElectricalConnectionDescriptionListDataType) - - if !assert.Equal(s.T(), 1, len(data.ElectricalConnectionDescriptionData)) { - return - } - - item1 := data.ElectricalConnectionDescriptionData[0] - assert.Equal(s.T(), 0, int(*item1.ElectricalConnectionId)) - assert.Equal(s.T(), string(model.ElectricalConnectionVoltageTypeTypeAc), string(*item1.PowerSupplyType)) - assert.Equal(s.T(), 1, int(*item1.AcConnectedPhases)) - assert.Equal(s.T(), string(model.EnergyDirectionTypeConsume), string(*item1.PositiveEnergyDirection)) -} - -func (s *ElectricalConnectionSuite) TestParameterDescriptionListData_RecvReply() { - // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), ec_parameterdescriptionlistdata_recv_reply_file_path)) - waitForAck(s.T(), msgCounter, s.writeHandler) - - // Assert - remoteDevice := s.sut.RemoteDeviceForSki(s.remoteSki) - assert.NotNil(s.T(), remoteDevice) - - ecFeature := remoteDevice.FeatureByEntityTypeAndRole( - remoteDevice.Entity(spine.NewAddressEntityType([]uint{1, 1})), - model.FeatureTypeTypeElectricalConnection, - model.RoleTypeServer) - assert.NotNil(s.T(), ecFeature) - - fdata := ecFeature.Data(model.FunctionTypeElectricalConnectionParameterDescriptionListData) - if !assert.NotNil(s.T(), fdata) { - return - } - data := fdata.(*model.ElectricalConnectionParameterDescriptionListDataType) - - if !assert.Equal(s.T(), 4, len(data.ElectricalConnectionParameterDescriptionData)) { - return - } - - item1 := data.ElectricalConnectionParameterDescriptionData[0] - assert.Equal(s.T(), 0, int(*item1.ElectricalConnectionId)) - assert.Equal(s.T(), 1, int(*item1.ParameterId)) - assert.Equal(s.T(), 1, int(*item1.MeasurementId)) - assert.Equal(s.T(), string(model.ElectricalConnectionVoltageTypeTypeAc), string(*item1.VoltageType)) - assert.Equal(s.T(), string(model.ElectricalConnectionPhaseNameTypeA), string(*item1.AcMeasuredPhases)) - assert.Equal(s.T(), string(model.ElectricalConnectionPhaseNameTypeNeutral), string(*item1.AcMeasuredInReferenceTo)) - assert.Equal(s.T(), string(model.ElectricalConnectionAcMeasurementTypeTypeReal), string(*item1.AcMeasurementType)) - assert.Equal(s.T(), string(model.ElectricalConnectionMeasurandVariantTypeRms), string(*item1.AcMeasurementVariant)) -} - -func (s *ElectricalConnectionSuite) TestPermittedValueSetListData_RecvNotifyPartial() { - // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), ec_permittedvaluesetlistdata_recv_notify_partial_file_path)) - waitForAck(s.T(), msgCounter, s.writeHandler) - - // Assert - remoteDevice := s.sut.RemoteDeviceForSki(s.remoteSki) - assert.NotNil(s.T(), remoteDevice) - - ecFeature := remoteDevice.FeatureByEntityTypeAndRole( - remoteDevice.Entity(spine.NewAddressEntityType([]uint{1, 1})), - model.FeatureTypeTypeElectricalConnection, - model.RoleTypeServer) - assert.NotNil(s.T(), ecFeature) - - fdata := ecFeature.Data(model.FunctionTypeElectricalConnectionPermittedValueSetListData) - if !assert.NotNil(s.T(), fdata) { - return - } - data := fdata.(*model.ElectricalConnectionPermittedValueSetListDataType) - - if !assert.Equal(s.T(), 3, len(data.ElectricalConnectionPermittedValueSetData)) { - return - } - - item1 := data.ElectricalConnectionPermittedValueSetData[0] - assert.Equal(s.T(), 0, int(*item1.ElectricalConnectionId)) - assert.Equal(s.T(), 1, int(*item1.ParameterId)) - assert.Equal(s.T(), 1, len(item1.PermittedValueSet)) - assert.Equal(s.T(), 1, len(item1.PermittedValueSet[0].Range)) - assert.NotNil(s.T(), item1.PermittedValueSet[0].Range) - assert.Equal(s.T(), 6, int(*item1.PermittedValueSet[0].Range[0].Min.Number)) - assert.Equal(s.T(), 0, int(*item1.PermittedValueSet[0].Range[0].Min.Scale)) - assert.Equal(s.T(), 16, int(*item1.PermittedValueSet[0].Range[0].Max.Number)) - assert.Equal(s.T(), 0, int(*item1.PermittedValueSet[0].Range[0].Max.Scale)) - assert.Nil(s.T(), item1.PermittedValueSet[0].Value) -} diff --git a/integration_tests/emobility_measurement_test.go b/integration_tests/emobility_measurement_test.go index f64d96f1..fbbb2111 100644 --- a/integration_tests/emobility_measurement_test.go +++ b/integration_tests/emobility_measurement_test.go @@ -2,56 +2,59 @@ package integrationtests import ( "testing" + "time" "github.com/enbility/eebus-go/features" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) +const ( + m_descriptionListData_recv_reply_file_path = "./testdata/m_descriptionListData_recv_reply.json" + m_measurementListData_recv_notify_file_path = "./testdata/m_measurementListData_recv_notify.json" + ec_parameterdescriptionlistdata_recv_reply_file_path = "./testdata/ec_parameterDescriptionListData_recv_reply.json" +) + func TestEmobilityMeasurementSuite(t *testing.T) { suite.Run(t, new(EmobilityMeasurementSuite)) } type EmobilityMeasurementSuite struct { suite.Suite - spine.SpineDataConnection - sut *spine.DeviceLocalImpl + sut api.DeviceLocalInterface + localEntity api.EntityLocalInterface measurement *features.Measurement electricalconnection *features.ElectricalConnection remoteSki string - readHandler spine.SpineDataProcessing + remoteDevice api.DeviceRemoteInterface writeHandler *WriteMessageHandler } -func (s *EmobilityMeasurementSuite) SetupSuite() { -} - func (s *EmobilityMeasurementSuite) BeforeTest(suiteName, testName string) { - s.sut = spine.NewDeviceLocalImpl("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode", - "TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart) - localEntity := spine.NewEntityLocalImpl(s.sut, model.EntityTypeTypeCEM, spine.NewAddressEntityType([]uint{1})) - s.sut.AddEntity(localEntity) + s.sut = spine.NewDeviceLocal("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode", + "TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + s.localEntity = spine.NewEntityLocal(s.sut, model.EntityTypeTypeCEM, spine.NewAddressEntityType([]uint{1})) + s.sut.AddEntity(s.localEntity) - f := spine.NewFeatureLocalImpl(1, localEntity, model.FeatureTypeTypeElectricalConnection, model.RoleTypeClient) - localEntity.AddFeature(f) - f = spine.NewFeatureLocalImpl(2, localEntity, model.FeatureTypeTypeMeasurement, model.RoleTypeClient) - localEntity.AddFeature(f) + f := spine.NewFeatureLocal(1, s.localEntity, model.FeatureTypeTypeElectricalConnection, model.RoleTypeClient) + s.localEntity.AddFeature(f) + f = spine.NewFeatureLocal(2, s.localEntity, model.FeatureTypeTypeMeasurement, model.RoleTypeClient) + s.localEntity.AddFeature(f) s.remoteSki = "TestRemoteSki" s.writeHandler = &WriteMessageHandler{} - s.readHandler = s.sut.AddRemoteDevice(s.remoteSki, s.writeHandler) - - initialCommunication(s.T(), s.readHandler, s.writeHandler) -} + _ = s.sut.SetupRemoteDevice(s.remoteSki, s.writeHandler) + s.remoteDevice = s.sut.RemoteDeviceForSki(s.remoteSki) -func (s *EmobilityMeasurementSuite) AfterTest(suiteName, testName string) { + initialCommunication(s.T(), s.remoteDevice, s.writeHandler) } func (s *EmobilityMeasurementSuite) TestGetValuesPerPhaseForScope() { @@ -59,20 +62,20 @@ func (s *EmobilityMeasurementSuite) TestGetValuesPerPhaseForScope() { assert.NotNil(s.T(), remoteEntity) var err error - s.measurement, err = features.NewMeasurement(model.RoleTypeClient, model.RoleTypeServer, s.sut, remoteEntity) + s.measurement, err = features.NewMeasurement(s.localEntity, remoteEntity) assert.Nil(s.T(), err) - s.electricalconnection, err = features.NewElectricalConnection(model.RoleTypeClient, model.RoleTypeServer, s.sut, remoteEntity) + s.electricalconnection, err = features.NewElectricalConnection(s.localEntity, remoteEntity) assert.Nil(s.T(), err) // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), ec_parameterdescriptionlistdata_recv_reply_file_path)) + msgCounter, _ := s.remoteDevice.HandleSpineMesssage(loadFileData(s.T(), ec_parameterdescriptionlistdata_recv_reply_file_path)) waitForAck(s.T(), msgCounter, s.writeHandler) - msgCounter, _ = s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), m_descriptionListData_recv_reply_file_path)) + msgCounter, _ = s.remoteDevice.HandleSpineMesssage(loadFileData(s.T(), m_descriptionListData_recv_reply_file_path)) waitForAck(s.T(), msgCounter, s.writeHandler) - msgCounter, _ = s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), m_measurementListData_recv_notify_file_path)) + msgCounter, _ = s.remoteDevice.HandleSpineMesssage(loadFileData(s.T(), m_measurementListData_recv_notify_file_path)) waitForAck(s.T(), msgCounter, s.writeHandler) measurement := model.MeasurementTypeTypeCurrent diff --git a/integration_tests/helper_test.go b/integration_tests/helper_test.go index 6c3dd2e1..566918d3 100644 --- a/integration_tests/helper_test.go +++ b/integration_tests/helper_test.go @@ -7,16 +7,14 @@ import ( "sync" "testing" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/stretchr/testify/assert" + shipapi "github.com/enbility/ship-go/api" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" ) const ( - wallbox_detaileddiscoverydata_recv_reply_file_path = "./testdata/wallbox_detaileddiscoverydata_recv_reply.json" - wallbox_detaileddiscoverydata_recv_notify_file_path = "./testdata/wallbox_detaileddiscoverydata_recv_notify.json" + wallbox_detaileddiscoverydata_recv_reply_file_path = ".//testdata/wallbox_detaileddiscoverydata_recv_reply.json" + wallbox_detaileddiscoverydata_recv_notify_file_path = ".//testdata/wallbox_detaileddiscoverydata_recv_notify.json" ) type WriteMessageHandler struct { @@ -25,9 +23,9 @@ type WriteMessageHandler struct { mux sync.Mutex } -var _ spine.SpineDataConnection = (*WriteMessageHandler)(nil) +var _ shipapi.ShipConnectionDataWriterInterface = (*WriteMessageHandler)(nil) -func (t *WriteMessageHandler) WriteSpineMessage(message []byte) { +func (t *WriteMessageHandler) WriteShipMessageWithPayload(message []byte) { t.mux.Lock() defer t.mux.Unlock() @@ -97,34 +95,18 @@ func (t *WriteMessageHandler) ResultWithReference(msgCounterReference *model.Msg return nil } -func beforeTest(suiteName, testName string, fId uint, ftype model.FeatureTypeType, frole model.RoleType) (*spine.DeviceLocalImpl, string, spine.SpineDataProcessing, *WriteMessageHandler) { - sut := spine.NewDeviceLocalImpl("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode", - "TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart) - localEntity := spine.NewEntityLocalImpl(sut, model.EntityTypeTypeCEM, spine.NewAddressEntityType([]uint{1})) - sut.AddEntity(localEntity) - f := spine.NewFeatureLocalImpl(fId, localEntity, ftype, frole) - localEntity.AddFeature(f) - - remoteSki := "TestRemoteSki" - - writeHandler := &WriteMessageHandler{} - remoteDevice := sut.AddRemoteDevice(remoteSki, writeHandler) - - return sut, remoteSki, remoteDevice, writeHandler -} - -func initialCommunication(t *testing.T, readHandler spine.SpineDataProcessing, writeHandler *WriteMessageHandler) { +func initialCommunication(t *testing.T, remoteDevice spineapi.DeviceRemoteInterface, writeHandler *WriteMessageHandler) { // Initial generic communication - _, _ = readHandler.HandleIncomingSpineMesssage(loadFileData(t, wallbox_detaileddiscoverydata_recv_reply_file_path)) + _, _ = remoteDevice.HandleSpineMesssage(loadFileData(t, wallbox_detaileddiscoverydata_recv_reply_file_path)) // Act - msgCounter, _ := readHandler.HandleIncomingSpineMesssage(loadFileData(t, wallbox_detaileddiscoverydata_recv_notify_file_path)) + msgCounter, _ := remoteDevice.HandleSpineMesssage(loadFileData(t, wallbox_detaileddiscoverydata_recv_notify_file_path)) waitForAck(t, msgCounter, writeHandler) } func loadFileData(t *testing.T, fileName string) []byte { - fileData, err := os.ReadFile(fileName) + fileData, err := os.ReadFile(fileName) // #nosec G304 if err != nil { t.Fatal(err) } @@ -132,45 +114,6 @@ func loadFileData(t *testing.T, fileName string) []byte { return fileData } -func checkSentData(t *testing.T, sendBytes []byte, msgSendFilePrefix string) { - msgSendExpectedBytes, err := os.ReadFile(msgSendFilePrefix + "_expected.json") - if err != nil { - t.Fatal(err) - } - - msgSendActualFileName := msgSendFilePrefix + "_actual.json" - equal := jsonDatagramEqual(t, msgSendExpectedBytes, sendBytes) - if !equal { - saveJsonToFile(t, sendBytes, msgSendActualFileName) - } - assert.Truef(t, equal, "Assert equal failed! Check '%s' ", msgSendActualFileName) -} - -func jsonDatagramEqual(t *testing.T, expectedJson, actualJson []byte) bool { - var actualDatagram model.Datagram - if err := json.Unmarshal(actualJson, &actualDatagram); err != nil { - t.Fatal(err) - } - var expectedDatagram model.Datagram - if err := json.Unmarshal(expectedJson, &expectedDatagram); err != nil { - t.Fatal(err) - } - - less := func(a, b model.FunctionPropertyType) bool { return string(*a.Function) < string(*b.Function) } - return cmp.Equal(expectedDatagram, actualDatagram, cmpopts.SortSlices(less)) -} - -func saveJsonToFile(t *testing.T, data json.RawMessage, fileName string) { - jsonIndent, err := json.MarshalIndent(data, "", " ") - if err != nil { - t.Fatal(err) - } - err = os.WriteFile(fileName, jsonIndent, os.ModePerm) - if err != nil { - t.Fatal(err) - } -} - func waitForAck(t *testing.T, msgCounterReference *model.MsgCounterType, writeHandler *WriteMessageHandler) { var datagram model.Datagram diff --git a/integration_tests/measurement_test.go b/integration_tests/measurement_test.go deleted file mode 100644 index 433e3a46..00000000 --- a/integration_tests/measurement_test.go +++ /dev/null @@ -1,163 +0,0 @@ -package integrationtests - -import ( - "testing" - "time" - - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -const ( - m_subscriptionRequestCall_recv_result_file_path = "./testdata/m_subscriptionRequestCall_recv_result.json" - m_descriptionListData_recv_reply_file_path = "./testdata/m_descriptionListData_recv_reply.json" - m_measurementListData_recv_notify_file_path = "./testdata/m_measurementListData_recv_notify.json" -) - -func TestMeasurementSuite(t *testing.T) { - suite.Run(t, new(MeasurementSuite)) -} - -type MeasurementSuite struct { - suite.Suite - sut *spine.DeviceLocalImpl - - remoteSki string - - readHandler spine.SpineDataProcessing - writeHandler *WriteMessageHandler -} - -func (s *MeasurementSuite) SetupSuite() { -} - -func (s *MeasurementSuite) BeforeTest(suiteName, testName string) { - s.sut, s.remoteSki, s.readHandler, s.writeHandler = beforeTest(suiteName, testName, 2, model.FeatureTypeTypeMeasurement, model.RoleTypeClient) - initialCommunication(s.T(), s.readHandler, s.writeHandler) -} - -func (s *MeasurementSuite) AfterTest(suiteName, testName string) { -} - -func (s *MeasurementSuite) TestDescriptionList_Recv() { - // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), m_descriptionListData_recv_reply_file_path)) - waitForAck(s.T(), msgCounter, s.writeHandler) - - // Assert - remoteDevice := s.sut.RemoteDeviceForSki(s.remoteSki) - assert.NotNil(s.T(), remoteDevice) - - mFeature := remoteDevice.FeatureByEntityTypeAndRole( - remoteDevice.Entity(spine.NewAddressEntityType([]uint{1, 1})), - model.FeatureTypeTypeMeasurement, - model.RoleTypeServer) - assert.NotNil(s.T(), mFeature) - - fdata := mFeature.Data(model.FunctionTypeMeasurementDescriptionListData) - if !assert.NotNil(s.T(), fdata) { - return - } - data := fdata.(*model.MeasurementDescriptionListDataType) - - if !assert.Equal(s.T(), 3, len(data.MeasurementDescriptionData)) { - return - } - - item1 := data.MeasurementDescriptionData[0] - assert.Equal(s.T(), 1, int(*item1.MeasurementId)) - assert.Equal(s.T(), string(model.MeasurementTypeTypeCurrent), string(*item1.MeasurementType)) - assert.Equal(s.T(), string(model.CommodityTypeTypeElectricity), string(*item1.CommodityType)) - assert.Equal(s.T(), string(model.UnitOfMeasurementTypeA), string(*item1.Unit)) - assert.Equal(s.T(), string(model.ScopeTypeTypeACCurrent), string(*item1.ScopeType)) -} - -func (s *MeasurementSuite) TestMeasurementList_Recv() { - // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), m_measurementListData_recv_notify_file_path)) - waitForAck(s.T(), msgCounter, s.writeHandler) - - // Assert - remoteDevice := s.sut.RemoteDeviceForSki(s.remoteSki) - assert.NotNil(s.T(), remoteDevice) - - mFeature := remoteDevice.FeatureByEntityTypeAndRole( - remoteDevice.Entity(spine.NewAddressEntityType([]uint{1, 1})), - model.FeatureTypeTypeMeasurement, - model.RoleTypeServer) - assert.NotNil(s.T(), mFeature) - - fdata := mFeature.Data(model.FunctionTypeMeasurementListData) - if !assert.NotNil(s.T(), fdata) { - return - } - data := fdata.(*model.MeasurementListDataType) - - if !assert.Equal(s.T(), 3, len(data.MeasurementData)) { - return - } - - item1 := data.MeasurementData[0] - assert.Equal(s.T(), 1, int(*item1.MeasurementId)) - assert.Equal(s.T(), string(model.MeasurementValueTypeTypeValue), string(*item1.ValueType)) - assert.Equal(s.T(), 5.0, item1.Value.GetValue()) - timestamp, err := item1.Timestamp.GetDateTimeType().GetTime() - assert.Nil(s.T(), err) - compareTimestamp := time.Date( - 2022, 11, 19, 15, 21, 50, 3000000, time.UTC) - assert.Equal(s.T(), compareTimestamp, timestamp) - assert.Equal(s.T(), string(model.MeasurementValueSourceTypeMeasuredValue), string(*item1.ValueSource)) -} - -func (s *MeasurementSuite) TestMeasurementByScope_Recv() { - // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), m_descriptionListData_recv_reply_file_path)) - waitForAck(s.T(), msgCounter, s.writeHandler) - - // Act - msgCounter, _ = s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), m_measurementListData_recv_notify_file_path)) - waitForAck(s.T(), msgCounter, s.writeHandler) - - // Assert - remoteDevice := s.sut.RemoteDeviceForSki(s.remoteSki) - assert.NotNil(s.T(), remoteDevice) - - mFeature := remoteDevice.FeatureByEntityTypeAndRole( - remoteDevice.Entity(spine.NewAddressEntityType([]uint{1, 1})), - model.FeatureTypeTypeMeasurement, - model.RoleTypeServer) - assert.NotNil(s.T(), mFeature) - - fdata := mFeature.Data(model.FunctionTypeMeasurementDescriptionListData) - if !assert.NotNil(s.T(), fdata) { - return - } - descData := fdata.(*model.MeasurementDescriptionListDataType) - - if !assert.Equal(s.T(), 3, len(descData.MeasurementDescriptionData)) { - return - } - - fdata = mFeature.Data(model.FunctionTypeMeasurementListData) - if !assert.NotNil(s.T(), fdata) { - return - } - mData := fdata.(*model.MeasurementListDataType) - - if !assert.Equal(s.T(), 3, len(mData.MeasurementData)) { - return - } - - item1 := mData.MeasurementData[0] - assert.Equal(s.T(), 1, int(*item1.MeasurementId)) - assert.Equal(s.T(), string(model.MeasurementValueTypeTypeValue), string(*item1.ValueType)) - assert.Equal(s.T(), 5.0, item1.Value.GetValue()) - timestamp, err := item1.Timestamp.GetDateTimeType().GetTime() - assert.Nil(s.T(), err) - compareTimestamp := time.Date( - 2022, 11, 19, 15, 21, 50, 3000000, time.UTC) - assert.Equal(s.T(), compareTimestamp, timestamp) - assert.Equal(s.T(), string(model.MeasurementValueSourceTypeMeasuredValue), string(*item1.ValueSource)) -} diff --git a/integration_tests/nodemanagement_test.go b/integration_tests/nodemanagement_test.go deleted file mode 100644 index 00b1009a..00000000 --- a/integration_tests/nodemanagement_test.go +++ /dev/null @@ -1,198 +0,0 @@ -package integrationtests - -import ( - "testing" - - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -const ( - nm_detaileddiscoverydata_send_read_file_prefix = "./testdata/nm_detaileddiscoverydata_send_read" - nm_detaileddiscoverydata_recv_read_file_path = "./testdata/nm_detaileddiscoverydata_recv_read.json" - nm_detaileddiscoverydata_send_reply_file_prefix = "./testdata/nm_detaileddiscoverydata_send_reply" - nm_detaileddiscoverydata_recv_read_ack_file_path = "./testdata/nm_detaileddiscoverydata_recv_read_ack.json" - nm_detaileddiscoverydata_send_result_file_prefix = "./testdata/nm_detaileddiscoverydata_send_result" - nm_subscriptionRequestCall_recv_call_file_path = "./testdata/nm_subscriptionRequestCall_recv_call.json" - nm_subscriptionRequestCall_send_result_file_prefix = "./testdata/nm_subscriptionRequestCall_send_result" - nm_destinationListData_recv_read_file_path = "./testdata/nm_destinationListData_recv_read.json" - nm_destinationListData_send_reply_file_prefix = "./testdata/nm_destinationListData_send_reply" -) - -func TestNodeManagementSuite(t *testing.T) { - suite.Run(t, new(NodeManagementSuite)) -} - -type NodeManagementSuite struct { - suite.Suite - sut *spine.DeviceLocalImpl - - remoteSki string - - readHandler spine.SpineDataProcessing - writeHandler *WriteMessageHandler -} - -func (s *NodeManagementSuite) SetupSuite() { -} - -func (s *NodeManagementSuite) BeforeTest(suiteName, testName string) { - s.sut = spine.NewDeviceLocalImpl("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode", - "TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart) - s.remoteSki = "TestRemoteSki" - - s.writeHandler = &WriteMessageHandler{} - - s.readHandler = s.sut.AddRemoteDevice(s.remoteSki, s.writeHandler) -} - -func (s *NodeManagementSuite) AfterTest(suiteName, testName string) { -} - -func (s *NodeManagementSuite) TestDetailedDiscovery_SendRead() { - // Act (see BeforeTest) - - // Assert - sendBytes := s.writeHandler.LastMessage() - checkSentData(s.T(), sendBytes, nm_detaileddiscoverydata_send_read_file_prefix) -} - -func (s *NodeManagementSuite) TestDetailedDiscovery_SendReply() { - // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), nm_detaileddiscoverydata_recv_read_file_path)) - - // Assert - sendBytes := s.writeHandler.MessageWithReference(msgCounter) - checkSentData(s.T(), sendBytes, nm_detaileddiscoverydata_send_reply_file_prefix) -} - -func (s *NodeManagementSuite) TestDetailedDiscovery_RecvReply() { - // Act - _, _ = s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), wallbox_detaileddiscoverydata_recv_reply_file_path)) - - // Assert - remoteDevice := s.sut.RemoteDeviceForSki(s.remoteSki) - assert.NotNil(s.T(), remoteDevice) - assert.Equal(s.T(), model.DeviceTypeTypeChargingStation, *remoteDevice.DeviceType()) - assert.Equal(s.T(), model.NetworkManagementFeatureSetTypeSmart, *remoteDevice.FeatureSet()) - - rEntities := remoteDevice.Entities() - assert.Equal(s.T(), 2, len(rEntities)) - di := rEntities[spine.DeviceInformationEntityId] - assert.NotNil(s.T(), di) - assert.Equal(s.T(), model.EntityTypeTypeDeviceInformation, di.EntityType()) - - diFeatures := di.Features() - assert.Equal(s.T(), 2, len(diFeatures)) - - nm := diFeatures[0] - assert.Equal(s.T(), spine.NodeManagementFeatureId, uint(*nm.Address().Feature)) - assert.Equal(s.T(), model.FeatureTypeTypeNodeManagement, nm.Type()) - assert.Equal(s.T(), model.RoleTypeSpecial, nm.Role()) - assert.Equal(s.T(), 8, len(nm.Operations())) - - dc := diFeatures[1] - assert.Equal(s.T(), 1, int(*dc.Address().Feature)) - assert.Equal(s.T(), model.FeatureTypeTypeDeviceClassification, dc.Type()) - assert.Equal(s.T(), model.RoleTypeServer, dc.Role()) - assert.Equal(s.T(), 1, len(dc.Operations())) - - evse := rEntities[1] - assert.NotNil(s.T(), evse) - assert.Equal(s.T(), model.EntityTypeTypeEVSE, evse.EntityType()) - - evseFeatures := evse.Features() - assert.Equal(s.T(), 3, len(evseFeatures)) - - evsedc := evseFeatures[0] - assert.Equal(s.T(), 1, int(*evsedc.Address().Feature)) - assert.Equal(s.T(), model.FeatureTypeTypeDeviceClassification, evsedc.Type()) - assert.Equal(s.T(), model.RoleTypeClient, evsedc.Role()) - assert.Equal(s.T(), 0, len(evsedc.Operations())) - - evsedd := evseFeatures[1] - assert.Equal(s.T(), 2, int(*evsedd.Address().Feature)) - assert.Equal(s.T(), model.FeatureTypeTypeDeviceDiagnosis, evsedd.Type()) - assert.Equal(s.T(), model.RoleTypeClient, evsedd.Role()) - assert.Equal(s.T(), 0, len(evsedd.Operations())) - - evseec := evseFeatures[2] - assert.Equal(s.T(), 3, int(*evseec.Address().Feature)) - assert.Equal(s.T(), model.FeatureTypeTypeElectricalConnection, evseec.Type()) - assert.Equal(s.T(), model.RoleTypeServer, evseec.Role()) - assert.Equal(s.T(), 0, len(evseec.Operations())) - -} - -func (s *NodeManagementSuite) TestDetailedDiscovery_RecvNotifyAdded() { - _, _ = s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), wallbox_detaileddiscoverydata_recv_reply_file_path)) - - // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), wallbox_detaileddiscoverydata_recv_notify_file_path)) - waitForAck(s.T(), msgCounter, s.writeHandler) - - // Assert - remoteDevice := s.sut.RemoteDeviceForSki(s.remoteSki) - assert.NotNil(s.T(), remoteDevice) - assert.Equal(s.T(), model.DeviceTypeTypeChargingStation, *remoteDevice.DeviceType()) - assert.Equal(s.T(), model.NetworkManagementFeatureSetTypeSmart, *remoteDevice.FeatureSet()) - - rEntities := remoteDevice.Entities() - if assert.Equal(s.T(), 3, len(rEntities)) { - { - di := rEntities[spine.DeviceInformationEntityId] - assert.NotNil(s.T(), di) - assert.Equal(s.T(), model.EntityTypeTypeDeviceInformation, di.EntityType()) - assert.Equal(s.T(), 2, len(di.Features())) - } - { - evse := rEntities[1] - assert.NotNil(s.T(), evse) - assert.Equal(s.T(), model.EntityTypeTypeEVSE, evse.EntityType()) - assert.Equal(s.T(), 3, len(evse.Features())) - } - { - ev := rEntities[2] - assert.NotNil(s.T(), ev) - assert.Equal(s.T(), model.EntityTypeTypeEV, ev.EntityType()) - assert.Equal(s.T(), 10, len(ev.Features())) - } - } -} - -func (s *NodeManagementSuite) TestDetailedDiscovery_SendReplyWithAcknowledge() { - // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), nm_detaileddiscoverydata_recv_read_ack_file_path)) - - // Assert - sentReply := s.writeHandler.MessageWithReference(msgCounter) - checkSentData(s.T(), sentReply, nm_detaileddiscoverydata_send_reply_file_prefix) - sentResult := s.writeHandler.ResultWithReference(msgCounter) - checkSentData(s.T(), sentResult, nm_detaileddiscoverydata_send_result_file_prefix) -} - -func (s *NodeManagementSuite) TestSubscriptionRequestCall_BeforeDetailedDiscovery() { - // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), nm_subscriptionRequestCall_recv_call_file_path)) - - // Assert - sentResult := s.writeHandler.ResultWithReference(msgCounter) - checkSentData(s.T(), sentResult, nm_subscriptionRequestCall_send_result_file_prefix) - - remoteDevice := s.sut.RemoteDeviceForSki(s.remoteSki) - subscriptionsForDevice := s.sut.SubscriptionManager().Subscriptions(remoteDevice) - assert.Equal(s.T(), 1, len(subscriptionsForDevice)) - subscriptionsOnFeature := s.sut.SubscriptionManager().SubscriptionsOnFeature(*spine.NodeManagementAddress(s.sut.Address())) - assert.Equal(s.T(), 1, len(subscriptionsOnFeature)) -} - -func (s *NodeManagementSuite) TestDestinationList_SendReply() { - // Act - msgCounter, _ := s.readHandler.HandleIncomingSpineMesssage(loadFileData(s.T(), nm_destinationListData_recv_read_file_path)) - - // Assert - sendBytes := s.writeHandler.MessageWithReference(msgCounter) - checkSentData(s.T(), sendBytes, nm_destinationListData_send_reply_file_prefix) -} diff --git a/integration_tests/testdata/dd_subscriptionRequestCall_recv.json b/integration_tests/testdata/dd_subscriptionRequestCall_recv.json deleted file mode 100644 index 599641ab..00000000 --- a/integration_tests/testdata/dd_subscriptionRequestCall_recv.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.1.1", - "addressSource": { - "device": "Wallbox", - "entity": [1], - "feature": 2 - }, - "addressDestination": { - "device": "HEMS", - "entity": [0], - "feature": 0 - }, - "msgCounter": 1, - "cmdClassifier": "call", - "ackRequest": true - }, - "payload": { - "cmd": [ - { - "nodeManagementSubscriptionRequestCall": { - "subscriptionRequest": { - "clientAddress": { - "device": "Wallbox", - "entity": [1], - "feature": 2 - }, - "serverAddress": { - "device": "HEMS", - "entity": [1], - "feature": 1 - }, - "serverFeatureType": "DeviceDiagnosis" - } - } - } - ] - } - } -} diff --git a/integration_tests/testdata/ec_descriptionListData_recv_reply.json b/integration_tests/testdata/ec_descriptionListData_recv_reply.json deleted file mode 100644 index 12e06b04..00000000 --- a/integration_tests/testdata/ec_descriptionListData_recv_reply.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.1.1", - "addressSource": { - "device": "Wallbox", - "entity": [1,1], - "feature": 7 - }, - "addressDestination": { - "device": "HEMS", - "entity": [1], - "feature": 1 - }, - "msgCounter": 10, - "msgCounterReference": 10, - "cmdClassifier": "reply", - "ackRequest": true - }, - "payload": { - "cmd": [ - { - "electricalConnectionDescriptionListData": { - "electricalConnectionDescriptionData": [ - { - "electricalConnectionId": 0, - "powerSupplyType": "ac", - "acConnectedPhases": 1, - "positiveEnergyDirection": "consume" - } - ] - } - } - ] - } - } -} diff --git a/integration_tests/testdata/ec_permittedvaluesetlistdata_recv_notify_partial.json b/integration_tests/testdata/ec_permittedvaluesetlistdata_recv_notify_partial.json deleted file mode 100644 index e7fe307a..00000000 --- a/integration_tests/testdata/ec_permittedvaluesetlistdata_recv_notify_partial.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.1.1", - "addressSource": { - "device": "Wallbox", - "entity": [1,1], - "feature": 7 - }, - "addressDestination": { - "device": "HEMS", - "entity": [1], - "feature": 1 - }, - "msgCounter": 10, - "cmdClassifier": "notify", - "ackRequest":true - }, - "payload": { - "cmd": [ - { - "function":"electricalConnectionPermittedValueSetListData", - "filter":[ - { - "cmdControl":{ - "partial":{} - } - } - ], - "electricalConnectionPermittedValueSetListData": { - "electricalConnectionPermittedValueSetData": [ - { - "electricalConnectionId": 0, - "parameterId": 1, - "permittedValueSet": [ - { - "range": [ - { - "min": { - "number": 6, - "scale": 0 - }, - "max": { - "number": 16, - "scale": 0 - } - } - ] - } - ] - }, - { - "electricalConnectionId": 0, - "parameterId": 2, - "permittedValueSet": [ - { - "range": [ - { - "min": { - "number": 6, - "scale": 0 - }, - "max": { - "number": 16, - "scale": 0 - } - } - ] - } - ] - }, - { - "electricalConnectionId": 0, - "parameterId": 3, - "permittedValueSet": [ - { - "range": [ - { - "min": { - "number": 6, - "scale": 0 - }, - "max": { - "number": 16, - "scale": 0 - } - } - ] - } - ] - } - ] - } - } - ] - } - } -} diff --git a/integration_tests/testdata/ec_subscriptionRequestCall_recv_result.json b/integration_tests/testdata/ec_subscriptionRequestCall_recv_result.json deleted file mode 100644 index 8186803c..00000000 --- a/integration_tests/testdata/ec_subscriptionRequestCall_recv_result.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.1.1", - "addressSource": { - "device": "Wallbox", - "entity": [ - 0 - ], - "feature": 0 - }, - "addressDestination": { - "device": "HEMS", - "entity": [ - 0 - ], - "feature": 0 - }, - "msgCounter": 3, - "msgCounterReference": 2, - "cmdClassifier": "result" - }, - "payload": { - "cmd": [ - { - "resultData": { - "errorNumber": 0 - } - } - ] - } - } -} diff --git a/integration_tests/testdata/nm_destinationListData_recv_read.json b/integration_tests/testdata/nm_destinationListData_recv_read.json deleted file mode 100644 index 9c4c1f65..00000000 --- a/integration_tests/testdata/nm_destinationListData_recv_read.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.2.0", - "addressSource": { - "device": "HEMS", - "entity": [ - 0 - ], - "feature": 0 - }, - "addressDestination": { - "entity": [ - 0 - ], - "feature": 0 - }, - "msgCounter": 1, - "cmdClassifier": "read" - }, - "payload": { - "cmd": [ - { - "nodeManagementDestinationListData": {} - } - ] - } - } -} \ No newline at end of file diff --git a/integration_tests/testdata/nm_destinationListData_send_reply_expected.json b/integration_tests/testdata/nm_destinationListData_send_reply_expected.json deleted file mode 100644 index 844ed77a..00000000 --- a/integration_tests/testdata/nm_destinationListData_send_reply_expected.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.1.1", - "addressSource": { - "device": "TestDeviceAddress", - "entity": [ - 0 - ], - "feature": 0 - }, - "addressDestination": { - "device": "HEMS", - "entity": [ - 0 - ], - "feature": 0 - }, - "msgCounter": 2, - "msgCounterReference": 1, - "cmdClassifier": "reply" - }, - "payload": { - "cmd": [ - { - "nodeManagementDestinationListData": { - "nodeManagementDestinationData": [ - { - "deviceDescription": { - "deviceAddress": { - "device": "TestDeviceAddress" - }, - "deviceType": "EnergyManagementSystem", - "networkFeatureSet": "smart" - } - } - ] - } - } - ] - } - } -} \ No newline at end of file diff --git a/integration_tests/testdata/nm_detaileddiscoverydata_recv_read.json b/integration_tests/testdata/nm_detaileddiscoverydata_recv_read.json deleted file mode 100644 index 536b5d3a..00000000 --- a/integration_tests/testdata/nm_detaileddiscoverydata_recv_read.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.2.0", - "addressSource": { - "device": "HEMS", - "entity": [ - 0 - ], - "feature": 0 - }, - "addressDestination": { - "entity": [ - 0 - ], - "feature": 0 - }, - "msgCounter": 1, - "cmdClassifier": "read" - }, - "payload": { - "cmd": [ - { - "nodeManagementDetailedDiscoveryData": {} - } - ] - } - } -} \ No newline at end of file diff --git a/integration_tests/testdata/nm_detaileddiscoverydata_recv_read_ack.json b/integration_tests/testdata/nm_detaileddiscoverydata_recv_read_ack.json deleted file mode 100644 index fc169543..00000000 --- a/integration_tests/testdata/nm_detaileddiscoverydata_recv_read_ack.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.2.0", - "addressSource": { - "device": "HEMS", - "entity": [ - 0 - ], - "feature": 0 - }, - "addressDestination": { - "entity": [ - 0 - ], - "feature": 0 - }, - "msgCounter": 1, - "cmdClassifier": "read", - "ackRequest":true - }, - "payload": { - "cmd": [ - { - "nodeManagementDetailedDiscoveryData": {} - } - ] - } - } -} \ No newline at end of file diff --git a/integration_tests/testdata/nm_detaileddiscoverydata_send_read_expected.json b/integration_tests/testdata/nm_detaileddiscoverydata_send_read_expected.json deleted file mode 100644 index 3f6ead35..00000000 --- a/integration_tests/testdata/nm_detaileddiscoverydata_send_read_expected.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.1.1", - "addressSource": { - "device": "TestDeviceAddress", - "entity": [ - 0 - ], - "feature": 0 - }, - "addressDestination": { - "entity": [ - 0 - ], - "feature": 0 - }, - "msgCounter": 1, - "cmdClassifier": "read" - }, - "payload": { - "cmd": [ - { - "nodeManagementDetailedDiscoveryData": {} - } - ] - } - } -} \ No newline at end of file diff --git a/integration_tests/testdata/nm_detaileddiscoverydata_send_reply_expected.json b/integration_tests/testdata/nm_detaileddiscoverydata_send_reply_expected.json deleted file mode 100644 index e9cf487d..00000000 --- a/integration_tests/testdata/nm_detaileddiscoverydata_send_reply_expected.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.1.1", - "addressSource": { - "device": "TestDeviceAddress", - "entity": [ - 0 - ], - "feature": 0 - }, - "addressDestination": { - "device": "HEMS", - "entity": [ - 0 - ], - "feature": 0 - }, - "msgCounter": 2, - "msgCounterReference": 1, - "cmdClassifier": "reply" - }, - "payload": { - "cmd": [ - { - "nodeManagementDetailedDiscoveryData": { - "specificationVersionList": { - "specificationVersion": [ - "1.1.1" - ] - }, - "deviceInformation": { - "description": { - "deviceAddress": { - "device": "TestDeviceAddress" - }, - "deviceType": "EnergyManagementSystem", - "networkFeatureSet": "smart" - } - }, - "entityInformation": [ - { - "description": { - "entityAddress": { - "device": "TestDeviceAddress", - "entity": [ - 0 - ] - }, - "entityType": "DeviceInformation" - } - } - ], - "featureInformation": [ - { - "description": { - "featureAddress": { - "device": "TestDeviceAddress", - "entity": [ - 0 - ], - "feature": 0 - }, - "featureType": "NodeManagement", - "role": "special", - "supportedFunction": [ - { - "function": "nodeManagementSubscriptionDeleteCall", - "possibleOperations": {} - }, - { - "function": "nodeManagementBindingData", - "possibleOperations": { - "read": {} - } - }, - { - "function": "nodeManagementBindingRequestCall", - "possibleOperations": {} - }, - { - "function": "nodeManagementBindingDeleteCall", - "possibleOperations": {} - }, - { - "function": "nodeManagementDestinationListData", - "possibleOperations": { - "read": {} - } - }, - { - "function": "nodeManagementDetailedDiscoveryData", - "possibleOperations": { - "read": {} - } - }, - { - "function": "nodeManagementUseCaseData", - "possibleOperations": { - "read": {} - } - }, - { - "function": "nodeManagementSubscriptionData", - "possibleOperations": { - "read": {} - } - }, - { - "function": "nodeManagementSubscriptionRequestCall", - "possibleOperations": {} - } - ] - } - }, - { - "description": { - "featureAddress": { - "device": "TestDeviceAddress", - "entity": [ - 0 - ], - "feature": 1 - }, - "featureType": "DeviceClassification", - "role": "server", - "supportedFunction": [ - { - "function": "deviceClassificationManufacturerData", - "possibleOperations": { - "read": {} - } - } - ] - } - } - ] - } - } - ] - } - } -} \ No newline at end of file diff --git a/integration_tests/testdata/nm_detaileddiscoverydata_send_result_expected.json b/integration_tests/testdata/nm_detaileddiscoverydata_send_result_expected.json deleted file mode 100644 index ef0b16d0..00000000 --- a/integration_tests/testdata/nm_detaileddiscoverydata_send_result_expected.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.1.1", - "addressSource": { - "device": "TestDeviceAddress", - "entity": [ - 0 - ], - "feature": 0 - }, - "addressDestination": { - "device": "HEMS", - "entity": [ - 0 - ], - "feature": 0 - }, - "msgCounter": 3, - "msgCounterReference": 1, - "cmdClassifier": "result" - }, - "payload": { - "cmd": [ - { - "resultData": { - "errorNumber": 0 - } - } - ] - } - } -} \ No newline at end of file diff --git a/integration_tests/testdata/nm_subscriptionRequestCall_recv_call.json b/integration_tests/testdata/nm_subscriptionRequestCall_recv_call.json deleted file mode 100644 index 3061f941..00000000 --- a/integration_tests/testdata/nm_subscriptionRequestCall_recv_call.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.2.0", - "addressSource": { - "device": "HEMS", - "entity": [ - 0 - ], - "feature": 0 - }, - "addressDestination": { - "entity": [ - 0 - ], - "feature": 0 - }, - "msgCounter": 1, - "cmdClassifier": "call", - "ackRequest": true - }, - "payload": { - "cmd": [ - { - "nodeManagementSubscriptionRequestCall": { - "subscriptionRequest": { - "clientAddress": { - "device": "HEMS", - "entity": [ - 0 - ], - "feature": 0 - }, - "serverAddress": { - "device": "TestDeviceAddress", - "entity": [ - 0 - ], - "feature": 0 - }, - "serverFeatureType": "NodeManagement" - } - } - } - ] - } - } -} \ No newline at end of file diff --git a/integration_tests/testdata/nm_subscriptionRequestCall_send_result_expected.json b/integration_tests/testdata/nm_subscriptionRequestCall_send_result_expected.json deleted file mode 100644 index ac1290bb..00000000 --- a/integration_tests/testdata/nm_subscriptionRequestCall_send_result_expected.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "datagram": { - "header": { - "specificationVersion": "1.1.1", - "addressSource": { - "device": "TestDeviceAddress", - "entity": [ - 0 - ], - "feature": 0 - }, - "addressDestination": { - "device": "HEMS", - "entity": [ - 0 - ], - "feature": 0 - }, - "msgCounter": 2, - "msgCounterReference": 1, - "cmdClassifier": "result" - }, - "payload": { - "cmd": [ - { - "resultData": { - "errorNumber": 0 - } - } - ] - } - } -} \ No newline at end of file diff --git a/logging/log.go b/logging/log.go deleted file mode 100644 index e65ab284..00000000 --- a/logging/log.go +++ /dev/null @@ -1,37 +0,0 @@ -package logging - -// Logging needs to be implemented, if the internal logs should be printed -type Logging interface { - Trace(args ...interface{}) - Tracef(format string, args ...interface{}) - Debug(args ...interface{}) - Debugf(format string, args ...interface{}) - Info(args ...interface{}) - Infof(format string, args ...interface{}) - Error(args ...interface{}) - Errorf(format string, args ...interface{}) -} - -// NoLogging is an empty implementation of Logging which does nothing. -type NoLogging struct{} - -func (l *NoLogging) Trace(args ...interface{}) {} -func (l *NoLogging) Tracef(format string, args ...interface{}) {} -func (l *NoLogging) Debug(args ...interface{}) {} -func (l *NoLogging) Debugf(format string, args ...interface{}) {} -func (l *NoLogging) Info(args ...interface{}) {} -func (l *NoLogging) Infof(format string, args ...interface{}) {} -func (l *NoLogging) Error(args ...interface{}) {} -func (l *NoLogging) Errorf(format string, args ...interface{}) {} - -var Log Logging = &NoLogging{} - -// Sets a custom logging implementation -// By default NoLogging is used, so no logs are printed -// This is used by service.SetLogging() -func SetLogging(logger Logging) { - if logger == nil { - return - } - Log = logger -} diff --git a/mocks/FeatureInterface.go b/mocks/FeatureInterface.go new file mode 100644 index 00000000..6626b099 --- /dev/null +++ b/mocks/FeatureInterface.go @@ -0,0 +1,322 @@ +// Code generated by mockery v2.42.1. DO NOT EDIT. + +package mocks + +import ( + api "github.com/enbility/spine-go/api" + + mock "github.com/stretchr/testify/mock" + + model "github.com/enbility/spine-go/model" +) + +// FeatureInterface is an autogenerated mock type for the FeatureInterface type +type FeatureInterface struct { + mock.Mock +} + +type FeatureInterface_Expecter struct { + mock *mock.Mock +} + +func (_m *FeatureInterface) EXPECT() *FeatureInterface_Expecter { + return &FeatureInterface_Expecter{mock: &_m.Mock} +} + +// AddResponseCallback provides a mock function with given fields: msgCounterReference, function +func (_m *FeatureInterface) AddResponseCallback(msgCounterReference model.MsgCounterType, function func(api.ResponseMessage)) error { + ret := _m.Called(msgCounterReference, function) + + if len(ret) == 0 { + panic("no return value specified for AddResponseCallback") + } + + var r0 error + if rf, ok := ret.Get(0).(func(model.MsgCounterType, func(api.ResponseMessage)) error); ok { + r0 = rf(msgCounterReference, function) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// FeatureInterface_AddResponseCallback_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddResponseCallback' +type FeatureInterface_AddResponseCallback_Call struct { + *mock.Call +} + +// AddResponseCallback is a helper method to define mock.On call +// - msgCounterReference model.MsgCounterType +// - function func(api.ResponseMessage) +func (_e *FeatureInterface_Expecter) AddResponseCallback(msgCounterReference interface{}, function interface{}) *FeatureInterface_AddResponseCallback_Call { + return &FeatureInterface_AddResponseCallback_Call{Call: _e.mock.On("AddResponseCallback", msgCounterReference, function)} +} + +func (_c *FeatureInterface_AddResponseCallback_Call) Run(run func(msgCounterReference model.MsgCounterType, function func(api.ResponseMessage))) *FeatureInterface_AddResponseCallback_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.MsgCounterType), args[1].(func(api.ResponseMessage))) + }) + return _c +} + +func (_c *FeatureInterface_AddResponseCallback_Call) Return(_a0 error) *FeatureInterface_AddResponseCallback_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureInterface_AddResponseCallback_Call) RunAndReturn(run func(model.MsgCounterType, func(api.ResponseMessage)) error) *FeatureInterface_AddResponseCallback_Call { + _c.Call.Return(run) + return _c +} + +// AddResultCallback provides a mock function with given fields: function +func (_m *FeatureInterface) AddResultCallback(function func(api.ResponseMessage)) { + _m.Called(function) +} + +// FeatureInterface_AddResultCallback_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddResultCallback' +type FeatureInterface_AddResultCallback_Call struct { + *mock.Call +} + +// AddResultCallback is a helper method to define mock.On call +// - function func(api.ResponseMessage) +func (_e *FeatureInterface_Expecter) AddResultCallback(function interface{}) *FeatureInterface_AddResultCallback_Call { + return &FeatureInterface_AddResultCallback_Call{Call: _e.mock.On("AddResultCallback", function)} +} + +func (_c *FeatureInterface_AddResultCallback_Call) Run(run func(function func(api.ResponseMessage))) *FeatureInterface_AddResultCallback_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(func(api.ResponseMessage))) + }) + return _c +} + +func (_c *FeatureInterface_AddResultCallback_Call) Return() *FeatureInterface_AddResultCallback_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureInterface_AddResultCallback_Call) RunAndReturn(run func(func(api.ResponseMessage))) *FeatureInterface_AddResultCallback_Call { + _c.Call.Return(run) + return _c +} + +// Bind provides a mock function with given fields: +func (_m *FeatureInterface) Bind() (*model.MsgCounterType, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Bind") + } + + var r0 *model.MsgCounterType + var r1 error + if rf, ok := ret.Get(0).(func() (*model.MsgCounterType, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() *model.MsgCounterType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FeatureInterface_Bind_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Bind' +type FeatureInterface_Bind_Call struct { + *mock.Call +} + +// Bind is a helper method to define mock.On call +func (_e *FeatureInterface_Expecter) Bind() *FeatureInterface_Bind_Call { + return &FeatureInterface_Bind_Call{Call: _e.mock.On("Bind")} +} + +func (_c *FeatureInterface_Bind_Call) Run(run func()) *FeatureInterface_Bind_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureInterface_Bind_Call) Return(_a0 *model.MsgCounterType, _a1 error) *FeatureInterface_Bind_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FeatureInterface_Bind_Call) RunAndReturn(run func() (*model.MsgCounterType, error)) *FeatureInterface_Bind_Call { + _c.Call.Return(run) + return _c +} + +// HasBinding provides a mock function with given fields: +func (_m *FeatureInterface) HasBinding() bool { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for HasBinding") + } + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// FeatureInterface_HasBinding_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasBinding' +type FeatureInterface_HasBinding_Call struct { + *mock.Call +} + +// HasBinding is a helper method to define mock.On call +func (_e *FeatureInterface_Expecter) HasBinding() *FeatureInterface_HasBinding_Call { + return &FeatureInterface_HasBinding_Call{Call: _e.mock.On("HasBinding")} +} + +func (_c *FeatureInterface_HasBinding_Call) Run(run func()) *FeatureInterface_HasBinding_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureInterface_HasBinding_Call) Return(_a0 bool) *FeatureInterface_HasBinding_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureInterface_HasBinding_Call) RunAndReturn(run func() bool) *FeatureInterface_HasBinding_Call { + _c.Call.Return(run) + return _c +} + +// HasSubscription provides a mock function with given fields: +func (_m *FeatureInterface) HasSubscription() bool { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for HasSubscription") + } + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// FeatureInterface_HasSubscription_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasSubscription' +type FeatureInterface_HasSubscription_Call struct { + *mock.Call +} + +// HasSubscription is a helper method to define mock.On call +func (_e *FeatureInterface_Expecter) HasSubscription() *FeatureInterface_HasSubscription_Call { + return &FeatureInterface_HasSubscription_Call{Call: _e.mock.On("HasSubscription")} +} + +func (_c *FeatureInterface_HasSubscription_Call) Run(run func()) *FeatureInterface_HasSubscription_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureInterface_HasSubscription_Call) Return(_a0 bool) *FeatureInterface_HasSubscription_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureInterface_HasSubscription_Call) RunAndReturn(run func() bool) *FeatureInterface_HasSubscription_Call { + _c.Call.Return(run) + return _c +} + +// Subscribe provides a mock function with given fields: +func (_m *FeatureInterface) Subscribe() (*model.MsgCounterType, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + + var r0 *model.MsgCounterType + var r1 error + if rf, ok := ret.Get(0).(func() (*model.MsgCounterType, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() *model.MsgCounterType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FeatureInterface_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe' +type FeatureInterface_Subscribe_Call struct { + *mock.Call +} + +// Subscribe is a helper method to define mock.On call +func (_e *FeatureInterface_Expecter) Subscribe() *FeatureInterface_Subscribe_Call { + return &FeatureInterface_Subscribe_Call{Call: _e.mock.On("Subscribe")} +} + +func (_c *FeatureInterface_Subscribe_Call) Run(run func()) *FeatureInterface_Subscribe_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureInterface_Subscribe_Call) Return(_a0 *model.MsgCounterType, _a1 error) *FeatureInterface_Subscribe_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FeatureInterface_Subscribe_Call) RunAndReturn(run func() (*model.MsgCounterType, error)) *FeatureInterface_Subscribe_Call { + _c.Call.Return(run) + return _c +} + +// NewFeatureInterface creates a new instance of FeatureInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewFeatureInterface(t interface { + mock.TestingT + Cleanup(func()) +}) *FeatureInterface { + mock := &FeatureInterface{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/ServiceInterface.go b/mocks/ServiceInterface.go new file mode 100644 index 00000000..7b71bf71 --- /dev/null +++ b/mocks/ServiceInterface.go @@ -0,0 +1,619 @@ +// Code generated by mockery v2.42.1. DO NOT EDIT. + +package mocks + +import ( + api "github.com/enbility/eebus-go/api" + logging "github.com/enbility/ship-go/logging" + + mock "github.com/stretchr/testify/mock" + + ship_goapi "github.com/enbility/ship-go/api" + + spine_goapi "github.com/enbility/spine-go/api" +) + +// ServiceInterface is an autogenerated mock type for the ServiceInterface type +type ServiceInterface struct { + mock.Mock +} + +type ServiceInterface_Expecter struct { + mock *mock.Mock +} + +func (_m *ServiceInterface) EXPECT() *ServiceInterface_Expecter { + return &ServiceInterface_Expecter{mock: &_m.Mock} +} + +// CancelPairingWithSKI provides a mock function with given fields: ski +func (_m *ServiceInterface) CancelPairingWithSKI(ski string) { + _m.Called(ski) +} + +// ServiceInterface_CancelPairingWithSKI_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CancelPairingWithSKI' +type ServiceInterface_CancelPairingWithSKI_Call struct { + *mock.Call +} + +// CancelPairingWithSKI is a helper method to define mock.On call +// - ski string +func (_e *ServiceInterface_Expecter) CancelPairingWithSKI(ski interface{}) *ServiceInterface_CancelPairingWithSKI_Call { + return &ServiceInterface_CancelPairingWithSKI_Call{Call: _e.mock.On("CancelPairingWithSKI", ski)} +} + +func (_c *ServiceInterface_CancelPairingWithSKI_Call) Run(run func(ski string)) *ServiceInterface_CancelPairingWithSKI_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *ServiceInterface_CancelPairingWithSKI_Call) Return() *ServiceInterface_CancelPairingWithSKI_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceInterface_CancelPairingWithSKI_Call) RunAndReturn(run func(string)) *ServiceInterface_CancelPairingWithSKI_Call { + _c.Call.Return(run) + return _c +} + +// Configuration provides a mock function with given fields: +func (_m *ServiceInterface) Configuration() *api.Configuration { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Configuration") + } + + var r0 *api.Configuration + if rf, ok := ret.Get(0).(func() *api.Configuration); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*api.Configuration) + } + } + + return r0 +} + +// ServiceInterface_Configuration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Configuration' +type ServiceInterface_Configuration_Call struct { + *mock.Call +} + +// Configuration is a helper method to define mock.On call +func (_e *ServiceInterface_Expecter) Configuration() *ServiceInterface_Configuration_Call { + return &ServiceInterface_Configuration_Call{Call: _e.mock.On("Configuration")} +} + +func (_c *ServiceInterface_Configuration_Call) Run(run func()) *ServiceInterface_Configuration_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ServiceInterface_Configuration_Call) Return(_a0 *api.Configuration) *ServiceInterface_Configuration_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ServiceInterface_Configuration_Call) RunAndReturn(run func() *api.Configuration) *ServiceInterface_Configuration_Call { + _c.Call.Return(run) + return _c +} + +// DisconnectSKI provides a mock function with given fields: ski, reason +func (_m *ServiceInterface) DisconnectSKI(ski string, reason string) { + _m.Called(ski, reason) +} + +// ServiceInterface_DisconnectSKI_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisconnectSKI' +type ServiceInterface_DisconnectSKI_Call struct { + *mock.Call +} + +// DisconnectSKI is a helper method to define mock.On call +// - ski string +// - reason string +func (_e *ServiceInterface_Expecter) DisconnectSKI(ski interface{}, reason interface{}) *ServiceInterface_DisconnectSKI_Call { + return &ServiceInterface_DisconnectSKI_Call{Call: _e.mock.On("DisconnectSKI", ski, reason)} +} + +func (_c *ServiceInterface_DisconnectSKI_Call) Run(run func(ski string, reason string)) *ServiceInterface_DisconnectSKI_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *ServiceInterface_DisconnectSKI_Call) Return() *ServiceInterface_DisconnectSKI_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceInterface_DisconnectSKI_Call) RunAndReturn(run func(string, string)) *ServiceInterface_DisconnectSKI_Call { + _c.Call.Return(run) + return _c +} + +// LocalDevice provides a mock function with given fields: +func (_m *ServiceInterface) LocalDevice() spine_goapi.DeviceLocalInterface { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for LocalDevice") + } + + var r0 spine_goapi.DeviceLocalInterface + if rf, ok := ret.Get(0).(func() spine_goapi.DeviceLocalInterface); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(spine_goapi.DeviceLocalInterface) + } + } + + return r0 +} + +// ServiceInterface_LocalDevice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LocalDevice' +type ServiceInterface_LocalDevice_Call struct { + *mock.Call +} + +// LocalDevice is a helper method to define mock.On call +func (_e *ServiceInterface_Expecter) LocalDevice() *ServiceInterface_LocalDevice_Call { + return &ServiceInterface_LocalDevice_Call{Call: _e.mock.On("LocalDevice")} +} + +func (_c *ServiceInterface_LocalDevice_Call) Run(run func()) *ServiceInterface_LocalDevice_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ServiceInterface_LocalDevice_Call) Return(_a0 spine_goapi.DeviceLocalInterface) *ServiceInterface_LocalDevice_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ServiceInterface_LocalDevice_Call) RunAndReturn(run func() spine_goapi.DeviceLocalInterface) *ServiceInterface_LocalDevice_Call { + _c.Call.Return(run) + return _c +} + +// LocalService provides a mock function with given fields: +func (_m *ServiceInterface) LocalService() *ship_goapi.ServiceDetails { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for LocalService") + } + + var r0 *ship_goapi.ServiceDetails + if rf, ok := ret.Get(0).(func() *ship_goapi.ServiceDetails); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*ship_goapi.ServiceDetails) + } + } + + return r0 +} + +// ServiceInterface_LocalService_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LocalService' +type ServiceInterface_LocalService_Call struct { + *mock.Call +} + +// LocalService is a helper method to define mock.On call +func (_e *ServiceInterface_Expecter) LocalService() *ServiceInterface_LocalService_Call { + return &ServiceInterface_LocalService_Call{Call: _e.mock.On("LocalService")} +} + +func (_c *ServiceInterface_LocalService_Call) Run(run func()) *ServiceInterface_LocalService_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ServiceInterface_LocalService_Call) Return(_a0 *ship_goapi.ServiceDetails) *ServiceInterface_LocalService_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ServiceInterface_LocalService_Call) RunAndReturn(run func() *ship_goapi.ServiceDetails) *ServiceInterface_LocalService_Call { + _c.Call.Return(run) + return _c +} + +// PairingDetailForSki provides a mock function with given fields: ski +func (_m *ServiceInterface) PairingDetailForSki(ski string) *ship_goapi.ConnectionStateDetail { + ret := _m.Called(ski) + + if len(ret) == 0 { + panic("no return value specified for PairingDetailForSki") + } + + var r0 *ship_goapi.ConnectionStateDetail + if rf, ok := ret.Get(0).(func(string) *ship_goapi.ConnectionStateDetail); ok { + r0 = rf(ski) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*ship_goapi.ConnectionStateDetail) + } + } + + return r0 +} + +// ServiceInterface_PairingDetailForSki_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PairingDetailForSki' +type ServiceInterface_PairingDetailForSki_Call struct { + *mock.Call +} + +// PairingDetailForSki is a helper method to define mock.On call +// - ski string +func (_e *ServiceInterface_Expecter) PairingDetailForSki(ski interface{}) *ServiceInterface_PairingDetailForSki_Call { + return &ServiceInterface_PairingDetailForSki_Call{Call: _e.mock.On("PairingDetailForSki", ski)} +} + +func (_c *ServiceInterface_PairingDetailForSki_Call) Run(run func(ski string)) *ServiceInterface_PairingDetailForSki_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *ServiceInterface_PairingDetailForSki_Call) Return(_a0 *ship_goapi.ConnectionStateDetail) *ServiceInterface_PairingDetailForSki_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ServiceInterface_PairingDetailForSki_Call) RunAndReturn(run func(string) *ship_goapi.ConnectionStateDetail) *ServiceInterface_PairingDetailForSki_Call { + _c.Call.Return(run) + return _c +} + +// RegisterRemoteSKI provides a mock function with given fields: ski +func (_m *ServiceInterface) RegisterRemoteSKI(ski string) { + _m.Called(ski) +} + +// ServiceInterface_RegisterRemoteSKI_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RegisterRemoteSKI' +type ServiceInterface_RegisterRemoteSKI_Call struct { + *mock.Call +} + +// RegisterRemoteSKI is a helper method to define mock.On call +// - ski string +func (_e *ServiceInterface_Expecter) RegisterRemoteSKI(ski interface{}) *ServiceInterface_RegisterRemoteSKI_Call { + return &ServiceInterface_RegisterRemoteSKI_Call{Call: _e.mock.On("RegisterRemoteSKI", ski)} +} + +func (_c *ServiceInterface_RegisterRemoteSKI_Call) Run(run func(ski string)) *ServiceInterface_RegisterRemoteSKI_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *ServiceInterface_RegisterRemoteSKI_Call) Return() *ServiceInterface_RegisterRemoteSKI_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceInterface_RegisterRemoteSKI_Call) RunAndReturn(run func(string)) *ServiceInterface_RegisterRemoteSKI_Call { + _c.Call.Return(run) + return _c +} + +// RemoteServiceForSKI provides a mock function with given fields: ski +func (_m *ServiceInterface) RemoteServiceForSKI(ski string) *ship_goapi.ServiceDetails { + ret := _m.Called(ski) + + if len(ret) == 0 { + panic("no return value specified for RemoteServiceForSKI") + } + + var r0 *ship_goapi.ServiceDetails + if rf, ok := ret.Get(0).(func(string) *ship_goapi.ServiceDetails); ok { + r0 = rf(ski) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*ship_goapi.ServiceDetails) + } + } + + return r0 +} + +// ServiceInterface_RemoteServiceForSKI_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteServiceForSKI' +type ServiceInterface_RemoteServiceForSKI_Call struct { + *mock.Call +} + +// RemoteServiceForSKI is a helper method to define mock.On call +// - ski string +func (_e *ServiceInterface_Expecter) RemoteServiceForSKI(ski interface{}) *ServiceInterface_RemoteServiceForSKI_Call { + return &ServiceInterface_RemoteServiceForSKI_Call{Call: _e.mock.On("RemoteServiceForSKI", ski)} +} + +func (_c *ServiceInterface_RemoteServiceForSKI_Call) Run(run func(ski string)) *ServiceInterface_RemoteServiceForSKI_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *ServiceInterface_RemoteServiceForSKI_Call) Return(_a0 *ship_goapi.ServiceDetails) *ServiceInterface_RemoteServiceForSKI_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ServiceInterface_RemoteServiceForSKI_Call) RunAndReturn(run func(string) *ship_goapi.ServiceDetails) *ServiceInterface_RemoteServiceForSKI_Call { + _c.Call.Return(run) + return _c +} + +// SetAutoAccept provides a mock function with given fields: value +func (_m *ServiceInterface) SetAutoAccept(value bool) { + _m.Called(value) +} + +// ServiceInterface_SetAutoAccept_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetAutoAccept' +type ServiceInterface_SetAutoAccept_Call struct { + *mock.Call +} + +// SetAutoAccept is a helper method to define mock.On call +// - value bool +func (_e *ServiceInterface_Expecter) SetAutoAccept(value interface{}) *ServiceInterface_SetAutoAccept_Call { + return &ServiceInterface_SetAutoAccept_Call{Call: _e.mock.On("SetAutoAccept", value)} +} + +func (_c *ServiceInterface_SetAutoAccept_Call) Run(run func(value bool)) *ServiceInterface_SetAutoAccept_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(bool)) + }) + return _c +} + +func (_c *ServiceInterface_SetAutoAccept_Call) Return() *ServiceInterface_SetAutoAccept_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceInterface_SetAutoAccept_Call) RunAndReturn(run func(bool)) *ServiceInterface_SetAutoAccept_Call { + _c.Call.Return(run) + return _c +} + +// SetLogging provides a mock function with given fields: logger +func (_m *ServiceInterface) SetLogging(logger logging.LoggingInterface) { + _m.Called(logger) +} + +// ServiceInterface_SetLogging_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetLogging' +type ServiceInterface_SetLogging_Call struct { + *mock.Call +} + +// SetLogging is a helper method to define mock.On call +// - logger logging.LoggingInterface +func (_e *ServiceInterface_Expecter) SetLogging(logger interface{}) *ServiceInterface_SetLogging_Call { + return &ServiceInterface_SetLogging_Call{Call: _e.mock.On("SetLogging", logger)} +} + +func (_c *ServiceInterface_SetLogging_Call) Run(run func(logger logging.LoggingInterface)) *ServiceInterface_SetLogging_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(logging.LoggingInterface)) + }) + return _c +} + +func (_c *ServiceInterface_SetLogging_Call) Return() *ServiceInterface_SetLogging_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceInterface_SetLogging_Call) RunAndReturn(run func(logging.LoggingInterface)) *ServiceInterface_SetLogging_Call { + _c.Call.Return(run) + return _c +} + +// Setup provides a mock function with given fields: +func (_m *ServiceInterface) Setup() error { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Setup") + } + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ServiceInterface_Setup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Setup' +type ServiceInterface_Setup_Call struct { + *mock.Call +} + +// Setup is a helper method to define mock.On call +func (_e *ServiceInterface_Expecter) Setup() *ServiceInterface_Setup_Call { + return &ServiceInterface_Setup_Call{Call: _e.mock.On("Setup")} +} + +func (_c *ServiceInterface_Setup_Call) Run(run func()) *ServiceInterface_Setup_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ServiceInterface_Setup_Call) Return(_a0 error) *ServiceInterface_Setup_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ServiceInterface_Setup_Call) RunAndReturn(run func() error) *ServiceInterface_Setup_Call { + _c.Call.Return(run) + return _c +} + +// Shutdown provides a mock function with given fields: +func (_m *ServiceInterface) Shutdown() { + _m.Called() +} + +// ServiceInterface_Shutdown_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Shutdown' +type ServiceInterface_Shutdown_Call struct { + *mock.Call +} + +// Shutdown is a helper method to define mock.On call +func (_e *ServiceInterface_Expecter) Shutdown() *ServiceInterface_Shutdown_Call { + return &ServiceInterface_Shutdown_Call{Call: _e.mock.On("Shutdown")} +} + +func (_c *ServiceInterface_Shutdown_Call) Run(run func()) *ServiceInterface_Shutdown_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ServiceInterface_Shutdown_Call) Return() *ServiceInterface_Shutdown_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceInterface_Shutdown_Call) RunAndReturn(run func()) *ServiceInterface_Shutdown_Call { + _c.Call.Return(run) + return _c +} + +// Start provides a mock function with given fields: +func (_m *ServiceInterface) Start() { + _m.Called() +} + +// ServiceInterface_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' +type ServiceInterface_Start_Call struct { + *mock.Call +} + +// Start is a helper method to define mock.On call +func (_e *ServiceInterface_Expecter) Start() *ServiceInterface_Start_Call { + return &ServiceInterface_Start_Call{Call: _e.mock.On("Start")} +} + +func (_c *ServiceInterface_Start_Call) Run(run func()) *ServiceInterface_Start_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ServiceInterface_Start_Call) Return() *ServiceInterface_Start_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceInterface_Start_Call) RunAndReturn(run func()) *ServiceInterface_Start_Call { + _c.Call.Return(run) + return _c +} + +// UnregisterRemoteSKI provides a mock function with given fields: ski +func (_m *ServiceInterface) UnregisterRemoteSKI(ski string) { + _m.Called(ski) +} + +// ServiceInterface_UnregisterRemoteSKI_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UnregisterRemoteSKI' +type ServiceInterface_UnregisterRemoteSKI_Call struct { + *mock.Call +} + +// UnregisterRemoteSKI is a helper method to define mock.On call +// - ski string +func (_e *ServiceInterface_Expecter) UnregisterRemoteSKI(ski interface{}) *ServiceInterface_UnregisterRemoteSKI_Call { + return &ServiceInterface_UnregisterRemoteSKI_Call{Call: _e.mock.On("UnregisterRemoteSKI", ski)} +} + +func (_c *ServiceInterface_UnregisterRemoteSKI_Call) Run(run func(ski string)) *ServiceInterface_UnregisterRemoteSKI_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *ServiceInterface_UnregisterRemoteSKI_Call) Return() *ServiceInterface_UnregisterRemoteSKI_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceInterface_UnregisterRemoteSKI_Call) RunAndReturn(run func(string)) *ServiceInterface_UnregisterRemoteSKI_Call { + _c.Call.Return(run) + return _c +} + +// UserIsAbleToApproveOrCancelPairingRequests provides a mock function with given fields: allow +func (_m *ServiceInterface) UserIsAbleToApproveOrCancelPairingRequests(allow bool) { + _m.Called(allow) +} + +// ServiceInterface_UserIsAbleToApproveOrCancelPairingRequests_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UserIsAbleToApproveOrCancelPairingRequests' +type ServiceInterface_UserIsAbleToApproveOrCancelPairingRequests_Call struct { + *mock.Call +} + +// UserIsAbleToApproveOrCancelPairingRequests is a helper method to define mock.On call +// - allow bool +func (_e *ServiceInterface_Expecter) UserIsAbleToApproveOrCancelPairingRequests(allow interface{}) *ServiceInterface_UserIsAbleToApproveOrCancelPairingRequests_Call { + return &ServiceInterface_UserIsAbleToApproveOrCancelPairingRequests_Call{Call: _e.mock.On("UserIsAbleToApproveOrCancelPairingRequests", allow)} +} + +func (_c *ServiceInterface_UserIsAbleToApproveOrCancelPairingRequests_Call) Run(run func(allow bool)) *ServiceInterface_UserIsAbleToApproveOrCancelPairingRequests_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(bool)) + }) + return _c +} + +func (_c *ServiceInterface_UserIsAbleToApproveOrCancelPairingRequests_Call) Return() *ServiceInterface_UserIsAbleToApproveOrCancelPairingRequests_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceInterface_UserIsAbleToApproveOrCancelPairingRequests_Call) RunAndReturn(run func(bool)) *ServiceInterface_UserIsAbleToApproveOrCancelPairingRequests_Call { + _c.Call.Return(run) + return _c +} + +// NewServiceInterface creates a new instance of ServiceInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewServiceInterface(t interface { + mock.TestingT + Cleanup(func()) +}) *ServiceInterface { + mock := &ServiceInterface{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/ServiceReaderInterface.go b/mocks/ServiceReaderInterface.go new file mode 100644 index 00000000..c7700837 --- /dev/null +++ b/mocks/ServiceReaderInterface.go @@ -0,0 +1,207 @@ +// Code generated by mockery v2.42.1. DO NOT EDIT. + +package mocks + +import ( + api "github.com/enbility/eebus-go/api" + mock "github.com/stretchr/testify/mock" + + ship_goapi "github.com/enbility/ship-go/api" +) + +// ServiceReaderInterface is an autogenerated mock type for the ServiceReaderInterface type +type ServiceReaderInterface struct { + mock.Mock +} + +type ServiceReaderInterface_Expecter struct { + mock *mock.Mock +} + +func (_m *ServiceReaderInterface) EXPECT() *ServiceReaderInterface_Expecter { + return &ServiceReaderInterface_Expecter{mock: &_m.Mock} +} + +// RemoteSKIConnected provides a mock function with given fields: service, ski +func (_m *ServiceReaderInterface) RemoteSKIConnected(service api.ServiceInterface, ski string) { + _m.Called(service, ski) +} + +// ServiceReaderInterface_RemoteSKIConnected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteSKIConnected' +type ServiceReaderInterface_RemoteSKIConnected_Call struct { + *mock.Call +} + +// RemoteSKIConnected is a helper method to define mock.On call +// - service api.ServiceInterface +// - ski string +func (_e *ServiceReaderInterface_Expecter) RemoteSKIConnected(service interface{}, ski interface{}) *ServiceReaderInterface_RemoteSKIConnected_Call { + return &ServiceReaderInterface_RemoteSKIConnected_Call{Call: _e.mock.On("RemoteSKIConnected", service, ski)} +} + +func (_c *ServiceReaderInterface_RemoteSKIConnected_Call) Run(run func(service api.ServiceInterface, ski string)) *ServiceReaderInterface_RemoteSKIConnected_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.ServiceInterface), args[1].(string)) + }) + return _c +} + +func (_c *ServiceReaderInterface_RemoteSKIConnected_Call) Return() *ServiceReaderInterface_RemoteSKIConnected_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceReaderInterface_RemoteSKIConnected_Call) RunAndReturn(run func(api.ServiceInterface, string)) *ServiceReaderInterface_RemoteSKIConnected_Call { + _c.Call.Return(run) + return _c +} + +// RemoteSKIDisconnected provides a mock function with given fields: service, ski +func (_m *ServiceReaderInterface) RemoteSKIDisconnected(service api.ServiceInterface, ski string) { + _m.Called(service, ski) +} + +// ServiceReaderInterface_RemoteSKIDisconnected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteSKIDisconnected' +type ServiceReaderInterface_RemoteSKIDisconnected_Call struct { + *mock.Call +} + +// RemoteSKIDisconnected is a helper method to define mock.On call +// - service api.ServiceInterface +// - ski string +func (_e *ServiceReaderInterface_Expecter) RemoteSKIDisconnected(service interface{}, ski interface{}) *ServiceReaderInterface_RemoteSKIDisconnected_Call { + return &ServiceReaderInterface_RemoteSKIDisconnected_Call{Call: _e.mock.On("RemoteSKIDisconnected", service, ski)} +} + +func (_c *ServiceReaderInterface_RemoteSKIDisconnected_Call) Run(run func(service api.ServiceInterface, ski string)) *ServiceReaderInterface_RemoteSKIDisconnected_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.ServiceInterface), args[1].(string)) + }) + return _c +} + +func (_c *ServiceReaderInterface_RemoteSKIDisconnected_Call) Return() *ServiceReaderInterface_RemoteSKIDisconnected_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceReaderInterface_RemoteSKIDisconnected_Call) RunAndReturn(run func(api.ServiceInterface, string)) *ServiceReaderInterface_RemoteSKIDisconnected_Call { + _c.Call.Return(run) + return _c +} + +// ServicePairingDetailUpdate provides a mock function with given fields: ski, detail +func (_m *ServiceReaderInterface) ServicePairingDetailUpdate(ski string, detail *ship_goapi.ConnectionStateDetail) { + _m.Called(ski, detail) +} + +// ServiceReaderInterface_ServicePairingDetailUpdate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ServicePairingDetailUpdate' +type ServiceReaderInterface_ServicePairingDetailUpdate_Call struct { + *mock.Call +} + +// ServicePairingDetailUpdate is a helper method to define mock.On call +// - ski string +// - detail *ship_goapi.ConnectionStateDetail +func (_e *ServiceReaderInterface_Expecter) ServicePairingDetailUpdate(ski interface{}, detail interface{}) *ServiceReaderInterface_ServicePairingDetailUpdate_Call { + return &ServiceReaderInterface_ServicePairingDetailUpdate_Call{Call: _e.mock.On("ServicePairingDetailUpdate", ski, detail)} +} + +func (_c *ServiceReaderInterface_ServicePairingDetailUpdate_Call) Run(run func(ski string, detail *ship_goapi.ConnectionStateDetail)) *ServiceReaderInterface_ServicePairingDetailUpdate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(*ship_goapi.ConnectionStateDetail)) + }) + return _c +} + +func (_c *ServiceReaderInterface_ServicePairingDetailUpdate_Call) Return() *ServiceReaderInterface_ServicePairingDetailUpdate_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceReaderInterface_ServicePairingDetailUpdate_Call) RunAndReturn(run func(string, *ship_goapi.ConnectionStateDetail)) *ServiceReaderInterface_ServicePairingDetailUpdate_Call { + _c.Call.Return(run) + return _c +} + +// ServiceShipIDUpdate provides a mock function with given fields: ski, shipdID +func (_m *ServiceReaderInterface) ServiceShipIDUpdate(ski string, shipdID string) { + _m.Called(ski, shipdID) +} + +// ServiceReaderInterface_ServiceShipIDUpdate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ServiceShipIDUpdate' +type ServiceReaderInterface_ServiceShipIDUpdate_Call struct { + *mock.Call +} + +// ServiceShipIDUpdate is a helper method to define mock.On call +// - ski string +// - shipdID string +func (_e *ServiceReaderInterface_Expecter) ServiceShipIDUpdate(ski interface{}, shipdID interface{}) *ServiceReaderInterface_ServiceShipIDUpdate_Call { + return &ServiceReaderInterface_ServiceShipIDUpdate_Call{Call: _e.mock.On("ServiceShipIDUpdate", ski, shipdID)} +} + +func (_c *ServiceReaderInterface_ServiceShipIDUpdate_Call) Run(run func(ski string, shipdID string)) *ServiceReaderInterface_ServiceShipIDUpdate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *ServiceReaderInterface_ServiceShipIDUpdate_Call) Return() *ServiceReaderInterface_ServiceShipIDUpdate_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceReaderInterface_ServiceShipIDUpdate_Call) RunAndReturn(run func(string, string)) *ServiceReaderInterface_ServiceShipIDUpdate_Call { + _c.Call.Return(run) + return _c +} + +// VisibleRemoteServicesUpdated provides a mock function with given fields: service, entries +func (_m *ServiceReaderInterface) VisibleRemoteServicesUpdated(service api.ServiceInterface, entries []ship_goapi.RemoteService) { + _m.Called(service, entries) +} + +// ServiceReaderInterface_VisibleRemoteServicesUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VisibleRemoteServicesUpdated' +type ServiceReaderInterface_VisibleRemoteServicesUpdated_Call struct { + *mock.Call +} + +// VisibleRemoteServicesUpdated is a helper method to define mock.On call +// - service api.ServiceInterface +// - entries []ship_goapi.RemoteService +func (_e *ServiceReaderInterface_Expecter) VisibleRemoteServicesUpdated(service interface{}, entries interface{}) *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call { + return &ServiceReaderInterface_VisibleRemoteServicesUpdated_Call{Call: _e.mock.On("VisibleRemoteServicesUpdated", service, entries)} +} + +func (_c *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call) Run(run func(service api.ServiceInterface, entries []ship_goapi.RemoteService)) *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.ServiceInterface), args[1].([]ship_goapi.RemoteService)) + }) + return _c +} + +func (_c *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call) Return() *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call { + _c.Call.Return() + return _c +} + +func (_c *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call) RunAndReturn(run func(api.ServiceInterface, []ship_goapi.RemoteService)) *ServiceReaderInterface_VisibleRemoteServicesUpdated_Call { + _c.Call.Return(run) + return _c +} + +// NewServiceReaderInterface creates a new instance of ServiceReaderInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewServiceReaderInterface(t interface { + mock.TestingT + Cleanup(func()) +}) *ServiceReaderInterface { + mock := &ServiceReaderInterface{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/service/cert.go b/service/cert.go deleted file mode 100644 index 7334cd4d..00000000 --- a/service/cert.go +++ /dev/null @@ -1,91 +0,0 @@ -package service - -import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/sha1" - "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "errors" - "fmt" - "math/big" - "time" -) - -var ciperSuites = []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // SHIP 9.1: required cipher suite - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, // SHIP 9.1: optional cipher suite -} - -// Create a ship compatible self signed certificate -// organizationalUnit is the OU of the certificate -// organization is the O of the certificate -// country is the C of the certificate -// commonName is the CN of the certificate -// Example for commonName: "deviceModel-deviceSerialNumber" -func CreateCertificate(organizationalUnit, organization, country, commonName string) (tls.Certificate, error) { - privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - return tls.Certificate{}, err - } - - // Create the EEBUS service SKI using the private key - asn1, err := x509.MarshalECPrivateKey(privateKey) - if err != nil { - return tls.Certificate{}, err - } - // SHIP 12.2: Required to be created according to RFC 3280 4.2.1.2 - ski := sha1.Sum(asn1) - - subject := pkix.Name{ - OrganizationalUnit: []string{organizationalUnit}, - Organization: []string{organization}, - Country: []string{country}, - CommonName: commonName, - } - - // Create a random serial big int value - maxValue := new(big.Int) - maxValue.Exp(big.NewInt(2), big.NewInt(130), nil).Sub(maxValue, big.NewInt(1)) - serialNumber, err := rand.Int(rand.Reader, maxValue) - if err != nil { - return tls.Certificate{}, err - } - - template := x509.Certificate{ - SignatureAlgorithm: x509.ECDSAWithSHA256, - SerialNumber: serialNumber, - Subject: subject, - NotBefore: time.Now(), // Valid starting now - NotAfter: time.Now().Add(time.Hour * 24 * 365 * 10), // Valid for 10 years - KeyUsage: x509.KeyUsageDigitalSignature, - BasicConstraintsValid: true, - IsCA: true, - SubjectKeyId: ski[:], - } - - certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey) - if err != nil { - return tls.Certificate{}, err - } - - tlsCertificate := tls.Certificate{ - Certificate: [][]byte{certBytes}, - PrivateKey: privateKey, - SupportedSignatureAlgorithms: []tls.SignatureScheme{tls.ECDSAWithP256AndSHA256}, - } - - return tlsCertificate, nil -} - -func skiFromCertificate(cert *x509.Certificate) (string, error) { - // check if the clients certificate provides a SKI - subjectKeyId := cert.SubjectKeyId - if len(subjectKeyId) != 20 { - return "", errors.New("Client certificate does not provide a SKI") - } - - return fmt.Sprintf("%0x", subjectKeyId), nil -} diff --git a/service/cert_test.go b/service/cert_test.go deleted file mode 100644 index 636b3be9..00000000 --- a/service/cert_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package service - -import ( - "crypto/x509" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestCertSuite(t *testing.T) { - suite.Run(t, new(CertSuite)) -} - -type CertSuite struct { - suite.Suite -} - -func (c *CertSuite) Test_CreateCertificate() { - cert, err := CreateCertificate("", "Org", "DE", "CN") - assert.Nil(c.T(), err) - assert.NotNil(c.T(), cert) -} - -func (c *CertSuite) Test_SkiFromCertificate() { - cert, err := CreateCertificate("", "Org", "DE", "CN") - assert.Nil(c.T(), err) - - leaf, err := x509.ParseCertificate(cert.Certificate[0]) - assert.Nil(c.T(), err) - - ski, err := skiFromCertificate(leaf) - assert.Nil(c.T(), err) - assert.NotNil(c.T(), ski) -} diff --git a/service/hub.go b/service/hub.go deleted file mode 100644 index 9d573681..00000000 --- a/service/hub.go +++ /dev/null @@ -1,709 +0,0 @@ -package service - -import ( - "crypto/tls" - "crypto/x509" - "errors" - "fmt" - "math/big" - "math/rand" - "net" - "net/http" - "strconv" - "sync" - "time" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/ship" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" - "github.com/gorilla/websocket" -) - -const shipWebsocketSubProtocol = "ship" // SHIP 10.2: sub protocol is required for websocket connections -const shipWebsocketPath = "/ship/" -const shipZeroConfServiceType = "_ship._tcp" -const shipZeroConfDomain = "local." - -// used for randomizing the connection initiation delay -// this limits the possibility of concurrent connection attempts from both sides -type connectionInitiationDelayTimeRange struct { - // defines the minimum and maximum wait time for when to try to initate an connection - min, max int -} - -// defines the delay timeframes in seconds depening on the connection attempt counter -// the last item will be re-used for higher attempt counter values -var connectionInitiationDelayTimeRanges = []connectionInitiationDelayTimeRange{ - {min: 0, max: 3}, - {min: 3, max: 10}, - {min: 10, max: 30}, - {min: 30, max: 60}, - {min: 60, max: 180}, - {min: 180, max: 360}, -} - -// interface for reporting data from connectionsHub to the EEBUSService -type serviceProvider interface { - // report a connection to a SKI - RemoteSKIConnected(ski string) - - // report a disconnection to a SKI - RemoteSKIDisconnected(ski string) - - // provide the SHIP ID received during SHIP handshake process - // the ID needs to be stored and then provided for remote services so it can be compared and verified - ReportServiceShipID(string, string) -} - -// handling all connections to remote services -type connectionsHub struct { - connections map[string]*ship.ShipConnection - - // which attempt is it to initate an connection to the remote SKI - connectionAttemptCounter map[string]int - connectionAttemptRunning map[string]bool - - configuration *Configuration - localService *ServiceDetails - - serviceProvider serviceProvider - - // The list of paired devices - pairedServices []*ServiceDetails - - // The web server for handling incoming websocket connections - httpServer *http.Server - - // Handling mDNS related tasks - mdns MdnsService - - // the SPINE local device - spineLocalDevice *spine.DeviceLocalImpl - - muxCon sync.Mutex - muxConAttempt sync.Mutex - muxReg sync.Mutex - muxMdns sync.Mutex -} - -func newConnectionsHub(serviceProvider serviceProvider, mdns MdnsService, spineLocalDevice *spine.DeviceLocalImpl, configuration *Configuration, localService *ServiceDetails) *connectionsHub { - hub := &connectionsHub{ - connections: make(map[string]*ship.ShipConnection), - connectionAttemptCounter: make(map[string]int), - connectionAttemptRunning: make(map[string]bool), - pairedServices: make([]*ServiceDetails, 0), - serviceProvider: serviceProvider, - spineLocalDevice: spineLocalDevice, - configuration: configuration, - localService: localService, - mdns: mdns, - } - - return hub -} - -// start the ConnectionsHub with all its services -func (h *connectionsHub) start() { - // start mDNS - err := h.mdns.SetupMdnsService() - if err != nil { - logging.Log.Debug("error during mdns setup:", err) - } - - // start the websocket server - go func() { - if err := h.startWebsocketServer(); err != nil { - logging.Log.Debug("error during websocket server starting:", err) - } - }() - - if err := h.mdns.AnnounceMdnsEntry(); err != nil { - logging.Log.Debug("error registering mDNS Service:", err) - } -} - -var _ ship.ShipServiceDataProvider = (*connectionsHub)(nil) - -// Returns if the provided SKI is from a registered service -func (h *connectionsHub) IsRemoteServiceForSKIPaired(ski string) bool { - if _, err := h.PairedServiceForSKI(ski); err != nil { - return false - } - - return true -} - -// The connection was closed, we need to clean up -func (h *connectionsHub) HandleConnectionClosed(connection *ship.ShipConnection, handshakeCompleted bool) { - // only remove this connection if it is the registered one for the ski! - // as we can have double connections but only one can be registered - if existingC := h.connectionForSKI(connection.RemoteSKI); existingC != nil { - if existingC.DataHandler == connection.DataHandler { - h.muxCon.Lock() - delete(h.connections, connection.RemoteSKI) - h.muxCon.Unlock() - } - - // connection close was after a completed handshake, so we can reset the attetmpt counter - if handshakeCompleted { - h.removeConnectionAttemptCounter(connection.RemoteSKI) - } - } - - h.serviceProvider.RemoteSKIDisconnected(connection.RemoteSKI) - - h.checkRestartMdnsSearch() -} - -// startup mDNS if a paired service is not connected -func (h *connectionsHub) checkRestartMdnsSearch() { - h.muxReg.Lock() - countPairedServices := len(h.pairedServices) - h.muxReg.Unlock() - h.muxCon.Lock() - countConnections := len(h.connections) - h.muxCon.Unlock() - - if countPairedServices > countConnections { - // if this is not a CEM also start the mDNS announcement - if h.localService.deviceType != model.DeviceTypeTypeEnergyManagementSystem { - _ = h.mdns.AnnounceMdnsEntry() - } - - logging.Log.Debug("restarting mdns search") - h.mdns.RegisterMdnsSearch(h) - } -} - -// Provides the SHIP ID the remote service reported during the handshake process -func (h *connectionsHub) ReportServiceShipID(ski string, shipdID string) { - h.serviceProvider.RemoteSKIConnected(ski) - - h.serviceProvider.ReportServiceShipID(ski, shipdID) -} - -// Disconnect a connection to an SKI, used by a service implementation -// e.g. if heartbeats go wrong -func (h *connectionsHub) DisconnectSKI(ski string, reason string) { - h.muxCon.Lock() - defer h.muxCon.Unlock() - - // The connection with the higher SKI should retain the connection - con, ok := h.connections[ski] - if !ok { - return - } - - con.CloseConnection(true, reason) -} - -// register a new ship Connection -func (h *connectionsHub) registerConnection(connection *ship.ShipConnection) { - h.muxCon.Lock() - h.connections[connection.RemoteSKI] = connection - h.muxCon.Unlock() - - // shutdown mDNS if this is not a CEM - if h.localService.deviceType != model.DeviceTypeTypeEnergyManagementSystem { - h.mdns.UnannounceMdnsEntry() - h.mdns.UnregisterMdnsSearch(h) - } -} - -// return the connection for a specific SKI -func (h *connectionsHub) connectionForSKI(ski string) *ship.ShipConnection { - h.muxCon.Lock() - defer h.muxCon.Unlock() - - con, ok := h.connections[ski] - if !ok { - return nil - } - return con -} - -// close all connections -func (h *connectionsHub) shutdown() { - h.mdns.ShutdownMdnsService() - for _, c := range h.connections { - c.CloseConnection(false, "") - } -} - -// return if there is a connection for a SKI -func (h *connectionsHub) isSkiConnected(ski string) bool { - h.muxCon.Lock() - defer h.muxCon.Unlock() - - // The connection with the higher SKI should retain the connection - _, ok := h.connections[ski] - return ok -} - -// Websocket connection handling - -// start the ship websocket server -func (h *connectionsHub) startWebsocketServer() error { - addr := fmt.Sprintf(":%d", h.configuration.port) - logging.Log.Debug("starting websocket server on", addr) - - h.httpServer = &http.Server{ - Addr: addr, - Handler: h, - TLSConfig: &tls.Config{ - Certificates: []tls.Certificate{h.configuration.certificate}, - ClientAuth: tls.RequireAnyClientCert, // SHIP 9: Client authentication is required - CipherSuites: ciperSuites, - VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { - skiFound := false - for _, v := range rawCerts { - cert, err := x509.ParseCertificate(v) - if err != nil { - return err - } - - if _, err := skiFromCertificate(cert); err == nil { - skiFound = true - break - } - } - if !skiFound { - return errors.New("no valid SKI provided in certificate") - } - - return nil - }, - }, - } - - if err := h.httpServer.ListenAndServeTLS("", ""); err != nil { - return err - } - - return nil -} - -// Connection Handling - -// HTTP Server callback for handling incoming connection requests -func (h *connectionsHub) ServeHTTP(w http.ResponseWriter, r *http.Request) { - upgrader := websocket.Upgrader{ - ReadBufferSize: ship.MaxMessageSize, - WriteBufferSize: ship.MaxMessageSize, - CheckOrigin: func(r *http.Request) bool { return true }, - Subprotocols: []string{shipWebsocketSubProtocol}, // SHIP 10.2: Sub protocol "ship" is required - } - - conn, err := upgrader.Upgrade(w, r, nil) - if err != nil { - logging.Log.Debug("error during connection upgrading:", err) - return - } - - // check if the client supports the ship sub protocol - if conn.Subprotocol() != shipWebsocketSubProtocol { - logging.Log.Debug("client does not support the ship sub protocol") - conn.Close() - return - } - - // check if the clients certificate provides a SKI - if len(r.TLS.PeerCertificates) == 0 { - logging.Log.Debug("client does not provide a certificate") - conn.Close() - return - } - - ski, err := skiFromCertificate(r.TLS.PeerCertificates[0]) - if err != nil { - logging.Log.Debug(err) - conn.Close() - return - } - - // normalize the incoming SKI - remoteService := NewServiceDetails(ski) - logging.Log.Debug("incoming connection request from", remoteService.SKI()) - - // Check if the remote service is paired - _, err = h.PairedServiceForSKI(remoteService.SKI()) - if err != nil { - logging.Log.Debug("ski", ski, "is not paired, closing the connection") - return - } - - // check if we already know this remote service - if remoteS, err := h.PairedServiceForSKI(remoteService.SKI()); err == nil { - remoteService = remoteS - } - - // don't allow a second connection - if !h.keepThisConnection(conn, true, remoteService) { - return - } - - dataHandler := ship.NewWebsocketConnection(conn, remoteService.SKI()) - shipConnection := ship.NewConnectionHandler(h, dataHandler, h.spineLocalDevice, ship.ShipRoleServer, h.localService.ShipID(), remoteService.SKI(), remoteService.ShipID()) - shipConnection.Run() - - h.registerConnection(shipConnection) -} - -// Connect to another EEBUS service -// -// returns error contains a reason for failing the connection or nil if no further tries should be processed -func (h *connectionsHub) connectFoundService(remoteService *ServiceDetails, host, port string) error { - if h.isSkiConnected(remoteService.SKI()) { - return nil - } - - logging.Log.Debugf("initiating connection to %s at %s:%s", remoteService.SKI(), host, port) - - dialer := &websocket.Dialer{ - Proxy: http.ProxyFromEnvironment, - HandshakeTimeout: 5 * time.Second, - TLSClientConfig: &tls.Config{ - Certificates: []tls.Certificate{h.configuration.certificate}, - InsecureSkipVerify: true, - CipherSuites: ciperSuites, - }, - Subprotocols: []string{shipWebsocketSubProtocol}, - } - - address := fmt.Sprintf("wss://%s:%s", host, port) - conn, _, err := dialer.Dial(address, nil) - if err != nil { - return err - } - - tlsConn := conn.UnderlyingConn().(*tls.Conn) - remoteCerts := tlsConn.ConnectionState().PeerCertificates - - if len(remoteCerts) == 0 || remoteCerts[0].SubjectKeyId == nil { - // Close connection as we couldn't get the remote SKI - errorString := fmt.Sprintf("closing connection to %s: could not get remote SKI from certificate", remoteService.SKI()) - conn.Close() - return errors.New(errorString) - } - - if _, err := skiFromCertificate(remoteCerts[0]); err != nil { - // Close connection as the remote SKI can't be correct - errorString := fmt.Sprintf("closing connection to %s: %s", remoteService.SKI(), err) - conn.Close() - return errors.New(errorString) - } - - remoteSKI := fmt.Sprintf("%0x", remoteCerts[0].SubjectKeyId) - - if remoteSKI != remoteService.SKI() { - errorString := fmt.Sprintf("closing connection to %s: SKI does not match %s", remoteService.SKI(), remoteSKI) - conn.Close() - return errors.New(errorString) - } - - if !h.keepThisConnection(conn, false, remoteService) { - errorString := fmt.Sprintf("closing connection to %s: ignoring this connection", remoteService.SKI()) - return errors.New(errorString) - } - - dataHandler := ship.NewWebsocketConnection(conn, remoteService.SKI()) - shipConnection := ship.NewConnectionHandler(h, dataHandler, h.spineLocalDevice, ship.ShipRoleClient, h.localService.ShipID(), remoteService.SKI(), remoteService.ShipID()) - shipConnection.Run() - - h.registerConnection(shipConnection) - - return nil -} - -// prevent double connections -// only keep the connection initiated by the higher SKI -// -// returns true if this connection is fine to be continue -// returns false if this connection should not be established or kept -func (h *connectionsHub) keepThisConnection(conn *websocket.Conn, incomingRequest bool, remoteService *ServiceDetails) bool { - // SHIP 12.2.2 defines: - // prevent double connections with SKI Comparison - // the node with the hight SKI value kees the most recent connection and - // and closes all other connections to the same SHIP node - // - // This is hard to implement without any flaws. Therefor I chose a - // different approach: The connection initiated by the higher SKI will be kept - - remoteSKI := remoteService.SKI() - existingC := h.connectionForSKI(remoteSKI) - if existingC == nil { - return true - } - - keep := false - if incomingRequest { - keep = remoteSKI > h.localService.SKI() - } else { - keep = h.localService.SKI() > remoteSKI - } - - if keep { - // we have an existing connection - // so keep the new (most recent) and close the old one - logging.Log.Debug("closing existing double connection") - go existingC.CloseConnection(false, "") - } else { - connType := "incoming" - if !incomingRequest { - connType = "outgoing" - } - logging.Log.Debugf("closing %s double connection, as the existing connection will be used", connType) - go func() { - _ = conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "double connection")) - time.Sleep(time.Millisecond * 100) - conn.Close() - }() - } - - return keep -} - -func (h *connectionsHub) PairedServiceForSKI(ski string) (*ServiceDetails, error) { - h.muxReg.Lock() - defer h.muxReg.Unlock() - - for _, service := range h.pairedServices { - if service.SKI() == ski { - return service, nil - } - } - return nil, fmt.Errorf("no registered service found for SKI %s", ski) -} - -// Adds a new device to the list of known devices which can be connected to -// and connect it if it is currently not connected -func (h *connectionsHub) PairRemoteService(service *ServiceDetails) { - // check if it is already registered - if _, err := h.PairedServiceForSKI(service.SKI()); err != nil { - h.muxReg.Lock() - h.pairedServices = append(h.pairedServices, service) - h.muxReg.Unlock() - } - - if !h.isSkiConnected(service.SKI()) { - h.mdns.RegisterMdnsSearch(h) - } -} - -// Remove a device from the list of known devices which can be connected to -// and disconnect it if it is currently connected -func (h *connectionsHub) UnpairRemoteService(ski string) error { - h.removeConnectionAttemptCounter(ski) - - newRegisteredDevice := make([]*ServiceDetails, 0) - - h.muxReg.Lock() - for _, device := range h.pairedServices { - if device.SKI() != ski { - newRegisteredDevice = append(newRegisteredDevice, device) - } - } - - h.pairedServices = newRegisteredDevice - h.muxReg.Unlock() - - if existingC := h.connectionForSKI(ski); existingC != nil { - existingC.CloseConnection(true, "pairing removed") - } - - return nil -} - -// Process reported mDNS services -func (h *connectionsHub) ReportMdnsEntries(entries map[string]MdnsEntry) { - h.muxMdns.Lock() - defer h.muxMdns.Unlock() - - for ski, entry := range entries { - // check if this ski is already connected - if h.isSkiConnected(ski) { - continue - } - - // Check if the remote service is paired - remoteService, err := h.PairedServiceForSKI(ski) - if err != nil { - continue - } - - // patch the addresses list if an IPv4 address was provided - if remoteService.IPv4() != "" { - if ip := net.ParseIP(remoteService.IPv4()); ip != nil { - entry.Addresses = []net.IP{ip} - } - } - - h.coordinateConnectionInitations(ski, entry) - } -} - -// coordinate connection initiation attempts to a remove service -func (h *connectionsHub) coordinateConnectionInitations(ski string, entry MdnsEntry) { - if h.isConnectionAttemptRunning(ski) { - return - } - - h.setConnectionAttemptRunning(ski, true) - counter, duration := h.getConnectionInitiationDelayTime(ski) - - logging.Log.Debugf("delaying connection to %s by %s to minimize double connection probability", ski, duration) - // we do not stop this thread and just let the timer run out - // otherwise we would need a stop channel for each ski - go func() { - // wait - <-time.After(duration) - - h.setConnectionAttemptRunning(ski, false) - - // check if the remoteService still exists - remoteService, err := h.PairedServiceForSKI(ski) - if err != nil { - return - } - - // check if the current counter is still the same, otherwise this counter is irrelevant - currentCounter, exists := h.getCurrentConnectionAttemptCounter(ski) - if !exists || currentCounter != counter { - return - } - - // connection attempt is not relevant if the device is no longer paired - if !h.IsRemoteServiceForSKIPaired(ski) { - return - } - - // connection attempt is not relevant if the device is already connected - if h.isSkiConnected(ski) { - return - } - - // now initiate the connection - if success := h.initateConnection(remoteService, entry); !success { - h.checkRestartMdnsSearch() - } - - }() -} - -// attempt to establish a connection to a remote service -// returns true if successful -func (h *connectionsHub) initateConnection(remoteService *ServiceDetails, entry MdnsEntry) bool { - var err error - - // try connecting via an IP address first - for _, address := range entry.Addresses { - logging.Log.Debug("trying to connect to", remoteService.SKI(), "at", address) - if err = h.connectFoundService(remoteService, address.String(), strconv.Itoa(entry.Port)); err != nil { - logging.Log.Debug("connection to", remoteService.SKI(), "failed: ", err) - } else { - return true - } - } - - // connectdion via IP address failed, try hostname - if len(entry.Host) > 0 { - logging.Log.Debug("trying to connect to", remoteService.SKI(), "at", entry.Host) - if err = h.connectFoundService(remoteService, entry.Host, strconv.Itoa(entry.Port)); err != nil { - logging.Log.Debugf("connection to %s failed: %s", remoteService.SKI(), err) - } else { - return true - } - } - - // no connection could be estabished via any of the provided addresses - // because no service was reachable at any of the addresses - return false -} - -// increase the connection attempt counter for the given ski -func (h *connectionsHub) increaseConnectionAttemptCounter(ski string) int { - h.muxConAttempt.Lock() - defer h.muxConAttempt.Unlock() - - currentCounter := 0 - if counter, exists := h.connectionAttemptCounter[ski]; exists { - currentCounter = counter + 1 - - if currentCounter >= len(connectionInitiationDelayTimeRanges)-1 { - currentCounter = len(connectionInitiationDelayTimeRanges) - 1 - } - } - - h.connectionAttemptCounter[ski] = currentCounter - - return currentCounter -} - -// remove the connection attempt counter for the given ski -func (h *connectionsHub) removeConnectionAttemptCounter(ski string) { - h.muxConAttempt.Lock() - defer h.muxConAttempt.Unlock() - - delete(h.connectionAttemptCounter, ski) -} - -// get the current attempt counter -func (h *connectionsHub) getCurrentConnectionAttemptCounter(ski string) (int, bool) { - h.muxConAttempt.Lock() - defer h.muxConAttempt.Unlock() - - counter, exists := h.connectionAttemptCounter[ski] - - return counter, exists -} - -// get the connection initiation delay time range for a given ski -// returns the current counter and the duration -func (h *connectionsHub) getConnectionInitiationDelayTime(ski string) (int, time.Duration) { - counter := h.increaseConnectionAttemptCounter(ski) - - h.muxConAttempt.Lock() - defer h.muxConAttempt.Unlock() - - timeRange := connectionInitiationDelayTimeRanges[counter] - - // get range in Milliseconds - min := timeRange.min * 1000 - max := timeRange.max * 1000 - - // seed with the local SKI for initializing rand - // TODO: remove when upping minimum go version to 1.20 - i := new(big.Int) - hex := fmt.Sprintf("0x%s", h.localService.SKI()) - randSource := rand.NewSource(time.Now().UnixNano()) - if _, err := fmt.Sscan(hex, i); err == nil { - randSource = rand.NewSource(i.Int64() + time.Now().UnixNano()) - } - - r := rand.New(randSource) - duration := r.Intn(max-min) + min - - return counter, time.Duration(duration) * time.Millisecond -} - -// set if a connection attempt is running/in progress -func (h *connectionsHub) setConnectionAttemptRunning(ski string, active bool) { - h.muxConAttempt.Lock() - defer h.muxConAttempt.Unlock() - - h.connectionAttemptRunning[ski] = active -} - -// return if a connection attempt is runnning/in progress -func (h *connectionsHub) isConnectionAttemptRunning(ski string) bool { - h.muxConAttempt.Lock() - defer h.muxConAttempt.Unlock() - - running, exists := h.connectionAttemptRunning[ski] - if !exists { - return false - } - - return running -} diff --git a/service/hub_test.go b/service/hub_test.go deleted file mode 100644 index 4a7f28aa..00000000 --- a/service/hub_test.go +++ /dev/null @@ -1,225 +0,0 @@ -package service - -import ( - "testing" - "time" - - "github.com/enbility/eebus-go/ship" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestHubSuite(t *testing.T) { - suite.Run(t, new(HubSuite)) -} - -type testStruct struct { - counter int - timeRange connectionInitiationDelayTimeRange -} - -type HubSuite struct { - suite.Suite - - tests []testStruct -} - -func (s *HubSuite) SetupSuite() { - s.tests = []testStruct{ - {0, connectionInitiationDelayTimeRanges[0]}, - {1, connectionInitiationDelayTimeRanges[1]}, - {2, connectionInitiationDelayTimeRanges[2]}, - {3, connectionInitiationDelayTimeRanges[3]}, - {4, connectionInitiationDelayTimeRanges[4]}, - {5, connectionInitiationDelayTimeRanges[5]}, - {6, connectionInitiationDelayTimeRanges[5]}, - {7, connectionInitiationDelayTimeRanges[5]}, - {8, connectionInitiationDelayTimeRanges[5]}, - {9, connectionInitiationDelayTimeRanges[5]}, - {10, connectionInitiationDelayTimeRanges[5]}, - } -} - -// Service Provider Interface -var _ serviceProvider = (*HubSuite)(nil) - -func (s *HubSuite) RemoteSKIConnected(string) {} -func (s *HubSuite) RemoteSKIDisconnected(string) {} -func (s *HubSuite) ReportServiceShipID(string, string) {} - -var _ MdnsService = (*HubSuite)(nil) - -func (s *HubSuite) SetupMdnsService() error { return nil } -func (s *HubSuite) ShutdownMdnsService() {} -func (s *HubSuite) AnnounceMdnsEntry() error { return nil } -func (s *HubSuite) UnannounceMdnsEntry() {} -func (s *HubSuite) RegisterMdnsSearch(cb MdnsSearch) {} -func (s *HubSuite) UnregisterMdnsSearch(cb MdnsSearch) {} - -func (s *HubSuite) Test_NewConnectionsHub() { - ski := "12af9e" - localService := NewServiceDetails(ski) - configuration := &Configuration{ - interfaces: []string{"en0"}, - } - hub := newConnectionsHub(s, s, nil, configuration, localService) - assert.NotNil(s.T(), hub) - - hub.start() -} - -func (s *HubSuite) Test_IsRemoteSKIPaired() { - sut := connectionsHub{ - connections: make(map[string]*ship.ShipConnection), - connectionAttemptCounter: make(map[string]int), - } - ski := "test" - - paired := sut.IsRemoteServiceForSKIPaired(ski) - assert.Equal(s.T(), false, paired) - - service := NewServiceDetails(ski) - // mark it as connected, so mDNS is not triggered - sut.connections[ski] = &ship.ShipConnection{} - sut.PairRemoteService(service) - - paired = sut.IsRemoteServiceForSKIPaired(ski) - assert.Equal(s.T(), true, paired) - - // remove the connection, so the test doesn't try to close it - delete(sut.connections, ski) - err := sut.UnpairRemoteService(ski) - assert.Nil(s.T(), err) - paired = sut.IsRemoteServiceForSKIPaired(ski) - assert.Equal(s.T(), false, paired) -} - -func (s *HubSuite) Test_CheckRestartMdnsSearch() { - sut := connectionsHub{ - connections: make(map[string]*ship.ShipConnection), - connectionAttemptCounter: make(map[string]int), - } - sut.checkRestartMdnsSearch() - // Nothing to verify yet -} - -func (s *HubSuite) Test_ReportServiceShipID() { - sut := connectionsHub{ - serviceProvider: s, - } - sut.ReportServiceShipID("", "") - // Nothing to verify yet -} - -func (s *HubSuite) Test_DisconnectSKI() { - sut := connectionsHub{ - connections: make(map[string]*ship.ShipConnection), - } - ski := "test" - sut.DisconnectSKI(ski, "none") -} - -func (s *HubSuite) Test_RegisterConnection() { - ski := "12af9e" - localService := NewServiceDetails(ski) - - sut := connectionsHub{ - connections: make(map[string]*ship.ShipConnection), - mdns: s, - localService: localService, - } - - ski = "test" - con := &ship.ShipConnection{ - RemoteSKI: ski, - } - sut.registerConnection(con) - assert.Equal(s.T(), 1, len(sut.connections)) - con = sut.connectionForSKI(ski) - assert.NotNil(s.T(), con) -} - -func (s *HubSuite) Test_IncreaseConnectionAttemptCounter() { - - // we just need a dummy for this test - sut := connectionsHub{ - connectionAttemptCounter: make(map[string]int), - } - ski := "test" - - for _, test := range s.tests { - sut.increaseConnectionAttemptCounter(ski) - - sut.muxConAttempt.Lock() - counter, exists := sut.connectionAttemptCounter[ski] - timeRange := connectionInitiationDelayTimeRanges[counter] - sut.muxConAttempt.Unlock() - - assert.Equal(s.T(), true, exists) - assert.Equal(s.T(), test.timeRange.min, timeRange.min) - assert.Equal(s.T(), test.timeRange.max, timeRange.max) - } -} - -func (s *HubSuite) Test_RemoveConnectionAttemptCounter() { - // we just need a dummy for this test - sut := connectionsHub{ - connectionAttemptCounter: make(map[string]int), - } - ski := "test" - - sut.increaseConnectionAttemptCounter(ski) - _, exists := sut.connectionAttemptCounter[ski] - assert.Equal(s.T(), true, exists) - - sut.removeConnectionAttemptCounter(ski) - _, exists = sut.connectionAttemptCounter[ski] - assert.Equal(s.T(), false, exists) -} - -func (s *HubSuite) Test_GetCurrentConnectionAttemptCounter() { - // we just need a dummy for this test - sut := connectionsHub{ - connectionAttemptCounter: make(map[string]int), - } - ski := "test" - - sut.increaseConnectionAttemptCounter(ski) - _, exists := sut.connectionAttemptCounter[ski] - assert.Equal(s.T(), exists, true) - sut.increaseConnectionAttemptCounter(ski) - - value, exists := sut.getCurrentConnectionAttemptCounter(ski) - assert.Equal(s.T(), 1, value) - assert.Equal(s.T(), true, exists) -} - -func (s *HubSuite) Test_GetConnectionInitiationDelayTime() { - // we just need a dummy for this test - ski := "12af9e" - localService := NewServiceDetails(ski) - sut := connectionsHub{ - localService: localService, - connectionAttemptCounter: make(map[string]int), - } - - counter, duration := sut.getConnectionInitiationDelayTime(ski) - assert.Equal(s.T(), 0, counter) - assert.LessOrEqual(s.T(), float64(s.tests[counter].timeRange.min), float64(duration/time.Second)) - assert.GreaterOrEqual(s.T(), float64(s.tests[counter].timeRange.max), float64(duration/time.Second)) -} - -func (s *HubSuite) Test_ConnectionAttemptRunning() { - // we just need a dummy for this test - ski := "test" - sut := connectionsHub{ - connectionAttemptRunning: make(map[string]bool), - } - - sut.setConnectionAttemptRunning(ski, true) - status := sut.isConnectionAttemptRunning(ski) - assert.Equal(s.T(), true, status) - sut.setConnectionAttemptRunning(ski, false) - status = sut.isConnectionAttemptRunning(ski) - assert.Equal(s.T(), false, status) -} diff --git a/service/mdns.go b/service/mdns.go deleted file mode 100644 index 6b4eef5d..00000000 --- a/service/mdns.go +++ /dev/null @@ -1,539 +0,0 @@ -package service - -import ( - "context" - "fmt" - "net" - "os" - "os/signal" - "strings" - "sync" - "syscall" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/util" - "github.com/godbus/dbus/v5" - "github.com/holoplot/go-avahi" - "github.com/libp2p/zeroconf/v2" -) - -type MdnsEntry struct { - Name string - Identifier string // mandatory - Path string // mandatory - Register bool // mandatory - Brand string // optional - Type string // optional - Model string // optional - Host string // mandatory - Port int // mandatory - Addresses []net.IP // mandatory -} - -// implemented by hubConnection, used by mdns -type MdnsSearch interface { - ReportMdnsEntries(entries map[string]MdnsEntry) -} - -// implemented by mdns, used by hubConnection -type MdnsService interface { - SetupMdnsService() error - ShutdownMdnsService() - AnnounceMdnsEntry() error - UnannounceMdnsEntry() - RegisterMdnsSearch(cb MdnsSearch) - UnregisterMdnsSearch(cb MdnsSearch) -} - -type mdns struct { - configuration *Configuration - ski string - - isAnnounced bool - isSearchingServices bool - - cancelChan chan bool - - // the currently available mDNS entries with the SKI as the key in the map - entries map[string]MdnsEntry - - // the registered callback, only connectionsHub is using this - searchDelegate MdnsSearch - - // The zeroconf service for mDNS related tasks - zc *zeroconf.Server - - // The alternative avahi mDNS service - av *avahi.Server - avEntryGroup *avahi.EntryGroup - - mux sync.Mutex -} - -func newMDNS(ski string, configuration *Configuration) *mdns { - m := &mdns{ - ski: ski, - configuration: configuration, - entries: make(map[string]MdnsEntry), - cancelChan: make(chan bool), - } - - return m -} - -var _ MdnsService = (*mdns)(nil) - -func (m *mdns) SetupMdnsService() error { - - if av, err := m.setupAvahi(); err == nil { - m.av = av - } - - // on startup always start mDNS announcement - if err := m.AnnounceMdnsEntry(); err != nil { - return err - } - - // catch signals - go func() { - signalC := make(chan os.Signal, 1) - signal.Notify(signalC, os.Interrupt, syscall.SIGTERM) - - <-signalC // wait for signal - - m.UnannounceMdnsEntry() - }() - - return nil -} - -// setup avahi for mDNS -func (m *mdns) setupAvahi() (*avahi.Server, error) { - dbusConn, err := dbus.SystemBus() - if err != nil { - return nil, err - } - - avahiServer, err := avahi.ServerNew(dbusConn) - if err != nil { - return nil, err - } - - if _, err := avahiServer.GetAPIVersion(); err != nil { - return nil, err - } - - return avahiServer, nil -} - -// Return allowed interfaces for mDNS -func (m *mdns) interfaces() ([]net.Interface, []int32, error) { - var ifaces []net.Interface - var ifaceIndexes []int32 - - if len(m.configuration.interfaces) > 0 { - ifaces = make([]net.Interface, len(m.configuration.interfaces)) - ifaceIndexes = make([]int32, len(m.configuration.interfaces)) - for i, ifaceName := range m.configuration.interfaces { - iface, err := net.InterfaceByName(ifaceName) - if err != nil { - return nil, nil, err - } - ifaces[i] = *iface - ifaceIndexes[i] = int32(iface.Index) - } - } - - if len(ifaces) == 0 { - ifaces = nil - ifaceIndexes = []int32{avahi.InterfaceUnspec} - } - - return ifaces, ifaceIndexes, nil -} - -// Announces the service to the network via mDNS -// A CEM service should always invoke this on startup -// Any other service should only invoke this whenever it is not connected to a CEM service -func (m *mdns) AnnounceMdnsEntry() error { - if m.isAnnounced { - return nil - } - - ifaces, ifaceIndexes, err := m.interfaces() - if err != nil { - return err - } - - serviceIdentifier := m.configuration.Identifier() - - txt := []string{ // SHIP 7.3.2 - "txtvers=1", - "path=" + shipWebsocketPath, - "id=" + serviceIdentifier, - "ski=" + m.ski, - "brand=" + m.configuration.deviceBrand, - "model=" + m.configuration.deviceModel, - "type=" + string(m.configuration.deviceType), - "register=" + fmt.Sprintf("%v", m.configuration.registerAutoAccept), - } - - logging.Log.Debug("mdns: announce") - - serviceName := m.configuration.MdnsServiceName() - - if m.av == nil { - logging.Log.Debug("mdns: using zeroconf") - // use Zeroconf library if avahi is not available - mDNSServer, err := zeroconf.Register(serviceName, shipZeroConfServiceType, shipZeroConfDomain, m.configuration.port, txt, ifaces) - if err == nil { - m.zc = mDNSServer - - m.isAnnounced = true - return nil - } - - return err - } - - // avahi - logging.Log.Debug("mdns: using avahi") - - entryGroup, err := m.av.EntryGroupNew() - if err != nil { - return err - } - - var btxt [][]byte - for _, t := range txt { - btxt = append(btxt, []byte(t)) - } - - for _, iface := range ifaceIndexes { - err = entryGroup.AddService(iface, avahi.ProtoUnspec, 0, serviceName, shipZeroConfServiceType, shipZeroConfDomain, "", uint16(m.configuration.port), btxt) - if err != nil { - return err - } - } - - err = entryGroup.Commit() - if err != nil { - return err - } - - m.avEntryGroup = entryGroup - m.isAnnounced = true - - return nil -} - -// Stop the mDNS announcement on the network -func (m *mdns) UnannounceMdnsEntry() { - if !m.isAnnounced { - return - } - - if m.zc != nil { - m.zc.Shutdown() - m.zc = nil - } - if m.av != nil { - m.av.EntryGroupFree(m.avEntryGroup) - m.avEntryGroup = nil - } - logging.Log.Debug("mdns: stop announcement") - - m.isAnnounced = false -} - -// Shutdown all of mDNS -func (m *mdns) ShutdownMdnsService() { - m.UnannounceMdnsEntry() - - if m.av != nil { - m.av.Close() - m.av = nil - } - - m.stopResolvingEntries() -} - -// Register a callback to be invoked for found mDNS entries -func (m *mdns) RegisterMdnsSearch(cb MdnsSearch) { - if m.searchDelegate != cb { - m.searchDelegate = cb - } - - m.mux.Lock() - - if !m.isSearchingServices { - m.isSearchingServices = true - m.mux.Unlock() - logging.Log.Debug("mdns: start search") - go m.resolveEntries() - return - } - - defer m.mux.Unlock() - - // do we already know some entries? - if len(m.entries) == 0 { - return - } - - // may this is already found - mdnsEntries := m.entries - - go m.searchDelegate.ReportMdnsEntries(mdnsEntries) -} - -// Remove a callback for found mDNS entries and stop searching if no callbacks are left -func (m *mdns) UnregisterMdnsSearch(cb MdnsSearch) { - m.mux.Lock() - defer m.mux.Unlock() - - m.searchDelegate = nil - - m.stopResolvingEntries() -} - -// search for mDNS entries and report them -// to be invoked in a background thread! -func (m *mdns) resolveEntries() { - // for Zeroconf we need a context - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - var err error - var avBrowser *avahi.ServiceBrowser - - zcEntries := make(chan *zeroconf.ServiceEntry) - defer close(zcEntries) - - if m.av != nil { - // instead of limiting search on specific allowed interfaces, we allow all and filter the results - if avBrowser, err = m.av.ServiceBrowserNew(avahi.InterfaceUnspec, avahi.ProtoUnspec, shipZeroConfServiceType, shipZeroConfDomain, 0); err != nil { - logging.Log.Debug("mdns: error setting up avahi browser:", err) - return - } - } else { - go func() { - _ = zeroconf.Browse(ctx, shipZeroConfServiceType, shipZeroConfDomain, zcEntries) - }() - } - - var end bool - for !end { - if m.av != nil { - select { - case <-m.cancelChan: - end = true - break - case service := <-avBrowser.AddChannel: - m.processAvahiService(service, false) - case service := <-avBrowser.RemoveChannel: - m.processAvahiService(service, true) - } - } else { - select { - case <-ctx.Done(): - end = true - break - case <-m.cancelChan: - ctx.Done() - case service := <-zcEntries: - // Zeroconf has issues with merging mDNS data and sometimes reports incomplete records - if len(service.Text) == 0 { - continue - } - - elements := m.parseTxt(service.Text) - - addresses := service.AddrIPv4 - // Only use IPv4 for now - // addresses = append(addresses, service.AddrIPv6...) - m.processMdnsEntry(elements, service.Instance, service.HostName, addresses, service.Port, false) - } - } - } - - if m.av != nil { - m.av.ServiceBrowserFree(avBrowser) - } - - m.mux.Lock() - m.isSearchingServices = false - m.mux.Unlock() -} - -// stop searching for mDNS entries -func (m *mdns) stopResolvingEntries() { - if m.cancelChan != nil { - if util.IsChannelClosed(m.cancelChan) { - return - } - - logging.Log.Debug("mdns: stop search") - - m.cancelChan <- true - } -} - -// process an avahi mDNS service -// as avahi returns a service per interface, we need to combine them -func (m *mdns) processAvahiService(service avahi.Service, remove bool) { - _, ifaceIndexes, err := m.interfaces() - if err != nil { - logging.Log.Debug("avahi - error getting interfaces:", err) - return - } - - // check if the service is within the allowed list - allow := false - if len(ifaceIndexes) == 1 && ifaceIndexes[0] == avahi.InterfaceUnspec { - allow = true - } else { - for _, iface := range ifaceIndexes { - if service.Interface == iface { - allow = true - break - } - } - } - - if !allow { - logging.Log.Debug("avahi - ignoring service as its interface is not in the allowed list:", service.Name) - return - } - - resolved, err := m.av.ResolveService(service.Interface, service.Protocol, service.Name, service.Type, service.Domain, avahi.ProtoUnspec, 0) - if err != nil { - logging.Log.Debug("avahi - error resolving service:", err) - return - } - - // convert [][]byte to []string manually - var txt []string - for _, element := range resolved.Txt { - txt = append(txt, string(element)) - } - elements := m.parseTxt(txt) - - // convert address to net.IP - address := net.ParseIP(resolved.Address) - // if the address can not be used, ignore the entry - if address == nil || address.IsUnspecified() { - logging.Log.Debug("avahi - service provides unusable address:", service.Name) - return - } - - // Ignore IPv6 addresses for now - if address.To4() == nil { - return - } - - m.processMdnsEntry(elements, resolved.Name, resolved.Host, []net.IP{address}, int(resolved.Port), remove) -} - -// parse mDNS text fields -func (m *mdns) parseTxt(txt []string) map[string]string { - result := make(map[string]string) - - for _, item := range txt { - s := strings.Split(item, "=") - if len(s) != 2 { - continue - } - result[s[0]] = s[1] - } - - return result -} - -// process an mDNS entry and manage mDNS entries map -func (m *mdns) processMdnsEntry(elements map[string]string, name, host string, addresses []net.IP, port int, remove bool) { - // check for mandatory text elements - mapItems := []string{"txtvers", "id", "path", "ski", "register"} - for _, item := range mapItems { - if _, ok := elements[item]; !ok { - return - } - } - - txtvers := elements["txtvers"] - // value of mandatory txtvers has to be 1 or the response be ignored: SHIP 7.3.2 - if txtvers != "1" { - return - } - - identifier := elements["id"] - path := elements["path"] - ski := elements["ski"] - - // ignore own service - if ski == m.ski { - return - } - - register := elements["register"] - // register has to be a boolean - if register != "true" && register != "false" { - return - } - - var deviceType, model, brand string - - if _, ok := elements["brand"]; ok { - brand = elements["brand"] - } - if _, ok := elements["type"]; ok { - deviceType = elements["type"] - } - if _, ok := elements["model"]; ok { - model = elements["model"] - } - - m.mux.Lock() - defer m.mux.Unlock() - - _, exists := m.entries[ski] - - if remove && exists { - // remove - // there will be a remove for each address with avahi, but we'll delete it right away - delete(m.entries, ski) - } else if exists { - // update - // avahi sends an item for each network address, merge them - entry := m.entries[ski] - - // we assume only network addresses are added - entry.Addresses = append(entry.Addresses, addresses...) - - m.entries[ski] = entry - } else if !exists && !remove { - // new - newEntry := MdnsEntry{ - Name: name, - Identifier: identifier, - Path: path, - Register: register == "true", - Brand: brand, - Type: deviceType, - Model: model, - Host: host, - Port: port, - Addresses: addresses, - } - m.entries[ski] = newEntry - - logging.Log.Debug("ski:", ski, "name:", name, "brand:", brand, "model:", model, "typ:", deviceType, "identifier:", identifier, "register:", register, "host:", host, "port:", port, "addresses:", addresses) - } else { - return - } - - if m.searchDelegate != nil { - mdnsEntries := m.entries - go m.searchDelegate.ReportMdnsEntries(mdnsEntries) - } -} diff --git a/service/service.go b/service/service.go index 4dc4914d..e700b3ae 100644 --- a/service/service.go +++ b/service/service.go @@ -2,97 +2,69 @@ package service import ( "crypto/x509" + "errors" "fmt" "sync" - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" + "github.com/enbility/eebus-go/api" + shipapi "github.com/enbility/ship-go/api" + "github.com/enbility/ship-go/cert" + "github.com/enbility/ship-go/hub" + "github.com/enbility/ship-go/logging" + "github.com/enbility/ship-go/mdns" + spineapi "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" ) -// interface for receiving data for specific events -type EEBUSServiceHandler interface { - // RemoteServicesListUpdated(services []ServiceDetails) - - // report a connection to a SKI - RemoteSKIConnected(service *EEBUSService, ski string) - - // report a disconnection to a SKI - RemoteSKIDisconnected(service *EEBUSService, ski string) - - // Provides the SHIP ID the remote service reported during the handshake process - // This needs to be persisted and passed on for future remote service connections - // when using `PairRemoteService` - ReportServiceShipID(ski string, shipdID string) -} - // A service is the central element of an EEBUS service // including its websocket server and a zeroconf service. -type EEBUSService struct { - Configuration *Configuration +type Service struct { + configuration *api.Configuration // The local service details - LocalService *ServiceDetails + localService *shipapi.ServiceDetails // Connection Registrations - connectionsHub *connectionsHub + connectionsHub shipapi.HubInterface // The SPINE specific device definition - spineLocalDevice *spine.DeviceLocalImpl + spineLocalDevice spineapi.DeviceLocalInterface - serviceHandler EEBUSServiceHandler + serviceHandler api.ServiceReaderInterface + + // defines wether a user interaction to accept pairing is possible + isPairingPossible bool startOnce sync.Once + + mux sync.Mutex } // creates a new EEBUS service -func NewEEBUSService(configuration *Configuration, serviceHandler EEBUSServiceHandler) *EEBUSService { - return &EEBUSService{ - Configuration: configuration, +func NewService(configuration *api.Configuration, serviceHandler api.ServiceReaderInterface) *Service { + return &Service{ + configuration: configuration, serviceHandler: serviceHandler, } } -var _ serviceProvider = (*EEBUSService)(nil) - -// report a connection to a SKI -func (s *EEBUSService) RemoteSKIConnected(ski string) { - s.serviceHandler.RemoteSKIConnected(s, ski) -} - -// report a disconnection to a SKI -func (s *EEBUSService) RemoteSKIDisconnected(ski string) { - s.serviceHandler.RemoteSKIDisconnected(s, ski) -} - -// Provides the SHIP ID the remote service reported during the handshake process -func (s *EEBUSService) ReportServiceShipID(ski string, shipdID string) { - s.serviceHandler.ReportServiceShipID(ski, shipdID) -} - -// Sets a custom logging implementation -// By default NoLogging is used, so no logs are printed -func (s *EEBUSService) SetLogging(logger logging.Logging) { - if logger == nil { - return - } - logging.Log = logger -} +var _ api.ServiceInterface = (*Service)(nil) // Starts the service by initializeing mDNS and the server. -func (s *EEBUSService) Setup() error { - if s.Configuration.port == 0 { - s.Configuration.port = defaultPort - } +func (s *Service) Setup() error { + sd := s.configuration - sd := s.Configuration + if len(sd.Certificate().Certificate) == 0 { + return errors.New("missing certificate") + } - leaf, err := x509.ParseCertificate(sd.certificate.Certificate[0]) + leaf, err := x509.ParseCertificate(sd.Certificate().Certificate[0]) if err != nil { return err } - ski, err := skiFromCertificate(leaf) + ski, err := cert.SkiFromCertificate(leaf) if err != nil { return err } @@ -105,131 +77,149 @@ func (s *EEBUSService) Setup() error { // The originator's unique ID // I assume those two to mean the same. // TODO: clarify - s.LocalService = NewServiceDetails(ski) - s.LocalService.SetShipID(sd.Identifier()) - s.LocalService.SetDeviceType(sd.deviceType) - s.LocalService.SetRegisterAutoAccept(sd.registerAutoAccept) + s.localService = shipapi.NewServiceDetails(ski) + s.localService.SetShipID(sd.Identifier()) + s.localService.SetDeviceType(string(sd.DeviceType())) - logging.Log.Info("Local SKI: ", ski) + logging.Log().Info("Local SKI: ", ski) - vendor := sd.vendorCode + vendor := sd.VendorCode() if vendor == "" { - vendor = sd.deviceBrand + vendor = sd.DeviceBrand() } - serial := sd.deviceSerialNumber + serial := sd.DeviceSerialNumber() if serial != "" { serial = fmt.Sprintf("-%s", serial) } // Create the SPINE device address, according to Protocol Specification 7.1.1.2 - deviceAdress := fmt.Sprintf("d:_i:%s_%s%s", vendor, sd.deviceModel, serial) + deviceAdress := fmt.Sprintf("d:_i:%s_%s%s", vendor, sd.DeviceModel(), serial) // Create the local SPINE device - s.spineLocalDevice = spine.NewDeviceLocalImpl( - sd.deviceBrand, - sd.deviceModel, - sd.deviceSerialNumber, + s.spineLocalDevice = spine.NewDeviceLocal( + sd.DeviceBrand(), + sd.DeviceModel(), + sd.DeviceSerialNumber(), sd.Identifier(), deviceAdress, - sd.deviceType, - sd.featureSet, + sd.DeviceType(), + sd.FeatureSet(), + sd.HeartbeatTimeout(), ) - // Create the device entity and add it to the SPINE device - entityAddress := []model.AddressEntityType{1} - var entityType model.EntityTypeType - switch sd.deviceType { - case model.DeviceTypeTypeEnergyManagementSystem: - entityType = model.EntityTypeTypeCEM - case model.DeviceTypeTypeChargingStation: - entityType = model.EntityTypeTypeEVSE - default: - logging.Log.Errorf("Unknown device type: %s", sd.deviceType) + // Create the device entities and add it to the SPINE device + for _, entityType := range sd.EntityTypes() { + entityAddressId := model.AddressEntityType(len(s.spineLocalDevice.Entities())) + entityAddress := []model.AddressEntityType{entityAddressId} + entity := spine.NewEntityLocal(s.spineLocalDevice, entityType, entityAddress) + s.spineLocalDevice.AddEntity(entity) } - entity := spine.NewEntityLocalImpl(s.spineLocalDevice, entityType, entityAddress) - s.spineLocalDevice.AddEntity(entity) // setup mDNS - mdns := newMDNS(s.LocalService.SKI(), s.Configuration) + mdns := mdns.NewMDNS( + s.localService.SKI(), + sd.DeviceBrand(), + sd.DeviceModel(), + string(sd.DeviceType()), + sd.Identifier(), + sd.MdnsServiceName(), + sd.Port(), + sd.Interfaces(), + sd.MdnsProviderSelection(), + ) // Setup connections hub with mDNS and websocket connection handling - s.connectionsHub = newConnectionsHub(s, mdns, s.spineLocalDevice, s.Configuration, s.LocalService) + s.connectionsHub = hub.NewHub(s, mdns, s.configuration.Port(), s.configuration.Certificate(), s.localService) return nil } // Starts the service -func (s *EEBUSService) Start() { +func (s *Service) Start() { s.startOnce.Do(func() { - s.connectionsHub.start() + s.connectionsHub.Start() }) } // Shutdown all services and stop the server. -func (s *EEBUSService) Shutdown() { +func (s *Service) Shutdown() { // Shut down all running connections - s.connectionsHub.shutdown() + s.connectionsHub.Shutdown() } -func (s *EEBUSService) LocalDevice() *spine.DeviceLocalImpl { - return s.spineLocalDevice +func (s *Service) Configuration() *api.Configuration { + return s.configuration } -// return the local entity 1 -func (s *EEBUSService) LocalEntity() *spine.EntityLocalImpl { - return s.spineLocalDevice.Entity([]model.AddressEntityType{1}) +func (s *Service) LocalService() *shipapi.ServiceDetails { + return s.localService } -// Add a new entity, used for connected EVs -// Only for EVSE implementations -func (s *EEBUSService) AddEntity(entity *spine.EntityLocalImpl) { - s.spineLocalDevice.AddEntity(entity) +func (s *Service) LocalDevice() spineapi.DeviceLocalInterface { + return s.spineLocalDevice } -// Remove an entity, used for disconnected EVs -// Only for EVSE implementations -func (s *EEBUSService) RemoveEntity(entity *spine.EntityLocalImpl) { - s.spineLocalDevice.RemoveEntity(entity) +// Sets a custom logging implementation +// By default NoLogging is used, so no logs are printed +func (s *Service) SetLogging(logger logging.LoggingInterface) { + if logger == nil { + return + } + logging.SetLogging(logger) } -// return all remote devices -func (s *EEBUSService) RemoteDevices() []*spine.DeviceRemoteImpl { - return s.spineLocalDevice.RemoteDevices() +// Get the current pairing details for a given SKI +func (s *Service) PairingDetailForSki(ski string) *shipapi.ConnectionStateDetail { + return s.connectionsHub.PairingDetailForSki(ski) } -func (s *EEBUSService) RemoteDeviceForSki(ski string) *spine.DeviceRemoteImpl { - return s.spineLocalDevice.RemoteDeviceForSki(ski) +// Returns the Service detail of a given remote SKI +func (s *Service) RemoteServiceForSKI(ski string) *shipapi.ServiceDetails { + return s.connectionsHub.ServiceForSKI(ski) } -// return a specific remote device of a given DeviceType -func (s *EEBUSService) RemoteDeviceOfType(deviceType model.DeviceTypeType) *spine.DeviceRemoteImpl { - for _, device := range s.spineLocalDevice.RemoteDevices() { - if *device.DeviceType() == deviceType { - return device - } - } - return nil +func (s *Service) SetAutoAccept(value bool) { + s.localService.SetAutoAccept(value) + s.connectionsHub.SetAutoAccept(value) } -// Adds a new device to the list of known devices which can be connected to -// and connect it if it is currently not connected -func (s *EEBUSService) PairRemoteService(service *ServiceDetails) { - s.connectionsHub.PairRemoteService(service) +func (s *Service) IsAutoAcceptEnabled() bool { + return s.localService.AutoAccept() } -// Returns if the provided SKI is from a registered service -func (s *EEBUSService) IsRemoteServiceForSKIPaired(ski string) bool { - return s.connectionsHub.IsRemoteServiceForSKIPaired(ski) +// Sets the SKI as being paired +// and connect it if paired and not currently being connected +func (s *Service) RegisterRemoteSKI(ski string) { + s.connectionsHub.RegisterRemoteSKI(ski) } -// Remove a device from the list of known devices which can be connected to -// and disconnect it if it is currently connected -func (s *EEBUSService) UnpairRemoteService(ski string) error { - return s.connectionsHub.UnpairRemoteService(ski) +// Sets the SKI as not being paired +// and disconnects it if connected +func (s *Service) UnregisterRemoteSKI(ski string) { + s.connectionsHub.UnregisterRemoteSKI(ski) } // Close a connection to a remote SKI -func (s *EEBUSService) DisconnectSKI(ski string, reason string) { +func (s *Service) DisconnectSKI(ski string, reason string) { s.connectionsHub.DisconnectSKI(ski, reason) } + +// Cancels the pairing process for a SKI +func (s *Service) CancelPairingWithSKI(ski string) { + s.connectionsHub.CancelPairingWithSKI(ski) +} + +// Define wether the user is able to react to an incoming pairing request +// +// Call this with `true` e.g. if the user is currently using a web interface +// where an incoming request can be accepted or denied +// +// Default is set to false, meaning every incoming pairing request will be +// automatically denied +func (s *Service) UserIsAbleToApproveOrCancelPairingRequests(allow bool) { + s.mux.Lock() + defer s.mux.Unlock() + + s.isPairingPossible = allow +} diff --git a/service/service_hub.go b/service/service_hub.go new file mode 100644 index 00000000..27230d75 --- /dev/null +++ b/service/service_hub.go @@ -0,0 +1,53 @@ +package service + +import ( + shipapi "github.com/enbility/ship-go/api" +) + +var _ shipapi.HubReaderInterface = (*Service)(nil) + +// report a connection to a SKI +func (s *Service) RemoteSKIConnected(ski string) { + s.serviceHandler.RemoteSKIConnected(s, ski) +} + +// report a disconnection to a SKI +func (s *Service) RemoteSKIDisconnected(ski string) { + if s.spineLocalDevice != nil { + s.spineLocalDevice.RemoveRemoteDeviceConnection(ski) + } + + s.serviceHandler.RemoteSKIDisconnected(s, ski) +} + +// report an approved handshake by a remote device +func (s *Service) SetupRemoteDevice(ski string, writeI shipapi.ShipConnectionDataWriterInterface) shipapi.ShipConnectionDataReaderInterface { + return s.LocalDevice().SetupRemoteDevice(ski, writeI) +} + +// report all currently visible EEBUS services +func (s *Service) VisibleRemoteServicesUpdated(entries []shipapi.RemoteService) { + s.serviceHandler.VisibleRemoteServicesUpdated(s, entries) +} + +// Provides the SHIP ID the remote service reported during the handshake process +// This needs to be persisted and passed on for future remote service connections +// when using `PairRemoteService` +func (s *Service) ServiceShipIDUpdate(ski string, shipdID string) { + s.serviceHandler.ServiceShipIDUpdate(ski, shipdID) +} + +// Provides the current pairing state for the remote service +// This is called whenever the state changes and can be used to +// provide user information for the pairing/connection process +func (s *Service) ServicePairingDetailUpdate(ski string, detail *shipapi.ConnectionStateDetail) { + s.serviceHandler.ServicePairingDetailUpdate(ski, detail) +} + +// return if the user is still able to trust the connection +func (s *Service) AllowWaitingForTrust(ski string) bool { + s.mux.Lock() + defer s.mux.Unlock() + + return s.isPairingPossible +} diff --git a/service/service_test.go b/service/service_test.go new file mode 100644 index 00000000..dbccf1ce --- /dev/null +++ b/service/service_test.go @@ -0,0 +1,164 @@ +package service + +import ( + "crypto/tls" + "testing" + "time" + + "github.com/enbility/eebus-go/api" + "github.com/enbility/eebus-go/mocks" + shipapi "github.com/enbility/ship-go/api" + "github.com/enbility/ship-go/cert" + "github.com/enbility/ship-go/logging" + shipmocks "github.com/enbility/ship-go/mocks" + spinemocks "github.com/enbility/spine-go/mocks" + "github.com/enbility/spine-go/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" +) + +func TestServiceSuite(t *testing.T) { + suite.Run(t, new(ServiceSuite)) +} + +type ServiceSuite struct { + suite.Suite + + config *api.Configuration + + sut *Service + + serviceReader *mocks.ServiceReaderInterface + conHub *shipmocks.HubInterface + logging *shipmocks.LoggingInterface + localDevice *spinemocks.DeviceLocalInterface +} + +func (s *ServiceSuite) WriteShipMessageWithPayload(message []byte) {} + +func (s *ServiceSuite) BeforeTest(suiteName, testName string) { + s.serviceReader = mocks.NewServiceReaderInterface(s.T()) + + s.conHub = shipmocks.NewHubInterface(s.T()) + + s.logging = shipmocks.NewLoggingInterface(s.T()) + + s.localDevice = spinemocks.NewDeviceLocalInterface(s.T()) + + certificate := tls.Certificate{} + var err error + s.config, err = api.NewConfiguration( + "vendor", "brand", "model", "serial", model.DeviceTypeTypeEnergyManagementSystem, + []model.EntityTypeType{model.EntityTypeTypeCEM}, 4729, certificate, 230.0, time.Second*4) + assert.Nil(s.T(), nil, err) + + s.sut = NewService(s.config, s.serviceReader) +} + +func (s *ServiceSuite) Test_EEBUSHandler() { + testSki := "test" + + s.sut.spineLocalDevice = s.localDevice + + entry := shipapi.RemoteService{ + Ski: testSki, + } + + entries := []shipapi.RemoteService{entry} + s.serviceReader.EXPECT().VisibleRemoteServicesUpdated(mock.Anything, mock.Anything).Return() + s.sut.VisibleRemoteServicesUpdated(entries) + + s.serviceReader.EXPECT().RemoteSKIConnected(mock.Anything, mock.Anything).Return() + s.sut.RemoteSKIConnected(testSki) + + s.serviceReader.EXPECT().RemoteSKIDisconnected(mock.Anything, mock.Anything).Return() + s.localDevice.EXPECT().RemoveRemoteDeviceConnection(testSki).Return() + s.sut.RemoteSKIDisconnected(testSki) + + s.serviceReader.EXPECT().ServiceShipIDUpdate(mock.Anything, mock.Anything).Return() + s.sut.ServiceShipIDUpdate(testSki, "shipid") + + s.serviceReader.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return() + detail := &shipapi.ConnectionStateDetail{} + s.sut.ServicePairingDetailUpdate(testSki, detail) + + s.sut.UserIsAbleToApproveOrCancelPairingRequests(true) + result := s.sut.AllowWaitingForTrust(testSki) + assert.Equal(s.T(), true, result) + + conf := s.sut.Configuration() + assert.Equal(s.T(), s.sut.configuration, conf) + + lService := s.sut.LocalService() + assert.Equal(s.T(), s.sut.localService, lService) +} + +func (s *ServiceSuite) Test_ConnectionsHub() { + testSki := "test" + + s.sut.connectionsHub = s.conHub + s.sut.spineLocalDevice = s.localDevice + s.sut.localService = shipapi.NewServiceDetails(testSki) + + s.conHub.EXPECT().PairingDetailForSki(mock.Anything).Return(nil) + s.sut.PairingDetailForSki(testSki) + + s.conHub.EXPECT().ServiceForSKI(mock.Anything).Return(nil) + details := s.sut.RemoteServiceForSKI(testSki) + assert.Nil(s.T(), details) + + s.localDevice.EXPECT().SetupRemoteDevice(mock.Anything, s).Return(nil) + s.sut.SetupRemoteDevice(testSki, s) + + s.conHub.EXPECT().SetAutoAccept(mock.Anything).Return() + s.sut.SetAutoAccept(true) + assert.True(s.T(), s.sut.IsAutoAcceptEnabled()) + + s.conHub.EXPECT().RegisterRemoteSKI(mock.Anything).Return() + s.sut.RegisterRemoteSKI(testSki) + + s.conHub.EXPECT().UnregisterRemoteSKI(mock.Anything).Return() + s.sut.UnregisterRemoteSKI(testSki) + + s.conHub.EXPECT().CancelPairingWithSKI(mock.Anything).Return() + s.sut.CancelPairingWithSKI(testSki) + + s.conHub.EXPECT().DisconnectSKI(mock.Anything, mock.Anything).Return() + s.sut.DisconnectSKI(testSki, "reason") +} + +func (s *ServiceSuite) Test_SetLogging() { + s.sut.SetLogging(nil) + assert.Equal(s.T(), &logging.NoLogging{}, logging.Log()) + + s.sut.SetLogging(s.logging) + assert.Equal(s.T(), s.logging, logging.Log()) + + s.sut.SetLogging(&logging.NoLogging{}) + assert.Equal(s.T(), &logging.NoLogging{}, logging.Log()) +} + +func (s *ServiceSuite) Test_Setup() { + err := s.sut.Setup() + assert.NotNil(s.T(), err) + + certificate, err := cert.CreateCertificate("unit", "org", "de", "cn") + assert.Nil(s.T(), err) + s.config.SetCertificate(certificate) + + err = s.sut.Setup() + assert.Nil(s.T(), err) + + s.sut.connectionsHub = s.conHub + s.conHub.EXPECT().Start() + s.sut.Start() + + time.Sleep(time.Millisecond * 200) + + s.conHub.EXPECT().Shutdown() + s.sut.Shutdown() + + device := s.sut.LocalDevice() + assert.NotNil(s.T(), device) +} diff --git a/ship/connection.go b/ship/connection.go deleted file mode 100644 index af82b42f..00000000 --- a/ship/connection.go +++ /dev/null @@ -1,322 +0,0 @@ -package ship - -import ( - "bytes" - "encoding/json" - "errors" - "strings" - "sync" - "time" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/ship/model" - shipUtil "github.com/enbility/eebus-go/ship/util" - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/util" -) - -// implemented by connectionsHub and used by shipConnection -type ConnectionHandler interface { - HandleClosedConnection(connection *ShipConnection) -} - -// A ShipConnection handles the data connection and coordinates SHIP and SPINE messages i/o -type ShipConnection struct { - // The ship connection mode of this connection - role shipRole - - // The remote SKI - RemoteSKI string - - // the remote SHIP Id - remoteShipID string - - // The local SHIP ID - localShipID string - - // data provider - serviceDataProvider ShipServiceDataProvider - - // Where to pass incoming SPINE messages to - spineDataProcessing spine.SpineDataProcessing - - // the handler for sending messages on the data connection - DataHandler ShipDataConnection - - // The current SHIP state - smeState shipMessageExchangeState - - // handles timeouts for the various states - // - // WaitForReady SHIP 13.4.4.1.3: The communication partner must send its "READY" state (or request for prolongation") before the timer expires. - // - // SendProlongationRequest SHIP 13.4.4.1.3: Local timer to request for prolongation at the communication partner in time (i.e. before the communication partner's Wait-For-Ready-Timer expires). - // - // ProlongationRequestReply SHIP 13.4.4.1.3: Detection of response timeout on prolongation request. - handshakeTimerRunning bool - handshakeTimerType timeoutTimerType - handshakeTimerStopChan chan struct{} - handshakeTimerMux sync.Mutex - - lastReceivedWaitingValue time.Duration // required for Prolong-Request-Reply-Timer - - // the SPINE local device - deviceLocalCon spine.DeviceLocalConnection - - shutdownOnce sync.Once - - mux sync.Mutex -} - -func NewConnectionHandler(dataProvider ShipServiceDataProvider, dataHandler ShipDataConnection, deviceLocalCon spine.DeviceLocalConnection, role shipRole, localShipID, remoteSki, remoteShipId string) *ShipConnection { - ship := &ShipConnection{ - serviceDataProvider: dataProvider, - deviceLocalCon: deviceLocalCon, - role: role, - localShipID: localShipID, - RemoteSKI: remoteSki, - remoteShipID: remoteShipId, - DataHandler: dataHandler, - smeState: cmiStateInitStart, - } - - ship.handshakeTimerStopChan = make(chan struct{}) - - dataHandler.InitDataProcessing(ship) - - return ship -} - -// start SHIP communication -func (c *ShipConnection) Run() { - c.handleShipMessage(false, nil) -} - -// report removing a connection -func (c *ShipConnection) removeRemoteDeviceConnection() { - c.deviceLocalCon.RemoveRemoteDeviceConnection(c.RemoteSKI) -} - -// close this ship connection -func (c *ShipConnection) CloseConnection(safe bool, reason string) { - c.shutdownOnce.Do(func() { - c.stopHandshakeTimer() - - c.removeRemoteDeviceConnection() - - if safe && c.smeState > cmiStateInitStart { - // SHIP 13.4.7: Connection Termination Announce - closeMessage := model.ConnectionClose{ - ConnectionClose: model.ConnectionCloseType{ - Phase: model.ConnectionClosePhaseTypeAnnounce, - Reason: util.Ptr(model.ConnectionCloseReasonType(reason)), - }, - } - - _ = c.sendShipModel(model.MsgTypeEnd, closeMessage) - - if c.smeState != smeError { - return - } - } - - c.DataHandler.CloseDataConnection() - c.serviceDataProvider.HandleConnectionClosed(c, c.smeState == smeComplete) - }) -} - -var _ spine.SpineDataConnection = (*ShipConnection)(nil) - -// SpineDataConnection interface implementation -func (c *ShipConnection) WriteSpineMessage(message []byte) { - if err := c.sendSpineData(message); err != nil { - logging.Log.Debug(c.RemoteSKI, "Error sending spine message: ", err) - return - } -} - -var _ ShipDataProcessing = (*ShipConnection)(nil) - -func (c *ShipConnection) shipModelFromMessage(message []byte) (*model.ShipData, error) { - _, jsonData := c.parseMessage(message, true) - - // Get the datagram from the message - data := model.ShipData{} - if err := json.Unmarshal(jsonData, &data); err != nil { - logging.Log.Debug(c.RemoteSKI, "error unmarshalling message: ", err) - return nil, err - } - - if data.Data.Payload == nil { - errorMsg := "received no valid payload" - logging.Log.Debug(c.RemoteSKI, errorMsg) - return nil, errors.New(errorMsg) - } - - return &data, nil -} - -// route the incoming message to either SHIP or SPINE message handlers -func (c *ShipConnection) HandleIncomingShipMessage(message []byte) { - // Check if this is a SHIP SME or SPINE message - if !c.hasSpineDatagram(message) { - c.handleShipMessage(false, message) - return - } - - data, err := c.shipModelFromMessage(message) - if err != nil { - return - } - - if c.spineDataProcessing == nil { - return - } - - // pass the payload to the SPINE read handler - _, _ = c.spineDataProcessing.HandleIncomingSpineMesssage([]byte(data.Data.Payload)) -} - -// checks wether the provided messages is a SHIP message -func (c *ShipConnection) hasSpineDatagram(message []byte) bool { - return bytes.Contains(message, []byte("datagram")) -} - -// the websocket data connection was closed from remote -func (c *ShipConnection) ReportConnectionError(err error) { - c.CloseConnection(false, "") -} - -const payloadPlaceholder = `{"place":"holder"}` - -func (c *ShipConnection) transformSpineDataIntoShipJson(data []byte) ([]byte, error) { - spineMsg, err := shipUtil.JsonIntoEEBUSJson(data) - if err != nil { - return nil, err - } - - payload := json.RawMessage([]byte(spineMsg)) - - // Workaround for the fact that SHIP payload is a json.RawMessage - // which would also be transformed into an array element but it shouldn't - // hence patching the payload into the message later after the SHIP - // and SPINE model are transformed independently - - // Create the message - shipMessage := model.ShipData{ - Data: model.DataType{ - Header: model.HeaderType{ - ProtocolId: model.ShipProtocolId, - }, - Payload: json.RawMessage([]byte(payloadPlaceholder)), - }, - } - - msg, err := json.Marshal(shipMessage) - if err != nil { - return nil, err - } - - eebusMsg, err := shipUtil.JsonIntoEEBUSJson(msg) - if err != nil { - return nil, err - } - - eebusMsg = strings.ReplaceAll(eebusMsg, `[`+payloadPlaceholder+`]`, string(payload)) - - return []byte(eebusMsg), nil -} - -func (c *ShipConnection) sendSpineData(data []byte) error { - eebusMsg, err := c.transformSpineDataIntoShipJson(data) - if err != nil { - return err - } - - if c.DataHandler.IsDataConnectionClosed() { - c.CloseConnection(false, "") - return errors.New("connection is closed") - } - - // Wrap the message into a binary message with the ship header - shipMsg := []byte{model.MsgTypeData} - shipMsg = append(shipMsg, eebusMsg...) - - err = c.DataHandler.WriteMessageToDataConnection(shipMsg) - if err != nil { - logging.Log.Debug("error sending message: ", err) - return err - } - - return nil -} - -// send a json message for a provided model to the websocket connection -func (c *ShipConnection) sendShipModel(typ byte, model interface{}) error { - shipMsg, err := c.shipMessage(typ, model) - if err != nil { - return err - } - - err = c.DataHandler.WriteMessageToDataConnection(shipMsg) - if err != nil { - return err - } - - return nil -} - -// Process a SHIP Json message -func (c *ShipConnection) processShipJsonMessage(message []byte, target any) error { - _, data := c.parseMessage(message, true) - - return json.Unmarshal(data, &target) -} - -// transform a SHIP model into EEBUS specific JSON -func (c *ShipConnection) shipMessage(typ byte, model interface{}) ([]byte, error) { - if c.DataHandler.IsDataConnectionClosed() { - c.CloseConnection(false, "") - return nil, errors.New("connection is closed") - } - - if model == nil { - return nil, errors.New("invalid data") - } - - msg, err := json.Marshal(model) - if err != nil { - return nil, err - } - - eebusMsg, err := shipUtil.JsonIntoEEBUSJson(msg) - if err != nil { - return nil, err - } - - // Wrap the message into a binary message with the ship header - shipMsg := []byte{typ} - shipMsg = append(shipMsg, eebusMsg...) - - return shipMsg, nil -} - -// return the SHIP message type, the SHIP message and an error -// -// enable jsonFormat if the return message is expected to be encoded in the eebus json format -func (c *ShipConnection) parseMessage(msg []byte, jsonFormat bool) (byte, []byte) { - if len(msg) == 0 { - return 0, nil - } - - // Extract the SHIP header byte - shipHeaderByte := msg[0] - // remove the SHIP header byte from the message - msg = msg[1:] - - if jsonFormat { - return shipHeaderByte, shipUtil.JsonFromEEBUSJson(msg) - } - - return shipHeaderByte, msg -} diff --git a/ship/connection_test.go b/ship/connection_test.go deleted file mode 100644 index f6a706b6..00000000 --- a/ship/connection_test.go +++ /dev/null @@ -1,106 +0,0 @@ -package ship - -import ( - "encoding/json" - "testing" - - "github.com/enbility/eebus-go/ship/model" - "github.com/enbility/eebus-go/spine" - spineModel "github.com/enbility/eebus-go/spine/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestConnectionSuite(t *testing.T) { - suite.Run(t, new(ConnectionSuite)) -} - -type ConnectionSuite struct { - suite.Suite - - sut *ShipConnection - - sentMessage []byte -} - -var _ ConnectionHandler = (*ConnectionSuite)(nil) - -func (s *ConnectionSuite) HandleClosedConnection(connection *ShipConnection) {} - -var _ ShipServiceDataProvider = (*ConnectionSuite)(nil) - -func (s *ConnectionSuite) IsRemoteServiceForSKIPaired(string) bool { return true } -func (s *ConnectionSuite) HandleConnectionClosed(*ShipConnection, bool) {} -func (s *ConnectionSuite) ReportServiceShipID(string, string) {} - -var _ ShipDataConnection = (*ConnectionSuite)(nil) - -func (s *ConnectionSuite) InitDataProcessing(dataProcessing ShipDataProcessing) {} - -func (s *ConnectionSuite) WriteMessageToDataConnection(message []byte) error { - s.sentMessage = message - return nil -} - -func (s *ConnectionSuite) CloseDataConnection() {} -func (w *ConnectionSuite) IsDataConnectionClosed() bool { return false } - -func (s *ConnectionSuite) SetupSuite() {} -func (s *ConnectionSuite) TearDownTest() {} - -func (s *ConnectionSuite) BeforeTest(suiteName, testName string) { - s.sentMessage = nil - localDevice := spine.NewDeviceLocalImpl("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode", - "TestDeviceAddress", spineModel.DeviceTypeTypeEnergyManagementSystem, spineModel.NetworkManagementFeatureSetTypeSmart) - - s.sut = NewConnectionHandler(s, s, localDevice, ShipRoleServer, "LocalShipID", "RemoveDevice", "RemoteShipID") -} - -func (s *ConnectionSuite) TestSendShipModel() { - err := s.sut.sendShipModel(model.MsgTypeInit, nil) - assert.NotNil(s.T(), err) - - closeMessage := model.ConnectionClose{ - ConnectionClose: model.ConnectionCloseType{ - Phase: model.ConnectionClosePhaseTypeAnnounce, - }, - } - - err = s.sut.sendShipModel(model.MsgTypeControl, closeMessage) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), s.sentMessage) -} - -func (s *ConnectionSuite) TestProcessShipJsonMessage() { - closeMessage := model.ConnectionClose{ - ConnectionClose: model.ConnectionCloseType{ - Phase: model.ConnectionClosePhaseTypeAnnounce, - }, - } - msg, err := json.Marshal(closeMessage) - assert.Nil(s.T(), err) - - newMsg := []byte{model.MsgTypeControl} - newMsg = append(newMsg, msg...) - - var data any - err = s.sut.processShipJsonMessage(newMsg, &data) - assert.Nil(s.T(), err) -} - -func (s *ConnectionSuite) TestSendSpineMessage() { - data := spineModel.Datagram{ - Datagram: spineModel.DatagramType{ - Header: spineModel.HeaderType{}, - Payload: spineModel.PayloadType{ - Cmd: []spineModel.CmdType{}, - }, - }, - } - - msg, err := json.Marshal(data) - assert.Nil(s.T(), err) - - err = s.sut.sendSpineData(msg) - assert.Nil(s.T(), err) -} diff --git a/ship/handshake.go b/ship/handshake.go deleted file mode 100644 index 1ef1fd58..00000000 --- a/ship/handshake.go +++ /dev/null @@ -1,241 +0,0 @@ -package ship - -import ( - "errors" - "time" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/ship/model" -) - -// handle incoming SHIP messages and coordinate Handshake States -func (c *ShipConnection) handleShipMessage(timeout bool, message []byte) { - if len(message) > 2 { - var closeMsg model.ConnectionClose - err := c.processShipJsonMessage(message, &closeMsg) - if err == nil && closeMsg.ConnectionClose.Phase != "" { - switch closeMsg.ConnectionClose.Phase { - case model.ConnectionClosePhaseTypeAnnounce: - // SHIP 13.4.7: Connection Termination Confirm - closeMessage := model.ConnectionClose{ - ConnectionClose: model.ConnectionCloseType{ - Phase: model.ConnectionClosePhaseTypeConfirm, - }, - } - - _ = c.sendShipModel(model.MsgTypeEnd, closeMessage) - - // wait a bit to let it send - <-time.After(500 * time.Millisecond) - - // - c.DataHandler.CloseDataConnection() - c.serviceDataProvider.HandleConnectionClosed(c, c.smeState == smeComplete) - case model.ConnectionClosePhaseTypeConfirm: - // we got a confirmation so close this connection - c.DataHandler.CloseDataConnection() - c.serviceDataProvider.HandleConnectionClosed(c, c.smeState == smeComplete) - } - - return - } - } - - c.handleState(timeout, message) -} - -// set a new handshake state and handle timers if needed -func (c *ShipConnection) setState(newState shipMessageExchangeState) { - c.mux.Lock() - defer c.mux.Unlock() - - c.smeState = newState - - switch newState { - case smeHelloStateReadyInit: - c.setHandshakeTimer(timeoutTimerTypeWaitForReady, tHelloInit) - case smeHelloStatePendingInit: - c.setHandshakeTimer(timeoutTimerTypeWaitForReady, tHelloInit) - case smeHelloStateOk: - c.stopHandshakeTimer() - case smeHelloStateAbort: - c.stopHandshakeTimer() - case smeProtHStateClientListenChoice: - c.setHandshakeTimer(timeoutTimerTypeWaitForReady, cmiTimeout) - case smeProtHStateClientOk: - c.stopHandshakeTimer() - } -} - -func (c *ShipConnection) getState() shipMessageExchangeState { - c.mux.Lock() - defer c.mux.Unlock() - - return c.smeState -} - -// handle handshake state transitions -func (c *ShipConnection) handleState(timeout bool, message []byte) { - switch c.getState() { - case smeError: - logging.Log.Debug(c.RemoteSKI, "connection is in error state") - return - - // cmiStateInit - case cmiStateInitStart: - // triggered without a message received - c.handshakeInit_cmiStateInitStart() - - case cmiStateClientWait: - if timeout { - c.endHandshakeWithError(errors.New("ship client handshake timeout")) - return - } - - c.handshakeInit_cmiStateClientWait(message) - - case cmiStateServerWait: - if timeout { - c.endHandshakeWithError(errors.New("ship server handshake timeout")) - return - } - c.handshakeInit_cmiStateServerWait(message) - - // smeHello - - case smeHelloState: - // go into the 1st substate right away - c.setState(smeHelloStateReadyInit) - c.handleState(timeout, message) - - case smeHelloStateReadyInit: - c.handshakeHello_Init() - - case smeHelloStateReadyListen: - if timeout { - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - return - } - - c.handshakeHello_ReadyListen(message) - - case smeHelloStatePendingInit: - c.handshakeHello_PendingInit() - - case smeHelloStatePendingListen: - if timeout { - c.handshakeHello_PendingTimeout() - return - } - - c.handshakeHello_PendingListen(message) - - case smeHelloStateOk: - c.handshakeProtocol_Init() - - case smeHelloStateAbort: - c.handshakeHello_Abort() - - // smeProtocol - - case smeProtHStateServerListenProposal: - c.handshakeProtocol_smeProtHStateServerListenProposal(message) - - case smeProtHStateServerListenConfirm: - c.handshakeProtocol_smeProtHStateServerListenConfirm(message) - - case smeProtHStateClientListenChoice: - c.stopHandshakeTimer() - c.handshakeProtocol_smeProtHStateClientListenChoice(message) - - case smeProtHStateClientOk: - c.setState(smePinStateCheckInit) - c.handleState(false, nil) - - case smeProtHStateServerOk: - c.setState(smePinStateCheckInit) - c.handleState(false, nil) - - // smePinState - - case smePinStateCheckInit: - c.handshakePin_Init() - - case smePinStateCheckListen: - c.handshakePin_smePinStateCheckListen(message) - - case smePinStateCheckOk: - c.handshakeAccessMethods_Init() - - // smeAccessMethods - - case smeAccessMethodsRequest: - c.handshakeAccessMethods_Request(message) - } -} - -// SHIP handshake is approved, now set the new state and the SPINE read handler -func (c *ShipConnection) approveHandshake() { - // Report to SPINE local device about this remote device connection - c.spineDataProcessing = c.deviceLocalCon.AddRemoteDevice(c.RemoteSKI, c) - c.stopHandshakeTimer() - c.setState(smeComplete) -} - -// end the handshake process because of an error -func (c *ShipConnection) endHandshakeWithError(err error) { - c.stopHandshakeTimer() - - c.setState(smeError) - - logging.Log.Debug(c.RemoteSKI, "SHIP handshake error:", err) - - c.CloseConnection(true, err.Error()) -} - -// set the handshake timer to a new duration and start the channel -func (c *ShipConnection) setHandshakeTimer(timerType timeoutTimerType, duration time.Duration) { - c.stopHandshakeTimer() - - c.setHandshakeTimerRunning(true) - c.handshakeTimerType = timerType - - go func() { - select { - case <-c.handshakeTimerStopChan: - return - case <-time.After(duration): - c.setHandshakeTimerRunning(false) - c.handleState(true, nil) - return - } - }() -} - -// stop the handshake timer and close the channel -func (c *ShipConnection) stopHandshakeTimer() { - if !c.getHandshakeTimerRunnging() { - return - } - - select { - case c.handshakeTimerStopChan <- struct{}{}: - default: - } - c.setHandshakeTimerRunning(false) -} - -func (c *ShipConnection) setHandshakeTimerRunning(value bool) { - c.handshakeTimerMux.Lock() - defer c.handshakeTimerMux.Unlock() - - c.handshakeTimerRunning = value -} - -func (c *ShipConnection) getHandshakeTimerRunnging() bool { - c.handshakeTimerMux.Lock() - defer c.handshakeTimerMux.Unlock() - - return c.handshakeTimerRunning -} diff --git a/ship/hs_access.go b/ship/hs_access.go deleted file mode 100644 index 0f327b8c..00000000 --- a/ship/hs_access.go +++ /dev/null @@ -1,81 +0,0 @@ -package ship - -import ( - "encoding/json" - "errors" - "fmt" - "strings" - - "github.com/enbility/eebus-go/ship/model" -) - -// Handshake Access covers the states smeAccess... - -func (c *ShipConnection) handshakeAccessMethods_Init() { - // Access Methods - accessMethodsRequest := model.AccessMethodsRequest{ - AccessMethodsRequest: model.AccessMethodsRequestType{}, - } - - if err := c.sendShipModel(model.MsgTypeControl, accessMethodsRequest); err != nil { - c.endHandshakeWithError(err) - return - } - - c.setHandshakeTimer(timeoutTimerTypeWaitForReady, cmiTimeout) - c.setState(smeAccessMethodsRequest) -} - -func (c *ShipConnection) handshakeAccessMethods_Request(message []byte) { - _, data := c.parseMessage(message, true) - - dataString := string(data) - - if strings.Contains(dataString, "\"accessMethodsRequest\":{") { - methodsId := c.localShipID - - accessMethods := model.AccessMethods{ - AccessMethods: model.AccessMethodsType{ - Id: &methodsId, - }, - } - if err := c.sendShipModel(model.MsgTypeControl, accessMethods); err != nil { - c.endHandshakeWithError(err) - } - return - } else if strings.Contains(dataString, "\"accessMethods\":{") { - // compare SHIP ID to stored value on pairing. SKI + SHIP ID should be verified on connection - // otherwise close connection with error "close 4450: SHIP id mismatch" - - var accessMethods model.AccessMethods - if err := json.Unmarshal([]byte(data), &accessMethods); err != nil { - c.endHandshakeWithError(err) - return - } - - if accessMethods.AccessMethods.Id == nil { - c.endHandshakeWithError(errors.New("Access methods response does not contain SHIP ID")) - return - } - - // if the ID string is empty, then we don't know it yet and can't be verified - if len(c.remoteShipID) > 0 && c.remoteShipID != *accessMethods.AccessMethods.Id { - c.endHandshakeWithError(errors.New("SHIP id mismatch")) - return - } - - // save and report the SHIP ID - if len(c.remoteShipID) == 0 { - c.remoteShipID = *accessMethods.AccessMethods.Id - - c.serviceDataProvider.ReportServiceShipID(c.RemoteSKI, c.remoteShipID) - } - - } else { - c.endHandshakeWithError(fmt.Errorf("access methods: invalid response: %s", dataString)) - return - } - - c.setState(smeApproved) - c.approveHandshake() -} diff --git a/ship/hs_access_test.go b/ship/hs_access_test.go deleted file mode 100644 index 155569f6..00000000 --- a/ship/hs_access_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package ship - -import ( - "testing" - - "github.com/enbility/eebus-go/ship/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestAccessSuite(t *testing.T) { - suite.Run(t, new(AccessSuite)) -} - -type AccessSuite struct { - suite.Suite -} - -func (s *AccessSuite) Test_Init() { - sut, data := initTest(ShipRoleClient) - - sut.setState(smePinStateCheckOk) - sut.handleState(false, nil) - - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeAccessMethodsRequest, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *AccessSuite) Test_Request() { - sut, data := initTest(ShipRoleClient) - - sut.setState(smeAccessMethodsRequest) - - accessMsg := model.AccessMethodsRequest{ - AccessMethodsRequest: model.AccessMethodsRequestType{}, - } - msg, err := sut.shipMessage(model.MsgTypeControl, accessMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - assert.Equal(s.T(), false, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeAccessMethodsRequest, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *AccessSuite) Test_Methods_Ok() { - sut, data := initTest(ShipRoleClient) - - sut.setState(smeAccessMethodsRequest) - - accessMsg := model.AccessMethods{ - AccessMethods: model.AccessMethodsType{ - Id: util.Ptr("RemoteShipID"), - }, - } - msg, err := sut.shipMessage(model.MsgTypeControl, accessMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - assert.Equal(s.T(), false, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeComplete, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *AccessSuite) Test_Methods_WrongShipID() { - sut, data := initTest(ShipRoleClient) - - sut.setState(smeAccessMethodsRequest) - - accessMsg := model.AccessMethods{ - AccessMethods: model.AccessMethodsType{ - Id: util.Ptr("WrongRemoteShipID"), - }, - } - msg, err := sut.shipMessage(model.MsgTypeControl, accessMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - assert.Equal(s.T(), false, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeError, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} diff --git a/ship/hs_hello.go b/ship/hs_hello.go deleted file mode 100644 index 2f94895e..00000000 --- a/ship/hs_hello.go +++ /dev/null @@ -1,227 +0,0 @@ -package ship - -import ( - "time" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/ship/model" - "github.com/enbility/eebus-go/util" -) - -// Handshake Hello covers the states smeHello... - -// SME_HELLO_STATE_READY_INIT -func (c *ShipConnection) handshakeHello_Init() { - if err := c.handshakeHelloSend(model.ConnectionHelloPhaseTypeReady, tHelloInit, false); err != nil { - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - return - } - - c.setState(smeHelloStateReadyListen) -} - -// SME_HELLO_STATE_READY_LISTEN -func (c *ShipConnection) handshakeHello_ReadyListen(message []byte) { - var helloReturnMsg model.ConnectionHello - if err := c.processShipJsonMessage(message, &helloReturnMsg); err != nil { - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - return - } - - hello := helloReturnMsg.ConnectionHello - - switch hello.Phase { - case model.ConnectionHelloPhaseTypeReady: - // HELLO_OK - c.setState(smeHelloStateOk) - - case model.ConnectionHelloPhaseTypePending: - // the phase is still pending an no prolongationRequest is set, ignore the message - if hello.ProlongationRequest == nil { - return - } - - // if we got a prolongation request, accept it - if *hello.ProlongationRequest { - if err := c.handshakeHelloSend(model.ConnectionHelloPhaseTypePending, tHelloInit, false); err != nil { - c.endHandshakeWithError(err) - return - } - } - - case model.ConnectionHelloPhaseTypeAborted: - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - return - - default: - // don't accept any other responses - logging.Log.Errorf("Unexpected connection hello phase: %s", hello.Phase) - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - return - } - - c.handleState(false, nil) -} - -// SME_HELLO_ABORT -func (c *ShipConnection) handshakeHello_Abort() { - c.stopHandshakeTimer() - - if err := c.handshakeHelloSend(model.ConnectionHelloPhaseTypeAborted, 0, false); err != nil { - c.endHandshakeWithError(err) - return - } - - c.CloseConnection(false, "") -} - -// SME_HELLO_PENDING_INIT -// TODO: clarify in which scenario and how we need to support getting into this state -func (c *ShipConnection) handshakeHello_PendingInit() { - if err := c.handshakeHelloSend(model.ConnectionHelloPhaseTypePending, tHelloInit, false); err != nil { - c.endHandshakeWithError(err) - return - } - - c.setState(smeHelloStatePendingListen) -} - -// SME_HELLO_PENDING_LISTEN -func (c *ShipConnection) handshakeHello_PendingListen(message []byte) { - var helloReturnMsg model.ConnectionHello - if err := c.processShipJsonMessage(message, &helloReturnMsg); err != nil { - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - return - } - - hello := helloReturnMsg.ConnectionHello - - switch hello.Phase { - case model.ConnectionHelloPhaseTypeReady: - if hello.Waiting == nil { - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - return - } - - c.stopHandshakeTimer() - - newDuration := time.Duration(*hello.Waiting) * time.Millisecond - duration := tHelloProlongThrInc - if newDuration >= duration { - // the duration has to be reduced - duration = newDuration - duration - - // check if it is less than T_hello_prolong_min - if newDuration >= tHelloProlongMin { - c.setHandshakeTimer(timeoutTimerTypeSendProlongationRequest, duration) - return - } - } - - if newDuration < tHelloProlongMin { - // I interpret 13.4.4.1.3 Page 64 Line 1550-1553 as this resulting in a timeout state - // TODO: verify this - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - } - - case model.ConnectionHelloPhaseTypePending: - if hello.Waiting != nil && hello.ProlongationRequest == nil { - c.stopHandshakeTimer() - - newDuration := time.Duration(*hello.Waiting) * time.Millisecond - c.lastReceivedWaitingValue = newDuration - duration := tHelloProlongThrInc - if newDuration >= duration { - // the duration has to be reduced - duration = newDuration - duration - - // check if it is less than T_hello_prolong_min - if newDuration >= tHelloProlongMin { - c.setHandshakeTimer(timeoutTimerTypeSendProlongationRequest, duration) - return - } - } - - if newDuration < tHelloProlongMin { - // I interpret 13.4.4.1.3 Page 64 Line 1557-1560 as this resulting in a timeout state - // TODO: verify this - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - } - - return - } - - if hello.Waiting == nil && hello.ProlongationRequest != nil && *hello.ProlongationRequest { - // if we got a prolongation request, accept it - if err := c.handshakeHelloSend(model.ConnectionHelloPhaseTypePending, tHelloInit, false); err != nil { - c.endHandshakeWithError(err) - } - - return - } - - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - - case model.ConnectionHelloPhaseTypeAborted: - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - return - - default: - // don't accept any other responses - logging.Log.Errorf("Unexpected connection hello phase: %s", hello.Phase) - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - return - } - - c.handleState(false, nil) -} - -func (c *ShipConnection) handshakeHello_PendingTimeout() { - if c.handshakeTimerType != timeoutTimerTypeSendProlongationRequest { - c.setState(smeHelloStateAbort) - c.handleState(false, nil) - return - } - - if err := c.handshakeHelloSend(model.ConnectionHelloPhaseTypePending, 0, true); err != nil { - c.endHandshakeWithError(err) - return - } - - if c.lastReceivedWaitingValue == 0 { - newValue := float64(tHelloInit.Milliseconds()) * 1.1 - c.lastReceivedWaitingValue = time.Duration(newValue) - } - c.setHandshakeTimer(timeoutTimerTypeProlongRequestReply, c.lastReceivedWaitingValue) -} - -func (c *ShipConnection) handshakeHelloSend(phase model.ConnectionHelloPhaseType, waitingDuration time.Duration, prolongation bool) error { - helloMsg := model.ConnectionHello{ - ConnectionHello: model.ConnectionHelloType{ - Phase: phase, - }, - } - - if waitingDuration > 0 { - helloMsg.ConnectionHello.Waiting = util.Ptr(uint(waitingDuration.Milliseconds())) - } - if prolongation { - helloMsg.ConnectionHello.ProlongationRequest = &prolongation - } - - if err := c.sendShipModel(model.MsgTypeControl, helloMsg); err != nil { - return err - } - return nil -} diff --git a/ship/hs_hello_client_test.go b/ship/hs_hello_client_test.go deleted file mode 100644 index 3fffa88f..00000000 --- a/ship/hs_hello_client_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package ship - -import ( - "testing" - - "github.com/enbility/eebus-go/ship/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestHelloClientSuite(t *testing.T) { - suite.Run(t, new(HelloClientSuite)) -} - -// Hello Client role specific tests -type HelloClientSuite struct { - suite.Suite - role shipRole -} - -func (s *HelloClientSuite) BeforeTest(suiteName, testName string) { - s.role = ShipRoleClient -} - -func (s *HelloClientSuite) Test_InitialState() { - sut, data := initTest(s.role) - - sut.setState(smeHelloState) - sut.handleState(false, nil) - - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeHelloStateReadyListen, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *HelloClientSuite) Test_ReadyListen_Ok() { - sut, _ := initTest(s.role) - - sut.setState(smeHelloStateReadyInit) // inits the timer - sut.setState(smeHelloStateReadyListen) - - helloMsg := model.ConnectionHello{ - ConnectionHello: model.ConnectionHelloType{ - Phase: model.ConnectionHelloPhaseTypeReady, - }, - } - - msg, err := sut.shipMessage(model.MsgTypeControl, helloMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - // the state goes from smeHelloStateOk directly to smeProtHStateClientInit to smeProtHStateClientListenChoice - assert.Equal(s.T(), smeProtHStateClientListenChoice, sut.getState()) - - shutdownTest(sut) -} diff --git a/ship/hs_hello_test.go b/ship/hs_hello_test.go deleted file mode 100644 index 276b6bb6..00000000 --- a/ship/hs_hello_test.go +++ /dev/null @@ -1,299 +0,0 @@ -package ship - -import ( - "testing" - "time" - - "github.com/enbility/eebus-go/ship/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestHelloSuite(t *testing.T) { - suite.Run(t, new(HelloSuite)) -} - -type HelloSuite struct { - suite.Suite - role shipRole -} - -func (s *HelloSuite) BeforeTest(suiteName, testName string) { - s.role = ShipRoleServer -} - -func (s *HelloSuite) Test_InitialState() { - sut, data := initTest(s.role) - - sut.setState(smeHelloState) - sut.handleState(false, nil) - - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeHelloStateReadyListen, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_ReadyListen_Init() { - sut, _ := initTest(s.role) - - sut.setState(smeHelloStateReadyInit) - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_ReadyListen_Ok() { - sut, _ := initTest(s.role) - - sut.setState(smeHelloStateReadyInit) // inits the timer - sut.setState(smeHelloStateReadyListen) - - helloMsg := model.ConnectionHello{ - ConnectionHello: model.ConnectionHelloType{ - Phase: model.ConnectionHelloPhaseTypeReady, - }, - } - - msg, err := sut.shipMessage(model.MsgTypeControl, helloMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - // the state goes from smeHelloStateOk directly to smeProtHStateServerInit to smeProtHStateClientListenProposal - assert.Equal(s.T(), smeProtHStateServerListenProposal, sut.getState()) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_ReadyListen_Timeout() { - skipCI(s.T()) - - sut, data := initTest(s.role) - - sut.setState(smeHelloStateReadyInit) // inits the timer - sut.setState(smeHelloStateReadyListen) - - time.Sleep(tHelloInit + time.Second) - - assert.Equal(s.T(), smeHelloStateAbort, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_ReadyListen_Ignore() { - sut, _ := initTest(s.role) - - sut.setState(smeHelloStateReadyInit) // inits the timer - sut.setState(smeHelloStateReadyListen) - - helloMsg := model.ConnectionHello{ - ConnectionHello: model.ConnectionHelloType{ - Phase: model.ConnectionHelloPhaseTypePending, - }, - } - - msg, err := sut.shipMessage(model.MsgTypeControl, helloMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - assert.Equal(s.T(), smeHelloStateReadyListen, sut.getState()) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_ReadyListen_Abort() { - sut, data := initTest(s.role) - - sut.setState(smeHelloStateReadyInit) // inits the timer - sut.setState(smeHelloStateReadyListen) - - helloMsg := model.ConnectionHello{ - ConnectionHello: model.ConnectionHelloType{ - Phase: model.ConnectionHelloPhaseTypeAborted, - }, - } - - msg, err := sut.shipMessage(model.MsgTypeControl, helloMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleShipMessage(false, msg) - - assert.Equal(s.T(), false, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeHelloStateAbort, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_PendingInit() { - sut, data := initTest(s.role) - - sut.setState(smeHelloStatePendingInit) - sut.handleState(false, nil) - - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeHelloStatePendingListen, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_PendingListen() { - sut, _ := initTest(s.role) - - sut.setState(smeHelloStatePendingInit) // inits the timer - sut.setState(smeHelloStatePendingListen) - sut.handleState(false, nil) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_PendingListen_Timeout() { - skipCI(s.T()) - - sut, data := initTest(s.role) - - sut.setState(smeHelloStatePendingInit) // inits the timer - sut.setState(smeHelloStatePendingListen) - - time.Sleep(tHelloInit + time.Second) - - assert.Equal(s.T(), smeHelloStateAbort, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_PendingListen_ReadyAbort() { - sut, data := initTest(s.role) - - sut.setState(smeHelloStatePendingInit) // inits the timer - sut.setState(smeHelloStatePendingListen) - - helloMsg := model.ConnectionHello{ - ConnectionHello: model.ConnectionHelloType{ - Phase: model.ConnectionHelloPhaseTypeReady, - }, - } - - msg, err := sut.shipMessage(model.MsgTypeControl, helloMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleShipMessage(false, msg) - - assert.Equal(s.T(), false, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeHelloStateAbort, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_PendingListen_ReadyWaiting() { - sut, _ := initTest(s.role) - - sut.setState(smeHelloStatePendingInit) // inits the timer - sut.setState(smeHelloStatePendingListen) - - helloMsg := model.ConnectionHello{ - ConnectionHello: model.ConnectionHelloType{ - Phase: model.ConnectionHelloPhaseTypeReady, - Waiting: util.Ptr(uint(tHelloInit.Milliseconds())), - }, - } - - msg, err := sut.shipMessage(model.MsgTypeControl, helloMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleShipMessage(false, msg) - - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeHelloStatePendingListen, sut.getState()) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_PendingListen_Abort() { - sut, data := initTest(s.role) - - sut.setState(smeHelloStatePendingInit) // inits the timer - sut.setState(smeHelloStatePendingListen) - - helloMsg := model.ConnectionHello{ - ConnectionHello: model.ConnectionHelloType{ - Phase: model.ConnectionHelloPhaseTypeAborted, - }, - } - - msg, err := sut.shipMessage(model.MsgTypeControl, helloMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleShipMessage(false, msg) - - assert.Equal(s.T(), false, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeHelloStateAbort, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_PendingListen_PendingWaiting() { - sut, _ := initTest(s.role) - - sut.setState(smeHelloStatePendingInit) // inits the timer - sut.setState(smeHelloStatePendingListen) - - helloMsg := model.ConnectionHello{ - ConnectionHello: model.ConnectionHelloType{ - Phase: model.ConnectionHelloPhaseTypePending, - Waiting: util.Ptr(uint(tHelloInit.Milliseconds())), - }, - } - - msg, err := sut.shipMessage(model.MsgTypeControl, helloMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleShipMessage(false, msg) - - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeHelloStatePendingListen, sut.getState()) - - shutdownTest(sut) -} - -func (s *HelloSuite) Test_PendingListen_PendingProlongation() { - sut, data := initTest(s.role) - - sut.setState(smeHelloStatePendingInit) // inits the timer - sut.setState(smeHelloStatePendingListen) - - helloMsg := model.ConnectionHello{ - ConnectionHello: model.ConnectionHelloType{ - Phase: model.ConnectionHelloPhaseTypePending, - ProlongationRequest: util.Ptr(true), - }, - } - - msg, err := sut.shipMessage(model.MsgTypeControl, helloMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleShipMessage(false, msg) - - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeHelloStatePendingListen, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} diff --git a/ship/hs_helper_test.go b/ship/hs_helper_test.go deleted file mode 100644 index 0a74ac0f..00000000 --- a/ship/hs_helper_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package ship - -import ( - "os" - "sync" - "testing" - - "github.com/enbility/eebus-go/spine" - spineModel "github.com/enbility/eebus-go/spine/model" -) - -type dataHandlerTest struct { - sentMessage []byte - - mux sync.Mutex - - handleConnectionClosedInvoked bool -} - -func (s *dataHandlerTest) lastMessage() []byte { - s.mux.Lock() - defer s.mux.Unlock() - - return s.sentMessage -} - -var _ ShipDataConnection = (*dataHandlerTest)(nil) - -func (s *dataHandlerTest) InitDataProcessing(dataProcessing ShipDataProcessing) {} - -func (s *dataHandlerTest) WriteMessageToDataConnection(message []byte) error { - s.mux.Lock() - defer s.mux.Unlock() - - s.sentMessage = message - - return nil -} - -func (s *dataHandlerTest) CloseDataConnection() {} -func (w *dataHandlerTest) IsDataConnectionClosed() bool { return false } - -var _ ConnectionHandler = (*dataHandlerTest)(nil) - -func (s *dataHandlerTest) HandleClosedConnection(connection *ShipConnection) {} - -var _ ShipServiceDataProvider = (*dataHandlerTest)(nil) - -func (s *dataHandlerTest) IsRemoteServiceForSKIPaired(string) bool { return true } -func (s *dataHandlerTest) HandleConnectionClosed(*ShipConnection, bool) { - s.handleConnectionClosedInvoked = true -} -func (s *dataHandlerTest) ReportServiceShipID(string, string) {} - -func initTest(role shipRole) (*ShipConnection, *dataHandlerTest) { - localDevice := spine.NewDeviceLocalImpl("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode", - "TestDeviceAddress", spineModel.DeviceTypeTypeEnergyManagementSystem, spineModel.NetworkManagementFeatureSetTypeSmart) - - dataHandler := &dataHandlerTest{} - conhandler := NewConnectionHandler(dataHandler, dataHandler, localDevice, role, "LocalShipID", "RemoveDevice", "RemoteShipID") - - return conhandler, dataHandler -} - -func shutdownTest(conhandler *ShipConnection) { - conhandler.stopHandshakeTimer() -} - -func skipCI(t *testing.T) { - if os.Getenv("ACTION_ENVIRONMENT") == "CI" { - t.Skip("Skipping testing in CI environment") - } -} diff --git a/ship/hs_init.go b/ship/hs_init.go deleted file mode 100644 index 291f37de..00000000 --- a/ship/hs_init.go +++ /dev/null @@ -1,74 +0,0 @@ -package ship - -import ( - "fmt" - - "github.com/enbility/eebus-go/ship/model" -) - -// Handshake initialization covers the states cmiState... - -// CMI_STATE_INIT_START -func (c *ShipConnection) handshakeInit_cmiStateInitStart() { - switch c.role { - case ShipRoleClient: - // CMI_STATE_CLIENT_SEND - c.setState(cmiStateClientSend) - if err := c.DataHandler.WriteMessageToDataConnection(shipInit); err != nil { - c.endHandshakeWithError(err) - return - } - c.setState(cmiStateClientWait) - case ShipRoleServer: - c.setState(cmiStateServerWait) - } - - c.setHandshakeTimer(timeoutTimerTypeWaitForReady, cmiTimeout) -} - -// CMI_STATE_SERVER_WAIT -func (c *ShipConnection) handshakeInit_cmiStateServerWait(message []byte) { - c.smeState = cmiStateServerEvaluate - - if !c.handshakeInit_cmiStateEvaluate(message) { - return - } - - if err := c.DataHandler.WriteMessageToDataConnection(shipInit); err != nil { - c.endHandshakeWithError(err) - return - } - - c.setState(smeHelloState) - c.handleState(false, nil) -} - -// CMI_STATE_CLIENT_WAIT -func (c *ShipConnection) handshakeInit_cmiStateClientWait(message []byte) { - c.smeState = cmiStateClientEvaluate - - if !c.handshakeInit_cmiStateEvaluate(message) { - return - } - - c.setState(smeHelloState) - c.handleState(false, nil) -} - -// CMI_STATE_SERVER_EVALUATE -// CMI_STATE_CLIENT_EVALUATE -// returns false in case of an error -func (c *ShipConnection) handshakeInit_cmiStateEvaluate(message []byte) bool { - msgType, data := c.parseMessage(message, false) - - if msgType != model.MsgTypeInit { - c.endHandshakeWithError(fmt.Errorf("Invalid SHIP MessageType, expected 0 and got %s" + string(msgType))) - return false - } - if data[0] != byte(0) { - c.endHandshakeWithError(fmt.Errorf("Invalid SHIP MessageValue, expected 0 and got %s" + string(data))) - return false - } - - return true -} diff --git a/ship/hs_init_client_test.go b/ship/hs_init_client_test.go deleted file mode 100644 index d12861d0..00000000 --- a/ship/hs_init_client_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package ship - -import ( - "testing" - - "github.com/enbility/eebus-go/ship/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestInitClientSuite(t *testing.T) { - suite.Run(t, new(InitClientSuite)) -} - -type InitClientSuite struct { - suite.Suite - role shipRole -} - -func (s *InitClientSuite) BeforeTest(suiteName, testName string) { - s.role = ShipRoleClient -} - -func (s *InitClientSuite) Test_Init() { - sut, _ := initTest(s.role) - - assert.Equal(s.T(), cmiStateInitStart, sut.getState()) - - shutdownTest(sut) -} - -func (s *InitClientSuite) Test_Start() { - sut, data := initTest(s.role) - - sut.setState(cmiStateInitStart) - - sut.handleState(false, nil) - - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - assert.Equal(s.T(), cmiStateClientWait, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - assert.Equal(s.T(), shipInit, data.lastMessage()) - - shutdownTest(sut) -} - -func (s *InitClientSuite) Test_ClientWait() { - sut, data := initTest(s.role) - - sut.setState(cmiStateClientWait) - - sut.handleState(false, shipInit) - - // the state goes from smeHelloState directly to smeHelloStateReadyInit to smeHelloStateReadyListen - assert.Equal(s.T(), smeHelloStateReadyListen, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *InitClientSuite) Test_ClientWait_Timeout() { - sut, data := initTest(s.role) - - sut.setState(cmiStateClientWait) - - sut.handleState(true, nil) - - assert.Equal(s.T(), smeError, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - assert.Equal(s.T(), data.handleConnectionClosedInvoked, true) - - shutdownTest(sut) -} - -func (s *InitClientSuite) Test_ClientWait_InvalidMsgType() { - sut, data := initTest(s.role) - - sut.setState(cmiStateClientWait) - - sut.handleState(false, []byte{0x05, 0x00}) - - assert.Equal(s.T(), smeError, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *InitClientSuite) Test_ClientWait_InvalidData() { - sut, data := initTest(s.role) - - sut.setState(cmiStateClientWait) - - sut.handleState(false, []byte{model.MsgTypeInit, 0x05}) - - assert.Equal(s.T(), smeError, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} diff --git a/ship/hs_init_server_test.go b/ship/hs_init_server_test.go deleted file mode 100644 index 913be6bb..00000000 --- a/ship/hs_init_server_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package ship - -import ( - "testing" - - "github.com/enbility/eebus-go/ship/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestInitServerSuite(t *testing.T) { - suite.Run(t, new(InitServerSuite)) -} - -type InitServerSuite struct { - suite.Suite - role shipRole -} - -func (s *InitServerSuite) BeforeTest(suiteName, testName string) { - s.role = ShipRoleServer -} - -func (s *InitServerSuite) Test_Init() { - sut, _ := initTest(s.role) - - assert.Equal(s.T(), cmiStateInitStart, sut.getState()) - - shutdownTest(sut) -} - -func (s *InitServerSuite) Test_Start() { - sut, _ := initTest(s.role) - - sut.setState(cmiStateInitStart) - - sut.handleState(false, nil) - - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - assert.Equal(s.T(), cmiStateServerWait, sut.getState()) - - shutdownTest(sut) -} - -func (s *InitServerSuite) Test_ServerWait() { - sut, data := initTest(s.role) - - sut.setState(cmiStateServerWait) - - sut.handleState(false, shipInit) - - // the state goes from smeHelloState directly to smeHelloStateReadyInit to smeHelloStateReadyListen - assert.Equal(s.T(), smeHelloStateReadyListen, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *InitServerSuite) Test_ServerWait_InvalidMsgType() { - sut, data := initTest(s.role) - - sut.setState(cmiStateServerWait) - - sut.handleState(false, []byte{0x05, 0x00}) - - assert.Equal(s.T(), smeError, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *InitServerSuite) Test_ServerWait_InvalidData() { - sut, data := initTest(s.role) - - sut.setState(cmiStateServerWait) - - sut.handleState(false, []byte{model.MsgTypeInit, 0x05}) - - assert.Equal(s.T(), smeError, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} diff --git a/ship/hs_pin.go b/ship/hs_pin.go deleted file mode 100644 index adf826d0..00000000 --- a/ship/hs_pin.go +++ /dev/null @@ -1,51 +0,0 @@ -package ship - -import ( - "encoding/json" - "errors" - - "github.com/enbility/eebus-go/ship/model" -) - -// Handshake Pin covers the states smePin... - -func (c *ShipConnection) handshakePin_Init() { - c.setState(smePinStateCheckInit) - - pinState := model.ConnectionPinState{ - ConnectionPinState: model.ConnectionPinStateType{ - PinState: model.PinStateTypeNone, - }, - } - - if err := c.sendShipModel(model.MsgTypeControl, pinState); err != nil { - c.endHandshakeWithError(err) - return - } - - c.setState(smePinStateCheckListen) -} - -func (c *ShipConnection) handshakePin_smePinStateCheckListen(message []byte) { - _, data := c.parseMessage(message, true) - - var connectionPinState model.ConnectionPinState - if err := json.Unmarshal([]byte(data), &connectionPinState); err != nil { - c.endHandshakeWithError(err) - return - } - - switch connectionPinState.ConnectionPinState.PinState { - case model.PinStateTypeNone: - c.setState(smePinStateCheckOk) - c.handleState(false, nil) - case model.PinStateTypeRequired: - c.endHandshakeWithError(errors.New("Got pin state: required (unsupported)")) - case model.PinStateTypeOptional: - c.endHandshakeWithError(errors.New("Got pin state: optional (unsupported)")) - case model.PinStateTypePinOk: - c.endHandshakeWithError(errors.New("Got pin state: ok (unsupported)")) - default: - c.endHandshakeWithError(errors.New("Got invalid pin state")) - } -} diff --git a/ship/hs_pin_test.go b/ship/hs_pin_test.go deleted file mode 100644 index c4ad0792..00000000 --- a/ship/hs_pin_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package ship - -import ( - "testing" - - "github.com/enbility/eebus-go/ship/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestPinSuite(t *testing.T) { - suite.Run(t, new(PinSuite)) -} - -type PinSuite struct { - suite.Suite -} - -func (s *PinSuite) Test_Init() { - sut, data := initTest(ShipRoleClient) - - sut.setState(smePinStateCheckInit) - sut.handleState(false, nil) - - assert.Equal(s.T(), false, sut.handshakeTimerRunning) - assert.Equal(s.T(), smePinStateCheckListen, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *PinSuite) Test_CheckListen_None() { - sut, data := initTest(ShipRoleClient) - - sut.setState(smePinStateCheckListen) - - pinState := model.ConnectionPinState{ - ConnectionPinState: model.ConnectionPinStateType{ - PinState: model.PinStateTypeNone, - }, - } - msg, err := sut.shipMessage(model.MsgTypeControl, pinState) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeAccessMethodsRequest, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *PinSuite) Test_CheckListen_Required() { - sut, data := initTest(ShipRoleClient) - - sut.setState(smePinStateCheckListen) - - pinState := model.ConnectionPinState{ - ConnectionPinState: model.ConnectionPinStateType{ - PinState: model.PinStateTypeRequired, - }, - } - msg, err := sut.shipMessage(model.MsgTypeControl, pinState) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - assert.Equal(s.T(), false, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeError, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *PinSuite) Test_CheckListen_Optional() { - sut, data := initTest(ShipRoleClient) - - sut.setState(smePinStateCheckListen) - - pinState := model.ConnectionPinState{ - ConnectionPinState: model.ConnectionPinStateType{ - PinState: model.PinStateTypeOptional, - }, - } - msg, err := sut.shipMessage(model.MsgTypeControl, pinState) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - assert.Equal(s.T(), false, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeError, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *PinSuite) Test_CheckListen_Ok() { - sut, data := initTest(ShipRoleClient) - - sut.setState(smePinStateCheckListen) - - pinState := model.ConnectionPinState{ - ConnectionPinState: model.ConnectionPinStateType{ - PinState: model.PinStateTypePinOk, - }, - } - msg, err := sut.shipMessage(model.MsgTypeControl, pinState) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - assert.Equal(s.T(), false, sut.handshakeTimerRunning) - assert.Equal(s.T(), smeError, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} diff --git a/ship/hs_prot.go b/ship/hs_prot.go deleted file mode 100644 index 96bd46fc..00000000 --- a/ship/hs_prot.go +++ /dev/null @@ -1,175 +0,0 @@ -package ship - -import ( - "encoding/json" - "errors" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/ship/model" -) - -// Handshake Prot covers the states smeProt... - -func (c *ShipConnection) handshakeProtocol_Init() { - switch c.role { - case ShipRoleServer: - c.setState(smeProtHStateServerInit) - c.setHandshakeTimer(timeoutTimerTypeWaitForReady, cmiTimeout) - c.setState(smeProtHStateServerListenProposal) - case ShipRoleClient: - c.setState(smeProtHStateClientInit) - c.handshakeProtocol_smeProtHStateClientInit() - } -} - -// provide a ship.MessageProtocolHandshake struct -func (c *ShipConnection) protocolHandshake() model.MessageProtocolHandshake { - protocolHandshake := model.MessageProtocolHandshake{ - MessageProtocolHandshake: model.MessageProtocolHandshakeType{ - Version: model.Version{Major: 1, Minor: 0}, - Formats: model.MessageProtocolFormatsType{ - Format: []model.MessageProtocolFormatType{model.MessageProtocolFormatTypeUTF8}, - }, - }, - } - - return protocolHandshake -} - -func (c *ShipConnection) handshakeProtocol_smeProtHStateServerListenProposal(message []byte) { - _, data := c.parseMessage(message, true) - - messageProtocolHandshake := model.MessageProtocolHandshake{} - if err := json.Unmarshal([]byte(data), &messageProtocolHandshake); err != nil { - c.endHandshakeWithError(err) - return - } - - if messageProtocolHandshake.MessageProtocolHandshake.HandshakeType != model.ProtocolHandshakeTypeTypeAnnounceMax { - c.endHandshakeWithError(errors.New("Invalid protocol handshake request")) - return - } - - c.stopHandshakeTimer() - - protocolHandshake := c.protocolHandshake() - protocolHandshake.MessageProtocolHandshake.HandshakeType = model.ProtocolHandshakeTypeTypeSelect - - if err := c.sendShipModel(model.MsgTypeControl, protocolHandshake); err != nil { - c.endHandshakeWithError(err) - } - - c.setHandshakeTimer(timeoutTimerTypeWaitForReady, cmiTimeout) - - c.setState(smeProtHStateServerListenConfirm) -} - -func (c *ShipConnection) handshakeProtocol_smeProtHStateServerListenConfirm(message []byte) { - _, data := c.parseMessage(message, true) - - var messageProtocolHandshake model.MessageProtocolHandshake - if err := json.Unmarshal([]byte(data), &messageProtocolHandshake); err != nil { - logging.Log.Debug(err) - c.abortProtocolHandshake(model.MessageProtocolHandshakeErrorErrorTypeUnexpectedMessage) - return - } - - if messageProtocolHandshake.MessageProtocolHandshake.HandshakeType != model.ProtocolHandshakeTypeTypeSelect { - logging.Log.Debug("invalid protocol handshake response") - c.abortProtocolHandshake(model.MessageProtocolHandshakeErrorErrorTypeSelectionMismatch) - return - } - - c.stopHandshakeTimer() - - c.setState(smeProtHStateServerOk) - c.handleState(false, nil) -} - -func (c *ShipConnection) handshakeProtocol_smeProtHStateClientInit() { - c.setState(smeProtHStateClientInit) - - protocolHandshake := c.protocolHandshake() - protocolHandshake.MessageProtocolHandshake.HandshakeType = model.ProtocolHandshakeTypeTypeAnnounceMax - - if err := c.sendShipModel(model.MsgTypeControl, protocolHandshake); err != nil { - c.endHandshakeWithError(err) - return - } - - c.setState(smeProtHStateClientListenChoice) -} - -func (c *ShipConnection) handshakeProtocol_smeProtHStateClientListenChoice(message []byte) { - _, data := c.parseMessage(message, true) - - messageProtocolHandshake := model.MessageProtocolHandshake{} - if err := json.Unmarshal([]byte(data), &messageProtocolHandshake); err != nil { - logging.Log.Debug(err) - c.abortProtocolHandshake(model.MessageProtocolHandshakeErrorErrorTypeUnexpectedMessage) - return - } - - msgHandshake := messageProtocolHandshake.MessageProtocolHandshake - - if msgHandshake.HandshakeType != model.ProtocolHandshakeTypeTypeSelect { - logging.Log.Debug("invalid protocol handshake response") - c.abortProtocolHandshake(model.MessageProtocolHandshakeErrorErrorTypeSelectionMismatch) - return - } - - if msgHandshake.Version.Major != 1 { - logging.Log.Debug("unsupported protocol major version") - c.abortProtocolHandshake(model.MessageProtocolHandshakeErrorErrorTypeSelectionMismatch) - return - } - - if msgHandshake.Version.Minor != 0 { - logging.Log.Debug("unsupported protocol minor version") - c.abortProtocolHandshake(model.MessageProtocolHandshakeErrorErrorTypeSelectionMismatch) - return - } - - if msgHandshake.Formats.Format == nil || len(msgHandshake.Formats.Format) == 0 { - logging.Log.Debug("format is missing") - c.abortProtocolHandshake(model.MessageProtocolHandshakeErrorErrorTypeSelectionMismatch) - return - } - - if len(msgHandshake.Formats.Format) != 1 { - logging.Log.Debug("unsupported format response") - c.abortProtocolHandshake(model.MessageProtocolHandshakeErrorErrorTypeSelectionMismatch) - return - } - - if msgHandshake.Formats.Format[0] != model.MessageProtocolFormatTypeUTF8 { - logging.Log.Debug("unsupported format") - c.abortProtocolHandshake(model.MessageProtocolHandshakeErrorErrorTypeSelectionMismatch) - return - } - - c.stopHandshakeTimer() - - protocolHandshake := c.protocolHandshake() - protocolHandshake.MessageProtocolHandshake.HandshakeType = model.ProtocolHandshakeTypeTypeSelect - - if err := c.sendShipModel(model.MsgTypeControl, protocolHandshake); err != nil { - c.endHandshakeWithError(err) - return - } - - c.setState(smeProtHStateClientOk) - c.handleState(false, nil) -} - -func (c *ShipConnection) abortProtocolHandshake(err model.MessageProtocolHandshakeErrorErrorType) { - c.stopHandshakeTimer() - - msg := model.MessageProtocolHandshakeError{ - Error: err, - } - - _ = c.sendShipModel(model.MsgTypeControl, msg) - - c.CloseConnection(false, "") -} diff --git a/ship/hs_prot_client_test.go b/ship/hs_prot_client_test.go deleted file mode 100644 index 2675e231..00000000 --- a/ship/hs_prot_client_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package ship - -import ( - "testing" - - "github.com/enbility/eebus-go/ship/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestProClientSuite(t *testing.T) { - suite.Run(t, new(ProClientSuite)) -} - -type ProClientSuite struct { - suite.Suite - - role shipRole -} - -func (s *ProClientSuite) BeforeTest(suiteName, testName string) { - s.role = ShipRoleClient -} - -func (s *ProClientSuite) Test_Init() { - sut, data := initTest(s.role) - - sut.setState(smeHelloStateOk) - - sut.handleState(false, nil) - - // the state goes from smeHelloStateOk to smeProtHStateClientInit to smeProtHStateClientListenChoice - assert.Equal(s.T(), smeProtHStateClientListenChoice, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *ProClientSuite) Test_ListenChoice() { - sut, data := initTest(s.role) - - sut.setState(smeProtHStateClientListenChoice) - - protMsg := model.MessageProtocolHandshake{ - MessageProtocolHandshake: model.MessageProtocolHandshakeType{ - HandshakeType: model.ProtocolHandshakeTypeTypeSelect, - Version: model.Version{Major: 1, Minor: 0}, - Formats: model.MessageProtocolFormatsType{ - Format: []model.MessageProtocolFormatType{model.MessageProtocolFormatTypeUTF8}, - }, - }, - } - - msg, err := sut.shipMessage(model.MsgTypeControl, protMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - assert.Equal(s.T(), false, sut.handshakeTimerRunning) - - // state goes directly from smeProtHStateClientOk to smePinStateCheckInit to smePinStateCheckListen - assert.Equal(s.T(), smePinStateCheckListen, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} diff --git a/ship/hs_prot_server_test.go b/ship/hs_prot_server_test.go deleted file mode 100644 index 0e6fcc64..00000000 --- a/ship/hs_prot_server_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package ship - -import ( - "testing" - - "github.com/enbility/eebus-go/ship/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestProServerSuite(t *testing.T) { - suite.Run(t, new(ProServerSuite)) -} - -type ProServerSuite struct { - suite.Suite - role shipRole -} - -func (s *ProServerSuite) BeforeTest(suiteName, testName string) { - s.role = ShipRoleServer -} - -func (s *ProServerSuite) Test_Init() { - sut, data := initTest(s.role) - - sut.setState(smeHelloStateOk) - - sut.handleState(false, nil) - - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - - // the state goes from smeHelloStateOk to smeProtHStateServerInit to smeProtHStateServerListenProposal - assert.Equal(s.T(), smeProtHStateServerListenProposal, sut.getState()) - assert.Nil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *ProServerSuite) Test_ListenProposal() { - sut, data := initTest(s.role) - - sut.setState(smeProtHStateServerListenProposal) - - protMsg := model.MessageProtocolHandshake{ - MessageProtocolHandshake: model.MessageProtocolHandshakeType{ - HandshakeType: model.ProtocolHandshakeTypeTypeAnnounceMax, - Version: model.Version{Major: 1, Minor: 0}, - Formats: model.MessageProtocolFormatsType{ - Format: []model.MessageProtocolFormatType{model.MessageProtocolFormatTypeUTF8}, - }, - }, - } - - msg, err := sut.shipMessage(model.MsgTypeControl, protMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - assert.Equal(s.T(), true, sut.handshakeTimerRunning) - - assert.Equal(s.T(), smeProtHStateServerListenConfirm, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} - -func (s *ProServerSuite) Test_ListenConfirm() { - sut, data := initTest(s.role) - - sut.setState(smeProtHStateServerListenConfirm) - - protMsg := model.MessageProtocolHandshake{ - MessageProtocolHandshake: model.MessageProtocolHandshakeType{ - HandshakeType: model.ProtocolHandshakeTypeTypeSelect, - Version: model.Version{Major: 1, Minor: 0}, - Formats: model.MessageProtocolFormatsType{ - Format: []model.MessageProtocolFormatType{model.MessageProtocolFormatTypeUTF8}, - }, - }, - } - - msg, err := sut.shipMessage(model.MsgTypeControl, protMsg) - assert.Nil(s.T(), err) - assert.NotNil(s.T(), msg) - - sut.handleState(false, msg) - - assert.Equal(s.T(), false, sut.handshakeTimerRunning) - - // state smeProtHStateServerOk directly goes to smePinStateCheckInit to smePinStateCheckListen - assert.Equal(s.T(), smePinStateCheckListen, sut.getState()) - assert.NotNil(s.T(), data.lastMessage()) - - shutdownTest(sut) -} diff --git a/ship/model/model.go b/ship/model/model.go deleted file mode 100644 index 2eb8710e..00000000 --- a/ship/model/model.go +++ /dev/null @@ -1,189 +0,0 @@ -package model - -import "encoding/json" - -const ( - MsgTypeInit byte = 0 - MsgTypeControl byte = 1 - MsgTypeData byte = 2 - MsgTypeEnd byte = 3 -) - -const ( - ShipProtocolId = "ee1.0" -) - -type ConnectionHelloPhaseType string - -const ( - ConnectionHelloPhaseTypePending ConnectionHelloPhaseType = "pending" - ConnectionHelloPhaseTypeReady ConnectionHelloPhaseType = "ready" - ConnectionHelloPhaseTypeAborted ConnectionHelloPhaseType = "aborted" -) - -type ConnectionHello struct { - ConnectionHello ConnectionHelloType `json:"connectionHello"` -} - -type ConnectionHelloType struct { - Phase ConnectionHelloPhaseType `json:"phase"` - Waiting *uint `json:"waiting,omitempty"` - ProlongationRequest *bool `json:"prolongationRequest,omitempty"` -} - -type MessageProtocolFormatType string - -const ( - MessageProtocolFormatTypeUTF8 MessageProtocolFormatType = "JSON-UTF8" - MessageProtocolFormatTypeUTF16 MessageProtocolFormatType = "JSON-UTF16" -) - -type MessageProtocolFormatsType struct { - Format []MessageProtocolFormatType `json:"format"` -} - -type ProtocolHandshakeTypeType string - -const ( - ProtocolHandshakeTypeTypeAnnounceMax ProtocolHandshakeTypeType = "announceMax" - ProtocolHandshakeTypeTypeSelect ProtocolHandshakeTypeType = "select" -) - -type Version struct { - Major uint8 `json:"major"` - Minor uint8 `json:"minor"` -} - -type MessageProtocolHandshakeType struct { - HandshakeType ProtocolHandshakeTypeType `json:"handshakeType"` - Version Version `json:"version"` - Formats MessageProtocolFormatsType `json:"formats"` -} - -type MessageProtocolHandshake struct { - MessageProtocolHandshake MessageProtocolHandshakeType `json:"messageProtocolHandshake"` -} - -type MessageProtocolHandshakeErrorErrorType uint8 - -const ( - MessageProtocolHandshakeErrorErrorTypeRFU MessageProtocolHandshakeErrorErrorType = 0 - MessageProtocolHandshakeErrorErrorTypeTimeout MessageProtocolHandshakeErrorErrorType = 1 - MessageProtocolHandshakeErrorErrorTypeUnexpectedMessage MessageProtocolHandshakeErrorErrorType = 2 - MessageProtocolHandshakeErrorErrorTypeSelectionMismatch MessageProtocolHandshakeErrorErrorType = 3 -) - -type MessageProtocolHandshakeErrorType struct { - Error MessageProtocolHandshakeErrorErrorType `json:"error"` -} - -type PinStateType string - -const ( - PinStateTypeRequired PinStateType = "required" - PinStateTypeOptional PinStateType = "optional" - PinStateTypePinOk PinStateType = "pinOk" - PinStateTypeNone PinStateType = "none" -) - -type PinInputPermissionType string - -const ( - PinInputPermissionTypeBusy PinInputPermissionType = "busy" - PinInputPermissionTypeOk PinInputPermissionType = "ok" -) - -type MessageProtocolHandshakeError struct { - Error MessageProtocolHandshakeErrorErrorType `json:"error"` -} - -type ConnectionPinStateType struct { - PinState PinStateType `json:"pinState"` - InputPermission *PinInputPermissionType `json:"inputPermission,omitempty"` -} - -type ConnectionPinState struct { - ConnectionPinState ConnectionPinStateType `json:"connectionPinState"` -} - -type PinValueType string - -type ConnectionPinInputType struct { - Pin PinValueType `json:"pin"` -} - -type ConnectionPinErrorErrorType uint8 - -type ConnectionPinErrorType struct { - Error ConnectionPinErrorErrorType `json:"error"` -} - -type ProtocolIdType string - -type HeaderType struct { - ProtocolId ProtocolIdType `json:"protocolId"` -} - -type ExtensionType struct { - ExtensionId *string `json:"extensionId,omitempty"` - Binary *byte `json:"binary,omitempty"` // HexBinary - String *string `json:"string,omitempty"` -} - -type ShipData struct { - Data DataType `json:"data"` -} - -type DataType struct { - Header HeaderType `json:"header"` - Payload json.RawMessage `json:"payload"` - Extension *ExtensionType `json:"extension,omitempty"` -} - -type ConnectionClosePhaseType string - -const ( - ConnectionClosePhaseTypeAnnounce ConnectionClosePhaseType = "announce" - ConnectionClosePhaseTypeConfirm ConnectionClosePhaseType = "confirm" -) - -type ConnectionCloseReasonType string - -const ( - ConnectionCloseReasonTypeUnspecific ConnectionCloseReasonType = "unspecific" - ConnectionCloseReasonTypeRemovedconnection ConnectionCloseReasonType = "removedConnection" -) - -type ConnectionClose struct { - ConnectionClose ConnectionCloseType `json:"connectionClose"` -} - -type ConnectionCloseType struct { - Phase ConnectionClosePhaseType `json:"phase"` - MaxTime *uint `json:"maxTime,omitempty"` - Reason *ConnectionCloseReasonType `json:"reason,omitempty"` -} - -type AccessMethodsRequest struct { - AccessMethodsRequest AccessMethodsRequestType `json:"accessMethodsRequest"` -} - -type AccessMethodsRequestType struct{} - -type Dns struct { - Uri string `json:"uri"` -} - -type DnsSdMDns struct { -} - -type AccessMethods struct { - AccessMethods AccessMethodsType `json:"accessMethods"` -} - -type AccessMethodsType struct { - Id *string `json:"id"` - DnsSdMDns *DnsSdMDns `json:"dnsSd_mDns,omitempty"` - // According to the Spec Dns should be of type *Dns, but the SHM 2.0 only uses a string and would cause a crash - Dns *string `json:"dns,omitempty"` -} diff --git a/ship/types.go b/ship/types.go deleted file mode 100644 index 6b72026f..00000000 --- a/ship/types.go +++ /dev/null @@ -1,145 +0,0 @@ -package ship - -import ( - "time" - - "github.com/enbility/eebus-go/ship/model" -) - -type shipRole string - -const ( - ShipRoleServer shipRole = "server" - ShipRoleClient shipRole = "client" -) - -const ( - writeWait = 10 * time.Second - - // Time allowed to read the next pong message from the peer. - pongWait = 60 * time.Second // SHIP 4.2: ping interval + pong timeout - // Send pings to peer with this period. Must be less than pongWait. - pingPeriod = 50 * time.Second // SHIP 4.2: ping interval - - // SHIP 9.2: Set maximum fragment length to 1024 bytes - MaxMessageSize = 1024 -) - -const ( - cmiTimeout = 10 * time.Second // SHIP 4.2 - cmiCloseTimeout = 100 * time.Millisecond - tHelloInit = 60 * time.Second // SHIP 13.4.4.1.3 - tHelloInc = 60 * time.Second - tHelloProlongThrInc = 30 * time.Second - tHelloProlongWaitingGap = 15 * time.Second - tHelloProlongMin = 1 * time.Second -) - -type timeoutTimerType uint - -const ( - // SHIP 13.4.4.1.3: The communication partner must send its "READY" state (or request for prolongation") before the timer expires. - timeoutTimerTypeWaitForReady timeoutTimerType = iota - // SHIP 13.4.4.1.3: Local timer to request for prolongation at the communication partner in time (i.e. before the communication partner's Wait-For-Ready-Timer expires). - timeoutTimerTypeSendProlongationRequest - // SHIP 13.4.4.1.3: Detection of response timeout on prolongation request. - timeoutTimerTypeProlongRequestReply -) - -type shipMessageExchangeState uint - -const ( - // Connection Mode Initialisation (CMI) SHIP 13.4.3 - cmiStateInitStart shipMessageExchangeState = iota - cmiStateClientSend - cmiStateClientWait - cmiStateClientEvaluate - cmiStateServerWait - cmiStateServerEvaluate - // Connection Data Preparation SHIP 13.4.4 - smeHelloState - smeHelloStateReadyInit - smeHelloStateReadyListen - smeHelloStateReadyTimeout - smeHelloStatePendingInit - smeHelloStatePendingListen - smeHelloStatePendingTimeout - smeHelloStateOk - smeHelloStateAbort - // Connection State Protocol Handhsake SHIP 13.4.4.2 - smeProtHStateServerInit - smeProtHStateClientInit - smeProtHStateServerListenProposal - smeProtHStateServerListenConfirm - smeProtHStateClientListenChoice - smeProtHStateTimeout - smeProtHStateClientOk - smeProtHStateServerOk - // Connection PIN State 13.4.5 - smePinStateCheckInit - smePinStateCheckListen - smePinStateCheckError - smePinStateCheckBusyInit - smePinStateCheckBusyWait - smePinStateCheckOk - smePinStateAskInit - smePinStateAskProcess - smePinStateAskRestricted - smePinStateAskOk - // ConnectionAccess Methods Identification 13.4.6 - smeAccessMethodsRequest - - // Handshake approved on both ends - smeApproved - - // Handshake process is successfully completed - smeComplete - - // Handshake ended with an error - smeError -) - -var shipInit []byte = []byte{model.MsgTypeInit, 0x00} - -// interface for handling the actual remote device data connection -// -// implemented by websocketConnection, used by ShipConnection -type ShipDataConnection interface { - // initialize data processing - InitDataProcessing(ShipDataProcessing) - - // send data via the connection to the remote device - WriteMessageToDataConnection([]byte) error - - // close the data connection - CloseDataConnection() - - // report if the data connection is closed - IsDataConnectionClosed() bool -} - -// interface for handling incoming data -// -// implemented by shipConnection, used by websocketConnection -type ShipDataProcessing interface { - // called for each incoming message - HandleIncomingShipMessage([]byte) - - // called if the data connection is closed unsafe - // e.g. due to connection issues - ReportConnectionError(error) -} - -// interface for getting service wide information -// -// implemented by connectionsHub, used by shipConnection -type ShipServiceDataProvider interface { - // check if the SKI is paired - IsRemoteServiceForSKIPaired(string) bool - - // report closing of a connection and if handshake did complete - HandleConnectionClosed(*ShipConnection, bool) - - // report the ship ID provided during the handshake - ReportServiceShipID(string, string) -} diff --git a/ship/util/helper.go b/ship/util/helper.go deleted file mode 100644 index a33458b1..00000000 --- a/ship/util/helper.go +++ /dev/null @@ -1,78 +0,0 @@ -package util - -import ( - "bytes" - "encoding/json" - "strings" - - "gitlab.com/c0b/go-ordered-json" -) - -// convert incoming EEBUS json format into standard json format -func JsonFromEEBUSJson(json []byte) []byte { - var result = bytes.ReplaceAll(json, []byte("[{"), []byte("{")) - result = bytes.ReplaceAll(result, []byte("},{"), []byte(",")) - result = bytes.ReplaceAll(result, []byte("}]"), []byte("}")) - result = bytes.ReplaceAll(result, []byte("[]"), []byte("{}")) - - return result -} - -// convert objects in json to be arrays with each field being an array alement as eebus expects it -func process_eebus_json_hierarchie_level(data interface{}) interface{} { - temp := data - switch temp.(type) { - case *ordered.OrderedMap: - var new_array []interface{} = make([]interface{}, 0) - - orderedData := data.(*ordered.OrderedMap) - iter := orderedData.EntriesIter() - for { - pair, ok := iter() - if !ok { - break - } - var new_value = process_eebus_json_hierarchie_level(pair.Value) - var new_object = map[string]interface{}{pair.Key: new_value} - new_array = append(new_array, new_object) - } - return new_array - - case []interface{}: - var new_array []interface{} = make([]interface{}, 0) - for _, value := range data.([]interface{}) { - var new_value = process_eebus_json_hierarchie_level(value) - new_array = append(new_array, new_value) - } - return new_array - default: - return data - } -} - -// convert json into the EEBUS json format -func JsonIntoEEBUSJson(data []byte) (string, error) { - // EEBUS defines the items to be ordered in the array, - // so we can't use map[string]interface{} as that would - // cause a random order when Unmarshalling - var temp *ordered.OrderedMap = ordered.NewOrderedMap() - - if err := json.Unmarshal(data, &temp); err != nil { - return "", err - } - - var result = process_eebus_json_hierarchie_level(temp) - - var b, err = json.Marshal(result) - if err != nil { - return "", err - } - - var json = string(b) - - // we are lazy: fix the first item being put into an array - json = strings.TrimPrefix(json, "[") - json = strings.TrimSuffix(json, "]") - - return json, nil -} diff --git a/ship/util/helper_test.go b/ship/util/helper_test.go deleted file mode 100644 index ae45a5a9..00000000 --- a/ship/util/helper_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package util_test - -import ( - "encoding/json" - "strings" - "testing" - - "github.com/enbility/eebus-go/ship/model" - "github.com/enbility/eebus-go/ship/util" -) - -func TestJsonFromEEBUSJson(t *testing.T) { - jsonTest := `{"datagram":[{"header":[{"specificationVersion":"1.2.0"},{"addressSource":[{"device":"d:_i:3210_EVSE"},{"entity":[1,1]},{"feature":6}]},{"addressDestination":[{"device":"d:_i:3210_HEMS"},{"entity":[1]},{"feature":1}]},{"msgCounter":194},{"msgCounterReference":4890},{"cmdClassifier":"reply"}]},{"payload":[{"cmd":[[{"deviceClassificationManufacturerData":[{"deviceName":""},{"deviceCode":""},{"brandName":""},{"powerSource":"mains3Phase"}]}]]}]}]}` - jsonExpected := `{"datagram":{"header":{"specificationVersion":"1.2.0","addressSource":{"device":"d:_i:3210_EVSE","entity":[1,1],"feature":6},"addressDestination":{"device":"d:_i:3210_HEMS","entity":[1],"feature":1},"msgCounter":194,"msgCounterReference":4890,"cmdClassifier":"reply"},"payload":{"cmd":[{"deviceClassificationManufacturerData":{"deviceName":"","deviceCode":"","brandName":"","powerSource":"mains3Phase"}}]}}}` - - var json = util.JsonFromEEBUSJson([]byte(jsonTest)) - - if string(json) != jsonExpected { - t.Errorf("\nExpected:\n %s\ngot:\n %s", jsonExpected, json) - } -} - -func TestJsonIntoEEBUSJson(t *testing.T) { - jsonTest := `{"datagram":{"header":{"specificationVersion":"1.2.0","addressSource":{"device":"d:_i:3210_EVSE","entity":[1,1],"feature":6},"addressDestination":{"device":"d:_i:3210_HEMS","entity":[1],"feature":1},"msgCounter":194,"msgCounterReference":4890,"cmdClassifier":"reply"},"payload":{"cmd":[{"deviceClassificationManufacturerData":{"deviceName":"","deviceCode":"","brandName":"","powerSource":"mains3Phase"}}]}}}` - jsonExpected := `{"datagram":[{"header":[{"specificationVersion":"1.2.0"},{"addressSource":[{"device":"d:_i:3210_EVSE"},{"entity":[1,1]},{"feature":6}]},{"addressDestination":[{"device":"d:_i:3210_HEMS"},{"entity":[1]},{"feature":1}]},{"msgCounter":194},{"msgCounterReference":4890},{"cmdClassifier":"reply"}]},{"payload":[{"cmd":[[{"deviceClassificationManufacturerData":[{"deviceName":""},{"deviceCode":""},{"brandName":""},{"powerSource":"mains3Phase"}]}]]}]}]}` - - var json, err = util.JsonIntoEEBUSJson([]byte(jsonTest)) - if err != nil { - println(err.Error()) - t.Errorf("\nExpected:\n %s\ngot:\n %s", jsonExpected, json) - } - - if json != jsonExpected { - t.Errorf("\nExpected:\n %s\ngot:\n %s", jsonExpected, json) - } -} - -const payloadPlaceholder = `{"place":"holder"}` - -func TestShipJsonIntoEEBUSJson(t *testing.T) { - spineTest := `{"datagram":{"header":{"specificationVersion":"1.2.0","addressSource":{"device":"Demo-EVSE-234567890","entity":[0],"feature":0},"addressDestination":{"device":"Demo-HEMS-123456789","entity":[0],"feature":0},"msgCounter":1,"cmdClassifier":"read"},"payload":{"cmd":[{"nodeManagementDetailedDiscoveryData":{}}]}}}` - jsonExpected := `{"data":[{"header":[{"protocolId":"ee1.0"}]},{"payload":{"datagram":[{"header":[{"specificationVersion":"1.2.0"},{"addressSource":[{"device":"Demo-EVSE-234567890"},{"entity":[0]},{"feature":0}]},{"addressDestination":[{"device":"Demo-HEMS-123456789"},{"entity":[0]},{"feature":0}]},{"msgCounter":1},{"cmdClassifier":"read"}]},{"payload":[{"cmd":[[{"nodeManagementDetailedDiscoveryData":[]}]]}]}]}}]}` - - // TODO: move this test into connection_test using "transformSpineDataIntoShipJson()" - spineMsg, err := util.JsonIntoEEBUSJson([]byte(spineTest)) - if err != nil { - t.Errorf(err.Error()) - } - payload := json.RawMessage([]byte(spineMsg)) - - shipMessage := model.ShipData{ - Data: model.DataType{ - Header: model.HeaderType{ - ProtocolId: model.ShipProtocolId, - }, - Payload: json.RawMessage([]byte(payloadPlaceholder)), - }, - } - - msg, err := json.Marshal(shipMessage) - if err != nil { - t.Errorf(err.Error()) - } - - json, err := util.JsonIntoEEBUSJson(msg) - if err != nil { - println(err.Error()) - t.Errorf("\nExpected:\n %s\ngot:\n %s", jsonExpected, json) - } - - json = strings.ReplaceAll(json, `[`+payloadPlaceholder+`]`, string(payload)) - - if json != jsonExpected { - t.Errorf("\nExpected:\n %s\ngot:\n %s", jsonExpected, json) - } -} diff --git a/ship/websocket.go b/ship/websocket.go deleted file mode 100644 index 95f0325a..00000000 --- a/ship/websocket.go +++ /dev/null @@ -1,243 +0,0 @@ -package ship - -import ( - "bytes" - "errors" - "fmt" - "sync" - "time" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/util" - "github.com/gorilla/websocket" -) - -// Handling of the actual websocket connection to a remote device -type websocketConnection struct { - // The actual websocket connection - conn *websocket.Conn - - // The implementation handling message processing - dataProcessing ShipDataProcessing - - // The connection was closed - closeChannel chan struct{} - - // The ship write channel for outgoing SHIP messages - shipWriteChannel chan []byte - - // internal handling of closed connections - connectionClosed bool - - remoteSki string - - muxConnClosed sync.Mutex - muxShipWrite sync.Mutex - shutdownOnce sync.Once -} - -// create a new websocket based shipDataProcessing implementation -func NewWebsocketConnection(conn *websocket.Conn, remoteSki string) *websocketConnection { - return &websocketConnection{ - conn: conn, - remoteSki: remoteSki, - } -} - -// check if the websocket connection is closed -func (w *websocketConnection) isConnClosed() bool { - w.muxConnClosed.Lock() - defer w.muxConnClosed.Unlock() - - return w.connectionClosed -} - -// check if the websocket connection is closed -func (w *websocketConnection) setConnClosed() { - w.muxConnClosed.Lock() - defer w.muxConnClosed.Unlock() - - w.connectionClosed = true -} - -func (w *websocketConnection) run() { - w.shipWriteChannel = make(chan []byte, 1) // Send outgoing ship messages - w.closeChannel = make(chan struct{}, 1) // Listen to close events - - go w.readShipPump() - go w.writeShipPump() -} - -// writePump pumps messages from the SPINE and SHIP writeChannels to the websocket connection -func (w *websocketConnection) writeShipPump() { - ticker := time.NewTicker(pingPeriod) - defer func() { - ticker.Stop() - }() - - for { - select { - case <-w.closeChannel: - return - - case message, ok := <-w.shipWriteChannel: - if w.isConnClosed() { - return - } - - _ = w.conn.SetWriteDeadline(time.Now().Add(writeWait)) - if !ok { - logging.Log.Debug(w.remoteSki, "Ship write channel closed") - // The write channel has been closed - _ = w.conn.WriteMessage(websocket.CloseMessage, []byte{}) - return - } - - if err := w.conn.WriteMessage(websocket.BinaryMessage, message); err != nil { - logging.Log.Debug(w.remoteSki, "error writing to websocket: ", err) - return - } - - var text string - if len(message) > 2 { - text = string(message[1:]) - } else if bytes.Equal(message, shipInit) { - text = "ship init" - } else { - text = "unknown single byte" - } - logging.Log.Trace("Send:", w.remoteSki, text) - - case <-ticker.C: - if w.isConnClosed() { - return - } - - _ = w.conn.SetWriteDeadline(time.Now().Add(writeWait)) - if err := w.conn.WriteMessage(websocket.PingMessage, nil); err != nil { - logging.Log.Debug(w.remoteSki, "error writing to websocket: ", err) - return - } - } - } -} - -// readShipPump checks for messages from the websocket connection -func (w *websocketConnection) readShipPump() { - _ = w.conn.SetReadDeadline(time.Now().Add(pongWait)) - w.conn.SetPongHandler(func(string) error { _ = w.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil }) - - for { - if w.isConnClosed() { - return - } - - message, err := w.readWebsocketMessage() - if err != nil { - logging.Log.Debug(w.remoteSki, "websocket read error: ", err) - w.close() - w.dataProcessing.ReportConnectionError(err) - return - } - - var text string - if len(message) > 2 { - text = string(message[1:]) - } else if bytes.Equal(message, shipInit) { - text = "ship init" - } else { - text = "unknown single byte" - } - logging.Log.Trace("Recv:", w.remoteSki, text) - - w.dataProcessing.HandleIncomingShipMessage(message) - } -} - -// read a message from the websocket connection -func (w *websocketConnection) readWebsocketMessage() ([]byte, error) { - if w.conn == nil { - return nil, errors.New("connection is not initialized") - } - - msgType, b, err := w.conn.ReadMessage() - if err != nil { - return nil, err - } - - if msgType != websocket.BinaryMessage { - return nil, errors.New("message is not a binary message") - } - - if len(b) < 2 { - return nil, fmt.Errorf("invalid ship message length") - } - - return b, nil -} - -// close the current websocket connection -func (w *websocketConnection) close() { - w.shutdownOnce.Do(func() { - if w.isConnClosed() { - return - } - - w.setConnClosed() - - w.muxShipWrite.Lock() - - if !util.IsChannelClosed(w.closeChannel) { - close(w.closeChannel) - w.closeChannel = nil - } - - if !util.IsChannelClosed(w.shipWriteChannel) { - close(w.shipWriteChannel) - w.shipWriteChannel = nil - } - - if w.conn != nil { - w.conn.Close() - } - - w.muxShipWrite.Unlock() - }) -} - -var _ ShipDataConnection = (*websocketConnection)(nil) - -func (w *websocketConnection) InitDataProcessing(dataProcessing ShipDataProcessing) { - w.dataProcessing = dataProcessing - - w.run() -} - -// write a message to the websocket connection -func (w *websocketConnection) WriteMessageToDataConnection(message []byte) error { - if w.isConnClosed() { - return errors.New("connection is closed") - } - - w.muxShipWrite.Lock() - defer w.muxShipWrite.Unlock() - - if w.conn == nil || w.shipWriteChannel == nil { - return errors.New("connection is closed") - } - - w.shipWriteChannel <- message - return nil -} - -// shutdown the connection and all internals -func (w *websocketConnection) CloseDataConnection() { - if !w.isConnClosed() { - w.close() - } -} - -// return if the connection is closed -func (w *websocketConnection) IsDataConnectionClosed() bool { - return w.isConnClosed() -} diff --git a/spine/binding_manager.go b/spine/binding_manager.go deleted file mode 100644 index e9f141e6..00000000 --- a/spine/binding_manager.go +++ /dev/null @@ -1,149 +0,0 @@ -package spine - -import ( - "errors" - "fmt" - "reflect" - "sync/atomic" - - "github.com/ahmetb/go-linq/v3" - "github.com/enbility/eebus-go/spine/model" -) - -type BindingManager interface { - AddBinding(localDevice *DeviceLocalImpl, remoteDevice *DeviceRemoteImpl, data model.BindingManagementRequestCallType) error - RemoveBinding(data model.BindingManagementDeleteCallType, remoteDevice *DeviceRemoteImpl) error - Bindings(remoteDevice *DeviceRemoteImpl) []*BindingEntry - BindingsOnFeature(featureAddress model.FeatureAddressType) []*BindingEntry -} - -type BindingEntry struct { - id uint64 - serverFeature FeatureLocal - clientFeature *FeatureRemoteImpl -} - -type BindingManagerImpl struct { - bindingNum uint64 - bindingEntries []*BindingEntry - // TODO: add persistence -} - -func NewBindingManager() BindingManager { - c := &BindingManagerImpl{ - bindingNum: 0, - } - - return c -} - -// is sent from the client (remote device) to the server (local device) -func (c *BindingManagerImpl) AddBinding(localDevice *DeviceLocalImpl, remoteDevice *DeviceRemoteImpl, data model.BindingManagementRequestCallType) error { - - serverFeature := localDevice.FeatureByAddress(data.ServerAddress) - if serverFeature == nil { - return fmt.Errorf("server feature '%s' in local device '%s' not found", data.ServerAddress, *localDevice.Address()) - } - if err := c.checkRoleAndType(serverFeature, model.RoleTypeServer, *data.ServerFeatureType); err != nil { - return err - } - - clientFeature := remoteDevice.FeatureByAddress(data.ClientAddress) - if clientFeature == nil { - return fmt.Errorf("client feature '%s' in remote device '%s' not found", data.ClientAddress, *remoteDevice.Address()) - } - if err := c.checkRoleAndType(clientFeature, model.RoleTypeClient, *data.ServerFeatureType); err != nil { - return err - } - - bindingEntry := &BindingEntry{ - id: c.bindingId(), - serverFeature: serverFeature, - clientFeature: clientFeature, - } - - // TOV-TODO: check if binding already exists - c.bindingEntries = append(c.bindingEntries, bindingEntry) - - payload := EventPayload{ - Ski: remoteDevice.ski, - EventType: EventTypeBindingChange, - ChangeType: ElementChangeAdd, - Data: data, - Feature: clientFeature, - } - Events.Publish(payload) - - // TOV-TODO: Send heartbeat to the feature which subscribed to DeviceDiagnostic - - return nil -} - -func (c *BindingManagerImpl) RemoveBinding(data model.BindingManagementDeleteCallType, remoteDevice *DeviceRemoteImpl) error { - // TODO: test this!!! - - var newBindingEntries []*BindingEntry - - // according to the spec 7.4.4 - // a. The absence of "bindingDelete. clientAddress. device" SHALL be treated as if it was - // present and set to the sender's "device" address part. - // b. The absence of "bindingDelete. serverAddress. device" SHALL be treated as if it was - // present and set to the recipient's "device" address part. - - clientAddress := data.ClientAddress - if data.ClientAddress.Device == nil { - clientAddress.Device = remoteDevice.Address() - } - - for _, item := range c.bindingEntries { - if !reflect.DeepEqual(item.clientFeature.Address(), clientAddress) { - newBindingEntries = append(newBindingEntries, item) - } - } - - if len(newBindingEntries) == len(c.bindingEntries) { - return errors.New("could not find requested BindingId to be removed") - } - - c.bindingEntries = newBindingEntries - - // TOV-TODO: stop heartbeat for remote device when it has no binding to DeviceDiagnostic anymore - return nil -} - -func (c *BindingManagerImpl) Bindings(remoteDevice *DeviceRemoteImpl) []*BindingEntry { - var result []*BindingEntry - - linq.From(c.bindingEntries).WhereT(func(s *BindingEntry) bool { - return s.clientFeature.Device().Ski() == remoteDevice.Ski() - }).ToSlice(&result) - - return result -} - -func (c *BindingManagerImpl) BindingsOnFeature(featureAddress model.FeatureAddressType) []*BindingEntry { - var result []*BindingEntry - - linq.From(c.bindingEntries).WhereT(func(s *BindingEntry) bool { - return reflect.DeepEqual(*s.serverFeature.Address(), featureAddress) - }).ToSlice(&result) - - return result -} - -func (c *BindingManagerImpl) bindingId() uint64 { - i := atomic.AddUint64(&c.bindingNum, 1) - return i -} - -func (c *BindingManagerImpl) checkRoleAndType(feature Feature, role model.RoleType, featureType model.FeatureTypeType) error { - if feature.Role() != model.RoleTypeSpecial && feature.Role() != role { - return fmt.Errorf("found feature %s is not matching required role %s", feature.Type(), role) - } - - if feature.Type() != featureType && feature.Type() != model.FeatureTypeTypeGeneric { - return fmt.Errorf("found feature %s is not matching required type %s", feature.Type(), featureType) - } - - return nil -} diff --git a/spine/const.go b/spine/const.go deleted file mode 100644 index 81209919..00000000 --- a/spine/const.go +++ /dev/null @@ -1,5 +0,0 @@ -package spine - -import "github.com/enbility/eebus-go/spine/model" - -var SpecificationVersion model.SpecificationVersionType = "1.1.1" diff --git a/spine/device.go b/spine/device.go deleted file mode 100644 index 3d2b6c50..00000000 --- a/spine/device.go +++ /dev/null @@ -1,61 +0,0 @@ -package spine - -import "github.com/enbility/eebus-go/spine/model" - -type DeviceImpl struct { - address *model.AddressDeviceType - dType *model.DeviceTypeType - featureSet *model.NetworkManagementFeatureSetType - useCaseManager *UseCaseManager -} - -// Initialize a new device -// Both values are required for a local device but provided as empty strings for a remote device -// as the address is only provided via detailed discovery response -func NewDeviceImpl(address *model.AddressDeviceType, dType *model.DeviceTypeType, featureSet *model.NetworkManagementFeatureSetType) *DeviceImpl { - deviceImpl := &DeviceImpl{ - useCaseManager: NewUseCaseManager(), - } - - if dType != nil { - deviceImpl.dType = dType - } - - if address != nil { - deviceImpl.address = address - } - - if featureSet != nil { - deviceImpl.featureSet = featureSet - } - - return deviceImpl -} - -func (r *DeviceImpl) Address() *model.AddressDeviceType { - return r.address -} - -func (r *DeviceImpl) UseCaseManager() *UseCaseManager { - return r.useCaseManager -} - -func (r *DeviceImpl) DeviceType() *model.DeviceTypeType { - return r.dType -} - -func (r *DeviceImpl) FeatureSet() *model.NetworkManagementFeatureSetType { - return r.featureSet -} - -func (r *DeviceImpl) DestinationData() model.NodeManagementDestinationDataType { - return model.NodeManagementDestinationDataType{ - DeviceDescription: &model.NetworkManagementDeviceDescriptionDataType{ - DeviceAddress: &model.DeviceAddressType{ - Device: r.Address(), - }, - DeviceType: r.DeviceType(), - NetworkFeatureSet: r.FeatureSet(), - }, - } -} diff --git a/spine/device_local.go b/spine/device_local.go deleted file mode 100644 index fc666fba..00000000 --- a/spine/device_local.go +++ /dev/null @@ -1,376 +0,0 @@ -package spine - -import ( - "errors" - "fmt" - "reflect" - "sync" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -// implemented by spine.DeviceLocalImpl and used by shipConnection -type DeviceLocalConnection interface { - RemoveRemoteDeviceConnection(ski string) - AddRemoteDevice(ski string, writeI SpineDataConnection) SpineDataProcessing -} - -type DeviceLocalImpl struct { - *DeviceImpl - entities []*EntityLocalImpl - subscriptionManager SubscriptionManager - bindingManager BindingManager - nodeManagement *NodeManagementImpl - - remoteDevices map[string]*DeviceRemoteImpl - - brandName string - deviceModel string - deviceCode string - serialNumber string - - mux sync.Mutex -} - -// BrandName is the brand -// DeviceModel is the model -// SerialNumber is the serial number -// DeviceCode is the SHIP id (accessMethods.id) -// DeviceAddress is the SPINE device address -func NewDeviceLocalImpl(brandName, deviceModel, serialNumber, deviceCode, deviceAddress string, deviceType model.DeviceTypeType, featureSet model.NetworkManagementFeatureSetType) *DeviceLocalImpl { - address := model.AddressDeviceType(deviceAddress) - - var fSet *model.NetworkManagementFeatureSetType - if len(featureSet) != 0 { - fSet = &featureSet - } - - res := &DeviceLocalImpl{ - DeviceImpl: NewDeviceImpl(&address, &deviceType, fSet), - subscriptionManager: NewSubscriptionManager(), - bindingManager: NewBindingManager(), - remoteDevices: make(map[string]*DeviceRemoteImpl), - brandName: brandName, - deviceModel: deviceModel, - serialNumber: serialNumber, - deviceCode: deviceCode, - } - - res.addDeviceInformation() - return res -} - -var _ DeviceLocalConnection = (*DeviceLocalImpl)(nil) - -func (r *DeviceLocalImpl) RemoveRemoteDeviceConnection(ski string) { - remoteDevice := r.RemoteDeviceForSki(ski) - - r.RemoveRemoteDevice(ski) - - // inform about the disconnection - payload := EventPayload{ - Ski: ski, - EventType: EventTypeDeviceChange, - ChangeType: ElementChangeRemove, - Device: remoteDevice, - } - Events.Publish(payload) -} - -// Helper method used by tests and AddRemoteDevice -func (r *DeviceLocalImpl) AddRemoteDeviceForSki(ski string, rDevice *DeviceRemoteImpl) { - r.mux.Lock() - r.remoteDevices[ski] = rDevice - r.mux.Unlock() -} - -// Adds a new remote device with a given SKI and triggers SPINE requesting device details -func (r *DeviceLocalImpl) AddRemoteDevice(ski string, writeI SpineDataConnection) SpineDataProcessing { - rDevice := NewDeviceRemoteImpl(r, ski, writeI) - - r.AddRemoteDeviceForSki(ski, rDevice) - - // Request Detailed Discovery Data - _, _ = r.nodeManagement.RequestDetailedDiscovery(rDevice.ski, rDevice.address, rDevice.sender) - - // TODO: Add error handling - // If the request returned an error, it should be retried until it does not - - // always add subscription, as it checks if it already exists - Events.Subscribe(r) - - return rDevice -} - -// React to some specific events -func (r *DeviceLocalImpl) HandleEvent(payload EventPayload) { - // Subscribe to NodeManagment after DetailedDiscovery is received - if payload.EventType != EventTypeDeviceChange { - return - } - - if payload.ChangeType != ElementChangeAdd { - return - } - - if payload.Data == nil { - return - } - - if len(payload.Ski) == 0 { - return - } - - if r.RemoteDeviceForSki(payload.Ski) == nil { - return - } - - switch payload.Data.(type) { - case *model.NodeManagementDetailedDiscoveryDataType: - _, _ = r.nodeManagement.Subscribe(payload.Feature.Device(), payload.Feature.Address()) - - // Request Use Case Data - _, _ = r.nodeManagement.RequestUseCaseData(payload.Device.ski, payload.Device.Address(), payload.Device.Sender()) - } -} - -func (r *DeviceLocalImpl) RemoveRemoteDevice(ski string) { - r.mux.Lock() - defer r.mux.Unlock() - - if r.remoteDevices[ski] == nil { - return - } - - r.remoteDevices[ski].CloseConnection() - delete(r.remoteDevices, ski) - - // only unsubscribe if we don't have any remote devices left - if len(r.remoteDevices) == 0 { - Events.Unsubscribe(r) - } -} - -func (r *DeviceLocalImpl) RemoteDevices() []*DeviceRemoteImpl { - r.mux.Lock() - defer r.mux.Unlock() - - res := make([]*DeviceRemoteImpl, 0) - for _, rDevice := range r.remoteDevices { - res = append(res, rDevice) - } - - return res -} - -func (r *DeviceLocalImpl) RemoteDeviceForSki(ski string) *DeviceRemoteImpl { - r.mux.Lock() - defer r.mux.Unlock() - - return r.remoteDevices[ski] -} - -func (r *DeviceLocalImpl) ProcessCmd(datagram model.DatagramType, remoteDevice *DeviceRemoteImpl) error { - destAddr := datagram.Header.AddressDestination - localFeature := r.FeatureByAddress(destAddr) - - cmdClassifier := datagram.Header.CmdClassifier - if len(datagram.Payload.Cmd) == 0 { - return errors.New("no payload cmd content available") - } - cmd := datagram.Payload.Cmd[0] - - // TODO check if cmd.Function is the same as the provided cmd value - filterPartial, filterDelete := cmd.ExtractFilter() - - remoteEntity := remoteDevice.Entity(datagram.Header.AddressSource.Entity) - remoteFeature := remoteDevice.FeatureByAddress(datagram.Header.AddressSource) - if remoteFeature == nil { - return fmt.Errorf("invalid remote feature address: '%s'", datagram.Header.AddressSource) - } - - message := &Message{ - RequestHeader: &datagram.Header, - CmdClassifier: *cmdClassifier, - Cmd: cmd, - FilterPartial: filterPartial, - FilterDelete: filterDelete, - FeatureRemote: remoteFeature, - EntityRemote: remoteEntity, - DeviceRemote: remoteDevice, - } - - ackRequest := datagram.Header.AckRequest - - if localFeature == nil { - errorMessage := "invalid feature address" - _ = remoteFeature.Sender().ResultError(message.RequestHeader, destAddr, NewErrorType(model.ErrorNumberTypeDestinationUnknown, errorMessage)) - - return errors.New(errorMessage) - } - - lfType := string(localFeature.Type()) - rfType := "" - if remoteFeature != nil { - remoteFeature.Type() - } - - logging.Log.Debug(datagram.PrintMessageOverview(false, lfType, rfType)) - - err := localFeature.HandleMessage(message) - if err != nil { - // TODO: add error description in a useful format - - // Don't send error responses for incoming resulterror messages - if message.CmdClassifier != model.CmdClassifierTypeResult { - _ = remoteFeature.Sender().ResultError(message.RequestHeader, localFeature.Address(), err) - } - - return errors.New(err.String()) - } - if ackRequest != nil && *ackRequest { - _ = remoteFeature.Sender().ResultSuccess(message.RequestHeader, localFeature.Address()) - } - - return nil -} - -func (r *DeviceLocalImpl) SubscriptionManager() SubscriptionManager { - return r.subscriptionManager -} - -func (r *DeviceLocalImpl) BindingManager() BindingManager { - return r.bindingManager -} - -func (r *DeviceLocalImpl) AddEntity(entity *EntityLocalImpl) { - r.entities = append(r.entities, entity) - - r.notifySubscribersOfEntity(entity, model.NetworkManagementStateChangeTypeAdded) -} - -func (r *DeviceLocalImpl) RemoveEntity(entity *EntityLocalImpl) { - for i, e := range r.entities { - if e == entity { - r.entities = append(r.entities[:i], r.entities[i+1:]...) - // TODO: delete subscriptions of removed entity (incl. delete call) - break - } - } -} - -func (r *DeviceLocalImpl) Entities() []*EntityLocalImpl { - return r.entities -} - -func (r *DeviceLocalImpl) Entity(id []model.AddressEntityType) *EntityLocalImpl { - for _, e := range r.entities { - if reflect.DeepEqual(id, e.Address().Entity) { - return e - } - } - return nil -} - -func (r *DeviceLocalImpl) FeatureByAddress(address *model.FeatureAddressType) FeatureLocal { - entity := r.Entity(address.Entity) - if entity != nil { - return entity.Feature(address.Feature) - } - return nil -} - -func (r *DeviceLocalImpl) FeatureByTypeAndRole(featureType model.FeatureTypeType, role model.RoleType) FeatureLocal { - if len(r.entities) < 1 { - return nil - } - - for _, entity := range r.entities { - for _, feature := range entity.Features() { - if feature.Type() == featureType && feature.Role() == role { - return feature - } - } - } - - return nil -} - -func (r *DeviceLocalImpl) Information() *model.NodeManagementDetailedDiscoveryDeviceInformationType { - res := model.NodeManagementDetailedDiscoveryDeviceInformationType{ - Description: &model.NetworkManagementDeviceDescriptionDataType{ - DeviceAddress: &model.DeviceAddressType{ - Device: r.address, - }, - DeviceType: r.dType, - NetworkFeatureSet: r.featureSet, - }, - } - return &res -} - -func (r *DeviceLocalImpl) NotifySubscribers(featureAddress *model.FeatureAddressType, cmd model.CmdType) { - subscriptions := r.SubscriptionManager().SubscriptionsOnFeature(*featureAddress) - for _, subscription := range subscriptions { - // TODO: error handling - _, _ = subscription.clientFeature.Sender().Notify(subscription.serverFeature.Address(), subscription.clientFeature.Address(), cmd) - } -} - -func (r *DeviceLocalImpl) notifySubscribersOfEntity(entity *EntityLocalImpl, state model.NetworkManagementStateChangeType) { - deviceInformation := r.Information() - entityInformation := *entity.Information() - entityInformation.Description.LastStateChange = &state - - var featureInformation []model.NodeManagementDetailedDiscoveryFeatureInformationType - if state == model.NetworkManagementStateChangeTypeAdded { - for _, f := range entity.Features() { - featureInformation = append(featureInformation, *f.Information()) - } - } - - cmd := model.CmdType{ - Function: util.Ptr(model.FunctionTypeNodeManagementDetailedDiscoveryData), - Filter: filterEmptyPartial(), - NodeManagementDetailedDiscoveryData: &model.NodeManagementDetailedDiscoveryDataType{ - SpecificationVersionList: &model.NodeManagementSpecificationVersionListType{ - SpecificationVersion: []model.SpecificationVersionDataType{model.SpecificationVersionDataType(SpecificationVersion)}, - }, - DeviceInformation: deviceInformation, - EntityInformation: []model.NodeManagementDetailedDiscoveryEntityInformationType{entityInformation}, - FeatureInformation: featureInformation, - }, - } - - r.NotifySubscribers(r.nodeManagement.Address(), cmd) -} - -func (r *DeviceLocalImpl) addDeviceInformation() { - entityType := model.EntityTypeTypeDeviceInformation - entity := NewEntityLocalImpl(r, entityType, []model.AddressEntityType{model.AddressEntityType(DeviceInformationEntityId)}) - - { - r.nodeManagement = NewNodeManagementImpl(entity.NextFeatureId(), entity) - entity.AddFeature(r.nodeManagement) - } - { - f := NewFeatureLocalImpl(entity.NextFeatureId(), entity, model.FeatureTypeTypeDeviceClassification, model.RoleTypeServer) - - f.AddFunctionType(model.FunctionTypeDeviceClassificationManufacturerData, true, false) - - manufacturerData := &model.DeviceClassificationManufacturerDataType{ - BrandName: util.Ptr(model.DeviceClassificationStringType(r.brandName)), - VendorName: util.Ptr(model.DeviceClassificationStringType(r.brandName)), - DeviceName: util.Ptr(model.DeviceClassificationStringType(r.deviceModel)), - DeviceCode: util.Ptr(model.DeviceClassificationStringType(r.deviceCode)), - SerialNumber: util.Ptr(model.DeviceClassificationStringType(r.serialNumber)), - } - f.SetData(model.FunctionTypeDeviceClassificationManufacturerData, manufacturerData) - - entity.AddFeature(f) - } - - r.entities = append(r.entities, entity) -} diff --git a/spine/device_local_test.go b/spine/device_local_test.go deleted file mode 100644 index c3b4008d..00000000 --- a/spine/device_local_test.go +++ /dev/null @@ -1,236 +0,0 @@ -package spine_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestDeviceLocalSuite(t *testing.T) { - suite.Run(t, new(DeviceLocalTestSuite)) -} - -type DeviceLocalTestSuite struct { - suite.Suite -} - -var _ spine.SpineDataConnection = (*DeviceLocalTestSuite)(nil) - -func (d *DeviceLocalTestSuite) WriteSpineMessage([]byte) {} - -func (d *DeviceLocalTestSuite) Test_RemoveRemoteDevice() { - sut := spine.NewDeviceLocalImpl("brand", "model", "serial", "code", "address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart) - - ski := "test" - sut.AddRemoteDevice(ski, d) - rDevice := sut.RemoteDeviceForSki(ski) - assert.NotNil(d.T(), rDevice) - - sut.RemoveRemoteDeviceConnection(ski) - - rDevice = sut.RemoteDeviceForSki(ski) - assert.Nil(d.T(), rDevice) -} - -func (d *DeviceLocalTestSuite) Test_RemoteDevice() { - sut := spine.NewDeviceLocalImpl("brand", "model", "serial", "code", "address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart) - localEntity := spine.NewEntityLocalImpl(sut, model.EntityTypeTypeCEM, spine.NewAddressEntityType([]uint{1})) - sut.AddEntity(localEntity) - - f := spine.NewFeatureLocalImpl(1, localEntity, model.FeatureTypeTypeElectricalConnection, model.RoleTypeClient) - localEntity.AddFeature(f) - f = spine.NewFeatureLocalImpl(2, localEntity, model.FeatureTypeTypeMeasurement, model.RoleTypeClient) - localEntity.AddFeature(f) - - ski := "test" - remote := sut.RemoteDeviceForSki(ski) - assert.Nil(d.T(), remote) - - devices := sut.RemoteDevices() - assert.Equal(d.T(), 0, len(devices)) - - sut.AddRemoteDevice(ski, d) - remote = sut.RemoteDeviceForSki(ski) - assert.NotNil(d.T(), remote) - - devices = sut.RemoteDevices() - assert.Equal(d.T(), 1, len(devices)) - - entities := sut.Entities() - assert.Equal(d.T(), 2, len(entities)) - - entity1 := sut.Entity([]model.AddressEntityType{1}) - assert.NotNil(d.T(), entity1) - - entity2 := sut.Entity([]model.AddressEntityType{2}) - assert.Nil(d.T(), entity2) - - featureAddress := &model.FeatureAddressType{ - Entity: []model.AddressEntityType{1}, - Feature: util.Ptr(model.AddressFeatureType(1)), - } - feature1 := sut.FeatureByAddress(featureAddress) - assert.NotNil(d.T(), feature1) - - feature2 := sut.FeatureByTypeAndRole(model.FeatureTypeTypeMeasurement, model.RoleTypeClient) - assert.NotNil(d.T(), feature2) - - sut.RemoveEntity(entity1) - entities = sut.Entities() - assert.Equal(d.T(), 1, len(entities)) - - sut.RemoveRemoteDevice(ski) - remote = sut.RemoteDeviceForSki(ski) - assert.Nil(d.T(), remote) -} - -func (d *DeviceLocalTestSuite) Test_ProcessCmd_Errors() { - sut := spine.NewDeviceLocalImpl("brand", "model", "serial", "code", "address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart) - localEntity := spine.NewEntityLocalImpl(sut, model.EntityTypeTypeCEM, spine.NewAddressEntityType([]uint{1})) - sut.AddEntity(localEntity) - - ski := "test" - sut.AddRemoteDevice(ski, d) - remote := sut.RemoteDeviceForSki(ski) - assert.NotNil(d.T(), remote) - - datagram := model.DatagramType{ - Header: model.HeaderType{ - AddressSource: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType("localdevice")), - }, - AddressDestination: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType("localdevice")), - }, - MsgCounter: util.Ptr(model.MsgCounterType(1)), - CmdClassifier: util.Ptr(model.CmdClassifierTypeRead), - }, - Payload: model.PayloadType{ - Cmd: []model.CmdType{}, - }, - } - - err := sut.ProcessCmd(datagram, remote) - assert.NotNil(d.T(), err) - - datagram = model.DatagramType{ - Header: model.HeaderType{ - AddressSource: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType("localdevice")), - }, - AddressDestination: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType("localdevice")), - }, - MsgCounter: util.Ptr(model.MsgCounterType(1)), - CmdClassifier: util.Ptr(model.CmdClassifierTypeRead), - }, - Payload: model.PayloadType{ - Cmd: []model.CmdType{ - {}, - }, - }, - } - - err = sut.ProcessCmd(datagram, remote) - assert.NotNil(d.T(), err) -} - -func (d *DeviceLocalTestSuite) Test_ProcessCmd() { - sut := spine.NewDeviceLocalImpl("brand", "model", "serial", "code", "address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart) - localEntity := spine.NewEntityLocalImpl(sut, model.EntityTypeTypeCEM, spine.NewAddressEntityType([]uint{1})) - sut.AddEntity(localEntity) - - f := spine.NewFeatureLocalImpl(1, localEntity, model.FeatureTypeTypeElectricalConnection, model.RoleTypeClient) - localEntity.AddFeature(f) - f = spine.NewFeatureLocalImpl(2, localEntity, model.FeatureTypeTypeMeasurement, model.RoleTypeClient) - localEntity.AddFeature(f) - f = spine.NewFeatureLocalImpl(3, localEntity, model.FeatureTypeTypeElectricalConnection, model.RoleTypeServer) - localEntity.AddFeature(f) - - ski := "test" - remoteDeviceName := "remote" - sut.AddRemoteDevice(ski, d) - remote := sut.RemoteDeviceForSki(ski) - assert.NotNil(d.T(), remote) - - detailedData := &model.NodeManagementDetailedDiscoveryDataType{ - DeviceInformation: &model.NodeManagementDetailedDiscoveryDeviceInformationType{ - Description: &model.NetworkManagementDeviceDescriptionDataType{ - DeviceAddress: &model.DeviceAddressType{ - Device: util.Ptr(model.AddressDeviceType(remoteDeviceName)), - }, - }, - }, - EntityInformation: []model.NodeManagementDetailedDiscoveryEntityInformationType{ - { - Description: &model.NetworkManagementEntityDescriptionDataType{ - EntityAddress: &model.EntityAddressType{ - Device: util.Ptr(model.AddressDeviceType(remoteDeviceName)), - Entity: []model.AddressEntityType{1}, - }, - EntityType: util.Ptr(model.EntityTypeTypeEVSE), - }, - }, - }, - FeatureInformation: []model.NodeManagementDetailedDiscoveryFeatureInformationType{ - { - Description: &model.NetworkManagementFeatureDescriptionDataType{ - FeatureAddress: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType(remoteDeviceName)), - Entity: []model.AddressEntityType{1}, - Feature: util.Ptr(model.AddressFeatureType(1)), - }, - FeatureType: util.Ptr(model.FeatureTypeTypeElectricalConnection), - Role: util.Ptr(model.RoleTypeServer), - }, - }, - }, - } - _, err := remote.AddEntityAndFeatures(true, detailedData) - assert.Nil(d.T(), err) - - datagram := model.DatagramType{ - Header: model.HeaderType{ - AddressSource: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType(remoteDeviceName)), - Entity: []model.AddressEntityType{1}, - Feature: util.Ptr(model.AddressFeatureType(1)), - }, - AddressDestination: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType("localdevice")), - Entity: []model.AddressEntityType{1}, - }, - MsgCounter: util.Ptr(model.MsgCounterType(1)), - CmdClassifier: util.Ptr(model.CmdClassifierTypeRead), - }, - Payload: model.PayloadType{ - Cmd: []model.CmdType{}, - }, - } - - err = sut.ProcessCmd(datagram, remote) - assert.NotNil(d.T(), err) - - cmd := model.CmdType{ - ElectricalConnectionParameterDescriptionListData: &model.ElectricalConnectionParameterDescriptionListDataType{}, - } - - datagram.Payload.Cmd = append(datagram.Payload.Cmd, cmd) - - err = sut.ProcessCmd(datagram, remote) - assert.NotNil(d.T(), err) - - datagram.Header.AddressDestination.Feature = util.Ptr(model.AddressFeatureType(1)) - - err = sut.ProcessCmd(datagram, remote) - assert.NotNil(d.T(), err) - - datagram.Header.AddressDestination.Feature = util.Ptr(model.AddressFeatureType(3)) - - err = sut.ProcessCmd(datagram, remote) - assert.Nil(d.T(), err) -} diff --git a/spine/device_remote.go b/spine/device_remote.go deleted file mode 100644 index 03782f25..00000000 --- a/spine/device_remote.go +++ /dev/null @@ -1,272 +0,0 @@ -package spine - -import ( - "encoding/json" - "errors" - "reflect" - "sync" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/spine/model" -) - -type DeviceRemoteImpl struct { - *DeviceImpl - - ski string - - entities []*EntityRemoteImpl - entitiesMutex sync.Mutex - - sender Sender - - localDevice *DeviceLocalImpl - - // Heartbeat Sender - heartbeatSender *HeartbeatSender -} - -var _ SpineDataProcessing = (*DeviceRemoteImpl)(nil) - -func NewDeviceRemoteImpl(localDevice *DeviceLocalImpl, ski string, writeHandler SpineDataConnection) *DeviceRemoteImpl { - sender := NewSender(writeHandler) - res := DeviceRemoteImpl{ - DeviceImpl: NewDeviceImpl(nil, nil, nil), - ski: ski, - localDevice: localDevice, - sender: sender, - heartbeatSender: NewHeartbeatSender(sender), - } - res.addNodeManagement() - - return &res -} - -// return the device SKI -func (d *DeviceRemoteImpl) Ski() string { - return d.ski -} - -// Needs to be called by the CEM implementation once a subscription for the local DeviceDiagnosis server feature is received -func (d *DeviceRemoteImpl) StartHeartbeatSend(senderAddr, destinationAddr *model.FeatureAddressType) { - d.heartbeatSender.StartHeartbeatSend(senderAddr, destinationAddr) -} - -func (d *DeviceRemoteImpl) IsHeartbeatMsgCounter(msgCounter model.MsgCounterType) bool { - return d.heartbeatSender.IsHeartbeatMsgCounter(msgCounter) -} - -// Needs to be called by the CEM implementation once a subscription for the local DeviceDiagnosis server feature is removed -func (d *DeviceRemoteImpl) Stopheartbeat() { - d.heartbeatSender.StopHeartbeat() -} - -// this connection is closed -func (d *DeviceRemoteImpl) CloseConnection() { - d.heartbeatSender.StopHeartbeat() -} - -// processing incoming SPINE message from the associated SHIP connection -func (d *DeviceRemoteImpl) HandleIncomingSpineMesssage(message []byte) (*model.MsgCounterType, error) { - datagram := model.Datagram{} - if err := json.Unmarshal([]byte(message), &datagram); err != nil { - return nil, err - } - err := d.localDevice.ProcessCmd(datagram.Datagram, d) - if err != nil { - logging.Log.Trace(err) - } - - return datagram.Datagram.Header.MsgCounter, nil -} - -func (d *DeviceRemoteImpl) addNodeManagement() { - deviceInformation := d.addNewEntity(model.EntityTypeTypeDeviceInformation, NewAddressEntityType([]uint{DeviceInformationEntityId})) - nodeManagement := NewFeatureRemoteImpl(deviceInformation.NextFeatureId(), deviceInformation, model.FeatureTypeTypeNodeManagement, model.RoleTypeSpecial) - deviceInformation.AddFeature(nodeManagement) -} - -func (d *DeviceRemoteImpl) Sender() Sender { - return d.sender -} - -// Return an entity with a given address -func (d *DeviceRemoteImpl) Entity(id []model.AddressEntityType) *EntityRemoteImpl { - d.entitiesMutex.Lock() - defer d.entitiesMutex.Unlock() - - for _, e := range d.entities { - if reflect.DeepEqual(id, e.Address().Entity) { - return e - } - } - return nil -} - -// Return all entities of this device -func (d *DeviceRemoteImpl) Entities() []*EntityRemoteImpl { - return d.entities -} - -// Return the feature for a given address -func (d *DeviceRemoteImpl) FeatureByAddress(address *model.FeatureAddressType) *FeatureRemoteImpl { - entity := d.Entity(address.Entity) - if entity != nil { - return entity.Feature(address.Feature) - } - return nil -} - -// Remove an entity with a given address from this device -func (d *DeviceRemoteImpl) RemoveByAddress(addr []model.AddressEntityType) *EntityRemoteImpl { - entityForRemoval := d.Entity(addr) - if entityForRemoval == nil { - return nil - } - - d.entitiesMutex.Lock() - defer d.entitiesMutex.Unlock() - - var newEntities []*EntityRemoteImpl - for _, item := range d.entities { - if !reflect.DeepEqual(item, entityForRemoval) { - newEntities = append(newEntities, item) - } - } - d.entities = newEntities - - return entityForRemoval -} - -// Get the feature for a given entity, feature type and feature role -func (r *DeviceRemoteImpl) FeatureByEntityTypeAndRole(entity *EntityRemoteImpl, featureType model.FeatureTypeType, role model.RoleType) *FeatureRemoteImpl { - if len(r.entities) < 1 { - return nil - } - - r.entitiesMutex.Lock() - defer r.entitiesMutex.Unlock() - - for _, e := range r.entities { - if entity != e { - continue - } - for _, feature := range entity.Features() { - if feature.Type() == featureType && feature.Role() == role { - return feature - } - } - } - - return nil -} - -func (d *DeviceRemoteImpl) UpdateDevice(description *model.NetworkManagementDeviceDescriptionDataType) { - if description != nil { - if description.DeviceAddress != nil && description.DeviceAddress.Device != nil { - d.address = description.DeviceAddress.Device - } - if description.DeviceType != nil { - d.dType = description.DeviceType - } - if description.NetworkFeatureSet != nil { - d.featureSet = description.NetworkFeatureSet - } - } -} - -func (d *DeviceRemoteImpl) AddEntityAndFeatures(initialData bool, data *model.NodeManagementDetailedDiscoveryDataType) ([]*EntityRemoteImpl, error) { - rEntites := make([]*EntityRemoteImpl, 0) - - for _, ei := range data.EntityInformation { - if err := d.CheckEntityInformation(initialData, ei); err != nil { - return nil, err - } - - entityAddress := ei.Description.EntityAddress.Entity - - entity := d.Entity(entityAddress) - if entity == nil { - entity = d.addNewEntity(*ei.Description.EntityType, entityAddress) - rEntites = append(rEntites, entity) - } - - entity.SetDescription(ei.Description.Description) - entity.RemoveAllFeatures() - - for _, fi := range data.FeatureInformation { - if reflect.DeepEqual(fi.Description.FeatureAddress.Entity, entityAddress) { - if f := unmarshalFeature(entity, fi); f != nil { - entity.AddFeature(f) - } - } - } - - // TOV-TODO: check this approach - // if err := f.announceFeatureDiscovery(entity); err != nil { - // return err - // } - } - - return rEntites, nil -} - -// check if the provided entity information is correct -// provide initialData to check if the entity is new and not an update -func (d *DeviceRemoteImpl) CheckEntityInformation(initialData bool, entity model.NodeManagementDetailedDiscoveryEntityInformationType) error { - description := entity.Description - if description == nil { - return errors.New("nodemanagement.replyDetailedDiscoveryData: invalid EntityInformation.Description") - } - - if description.EntityAddress == nil { - return errors.New("nodemanagement.replyDetailedDiscoveryData: invalid EntityInformation.Description.EntityAddress") - } - - if description.EntityAddress.Entity == nil { - return errors.New("nodemanagement.replyDetailedDiscoveryData: invalid EntityInformation.Description.EntityAddress.Entity") - } - - // Consider on initial NodeManagement Detailed Discovery, the device being empty as it is not yet known - if initialData { - return nil - } - - address := d.Address() - if description.EntityAddress.Device != nil && address != nil && *description.EntityAddress.Device != *address { - return errors.New("nodemanagement.replyDetailedDiscoveryData: device address mismatch") - } - - return nil -} - -func (d *DeviceRemoteImpl) addNewEntity(eType model.EntityTypeType, address []model.AddressEntityType) *EntityRemoteImpl { - newEntity := NewEntityRemoteImpl(d, eType, address) - return d.addEntity(newEntity) -} - -func (d *DeviceRemoteImpl) addEntity(entity *EntityRemoteImpl) *EntityRemoteImpl { - d.entitiesMutex.Lock() - defer d.entitiesMutex.Unlock() - - d.entities = append(d.entities, entity) - - return entity -} - -func unmarshalFeature(entity *EntityRemoteImpl, - featureData model.NodeManagementDetailedDiscoveryFeatureInformationType, -) *FeatureRemoteImpl { - var result *FeatureRemoteImpl - - if fid := featureData.Description; fid != nil { - - result = NewFeatureRemoteImpl(uint(*fid.FeatureAddress.Feature), entity, *fid.FeatureType, *fid.Role) - - result.SetDescription(fid.Description) - result.SetMaxResponseDelay(fid.MaxResponseDelay) - result.SetOperations(fid.SupportedFunction) - } - - return result -} diff --git a/spine/entity.go b/spine/entity.go deleted file mode 100644 index 03396314..00000000 --- a/spine/entity.go +++ /dev/null @@ -1,80 +0,0 @@ -package spine - -import ( - "github.com/ahmetb/go-linq/v3" - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -const DeviceInformationEntityId uint = 0 - -var DeviceInformationAddressEntity = []model.AddressEntityType{model.AddressEntityType(DeviceInformationEntityId)} - -type EntityImpl struct { - eType model.EntityTypeType - address *model.EntityAddressType - description *model.DescriptionType - fIdGenerator func() uint -} - -func NewEntity(eType model.EntityTypeType, deviceAdress *model.AddressDeviceType, entityAddress []model.AddressEntityType) *EntityImpl { - entity := &EntityImpl{ - eType: eType, - address: &model.EntityAddressType{ - Device: deviceAdress, - Entity: entityAddress, - }, - } - if entityAddress[0] == 0 { - // Entity 0 Feature addresses start with 0 - entity.fIdGenerator = newFeatureIdGenerator(0) - } else { - // Entity 1 and further Feature addresses start with 1 - entity.fIdGenerator = newFeatureIdGenerator(1) - } - - return entity -} - -func (r *EntityImpl) EntityType() model.EntityTypeType { - return r.eType -} - -func (r *EntityImpl) Address() *model.EntityAddressType { - return r.address -} - -func (r *EntityImpl) SetDescription(d *model.DescriptionType) { - r.description = d -} - -func (r *EntityImpl) NextFeatureId() uint { - return r.fIdGenerator() -} - -func EntityAddressType(deviceAdress *model.AddressDeviceType, entityAddress []model.AddressEntityType) *model.EntityAddressType { - return &model.EntityAddressType{ - Device: deviceAdress, - Entity: entityAddress, - } -} - -func NewEntityAddressType(deviceName string, entityIds []uint) *model.EntityAddressType { - return &model.EntityAddressType{ - Device: util.Ptr(model.AddressDeviceType(deviceName)), - Entity: NewAddressEntityType(entityIds), - } -} - -func NewAddressEntityType(entityIds []uint) []model.AddressEntityType { - var addressEntity []model.AddressEntityType - linq.From(entityIds).SelectT(func(i uint) model.AddressEntityType { return model.AddressEntityType(i) }).ToSlice(&addressEntity) - return addressEntity -} - -func newFeatureIdGenerator(id uint) func() uint { - return func() uint { - defer func() { id += 1 }() - return id - } -} diff --git a/spine/entity_local.go b/spine/entity_local.go deleted file mode 100644 index 2fe0561a..00000000 --- a/spine/entity_local.go +++ /dev/null @@ -1,89 +0,0 @@ -package spine - -import ( - "github.com/enbility/eebus-go/spine/model" -) - -type EntityLocalImpl struct { - *EntityImpl - device *DeviceLocalImpl - features []FeatureLocal -} - -func NewEntityLocalImpl(device *DeviceLocalImpl, eType model.EntityTypeType, entityAddress []model.AddressEntityType) *EntityLocalImpl { - return &EntityLocalImpl{ - EntityImpl: NewEntity(eType, device.Address(), entityAddress), - device: device, - } -} - -func (r *EntityLocalImpl) Device() *DeviceLocalImpl { - return r.device -} - -// Add a feature to the entity if it is not already added -func (r *EntityLocalImpl) AddFeature(f FeatureLocal) { - // check if this feature is already added - for _, f2 := range r.features { - if f2.Type() == f.Type() && f2.Role() == f.Role() { - return - } - } - r.features = append(r.features, f) -} - -// either returns an existing feature or creates a new one -// for a given entity, featuretype and role -func (r *EntityLocalImpl) GetOrAddFeature(featureType model.FeatureTypeType, role model.RoleType) FeatureLocal { - if f := r.FeatureOfTypeAndRole(featureType, role); f != nil { - return f - } - f := NewFeatureLocalImpl(r.NextFeatureId(), r, featureType, role) - - description := string(featureType) - switch role { - case model.RoleTypeClient: - description += " Client" - case model.RoleTypeServer: - description += " Server" - } - f.SetDescriptionString(description) - r.features = append(r.features, f) - return f -} - -func (r *EntityLocalImpl) FeatureOfTypeAndRole(featureType model.FeatureTypeType, role model.RoleType) FeatureLocal { - for _, f := range r.features { - if f.Type() == featureType && f.Role() == role { - return f - } - } - return nil -} - -func (r *EntityLocalImpl) Features() []FeatureLocal { - return r.features -} - -func (r *EntityLocalImpl) Feature(addressFeature *model.AddressFeatureType) FeatureLocal { - if addressFeature == nil { - return nil - } - for _, f := range r.features { - if *f.Address().Feature == *addressFeature { - return f - } - } - return nil -} - -func (r *EntityLocalImpl) Information() *model.NodeManagementDetailedDiscoveryEntityInformationType { - res := model.NodeManagementDetailedDiscoveryEntityInformationType{ - Description: &model.NetworkManagementEntityDescriptionDataType{ - EntityAddress: r.Address(), - EntityType: &r.eType, - }, - } - - return &res -} diff --git a/spine/entity_remote.go b/spine/entity_remote.go deleted file mode 100644 index ed3b1e0f..00000000 --- a/spine/entity_remote.go +++ /dev/null @@ -1,43 +0,0 @@ -package spine - -import ( - "github.com/enbility/eebus-go/spine/model" -) - -type EntityRemoteImpl struct { - *EntityImpl - device *DeviceRemoteImpl - features []*FeatureRemoteImpl -} - -func NewEntityRemoteImpl(device *DeviceRemoteImpl, eType model.EntityTypeType, entityAddress []model.AddressEntityType) *EntityRemoteImpl { - return &EntityRemoteImpl{ - EntityImpl: NewEntity(eType, device.Address(), entityAddress), - device: device, - } -} - -func (r *EntityRemoteImpl) Device() *DeviceRemoteImpl { - return r.device -} - -func (r *EntityRemoteImpl) AddFeature(f *FeatureRemoteImpl) { - r.features = append(r.features, f) -} - -func (r *EntityRemoteImpl) Features() []*FeatureRemoteImpl { - return r.features -} - -func (r *EntityRemoteImpl) Feature(addressFeature *model.AddressFeatureType) *FeatureRemoteImpl { - for _, f := range r.features { - if *f.Address().Feature == *addressFeature { - return f - } - } - return nil -} - -func (r *EntityRemoteImpl) RemoveAllFeatures() { - r.features = nil -} diff --git a/spine/error.go b/spine/error.go deleted file mode 100644 index ce528b46..00000000 --- a/spine/error.go +++ /dev/null @@ -1,48 +0,0 @@ -package spine - -import ( - "fmt" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -type ErrorType struct { - ErrorNumber model.ErrorNumberType - Description *model.DescriptionType -} - -func NewErrorType(errorNumber model.ErrorNumberType, description string) *ErrorType { - return &ErrorType{ - ErrorNumber: errorNumber, - Description: util.Ptr(model.DescriptionType(description)), - } -} - -func NewErrorTypeFromNumber(errorNumber model.ErrorNumberType) *ErrorType { - return &ErrorType{ - ErrorNumber: errorNumber, - } -} - -func NewErrorTypeFromString(description string) *ErrorType { - return NewErrorType(model.ErrorNumberTypeGeneralError, description) -} - -func NewErrorTypeFromResult(result *model.ResultDataType) *ErrorType { - if *result.ErrorNumber == model.ErrorNumberTypeNoError { - return nil - } - - return &ErrorType{ - ErrorNumber: *result.ErrorNumber, - Description: result.Description, - } -} - -func (e *ErrorType) String() string { - if e.Description != nil && len(*e.Description) > 0 { - return fmt.Sprintf("Error %d: %s", e.ErrorNumber, *e.Description) - } - return fmt.Sprintf("Error %d", e.ErrorNumber) -} diff --git a/spine/events.go b/spine/events.go deleted file mode 100644 index 103bf4a1..00000000 --- a/spine/events.go +++ /dev/null @@ -1,85 +0,0 @@ -package spine - -import ( - "sync" - - "github.com/enbility/eebus-go/spine/model" -) - -var Events events - -type ElementChangeType uint16 - -const ( - ElementChangeAdd ElementChangeType = iota - ElementChangeUpdate - ElementChangeRemove -) - -type EventType uint16 - -const ( - EventTypeDeviceChange EventType = iota // Sent after successful response of NodeManagementDetailedDiscovery - EventTypeEntityChange // Sent after successful response of NodeManagementDetailedDiscovery - EventTypeSubscriptionChange // Sent after successful subscription request from remote - EventTypeBindingChange // Sent after successful binding request from remote - EventTypeDataChange // Sent after remote provided new data items for a function -) - -type EventPayload struct { - Ski string // required - EventType EventType // required - ChangeType ElementChangeType // required - Device *DeviceRemoteImpl // required for DetailedDiscovery Call - Entity *EntityRemoteImpl // required for DetailedDiscovery Call and Notify - Feature *FeatureRemoteImpl - CmdClassifier *model.CmdClassifierType // optional, used together with EventType EventTypeDataChange - Data any -} - -type EventHandler interface { - HandleEvent(EventPayload) -} - -type events struct { - mu sync.Mutex - handlers []EventHandler -} - -func (r *events) Subscribe(handler EventHandler) { - r.mu.Lock() - defer r.mu.Unlock() - - exists := false - for _, item := range r.handlers { - if item == handler { - exists = true - break - } - } - - if !exists { - r.handlers = append(r.handlers, handler) - } -} - -func (r *events) Unsubscribe(handler EventHandler) { - r.mu.Lock() - defer r.mu.Unlock() - - var newHandlers []EventHandler - for _, item := range r.handlers { - if item != handler { - newHandlers = append(newHandlers, item) - } - } - r.handlers = newHandlers -} - -func (r *events) Publish(payload EventPayload) { - r.mu.Lock() - defer r.mu.Unlock() - for _, handler := range r.handlers { - go handler.HandleEvent(payload) - } -} diff --git a/spine/feature.go b/spine/feature.go deleted file mode 100644 index e359daa9..00000000 --- a/spine/feature.go +++ /dev/null @@ -1,79 +0,0 @@ -package spine - -import ( - "fmt" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -type Feature interface { - Address() *model.FeatureAddressType - Type() model.FeatureTypeType - Role() model.RoleType -} - -type FeatureImpl struct { - address *model.FeatureAddressType - ftype model.FeatureTypeType - description *model.DescriptionType - role model.RoleType - operations map[model.FunctionType]*Operations -} - -var _ Feature = (*FeatureImpl)(nil) - -func NewFeatureImpl(address *model.FeatureAddressType, ftype model.FeatureTypeType, role model.RoleType) *FeatureImpl { - res := &FeatureImpl{ - address: address, - ftype: ftype, - role: role, - } - - return res -} - -func (r *FeatureImpl) Address() *model.FeatureAddressType { - return r.address -} - -func (r *FeatureImpl) Type() model.FeatureTypeType { - return r.ftype -} - -func (r *FeatureImpl) Role() model.RoleType { - return r.role -} - -func (r *FeatureImpl) Operations() map[model.FunctionType]*Operations { - return r.operations -} - -func (r *FeatureImpl) Description() *model.DescriptionType { - return r.description -} - -func (r *FeatureImpl) SetDescription(d *model.DescriptionType) { - r.description = d -} - -func (r *FeatureImpl) SetDescriptionString(s string) { - r.description = util.Ptr(model.DescriptionType(s)) -} - -func (r *FeatureImpl) String() string { - if r == nil { - return "" - } - return fmt.Sprintf("Id: %d (%s)", *r.Address().Feature, *r.Description()) -} - -func featureAddressType(id uint, entityAddress *model.EntityAddressType) *model.FeatureAddressType { - res := model.FeatureAddressType{ - Device: entityAddress.Device, - Entity: entityAddress.Entity, - Feature: util.Ptr(model.AddressFeatureType(id)), - } - - return &res -} diff --git a/spine/feature_local.go b/spine/feature_local.go deleted file mode 100644 index 11225c1a..00000000 --- a/spine/feature_local.go +++ /dev/null @@ -1,453 +0,0 @@ -package spine - -import ( - "fmt" - "time" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -type FeatureLocal interface { - Feature - Data(function model.FunctionType) any - SetData(function model.FunctionType, data any) - AddResultHandler(handler FeatureResult) - Information() *model.NodeManagementDetailedDiscoveryFeatureInformationType - AddFunctionType(function model.FunctionType, read, write bool) - RequestData( - function model.FunctionType, - selector any, - elements any, - destination *FeatureRemoteImpl) (*model.MsgCounterType, *ErrorType) - RequestDataBySenderAddress( - cmd model.CmdType, - sender Sender, - destinationSki string, - destinationAddress *model.FeatureAddressType, - maxDelay time.Duration) (*model.MsgCounterType, *ErrorType) - FetchRequestData( - msgCounter model.MsgCounterType, - destination *FeatureRemoteImpl) (any, *ErrorType) - RequestAndFetchData( - function model.FunctionType, - selector any, - elements any, - destination *FeatureRemoteImpl) (any, *ErrorType) - Subscribe(remoteDevice *DeviceRemoteImpl, remoteAdress *model.FeatureAddressType) (*model.MsgCounterType, *ErrorType) - // SubscribeAndWait(remoteDevice *DeviceRemoteImpl, remoteAdress *model.FeatureAddressType) *ErrorType // Subscribes the local feature to the given destination feature; the go routine will block until the response is processed - Bind(remoteDevice *DeviceRemoteImpl, remoteAdress *model.FeatureAddressType) (*model.MsgCounterType, *ErrorType) - // BindAndWait(remoteDevice *DeviceRemoteImpl, remoteAddress *model.FeatureAddressType) *ErrorType - NotifyData( - function model.FunctionType, - deleteSelector, partialSelector any, - partialWithoutSelector bool, - deleteElements any, - destination *FeatureRemoteImpl) (*model.MsgCounterType, *ErrorType) - WriteData( - function model.FunctionType, - deleteSelector, partialSelector any, - deleteElements any, - destination *FeatureRemoteImpl) (*model.MsgCounterType, *ErrorType) - HandleMessage(message *Message) *ErrorType -} - -type FeatureResult interface { - HandleResult(ResultMessage) -} - -var _ FeatureLocal = (*FeatureLocalImpl)(nil) - -type FeatureLocalImpl struct { - *FeatureImpl - entity *EntityLocalImpl - functionDataMap map[model.FunctionType]FunctionDataCmd - pendingRequests PendingRequests - resultHandler []FeatureResult -} - -func NewFeatureLocalImpl(id uint, entity *EntityLocalImpl, ftype model.FeatureTypeType, role model.RoleType) *FeatureLocalImpl { - res := &FeatureLocalImpl{ - FeatureImpl: NewFeatureImpl( - featureAddressType(id, entity.Address()), - ftype, - role), - entity: entity, - functionDataMap: make(map[model.FunctionType]FunctionDataCmd), - pendingRequests: NewPendingRequest(), - } - - for _, fd := range CreateFunctionData[FunctionDataCmd](ftype) { - res.functionDataMap[fd.Function()] = fd - } - res.operations = make(map[model.FunctionType]*Operations) - - return res -} - -func (r *FeatureLocalImpl) Device() *DeviceLocalImpl { - return r.entity.Device() -} - -func (r *FeatureLocalImpl) Entity() *EntityLocalImpl { - return r.entity -} - -// Add supported function to the feature if its role is Server or Special -func (r *FeatureLocalImpl) AddFunctionType(function model.FunctionType, read, write bool) { - if r.role != model.RoleTypeServer && r.role != model.RoleTypeSpecial { - return - } - if r.operations[function] != nil { - return - } - r.operations[function] = NewOperations(read, write) -} - -func (r *FeatureLocalImpl) Data(function model.FunctionType) any { - return r.functionData(function).DataAny() -} - -func (r *FeatureLocalImpl) SetData(function model.FunctionType, data any) { - fd := r.functionData(function) - fd.UpdateDataAny(data, nil, nil) - - r.Device().NotifySubscribers(r.Address(), fd.NotifyCmdType(nil, nil, false, nil)) -} - -func (r *FeatureLocalImpl) AddResultHandler(handler FeatureResult) { - r.resultHandler = append(r.resultHandler, handler) -} - -func (r *FeatureLocalImpl) Information() *model.NodeManagementDetailedDiscoveryFeatureInformationType { - var funs []model.FunctionPropertyType - for fun, operations := range r.operations { - var functionType model.FunctionType = model.FunctionType(fun) - sf := model.FunctionPropertyType{ - Function: &functionType, - PossibleOperations: operations.Information(), - } - - funs = append(funs, sf) - } - - res := model.NodeManagementDetailedDiscoveryFeatureInformationType{ - Description: &model.NetworkManagementFeatureDescriptionDataType{ - FeatureAddress: r.Address(), - FeatureType: &r.ftype, - Role: &r.role, - Description: r.description, - SupportedFunction: funs, - }, - } - - return &res -} - -func (r *FeatureLocalImpl) RequestData( - function model.FunctionType, - selector any, - elements any, - destination *FeatureRemoteImpl) (*model.MsgCounterType, *ErrorType) { - fd := r.functionData(function) - cmd := fd.ReadCmdType(selector, elements) - - return r.RequestDataBySenderAddress(cmd, destination.Sender(), destination.Device().ski, destination.Address(), destination.MaxResponseDelayDuration()) -} - -func (r *FeatureLocalImpl) RequestDataBySenderAddress( - cmd model.CmdType, - sender Sender, - deviceSki string, - destinationAddress *model.FeatureAddressType, - maxDelay time.Duration) (*model.MsgCounterType, *ErrorType) { - - msgCounter, err := sender.Request(model.CmdClassifierTypeRead, r.Address(), destinationAddress, false, []model.CmdType{cmd}) - if err == nil { - r.pendingRequests.Add(deviceSki, *msgCounter, maxDelay) - return msgCounter, nil - } - - return msgCounter, NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) -} - -// Wait and return the response from destination for a message with the msgCounter ID -// this will block until the response is received -func (r *FeatureLocalImpl) FetchRequestData( - msgCounter model.MsgCounterType, - destination *FeatureRemoteImpl) (any, *ErrorType) { - - return r.pendingRequests.GetData(destination.Device().ski, msgCounter) -} - -// Send a data request for function to destination and return the response -// this will block until the response is received -func (r *FeatureLocalImpl) RequestAndFetchData( - function model.FunctionType, - selector any, - elements any, - destination *FeatureRemoteImpl) (any, *ErrorType) { - - msgCounter, err := r.RequestData(function, selector, elements, destination) - if err != nil { - return nil, err - } - - return r.FetchRequestData(*msgCounter, destination) -} - -// Subscribe to a remote feature -func (r *FeatureLocalImpl) Subscribe(remoteDevice *DeviceRemoteImpl, remoteAdress *model.FeatureAddressType) (*model.MsgCounterType, *ErrorType) { - if r.Role() == model.RoleTypeServer { - return nil, NewErrorTypeFromString(fmt.Sprintf("the server feature '%s' cannot request a subscription", r)) - } - - msgCounter, err := remoteDevice.Sender().Subscribe(r.Address(), remoteAdress, r.ftype) - if err != nil { - return nil, NewErrorTypeFromString(err.Error()) - } - - return msgCounter, nil -} - -/* -TODO: check if this function is needed and can be fixed, see https://github.com/enbility/eebus-go/issues/31 -// Subscribe to a remote feature and wait for the result -func (r *FeatureLocalImpl) SubscribeAndWait(remoteDevice *DeviceRemoteImpl, remoteAdress *model.FeatureAddressType) *ErrorType { - if r.Role() == model.RoleTypeServer { - return NewErrorTypeFromString(fmt.Sprintf("the server feature '%s' cannot request a subscription", r)) - } - - msgCounter, err := remoteDevice.Sender().Subscribe(r.Address(), remoteAdress, r.ftype) - if err != nil { - return NewErrorTypeFromString(err.Error()) - } - - maxDelay := defaultMaxResponseDelay - rf := remoteDevice.FeatureByAddress(NodeManagementAddress(remoteDevice.Address())) - if rf != nil { - maxDelay = rf.MaxResponseDelayDuration() - } - - r.pendingRequests.Add(*msgCounter, maxDelay) - // this will block the go routine until the response is procedded - _, result := r.pendingRequests.GetData(*msgCounter) - // TODO: activate polling when subscription failed - - return result -} -*/ - -// Bind to a remote feature -func (r *FeatureLocalImpl) Bind(remoteDevice *DeviceRemoteImpl, remoteAddress *model.FeatureAddressType) (*model.MsgCounterType, *ErrorType) { - if r.Role() == model.RoleTypeServer { - return nil, NewErrorTypeFromString(fmt.Sprintf("the server feature '%s' cannot request a subscription", r)) - } - - msgCounter, err := remoteDevice.Sender().Bind(r.Address(), remoteAddress, r.ftype) - if err != nil { - return nil, NewErrorTypeFromString(err.Error()) - } - - return msgCounter, nil -} - -/* -TODO: check if this function is needed and can be fixed, see https://github.com/enbility/eebus-go/issues/31 -// Bind to a remote feature and wait for the result -func (r *FeatureLocalImpl) BindAndWait(remoteDevice *DeviceRemoteImpl, remoteAddress *model.FeatureAddressType) *ErrorType { - if r.Role() == model.RoleTypeServer { - return NewErrorTypeFromString(fmt.Sprintf("the server feature '%s' cannot request a subscription", r)) - } - - msgCounter, err := remoteDevice.Sender().Bind(r.Address(), remoteAddress, r.ftype) - if err != nil { - return NewErrorTypeFromString(err.Error()) - } - - maxDelay := defaultMaxResponseDelay - rf := remoteDevice.FeatureByAddress(remoteAddress) - if rf != nil { - maxDelay = rf.MaxResponseDelayDuration() - } - - r.pendingRequests.Add(*msgCounter, maxDelay) - // this will block the go routine until the response is procedded - _, result := r.pendingRequests.GetData(*msgCounter) - // TODO: activate polling when binding failed - - return result -} -*/ - -// Send a notification message with the current data of function to the destination -func (r *FeatureLocalImpl) NotifyData( - function model.FunctionType, - deleteSelector, partialSelector any, - partialWithoutSelector bool, - deleteElements any, - destination *FeatureRemoteImpl) (*model.MsgCounterType, *ErrorType) { - fd := r.functionData(function) - cmd := fd.NotifyCmdType(deleteSelector, partialSelector, partialWithoutSelector, deleteElements) - - msgCounter, err := destination.Sender().Request(model.CmdClassifierTypeRead, r.Address(), destination.Address(), false, []model.CmdType{cmd}) - if err != nil { - return nil, NewErrorTypeFromString(err.Error()) - } - return msgCounter, nil -} - -// Send a write message with provided data of function to the destination -func (r *FeatureLocalImpl) WriteData( - function model.FunctionType, - deleteSelector, partialSelector any, - deleteElements any, - destination *FeatureRemoteImpl) (*model.MsgCounterType, *ErrorType) { - fd := r.functionData(function) - cmd := fd.WriteCmdType(deleteSelector, partialSelector, deleteElements) - - msgCounter, err := destination.Sender().Write(r.Address(), destination.Address(), cmd) - if err != nil { - return nil, NewErrorTypeFromString(err.Error()) - } - - return msgCounter, nil -} - -func (r *FeatureLocalImpl) HandleMessage(message *Message) *ErrorType { - if message.Cmd.ResultData != nil { - return r.processResult(message) - } - - cmdData, err := message.Cmd.Data() - if err != nil { - return NewErrorType(model.ErrorNumberTypeCommandNotSupported, err.Error()) - } - if cmdData.Function == nil { - return NewErrorType(model.ErrorNumberTypeCommandNotSupported, "No function found for cmd data") - } - - switch message.CmdClassifier { - case model.CmdClassifierTypeRead: - if err := r.processRead(*cmdData.Function, message.RequestHeader, message.FeatureRemote); err != nil { - return err - } - case model.CmdClassifierTypeReply: - if err := r.processReply(*cmdData.Function, cmdData.Value, message.RequestHeader, message.FeatureRemote); err != nil { - return err - } - case model.CmdClassifierTypeNotify: - if err := r.processNotify(*cmdData.Function, cmdData.Value, message.FilterPartial, message.FilterDelete, message.FeatureRemote); err != nil { - return err - } - default: - return NewErrorTypeFromString(fmt.Sprintf("CmdClassifier not implemented: %s", message.CmdClassifier)) - } - - return nil -} - -func (r *FeatureLocalImpl) processResult(message *Message) *ErrorType { - switch message.CmdClassifier { - case model.CmdClassifierTypeResult: - if *message.Cmd.ResultData.ErrorNumber != model.ErrorNumberTypeNoError { - // error numbers explained in Resource Spec 3.11 - errorString := fmt.Sprintf("Error Result received %d", *message.Cmd.ResultData.ErrorNumber) - if message.Cmd.ResultData.Description != nil { - errorString += fmt.Sprintf(": %s", *message.Cmd.ResultData.Description) - } - logging.Log.Debug(errorString) - } - - // we don't need to populate this error as requests don't require a pendingRequest entry - _ = r.pendingRequests.SetResult(message.DeviceRemote.ski, *message.RequestHeader.MsgCounterReference, NewErrorTypeFromResult(message.Cmd.ResultData)) - - if r.resultHandler == nil || message.RequestHeader.MsgCounterReference == nil { - return nil - } - - // call the Features Error Handler - errorMsg := ResultMessage{ - MsgCounterReference: *message.RequestHeader.MsgCounterReference, - Result: message.Cmd.ResultData, - FeatureLocal: r, - FeatureRemote: message.FeatureRemote, - DeviceRemote: message.DeviceRemote, - } - - for _, item := range r.resultHandler { - go item.HandleResult(errorMsg) - } - - return nil - - default: - return NewErrorType( - model.ErrorNumberTypeGeneralError, - fmt.Sprintf("ResultData CmdClassifierType %s not implemented", message.CmdClassifier)) - } -} - -func (r *FeatureLocalImpl) processRead(function model.FunctionType, requestHeader *model.HeaderType, featureRemote *FeatureRemoteImpl) *ErrorType { - // is this a read request to a local server/special feature? - if r.role == model.RoleTypeClient { - // Read requests to a client feature are not allowed - return NewErrorTypeFromNumber(model.ErrorNumberTypeCommandRejected) - } - - cmd := r.functionData(function).ReplyCmdType(false) - if err := featureRemote.Sender().Reply(requestHeader, r.Address(), cmd); err != nil { - return NewErrorTypeFromString(err.Error()) - } - - return nil -} - -func (r *FeatureLocalImpl) processReply(function model.FunctionType, data any, requestHeader *model.HeaderType, featureRemote *FeatureRemoteImpl) *ErrorType { - featureRemote.UpdateData(function, data, nil, nil) - _ = r.pendingRequests.SetData(featureRemote.Device().ski, *requestHeader.MsgCounterReference, data) - // an error in SetData only means that there is no pendingRequest waiting for this dataset - // so this is nothing to consider as an error to return - - // the data was updated, so send an event, other event handlers may watch out for this as well - payload := EventPayload{ - Ski: featureRemote.Device().ski, - EventType: EventTypeDataChange, - ChangeType: ElementChangeUpdate, - Feature: featureRemote, - Device: featureRemote.Device(), - Entity: featureRemote.Entity(), - CmdClassifier: util.Ptr(model.CmdClassifierTypeReply), - Data: data, - } - Events.Publish(payload) - - return nil -} - -func (r *FeatureLocalImpl) processNotify(function model.FunctionType, data any, filterPartial *model.FilterType, filterDelete *model.FilterType, featureRemote *FeatureRemoteImpl) *ErrorType { - featureRemote.UpdateData(function, data, filterPartial, filterDelete) - - payload := EventPayload{ - Ski: featureRemote.Device().ski, - EventType: EventTypeDataChange, - ChangeType: ElementChangeUpdate, - Feature: featureRemote, - Device: featureRemote.Device(), - Entity: featureRemote.Entity(), - CmdClassifier: util.Ptr(model.CmdClassifierTypeNotify), - Data: data, - } - Events.Publish(payload) - - return nil -} - -func (r *FeatureLocalImpl) functionData(function model.FunctionType) FunctionDataCmd { - fd, found := r.functionDataMap[function] - if !found { - panic(fmt.Errorf("Data was not found for function '%s'", function)) - } - return fd -} diff --git a/spine/feature_local_test.go b/spine/feature_local_test.go deleted file mode 100644 index a7296b3e..00000000 --- a/spine/feature_local_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package spine_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/mocks" - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/suite" -) - -func TestDeviceClassificationSuite(t *testing.T) { - suite.Run(t, new(DeviceClassificationTestSuite)) -} - -type DeviceClassificationTestSuite struct { - suite.Suite - senderMock *mocks.Sender - function model.FunctionType - featureType model.FeatureTypeType - msgCounter model.MsgCounterType - remoteFeature *spine.FeatureRemoteImpl - sut *spine.FeatureLocalImpl -} - -func (suite *DeviceClassificationTestSuite) SetupSuite() { - suite.senderMock = mocks.NewSender(suite.T()) - suite.function = model.FunctionTypeDeviceClassificationManufacturerData - suite.featureType = model.FeatureTypeTypeDeviceClassification - suite.msgCounter = model.MsgCounterType(1) - - suite.remoteFeature = spine.CreateRemoteDeviceAndFeature(1, suite.featureType, model.RoleTypeServer, suite.senderMock) - suite.sut = CreateLocalDeviceAndFeature(1, suite.featureType, model.RoleTypeClient) -} - -func (suite *DeviceClassificationTestSuite) TestDeviceClassification_Request_Reply() { - suite.senderMock.On("Request", model.CmdClassifierTypeRead, suite.sut.Address(), suite.remoteFeature.Address(), false, mock.AnythingOfType("[]model.CmdType")).Return(&suite.msgCounter, nil) - - // send data request - msgCounter, err := suite.sut.RequestData(suite.function, nil, nil, suite.remoteFeature) - assert.Nil(suite.T(), err) - - manufacturerData := &model.DeviceClassificationManufacturerDataType{ - BrandName: util.Ptr(model.DeviceClassificationStringType("brand name")), - VendorName: util.Ptr(model.DeviceClassificationStringType("vendor name")), - DeviceName: util.Ptr(model.DeviceClassificationStringType("device name")), - DeviceCode: util.Ptr(model.DeviceClassificationStringType("device code")), - SerialNumber: util.Ptr(model.DeviceClassificationStringType("serial number")), - } - - replyMsg := spine.Message{ - Cmd: model.CmdType{ - DeviceClassificationManufacturerData: manufacturerData, - }, - CmdClassifier: model.CmdClassifierTypeReply, - RequestHeader: &model.HeaderType{ - MsgCounter: util.Ptr(model.MsgCounterType(1)), - MsgCounterReference: &suite.msgCounter, - }, - FeatureRemote: suite.remoteFeature, - } - // set response - msgErr := suite.sut.HandleMessage(&replyMsg) - if assert.Nil(suite.T(), msgErr) { - remoteData := suite.remoteFeature.Data(suite.function) - assert.IsType(suite.T(), &model.DeviceClassificationManufacturerDataType{}, remoteData, "Data has wrong type") - } - - // Act - result, err := suite.sut.FetchRequestData(*msgCounter, suite.remoteFeature) - assert.Nil(suite.T(), err) - assert.NotNil(suite.T(), result) - assert.IsType(suite.T(), &model.DeviceClassificationManufacturerDataType{}, result, "Data has wrong type") - receivedData := result.(*model.DeviceClassificationManufacturerDataType) - - assert.Equal(suite.T(), manufacturerData.BrandName, receivedData.BrandName) - assert.Equal(suite.T(), manufacturerData.VendorName, receivedData.VendorName) - assert.Equal(suite.T(), manufacturerData.DeviceName, receivedData.DeviceName) - assert.Equal(suite.T(), manufacturerData.DeviceCode, receivedData.DeviceCode) - assert.Equal(suite.T(), manufacturerData.SerialNumber, receivedData.SerialNumber) -} - -func (suite *DeviceClassificationTestSuite) TestDeviceClassification_Request_Error() { - suite.senderMock.On("Request", model.CmdClassifierTypeRead, suite.sut.Address(), suite.remoteFeature.Address(), false, mock.AnythingOfType("[]model.CmdType")).Return(&suite.msgCounter, nil) - - const errorNumber = model.ErrorNumberTypeGeneralError - const errorDescription = "error occurred" - - // send data request - msgCounter, err := suite.sut.RequestData(suite.function, nil, nil, suite.remoteFeature) - assert.Nil(suite.T(), err) - - replyMsg := spine.Message{ - Cmd: model.CmdType{ - ResultData: &model.ResultDataType{ - ErrorNumber: util.Ptr(model.ErrorNumberType(errorNumber)), - Description: util.Ptr(model.DescriptionType(errorDescription)), - }, - }, - CmdClassifier: model.CmdClassifierTypeResult, - RequestHeader: &model.HeaderType{ - MsgCounter: util.Ptr(model.MsgCounterType(1)), - MsgCounterReference: &suite.msgCounter, - }, - FeatureRemote: suite.remoteFeature, - EntityRemote: suite.remoteFeature.Entity(), - DeviceRemote: suite.remoteFeature.Device(), - } - - // set response - msgErr := suite.sut.HandleMessage(&replyMsg) - if assert.Nil(suite.T(), msgErr) { - remoteData := suite.remoteFeature.Data(suite.function) - assert.Nil(suite.T(), remoteData) - } - - // Act - result, err := suite.sut.FetchRequestData(*msgCounter, suite.remoteFeature) - assert.Nil(suite.T(), result) - assert.NotNil(suite.T(), err) - assert.Equal(suite.T(), errorNumber, err.ErrorNumber) - assert.Equal(suite.T(), errorDescription, string(*err.Description)) -} - -func CreateLocalDeviceAndFeature(entityId uint, featureType model.FeatureTypeType, role model.RoleType) *spine.FeatureLocalImpl { - localDevice := spine.NewDeviceLocalImpl("Vendor", "DeviceName", "SerialNumber", "DeviceCode", "Address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart) - localEntity := spine.NewEntityLocalImpl(localDevice, model.EntityTypeTypeEVSE, []model.AddressEntityType{model.AddressEntityType(entityId)}) - localDevice.AddEntity(localEntity) - localFeature := spine.NewFeatureLocalImpl(localEntity.NextFeatureId(), localEntity, featureType, role) - localEntity.AddFeature(localFeature) - return localFeature -} diff --git a/spine/feature_remote.go b/spine/feature_remote.go deleted file mode 100644 index 70a11f47..00000000 --- a/spine/feature_remote.go +++ /dev/null @@ -1,93 +0,0 @@ -package spine - -import ( - "fmt" - "time" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/rickb777/date/period" -) - -const defaultMaxResponseDelay = time.Duration(time.Second * 10) - -type FeatureRemoteImpl struct { - *FeatureImpl - entity *EntityRemoteImpl - functionDataMap map[model.FunctionType]FunctionData - maxResponseDelay *time.Duration -} - -func NewFeatureRemoteImpl(id uint, entity *EntityRemoteImpl, ftype model.FeatureTypeType, role model.RoleType) *FeatureRemoteImpl { - res := &FeatureRemoteImpl{ - FeatureImpl: NewFeatureImpl( - featureAddressType(id, entity.Address()), - ftype, - role), - entity: entity, - functionDataMap: make(map[model.FunctionType]FunctionData), - } - for _, fd := range CreateFunctionData[FunctionData](ftype) { - res.functionDataMap[fd.Function()] = fd - } - - res.operations = make(map[model.FunctionType]*Operations) - - return res -} - -func (r *FeatureRemoteImpl) Data(function model.FunctionType) any { - return r.functionData(function).DataAny() -} - -func (r *FeatureRemoteImpl) UpdateData(function model.FunctionType, data any, filterPartial *model.FilterType, filterDelete *model.FilterType) { - r.functionData(function).UpdateDataAny(data, filterPartial, filterDelete) - // TODO: fire event -} - -func (r *FeatureRemoteImpl) Sender() Sender { - return r.Device().Sender() -} - -func (r *FeatureRemoteImpl) Device() *DeviceRemoteImpl { - return r.entity.Device() -} - -func (r *FeatureRemoteImpl) Entity() *EntityRemoteImpl { - return r.entity -} - -func (r *FeatureRemoteImpl) SetOperations(functions []model.FunctionPropertyType) { - r.operations = make(map[model.FunctionType]*Operations) - for _, sf := range functions { - r.operations[*sf.Function] = NewOperations(sf.PossibleOperations.Read != nil, sf.PossibleOperations.Write != nil) - } -} - -func (r *FeatureRemoteImpl) SetMaxResponseDelay(delay *model.MaxResponseDelayType) { - if delay == nil { - return - } - p, err := period.Parse(string(*delay)) - if err != nil { - r.maxResponseDelay = util.Ptr(p.DurationApprox()) - } else { - logging.Log.Debug(err) - } -} - -func (r *FeatureRemoteImpl) MaxResponseDelayDuration() time.Duration { - if r.maxResponseDelay != nil { - return *r.maxResponseDelay - } - return defaultMaxResponseDelay -} - -func (r *FeatureRemoteImpl) functionData(function model.FunctionType) FunctionData { - fd, found := r.functionDataMap[function] - if !found { - panic(fmt.Errorf("Data was not found for function '%s'", function)) - } - return fd -} diff --git a/spine/feature_remote_test.go b/spine/feature_remote_test.go deleted file mode 100644 index fe006085..00000000 --- a/spine/feature_remote_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package spine - -import ( - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -func CreateRemoteDeviceAndFeature(entityId uint, featureType model.FeatureTypeType, role model.RoleType, sender Sender) *FeatureRemoteImpl { - localDevice := NewDeviceLocalImpl("Vendor", "DeviceName", "SerialNumber", "DeviceCode", "Address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart) - - remoteDevice := NewDeviceRemoteImpl(localDevice, "ski", nil) - remoteDevice.address = util.Ptr(model.AddressDeviceType("Address")) - remoteDevice.sender = sender - remoteEntity := NewEntityRemoteImpl(remoteDevice, model.EntityTypeTypeEVSE, []model.AddressEntityType{model.AddressEntityType(entityId)}) - remoteDevice.addEntity(remoteEntity) - remoteFeature := NewFeatureRemoteImpl(remoteEntity.NextFeatureId(), remoteEntity, featureType, role) - remoteEntity.AddFeature(remoteFeature) - return remoteFeature -} diff --git a/spine/function_data.go b/spine/function_data.go deleted file mode 100644 index f077e8cc..00000000 --- a/spine/function_data.go +++ /dev/null @@ -1,88 +0,0 @@ -package spine - -import ( - "fmt" - "sync" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -type FunctionData interface { - Function() model.FunctionType - DataAny() any - UpdateDataAny(data any, filterPartial *model.FilterType, filterDelete *model.FilterType) -} - -var _ FunctionData = (*FunctionDataImpl[int])(nil) - -type FunctionDataImpl[T any] struct { - functionType model.FunctionType - data *T - - mux sync.Mutex -} - -func NewFunctionData[T any](function model.FunctionType) *FunctionDataImpl[T] { - return &FunctionDataImpl[T]{ - functionType: function, - } -} - -func (r *FunctionDataImpl[T]) Function() model.FunctionType { - return r.functionType -} - -func (r *FunctionDataImpl[T]) Data() *T { - r.mux.Lock() - defer r.mux.Unlock() - - // copy the data and return it as the data can be updated - // and newly assigned at any time otherwise we run into panics - // because of invalid memory address or nil pointer dereference - var copiedData T - if r.data == nil { - return nil - } - - copiedData = *r.data - - return &copiedData -} - -func (r *FunctionDataImpl[T]) UpdateData(newData *T, filterPartial *model.FilterType, filterDelete *model.FilterType) *ErrorType { - r.mux.Lock() - defer r.mux.Unlock() - - if filterPartial == nil && filterDelete == nil { - // just set the data - r.data = newData - return nil - } - - supported := util.Implements[T, model.Updater]() - if !supported { - return NewErrorTypeFromString(fmt.Sprintf("partial updates are not supported for type '%s'", util.Type[T]().Name())) - } - - if r.data == nil { - r.data = new(T) - } - - updater := any(r.data).(model.Updater) - updater.UpdateList(newData, filterPartial, filterDelete) - - return nil -} - -func (r *FunctionDataImpl[T]) DataAny() any { - return r.Data() -} - -func (r *FunctionDataImpl[T]) UpdateDataAny(newData any, filterPartial *model.FilterType, filterDelete *model.FilterType) { - err := r.UpdateData(newData.(*T), filterPartial, filterDelete) - if err != nil { - logging.Log.Debug(err.String()) - } -} diff --git a/spine/function_data_cmd.go b/spine/function_data_cmd.go deleted file mode 100644 index d0ac25ba..00000000 --- a/spine/function_data_cmd.go +++ /dev/null @@ -1,841 +0,0 @@ -package spine - -import ( - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -type FunctionDataCmd interface { - FunctionData - ReadCmdType(partialSelector any, elements any) model.CmdType - ReplyCmdType(partial bool) model.CmdType - NotifyCmdType(deleteSelector, partialSelector any, partialWithoutSelector bool, deleteElements any) model.CmdType - WriteCmdType(deleteSelector, partialSelector any, deleteElements any) model.CmdType -} - -var _ FunctionDataCmd = (*FunctionDataCmdImpl[int])(nil) - -type FunctionDataCmdImpl[T any] struct { - *FunctionDataImpl[T] -} - -func NewFunctionDataCmd[T any](function model.FunctionType) *FunctionDataCmdImpl[T] { - return &FunctionDataCmdImpl[T]{ - FunctionDataImpl: NewFunctionData[T](function), - } -} - -func (r *FunctionDataCmdImpl[T]) ReadCmdType(partialSelector any, elements any) model.CmdType { - cmd := createCmd[T](r.functionType, nil) - - var filters []model.FilterType - filters = filtersForSelectorsElements(r.functionType, filters, nil, partialSelector, nil, elements) - if len(filters) > 0 { - cmd.Filter = filters - } - - return cmd -} - -func (r *FunctionDataCmdImpl[T]) ReplyCmdType(partial bool) model.CmdType { - cmd := createCmd(r.functionType, r.data) - if partial { - cmd.Filter = filterEmptyPartial() - } - return cmd -} - -func (r *FunctionDataCmdImpl[T]) NotifyCmdType(deleteSelector, partialSelector any, partialWithoutSelector bool, deleteElements any) model.CmdType { - cmd := createCmd(r.functionType, r.data) - cmd.Function = util.Ptr(model.FunctionType(r.functionType)) - - if partialWithoutSelector { - cmd.Filter = filterEmptyPartial() - return cmd - } - var filters []model.FilterType - if filters := filtersForSelectorsElements(r.functionType, filters, deleteSelector, partialSelector, deleteElements, nil); len(filters) > 0 { - cmd.Filter = filters - } - - return cmd -} - -func (r *FunctionDataCmdImpl[T]) WriteCmdType(deleteSelector, partialSelector any, deleteElements any) model.CmdType { - cmd := createCmd(r.functionType, r.data) - - var filters []model.FilterType - if filters := filtersForSelectorsElements(r.functionType, filters, deleteSelector, partialSelector, deleteElements, nil); len(filters) > 0 { - cmd.Filter = filters - } - - return cmd -} - -func filtersForSelectorsElements(functionType model.FunctionType, filters []model.FilterType, deleteSelector, partialSelector any, deleteElements, readElements any) []model.FilterType { - if deleteSelector != nil || deleteElements != nil { - filter := model.FilterType{CmdControl: &model.CmdControlType{Delete: &model.ElementTagType{}}} - if deleteSelector != nil { - filter = addSelectorToFilter(filter, functionType, &deleteSelector) - } - if deleteElements != nil { - filter = addElementToFilter(filter, functionType, &deleteElements) - } - filters = append(filters, filter) - } - - if partialSelector != nil || readElements != nil { - filter := model.FilterType{CmdControl: &model.CmdControlType{Partial: &model.ElementTagType{}}} - if partialSelector != nil { - filter = addSelectorToFilter(filter, functionType, &partialSelector) - } - if readElements != nil { - filter = addElementToFilter(filter, functionType, &readElements) - } - filters = append(filters, filter) - } - - return filters -} - -// simple helper for adding a single filterType without any selectors -func filterEmptyPartial() []model.FilterType { - return []model.FilterType{{CmdControl: &model.CmdControlType{Partial: &model.ElementTagType{}}}} -} - -func addSelectorToFilter[T any](filter model.FilterType, function model.FunctionType, data *T) model.FilterType { - result := filter - - switch function { - case model.FunctionTypeAlarmListData: - result.AlarmListDataSelectors = castData[model.AlarmListDataSelectorsType](data) - case model.FunctionTypeBillConstraintsListData: - result.BillConstraintsListDataSelectors = castData[model.BillConstraintsListDataSelectorsType](data) - case model.FunctionTypeBillDescriptionListData: - result.BillDescriptionListDataSelectors = castData[model.BillDescriptionListDataSelectorsType](data) - case model.FunctionTypeBillListData: - result.BillListDataSelectors = castData[model.BillListDataSelectorsType](data) - case model.FunctionTypeBindingManagementEntryListData: - result.BindingManagementEntryListDataSelectors = castData[model.BindingManagementEntryListDataSelectorsType](data) - case model.FunctionTypeCommodityListData: - result.CommodityListDataSelectors = castData[model.CommodityListDataSelectorsType](data) - case model.FunctionTypeDeviceConfigurationKeyValueConstraintsListData: - result.DeviceConfigurationKeyValueConstraintsListDataSelectors = castData[model.DeviceConfigurationKeyValueConstraintsListDataSelectorsType](data) - case model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData: - result.DeviceConfigurationKeyValueDescriptionListDataSelectors = castData[model.DeviceConfigurationKeyValueDescriptionListDataSelectorsType](data) - case model.FunctionTypeDeviceConfigurationKeyValueListData: - result.DeviceConfigurationKeyValueListDataSelectors = castData[model.DeviceConfigurationKeyValueListDataSelectorsType](data) - case model.FunctionTypeDirectControlActivityListData: - result.DirectControlActivityListDataSelectors = castData[model.DirectControlActivityListDataSelectorsType](data) - case model.FunctionTypeElectricalConnectionDescriptionListData: - filter.ElectricalConnectionDescriptionListDataSelectors = castData[model.ElectricalConnectionDescriptionListDataSelectorsType](data) - case model.FunctionTypeElectricalConnectionParameterDescriptionListData: - filter.ElectricalConnectionParameterDescriptionListDataSelectors = castData[model.ElectricalConnectionParameterDescriptionListDataSelectorsType](data) - case model.FunctionTypeElectricalConnectionPermittedValueSetListData: - result.ElectricalConnectionPermittedValueSetListDataSelectors = castData[model.ElectricalConnectionPermittedValueSetListDataSelectorsType](data) - case model.FunctionTypeElectricalConnectionStateListData: - result.ElectricalConnectionStateListDataSelectors = castData[model.ElectricalConnectionStateListDataSelectorsType](data) - case model.FunctionTypeHvacOperationModeDescriptionListData: - result.HvacOperationModeDescriptionListDataSelectors = castData[model.HvacOperationModeDescriptionListDataSelectorsType](data) - case model.FunctionTypeHvacOverrunDescriptionListData: - result.HvacOverrunDescriptionListDataSelectors = castData[model.HvacOverrunDescriptionListDataSelectorsType](data) - case model.FunctionTypeHvacOverrunListData: - result.HvacOverrunListDataSelectors = castData[model.HvacOverrunListDataSelectorsType](data) - case model.FunctionTypeHvacSystemFunctionDescriptionListData: - result.HvacSystemFunctionDescriptionListDataSelectors = castData[model.HvacSystemFunctionDescriptionListDataSelectorsType](data) - case model.FunctionTypeHvacSystemFunctionListData: - result.HvacSystemFunctionListDataSelectors = castData[model.HvacSystemFunctionListDataSelectorsType](data) - case model.FunctionTypeHvacSystemFunctionOperationModeRelationListData: - result.HvacSystemFunctionOperationModeRelationListDataSelectors = castData[model.HvacSystemFunctionOperationModeRelationListDataSelectorsType](data) - case model.FunctionTypeHvacSystemFunctionPowerSequenceRelationListData: - result.HvacSystemFunctionPowerSequenceRelationListDataSelectors = castData[model.HvacSystemFunctionPowerSequenceRelationListDataSelectorsType](data) - case model.FunctionTypeHvacSystemFunctionSetPointRelationListData: - result.HvacSystemFunctionSetpointRelationListDataSelectors = castData[model.HvacSystemFunctionSetpointRelationListDataSelectorsType](data) - case model.FunctionTypeIdentificationListData: - result.IdentificationListDataSelectors = castData[model.IdentificationListDataSelectorsType](data) - case model.FunctionTypeIncentiveDescriptionListData: - result.IncentiveDescriptionListDataSelectors = castData[model.IncentiveDescriptionListDataSelectorsType](data) - case model.FunctionTypeIncentiveListData: - result.IncentiveListDataSelectors = castData[model.IncentiveListDataSelectorsType](data) - case model.FunctionTypeIncentiveTableConstraintsData: - result.IncentiveTableConstraintsDataSelectors = castData[model.IncentiveTableConstraintsDataSelectorsType](data) - case model.FunctionTypeIncentiveTableData: - result.IncentiveTableDataSelectors = castData[model.IncentiveTableDataSelectorsType](data) - case model.FunctionTypeIncentiveTableDescriptionData: - result.IncentiveTableDescriptionDataSelectors = castData[model.IncentiveTableDescriptionDataSelectorsType](data) - case model.FunctionTypeLoadControlEventListData: - result.LoadControlEventListDataSelectors = castData[model.LoadControlEventListDataSelectorsType](data) - case model.FunctionTypeLoadControlLimitConstraintsListData: - result.LoadControlLimitConstraintsListDataSelectors = castData[model.LoadControlLimitConstraintsListDataSelectorsType](data) - case model.FunctionTypeLoadControlLimitDescriptionListData: - result.LoadControlLimitDescriptionListDataSelectors = castData[model.LoadControlLimitDescriptionListDataSelectorsType](data) - case model.FunctionTypeLoadControlLimitListData: - result.LoadControlLimitListDataSelectors = castData[model.LoadControlLimitListDataSelectorsType](data) - case model.FunctionTypeLoadControlStateListData: - result.LoadControlStateListDataSelectors = castData[model.LoadControlStateListDataSelectorsType](data) - case model.FunctionTypeMeasurementConstraintsListData: - result.MeasurementConstraintsListDataSelectors = castData[model.MeasurementConstraintsListDataSelectorsType](data) - case model.FunctionTypeMeasurementDescriptionListData: - result.MeasurementDescriptionListDataSelectors = castData[model.MeasurementDescriptionListDataSelectorsType](data) - case model.FunctionTypeMeasurementListData: - result.MeasurementListDataSelectors = castData[model.MeasurementListDataSelectorsType](data) - case model.FunctionTypeMeasurementThresholdRelationListData: - result.MeasurementThresholdRelationListDataSelectors = castData[model.MeasurementThresholdRelationListDataSelectorsType](data) - case model.FunctionTypeMessagingListData: - result.MessagingListDataSelectors = castData[model.MessagingListDataSelectorsType](data) - case model.FunctionTypeNetworkManagementDeviceDescriptionListData: - result.NetworkManagementDeviceDescriptionListDataSelectors = castData[model.NetworkManagementDeviceDescriptionListDataSelectorsType](data) - case model.FunctionTypeNetworkManagementEntityDescriptionListData: - result.NetworkManagementEntityDescriptionListDataSelectors = castData[model.NetworkManagementEntityDescriptionListDataSelectorsType](data) - case model.FunctionTypeNetworkManagementFeatureDescriptionListData: - result.NetworkManagementFeatureDescriptionListDataSelectors = castData[model.NetworkManagementFeatureDescriptionListDataSelectorsType](data) - case model.FunctionTypeNodeManagementBindingData: - result.NodeManagementBindingDataSelectors = castData[model.NodeManagementBindingDataSelectorsType](data) - case model.FunctionTypeNodeManagementDestinationListData: - result.NodeManagementDestinationListDataSelectors = castData[model.NodeManagementDestinationListDataSelectorsType](data) - case model.FunctionTypeNodeManagementDetailedDiscoveryData: - result.NodeManagementDetailedDiscoveryDataSelectors = castData[model.NodeManagementDetailedDiscoveryDataSelectorsType](data) - case model.FunctionTypeNodeManagementSubscriptionData: - result.NodeManagementSubscriptionDataSelectors = castData[model.NodeManagementSubscriptionDataSelectorsType](data) - case model.FunctionTypeNodeManagementUseCaseData: - result.NodeManagementUseCaseDataSelectors = castData[model.NodeManagementUseCaseDataSelectorsType](data) - case model.FunctionTypeOperatingConstraintsDurationListData: - result.OperatingConstraintsDurationListDataSelectors = castData[model.OperatingConstraintsDurationListDataSelectorsType](data) - case model.FunctionTypeOperatingConstraintsInterruptListData: - result.OperatingConstraintsInterruptListDataSelectors = castData[model.OperatingConstraintsInterruptListDataSelectorsType](data) - case model.FunctionTypeOperatingConstraintsPowerDescriptionListData: - result.OperatingConstraintsPowerDescriptionListDataSelectors = castData[model.OperatingConstraintsPowerDescriptionListDataSelectorsType](data) - case model.FunctionTypeOperatingConstraintsPowerLevelListData: - result.OperatingConstraintsPowerLevelListDataSelectors = castData[model.OperatingConstraintsPowerLevelListDataSelectorsType](data) - case model.FunctionTypeOperatingConstraintsPowerRangeListData: - result.OperatingConstraintsPowerRangeListDataSelectors = castData[model.OperatingConstraintsPowerRangeListDataSelectorsType](data) - case model.FunctionTypeOperatingConstraintsResumeImplicationListData: - result.OperatingConstraintsResumeImplicationListDataSelectors = castData[model.OperatingConstraintsResumeImplicationListDataSelectorsType](data) - case model.FunctionTypePowerSequenceAlternativesRelationListData: - result.PowerSequenceAlternativesRelationListDataSelectors = castData[model.PowerSequenceAlternativesRelationListDataSelectorsType](data) - case model.FunctionTypePowerSequenceDescriptionListData: - result.PowerSequenceDescriptionListDataSelectors = castData[model.PowerSequenceDescriptionListDataSelectorsType](data) - case model.FunctionTypePowerSequencePriceListData: - result.PowerSequencePriceListDataSelectors = castData[model.PowerSequencePriceListDataSelectorsType](data) - case model.FunctionTypePowerSequenceScheduleConstraintsListData: - result.PowerSequenceScheduleConstraintsListDataSelectors = castData[model.PowerSequenceScheduleConstraintsListDataSelectorsType](data) - case model.FunctionTypePowerSequenceScheduleListData: - result.PowerSequenceScheduleListDataSelectors = castData[model.PowerSequenceScheduleListDataSelectorsType](data) - case model.FunctionTypePowerSequenceSchedulePreferenceListData: - result.PowerSequenceSchedulePreferenceListDataSelectors = castData[model.PowerSequenceSchedulePreferenceListDataSelectorsType](data) - case model.FunctionTypePowerSequenceStateListData: - result.PowerSequenceStateListDataSelectors = castData[model.PowerSequenceStateListDataSelectorsType](data) - case model.FunctionTypePowerTimeSlotScheduleConstraintsListData: - result.PowerTimeSlotScheduleConstraintsListDataSelectors = castData[model.PowerTimeSlotScheduleConstraintsListDataSelectorsType](data) - case model.FunctionTypePowerTimeSlotScheduleListData: - result.PowerTimeSlotScheduleListDataSelectors = castData[model.PowerTimeSlotScheduleListDataSelectorsType](data) - case model.FunctionTypePowerTimeSlotValueListData: - result.PowerTimeSlotValueListDataSelectors = castData[model.PowerTimeSlotValueListDataSelectorsType](data) - case model.FunctionTypeSensingListData: - result.SensingListDataSelectors = castData[model.SensingListDataSelectorsType](data) - case model.FunctionTypeSetpointConstraintsListData: - result.SetpointConstraintsListDataSelectors = castData[model.SetpointConstraintsListDataSelectorsType](data) - case model.FunctionTypeSetpointDescriptionListData: - result.SetpointDescriptionListDataSelectors = castData[model.SetpointDescriptionListDataSelectorsType](data) - case model.FunctionTypeSetpointListData: - result.SetpointListDataSelectors = castData[model.SetpointListDataSelectorsType](data) - case model.FunctionTypeSmartEnergyManagementPsData: - result.SmartEnergyManagementPsDataSelectors = castData[model.SmartEnergyManagementPsDataSelectorsType](data) - case model.FunctionTypeSmartEnergyManagementPsPriceData: - result.SmartEnergyManagementPsPriceDataSelectors = castData[model.SmartEnergyManagementPsPriceDataSelectorsType](data) - case model.FunctionTypeSpecificationVersionListData: - result.SpecificationVersionListDataSelectors = castData[model.SpecificationVersionListDataSelectorsType](data) - case model.FunctionTypeSupplyConditionListData: - result.SupplyConditionListDataSelectors = castData[model.SupplyConditionListDataSelectorsType](data) - case model.FunctionTypeSupplyConditionThresholdRelationListData: - result.SupplyConditionThresholdRelationListDataSelectors = castData[model.SupplyConditionThresholdRelationListDataSelectorsType](data) - case model.FunctionTypeTariffBoundaryRelationListData: - result.TariffBoundaryRelationListDataSelectors = castData[model.TariffBoundaryRelationListDataSelectorsType](data) - case model.FunctionTypeTariffDescriptionListData: - result.TariffDescriptionListDataSelectors = castData[model.TariffDescriptionListDataSelectorsType](data) - case model.FunctionTypeTariffListData: - result.TariffListDataSelectors = castData[model.TariffListDataSelectorsType](data) - case model.FunctionTypeTariffTierRelationListData: - result.TariffTierRelationListDataSelectors = castData[model.TariffTierRelationListDataSelectorsType](data) - case model.FunctionTypeTaskManagementJobDescriptionListData: - result.TaskManagementJobDescriptionListDataSelectors = castData[model.TaskManagementJobDescriptionListDataSelectorsType](data) - case model.FunctionTypeTaskManagementJobListData: - result.TaskManagementJobListDataSelectors = castData[model.TaskManagementJobListDataSelectorsType](data) - case model.FunctionTypeTaskManagementJobRelationListData: - result.TaskManagementJobRelationListDataSelectors = castData[model.TaskManagementJobRelationListDataSelectorsType](data) - case model.FunctionTypeThresholdConstraintsListData: - result.ThresholdConstraintsListDataSelectors = castData[model.ThresholdConstraintsListDataSelectorsType](data) - case model.FunctionTypeThresholdDescriptionListData: - result.ThresholdDescriptionListDataSelectors = castData[model.ThresholdDescriptionListDataSelectorsType](data) - case model.FunctionTypeThresholdListData: - result.ThresholdListDataSelectors = castData[model.ThresholdListDataSelectorsType](data) - case model.FunctionTypeTierBoundaryDescriptionListData: - result.TierBoundaryDescriptionListDataSelectors = castData[model.TierBoundaryDescriptionListDataSelectorsType](data) - case model.FunctionTypeTierBoundaryListData: - result.TierBoundaryListDataSelectors = castData[model.TierBoundaryListDataSelectorsType](data) - case model.FunctionTypeTierDescriptionListData: - result.TierDescriptionListDataSelectors = castData[model.TierDescriptionListDataSelectorsType](data) - case model.FunctionTypeTierIncentiveRelationListData: - result.TierIncentiveRelationListDataSelectors = castData[model.TierIncentiveRelationListDataSelectorsType](data) - case model.FunctionTypeTierListData: - result.TierListDataSelectors = castData[model.TierListDataSelectorsType](data) - case model.FunctionTypeTimeSeriesConstraintsListData: - result.TimeSeriesConstraintsListDataSelectors = castData[model.TimeSeriesConstraintsListDataSelectorsType](data) - case model.FunctionTypeTimeSeriesDescriptionListData: - result.TimeSeriesDescriptionListDataSelectors = castData[model.TimeSeriesDescriptionListDataSelectorsType](data) - case model.FunctionTypeTimeSeriesListData: - result.TimeSeriesListDataSelectors = castData[model.TimeSeriesListDataSelectorsType](data) - case model.FunctionTypeTimeTableConstraintsListData: - result.TimeTableConstraintsListDataSelectors = castData[model.TimeTableConstraintsListDataSelectorsType](data) - case model.FunctionTypeTimeTableDescriptionListData: - result.TimeTableDescriptionListDataSelectors = castData[model.TimeTableDescriptionListDataSelectorsType](data) - case model.FunctionTypeTimeTableListData: - result.TimeTableListDataSelectors = castData[model.TimeTableListDataSelectorsType](data) - case model.FunctionTypeUseCaseInformationListData: - result.UseCaseInformationListDataSelectors = castData[model.UseCaseInformationListDataSelectorsType](data) - } - - return result -} - -func addElementToFilter[T any](filter model.FilterType, function model.FunctionType, data *T) model.FilterType { - result := filter - - switch function { - case model.FunctionTypeActuatorLevelData: - result.ActuatorLevelDataElements = castData[model.ActuatorLevelDataElementsType](data) - case model.FunctionTypeActuatorLevelDescriptionData: - result.ActuatorLevelDescriptionDataElements = castData[model.ActuatorLevelDescriptionDataElementsType](data) - case model.FunctionTypeActuatorSwitchData: - result.ActuatorSwitchDataElements = castData[model.ActuatorSwitchDataElementsType](data) - case model.FunctionTypeActuatorSwitchDescriptionData: - result.ActuatorSwitchDescriptionDataElements = castData[model.ActuatorSwitchDescriptionDataElementsType](data) - case model.FunctionTypeAlarmListData: - result.AlarmDataElements = castData[model.AlarmDataElementsType](data) - case model.FunctionTypeBillConstraintsListData: - result.BillConstraintsDataElements = castData[model.BillConstraintsDataElementsType](data) - case model.FunctionTypeBillDescriptionListData: - result.BillDescriptionDataElements = castData[model.BillDescriptionDataElementsType](data) - case model.FunctionTypeBillListData: - result.BillDataElements = castData[model.BillDataElementsType](data) - case model.FunctionTypeBindingManagementDeleteCall: - result.BindingManagementDeleteCallElements = castData[model.BindingManagementDeleteCallElementsType](data) - case model.FunctionTypeBindingManagementEntryListData: - result.BindingManagementEntryDataElements = castData[model.BindingManagementEntryDataElementsType](data) - case model.FunctionTypeBindingManagementRequestCall: - result.BindingManagementRequestCallElements = castData[model.BindingManagementRequestCallElementsType](data) - case model.FunctionTypeCommodityListData: - result.CommodityDataElements = castData[model.CommodityDataElementsType](data) - case model.FunctionTypeDataTunnelingCall: - result.DataTunnelingCallElements = castData[model.DataTunnelingCallElementsType](data) - case model.FunctionTypeDeviceClassificationManufacturerData: - result.DeviceClassificationManufacturerDataElements = castData[model.DeviceClassificationManufacturerDataElementsType](data) - case model.FunctionTypeDeviceClassificationUserData: - result.DeviceClassificationUserDataElements = castData[model.DeviceClassificationUserDataElementsType](data) - case model.FunctionTypeDeviceConfigurationKeyValueConstraintsListData: - result.DeviceConfigurationKeyValueConstraintsDataElements = castData[model.DeviceConfigurationKeyValueConstraintsDataElementsType](data) - case model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData: - result.DeviceConfigurationKeyValueDescriptionDataElements = castData[model.DeviceConfigurationKeyValueDescriptionDataElementsType](data) - case model.FunctionTypeDeviceConfigurationKeyValueListData: - result.DeviceConfigurationKeyValueDataElements = castData[model.DeviceConfigurationKeyValueDataElementsType](data) - case model.FunctionTypeDeviceDiagnosisHeartbeatData: - result.DeviceDiagnosisHeartbeatDataElements = castData[model.DeviceDiagnosisHeartbeatDataElementsType](data) - case model.FunctionTypeDeviceDiagnosisServiceData: - result.DeviceDiagnosisServiceDataElements = castData[model.DeviceDiagnosisServiceDataElementsType](data) - case model.FunctionTypeDeviceDiagnosisStateData: - result.DeviceDiagnosisStateDataElements = castData[model.DeviceDiagnosisStateDataElementsType](data) - case model.FunctionTypeDirectControlActivityListData: - result.DirectControlActivityDataElements = castData[model.DirectControlActivityDataElementsType](data) - case model.FunctionTypeDirectControlDescriptionData: - result.DirectControlDescriptionDataElements = castData[model.DirectControlDescriptionDataElementsType](data) - case model.FunctionTypeElectricalConnectionDescriptionListData: - result.ElectricalConnectionDescriptionDataElements = castData[model.ElectricalConnectionDescriptionDataElementsType](data) - case model.FunctionTypeElectricalConnectionParameterDescriptionListData: - result.ElectricalConnectionParameterDescriptionDataElements = castData[model.ElectricalConnectionParameterDescriptionDataElementsType](data) - case model.FunctionTypeElectricalConnectionPermittedValueSetListData: - result.ElectricalConnectionPermittedValueSetDataElements = castData[model.ElectricalConnectionPermittedValueSetDataElementsType](data) - case model.FunctionTypeElectricalConnectionStateListData: - result.ElectricalConnectionStateDataElements = castData[model.ElectricalConnectionStateDataElementsType](data) - case model.FunctionTypeHvacOperationModeDescriptionListData: - result.HvacOperationModeDescriptionDataElements = castData[model.HvacOperationModeDescriptionDataElementsType](data) - case model.FunctionTypeHvacOverrunDescriptionListData: - result.HvacOverrunDescriptionDataElements = castData[model.HvacOverrunDescriptionDataElementsType](data) - case model.FunctionTypeHvacOverrunListData: - result.HvacOverrunDataElements = castData[model.HvacOverrunDataElementsType](data) - case model.FunctionTypeHvacSystemFunctionDescriptionListData: - result.HvacSystemFunctionDescriptionDataElements = castData[model.HvacSystemFunctionDescriptionDataElementsType](data) - case model.FunctionTypeHvacSystemFunctionListData: - result.HvacSystemFunctionDataElements = castData[model.HvacSystemFunctionDataElementsType](data) - case model.FunctionTypeHvacSystemFunctionOperationModeRelationListData: - result.HvacSystemFunctionOperationModeRelationDataElements = castData[model.HvacSystemFunctionOperationModeRelationDataElementsType](data) - case model.FunctionTypeHvacSystemFunctionPowerSequenceRelationListData: - result.HvacSystemFunctionPowerSequenceRelationDataElements = castData[model.HvacSystemFunctionPowerSequenceRelationDataElementsType](data) - case model.FunctionTypeHvacSystemFunctionSetPointRelationListData: - result.HvacSystemFunctionSetpointRelationDataElements = castData[model.HvacSystemFunctionSetpointRelationDataElementsType](data) - case model.FunctionTypeIdentificationListData: - result.IdentificationDataElements = castData[model.IdentificationDataElementsType](data) - case model.FunctionTypeIncentiveDescriptionListData: - result.IncentiveDescriptionDataElements = castData[model.IncentiveDescriptionDataElementsType](data) - case model.FunctionTypeIncentiveListData: - result.IncentiveDataElements = castData[model.IncentiveDataElementsType](data) - case model.FunctionTypeIncentiveTableConstraintsData: - result.IncentiveTableConstraintsDataElements = castData[model.IncentiveTableConstraintsDataElementsType](data) - case model.FunctionTypeIncentiveTableData: - result.IncentiveTableDataElements = castData[model.IncentiveTableDataElementsType](data) - case model.FunctionTypeIncentiveTableDescriptionData: - result.IncentiveTableDescriptionDataElements = castData[model.IncentiveTableDescriptionDataElementsType](data) - case model.FunctionTypeLoadControlEventListData: - result.LoadControlEventDataElements = castData[model.LoadControlEventDataElementsType](data) - case model.FunctionTypeLoadControlLimitConstraintsListData: - result.LoadControlLimitConstraintsDataElements = castData[model.LoadControlLimitConstraintsDataElementsType](data) - case model.FunctionTypeLoadControlLimitDescriptionListData: - result.LoadControlLimitDescriptionDataElements = castData[model.LoadControlLimitDescriptionDataElementsType](data) - case model.FunctionTypeLoadControlLimitListData: - result.LoadControlLimitDataElements = castData[model.LoadControlLimitDataElementsType](data) - case model.FunctionTypeLoadControlNodeData: - result.LoadControlNodeDataElements = castData[model.LoadControlNodeDataElementsType](data) - case model.FunctionTypeLoadControlStateListData: - result.LoadControlStateDataElements = castData[model.LoadControlStateDataElementsType](data) - case model.FunctionTypeMeasurementConstraintsListData: - result.MeasurementConstraintsDataElements = castData[model.MeasurementConstraintsDataElementsType](data) - case model.FunctionTypeMeasurementDescriptionListData: - result.MeasurementDescriptionDataElements = castData[model.MeasurementDescriptionDataElementsType](data) - case model.FunctionTypeMeasurementListData: - result.MeasurementDataElements = castData[model.MeasurementDataElementsType](data) - case model.FunctionTypeMeasurementThresholdRelationListData: - result.MeasurementThresholdRelationDataElements = castData[model.MeasurementThresholdRelationDataElementsType](data) - case model.FunctionTypeMessagingListData: - result.MessagingDataElements = castData[model.MessagingDataElementsType](data) - case model.FunctionTypeNetworkManagementAbortCall: - result.NetworkManagementAbortCallElements = castData[model.NetworkManagementAbortCallElementsType](data) - case model.FunctionTypeNetworkManagementAddNodeCall: - result.NetworkManagementAddNodeCallElements = castData[model.NetworkManagementAddNodeCallElementsType](data) - case model.FunctionTypeNetworkManagementDeviceDescriptionListData: - result.NetworkManagementDeviceDescriptionDataElements = castData[model.NetworkManagementDeviceDescriptionDataElementsType](data) - case model.FunctionTypeNetworkManagementDiscoverCall: - result.NetworkManagementDiscoverCallElements = castData[model.NetworkManagementDiscoverCallElementsType](data) - case model.FunctionTypeNetworkManagementEntityDescriptionListData: - result.NetworkManagementEntityDescriptionDataElements = castData[model.NetworkManagementEntityDescriptionDataElementsType](data) - case model.FunctionTypeNetworkManagementFeatureDescriptionListData: - result.NetworkManagementFeatureDescriptionDataElements = castData[model.NetworkManagementFeatureDescriptionDataElementsType](data) - case model.FunctionTypeNetworkManagementJoiningModeData: - result.NetworkManagementJoiningModeDataElements = castData[model.NetworkManagementJoiningModeDataElementsType](data) - case model.FunctionTypeNetworkManagementModifyNodeCall: - result.NetworkManagementModifyNodeCallElements = castData[model.NetworkManagementModifyNodeCallElementsType](data) - case model.FunctionTypeNetworkManagementProcessStateData: - result.NetworkManagementProcessStateDataElements = castData[model.NetworkManagementProcessStateDataElementsType](data) - case model.FunctionTypeNetworkManagementRemoveNodeCall: - result.NetworkManagementRemoveNodeCallElements = castData[model.NetworkManagementRemoveNodeCallElementsType](data) - case model.FunctionTypeNetworkManagementReportCandidateData: - result.NetworkManagementReportCandidateDataElements = castData[model.NetworkManagementReportCandidateDataElementsType](data) - case model.FunctionTypeNetworkManagementScanNetworkCall: - result.NetworkManagementScanNetworkCallElements = castData[model.NetworkManagementScanNetworkCallElementsType](data) - case model.FunctionTypeNodeManagementBindingData: - result.NodeManagementBindingDataElements = castData[model.NodeManagementBindingDataElementsType](data) - case model.FunctionTypeNodeManagementBindingDeleteCall: - result.NodeManagementBindingDeleteCallElements = castData[model.NodeManagementBindingDeleteCallElementsType](data) - case model.FunctionTypeNodeManagementBindingRequestCall: - result.NodeManagementBindingRequestCallElements = castData[model.NodeManagementBindingRequestCallElementsType](data) - case model.FunctionTypeNodeManagementDestinationListData: - result.NodeManagementDestinationDataElements = castData[model.NodeManagementDestinationDataElementsType](data) - case model.FunctionTypeNodeManagementDetailedDiscoveryData: - result.NodeManagementDetailedDiscoveryDataElements = castData[model.NodeManagementDetailedDiscoveryDataElementsType](data) - case model.FunctionTypeNodeManagementSubscriptionData: - result.NodeManagementSubscriptionDataElements = castData[model.NodeManagementSubscriptionDataElementsType](data) - case model.FunctionTypeNodeManagementSubscriptionDeleteCall: - result.NodeManagementSubscriptionDeleteCallElements = castData[model.NodeManagementSubscriptionDeleteCallElementsType](data) - case model.FunctionTypeNodeManagementSubscriptionRequestCall: - result.NodeManagementSubscriptionRequestCallElements = castData[model.NodeManagementSubscriptionRequestCallElementsType](data) - case model.FunctionTypeNodeManagementUseCaseData: - result.NodeManagementUseCaseDataElements = castData[model.NodeManagementUseCaseDataElementsType](data) - case model.FunctionTypeOperatingConstraintsDurationListData: - result.OperatingConstraintsDurationDataElements = castData[model.OperatingConstraintsDurationDataElementsType](data) - case model.FunctionTypeOperatingConstraintsInterruptListData: - result.OperatingConstraintsInterruptDataElements = castData[model.OperatingConstraintsInterruptDataElementsType](data) - case model.FunctionTypeOperatingConstraintsPowerDescriptionListData: - result.OperatingConstraintsPowerDescriptionDataElements = castData[model.OperatingConstraintsPowerDescriptionDataElementsType](data) - case model.FunctionTypeOperatingConstraintsPowerLevelListData: - result.OperatingConstraintsPowerLevelDataElements = castData[model.OperatingConstraintsPowerLevelDataElementsType](data) - case model.FunctionTypeOperatingConstraintsPowerRangeListData: - result.OperatingConstraintsPowerRangeDataElements = castData[model.OperatingConstraintsPowerRangeDataElementsType](data) - case model.FunctionTypeOperatingConstraintsResumeImplicationListData: - result.OperatingConstraintsResumeImplicationDataElements = castData[model.OperatingConstraintsResumeImplicationDataElementsType](data) - case model.FunctionTypePowerSequenceAlternativesRelationListData: - result.PowerSequenceAlternativesRelationDataElements = castData[model.PowerSequenceAlternativesRelationDataElementsType](data) - case model.FunctionTypePowerSequenceDescriptionListData: - result.PowerSequenceDescriptionDataElements = castData[model.PowerSequenceDescriptionDataElementsType](data) - case model.FunctionTypePowerSequenceNodeScheduleInformationData: - result.PowerSequenceNodeScheduleInformationDataElements = castData[model.PowerSequenceNodeScheduleInformationDataElementsType](data) - case model.FunctionTypePowerSequencePriceCalculationRequestCall: - result.PowerSequencePriceCalculationRequestCallElements = castData[model.PowerSequencePriceCalculationRequestCallElementsType](data) - case model.FunctionTypePowerSequencePriceListData: - result.PowerSequencePriceDataElements = castData[model.PowerSequencePriceDataElementsType](data) - case model.FunctionTypePowerSequenceScheduleConfigurationRequestCall: - result.PowerSequenceScheduleConfigurationRequestCallElements = castData[model.PowerSequenceScheduleConfigurationRequestCallElementsType](data) - case model.FunctionTypePowerSequenceScheduleConstraintsListData: - result.PowerSequenceScheduleConstraintsDataElements = castData[model.PowerSequenceScheduleConstraintsDataElementsType](data) - case model.FunctionTypePowerSequenceScheduleListData: - result.PowerSequenceScheduleDataElements = castData[model.PowerSequenceScheduleDataElementsType](data) - case model.FunctionTypePowerSequenceSchedulePreferenceListData: - result.PowerSequenceSchedulePreferenceDataElements = castData[model.PowerSequenceSchedulePreferenceDataElementsType](data) - case model.FunctionTypePowerSequenceStateListData: - result.PowerSequenceStateDataElements = castData[model.PowerSequenceStateDataElementsType](data) - case model.FunctionTypePowerTimeSlotScheduleConstraintsListData: - result.PowerTimeSlotScheduleConstraintsDataElements = castData[model.PowerTimeSlotScheduleConstraintsDataElementsType](data) - case model.FunctionTypePowerTimeSlotScheduleListData: - result.PowerTimeSlotScheduleDataElements = castData[model.PowerTimeSlotScheduleDataElementsType](data) - case model.FunctionTypePowerTimeSlotValueListData: - result.PowerTimeSlotValueDataElements = castData[model.PowerTimeSlotValueDataElementsType](data) - case model.FunctionTypeSensingListData: - result.SensingDataElements = castData[model.SensingDataElementsType](data) - case model.FunctionTypeSetpointConstraintsListData: - result.SetpointConstraintsDataElements = castData[model.SetpointConstraintsDataElementsType](data) - case model.FunctionTypeSetpointDescriptionListData: - result.SensingDescriptionDataElements = castData[model.SensingDescriptionDataElementsType](data) - case model.FunctionTypeSetpointListData: - result.SetpointDataElements = castData[model.SetpointDataElementsType](data) - case model.FunctionTypeSmartEnergyManagementPsConfigurationRequestCall: - result.SmartEnergyManagementPsConfigurationRequestCallElements = castData[model.SmartEnergyManagementPsConfigurationRequestCallElementsType](data) - case model.FunctionTypeSmartEnergyManagementPsData: - result.SmartEnergyManagementPsDataElements = castData[model.SmartEnergyManagementPsDataElementsType](data) - case model.FunctionTypeSmartEnergyManagementPsPriceCalculationRequestCall: - result.SmartEnergyManagementPsPriceCalculationRequestCallElements = castData[model.SmartEnergyManagementPsPriceCalculationRequestCallElementsType](data) - case model.FunctionTypeSmartEnergyManagementPsPriceData: - result.SmartEnergyManagementPsPriceDataElements = castData[model.SmartEnergyManagementPsPriceDataElementsType](data) - case model.FunctionTypeSpecificationVersionListData: - result.SpecificationVersionDataElements = castData[model.SpecificationVersionDataElementsType](data) - case model.FunctionTypeSubscriptionManagementDeleteCall: - result.SubscriptionManagementDeleteCallElements = castData[model.SubscriptionManagementDeleteCallElementsType](data) - case model.FunctionTypeSubscriptionManagementEntryListData: - result.SubscriptionManagementEntryDataElements = castData[model.SubscriptionManagementEntryDataElementsType](data) - case model.FunctionTypeSubscriptionManagementRequestCall: - result.SubscriptionManagementRequestCallElements = castData[model.SubscriptionManagementRequestCallElementsType](data) - case model.FunctionTypeSupplyConditionListData: - result.SupplyConditionDataElements = castData[model.SupplyConditionDataElementsType](data) - case model.FunctionTypeSupplyConditionDescriptionListData: - result.SupplyConditionDescriptionDataElements = castData[model.SupplyConditionDescriptionDataElementsType](data) - case model.FunctionTypeSupplyConditionThresholdRelationListData: - result.SupplyConditionThresholdRelationDataElements = castData[model.SupplyConditionThresholdRelationDataElementsType](data) - case model.FunctionTypeTariffBoundaryRelationListData: - result.TariffBoundaryRelationDataElements = castData[model.TariffBoundaryRelationDataElementsType](data) - case model.FunctionTypeTariffDescriptionListData: - result.TariffDescriptionDataElements = castData[model.TariffDescriptionDataElementsType](data) - case model.FunctionTypeTariffListData: - result.TariffDataElements = castData[model.TariffDataElementsType](data) - case model.FunctionTypeTariffOverallConstraintsData: - result.TariffOverallConstraintsDataElements = castData[model.TariffOverallConstraintsDataElementsType](data) - case model.FunctionTypeTariffTierRelationListData: - result.TariffTierRelationDataElements = castData[model.TariffTierRelationDataElementsType](data) - case model.FunctionTypeTaskManagementJobDescriptionListData: - result.TaskManagementJobDescriptionDataElements = castData[model.TaskManagementJobDescriptionDataElementsType](data) - case model.FunctionTypeTaskManagementJobListData: - result.TaskManagementJobDataElements = castData[model.TaskManagementJobDataElementsType](data) - case model.FunctionTypeTaskManagementJobRelationListData: - result.TaskManagementJobRelationDataElements = castData[model.TaskManagementJobRelationDataElementsType](data) - case model.FunctionTypeTaskManagementOverviewData: - result.TaskManagementOverviewDataElements = castData[model.TaskManagementOverviewDataElementsType](data) - case model.FunctionTypeThresholdConstraintsListData: - result.ThresholdConstraintsDataElements = castData[model.ThresholdConstraintsDataElementsType](data) - case model.FunctionTypeThresholdDescriptionListData: - result.ThresholdDescriptionDataElements = castData[model.ThresholdDescriptionDataElementsType](data) - case model.FunctionTypeThresholdListData: - result.ThresholdDataElements = castData[model.ThresholdDataElementsType](data) - case model.FunctionTypeTierBoundaryDescriptionListData: - result.TierBoundaryDescriptionDataElements = castData[model.TierBoundaryDescriptionDataElementsType](data) - case model.FunctionTypeTierBoundaryListData: - result.TierBoundaryDataElements = castData[model.TierBoundaryDataElementsType](data) - case model.FunctionTypeTierDescriptionListData: - result.TierDescriptionDataElements = castData[model.TierDescriptionDataElementsType](data) - case model.FunctionTypeTierIncentiveRelationListData: - result.TierIncentiveRelationDataElements = castData[model.TierIncentiveRelationDataElementsType](data) - case model.FunctionTypeTierListData: - result.TierDataElements = castData[model.TierDataElementsType](data) - case model.FunctionTypeTimeDistributorData: - result.TimeDistributorDataElements = castData[model.TimeDistributorDataElementsType](data) - case model.FunctionTypeTimeDistributorEnquiryCall: - result.TimeDistributorEnquiryCallElements = castData[model.TimeDistributorEnquiryCallElementsType](data) - case model.FunctionTypeTimeInformationData: - result.TimeInformationDataElements = castData[model.TimeInformationDataElementsType](data) - case model.FunctionTypeTimePrecisionData: - result.TimePrecisionDataElements = castData[model.TimePrecisionDataElementsType](data) - case model.FunctionTypeTimeSeriesConstraintsListData: - result.TimeSeriesConstraintsDataElements = castData[model.TimeSeriesConstraintsDataElementsType](data) - case model.FunctionTypeTimeSeriesDescriptionListData: - result.TimeSeriesDescriptionDataElements = castData[model.TimeSeriesDescriptionDataElementsType](data) - case model.FunctionTypeTimeSeriesListData: - result.TimeSeriesDataElements = castData[model.TimeSeriesDataElementsType](data) - case model.FunctionTypeTimeTableConstraintsListData: - result.TimeTableConstraintsDataElements = castData[model.TimeTableConstraintsDataElementsType](data) - case model.FunctionTypeTimeTableDescriptionListData: - result.TimeTableDescriptionDataElements = castData[model.TimeTableDescriptionDataElementsType](data) - case model.FunctionTypeTimeTableListData: - result.TimeTableDataElements = castData[model.TimeTableDataElementsType](data) - case model.FunctionTypeUseCaseInformationListData: - result.UseCaseInformationDataElements = castData[model.UseCaseInformationDataElementsType](data) - } - - return result -} - -func createCmd[T any](function model.FunctionType, data *T) model.CmdType { - result := model.CmdType{} - - switch function { - case model.FunctionTypeActuatorLevelData: - result.ActuatorLevelData = castData[model.ActuatorLevelDataType](data) - case model.FunctionTypeActuatorLevelDescriptionData: - result.ActuatorLevelDescriptionData = castData[model.ActuatorLevelDescriptionDataType](data) - case model.FunctionTypeActuatorSwitchData: - result.ActuatorSwitchData = castData[model.ActuatorSwitchDataType](data) - case model.FunctionTypeActuatorSwitchDescriptionData: - result.ActuatorSwitchDescriptionData = castData[model.ActuatorSwitchDescriptionDataType](data) - case model.FunctionTypeAlarmListData: - result.AlarmListData = castData[model.AlarmListDataType](data) - case model.FunctionTypeBillConstraintsListData: - result.BillConstraintsListData = castData[model.BillConstraintsListDataType](data) - case model.FunctionTypeBillDescriptionListData: - result.BillDescriptionListData = castData[model.BillDescriptionListDataType](data) - case model.FunctionTypeBillListData: - result.BillListData = castData[model.BillListDataType](data) - case model.FunctionTypeBindingManagementDeleteCall: - result.BindingManagementDeleteCall = castData[model.BindingManagementDeleteCallType](data) - case model.FunctionTypeBindingManagementEntryListData: - result.BindingManagementEntryListData = castData[model.BindingManagementEntryListDataType](data) - case model.FunctionTypeBindingManagementRequestCall: - result.BindingManagementRequestCall = castData[model.BindingManagementRequestCallType](data) - case model.FunctionTypeCommodityListData: - result.CommodityListData = castData[model.CommodityListDataType](data) - case model.FunctionTypeDataTunnelingCall: - result.DataTunnelingCall = castData[model.DataTunnelingCallType](data) - case model.FunctionTypeDeviceClassificationManufacturerData: - result.DeviceClassificationManufacturerData = castData[model.DeviceClassificationManufacturerDataType](data) - case model.FunctionTypeDeviceClassificationUserData: - result.DeviceClassificationUserData = castData[model.DeviceClassificationUserDataType](data) - case model.FunctionTypeDeviceConfigurationKeyValueConstraintsListData: - result.DeviceConfigurationKeyValueConstraintsListData = castData[model.DeviceConfigurationKeyValueConstraintsListDataType](data) - case model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData: - result.DeviceConfigurationKeyValueDescriptionListData = castData[model.DeviceConfigurationKeyValueDescriptionListDataType](data) - case model.FunctionTypeDeviceConfigurationKeyValueListData: - result.DeviceConfigurationKeyValueListData = castData[model.DeviceConfigurationKeyValueListDataType](data) - case model.FunctionTypeDeviceDiagnosisHeartbeatData: - result.DeviceDiagnosisHeartbeatData = castData[model.DeviceDiagnosisHeartbeatDataType](data) - case model.FunctionTypeDeviceDiagnosisServiceData: - result.DeviceDiagnosisServiceData = castData[model.DeviceDiagnosisServiceDataType](data) - case model.FunctionTypeDeviceDiagnosisStateData: - result.DeviceDiagnosisStateData = castData[model.DeviceDiagnosisStateDataType](data) - case model.FunctionTypeDirectControlActivityListData: - result.DirectControlActivityListData = castData[model.DirectControlActivityListDataType](data) - case model.FunctionTypeDirectControlDescriptionData: - result.DirectControlDescriptionData = castData[model.DirectControlDescriptionDataType](data) - case model.FunctionTypeElectricalConnectionDescriptionListData: - result.ElectricalConnectionDescriptionListData = castData[model.ElectricalConnectionDescriptionListDataType](data) - case model.FunctionTypeElectricalConnectionParameterDescriptionListData: - result.ElectricalConnectionParameterDescriptionListData = castData[model.ElectricalConnectionParameterDescriptionListDataType](data) - case model.FunctionTypeElectricalConnectionPermittedValueSetListData: - result.ElectricalConnectionPermittedValueSetListData = castData[model.ElectricalConnectionPermittedValueSetListDataType](data) - case model.FunctionTypeElectricalConnectionStateListData: - result.ElectricalConnectionStateListData = castData[model.ElectricalConnectionStateListDataType](data) - case model.FunctionTypeHvacOperationModeDescriptionListData: - result.HvacOperationModeDescriptionListData = castData[model.HvacOperationModeDescriptionListDataType](data) - case model.FunctionTypeHvacOverrunDescriptionListData: - result.HvacOverrunDescriptionListData = castData[model.HvacOverrunDescriptionListDataType](data) - case model.FunctionTypeHvacOverrunListData: - result.HvacOverrunListData = castData[model.HvacOverrunListDataType](data) - case model.FunctionTypeHvacSystemFunctionDescriptionListData: - result.HvacSystemFunctionDescriptionListData = castData[model.HvacSystemFunctionDescriptionListDataType](data) - case model.FunctionTypeHvacSystemFunctionListData: - result.HvacSystemFunctionListData = castData[model.HvacSystemFunctionListDataType](data) - case model.FunctionTypeHvacSystemFunctionOperationModeRelationListData: - result.HvacSystemFunctionOperationModeRelationListData = castData[model.HvacSystemFunctionOperationModeRelationListDataType](data) - case model.FunctionTypeHvacSystemFunctionPowerSequenceRelationListData: - result.HvacSystemFunctionPowerSequenceRelationListData = castData[model.HvacSystemFunctionPowerSequenceRelationListDataType](data) - case model.FunctionTypeHvacSystemFunctionSetPointRelationListData: - result.HvacSystemFunctionSetPointRelationListData = castData[model.HvacSystemFunctionSetpointRelationListDataType](data) - case model.FunctionTypeIdentificationListData: - result.IdentificationListData = castData[model.IdentificationListDataType](data) - case model.FunctionTypeIncentiveDescriptionListData: - result.IncentiveDescriptionListData = castData[model.IncentiveDescriptionListDataType](data) - case model.FunctionTypeIncentiveListData: - result.IncentiveListData = castData[model.IncentiveListDataType](data) - case model.FunctionTypeIncentiveTableConstraintsData: - result.IncentiveTableConstraintsData = castData[model.IncentiveTableConstraintsDataType](data) - case model.FunctionTypeIncentiveTableData: - result.IncentiveTableData = castData[model.IncentiveTableDataType](data) - case model.FunctionTypeIncentiveTableDescriptionData: - result.IncentiveTableDescriptionData = castData[model.IncentiveTableDescriptionDataType](data) - case model.FunctionTypeLoadControlEventListData: - result.LoadControlEventListData = castData[model.LoadControlEventListDataType](data) - case model.FunctionTypeLoadControlLimitConstraintsListData: - result.LoadControlLimitConstraintsListData = castData[model.LoadControlLimitConstraintsListDataType](data) - case model.FunctionTypeLoadControlLimitDescriptionListData: - result.LoadControlLimitDescriptionListData = castData[model.LoadControlLimitDescriptionListDataType](data) - case model.FunctionTypeLoadControlLimitListData: - result.LoadControlLimitListData = castData[model.LoadControlLimitListDataType](data) - case model.FunctionTypeLoadControlNodeData: - result.LoadControlNodeData = castData[model.LoadControlNodeDataType](data) - case model.FunctionTypeLoadControlStateListData: - result.LoadControlStateListData = castData[model.LoadControlStateListDataType](data) - case model.FunctionTypeMeasurementConstraintsListData: - result.MeasurementConstraintsListData = castData[model.MeasurementConstraintsListDataType](data) - case model.FunctionTypeMeasurementDescriptionListData: - result.MeasurementDescriptionListData = castData[model.MeasurementDescriptionListDataType](data) - case model.FunctionTypeMeasurementListData: - result.MeasurementListData = castData[model.MeasurementListDataType](data) - case model.FunctionTypeMeasurementThresholdRelationListData: - result.MeasurementThresholdRelationListData = castData[model.MeasurementThresholdRelationListDataType](data) - case model.FunctionTypeMessagingListData: - result.MessagingListData = castData[model.MessagingListDataType](data) - case model.FunctionTypeNetworkManagementAbortCall: - result.NetworkManagementAbortCall = castData[model.NetworkManagementAbortCallType](data) - case model.FunctionTypeNetworkManagementAddNodeCall: - result.NetworkManagementAddNodeCall = castData[model.NetworkManagementAddNodeCallType](data) - case model.FunctionTypeNetworkManagementDeviceDescriptionListData: - result.NetworkManagementDeviceDescriptionListData = castData[model.NetworkManagementDeviceDescriptionListDataType](data) - case model.FunctionTypeNetworkManagementDiscoverCall: - result.NetworkManagementDiscoverCall = castData[model.NetworkManagementDiscoverCallType](data) - case model.FunctionTypeNetworkManagementEntityDescriptionListData: - result.NetworkManagementEntityDescriptionListData = castData[model.NetworkManagementEntityDescriptionListDataType](data) - case model.FunctionTypeNetworkManagementFeatureDescriptionListData: - result.NetworkManagementFeatureDescriptionListData = castData[model.NetworkManagementFeatureDescriptionListDataType](data) - case model.FunctionTypeNetworkManagementJoiningModeData: - result.NetworkManagementJoiningModeData = castData[model.NetworkManagementJoiningModeDataType](data) - case model.FunctionTypeNetworkManagementModifyNodeCall: - result.NetworkManagementModifyNodeCall = castData[model.NetworkManagementModifyNodeCallType](data) - case model.FunctionTypeNetworkManagementProcessStateData: - result.NetworkManagementProcessStateData = castData[model.NetworkManagementProcessStateDataType](data) - case model.FunctionTypeNetworkManagementRemoveNodeCall: - result.NetworkManagementRemoveNodeCall = castData[model.NetworkManagementRemoveNodeCallType](data) - case model.FunctionTypeNetworkManagementReportCandidateData: - result.NetworkManagementReportCandidateData = castData[model.NetworkManagementReportCandidateDataType](data) - case model.FunctionTypeNetworkManagementScanNetworkCall: - result.NetworkManagementScanNetworkCall = castData[model.NetworkManagementScanNetworkCallType](data) - case model.FunctionTypeOperatingConstraintsDurationListData: - result.OperatingConstraintsDurationListData = castData[model.OperatingConstraintsDurationListDataType](data) - case model.FunctionTypeOperatingConstraintsInterruptListData: - result.OperatingConstraintsInterruptListData = castData[model.OperatingConstraintsInterruptListDataType](data) - case model.FunctionTypeOperatingConstraintsPowerDescriptionListData: - result.OperatingConstraintsPowerDescriptionListData = castData[model.OperatingConstraintsPowerDescriptionListDataType](data) - case model.FunctionTypeOperatingConstraintsPowerLevelListData: - result.OperatingConstraintsPowerLevelListData = castData[model.OperatingConstraintsPowerLevelListDataType](data) - case model.FunctionTypeOperatingConstraintsPowerRangeListData: - result.OperatingConstraintsPowerRangeListData = castData[model.OperatingConstraintsPowerRangeListDataType](data) - case model.FunctionTypeOperatingConstraintsResumeImplicationListData: - result.OperatingConstraintsResumeImplicationListData = castData[model.OperatingConstraintsResumeImplicationListDataType](data) - case model.FunctionTypePowerSequenceAlternativesRelationListData: - result.PowerSequenceAlternativesRelationListData = castData[model.PowerSequenceAlternativesRelationListDataType](data) - case model.FunctionTypePowerSequenceDescriptionListData: - result.PowerSequenceDescriptionListData = castData[model.PowerSequenceDescriptionListDataType](data) - case model.FunctionTypePowerSequenceNodeScheduleInformationData: - result.PowerSequenceNodeScheduleInformationData = castData[model.PowerSequenceNodeScheduleInformationDataType](data) - case model.FunctionTypePowerSequencePriceCalculationRequestCall: - result.PowerSequencePriceCalculationRequestCall = castData[model.PowerSequencePriceCalculationRequestCallType](data) - case model.FunctionTypePowerSequencePriceListData: - result.PowerSequencePriceListData = castData[model.PowerSequencePriceListDataType](data) - case model.FunctionTypePowerSequenceScheduleConfigurationRequestCall: - result.PowerSequenceScheduleConfigurationRequestCall = castData[model.PowerSequenceScheduleConfigurationRequestCallType](data) - case model.FunctionTypePowerSequenceScheduleConstraintsListData: - result.PowerSequenceScheduleConstraintsListData = castData[model.PowerSequenceScheduleConstraintsListDataType](data) - case model.FunctionTypePowerSequenceScheduleListData: - result.PowerSequenceScheduleListData = castData[model.PowerSequenceScheduleListDataType](data) - case model.FunctionTypePowerSequenceSchedulePreferenceListData: - result.PowerSequenceSchedulePreferenceListData = castData[model.PowerSequenceSchedulePreferenceListDataType](data) - case model.FunctionTypePowerSequenceStateListData: - result.PowerSequenceStateListData = castData[model.PowerSequenceStateListDataType](data) - case model.FunctionTypePowerTimeSlotScheduleConstraintsListData: - result.PowerTimeSlotScheduleConstraintsListData = castData[model.PowerTimeSlotScheduleConstraintsListDataType](data) - case model.FunctionTypePowerTimeSlotScheduleListData: - result.PowerTimeSlotScheduleListData = castData[model.PowerTimeSlotScheduleListDataType](data) - case model.FunctionTypePowerTimeSlotValueListData: - result.PowerTimeSlotValueListData = castData[model.PowerTimeSlotValueListDataType](data) - case model.FunctionTypeResultData: - result.ResultData = castData[model.ResultDataType](data) - case model.FunctionTypeSensingDescriptionData: - result.SensingDescriptionData = castData[model.SensingDescriptionDataType](data) - case model.FunctionTypeSensingListData: - result.SensingListData = castData[model.SensingListDataType](data) - case model.FunctionTypeSetpointConstraintsListData: - result.SetpointConstraintsListData = castData[model.SetpointConstraintsListDataType](data) - case model.FunctionTypeSetpointDescriptionListData: - result.SetpointDescriptionListData = castData[model.SetpointDescriptionListDataType](data) - case model.FunctionTypeSetpointListData: - result.SetpointListData = castData[model.SetpointListDataType](data) - case model.FunctionTypeSmartEnergyManagementPsConfigurationRequestCall: - result.SmartEnergyManagementPsConfigurationRequestCall = castData[model.SmartEnergyManagementPsConfigurationRequestCallType](data) - case model.FunctionTypeSmartEnergyManagementPsData: - result.SmartEnergyManagementPsData = castData[model.SmartEnergyManagementPsDataType](data) - case model.FunctionTypeSmartEnergyManagementPsPriceCalculationRequestCall: - result.SmartEnergyManagementPsPriceCalculationRequestCall = castData[model.SmartEnergyManagementPsPriceCalculationRequestCallType](data) - case model.FunctionTypeSmartEnergyManagementPsPriceData: - result.SmartEnergyManagementPsPriceData = castData[model.SmartEnergyManagementPsPriceDataType](data) - case model.FunctionTypeSpecificationVersionListData: - result.SpecificationVersionListData = castData[model.SpecificationVersionListDataType](data) - case model.FunctionTypeSupplyConditionListData: - result.SupplyConditionListData = castData[model.SupplyConditionListDataType](data) - case model.FunctionTypeSupplyConditionThresholdRelationListData: - result.SupplyConditionThresholdRelationListData = castData[model.SupplyConditionThresholdRelationListDataType](data) - case model.FunctionTypeTariffBoundaryRelationListData: - result.TariffBoundaryRelationListData = castData[model.TariffBoundaryRelationListDataType](data) - case model.FunctionTypeTariffDescriptionListData: - result.TariffDescriptionListData = castData[model.TariffDescriptionListDataType](data) - case model.FunctionTypeTariffListData: - result.TariffListData = castData[model.TariffListDataType](data) - case model.FunctionTypeTariffOverallConstraintsData: - result.TariffOverallConstraintsData = castData[model.TariffOverallConstraintsDataType](data) - case model.FunctionTypeTariffTierRelationListData: - result.TariffTierRelationListData = castData[model.TariffTierRelationListDataType](data) - case model.FunctionTypeTaskManagementJobDescriptionListData: - result.TaskManagementJobDescriptionListData = castData[model.TaskManagementJobDescriptionListDataType](data) - case model.FunctionTypeTaskManagementJobListData: - result.TaskManagementJobListData = castData[model.TaskManagementJobListDataType](data) - case model.FunctionTypeTaskManagementJobRelationListData: - result.TaskManagementJobRelationListData = castData[model.TaskManagementJobRelationListDataType](data) - case model.FunctionTypeTaskManagementOverviewData: - result.TaskManagementOverviewData = castData[model.TaskManagementOverviewDataType](data) - case model.FunctionTypeThresholdConstraintsListData: - result.ThresholdConstraintsListData = castData[model.ThresholdConstraintsListDataType](data) - case model.FunctionTypeThresholdDescriptionListData: - result.ThresholdDescriptionListData = castData[model.ThresholdDescriptionListDataType](data) - case model.FunctionTypeThresholdListData: - result.ThresholdListData = castData[model.ThresholdListDataType](data) - case model.FunctionTypeTierBoundaryDescriptionListData: - result.TierBoundaryDescriptionListData = castData[model.TierBoundaryDescriptionListDataType](data) - case model.FunctionTypeTierBoundaryListData: - result.TierBoundaryListData = castData[model.TierBoundaryListDataType](data) - case model.FunctionTypeTierDescriptionListData: - result.TierDescriptionListData = castData[model.TierDescriptionListDataType](data) - case model.FunctionTypeTierIncentiveRelationListData: - result.TierIncentiveRelationListData = castData[model.TierIncentiveRelationListDataType](data) - case model.FunctionTypeTierListData: - result.TierListData = castData[model.TierListDataType](data) - case model.FunctionTypeTimeDistributorData: - result.TimeDistributorData = castData[model.TimeDistributorDataType](data) - case model.FunctionTypeTimeDistributorEnquiryCall: - result.TimeDistributorEnquiryCall = castData[model.TimeDistributorEnquiryCallType](data) - case model.FunctionTypeTimeInformationData: - result.TimeInformationData = castData[model.TimeInformationDataType](data) - case model.FunctionTypeTimePrecisionData: - result.TimePrecisionData = castData[model.TimePrecisionDataType](data) - case model.FunctionTypeTimeSeriesConstraintsListData: - result.TimeSeriesConstraintsListData = castData[model.TimeSeriesConstraintsListDataType](data) - case model.FunctionTypeTimeSeriesDescriptionListData: - result.TimeSeriesDescriptionListData = castData[model.TimeSeriesDescriptionListDataType](data) - case model.FunctionTypeTimeSeriesListData: - result.TimeSeriesListData = castData[model.TimeSeriesListDataType](data) - case model.FunctionTypeTimeTableConstraintsListData: - result.TimeTableConstraintsListData = castData[model.TimeTableConstraintsListDataType](data) - case model.FunctionTypeTimeTableDescriptionListData: - result.TimeTableDescriptionListData = castData[model.TimeTableDescriptionListDataType](data) - case model.FunctionTypeTimeTableListData: - result.TimeTableListData = castData[model.TimeTableListDataType](data) - // add more model types here - } - - return result -} - -func castData[D, S any](data *S) *D { - if data == nil { - return new(D) - } - return any(data).(*D) -} diff --git a/spine/function_data_cmd_test.go b/spine/function_data_cmd_test.go deleted file mode 100644 index 34ccf883..00000000 --- a/spine/function_data_cmd_test.go +++ /dev/null @@ -1,1140 +0,0 @@ -package spine - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -func TestFunctionDataCmdSuite(t *testing.T) { - suite.Run(t, new(FctDataCmdSuite)) -} - -type FctDataCmdSuite struct { - suite.Suite - function model.FunctionType - data *model.DeviceClassificationManufacturerDataType - sut *FunctionDataCmdImpl[model.DeviceClassificationManufacturerDataType] -} - -func (suite *FctDataCmdSuite) SetupSuite() { - suite.function = model.FunctionTypeDeviceClassificationManufacturerData - suite.data = &model.DeviceClassificationManufacturerDataType{ - DeviceName: util.Ptr(model.DeviceClassificationStringType("device name")), - } - suite.sut = NewFunctionDataCmd[model.DeviceClassificationManufacturerDataType](suite.function) - suite.sut.UpdateData(suite.data, nil, nil) -} - -func (suite *FctDataCmdSuite) TestFunctionDataCmd_ReadCmd() { - readCmd := suite.sut.ReadCmdType(nil, nil) - assert.NotNil(suite.T(), readCmd.DeviceClassificationManufacturerData) - assert.Nil(suite.T(), readCmd.DeviceClassificationManufacturerData.DeviceName) - - partialS := model.NewFilterTypePartial() - readCmd = suite.sut.ReadCmdType(partialS, nil) - assert.NotNil(suite.T(), readCmd.DeviceClassificationManufacturerData) - assert.Nil(suite.T(), readCmd.DeviceClassificationManufacturerData.DeviceName) -} - -func (suite *FctDataCmdSuite) TestFunctionDataCmd_ReplyCmd() { - readCmd := suite.sut.ReplyCmdType(false) - assert.NotNil(suite.T(), readCmd.DeviceClassificationManufacturerData) - assert.Equal(suite.T(), suite.data.DeviceName, readCmd.DeviceClassificationManufacturerData.DeviceName) - - readCmd = suite.sut.ReplyCmdType(true) - assert.NotNil(suite.T(), readCmd.DeviceClassificationManufacturerData) - assert.Equal(suite.T(), suite.data.DeviceName, readCmd.DeviceClassificationManufacturerData.DeviceName) -} - -func (suite *FctDataCmdSuite) TestFunctionDataCmd_NotifyCmd() { - readCmd := suite.sut.NotifyCmdType(nil, nil, false, nil) - assert.NotNil(suite.T(), readCmd.DeviceClassificationManufacturerData) - assert.Equal(suite.T(), suite.data.DeviceName, readCmd.DeviceClassificationManufacturerData.DeviceName) - - readCmd = suite.sut.NotifyCmdType(nil, nil, true, nil) - assert.NotNil(suite.T(), readCmd.DeviceClassificationManufacturerData) - assert.Equal(suite.T(), suite.data.DeviceName, readCmd.DeviceClassificationManufacturerData.DeviceName) - - deleteS := model.NewFilterTypePartial() - readCmd = suite.sut.NotifyCmdType(deleteS, nil, false, nil) - assert.NotNil(suite.T(), readCmd.DeviceClassificationManufacturerData) - assert.Equal(suite.T(), suite.data.DeviceName, readCmd.DeviceClassificationManufacturerData.DeviceName) -} - -func (suite *FctDataCmdSuite) TestFunctionDataCmd_WriteCmd() { - readCmd := suite.sut.WriteCmdType(nil, nil, nil) - assert.NotNil(suite.T(), readCmd.DeviceClassificationManufacturerData) - assert.Equal(suite.T(), suite.data.DeviceName, readCmd.DeviceClassificationManufacturerData.DeviceName) - - partialS := model.NewFilterTypePartial() - readCmd = suite.sut.WriteCmdType(nil, partialS, nil) - assert.NotNil(suite.T(), readCmd.DeviceClassificationManufacturerData) - assert.Equal(suite.T(), suite.data.DeviceName, readCmd.DeviceClassificationManufacturerData.DeviceName) -} - -func (suite *FctDataCmdSuite) Test_AddSelectorToFilter() { - filter := model.FilterType{CmdControl: &model.CmdControlType{Partial: &model.ElementTagType{}}} - - result := addSelectorToFilter(filter, model.FunctionTypeAlarmListData, &model.AlarmListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeBillConstraintsListData, &model.BillConstraintsListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeBillDescriptionListData, &model.BillDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeBillListData, &model.BillListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeBindingManagementEntryListData, &model.BindingManagementEntryListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeCommodityListData, &model.CommodityListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeDeviceConfigurationKeyValueConstraintsListData, &model.DeviceConfigurationKeyValueConstraintsListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData, &model.DeviceConfigurationKeyValueDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeDeviceConfigurationKeyValueListData, &model.DeviceConfigurationKeyValueListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeDirectControlActivityListData, &model.DirectControlActivityListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeElectricalConnectionDescriptionListData, &model.ElectricalConnectionDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeElectricalConnectionParameterDescriptionListData, &model.ElectricalConnectionParameterDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeElectricalConnectionPermittedValueSetListData, &model.ElectricalConnectionPermittedValueSetListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeElectricalConnectionStateListData, &model.ElectricalConnectionStateListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeHvacOperationModeDescriptionListData, &model.HvacOperationModeDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeHvacOverrunDescriptionListData, &model.HvacOverrunDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeHvacOverrunListData, &model.HvacOverrunListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeHvacSystemFunctionDescriptionListData, &model.HvacSystemFunctionDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeHvacSystemFunctionListData, &model.HvacSystemFunctionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeHvacSystemFunctionOperationModeRelationListData, &model.HvacSystemFunctionOperationModeRelationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeHvacSystemFunctionPowerSequenceRelationListData, &model.HvacSystemFunctionPowerSequenceRelationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeHvacSystemFunctionSetPointRelationListData, &model.HvacSystemFunctionSetpointRelationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeIdentificationListData, &model.IdentificationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeIncentiveDescriptionListData, &model.IncentiveDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeIncentiveListData, &model.IncentiveListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeIncentiveTableConstraintsData, &model.IncentiveTableConstraintsDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeIncentiveTableData, &model.IncentiveTableDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeIncentiveTableDescriptionData, &model.IncentiveTableDescriptionDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeLoadControlEventListData, &model.LoadControlEventListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeLoadControlLimitConstraintsListData, &model.LoadControlLimitConstraintsListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeLoadControlLimitDescriptionListData, &model.LoadControlLimitDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeLoadControlLimitListData, &model.LoadControlLimitListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeLoadControlStateListData, &model.LoadControlStateListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeMeasurementConstraintsListData, &model.MeasurementConstraintsListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeMeasurementDescriptionListData, &model.MeasurementDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeMeasurementListData, &model.MeasurementListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeMeasurementThresholdRelationListData, &model.MeasurementThresholdRelationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeMessagingListData, &model.MessagingListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeNetworkManagementDeviceDescriptionListData, &model.NetworkManagementDeviceDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeNetworkManagementEntityDescriptionListData, &model.NetworkManagementEntityDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeNetworkManagementFeatureDescriptionListData, &model.NetworkManagementFeatureDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeNodeManagementBindingData, &model.NodeManagementBindingDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeNodeManagementDestinationListData, &model.NodeManagementDestinationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeNodeManagementDetailedDiscoveryData, &model.NodeManagementDetailedDiscoveryDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeNodeManagementSubscriptionData, &model.NodeManagementSubscriptionDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeNodeManagementUseCaseData, &model.NodeManagementUseCaseDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeOperatingConstraintsDurationListData, &model.OperatingConstraintsDurationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeOperatingConstraintsInterruptListData, &model.OperatingConstraintsInterruptListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeOperatingConstraintsPowerDescriptionListData, &model.OperatingConstraintsPowerDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeOperatingConstraintsPowerLevelListData, &model.OperatingConstraintsPowerLevelListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeOperatingConstraintsPowerRangeListData, &model.OperatingConstraintsPowerRangeListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeOperatingConstraintsResumeImplicationListData, &model.OperatingConstraintsResumeImplicationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypePowerSequenceAlternativesRelationListData, &model.PowerSequenceAlternativesRelationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypePowerSequenceDescriptionListData, &model.PowerSequenceDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypePowerSequencePriceListData, &model.PowerSequencePriceListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypePowerSequenceScheduleConstraintsListData, &model.PowerSequenceScheduleConstraintsListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypePowerSequenceScheduleListData, &model.PowerSequenceScheduleListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypePowerSequenceSchedulePreferenceListData, &model.PowerSequenceSchedulePreferenceListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypePowerSequenceStateListData, &model.PowerSequenceStateListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypePowerTimeSlotScheduleConstraintsListData, &model.PowerTimeSlotScheduleConstraintsListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypePowerTimeSlotScheduleListData, &model.PowerTimeSlotScheduleListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypePowerTimeSlotValueListData, &model.PowerTimeSlotValueListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeSensingListData, &model.SensingListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeSetpointConstraintsListData, &model.SetpointConstraintsListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeSetpointDescriptionListData, &model.SetpointDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeSetpointListData, &model.SetpointListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeSmartEnergyManagementPsData, &model.SmartEnergyManagementPsDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeSmartEnergyManagementPsPriceData, &model.SmartEnergyManagementPsPriceDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeSpecificationVersionListData, &model.SpecificationVersionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeSupplyConditionListData, &model.SupplyConditionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeSupplyConditionThresholdRelationListData, &model.SupplyConditionThresholdRelationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTariffBoundaryRelationListData, &model.TariffBoundaryRelationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTariffDescriptionListData, &model.TariffDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTariffListData, &model.TariffListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTariffTierRelationListData, &model.TariffTierRelationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTaskManagementJobDescriptionListData, &model.TaskManagementJobDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTaskManagementJobListData, &model.TaskManagementJobListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTaskManagementJobRelationListData, &model.TaskManagementJobRelationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeThresholdConstraintsListData, &model.ThresholdConstraintsListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeThresholdDescriptionListData, &model.ThresholdDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeThresholdListData, &model.ThresholdListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTierBoundaryDescriptionListData, &model.TierBoundaryDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTierBoundaryListData, &model.TierBoundaryListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTierDescriptionListData, &model.TierDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTierIncentiveRelationListData, &model.TierIncentiveRelationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTierListData, &model.TierListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTimeSeriesConstraintsListData, &model.TimeSeriesConstraintsListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTimeSeriesDescriptionListData, &model.TimeSeriesDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTimeSeriesListData, &model.TimeSeriesListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTimeTableConstraintsListData, &model.TimeTableConstraintsListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTimeTableDescriptionListData, &model.TimeTableDescriptionListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeTimeTableListData, &model.TimeTableListDataSelectorsType{}) - assert.NotNil(suite.T(), result) - - result = addSelectorToFilter(filter, model.FunctionTypeUseCaseInformationListData, &model.UseCaseInformationListDataSelectorsType{}) - assert.NotNil(suite.T(), result) -} - -func (suite *FctDataCmdSuite) Test_AddElementsToFilter() { - filter := model.FilterType{CmdControl: &model.CmdControlType{Partial: &model.ElementTagType{}}} - - result := addElementToFilter(filter, model.FunctionTypeActuatorLevelData, &model.ActuatorLevelDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeActuatorLevelDescriptionData, &model.ActuatorLevelDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeActuatorSwitchData, &model.ActuatorSwitchDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeActuatorSwitchDescriptionData, &model.ActuatorSwitchDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeAlarmListData, &model.AlarmDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeBillConstraintsListData, &model.BillConstraintsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeBillDescriptionListData, &model.BillDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeBillListData, &model.BillDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeBindingManagementDeleteCall, &model.BindingManagementDeleteCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeBindingManagementEntryListData, &model.BindingManagementEntryDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeBindingManagementRequestCall, &model.BindingManagementRequestCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeCommodityListData, &model.CommodityDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeDataTunnelingCall, &model.DataTunnelingCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeDeviceClassificationManufacturerData, &model.DeviceClassificationManufacturerDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeDeviceClassificationUserData, &model.DeviceClassificationUserDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeDeviceConfigurationKeyValueConstraintsListData, &model.DeviceConfigurationKeyValueConstraintsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData, &model.DeviceConfigurationKeyValueDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeDeviceConfigurationKeyValueListData, &model.DeviceConfigurationKeyValueDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeDeviceDiagnosisHeartbeatData, &model.DeviceDiagnosisHeartbeatDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeDeviceDiagnosisServiceData, &model.DeviceDiagnosisServiceDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeDeviceDiagnosisStateData, &model.DeviceDiagnosisStateDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeDirectControlActivityListData, &model.DirectControlActivityDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeDirectControlDescriptionData, &model.DirectControlDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeElectricalConnectionDescriptionListData, &model.ElectricalConnectionDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeElectricalConnectionParameterDescriptionListData, &model.ElectricalConnectionParameterDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeElectricalConnectionPermittedValueSetListData, &model.ElectricalConnectionPermittedValueSetDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeElectricalConnectionStateListData, &model.ElectricalConnectionStateDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeHvacOperationModeDescriptionListData, &model.HvacOperationModeDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeHvacOverrunDescriptionListData, &model.HvacOverrunDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeHvacOverrunListData, &model.HvacOverrunDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeHvacSystemFunctionDescriptionListData, &model.HvacSystemFunctionDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeHvacSystemFunctionListData, &model.HvacSystemFunctionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeHvacSystemFunctionOperationModeRelationListData, &model.HvacSystemFunctionOperationModeRelationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeHvacSystemFunctionPowerSequenceRelationListData, &model.HvacSystemFunctionPowerSequenceRelationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeHvacSystemFunctionSetPointRelationListData, &model.HvacSystemFunctionSetpointRelationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeIdentificationListData, &model.IdentificationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeIncentiveDescriptionListData, &model.IncentiveDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeIncentiveListData, &model.IncentiveDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeIncentiveTableConstraintsData, &model.IncentiveTableConstraintsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeIncentiveTableData, &model.IncentiveTableDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeIncentiveTableDescriptionData, &model.IncentiveTableDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeLoadControlEventListData, &model.LoadControlEventDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeLoadControlLimitConstraintsListData, &model.LoadControlLimitConstraintsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeLoadControlLimitDescriptionListData, &model.LoadControlLimitDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeLoadControlLimitListData, &model.LoadControlLimitDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeLoadControlNodeData, &model.LoadControlNodeDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeLoadControlStateListData, &model.LoadControlStateDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeMeasurementConstraintsListData, &model.MeasurementConstraintsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeMeasurementDescriptionListData, &model.MeasurementDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeMeasurementListData, &model.MeasurementDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeMeasurementThresholdRelationListData, &model.MeasurementThresholdRelationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeMessagingListData, &model.MessagingDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNetworkManagementAbortCall, &model.NetworkManagementAbortCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNetworkManagementAddNodeCall, &model.NetworkManagementAddNodeCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNetworkManagementDeviceDescriptionListData, &model.NetworkManagementDeviceDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNetworkManagementDiscoverCall, &model.NetworkManagementDiscoverCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNetworkManagementEntityDescriptionListData, &model.NetworkManagementEntityDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNetworkManagementFeatureDescriptionListData, &model.NetworkManagementFeatureDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNetworkManagementJoiningModeData, &model.NetworkManagementJoiningModeDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNetworkManagementModifyNodeCall, &model.NetworkManagementModifyNodeCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNetworkManagementProcessStateData, &model.NetworkManagementProcessStateDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNetworkManagementRemoveNodeCall, &model.NetworkManagementRemoveNodeCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNetworkManagementReportCandidateData, &model.NetworkManagementReportCandidateDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNetworkManagementScanNetworkCall, &model.NetworkManagementScanNetworkCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNodeManagementBindingData, &model.NodeManagementBindingDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNodeManagementBindingDeleteCall, &model.NodeManagementBindingDeleteCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNodeManagementBindingRequestCall, &model.NodeManagementBindingRequestCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNodeManagementDestinationListData, &model.NodeManagementDestinationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNodeManagementDetailedDiscoveryData, &model.NodeManagementDetailedDiscoveryDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNodeManagementSubscriptionData, &model.NodeManagementSubscriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNodeManagementSubscriptionDeleteCall, &model.NodeManagementSubscriptionDeleteCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNodeManagementSubscriptionRequestCall, &model.NodeManagementSubscriptionRequestCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeNodeManagementUseCaseData, &model.NodeManagementUseCaseDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeOperatingConstraintsDurationListData, &model.OperatingConstraintsDurationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeOperatingConstraintsInterruptListData, &model.OperatingConstraintsInterruptDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeOperatingConstraintsPowerDescriptionListData, &model.OperatingConstraintsPowerDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeOperatingConstraintsPowerLevelListData, &model.OperatingConstraintsPowerLevelDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeOperatingConstraintsPowerRangeListData, &model.OperatingConstraintsPowerRangeDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeOperatingConstraintsResumeImplicationListData, &model.OperatingConstraintsResumeImplicationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerSequenceAlternativesRelationListData, &model.PowerSequenceAlternativesRelationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerSequenceDescriptionListData, &model.PowerSequenceDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerSequenceNodeScheduleInformationData, &model.PowerSequenceNodeScheduleInformationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerSequencePriceCalculationRequestCall, &model.PowerSequencePriceCalculationRequestCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerSequencePriceListData, &model.PowerSequencePriceDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerSequenceScheduleConfigurationRequestCall, &model.PowerSequenceScheduleConfigurationRequestCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerSequenceScheduleConstraintsListData, &model.PowerSequenceScheduleConstraintsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerSequenceScheduleListData, &model.PowerSequenceScheduleDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerSequenceSchedulePreferenceListData, &model.PowerSequenceSchedulePreferenceDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerSequenceStateListData, &model.PowerSequenceStateDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerTimeSlotScheduleConstraintsListData, &model.PowerTimeSlotScheduleConstraintsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerTimeSlotScheduleListData, &model.PowerTimeSlotScheduleDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypePowerTimeSlotValueListData, &model.PowerTimeSlotValueDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSensingListData, &model.SensingDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSetpointConstraintsListData, &model.SetpointConstraintsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSetpointDescriptionListData, &model.SensingDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSetpointListData, &model.SetpointDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSmartEnergyManagementPsConfigurationRequestCall, &model.SmartEnergyManagementPsConfigurationRequestCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSmartEnergyManagementPsData, &model.SmartEnergyManagementPsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSmartEnergyManagementPsPriceCalculationRequestCall, &model.SmartEnergyManagementPsPriceCalculationRequestCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSmartEnergyManagementPsPriceData, &model.SmartEnergyManagementPsPriceDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSpecificationVersionListData, &model.SpecificationVersionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSubscriptionManagementDeleteCall, &model.SubscriptionManagementDeleteCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSubscriptionManagementEntryListData, &model.SubscriptionManagementEntryDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSubscriptionManagementRequestCall, &model.SubscriptionManagementRequestCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSupplyConditionListData, &model.SupplyConditionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSupplyConditionDescriptionListData, &model.SupplyConditionDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeSupplyConditionThresholdRelationListData, &model.SupplyConditionThresholdRelationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTariffBoundaryRelationListData, &model.TariffBoundaryRelationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTariffDescriptionListData, &model.TariffDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTariffListData, &model.TariffDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTariffOverallConstraintsData, &model.TariffOverallConstraintsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTariffTierRelationListData, &model.TariffTierRelationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTaskManagementJobDescriptionListData, &model.TaskManagementJobDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTaskManagementJobListData, &model.TaskManagementJobDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTaskManagementJobRelationListData, &model.TaskManagementJobRelationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTaskManagementOverviewData, &model.TaskManagementOverviewDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeThresholdConstraintsListData, &model.ThresholdConstraintsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeThresholdDescriptionListData, &model.ThresholdDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeThresholdListData, &model.ThresholdDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTierBoundaryDescriptionListData, &model.TierBoundaryDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTierBoundaryListData, &model.TierBoundaryDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTierDescriptionListData, &model.TierDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTierIncentiveRelationListData, &model.TierIncentiveRelationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTierListData, &model.TierDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTimeDistributorData, &model.TimeDistributorDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTimeDistributorEnquiryCall, &model.TimeDistributorEnquiryCallElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTimeInformationData, &model.TimeInformationDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTimePrecisionData, &model.TimePrecisionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTimeSeriesConstraintsListData, &model.TimeSeriesConstraintsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTimeSeriesDescriptionListData, &model.TimeSeriesDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTimeSeriesListData, &model.TimeSeriesDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTimeTableConstraintsListData, &model.TimeTableConstraintsDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTimeTableDescriptionListData, &model.TimeTableDescriptionDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeTimeTableListData, &model.TimeTableDataElementsType{}) - assert.NotNil(suite.T(), result) - - result = addElementToFilter(filter, model.FunctionTypeUseCaseInformationListData, &model.UseCaseInformationDataElementsType{}) - assert.NotNil(suite.T(), result) -} - -func (suite *FctDataCmdSuite) Test_CreateCmd() { - result := createCmd(model.FunctionTypeActuatorLevelData, &model.ActuatorLevelDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeActuatorLevelDescriptionData, &model.ActuatorLevelDescriptionDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeActuatorSwitchData, &model.ActuatorSwitchDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeActuatorSwitchDescriptionData, &model.ActuatorSwitchDescriptionDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeAlarmListData, &model.AlarmListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeBillConstraintsListData, &model.BillConstraintsListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeBillDescriptionListData, &model.BillDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeBillListData, &model.BillListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeBindingManagementDeleteCall, &model.BindingManagementDeleteCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeBindingManagementEntryListData, &model.BindingManagementEntryListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeBindingManagementRequestCall, &model.BindingManagementRequestCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeCommodityListData, &model.CommodityListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeDataTunnelingCall, &model.DataTunnelingCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeDeviceClassificationManufacturerData, &model.DeviceClassificationManufacturerDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeDeviceClassificationUserData, &model.DeviceClassificationUserDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeDeviceConfigurationKeyValueConstraintsListData, &model.DeviceConfigurationKeyValueConstraintsListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData, &model.DeviceConfigurationKeyValueDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeDeviceConfigurationKeyValueListData, &model.DeviceConfigurationKeyValueListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeDeviceDiagnosisHeartbeatData, &model.DeviceDiagnosisHeartbeatDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeDeviceDiagnosisServiceData, &model.DeviceDiagnosisServiceDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeDeviceDiagnosisStateData, &model.DeviceDiagnosisStateDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeDirectControlActivityListData, &model.DirectControlActivityListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeDirectControlDescriptionData, &model.DirectControlDescriptionDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeElectricalConnectionDescriptionListData, &model.ElectricalConnectionDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeElectricalConnectionParameterDescriptionListData, &model.ElectricalConnectionParameterDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeElectricalConnectionPermittedValueSetListData, &model.ElectricalConnectionPermittedValueSetListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeElectricalConnectionStateListData, &model.ElectricalConnectionStateListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeHvacOperationModeDescriptionListData, &model.HvacOperationModeDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeHvacOverrunDescriptionListData, &model.HvacOverrunDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeHvacOverrunListData, &model.HvacOverrunListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeHvacSystemFunctionDescriptionListData, &model.HvacSystemFunctionDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeHvacSystemFunctionListData, &model.HvacSystemFunctionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeHvacSystemFunctionOperationModeRelationListData, &model.HvacSystemFunctionOperationModeRelationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeHvacSystemFunctionPowerSequenceRelationListData, &model.HvacSystemFunctionPowerSequenceRelationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeHvacSystemFunctionSetPointRelationListData, &model.HvacSystemFunctionSetpointRelationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeIdentificationListData, &model.IdentificationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeIncentiveDescriptionListData, &model.IncentiveDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeIncentiveListData, &model.IncentiveListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeIncentiveTableConstraintsData, &model.IncentiveTableConstraintsDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeIncentiveTableData, &model.IncentiveTableDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeIncentiveTableDescriptionData, &model.IncentiveTableDescriptionDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeLoadControlEventListData, &model.LoadControlEventListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeLoadControlLimitConstraintsListData, &model.LoadControlLimitConstraintsListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeLoadControlLimitDescriptionListData, &model.LoadControlLimitDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeLoadControlLimitListData, &model.LoadControlLimitListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeLoadControlNodeData, &model.LoadControlNodeDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeLoadControlStateListData, &model.LoadControlStateListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeMeasurementConstraintsListData, &model.MeasurementConstraintsListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeMeasurementDescriptionListData, &model.MeasurementDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeMeasurementListData, &model.MeasurementListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeMeasurementThresholdRelationListData, &model.MeasurementThresholdRelationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeMessagingListData, &model.MessagingListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeNetworkManagementAbortCall, &model.NetworkManagementAbortCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeNetworkManagementAddNodeCall, &model.NetworkManagementAddNodeCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeNetworkManagementDeviceDescriptionListData, &model.NetworkManagementDeviceDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeNetworkManagementDiscoverCall, &model.NetworkManagementDiscoverCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeNetworkManagementEntityDescriptionListData, &model.NetworkManagementEntityDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeNetworkManagementFeatureDescriptionListData, &model.NetworkManagementFeatureDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeNetworkManagementJoiningModeData, &model.NetworkManagementJoiningModeDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeNetworkManagementModifyNodeCall, &model.NetworkManagementModifyNodeCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeNetworkManagementProcessStateData, &model.NetworkManagementProcessStateDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeNetworkManagementRemoveNodeCall, &model.NetworkManagementRemoveNodeCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeNetworkManagementReportCandidateData, &model.NetworkManagementReportCandidateDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeNetworkManagementScanNetworkCall, &model.NetworkManagementScanNetworkCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeOperatingConstraintsDurationListData, &model.OperatingConstraintsDurationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeOperatingConstraintsInterruptListData, &model.OperatingConstraintsInterruptListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeOperatingConstraintsPowerDescriptionListData, &model.OperatingConstraintsPowerDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeOperatingConstraintsPowerLevelListData, &model.OperatingConstraintsPowerLevelListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeOperatingConstraintsPowerRangeListData, &model.OperatingConstraintsPowerRangeListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeOperatingConstraintsResumeImplicationListData, &model.OperatingConstraintsResumeImplicationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerSequenceAlternativesRelationListData, &model.PowerSequenceAlternativesRelationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerSequenceDescriptionListData, &model.PowerSequenceDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerSequenceNodeScheduleInformationData, &model.PowerSequenceNodeScheduleInformationDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerSequencePriceCalculationRequestCall, &model.PowerSequencePriceCalculationRequestCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerSequencePriceListData, &model.PowerSequencePriceListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerSequenceScheduleConfigurationRequestCall, &model.PowerSequenceScheduleConfigurationRequestCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerSequenceScheduleConstraintsListData, &model.PowerSequenceScheduleConstraintsListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerSequenceScheduleListData, &model.PowerSequenceScheduleListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerSequenceSchedulePreferenceListData, &model.PowerSequenceSchedulePreferenceListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerSequenceStateListData, &model.PowerSequenceStateListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerTimeSlotScheduleConstraintsListData, &model.PowerTimeSlotScheduleConstraintsListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerTimeSlotScheduleListData, &model.PowerTimeSlotScheduleListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypePowerTimeSlotValueListData, &model.PowerTimeSlotValueListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeResultData, &model.ResultDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeSensingDescriptionData, &model.SensingDescriptionDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeSensingListData, &model.SensingListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeSetpointConstraintsListData, &model.SetpointConstraintsListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeSetpointDescriptionListData, &model.SetpointDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeSetpointListData, &model.SetpointListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeSmartEnergyManagementPsConfigurationRequestCall, &model.SmartEnergyManagementPsConfigurationRequestCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeSmartEnergyManagementPsData, &model.SmartEnergyManagementPsDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeSmartEnergyManagementPsPriceCalculationRequestCall, &model.SmartEnergyManagementPsPriceCalculationRequestCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeSmartEnergyManagementPsPriceData, &model.SmartEnergyManagementPsPriceDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeSpecificationVersionListData, &model.SpecificationVersionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeSupplyConditionListData, &model.SupplyConditionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeSupplyConditionThresholdRelationListData, &model.SupplyConditionThresholdRelationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTariffBoundaryRelationListData, &model.TariffBoundaryRelationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTariffDescriptionListData, &model.TariffDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTariffListData, &model.TariffListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTariffOverallConstraintsData, &model.TariffOverallConstraintsDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTariffTierRelationListData, &model.TariffTierRelationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTaskManagementJobDescriptionListData, &model.TaskManagementJobDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTaskManagementJobListData, &model.TaskManagementJobListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTaskManagementJobRelationListData, &model.TaskManagementJobRelationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTaskManagementOverviewData, &model.TaskManagementOverviewDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeThresholdConstraintsListData, &model.ThresholdConstraintsListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeThresholdDescriptionListData, &model.ThresholdDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeThresholdListData, &model.ThresholdListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTierBoundaryDescriptionListData, &model.TierBoundaryDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTierBoundaryListData, &model.TierBoundaryListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTierDescriptionListData, &model.TierDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTierIncentiveRelationListData, &model.TierIncentiveRelationListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTierListData, &model.TierListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTimeDistributorData, &model.TimeDistributorDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTimeDistributorEnquiryCall, &model.TimeDistributorEnquiryCallType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTimeInformationData, &model.TimeInformationDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTimePrecisionData, &model.TimePrecisionDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTimeSeriesConstraintsListData, &model.TimeSeriesConstraintsListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTimeSeriesDescriptionListData, &model.TimeSeriesDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTimeSeriesListData, &model.TimeSeriesListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTimeTableConstraintsListData, &model.TimeTableConstraintsListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTimeTableDescriptionListData, &model.TimeTableDescriptionListDataType{}) - assert.NotNil(suite.T(), result) - - result = createCmd(model.FunctionTypeTimeTableListData, &model.TimeTableListDataType{}) - assert.NotNil(suite.T(), result) -} diff --git a/spine/function_data_factory.go b/spine/function_data_factory.go deleted file mode 100644 index 6b9520db..00000000 --- a/spine/function_data_factory.go +++ /dev/null @@ -1,301 +0,0 @@ -package spine - -import ( - "fmt" - - "github.com/enbility/eebus-go/spine/model" -) - -func CreateFunctionData[F any](featureType model.FeatureTypeType) []F { - if featureType == model.FeatureTypeTypeNodeManagement { - return []F{} // NodeManagement implementation is not using function data - } - - // Some devices use generic for everything (e.g. Vaillant Arotherm heatpump) - // or for some things like the SMA HM 2.0 or Elli Wallbox, which uses Generic feature - // for Heartbeats, even though that should go into FeatureTypeTypeDeviceDiagnosis - // Hence we add everything to the Generic feature, as we don't know what might be needed - - var result []F - - if featureType == model.FeatureTypeTypeActuatorLevel || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.ActuatorLevelDataType, F](model.FunctionTypeActuatorLevelData), - createFunctionData[model.ActuatorLevelDescriptionDataType, F](model.FunctionTypeActuatorLevelDescriptionData), - }...) - } - - if featureType == model.FeatureTypeTypeActuatorSwitch || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.ActuatorSwitchDataType, F](model.FunctionTypeActuatorSwitchData), - createFunctionData[model.ActuatorSwitchDescriptionDataType, F](model.FunctionTypeActuatorSwitchDescriptionData), - }...) - } - - if featureType == model.FeatureTypeTypeAlarm || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.AlarmListDataType, F](model.FunctionTypeAlarmListData), - }...) - } - - if featureType == model.FeatureTypeTypeBill || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.BillDescriptionListDataType, F](model.FunctionTypeBillDescriptionListData), - createFunctionData[model.BillConstraintsListDataType, F](model.FunctionTypeBillConstraintsListData), - createFunctionData[model.BillListDataType, F](model.FunctionTypeBillListData), - }...) - } - - if featureType == model.FeatureTypeTypeDataTunneling || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.DataTunnelingCallType, F](model.FunctionTypeDataTunnelingCall), - }...) - } - - if featureType == model.FeatureTypeTypeDeviceClassification || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.DeviceClassificationManufacturerDataType, F](model.FunctionTypeDeviceClassificationManufacturerData), - createFunctionData[model.DeviceClassificationUserDataType, F](model.FunctionTypeDeviceClassificationUserData), - }...) - } - - if featureType == model.FeatureTypeTypeDeviceConfiguration || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.DeviceConfigurationKeyValueConstraintsListDataType, F](model.FunctionTypeDeviceConfigurationKeyValueConstraintsListData), - createFunctionData[model.DeviceConfigurationKeyValueDescriptionListDataType, F](model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData), - createFunctionData[model.DeviceConfigurationKeyValueListDataType, F](model.FunctionTypeDeviceConfigurationKeyValueListData), - }...) - } - - if featureType == model.FeatureTypeTypeDeviceDiagnosis || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.DeviceDiagnosisStateDataType, F](model.FunctionTypeDeviceDiagnosisStateData), - createFunctionData[model.DeviceDiagnosisHeartbeatDataType, F](model.FunctionTypeDeviceDiagnosisHeartbeatData), - createFunctionData[model.DeviceDiagnosisServiceDataType, F](model.FunctionTypeDeviceDiagnosisServiceData), - }...) - } - - if featureType == model.FeatureTypeTypeDirectControl || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.DirectControlActivityListDataType, F](model.FunctionTypeDirectControlActivityListData), - createFunctionData[model.DirectControlDescriptionDataType, F](model.FunctionTypeDirectControlDescriptionData), - }...) - } - - if featureType == model.FeatureTypeTypeElectricalConnection || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.ElectricalConnectionDescriptionListDataType, F](model.FunctionTypeElectricalConnectionDescriptionListData), - createFunctionData[model.ElectricalConnectionParameterDescriptionListDataType, F](model.FunctionTypeElectricalConnectionParameterDescriptionListData), - createFunctionData[model.ElectricalConnectionPermittedValueSetListDataType, F](model.FunctionTypeElectricalConnectionPermittedValueSetListData), - createFunctionData[model.ElectricalConnectionStateListDataType, F](model.FunctionTypeElectricalConnectionStateListData), - }...) - } - - if featureType == model.FeatureTypeTypeHvac || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.HvacOperationModeDescriptionDataType, F](model.FunctionTypeHvacOperationModeDescriptionListData), - createFunctionData[model.HvacOverrunDescriptionListDataType, F](model.FunctionTypeHvacOverrunDescriptionListData), - createFunctionData[model.HvacOverrunListDataType, F](model.FunctionTypeHvacOverrunListData), - createFunctionData[model.HvacSystemFunctionDescriptionDataType, F](model.FunctionTypeHvacSystemFunctionDescriptionListData), - createFunctionData[model.HvacSystemFunctionListDataType, F](model.FunctionTypeHvacSystemFunctionListData), - createFunctionData[model.HvacSystemFunctionOperationModeRelationListDataType, F](model.FunctionTypeHvacSystemFunctionOperationModeRelationListData), - createFunctionData[model.HvacSystemFunctionPowerSequenceRelationListDataType, F](model.FunctionTypeHvacSystemFunctionPowerSequenceRelationListData), - createFunctionData[model.HvacSystemFunctionSetpointRelationListDataType, F](model.FunctionTypeHvacSystemFunctionSetPointRelationListData), - }...) - } - - if featureType == model.FeatureTypeTypeIdentification || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.IdentificationListDataType, F](model.FunctionTypeIdentificationListData), - }...) - } - - if featureType == model.FeatureTypeTypeIncentiveTable || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.IncentiveTableDescriptionDataType, F](model.FunctionTypeIncentiveTableDescriptionData), - createFunctionData[model.IncentiveTableConstraintsDataType, F](model.FunctionTypeIncentiveTableConstraintsData), - createFunctionData[model.IncentiveTableDataType, F](model.FunctionTypeIncentiveTableData), - }...) - } - - if featureType == model.FeatureTypeTypeLoadControl || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.LoadControlEventListDataType, F](model.FunctionTypeLoadControlEventListData), - createFunctionData[model.LoadControlLimitConstraintsListDataType, F](model.FunctionTypeLoadControlLimitConstraintsListData), - createFunctionData[model.LoadControlLimitDescriptionListDataType, F](model.FunctionTypeLoadControlLimitDescriptionListData), - createFunctionData[model.LoadControlLimitListDataType, F](model.FunctionTypeLoadControlLimitListData), - createFunctionData[model.LoadControlNodeDataType, F](model.FunctionTypeLoadControlNodeData), - createFunctionData[model.LoadControlStateListDataType, F](model.FunctionTypeLoadControlStateListData), - }...) - } - - if featureType == model.FeatureTypeTypeMeasurement || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.MeasurementListDataType, F](model.FunctionTypeMeasurementListData), - createFunctionData[model.MeasurementDescriptionListDataType, F](model.FunctionTypeMeasurementDescriptionListData), - createFunctionData[model.MeasurementConstraintsListDataType, F](model.FunctionTypeMeasurementConstraintsListData), - createFunctionData[model.MeasurementThresholdRelationListDataType, F](model.FunctionTypeMeasurementThresholdRelationListData), - }...) - } - - if featureType == model.FeatureTypeTypeMessaging || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.MessagingListDataType, F](model.FunctionTypeMessagingListData), - }...) - } - - if featureType == model.FeatureTypeTypeNetworkManagement || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.NetworkManagementAbortCallType, F](model.FunctionTypeNetworkManagementAbortCall), - createFunctionData[model.NetworkManagementAddNodeCallType, F](model.FunctionTypeNetworkManagementAddNodeCall), - createFunctionData[model.NetworkManagementDeviceDescriptionListDataType, F](model.FunctionTypeNetworkManagementDeviceDescriptionListData), - createFunctionData[model.NetworkManagementDiscoverCallType, F](model.FunctionTypeNetworkManagementDiscoverCall), - createFunctionData[model.NetworkManagementEntityDescriptionListDataType, F](model.FunctionTypeNetworkManagementEntityDescriptionListData), - createFunctionData[model.NetworkManagementFeatureDescriptionListDataType, F](model.FunctionTypeNetworkManagementFeatureDescriptionListData), - createFunctionData[model.NetworkManagementJoiningModeDataType, F](model.FunctionTypeNetworkManagementJoiningModeData), - createFunctionData[model.NetworkManagementModifyNodeCallType, F](model.FunctionTypeNetworkManagementModifyNodeCall), - createFunctionData[model.NetworkManagementProcessStateDataType, F](model.FunctionTypeNetworkManagementProcessStateData), - createFunctionData[model.NetworkManagementRemoveNodeCallType, F](model.FunctionTypeNetworkManagementRemoveNodeCall), - createFunctionData[model.NetworkManagementReportCandidateDataType, F](model.FunctionTypeNetworkManagementReportCandidateData), - createFunctionData[model.NetworkManagementScanNetworkCallType, F](model.FunctionTypeNetworkManagementScanNetworkCall), - }...) - } - - if featureType == model.FeatureTypeTypeOperatingConstraints || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.OperatingConstraintsDurationListDataType, F](model.FunctionTypeOperatingConstraintsDurationListData), - createFunctionData[model.OperatingConstraintsInterruptListDataType, F](model.FunctionTypeOperatingConstraintsInterruptListData), - createFunctionData[model.OperatingConstraintsPowerDescriptionListDataType, F](model.FunctionTypeOperatingConstraintsPowerDescriptionListData), - createFunctionData[model.OperatingConstraintsPowerLevelListDataType, F](model.FunctionTypeOperatingConstraintsPowerLevelListData), - createFunctionData[model.OperatingConstraintsPowerRangeListDataType, F](model.FunctionTypeOperatingConstraintsPowerRangeListData), - createFunctionData[model.OperatingConstraintsResumeImplicationListDataType, F](model.FunctionTypeOperatingConstraintsResumeImplicationListData), - }...) - } - - if featureType == model.FeatureTypeTypePowerSequences || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.PowerSequenceAlternativesRelationListDataType, F](model.FunctionTypePowerSequenceAlternativesRelationListData), - createFunctionData[model.PowerSequenceDescriptionListDataType, F](model.FunctionTypePowerSequenceDescriptionListData), - createFunctionData[model.PowerSequenceNodeScheduleInformationDataType, F](model.FunctionTypePowerSequenceNodeScheduleInformationData), - createFunctionData[model.PowerSequencePriceCalculationRequestCallType, F](model.FunctionTypePowerSequencePriceCalculationRequestCall), - createFunctionData[model.PowerSequencePriceListDataType, F](model.FunctionTypePowerSequencePriceListData), - createFunctionData[model.PowerSequenceScheduleConfigurationRequestCallType, F](model.FunctionTypePowerSequenceScheduleConfigurationRequestCall), - createFunctionData[model.PowerSequenceScheduleConstraintsListDataType, F](model.FunctionTypePowerSequenceScheduleConstraintsListData), - createFunctionData[model.PowerSequenceScheduleListDataType, F](model.FunctionTypePowerSequenceScheduleListData), - createFunctionData[model.PowerSequenceSchedulePreferenceListDataType, F](model.FunctionTypePowerSequenceSchedulePreferenceListData), - createFunctionData[model.PowerSequenceStateListDataType, F](model.FunctionTypePowerSequenceStateListData), - createFunctionData[model.PowerTimeSlotScheduleConstraintsListDataType, F](model.FunctionTypePowerTimeSlotScheduleConstraintsListData), - createFunctionData[model.PowerTimeSlotScheduleListDataType, F](model.FunctionTypePowerTimeSlotScheduleListData), - createFunctionData[model.PowerTimeSlotValueListDataType, F](model.FunctionTypePowerTimeSlotValueListData), - }...) - } - - if featureType == model.FeatureTypeTypeSensing || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.SensingDescriptionDataType, F](model.FunctionTypeSensingDescriptionData), - createFunctionData[model.SensingListDataType, F](model.FunctionTypeSensingListData), - }...) - } - - if featureType == model.FeatureTypeTypeSetpoint || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.SetpointConstraintsListDataType, F](model.FunctionTypeSetpointConstraintsListData), - createFunctionData[model.SetpointDescriptionListDataType, F](model.FunctionTypeSetpointDescriptionListData), - createFunctionData[model.SetpointListDataType, F](model.FunctionTypeSetpointListData), - }...) - } - - if featureType == model.FeatureTypeTypeSmartEnergyManagementPs || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.SmartEnergyManagementPsConfigurationRequestCallType, F](model.FunctionTypeSmartEnergyManagementPsConfigurationRequestCall), - createFunctionData[model.SmartEnergyManagementPsDataType, F](model.FunctionTypeSmartEnergyManagementPsData), - createFunctionData[model.SmartEnergyManagementPsPriceCalculationRequestCallType, F](model.FunctionTypeSmartEnergyManagementPsPriceCalculationRequestCall), - createFunctionData[model.SmartEnergyManagementPsPriceDataType, F](model.FunctionTypeSmartEnergyManagementPsPriceData), - }...) - } - - if featureType == model.FeatureTypeTypeSupplyCondition || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.SupplyConditionDescriptionListDataType, F](model.FunctionTypeSupplyConditionDescriptionListData), - createFunctionData[model.SupplyConditionListDataType, F](model.FunctionTypeSupplyConditionListData), - createFunctionData[model.SupplyConditionThresholdRelationListDataType, F](model.FunctionTypeSupplyConditionThresholdRelationListData), - }...) - } - - if featureType == model.FeatureTypeTypeTariffInformation || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.IncentiveDescriptionListDataType, F](model.FunctionTypeIncentiveDescriptionListData), - createFunctionData[model.IncentiveListDataType, F](model.FunctionTypeIncentiveListData), - createFunctionData[model.TariffBoundaryRelationListDataType, F](model.FunctionTypeTariffBoundaryRelationListData), - createFunctionData[model.TariffDescriptionListDataType, F](model.FunctionTypeTariffDescriptionListData), - createFunctionData[model.TariffListDataType, F](model.FunctionTypeTariffListData), - createFunctionData[model.TariffOverallConstraintsDataType, F](model.FunctionTypeTariffOverallConstraintsData), - createFunctionData[model.TariffTierRelationListDataType, F](model.FunctionTypeTariffTierRelationListData), - createFunctionData[model.TierBoundaryDescriptionListDataType, F](model.FunctionTypeTierBoundaryDescriptionListData), - createFunctionData[model.TierBoundaryListDataType, F](model.FunctionTypeTierBoundaryListData), - createFunctionData[model.TierDescriptionListDataType, F](model.FunctionTypeTierDescriptionListData), - createFunctionData[model.TierIncentiveRelationListDataType, F](model.FunctionTypeTierIncentiveRelationListData), - createFunctionData[model.TierListDataType, F](model.FunctionTypeTierListData), - }...) - } - - if featureType == model.FeatureTypeTypeTaskManagement || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.TaskManagementJobDescriptionListDataType, F](model.FunctionTypeTaskManagementJobDescriptionListData), - createFunctionData[model.TaskManagementJobListDataType, F](model.FunctionTypeTaskManagementJobListData), - createFunctionData[model.TaskManagementJobRelationListDataType, F](model.FunctionTypeTaskManagementJobRelationListData), - createFunctionData[model.TaskManagementOverviewDataType, F](model.FunctionTypeTaskManagementOverviewData), - }...) - } - - if featureType == model.FeatureTypeTypeThreshold || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.ThresholdConstraintsListDataType, F](model.FunctionTypeThresholdConstraintsListData), - createFunctionData[model.ThresholdDescriptionListDataType, F](model.FunctionTypeThresholdDescriptionListData), - createFunctionData[model.ThresholdListDataType, F](model.FunctionTypeThresholdListData), - }...) - } - - if featureType == model.FeatureTypeTypeTimeInformation || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.TimeDistributorDataType, F](model.FunctionTypeTimeDistributorData), - createFunctionData[model.TimeDistributorEnquiryCallType, F](model.FunctionTypeTimeDistributorEnquiryCall), - createFunctionData[model.TimeInformationDataType, F](model.FunctionTypeTimeInformationData), - createFunctionData[model.TimePrecisionDataType, F](model.FunctionTypeTimePrecisionData), - }...) - } - - if featureType == model.FeatureTypeTypeTimeSeries || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.TimeSeriesDescriptionListDataType, F](model.FunctionTypeTimeSeriesDescriptionListData), - createFunctionData[model.TimeSeriesConstraintsListDataType, F](model.FunctionTypeTimeSeriesConstraintsListData), - createFunctionData[model.TimeSeriesListDataType, F](model.FunctionTypeTimeSeriesListData), - }...) - } - - if featureType == model.FeatureTypeTypeTimeTable || featureType == model.FeatureTypeTypeGeneric { - result = append(result, []F{ - createFunctionData[model.TimeTableConstraintsListDataType, F](model.FunctionTypeTimeTableConstraintsListData), - createFunctionData[model.TimeTableDescriptionListDataType, F](model.FunctionTypeTimeTableDescriptionListData), - createFunctionData[model.TimeTableListDataType, F](model.FunctionTypeTimeTableListData), - }...) - } - - if len(result) == 0 { - panic(fmt.Errorf("unknown featureType '%s'", featureType)) - } - - return result -} - -func createFunctionData[T any, F any](functionType model.FunctionType) F { - x := any(new(F)) - switch x.(type) { - case *FunctionDataCmd: - return any(NewFunctionDataCmd[T](functionType)).(F) - case *FunctionData: - return any(NewFunctionData[T](functionType)).(F) - default: - panic(fmt.Errorf("only FunctionData and FunctionDataCmd are supported")) - } -} diff --git a/spine/function_data_factory_test.go b/spine/function_data_factory_test.go deleted file mode 100644 index 368b8562..00000000 --- a/spine/function_data_factory_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package spine - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/stretchr/testify/assert" -) - -func TestFunctionDataFactory_FunctionData(t *testing.T) { - result := CreateFunctionData[FunctionData](model.FeatureTypeTypeBill) - assert.Equal(t, 3, len(result)) - assert.IsType(t, &FunctionDataImpl[model.BillDescriptionListDataType]{}, result[0]) - assert.IsType(t, &FunctionDataImpl[model.BillConstraintsListDataType]{}, result[1]) - assert.IsType(t, &FunctionDataImpl[model.BillListDataType]{}, result[2]) - - result = CreateFunctionData[FunctionData](model.FeatureTypeTypeDeviceClassification) - assert.Equal(t, 2, len(result)) - assert.IsType(t, &FunctionDataImpl[model.DeviceClassificationManufacturerDataType]{}, result[0]) - assert.IsType(t, &FunctionDataImpl[model.DeviceClassificationUserDataType]{}, result[1]) - - result = CreateFunctionData[FunctionData](model.FeatureTypeTypeDeviceConfiguration) - assert.Equal(t, 3, len(result)) - assert.IsType(t, &FunctionDataImpl[model.DeviceConfigurationKeyValueConstraintsListDataType]{}, result[0]) - assert.IsType(t, &FunctionDataImpl[model.DeviceConfigurationKeyValueDescriptionListDataType]{}, result[1]) - assert.IsType(t, &FunctionDataImpl[model.DeviceConfigurationKeyValueListDataType]{}, result[2]) - - result = CreateFunctionData[FunctionData](model.FeatureTypeTypeDeviceDiagnosis) - assert.Equal(t, 3, len(result)) - assert.IsType(t, &FunctionDataImpl[model.DeviceDiagnosisStateDataType]{}, result[0]) - assert.IsType(t, &FunctionDataImpl[model.DeviceDiagnosisHeartbeatDataType]{}, result[1]) - - result = CreateFunctionData[FunctionData](model.FeatureTypeTypeElectricalConnection) - assert.Equal(t, 4, len(result)) - assert.IsType(t, &FunctionDataImpl[model.ElectricalConnectionDescriptionListDataType]{}, result[0]) - assert.IsType(t, &FunctionDataImpl[model.ElectricalConnectionParameterDescriptionListDataType]{}, result[1]) - assert.IsType(t, &FunctionDataImpl[model.ElectricalConnectionPermittedValueSetListDataType]{}, result[2]) - - result = CreateFunctionData[FunctionData](model.FeatureTypeTypeHvac) - assert.Equal(t, 8, len(result)) - assert.IsType(t, &FunctionDataImpl[model.HvacOperationModeDescriptionDataType]{}, result[0]) - assert.IsType(t, &FunctionDataImpl[model.HvacOverrunDescriptionListDataType]{}, result[1]) - assert.IsType(t, &FunctionDataImpl[model.HvacOverrunListDataType]{}, result[2]) - assert.IsType(t, &FunctionDataImpl[model.HvacSystemFunctionDescriptionDataType]{}, result[3]) - assert.IsType(t, &FunctionDataImpl[model.HvacSystemFunctionListDataType]{}, result[4]) - - result = CreateFunctionData[FunctionData](model.FeatureTypeTypeIdentification) - assert.Equal(t, 1, len(result)) - assert.IsType(t, &FunctionDataImpl[model.IdentificationListDataType]{}, result[0]) - - result = CreateFunctionData[FunctionData](model.FeatureTypeTypeIncentiveTable) - assert.Equal(t, 3, len(result)) - assert.IsType(t, &FunctionDataImpl[model.IncentiveTableDescriptionDataType]{}, result[0]) - assert.IsType(t, &FunctionDataImpl[model.IncentiveTableConstraintsDataType]{}, result[1]) - assert.IsType(t, &FunctionDataImpl[model.IncentiveTableDataType]{}, result[2]) - - result = CreateFunctionData[FunctionData](model.FeatureTypeTypeLoadControl) - assert.Equal(t, 6, len(result)) - assert.IsType(t, &FunctionDataImpl[model.LoadControlEventListDataType]{}, result[0]) - assert.IsType(t, &FunctionDataImpl[model.LoadControlLimitConstraintsListDataType]{}, result[1]) - assert.IsType(t, &FunctionDataImpl[model.LoadControlLimitDescriptionListDataType]{}, result[2]) - assert.IsType(t, &FunctionDataImpl[model.LoadControlLimitListDataType]{}, result[3]) - - result = CreateFunctionData[FunctionData](model.FeatureTypeTypeMeasurement) - assert.Equal(t, 4, len(result)) - assert.IsType(t, &FunctionDataImpl[model.MeasurementListDataType]{}, result[0]) - assert.IsType(t, &FunctionDataImpl[model.MeasurementDescriptionListDataType]{}, result[1]) - assert.IsType(t, &FunctionDataImpl[model.MeasurementConstraintsListDataType]{}, result[2]) - assert.IsType(t, &FunctionDataImpl[model.MeasurementThresholdRelationListDataType]{}, result[3]) - - result = CreateFunctionData[FunctionData](model.FeatureTypeTypeTimeSeries) - assert.Equal(t, 3, len(result)) - assert.IsType(t, &FunctionDataImpl[model.TimeSeriesDescriptionListDataType]{}, result[0]) - assert.IsType(t, &FunctionDataImpl[model.TimeSeriesConstraintsListDataType]{}, result[1]) - assert.IsType(t, &FunctionDataImpl[model.TimeSeriesListDataType]{}, result[2]) - - result = CreateFunctionData[FunctionData](model.FeatureTypeTypeGeneric) - assert.Equal(t, 118, len(result)) -} - -func TestFunctionDataFactory_FunctionDataCmd(t *testing.T) { - result := CreateFunctionData[FunctionDataCmd](model.FeatureTypeTypeDeviceClassification) - assert.Equal(t, 2, len(result)) - assert.IsType(t, &FunctionDataCmdImpl[model.DeviceClassificationManufacturerDataType]{}, result[0]) - assert.IsType(t, &FunctionDataCmdImpl[model.DeviceClassificationUserDataType]{}, result[1]) -} - -func TestFunctionDataFactory_NodeMgmtFeatureType(t *testing.T) { - result := CreateFunctionData[FunctionDataCmd](model.FeatureTypeTypeNodeManagement) - assert.Equal(t, 0, len(result)) -} - -func TestFunctionDataFactory_unknownFunctionDataType(t *testing.T) { - assert.PanicsWithError(t, "only FunctionData and FunctionDataCmd are supported", - func() { CreateFunctionData[int](model.FeatureTypeTypeDeviceClassification) }) -} diff --git a/spine/function_data_test.go b/spine/function_data_test.go deleted file mode 100644 index 79027212..00000000 --- a/spine/function_data_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package spine - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestFunctionData_UpdateData(t *testing.T) { - newData := &model.DeviceClassificationManufacturerDataType{ - DeviceName: util.Ptr(model.DeviceClassificationStringType("device name")), - } - functionType := model.FunctionTypeDeviceClassificationManufacturerData - sut := NewFunctionData[model.DeviceClassificationManufacturerDataType](functionType) - sut.UpdateData(newData, nil, nil) - getData := sut.Data() - - assert.Equal(t, newData.DeviceName, getData.DeviceName) - assert.Equal(t, functionType, sut.Function()) - - // another update should not be reflected in the first dataset - newData = &model.DeviceClassificationManufacturerDataType{ - DeviceName: util.Ptr(model.DeviceClassificationStringType("new device name")), - } - sut.UpdateData(newData, nil, nil) - getNewData := sut.Data() - - assert.Equal(t, newData.DeviceName, getNewData.DeviceName) - assert.NotEqual(t, getData.DeviceName, getNewData.DeviceName) - assert.Equal(t, functionType, sut.Function()) -} - -func TestFunctionData_UpdateDataPartial(t *testing.T) { - newData := &model.ElectricalConnectionPermittedValueSetListDataType{ - ElectricalConnectionPermittedValueSetData: []model.ElectricalConnectionPermittedValueSetDataType{ - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(1)), - ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(1)), - PermittedValueSet: []model.ScaledNumberSetType{ - { - Range: []model.ScaledNumberRangeType{ - { - Min: &model.ScaledNumberType{ - Number: util.Ptr(model.NumberType(6)), - Scale: util.Ptr(model.ScaleType(0)), - }, - }, - }, - }, - }, - }, - }, - } - functionType := model.FunctionTypeElectricalConnectionPermittedValueSetListData - sut := NewFunctionData[model.ElectricalConnectionPermittedValueSetListDataType](functionType) - - err := sut.UpdateData(newData, &model.FilterType{CmdControl: &model.CmdControlType{Partial: &model.ElementTagType{}}}, nil) - if assert.Nil(t, err) { - getData := sut.Data() - assert.Equal(t, 1, len(getData.ElectricalConnectionPermittedValueSetData)) - } -} - -func TestFunctionData_UpdateDataPartial_Supported(t *testing.T) { - newData := &model.HvacOverrunListDataType{ - HvacOverrunData: []model.HvacOverrunDataType{ - { - OverrunId: util.Ptr(model.HvacOverrunIdType(1)), - }, - }, - } - functionType := model.FunctionTypeHvacOverrunListData - sut := NewFunctionData[model.HvacOverrunListDataType](functionType) - - err := sut.UpdateData(newData, &model.FilterType{CmdControl: &model.CmdControlType{Partial: &model.ElementTagType{}}}, nil) - assert.Nil(t, err) -} diff --git a/spine/heartbeat.go b/spine/heartbeat.go deleted file mode 100644 index b7672d0f..00000000 --- a/spine/heartbeat.go +++ /dev/null @@ -1,148 +0,0 @@ -package spine - -import ( - "sync" - "sync/atomic" - "time" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/spine/model" -) - -const hearbeatMsgCountersSize = 10 - -type HeartbeatSender struct { - heartBeatNum uint64 // see https://github.com/golang/go/issues/11891 - stopHeartbeatC chan struct{} - stopMux sync.Mutex - senderAddr, destinationAddr *model.FeatureAddressType - sender Sender - heartBeatTimeout *model.DurationType - - msgCounters []model.MsgCounterType - - mux sync.Mutex -} - -func NewHeartbeatSender(sender Sender) *HeartbeatSender { - h := &HeartbeatSender{ - sender: sender, - } - // default to 4 seconds timeout - h.heartBeatTimeout = model.NewDurationType(time.Second * 4) - - return h -} - -func (c *HeartbeatSender) AddMsgCounter(msgCounter *model.MsgCounterType) { - if msgCounter == nil { - return - } - - c.mux.Lock() - defer c.mux.Unlock() - - c.msgCounters = append(c.msgCounters, *msgCounter) - if len(c.msgCounters) > hearbeatMsgCountersSize { - c.msgCounters = c.msgCounters[1:] - } -} - -func (c *HeartbeatSender) IsHeartbeatMsgCounter(msgCounter model.MsgCounterType) bool { - c.mux.Lock() - defer c.mux.Unlock() - - for _, item := range c.msgCounters { - if item == msgCounter { - return true - } - } - - return false -} - -func (c *HeartbeatSender) StartHeartbeatSend(senderAddr, destinationAddr *model.FeatureAddressType) { - // stop a already running heartbeat - c.StopHeartbeat() - - c.senderAddr = senderAddr - c.destinationAddr = destinationAddr - - c.stopHeartbeatC = make(chan struct{}) - - go func() { - c.sendHearbeat(c.stopHeartbeatC, 800*time.Millisecond) - }() -} - -func (c *HeartbeatSender) StopHeartbeat() { - c.stopMux.Lock() - defer c.stopMux.Unlock() - - if c.stopHeartbeatC != nil && !c.isHeartbeatClosed() { - close(c.stopHeartbeatC) - } -} - -func (c *HeartbeatSender) heartbeatCmd(t time.Time) model.CmdType { - timestamp := t.UTC().Format(time.RFC3339) - cmd := model.CmdType{ - DeviceDiagnosisHeartbeatData: &model.DeviceDiagnosisHeartbeatDataType{ - Timestamp: ×tamp, - HeartbeatCounter: c.heartBeatCounter(), - HeartbeatTimeout: c.heartBeatTimeout, - }, - } - - return cmd -} - -func (c *HeartbeatSender) SendHeartBeatData(requestHeader *model.HeaderType) error { - // TODO is this all we need here? - - cmd := c.heartbeatCmd(time.Now()) - - return c.sender.Reply(requestHeader, c.senderAddr, cmd) -} - -func (c *HeartbeatSender) sendHearbeat(stopC chan struct{}, d time.Duration) { - ticker := time.NewTicker(d) - for { - select { - case <-ticker.C: - - if c.senderAddr == nil || c.destinationAddr == nil { - break - } - - cmd := c.heartbeatCmd(time.Now()) - - msgCounter, err := c.sender.Notify(c.senderAddr, c.destinationAddr, cmd) - if err != nil { - logging.Log.Debug("ERROR sending heartbeat: ", err) - } - if msgCounter != nil { - c.msgCounters = append(c.msgCounters, *msgCounter) - } - - case <-stopC: - return - } - } -} - -func (c *HeartbeatSender) isHeartbeatClosed() bool { - select { - case <-c.stopHeartbeatC: - return true - default: - } - - return false -} - -// TODO heartBeatCounter should be global on CEM level, not on connection level -func (c *HeartbeatSender) heartBeatCounter() *uint64 { - i := atomic.AddUint64(&c.heartBeatNum, 1) - return &i -} diff --git a/spine/message.go b/spine/message.go deleted file mode 100644 index 86d6a5b4..00000000 --- a/spine/message.go +++ /dev/null @@ -1,23 +0,0 @@ -package spine - -import "github.com/enbility/eebus-go/spine/model" - -type Message struct { - RequestHeader *model.HeaderType - CmdClassifier model.CmdClassifierType - Cmd model.CmdType - FilterPartial *model.FilterType - FilterDelete *model.FilterType - FeatureRemote *FeatureRemoteImpl - EntityRemote *EntityRemoteImpl - DeviceRemote *DeviceRemoteImpl -} - -type ResultMessage struct { - MsgCounterReference model.MsgCounterType // required - Result *model.ResultDataType // required, may not be nil - FeatureLocal *FeatureLocalImpl // required, may not be nil - FeatureRemote *FeatureRemoteImpl // required, may not be nil - EntityRemote *EntityRemoteImpl // required, may not be nil - DeviceRemote *DeviceRemoteImpl // required, may not be nil -} diff --git a/spine/mocks/Sender.go b/spine/mocks/Sender.go deleted file mode 100644 index 3d7b1a71..00000000 --- a/spine/mocks/Sender.go +++ /dev/null @@ -1,186 +0,0 @@ -// Code generated by mockery v2.14.1. DO NOT EDIT. - -package mocks - -import ( - spine "github.com/enbility/eebus-go/spine" - model "github.com/enbility/eebus-go/spine/model" - mock "github.com/stretchr/testify/mock" -) - -// Sender is an autogenerated mock type for the Sender type -type Sender struct { - mock.Mock -} - -// Bind provides a mock function with given fields: senderAddress, destinationAddress, serverFeatureType -func (_m *Sender) Bind(senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType, serverFeatureType model.FeatureTypeType) (*model.MsgCounterType, error) { - ret := _m.Called(senderAddress, destinationAddress, serverFeatureType) - - var r0 *model.MsgCounterType - if rf, ok := ret.Get(0).(func(*model.FeatureAddressType, *model.FeatureAddressType, model.FeatureTypeType) *model.MsgCounterType); ok { - r0 = rf(senderAddress, destinationAddress, serverFeatureType) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.MsgCounterType) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(*model.FeatureAddressType, *model.FeatureAddressType, model.FeatureTypeType) error); ok { - r1 = rf(senderAddress, destinationAddress, serverFeatureType) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Notify provides a mock function with given fields: senderAddress, destinationAddress, cmd -func (_m *Sender) Notify(senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType, cmd model.CmdType) (*model.MsgCounterType, error) { - ret := _m.Called(senderAddress, destinationAddress, cmd) - - var r0 *model.MsgCounterType - if rf, ok := ret.Get(0).(func(*model.FeatureAddressType, *model.FeatureAddressType, model.CmdType) *model.MsgCounterType); ok { - r0 = rf(senderAddress, destinationAddress, cmd) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.MsgCounterType) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(*model.FeatureAddressType, *model.FeatureAddressType, model.CmdType) error); ok { - r1 = rf(senderAddress, destinationAddress, cmd) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Reply provides a mock function with given fields: requestHeader, senderAddress, cmd -func (_m *Sender) Reply(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType, cmd model.CmdType) error { - ret := _m.Called(requestHeader, senderAddress, cmd) - - var r0 error - if rf, ok := ret.Get(0).(func(*model.HeaderType, *model.FeatureAddressType, model.CmdType) error); ok { - r0 = rf(requestHeader, senderAddress, cmd) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Request provides a mock function with given fields: cmdClassifier, senderAddress, destinationAddress, ackRequest, cmd -func (_m *Sender) Request(cmdClassifier model.CmdClassifierType, senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType, ackRequest bool, cmd []model.CmdType) (*model.MsgCounterType, error) { - ret := _m.Called(cmdClassifier, senderAddress, destinationAddress, ackRequest, cmd) - - var r0 *model.MsgCounterType - if rf, ok := ret.Get(0).(func(model.CmdClassifierType, *model.FeatureAddressType, *model.FeatureAddressType, bool, []model.CmdType) *model.MsgCounterType); ok { - r0 = rf(cmdClassifier, senderAddress, destinationAddress, ackRequest, cmd) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.MsgCounterType) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(model.CmdClassifierType, *model.FeatureAddressType, *model.FeatureAddressType, bool, []model.CmdType) error); ok { - r1 = rf(cmdClassifier, senderAddress, destinationAddress, ackRequest, cmd) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ResultError provides a mock function with given fields: requestHeader, senderAddress, err -func (_m *Sender) ResultError(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType, err *spine.ErrorType) error { - ret := _m.Called(requestHeader, senderAddress, err) - - var r0 error - if rf, ok := ret.Get(0).(func(*model.HeaderType, *model.FeatureAddressType, *spine.ErrorType) error); ok { - r0 = rf(requestHeader, senderAddress, err) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ResultSuccess provides a mock function with given fields: requestHeader, senderAddress -func (_m *Sender) ResultSuccess(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType) error { - ret := _m.Called(requestHeader, senderAddress) - - var r0 error - if rf, ok := ret.Get(0).(func(*model.HeaderType, *model.FeatureAddressType) error); ok { - r0 = rf(requestHeader, senderAddress) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Subscribe provides a mock function with given fields: senderAddress, destinationAddress, serverFeatureType -func (_m *Sender) Subscribe(senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType, serverFeatureType model.FeatureTypeType) (*model.MsgCounterType, error) { - ret := _m.Called(senderAddress, destinationAddress, serverFeatureType) - - var r0 *model.MsgCounterType - if rf, ok := ret.Get(0).(func(*model.FeatureAddressType, *model.FeatureAddressType, model.FeatureTypeType) *model.MsgCounterType); ok { - r0 = rf(senderAddress, destinationAddress, serverFeatureType) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.MsgCounterType) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(*model.FeatureAddressType, *model.FeatureAddressType, model.FeatureTypeType) error); ok { - r1 = rf(senderAddress, destinationAddress, serverFeatureType) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Write provides a mock function with given fields: senderAddress, destinationAddress, cmd -func (_m *Sender) Write(senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType, cmd model.CmdType) (*model.MsgCounterType, error) { - ret := _m.Called(senderAddress, destinationAddress, cmd) - - var r0 *model.MsgCounterType - if rf, ok := ret.Get(0).(func(*model.FeatureAddressType, *model.FeatureAddressType, model.CmdType) *model.MsgCounterType); ok { - r0 = rf(senderAddress, destinationAddress, cmd) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.MsgCounterType) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(*model.FeatureAddressType, *model.FeatureAddressType, model.CmdType) error); ok { - r1 = rf(senderAddress, destinationAddress, cmd) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -type mockConstructorTestingTNewSender interface { - mock.TestingT - Cleanup(func()) -} - -// NewSender creates a new instance of Sender. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSender(t mockConstructorTestingTNewSender) *Sender { - mock := &Sender{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/spine/model/actuatorlevel.go b/spine/model/actuatorlevel.go deleted file mode 100644 index 64e4077d..00000000 --- a/spine/model/actuatorlevel.go +++ /dev/null @@ -1,36 +0,0 @@ -package model - -type ActuatorLevelFctType string - -const ( - ActuatorLevelFctTypeStart ActuatorLevelFctType = "start" - ActuatorLevelFctTypeUp ActuatorLevelFctType = "up" - ActuatorLevelFctTypeDown ActuatorLevelFctType = "down" - ActuatorLevelFctTypeStop ActuatorLevelFctType = "stop" - ActuatorLevelFctTypePercentageAbsolute ActuatorLevelFctType = "percentageAbsolute" - ActuatorLevelFctTypePercentageRelative ActuatorLevelFctType = "percentageRelative" - ActuatorLevelFctTypeAbsolut ActuatorLevelFctType = "absolut" - ActuatorLevelFctTypeRelative ActuatorLevelFctType = "relative" -) - -type ActuatorLevelDataType struct { - Function *ActuatorLevelFctType `json:"function,omitempty"` - Value *ScaledNumberType `json:"value,omitempty"` -} - -type ActuatorLevelDataElementsType struct { - Function *ElementTagType `json:"function,omitempty"` - Value *ElementTagType `json:"value,omitempty"` -} - -type ActuatorLevelDescriptionDataType struct { - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` - LevelDefaultUnit *UnitOfMeasurementType `json:"levelDefaultUnit,omitempty"` -} - -type ActuatorLevelDescriptionDataElementsType struct { - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` - LevelDefaultUnit *ElementTagType `json:"levelDefaultUnit,omitempty"` -} diff --git a/spine/model/actuatorswitch.go b/spine/model/actuatorswitch.go deleted file mode 100644 index cd76d39d..00000000 --- a/spine/model/actuatorswitch.go +++ /dev/null @@ -1,27 +0,0 @@ -package model - -type ActuatorSwitchFctType string - -const ( - ActuatorSwitchFctTypeOn ActuatorSwitchFctType = "on" - ActuatorSwitchFctTypeOff ActuatorSwitchFctType = "off" - ActuatorSwitchFctTypeToggle ActuatorSwitchFctType = "toggle" -) - -type ActuatorSwitchDataType struct { - Function *ActuatorSwitchFctType `json:"function,omitempty"` -} - -type ActuatorSwitchDataElementsType struct { - Function *ElementTagType `json:"function,omitempty"` -} - -type ActuatorSwitchDescriptionDataType struct { - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type ActuatorSwitchDescriptionDataElementsType struct { - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} diff --git a/spine/model/alarm.go b/spine/model/alarm.go deleted file mode 100644 index 7158fce4..00000000 --- a/spine/model/alarm.go +++ /dev/null @@ -1,44 +0,0 @@ -package model - -type AlarmIdType uint - -type AlarmTypeType string - -const ( - AlarmTypeTypeAlarmCancelled AlarmTypeType = "alarmCancelled" - AlarmTypeTypeUnderThreshold AlarmTypeType = "underThreshold" - AlarmTypeTypeOverThreshold AlarmTypeType = "overThreshold" -) - -type AlarmDataType struct { - AlarmId *AlarmIdType `json:"alarmId,omitempty" eebus:"key"` - ThresholdId *ThresholdIdType `json:"thresholdId,omitempty"` - Timestamp *AbsoluteOrRelativeTimeType `json:"timestamp,omitempty"` - AlarmType *AlarmTypeType `json:"alarmType,omitempty"` - MeasuredValue *ScaledNumberType `json:"measuredValue,omitempty"` - EvaluationPeriod *TimePeriodType `json:"evaluationPeriod,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type AlarmDataElementsType struct { - AlarmId *ElementTagType `json:"alarmId,omitempty"` - ThresholdId *ElementTagType `json:"thresholdId,omitempty"` - Timestamp *ElementTagType `json:"timestamp,omitempty"` - AlarmType *ElementTagType `json:"alarmType,omitempty"` - MeasuredValue *ScaledNumberElementsType `json:"measuredValue,omitempty"` - EvaluationPeriod *TimePeriodElementsType `json:"evaluationPeriod,omitempty"` - ScopeType *ElementTagType `json:"scopeType,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type AlarmListDataType struct { - AlarmListData []AlarmDataType `json:"alarmListData,omitempty"` -} - -type AlarmListDataSelectorsType struct { - AlarmId *AlarmIdType `json:"alarmId,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` -} diff --git a/spine/model/alarm_additions.go b/spine/model/alarm_additions.go deleted file mode 100644 index 80e85b72..00000000 --- a/spine/model/alarm_additions.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -// AlarmListDataType - -var _ Updater = (*AlarmListDataType)(nil) - -func (r *AlarmListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []AlarmDataType - if newList != nil { - newData = newList.(*AlarmListDataType).AlarmListData - } - - r.AlarmListData = UpdateList(r.AlarmListData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/alarm_additions_test.go b/spine/model/alarm_additions_test.go deleted file mode 100644 index 6f947eb4..00000000 --- a/spine/model/alarm_additions_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestAlarmListDataType_Update(t *testing.T) { - sut := model.AlarmListDataType{ - AlarmListData: []model.AlarmDataType{ - { - AlarmId: util.Ptr(model.AlarmIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - AlarmId: util.Ptr(model.AlarmIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.AlarmListDataType{ - AlarmListData: []model.AlarmDataType{ - { - AlarmId: util.Ptr(model.AlarmIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.AlarmListData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.AlarmId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.AlarmId)) - assert.Equal(t, "new", string(*item2.Description)) -} diff --git a/spine/model/bill.go b/spine/model/bill.go deleted file mode 100644 index a0589fbf..00000000 --- a/spine/model/bill.go +++ /dev/null @@ -1,155 +0,0 @@ -package model - -type BillIdType uint - -type BillTypeType string - -const ( - BillTypeTypeChargingSummary BillTypeType = "chargingSummary" -) - -type BillPositionIdType uint - -type BillPositionCountType BillPositionIdType - -type BillPositionTypeType string - -const ( - BillPositionTypeTypeGridElectricEnergy BillPositionTypeType = "gridElectricEnergy" - BillPositionTypeTypeSelfProducedElectricEnergy BillPositionTypeType = "selfProducedElectricEnergy" -) - -type BillValueIdType uint - -type BillCostIdType uint - -type BillCostTypeType string - -const ( - BillCostTypeTypeAbsolutePrice BillCostTypeType = "absolutePrice" - BillCostTypeTypeRelativePrice BillCostTypeType = "relativePrice" - BillCostTypeTypeCo2Emission BillCostTypeType = "co2Emission" - BillCostTypeTypeRenewableEnergy BillCostTypeType = "renewableEnergy" - BillCostTypeTypeRadioactiveWaste BillCostTypeType = "radioactiveWaste" -) - -type BillValueType struct { - ValueId *BillValueIdType `json:"valueId,omitempty"` - Unit *UnitOfMeasurementType `json:"unit,omitempty"` - Value *ScaledNumberType `json:"value,omitempty"` - ValuePercentage *ScaledNumberType `json:"valuePercentage,omitempty"` -} - -type BillValueElementsType struct { - ValueId *ElementTagType `json:"valueId,omitempty"` - Unit *ElementTagType `json:"unit,omitempty"` - Value *ElementTagType `json:"value,omitempty"` - ValuePercentage *ElementTagType `json:"valuePercentage,omitempty"` -} - -type BillCostType struct { - CostId *BillCostIdType `json:"costId,omitempty"` - CostType *BillCostTypeType `json:"costType,omitempty"` - ValueId *BillValueIdType `json:"valueId,omitempty"` - Unit *UnitOfMeasurementType `json:"unit,omitempty"` - Currency *CurrencyType `json:"currency,omitempty"` - Cost *ScaledNumberType `json:"cost,omitempty"` - CostPercentage *ScaledNumberType `json:"costPercentage,omitempty"` -} - -type BillCostElementsType struct { - CostId *ElementTagType `json:"costId,omitempty"` - CostType *ElementTagType `json:"costType,omitempty"` - ValueId *ElementTagType `json:"valueId,omitempty"` - Unit *ElementTagType `json:"unit,omitempty"` - Currency *ElementTagType `json:"currency,omitempty"` - Cost *ScaledNumberElementsType `json:"cost,omitempty"` - CostPercentage *ScaledNumberElementsType `json:"costPercentage,omitempty"` -} - -type BillPositionType struct { - PositionId *BillPositionIdType `json:"positionId,omitempty"` - PositionType *BillPositionTypeType `json:"positionType,omitempty"` - TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` - Value *BillValueType `json:"value,omitempty"` - Cost *BillCostType `json:"cost,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type BillPositionElementsType struct { - PositionId *ElementTagType `json:"positionId,omitempty"` - PositionType *ElementTagType `json:"positionType,omitempty"` - TimePeriod *TimePeriodElementsType `json:"timePeriod,omitempty"` - Value *BillValueElementsType `json:"value,omitempty"` - Cost *BillCostElementsType `json:"cost,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type BillDataType struct { - BillId *BillIdType `json:"billId,omitempty" eebus:"key"` - BillType *BillTypeType `json:"billType,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` - Total *BillPositionType `json:"total,omitempty"` - Position []BillPositionType `json:"position,omitempty"` -} - -type BillDataElementsType struct { - BillId *ElementTagType `json:"billId,omitempty"` - BillType *ElementTagType `json:"billType,omitempty"` - ScopeType *ElementTagType `json:"scopeType,omitempty"` - Total *BillPositionElementsType `json:"total,omitempty"` - Position *BillPositionElementsType `json:"position,omitempty"` -} - -type BillListDataType struct { - BillData []BillDataType `json:"billData,omitempty"` -} - -type BillListDataSelectorsType struct { - BillId *BillIdType `json:"billId,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` -} - -type BillConstraintsDataType struct { - BillId *BillIdType `json:"billId,omitempty" eebus:"key"` - PositionCountMin *BillPositionCountType `json:"positionCountMin,omitempty"` - PositionCountMax *BillPositionCountType `json:"positionCountMax,omitempty"` -} - -type BillConstraintsDataElementsType struct { - BillId *ElementTagType `json:"billId,omitempty"` - PositionCountMin *ElementTagType `json:"positionCountMin,omitempty"` - PositionCountMax *ElementTagType `json:"positionCountMax,omitempty"` -} - -type BillConstraintsListDataType struct { - BillConstraintsData []BillConstraintsDataType `json:"billConstraintsData,omitempty"` -} - -type BillConstraintsListDataSelectorsType struct { - BillId *BillIdType `json:"billId,omitempty"` -} - -type BillDescriptionDataType struct { - BillId *BillIdType `json:"billId,omitempty" eebus:"key"` - BillWriteable *bool `json:"billWriteable,omitempty"` - UpdateRequired *bool `json:"updateRequired,omitempty"` - SupportedBillType []BillTypeType `json:"supportedBillType,omitempty"` -} - -type BillDescriptionDataElementsType struct { - BillId *ElementTagType `json:"billId,omitempty"` - BillWriteable *ElementTagType `json:"billWriteable,omitempty"` - UpdateRequired *ElementTagType `json:"updateRequired,omitempty"` - SupportedBillType *ElementTagType `json:"supportedBillType,omitempty"` -} - -type BillDescriptionListDataType struct { - BillDescriptionData []BillDescriptionDataType `json:"billDescriptionData,omitempty"` -} - -type BillDescriptionListDataSelectorsType struct { - BillId *BillIdType `json:"billId,omitempty"` -} diff --git a/spine/model/bill_additions.go b/spine/model/bill_additions.go deleted file mode 100644 index 8e08654e..00000000 --- a/spine/model/bill_additions.go +++ /dev/null @@ -1,40 +0,0 @@ -package model - -// BillListDataType - -var _ Updater = (*BillListDataType)(nil) - -func (r *BillListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []BillDataType - if newList != nil { - newData = newList.(*BillListDataType).BillData - } - - r.BillData = UpdateList(r.BillData, newData, filterPartial, filterDelete) -} - -// BillConstraintsListDataType - -var _ Updater = (*BillConstraintsListDataType)(nil) - -func (r *BillConstraintsListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []BillConstraintsDataType - if newList != nil { - newData = newList.(*BillConstraintsListDataType).BillConstraintsData - } - - r.BillConstraintsData = UpdateList(r.BillConstraintsData, newData, filterPartial, filterDelete) -} - -// BillDescriptionListDataType - -var _ Updater = (*BillDescriptionListDataType)(nil) - -func (r *BillDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []BillDescriptionDataType - if newList != nil { - newData = newList.(*BillDescriptionListDataType).BillDescriptionData - } - - r.BillDescriptionData = UpdateList(r.BillDescriptionData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/bill_additions_test.go b/spine/model/bill_additions_test.go deleted file mode 100644 index 50fa8db7..00000000 --- a/spine/model/bill_additions_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestBillListDataType_Update(t *testing.T) { - sut := model.BillListDataType{ - BillData: []model.BillDataType{ - { - BillId: util.Ptr(model.BillIdType(0)), - ScopeType: util.Ptr(model.ScopeTypeTypeACCurrent), - }, - { - BillId: util.Ptr(model.BillIdType(1)), - ScopeType: util.Ptr(model.ScopeTypeTypeACCurrent), - }, - }, - } - - newData := model.BillListDataType{ - BillData: []model.BillDataType{ - { - BillId: util.Ptr(model.BillIdType(1)), - ScopeType: util.Ptr(model.ScopeTypeTypeACPower), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.BillData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.BillId)) - assert.Equal(t, model.ScopeTypeTypeACCurrent, *item1.ScopeType) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.BillId)) - assert.Equal(t, model.ScopeTypeTypeACPower, *item2.ScopeType) -} - -func TestBillConstraintsListDataType_Update(t *testing.T) { - sut := model.BillConstraintsListDataType{ - BillConstraintsData: []model.BillConstraintsDataType{ - { - BillId: util.Ptr(model.BillIdType(0)), - PositionCountMin: util.Ptr(model.BillPositionCountType(0)), - }, - { - BillId: util.Ptr(model.BillIdType(1)), - PositionCountMin: util.Ptr(model.BillPositionCountType(0)), - }, - }, - } - - newData := model.BillConstraintsListDataType{ - BillConstraintsData: []model.BillConstraintsDataType{ - { - BillId: util.Ptr(model.BillIdType(1)), - PositionCountMin: util.Ptr(model.BillPositionCountType(1)), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.BillConstraintsData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.BillId)) - assert.Equal(t, 0, int(*item1.PositionCountMin)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.BillId)) - assert.Equal(t, 1, int(*item2.PositionCountMin)) -} - -func TestBillDescriptionListDataType_Update(t *testing.T) { - sut := model.BillDescriptionListDataType{ - BillDescriptionData: []model.BillDescriptionDataType{ - { - BillId: util.Ptr(model.BillIdType(0)), - UpdateRequired: util.Ptr(false), - }, - { - BillId: util.Ptr(model.BillIdType(1)), - UpdateRequired: util.Ptr(false), - }, - }, - } - - newData := model.BillDescriptionListDataType{ - BillDescriptionData: []model.BillDescriptionDataType{ - { - BillId: util.Ptr(model.BillIdType(1)), - UpdateRequired: util.Ptr(true), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.BillDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.BillId)) - assert.Equal(t, false, *item1.UpdateRequired) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.BillId)) - assert.Equal(t, true, *item2.UpdateRequired) -} diff --git a/spine/model/bindingmanagement.go b/spine/model/bindingmanagement.go deleted file mode 100644 index 719d6716..00000000 --- a/spine/model/bindingmanagement.go +++ /dev/null @@ -1,53 +0,0 @@ -package model - -type BindingIdType uint - -type BindingManagementEntryDataType struct { - BindingId *BindingIdType `json:"bindingId,omitempty" eebus:"key"` - ClientAddress *FeatureAddressType `json:"clientAddress,omitempty"` - ServerAddress *FeatureAddressType `json:"serverAddress,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type BindingManagementEntryDataElementsType struct { - BindingId *ElementTagType `json:"bindingId,omitempty"` - ClientAddress *ElementTagType `json:"clientAddress,omitempty"` - ServerAddress *ElementTagType `json:"serverAddress,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type BindingManagementEntryListDataType struct { - BindingManagementEntryData []BindingManagementEntryDataType `json:"bindingManagementEntryData,omitempty"` -} - -type BindingManagementEntryListDataSelectorsType struct { - BindingId *BindingIdType `json:"bindingId,omitempty"` - ClientAddress *FeatureAddressType `json:"clientAddress,omitempty"` - ServerAddress *FeatureAddressType `json:"serverAddress,omitempty"` -} - -type BindingManagementRequestCallType struct { - ClientAddress *FeatureAddressType `json:"clientAddress,omitempty"` - ServerAddress *FeatureAddressType `json:"serverAddress,omitempty"` - ServerFeatureType *FeatureTypeType `json:"serverFeatureType,omitempty"` -} - -type BindingManagementRequestCallElementsType struct { - ClientAddress *ElementTagType `json:"clientAddress,omitempty"` - ServerAddress *ElementTagType `json:"serverAddress,omitempty"` - ServerFeatureType *ElementTagType `json:"serverFeatureType,omitempty"` -} - -type BindingManagementDeleteCallType struct { - BindingId *BindingIdType `json:"bindingId,omitempty"` - ClientAddress *FeatureAddressType `json:"clientAddress,omitempty"` - ServerAddress *FeatureAddressType `json:"serverAddress,omitempty"` -} - -type BindingManagementDeleteCallElementsType struct { - BindingId *ElementTagType `json:"bindingId,omitempty"` - ClientAddress *ElementTagType `json:"clientAddress,omitempty"` - ServerAddress *ElementTagType `json:"serverAddress,omitempty"` -} diff --git a/spine/model/bindingmanagement_additions.go b/spine/model/bindingmanagement_additions.go deleted file mode 100644 index c7d31e97..00000000 --- a/spine/model/bindingmanagement_additions.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -// BindingManagementEntryListDataType - -var _ Updater = (*BindingManagementEntryListDataType)(nil) - -func (r *BindingManagementEntryListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []BindingManagementEntryDataType - if newList != nil { - newData = newList.(*BindingManagementEntryListDataType).BindingManagementEntryData - } - - r.BindingManagementEntryData = UpdateList(r.BindingManagementEntryData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/bindingmanagement_additions_test.go b/spine/model/bindingmanagement_additions_test.go deleted file mode 100644 index f1a14f2f..00000000 --- a/spine/model/bindingmanagement_additions_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestBindingManagementEntryListDataType_Update(t *testing.T) { - sut := model.BindingManagementEntryListDataType{ - BindingManagementEntryData: []model.BindingManagementEntryDataType{ - { - BindingId: util.Ptr(model.BindingIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - BindingId: util.Ptr(model.BindingIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.BindingManagementEntryListDataType{ - BindingManagementEntryData: []model.BindingManagementEntryDataType{ - { - BindingId: util.Ptr(model.BindingIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.BindingManagementEntryData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.BindingId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.BindingId)) - assert.Equal(t, "new", string(*item2.Description)) -} diff --git a/spine/model/collection_operations.go b/spine/model/collection_operations.go deleted file mode 100644 index 84d6ccc6..00000000 --- a/spine/model/collection_operations.go +++ /dev/null @@ -1,122 +0,0 @@ -package model - -import ( - "fmt" - "reflect" -) - -// creates an hash key by using fields that have eebus tag "key" -func hashKey(data any) string { - result := "" - - keys := keyFieldNames(data) - - if len(keys) == 0 { - return result - } - - v := reflect.ValueOf(data) - - for _, fieldName := range keys { - f := v.FieldByName(fieldName) - - if f.IsNil() || !f.IsValid() { - return result - } - - switch f.Elem().Kind() { - case reflect.String: - value := f.Elem().String() - - if len(result) > 0 { - result = fmt.Sprintf("%s|", result) - } - result = fmt.Sprintf("%s%s", result, value) - - case reflect.Uint: - value := f.Elem().Uint() - - if len(result) > 0 { - result = fmt.Sprintf("%s|", result) - } - result = fmt.Sprintf("%s%d", result, value) - - default: - return result - } - } - - return result -} - -// Merges two slices into one. The item in the first slice will be replaced by the one in the second slice -// if the hash key is the same. Items in the second slice which are not in the first will be added. -func Merge[T any](s1 []T, s2 []T) []T { - result := []T{} - - m2 := ToMap(s2) - - // go through the first slice - m1 := make(map[string]T, len(s1)) - for _, s1Item := range s1 { - s1ItemHash := hashKey(s1Item) - // s1ItemHash := s1Item.HashKey() - s2Item, exist := m2[s1ItemHash] - if exist { - // the item in the first slice will be replaces by the one of the second slice - result = append(result, s2Item) - } else { - result = append(result, s1Item) - } - - m1[s1ItemHash] = s1Item - } - - // append items which were not in the first slice - for _, s2Item := range s2 { - s2ItemHash := hashKey(s2Item) - // s2ItemHash := s2Item.HashKey() - _, exist := m1[s2ItemHash] - if !exist { - result = append(result, s2Item) - } - } - - return result -} - -func ToMap[T any](s []T) map[string]T { - result := make(map[string]T, len(s)) - for _, item := range s { - result[hashKey(item)] = item - } - return result -} - -/* -func FindFirst[T any](s []T, predicate func(i T) bool) *T { - for _, item := range s { - if predicate(item) { - return &item - } - } - return nil -} - -func Values[K comparable, V any](m map[K]V) []V { - ret := make([]V, 0, len(m)) - for _, v := range m { - ret = append(ret, v) - } - return ret -} - -// casts all elements in slice s to type D -func CastElements[S any, D any](s []S) []D { - result := make([]D, len(s)) - for i, item := range s { - result[i] = any(item).(D) - } - return result -} -*/ diff --git a/spine/model/collection_operations_test.go b/spine/model/collection_operations_test.go deleted file mode 100644 index 660ffd26..00000000 --- a/spine/model/collection_operations_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package model_test - -import ( - "fmt" - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -type testStruct struct { - id *uint `eebus:"key"` - data *string -} - -func (r testStruct) HashKey() string { - return fmt.Sprintf("%d", r.id) -} - -func TestUnion_NewData(t *testing.T) { - existingData := []testStruct{ - {id: util.Ptr(uint(1)), data: util.Ptr(string("data1"))}, - } - - newData := []testStruct{ - {id: util.Ptr(uint(2)), data: util.Ptr(string("data2"))}, - } - - // Act - result := model.Merge(existingData, newData) - - if assert.Equal(t, 2, len(result)) { - assert.Equal(t, 1, int(*result[0].id)) - assert.Equal(t, "data1", string(*result[0].data)) - assert.Equal(t, 2, int(*result[1].id)) - assert.Equal(t, "data2", string(*result[1].data)) - } -} - -func TestUnion_NewAndUpdateData(t *testing.T) { - existingData := []testStruct{ - {id: util.Ptr(uint(1)), data: util.Ptr(string("data1"))}, - {id: util.Ptr(uint(2)), data: util.Ptr(string("data2"))}, - } - - newData := []testStruct{ - {id: util.Ptr(uint(2)), data: util.Ptr(string("data22"))}, - {id: util.Ptr(uint(3)), data: util.Ptr(string("data33"))}, - } - - // Act - result := model.Merge(existingData, newData) - - if assert.Equal(t, 3, len(result)) { - assert.Equal(t, 1, int(*result[0].id)) - assert.Equal(t, "data1", string(*result[0].data)) - assert.Equal(t, 2, int(*result[1].id)) - assert.Equal(t, "data22", string(*result[1].data)) - assert.Equal(t, 3, int(*result[2].id)) - assert.Equal(t, "data33", string(*result[2].data)) - } -} diff --git a/spine/model/commandframe.go b/spine/model/commandframe.go deleted file mode 100644 index fb9c63a2..00000000 --- a/spine/model/commandframe.go +++ /dev/null @@ -1,410 +0,0 @@ -package model - -type MsgCounterType uint64 - -type CmdClassifierType string - -const ( - CmdClassifierTypeRead CmdClassifierType = "read" - CmdClassifierTypeReply CmdClassifierType = "reply" - CmdClassifierTypeNotify CmdClassifierType = "notify" - CmdClassifierTypeWrite CmdClassifierType = "write" - CmdClassifierTypeCall CmdClassifierType = "call" - CmdClassifierTypeResult CmdClassifierType = "result" -) - -type FilterIdType uint - -type FilterType struct { - FilterId *FilterIdType `json:"filterId,omitempty"` - CmdControl *CmdControlType `json:"cmdControl,omitempty"` - - // DataSelectorsChoiceGroup - AlarmListDataSelectors *AlarmListDataSelectorsType `json:"alarmListDataSelectors,omitempty" eebus:"typ:selector,fct:alarmListData"` - BillConstraintsListDataSelectors *BillConstraintsListDataSelectorsType `json:"billConstraintsListDataSelectors,omitempty" eebus:"typ:selector,fct:billConstraintsListData"` - BillDescriptionListDataSelectors *BillDescriptionListDataSelectorsType `json:"billDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:billDescriptionListData"` - BillListDataSelectors *BillListDataSelectorsType `json:"billListDataSelectors,omitempty" eebus:"typ:selector,fct:billListData"` - BindingManagementEntryListDataSelectors *BindingManagementEntryListDataSelectorsType `json:"bindingManagementEntryListDataSelectors,omitempty" eebus:"typ:selector,fct:bindingManagementEntryListData"` - CommodityListDataSelectors *CommodityListDataSelectorsType `json:"commodityListDataSelectors,omitempty" eebus:"typ:selector,fct:commodityListData"` - DeviceConfigurationKeyValueConstraintsListDataSelectors *DeviceConfigurationKeyValueConstraintsListDataSelectorsType `json:"deviceConfigurationKeyValueConstraintsListDataSelectors,omitempty" eebus:"typ:selector,fct:deviceConfigurationKeyValueConstraintsListData"` - DeviceConfigurationKeyValueDescriptionListDataSelectors *DeviceConfigurationKeyValueDescriptionListDataSelectorsType `json:"deviceConfigurationKeyValueDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:deviceConfigurationKeyValueDescriptionListData"` - DeviceConfigurationKeyValueListDataSelectors *DeviceConfigurationKeyValueListDataSelectorsType `json:"deviceConfigurationKeyValueListDataSelectors,omitempty" eebus:"typ:selector,fct:deviceConfigurationKeyValueListData"` - DirectControlActivityListDataSelectors *DirectControlActivityListDataSelectorsType `json:"directControlActivityListDataSelectors,omitempty" eebus:"typ:selector,fct:directControlActivityListData"` - ElectricalConnectionDescriptionListDataSelectors *ElectricalConnectionDescriptionListDataSelectorsType `json:"electricalConnectionDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:electricalConnectionDescriptionListData"` - ElectricalConnectionParameterDescriptionListDataSelectors *ElectricalConnectionParameterDescriptionListDataSelectorsType `json:"electricalConnectionParameterDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:electricalConnectionParameterDescriptionListData"` - ElectricalConnectionPermittedValueSetListDataSelectors *ElectricalConnectionPermittedValueSetListDataSelectorsType `json:"electricalConnectionPermittedValueSetListDataSelectors,omitempty" eebus:"typ:selector,fct:electricalConnectionPermittedValueSetListData"` - ElectricalConnectionStateListDataSelectors *ElectricalConnectionStateListDataSelectorsType `json:"electricalConnectionStateListDataSelectors,omitempty" eebus:"typ:selector,fct:electricalConnectionStateListData"` - HvacOperationModeDescriptionListDataSelectors *HvacOperationModeDescriptionListDataSelectorsType `json:"hvacOperationModeDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:hvacOperationModeDescriptionListData"` - HvacOverrunDescriptionListDataSelectors *HvacOverrunDescriptionListDataSelectorsType `json:"hvacOverrunDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:hvacOverrunDescriptionListData"` - HvacOverrunListDataSelectors *HvacOverrunListDataSelectorsType `json:"hvacOverrunListDataSelectors,omitempty" eebus:"typ:selector,fct:hvacOverrunListData"` - HvacSystemFunctionDescriptionListDataSelectors *HvacSystemFunctionDescriptionListDataSelectorsType `json:"hvacSystemFunctionDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:hvacSystemFunctionDescriptionListData"` - HvacSystemFunctionListDataSelectors *HvacSystemFunctionListDataSelectorsType `json:"hvacSystemFunctionListDataSelectors,omitempty" eebus:"typ:selector,fct:hvacSystemFunctionListData"` - HvacSystemFunctionOperationModeRelationListDataSelectors *HvacSystemFunctionOperationModeRelationListDataSelectorsType `json:"hvacSystemFunctionOperationModeRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:hvacSystemFunctionOperationModeRelationListData"` - HvacSystemFunctionPowerSequenceRelationListDataSelectors *HvacSystemFunctionPowerSequenceRelationListDataSelectorsType `json:"hvacSystemFunctionPowerSequenceRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:hvacSystemFunctionPowerSequenceRelationListData"` - HvacSystemFunctionSetpointRelationListDataSelectors *HvacSystemFunctionSetpointRelationListDataSelectorsType `json:"hvacSystemFunctionSetpointRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:hvacSystemFunctionSetpointRelationListData"` - IdentificationListDataSelectors *IdentificationListDataSelectorsType `json:"identificationListDataSelectors,omitempty" eebus:"typ:selector,fct:identificationListData"` - IncentiveDescriptionListDataSelectors *IncentiveDescriptionListDataSelectorsType `json:"incentiveDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:incentiveDescriptionListData"` - IncentiveListDataSelectors *IncentiveListDataSelectorsType `json:"incentiveListDataSelectors,omitempty" eebus:"typ:selector,fct:incentiveListData"` - IncentiveTableConstraintsDataSelectors *IncentiveTableConstraintsDataSelectorsType `json:"incentiveTableConstraintsDataSelectors,omitempty" eebus:"typ:selector,fct:incentiveTableConstraintsData"` - IncentiveTableDataSelectors *IncentiveTableDataSelectorsType `json:"incentiveTableDataSelectors,omitempty" eebus:"typ:selector,fct:incentiveTableData"` - IncentiveTableDescriptionDataSelectors *IncentiveTableDescriptionDataSelectorsType `json:"incentiveTableDescriptionDataSelectors,omitempty" eebus:"typ:selector,fct:incentiveTableDescriptionData"` - LoadControlEventListDataSelectors *LoadControlEventListDataSelectorsType `json:"loadControlEventListDataSelectors,omitempty" eebus:"typ:selector,fct:loadControlEventListData"` - LoadControlLimitConstraintsListDataSelectors *LoadControlLimitConstraintsListDataSelectorsType `json:"loadControlLimitConstraintsListDataSelectors,omitempty" eebus:"typ:selector,fct:loadControlLimitConstraintsListData"` - LoadControlLimitDescriptionListDataSelectors *LoadControlLimitDescriptionListDataSelectorsType `json:"loadControlLimitDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:loadControlLimitDescriptionListData"` - LoadControlLimitListDataSelectors *LoadControlLimitListDataSelectorsType `json:"loadControlLimitListDataSelectors,omitempty" eebus:"typ:selector,fct:loadControlLimitListData"` - LoadControlStateListDataSelectors *LoadControlStateListDataSelectorsType `json:"loadControlStateListDataSelectors,omitempty" eebus:"typ:selector,fct:loadControlStateListData"` - MeasurementConstraintsListDataSelectors *MeasurementConstraintsListDataSelectorsType `json:"measurementConstraintsListDataSelectors,omitempty" eebus:"typ:selector,fct:measurementConstraintsListData"` - MeasurementDescriptionListDataSelectors *MeasurementDescriptionListDataSelectorsType `json:"measurementDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:measurementDescriptionListData"` - MeasurementListDataSelectors *MeasurementListDataSelectorsType `json:"measurementListDataSelectors,omitempty" eebus:"typ:selector,fct:measurementListData"` - MeasurementThresholdRelationListDataSelectors *MeasurementThresholdRelationListDataSelectorsType `json:"measurementThresholdRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:measurementThresholdRelationListData"` - MessagingListDataSelectors *MessagingListDataSelectorsType `json:"messagingListDataSelectors,omitempty" eebus:"typ:selector,fct:messagingListData"` - NetworkManagementDeviceDescriptionListDataSelectors *NetworkManagementDeviceDescriptionListDataSelectorsType `json:"networkManagementDeviceDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:networkManagementDeviceDescriptionListData"` - NetworkManagementEntityDescriptionListDataSelectors *NetworkManagementEntityDescriptionListDataSelectorsType `json:"networkManagementEntityDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:networkManagementEntityDescriptionListData"` - NetworkManagementFeatureDescriptionListDataSelectors *NetworkManagementFeatureDescriptionListDataSelectorsType `json:"networkManagementFeatureDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:networkManagementFeatureDescriptionList"` - NodeManagementBindingDataSelectors *NodeManagementBindingDataSelectorsType `json:"nodeManagementBindingDataSelectors,omitempty" eebus:"typ:selector,fct:nodeManagementBindingData"` - NodeManagementDestinationListDataSelectors *NodeManagementDestinationListDataSelectorsType `json:"nodeManagementDestinationListDataSelectors,omitempty" eebus:"typ:selector,fct:nodeManagementDestinationListData"` - NodeManagementDetailedDiscoveryDataSelectors *NodeManagementDetailedDiscoveryDataSelectorsType `json:"nodeManagementDetailedDiscoveryDataSelectors,omitempty" eebus:"typ:selector,fct:nodeManagementDetailedDiscoveryData"` - NodeManagementSubscriptionDataSelectors *NodeManagementSubscriptionDataSelectorsType `json:"nodeManagementSubscriptionDataSelectors,omitempty" eebus:"typ:selector,fct:nodeManagementSubscriptionData"` - NodeManagementUseCaseDataSelectors *NodeManagementUseCaseDataSelectorsType `json:"nodeManagementUseCaseDataSelectors,omitempty" eebus:"typ:selector,fct:nodeManagementUseCaseData"` - OperatingConstraintsDurationListDataSelectors *OperatingConstraintsDurationListDataSelectorsType `json:"operatingConstraintsDurationListDataSelectors,omitempty" eebus:"typ:selector,fct:operatingConstraintsDurationListData"` - OperatingConstraintsInterruptListDataSelectors *OperatingConstraintsInterruptListDataSelectorsType `json:"operatingConstraintsInterruptListDataSelectors,omitempty" eebus:"typ:selector,fct:operatingConstraintsInterruptListData"` - OperatingConstraintsPowerDescriptionListDataSelectors *OperatingConstraintsPowerDescriptionListDataSelectorsType `json:"operatingConstraintsPowerDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:operatingConstraintsPowerDescriptionListData"` - OperatingConstraintsPowerLevelListDataSelectors *OperatingConstraintsPowerLevelListDataSelectorsType `json:"operatingConstraintsPowerLevelListDataSelectors,omitempty" eebus:"typ:selector,fct:operatingConstraintsPowerLevelListData"` - OperatingConstraintsPowerRangeListDataSelectors *OperatingConstraintsPowerRangeListDataSelectorsType `json:"operatingConstraintsPowerRangeListDataSelectors,omitempty" eebus:"typ:selector,fct:operatingConstraintsPowerRangeListData"` - OperatingConstraintsResumeImplicationListDataSelectors *OperatingConstraintsResumeImplicationListDataSelectorsType `json:"operatingConstraintsResumeImplicationListDataSelectors,omitempty" eebus:"typ:selector,fct:operatingConstraintsResumeImplicationListData"` - PowerSequenceAlternativesRelationListDataSelectors *PowerSequenceAlternativesRelationListDataSelectorsType `json:"powerSequenceAlternativesRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:powerSequenceAlternativesRelationListData"` - PowerSequenceDescriptionListDataSelectors *PowerSequenceDescriptionListDataSelectorsType `json:"powerSequenceDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:powerSequenceDescriptionListData"` - PowerSequencePriceListDataSelectors *PowerSequencePriceListDataSelectorsType `json:"powerSequencePriceListDataSelectors,omitempty" eebus:"typ:selector,fct:powerSequencePriceListData"` - PowerSequenceScheduleConstraintsListDataSelectors *PowerSequenceScheduleConstraintsListDataSelectorsType `json:"powerSequenceScheduleConstraintsListDataSelectors,omitempty" eebus:"typ:selector,fct:powerSequenceScheduleConstraintsListData"` - PowerSequenceScheduleListDataSelectors *PowerSequenceScheduleListDataSelectorsType `json:"powerSequenceScheduleListDataSelectors,omitempty" eebus:"typ:selector,fct:powerSequenceScheduleListData"` - PowerSequenceSchedulePreferenceListDataSelectors *PowerSequenceSchedulePreferenceListDataSelectorsType `json:"powerSequenceSchedulePreferenceListDataSelectors,omitempty" eebus:"typ:selector,fct:powerSequenceSchedulePreferenceListData"` - PowerSequenceStateListDataSelectors *PowerSequenceStateListDataSelectorsType `json:"powerSequenceStateListDataSelectors,omitempty" eebus:"typ:selector,fct:powerSequenceStateListData"` - PowerTimeSlotScheduleConstraintsListDataSelectors *PowerTimeSlotScheduleConstraintsListDataSelectorsType `json:"powerTimeSlotScheduleConstraintsListDataSelectors,omitempty" eebus:"typ:selector,fct:powerTimeSlotScheduleConstraintsListData"` - PowerTimeSlotScheduleListDataSelectors *PowerTimeSlotScheduleListDataSelectorsType `json:"powerTimeSlotScheduleListDataSelectors,omitempty" eebus:"typ:selector,fct:powerTimeSlotScheduleListData"` - PowerTimeSlotValueListDataSelectors *PowerTimeSlotValueListDataSelectorsType `json:"powerTimeSlotValueListDataSelectors,omitempty" eebus:"typ:selector,fct:powerTimeSlotValueListData"` - SensingListDataSelectors *SensingListDataSelectorsType `json:"sensingListDataSelectors,omitempty" eebus:"typ:selector,fct:sensingListData"` - SetpointConstraintsListDataSelectors *SetpointConstraintsListDataSelectorsType `json:"setpointConstraintsListDataSelectors,omitempty" eebus:"typ:selector,fct:setpointConstraintsListData"` - SetpointDescriptionListDataSelectors *SetpointDescriptionListDataSelectorsType `json:"setpointDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:setpointDescriptionListData"` - SetpointListDataSelectors *SetpointListDataSelectorsType `json:"setpointListDataSelectors,omitempty" eebus:"typ:selector,fct:setpointListData"` - SmartEnergyManagementPsDataSelectors *SmartEnergyManagementPsDataSelectorsType `json:"smartEnergyManagementPsDataSelectors,omitempty" eebus:"typ:selector,fct:smartEnergyManagementPsData"` - SmartEnergyManagementPsPriceDataSelectors *SmartEnergyManagementPsPriceDataSelectorsType `json:"smartEnergyManagementPsPriceDataSelectors,omitempty" eebus:"typ:selector,fct:smartEnergyManagementPsPriceData"` - SpecificationVersionListDataSelectors *SpecificationVersionListDataSelectorsType `json:"specificationVersionListDataSelectors,omitempty" eebus:"typ:selector,fct:specificationVersionListData"` - SubscriptionManagementEntryListDataSelectors *SubscriptionManagementEntryListDataSelectorsType `json:"subscriptionManagementEntryListDataSelectors,omitempty" eebus:"typ:selector,fct:subscriptionManagementEntryListData"` - SupplyConditionDescriptionListDataSelectors *SupplyConditionDescriptionListDataSelectorsType `json:"supplyConditionDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:supplyConditionDescriptionListData"` - SupplyConditionListDataSelectors *SupplyConditionListDataSelectorsType `json:"supplyConditionListDataSelectors,omitempty" eebus:"typ:selector,fct:supplyConditionListData"` - SupplyConditionThresholdRelationListDataSelectors *SupplyConditionThresholdRelationListDataSelectorsType `json:"supplyConditionThresholdRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:supplyConditionThresholdRelationListData"` - TariffBoundaryRelationListDataSelectors *TariffBoundaryRelationListDataSelectorsType `json:"tariffBoundaryRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:tariffBoundaryRelationListData"` - TariffDescriptionListDataSelectors *TariffDescriptionListDataSelectorsType `json:"tariffDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:tariffDescriptionListData"` - TariffListDataSelectors *TariffListDataSelectorsType `json:"tariffListDataSelectors,omitempty" eebus:"typ:selector,fct:tariffListData"` - TariffTierRelationListDataSelectors *TariffTierRelationListDataSelectorsType `json:"tariffTierRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:tariffTierRelationListData"` - TaskManagementJobDescriptionListDataSelectors *TaskManagementJobDescriptionListDataSelectorsType `json:"taskManagementJobDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:taskManagementJobDescriptionListData"` - TaskManagementJobListDataSelectors *TaskManagementJobListDataSelectorsType `json:"taskManagementJobListDataSelectors,omitempty" eebus:"typ:selector,fct:taskManagementJobListData"` - TaskManagementJobRelationListDataSelectors *TaskManagementJobRelationListDataSelectorsType `json:"taskManagementJobRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:taskManagementJobRelationListData"` - ThresholdConstraintsListDataSelectors *ThresholdConstraintsListDataSelectorsType `json:"thresholdConstraintsListDataSelectors,omitempty" eebus:"typ:selector,fct:thresholdConstraintsListData"` - ThresholdDescriptionListDataSelectors *ThresholdDescriptionListDataSelectorsType `json:"thresholdDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:thresholdDescriptionListData"` - ThresholdListDataSelectors *ThresholdListDataSelectorsType `json:"thresholdListDataSelectors,omitempty" eebus:"typ:selector,fct:thresholdListData"` - TierBoundaryDescriptionListDataSelectors *TierBoundaryDescriptionListDataSelectorsType `json:"tierBoundaryDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:tierBoundaryDescriptionListData"` - TierBoundaryListDataSelectors *TierBoundaryListDataSelectorsType `json:"tierBoundaryListDataSelectors,omitempty" eebus:"typ:selector,fct:tierBoundaryListData"` - TierDescriptionListDataSelectors *TierDescriptionListDataSelectorsType `json:"tierDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:tierDescriptionListData"` - TierIncentiveRelationListDataSelectors *TierIncentiveRelationListDataSelectorsType `json:"tierIncentiveRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:tierIncentiveRelationListData"` - TierListDataSelectors *TierListDataSelectorsType `json:"tierListDataSelectors,omitempty" eebus:"typ:selector,fct:tierListData"` - TimeSeriesConstraintsListDataSelectors *TimeSeriesConstraintsListDataSelectorsType `json:"timeSeriesConstraintsListDataSelectors,omitempty" eebus:"typ:selector,fct:timeSeriesConstraintsListData"` - TimeSeriesDescriptionListDataSelectors *TimeSeriesDescriptionListDataSelectorsType `json:"timeSeriesDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:timeSeriesDescriptionListData"` - TimeSeriesListDataSelectors *TimeSeriesListDataSelectorsType `json:"timeSeriesListDataSelectors,omitempty" eebus:"typ:selector,fct:timeSeriesListData"` - TimeTableConstraintsListDataSelectors *TimeTableConstraintsListDataSelectorsType `json:"timeTableConstraintsListDataSelectors,omitempty" eebus:"typ:selector,fct:timeTableConstraintsListData"` - TimeTableDescriptionListDataSelectors *TimeTableDescriptionListDataSelectorsType `json:"timeTableDescriptionListDataSelectors,omitempty" eebus:"typ:selector,fct:timeTableDescriptionListData"` - TimeTableListDataSelectors *TimeTableListDataSelectorsType `json:"timeTableListDataSelectors,omitempty" eebus:"typ:selector,fct:timeTableListData"` - UseCaseInformationListDataSelectors *UseCaseInformationListDataSelectorsType `json:"useCaseInformationListDataSelectors,omitempty" eebus:"typ:selector,fct:useCaseInformationListData"` - - // DataElementsChoiceGroup - ActuatorLevelDataElements *ActuatorLevelDataElementsType `json:"actuatorLevelDataElements,omitempty" eebus:"typ:elements,fct:actuatorLevelData"` - ActuatorLevelDescriptionDataElements *ActuatorLevelDescriptionDataElementsType `json:"actuatorLevelDescriptionDataElements,omitempty" eebus:"typ:elements,fct:actuatorLevelDescriptionData"` - ActuatorSwitchDataElements *ActuatorSwitchDataElementsType `json:"actuatorSwitchDataElements,omitempty" eebus:"typ:elements,fct:actuatorSwitchData"` - ActuatorSwitchDescriptionDataElements *ActuatorSwitchDescriptionDataElementsType `json:"actuatorSwitchDescriptionDataElements,omitempty" eebus:"typ:elements,fct:actuatorSwitchDescriptionData"` - AlarmDataElements *AlarmDataElementsType `json:"alarmDataElements,omitempty" eebus:"typ:elements,fct:alarmListData"` - BillConstraintsDataElements *BillConstraintsDataElementsType `json:"billConstraintsDataElements,omitempty" eebus:"typ:elements,fct:billConstraintsListData"` - BillDataElements *BillDataElementsType `json:"billDataElements,omitempty" eebus:"typ:elements,fct:billListData"` - BillDescriptionDataElements *BillDescriptionDataElementsType `json:"billDescriptionDataElements,omitempty" eebus:"typ:elements,fct:billDescriptionListData"` - BindingManagementDeleteCallElements *BindingManagementDeleteCallElementsType `json:"bindingManagementDeleteCallElements,omitempty" eebus:"typ:elements,fct:bindingManagementDeleteCall"` - BindingManagementEntryDataElements *BindingManagementEntryDataElementsType `json:"bindingManagementEntryDataElements,omitempty" eebus:"typ:elements,fct:bindingManagementEntryListData"` - BindingManagementRequestCallElements *BindingManagementRequestCallElementsType `json:"bindingManagementRequestCallElements,omitempty" eebus:"typ:elements,fct:bindingManagementRequestCall"` - CommodityDataElements *CommodityDataElementsType `json:"commodityDataElements,omitempty" eebus:"typ:elements,fct:commodityListData"` - DataTunnelingCallElements *DataTunnelingCallElementsType `json:"dataTunnelingCallElements,omitempty" eebus:"typ:elements,fct:dataTunnelingCall"` - DeviceClassificationManufacturerDataElements *DeviceClassificationManufacturerDataElementsType `json:"deviceClassificationManufacturerDataElements,omitempty" eebus:"typ:elements,fct:deviceClassificationManufacturerData"` - DeviceClassificationUserDataElements *DeviceClassificationUserDataElementsType `json:"deviceClassificationUserDataElements,omitempty" eebus:"typ:elements,fct:deviceClassificationUserData"` - DeviceConfigurationKeyValueConstraintsDataElements *DeviceConfigurationKeyValueConstraintsDataElementsType `json:"deviceConfigurationKeyValueConstraintsDataElements,omitempty" eebus:"typ:elements,fct:deviceConfigurationKeyValueConstraintsListData"` - DeviceConfigurationKeyValueDataElements *DeviceConfigurationKeyValueDataElementsType `json:"deviceConfigurationKeyValueDataElements,omitempty" eebus:"typ:elements,fct:deviceConfigurationKeyValueListData"` - DeviceConfigurationKeyValueDescriptionDataElements *DeviceConfigurationKeyValueDescriptionDataElementsType `json:"deviceConfigurationKeyValueDescriptionDataElements,omitempty" eebus:"typ:elements,fct:deviceConfigurationKeyValueDescriptionListData"` - DeviceDiagnosisHeartbeatDataElements *DeviceDiagnosisHeartbeatDataElementsType `json:"deviceDiagnosisHeartbeatDataElements,omitempty" eebus:"typ:elements,fct:deviceDiagnosisHeartbeatData"` - DeviceDiagnosisServiceDataElements *DeviceDiagnosisServiceDataElementsType `json:"deviceDiagnosisServiceDataElements,omitempty" eebus:"typ:elements,fct:deviceDiagnosisServiceData"` - DeviceDiagnosisStateDataElements *DeviceDiagnosisStateDataElementsType `json:"deviceDiagnosisStateDataElements,omitempty" eebus:"typ:elements,fct:deviceDiagnosisStateData"` - DirectControlActivityDataElements *DirectControlActivityDataElementsType `json:"directControlActivityDataElements,omitempty" eebus:"typ:elements,fct:directControlActivityListData"` - DirectControlDescriptionDataElements *DirectControlDescriptionDataElementsType `json:"directControlDescriptionDataElements,omitempty" eebus:"typ:elements,fct:directControlDescriptionData"` - ElectricalConnectionDescriptionDataElements *ElectricalConnectionDescriptionDataElementsType `json:"electricalConnectionDescriptionDataElements,omitempty" eebus:"typ:elements,fct:electricalConnectionDescriptionListData"` - ElectricalConnectionParameterDescriptionDataElements *ElectricalConnectionParameterDescriptionDataElementsType `json:"electricalConnectionParameterDescriptionDataElements,omitempty" eebus:"typ:elements,fct:electricalConnectionParameterDescriptionListData"` - ElectricalConnectionPermittedValueSetDataElements *ElectricalConnectionPermittedValueSetDataElementsType `json:"electricalConnectionPermittedValueSetDataElements,omitempty" eebus:"typ:elements,fct:electricalConnectionPermittedValueSetListData"` - ElectricalConnectionStateDataElements *ElectricalConnectionStateDataElementsType `json:"electricalConnectionStateDataElements,omitempty" eebus:"typ:elements,fct:electricalConnectionStateListData"` - HvacOperationModeDescriptionDataElements *HvacOperationModeDescriptionDataElementsType `json:"hvacOperationModeDescriptionDataElements,omitempty" eebus:"typ:elements,fct:hvacOperationModeDescriptionListData"` - HvacOverrunDataElements *HvacOverrunDataElementsType `json:"hvacOverrunDataElements,omitempty" eebus:"typ:elements,fct:hvacOverrunListData"` - HvacOverrunDescriptionDataElements *HvacOverrunDescriptionDataElementsType `json:"hvacOverrunDescriptionDataElements,omitempty" eebus:"typ:elements,fct:hvacOverrunDescriptionListData"` - HvacSystemFunctionDataElements *HvacSystemFunctionDataElementsType `json:"hvacSystemFunctionDataElements,omitempty" eebus:"typ:elements,fct:hvacSystemFunctionListData"` - HvacSystemFunctionDescriptionDataElements *HvacSystemFunctionDescriptionDataElementsType `json:"hvacSystemFunctionDescriptionDataElements,omitempty" eebus:"typ:elements,fct:hvacSystemFunctionDescriptionListData"` - HvacSystemFunctionOperationModeRelationDataElements *HvacSystemFunctionOperationModeRelationDataElementsType `json:"hvacSystemFunctionOperationModeRelationDataElements,omitempty" eebus:"typ:elements,fct:hvacSystemFunctionOperationModeRelationListData"` - HvacSystemFunctionPowerSequenceRelationDataElements *HvacSystemFunctionPowerSequenceRelationDataElementsType `json:"hvacSystemFunctionPowerSequenceRelationDataElements,omitempty" eebus:"typ:elements,fct:hvacSystemFunctionPowerSequenceRelationListData"` - HvacSystemFunctionSetpointRelationDataElements *HvacSystemFunctionSetpointRelationDataElementsType `json:"hvacSystemFunctionSetpointRelationDataElements,omitempty" eebus:"typ:elements,fct:hvacSystemFunctionSetpointRelationListData"` - IdentificationDataElements *IdentificationDataElementsType `json:"identificationDataElements,omitempty" eebus:"typ:elements,fct:identificationListData"` - IncentiveDataElements *IncentiveDataElementsType `json:"incentiveDataElements,omitempty" eebus:"typ:elements,fct:incentiveListData"` - IncentiveDescriptionDataElements *IncentiveDescriptionDataElementsType `json:"incentiveDescriptionDataElements,omitempty" eebus:"typ:elements,fct:incentiveDescriptionListData"` - IncentiveTableConstraintsDataElements *IncentiveTableConstraintsDataElementsType `json:"incentiveTableConstraintsDataElements,omitempty" eebus:"typ:elements,fct:incentiveTableConstraintsData"` - IncentiveTableDataElements *IncentiveTableDataElementsType `json:"incentiveTableDataElements,omitempty" eebus:"typ:elements,fct:incentiveTableData"` - IncentiveTableDescriptionDataElements *IncentiveTableDescriptionDataElementsType `json:"incentiveTableDescriptionDataElements,omitempty" eebus:"typ:elements,fct:incentiveTableDescriptionData"` - LoadControlEventDataElements *LoadControlEventDataElementsType `json:"loadControlEventDataElements,omitempty" eebus:"typ:elements,fct:loadControlEventListData"` - LoadControlLimitConstraintsDataElements *LoadControlLimitConstraintsDataElementsType `json:"loadControlLimitConstraintsDataElements,omitempty" eebus:"typ:elements,fct:loadControlLimitConstraintsListData"` - LoadControlLimitDataElements *LoadControlLimitDataElementsType `json:"loadControlLimitDataElements,omitempty" eebus:"typ:elements,fct:loadControlLimitListData"` - LoadControlLimitDescriptionDataElements *LoadControlLimitDescriptionDataElementsType `json:"loadControlLimitDescriptionDataElements,omitempty" eebus:"typ:elements,fct:loadControlLimitDescriptionListData"` - LoadControlNodeDataElements *LoadControlNodeDataElementsType `json:"loadControlNodeDataElements,omitempty" eebus:"typ:elements,fct:loadControlNodeData"` - LoadControlStateDataElements *LoadControlStateDataElementsType `json:"loadControlStateDataElements,omitempty" eebus:"typ:elements,fct:loadControlStateListData"` - MeasurementConstraintsDataElements *MeasurementConstraintsDataElementsType `json:"measurementConstraintsDataElements,omitempty" eebus:"typ:elements,fct:measurementConstraintsListData"` - MeasurementDataElements *MeasurementDataElementsType `json:"measurementDataElements,omitempty" eebus:"typ:elements,fct:measurementListData"` - MeasurementDescriptionDataElements *MeasurementDescriptionDataElementsType `json:"measurementDescriptionDataElements,omitempty" eebus:"typ:elements,fct:measurementDescriptionListData"` - MeasurementThresholdRelationDataElements *MeasurementThresholdRelationDataElementsType `json:"measurementThresholdRelationDataElements,omitempty" eebus:"typ:elements,fct:measurementThresholdRelationListData"` - MessagingDataElements *MessagingDataElementsType `json:"messagingDataElements,omitempty" eebus:"typ:elements,fct:messagingListData"` - NetworkManagementAbortCallElements *NetworkManagementAbortCallElementsType `json:"networkManagementAbortCallElements,omitempty" eebus:"typ:elements,fct:networkManagementAbortCall"` - NetworkManagementAddNodeCallElements *NetworkManagementAddNodeCallElementsType `json:"networkManagementAddNodeCallElements,omitempty" eebus:"typ:elements,fct:networkManagementAddNodeCall"` - NetworkManagementDeviceDescriptionDataElements *NetworkManagementDeviceDescriptionDataElementsType `json:"networkManagementDeviceDescriptionDataElements,omitempty" eebus:"typ:elements,fct:networkManagementDeviceDescriptionListData"` - NetworkManagementDiscoverCallElements *NetworkManagementDiscoverCallElementsType `json:"networkManagementDiscoverCallElements,omitempty" eebus:"typ:elements,fct:networkManagementDiscoverCall"` - NetworkManagementEntityDescriptionDataElements *NetworkManagementEntityDescriptionDataElementsType `json:"networkManagementEntityDescriptionDataElements,omitempty" eebus:"typ:elements,fct:networkManagementEntityDescriptionListData"` - NetworkManagementFeatureDescriptionDataElements *NetworkManagementFeatureDescriptionDataElementsType `json:"networkManagementFeatureDescriptionDataElements,omitempty" eebus:"typ:elements,fct:networkManagementFeatureDescriptionListData"` - NetworkManagementJoiningModeDataElements *NetworkManagementJoiningModeDataElementsType `json:"networkManagementJoiningModeDataElements,omitempty" eebus:"typ:elements,fct:networkManagementJoiningModeData"` - NetworkManagementModifyNodeCallElements *NetworkManagementModifyNodeCallElementsType `json:"networkManagementModifyNodeCallElements,omitempty" eebus:"typ:elements,fct:networkManagementModifyNodeCall"` - NetworkManagementProcessStateDataElements *NetworkManagementProcessStateDataElementsType `json:"networkManagementProcessStateDataElements,omitempty" eebus:"typ:elements,fct:networkManagementProcessStateData"` - NetworkManagementRemoveNodeCallElements *NetworkManagementRemoveNodeCallElementsType `json:"networkManagementRemoveNodeCallElements,omitempty" eebus:"typ:elements,fct:networkManagementRemoveNodeCall"` - NetworkManagementReportCandidateDataElements *NetworkManagementReportCandidateDataElementsType `json:"networkManagementReportCandidateDataElements,omitempty" eebus:"typ:elements,fct:networkManagementReportCandidateData"` - NetworkManagementScanNetworkCallElements *NetworkManagementScanNetworkCallElementsType `json:"networkManagementScanNetworkCallElements,omitempty" eebus:"typ:elements,fct:networkManagementScanNetworkCall"` - NodeManagementBindingDataElements *NodeManagementBindingDataElementsType `json:"nodeManagementBindingDataElements,omitempty" eebus:"typ:elements,fct:nodeManagementBindingData"` - NodeManagementBindingDeleteCallElements *NodeManagementBindingDeleteCallElementsType `json:"nodeManagementBindingDeleteCallElements,omitempty" eebus:"typ:elements,fct:nodeManagementBindingDeleteCall"` - NodeManagementBindingRequestCallElements *NodeManagementBindingRequestCallElementsType `json:"nodeManagementBindingRequestCallElements,omitempty" eebus:"typ:elements,fct:nodeManagementBindingRequestCall"` - NodeManagementDestinationDataElements *NodeManagementDestinationDataElementsType `json:"nodeManagementDestinationDataElements,omitempty" eebus:"typ:elements,fct:nodeManagementDestinationListData"` - NodeManagementDetailedDiscoveryDataElements *NodeManagementDetailedDiscoveryDataElementsType `json:"nodeManagementDetailedDiscoveryDataElements,omitempty" eebus:"typ:elements,fct:nodeManagementDetailedDiscoveryData"` - NodeManagementSubscriptionDataElements *NodeManagementSubscriptionDataElementsType `json:"nodeManagementSubscriptionDataElements,omitempty" eebus:"typ:elements,fct:nodeManagementSubscriptionData"` - NodeManagementSubscriptionDeleteCallElements *NodeManagementSubscriptionDeleteCallElementsType `json:"nodeManagementSubscriptionDeleteCallElements,omitempty" eebus:"typ:elements,fct:nodeManagementSubscriptionDeleteCall"` - NodeManagementSubscriptionRequestCallElements *NodeManagementSubscriptionRequestCallElementsType `json:"nodeManagementSubscriptionRequestCallElements,omitempty" eebus:"typ:elements,fct:nodeManagementSubscriptionRequestCall"` - NodeManagementUseCaseDataElements *NodeManagementUseCaseDataElementsType `json:"nodeManagementUseCaseDataElements,omitempty" eebus:"typ:elements,fct:nodeManagementUseCaseData"` - OperatingConstraintsDurationDataElements *OperatingConstraintsDurationDataElementsType `json:"operatingConstraintsDurationDataElements,omitempty" eebus:"typ:elements,fct:operatingConstraintsDurationListData"` - OperatingConstraintsInterruptDataElements *OperatingConstraintsInterruptDataElementsType `json:"operatingConstraintsInterruptDataElements,omitempty" eebus:"typ:elements,fct:operatingConstraintsInterruptListData"` - OperatingConstraintsPowerDescriptionDataElements *OperatingConstraintsPowerDescriptionDataElementsType `json:"operatingConstraintsPowerDescriptionDataElements,omitempty" eebus:"typ:elements,fct:operatingConstraintsPowerDescriptionListData"` - OperatingConstraintsPowerLevelDataElements *OperatingConstraintsPowerLevelDataElementsType `json:"operatingConstraintsPowerLevelDataElements,omitempty" eebus:"typ:elements,fct:operatingConstraintsPowerLevelListData"` - OperatingConstraintsPowerRangeDataElements *OperatingConstraintsPowerRangeDataElementsType `json:"operatingConstraintsPowerRangeDataElements,omitempty" eebus:"typ:elements,fct:operatingConstraintsPowerRangeListData"` - OperatingConstraintsResumeImplicationDataElements *OperatingConstraintsResumeImplicationDataElementsType `json:"operatingConstraintsResumeImplicationDataElements,omitempty" eebus:"typ:elements,fct:operatingConstraintsResumeImplicationListData"` - PowerSequenceAlternativesRelationDataElements *PowerSequenceAlternativesRelationDataElementsType `json:"powerSequenceAlternativesRelationDataElements,omitempty" eebus:"typ:elements,fct:powerSequenceAlternativesRelationListData"` - PowerSequenceDescriptionDataElements *PowerSequenceDescriptionDataElementsType `json:"powerSequenceDescriptionDataElements,omitempty" eebus:"typ:elements,fct:powerSequenceDescriptionListData"` - PowerSequenceNodeScheduleInformationDataElements *PowerSequenceNodeScheduleInformationDataElementsType `json:"powerSequenceNodeScheduleInformationDataElements,omitempty" eebus:"typ:elements,fct:powerSequenceNodeScheduleInformationData"` - PowerSequencePriceCalculationRequestCallElements *PowerSequencePriceCalculationRequestCallElementsType `json:"powerSequencePriceCalculationRequestCallElements,omitempty" eebus:"typ:elements,fct:powerSequencePriceCalculationRequestCall"` - PowerSequencePriceDataElements *PowerSequencePriceDataElementsType `json:"powerSequencePriceDataElements,omitempty" eebus:"typ:elements,fct:powerSequencePriceListData"` - PowerSequenceScheduleConfigurationRequestCallElements *PowerSequenceScheduleConfigurationRequestCallElementsType `json:"powerSequenceScheduleConfigurationRequestCallElements,omitempty" eebus:"typ:elements,fct:powerSequenceScheduleConfigurationRequestCall"` - PowerSequenceScheduleConstraintsDataElements *PowerSequenceScheduleConstraintsDataElementsType `json:"powerSequenceScheduleConstraintsDataElements,omitempty" eebus:"typ:elements,fct:powerSequenceScheduleConstraintsListData"` - PowerSequenceScheduleDataElements *PowerSequenceScheduleDataElementsType `json:"powerSequenceScheduleDataElements,omitempty" eebus:"typ:elements,fct:powerSequenceScheduleListData"` - PowerSequenceSchedulePreferenceDataElements *PowerSequenceSchedulePreferenceDataElementsType `json:"powerSequenceSchedulePreferenceDataElements,omitempty" eebus:"typ:elements,fct:powerSequenceSchedulePreferenceListData"` - PowerSequenceStateDataElements *PowerSequenceStateDataElementsType `json:"powerSequenceStateDataElements,omitempty" eebus:"typ:elements,fct:powerSequenceStateListData"` - PowerTimeSlotScheduleConstraintsDataElements *PowerTimeSlotScheduleConstraintsDataElementsType `json:"powerTimeSlotScheduleConstraintsDataElements,omitempty" eebus:"typ:elements,fct:powerTimeSlotScheduleConstraintsListData"` - PowerTimeSlotScheduleDataElements *PowerTimeSlotScheduleDataElementsType `json:"powerTimeSlotScheduleDataElements,omitempty" eebus:"typ:elements,fct:powerTimeSlotScheduleListData"` - PowerTimeSlotValueDataElements *PowerTimeSlotValueDataElementsType `json:"powerTimeSlotValueDataElements,omitempty" eebus:"typ:elements,fct:powerTimeSlotValueListData"` - SensingDataElements *SensingDataElementsType `json:"sensingDataElements,omitempty" eebus:"typ:elements,fct:sensingListData"` - SensingDescriptionDataElements *SensingDescriptionDataElementsType `json:"sensingDescriptionDataElements,omitempty" eebus:"typ:elements,fct:sensingDescriptionData"` - SetpointConstraintsDataElements *SetpointConstraintsDataElementsType `json:"setpointConstraintsDataElements,omitempty" eebus:"typ:elements,fct:setpointConstraintsListData"` - SetpointDataElements *SetpointDataElementsType `json:"setpointDataElements,omitempty" eebus:"typ:elements,fct:setpointListData"` - SetpointDescriptionDataElements *SetpointDescriptionDataElementsType `json:"setpointDescriptionDataElements,omitempty" eebus:"typ:elements,fct:"` - SmartEnergyManagementPsConfigurationRequestCallElements *SmartEnergyManagementPsConfigurationRequestCallElementsType `json:"smartEnergyManagementPsConfigurationRequestCallElements,omitempty" eebus:"typ:elements,fct:smartEnergyManagementPsConfigurationRequestCall"` - SmartEnergyManagementPsDataElements *SmartEnergyManagementPsDataElementsType `json:"smartEnergyManagementPsDataElements,omitempty" eebus:"typ:elements,fct:smartEnergyManagementPsData"` - SmartEnergyManagementPsPriceCalculationRequestCallElements *SmartEnergyManagementPsPriceCalculationRequestCallElementsType `json:"smartEnergyManagementPsPriceCalculationRequestCallElements,omitempty" eebus:"typ:elements,fct:smartEnergyManagementPsPriceCalculationRequestCall"` - SmartEnergyManagementPsPriceDataElements *SmartEnergyManagementPsPriceDataElementsType `json:"smartEnergyManagementPsPriceDataElements,omitempty" eebus:"typ:elements,fct:smartEnergyManagementPsPriceData"` - SpecificationVersionDataElements *SpecificationVersionDataElementsType `json:"specificationVersionDataElements,omitempty" eebus:"typ:elements,fct:specificationVersionListData"` - SubscriptionManagementDeleteCallElements *SubscriptionManagementDeleteCallElementsType `json:"subscriptionManagementDeleteCallElements,omitempty" eebus:"typ:elements,fct:subscriptionManagementDeleteCall"` - SubscriptionManagementEntryDataElements *SubscriptionManagementEntryDataElementsType `json:"subscriptionManagementEntryDataElements,omitempty" eebus:"typ:elements,fct:subscriptionManagementEntryListData"` - SubscriptionManagementRequestCallElements *SubscriptionManagementRequestCallElementsType `json:"subscriptionManagementRequestCallElements,omitempty" eebus:"typ:elements,fct:subscriptionManagementRequestCall"` - SupplyConditionDataElements *SupplyConditionDataElementsType `json:"supplyConditionDataElements,omitempty" eebus:"typ:elements,fct:supplyConditionListData"` - SupplyConditionDescriptionDataElements *SupplyConditionDescriptionDataElementsType `json:"supplyConditionDescriptionDataElements,omitempty" eebus:"typ:elements,fct:supplyConditionDescriptionListData"` - SupplyConditionThresholdRelationDataElements *SupplyConditionThresholdRelationDataElementsType `json:"supplyConditionThresholdRelationDataElements,omitempty" eebus:"typ:elements,fct:supplyConditionThresholdRelationListData"` - TariffBoundaryRelationDataElements *TariffBoundaryRelationDataElementsType `json:"tariffBoundaryRelationDataElements,omitempty" eebus:"typ:elements,fct:tariffBoundaryRelationListData"` - TariffDataElements *TariffDataElementsType `json:"tariffDataElements,omitempty" eebus:"typ:elements,fct:tariffListData"` - TariffDescriptionDataElements *TariffDescriptionDataElementsType `json:"tariffDescriptionDataElements,omitempty" eebus:"typ:elements,fct:tariffDescriptionListData"` - TariffOverallConstraintsDataElements *TariffOverallConstraintsDataElementsType `json:"tariffOverallConstraintsDataElements,omitempty" eebus:"typ:elements,fct:tariffOverallConstraintsData"` - TariffTierRelationDataElements *TariffTierRelationDataElementsType `json:"tariffTierRelationDataElements,omitempty" eebus:"typ:elements,fct:tariffTierRelationListData"` - TaskManagementJobDataElements *TaskManagementJobDataElementsType `json:"taskManagementJobDataElements,omitempty" eebus:"typ:elements,fct:taskManagementJobListData"` - TaskManagementJobDescriptionDataElements *TaskManagementJobDescriptionDataElementsType `json:"taskManagementJobDescriptionDataElements,omitempty" eebus:"typ:elements,fct:taskManagementJobDescriptionListData"` - TaskManagementJobRelationDataElements *TaskManagementJobRelationDataElementsType `json:"taskManagementJobRelationDataElements,omitempty" eebus:"typ:elements,fct:taskManagementJobRelationListData"` - TaskManagementOverviewDataElements *TaskManagementOverviewDataElementsType `json:"taskManagementOverviewDataElements,omitempty" eebus:"typ:elements,fct:taskManagementOverviewData"` - ThresholdConstraintsDataElements *ThresholdConstraintsDataElementsType `json:"thresholdConstraintsDataElements,omitempty" eebus:"typ:elements,fct:thresholdConstraintsListData"` - ThresholdDataElements *ThresholdDataElementsType `json:"thresholdDataElements,omitempty" eebus:"typ:elements,fct:thresholdListData"` - ThresholdDescriptionDataElements *ThresholdDescriptionDataElementsType `json:"thresholdDescriptionDataElements,omitempty" eebus:"typ:elements,fct:thresholdDescriptionListData"` - TierBoundaryDataElements *TierBoundaryDataElementsType `json:"tierBoundaryDataElements,omitempty" eebus:"typ:elements,fct:tierBoundaryListData"` - TierBoundaryDescriptionDataElements *TierBoundaryDescriptionDataElementsType `json:"tierBoundaryDescriptionDataElements,omitempty" eebus:"typ:elements,fct:tierBoundaryDescriptionListData"` - TierDataElements *TierDataElementsType `json:"tierDataElements,omitempty" eebus:"typ:elements,fct:tierListData"` - TierDescriptionDataElements *TierDescriptionDataElementsType `json:"tierDescriptionDataElements,omitempty" eebus:"typ:elements,fct:tierDescriptionListData"` - TierIncentiveRelationDataElements *TierIncentiveRelationDataElementsType `json:"tierIncentiveRelationDataElements,omitempty" eebus:"typ:elements,fct:tierIncentiveRelationListData"` - TimeDistributorDataElements *TimeDistributorDataElementsType `json:"timeDistributorDataElements,omitempty" eebus:"typ:elements,fct:timeDistributorData"` - TimeDistributorEnquiryCallElements *TimeDistributorEnquiryCallElementsType `json:"timeDistributorEnquiryCallElements,omitempty" eebus:"typ:elements,fct:timeDistributorEnquiryCall"` - TimeInformationDataElements *TimeInformationDataElementsType `json:"timeInformationDataElements,omitempty" eebus:"typ:elements,fct:timeInformationData"` - TimePrecisionDataElements *TimePrecisionDataElementsType `json:"timePrecisionDataElements,omitempty" eebus:"typ:elements,fct:timePrecisionData"` - TimeSeriesConstraintsDataElements *TimeSeriesConstraintsDataElementsType `json:"timeSeriesConstraintsDataElements,omitempty" eebus:"typ:elements,fct:timeSeriesConstraintsListData"` - TimeSeriesDataElements *TimeSeriesDataElementsType `json:"timeSeriesDataElements,omitempty" eebus:"typ:elements,fct:timeSeriesListData"` - TimeSeriesDescriptionDataElements *TimeSeriesDescriptionDataElementsType `json:"timeSeriesDescriptionDataElements,omitempty" eebus:"typ:elements,fct:timeSeriesDescriptionListData"` - TimeTableConstraintsDataElements *TimeTableConstraintsDataElementsType `json:"timeTableConstraintsDataElements,omitempty" eebus:"typ:elements,fct:timeTableConstraintsListData"` - TimeTableDataElements *TimeTableDataElementsType `json:"timeTableDataElements,omitempty" eebus:"typ:elements,fct:timeTableListData"` - TimeTableDescriptionDataElements *TimeTableDescriptionDataElementsType `json:"timeTableDescriptionDataElements,omitempty" eebus:"typ:elements,fct:timeTableDescriptionListData"` - UseCaseInformationDataElements *UseCaseInformationDataElementsType `json:"useCaseInformationDataElements,omitempty" eebus:"typ:elements,fct:useCaseInformationListData"` -} - -type CmdControlType struct { - Delete *ElementTagType `json:"delete,omitempty"` - Partial *ElementTagType `json:"partial,omitempty"` -} - -type CmdType struct { - // CmdOptionGroup - Function *FunctionType `json:"function,omitempty"` - Filter []FilterType `json:"filter,omitempty"` - - // DataChoiceGroup - ActuatorLevelData *ActuatorLevelDataType `json:"actuatorLevelData,omitempty" eebus:"fct:actuatorLevelData"` - ActuatorLevelDescriptionData *ActuatorLevelDescriptionDataType `json:"actuatorLevelDescriptionData,omitempty" eebus:"fct:actuatorLevelDescriptionData"` - ActuatorSwitchData *ActuatorSwitchDataType `json:"actuatorSwitchData,omitempty" eebus:"fct:actuatorSwitchData"` - ActuatorSwitchDescriptionData *ActuatorSwitchDescriptionDataType `json:"actuatorSwitchDescriptionData,omitempty" eebus:"fct:actuatorSwitchDescriptionData"` - AlarmListData *AlarmListDataType `json:"alarmListData,omitempty" eebus:"fct:alarmListData"` - BillConstraintsListData *BillConstraintsListDataType `json:"billConstraintsListData,omitempty" eebus:"fct:billConstraintsListData"` - BillDescriptionListData *BillDescriptionListDataType `json:"billDescriptionListData,omitempty" eebus:"fct:billDescriptionListData"` - BillListData *BillListDataType `json:"billListData,omitempty" eebus:"fct:billListData"` - BindingManagementDeleteCall *BindingManagementDeleteCallType `json:"bindingManagementDeleteCall,omitempty" eebus:"fct:bindingManagementDeleteCall"` - BindingManagementEntryListData *BindingManagementEntryListDataType `json:"bindingManagementEntryListData,omitempty" eebus:"fct:bindingManagementEntryListData"` - BindingManagementRequestCall *BindingManagementRequestCallType `json:"bindingManagementRequestCall,omitempty" eebus:"fct:bindingManagementRequestCall"` - CommodityListData *CommodityListDataType `json:"commodityListData,omitempty" eebus:"fct:commodityListData"` - DataTunnelingCall *DataTunnelingCallType `json:"dataTunnelingCall,omitempty" eebus:"fct:dataTunnelingCall"` - DeviceClassificationManufacturerData *DeviceClassificationManufacturerDataType `json:"deviceClassificationManufacturerData,omitempty" eebus:"fct:deviceClassificationManufacturerData"` - DeviceClassificationUserData *DeviceClassificationUserDataType `json:"deviceClassificationUserData,omitempty" eebus:"fct:deviceClassificationUserData"` - DeviceConfigurationKeyValueConstraintsListData *DeviceConfigurationKeyValueConstraintsListDataType `json:"deviceConfigurationKeyValueConstraintsListData,omitempty" eebus:"fct:deviceConfigurationKeyValueConstraintsListData"` - DeviceConfigurationKeyValueDescriptionListData *DeviceConfigurationKeyValueDescriptionListDataType `json:"deviceConfigurationKeyValueDescriptionListData,omitempty" eebus:"fct:deviceConfigurationKeyValueDescriptionListData"` - DeviceConfigurationKeyValueListData *DeviceConfigurationKeyValueListDataType `json:"deviceConfigurationKeyValueListData,omitempty" eebus:"fct:deviceConfigurationKeyValueListData"` - DeviceDiagnosisHeartbeatData *DeviceDiagnosisHeartbeatDataType `json:"deviceDiagnosisHeartbeatData,omitempty" eebus:"fct:deviceDiagnosisHeartbeatData"` - DeviceDiagnosisServiceData *DeviceDiagnosisServiceDataType `json:"deviceDiagnosisServiceData,omitempty" eebus:"fct:deviceDiagnosisServiceData"` - DeviceDiagnosisStateData *DeviceDiagnosisStateDataType `json:"deviceDiagnosisStateData,omitempty" eebus:"fct:deviceDiagnosisStateData"` - DirectControlActivityListData *DirectControlActivityListDataType `json:"directControlActivityListData,omitempty" eebus:"fct:directControlActivityListData"` - DirectControlDescriptionData *DirectControlDescriptionDataType `json:"directControlDescriptionData,omitempty" eebus:"fct:directControlDescriptionData"` - ElectricalConnectionDescriptionListData *ElectricalConnectionDescriptionListDataType `json:"electricalConnectionDescriptionListData,omitempty" eebus:"fct:electricalConnectionDescriptionListData"` - ElectricalConnectionParameterDescriptionListData *ElectricalConnectionParameterDescriptionListDataType `json:"electricalConnectionParameterDescriptionListData,omitempty" eebus:"fct:electricalConnectionParameterDescriptionListData"` - ElectricalConnectionPermittedValueSetListData *ElectricalConnectionPermittedValueSetListDataType `json:"electricalConnectionPermittedValueSetListData,omitempty" eebus:"fct:electricalConnectionPermittedValueSetListData"` - ElectricalConnectionStateListData *ElectricalConnectionStateListDataType `json:"electricalConnectionStateListData,omitempty" eebus:"fct:electricalConnectionStateListData"` - HvacOperationModeDescriptionListData *HvacOperationModeDescriptionListDataType `json:"hvacOperationModeDescriptionListData,omitempty" eebus:"fct:hvacOperationModeDescriptionListData"` - HvacOverrunDescriptionListData *HvacOverrunDescriptionListDataType `json:"hvacOverrunDescriptionListData,omitempty" eebus:"fct:hvacOverrunDescriptionListData"` - HvacOverrunListData *HvacOverrunListDataType `json:"hvacOverrunListData,omitempty" eebus:"fct:hvacOverrunListData"` - HvacSystemFunctionDescriptionListData *HvacSystemFunctionDescriptionListDataType `json:"hvacSystemFunctionDescriptionListData,omitempty" eebus:"fct:hvacSystemFunctionDescriptionListData"` - HvacSystemFunctionListData *HvacSystemFunctionListDataType `json:"hvacSystemFunctionListData,omitempty" eebus:"fct:hvacSystemFunctionListData"` - HvacSystemFunctionOperationModeRelationListData *HvacSystemFunctionOperationModeRelationListDataType `json:"hvacSystemFunctionOperationModeRelationListData,omitempty" eebus:"fct:hvacSystemFunctionOperationModeRelationListData"` - HvacSystemFunctionPowerSequenceRelationListData *HvacSystemFunctionPowerSequenceRelationListDataType `json:"hvacSystemFunctionPowerSequenceRelationListData,omitempty" eebus:"fct:hvacSystemFunctionPowerSequenceRelationListData"` - HvacSystemFunctionSetPointRelationListData *HvacSystemFunctionSetpointRelationListDataType `json:"hvacSystemFunctionSetpointRelationListData,omitempty" eebus:"fct:hvacSystemFunctionSetpointRelationListData"` - IdentificationListData *IdentificationListDataType `json:"identificationListData,omitempty" eebus:"fct:identificationListData"` - IncentiveDescriptionListData *IncentiveDescriptionListDataType `json:"incentiveDescriptionListData,omitempty" eebus:"fct:incentiveDescriptionListData"` - IncentiveListData *IncentiveListDataType `json:"incentiveListData,omitempty" eebus:"fct:incentiveListData"` - IncentiveTableConstraintsData *IncentiveTableConstraintsDataType `json:"incentiveTableConstraintsData,omitempty" eebus:"fct:incentiveTableConstraintsData"` - IncentiveTableData *IncentiveTableDataType `json:"incentiveTableData,omitempty" eebus:"fct:incentiveTableData"` - IncentiveTableDescriptionData *IncentiveTableDescriptionDataType `json:"incentiveTableDescriptionData,omitempty" eebus:"fct:incentiveTableDescriptionData"` - LoadControlEventListData *LoadControlEventListDataType `json:"loadControlEventListData,omitempty" eebus:"fct:loadControlEventListData"` - LoadControlLimitConstraintsListData *LoadControlLimitConstraintsListDataType `json:"loadControlLimitConstraintsListData,omitempty" eebus:"fct:loadControlLimitConstraintsListData"` - LoadControlLimitDescriptionListData *LoadControlLimitDescriptionListDataType `json:"loadControlLimitDescriptionListData,omitempty" eebus:"fct:loadControlLimitDescriptionListData"` - LoadControlLimitListData *LoadControlLimitListDataType `json:"loadControlLimitListData,omitempty" eebus:"fct:loadControlLimitListData"` - LoadControlNodeData *LoadControlNodeDataType `json:"loadControlNodeData,omitempty" eebus:"fct:loadControlNodeData"` - LoadControlStateListData *LoadControlStateListDataType `json:"loadControlStateListData,omitempty" eebus:"fct:loadControlStateListData"` - MeasurementConstraintsListData *MeasurementConstraintsListDataType `json:"measurementConstraintsListData,omitempty" eebus:"fct:measurementConstraintsListData"` - MeasurementDescriptionListData *MeasurementDescriptionListDataType `json:"measurementDescriptionListData,omitempty" eebus:"fct:measurementDescriptionListData"` - MeasurementListData *MeasurementListDataType `json:"measurementListData,omitempty" eebus:"fct:measurementListData"` - MeasurementThresholdRelationListData *MeasurementThresholdRelationListDataType `json:"measurementThresholdRelationListData,omitempty" eebus:"fct:measurementThresholdRelationListData"` - MessagingListData *MessagingListDataType `json:"messagingListData,omitempty" eebus:"fct:messagingListData"` - NetworkManagementAbortCall *NetworkManagementAbortCallType `json:"networkManagementAbortCall,omitempty" eebus:"fct:networkManagementAbortCall"` - NetworkManagementAddNodeCall *NetworkManagementAddNodeCallType `json:"networkManagementAddNodeCall,omitempty" eebus:"fct:networkManagementAddNodeCall"` - NetworkManagementDeviceDescriptionListData *NetworkManagementDeviceDescriptionListDataType `json:"networkManagementDeviceDescriptionListData,omitempty" eebus:"fct:networkManagementDeviceDescriptionListData"` - NetworkManagementDiscoverCall *NetworkManagementDiscoverCallType `json:"networkManagementDiscoverCall,omitempty" eebus:"fct:networkManagementDiscoverCall"` - NetworkManagementEntityDescriptionListData *NetworkManagementEntityDescriptionListDataType `json:"networkManagementEntityDescriptionListData,omitempty" eebus:"fct:networkManagementEntityDescriptionListData"` - NetworkManagementFeatureDescriptionListData *NetworkManagementFeatureDescriptionListDataType `json:"networkManagementFeatureDescriptionListData,omitempty" eebus:"fct:networkManagementFeatureDescriptionListData"` - NetworkManagementJoiningModeData *NetworkManagementJoiningModeDataType `json:"networkManagementJoiningModeData,omitempty" eebus:"fct:networkManagementJoiningModeData"` - NetworkManagementModifyNodeCall *NetworkManagementModifyNodeCallType `json:"networkManagementModifyNodeCall,omitempty" eebus:"fct:networkManagementModifyNodeCall"` - NetworkManagementProcessStateData *NetworkManagementProcessStateDataType `json:"networkManagementProcessStateData,omitempty" eebus:"fct:networkManagementProcessStateData"` - NetworkManagementRemoveNodeCall *NetworkManagementRemoveNodeCallType `json:"networkManagementRemoveNodeCall,omitempty" eebus:"fct:networkManagementRemoveNodeCall"` - NetworkManagementReportCandidateData *NetworkManagementReportCandidateDataType `json:"networkManagementReportCandidateData,omitempty" eebus:"fct:networkManagementReportCandidateData"` - NetworkManagementScanNetworkCall *NetworkManagementScanNetworkCallType `json:"networkManagementScanNetworkCall,omitempty" eebus:"fct:networkManagementScanNetworkCall"` - NodeManagementBindingData *NodeManagementBindingDataType `json:"nodeManagementBindingData,omitempty" eebus:"fct:nodeManagementBindingData"` - NodeManagementBindingDeleteCall *NodeManagementBindingDeleteCallType `json:"nodeManagementBindingDeleteCall,omitempty" eebus:"fct:nodeManagementBindingDeleteCall"` - NodeManagementBindingRequestCall *NodeManagementBindingRequestCallType `json:"nodeManagementBindingRequestCall,omitempty" eebus:"fct:nodeManagementBindingRequestCall"` - NodeManagementDestinationListData *NodeManagementDestinationListDataType `json:"nodeManagementDestinationListData,omitempty" eebus:"fct:nodeManagementDestinationListData"` - NodeManagementDetailedDiscoveryData *NodeManagementDetailedDiscoveryDataType `json:"nodeManagementDetailedDiscoveryData,omitempty" eebus:"fct:nodeManagementDetailedDiscoveryData"` - NodeManagementSubscriptionData *NodeManagementSubscriptionDataType `json:"nodeManagementSubscriptionData,omitempty" eebus:"fct:nodeManagementSubscriptionData"` - NodeManagementSubscriptionDeleteCall *NodeManagementSubscriptionDeleteCallType `json:"nodeManagementSubscriptionDeleteCall,omitempty" eebus:"fct:nodeManagementSubscriptionDeleteCall"` - NodeManagementSubscriptionRequestCall *NodeManagementSubscriptionRequestCallType `json:"nodeManagementSubscriptionRequestCall,omitempty" eebus:"fct:nodeManagementSubscriptionRequestCall"` - NodeManagementUseCaseData *NodeManagementUseCaseDataType `json:"nodeManagementUseCaseData,omitempty" eebus:"fct:nodeManagementUseCaseData"` - OperatingConstraintsDurationListData *OperatingConstraintsDurationListDataType `json:"operatingConstraintsDurationListData,omitempty" eebus:"fct:operatingConstraintsDurationListData"` - OperatingConstraintsInterruptListData *OperatingConstraintsInterruptListDataType `json:"operatingConstraintsInterruptListData,omitempty" eebus:"fct:operatingConstraintsInterruptListData"` - OperatingConstraintsPowerDescriptionListData *OperatingConstraintsPowerDescriptionListDataType `json:"operatingConstraintsPowerDescriptionListData,omitempty" eebus:"fct:operatingConstraintsPowerDescriptionListData"` - OperatingConstraintsPowerLevelListData *OperatingConstraintsPowerLevelListDataType `json:"operatingConstraintsPowerLevelListData,omitempty" eebus:"fct:operatingConstraintsPowerLevelListData"` - OperatingConstraintsPowerRangeListData *OperatingConstraintsPowerRangeListDataType `json:"operatingConstraintsPowerRangeListData,omitempty" eebus:"fct:operatingConstraintsPowerRangeListData"` - OperatingConstraintsResumeImplicationListData *OperatingConstraintsResumeImplicationListDataType `json:"operatingConstraintsResumeImplicationListData,omitempty" eebus:"fct:operatingConstraintsResumeImplicationListData"` - PowerSequenceAlternativesRelationListData *PowerSequenceAlternativesRelationListDataType `json:"powerSequenceAlternativesRelationListData,omitempty" eebus:"fct:powerSequenceAlternativesRelationListData"` - PowerSequenceDescriptionListData *PowerSequenceDescriptionListDataType `json:"powerSequenceDescriptionListData,omitempty" eebus:"fct:powerSequenceDescriptionListData"` - PowerSequenceNodeScheduleInformationData *PowerSequenceNodeScheduleInformationDataType `json:"powerSequenceNodeScheduleInformationData,omitempty" eebus:"fct:powerSequenceNodeScheduleInformationData"` - PowerSequencePriceCalculationRequestCall *PowerSequencePriceCalculationRequestCallType `json:"powerSequencePriceCalculationRequestCall,omitempty" eebus:"fct:powerSequencePriceCalculationRequestCall"` - PowerSequencePriceListData *PowerSequencePriceListDataType `json:"powerSequencePriceListData,omitempty" eebus:"fct:powerSequencePriceListData"` - PowerSequenceScheduleConfigurationRequestCall *PowerSequenceScheduleConfigurationRequestCallType `json:"powerSequenceScheduleConfigurationRequestCall,omitempty" eebus:"fct:powerSequenceScheduleConfigurationRequestCall"` - PowerSequenceScheduleConstraintsListData *PowerSequenceScheduleConstraintsListDataType `json:"powerSequenceScheduleConstraintsListData,omitempty" eebus:"fct:powerSequenceScheduleConstraintsListData"` - PowerSequenceScheduleListData *PowerSequenceScheduleListDataType `json:"powerSequenceScheduleListData,omitempty" eebus:"fct:powerSequenceScheduleListData"` - PowerSequenceSchedulePreferenceListData *PowerSequenceSchedulePreferenceListDataType `json:"powerSequenceSchedulePreferenceListData,omitempty" eebus:"fct:powerSequenceSchedulePreferenceListData"` - PowerSequenceStateListData *PowerSequenceStateListDataType `json:"powerSequenceStateListData,omitempty" eebus:"fct:powerSequenceStateListData"` - PowerTimeSlotScheduleConstraintsListData *PowerTimeSlotScheduleConstraintsListDataType `json:"powerTimeSlotScheduleConstraintsListData,omitempty" eebus:"fct:powerTimeSlotScheduleConstraintsListData"` - PowerTimeSlotScheduleListData *PowerTimeSlotScheduleListDataType `json:"powerTimeSlotScheduleListData,omitempty" eebus:"fct:powerTimeSlotScheduleListData"` - PowerTimeSlotValueListData *PowerTimeSlotValueListDataType `json:"powerTimeSlotValueListData,omitempty" eebus:"fct:powerTimeSlotValueListData"` - ResultData *ResultDataType `json:"resultData,omitempty" eebus:"fct:resultData"` - SensingDescriptionData *SensingDescriptionDataType `json:"sensingDescriptionData,omitempty" eebus:"fct:sensingDescriptionData"` - SensingListData *SensingListDataType `json:"sensingListData,omitempty" eebus:"fct:sensingListData"` - SetpointConstraintsListData *SetpointConstraintsListDataType `json:"setpointConstraintsListData,omitempty" eebus:"fct:setpointConstraintsListData"` - SetpointDescriptionListData *SetpointDescriptionListDataType `json:"setpointDescriptionListData,omitempty" eebus:"fct:setpointDescriptionListData"` - SetpointListData *SetpointListDataType `json:"setpointListData,omitempty" eebus:"fct:setpointListData"` - SmartEnergyManagementPsConfigurationRequestCall *SmartEnergyManagementPsConfigurationRequestCallType `json:"smartEnergyManagementPsConfigurationRequestCall,omitempty" eebus:"fct:smartEnergyManagementPsConfigurationRequestCall"` - SmartEnergyManagementPsData *SmartEnergyManagementPsDataType `json:"smartEnergyManagementPsData,omitempty" eebus:"fct:smartEnergyManagementPsData"` - SmartEnergyManagementPsPriceCalculationRequestCall *SmartEnergyManagementPsPriceCalculationRequestCallType `json:"smartEnergyManagementPsPriceCalculationRequestCall,omitempty" eebus:"fct:smartEnergyManagementPsPriceCalculationRequestCall"` - SmartEnergyManagementPsPriceData *SmartEnergyManagementPsPriceDataType `json:"smartEnergyManagementPsPriceData,omitempty" eebus:"fct:smartEnergyManagementPsPriceData"` - SpecificationVersionListData *SpecificationVersionListDataType `json:"specificationVersionListData,omitempty" eebus:"fct:specificationVersionListData"` - SubscriptionManagementDeleteCall *SubscriptionManagementDeleteCallType `json:"subscriptionManagementDeleteCall,omitempty" eebus:"fct:subscriptionManagementDeleteCall"` - SubscriptionManagementEntryListData *SubscriptionManagementEntryListDataType `json:"subscriptionManagementEntryListData,omitempty" eebus:"fct:subscriptionManagementEntryListData"` - SubscriptionManagementRequestCall *SubscriptionManagementRequestCallType `json:"subscriptionManagementRequestCall,omitempty" eebus:"fct:subscriptionManagementRequestCall"` - SupplyConditionDescriptionListData *SupplyConditionDescriptionListDataType `json:"supplyConditionDescriptionListData,omitempty" eebus:"fct:supplyConditionDescriptionListData"` - SupplyConditionListData *SupplyConditionListDataType `json:"supplyConditionListData,omitempty" eebus:"fct:supplyConditionListData"` - SupplyConditionThresholdRelationListData *SupplyConditionThresholdRelationListDataType `json:"supplyConditionThresholdRelationListData,omitempty" eebus:"fct:supplyConditionThresholdRelationListData"` - TariffBoundaryRelationListData *TariffBoundaryRelationListDataType `json:"tariffBoundaryRelationListData,omitempty" eebus:"fct:tariffBoundaryRelationListData"` - TariffDescriptionListData *TariffDescriptionListDataType `json:"tariffDescriptionListData,omitempty" eebus:"fct:tariffDescriptionListData"` - TariffListData *TariffListDataType `json:"tariffListData,omitempty" eebus:"fct:tariffListData"` - TariffOverallConstraintsData *TariffOverallConstraintsDataType `json:"tariffOverallConstraintsData,omitempty" eebus:"fct:tariffOverallConstraintsData"` - TariffTierRelationListData *TariffTierRelationListDataType `json:"tariffTierRelationListData,omitempty" eebus:"fct:tariffTierRelationListData"` - TaskManagementJobDescriptionListData *TaskManagementJobDescriptionListDataType `json:"taskManagementJobDescriptionListData,omitempty" eebus:"fct:taskManagementJobDescriptionListData"` - TaskManagementJobListData *TaskManagementJobListDataType `json:"taskManagementJobListData,omitempty" eebus:"fct:taskManagementJobListData"` - TaskManagementJobRelationListData *TaskManagementJobRelationListDataType `json:"taskManagementJobRelationListData,omitempty" eebus:"fct:taskManagementJobRelationListData"` - TaskManagementOverviewData *TaskManagementOverviewDataType `json:"taskManagementOverviewData,omitempty" eebus:"fct:taskManagementOverviewData"` - ThresholdConstraintsListData *ThresholdConstraintsListDataType `json:"thresholdConstraintsListData,omitempty" eebus:"fct:thresholdConstraintsListData"` - ThresholdDescriptionListData *ThresholdDescriptionListDataType `json:"thresholdDescriptionListData,omitempty" eebus:"fct:thresholdDescriptionListData"` - ThresholdListData *ThresholdListDataType `json:"thresholdListData,omitempty" eebus:"fct:thresholdListData"` - TierBoundaryDescriptionListData *TierBoundaryDescriptionListDataType `json:"tierBoundaryDescriptionListData,omitempty" eebus:"fct:tierBoundaryDescriptionListData"` - TierBoundaryListData *TierBoundaryListDataType `json:"tierBoundaryListData,omitempty" eebus:"fct:tierBoundaryListData"` - TierDescriptionListData *TierDescriptionListDataType `json:"tierDescriptionListData,omitempty" eebus:"fct:tierDescriptionListData"` - TierIncentiveRelationListData *TierIncentiveRelationListDataType `json:"tierIncentiveRelationListData,omitempty" eebus:"fct:tierIncentiveRelationListData"` - TierListData *TierListDataType `json:"tierListData,omitempty" eebus:"fct:tierListData"` - TimeDistributorData *TimeDistributorDataType `json:"timeDistributorData,omitempty" eebus:"fct:timeDistributorData"` - TimeDistributorEnquiryCall *TimeDistributorEnquiryCallType `json:"timeDistributorEnquiryCall,omitempty" eebus:"fct:timeDistributorEnquiryCall"` - TimeInformationData *TimeInformationDataType `json:"timeInformationData,omitempty" eebus:"fct:timeInformationData"` - TimePrecisionData *TimePrecisionDataType `json:"timePrecisionData,omitempty" eebus:"fct:timePrecisionData"` - TimeSeriesConstraintsListData *TimeSeriesConstraintsListDataType `json:"timeSeriesConstraintsListData,omitempty" eebus:"fct:timeSeriesConstraintsListData"` - TimeSeriesDescriptionListData *TimeSeriesDescriptionListDataType `json:"timeSeriesDescriptionListData,omitempty" eebus:"fct:timeSeriesDescriptionListData"` - TimeSeriesListData *TimeSeriesListDataType `json:"timeSeriesListData,omitempty" eebus:"fct:timeSeriesListData"` - TimeTableConstraintsListData *TimeTableConstraintsListDataType `json:"timeTableConstraintsListData,omitempty" eebus:"fct:timeTableConstraintsListData"` - TimeTableDescriptionListData *TimeTableDescriptionListDataType `json:"timeTableDescriptionListData,omitempty" eebus:"fct:timeTableDescriptionListData"` - TimeTableListData *TimeTableListDataType `json:"timeTableListData,omitempty" eebus:"fct:timeTableListData"` - UseCaseInformationListData *UseCaseInformationListDataType `json:"useCaseInformationListData,omitempty" eebus:"fct:useCaseInformationListData"` - - // DataExtendGroup - ManufacturerSpecificExtension *string `json:"manufacturerSpecificExtension,omitempty"` - LastUpdateAt *AbsoluteOrRelativeTimeType `json:"lastUpdateAt,omitempty"` -} diff --git a/spine/model/commandframe_additions.go b/spine/model/commandframe_additions.go deleted file mode 100644 index 853e8a1c..00000000 --- a/spine/model/commandframe_additions.go +++ /dev/null @@ -1,190 +0,0 @@ -package model - -import ( - "errors" - "fmt" - "reflect" - - "github.com/enbility/eebus-go/util" -) - -func (r *MsgCounterType) String() string { - if r == nil { - return "" - } - return fmt.Sprintf("%d", *r) -} - -// FilterData stores the function field name and -// selector field name for a function -type FilterData struct { - Elements any - Selector any - Function *FunctionType -} - -func (f *FilterData) SelectorMatch(item any) bool { - if f.Selector == nil { - return false - } - - v := reflect.ValueOf(f.Selector).Elem() - t := reflect.TypeOf(f.Selector).Elem() - - for i := 0; i < v.NumField(); i++ { - field := v.Field(i) - if field.Kind() != reflect.Ptr { - continue - } - - if field.IsNil() { - continue - } - - fieldname := t.Field(i).Name - value := field.Elem().Interface() - - itemV := reflect.ValueOf(item).Elem() - itemF := itemV.FieldByName(fieldname) - if !itemF.IsValid() { - continue - } - - itemValue := itemF.Elem().Interface() - if itemValue != value { - return false - } - } - - return true -} - -// Get the data and some meta data for the current value -func (f *FilterType) Data() (*FilterData, error) { - var elements any = nil - var selector any = nil - var function string - - v := reflect.ValueOf(*f) - for i := 0; i < v.NumField(); i++ { - f := v.Field(i) - if f.Kind() != reflect.Ptr { - continue - } - - if f.IsNil() { - continue - } - - sf := v.Type().Field(i) - // Exclude the generic fields - if sf.Name == "CmdControl" || sf.Name == "FilterId" { - continue - } - - eebusTags := EEBusTags(sf) - fname, exists := eebusTags[EEBusTagFunction] - if !exists || len(fname) == 0 { - continue - } - typ, exists := eebusTags[EEBusTagType] - if !exists || len(typ) == 0 { - continue - } - - function = fname - - switch typ { - case string(EEBusTagTypeTypeSelector): - selector = f.Interface() - case string(EEbusTagTypeTypeElements): - elements = f.Interface() - } - } - - if len(function) == 0 { - return nil, errors.New("Data not found in Filter") - } - - ft := util.Ptr(FunctionType(function)) - - return &FilterData{ - Elements: elements, - Selector: selector, - Function: ft, - }, nil -} - -// CmdData stores the function field name for a cmd field -type CmdData struct { - FieldName string - Function *FunctionType - Value any -} - -// Get the data and some meta data of the current value -func (cmd *CmdType) Data() (*CmdData, error) { - v := reflect.ValueOf(*cmd) - for i := 0; i < v.NumField(); i++ { - f := v.Field(i) - if f.Kind() != reflect.Ptr { - continue - } - - if f.IsNil() { - continue - } - - sf := v.Type().Field(i) - // Exclude the CmdOptionGroup fields - if sf.Name == "Function" || sf.Name == "Filter" { - continue - } - - eebusTags := EEBusTags(sf) - function, exists := eebusTags[EEBusTagFunction] - if !exists { - continue - } - - var ft *FunctionType = nil - if len(function) > 0 { - ft = util.Ptr(FunctionType(function)) - } - - return &CmdData{ - FieldName: sf.Name, - Function: ft, - Value: f.Interface(), - }, nil - } - - return nil, errors.New("Data not found in Cmd") -} - -// Get the non empty field name of the data type -func (cmd *CmdType) DataName() string { - data, err := cmd.Data() - if err != nil { - return "unknown" - } - - return data.FieldName -} - -func (cmd *CmdType) ExtractFilter() (filterPartial *FilterType, filterDelete *FilterType) { - if cmd != nil && cmd.Filter != nil && len(cmd.Filter) > 0 { - for i := range cmd.Filter { - if cmd.Filter[i].CmdControl.Partial != nil { - filterPartial = &cmd.Filter[i] - } else if cmd.Filter[i].CmdControl.Delete != nil { - filterDelete = &cmd.Filter[i] - } - } - } - return -} - -func NewFilterTypePartial() *FilterType { - return &FilterType{CmdControl: &CmdControlType{Partial: &ElementTagType{}}} -} diff --git a/spine/model/commandframe_additions_test.go b/spine/model/commandframe_additions_test.go deleted file mode 100644 index 60241907..00000000 --- a/spine/model/commandframe_additions_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/stretchr/testify/assert" -) - -func TestCmdType_Data(t *testing.T) { - data := &model.NodeManagementDetailedDiscoveryDataType{ - SpecificationVersionList: &model.NodeManagementSpecificationVersionListType{[]model.SpecificationVersionDataType{model.SpecificationVersionDataType("dummy")}}, - } - - sut := &model.CmdType{ - NodeManagementDetailedDiscoveryData: data, - } - - // Act - cmdData, err := sut.Data() - assert.Nil(t, err) - assert.NotNil(t, cmdData) - assert.Equal(t, "NodeManagementDetailedDiscoveryData", cmdData.FieldName) - assert.Equal(t, model.FunctionTypeNodeManagementDetailedDiscoveryData, *cmdData.Function) - assert.Equal(t, data, cmdData.Value) -} - -func TestCmdType_ExtractFilter_NoFilter(t *testing.T) { - sut := &model.CmdType{ - NodeManagementDetailedDiscoveryData: &model.NodeManagementDetailedDiscoveryDataType{}, - } - - // Act - filterPartial, filterDelete := sut.ExtractFilter() - assert.Nil(t, filterPartial) - assert.Nil(t, filterDelete) -} - -func TestCmdType_ExtractFilter_FilterPartialDelete(t *testing.T) { - - filterP := model.FilterType{ - CmdControl: &model.CmdControlType{Partial: &model.ElementTagType{}}, - NodeManagementDetailedDiscoveryDataSelectors: &model.NodeManagementDetailedDiscoveryDataSelectorsType{}, - } - filterD := model.FilterType{ - CmdControl: &model.CmdControlType{Delete: &model.ElementTagType{}}, - NodeManagementDetailedDiscoveryDataSelectors: &model.NodeManagementDetailedDiscoveryDataSelectorsType{}, - } - - sut := &model.CmdType{ - Filter: []model.FilterType{filterD, filterP}, - NodeManagementDetailedDiscoveryData: &model.NodeManagementDetailedDiscoveryDataType{}, - } - - // Act - filterPartial, filterDelete := sut.ExtractFilter() - assert.NotNil(t, filterPartial) - assert.Equal(t, &filterP, filterPartial) - assert.NotNil(t, filterDelete) - assert.Equal(t, &filterD, filterDelete) -} diff --git a/spine/model/commondatatypes.go b/spine/model/commondatatypes.go deleted file mode 100644 index dd19e52d..00000000 --- a/spine/model/commondatatypes.go +++ /dev/null @@ -1,933 +0,0 @@ -package model - -type ElementTagType struct{} - -type LabelType string - -type DescriptionType string - -type SpecificationVersionType string - -type TimePeriodType struct { - StartTime *AbsoluteOrRelativeTimeType `json:"startTime,omitempty"` - EndTime *AbsoluteOrRelativeTimeType `json:"endTime,omitempty"` -} - -type TimePeriodElementsType struct { - StartTime *ElementTagType `json:"startTime,omitempty"` - EndTime *ElementTagType `json:"endTime,omitempty"` -} - -type TimestampIntervalType struct { - StartTime *AbsoluteOrRelativeTimeType `json:"startTime,omitempty"` - EndTime *AbsoluteOrRelativeTimeType `json:"endTime,omitempty"` -} - -type TimeType string - -type DateType string - -type DateTimeType string - -type DurationType string - -type AbsoluteOrRelativeTimeType string - -type RecurringIntervalType string - -const ( - RecurringIntervalTypeYearly RecurringIntervalType = "yearly" - RecurringIntervalTypeMonthly RecurringIntervalType = "monthly" - RecurringIntervalTypeWeekly RecurringIntervalType = "weekly" - RecurringIntervalTypeDaily RecurringIntervalType = "daily" - RecurringIntervalTypeHourly RecurringIntervalType = "hourly" - RecurringIntervalTypeEveryminute RecurringIntervalType = "everyMinute" - RecurringIntervalTypeEverysecond RecurringIntervalType = "everySecond" -) - -type MonthType string - -const ( - MonthTypeJanuary MonthType = "january" - MonthTypeFebruary MonthType = "february" - MonthTypeMarch MonthType = "march" - MonthTypeApril MonthType = "april" - MonthTypeMay MonthType = "may" - MonthTypeJune MonthType = "june" - MonthTypeJuly MonthType = "july" - MonthTypeAugust MonthType = "august" - MonthTypeSeptember MonthType = "september" - MonthTypeOctober MonthType = "october" - MonthTypeNovember MonthType = "november" - MonthTypeDecember MonthType = "december" -) - -type DayOfMonthType uint8 - -type CalendarWeekType uint8 - -type DayOfWeekType string - -const ( - DayOfWeekTypeMonday DayOfWeekType = "monday" - DayOfWeekTypeTuesday DayOfWeekType = "tuesday" - DayOfWeekTypeWednesday DayOfWeekType = "wednesday" - DayOfWeekTypeThursday DayOfWeekType = "thursday" - DayOfWeekTypeFriday DayOfWeekType = "friday" - DayOfWeekTypeSaturday DayOfWeekType = "saturday" - DayOfWeekTypeSunday DayOfWeekType = "sunday" -) - -type DaysOfWeekType struct { - Monday *ElementTagType `json:"monday,omitempty"` - Tuesday *ElementTagType `json:"tuesday,omitempty"` - Wednesday *ElementTagType `json:"wednesday,omitempty"` - Thursday *ElementTagType `json:"thursday,omitempty"` - Friday *ElementTagType `json:"friday,omitempty"` - Saturday *ElementTagType `json:"saturday,omitempty"` - Sunday *ElementTagType `json:"sunday,omitempty"` -} - -type OccurrenceType string - -const ( - OccurrenceTypeFirst OccurrenceType = "first" - OccurrenceTypeSecond OccurrenceType = "second" - OccurrenceTypeThird OccurrenceType = "third" - OccurrenceTypeFourth OccurrenceType = "fourth" - OccurrenceTypeLast OccurrenceType = "last" -) - -type AbsoluteOrRecurringTimeType struct { - DateTime *DateTimeType `json:"dateTime,omitempty"` - Month *MonthType `json:"month,omitempty"` - DayOfMonth *DayOfMonthType `json:"dayOfMonth,omitempty"` - CalendarWeek *CalendarWeekType `json:"calendarWeek,omitempty"` - DayOfWeekOccurrence *OccurrenceType `json:"dayOfWeekOccurrence,omitempty"` - DaysOfWeek *DaysOfWeekType `json:"daysOfWeek,omitempty"` - Time *TimeType `json:"time,omitempty"` - Relative *DurationType `json:"relative,omitempty"` -} - -type AbsoluteOrRecurringTimeElementsType struct { - DateTime *ElementTagType `json:"dateTime,omitempty"` - Month *ElementTagType `json:"month,omitempty"` - DayOfMonth *ElementTagType `json:"dayOfMonth,omitempty"` - CalendarWeek *ElementTagType `json:"calendarWeek,omitempty"` - DayOfWeekOccurrence *ElementTagType `json:"dayOfWeekOccurrence,omitempty"` - DaysOfWeek *ElementTagType `json:"daysOfWeek,omitempty"` - Time *ElementTagType `json:"time,omitempty"` - Relative *ElementTagType `json:"relative,omitempty"` -} - -type RecurrenceInformationType struct { - RecurringInterval *RecurringIntervalType `json:"recurringInterval,omitempty"` - RecurringIntervalStep *uint `json:"recurringIntervalStep,omitempty"` - FirstExecution *DateTimeType `json:"firstExecution,omitempty"` - ExecutionCount *uint `json:"executionCount,omitempty"` - LastExecution *DateTimeType `json:"lastExecution,omitempty"` -} - -type RecurrenceInformationElementsType struct { - RecurringInterval *ElementTagType `json:"recurringInterval,omitempty"` - RecurringIntervalStep *ElementTagType `json:"recurringIntervalStep,omitempty"` - FirstExecution *ElementTagType `json:"firstExecution,omitempty"` - ExecutionCount *ElementTagType `json:"executionCount,omitempty"` - LastExecution *ElementTagType `json:"lastExecution,omitempty"` -} - -type ScaledNumberRangeType struct { - Min *ScaledNumberType `json:"min,omitempty"` - Max *ScaledNumberType `json:"max,omitempty"` -} - -type ScaledNumberRangeElementsType struct { - Min *ElementTagType `json:"min,omitempty"` - Max *ElementTagType `json:"max,omitempty"` -} - -type ScaledNumberSetType struct { - Value []ScaledNumberType `json:"value,omitempty"` - Range []ScaledNumberRangeType `json:"range,omitempty"` -} - -type ScaledNumberSetElementsType struct { - Value *ElementTagType `json:"value,omitempty"` - Range *ElementTagType `json:"range,omitempty"` -} - -type NumberType int64 - -type ScaleType int8 - -type ScaledNumberType struct { - Number *NumberType `json:"number,omitempty"` - Scale *ScaleType `json:"scale,omitempty"` -} - -type ScaledNumberElementsType struct { - Number *ElementTagType `json:"number,omitempty"` - Scale *ElementTagType `json:"scale,omitempty"` -} - -type MaxResponseDelayType DurationType - -type CommodityTypeType string - -const ( - CommodityTypeTypeElectricity CommodityTypeType = "electricity" - CommodityTypeTypeGas CommodityTypeType = "gas" - CommodityTypeTypeOil CommodityTypeType = "oil" - CommodityTypeTypeWater CommodityTypeType = "water" - CommodityTypeTypeWastewater CommodityTypeType = "wasteWater" - CommodityTypeTypeDomestichotwater CommodityTypeType = "domesticHotWater" - CommodityTypeTypeHeatingwater CommodityTypeType = "heatingWater" - CommodityTypeTypeSteam CommodityTypeType = "steam" - CommodityTypeTypeHeat CommodityTypeType = "heat" - CommodityTypeTypeCoolingload CommodityTypeType = "coolingLoad" - CommodityTypeTypeAir CommodityTypeType = "air" -) - -type EnergyDirectionType string - -const ( - EnergyDirectionTypeConsume EnergyDirectionType = "consume" - EnergyDirectionTypeProduce EnergyDirectionType = "produce" -) - -type EnergyModeType string - -const ( - EnergyModeTypeConsume EnergyModeType = "consume" - EnergyModeTypeProduce EnergyModeType = "produce" - EnergyModeTypeIdle EnergyModeType = "idle" - EnergyModeTypeAuto EnergyModeType = "auto" -) - -type UnitOfMeasurementType string - -const ( - UnitOfMeasurementTypeUnknown UnitOfMeasurementType = "unknown" - UnitOfMeasurementType1 UnitOfMeasurementType = "1" - UnitOfMeasurementTypem UnitOfMeasurementType = "m" - UnitOfMeasurementTypekg UnitOfMeasurementType = "kg" - UnitOfMeasurementTypes UnitOfMeasurementType = "s" - UnitOfMeasurementTypeA UnitOfMeasurementType = "A" - UnitOfMeasurementTypeK UnitOfMeasurementType = "K" - UnitOfMeasurementTypemol UnitOfMeasurementType = "mol" - UnitOfMeasurementTypecd UnitOfMeasurementType = "cd" - UnitOfMeasurementTypeV UnitOfMeasurementType = "V" - UnitOfMeasurementTypeW UnitOfMeasurementType = "W" - UnitOfMeasurementTypeWh UnitOfMeasurementType = "Wh" - UnitOfMeasurementTypeVA UnitOfMeasurementType = "VA" - UnitOfMeasurementTypeVAh UnitOfMeasurementType = "VAh" - UnitOfMeasurementTypevar UnitOfMeasurementType = "var" - UnitOfMeasurementTypevarh UnitOfMeasurementType = "varh" - UnitOfMeasurementTypedegC UnitOfMeasurementType = "degC" - UnitOfMeasurementTypedegF UnitOfMeasurementType = "degF" - UnitOfMeasurementTypeLm UnitOfMeasurementType = "Lm" - UnitOfMeasurementTypelx UnitOfMeasurementType = "lx" - UnitOfMeasurementTypeOhm UnitOfMeasurementType = "Ohm" - UnitOfMeasurementTypeHz UnitOfMeasurementType = "Hz" - UnitOfMeasurementTypedB UnitOfMeasurementType = "dB" - UnitOfMeasurementTypedBm UnitOfMeasurementType = "dBm" - UnitOfMeasurementTypepct UnitOfMeasurementType = "pct" - UnitOfMeasurementTypeppm UnitOfMeasurementType = "ppm" - UnitOfMeasurementTypel UnitOfMeasurementType = "l" - UnitOfMeasurementTypels UnitOfMeasurementType = "l/s" - UnitOfMeasurementTypelh UnitOfMeasurementType = "l/h" - UnitOfMeasurementTypedeg UnitOfMeasurementType = "deg" - UnitOfMeasurementTyperad UnitOfMeasurementType = "rad" - UnitOfMeasurementTyperads UnitOfMeasurementType = "rad/s" - UnitOfMeasurementTypesr UnitOfMeasurementType = "sr" - UnitOfMeasurementTypeGy UnitOfMeasurementType = "Gy" - UnitOfMeasurementTypeBq UnitOfMeasurementType = "Bq" - UnitOfMeasurementTypeBqm3 UnitOfMeasurementType = "Bq/m^3" - UnitOfMeasurementTypeSv UnitOfMeasurementType = "Sv" - UnitOfMeasurementTypeRd UnitOfMeasurementType = "Rd" - UnitOfMeasurementTypeC UnitOfMeasurementType = "C" - UnitOfMeasurementTypeF UnitOfMeasurementType = "F" - UnitOfMeasurementTypeH UnitOfMeasurementType = "H" - UnitOfMeasurementTypeJ UnitOfMeasurementType = "J" - UnitOfMeasurementTypeN UnitOfMeasurementType = "N" - UnitOfMeasurementTypeNm UnitOfMeasurementType = "N_m" - UnitOfMeasurementTypeNs UnitOfMeasurementType = "N_s" - UnitOfMeasurementTypeWb UnitOfMeasurementType = "Wb" - UnitOfMeasurementTypeT UnitOfMeasurementType = "T" - UnitOfMeasurementTypePa UnitOfMeasurementType = "Pa" - UnitOfMeasurementTypebar UnitOfMeasurementType = "bar" - UnitOfMeasurementTypeatm UnitOfMeasurementType = "atm" - UnitOfMeasurementTypepsi UnitOfMeasurementType = "psi" - UnitOfMeasurementTypemmHg UnitOfMeasurementType = "mmHg" - UnitOfMeasurementTypem2 UnitOfMeasurementType = "m^2" - UnitOfMeasurementTypem3 UnitOfMeasurementType = "m^3" - UnitOfMeasurementTypem3h UnitOfMeasurementType = "m^3/h" - UnitOfMeasurementTypems UnitOfMeasurementType = "m/s" - UnitOfMeasurementTypems2 UnitOfMeasurementType = "m/s^2" - UnitOfMeasurementTypem3s UnitOfMeasurementType = "m^3/s" - UnitOfMeasurementTypemm3 UnitOfMeasurementType = "m/m^3" - UnitOfMeasurementTypekgm3 UnitOfMeasurementType = "kg/m^3" - UnitOfMeasurementTypekgm UnitOfMeasurementType = "kg_m" - UnitOfMeasurementTypem2s UnitOfMeasurementType = "m^2/s" - UnitOfMeasurementTypewmk UnitOfMeasurementType = "W/m_K" - UnitOfMeasurementTypeJK UnitOfMeasurementType = "J/K" - UnitOfMeasurementType1s UnitOfMeasurementType = "1/s" - UnitOfMeasurementTypeWm2 UnitOfMeasurementType = "W/m^2" - UnitOfMeasurementTypeJm2 UnitOfMeasurementType = "J/m^2" - UnitOfMeasurementTypeS UnitOfMeasurementType = "S" - UnitOfMeasurementTypeSm UnitOfMeasurementType = "S/m" - UnitOfMeasurementTypeKs UnitOfMeasurementType = "K/s" - UnitOfMeasurementTypePas UnitOfMeasurementType = "Pa/s" - UnitOfMeasurementTypeJkgK UnitOfMeasurementType = "J/kg_K" - UnitOfMeasurementTypeVs UnitOfMeasurementType = "Vs" - UnitOfMeasurementTypeVm UnitOfMeasurementType = "V/m" - UnitOfMeasurementTypeVHz UnitOfMeasurementType = "V/Hz" - UnitOfMeasurementTypeAs UnitOfMeasurementType = "As" - UnitOfMeasurementTypeAm UnitOfMeasurementType = "A/m" - UnitOfMeasurementTypeHzs UnitOfMeasurementType = "Hz/s" - UnitOfMeasurementTypekgs UnitOfMeasurementType = "kg/s" - UnitOfMeasurementTypekgm2 UnitOfMeasurementType = "kg_m^2" - UnitOfMeasurementTypeJWh UnitOfMeasurementType = "J/Wh" - UnitOfMeasurementTypeWs UnitOfMeasurementType = "W/s" - UnitOfMeasurementTypeft3 UnitOfMeasurementType = "ft^3" - UnitOfMeasurementTypeft3h UnitOfMeasurementType = "ft^3/h" - UnitOfMeasurementTypeccf UnitOfMeasurementType = "ccf" - UnitOfMeasurementTypeccfh UnitOfMeasurementType = "ccf/h" - UnitOfMeasurementTypeUSliqgal UnitOfMeasurementType = "US.liq.gal" - UnitOfMeasurementTypeUSliqgalh UnitOfMeasurementType = "US.liq.gal/h" - UnitOfMeasurementTypeImpgal UnitOfMeasurementType = "Imp.gal" - UnitOfMeasurementTypeImpgalh UnitOfMeasurementType = "Imp.gal/h" - UnitOfMeasurementTypeBtu UnitOfMeasurementType = "Btu" - UnitOfMeasurementTypeBtuh UnitOfMeasurementType = "Btu/h" - UnitOfMeasurementTypeAh UnitOfMeasurementType = "Ah" - UnitOfMeasurementTypekgWh UnitOfMeasurementType = "kg/Wh" -) - -type CurrencyType string - -const ( - CurrencyTypeAed CurrencyType = "AED" - CurrencyTypeAfn CurrencyType = "AFN" - CurrencyTypeAll CurrencyType = "ALL" - CurrencyTypeAmd CurrencyType = "AMD" - CurrencyTypeAng CurrencyType = "ANG" - CurrencyTypeAoa CurrencyType = "AOA" - CurrencyTypeArs CurrencyType = "ARS" - CurrencyTypeAud CurrencyType = "AUD" - CurrencyTypeAwg CurrencyType = "AWG" - CurrencyTypeAzn CurrencyType = "AZN" - CurrencyTypeBam CurrencyType = "BAM" - CurrencyTypeBbd CurrencyType = "BBD" - CurrencyTypeBdt CurrencyType = "BDT" - CurrencyTypeBgn CurrencyType = "BGN" - CurrencyTypeBhd CurrencyType = "BHD" - CurrencyTypeBif CurrencyType = "BIF" - CurrencyTypeBmd CurrencyType = "BMD" - CurrencyTypeBnd CurrencyType = "BND" - CurrencyTypeBob CurrencyType = "BOB" - CurrencyTypeBov CurrencyType = "BOV" - CurrencyTypeBrl CurrencyType = "BRL" - CurrencyTypeBsd CurrencyType = "BSD" - CurrencyTypeBtn CurrencyType = "BTN" - CurrencyTypeBwp CurrencyType = "BWP" - CurrencyTypeByr CurrencyType = "BYR" - CurrencyTypeBzd CurrencyType = "BZD" - CurrencyTypeCad CurrencyType = "CAD" - CurrencyTypeCdf CurrencyType = "CDF" - CurrencyTypeChe CurrencyType = "CHE" - CurrencyTypeChf CurrencyType = "CHF" - CurrencyTypeChw CurrencyType = "CHW" - CurrencyTypeClf CurrencyType = "CLF" - CurrencyTypeClp CurrencyType = "CLP" - CurrencyTypeCny CurrencyType = "CNY" - CurrencyTypeCop CurrencyType = "COP" - CurrencyTypeCou CurrencyType = "COU" - CurrencyTypeCrc CurrencyType = "CRC" - CurrencyTypeCuc CurrencyType = "CUC" - CurrencyTypeCup CurrencyType = "CUP" - CurrencyTypeCve CurrencyType = "CVE" - CurrencyTypeCzk CurrencyType = "CZK" - CurrencyTypeDjf CurrencyType = "DJF" - CurrencyTypeDkk CurrencyType = "DKK" - CurrencyTypeDop CurrencyType = "DOP" - CurrencyTypeDzd CurrencyType = "DZD" - CurrencyTypeEgp CurrencyType = "EGP" - CurrencyTypeErn CurrencyType = "ERN" - CurrencyTypeEtb CurrencyType = "ETB" - CurrencyTypeEur CurrencyType = "EUR" - CurrencyTypeFjd CurrencyType = "FJD" - CurrencyTypeFkp CurrencyType = "FKP" - CurrencyTypeGbp CurrencyType = "GBP" - CurrencyTypeGel CurrencyType = "GEL" - CurrencyTypeGhs CurrencyType = "GHS" - CurrencyTypeGip CurrencyType = "GIP" - CurrencyTypeGmd CurrencyType = "GMD" - CurrencyTypeGnf CurrencyType = "GNF" - CurrencyTypeGtq CurrencyType = "GTQ" - CurrencyTypeGyd CurrencyType = "GYD" - CurrencyTypeHkd CurrencyType = "HKD" - CurrencyTypeHnl CurrencyType = "HNL" - CurrencyTypeHrk CurrencyType = "HRK" - CurrencyTypeHtg CurrencyType = "HTG" - CurrencyTypeHuf CurrencyType = "HUF" - CurrencyTypeIdr CurrencyType = "IDR" - CurrencyTypeIls CurrencyType = "ILS" - CurrencyTypeInr CurrencyType = "INR" - CurrencyTypeIqd CurrencyType = "IQD" - CurrencyTypeIrr CurrencyType = "IRR" - CurrencyTypeIsk CurrencyType = "ISK" - CurrencyTypeJmd CurrencyType = "JMD" - CurrencyTypeJod CurrencyType = "JOD" - CurrencyTypeJpy CurrencyType = "JPY" - CurrencyTypeKes CurrencyType = "KES" - CurrencyTypeKgs CurrencyType = "KGS" - CurrencyTypeKhr CurrencyType = "KHR" - CurrencyTypeKmf CurrencyType = "KMF" - CurrencyTypeKpw CurrencyType = "KPW" - CurrencyTypeKrw CurrencyType = "KRW" - CurrencyTypeKwd CurrencyType = "KWD" - CurrencyTypeKyd CurrencyType = "KYD" - CurrencyTypeKzt CurrencyType = "KZT" - CurrencyTypeLak CurrencyType = "LAK" - CurrencyTypeLbp CurrencyType = "LBP" - CurrencyTypeLkr CurrencyType = "LKR" - CurrencyTypeLrd CurrencyType = "LRD" - CurrencyTypeLsl CurrencyType = "LSL" - CurrencyTypeLyd CurrencyType = "LYD" - CurrencyTypeMad CurrencyType = "MAD" - CurrencyTypeMdl CurrencyType = "MDL" - CurrencyTypeMga CurrencyType = "MGA" - CurrencyTypeMkd CurrencyType = "MKD" - CurrencyTypeMmk CurrencyType = "MMK" - CurrencyTypeMnt CurrencyType = "MNT" - CurrencyTypeMop CurrencyType = "MOP" - CurrencyTypeMro CurrencyType = "MRO" - CurrencyTypeMur CurrencyType = "MUR" - CurrencyTypeMvr CurrencyType = "MVR" - CurrencyTypeMwk CurrencyType = "MWK" - CurrencyTypeMxn CurrencyType = "MXN" - CurrencyTypeMxv CurrencyType = "MXV" - CurrencyTypeMyr CurrencyType = "MYR" - CurrencyTypeMzn CurrencyType = "MZN" - CurrencyTypeNad CurrencyType = "NAD" - CurrencyTypeNgn CurrencyType = "NGN" - CurrencyTypeNio CurrencyType = "NIO" - CurrencyTypeNok CurrencyType = "NOK" - CurrencyTypeNpr CurrencyType = "NPR" - CurrencyTypeNzd CurrencyType = "NZD" - CurrencyTypeOmr CurrencyType = "OMR" - CurrencyTypePab CurrencyType = "PAB" - CurrencyTypePen CurrencyType = "PEN" - CurrencyTypePgk CurrencyType = "PGK" - CurrencyTypePhp CurrencyType = "PHP" - CurrencyTypePkr CurrencyType = "PKR" - CurrencyTypePln CurrencyType = "PLN" - CurrencyTypePyg CurrencyType = "PYG" - CurrencyTypeQar CurrencyType = "QAR" - CurrencyTypeRon CurrencyType = "RON" - CurrencyTypeRsd CurrencyType = "RSD" - CurrencyTypeRub CurrencyType = "RUB" - CurrencyTypeRwf CurrencyType = "RWF" - CurrencyTypeSar CurrencyType = "SAR" - CurrencyTypeSbd CurrencyType = "SBD" - CurrencyTypeScr CurrencyType = "SCR" - CurrencyTypeSdg CurrencyType = "SDG" - CurrencyTypeSek CurrencyType = "SEK" - CurrencyTypeSgd CurrencyType = "SGD" - CurrencyTypeShp CurrencyType = "SHP" - CurrencyTypeSll CurrencyType = "SLL" - CurrencyTypeSos CurrencyType = "SOS" - CurrencyTypeSrd CurrencyType = "SRD" - CurrencyTypeSsp CurrencyType = "SSP" - CurrencyTypeStd CurrencyType = "STD" - CurrencyTypeSvc CurrencyType = "SVC" - CurrencyTypeSyp CurrencyType = "SYP" - CurrencyTypeSzl CurrencyType = "SZL" - CurrencyTypeThb CurrencyType = "THB" - CurrencyTypeTjs CurrencyType = "TJS" - CurrencyTypeTmt CurrencyType = "TMT" - CurrencyTypeTnd CurrencyType = "TND" - CurrencyTypeTop CurrencyType = "TOP" - CurrencyTypeTry CurrencyType = "TRY" - CurrencyTypeTtd CurrencyType = "TTD" - CurrencyTypeTwd CurrencyType = "TWD" - CurrencyTypeTzs CurrencyType = "TZS" - CurrencyTypeUah CurrencyType = "UAH" - CurrencyTypeUgx CurrencyType = "UGX" - CurrencyTypeUsd CurrencyType = "USD" - CurrencyTypeUsn CurrencyType = "USN" - CurrencyTypeUyi CurrencyType = "UYI" - CurrencyTypeUyu CurrencyType = "UYU" - CurrencyTypeUzs CurrencyType = "UZS" - CurrencyTypeVef CurrencyType = "VEF" - CurrencyTypeVnd CurrencyType = "VND" - CurrencyTypeVuv CurrencyType = "VUV" - CurrencyTypeWst CurrencyType = "WST" - CurrencyTypeXaf CurrencyType = "XAF" - CurrencyTypeXag CurrencyType = "XAG" - CurrencyTypeXau CurrencyType = "XAU" - CurrencyTypeXba CurrencyType = "XBA" - CurrencyTypeXbb CurrencyType = "XBB" - CurrencyTypeXbc CurrencyType = "XBC" - CurrencyTypeXbd CurrencyType = "XBD" - CurrencyTypeXcd CurrencyType = "XCD" - CurrencyTypeXdr CurrencyType = "XDR" - CurrencyTypeXof CurrencyType = "XOF" - CurrencyTypeXpd CurrencyType = "XPD" - CurrencyTypeXpf CurrencyType = "XPF" - CurrencyTypeXpt CurrencyType = "XPT" - CurrencyTypeXsu CurrencyType = "XSU" - CurrencyTypeXts CurrencyType = "XTS" - CurrencyTypeXua CurrencyType = "XUA" - CurrencyTypeXxx CurrencyType = "XXX" - CurrencyTypeYer CurrencyType = "YER" - CurrencyTypeZar CurrencyType = "ZAR" - CurrencyTypeZmw CurrencyType = "ZMW" - CurrencyTypeZwl CurrencyType = "ZWL" -) - -type AddressDeviceType string - -type AddressEntityType uint - -type AddressFeatureType uint - -type DeviceAddressType struct { - Device *AddressDeviceType `json:"device,omitempty"` -} - -type DeviceAddressElementsType struct { - Device *ElementTagType `json:"device,omitempty"` -} - -type EntityAddressType struct { - Device *AddressDeviceType `json:"device,omitempty"` - Entity []AddressEntityType `json:"entity,omitempty"` -} - -type EntityAddressElementsType struct { - Device *ElementTagType `json:"device,omitempty"` - Entity *ElementTagType `json:"entity,omitempty"` -} - -type FeatureAddressType struct { - Device *AddressDeviceType `json:"device,omitempty"` - Entity []AddressEntityType `json:"entity,omitempty"` - Feature *AddressFeatureType `json:"feature,omitempty"` -} - -type FeatureAddressElementsType struct { - Device *ElementTagType `json:"device,omitempty"` - Entity *ElementTagType `json:"entity,omitempty"` - Feature *ElementTagType `json:"feature,omitempty"` -} - -type ScopeTypeType string - -const ( - ScopeTypeTypeAC ScopeTypeType = "ac" - ScopeTypeTypeACCosPhiGrid ScopeTypeType = "acCosPhiGrid" - ScopeTypeTypeACCurrentA ScopeTypeType = "acCurrentA" - ScopeTypeTypeACCurrentB ScopeTypeType = "acCurrentB" - ScopeTypeTypeACCurrentC ScopeTypeType = "acCurrentC" - ScopeTypeTypeACFrequency ScopeTypeType = "acFrequency" - ScopeTypeTypeACFrequencyGrid ScopeTypeType = "acFrequencyGrid" - ScopeTypeTypeACPowerA ScopeTypeType = "acPowerA" - ScopeTypeTypeACPowerB ScopeTypeType = "acPowerB" - ScopeTypeTypeACPowerC ScopeTypeType = "acPowerC" - ScopeTypeTypeACPowerLimitPct ScopeTypeType = "acPowerLimitPct" - ScopeTypeTypeACPowerTotal ScopeTypeType = "acPowerTotal" - ScopeTypeTypeACVoltageA ScopeTypeType = "acVoltageA" - ScopeTypeTypeACVoltageB ScopeTypeType = "acVoltageB" - ScopeTypeTypeACVoltageC ScopeTypeType = "acVoltageC" - ScopeTypeTypeACYieldDay ScopeTypeType = "acYieldDay" - ScopeTypeTypeACYieldTotal ScopeTypeType = "acYieldTotal" - ScopeTypeTypeDCCurrent ScopeTypeType = "dcCurrent" - ScopeTypeTypeDCPower ScopeTypeType = "dcPower" - ScopeTypeTypeDCString1 ScopeTypeType = "dcString1" - ScopeTypeTypeDCString2 ScopeTypeType = "dcString2" - ScopeTypeTypeDCString3 ScopeTypeType = "dcString3" - ScopeTypeTypeDCString4 ScopeTypeType = "dcString4" - ScopeTypeTypeDCString5 ScopeTypeType = "dcString5" - ScopeTypeTypeDCString6 ScopeTypeType = "dcString6" - ScopeTypeTypeDCTotal ScopeTypeType = "dcTotal" - ScopeTypeTypeDCVoltage ScopeTypeType = "dcVoltage" - ScopeTypeTypeDhwTemperature ScopeTypeType = "dhwTemperature" - ScopeTypeTypeFlowTemperature ScopeTypeType = "flowTemperature" - ScopeTypeTypeOutsideAirTemperature ScopeTypeType = "outsideAirTemperature" - ScopeTypeTypeReturnTemperature ScopeTypeType = "returnTemperature" - ScopeTypeTypeRoomAirTemperature ScopeTypeType = "roomAirTemperature" - ScopeTypeTypeCharge ScopeTypeType = "charge" - ScopeTypeTypeStateOfCharge ScopeTypeType = "stateOfCharge" - ScopeTypeTypeDischarge ScopeTypeType = "discharge" - ScopeTypeTypeGridConsumption ScopeTypeType = "gridConsumption" - ScopeTypeTypeGridFeedIn ScopeTypeType = "gridFeedIn" - ScopeTypeTypeSelfConsumption ScopeTypeType = "selfConsumption" - ScopeTypeTypeOverloadProtection ScopeTypeType = "overloadProtection" - ScopeTypeTypeACPower ScopeTypeType = "acPower" - ScopeTypeTypeACEnergy ScopeTypeType = "acEnergy" - ScopeTypeTypeACCurrent ScopeTypeType = "acCurrent" - ScopeTypeTypeACVoltage ScopeTypeType = "acVoltage" - ScopeTypeTypeBatteryControl ScopeTypeType = "batteryControl" - ScopeTypeTypeSimpleIncentiveTable ScopeTypeType = "simpleIncentiveTable" -) - -type RoleType string - -const ( - RoleTypeClient RoleType = "client" - RoleTypeServer RoleType = "server" - RoleTypeSpecial RoleType = "special" -) - -type FeatureGroupType string - -type DeviceTypeType string - -const ( - DeviceTypeTypeDishwasher DeviceTypeType = "Dishwasher" - DeviceTypeTypeDryer DeviceTypeType = "Dryer" - DeviceTypeTypeEnvironmentSensor DeviceTypeType = "EnvironmentSensor" - DeviceTypeTypeGeneric DeviceTypeType = "Generic" - DeviceTypeTypeHeatgenerationSystem DeviceTypeType = "HeatGenerationSystem" - DeviceTypeTypeHeatsinkSystem DeviceTypeType = "HeatSinkSystem" - DeviceTypeTypeHeatstorageSystem DeviceTypeType = "HeatStorageSystem" - DeviceTypeTypeHVACController DeviceTypeType = "HVACController" - DeviceTypeTypeSubmeter DeviceTypeType = "SubMeter" - DeviceTypeTypeWasher DeviceTypeType = "Washer" - DeviceTypeTypeElectricitySupplySystem DeviceTypeType = "ElectricitySupplySystem" - DeviceTypeTypeEnergyManagementSystem DeviceTypeType = "EnergyManagementSystem" - DeviceTypeTypeInverter DeviceTypeType = "Inverter" - DeviceTypeTypeChargingStation DeviceTypeType = "ChargingStation" -) - -type EntityTypeType string - -const ( - EntityTypeTypeBattery EntityTypeType = "Battery" - EntityTypeTypeCompressor EntityTypeType = "Compressor" - EntityTypeTypeDeviceInformation EntityTypeType = "DeviceInformation" - EntityTypeTypeDHWCircuit EntityTypeType = "DHWCircuit" - EntityTypeTypeDHWStorage EntityTypeType = "DHWStorage" - EntityTypeTypeDishwasher EntityTypeType = "Dishwasher" - EntityTypeTypeDryer EntityTypeType = "Dryer" - EntityTypeTypeElectricalImmersionheater EntityTypeType = "ElectricalImmersionHeater" - EntityTypeTypeFan EntityTypeType = "Fan" - EntityTypeTypeGasHeatingAppliance EntityTypeType = "GasHeatingAppliance" - EntityTypeTypeGeneric EntityTypeType = "Generic" - EntityTypeTypeHeatingBufferStorage EntityTypeType = "HeatingBufferStorage" - EntityTypeTypeHeatingCircuit EntityTypeType = "HeatingCircuit" - EntityTypeTypeHeatingObject EntityTypeType = "HeatingObject" - EntityTypeTypeHeatingZone EntityTypeType = "HeatingZone" - EntityTypeTypeHeatPumpAppliance EntityTypeType = "HeatPumpAppliance" - EntityTypeTypeHeatSinkCircuit EntityTypeType = "HeatSinkCircuit" - EntityTypeTypeHeatSourceCircuit EntityTypeType = "HeatSourceCircuit" - EntityTypeTypeHeatSourceUnit EntityTypeType = "HeatSourceUnit" - EntityTypeTypeHvacController EntityTypeType = "HVACController" - EntityTypeTypeHvacRoom EntityTypeType = "HVACRoom" - EntityTypeTypeInstantDHWheater EntityTypeType = "InstantDHWHeater" - EntityTypeTypeInverter EntityTypeType = "Inverter" - EntityTypeTypeOilHeatingAppliance EntityTypeType = "OilHeatingAppliance" - EntityTypeTypePump EntityTypeType = "Pump" - EntityTypeTypeRefrigerantCircuit EntityTypeType = "RefrigerantCircuit" - EntityTypeTypeSmartEnergyAppliance EntityTypeType = "SmartEnergyAppliance" - EntityTypeTypeSolarDHWStorage EntityTypeType = "SolarDHWStorage" - EntityTypeTypeSolarThermalCircuit EntityTypeType = "SolarThermalCircuit" - EntityTypeTypeSubmeterElectricity EntityTypeType = "SubMeterElectricity" - EntityTypeTypeTemperatureSensor EntityTypeType = "TemperatureSensor" - EntityTypeTypeWasher EntityTypeType = "Washer" - EntityTypeTypeBatterySystem EntityTypeType = "BatterySystem" - EntityTypeTypeElectricityGenerationSystem EntityTypeType = "ElectricityGenerationSystem" - EntityTypeTypeElectricityStorageSystem EntityTypeType = "ElectricityStorageSystem" - EntityTypeTypeGridConnectionPointOfPremises EntityTypeType = "GridConnectionPointOfPremises" - EntityTypeTypeHousehold EntityTypeType = "Household" - EntityTypeTypePVSystem EntityTypeType = "PVSystem" - EntityTypeTypeEV EntityTypeType = "EV" - EntityTypeTypeEVSE EntityTypeType = "EVSE" - EntityTypeTypeChargingOutlet EntityTypeType = "ChargingOutlet" - EntityTypeTypeCEM EntityTypeType = "CEM" -) - -type FeatureTypeType string - -const ( - FeatureTypeTypeActuatorLevel FeatureTypeType = "ActuatorLevel" - FeatureTypeTypeActuatorSwitch FeatureTypeType = "ActuatorSwitch" - FeatureTypeTypeAlarm FeatureTypeType = "Alarm" - FeatureTypeTypeDataTunneling FeatureTypeType = "DataTunneling" - FeatureTypeTypeDeviceClassification FeatureTypeType = "DeviceClassification" - FeatureTypeTypeDeviceDiagnosis FeatureTypeType = "DeviceDiagnosis" - FeatureTypeTypeDirectControl FeatureTypeType = "DirectControl" - FeatureTypeTypeElectricalConnection FeatureTypeType = "ElectricalConnection" - FeatureTypeTypeGeneric FeatureTypeType = "Generic" - FeatureTypeTypeHvac FeatureTypeType = "HVAC" - FeatureTypeTypeLoadControl FeatureTypeType = "LoadControl" - FeatureTypeTypeMeasurement FeatureTypeType = "Measurement" - FeatureTypeTypeMessaging FeatureTypeType = "Messaging" - FeatureTypeTypeNetworkManagement FeatureTypeType = "NetworkManagement" - FeatureTypeTypeNodeManagement FeatureTypeType = "NodeManagement" - FeatureTypeTypeOperatingConstraints FeatureTypeType = "OperatingConstraints" - FeatureTypeTypePowerSequences FeatureTypeType = "PowerSequences" - FeatureTypeTypeSensing FeatureTypeType = "Sensing" - FeatureTypeTypeSetpoint FeatureTypeType = "Setpoint" - FeatureTypeTypeSmartEnergyManagementPs FeatureTypeType = "SmartEnergyManagementPs" - FeatureTypeTypeTaskManagement FeatureTypeType = "TaskManagement" - FeatureTypeTypeThreshold FeatureTypeType = "Threshold" - FeatureTypeTypeTimeInformation FeatureTypeType = "TimeInformation" - FeatureTypeTypeTimeTable FeatureTypeType = "TimeTable" - FeatureTypeTypeDeviceConfiguration FeatureTypeType = "DeviceConfiguration" - FeatureTypeTypeSupplyCondition FeatureTypeType = "SupplyCondition" - FeatureTypeTypeTimeSeries FeatureTypeType = "TimeSeries" - FeatureTypeTypeTariffInformation FeatureTypeType = "TariffInformation" - FeatureTypeTypeIncentiveTable FeatureTypeType = "IncentiveTable" - FeatureTypeTypeBill FeatureTypeType = "Bill" - FeatureTypeTypeIdentification FeatureTypeType = "Identification" -) - -type FeatureSpecificUsageType string - -const ( - // FeatureDirectControlSpecificUsageEnumType - FeatureSpecificUsageTypeHistory FeatureSpecificUsageType = "History" - FeatureSpecificUsageTypeRealtime FeatureSpecificUsageType = "RealTime" - - // FeatureHvacSpecificUsageEnumType - FeatureSpecificUsageTypeOperationmode FeatureSpecificUsageType = "OperationMode" - FeatureSpecificUsageTypeOverrun FeatureSpecificUsageType = "Overrun" - - // FeatureMeasurementSpecificUsageEnumType - FeatureSpecificUsageTypeContact FeatureSpecificUsageType = "Contact" - FeatureSpecificUsageTypeElectrical FeatureSpecificUsageType = "Electrical" - FeatureSpecificUsageTypeHeat FeatureSpecificUsageType = "Heat" - FeatureSpecificUsageTypeLevel FeatureSpecificUsageType = "Level" - FeatureSpecificUsageTypePressure FeatureSpecificUsageType = "Pressure" - FeatureSpecificUsageTypeTemperature FeatureSpecificUsageType = "Temperature" - - // FeatureSetpointSpecificUsageEnumType - - // FeatureSmartEnergyManagementPsSpecificUsageEnumType - FeatureSpecificUsageTypeFixedForecast FeatureSpecificUsageType = "FixedForecast" - FeatureSpecificUsageTypeFlexibleChosenForecast FeatureSpecificUsageType = "FlexibleChosenForecast" - FeatureSpecificUsageTypeFlexibleOptionalForecast FeatureSpecificUsageType = "FlexibleOptionalForecast" - FeatureSpecificUsageTypeOptionalSequenceBasedImmediateControl FeatureSpecificUsageType = "OptionalSequenceBasedImmediateControl" -) - -type FeatureDirectControlSpecificUsageEnumType string - -const ( - FeatureDirectControlSpecificUsageEnumTypeHistory FeatureDirectControlSpecificUsageEnumType = "History" - FeatureDirectControlSpecificUsageEnumTypeRealtime FeatureDirectControlSpecificUsageEnumType = "RealTime" -) - -type FeatureHvacSpecificUsageEnumType string - -const ( - FeatureHvacSpecificUsageEnumTypeOperationmode FeatureHvacSpecificUsageEnumType = "OperationMode" - FeatureHvacSpecificUsageEnumTypeOverrun FeatureHvacSpecificUsageEnumType = "Overrun" -) - -type FeatureMeasurementSpecificUsageEnumType string - -const ( - FeatureMeasurementSpecificUsageEnumTypeContact FeatureMeasurementSpecificUsageEnumType = "Contact" - FeatureMeasurementSpecificUsageEnumTypeElectrical FeatureMeasurementSpecificUsageEnumType = "Electrical" - FeatureMeasurementSpecificUsageEnumTypeHeat FeatureMeasurementSpecificUsageEnumType = "Heat" - FeatureMeasurementSpecificUsageEnumTypeLevel FeatureMeasurementSpecificUsageEnumType = "Level" - FeatureMeasurementSpecificUsageEnumTypePressure FeatureMeasurementSpecificUsageEnumType = "Pressure" - FeatureMeasurementSpecificUsageEnumTypeTemperature FeatureMeasurementSpecificUsageEnumType = "Temperature" -) - -type FeatureSetpointSpecificUsageEnumType string - -const ( - // FeatureMeasurementSpecificUsageEnumType - FeatureSetpointSpecificUsageEnumTypeContact FeatureSetpointSpecificUsageEnumType = "Contact" - FeatureSetpointSpecificUsageEnumTypeElectrical FeatureSetpointSpecificUsageEnumType = "Electrical" - FeatureSetpointSpecificUsageEnumTypeHeat FeatureSetpointSpecificUsageEnumType = "Heat" - FeatureSetpointSpecificUsageEnumTypeLevel FeatureSetpointSpecificUsageEnumType = "Level" - FeatureSetpointSpecificUsageEnumTypePressure FeatureSetpointSpecificUsageEnumType = "Pressure" - FeatureSetpointSpecificUsageEnumTypeTemperature FeatureSetpointSpecificUsageEnumType = "Temperature" -) - -type FeatureSmartEnergyManagementPsSpecificUsageEnumType string - -const ( - FeatureSmartEnergyManagementPsSpecificUsageEnumTypeFixedForecast FeatureSmartEnergyManagementPsSpecificUsageEnumType = "FixedForecast" - FeatureSmartEnergyManagementPsSpecificUsageEnumTypeFlexibleChosenForecast FeatureSmartEnergyManagementPsSpecificUsageEnumType = "FlexibleChosenForecast" - FeatureSmartEnergyManagementPsSpecificUsageEnumTypeFlexibleOptionalForecast FeatureSmartEnergyManagementPsSpecificUsageEnumType = "FlexibleOptionalForecast" - FeatureSmartEnergyManagementPsSpecificUsageEnumTypeOptionalSequenceBasedImmediateControl FeatureSmartEnergyManagementPsSpecificUsageEnumType = "OptionalSequenceBasedImmediateControl" -) - -type FunctionType string - -const ( - FunctionTypeActuatorLevelData FunctionType = "actuatorLevelData" - FunctionTypeActuatorLevelDescriptionData FunctionType = "actuatorLevelDescriptionData" - FunctionTypeActuatorSwitchData FunctionType = "actuatorSwitchData" - FunctionTypeActuatorSwitchDescriptionData FunctionType = "actuatorSwitchDescriptionData" - FunctionTypeAlarmListData FunctionType = "alarmListData" - FunctionTypeBindingManagementDeleteCall FunctionType = "bindingManagementDeleteCall" - FunctionTypeBindingManagementEntryListData FunctionType = "bindingManagementEntryListData" - FunctionTypeBindingManagementRequestCall FunctionType = "bindingManagementRequestCall" - FunctionTypeDataTunnelingCall FunctionType = "dataTunnelingCall" - FunctionTypeDeviceClassificationManufacturerData FunctionType = "deviceClassificationManufacturerData" - FunctionTypeDeviceClassificationUserData FunctionType = "deviceClassificationUserData" - FunctionTypeDeviceDiagnosisHeartbeatData FunctionType = "deviceDiagnosisHeartbeatData" - FunctionTypeDeviceDiagnosisServiceData FunctionType = "deviceDiagnosisServiceData" - FunctionTypeDeviceDiagnosisStateData FunctionType = "deviceDiagnosisStateData" - FunctionTypeDirectControlActivityListData FunctionType = "directControlActivityListData" - FunctionTypeDirectControlDescriptionData FunctionType = "directControlDescriptionData" - FunctionTypeElectricalConnectionDescriptionListData FunctionType = "electricalConnectionDescriptionListData" - FunctionTypeElectricalConnectionParameterDescriptionListData FunctionType = "electricalConnectionParameterDescriptionListData" - FunctionTypeElectricalConnectionStateListData FunctionType = "electricalConnectionStateListData" - FunctionTypeHvacOperationModeDescriptionListData FunctionType = "hvacOperationModeDescriptionListData" - FunctionTypeHvacOverrunDescriptionListData FunctionType = "hvacOverrunDescriptionListData" - FunctionTypeHvacOverrunListData FunctionType = "hvacOverrunListData" - FunctionTypeHvacSystemFunctionDescriptionListData FunctionType = "hvacSystemFunctionDescriptionListData" - FunctionTypeHvacSystemFunctionListData FunctionType = "hvacSystemFunctionListData" - FunctionTypeHvacSystemFunctionOperationModeRelationListData FunctionType = "hvacSystemFunctionOperationModeRelationListData" - FunctionTypeHvacSystemFunctionPowerSequenceRelationListData FunctionType = "hvacSystemFunctionPowerSequenceRelationListData" - FunctionTypeHvacSystemFunctionSetPointRelationListData FunctionType = "hvacSystemFunctionSetpointRelationListData" - FunctionTypeLoadControlEventListData FunctionType = "loadControlEventListData" - FunctionTypeLoadControlStateListData FunctionType = "loadControlStateListData" - FunctionTypeMeasurementConstraintsListData FunctionType = "measurementConstraintsListData" - FunctionTypeMeasurementDescriptionListData FunctionType = "measurementDescriptionListData" - FunctionTypeMeasurementListData FunctionType = "measurementListData" - FunctionTypeMeasurementThresholdRelationListData FunctionType = "measurementThresholdRelationListData" - FunctionTypeMessagingListData FunctionType = "messagingListData" - FunctionTypeNetworkManagementAbortCall FunctionType = "networkManagementAbortCall" - FunctionTypeNetworkManagementAddNodeCall FunctionType = "networkManagementAddNodeCall" - FunctionTypeNetworkManagementDeviceDescriptionListData FunctionType = "networkManagementDeviceDescriptionListData" - FunctionTypeNetworkManagementDiscoverCall FunctionType = "networkManagementDiscoverCall" - FunctionTypeNetworkManagementEntityDescriptionListData FunctionType = "networkManagementEntityDescriptionListData" - FunctionTypeNetworkManagementFeatureDescriptionListData FunctionType = "networkManagementFeatureDescriptionListData" - FunctionTypeNetworkManagementJoiningModeData FunctionType = "networkManagementJoiningModeData" - FunctionTypeNetworkManagementModifyNodeCall FunctionType = "networkManagementModifyNodeCall" - FunctionTypeNetworkManagementProcessStateData FunctionType = "networkManagementProcessStateData" - FunctionTypeNetworkManagementRemoveNodeCall FunctionType = "networkManagementRemoveNodeCall" - FunctionTypeNetworkManagementReportCandidateData FunctionType = "networkManagementReportCandidateData" - FunctionTypeNetworkManagementScanNetworkCall FunctionType = "networkManagementScanNetworkCall" - FunctionTypeNodeManagementBindingData FunctionType = "nodeManagementBindingData" - FunctionTypeNodeManagementBindingDeleteCall FunctionType = "nodeManagementBindingDeleteCall" - FunctionTypeNodeManagementBindingRequestCall FunctionType = "nodeManagementBindingRequestCall" - FunctionTypeNodeManagementDestinationListData FunctionType = "nodeManagementDestinationListData" - FunctionTypeNodeManagementDetailedDiscoveryData FunctionType = "nodeManagementDetailedDiscoveryData" - FunctionTypeNodeManagementSubscriptionData FunctionType = "nodeManagementSubscriptionData" - FunctionTypeNodeManagementSubscriptionDeleteCall FunctionType = "nodeManagementSubscriptionDeleteCall" - FunctionTypeNodeManagementSubscriptionRequestCall FunctionType = "nodeManagementSubscriptionRequestCall" - FunctionTypeOperatingConstraintsDurationListData FunctionType = "operatingConstraintsDurationListData" - FunctionTypeOperatingConstraintsInterruptListData FunctionType = "operatingConstraintsInterruptListData" - FunctionTypeOperatingConstraintsPowerDescriptionListData FunctionType = "operatingConstraintsPowerDescriptionListData" - FunctionTypeOperatingConstraintsPowerLevelListData FunctionType = "operatingConstraintsPowerLevelListData" - FunctionTypeOperatingConstraintsPowerRangeListData FunctionType = "operatingConstraintsPowerRangeListData" - FunctionTypeOperatingConstraintsResumeImplicationListData FunctionType = "operatingConstraintsResumeImplicationListData" - FunctionTypePowerSequenceAlternativesRelationListData FunctionType = "powerSequenceAlternativesRelationListData" - FunctionTypePowerSequenceDescriptionListData FunctionType = "powerSequenceDescriptionListData" - FunctionTypePowerSequenceNodeScheduleInformationData FunctionType = "powerSequenceNodeScheduleInformationData" - FunctionTypePowerSequencePriceCalculationRequestCall FunctionType = "powerSequencePriceCalculationRequestCall" - FunctionTypePowerSequencePriceListData FunctionType = "powerSequencePriceListData" - FunctionTypePowerSequenceScheduleConfigurationRequestCall FunctionType = "powerSequenceScheduleConfigurationRequestCall" - FunctionTypePowerSequenceScheduleConstraintsListData FunctionType = "powerSequenceScheduleConstraintsListData" - FunctionTypePowerSequenceScheduleListData FunctionType = "powerSequenceScheduleListData" - FunctionTypePowerSequenceSchedulePreferenceListData FunctionType = "powerSequenceSchedulePreferenceListData" - FunctionTypePowerSequenceStateListData FunctionType = "powerSequenceStateListData" - FunctionTypePowerTimeSlotScheduleConstraintsListData FunctionType = "powerTimeSlotScheduleConstraintsListData" - FunctionTypePowerTimeSlotScheduleListData FunctionType = "powerTimeSlotScheduleListData" - FunctionTypePowerTimeSlotValueListData FunctionType = "powerTimeSlotValueListData" - FunctionTypeResultData FunctionType = "resultData" - FunctionTypeSensingDescriptionData FunctionType = "sensingDescriptionData" - FunctionTypeSensingListData FunctionType = "sensingListData" - FunctionTypeSetpointConstraintsListData FunctionType = "setpointConstraintsListData" - FunctionTypeSetpointDescriptionListData FunctionType = "setpointDescriptionListData" - FunctionTypeSetpointListData FunctionType = "setpointListData" - FunctionTypeSmartEnergyManagementPsConfigurationRequestCall FunctionType = "smartEnergyManagementPsConfigurationRequestCall" - FunctionTypeSmartEnergyManagementPsData FunctionType = "smartEnergyManagementPsData" - FunctionTypeSmartEnergyManagementPsPriceCalculationRequestCall FunctionType = "smartEnergyManagementPsPriceCalculationRequestCall" - FunctionTypeSmartEnergyManagementPsPriceData FunctionType = "smartEnergyManagementPsPriceData" - FunctionTypeSpecificationVersionListData FunctionType = "specificationVersionListData" - FunctionTypeSubscriptionManagementDeleteCall FunctionType = "subscriptionManagementDeleteCall" - FunctionTypeSubscriptionManagementEntryListData FunctionType = "subscriptionManagementEntryListData" - FunctionTypeSubscriptionManagementRequestCall FunctionType = "subscriptionManagementRequestCall" - FunctionTypeSupplyConditionDescriptionListData FunctionType = "supplyConditionDescriptionListData" - FunctionTypeSupplyConditionListData FunctionType = "supplyConditionListData" - FunctionTypeSupplyConditionThresholdRelationListData FunctionType = "supplyConditionThresholdRelationListData" - FunctionTypeTaskManagementJobDescriptionListData FunctionType = "taskManagementJobDescriptionListData" - FunctionTypeTaskManagementJobListData FunctionType = "taskManagementJobListData" - FunctionTypeTaskManagementJobRelationListData FunctionType = "taskManagementJobRelationListData" - FunctionTypeTaskManagementOverviewData FunctionType = "taskManagementOverviewData" - FunctionTypeThresholdConstraintsListData FunctionType = "thresholdConstraintsListData" - FunctionTypeThresholdDescriptionListData FunctionType = "thresholdDescriptionListData" - FunctionTypeThresholdListData FunctionType = "thresholdListData" - FunctionTypeTimeDistributorData FunctionType = "timeDistributorData" - FunctionTypeTimeDistributorEnquiryCall FunctionType = "timeDistributorEnquiryCall" - FunctionTypeTimeInformationData FunctionType = "timeInformationData" - FunctionTypeTimePrecisionData FunctionType = "timePrecisionData" - FunctionTypeTimeTableConstraintsListData FunctionType = "timeTableConstraintsListData" - FunctionTypeTimeTableDescriptionListData FunctionType = "timeTableDescriptionListData" - FunctionTypeTimeTableListData FunctionType = "timeTableListData" - FunctionTypeDeviceConfigurationKeyValueConstraintsListData FunctionType = "deviceConfigurationKeyValueConstraintsListData" - FunctionTypeDeviceConfigurationKeyValueListData FunctionType = "deviceConfigurationKeyValueListData" - FunctionTypeDeviceConfigurationKeyValueDescriptionListData FunctionType = "deviceConfigurationKeyValueDescriptionListData" - FunctionTypeLoadControlLimitConstraintsListData FunctionType = "loadControlLimitConstraintsListData" - FunctionTypeLoadControlLimitDescriptionListData FunctionType = "loadControlLimitDescriptionListData" - FunctionTypeLoadControlLimitListData FunctionType = "loadControlLimitListData" - FunctionTypeLoadControlNodeData FunctionType = "loadControlNodeData" - FunctionTypeTimeSeriesConstraintsListData FunctionType = "timeSeriesConstraintsListData" - FunctionTypeTimeSeriesDescriptionListData FunctionType = "timeSeriesDescriptionListData" - FunctionTypeTimeSeriesListData FunctionType = "timeSeriesListData" - FunctionTypeTariffOverallConstraintsData FunctionType = "tariffOverallConstraintsData" - FunctionTypeTariffListData FunctionType = "tariffListData" - FunctionTypeTariffBoundaryRelationListData FunctionType = "tariffBoundaryRelationListData" - FunctionTypeTariffTierRelationListData FunctionType = "tariffTierRelationListData" - FunctionTypeTariffDescriptionListData FunctionType = "tariffDescriptionListData" - FunctionTypeTierBoundaryListData FunctionType = "tierBoundaryListData" - FunctionTypeTierBoundaryDescriptionListData FunctionType = "tierBoundaryDescriptionListData" - FunctionTypeCommodityListData FunctionType = "commodityListData" - FunctionTypeTierListData FunctionType = "tierListData" - FunctionTypeTierIncentiveRelationListData FunctionType = "tierIncentiveRelationListData" - FunctionTypeTierDescriptionListData FunctionType = "tierDescriptionListData" - FunctionTypeIncentiveListData FunctionType = "incentiveListData" - FunctionTypeIncentiveDescriptionListData FunctionType = "incentiveDescriptionListData" - FunctionTypeIncentiveTableData FunctionType = "incentiveTableData" - FunctionTypeIncentiveTableDescriptionData FunctionType = "incentiveTableDescriptionData" - FunctionTypeIncentiveTableConstraintsData FunctionType = "incentiveTableConstraintsData" - FunctionTypeElectricalConnectionPermittedValueSetListData FunctionType = "electricalConnectionPermittedValueSetListData" - FunctionTypeUseCaseInformationListData FunctionType = "useCaseInformationListData" - FunctionTypeNodeManagementUseCaseData FunctionType = "nodeManagementUseCaseData" - FunctionTypeBillConstraintsListData FunctionType = "billConstraintsListData" - FunctionTypeBillDescriptionListData FunctionType = "billDescriptionListData" - FunctionTypeBillListData FunctionType = "billListData" - FunctionTypeIdentificationListData FunctionType = "identificationListData" -) - -type PossibleOperationsClassifierType struct { - Partial *ElementTagType `json:"partial,omitempty"` -} - -type PossibleOperationsReadType struct { - Partial *ElementTagType `json:"partial,omitempty"` -} - -type PossibleOperationsWriteType struct { - Partial *ElementTagType `json:"partial,omitempty"` -} - -type PossibleOperationsType struct { - Read *PossibleOperationsReadType `json:"read,omitempty"` - Write *PossibleOperationsWriteType `json:"write,omitempty"` -} - -type PossibleOperationsElementsType struct { - Read *ElementTagType `json:"read,omitempty"` - Write *ElementTagType `json:"write,omitempty"` -} - -type FunctionPropertyType struct { - Function *FunctionType `json:"function,omitempty"` - PossibleOperations *PossibleOperationsType `json:"possibleOperations,omitempty"` -} - -type FunctionPropertyElementsType struct { - Function *ElementTagType `json:"function,omitempty"` - PossibleOperations *ElementTagType `json:"possibleOperations,omitempty"` -} diff --git a/spine/model/commondatatypes_additions.go b/spine/model/commondatatypes_additions.go deleted file mode 100644 index 3486dd47..00000000 --- a/spine/model/commondatatypes_additions.go +++ /dev/null @@ -1,228 +0,0 @@ -package model - -import ( - "errors" - "fmt" - "math" - "strconv" - "strings" - "time" - - "github.com/rickb777/date/period" -) - -// TimeType xs:time - -func NewTimeType(t string) *TimeType { - value := TimeType(t) - return &value -} - -func (s *TimeType) GetTime() (time.Time, error) { - allowedFormats := []string{ - "15:04:05.999999999", - "15:04:05.999999999Z", - "15:04:05", - "15:04:05Z", - "15:04:05+07:00", - "15:04:05-07:00", - } - - for _, format := range allowedFormats { - if value, err := time.Parse(format, string(*s)); err == nil { - return value, nil - } - } - - return time.Time{}, errors.New("unsupported time format") -} - -// DateType xs:date - -func NewDateType(t string) *DateType { - value := DateType(t) - return &value -} - -// 2001-10-26, 2001-10-26+02:00, 2001-10-26Z, 2001-10-26+00:00, -2001-10-26, or -20000-04-01 -func (d *DateType) GetTime() (time.Time, error) { - allowedFormats := []string{ - "2006-01-02", - "2006-01-02Z", - "2006-01-02+07:00", - } - - for _, format := range allowedFormats { - if value, err := time.Parse(format, string(*d)); err == nil { - return value, nil - } - } - - return time.Time{}, errors.New("unsupported date format") -} - -// DateTimeType xs:datetime - -func NewDateTimeType(t string) *DateTimeType { - value := DateTimeType(t) - return &value -} - -func NewDateTimeTypeFromTime(t time.Time) *DateTimeType { - s := t.Format(time.RFC3339) - return NewDateTimeType(s) -} - -func (d *DateTimeType) GetTime() (time.Time, error) { - allowedFormats := []string{ - "2006-01-02T15:04:05.999999999", - "2006-01-02T15:04:05.999999999Z", - "2006-01-02T15:04:05", - "2006-01-02T15:04:05Z", - "2006-01-02T15:04:05+07:00", - "2006-01-02T15:04:05-07:00", - time.RFC3339, - } - - for _, format := range allowedFormats { - if value, err := time.Parse(format, string(*d)); err == nil { - return value, nil - } - } - - return time.Time{}, errors.New("unsupported datetime format") -} - -// DurationType - -func NewDurationType(duration time.Duration) *DurationType { - d, _ := period.NewOf(duration) - value := DurationType(d.String()) - return &value -} - -func (d *DurationType) GetTimeDuration() (time.Duration, error) { - return getTimeDurationFromString(string(*d)) -} - -// helper for DurationType and AbsoluteOrRelativeTimeType -func getTimeDurationFromString(s string) (time.Duration, error) { - p, err := period.Parse(string(s)) - if err != nil { - return 0, err - } - - return p.DurationApprox(), nil -} - -// AbsoluteOrRelativeTimeType -// can be of type TimeType or DurationType - -func NewAbsoluteOrRelativeTimeType(s string) *AbsoluteOrRelativeTimeType { - value := AbsoluteOrRelativeTimeType(s) - return &value -} - -func NewAbsoluteOrRelativeTimeTypeFromDuration(t time.Duration) *AbsoluteOrRelativeTimeType { - s := NewDurationType(t) - value := AbsoluteOrRelativeTimeType(*s) - return &value -} - -func NewAbsoluteOrRelativeTimeTypeFromTime(t time.Time) *AbsoluteOrRelativeTimeType { - s := NewDateTimeTypeFromTime(t) - value := AbsoluteOrRelativeTimeType(*s) - return &value -} - -func (a *AbsoluteOrRelativeTimeType) GetDateTimeType() *DateTimeType { - value := NewDateTimeType(string(*a)) - return value -} - -func (a *AbsoluteOrRelativeTimeType) GetTime() (time.Time, error) { - value := NewDateTimeType(string(*a)) - t, err := value.GetTime() - if err != nil { - return time.Time{}, err - } - - return t, nil -} - -func (a *AbsoluteOrRelativeTimeType) GetDurationType() (*DurationType, error) { - value, err := a.GetTimeDuration() - if err != nil { - return nil, err - } - - return NewDurationType(value), nil -} - -func (a *AbsoluteOrRelativeTimeType) GetTimeDuration() (time.Duration, error) { - return getTimeDurationFromString(string(*a)) -} - -// ScaledNumberType - -func (m *ScaledNumberType) GetValue() float64 { - if m.Number == nil { - return 0 - } - var scale float64 = 0 - if m.Scale != nil { - scale = float64(*m.Scale) - } - return float64(*m.Number) * math.Pow(10, scale) -} - -func NewScaledNumberType(value float64) *ScaledNumberType { - m := &ScaledNumberType{} - - numberOfDecimals := 0 - temp := strconv.FormatFloat(value, 'f', -1, 64) - index := strings.IndexByte(temp, '.') - if index > -1 { - numberOfDecimals = len(temp) - index - 1 - } - - // We limit this to 4 digits for now - if numberOfDecimals > 4 { - numberOfDecimals = 4 - } - - numberValue := NumberType(math.Trunc(value * math.Pow(10, float64(numberOfDecimals)))) - m.Number = &numberValue - - if numberValue != 0 { - scaleValue := ScaleType(-numberOfDecimals) - m.Scale = &scaleValue - } - - return m -} - -// FeatureAddressType - -func (r *FeatureAddressType) String() string { - if r == nil { - return "" - } - - var result string = "" - if r.Device != nil { - result += string(*r.Device) - } - result += ":[" - for index, id := range r.Entity { - if index > 0 { - result += "," - } - result += fmt.Sprintf("%d", id) - } - result += "]:" - if r.Feature != nil { - result += fmt.Sprintf("%d", *r.Feature) - } - return result -} diff --git a/spine/model/commondatatypes_additions_test.go b/spine/model/commondatatypes_additions_test.go deleted file mode 100644 index b29efbf9..00000000 --- a/spine/model/commondatatypes_additions_test.go +++ /dev/null @@ -1,282 +0,0 @@ -package model - -import ( - "testing" - "time" -) - -func TestTimeType(t *testing.T) { - tc := []struct { - in string - parse string - }{ - {"21:32:52.12679", "15:04:05.999999999"}, - {"21:32:52.12679Z", "15:04:05.999999999Z"}, - {"21:32:52", "15:04:05"}, - {"19:32:52Z", "15:04:05Z"}, - {"19:32:52+07:00", "15:04:05+07:00"}, - {"19:32:52-07:00", "15:04:05-07:00"}, - } - - for _, tc := range tc { - got := NewTimeType(tc.in) - expect, err := time.Parse(tc.parse, tc.in) - if err != nil { - t.Errorf("Parsing failure with %s and parser %s: %s", tc.in, tc.parse, err) - continue - } - value, err := got.GetTime() - if err != nil { - t.Errorf("Test Failure with %s and parser %s: %s", tc.in, tc.parse, err) - continue - } - - if value.UTC() != expect.UTC() { - t.Errorf("Test failure for %s, expected %s and got %s", tc.in, value.String(), expect.String()) - } - } -} - -func TestDateType(t *testing.T) { - tc := []struct { - in string - parse string - }{ - {"2022-02-01", "2006-01-02"}, - {"2022-02-01Z", "2006-01-02Z"}, - {"2022-02-01+07:00", "2006-01-02+07:00"}, - } - - for _, tc := range tc { - got := NewDateType(tc.in) - expect, err := time.Parse(tc.parse, tc.in) - if err != nil { - t.Errorf("Parsing failure with %s and parser %s: %s", tc.in, tc.parse, err) - continue - } - value, err := got.GetTime() - if err != nil { - t.Errorf("Test Failure with %s and parser %s: %s", tc.in, tc.parse, err) - continue - } - - if value.UTC() != expect.UTC() { - t.Errorf("Test failure for %s, expected %s and got %s", tc.in, value.String(), expect.String()) - } - } -} - -func TestDateTimeType(t *testing.T) { - tc := []struct { - in string - parse string - }{ - {"2022-02-01T21:32:52.12679", "2006-01-02T15:04:05.999999999"}, - {"2022-02-01T21:32:52.12679Z", "2006-01-02T15:04:05.999999999Z"}, - {"2022-02-01T21:32:52", "2006-01-02T15:04:05"}, - {"2022-02-01T19:32:52Z", "2006-01-02T15:04:05Z"}, - {"2022-02-01T19:32:52+07:00", "2006-01-02T15:04:05+07:00"}, - {"2022-02-01T19:32:52-07:00", "2006-01-02T15:04:05-07:00"}, - } - - for _, tc := range tc { - got := NewDateTimeType(tc.in) - expect, err := time.Parse(tc.parse, tc.in) - if err != nil { - t.Errorf("Parsing failure with %s and parser %s: %s", tc.in, tc.parse, err) - continue - } - value, err := got.GetTime() - if err != nil { - t.Errorf("Test Failure with %s and parser %s: %s", tc.in, tc.parse, err) - continue - } - - if value.UTC() != expect.UTC() { - t.Errorf("Test failure for %s, expected %s and got %s", tc.in, value.String(), expect.String()) - } - } -} - -func TestDurationType(t *testing.T) { - tc := []struct { - in time.Duration - out string - }{ - {time.Duration(4) * time.Second, "PT4S"}, - } - - for _, tc := range tc { - duration := NewDurationType(tc.in) - got, err := duration.GetTimeDuration() - if err != nil { - t.Errorf("Test Failure with %s: %s", tc.in, err) - continue - } - if got != tc.in { - t.Errorf("Test failure for %d, got %d", tc.in, got) - } - if string(*duration) != tc.out { - t.Errorf("Test failure for %d, expected %s got %s", tc.in, tc.out, string(*duration)) - } - } -} - -func TestAbsoluteOrRelativeTimeTypeAbsolute(t *testing.T) { - tc := []struct { - in string - dateTime time.Time - }{ - {"2022-02-01T19:32:52Z", time.Date(2022, 02, 01, 19, 32, 52, 0, time.UTC)}, - } - - for _, tc := range tc { - a := NewAbsoluteOrRelativeTimeType(tc.in) - got, err := a.GetTime() - if err != nil { - t.Errorf("Test Failure with %s: %s", tc.in, err) - continue - } - if got != tc.dateTime { - t.Errorf("Test failure for %s, expected %s got %s", tc.in, tc.dateTime.String(), got.String()) - } - - d := a.GetDateTimeType() - got, err = d.GetTime() - if err != nil { - t.Errorf("Test Failure with %s: %s", tc.in, err) - continue - } - if got != tc.dateTime { - t.Errorf("Test failure for %s, expected %s got %s", tc.in, tc.dateTime.String(), got.String()) - } - } -} - -func TestAbsoluteOrRelativeTimeTypeDuration(t *testing.T) { - tc := []struct { - in time.Duration - out string - }{ - {time.Duration(4) * time.Second, "PT4S"}, - } - - for _, tc := range tc { - a := NewAbsoluteOrRelativeTimeTypeFromDuration(tc.in) - got, err := a.GetDurationType() - if err != nil { - t.Errorf("Test Failure with %d: %s", tc.in, err) - continue - } - if string(*got) != tc.out { - t.Errorf("Test failure for %d, expected %s got %s", tc.in, tc.out, string(*got)) - } - - d, err := a.GetTimeDuration() - if err != nil { - t.Errorf("Test Failure with %d: %s", tc.in, err) - continue - } - got = NewDurationType(d) - if string(*got) != tc.out { - t.Errorf("Test failure for %d, expected %s got %s", tc.in, tc.out, string(*got)) - } - } -} - -func TestAbsoluteOrRelativeTimeTypeRelative(t *testing.T) { - tc := []struct { - in string - out time.Duration - }{ - {"PT4S", time.Duration(4) * time.Second}, - } - - for _, tc := range tc { - a := NewAbsoluteOrRelativeTimeType(tc.in) - got, err := a.GetTimeDuration() - if err != nil { - t.Errorf("Test Failure with %s: %s", tc.in, err) - continue - } - if got != tc.out { - t.Errorf("Test failure for %s, expected %d got %d", tc.in, tc.out, got) - } - - d, err := a.GetDurationType() - if err != nil { - t.Errorf("Test Failure with %s: %s", tc.in, err) - continue - } - got, err = d.GetTimeDuration() - if err != nil { - t.Errorf("Test Failure with %s: %s", tc.in, err) - continue - } - if got != tc.out { - t.Errorf("Test failure for %s, expected %d got %d", tc.in, tc.out, got) - } - } -} - -func TestNewScaledNumberType(t *testing.T) { - tc := []struct { - in float64 - number int64 - scale int - }{ - {0, 0, 0}, - {0.1, 1, -1}, - {1.0, 1, 0}, - {6.25, 625, -2}, - {10, 10, 0}, - {12.5952, 125952, -4}, - {13.1637, 131637, -4}, - } - - for _, tc := range tc { - got := NewScaledNumberType(tc.in) - number := int64(*got.Number) - scale := 0 - if got.Scale != nil { - scale = int(*got.Scale) - } - if number != tc.number || scale != tc.scale { - t.Errorf("NewScaledNumberType(%v) = %d %d, want %d %d", tc.in, got.Number, got.Scale, tc.number, tc.scale) - } - - val := got.GetValue() - if val != tc.in { - t.Errorf("GetValue(%d %d) = %f, want %f", tc.number, tc.scale, val, tc.in) - } - } -} - -func TestFeatureAddressTypeString(t *testing.T) { - tc := []struct { - device AddressDeviceType - entity []AddressEntityType - feature AddressFeatureType - out string - }{ - { - "Device", - []AddressEntityType{1, 1}, - 0, - "Device:[1,1]:0", - }, - } - - for _, tc := range tc { - f := FeatureAddressType{ - Device: &tc.device, - Entity: tc.entity, - Feature: &tc.feature, - } - - got := f.String() - if got != tc.out { - t.Errorf("TestFeatureAddressTypeString(), got %s, expects %s", got, tc.out) - } - } -} diff --git a/spine/model/datagram.go b/spine/model/datagram.go deleted file mode 100644 index d51a9c7c..00000000 --- a/spine/model/datagram.go +++ /dev/null @@ -1,26 +0,0 @@ -package model - -type Datagram struct { - Datagram DatagramType `json:"datagram"` -} - -type DatagramType struct { - Header HeaderType `json:"header"` - Payload PayloadType `json:"payload"` -} - -type HeaderType struct { - SpecificationVersion *SpecificationVersionType `json:"specificationVersion,omitempty"` - AddressSource *FeatureAddressType `json:"addressSource,omitempty"` - AddressDestination *FeatureAddressType `json:"addressDestination,omitempty"` - AddressOriginator *FeatureAddressType `json:"addressOriginator,omitempty"` - MsgCounter *MsgCounterType `json:"msgCounter,omitempty"` - MsgCounterReference *MsgCounterType `json:"msgCounterReference,omitempty"` - CmdClassifier *CmdClassifierType `json:"cmdClassifier,omitempty"` - AckRequest *bool `json:"ackRequest,omitempty"` - Timestamp *AbsoluteOrRelativeTimeType `json:"timestamp,omitempty"` -} - -type PayloadType struct { - Cmd []CmdType `json:"cmd"` -} diff --git a/spine/model/datagram_additions.go b/spine/model/datagram_additions.go deleted file mode 100644 index f0d1080b..00000000 --- a/spine/model/datagram_additions.go +++ /dev/null @@ -1,42 +0,0 @@ -package model - -import ( - "fmt" -) - -func (d *DatagramType) PrintMessageOverview(send bool, localFeature, remoteFeature string) string { - var result string - - transmission := "Send" - device := "" - if d.Header.AddressDestination.Device != nil { - device = string(*d.Header.AddressDestination.Device) - } - if !send { - transmission = "Recv" - if d.Header.AddressSource.Device != nil { - device = string(*d.Header.AddressSource.Device) - } - device = fmt.Sprintf("%s:%s to %s", device, remoteFeature, localFeature) - } - - cmdClassifier := *d.Header.CmdClassifier - msgCounter := *d.Header.MsgCounter - cmd := d.Payload.Cmd[0] - - switch cmdClassifier { - case CmdClassifierTypeRead: - result = fmt.Sprintf("%s: %s %s %d %s", transmission, device, cmdClassifier, msgCounter, cmd.DataName()) - case CmdClassifierTypeReply: - msgCounterRef := *d.Header.MsgCounterReference - result = fmt.Sprintf("%s: %s %s %d %d %s", transmission, device, cmdClassifier, msgCounter, msgCounterRef, cmd.DataName()) - case CmdClassifierTypeResult: - msgCounterRef := *d.Header.MsgCounterReference - errorNumber := *d.Payload.Cmd[0].ResultData.ErrorNumber - result = fmt.Sprintf("%s: %s %s %d %d %s %d", transmission, device, cmdClassifier, msgCounter, msgCounterRef, cmd.DataName(), errorNumber) - default: - result = fmt.Sprintf("%s: %s %s %d %s", transmission, device, cmdClassifier, msgCounter, cmd.DataName()) - } - - return result -} diff --git a/spine/model/datagram_additions_test.go b/spine/model/datagram_additions_test.go deleted file mode 100644 index 249ad45b..00000000 --- a/spine/model/datagram_additions_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -func TestPrintMessageOverview_Read_Send(t *testing.T) { - datagram := &model.DatagramType{ - Header: model.HeaderType{ - AddressSource: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType("localdevice")), - }, - AddressDestination: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType("localdevice")), - }, - MsgCounter: util.Ptr(model.MsgCounterType(1)), - CmdClassifier: util.Ptr(model.CmdClassifierTypeRead), - }, - Payload: model.PayloadType{ - Cmd: []model.CmdType{ - {}, - }, - }, - } - - datagram.PrintMessageOverview(false, "", "") -} - -func TestPrintMessageOverview_Read_Recv(t *testing.T) { - datagram := &model.DatagramType{ - Header: model.HeaderType{ - AddressSource: &model.FeatureAddressType{}, - AddressDestination: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType("localdevice")), - }, - MsgCounter: util.Ptr(model.MsgCounterType(1)), - CmdClassifier: util.Ptr(model.CmdClassifierTypeRead), - }, - Payload: model.PayloadType{ - Cmd: []model.CmdType{ - {}, - }, - }, - } - - datagram.PrintMessageOverview(true, "", "") -} - -func TestPrintMessageOverview_Reply_Recv(t *testing.T) { - datagram := &model.DatagramType{ - Header: model.HeaderType{ - AddressSource: &model.FeatureAddressType{}, - AddressDestination: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType("localdevice")), - }, - MsgCounter: util.Ptr(model.MsgCounterType(1)), - MsgCounterReference: util.Ptr(model.MsgCounterType(1)), - CmdClassifier: util.Ptr(model.CmdClassifierTypeReply), - }, - Payload: model.PayloadType{ - Cmd: []model.CmdType{ - {}, - }, - }, - } - - datagram.PrintMessageOverview(true, "", "") -} - -func TestPrintMessageOverview_Result_Recv(t *testing.T) { - datagram := &model.DatagramType{ - Header: model.HeaderType{ - AddressSource: &model.FeatureAddressType{}, - AddressDestination: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType("localdevice")), - }, - MsgCounter: util.Ptr(model.MsgCounterType(1)), - MsgCounterReference: util.Ptr(model.MsgCounterType(1)), - CmdClassifier: util.Ptr(model.CmdClassifierTypeResult), - }, - Payload: model.PayloadType{ - Cmd: []model.CmdType{ - { - ResultData: &model.ResultDataType{ - ErrorNumber: util.Ptr(model.ErrorNumberType(1)), - }, - }, - }, - }, - } - - datagram.PrintMessageOverview(true, "", "") -} - -func TestPrintMessageOverview_Write_Recv(t *testing.T) { - datagram := &model.DatagramType{ - Header: model.HeaderType{ - AddressSource: &model.FeatureAddressType{}, - AddressDestination: &model.FeatureAddressType{ - Device: util.Ptr(model.AddressDeviceType("localdevice")), - }, - MsgCounter: util.Ptr(model.MsgCounterType(1)), - MsgCounterReference: util.Ptr(model.MsgCounterType(1)), - CmdClassifier: util.Ptr(model.CmdClassifierTypeWrite), - }, - Payload: model.PayloadType{ - Cmd: []model.CmdType{ - {}, - }, - }, - } - - datagram.PrintMessageOverview(true, "", "") -} diff --git a/spine/model/datatunneling.go b/spine/model/datatunneling.go deleted file mode 100644 index 7246c987..00000000 --- a/spine/model/datatunneling.go +++ /dev/null @@ -1,27 +0,0 @@ -package model - -type PurposeIdType string - -type ChannelIdType uint - -type DataTunnelingHeaderType struct { - PurposeId *PurposeIdType `json:"purposeId,omitempty"` - ChannelId *ChannelIdType `json:"channelId,omitempty"` - SequenceId *uint `json:"sequenceId,omitempty"` -} - -type DataTunnelingHeaderElementsType struct { - PurposeId *ElementTagType `json:"purposeId,omitempty"` - ChannelId *ElementTagType `json:"channelId,omitempty"` - SequenceId *ElementTagType `json:"sequenceId,omitempty"` -} - -type DataTunnelingCallType struct { - Header *DataTunnelingHeaderType `json:"header,omitempty"` - Payload *string `json:"payload,omitempty"` -} - -type DataTunnelingCallElementsType struct { - Header *DataTunnelingHeaderElementsType `json:"header,omitempty"` - Payload *ElementTagType `json:"payload,omitempty"` -} diff --git a/spine/model/deviceclassification.go b/spine/model/deviceclassification.go deleted file mode 100644 index 51e84274..00000000 --- a/spine/model/deviceclassification.go +++ /dev/null @@ -1,55 +0,0 @@ -package model - -type DeviceClassificationStringType string - -type PowerSourceType string - -const ( - PowerSourceTypeUnknown PowerSourceType = "unknown" - PowerSourceTypeMainssinglephase PowerSourceType = "mainsSinglePhase" - PowerSourceTypeMains3Phase PowerSourceType = "mains3Phase" - PowerSourceTypeBattery PowerSourceType = "battery" - PowerSourceTypeDc PowerSourceType = "dc" -) - -type DeviceClassificationManufacturerDataType struct { - DeviceName *DeviceClassificationStringType `json:"deviceName,omitempty"` - DeviceCode *DeviceClassificationStringType `json:"deviceCode,omitempty"` - SerialNumber *DeviceClassificationStringType `json:"serialNumber,omitempty"` - SoftwareRevision *DeviceClassificationStringType `json:"softwareRevision,omitempty"` - HardwareRevision *DeviceClassificationStringType `json:"hardwareRevision,omitempty"` - VendorName *DeviceClassificationStringType `json:"vendorName,omitempty"` - VendorCode *DeviceClassificationStringType `json:"vendorCode,omitempty"` - BrandName *DeviceClassificationStringType `json:"brandName,omitempty"` - PowerSource *PowerSourceType `json:"powerSource,omitempty"` - ManufacturerNodeIdentification *DeviceClassificationStringType `json:"manufacturerNodeIdentification,omitempty"` - ManufacturerLabel *LabelType `json:"manufacturerLabel,omitempty"` - ManufacturerDescription *DescriptionType `json:"manufacturerDescription,omitempty"` -} - -type DeviceClassificationManufacturerDataElementsType struct { - DeviceName *ElementTagType `json:"deviceName,omitempty"` - DeviceCode *ElementTagType `json:"deviceCode,omitempty"` - SerialNumber *ElementTagType `json:"serialNumber,omitempty"` - SoftwareRevision *ElementTagType `json:"softwareRevision,omitempty"` - HardwareRevision *ElementTagType `json:"hardwareRevision,omitempty"` - VendorName *ElementTagType `json:"vendorName,omitempty"` - VendorCode *ElementTagType `json:"vendorCode,omitempty"` - BrandName *ElementTagType `json:"brandName,omitempty"` - PowerSource *ElementTagType `json:"powerSource,omitempty"` - ManufacturerNodeIdentification *ElementTagType `json:"manufacturerNodeIdentification,omitempty"` - ManufacturerLabel *ElementTagType `json:"manufacturerLabel,omitempty"` - ManufacturerDescription *ElementTagType `json:"manufacturerDescription,omitempty"` -} - -type DeviceClassificationUserDataType struct { - UserNodeIdentification *DeviceClassificationStringType `json:"userNodeIdentification,omitempty"` - UserLabel *LabelType `json:"userLabel,omitempty"` - UserDescription *DescriptionType `json:"userDescription,omitempty"` -} - -type DeviceClassificationUserDataElementsType struct { - UserNodeIdentification *ElementTagType `json:"userNodeIdentification,omitempty"` - UserLabel *ElementTagType `json:"userLabel,omitempty"` - UserDescription *ElementTagType `json:"userDescription,omitempty"` -} diff --git a/spine/model/deviceconfiguration.go b/spine/model/deviceconfiguration.go deleted file mode 100644 index a0f87144..00000000 --- a/spine/model/deviceconfiguration.go +++ /dev/null @@ -1,115 +0,0 @@ -package model - -type DeviceConfigurationKeyIdType uint - -type DeviceConfigurationKeyValueStringType string - -type DeviceConfigurationKeyNameType string - -const ( - DeviceConfigurationKeyNameTypePeakPowerOfPVSystem DeviceConfigurationKeyNameType = "peakPowerOfPvSystem" - DeviceConfigurationKeyNameTypePvCurtailmentLimitFactor DeviceConfigurationKeyNameType = "pvCurtailmentLimitFactor" - DeviceConfigurationKeyNameTypeAsymmetricChargingSupported DeviceConfigurationKeyNameType = "asymmetricChargingSupported" - DeviceConfigurationKeyNameTypeCommunicationsStandard DeviceConfigurationKeyNameType = "communicationsStandard" -) - -type DeviceConfigurationKeyValueTypeType string - -const ( - DeviceConfigurationKeyValueTypeTypeBoolean DeviceConfigurationKeyValueTypeType = "boolean" - DeviceConfigurationKeyValueTypeTypeDate DeviceConfigurationKeyValueTypeType = "date" - DeviceConfigurationKeyValueTypeTypeDateTime DeviceConfigurationKeyValueTypeType = "dateTime" - DeviceConfigurationKeyValueTypeTypeDuration DeviceConfigurationKeyValueTypeType = "duration" - DeviceConfigurationKeyValueTypeTypeString DeviceConfigurationKeyValueTypeType = "string" - DeviceConfigurationKeyValueTypeTypeTime DeviceConfigurationKeyValueTypeType = "time" - DeviceConfigurationKeyValueTypeTypeScaledNumber DeviceConfigurationKeyValueTypeType = "scaledNumber" -) - -type DeviceConfigurationKeyValueValueType struct { - Boolean *bool `json:"boolean,omitempty"` - Date *DateType `json:"date,omitempty"` - DateTime *DateTimeType `json:"dateTime,omitempty"` - Duration *DurationType `json:"duration,omitempty"` - String *DeviceConfigurationKeyValueStringType `json:"string,omitempty"` - Time *TimeType `json:"time,omitempty"` - ScaledNumber *ScaledNumberType `json:"scaledNumber,omitempty"` -} - -type DeviceConfigurationKeyValueValueElementsType struct { - Boolean *ElementTagType `json:"boolean,omitempty"` - Date *ElementTagType `json:"date,omitempty"` - DateTime *ElementTagType `json:"dateTime,omitempty"` - Duration *ElementTagType `json:"duration,omitempty"` - String *ElementTagType `json:"string,omitempty"` - Time *ElementTagType `json:"time,omitempty"` - ScaledNumber *ScaledNumberElementsType `json:"scaledNumber,omitempty"` -} - -type DeviceConfigurationKeyValueDataType struct { - KeyId *DeviceConfigurationKeyIdType `json:"keyId,omitempty" eebus:"key"` - Value *DeviceConfigurationKeyValueValueType `json:"value,omitempty"` - IsValueChangeable *bool `json:"isValueChangeable,omitempty"` -} - -type DeviceConfigurationKeyValueDataElementsType struct { - KeyId *ElementTagType `json:"keyId,omitempty"` - Value *DeviceConfigurationKeyValueValueElementsType `json:"value,omitempty"` - IsValueChangeable *ElementTagType `json:"isValueChangeable,omitempty"` -} - -type DeviceConfigurationKeyValueListDataType struct { - DeviceConfigurationKeyValueData []DeviceConfigurationKeyValueDataType `json:"deviceConfigurationKeyValueData,omitempty"` -} - -type DeviceConfigurationKeyValueListDataSelectorsType struct { - KeyId *DeviceConfigurationKeyIdType `json:"keyId,omitempty"` -} - -type DeviceConfigurationKeyValueDescriptionDataType struct { - KeyId *DeviceConfigurationKeyIdType `json:"keyId,omitempty" eebus:"key"` - KeyName *DeviceConfigurationKeyNameType `json:"keyName,omitempty"` - ValueType *DeviceConfigurationKeyValueTypeType `json:"valueType,omitempty"` - Unit *UnitOfMeasurementType `json:"unit,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type DeviceConfigurationKeyValueDescriptionDataElementsType struct { - KeyId *ElementTagType `json:"keyId,omitempty"` - KeyName *ElementTagType `json:"keyName,omitempty"` - ValueType *ElementTagType `json:"valueType,omitempty"` - Unit *ElementTagType `json:"unit,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type DeviceConfigurationKeyValueDescriptionListDataType struct { - DeviceConfigurationKeyValueDescriptionData []DeviceConfigurationKeyValueDescriptionDataType `json:"deviceConfigurationKeyValueDescriptionData,omitempty"` -} - -type DeviceConfigurationKeyValueDescriptionListDataSelectorsType struct { - KeyId *DeviceConfigurationKeyIdType `json:"keyId,omitempty"` - KeyName *string `json:"keyName,omitempty"` -} - -type DeviceConfigurationKeyValueConstraintsDataType struct { - KeyId *DeviceConfigurationKeyIdType `json:"keyId,omitempty" eebus:"key"` - ValueRangeMin *DeviceConfigurationKeyValueValueType `json:"valueRangeMin,omitempty"` - ValueRangeMax *DeviceConfigurationKeyValueValueType `json:"valueRangeMax,omitempty"` - ValueStepSize *DeviceConfigurationKeyValueValueType `json:"valueStepSize,omitempty"` -} - -type DeviceConfigurationKeyValueConstraintsDataElementsType struct { - KeyId *ElementTagType `json:"keyId,omitempty"` - ValueRangeMin *DeviceConfigurationKeyValueValueElementsType `json:"valueRangeMin,omitempty"` - ValueRangeMax *DeviceConfigurationKeyValueValueElementsType `json:"valueRangeMax,omitempty"` - ValueStepSize *DeviceConfigurationKeyValueValueElementsType `json:"valueStepSize,omitempty"` -} - -type DeviceConfigurationKeyValueConstraintsListDataType struct { - DeviceConfigurationKeyValueConstraintsData []DeviceConfigurationKeyValueConstraintsDataType `json:"deviceConfigurationKeyValueConstraintsData,omitempty"` -} - -type DeviceConfigurationKeyValueConstraintsListDataSelectorsType struct { - KeyId *DeviceConfigurationKeyIdType `json:"keyId,omitempty"` -} diff --git a/spine/model/deviceconfiguration_additions.go b/spine/model/deviceconfiguration_additions.go deleted file mode 100644 index 07cc2475..00000000 --- a/spine/model/deviceconfiguration_additions.go +++ /dev/null @@ -1,40 +0,0 @@ -package model - -// DeviceConfigurationKeyValueListDataType - -var _ Updater = (*DeviceConfigurationKeyValueListDataType)(nil) - -func (r *DeviceConfigurationKeyValueListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []DeviceConfigurationKeyValueDataType - if newList != nil { - newData = newList.(*DeviceConfigurationKeyValueListDataType).DeviceConfigurationKeyValueData - } - - r.DeviceConfigurationKeyValueData = UpdateList(r.DeviceConfigurationKeyValueData, newData, filterPartial, filterDelete) -} - -// DeviceConfigurationKeyValueDescriptionListDataType - -var _ Updater = (*DeviceConfigurationKeyValueDescriptionListDataType)(nil) - -func (r *DeviceConfigurationKeyValueDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []DeviceConfigurationKeyValueDescriptionDataType - if newList != nil { - newData = newList.(*DeviceConfigurationKeyValueDescriptionListDataType).DeviceConfigurationKeyValueDescriptionData - } - - r.DeviceConfigurationKeyValueDescriptionData = UpdateList(r.DeviceConfigurationKeyValueDescriptionData, newData, filterPartial, filterDelete) -} - -// DeviceConfigurationKeyValueConstraintsListDataType - -var _ Updater = (*DeviceConfigurationKeyValueConstraintsListDataType)(nil) - -func (r *DeviceConfigurationKeyValueConstraintsListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []DeviceConfigurationKeyValueConstraintsDataType - if newList != nil { - newData = newList.(*DeviceConfigurationKeyValueConstraintsListDataType).DeviceConfigurationKeyValueConstraintsData - } - - r.DeviceConfigurationKeyValueConstraintsData = UpdateList(r.DeviceConfigurationKeyValueConstraintsData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/deviceconfiguration_additions_test.go b/spine/model/deviceconfiguration_additions_test.go deleted file mode 100644 index 020165d4..00000000 --- a/spine/model/deviceconfiguration_additions_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestDeviceConfigurationKeyValueListDataType_Update(t *testing.T) { - sut := model.DeviceConfigurationKeyValueListDataType{ - DeviceConfigurationKeyValueData: []model.DeviceConfigurationKeyValueDataType{ - { - KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(0)), - Value: &model.DeviceConfigurationKeyValueValueType{ - Boolean: util.Ptr(true), - }, - }, - { - KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)), - Value: &model.DeviceConfigurationKeyValueValueType{ - Boolean: util.Ptr(true), - }, - }, - }, - } - - newData := model.DeviceConfigurationKeyValueListDataType{ - DeviceConfigurationKeyValueData: []model.DeviceConfigurationKeyValueDataType{ - { - KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)), - Value: &model.DeviceConfigurationKeyValueValueType{ - Boolean: util.Ptr(false), - }, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.DeviceConfigurationKeyValueData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.KeyId)) - assert.Equal(t, true, *item1.Value.Boolean) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.KeyId)) - assert.Equal(t, false, *item2.Value.Boolean) -} - -func TestDeviceConfigurationKeyValueDescriptionListDataType_Update(t *testing.T) { - sut := model.DeviceConfigurationKeyValueDescriptionListDataType{ - DeviceConfigurationKeyValueDescriptionData: []model.DeviceConfigurationKeyValueDescriptionDataType{ - { - KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(0)), - ValueType: util.Ptr(model.DeviceConfigurationKeyValueTypeTypeBoolean), - }, - { - KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)), - ValueType: util.Ptr(model.DeviceConfigurationKeyValueTypeTypeBoolean), - }, - }, - } - - newData := model.DeviceConfigurationKeyValueDescriptionListDataType{ - DeviceConfigurationKeyValueDescriptionData: []model.DeviceConfigurationKeyValueDescriptionDataType{ - { - KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)), - ValueType: util.Ptr(model.DeviceConfigurationKeyValueTypeTypeString), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.DeviceConfigurationKeyValueDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.KeyId)) - assert.Equal(t, model.DeviceConfigurationKeyValueTypeTypeBoolean, *item1.ValueType) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.KeyId)) - assert.Equal(t, model.DeviceConfigurationKeyValueTypeTypeString, *item2.ValueType) -} - -func TestDeviceConfigurationKeyValueConstraintsListDataType_Update(t *testing.T) { - sut := model.DeviceConfigurationKeyValueConstraintsListDataType{ - DeviceConfigurationKeyValueConstraintsData: []model.DeviceConfigurationKeyValueConstraintsDataType{ - { - KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(0)), - ValueStepSize: &model.DeviceConfigurationKeyValueValueType{ - Boolean: util.Ptr(true), - }, - }, - { - KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)), - ValueStepSize: &model.DeviceConfigurationKeyValueValueType{ - Boolean: util.Ptr(true), - }, - }, - }, - } - - newData := model.DeviceConfigurationKeyValueConstraintsListDataType{ - DeviceConfigurationKeyValueConstraintsData: []model.DeviceConfigurationKeyValueConstraintsDataType{ - { - KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)), - ValueStepSize: &model.DeviceConfigurationKeyValueValueType{ - Boolean: util.Ptr(false), - }, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.DeviceConfigurationKeyValueConstraintsData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.KeyId)) - assert.Equal(t, true, *item1.ValueStepSize.Boolean) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.KeyId)) - assert.Equal(t, false, *item2.ValueStepSize.Boolean) -} diff --git a/spine/model/devicediagnosis.go b/spine/model/devicediagnosis.go deleted file mode 100644 index eb844fac..00000000 --- a/spine/model/devicediagnosis.go +++ /dev/null @@ -1,74 +0,0 @@ -package model - -type VendorStateCodeType string - -type LastErrorCodeType string - -type DeviceDiagnosisOperatingStateType string - -const ( - DeviceDiagnosisOperatingStateTypeNormalOperation DeviceDiagnosisOperatingStateType = "normalOperation" - DeviceDiagnosisOperatingStateTypeStandby DeviceDiagnosisOperatingStateType = "standby" - DeviceDiagnosisOperatingStateTypeFailure DeviceDiagnosisOperatingStateType = "failure" - DeviceDiagnosisOperatingStateTypeServiceNeeded DeviceDiagnosisOperatingStateType = "serviceNeeded" - DeviceDiagnosisOperatingStateTypeOverrideDetected DeviceDiagnosisOperatingStateType = "overrideDetected" - DeviceDiagnosisOperatingStateTypeInAlarm DeviceDiagnosisOperatingStateType = "inAlarm" - DeviceDiagnosisOperatingStateTypeNotReachable DeviceDiagnosisOperatingStateType = "notReachable" - DeviceDiagnosisOperatingStateTypeFinished DeviceDiagnosisOperatingStateType = "finished" -) - -type PowerSupplyConditionType string - -const ( - PowerSupplyConditionTypeGood PowerSupplyConditionType = "good" - PowerSupplyConditionTypeLow PowerSupplyConditionType = "low" - PowerSupplyConditionTypeCritical PowerSupplyConditionType = "critical" - PowerSupplyConditionTypeUnknown PowerSupplyConditionType = "unknown" - PowerSupplyConditionTypeError PowerSupplyConditionType = "error" -) - -type DeviceDiagnosisStateDataType struct { - Timestamp *string `json:"timestamp,omitempty"` - OperatingState *DeviceDiagnosisOperatingStateType `json:"operatingState,omitempty"` - VendorStateCode *VendorStateCodeType `json:"vendorStateCode,omitempty"` - LastErrorCode *LastErrorCodeType `json:"lastErrorCode,omitempty"` - UpTime *DurationType `json:"upTime,omitempty"` - TotalUpTime *DurationType `json:"totalUpTime,omitempty"` - PowerSupplyCondition *PowerSupplyConditionType `json:"powerSupplyCondition,omitempty"` -} - -type DeviceDiagnosisStateDataElementsType struct { - Timestamp *ElementTagType `json:"timestamp,omitempty"` - OperatingState *ElementTagType `json:"operatingState,omitempty"` - VendorStateCode *ElementTagType `json:"vendorStateCode,omitempty"` - LastErrorCode *ElementTagType `json:"lastErrorCode,omitempty"` - UpTime *ElementTagType `json:"upTime,omitempty"` - TotalUpTime *ElementTagType `json:"totalUpTime,omitempty"` - PowerSupplyCondition *ElementTagType `json:"powerSupplyCondition,omitempty"` -} - -type DeviceDiagnosisHeartbeatDataType struct { - Timestamp *string `json:"timestamp,omitempty"` - HeartbeatCounter *uint64 `json:"heartbeatCounter,omitempty"` - HeartbeatTimeout *DurationType `json:"heartbeatTimeout,omitempty"` -} - -type DeviceDiagnosisHeartbeatDataElementsType struct { - Timestamp *ElementTagType `json:"timestamp,omitempty"` - HeartbeatCounter *ElementTagType `json:"heartbeatCounter,omitempty"` - HeartbeatTimeout *ElementTagType `json:"heartbeatTimeout,omitempty"` -} - -type DeviceDiagnosisServiceDataType struct { - Timestamp *string `json:"timestamp,omitempty"` - InstallationTime *string `json:"installationTime,omitempty"` - BootCounter *uint64 `json:"bootCounter,omitempty"` - NextService *string `json:"nextService,omitempty"` -} - -type DeviceDiagnosisServiceDataElementsType struct { - Timestamp *ElementTagType `json:"timestamp,omitempty"` - InstallationTime *ElementTagType `json:"installationTime,omitempty"` - BootCounter *ElementTagType `json:"bootCounter,omitempty"` - NextService *ElementTagType `json:"nextService,omitempty"` -} diff --git a/spine/model/directcontrol.go b/spine/model/directcontrol.go deleted file mode 100644 index 47ab26f3..00000000 --- a/spine/model/directcontrol.go +++ /dev/null @@ -1,55 +0,0 @@ -package model - -type DirectControlActivityStateType string - -const ( - DirectControlActivityStateTypeRunning AlarmTypeType = "running" - DirectControlActivityStateTypePaused AlarmTypeType = "paused" - DirectControlActivityStateTypeInactive AlarmTypeType = "inactive" -) - -type DirectControlActivityDataType struct { - Timestamp *AbsoluteOrRelativeTimeType `json:"timestamp,omitempty"` - ActivityState *DirectControlActivityStateType `json:"activityState,omitempty"` - IsActivityStateChangeable *bool `json:"isActivityStateChangeable,omitempty"` - EnergyMode *EnergyModeType `json:"energyMode,omitempty"` - IsEnergyModeChangeable *bool `json:"isEnergyModeChangeable,omitempty"` - Power *ScaledNumberType `json:"power,omitempty"` - IsPowerChangeable *bool `json:"isPowerChangeable,omitempty"` - Energy *ScaledNumberType `json:"energy,omitempty"` - IsEnergyChangeable *bool `json:"isEnergyChangeable,omitempty"` - Sequence_id *PowerSequenceIdType `json:"sequence_id,omitempty"` -} - -type DirectControlActivityDataElementsType struct { - Timestamp *ElementTagType `json:"timestamp,omitempty"` - ActivityState *ElementTagType `json:"activityState,omitempty"` - IsActivityStateChangeable *ElementTagType `json:"isActivityStateChangeable,omitempty"` - EnergyMode *ElementTagType `json:"energyMode,omitempty"` - IsEnergyModeChangeable *ElementTagType `json:"isEnergyModeChangeable,omitempty"` - Power *ScaledNumberElementsType `json:"power,omitempty"` - IsPowerChangeable *ElementTagType `json:"isPowerChangeable,omitempty"` - Energy *ScaledNumberElementsType `json:"energy,omitempty"` - IsEnergyChangeable *ElementTagType `json:"isEnergyChangeable,omitempty"` - Sequence_id *ElementTagType `json:"sequence_id,omitempty"` -} - -type DirectControlActivityListDataType struct { - DirectControlActivityDataElements []DirectControlActivityDataType `json:"directControlActivityDataElements,omitempty"` -} - -type DirectControlActivityListDataSelectorsType struct { - TimestampInterval *TimestampIntervalType `json:"timestampInterval,omitempty"` -} - -type DirectControlDescriptionDataType struct { - PositiveEnergyDirection *EnergyDirectionType `json:"positiveEnergyDirection,omitempty"` - PowerUnit *UnitOfMeasurementType `json:"powerUnit,omitempty"` - EnergyUnit *UnitOfMeasurementType `json:"energyUnit,omitempty"` -} - -type DirectControlDescriptionDataElementsType struct { - PositiveEnergyDirection *ElementTagType `json:"positiveEnergyDirection,omitempty"` - PowerUnit *ElementTagType `json:"powerUnit,omitempty"` - EnergyUnit *ElementTagType `json:"energyUnit,omitempty"` -} diff --git a/spine/model/eebus_tags.go b/spine/model/eebus_tags.go deleted file mode 100644 index 8e9d4241..00000000 --- a/spine/model/eebus_tags.go +++ /dev/null @@ -1,46 +0,0 @@ -package model - -import ( - "reflect" - "strings" - - "github.com/enbility/eebus-go/logging" -) - -type EEBusTag string - -const ( - EEBusTagFunction EEBusTag = "fct" - EEBusTagType EEBusTag = "typ" - EEBusTagKey EEBusTag = "key" -) - -type EEBusTagTypeType string - -const ( - EEBusTagTypeTypeSelector EEBusTagTypeType = "selector" - EEbusTagTypeTypeElements EEBusTagTypeType = "elements" -) - -const EEBusTagName string = "eebus" - -func EEBusTags(field reflect.StructField) map[EEBusTag]string { - result := make(map[EEBusTag]string) - tags := field.Tag.Get(EEBusTagName) - if len(tags) == 0 { - return result - } - for _, tag := range strings.Split(tags, ",") { - pair := strings.Split(tag, ":") - if len(pair) == 1 { - // boolean tags like "key" - result[EEBusTag(pair[0])] = "true" - } else if len(pair) == 2 { - result[EEBusTag(pair[0])] = pair[1] - } else { - logging.Log.Errorf("error: malformatted eebus tag: '%s'", tags) - } - } - - return result -} diff --git a/spine/model/electricalconnection.go b/spine/model/electricalconnection.go deleted file mode 100644 index a0bbbddb..00000000 --- a/spine/model/electricalconnection.go +++ /dev/null @@ -1,177 +0,0 @@ -package model - -type ElectricalConnectionIdType uint - -type ElectricalConnectionParameterIdType uint - -type ElectricalConnectionMeasurandVariantType string - -const ( - ElectricalConnectionMeasurandVariantTypeAmplitude ElectricalConnectionMeasurandVariantType = "amplitude" - ElectricalConnectionMeasurandVariantTypeRms ElectricalConnectionMeasurandVariantType = "rms" - ElectricalConnectionMeasurandVariantTypeInstantaneous ElectricalConnectionMeasurandVariantType = "instantaneous" - ElectricalConnectionMeasurandVariantTypeAngle ElectricalConnectionMeasurandVariantType = "angle" - ElectricalConnectionMeasurandVariantTypeCosphi ElectricalConnectionMeasurandVariantType = "cosPhi" -) - -type ElectricalConnectionVoltageTypeType string - -const ( - ElectricalConnectionVoltageTypeTypeAc ElectricalConnectionVoltageTypeType = "ac" - ElectricalConnectionVoltageTypeTypeDc ElectricalConnectionVoltageTypeType = "dc" -) - -type ElectricalConnectionAcMeasurementTypeType string - -const ( - ElectricalConnectionAcMeasurementTypeTypeReal ElectricalConnectionAcMeasurementTypeType = "real" - ElectricalConnectionAcMeasurementTypeTypeReactive ElectricalConnectionAcMeasurementTypeType = "reactive" - ElectricalConnectionAcMeasurementTypeTypeApparent ElectricalConnectionAcMeasurementTypeType = "apparent" - ElectricalConnectionAcMeasurementTypeTypePhase ElectricalConnectionAcMeasurementTypeType = "phase" -) - -type ElectricalConnectionPhaseNameType string - -const ( - ElectricalConnectionPhaseNameTypeA ElectricalConnectionPhaseNameType = "a" - ElectricalConnectionPhaseNameTypeB ElectricalConnectionPhaseNameType = "b" - ElectricalConnectionPhaseNameTypeC ElectricalConnectionPhaseNameType = "c" - ElectricalConnectionPhaseNameTypeAb ElectricalConnectionPhaseNameType = "ab" - ElectricalConnectionPhaseNameTypeBc ElectricalConnectionPhaseNameType = "bc" - ElectricalConnectionPhaseNameTypeAc ElectricalConnectionPhaseNameType = "ac" - ElectricalConnectionPhaseNameTypeAbc ElectricalConnectionPhaseNameType = "abc" - ElectricalConnectionPhaseNameTypeNeutral ElectricalConnectionPhaseNameType = "neutral" - ElectricalConnectionPhaseNameTypeGround ElectricalConnectionPhaseNameType = "ground" - ElectricalConnectionPhaseNameTypeNone ElectricalConnectionPhaseNameType = "none" -) - -type ElectricalConnectionConnectionPointType string - -const ( - ElectricalConnectionConnectionPointTypeGrid ElectricalConnectionConnectionPointType = "grid" - ElectricalConnectionConnectionPointTypeHome ElectricalConnectionConnectionPointType = "home" - ElectricalConnectionConnectionPointTypePv ElectricalConnectionConnectionPointType = "pv" - ElectricalConnectionConnectionPointTypeSd ElectricalConnectionConnectionPointType = "sd" - ElectricalConnectionConnectionPointTypeOther ElectricalConnectionConnectionPointType = "other" -) - -type ElectricalConnectionParameterDescriptionDataType struct { - ElectricalConnectionId *ElectricalConnectionIdType `json:"electricalConnectionId,omitempty" eebus:"key"` - ParameterId *ElectricalConnectionParameterIdType `json:"parameterId,omitempty" eebus:"key"` - MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` - VoltageType *ElectricalConnectionVoltageTypeType `json:"voltageType,omitempty"` - AcMeasuredPhases *ElectricalConnectionPhaseNameType `json:"acMeasuredPhases,omitempty"` - AcMeasuredInReferenceTo *ElectricalConnectionPhaseNameType `json:"acMeasuredInReferenceTo,omitempty"` - AcMeasurementType *ElectricalConnectionAcMeasurementTypeType `json:"acMeasurementType,omitempty"` - AcMeasurementVariant *ElectricalConnectionMeasurandVariantType `json:"acMeasurementVariant,omitempty"` - AcMeasuredHarmonic *uint8 `json:"acMeasuredHarmonic,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type ElectricalConnectionParameterDescriptionDataElementsType struct { - ElectricalConnectionId *ElementTagType `json:"electricalConnectionId,omitempty"` - ParameterId *ElementTagType `json:"parameterId,omitempty"` - MeasurementId *ElementTagType `json:"measurementId,omitempty"` - VoltageType *ElementTagType `json:"voltageType,omitempty"` - AcMeasuredPhases *ElementTagType `json:"acMeasuredPhases,omitempty"` - AcMeasuredInReferenceTo *ElementTagType `json:"acMeasuredInReferenceTo,omitempty"` - AcMeasurementType *ElementTagType `json:"acMeasurementType,omitempty"` - AcMeasurementVariant *ElementTagType `json:"acMeasurementVariant,omitempty"` - AcMeasuredHarmonic *ElementTagType `json:"acMeasuredHarmonic,omitempty"` - ScopeType *ElementTagType `json:"scopeType,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type ElectricalConnectionParameterDescriptionListDataType struct { - ElectricalConnectionParameterDescriptionData []ElectricalConnectionParameterDescriptionDataType `json:"electricalConnectionParameterDescriptionData,omitempty"` -} - -type ElectricalConnectionParameterDescriptionListDataSelectorsType struct { - ElectricalConnectionId *ElectricalConnectionIdType `json:"electricalConnectionId,omitempty"` - ParameterId *ElectricalConnectionParameterIdType `json:"parameterId,omitempty"` - MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` -} - -type ElectricalConnectionPermittedValueSetDataType struct { - ElectricalConnectionId *ElectricalConnectionIdType `json:"electricalConnectionId,omitempty" eebus:"key"` - ParameterId *ElectricalConnectionParameterIdType `json:"parameterId,omitempty" eebus:"key"` - PermittedValueSet []ScaledNumberSetType `json:"permittedValueSet,omitempty"` -} - -type ElectricalConnectionPermittedValueSetDataElementsType struct { - ElectricalConnectionId *ElementTagType `json:"electricalConnectionId,omitempty"` - ParameterId *ElementTagType `json:"parameterId,omitempty"` - PermittedValueSet *ElementTagType `json:"permittedValueSet,omitempty"` -} - -type ElectricalConnectionPermittedValueSetListDataType struct { - ElectricalConnectionPermittedValueSetData []ElectricalConnectionPermittedValueSetDataType `json:"electricalConnectionPermittedValueSetData,omitempty"` -} - -type ElectricalConnectionPermittedValueSetListDataSelectorsType struct { - ElectricalConnectionId *ElectricalConnectionIdType `json:"electricalConnectionId,omitempty"` - ParameterId *ElectricalConnectionParameterIdType `json:"parameterId,omitempty"` -} - -type ElectricalConnectionStateDataType struct { - ElectricalConnectionId *ElectricalConnectionIdType `json:"electricalConnectionId,omitempty" eebus:"key"` - Timestamp *AbsoluteOrRelativeTimeType `json:"timestamp,omitempty"` - CurrentEnergyMode *EnergyModeType `json:"currentEnergyMode,omitempty"` - ConsumptionTime *DurationType `json:"consumptionTime,omitempty"` - ProductionTime *DurationType `json:"productionTime,omitempty"` - TotalConsumptionTime *DurationType `json:"totalConsumptionTime,omitempty"` - TotalProductionTime *DurationType `json:"totalProductionTime,omitempty"` -} - -type ElectricalConnectionStateDataElementsType struct { - ElectricalConnectionId *ElementTagType `json:"electricalConnectionId,omitempty"` - Timestamp *ElementTagType `json:"timestamp,omitempty"` - CurrentEnergyMode *ElementTagType `json:"currentEnergyMode,omitempty"` - ConsumptionTime *ElementTagType `json:"consumptionTime,omitempty"` - ProductionTime *ElementTagType `json:"productionTime,omitempty"` - TotalConsumptionTime *ElementTagType `json:"totalConsumptionTime,omitempty"` - TotalProductionTime *ElementTagType `json:"totalProductionTime,omitempty"` -} - -type ElectricalConnectionStateListDataType struct { - ElectricalConnectionStateData []ElectricalConnectionStateDataType `json:"electricalConnectionStateData,omitempty"` -} - -type ElectricalConnectionStateListDataSelectorsType struct { - ElectricalConnectionId *ElectricalConnectionIdType `json:"electricalConnectionId,omitempty"` -} - -type ElectricalConnectionDescriptionDataType struct { - ElectricalConnectionId *ElectricalConnectionIdType `json:"electricalConnectionId,omitempty" eebus:"key"` - PowerSupplyType *ElectricalConnectionVoltageTypeType `json:"powerSupplyType,omitempty"` - AcConnectedPhases *uint `json:"acConnectedPhases,omitempty"` - AcRmsPeriodDuration *DurationType `json:"acRmsPeriodDuration,omitempty"` - PositiveEnergyDirection *EnergyDirectionType `json:"positiveEnergyDirection,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type ElectricalConnectionDescriptionDataElementsType struct { - ElectricalConnectionId *ElementTagType `json:"electricalConnectionId,omitempty"` - PowerSupplyType *ElementTagType `json:"powerSupplyType,omitempty"` - AcConnectedPhases *ElementTagType `json:"acConnectedPhases,omitempty"` - AcRmsPeriodDuration *ElementTagType `json:"acRmsPeriodDuration,omitempty"` - PositiveEnergyDirection *ElementTagType `json:"positiveEnergyDirection,omitempty"` - ScopeType *ElementTagType `json:"scopeType,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type ElectricalConnectionDescriptionListDataType struct { - ElectricalConnectionDescriptionData []ElectricalConnectionDescriptionDataType `json:"electricalConnectionDescriptionData,omitempty"` -} - -type ElectricalConnectionDescriptionListDataSelectorsType struct { - ElectricalConnectionId *ElectricalConnectionIdType `json:"electricalConnectionId,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` -} diff --git a/spine/model/electricalconnection_additions.go b/spine/model/electricalconnection_additions.go deleted file mode 100644 index 4db12443..00000000 --- a/spine/model/electricalconnection_additions.go +++ /dev/null @@ -1,53 +0,0 @@ -package model - -// ElectricalConnectionStateListDataType - -var _ Updater = (*ElectricalConnectionStateListDataType)(nil) - -func (r *ElectricalConnectionStateListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []ElectricalConnectionStateDataType - if newList != nil { - newData = newList.(*ElectricalConnectionStateListDataType).ElectricalConnectionStateData - } - - r.ElectricalConnectionStateData = UpdateList(r.ElectricalConnectionStateData, newData, filterPartial, filterDelete) -} - -// ElectricalConnectionPermittedValueSetListDataType - -var _ Updater = (*ElectricalConnectionPermittedValueSetListDataType)(nil) - -func (r *ElectricalConnectionPermittedValueSetListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []ElectricalConnectionPermittedValueSetDataType - if newList != nil { - newData = newList.(*ElectricalConnectionPermittedValueSetListDataType).ElectricalConnectionPermittedValueSetData - } - - r.ElectricalConnectionPermittedValueSetData = UpdateList(r.ElectricalConnectionPermittedValueSetData, newData, filterPartial, filterDelete) -} - -// ElectricalConnectionDescriptionListDataType - -var _ Updater = (*ElectricalConnectionDescriptionListDataType)(nil) - -func (r *ElectricalConnectionDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []ElectricalConnectionDescriptionDataType - if newList != nil { - newData = newList.(*ElectricalConnectionDescriptionListDataType).ElectricalConnectionDescriptionData - } - - r.ElectricalConnectionDescriptionData = UpdateList(r.ElectricalConnectionDescriptionData, newData, filterPartial, filterDelete) -} - -// ElectricalConnectionParameterDescriptionListDataType - -var _ Updater = (*ElectricalConnectionParameterDescriptionListDataType)(nil) - -func (r *ElectricalConnectionParameterDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []ElectricalConnectionParameterDescriptionDataType - if newList != nil { - newData = newList.(*ElectricalConnectionParameterDescriptionListDataType).ElectricalConnectionParameterDescriptionData - } - - r.ElectricalConnectionParameterDescriptionData = UpdateList(r.ElectricalConnectionParameterDescriptionData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/electricalconnection_additions_test.go b/spine/model/electricalconnection_additions_test.go deleted file mode 100644 index bb533973..00000000 --- a/spine/model/electricalconnection_additions_test.go +++ /dev/null @@ -1,1189 +0,0 @@ -package model_test - -import ( - "encoding/json" - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestElectricalConnectionStateListDataType_Update(t *testing.T) { - sut := model.ElectricalConnectionStateListDataType{ - ElectricalConnectionStateData: []model.ElectricalConnectionStateDataType{ - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), - CurrentEnergyMode: util.Ptr(model.EnergyModeTypeProduce), - }, - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(1)), - CurrentEnergyMode: util.Ptr(model.EnergyModeTypeProduce), - }, - }, - } - - newData := model.ElectricalConnectionStateListDataType{ - ElectricalConnectionStateData: []model.ElectricalConnectionStateDataType{ - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(1)), - CurrentEnergyMode: util.Ptr(model.EnergyModeTypeConsume), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.ElectricalConnectionStateData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.ElectricalConnectionId)) - assert.Equal(t, model.EnergyModeTypeProduce, *item1.CurrentEnergyMode) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.ElectricalConnectionId)) - assert.Equal(t, model.EnergyModeTypeConsume, *item2.CurrentEnergyMode) -} - -// verifies that a subset of existing items will be updated with identified new values -func TestElectricalConnectionPermittedValueSetListDataType_Update_Modify(t *testing.T) { - sut := model.ElectricalConnectionPermittedValueSetListDataType{ - ElectricalConnectionPermittedValueSetData: []model.ElectricalConnectionPermittedValueSetDataType{ - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), - ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(0)), - PermittedValueSet: []model.ScaledNumberSetType{ - { - Range: []model.ScaledNumberRangeType{ - { - Min: model.NewScaledNumberType(1), - }, - }, - }, - }, - }, - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), - ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(1)), - PermittedValueSet: []model.ScaledNumberSetType{ - { - Range: []model.ScaledNumberRangeType{ - { - Min: model.NewScaledNumberType(6), - Max: model.NewScaledNumberType(16), - }, - }, - }, - }, - }, - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), - ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(2)), - PermittedValueSet: []model.ScaledNumberSetType{ - { - Range: []model.ScaledNumberRangeType{ - { - Min: model.NewScaledNumberType(6), - Max: model.NewScaledNumberType(16), - }, - }, - }, - }, - }, - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), - ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(3)), - PermittedValueSet: []model.ScaledNumberSetType{ - { - Range: []model.ScaledNumberRangeType{ - { - Min: model.NewScaledNumberType(6), - Max: model.NewScaledNumberType(16), - }, - }, - }, - }, - }, - }, - } - - newData := model.ElectricalConnectionPermittedValueSetListDataType{ - ElectricalConnectionPermittedValueSetData: []model.ElectricalConnectionPermittedValueSetDataType{ - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), - ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(1)), - PermittedValueSet: []model.ScaledNumberSetType{ - { - Range: []model.ScaledNumberRangeType{ - { - Min: model.NewScaledNumberType(2), - Max: model.NewScaledNumberType(16), - }, - }, - }, - }, - }, - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), - ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(2)), - PermittedValueSet: []model.ScaledNumberSetType{ - { - Range: []model.ScaledNumberRangeType{ - { - Min: model.NewScaledNumberType(2), - Max: model.NewScaledNumberType(16), - }, - }, - }, - }, - }, - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), - ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(3)), - PermittedValueSet: []model.ScaledNumberSetType{ - { - Range: []model.ScaledNumberRangeType{ - { - Min: model.NewScaledNumberType(2), - Max: model.NewScaledNumberType(16), - }, - }, - }, - }, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.ElectricalConnectionPermittedValueSetData - // check the non changing items - assert.Equal(t, 4, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.ElectricalConnectionId)) - assert.Equal(t, 0, int(*item1.ParameterId)) - assert.Equal(t, 1, len(item1.PermittedValueSet)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 0, int(*item2.ElectricalConnectionId)) - assert.Equal(t, 1, int(*item2.ParameterId)) - assert.Equal(t, 1, len(item2.PermittedValueSet)) - valueSet := item2.PermittedValueSet[0] - assert.Equal(t, 1, len(valueSet.Range)) - rangeSet := valueSet.Range[0] - assert.Equal(t, 2.0, rangeSet.Min.GetValue()) - assert.Equal(t, 16.0, rangeSet.Max.GetValue()) -} - -// verifies that a subset of existing items will be updated with identified new values -func TestElectricalConnectionPermittedValueSetListDataType_Update_Modify_Selector(t *testing.T) { - existingDataJson := `{ - "electricalConnectionPermittedValueSetData":[ - { - "electricalConnectionId":0, - "parameterId":0, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":1,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":1, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":2, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":3, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - } - ] - }` - - var sut model.ElectricalConnectionPermittedValueSetListDataType - err := json.Unmarshal([]byte(existingDataJson), &sut) - if assert.Nil(t, err) == false { - return - } - - newDataJson := `{ - "electricalConnectionPermittedValueSetData":[ - { - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":2,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - } - ] - }` - - var newData model.ElectricalConnectionPermittedValueSetListDataType - err = json.Unmarshal([]byte(newDataJson), &newData) - if assert.Nil(t, err) == false { - return - } - - partial := &model.FilterType{ - CmdControl: &model.CmdControlType{ - Partial: &model.ElementTagType{}, - }, - ElectricalConnectionPermittedValueSetListDataSelectors: &model.ElectricalConnectionPermittedValueSetListDataSelectorsType{ - ElectricalConnectionId: util.Ptr[model.ElectricalConnectionIdType](0), - ParameterId: util.Ptr[model.ElectricalConnectionParameterIdType](1), - }, - } - - // Act - sut.UpdateList(&newData, partial, nil) - - data := sut.ElectricalConnectionPermittedValueSetData - // check the non changing items - assert.Equal(t, 4, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.ElectricalConnectionId)) - assert.Equal(t, 0, int(*item1.ParameterId)) - assert.Equal(t, 1, len(item1.PermittedValueSet)) - item3 := data[2] - assert.Equal(t, 0, int(*item3.ElectricalConnectionId)) - assert.Equal(t, 2, int(*item3.ParameterId)) - assert.Equal(t, 1, len(item3.PermittedValueSet)) - valueSet := item3.PermittedValueSet[0] - assert.Equal(t, 1, len(valueSet.Range)) - rangeSet := valueSet.Range[0] - assert.Equal(t, 6.0, rangeSet.Min.GetValue()) - assert.Equal(t, 16.0, rangeSet.Max.GetValue()) - - // check properties of updated item - item2 := sut.ElectricalConnectionPermittedValueSetData[1] - assert.Equal(t, 0, int(*item2.ElectricalConnectionId)) - assert.Equal(t, 1, int(*item2.ParameterId)) - assert.Equal(t, 1, len(item2.PermittedValueSet)) - valueSet = item2.PermittedValueSet[0] - assert.Equal(t, 1, len(valueSet.Range)) - rangeSet = valueSet.Range[0] - assert.Equal(t, 2.0, rangeSet.Min.GetValue()) - assert.Equal(t, 16.0, rangeSet.Max.GetValue()) -} - -// verifies that a subset of existing items will be updated with identified new values -func TestElectricalConnectionPermittedValueSetListDataType_Update_Delete_Modify(t *testing.T) { - existingDataJson := `{ - "electricalConnectionPermittedValueSetData":[ - { - "electricalConnectionId":0, - "parameterId":0, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":1,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":1, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":2, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":3, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - } - ] - }` - - var sut model.ElectricalConnectionPermittedValueSetListDataType - err := json.Unmarshal([]byte(existingDataJson), &sut) - if assert.Nil(t, err) == false { - return - } - - newDataJson := `{ - "electricalConnectionPermittedValueSetData":[ - { - "electricalConnectionId":0, - "parameterId":1, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":2,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":2, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":2,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":3, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":2,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - } - ] - }` - - var newData model.ElectricalConnectionPermittedValueSetListDataType - err = json.Unmarshal([]byte(newDataJson), &newData) - if assert.Nil(t, err) == false { - return - } - - delete := &model.FilterType{ - CmdControl: &model.CmdControlType{ - Delete: &model.ElementTagType{}, - }, - ElectricalConnectionPermittedValueSetListDataSelectors: &model.ElectricalConnectionPermittedValueSetListDataSelectorsType{ - ElectricalConnectionId: util.Ptr[model.ElectricalConnectionIdType](0), - ParameterId: util.Ptr[model.ElectricalConnectionParameterIdType](0), - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), delete) - - data := sut.ElectricalConnectionPermittedValueSetData - // check the deleted item is gone - assert.Equal(t, 3, len(data)) - // check properties of updated item - item1 := data[0] - assert.Equal(t, 0, int(*item1.ElectricalConnectionId)) - assert.Equal(t, 1, int(*item1.ParameterId)) - assert.Equal(t, 1, len(item1.PermittedValueSet)) - valueSet := item1.PermittedValueSet[0] - assert.Equal(t, 1, len(valueSet.Range)) - rangeSet := valueSet.Range[0] - assert.Equal(t, 2.0, rangeSet.Min.GetValue()) - assert.Equal(t, 16.0, rangeSet.Max.GetValue()) -} - -// verifies that a subset of existing items will be updated with identified new values -func TestElectricalConnectionPermittedValueSetListDataType_Update_Delete(t *testing.T) { - existingDataJson := `{ - "electricalConnectionPermittedValueSetData":[ - { - "electricalConnectionId":0, - "parameterId":0, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":1,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":1, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":2, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":3, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - } - ] - }` - - var sut model.ElectricalConnectionPermittedValueSetListDataType - err := json.Unmarshal([]byte(existingDataJson), &sut) - if assert.Nil(t, err) == false { - return - } - - delete := &model.FilterType{ - CmdControl: &model.CmdControlType{ - Delete: &model.ElementTagType{}, - }, - ElectricalConnectionPermittedValueSetListDataSelectors: &model.ElectricalConnectionPermittedValueSetListDataSelectorsType{ - ElectricalConnectionId: util.Ptr[model.ElectricalConnectionIdType](0), - ParameterId: util.Ptr[model.ElectricalConnectionParameterIdType](0), - }, - } - - // Act - sut.UpdateList(nil, nil, delete) - - data := sut.ElectricalConnectionPermittedValueSetData - // check the deleted item is added again - assert.Equal(t, 3, len(data)) - // check properties of remaining item - item1 := data[0] - assert.Equal(t, 0, int(*item1.ElectricalConnectionId)) - assert.Equal(t, 1, int(*item1.ParameterId)) - assert.Equal(t, 1, len(item1.PermittedValueSet)) - valueSet := item1.PermittedValueSet[0] - assert.Equal(t, 1, len(valueSet.Range)) - rangeSet := valueSet.Range[0] - assert.Equal(t, 6.0, rangeSet.Min.GetValue()) - assert.Equal(t, 16.0, rangeSet.Max.GetValue()) -} - -// verifies that a subset of existing items will be updated with identified new values -func TestElectricalConnectionPermittedValueSetListDataType_Update_Delete_Element(t *testing.T) { - existingDataJson := `{ - "electricalConnectionPermittedValueSetData":[ - { - "electricalConnectionId":0, - "parameterId":0, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":1,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":1, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":2, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":3, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - } - ] - }` - - var sut model.ElectricalConnectionPermittedValueSetListDataType - err := json.Unmarshal([]byte(existingDataJson), &sut) - if assert.Nil(t, err) == false { - return - } - - delete := &model.FilterType{ - CmdControl: &model.CmdControlType{ - Delete: &model.ElementTagType{}, - }, - ElectricalConnectionPermittedValueSetDataElements: &model.ElectricalConnectionPermittedValueSetDataElementsType{ - PermittedValueSet: &model.ElementTagType{}, - }, - ElectricalConnectionPermittedValueSetListDataSelectors: &model.ElectricalConnectionPermittedValueSetListDataSelectorsType{ - ElectricalConnectionId: util.Ptr[model.ElectricalConnectionIdType](0), - ParameterId: util.Ptr[model.ElectricalConnectionParameterIdType](0), - }, - } - - // Act - sut.UpdateList(nil, nil, delete) - - data := sut.ElectricalConnectionPermittedValueSetData - // check no items are deleted - assert.Equal(t, 4, len(data)) - // check permitted value is removed from item with ID 0 - item1 := data[0] - assert.Equal(t, 0, int(*item1.ElectricalConnectionId)) - assert.Equal(t, 0, int(*item1.ParameterId)) - var nilValue []model.ScaledNumberSetType - assert.Equal(t, nilValue, item1.PermittedValueSet) - - // check properties of remaining item - item2 := data[1] - assert.Equal(t, 0, int(*item2.ElectricalConnectionId)) - assert.Equal(t, 1, int(*item2.ParameterId)) - assert.Equal(t, 1, len(item2.PermittedValueSet)) - valueSet := item2.PermittedValueSet[0] - assert.Equal(t, 1, len(valueSet.Range)) - rangeSet := valueSet.Range[0] - assert.Equal(t, 6.0, rangeSet.Min.GetValue()) - assert.Equal(t, 16.0, rangeSet.Max.GetValue()) -} - -// verifies that a subset of existing items will be updated with identified new values -func TestElectricalConnectionPermittedValueSetListDataType_Update_Delete_OnlyElement(t *testing.T) { - existingDataJson := `{ - "electricalConnectionPermittedValueSetData":[ - { - "electricalConnectionId":0, - "parameterId":0, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":1,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":1, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":2, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":3, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - } - ] - }` - - var sut model.ElectricalConnectionPermittedValueSetListDataType - err := json.Unmarshal([]byte(existingDataJson), &sut) - if assert.Nil(t, err) == false { - return - } - - delete := &model.FilterType{ - CmdControl: &model.CmdControlType{ - Delete: &model.ElementTagType{}, - }, - ElectricalConnectionPermittedValueSetDataElements: &model.ElectricalConnectionPermittedValueSetDataElementsType{ - PermittedValueSet: &model.ElementTagType{}, - }, - } - - // Act - sut.UpdateList(nil, nil, delete) - - data := sut.ElectricalConnectionPermittedValueSetData - // check no items are deleted - assert.Equal(t, 4, len(data)) - // check permitted value is removed from item with ID 0 - item1 := data[0] - assert.Equal(t, 0, int(*item1.ElectricalConnectionId)) - assert.Equal(t, 0, int(*item1.ParameterId)) - var nilValue []model.ScaledNumberSetType - assert.Equal(t, nilValue, item1.PermittedValueSet) - - // check properties - item2 := data[1] - assert.Equal(t, 0, int(*item2.ElectricalConnectionId)) - assert.Equal(t, 1, int(*item2.ParameterId)) - assert.Equal(t, nilValue, item2.PermittedValueSet) - - item3 := data[2] - assert.Equal(t, 0, int(*item3.ElectricalConnectionId)) - assert.Equal(t, 2, int(*item3.ParameterId)) - assert.Equal(t, nilValue, item3.PermittedValueSet) - - item4 := data[3] - assert.Equal(t, 0, int(*item4.ElectricalConnectionId)) - assert.Equal(t, 3, int(*item4.ParameterId)) - assert.Equal(t, nilValue, item4.PermittedValueSet) -} - -// verifies that a subset of existing items will be updated with identified new values -func TestElectricalConnectionPermittedValueSetListDataType_Update_Delete_Add(t *testing.T) { - existingDataJson := `{ - "electricalConnectionPermittedValueSetData":[ - { - "electricalConnectionId":0, - "parameterId":0, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":1,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":1, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":2, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":3, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":6,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - } - ] - }` - - var sut model.ElectricalConnectionPermittedValueSetListDataType - err := json.Unmarshal([]byte(existingDataJson), &sut) - if assert.Nil(t, err) == false { - return - } - - newDataJson := `{ - "electricalConnectionPermittedValueSetData":[ - { - "electricalConnectionId":0, - "parameterId":0, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":1,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":1, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":2,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":2, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":2,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - }, - { - "electricalConnectionId":0, - "parameterId":3, - "permittedValueSet":[ - { - "range":[ - { - "min":{"number":2,"scale":0}, - "max":{"number":16,"scale":0} - } - ] - } - ] - } - ] - }` - - var newData model.ElectricalConnectionPermittedValueSetListDataType - err = json.Unmarshal([]byte(newDataJson), &newData) - if assert.Nil(t, err) == false { - return - } - - delete := &model.FilterType{ - CmdControl: &model.CmdControlType{ - Delete: &model.ElementTagType{}, - }, - ElectricalConnectionPermittedValueSetListDataSelectors: &model.ElectricalConnectionPermittedValueSetListDataSelectorsType{ - ElectricalConnectionId: util.Ptr[model.ElectricalConnectionIdType](0), - ParameterId: util.Ptr[model.ElectricalConnectionParameterIdType](0), - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), delete) - - data := sut.ElectricalConnectionPermittedValueSetData - // check the deleted item is added again - assert.Equal(t, 4, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.ElectricalConnectionId)) - assert.Equal(t, 0, int(*item1.ParameterId)) - assert.Equal(t, 1, len(item1.PermittedValueSet)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 0, int(*item2.ElectricalConnectionId)) - assert.Equal(t, 1, int(*item2.ParameterId)) - assert.Equal(t, 1, len(item2.PermittedValueSet)) - valueSet := item2.PermittedValueSet[0] - assert.Equal(t, 1, len(valueSet.Range)) - rangeSet := valueSet.Range[0] - assert.Equal(t, 2.0, rangeSet.Min.GetValue()) - assert.Equal(t, 16.0, rangeSet.Max.GetValue()) -} - -// verifies that an item in the payload which is not in the existing data will be added -func TestElectricalConnectionPermittedValueSetListDataType_Update_NewItem(t *testing.T) { - existingDataJson := `{ - "electricalConnectionPermittedValueSetData": [ - { - "electricalConnectionId": 1, - "parameterId": 1, - "permittedValueSet": [ - { - "range": [ - { - "min": { "number": 3, "scale": 0 }, - "max": { "number": 6, "scale": 0 } - } - ] - } - ] - } - ] - }` - - var sut model.ElectricalConnectionPermittedValueSetListDataType - err := json.Unmarshal([]byte(existingDataJson), &sut) - if assert.Nil(t, err) == false { - return - } - - newDataJson := `{ - "electricalConnectionPermittedValueSetData": [ - { - "electricalConnectionId": 1, - "parameterId": 2, - "permittedValueSet": [ - { - "range": [ - { - "min": { "number": 9, "scale": 0 }, - "max": { "number": 19, "scale": 0 } - } - ] - }, - { - "range": [ - { - "min": { "number": 30, "scale": 0 }, - "max": { "number": 36, "scale": 0 } - } - ] - } - ] - } - ] - }` - - var newData model.ElectricalConnectionPermittedValueSetListDataType - err = json.Unmarshal([]byte(newDataJson), &newData) - if assert.Nil(t, err) == false { - return - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.ElectricalConnectionPermittedValueSetData - // new item should be added - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 1, int(*item1.ElectricalConnectionId)) - assert.Equal(t, 1, int(*item1.ParameterId)) - assert.Equal(t, 1, len(item1.PermittedValueSet)) - // check properties of added item - item2 := data[1] - assert.Equal(t, 1, int(*item2.ElectricalConnectionId)) - assert.Equal(t, 2, int(*item2.ParameterId)) - assert.Equal(t, 2, len(item2.PermittedValueSet)) -} - -// verifies that an item in the payload which has no identifiers will be copied to all existing data -// (see EEBus_SPINE_TS_ProtocolSpecification.pdf, Table 7: Considered cmdOptions combinations for classifier "notify") -func TestElectricalConnectionPermittedValueSetListDataType_UpdateWithoutIdenifiers(t *testing.T) { - existingDataJson := `{ - "electricalConnectionPermittedValueSetData": [ - { - "electricalConnectionId": 1, - "parameterId": 1, - "permittedValueSet": [ - { - "range": [ - { - "min": { "number": 3, "scale": 0 }, - "max": { "number": 6, "scale": 0 } - } - ] - } - ] - }, - { - "electricalConnectionId": 1, - "parameterId": 2, - "permittedValueSet": [ - { - "range": [ - { - "min": { "number": 6, "scale": 0 }, - "max": { "number": 12, "scale": 0 } - } - ] - } - ] - } ] - }` - - var sut model.ElectricalConnectionPermittedValueSetListDataType - err := json.Unmarshal([]byte(existingDataJson), &sut) - if assert.Nil(t, err) == false { - return - } - - // item with no identifiers - newDataJson := `{ - "electricalConnectionPermittedValueSetData": [ - { - "permittedValueSet": [ - { - "range": [ - { - "min": { "number": 30, "scale": 0 }, - "max": { "number": 36, "scale": 0 } - } - ] - } - ] - } - ] - }` - - var newData model.ElectricalConnectionPermittedValueSetListDataType - err = json.Unmarshal([]byte(newDataJson), &newData) - if assert.Nil(t, err) == false { - return - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.ElectricalConnectionPermittedValueSetData - // the new item should not be added - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 1, int(*item1.ElectricalConnectionId)) - assert.Equal(t, 1, int(*item1.ParameterId)) - assert.Equal(t, 1, len(item1.PermittedValueSet)) - valueSet := item1.PermittedValueSet[0] - assert.Equal(t, 1, len(valueSet.Range)) - // the values of the item in the payload should be copied to the first item - assert.Equal(t, 30, int(*valueSet.Range[0].Min.Number)) - assert.Equal(t, 0, int(*valueSet.Range[0].Min.Scale)) - assert.Equal(t, 36, int(*valueSet.Range[0].Max.Number)) - assert.Equal(t, 0, int(*valueSet.Range[0].Max.Scale)) - - item2 := data[1] - assert.Equal(t, 1, int(*item2.ElectricalConnectionId)) - assert.Equal(t, 2, int(*item2.ParameterId)) - assert.Equal(t, 1, len(item2.PermittedValueSet)) - valueSet = item2.PermittedValueSet[0] - assert.Equal(t, 1, len(valueSet.Range)) - // the values of the item in the payload should be also copied to the second item - assert.Equal(t, 30, int(*valueSet.Range[0].Min.Number)) - assert.Equal(t, 0, int(*valueSet.Range[0].Min.Scale)) - assert.Equal(t, 36, int(*valueSet.Range[0].Max.Number)) - assert.Equal(t, 0, int(*valueSet.Range[0].Max.Scale)) -} - -func TestElectricalConnectionDescriptionListDataType_Update(t *testing.T) { - sut := model.ElectricalConnectionDescriptionListDataType{ - ElectricalConnectionDescriptionData: []model.ElectricalConnectionDescriptionDataType{ - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), - PowerSupplyType: util.Ptr(model.ElectricalConnectionVoltageTypeTypeAc), - }, - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(1)), - PowerSupplyType: util.Ptr(model.ElectricalConnectionVoltageTypeTypeAc), - }, - }, - } - - newData := model.ElectricalConnectionDescriptionListDataType{ - ElectricalConnectionDescriptionData: []model.ElectricalConnectionDescriptionDataType{ - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(1)), - PowerSupplyType: util.Ptr(model.ElectricalConnectionVoltageTypeTypeDc), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.ElectricalConnectionDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.ElectricalConnectionId)) - assert.Equal(t, model.ElectricalConnectionVoltageTypeTypeAc, *item1.PowerSupplyType) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.ElectricalConnectionId)) - assert.Equal(t, model.ElectricalConnectionVoltageTypeTypeDc, *item2.PowerSupplyType) -} - -func TestElectricalConnectionParameterDescriptionListDataType_Update(t *testing.T) { - sut := model.ElectricalConnectionParameterDescriptionListDataType{ - ElectricalConnectionParameterDescriptionData: []model.ElectricalConnectionParameterDescriptionDataType{ - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(0)), - ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(0)), - VoltageType: util.Ptr(model.ElectricalConnectionVoltageTypeTypeAc), - }, - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(1)), - ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(0)), - MeasurementId: util.Ptr(model.MeasurementIdType(0)), - VoltageType: util.Ptr(model.ElectricalConnectionVoltageTypeTypeAc), - }, - }, - } - - newData := model.ElectricalConnectionParameterDescriptionListDataType{ - ElectricalConnectionParameterDescriptionData: []model.ElectricalConnectionParameterDescriptionDataType{ - { - ElectricalConnectionId: util.Ptr(model.ElectricalConnectionIdType(1)), - ParameterId: util.Ptr(model.ElectricalConnectionParameterIdType(0)), - VoltageType: util.Ptr(model.ElectricalConnectionVoltageTypeTypeDc), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.ElectricalConnectionParameterDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.ElectricalConnectionId)) - assert.Equal(t, model.ElectricalConnectionVoltageTypeTypeAc, *item1.VoltageType) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.ElectricalConnectionId)) - assert.Equal(t, model.ElectricalConnectionVoltageTypeTypeDc, *item2.VoltageType) -} diff --git a/spine/model/hvac.go b/spine/model/hvac.go deleted file mode 100644 index 060d3d55..00000000 --- a/spine/model/hvac.go +++ /dev/null @@ -1,222 +0,0 @@ -package model - -type HvacSystemFunctionIdType uint - -type HvacSystemFunctionTypeType string - -const ( - HvacSystemFunctionTypeTypeHeating HvacSystemFunctionTypeType = "heating" - HvacSystemFunctionTypeTypeCooling HvacSystemFunctionTypeType = "cooling" - HvacSystemFunctionTypeTypeVentilation HvacSystemFunctionTypeType = "ventilation" - HvacSystemFunctionTypeTypeDhw HvacSystemFunctionTypeType = "dhw" -) - -type HvacOperationModeIdType uint - -type HvacOperationModeTypeType string - -const ( - HvacOperationModeTypeTypeAuto HvacOperationModeTypeType = "auto" - HvacOperationModeTypeTypeOn HvacOperationModeTypeType = "on" - HvacOperationModeTypeTypeOff HvacOperationModeTypeType = "off" - HvacOperationModeTypeTypeEco HvacOperationModeTypeType = "eco" -) - -type HvacOverrunIdType uint - -type HvacOverrunTypeType string - -const ( - HvacOverrunTypeTypeOneTimeDhw HvacOverrunTypeType = "oneTimeDhw" - HvacOverrunTypeTypeParty HvacOverrunTypeType = "party" - HvacOverrunTypeTypeSgReadyCondition1 HvacOverrunTypeType = "sgReadyCondition1" - HvacOverrunTypeTypeSgReadyCondition3 HvacOverrunTypeType = "sgReadyCondition3" - HvacOverrunTypeTypeSgReadyCondition4 HvacOverrunTypeType = "sgReadyCondition4" - HvacOverrunTypeTypeOneDayAway HvacOverrunTypeType = "oneDayAway" - HvacOverrunTypeTypeOneDayAtHome HvacOverrunTypeType = "oneDayAtHome" - HvacOverrunTypeTypeOneTimeVentilation HvacOverrunTypeType = "oneTimeVentilation" - HvacOverrunTypeTypeHvacSystemOff HvacOverrunTypeType = "hvacSystemOff" - HvacOverrunTypeTypeValveKick HvacOverrunTypeType = "valveKick" -) - -type HvacOverrunStatusType string - -const ( - HvacOverrunStatusTypeActive HvacOverrunStatusType = "active" - HvacOverrunStatusTypeRunning HvacOverrunStatusType = "running" - HvacOverrunStatusTypeFinished HvacOverrunStatusType = "finished" - HvacOverrunStatusTypeInactive HvacOverrunStatusType = "inactive" -) - -type HvacSystemFunctionDataType struct { - SystemFunctionId *HvacSystemFunctionIdType `json:"systemFunctionId,omitempty" eebus:"key"` - CurrentOperationModeId *HvacOperationModeIdType `json:"currentOperationModeId,omitempty"` - IsOperationModeIdChangeable *bool `json:"isOperationModeIdChangeable,omitempty"` - CurrentSetpointId *SetpointIdType `json:"currentSetpointId,omitempty"` - IsSetpointIdChangeable *bool `json:"isSetpointIdChangeable,omitempty"` - IsOverrunActive *bool `json:"isOverrunActive,omitempty"` -} - -type HvacSystemFunctionDataElementsType struct { - SystemFunctionId *ElementTagType `json:"systemFunctionId,omitempty"` - CurrentOperationModeId *ElementTagType `json:"currentOperationModeId,omitempty"` - IsOperationModeIdChangeable *ElementTagType `json:"isOperationModeIdChangeable,omitempty"` - CurrentSetpointId *ElementTagType `json:"currentSetpointId,omitempty"` - IsSetpointIdChangeable *ElementTagType `json:"isSetpointIdChangeable,omitempty"` - IsOverrunActive *ElementTagType `json:"isOverrunActive,omitempty"` -} - -type HvacSystemFunctionListDataType struct { - HvacSystemFunctionData []HvacSystemFunctionDataType `json:"hvacSystemFunctionData,omitempty"` -} - -type HvacSystemFunctionListDataSelectorsType struct { - SystemFunctionId []HvacSystemFunctionIdType `json:"systemFunctionId,omitempty"` -} - -type HvacSystemFunctionOperationModeRelationDataType struct { - SystemFunctionId *HvacSystemFunctionIdType `json:"systemFunctionId,omitempty" eebus:"key"` - OperationModeId *HvacOperationModeIdType `json:"operationModeId,omitempty"` -} - -type HvacSystemFunctionOperationModeRelationDataElementsType struct { - SystemFunctionId *ElementTagType `json:"systemFunctionId,omitempty"` - OperationModeId *ElementTagType `json:"operationModeId,omitempty"` -} - -type HvacSystemFunctionOperationModeRelationListDataType struct { - HvacSystemFunctionOperationModeRelationData []HvacSystemFunctionOperationModeRelationDataType `json:"hvacSystemFunctionOperationModeRelationData,omitempty"` -} - -type HvacSystemFunctionOperationModeRelationListDataSelectorsType struct { - SystemFunctionId []HvacSystemFunctionIdType `json:"systemFunctionId,omitempty"` -} - -type HvacSystemFunctionSetpointRelationDataType struct { - SystemFunctionId *HvacSystemFunctionIdType `json:"systemFunctionId,omitempty" eebus:"key"` - OperationModeId *HvacOperationModeIdType `json:"operationModeId,omitempty"` - SetpointId *SetpointIdType `json:"setpointId,omitempty"` -} - -type HvacSystemFunctionSetpointRelationDataElementsType struct { - SystemFunctionId *ElementTagType `json:"systemFunctionId,omitempty"` - OperationModeId *ElementTagType `json:"operationModeId,omitempty"` - SetpointId *ElementTagType `json:"setpointId,omitempty"` -} - -type HvacSystemFunctionSetpointRelationListDataType struct { - HvacSystemFunctionSetpointRelationData []HvacSystemFunctionSetpointRelationDataType `json:"hvacSystemFunctionSetpointRelationData,omitempty"` -} - -type HvacSystemFunctionSetpointRelationListDataSelectorsType struct { - SystemFunctionId *HvacSystemFunctionIdType `json:"systemFunctionId,omitempty"` - OperationModeId *HvacOperationModeIdType `json:"operationModeId,omitempty"` -} - -type HvacSystemFunctionPowerSequenceRelationDataType struct { - SystemFunctionId *HvacSystemFunctionIdType `json:"systemFunctionId,omitempty" eebus:"key"` - SequenceId []PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type HvacSystemFunctionPowerSequenceRelationDataElementsType struct { - SystemFunctionId *ElementTagType `json:"systemFunctionId,omitempty"` - SequenceId *ElementTagType `json:"sequenceId,omitempty"` -} - -type HvacSystemFunctionPowerSequenceRelationListDataType struct { - HvacSystemFunctionPowerSequenceRelationData []HvacSystemFunctionPowerSequenceRelationDataType `json:"hvacSystemFunctionPowerSequenceRelationData,omitempty"` -} - -type HvacSystemFunctionPowerSequenceRelationListDataSelectorsType struct { - SystemFunctionId *HvacSystemFunctionIdType `json:"systemFunctionId,omitempty"` -} - -type HvacSystemFunctionDescriptionDataType struct { - SystemFunctionId *HvacSystemFunctionIdType `json:"systemFunctionId,omitempty" eebus:"key"` - SystemFunctionType *HvacSystemFunctionTypeType `json:"systemFunctionType,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type HvacSystemFunctionDescriptionDataElementsType struct { - SystemFunctionId *ElementTagType `json:"systemFunctionId,omitempty"` - SystemFunctionType *ElementTagType `json:"systemFunctionType,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type HvacSystemFunctionDescriptionListDataType struct { - HvacSystemFunctionDescriptionData []HvacSystemFunctionDescriptionDataType `json:"hvacSystemFunctionDescriptionData,omitempty"` -} - -type HvacSystemFunctionDescriptionListDataSelectorsType struct { - SystemFunctionId *HvacSystemFunctionIdType `json:"systemFunctionId,omitempty"` -} - -type HvacOperationModeDescriptionDataType struct { - OperationModeId *HvacOperationModeIdType `json:"operationModeId,omitempty" eebus:"key"` - OperationModeType *HvacOperationModeTypeType `json:"operationModeType,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type HvacOperationModeDescriptionDataElementsType struct { - OperationModeId *ElementTagType `json:"operationModeId,omitempty"` - OperationModeType *ElementTagType `json:"operationModeType,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type HvacOperationModeDescriptionListDataType struct { - HvacOperationModeDescriptionData []HvacOperationModeDescriptionDataType `json:"hvacOperationModeDescriptionData,omitempty"` -} - -type HvacOperationModeDescriptionListDataSelectorsType struct { - OperationModeId *HvacOperationModeIdType `json:"operationModeId,omitempty"` -} - -type HvacOverrunDataType struct { - OverrunId *HvacOverrunIdType `json:"overrunId,omitempty" eebus:"key"` - OverrunStatus *HvacOverrunStatusType `json:"overrunStatus,omitempty"` - TimeTableId *TimeTableIdType `json:"timeTableId,omitempty"` - IsOverrunStatusChangeable *bool `json:"isOverrunStatusChangeable,omitempty"` -} - -type HvacOverrunDataElementsType struct { - OverrunId *ElementTagType `json:"overrunId,omitempty"` - OverrunStatus *ElementTagType `json:"overrunStatus,omitempty"` - TimeTableId *ElementTagType `json:"timeTableId,omitempty"` - IsOverrunStatusChangeable *ElementTagType `json:"isOverrunStatusChangeable,omitempty"` -} - -type HvacOverrunListDataType struct { - HvacOverrunData []HvacOverrunDataType `json:"hvacOverrunData,omitempty"` -} - -type HvacOverrunListDataSelectorsType struct { - OverrunId *HvacOverrunIdType `json:"overrunId,omitempty"` -} - -type HvacOverrunDescriptionDataType struct { - OverrunId *HvacOverrunIdType `json:"overrunId,omitempty" eebus:"key"` - OverrunType *HvacOverrunTypeType `json:"overrunType,omitempty"` - AffectedSystemFunctionId []HvacSystemFunctionIdType `json:"affectedSystemFunctionId,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type HvacOverrunDescriptionDataElementsType struct { - OverrunId *ElementTagType `json:"overrunId,omitempty"` - OverrunType *ElementTagType `json:"overrunType,omitempty"` - AffectedSystemFunctionId *ElementTagType `json:"affectedSystemFunctionId,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type HvacOverrunDescriptionListDataType struct { - HvacOverrunDescriptionData []HvacOverrunDescriptionDataType `json:"hvacOverrunDescriptionData,omitempty"` -} - -type HvacOverrunDescriptionListDataSelectorsType struct { - OverrunId *HvacOverrunIdType `json:"overrunId,omitempty"` -} diff --git a/spine/model/hvac_additions.go b/spine/model/hvac_additions.go deleted file mode 100644 index a62824b5..00000000 --- a/spine/model/hvac_additions.go +++ /dev/null @@ -1,105 +0,0 @@ -package model - -// HvacSystemFunctionListDataType - -var _ Updater = (*HvacSystemFunctionListDataType)(nil) - -func (r *HvacSystemFunctionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []HvacSystemFunctionDataType - if newList != nil { - newData = newList.(*HvacSystemFunctionListDataType).HvacSystemFunctionData - } - - r.HvacSystemFunctionData = UpdateList(r.HvacSystemFunctionData, newData, filterPartial, filterDelete) -} - -// HvacSystemFunctionOperationModeRelationListDataType - -var _ Updater = (*HvacSystemFunctionOperationModeRelationListDataType)(nil) - -func (r *HvacSystemFunctionOperationModeRelationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []HvacSystemFunctionOperationModeRelationDataType - if newList != nil { - newData = newList.(*HvacSystemFunctionOperationModeRelationListDataType).HvacSystemFunctionOperationModeRelationData - } - - r.HvacSystemFunctionOperationModeRelationData = UpdateList(r.HvacSystemFunctionOperationModeRelationData, newData, filterPartial, filterDelete) -} - -// HvacSystemFunctionSetpointRelationListDataType - -var _ Updater = (*HvacSystemFunctionSetpointRelationListDataType)(nil) - -func (r *HvacSystemFunctionSetpointRelationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []HvacSystemFunctionSetpointRelationDataType - if newList != nil { - newData = newList.(*HvacSystemFunctionSetpointRelationListDataType).HvacSystemFunctionSetpointRelationData - } - - r.HvacSystemFunctionSetpointRelationData = UpdateList(r.HvacSystemFunctionSetpointRelationData, newData, filterPartial, filterDelete) -} - -// HvacSystemFunctionPowerSequenceRelationListDataType - -var _ Updater = (*HvacSystemFunctionPowerSequenceRelationListDataType)(nil) - -func (r *HvacSystemFunctionPowerSequenceRelationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []HvacSystemFunctionPowerSequenceRelationDataType - if newList != nil { - newData = newList.(*HvacSystemFunctionPowerSequenceRelationListDataType).HvacSystemFunctionPowerSequenceRelationData - } - - r.HvacSystemFunctionPowerSequenceRelationData = UpdateList(r.HvacSystemFunctionPowerSequenceRelationData, newData, filterPartial, filterDelete) -} - -// HvacSystemFunctionDescriptionListDataType - -var _ Updater = (*HvacSystemFunctionDescriptionListDataType)(nil) - -func (r *HvacSystemFunctionDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []HvacSystemFunctionDescriptionDataType - if newList != nil { - newData = newList.(*HvacSystemFunctionDescriptionListDataType).HvacSystemFunctionDescriptionData - } - - r.HvacSystemFunctionDescriptionData = UpdateList(r.HvacSystemFunctionDescriptionData, newData, filterPartial, filterDelete) -} - -// HvacOperationModeDescriptionListDataType - -var _ Updater = (*HvacOperationModeDescriptionListDataType)(nil) - -func (r *HvacOperationModeDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []HvacOperationModeDescriptionDataType - if newList != nil { - newData = newList.(*HvacOperationModeDescriptionListDataType).HvacOperationModeDescriptionData - } - - r.HvacOperationModeDescriptionData = UpdateList(r.HvacOperationModeDescriptionData, newData, filterPartial, filterDelete) -} - -// HvacOverrunListDataType - -var _ Updater = (*HvacOverrunListDataType)(nil) - -func (r *HvacOverrunListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []HvacOverrunDataType - if newList != nil { - newData = newList.(*HvacOverrunListDataType).HvacOverrunData - } - - r.HvacOverrunData = UpdateList(r.HvacOverrunData, newData, filterPartial, filterDelete) -} - -// HvacOverrunDescriptionListDataType - -var _ Updater = (*HvacOverrunDescriptionListDataType)(nil) - -func (r *HvacOverrunDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []HvacOverrunDescriptionDataType - if newList != nil { - newData = newList.(*HvacOverrunDescriptionListDataType).HvacOverrunDescriptionData - } - - r.HvacOverrunDescriptionData = UpdateList(r.HvacOverrunDescriptionData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/hvac_additions_test.go b/spine/model/hvac_additions_test.go deleted file mode 100644 index 0574c774..00000000 --- a/spine/model/hvac_additions_test.go +++ /dev/null @@ -1,313 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestHvacSystemFunctionListDataType_Update(t *testing.T) { - sut := model.HvacSystemFunctionListDataType{ - HvacSystemFunctionData: []model.HvacSystemFunctionDataType{ - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(0)), - IsOverrunActive: util.Ptr(false), - }, - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(1)), - IsOverrunActive: util.Ptr(false), - }, - }, - } - - newData := model.HvacSystemFunctionListDataType{ - HvacSystemFunctionData: []model.HvacSystemFunctionDataType{ - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(1)), - IsOverrunActive: util.Ptr(true), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.HvacSystemFunctionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SystemFunctionId)) - assert.Equal(t, false, *item1.IsOverrunActive) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SystemFunctionId)) - assert.Equal(t, true, *item2.IsOverrunActive) -} - -func TestHvacSystemFunctionOperationModeRelationListDataType_Update(t *testing.T) { - sut := model.HvacSystemFunctionOperationModeRelationListDataType{ - HvacSystemFunctionOperationModeRelationData: []model.HvacSystemFunctionOperationModeRelationDataType{ - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(0)), - OperationModeId: util.Ptr(model.HvacOperationModeIdType(0)), - }, - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(1)), - OperationModeId: util.Ptr(model.HvacOperationModeIdType(0)), - }, - }, - } - - newData := model.HvacSystemFunctionOperationModeRelationListDataType{ - HvacSystemFunctionOperationModeRelationData: []model.HvacSystemFunctionOperationModeRelationDataType{ - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(1)), - OperationModeId: util.Ptr(model.HvacOperationModeIdType(1)), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.HvacSystemFunctionOperationModeRelationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SystemFunctionId)) - assert.Equal(t, 0, int(*item1.OperationModeId)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SystemFunctionId)) - assert.Equal(t, 1, int(*item2.OperationModeId)) -} - -func TestHvacSystemFunctionSetpointRelationListDataType_Update(t *testing.T) { - sut := model.HvacSystemFunctionSetpointRelationListDataType{ - HvacSystemFunctionSetpointRelationData: []model.HvacSystemFunctionSetpointRelationDataType{ - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(0)), - OperationModeId: util.Ptr(model.HvacOperationModeIdType(0)), - }, - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(1)), - OperationModeId: util.Ptr(model.HvacOperationModeIdType(0)), - }, - }, - } - - newData := model.HvacSystemFunctionSetpointRelationListDataType{ - HvacSystemFunctionSetpointRelationData: []model.HvacSystemFunctionSetpointRelationDataType{ - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(1)), - OperationModeId: util.Ptr(model.HvacOperationModeIdType(1)), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.HvacSystemFunctionSetpointRelationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SystemFunctionId)) - assert.Equal(t, 0, int(*item1.OperationModeId)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SystemFunctionId)) - assert.Equal(t, 1, int(*item2.OperationModeId)) -} - -func TestHvacSystemFunctionPowerSequenceRelationListDataType_Update(t *testing.T) { - sut := model.HvacSystemFunctionPowerSequenceRelationListDataType{ - HvacSystemFunctionPowerSequenceRelationData: []model.HvacSystemFunctionPowerSequenceRelationDataType{ - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(0)), - SequenceId: []model.PowerSequenceIdType{0}, - }, - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(1)), - SequenceId: []model.PowerSequenceIdType{0}, - }, - }, - } - - newData := model.HvacSystemFunctionPowerSequenceRelationListDataType{ - HvacSystemFunctionPowerSequenceRelationData: []model.HvacSystemFunctionPowerSequenceRelationDataType{ - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(1)), - SequenceId: []model.PowerSequenceIdType{1}, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.HvacSystemFunctionPowerSequenceRelationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SystemFunctionId)) - assert.Equal(t, 0, int(item1.SequenceId[0])) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SystemFunctionId)) - assert.Equal(t, 1, int(item2.SequenceId[0])) -} - -func TestHvacSystemFunctionDescriptionListDataType_Update(t *testing.T) { - sut := model.HvacSystemFunctionDescriptionListDataType{ - HvacSystemFunctionDescriptionData: []model.HvacSystemFunctionDescriptionDataType{ - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.HvacSystemFunctionDescriptionListDataType{ - HvacSystemFunctionDescriptionData: []model.HvacSystemFunctionDescriptionDataType{ - { - SystemFunctionId: util.Ptr(model.HvacSystemFunctionIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.HvacSystemFunctionDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SystemFunctionId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SystemFunctionId)) - assert.Equal(t, "new", string(*item2.Description)) -} - -func TestHvacOperationModeDescriptionListDataType_Update(t *testing.T) { - sut := model.HvacOperationModeDescriptionListDataType{ - HvacOperationModeDescriptionData: []model.HvacOperationModeDescriptionDataType{ - { - OperationModeId: util.Ptr(model.HvacOperationModeIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - OperationModeId: util.Ptr(model.HvacOperationModeIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.HvacOperationModeDescriptionListDataType{ - HvacOperationModeDescriptionData: []model.HvacOperationModeDescriptionDataType{ - { - OperationModeId: util.Ptr(model.HvacOperationModeIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.HvacOperationModeDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.OperationModeId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.OperationModeId)) - assert.Equal(t, "new", string(*item2.Description)) -} - -func TestHvacOverrunListDataType_Update(t *testing.T) { - sut := model.HvacOverrunListDataType{ - HvacOverrunData: []model.HvacOverrunDataType{ - { - OverrunId: util.Ptr(model.HvacOverrunIdType(0)), - IsOverrunStatusChangeable: util.Ptr(false), - }, - { - OverrunId: util.Ptr(model.HvacOverrunIdType(1)), - IsOverrunStatusChangeable: util.Ptr(false), - }, - }, - } - - newData := model.HvacOverrunListDataType{ - HvacOverrunData: []model.HvacOverrunDataType{ - { - OverrunId: util.Ptr(model.HvacOverrunIdType(1)), - IsOverrunStatusChangeable: util.Ptr(true), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.HvacOverrunData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.OverrunId)) - assert.Equal(t, false, *item1.IsOverrunStatusChangeable) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.OverrunId)) - assert.Equal(t, true, *item2.IsOverrunStatusChangeable) -} - -func TestHvacOverrunDescriptionListDataType_Update(t *testing.T) { - sut := model.HvacOverrunDescriptionListDataType{ - HvacOverrunDescriptionData: []model.HvacOverrunDescriptionDataType{ - { - OverrunId: util.Ptr(model.HvacOverrunIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - OverrunId: util.Ptr(model.HvacOverrunIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.HvacOverrunDescriptionListDataType{ - HvacOverrunDescriptionData: []model.HvacOverrunDescriptionDataType{ - { - OverrunId: util.Ptr(model.HvacOverrunIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.HvacOverrunDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.OverrunId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.OverrunId)) - assert.Equal(t, "new", string(*item2.Description)) -} diff --git a/spine/model/identification.go b/spine/model/identification.go deleted file mode 100644 index f42e3dc5..00000000 --- a/spine/model/identification.go +++ /dev/null @@ -1,36 +0,0 @@ -package model - -type IdentificationIdType uint - -type IdentificationTypeType string - -const ( - IdentificationTypeTypeEui48 IdentificationTypeType = "eui48" - IdentificationTypeTypeEui64 IdentificationTypeType = "eui64" - IdentificationTypeTypeUserrfidtag IdentificationTypeType = "userRfidTag" -) - -type IdentificationValueType string - -type IdentificationDataType struct { - IdentificationId *IdentificationIdType `json:"identificationId,omitempty" eebus:"key"` - IdentificationType *IdentificationTypeType `json:"identificationType,omitempty"` - IdentificationValue *IdentificationValueType `json:"identificationValue,omitempty"` - Authorized *bool `json:"authorized,omitempty"` -} - -type IdentificationDataElementsType struct { - IdentificationId *ElementTagType `json:"identificationId,omitempty"` - IdentificationType *ElementTagType `json:"identificationType,omitempty"` - IdentificationValue *ElementTagType `json:"identificationValue,omitempty"` - Authorized *ElementTagType `json:"authorized,omitempty"` -} - -type IdentificationListDataType struct { - IdentificationData []IdentificationDataType `json:"identificationData,omitempty"` -} - -type IdentificationListDataSelectorsType struct { - IdentificationId *IdentificationIdType `json:"identificationId,omitempty"` - IdentificationType *IdentificationTypeType `json:"identificationType,omitempty"` -} diff --git a/spine/model/identification_additions.go b/spine/model/identification_additions.go deleted file mode 100644 index 68be5742..00000000 --- a/spine/model/identification_additions.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -// IdentificationListDataType - -var _ Updater = (*IdentificationListDataType)(nil) - -func (r *IdentificationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []IdentificationDataType - if newList != nil { - newData = newList.(*IdentificationListDataType).IdentificationData - } - - r.IdentificationData = UpdateList(r.IdentificationData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/identification_additions_test.go b/spine/model/identification_additions_test.go deleted file mode 100644 index fd3b41f3..00000000 --- a/spine/model/identification_additions_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestIdentificationListDataType_Update(t *testing.T) { - sut := model.IdentificationListDataType{ - IdentificationData: []model.IdentificationDataType{ - { - IdentificationId: util.Ptr(model.IdentificationIdType(0)), - IdentificationType: util.Ptr(model.IdentificationTypeTypeEui48), - }, - { - IdentificationId: util.Ptr(model.IdentificationIdType(1)), - IdentificationType: util.Ptr(model.IdentificationTypeTypeEui48), - }, - }, - } - - newData := model.IdentificationListDataType{ - IdentificationData: []model.IdentificationDataType{ - { - IdentificationId: util.Ptr(model.IdentificationIdType(1)), - IdentificationType: util.Ptr(model.IdentificationTypeTypeEui64), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.IdentificationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.IdentificationId)) - assert.Equal(t, model.IdentificationTypeTypeEui48, *item1.IdentificationType) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.IdentificationId)) - assert.Equal(t, model.IdentificationTypeTypeEui64, *item2.IdentificationType) -} diff --git a/spine/model/incentivetable.go b/spine/model/incentivetable.go deleted file mode 100644 index c5cacb0d..00000000 --- a/spine/model/incentivetable.go +++ /dev/null @@ -1,103 +0,0 @@ -package model - -type IncentiveTableType struct { - Tariff *TariffDataType `json:"tariff,omitempty"` // ignoring changes - IncentiveSlot []IncentiveTableIncentiveSlotType `json:"incentiveSlot,omitempty"` -} - -type IncentiveTableElementsType struct { - Tariff *TariffDataElementsType `json:"tariff,omitempty"` // ignoring changes - IncentiveSlot *IncentiveTableIncentiveSlotElementsType `json:"incentiveSlot,omitempty"` -} - -type IncentiveTableIncentiveSlotType struct { - TimeInterval *TimeTableDataType `json:"timeInterval,omitempty"` // ignoring changes - Tier []IncentiveTableTierType `json:"tier,omitempty"` -} - -type IncentiveTableIncentiveSlotElementsType struct { - TimeInterval *TimeTableDataElementsType `json:"timeInterval,omitempty"` // ignoring changes - Tier *IncentiveTableTierElementsType `json:"tier,omitempty"` -} - -type IncentiveTableTierType struct { - Tier *TierDataType `json:"tier,omitempty"` // ignoring changes - Boundary []TierBoundaryDataType `json:"boundary,omitempty"` // ignoring changes - Incentive []IncentiveDataType `json:"incentive,omitempty"` // ignoring changes -} - -type IncentiveTableTierElementsType struct { - Tier *TierDataElementsType `json:"tier,omitempty"` // ignoring changes - Boundary *TierBoundaryDataElementsType `json:"boundary,omitempty"` // ignoring changes - Incentive *IncentiveDataElementsType `json:"incentive,omitempty"` // ignoring changes -} - -type IncentiveTableDataType struct { - IncentiveTable []IncentiveTableType `json:"incentiveTable,omitempty"` -} - -type IncentiveTableDataElementsType struct { - IncentiveTable *IncentiveTableElementsType `json:"incentiveTable,omitempty"` -} - -type IncentiveTableDataSelectorsType struct { - Tariff *TariffListDataSelectorsType `json:"tariff,omitempty"` -} - -type IncentiveTableDescriptionType struct { - TariffDescription *TariffDescriptionDataType `json:"tariffDescription,omitempty"` - Tier []IncentiveTableDescriptionTierType `json:"tier,omitempty"` -} - -type IncentiveTableDescriptionElementsType struct { - TariffDescription *TariffDescriptionDataElementsType `json:"tariffDescription,omitempty"` - Tier *IncentiveTableDescriptionTierType `json:"tier,omitempty"` -} - -type IncentiveTableDescriptionTierType struct { - TierDescription *TierDescriptionDataType `json:"tierDescription,omitempty"` - BoundaryDescription []TierBoundaryDescriptionDataType `json:"boundaryDescription,omitempty"` - IncentiveDescription []IncentiveDescriptionDataType `json:"incentiveDescription,omitempty"` -} - -type IncentiveTableDescriptionTierElementsType struct { - TierDescription *TierDescriptionDataElementsType `json:"tierDescription,omitempty"` - BoundaryDescription *TierBoundaryDescriptionDataElementsType `json:"boundaryDescription,omitempty"` - IncentiveDescription *IncentiveDescriptionDataElementsType `json:"incentiveDescription,omitempty"` -} - -type IncentiveTableDescriptionDataType struct { - IncentiveTableDescription []IncentiveTableDescriptionType `json:"incentiveTableDescription,omitempty"` -} - -type IncentiveTableDescriptionDataElementsType struct { - IncentiveTableDescription *IncentiveTableDescriptionElementsType `json:"incentiveTableDescription,omitempty"` -} - -type IncentiveTableDescriptionDataSelectorsType struct { - TariffDescription *TariffDescriptionListDataSelectorsType `json:"tariffDescription,omitempty"` -} - -type IncentiveTableConstraintsType struct { - Tariff *TariffDataType `json:"tariff,omitempty"` - TariffConstraints *TariffOverallConstraintsDataType `json:"tariffConstraints,omitempty"` - IncentiveSlotConstraints *TimeTableConstraintsDataType `json:"incentiveSlotConstraints,omitempty"` -} - -type IncentiveTableConstraintsElementsType struct { - Tariff *TariffDataElementsType `json:"tariff,omitempty"` - TariffConstraints *TariffOverallConstraintsDataElementsType `json:"tariffConstraints,omitempty"` - IncentiveSlotConstraints *TimeTableConstraintsDataElementsType `json:"incentiveSlotConstraints,omitempty"` -} - -type IncentiveTableConstraintsDataType struct { - IncentiveTableConstraints []IncentiveTableConstraintsType `json:"incentiveTableConstraints,omitempty"` -} - -type IncentiveTableConstraintsDataElementsType struct { - IncentiveTableConstraints *IncentiveTableConstraintsElementsType `json:"incentiveTableConstraints,omitempty"` -} - -type IncentiveTableConstraintsDataSelectorsType struct { - Tariff *TariffListDataSelectorsType `json:"tariff,omitempty"` -} diff --git a/spine/model/loadcontrol.go b/spine/model/loadcontrol.go deleted file mode 100644 index 4d8460b7..00000000 --- a/spine/model/loadcontrol.go +++ /dev/null @@ -1,184 +0,0 @@ -package model - -type LoadControlEventIdType uint - -type LoadControlEventActionType string - -const ( - LoadControlEventActionTypePause LoadControlEventActionType = "pause" - LoadControlEventActionTypeResume LoadControlEventActionType = "resume" - LoadControlEventActionTypeReduce LoadControlEventActionType = "reduce" - LoadControlEventActionTypeIncrease LoadControlEventActionType = "increase" - LoadControlEventActionTypeEmergency LoadControlEventActionType = "emergency" - LoadControlEventActionTypeNormal LoadControlEventActionType = "normal" -) - -type LoadControlEventStateType string - -const ( - LoadControlEventStateTypeEventAccepted LoadControlEventStateType = "eventAccepted" - LoadControlEventStateTypeEventStarted LoadControlEventStateType = "eventStarted" - LoadControlEventStateTypeEventStopped LoadControlEventStateType = "eventStopped" - LoadControlEventStateTypeEventRejected LoadControlEventStateType = "eventRejected" - LoadControlEventStateTypeEventCancelled LoadControlEventStateType = "eventCancelled" - LoadControlEventStateTypeEventError LoadControlEventStateType = "eventError" -) - -type LoadControlLimitIdType uint - -type LoadControlLimitTypeType string - -const ( - LoadControlLimitTypeTypeMinValueLimit LoadControlLimitTypeType = "minValueLimit" - LoadControlLimitTypeTypeMaxValueLimit LoadControlLimitTypeType = "maxValueLimit" -) - -type LoadControlCategoryType string - -const ( - LoadControlCategoryTypeObligation LoadControlCategoryType = "obligation" - LoadControlCategoryTypeRecommendation LoadControlCategoryType = "recommendation" - LoadControlCategoryTypeOptimization LoadControlCategoryType = "optimization" -) - -type LoadControlNodeDataType struct { - IsNodeRemoteControllable *bool `json:"isNodeRemoteControllable,omitempty"` -} - -type LoadControlNodeDataElementsType struct { - IsNodeRemoteControllable *ElementTagType `json:"isNodeRemoteControllable,omitempty"` -} - -type LoadControlEventDataType struct { - Timestamp *string `json:"timestamp,omitempty"` - EventId *LoadControlEventIdType `json:"eventId,omitempty" eebus:"key"` - EventActionConsume *LoadControlEventActionType `json:"eventActionConsume,omitempty"` - EventActionProduce *LoadControlEventActionType `json:"eventActionProduce,omitempty"` - TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` -} - -type LoadControlEventDataElementsType struct { - Timestamp *ElementTagType `json:"timestamp,omitempty"` - EventId *ElementTagType `json:"eventId,omitempty"` - EventActionConsume *ElementTagType `json:"eventActionConsume,omitempty"` - EventActionProduce *ElementTagType `json:"eventActionProduce,omitempty"` - TimePeriod *TimePeriodElementsType `json:"timePeriod,omitempty"` -} - -type LoadControlEventListDataType struct { - LoadControlEventData []LoadControlEventDataType `json:"loadControlEventData,omitempty"` -} - -type LoadControlEventListDataSelectorsType struct { - TimestampInterval *TimestampIntervalType `json:"timestampInterval,omitempty"` - EventId *LoadControlEventIdType `json:"eventId,omitempty"` -} - -type LoadControlStateDataType struct { - Timestamp *string `json:"timestamp"` - EventId *LoadControlEventIdType `json:"eventId,omitempty" eebus:"key"` - EventStateConsume *LoadControlEventStateType `json:"eventStateConsume"` - AppliedEventActionConsume *LoadControlEventActionType `json:"appliedEventActionConsume"` - EventStateProduce *LoadControlEventStateType `json:"eventStateProduce"` - AppliedEventActionProduce *LoadControlEventActionType `json:"appliedEventActionProduce"` -} - -type LoadControlStateDataElementsType struct { - Timestamp *ElementTagType `json:"timestamp"` - EventId *ElementTagType `json:"eventId,omitempty"` - EventStateConsume *ElementTagType `json:"eventStateConsume"` - AppliedEventActionConsume *ElementTagType `json:"appliedEventActionConsume"` - EventStateProduce *ElementTagType `json:"eventStateProduce"` - AppliedEventActionProduce *ElementTagType `json:"appliedEventActionProduce"` -} - -type LoadControlStateListDataType struct { - LoadControlStateData []LoadControlStateDataType `json:"loadControlStateData,omitempty"` -} - -type LoadControlStateListDataSelectorsType struct { - TimestampInterval *TimestampIntervalType `json:"timestampInterval,omitempty"` - EventId *LoadControlEventIdType `json:"eventId,omitempty"` -} - -type LoadControlLimitDataType struct { - LimitId *LoadControlLimitIdType `json:"limitId,omitempty" eebus:"key"` - IsLimitChangeable *bool `json:"isLimitChangeable,omitempty"` - IsLimitActive *bool `json:"isLimitActive,omitempty"` - TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` - Value *ScaledNumberType `json:"value,omitempty"` -} - -type LoadControlLimitDataElementsType struct { - LimitId *ElementTagType `json:"limitId,omitempty"` - IsLimitChangeable *ElementTagType `json:"isLimitChangeable,omitempty"` - IsLimitActive *ElementTagType `json:"isLimitActive,omitempty"` - TimePeriod *TimePeriodElementsType `json:"timePeriod,omitempty"` - Value *ScaledNumberElementsType `json:"value,omitempty"` -} - -type LoadControlLimitListDataType struct { - LoadControlLimitData []LoadControlLimitDataType `json:"loadControlLimitData,omitempty"` -} - -type LoadControlLimitListDataSelectorsType struct { - LimitId *LoadControlLimitIdType `json:"limitId,omitempty"` -} - -type LoadControlLimitConstraintsDataType struct { - LimitId *LoadControlLimitIdType `json:"limitId,omitempty" eebus:"key"` - ValueRangeMin *ScaledNumberType `json:"valueRangeMin,omitempty"` - ValueRangeMax *ScaledNumberType `json:"valueRangeMax,omitempty"` - ValueStepSize *ScaledNumberType `json:"valueStepSize,omitempty"` -} - -type LoadControlLimitConstraintsDataElementsType struct { - LimitId *ElementTagType `json:"limitId,omitempty"` - ValueRangeMin *ScaledNumberElementsType `json:"valueRangeMin,omitempty"` - ValueRangeMax *ScaledNumberElementsType `json:"valueRangeMax,omitempty"` - ValueStepSize *ScaledNumberElementsType `json:"valueStepSize,omitempty"` -} - -type LoadControlLimitConstraintsListDataType struct { - LoadControlLimitConstraintsData []LoadControlLimitConstraintsDataType `json:"loadControlLimitConstraintsData,omitempty"` -} - -type LoadControlLimitConstraintsListDataSelectorsType struct { - LimitId *LoadControlLimitIdType `json:"limitId,omitempty"` -} - -type LoadControlLimitDescriptionDataType struct { - LimitId *LoadControlLimitIdType `json:"limitId,omitempty" eebus:"key"` - LimitType *LoadControlLimitTypeType `json:"limitType,omitempty"` - LimitCategory *LoadControlCategoryType `json:"limitCategory,omitempty"` - LimitDirection *EnergyDirectionType `json:"limitDirection,omitempty"` - MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` - Unit *UnitOfMeasurementType `json:"unit,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type LoadControlLimitDescriptionDataElementsType struct { - LimitId *ElementTagType `json:"limitId,omitempty"` - LimitType *ElementTagType `json:"limitType,omitempty"` - LimitCategory *ElementTagType `json:"limitCategory,omitempty"` - LimitDirection *ElementTagType `json:"limitDirection,omitempty"` - MeasurementId *ElementTagType `json:"measurementId,omitempty"` - Unit *ElementTagType `json:"unit,omitempty"` - ScopeType *ElementTagType `json:"scopeType,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type LoadControlLimitDescriptionListDataType struct { - LoadControlLimitDescriptionData []LoadControlLimitDescriptionDataType `json:"loadControlLimitDescriptionData,omitempty"` -} - -type LoadControlLimitDescriptionListDataSelectorsType struct { - LimitId *LoadControlLimitIdType `json:"limitId,omitempty"` - LimitType *LoadControlLimitTypeType `json:"limitType,omitempty"` - LimitDirection *EnergyDirectionType `json:"limitDirection,omitempty"` - MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` -} diff --git a/spine/model/loadcontrol_additions.go b/spine/model/loadcontrol_additions.go deleted file mode 100644 index 4b05559f..00000000 --- a/spine/model/loadcontrol_additions.go +++ /dev/null @@ -1,66 +0,0 @@ -package model - -// LoadControlEventListDataType - -var _ Updater = (*LoadControlEventListDataType)(nil) - -func (r *LoadControlEventListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []LoadControlEventDataType - if newList != nil { - newData = newList.(*LoadControlEventListDataType).LoadControlEventData - } - - r.LoadControlEventData = UpdateList(r.LoadControlEventData, newData, filterPartial, filterDelete) -} - -// LoadControlStateListDataType - -var _ Updater = (*LoadControlStateListDataType)(nil) - -func (r *LoadControlStateListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []LoadControlStateDataType - if newList != nil { - newData = newList.(*LoadControlStateListDataType).LoadControlStateData - } - - r.LoadControlStateData = UpdateList(r.LoadControlStateData, newData, filterPartial, filterDelete) -} - -// LoadControlLimitListDataType - -var _ Updater = (*LoadControlLimitListDataType)(nil) - -func (r *LoadControlLimitListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []LoadControlLimitDataType - if newList != nil { - newData = newList.(*LoadControlLimitListDataType).LoadControlLimitData - } - - r.LoadControlLimitData = UpdateList(r.LoadControlLimitData, newData, filterPartial, filterDelete) -} - -// LoadControlLimitConstraintsListDataType - -var _ Updater = (*LoadControlLimitConstraintsListDataType)(nil) - -func (r *LoadControlLimitConstraintsListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []LoadControlLimitConstraintsDataType - if newList != nil { - newData = newList.(*LoadControlLimitConstraintsListDataType).LoadControlLimitConstraintsData - } - - r.LoadControlLimitConstraintsData = UpdateList(r.LoadControlLimitConstraintsData, newData, filterPartial, filterDelete) -} - -// LoadControlLimitDescriptionListDataType - -var _ Updater = (*LoadControlLimitDescriptionListDataType)(nil) - -func (r *LoadControlLimitDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []LoadControlLimitDescriptionDataType - if newList != nil { - newData = newList.(*LoadControlLimitDescriptionListDataType).LoadControlLimitDescriptionData - } - - r.LoadControlLimitDescriptionData = UpdateList(r.LoadControlLimitDescriptionData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/loadcontrol_additions_test.go b/spine/model/loadcontrol_additions_test.go deleted file mode 100644 index c204ed51..00000000 --- a/spine/model/loadcontrol_additions_test.go +++ /dev/null @@ -1,199 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestLoadControlEventListDataType_Update(t *testing.T) { - sut := model.LoadControlEventListDataType{ - LoadControlEventData: []model.LoadControlEventDataType{ - { - EventId: util.Ptr(model.LoadControlEventIdType(0)), - EventActionConsume: util.Ptr(model.LoadControlEventActionTypeNormal), - }, - { - EventId: util.Ptr(model.LoadControlEventIdType(1)), - EventActionConsume: util.Ptr(model.LoadControlEventActionTypeNormal), - }, - }, - } - - newData := model.LoadControlEventListDataType{ - LoadControlEventData: []model.LoadControlEventDataType{ - { - EventId: util.Ptr(model.LoadControlEventIdType(1)), - EventActionConsume: util.Ptr(model.LoadControlEventActionTypeIncrease), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.LoadControlEventData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.EventId)) - assert.Equal(t, model.LoadControlEventActionTypeNormal, *item1.EventActionConsume) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.EventId)) - assert.Equal(t, model.LoadControlEventActionTypeIncrease, *item2.EventActionConsume) -} - -func TestLoadControlStateListDataType_Update(t *testing.T) { - sut := model.LoadControlStateListDataType{ - LoadControlStateData: []model.LoadControlStateDataType{ - { - EventId: util.Ptr(model.LoadControlEventIdType(0)), - EventStateConsume: util.Ptr(model.LoadControlEventStateTypeEventAccepted), - }, - { - EventId: util.Ptr(model.LoadControlEventIdType(1)), - EventStateConsume: util.Ptr(model.LoadControlEventStateTypeEventAccepted), - }, - }, - } - - newData := model.LoadControlStateListDataType{ - LoadControlStateData: []model.LoadControlStateDataType{ - { - EventId: util.Ptr(model.LoadControlEventIdType(1)), - EventStateConsume: util.Ptr(model.LoadControlEventStateTypeEventStopped), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.LoadControlStateData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.EventId)) - assert.Equal(t, model.LoadControlEventStateTypeEventAccepted, *item1.EventStateConsume) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.EventId)) - assert.Equal(t, model.LoadControlEventStateTypeEventStopped, *item2.EventStateConsume) -} - -func TestLoadControlLimitListDataType_Update(t *testing.T) { - sut := model.LoadControlLimitListDataType{ - LoadControlLimitData: []model.LoadControlLimitDataType{ - { - LimitId: util.Ptr(model.LoadControlLimitIdType(0)), - IsLimitChangeable: util.Ptr(false), - }, - { - LimitId: util.Ptr(model.LoadControlLimitIdType(1)), - IsLimitChangeable: util.Ptr(false), - }, - }, - } - - newData := model.LoadControlLimitListDataType{ - LoadControlLimitData: []model.LoadControlLimitDataType{ - { - LimitId: util.Ptr(model.LoadControlLimitIdType(1)), - IsLimitChangeable: util.Ptr(true), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.LoadControlLimitData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.LimitId)) - assert.Equal(t, false, *item1.IsLimitChangeable) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.LimitId)) - assert.Equal(t, true, *item2.IsLimitChangeable) -} - -func TestLoadControlLimitConstraintsListDataType_Update(t *testing.T) { - sut := model.LoadControlLimitConstraintsListDataType{ - LoadControlLimitConstraintsData: []model.LoadControlLimitConstraintsDataType{ - { - LimitId: util.Ptr(model.LoadControlLimitIdType(0)), - ValueStepSize: model.NewScaledNumberType(1), - }, - { - LimitId: util.Ptr(model.LoadControlLimitIdType(1)), - ValueStepSize: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.LoadControlLimitConstraintsListDataType{ - LoadControlLimitConstraintsData: []model.LoadControlLimitConstraintsDataType{ - { - LimitId: util.Ptr(model.LoadControlLimitIdType(1)), - ValueStepSize: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.LoadControlLimitConstraintsData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.LimitId)) - assert.Equal(t, 1.0, float64(item1.ValueStepSize.GetValue())) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.LimitId)) - assert.Equal(t, 10.0, float64(item2.ValueStepSize.GetValue())) -} - -func TestLoadControlLimitDescriptionListDataType_Update(t *testing.T) { - sut := model.LoadControlLimitDescriptionListDataType{ - LoadControlLimitDescriptionData: []model.LoadControlLimitDescriptionDataType{ - { - LimitId: util.Ptr(model.LoadControlLimitIdType(0)), - LimitCategory: util.Ptr(model.LoadControlCategoryTypeObligation), - }, - { - LimitId: util.Ptr(model.LoadControlLimitIdType(1)), - LimitCategory: util.Ptr(model.LoadControlCategoryTypeObligation), - }, - }, - } - - newData := model.LoadControlLimitDescriptionListDataType{ - LoadControlLimitDescriptionData: []model.LoadControlLimitDescriptionDataType{ - { - LimitId: util.Ptr(model.LoadControlLimitIdType(1)), - LimitCategory: util.Ptr(model.LoadControlCategoryTypeOptimization), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.LoadControlLimitDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.LimitId)) - assert.Equal(t, model.LoadControlCategoryTypeObligation, *item1.LimitCategory) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.LimitId)) - assert.Equal(t, model.LoadControlCategoryTypeOptimization, *item2.LimitCategory) -} diff --git a/spine/model/measurement.go b/spine/model/measurement.go deleted file mode 100644 index 657a3636..00000000 --- a/spine/model/measurement.go +++ /dev/null @@ -1,190 +0,0 @@ -package model - -type MeasurementIdType uint - -type MeasurementTypeType string - -const ( - MeasurementTypeTypeAcceleration MeasurementTypeType = "acceleration" - MeasurementTypeTypeAngle MeasurementTypeType = "angle" - MeasurementTypeTypeAngularVelocity MeasurementTypeType = "angularVelocity" - MeasurementTypeTypeArea MeasurementTypeType = "area" - MeasurementTypeTypeAtmosphericPressure MeasurementTypeType = "atmosphericPressure" - MeasurementTypeTypeCapacity MeasurementTypeType = "capacity" - MeasurementTypeTypeConcentration MeasurementTypeType = "concentration" - MeasurementTypeTypeCount MeasurementTypeType = "count" - MeasurementTypeTypeCurrent MeasurementTypeType = "current" - MeasurementTypeTypeDensity MeasurementTypeType = "density" - MeasurementTypeTypeDistance MeasurementTypeType = "distance" - MeasurementTypeTypeElectricField MeasurementTypeType = "electricField" - MeasurementTypeTypeEnergy MeasurementTypeType = "energy" - MeasurementTypeTypeForce MeasurementTypeType = "force" - MeasurementTypeTypeFrequency MeasurementTypeType = "frequency" - MeasurementTypeTypeHarmonicDistortion MeasurementTypeType = "harmonicDistortion" - MeasurementTypeTypeHeat MeasurementTypeType = "heat" - MeasurementTypeTypeHeatFlux MeasurementTypeType = "heatFlux" - MeasurementTypeTypeIlluminance MeasurementTypeType = "illuminance" - MeasurementTypeTypeImpulse MeasurementTypeType = "impulse" - MeasurementTypeTypeLevel MeasurementTypeType = "level" - MeasurementTypeTypeMagneticField MeasurementTypeType = "magneticField" - MeasurementTypeTypeMass MeasurementTypeType = "mass" - MeasurementTypeTypeMassFlow MeasurementTypeType = "massFlow" - MeasurementTypeTypeParticles MeasurementTypeType = "particles" - MeasurementTypeTypePercentage MeasurementTypeType = "percentage" - MeasurementTypeTypePower MeasurementTypeType = "power" - MeasurementTypeTypePowerFactor MeasurementTypeType = "powerFactor" - MeasurementTypeTypePressure MeasurementTypeType = "pressure" - MeasurementTypeTypeRadonActivity MeasurementTypeType = "radonActivity" - MeasurementTypeTypeRelativeHumidity MeasurementTypeType = "relativeHumidity" - MeasurementTypeTypeResistance MeasurementTypeType = "resistance" - MeasurementTypeTypeSolarRadiation MeasurementTypeType = "solarRadiation" - MeasurementTypeTypeSpeed MeasurementTypeType = "speed" - MeasurementTypeTypeTemperature MeasurementTypeType = "temperature" - MeasurementTypeTypeTime MeasurementTypeType = "time" - MeasurementTypeTypeTorque MeasurementTypeType = "torque" - MeasurementTypeTypeUnknown MeasurementTypeType = "unknown" - MeasurementTypeTypeVelocity MeasurementTypeType = "velocity" - MeasurementTypeTypeVoltage MeasurementTypeType = "voltage" - MeasurementTypeTypeVolume MeasurementTypeType = "volume" - MeasurementTypeTypeVolumetricFlow MeasurementTypeType = "volumetricFlow" -) - -type MeasurementValueTypeType string - -const ( - MeasurementValueTypeTypeValue MeasurementValueTypeType = "value" - MeasurementValueTypeTypeAverageValue MeasurementValueTypeType = "averageValue" - MeasurementValueTypeTypeMinvValue MeasurementValueTypeType = "minValue" - MeasurementValueTypeTypeMaxvVlue MeasurementValueTypeType = "maxValue" - MeasurementValueTypeTypeStandardDeviation MeasurementValueTypeType = "standardDeviation" -) - -type MeasurementValueSourceType string - -const ( - MeasurementValueSourceTypeMeasuredValue MeasurementValueSourceType = "measuredValue" - MeasurementValueSourceTypeCalculatedValue MeasurementValueSourceType = "calculatedValue" - MeasurementValueSourceTypeEmpiricalValue MeasurementValueSourceType = "empiricalValue" -) - -type MeasurementValueTendencyType string - -const ( - MeasurementValueTendencyTypeRising MeasurementValueTendencyType = "rising" - MeasurementValueTendencyTypeStable MeasurementValueTendencyType = "stable" - MeasurementValueTendencyTypeFalling MeasurementValueTendencyType = "falling" -) - -type MeasurementValueStateType string - -const ( - MeasurementValueStateTypeNormal MeasurementValueStateType = "normal" - MeasurementValueStateTypeOutofrange MeasurementValueStateType = "outOfRange" - MeasurementValueStateTypeError MeasurementValueStateType = "error" -) - -type MeasurementDataType struct { - MeasurementId *MeasurementIdType `json:"measurementId,omitempty" eebus:"key"` - ValueType *MeasurementValueTypeType `json:"valueType,omitempty" eebus:"key"` - Timestamp *AbsoluteOrRelativeTimeType `json:"timestamp,omitempty"` - Value *ScaledNumberType `json:"value,omitempty"` - EvaluationPeriod *TimePeriodType `json:"evaluationPeriod,omitempty"` - ValueSource *MeasurementValueSourceType `json:"valueSource,omitempty"` - ValueTendency *MeasurementValueTendencyType `json:"valueTendency,omitempty"` - ValueState *MeasurementValueStateType `json:"valueState,omitempty"` -} - -type MeasurementDataElementsType struct { - MeasurementId *ElementTagType `json:"measurementId,omitempty"` - ValueType *ElementTagType `json:"valueType,omitempty"` - Timestamp *ElementTagType `json:"timestamp,omitempty"` - Value *ElementTagType `json:"value,omitempty"` - EvaluationPeriod *ElementTagType `json:"evaluationPeriod,omitempty"` - ValueSource *ElementTagType `json:"valueSource,omitempty"` - ValueTendency *ElementTagType `json:"valueTendency,omitempty"` - ValueState *ElementTagType `json:"valueState,omitempty"` -} - -type MeasurementListDataType struct { - MeasurementData []MeasurementDataType `json:"measurementData,omitempty"` -} - -type MeasurementListDataSelectorsType struct { - MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` - ValueType *MeasurementValueTypeType `json:"valueType,omitempty"` - TimestampInterval *TimestampIntervalType `json:"timestampInterval,omitempty"` -} - -type MeasurementConstraintsDataType struct { - MeasurementId *MeasurementIdType `json:"measurementId,omitempty" eebus:"key"` - ValueRangeMin *ScaledNumberType `json:"valueRangeMin,omitempty"` - ValueRangeMax *ScaledNumberType `json:"valueRangeMax,omitempty"` - ValueStepSize *ScaledNumberType `json:"valueStepSize,omitempty"` -} - -type MeasurementConstraintsDataElementsType struct { - MeasurementId *ElementTagType `json:"measurementId,omitempty"` - ValueRangeMin *ScaledNumberElementsType `json:"valueRangeMin,omitempty"` - ValueRangeMax *ScaledNumberElementsType `json:"valueRangeMax,omitempty"` - ValueStepSize *ScaledNumberElementsType `json:"valueStepSize,omitempty"` -} - -type MeasurementConstraintsListDataType struct { - MeasurementConstraintsData []MeasurementConstraintsDataType `json:"measurementConstraintsData,omitempty"` -} - -type MeasurementConstraintsListDataSelectorsType struct { - MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` -} - -type MeasurementDescriptionDataType struct { - MeasurementId *MeasurementIdType `json:"measurementId,omitempty" eebus:"key"` - MeasurementType *MeasurementTypeType `json:"measurementType,omitempty"` - CommodityType *CommodityTypeType `json:"commodityType,omitempty"` - Unit *UnitOfMeasurementType `json:"unit,omitempty"` - CalibrationValue *ScaledNumberType `json:"calibrationValue,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type MeasurementDescriptionDataElementsType struct { - MeasurementId *ElementTagType `json:"measurementId,omitempty"` - MeasurementType *ElementTagType `json:"measurementType,omitempty"` - CommodityType *ElementTagType `json:"commodityType,omitempty"` - Unit *ElementTagType `json:"unit,omitempty"` - CalibrationValue *ScaledNumberElementsType `json:"calibrationValue,omitempty"` - ScopeType *ElementTagType `json:"scopeType,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type MeasurementDescriptionListDataType struct { - MeasurementDescriptionData []MeasurementDescriptionDataType `json:"measurementDescriptionData,omitempty"` -} - -type MeasurementDescriptionListDataSelectorsType struct { - MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` - MeasurementType *MeasurementTypeType `json:"measurementType,omitempty"` - CommodityType *CommodityTypeType `json:"commodityType,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` -} - -type MeasurementThresholdRelationDataType struct { - MeasurementId *MeasurementIdType `json:"measurementId,omitempty" eebus:"key"` - ThresholdId []ThresholdIdType `json:"thresholdId,omitempty"` -} - -type MeasurementThresholdRelationDataElementsType struct { - MeasurementId *ElementTagType `json:"measurementId,omitempty"` - ThresholdId *ElementTagType `json:"thresholdId,omitempty"` -} - -type MeasurementThresholdRelationListDataType struct { - MeasurementThresholdRelationData []MeasurementThresholdRelationDataType `json:"measurementThresholdRelationData,omitempty"` -} - -type MeasurementThresholdRelationListDataSelectorsType struct { - MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` - ThresholdId *ThresholdIdType `json:"thresholdId,omitempty"` -} diff --git a/spine/model/measurement_additions.go b/spine/model/measurement_additions.go deleted file mode 100644 index 4d75432e..00000000 --- a/spine/model/measurement_additions.go +++ /dev/null @@ -1,53 +0,0 @@ -package model - -// MeasurementListDataType - -var _ Updater = (*MeasurementListDataType)(nil) - -func (r *MeasurementListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []MeasurementDataType - if newList != nil { - newData = newList.(*MeasurementListDataType).MeasurementData - } - - r.MeasurementData = UpdateList(r.MeasurementData, newData, filterPartial, filterDelete) -} - -// MeasurementConstraintsListDataType - -var _ Updater = (*MeasurementConstraintsListDataType)(nil) - -func (r *MeasurementConstraintsListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []MeasurementConstraintsDataType - if newList != nil { - newData = newList.(*MeasurementConstraintsListDataType).MeasurementConstraintsData - } - - r.MeasurementConstraintsData = UpdateList(r.MeasurementConstraintsData, newData, filterPartial, filterDelete) -} - -// MeasurementDescriptionListDataType - -var _ Updater = (*MeasurementDescriptionListDataType)(nil) - -func (r *MeasurementDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []MeasurementDescriptionDataType - if newList != nil { - newData = newList.(*MeasurementDescriptionListDataType).MeasurementDescriptionData - } - - r.MeasurementDescriptionData = UpdateList(r.MeasurementDescriptionData, newData, filterPartial, filterDelete) -} - -// MeasurementThresholdRelationListDataType - -var _ Updater = (*MeasurementThresholdRelationListDataType)(nil) - -func (r *MeasurementThresholdRelationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []MeasurementThresholdRelationDataType - if newList != nil { - newData = newList.(*MeasurementThresholdRelationListDataType).MeasurementThresholdRelationData - } - - r.MeasurementThresholdRelationData = UpdateList(r.MeasurementThresholdRelationData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/measurement_additions_test.go b/spine/model/measurement_additions_test.go deleted file mode 100644 index cec94b09..00000000 --- a/spine/model/measurement_additions_test.go +++ /dev/null @@ -1,208 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestMeasurementListDataType_Update_Add(t *testing.T) { - sut := model.MeasurementListDataType{ - MeasurementData: []model.MeasurementDataType{ - { - MeasurementId: util.Ptr(model.MeasurementIdType(0)), - ValueType: util.Ptr(model.MeasurementValueTypeTypeAverageValue), - Value: model.NewScaledNumberType(1), - }, - { - MeasurementId: util.Ptr(model.MeasurementIdType(1)), - ValueType: util.Ptr(model.MeasurementValueTypeTypeAverageValue), - Value: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.MeasurementListDataType{ - MeasurementData: []model.MeasurementDataType{ - { - MeasurementId: util.Ptr(model.MeasurementIdType(1)), - ValueType: util.Ptr(model.MeasurementValueTypeTypeValue), - Value: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.MeasurementData - // check the non changing items - assert.Equal(t, 3, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.MeasurementId)) - assert.Equal(t, model.MeasurementValueTypeTypeAverageValue, *item1.ValueType) - assert.Equal(t, 1.0, item1.Value.GetValue()) - item2 := data[1] - assert.Equal(t, 1, int(*item2.MeasurementId)) - assert.Equal(t, model.MeasurementValueTypeTypeAverageValue, *item2.ValueType) - assert.Equal(t, 1.0, item2.Value.GetValue()) -} - -func TestMeasurementListDataType_Update_Replace(t *testing.T) { - sut := model.MeasurementListDataType{ - MeasurementData: []model.MeasurementDataType{ - { - MeasurementId: util.Ptr(model.MeasurementIdType(0)), - ValueType: util.Ptr(model.MeasurementValueTypeTypeAverageValue), - Value: model.NewScaledNumberType(1), - }, - { - MeasurementId: util.Ptr(model.MeasurementIdType(1)), - ValueType: util.Ptr(model.MeasurementValueTypeTypeValue), - Value: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.MeasurementListDataType{ - MeasurementData: []model.MeasurementDataType{ - { - MeasurementId: util.Ptr(model.MeasurementIdType(1)), - ValueType: util.Ptr(model.MeasurementValueTypeTypeValue), - Value: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.MeasurementData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.MeasurementId)) - assert.Equal(t, model.MeasurementValueTypeTypeAverageValue, *item1.ValueType) - assert.Equal(t, 1.0, item1.Value.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.MeasurementId)) - assert.Equal(t, model.MeasurementValueTypeTypeValue, *item2.ValueType) - assert.Equal(t, 10.0, item2.Value.GetValue()) -} - -func TestMeasurementConstraintsListDataType_Update(t *testing.T) { - sut := model.MeasurementConstraintsListDataType{ - MeasurementConstraintsData: []model.MeasurementConstraintsDataType{ - { - MeasurementId: util.Ptr(model.MeasurementIdType(0)), - ValueStepSize: model.NewScaledNumberType(1), - }, - { - MeasurementId: util.Ptr(model.MeasurementIdType(1)), - ValueStepSize: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.MeasurementConstraintsListDataType{ - MeasurementConstraintsData: []model.MeasurementConstraintsDataType{ - { - MeasurementId: util.Ptr(model.MeasurementIdType(1)), - ValueStepSize: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.MeasurementConstraintsData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.MeasurementId)) - assert.Equal(t, 1.0, item1.ValueStepSize.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.MeasurementId)) - assert.Equal(t, 10.0, item2.ValueStepSize.GetValue()) -} - -func TestMeasurementDescriptionListDataType_Update(t *testing.T) { - sut := model.MeasurementDescriptionListDataType{ - MeasurementDescriptionData: []model.MeasurementDescriptionDataType{ - { - MeasurementId: util.Ptr(model.MeasurementIdType(0)), - ScopeType: util.Ptr(model.ScopeTypeTypeACCurrent), - }, - { - MeasurementId: util.Ptr(model.MeasurementIdType(1)), - ScopeType: util.Ptr(model.ScopeTypeTypeACCurrent), - }, - }, - } - - newData := model.MeasurementDescriptionListDataType{ - MeasurementDescriptionData: []model.MeasurementDescriptionDataType{ - { - MeasurementId: util.Ptr(model.MeasurementIdType(1)), - ScopeType: util.Ptr(model.ScopeTypeTypeACPower), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.MeasurementDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.MeasurementId)) - assert.Equal(t, model.ScopeTypeTypeACCurrent, *item1.ScopeType) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.MeasurementId)) - assert.Equal(t, model.ScopeTypeTypeACPower, *item2.ScopeType) -} - -func TestMeasurementThresholdRelationListDataType_Update(t *testing.T) { - sut := model.MeasurementThresholdRelationListDataType{ - MeasurementThresholdRelationData: []model.MeasurementThresholdRelationDataType{ - { - MeasurementId: util.Ptr(model.MeasurementIdType(0)), - ThresholdId: []model.ThresholdIdType{model.ThresholdIdType(0)}, - }, - { - MeasurementId: util.Ptr(model.MeasurementIdType(1)), - ThresholdId: []model.ThresholdIdType{model.ThresholdIdType(0)}, - }, - }, - } - - newData := model.MeasurementThresholdRelationListDataType{ - MeasurementThresholdRelationData: []model.MeasurementThresholdRelationDataType{ - { - MeasurementId: util.Ptr(model.MeasurementIdType(1)), - ThresholdId: []model.ThresholdIdType{model.ThresholdIdType(1)}, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.MeasurementThresholdRelationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.MeasurementId)) - assert.Equal(t, 0, int(item1.ThresholdId[0])) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.MeasurementId)) - assert.Equal(t, 1, int(item2.ThresholdId[0])) -} diff --git a/spine/model/messaging.go b/spine/model/messaging.go deleted file mode 100644 index 07c606d1..00000000 --- a/spine/model/messaging.go +++ /dev/null @@ -1,39 +0,0 @@ -package model - -type MessagingNumberType uint - -type MessagingDataTextType string - -type MessagingTypeType string - -const ( - MessagingTypeTypeLogging MessagingTypeType = "logging" - MessagingTypeTypeInformation MessagingTypeType = "information" - MessagingTypeTypeWarning MessagingTypeType = "warning" - MessagingTypeTypeAlarm MessagingTypeType = "alarm" - MessagingTypeTypeEmergency MessagingTypeType = "emergency" - MessagingTypeTypeObsolete MessagingTypeType = "obsolete" -) - -type MessagingDataType struct { - Timestamp *AbsoluteOrRelativeTimeType `json:"timestamp,omitempty"` - MessagingNumber *MessagingNumberType `json:"messagingNumber,omitempty" eebus:"key"` - MessagingType *MessagingTypeType `json:"type,omitempty"` // xsd defines "type", but that is a reserved keyword - Text *MessagingDataTextType `json:"text,omitempty"` -} - -type MessagingDataElementsType struct { - Timestamp *ElementTagType `json:"timestamp,omitempty"` - MessagingNumber *ElementTagType `json:"messagingNumber,omitempty"` - MessagingType *ElementTagType `json:"type,omitempty"` - Text *ElementTagType `json:"text,omitempty"` -} - -type MessagingListDataType struct { - MessagingData []MessagingDataType `json:"messagingData,omitempty"` -} - -type MessagingListDataSelectorsType struct { - TimestampInterval *TimestampIntervalType `json:"timestampInterval,omitempty"` - MessagingNumber *MessagingNumberType `json:"messagingNumber,omitempty"` -} diff --git a/spine/model/messaging_additions.go b/spine/model/messaging_additions.go deleted file mode 100644 index d8b89a0d..00000000 --- a/spine/model/messaging_additions.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -// MessagingListDataType - -var _ Updater = (*MessagingListDataType)(nil) - -func (r *MessagingListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []MessagingDataType - if newList != nil { - newData = newList.(*MessagingListDataType).MessagingData - } - - r.MessagingData = UpdateList(r.MessagingData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/messaging_additions_test.go b/spine/model/messaging_additions_test.go deleted file mode 100644 index c2c5d7cb..00000000 --- a/spine/model/messaging_additions_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestMessagingListDataType_Update(t *testing.T) { - sut := model.MessagingListDataType{ - MessagingData: []model.MessagingDataType{ - { - MessagingNumber: util.Ptr(model.MessagingNumberType(0)), - Text: util.Ptr(model.MessagingDataTextType("old")), - }, - { - MessagingNumber: util.Ptr(model.MessagingNumberType(1)), - Text: util.Ptr(model.MessagingDataTextType("old")), - }, - }, - } - - newData := model.MessagingListDataType{ - MessagingData: []model.MessagingDataType{ - { - MessagingNumber: util.Ptr(model.MessagingNumberType(1)), - Text: util.Ptr(model.MessagingDataTextType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.MessagingData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.MessagingNumber)) - assert.Equal(t, "old", string(*item1.Text)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.MessagingNumber)) - assert.Equal(t, "new", string(*item2.Text)) -} diff --git a/spine/model/networkmanagement.go b/spine/model/networkmanagement.go deleted file mode 100644 index 7c6d37c9..00000000 --- a/spine/model/networkmanagement.go +++ /dev/null @@ -1,239 +0,0 @@ -package model - -type NetworkManagementNativeSetupType string - -type NetworkManagementScanSetupType string - -type NetworkManagementSetupType string - -type NetworkManagementCandidateSetupType string - -type NetworkManagementTechnologyAddressType string - -type NetworkManagementCommunicationsTechnologyInformationType string - -type NetworkManagementMinimumTrustLevelType string - -type NetworkManagementProcessTimeoutType DurationType - -type NetworkManagementFeatureSetType string - -const ( - NetworkManagementFeatureSetTypeGateway NetworkManagementFeatureSetType = "gateway" - NetworkManagementFeatureSetTypeRouter NetworkManagementFeatureSetType = "router" - NetworkManagementFeatureSetTypeSmart NetworkManagementFeatureSetType = "smart" - NetworkManagementFeatureSetTypeSimple NetworkManagementFeatureSetType = "simple" -) - -type NetworkManagementProcessStateStateType string - -const ( - NetworkManagementProcessStateStateTypeSucceeded NetworkManagementProcessStateStateType = "succeeded" - NetworkManagementProcessStateStateTypeFailed NetworkManagementProcessStateStateType = "failed" - NetworkManagementProcessStateStateTypeAborted NetworkManagementProcessStateStateType = "aborted" -) - -type NetworkManagementStateChangeType string - -const ( - NetworkManagementStateChangeTypeAdded NetworkManagementStateChangeType = "added" - NetworkManagementStateChangeTypeRemoved NetworkManagementStateChangeType = "removed" - NetworkManagementStateChangeTypeModified NetworkManagementStateChangeType = "modified" -) - -type NetworkManagementAddNodeCallType struct { - NodeAddress *FeatureAddressType `json:"nodeAddress,omitempty"` - NativeSetup *NetworkManagementNativeSetupType `json:"nativeSetup,omitempty"` - Timeout *NetworkManagementProcessTimeoutType `json:"timeout,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type NetworkManagementAddNodeCallElementsType struct { - NodeAddress *FeatureAddressElementsType `json:"nodeAddress,omitempty"` - NativeSetup *ElementTagType `json:"nativeSetup,omitempty"` - Timeout *ElementTagType `json:"timeout,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type NetworkManagementRemoveNodeCallType struct { - NodeAddress *FeatureAddressType `json:"nodeAddress,omitempty"` - Timeout *NetworkManagementProcessTimeoutType `json:"timeout,omitempty"` -} - -type NetworkManagementRemoveNodeCallElementsType struct { - NodeAddress *FeatureAddressElementsType `json:"nodeAddress,omitempty"` - Timeout *ElementTagType `json:"timeout,omitempty"` -} - -type NetworkManagementModifyNodeCallType struct { - NodeAddress *FeatureAddressType `json:"nodeAddress,omitempty"` - NativeSetup *NetworkManagementNativeSetupType `json:"nativeSetup,omitempty"` - Timeout *NetworkManagementProcessTimeoutType `json:"timeout,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type NetworkManagementModifyNodeCallElementsType struct { - NodeAddress *FeatureAddressElementsType `json:"nodeAddress,omitempty"` - NativeSetup *ElementTagType `json:"nativeSetup,omitempty"` - Timeout *ElementTagType `json:"timeout,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type NetworkManagementScanNetworkCallType struct { - ScanSetup *NetworkManagementScanSetupType `json:"scanSetup,omitempty"` - Timeout *NetworkManagementProcessTimeoutType `json:"timeout,omitempty"` -} - -type NetworkManagementScanNetworkCallElementsType struct { - ScanSetup *ElementTagType `json:"scanSetup,omitempty"` - Timeout *ElementTagType `json:"timeout,omitempty"` -} - -type NetworkManagementDiscoverCallType struct { - DiscoverAddress *FeatureAddressType `json:"discoverAddress,omitempty"` -} - -type NetworkManagementDiscoverCallElementsType struct { - DiscoverAddress *FeatureAddressElementsType `json:"discoverAddress,omitempty"` -} - -type NetworkManagementAbortCallType struct{} - -type NetworkManagementAbortCallElementsType struct{} - -type NetworkManagementProcessStateDataType struct { - State *NetworkManagementProcessStateStateType `json:"state,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type NetworkManagementProcessStateDataElementsType struct { - State *ElementTagType `json:"state,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type NetworkManagementJoiningModeDataType struct { - Setup *NetworkManagementSetupType `json:"setup,omitempty"` -} - -type NetworkManagementJoiningModeDataElementsType struct { - Setup *ElementTagType `json:"setup,omitempty"` -} - -type NetworkManagementReportCandidateDataType struct { - CandidateSetup *NetworkManagementCandidateSetupType `json:"candidateSetup,omitempty"` - SetupUsableForAdd *bool `json:"setupUsableForAdd,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type NetworkManagementReportCandidateDataElementsType struct { - CandidateSetup *ElementTagType `json:"candidateSetup,omitempty"` - SetupUsableForAdd *ElementTagType `json:"setupUsableForAdd,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type NetworkManagementDeviceDescriptionDataType struct { - DeviceAddress *DeviceAddressType `json:"deviceAddress,omitempty"` - DeviceType *DeviceTypeType `json:"deviceType,omitempty"` - NetworkManagementResponsibleAddress *FeatureAddressType `json:"networkManagementResponsibleAddress,omitempty"` - NativeSetup *NetworkManagementNativeSetupType `json:"nativeSetup,omitempty"` - TechnologyAddress *NetworkManagementTechnologyAddressType `json:"technologyAddress,omitempty"` - CommunicationsTechnologyInformation *NetworkManagementCommunicationsTechnologyInformationType `json:"communicationsTechnologyInformation,omitempty"` - NetworkFeatureSet *NetworkManagementFeatureSetType `json:"networkFeatureSet,omitempty"` - LastStateChange *NetworkManagementStateChangeType `json:"lastStateChange,omitempty"` - MinimumTrustLevel *NetworkManagementMinimumTrustLevelType `json:"minimumTrustLevel,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type NetworkManagementDeviceDescriptionDataElementsType struct { - DeviceAddress *ElementTagType `json:"deviceAddress,omitempty"` - DeviceType *ElementTagType `json:"deviceType,omitempty"` - NetworkManagementResponsibleAddress *ElementTagType `json:"networkManagementResponsibleAddress,omitempty"` - NativeSetup *ElementTagType `json:"nativeSetup,omitempty"` - TechnologyAddress *ElementTagType `json:"technologyAddress,omitempty"` - CommunicationsTechnologyInformation *ElementTagType `json:"communicationsTechnologyInformation,omitempty"` - NetworkFeatureSet *ElementTagType `json:"networkFeatureSet,omitempty"` - LastStateChange *ElementTagType `json:"lastStateChange,omitempty"` - MinimumTrustLevel *ElementTagType `json:"minimumTrustLevel,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type NetworkManagementDeviceDescriptionListDataType struct { - NetworkManagementDeviceDescriptionData []NetworkManagementDeviceDescriptionDataType `json:"networkManagementDeviceDescriptionData,omitempty"` -} - -type NetworkManagementDeviceDescriptionListDataSelectorsType struct { - DeviceAddress *DeviceAddressType `json:"deviceAddress,omitempty"` - DeviceType *DeviceTypeType `json:"deviceType,omitempty"` -} - -type NetworkManagementEntityDescriptionDataType struct { - EntityAddress *EntityAddressType `json:"entityAddress,omitempty"` - EntityType *EntityTypeType `json:"entityType,omitempty"` - LastStateChange *NetworkManagementStateChangeType `json:"lastStateChange,omitempty"` - MinimumTrustLevel *NetworkManagementMinimumTrustLevelType `json:"minimumTrustLevel,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type NetworkManagementEntityDescriptionDataElementsType struct { - EntityAddress *ElementTagType `json:"entityAddress,omitempty"` - EntityType *ElementTagType `json:"entityType,omitempty"` - LastStateChange *ElementTagType `json:"lastStateChange,omitempty"` - MinimumTrustLevel *ElementTagType `json:"minimumTrustLevel,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type NetworkManagementEntityDescriptionListDataType struct { - NetworkManagementEntityDescriptionData []NetworkManagementEntityDescriptionDataType `json:"networkManagementEntityDescriptionData,omitempty"` -} - -type NetworkManagementEntityDescriptionListDataSelectorsType struct { - EntityAddress *EntityAddressType `json:"entityAddress,omitempty"` - EntityType *EntityTypeType `json:"entityType,omitempty"` -} - -type NetworkManagementFeatureDescriptionDataType struct { - FeatureAddress *FeatureAddressType `json:"featureAddress,omitempty"` - FeatureType *FeatureTypeType `json:"featureType,omitempty"` - SpecificUsage []FeatureSpecificUsageType `json:"specificUsage,omitempty"` - FeatureGroup *FeatureGroupType `json:"featureGroup,omitempty"` - Role *RoleType `json:"role,omitempty"` - SupportedFunction []FunctionPropertyType `json:"supportedFunction,omitempty"` - LastStateChange *NetworkManagementStateChangeType `json:"lastStateChange,omitempty"` - MinimumTrustLevel *NetworkManagementMinimumTrustLevelType `json:"minimumTrustLevel,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` - MaxResponseDelay *MaxResponseDelayType `json:"maxResponseDelay,omitempty"` -} - -type NetworkManagementFeatureDescriptionDataElementsType struct { - FeatureAddress *FeatureAddressElementsType `json:"featureAddress,omitempty"` - FeatureType *ElementTagType `json:"featureType,omitempty"` - SpecificUsage *ElementTagType `json:"specificUsage,omitempty"` - FeatureGroup *ElementTagType `json:"featureGroup,omitempty"` - Role *ElementTagType `json:"role,omitempty"` - SupportedFunction *FunctionPropertyElementsType `json:"supportedFunction,omitempty"` - LastStateChange *ElementTagType `json:"lastStateChange,omitempty"` - MinimumTrustLevel *ElementTagType `json:"minimumTrustLevel,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` - MaxResponseDelay *ElementTagType `json:"maxResponseDelay,omitempty"` -} - -type NetworkManagementFeatureDescriptionListDataType struct { - NetworkManagementFeatureDescriptionData []NetworkManagementFeatureDescriptionDataType `json:"networkManagementFeatureDescriptionData,omitempty"` -} - -type NetworkManagementFeatureDescriptionListDataSelectorsType struct { - FeatureAddress *FeatureAddressType `json:"featureAddress,omitempty"` - FeatureType *FeatureTypeType `json:"featureType,omitempty"` -} diff --git a/spine/model/networkmanagement_additions.go b/spine/model/networkmanagement_additions.go deleted file mode 100644 index fbca8e81..00000000 --- a/spine/model/networkmanagement_additions.go +++ /dev/null @@ -1,40 +0,0 @@ -package model - -// NetworkManagementDeviceDescriptionListDataType - -var _ Updater = (*NetworkManagementDeviceDescriptionListDataType)(nil) - -func (r *NetworkManagementDeviceDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []NetworkManagementDeviceDescriptionDataType - if newList != nil { - newData = newList.(*NetworkManagementDeviceDescriptionListDataType).NetworkManagementDeviceDescriptionData - } - - r.NetworkManagementDeviceDescriptionData = UpdateList(r.NetworkManagementDeviceDescriptionData, newData, filterPartial, filterDelete) -} - -// NetworkManagementEntityDescriptionListDataType - -var _ Updater = (*NetworkManagementEntityDescriptionListDataType)(nil) - -func (r *NetworkManagementEntityDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []NetworkManagementEntityDescriptionDataType - if newList != nil { - newData = newList.(*NetworkManagementEntityDescriptionListDataType).NetworkManagementEntityDescriptionData - } - - r.NetworkManagementEntityDescriptionData = UpdateList(r.NetworkManagementEntityDescriptionData, newData, filterPartial, filterDelete) -} - -// NetworkManagementFeatureDescriptionListDataType - -var _ Updater = (*NetworkManagementFeatureDescriptionListDataType)(nil) - -func (r *NetworkManagementFeatureDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []NetworkManagementFeatureDescriptionDataType - if newList != nil { - newData = newList.(*NetworkManagementFeatureDescriptionListDataType).NetworkManagementFeatureDescriptionData - } - - r.NetworkManagementFeatureDescriptionData = UpdateList(r.NetworkManagementFeatureDescriptionData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/nodemanagement.go b/spine/model/nodemanagement.go deleted file mode 100644 index afbd6e4a..00000000 --- a/spine/model/nodemanagement.go +++ /dev/null @@ -1,136 +0,0 @@ -package model - -type NodeManagementSpecificationVersionListType struct { - SpecificationVersion []SpecificationVersionDataType `json:"specificationVersion,omitempty"` -} -type NodeManagementSpecificationVersionListElementsType struct { - SpecificationVersion *SpecificationVersionDataElementsType `json:"specificationVersion,omitempty"` -} - -type NodeManagementDetailedDiscoveryDeviceInformationType struct { - Description *NetworkManagementDeviceDescriptionDataType `json:"description,omitempty"` -} - -type NodeManagementDetailedDiscoveryDeviceInformationElementsType struct { - Description *NetworkManagementDeviceDescriptionDataElementsType `json:"description,omitempty"` -} - -type NodeManagementDetailedDiscoveryEntityInformationType struct { - Description *NetworkManagementEntityDescriptionDataType `json:"description,omitempty"` -} - -type NodeManagementDetailedDiscoveryEntityInformationElementsType struct { - Description *NetworkManagementEntityDescriptionDataElementsType `json:"description,omitempty"` -} - -type NodeManagementDetailedDiscoveryFeatureInformationType struct { - Description *NetworkManagementFeatureDescriptionDataType `json:"description,omitempty"` -} - -type NodeManagementDetailedDiscoveryFeatureInformationElementsType struct { - Description *NetworkManagementFeatureDescriptionDataElementsType `json:"description,omitempty"` -} - -type NodeManagementDetailedDiscoveryDataType struct { - SpecificationVersionList *NodeManagementSpecificationVersionListType `json:"specificationVersionList,omitempty"` - DeviceInformation *NodeManagementDetailedDiscoveryDeviceInformationType `json:"deviceInformation,omitempty"` - EntityInformation []NodeManagementDetailedDiscoveryEntityInformationType `json:"entityInformation,omitempty"` - FeatureInformation []NodeManagementDetailedDiscoveryFeatureInformationType `json:"featureInformation,omitempty"` -} - -type NodeManagementDetailedDiscoveryDataElementsType struct { - SpecificationVersionList *NodeManagementSpecificationVersionListElementsType `json:"specificationVersionList,omitempty"` - DeviceInformation *NodeManagementDetailedDiscoveryDeviceInformationElementsType `json:"deviceInformation,omitempty"` - EntityInformation *NodeManagementDetailedDiscoveryEntityInformationElementsType `json:"entityInformation,omitempty"` - FeatureInformation *NodeManagementDetailedDiscoveryFeatureInformationElementsType `json:"featureInformation,omitempty"` -} - -type NodeManagementDetailedDiscoveryDataSelectorsType struct { - DeviceInformation *NetworkManagementDeviceDescriptionListDataSelectorsType `json:"deviceInformation,omitempty"` - EntityInformation *NetworkManagementEntityDescriptionListDataSelectorsType `json:"entityInformation,omitempty"` - FeatureInformation *NetworkManagementFeatureDescriptionListDataSelectorsType `json:"featureInformation,omitempty"` -} - -type NodeManagementBindingDataType struct { - BindingEntry []BindingManagementEntryDataType `json:"bindingEntry,omitempty"` -} - -type NodeManagementBindingDataElementsType struct { - BindingEntry *BindingManagementEntryDataElementsType `json:"bindingEntry,omitempty"` -} - -type NodeManagementBindingDataSelectorsType struct { - BindingEntry *BindingManagementEntryListDataSelectorsType `json:"bindingEntry,omitempty"` -} - -type NodeManagementBindingRequestCallType struct { - BindingRequest *BindingManagementRequestCallType `json:"bindingRequest,omitempty"` -} - -type NodeManagementBindingRequestCallElementsType struct { - BindingRequest *BindingManagementRequestCallElementsType `json:"bindingRequest,omitempty"` -} - -type NodeManagementBindingDeleteCallType struct { - BindingDelete *BindingManagementDeleteCallType `json:"bindingDelete,omitempty"` -} - -type NodeManagementBindingDeleteCallElementsType struct { - BindingDelete *BindingManagementDeleteCallElementsType `json:"bindingDelete,omitempty"` -} - -type NodeManagementSubscriptionDataType struct { - SubscriptionEntry []SubscriptionManagementEntryDataType `json:"subscriptionEntry,omitempty"` -} - -type NodeManagementSubscriptionDataElementsType struct { - SubscriptionEntry *SubscriptionManagementEntryDataElementsType `json:"subscriptionEntry,omitempty"` -} - -type NodeManagementSubscriptionDataSelectorsType struct { - SubscriptionEntry *SubscriptionManagementEntryListDataSelectorsType `json:"subscriptionEntry,omitempty"` -} - -type NodeManagementSubscriptionRequestCallType struct { - SubscriptionRequest *SubscriptionManagementRequestCallType `json:"subscriptionRequest,omitempty"` -} - -type NodeManagementSubscriptionRequestCallElementsType struct { - SubscriptionRequest *SubscriptionManagementRequestCallElementsType `json:"subscriptionRequest,omitempty"` -} - -type NodeManagementSubscriptionDeleteCallType struct { - SubscriptionDelete *SubscriptionManagementDeleteCallType `json:"subscriptionDelete,omitempty"` -} - -type NodeManagementSubscriptionDeleteCallElementsType struct { - SubscriptionDelete *SubscriptionManagementDeleteCallElementsType `json:"subscriptionDelete,omitempty"` -} - -type NodeManagementDestinationDataType struct { - DeviceDescription *NetworkManagementDeviceDescriptionDataType `json:"deviceDescription,omitempty"` -} - -type NodeManagementDestinationDataElementsType struct { - DeviceDescription *NetworkManagementDeviceDescriptionDataElementsType `json:"deviceDescription,omitempty"` -} - -type NodeManagementDestinationListDataType struct { - NodeManagementDestinationData []NodeManagementDestinationDataType `json:"nodeManagementDestinationData,omitempty"` -} - -type NodeManagementDestinationListDataSelectorsType struct { - DeviceDescription *NetworkManagementDeviceDescriptionListDataSelectorsType `json:"deviceDescription,omitempty"` -} - -type NodeManagementUseCaseDataType struct { - UseCaseInformation []UseCaseInformationDataType `json:"useCaseInformation,omitempty"` -} - -type NodeManagementUseCaseDataElementsType struct { - UseCaseInformation *UseCaseInformationDataElementsType `json:"useCaseInformation,omitempty"` -} - -type NodeManagementUseCaseDataSelectorsType struct { - UseCaseInformation *UseCaseInformationListDataSelectorsType `json:"useCaseInformation,omitempty"` -} diff --git a/spine/model/nodemanagement_additions.go b/spine/model/nodemanagement_additions.go deleted file mode 100644 index a3466f67..00000000 --- a/spine/model/nodemanagement_additions.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -// NodeManagementDestinationListDataType - -var _ Updater = (*NodeManagementDestinationListDataType)(nil) - -func (r *NodeManagementDestinationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []NodeManagementDestinationDataType - if newList != nil { - newData = newList.(*NodeManagementDestinationListDataType).NodeManagementDestinationData - } - - r.NodeManagementDestinationData = UpdateList(r.NodeManagementDestinationData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/operatingconstraints.go b/spine/model/operatingconstraints.go deleted file mode 100644 index 5d760489..00000000 --- a/spine/model/operatingconstraints.go +++ /dev/null @@ -1,143 +0,0 @@ -package model - -type OperatingConstraintsInterruptDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - IsPausable *bool `json:"isPausable,omitempty"` - IsStoppable *bool `json:"isStoppable,omitempty"` - NotInterruptibleAtHighPower *bool `json:"notInterruptibleAtHighPower,omitempty"` - MaxCyclesPerDay *uint `json:"maxCyclesPerDay,omitempty"` -} - -type OperatingConstraintsInterruptDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - IsPausable *ElementTagType `json:"isPausable,omitempty"` - IsStoppable *ElementTagType `json:"isStoppable,omitempty"` - NotInterruptibleAtHighPower *ElementTagType `json:"notInterruptibleAtHighPower,omitempty"` - MaxCyclesPerDay *ElementTagType `json:"maxCyclesPerDay,omitempty"` -} - -type OperatingConstraintsInterruptListDataType struct { - OperatingConstraintsInterruptData []OperatingConstraintsInterruptDataType `json:"operatingConstraintsInterruptData,omitempty"` -} - -type OperatingConstraintsInterruptListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type OperatingConstraintsDurationDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - ActiveDurationMin *DurationType `json:"activeDurationMin,omitempty"` - ActiveDurationMax *DurationType `json:"activeDurationMax,omitempty"` - PauseDurationMin *DurationType `json:"pauseDurationMin,omitempty"` - PauseDurationMax *DurationType `json:"pauseDurationMax,omitempty"` - ActiveDurationSumMin *DurationType `json:"activeDurationSumMin,omitempty"` - ActiveDurationSumMax *DurationType `json:"activeDurationSumMax,omitempty"` -} - -type OperatingConstraintsDurationDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - ActiveDurationMin *ElementTagType `json:"activeDurationMin,omitempty"` - ActiveDurationMax *ElementTagType `json:"activeDurationMax,omitempty"` - PauseDurationMin *ElementTagType `json:"pauseDurationMin,omitempty"` - PauseDurationMax *ElementTagType `json:"pauseDurationMax,omitempty"` - ActiveDurationSumMin *ElementTagType `json:"activeDurationSumMin,omitempty"` - ActiveDurationSumMax *ElementTagType `json:"activeDurationSumMax,omitempty"` -} - -type OperatingConstraintsDurationListDataType struct { - OperatingConstraintsDurationData []OperatingConstraintsDurationDataType `json:"operatingConstraintsDurationData,omitempty"` -} - -type OperatingConstraintsDurationListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type OperatingConstraintsPowerDescriptionDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - PositiveEnergyDirection *EnergyDirectionType `json:"positiveEnergyDirection,omitempty"` - PowerUnit *UnitOfMeasurementType `json:"powerUnit,omitempty"` - EnergyUnit *UnitOfMeasurementType `json:"energyUnit,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type OperatingConstraintsPowerDescriptionDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - PositiveEnergyDirection *ElementTagType `json:"positiveEnergyDirection,omitempty"` - PowerUnit *ElementTagType `json:"powerUnit,omitempty"` - EnergyUnit *ElementTagType `json:"energyUnit,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type OperatingConstraintsPowerDescriptionListDataType struct { - OperatingConstraintsPowerDescriptionData []OperatingConstraintsPowerDescriptionDataType `json:"operatingConstraintsPowerDescriptionData,omitempty"` -} - -type OperatingConstraintsPowerDescriptionListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type OperatingConstraintsPowerRangeDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - PowerMin *ScaledNumberType `json:"powerMin,omitempty"` - PowerMax *ScaledNumberType `json:"powerMax,omitempty"` - EnergyMin *ScaledNumberType `json:"energyMin,omitempty"` - EnergyMax *ScaledNumberType `json:"energyMax,omitempty"` -} - -type OperatingConstraintsPowerRangeDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - PowerMin *ElementTagType `json:"powerMin,omitempty"` - PowerMax *ElementTagType `json:"powerMax,omitempty"` - EnergyMin *ElementTagType `json:"energyMin,omitempty"` - EnergyMax *ElementTagType `json:"energyMax,omitempty"` -} - -type OperatingConstraintsPowerRangeListDataType struct { - OperatingConstraintsPowerRangeData []OperatingConstraintsPowerRangeDataType `json:"operatingConstraintsPowerRangeData,omitempty"` -} - -type OperatingConstraintsPowerRangeListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type OperatingConstraintsPowerLevelDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - Power *ScaledNumberType `json:"power,omitempty"` -} - -type OperatingConstraintsPowerLevelDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - Power *ElementTagType `json:"power,omitempty"` -} - -type OperatingConstraintsPowerLevelListDataType struct { - OperatingConstraintsPowerLevelData []OperatingConstraintsPowerLevelDataType `json:"operatingConstraintsPowerLevelData,omitempty"` -} - -type OperatingConstraintsPowerLevelListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type OperatingConstraintsResumeImplicationDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - ResumeEnergyEstimated *ScaledNumberType `json:"resumeEnergyEstimated,omitempty"` - EnergyUnit *UnitOfMeasurementType `json:"energyUnit,omitempty"` - ResumeCostEstimated *ScaledNumberType `json:"resumeCostEstimated,omitempty"` - Currency *CurrencyType `json:"currency,omitempty"` -} - -type OperatingConstraintsResumeImplicationDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - ResumeEnergyEstimated *ScaledNumberElementsType `json:"resumeEnergyEstimated,omitempty"` - EnergyUnit *ElementTagType `json:"energyUnit,omitempty"` - ResumeCostEstimated *ScaledNumberElementsType `json:"resumeCostEstimated,omitempty"` - Currency *ElementTagType `json:"currency,omitempty"` -} - -type OperatingConstraintsResumeImplicationListDataType struct { - OperatingConstraintsResumeImplicationData []OperatingConstraintsResumeImplicationDataType `json:"operatingConstraintsResumeImplicationData,omitempty"` -} - -type OperatingConstraintsResumeImplicationListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} diff --git a/spine/model/operatingconstraints_additions.go b/spine/model/operatingconstraints_additions.go deleted file mode 100644 index 7070c1b3..00000000 --- a/spine/model/operatingconstraints_additions.go +++ /dev/null @@ -1,79 +0,0 @@ -package model - -// OperatingConstraintsInterruptListDataType - -var _ Updater = (*OperatingConstraintsInterruptListDataType)(nil) - -func (r *OperatingConstraintsInterruptListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []OperatingConstraintsInterruptDataType - if newList != nil { - newData = newList.(*OperatingConstraintsInterruptListDataType).OperatingConstraintsInterruptData - } - - r.OperatingConstraintsInterruptData = UpdateList(r.OperatingConstraintsInterruptData, newData, filterPartial, filterDelete) -} - -// OperatingConstraintsDurationListDataType - -var _ Updater = (*OperatingConstraintsDurationListDataType)(nil) - -func (r *OperatingConstraintsDurationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []OperatingConstraintsDurationDataType - if newList != nil { - newData = newList.(*OperatingConstraintsDurationListDataType).OperatingConstraintsDurationData - } - - r.OperatingConstraintsDurationData = UpdateList(r.OperatingConstraintsDurationData, newData, filterPartial, filterDelete) -} - -// OperatingConstraintsPowerDescriptionListDataType - -var _ Updater = (*OperatingConstraintsPowerDescriptionListDataType)(nil) - -func (r *OperatingConstraintsPowerDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []OperatingConstraintsPowerDescriptionDataType - if newList != nil { - newData = newList.(*OperatingConstraintsPowerDescriptionListDataType).OperatingConstraintsPowerDescriptionData - } - - r.OperatingConstraintsPowerDescriptionData = UpdateList(r.OperatingConstraintsPowerDescriptionData, newData, filterPartial, filterDelete) -} - -// OperatingConstraintsPowerRangeListDataType - -var _ Updater = (*OperatingConstraintsPowerRangeListDataType)(nil) - -func (r *OperatingConstraintsPowerRangeListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []OperatingConstraintsPowerRangeDataType - if newList != nil { - newData = newList.(*OperatingConstraintsPowerRangeListDataType).OperatingConstraintsPowerRangeData - } - - r.OperatingConstraintsPowerRangeData = UpdateList(r.OperatingConstraintsPowerRangeData, newData, filterPartial, filterDelete) -} - -// OperatingConstraintsPowerLevelListDataType - -var _ Updater = (*OperatingConstraintsPowerLevelListDataType)(nil) - -func (r *OperatingConstraintsPowerLevelListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []OperatingConstraintsPowerLevelDataType - if newList != nil { - newData = newList.(*OperatingConstraintsPowerLevelListDataType).OperatingConstraintsPowerLevelData - } - - r.OperatingConstraintsPowerLevelData = UpdateList(r.OperatingConstraintsPowerLevelData, newData, filterPartial, filterDelete) -} - -// OperatingConstraintsResumeImplicationListDataType - -var _ Updater = (*OperatingConstraintsResumeImplicationListDataType)(nil) - -func (r *OperatingConstraintsResumeImplicationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []OperatingConstraintsResumeImplicationDataType - if newList != nil { - newData = newList.(*OperatingConstraintsResumeImplicationListDataType).OperatingConstraintsResumeImplicationData - } - - r.OperatingConstraintsResumeImplicationData = UpdateList(r.OperatingConstraintsResumeImplicationData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/operatingconstraints_additions_test.go b/spine/model/operatingconstraints_additions_test.go deleted file mode 100644 index c9a715a2..00000000 --- a/spine/model/operatingconstraints_additions_test.go +++ /dev/null @@ -1,240 +0,0 @@ -package model_test - -import ( - "testing" - "time" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestOperatingConstraintsInterruptListDataType_Update(t *testing.T) { - sut := model.OperatingConstraintsInterruptListDataType{ - OperatingConstraintsInterruptData: []model.OperatingConstraintsInterruptDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - IsPausable: util.Ptr(false), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - IsPausable: util.Ptr(false), - }, - }, - } - - newData := model.OperatingConstraintsInterruptListDataType{ - OperatingConstraintsInterruptData: []model.OperatingConstraintsInterruptDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - IsPausable: util.Ptr(true), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.OperatingConstraintsInterruptData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, false, *item1.IsPausable) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, true, *item2.IsPausable) -} - -func TestOperatingConstraintsDurationListDataType_Update(t *testing.T) { - sut := model.OperatingConstraintsDurationListDataType{ - OperatingConstraintsDurationData: []model.OperatingConstraintsDurationDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - ActiveDurationMin: model.NewDurationType(1 * time.Second), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - ActiveDurationMin: model.NewDurationType(1 * time.Second), - }, - }, - } - - newData := model.OperatingConstraintsDurationListDataType{ - OperatingConstraintsDurationData: []model.OperatingConstraintsDurationDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - ActiveDurationMin: model.NewDurationType(10 * time.Second), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.OperatingConstraintsDurationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - duration, _ := item1.ActiveDurationMin.GetTimeDuration() - assert.Equal(t, time.Duration(1*time.Second), duration) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - duration, _ = item2.ActiveDurationMin.GetTimeDuration() - assert.Equal(t, time.Duration(10*time.Second), duration) -} - -func TestOperatingConstraintsPowerDescriptionListDataType_Update(t *testing.T) { - sut := model.OperatingConstraintsPowerDescriptionListDataType{ - OperatingConstraintsPowerDescriptionData: []model.OperatingConstraintsPowerDescriptionDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - PositiveEnergyDirection: util.Ptr(model.EnergyDirectionTypeConsume), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - PositiveEnergyDirection: util.Ptr(model.EnergyDirectionTypeConsume), - }, - }, - } - - newData := model.OperatingConstraintsPowerDescriptionListDataType{ - OperatingConstraintsPowerDescriptionData: []model.OperatingConstraintsPowerDescriptionDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - PositiveEnergyDirection: util.Ptr(model.EnergyDirectionTypeProduce), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.OperatingConstraintsPowerDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, model.EnergyDirectionTypeConsume, *item1.PositiveEnergyDirection) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, model.EnergyDirectionTypeProduce, *item2.PositiveEnergyDirection) -} - -func TestOperatingConstraintsPowerRangeListDataType_Update(t *testing.T) { - sut := model.OperatingConstraintsPowerRangeListDataType{ - OperatingConstraintsPowerRangeData: []model.OperatingConstraintsPowerRangeDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - PowerMin: model.NewScaledNumberType(1), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - PowerMin: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.OperatingConstraintsPowerRangeListDataType{ - OperatingConstraintsPowerRangeData: []model.OperatingConstraintsPowerRangeDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - PowerMin: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.OperatingConstraintsPowerRangeData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, 1.0, item1.PowerMin.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, 10.0, item2.PowerMin.GetValue()) -} - -func TestOperatingConstraintsPowerLevelListDataType_Update(t *testing.T) { - sut := model.OperatingConstraintsPowerLevelListDataType{ - OperatingConstraintsPowerLevelData: []model.OperatingConstraintsPowerLevelDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - Power: model.NewScaledNumberType(1), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - Power: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.OperatingConstraintsPowerLevelListDataType{ - OperatingConstraintsPowerLevelData: []model.OperatingConstraintsPowerLevelDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - Power: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.OperatingConstraintsPowerLevelData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, 1.0, item1.Power.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, 10.0, item2.Power.GetValue()) -} - -func TestOperatingConstraintsResumeImplicationListDataType_Update(t *testing.T) { - sut := model.OperatingConstraintsResumeImplicationListDataType{ - OperatingConstraintsResumeImplicationData: []model.OperatingConstraintsResumeImplicationDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - ResumeEnergyEstimated: model.NewScaledNumberType(1), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - ResumeEnergyEstimated: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.OperatingConstraintsResumeImplicationListDataType{ - OperatingConstraintsResumeImplicationData: []model.OperatingConstraintsResumeImplicationDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - ResumeEnergyEstimated: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.OperatingConstraintsResumeImplicationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, 1.0, item1.ResumeEnergyEstimated.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, 10.0, item2.ResumeEnergyEstimated.GetValue()) -} diff --git a/spine/model/powersequences.go b/spine/model/powersequences.go deleted file mode 100644 index 8ac515ef..00000000 --- a/spine/model/powersequences.go +++ /dev/null @@ -1,331 +0,0 @@ -package model - -type AlternativesIdType uint - -type PowerSequenceIdType uint - -type PowerTimeSlotNumberType uint - -type PowerTimeSlotValueTypeType string - -const ( - PowerTimeSlotValueTypeTypePower PowerTimeSlotValueTypeType = "power" - PowerTimeSlotValueTypeTypePowerMin PowerTimeSlotValueTypeType = "powerMin" - PowerTimeSlotValueTypeTypePowerMax PowerTimeSlotValueTypeType = "powerMax" - PowerTimeSlotValueTypeTypePowerExpectedValue PowerTimeSlotValueTypeType = "powerExpectedValue" - PowerTimeSlotValueTypeTypePowerStandardDeviation PowerTimeSlotValueTypeType = "powerStandardDeviation" - PowerTimeSlotValueTypeTypePowerSkewness PowerTimeSlotValueTypeType = "powerSkewness" - PowerTimeSlotValueTypeTypeEnergy PowerTimeSlotValueTypeType = "energy" - PowerTimeSlotValueTypeTypeEnergyMin PowerTimeSlotValueTypeType = "energyMin" - PowerTimeSlotValueTypeTypeEnergyMax PowerTimeSlotValueTypeType = "energyMax" - PowerTimeSlotValueTypeTypeEnergyExpectedValue PowerTimeSlotValueTypeType = "energyExpectedValue" - PowerTimeSlotValueTypeTypeEnergyStandardDeviation PowerTimeSlotValueTypeType = "energyStandardDeviation" - PowerTimeSlotValueTypeTypeEnergySkewness PowerTimeSlotValueTypeType = "energySkewness" -) - -type PowerSequenceScopeType string - -const ( - PowerSequenceScopeTypeForecast PowerSequenceScopeType = "forecast" - PowerSequenceScopeTypeMeasurement PowerSequenceScopeType = "measurement" - PowerSequenceScopeTypeRecommendation PowerSequenceScopeType = "recommendation" -) - -type PowerSequenceStateType string - -const ( - PowerSequenceStateTypeRunning PowerSequenceStateType = "running" - PowerSequenceStateTypePaused PowerSequenceStateType = "paused" - PowerSequenceStateTypeScheduled PowerSequenceStateType = "scheduled" - PowerSequenceStateTypeScheduledPaused PowerSequenceStateType = "scheduledPaused" - PowerSequenceStateTypePending PowerSequenceStateType = "pending" - PowerSequenceStateTypeInactive PowerSequenceStateType = "inactive" - PowerSequenceStateTypeCompleted PowerSequenceStateType = "completed" - PowerSequenceStateTypeInvalid PowerSequenceStateType = "invalid" -) - -type PowerTimeSlotScheduleDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - SlotNumber *PowerTimeSlotNumberType `json:"slotNumber,omitempty"` - TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` - DefaultDuration *DurationType `json:"defaultDuration,omitempty"` - DurationUncertainty *DurationType `json:"durationUncertainty,omitempty"` - SlotActivated *bool `json:"slotActivated,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type PowerTimeSlotScheduleDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - SlotNumber *ElementTagType `json:"slotNumber,omitempty"` - TimePeriod *ElementTagType `json:"timePeriod,omitempty"` - DefaultDuration *ElementTagType `json:"defaultDuration,omitempty"` - DurationUncertainty *ElementTagType `json:"durationUncertainty,omitempty"` - SlotActivated *ElementTagType `json:"slotActivated,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type PowerTimeSlotScheduleListDataType struct { - PowerTimeSlotScheduleData []PowerTimeSlotScheduleDataType `json:"powerTimeSlotScheduleData,omitempty"` -} - -type PowerTimeSlotScheduleListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` - SlotNumber *PowerTimeSlotNumberType `json:"slotNumber,omitempty"` -} - -type PowerTimeSlotValueDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - SlotNumber *PowerTimeSlotNumberType `json:"slotNumber,omitempty"` - ValueType *PowerTimeSlotValueTypeType `json:"valueType,omitempty"` - Value *ScaledNumberType `json:"value,omitempty"` -} - -type PowerTimeSlotValueDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - SlotNumber *ElementTagType `json:"slotNumber,omitempty"` - ValueType *ElementTagType `json:"valueType,omitempty"` - Value *ScaledNumberElementsType `json:"value,omitempty"` -} - -type PowerTimeSlotValueListDataType struct { - PowerTimeSlotValueData []PowerTimeSlotValueDataType `json:"powerTimeSlotValueListData,omitempty"` -} - -type PowerTimeSlotValueListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` - SlotNumber *PowerTimeSlotNumberType `json:"slotNumber,omitempty"` - ValueType *PowerTimeSlotValueTypeType `json:"valueType,omitempty"` -} - -type PowerTimeSlotScheduleConstraintsDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - SlotNumber *PowerTimeSlotNumberType `json:"slotNumber,omitempty"` - EarliestStartTime *AbsoluteOrRelativeTimeType `json:"earliestStartTime,omitempty"` - LatestEndTime *AbsoluteOrRelativeTimeType `json:"latestEndTime,omitempty"` - MinDuration *DurationType `json:"minDuration,omitempty"` - MaxDuration *DurationType `json:"maxDuration,omitempty"` - OptionalSlot *bool `json:"optionalSlot,omitempty"` -} - -type PowerTimeSlotScheduleConstraintsDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - SlotNumber *ElementTagType `json:"slotNumber,omitempty"` - EarliestStartTime *ElementTagType `json:"earliestStartTime,omitempty"` - LatestEndTime *ElementTagType `json:"latestEndTime,omitempty"` - MinDuration *ElementTagType `json:"minDuration,omitempty"` - MaxDuration *ElementTagType `json:"maxDuration,omitempty"` - OptionalSlot *ElementTagType `json:"optionalSlot,omitempty"` -} - -type PowerTimeSlotScheduleConstraintsListDataType struct { - PowerTimeSlotScheduleConstraintsData []PowerTimeSlotScheduleConstraintsDataType `json:"powerTimeSlotScheduleConstraintsData,omitempty"` -} - -type PowerTimeSlotScheduleConstraintsListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` - SlotNumber *PowerTimeSlotNumberType `json:"slotNumber,omitempty"` -} - -type PowerSequenceAlternativesRelationDataType struct { - AlternativeId *AlternativesIdType `json:"alternativeId,omitempty" eebus:"key"` - SequenceId []PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type PowerSequenceAlternativesRelationDataElementsType struct { - AlternativeId *ElementTagType `json:"alternativeId,omitempty"` - SequenceId *ElementTagType `json:"sequenceId,omitempty"` -} - -type PowerSequenceAlternativesRelationListDataType struct { - PowerSequenceAlternativesRelationData []PowerSequenceAlternativesRelationDataType `json:"powerSequenceAlternativesRelationData,omitempty"` -} - -type PowerSequenceAlternativesRelationListDataSelectorsType struct { - AlternativeId *AlternativesIdType `json:"alternativeId,omitempty"` - SequenceId []PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type PowerSequenceDescriptionDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - Description *DescriptionType `json:"description,omitempty"` - PositiveEnergyDirection *EnergyDirectionType `json:"positiveEnergyDirection,omitempty"` - PowerUnit *UnitOfMeasurementType `json:"powerUnit,omitempty"` - EnergyUnit *UnitOfMeasurementType `json:"energyUnit,omitempty"` - ValueSource *MeasurementValueSourceType `json:"valueSource,omitempty"` - Scope *PowerSequenceScopeType `json:"scope,omitempty"` - TaskIdentifier *uint `json:"taskIdentifier,omitempty"` - RepetitionsTotal *uint `json:"repetitionsTotal,omitempty"` -} - -type PowerSequenceDescriptionDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - Description *ElementTagType `json:"description,omitempty"` - PositiveEnergyDirection *ElementTagType `json:"positiveEnergyDirection,omitempty"` - PowerUnit *ElementTagType `json:"powerUnit,omitempty"` - EnergyUnit *ElementTagType `json:"energyUnit,omitempty"` - ValueSource *ElementTagType `json:"valueSource,omitempty"` - Scope *ElementTagType `json:"scope,omitempty"` - TaskIdentifier *ElementTagType `json:"taskIdentifier,omitempty"` - RepetitionsTotal *ElementTagType `json:"repetitionsTotal,omitempty"` -} - -type PowerSequenceDescriptionListDataType struct { - PowerSequenceDescriptionData []PowerSequenceDescriptionDataType `json:"powerSequenceDescriptionData,omitempty"` -} - -type PowerSequenceDescriptionListDataSelectorsType struct { - SequenceId []PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type PowerSequenceStateDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - State *PowerSequenceStateType `json:"state,omitempty"` - ActiveSlotNumber *PowerTimeSlotNumberType `json:"activeSlotNumber,omitempty"` - ElapsedSlotTime *DurationType `json:"elapsedSlotTime,omitempty"` - RemainingSlotTime *DurationType `json:"remainingSlotTime,omitempty"` - SequenceRemoteControllable *bool `json:"sequenceRemoteControllable,omitempty"` - ActiveRepetitionNumber *uint `json:"activeRepetitionNumber,omitempty"` - RemainingPauseTime *DurationType `json:"remainingPauseTime,omitempty"` -} - -type PowerSequenceStateDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - State *ElementTagType `json:"state,omitempty"` - ActiveSlotNumber *ElementTagType `json:"activeSlotNumber,omitempty"` - ElapsedSlotTime *ElementTagType `json:"elapsedSlotTime,omitempty"` - RemainingSlotTime *ElementTagType `json:"remainingSlotTime,omitempty"` - SequenceRemoteControllable *ElementTagType `json:"sequenceRemoteControllable,omitempty"` - ActiveRepetitionNumber *ElementTagType `json:"activeRepetitionNumber,omitempty"` - RemainingPauseTime *ElementTagType `json:"remainingPauseTime,omitempty"` -} - -type PowerSequenceStateListDataType struct { - PowerSequenceStateData []PowerSequenceStateDataType `json:"powerSequenceStateData,omitempty"` -} - -type PowerSequenceStateListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type PowerSequenceScheduleDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - StartTime *AbsoluteOrRelativeTimeType `json:"startTime,omitempty"` - EndTime *AbsoluteOrRelativeTimeType `json:"endTime,omitempty"` -} - -type PowerSequenceScheduleDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - StartTime *ElementTagType `json:"startTime,omitempty"` - EndTime *ElementTagType `json:"endTime,omitempty"` -} - -type PowerSequenceScheduleListDataType struct { - PowerSequenceScheduleData []PowerSequenceScheduleDataType `json:"powerSequenceScheduleData,omitempty"` -} - -type PowerSequenceScheduleListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type PowerSequenceScheduleConstraintsDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - EarliestStartTime *AbsoluteOrRelativeTimeType `json:"earliestStartTime,omitempty"` - LatestStartTime *AbsoluteOrRelativeTimeType `json:"latestStartTime,omitempty"` - EarliestEndTime *AbsoluteOrRelativeTimeType `json:"earliestEndTime,omitempty"` - LatestEndTime *AbsoluteOrRelativeTimeType `json:"latestEndTime,omitempty"` - OptionalSequence *bool `json:"optionalSequence,omitempty"` -} - -type PowerSequenceScheduleConstraintsDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - EarliestStartTime *ElementTagType `json:"earliestStartTime,omitempty"` - LatestStartTime *ElementTagType `json:"latestStartTime,omitempty"` - EarliestEndTime *ElementTagType `json:"earliestEndTime,omitempty"` - LatestEndTime *ElementTagType `json:"latestEndTime,omitempty"` - OptionalSequence *ElementTagType `json:"optionalSequence,omitempty"` -} - -type PowerSequenceScheduleConstraintsListDataType struct { - PowerSequenceScheduleConstraintsData []PowerSequenceScheduleConstraintsDataType `json:"powerSequenceScheduleConstraintsData,omitempty"` -} - -type PowerSequenceScheduleConstraintsListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type PowerSequencePriceDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - PotentialStartTime *AbsoluteOrRelativeTimeType `json:"potentialStartTime,omitempty"` - Price *ScaledNumberType `json:"price,omitempty"` - Currency *CurrencyType `json:"currency,omitempty"` -} - -type PowerSequencePriceDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - PotentialStartTime *ElementTagType `json:"potentialStartTime,omitempty"` - Price *ElementTagType `json:"price,omitempty"` - Currency *ElementTagType `json:"currency,omitempty"` -} - -type PowerSequencePriceListDataType struct { - PowerSequencePriceData []PowerSequencePriceDataType `json:"powerSequencePriceData,omitempty"` -} - -type PowerSequencePriceListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` - PotentialStartTimeInterval *AbsoluteOrRelativeTimeType `json:"potentialStartTimeInterval,omitempty"` -} - -type PowerSequenceSchedulePreferenceDataType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty" eebus:"key"` - Greenest *bool `json:"greenest,omitempty"` - Cheapest *bool `json:"cheapest,omitempty"` -} - -type PowerSequenceSchedulePreferenceDataElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - Greenest *ElementTagType `json:"greenest,omitempty"` - Cheapest *ElementTagType `json:"cheapest,omitempty"` -} - -type PowerSequenceSchedulePreferenceListDataType struct { - PowerSequenceSchedulePreferenceData []PowerSequenceSchedulePreferenceDataType `json:"powerSequenceSchedulePreferenceData,omitempty"` -} - -type PowerSequenceSchedulePreferenceListDataSelectorsType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type PowerSequenceNodeScheduleInformationDataType struct { - NodeRemoteControllable *bool `json:"nodeRemoteControllable,omitempty"` - SupportsSingleSlotSchedulingOnly *bool `json:"supportsSingleSlotSchedulingOnly,omitempty"` - AlternativesCount *uint `json:"alternativesCount,omitempty"` - TotalSequencesCountMax *uint `json:"totalSequencesCountMax,omitempty"` - SupportsReselection *bool `json:"supportsReselection,omitempty"` -} - -type PowerSequenceNodeScheduleInformationDataElementsType struct { - NodeRemoteControllable *ElementTagType `json:"nodeRemoteControllable,omitempty"` - SupportsSingleSlotSchedulingOnly *ElementTagType `json:"supportsSingleSlotSchedulingOnly,omitempty"` - AlternativesCount *ElementTagType `json:"alternativesCount,omitempty"` - TotalSequencesCountMax *ElementTagType `json:"totalSequencesCountMax,omitempty"` - SupportsReselection *ElementTagType `json:"supportsReselection,omitempty"` -} - -type PowerSequenceScheduleConfigurationRequestCallType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type PowerSequenceScheduleConfigurationRequestCallElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` -} - -type PowerSequencePriceCalculationRequestCallType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` - PotentialStartTime *AbsoluteOrRelativeTimeType `json:"potentialStartTime,omitempty"` -} - -type PowerSequencePriceCalculationRequestCallElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` - PotentialStartTime *ElementTagType `json:"potentialStartTime,omitempty"` -} diff --git a/spine/model/powersequences_additions.go b/spine/model/powersequences_additions.go deleted file mode 100644 index f2329597..00000000 --- a/spine/model/powersequences_additions.go +++ /dev/null @@ -1,131 +0,0 @@ -package model - -// PowerTimeSlotScheduleListDataType - -var _ Updater = (*PowerTimeSlotScheduleListDataType)(nil) - -func (r *PowerTimeSlotScheduleListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []PowerTimeSlotScheduleDataType - if newList != nil { - newData = newList.(*PowerTimeSlotScheduleListDataType).PowerTimeSlotScheduleData - } - - r.PowerTimeSlotScheduleData = UpdateList(r.PowerTimeSlotScheduleData, newData, filterPartial, filterDelete) -} - -// PowerTimeSlotValueListDataType - -var _ Updater = (*PowerTimeSlotValueListDataType)(nil) - -func (r *PowerTimeSlotValueListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []PowerTimeSlotValueDataType - if newList != nil { - newData = newList.(*PowerTimeSlotValueListDataType).PowerTimeSlotValueData - } - - r.PowerTimeSlotValueData = UpdateList(r.PowerTimeSlotValueData, newData, filterPartial, filterDelete) -} - -// PowerTimeSlotScheduleConstraintsListDataType - -var _ Updater = (*PowerTimeSlotScheduleConstraintsListDataType)(nil) - -func (r *PowerTimeSlotScheduleConstraintsListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []PowerTimeSlotScheduleConstraintsDataType - if newList != nil { - newData = newList.(*PowerTimeSlotScheduleConstraintsListDataType).PowerTimeSlotScheduleConstraintsData - } - - r.PowerTimeSlotScheduleConstraintsData = UpdateList(r.PowerTimeSlotScheduleConstraintsData, newData, filterPartial, filterDelete) -} - -// PowerSequenceAlternativesRelationListDataType - -var _ Updater = (*PowerSequenceAlternativesRelationListDataType)(nil) - -func (r *PowerSequenceAlternativesRelationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []PowerSequenceAlternativesRelationDataType - if newList != nil { - newData = newList.(*PowerSequenceAlternativesRelationListDataType).PowerSequenceAlternativesRelationData - } - - r.PowerSequenceAlternativesRelationData = UpdateList(r.PowerSequenceAlternativesRelationData, newData, filterPartial, filterDelete) -} - -// PowerSequenceDescriptionListDataType - -var _ Updater = (*PowerSequenceDescriptionListDataType)(nil) - -func (r *PowerSequenceDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []PowerSequenceDescriptionDataType - if newList != nil { - newData = newList.(*PowerSequenceDescriptionListDataType).PowerSequenceDescriptionData - } - - r.PowerSequenceDescriptionData = UpdateList(r.PowerSequenceDescriptionData, newData, filterPartial, filterDelete) -} - -// PowerSequenceStateListDataType - -var _ Updater = (*PowerSequenceStateListDataType)(nil) - -func (r *PowerSequenceStateListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []PowerSequenceStateDataType - if newList != nil { - newData = newList.(*PowerSequenceStateListDataType).PowerSequenceStateData - } - - r.PowerSequenceStateData = UpdateList(r.PowerSequenceStateData, newData, filterPartial, filterDelete) -} - -// PowerSequenceScheduleListDataType - -var _ Updater = (*PowerSequenceScheduleListDataType)(nil) - -func (r *PowerSequenceScheduleListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []PowerSequenceScheduleDataType - if newList != nil { - newData = newList.(*PowerSequenceScheduleListDataType).PowerSequenceScheduleData - } - - r.PowerSequenceScheduleData = UpdateList(r.PowerSequenceScheduleData, newData, filterPartial, filterDelete) -} - -// PowerSequenceScheduleConstraintsListDataType - -var _ Updater = (*PowerSequenceScheduleConstraintsListDataType)(nil) - -func (r *PowerSequenceScheduleConstraintsListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []PowerSequenceScheduleConstraintsDataType - if newList != nil { - newData = newList.(*PowerSequenceScheduleConstraintsListDataType).PowerSequenceScheduleConstraintsData - } - - r.PowerSequenceScheduleConstraintsData = UpdateList(r.PowerSequenceScheduleConstraintsData, newData, filterPartial, filterDelete) -} - -// PowerSequencePriceListDataType - -var _ Updater = (*PowerSequencePriceListDataType)(nil) - -func (r *PowerSequencePriceListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []PowerSequencePriceDataType - if newList != nil { - newData = newList.(*PowerSequencePriceListDataType).PowerSequencePriceData - } - - r.PowerSequencePriceData = UpdateList(r.PowerSequencePriceData, newData, filterPartial, filterDelete) -} - -// PowerSequenceSchedulePreferenceListDataType - -var _ Updater = (*PowerSequenceSchedulePreferenceListDataType)(nil) - -func (r *PowerSequenceSchedulePreferenceListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []PowerSequenceSchedulePreferenceDataType - if newList != nil { - newData = newList.(*PowerSequenceSchedulePreferenceListDataType).PowerSequenceSchedulePreferenceData - } - - r.PowerSequenceSchedulePreferenceData = UpdateList(r.PowerSequenceSchedulePreferenceData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/powersequences_additions_test.go b/spine/model/powersequences_additions_test.go deleted file mode 100644 index cbc4c63c..00000000 --- a/spine/model/powersequences_additions_test.go +++ /dev/null @@ -1,392 +0,0 @@ -package model_test - -import ( - "testing" - "time" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestPowerTimeSlotScheduleListDataType_Update(t *testing.T) { - sut := model.PowerTimeSlotScheduleListDataType{ - PowerTimeSlotScheduleData: []model.PowerTimeSlotScheduleDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - SlotActivated: util.Ptr(false), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - SlotActivated: util.Ptr(false), - }, - }, - } - - newData := model.PowerTimeSlotScheduleListDataType{ - PowerTimeSlotScheduleData: []model.PowerTimeSlotScheduleDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - SlotActivated: util.Ptr(true), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.PowerTimeSlotScheduleData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, false, *item1.SlotActivated) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, true, *item2.SlotActivated) -} - -func TestPowerTimeSlotValueListDataType_Update(t *testing.T) { - sut := model.PowerTimeSlotValueListDataType{ - PowerTimeSlotValueData: []model.PowerTimeSlotValueDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - Value: model.NewScaledNumberType(1), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - Value: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.PowerTimeSlotValueListDataType{ - PowerTimeSlotValueData: []model.PowerTimeSlotValueDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - Value: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.PowerTimeSlotValueData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, 1.0, item1.Value.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, 10.0, item2.Value.GetValue()) -} - -func TestPowerTimeSlotScheduleConstraintsListDataType_Update(t *testing.T) { - sut := model.PowerTimeSlotScheduleConstraintsListDataType{ - PowerTimeSlotScheduleConstraintsData: []model.PowerTimeSlotScheduleConstraintsDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - MinDuration: model.NewDurationType(1 * time.Second), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - MinDuration: model.NewDurationType(1 * time.Second), - }, - }, - } - - newData := model.PowerTimeSlotScheduleConstraintsListDataType{ - PowerTimeSlotScheduleConstraintsData: []model.PowerTimeSlotScheduleConstraintsDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - MinDuration: model.NewDurationType(10 * time.Second), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.PowerTimeSlotScheduleConstraintsData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - duration, _ := item1.MinDuration.GetTimeDuration() - assert.Equal(t, time.Duration(1*time.Second), duration) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - duration, _ = item2.MinDuration.GetTimeDuration() - assert.Equal(t, time.Duration(10*time.Second), duration) -} - -func TestPowerSequenceAlternativesRelationListDataType_Update(t *testing.T) { - sut := model.PowerSequenceAlternativesRelationListDataType{ - PowerSequenceAlternativesRelationData: []model.PowerSequenceAlternativesRelationDataType{ - { - AlternativeId: util.Ptr(model.AlternativesIdType(0)), - SequenceId: []model.PowerSequenceIdType{0}, - }, - { - AlternativeId: util.Ptr(model.AlternativesIdType(1)), - SequenceId: []model.PowerSequenceIdType{0}, - }, - }, - } - - newData := model.PowerSequenceAlternativesRelationListDataType{ - PowerSequenceAlternativesRelationData: []model.PowerSequenceAlternativesRelationDataType{ - { - AlternativeId: util.Ptr(model.AlternativesIdType(1)), - SequenceId: []model.PowerSequenceIdType{1}, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.PowerSequenceAlternativesRelationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.AlternativeId)) - assert.Equal(t, 0, int(item1.SequenceId[0])) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.AlternativeId)) - assert.Equal(t, 1, int(item2.SequenceId[0])) -} - -func TestPowerSequenceDescriptionListDataType_Update(t *testing.T) { - sut := model.PowerSequenceDescriptionListDataType{ - PowerSequenceDescriptionData: []model.PowerSequenceDescriptionDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - PositiveEnergyDirection: util.Ptr(model.EnergyDirectionTypeConsume), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - PositiveEnergyDirection: util.Ptr(model.EnergyDirectionTypeConsume), - }, - }, - } - - newData := model.PowerSequenceDescriptionListDataType{ - PowerSequenceDescriptionData: []model.PowerSequenceDescriptionDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - PositiveEnergyDirection: util.Ptr(model.EnergyDirectionTypeProduce), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.PowerSequenceDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, model.EnergyDirectionTypeConsume, *item1.PositiveEnergyDirection) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, model.EnergyDirectionTypeProduce, *item2.PositiveEnergyDirection) -} - -func TestPowerSequenceStateListDataType_Update(t *testing.T) { - sut := model.PowerSequenceStateListDataType{ - PowerSequenceStateData: []model.PowerSequenceStateDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - State: util.Ptr(model.PowerSequenceStateTypeRunning), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - State: util.Ptr(model.PowerSequenceStateTypeRunning), - }, - }, - } - - newData := model.PowerSequenceStateListDataType{ - PowerSequenceStateData: []model.PowerSequenceStateDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - State: util.Ptr(model.PowerSequenceStateTypeCompleted), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.PowerSequenceStateData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, model.PowerSequenceStateTypeRunning, *item1.State) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, model.PowerSequenceStateTypeCompleted, *item2.State) -} - -func TestPowerSequenceScheduleListDataType_Update(t *testing.T) { - sut := model.PowerSequenceScheduleListDataType{ - PowerSequenceScheduleData: []model.PowerSequenceScheduleDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - EndTime: model.NewAbsoluteOrRelativeTimeType("PT2H"), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - EndTime: model.NewAbsoluteOrRelativeTimeType("PT2H"), - }, - }, - } - - newData := model.PowerSequenceScheduleListDataType{ - PowerSequenceScheduleData: []model.PowerSequenceScheduleDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - EndTime: model.NewAbsoluteOrRelativeTimeType("PT4H"), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.PowerSequenceScheduleData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, "PT2H", string(*item1.EndTime)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, "PT4H", string(*item2.EndTime)) -} - -func TestPowerSequenceScheduleConstraintsListDataType_Update(t *testing.T) { - sut := model.PowerSequenceScheduleConstraintsListDataType{ - PowerSequenceScheduleConstraintsData: []model.PowerSequenceScheduleConstraintsDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - EarliestEndTime: model.NewAbsoluteOrRelativeTimeType("PT2H"), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - EarliestEndTime: model.NewAbsoluteOrRelativeTimeType("PT2H"), - }, - }, - } - - newData := model.PowerSequenceScheduleConstraintsListDataType{ - PowerSequenceScheduleConstraintsData: []model.PowerSequenceScheduleConstraintsDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - EarliestEndTime: model.NewAbsoluteOrRelativeTimeType("PT4H"), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.PowerSequenceScheduleConstraintsData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, "PT2H", string(*item1.EarliestEndTime)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, "PT4H", string(*item2.EarliestEndTime)) -} - -func TestPowerSequencePriceListDataType_Update(t *testing.T) { - sut := model.PowerSequencePriceListDataType{ - PowerSequencePriceData: []model.PowerSequencePriceDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - Price: model.NewScaledNumberType(1), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - Price: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.PowerSequencePriceListDataType{ - PowerSequencePriceData: []model.PowerSequencePriceDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - Price: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.PowerSequencePriceData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, 1.0, item1.Price.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, 10.0, item2.Price.GetValue()) -} - -func TestPowerSequenceSchedulePreferenceListDataType_Update(t *testing.T) { - sut := model.PowerSequenceSchedulePreferenceListDataType{ - PowerSequenceSchedulePreferenceData: []model.PowerSequenceSchedulePreferenceDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(0)), - Cheapest: util.Ptr(false), - }, - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - Cheapest: util.Ptr(false), - }, - }, - } - - newData := model.PowerSequenceSchedulePreferenceListDataType{ - PowerSequenceSchedulePreferenceData: []model.PowerSequenceSchedulePreferenceDataType{ - { - SequenceId: util.Ptr(model.PowerSequenceIdType(1)), - Cheapest: util.Ptr(true), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.PowerSequenceSchedulePreferenceData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SequenceId)) - assert.Equal(t, false, *item1.Cheapest) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SequenceId)) - assert.Equal(t, true, *item2.Cheapest) -} diff --git a/spine/model/result.go b/spine/model/result.go deleted file mode 100644 index 59c2bcd8..00000000 --- a/spine/model/result.go +++ /dev/null @@ -1,21 +0,0 @@ -package model - -type ErrorNumberType uint - -const ( - ErrorNumberTypeNoError ErrorNumberType = iota - ErrorNumberTypeGeneralError - ErrorNumberTypeTimeout - ErrorNumberTypeOverload - ErrorNumberTypeDestinationUnknown - ErrorNumberTypeDestinationUnreachable - ErrorNumberTypeCommandNotSupported - ErrorNumberTypeCommandRejected - ErrorNumberTypeRestrictedFunctionExchangeCombinationNotSupported - ErrorNumberTypeBindingIsNecessaryForThisCommand -) - -type ResultDataType struct { - ErrorNumber *ErrorNumberType `json:"errorNumber,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} diff --git a/spine/model/sensing.go b/spine/model/sensing.go deleted file mode 100644 index e19ba3d9..00000000 --- a/spine/model/sensing.go +++ /dev/null @@ -1,99 +0,0 @@ -package model - -type SensingStateType string - -const ( - SensingStateTypeOn SensingStateType = "on" - SensingStateTypeOff SensingStateType = "off" - SensingStateTypeToggle SensingStateType = "toggle" - SensingStateTypeLevel SensingStateType = "level" - SensingStateTypeLevelUp SensingStateType = "levelUp" - SensingStateTypeLevelDown SensingStateType = "levelDown" - SensingStateTypeLevelStart SensingStateType = "levelStart" - SensingStateTypeLevelStop SensingStateType = "levelStop" - SensingStateTypeLevelAbsolute SensingStateType = "levelAbsolute" - SensingStateTypeLevelRelative SensingStateType = "levelRelative" - SensingStateTypeLevelPercentageAbsolute SensingStateType = "levelPercentageAbsolute" - SensingStateTypeLevelPercentageRelative SensingStateType = "levelPercentageRelative" - SensingStateTypePressed SensingStateType = "pressed" - SensingStateTypeLongPressed SensingStateType = "longPressed" - SensingStateTypeReleased SensingStateType = "released" - SensingStateTypeChanged SensingStateType = "changed" - SensingStateTypeStarted SensingStateType = "started" - SensingStateTypeStopped SensingStateType = "stopped" - SensingStateTypePaused SensingStateType = "paused" - SensingStateTypeMiddle SensingStateType = "middle" - SensingStateTypeUp SensingStateType = "up" - SensingStateTypeDown SensingStateType = "down" - SensingStateTypeForward SensingStateType = "forward" - SensingStateTypeBackwards SensingStateType = "backwards" - SensingStateTypeOpen SensingStateType = "open" - SensingStateTypeClosed SensingStateType = "closed" - SensingStateTypeOpening SensingStateType = "opening" - SensingStateTypeClosing SensingStateType = "closing" - SensingStateTypeHigh SensingStateType = "high" - SensingStateTypeLow SensingStateType = "low" - SensingStateTypeDay SensingStateType = "day" - SensingStateTypeNight SensingStateType = "night" - SensingStateTypeDetected SensingStateType = "detected" - SensingStateTypeNotDetected SensingStateType = "notDetected" - SensingStateTypeAlarmed SensingStateType = "alarmed" - SensingStateTypeNotAlarmed SensingStateType = "notAlarmed" -) - -type SensingTypeType string - -const ( - SensingTypeTypeSwitch SensingTypeType = "switch" - SensingTypeTypeButton SensingTypeType = "button" - SensingTypeTypeLevel SensingTypeType = "level" - SensingTypeTypeLevelSwitch SensingTypeType = "levelSwitch" - SensingTypeTypeWindowHandle SensingTypeType = "windowHandle" - SensingTypeTypeContactSensor SensingTypeType = "contactSensor" - SensingTypeTypeOccupancySensor SensingTypeType = "occupancySensor" - SensingTypeTypeMotionDetector SensingTypeType = "motionDetector" - SensingTypeTypeFireDetector SensingTypeType = "fireDetector" - SensingTypeTypeSmokeDetector SensingTypeType = "smokeDetector" - SensingTypeTypeHeatDetector SensingTypeType = "heatDetector" - SensingTypeTypeWaterDetector SensingTypeType = "waterDetector" - SensingTypeTypeGasDetector SensingTypeType = "gasDetector" - SensingTypeTypeAlarmSensor SensingTypeType = "alarmSensor" - SensingTypeTypePowerAlarmSensor SensingTypeType = "powerAlarmSensor" - SensingTypeTypeDayNightIndicator SensingTypeType = "dayNightIndicator" -) - -type SensingDataType struct { - Timestamp *AbsoluteOrRelativeTimeType `json:"timestamp,omitempty"` - State *SensingStateType `json:"state,omitempty"` - Value *ScaledNumberType `json:"value,omitempty"` -} - -type SensingDataElementsType struct { - Timestamp *ElementTagType `json:"timestamp,omitempty"` - State *ElementTagType `json:"state,omitempty"` - Value *ScaledNumberElementsType `json:"value,omitempty"` -} - -type SensingListDataType struct { - SensingData []SensingDataType `json:"sensingData,omitempty"` -} - -type SensingListDataSelectorsType struct { - TimestampInterval *TimestampIntervalType `json:"timestampInterval,omitempty"` -} - -type SensingDescriptionDataType struct { - SensingType *SensingTypeType `json:"sensingType,omitempty"` - Unit *UnitOfMeasurementType `json:"unit,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type SensingDescriptionDataElementsType struct { - SensingType *ElementTagType `json:"sensingType,omitempty"` - Unit *ElementTagType `json:"unit,omitempty"` - ScopeType *ElementTagType `json:"scopeType,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} diff --git a/spine/model/sensing_additions.go b/spine/model/sensing_additions.go deleted file mode 100644 index b79094dd..00000000 --- a/spine/model/sensing_additions.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -// SensingListDataType - -var _ Updater = (*SensingListDataType)(nil) - -func (r *SensingListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []SensingDataType - if newList != nil { - newData = newList.(*SensingListDataType).SensingData - } - - r.SensingData = UpdateList(r.SensingData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/setpoint.go b/spine/model/setpoint.go deleted file mode 100644 index e403b2b4..00000000 --- a/spine/model/setpoint.go +++ /dev/null @@ -1,92 +0,0 @@ -package model - -type SetpointIdType uint - -type SetpointTypeType string - -const ( - SetpointTypeTypeValueAbsolute SetpointTypeType = "valueAbsolute" - SetpointTypeTypeValueRelative SetpointTypeType = "valueRelative" -) - -type SetpointDataType struct { - SetpointId *SetpointIdType `json:"setpointId,omitempty" eebus:"key"` - Value *ScaledNumberType `json:"value,omitempty"` - ValueMin *ScaledNumberType `json:"valueMin,omitempty"` - ValueMax *ScaledNumberType `json:"valueMax,omitempty"` - ValueToleranceAbsolute *ScaledNumberType `json:"valueToleranceAbsolute,omitempty"` - ValueTolerancePercentage *ScaledNumberType `json:"valueTolerancePercentage,omitempty"` -} - -type SetpointDataElementsType struct { - SetpointId *ElementTagType `json:"setpointId,omitempty"` - Value *ScaledNumberElementsType `json:"value,omitempty"` - ValueMin *ScaledNumberElementsType `json:"valueMin,omitempty"` - ValueMax *ScaledNumberElementsType `json:"valueMax,omitempty"` - ValueToleranceAbsolute *ScaledNumberElementsType `json:"valueToleranceAbsolute,omitempty"` - ValueTolerancePercentage *ScaledNumberElementsType `json:"valueTolerancePercentage,omitempty"` -} - -type SetpointListDataType struct { - SetpointData []SetpointDataType `json:"setpointData,omitempty"` -} - -type SetpointListDataSelectorsType struct { - SetpointId *SetpointIdType `json:"setpointId,omitempty"` -} - -type SetpointConstraintsDataType struct { - SetpointId *SetpointIdType `json:"setpointId,omitempty" eebus:"key"` - SetpointRangeMin *ScaledNumberType `json:"setpointRangeMin,omitempty"` - SetpointRangeMax *ScaledNumberType `json:"setpointRangeMax,omitempty"` - SetpointStepSize *ScaledNumberType `json:"setpointStepSize,omitempty"` -} - -type SetpointConstraintsDataElementsType struct { - SetpointId *ElementTagType `json:"setpointId,omitempty"` - SetpointRangeMin *ScaledNumberElementsType `json:"setpointRangeMin,omitempty"` - SetpointRangeMax *ScaledNumberElementsType `json:"setpointRangeMax,omitempty"` - SetpointStepSize *ScaledNumberElementsType `json:"setpointStepSize,omitempty"` -} - -type SetpointConstraintsListDataType struct { - SetpointConstraintsData []SetpointConstraintsDataType `json:"setpointConstraintsData,omitempty"` -} - -type SetpointConstraintsListDataSelectorsType struct { - SetpointId *SetpointIdType `json:"setpointId,omitempty"` -} - -type SetpointDescriptionDataType struct { - SetpointId *SetpointIdType `json:"setpointId,omitempty" eebus:"key"` - MeasurementId *SetpointIdType `json:"measurementId,omitempty"` - TimeTableId *SetpointIdType `json:"timeTableId,omitempty"` - SetpointType *SetpointTypeType `json:"setpointType,omitempty"` - Unit *ScaledNumberType `json:"unit,omitempty"` - ScopeType *ScaledNumberType `json:"scopeType,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type SetpointDescriptionDataElementsType struct { - SetpointId *ElementTagType `json:"setpointId,omitempty"` - MeasurementId *ElementTagType `json:"measurementId,omitempty"` - TimeTableId *ElementTagType `json:"timeTableId,omitempty"` - SetpointType *ElementTagType `json:"setpointType,omitempty"` - Unit *ElementTagType `json:"unit,omitempty"` - ScopeType *ElementTagType `json:"scopeType,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type SetpointDescriptionListDataType struct { - SetpointDescriptionData []SetpointDescriptionDataType `json:"setpointDescriptionData,omitempty"` -} - -type SetpointDescriptionListDataSelectorsType struct { - SetpointId *SetpointIdType `json:"setpointId,omitempty"` - MeasurementId *SetpointIdType `json:"measurementId,omitempty"` - TimeTableId *SetpointIdType `json:"timeTableId,omitempty"` - SetpointType *SetpointIdType `json:"setpointType,omitempty"` - ScopeType *ScaledNumberType `json:"scopeType,omitempty"` -} diff --git a/spine/model/setpoint_additions.go b/spine/model/setpoint_additions.go deleted file mode 100644 index 8ab7915c..00000000 --- a/spine/model/setpoint_additions.go +++ /dev/null @@ -1,27 +0,0 @@ -package model - -// SetpointListDataType - -var _ Updater = (*SetpointListDataType)(nil) - -func (r *SetpointListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []SetpointDataType - if newList != nil { - newData = newList.(*SetpointListDataType).SetpointData - } - - r.SetpointData = UpdateList(r.SetpointData, newData, filterPartial, filterDelete) -} - -// SetpointDescriptionListDataType - -var _ Updater = (*SetpointDescriptionListDataType)(nil) - -func (r *SetpointDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []SetpointDescriptionDataType - if newList != nil { - newData = newList.(*SetpointDescriptionListDataType).SetpointDescriptionData - } - - r.SetpointDescriptionData = UpdateList(r.SetpointDescriptionData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/setpoint_additions_test.go b/spine/model/setpoint_additions_test.go deleted file mode 100644 index dbcaefbb..00000000 --- a/spine/model/setpoint_additions_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestSetpointListDataType_Update(t *testing.T) { - sut := model.SetpointListDataType{ - SetpointData: []model.SetpointDataType{ - { - SetpointId: util.Ptr(model.SetpointIdType(0)), - Value: model.NewScaledNumberType(1), - }, - { - SetpointId: util.Ptr(model.SetpointIdType(1)), - Value: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.SetpointListDataType{ - SetpointData: []model.SetpointDataType{ - { - SetpointId: util.Ptr(model.SetpointIdType(1)), - Value: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.SetpointData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SetpointId)) - assert.Equal(t, 1.0, item1.Value.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SetpointId)) - assert.Equal(t, 10.0, item2.Value.GetValue()) -} - -func TestSetpointDescriptionListDataType_Update(t *testing.T) { - sut := model.SetpointDescriptionListDataType{ - SetpointDescriptionData: []model.SetpointDescriptionDataType{ - { - SetpointId: util.Ptr(model.SetpointIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - SetpointId: util.Ptr(model.SetpointIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.SetpointDescriptionListDataType{ - SetpointDescriptionData: []model.SetpointDescriptionDataType{ - { - SetpointId: util.Ptr(model.SetpointIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.SetpointDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SetpointId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SetpointId)) - assert.Equal(t, "new", string(*item2.Description)) -} diff --git a/spine/model/smartenergymanagementps.go b/spine/model/smartenergymanagementps.go deleted file mode 100644 index 7f95c004..00000000 --- a/spine/model/smartenergymanagementps.go +++ /dev/null @@ -1,104 +0,0 @@ -package model - -type SmartEnergyManagementPsAlternativesRelationType PowerSequenceAlternativesRelationDataType // ignoring the custom changes - -type SmartEnergyManagementPsAlternativesRelationElementsType PowerSequenceAlternativesRelationDataElementsType // ignoring changes - -type SmartEnergyManagementPsAlternativesType struct { - Relation *SmartEnergyManagementPsAlternativesRelationType `json:"relation,omitempty"` - PowerSequence []SmartEnergyManagementPsPowerSequenceType `json:"powerSequence,omitempty"` -} - -type SmartEnergyManagementPsAlternativesElementsType struct { - Relation *SmartEnergyManagementPsAlternativesRelationElementsType `json:"relation,omitempty"` - PowerSequence *SmartEnergyManagementPsPowerSequenceElementsType `json:"powerSequence,omitempty"` -} - -type SmartEnergyManagementPsPowerSequenceType struct { - Description *PowerSequenceDescriptionDataType `json:"description,omitempty"` // ignoring changes - State *PowerSequenceStateDataType `json:"state,omitempty"` // ignoring changes - Schedule *PowerSequenceScheduleDataType `json:"schedule,omitempty"` // ignoring changes - ScheduleConstraints *PowerSequenceScheduleConstraintsDataType `json:"scheduleConstraints,omitempty"` // ignoring changes - SchedulePreference *PowerSequenceSchedulePreferenceDataType `json:"schedulePreference,omitempty"` // ignoring changes - OperatingConstraintsInterrupt *OperatingConstraintsInterruptDataType `json:"operatingConstraintsInterrupt,omitempty"` // ignoring changes - OperatingConstraintsDuration *OperatingConstraintsDurationDataType `json:"operatingConstraintsDuration,omitempty"` // ignoring changes - OperatingConstraintsResumeImplication *OperatingConstraintsResumeImplicationDataType `json:"operatingConstraintsResumeImplication,omitempty"` // ignoring changes - PowerTimeSlot []SmartEnergyManagementPsPowerTimeSlotType `json:"powerTimeSlot,omitempty"` // ignoring changes -} - -type SmartEnergyManagementPsPowerSequenceElementsType struct { - Description *PowerSequenceDescriptionDataElementsType `json:"description,omitempty"` - State *PowerSequenceStateDataElementsType `json:"state,omitempty"` - Schedule *PowerSequenceScheduleDataElementsType `json:"schedule,omitempty"` - ScheduleConstraints *PowerSequenceScheduleConstraintsDataElementsType `json:"scheduleConstraints,omitempty"` - SchedulePreference *PowerSequenceSchedulePreferenceDataElementsType `json:"schedulePreference,omitempty"` - OperatingConstraintsInterrupt *OperatingConstraintsInterruptDataElementsType `json:"operatingConstraintsInterrupt,omitempty"` - OperatingConstraintsDuration *OperatingConstraintsDurationDataElementsType `json:"operatingConstraintsDuration,omitempty"` - OperatingConstraintsResumeImplication *OperatingConstraintsResumeImplicationDataElementsType `json:"operatingConstraintsResumeImplication,omitempty"` - PowerTimeSlot *SmartEnergyManagementPsPowerTimeSlotElementsType `json:"powerTimeSlot,omitempty"` -} - -type SmartEnergyManagementPsPowerTimeSlotType struct { - Schedule *PowerTimeSlotScheduleDataType `json:"schedule,omitempty"` // ignoring changes - ValueList *SmartEnergyManagementPsPowerTimeSlotValueListType `json:"valueList,omitempty"` - ScheduleConstraints *PowerTimeSlotScheduleConstraintsDataType `json:"scheduleConstraints,omitempty"` // ignoring changes -} - -type SmartEnergyManagementPsPowerTimeSlotElementsType struct { - Schedule *PowerTimeSlotScheduleDataElementsType `json:"schedule,omitempty"` // ignoring changes - ValueList *SmartEnergyManagementPsPowerTimeSlotValueListElementsType `json:"valueList,omitempty"` - ScheduleConstraints *PowerTimeSlotScheduleConstraintsDataElementsType `json:"scheduleConstraints,omitempty"` // ignoring changes -} - -type SmartEnergyManagementPsPowerTimeSlotValueListType struct { - Value []PowerTimeSlotValueDataType `json:"value,omitempty"` // ignoring changes -} - -type SmartEnergyManagementPsPowerTimeSlotValueListElementsType struct { - Value *PowerTimeSlotValueDataElementsType `json:"value,omitempty"` -} - -type SmartEnergyManagementPsDataType struct { - NodeScheduleInformation *PowerSequenceNodeScheduleInformationDataType `json:"nodeScheduleInformation,omitempty"` // ignoring changes - Alternatives []SmartEnergyManagementPsAlternativesType `json:"alternatives,omitempty"` -} - -type SmartEnergyManagementPsDataElementsType struct { - NodeScheduleInformation *PowerSequenceNodeScheduleInformationDataElementsType `json:"nodeScheduleInformation,omitempty"` - Alternatives *SmartEnergyManagementPsAlternativesElementsType `json:"alternatives,omitempty"` -} - -type SmartEnergyManagementPsDataSelectorsType struct { - AlternativesRelation *PowerSequenceAlternativesRelationListDataSelectorsType `json:"alternativesRelation,omitempty"` // ignoring changes - PowerSequenceDescription *PowerSequenceDescriptionListDataSelectorsType `json:"powerSequenceDescription,omitempty"` // ignoring changes - PowerTimeSlotSchedule *PowerTimeSlotScheduleListDataSelectorsType `json:"powerTimeSlotSchedule,omitempty"` // ignoring changes - PowerTimeSlotValue *PowerTimeSlotValueListDataSelectorsType `json:"powerTimeSlotValue,omitempty"` // ignoring changes -} - -type SmartEnergyManagementPsPriceDataType struct { - Price *PowerSequencePriceDataType `json:"price,omitempty"` // ignoring changes -} - -type SmartEnergyManagementPsPriceDataElementsType struct { - Price *PowerSequencePriceDataElementsType `json:"price,omitempty"` // ignoring changes -} - -type SmartEnergyManagementPsPriceDataSelectorsType struct { - Price *PowerSequencePriceListDataSelectorsType `json:"price,omitempty"` // ignoring changes -} - -type SmartEnergyManagementPsConfigurationRequestCallType struct { - ScheduleConfigurationRequest *PowerSequenceScheduleConfigurationRequestCallType `json:"scheduleConfigurationRequest,omitempty"` // ignoring changes -} - -type SmartEnergyManagementPsConfigurationRequestCallElementsType struct { - ScheduleConfigurationRequest *PowerSequenceScheduleConfigurationRequestCallElementsType `json:"scheduleConfigurationRequest,omitempty"` // ignoring changes -} - -type SmartEnergyManagementPsPriceCalculationRequestCallType struct { - PriceCalculationRequest *PowerSequencePriceCalculationRequestCallType `json:"priceCalculationRequest,omitempty"` // ignoring changes -} - -type SmartEnergyManagementPsPriceCalculationRequestCallElementsType struct { - PriceCalculationRequest *PowerSequencePriceCalculationRequestCallElementsType `json:"priceCalculationRequest,omitempty"` // ignoring changes -} diff --git a/spine/model/subscriptionmanagement.go b/spine/model/subscriptionmanagement.go deleted file mode 100644 index d5714004..00000000 --- a/spine/model/subscriptionmanagement.go +++ /dev/null @@ -1,53 +0,0 @@ -package model - -type SubscriptionIdType uint - -type SubscriptionManagementEntryDataType struct { - SubscriptionId *SubscriptionIdType `json:"subscriptionId,omitempty" eebus:"key"` - ClientAddress *FeatureAddressType `json:"clientAddress,omitempty"` - ServerAddress *FeatureAddressType `json:"serverAddress,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type SubscriptionManagementEntryDataElementsType struct { - SubscriptionId *ElementTagType `json:"subscriptionId,omitempty"` - ClientAddress *FeatureAddressElementsType `json:"clientAddress,omitempty"` - ServerAddress *FeatureAddressElementsType `json:"serverAddress,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type SubscriptionManagementEntryListDataType struct { - SubscriptionManagementEntryData []SubscriptionManagementEntryDataType `json:"subscriptionManagementEntryData,omitempty"` -} - -type SubscriptionManagementEntryListDataSelectorsType struct { - SubscriptionId *SubscriptionIdType `json:"subscriptionId,omitempty"` - ClientAddress *FeatureAddressType `json:"clientAddress,omitempty"` - ServerAddress *FeatureAddressType `json:"serverAddress,omitempty"` -} - -type SubscriptionManagementRequestCallType struct { - ClientAddress *FeatureAddressType `json:"clientAddress,omitempty"` - ServerAddress *FeatureAddressType `json:"serverAddress,omitempty"` - ServerFeatureType *FeatureTypeType `json:"serverFeatureType,omitempty"` -} - -type SubscriptionManagementRequestCallElementsType struct { - ClientAddress *FeatureAddressElementsType `json:"clientAddress,omitempty"` - ServerAddress *FeatureAddressElementsType `json:"serverAddress,omitempty"` - ServerFeatureType *ElementTagType `json:"serverFeatureType,omitempty"` -} - -type SubscriptionManagementDeleteCallType struct { - SubscriptionId *SubscriptionIdType `json:"subscriptionId,omitempty"` - ClientAddress *FeatureAddressType `json:"clientAddress,omitempty"` - ServerAddress *FeatureAddressType `json:"serverAddress,omitempty"` -} - -type SubscriptionManagementDeleteCallElementsType struct { - SubscriptionId *ElementTagType `json:"subscriptionId,omitempty"` - ClientAddress *FeatureAddressElementsType `json:"clientAddress,omitempty"` - ServerAddress *FeatureAddressElementsType `json:"serverAddress,omitempty"` -} diff --git a/spine/model/subscriptionmanagement_additions.go b/spine/model/subscriptionmanagement_additions.go deleted file mode 100644 index e923d345..00000000 --- a/spine/model/subscriptionmanagement_additions.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -// SubscriptionManagementEntryListDataType - -var _ Updater = (*SubscriptionManagementEntryListDataType)(nil) - -func (r *SubscriptionManagementEntryListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []SubscriptionManagementEntryDataType - if newList != nil { - newData = newList.(*SubscriptionManagementEntryListDataType).SubscriptionManagementEntryData - } - - r.SubscriptionManagementEntryData = UpdateList(r.SubscriptionManagementEntryData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/subscriptionmanagement_additions_test.go b/spine/model/subscriptionmanagement_additions_test.go deleted file mode 100644 index 0f783041..00000000 --- a/spine/model/subscriptionmanagement_additions_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestSubscriptionManagementEntryListDataType_Update(t *testing.T) { - sut := model.SubscriptionManagementEntryListDataType{ - SubscriptionManagementEntryData: []model.SubscriptionManagementEntryDataType{ - { - SubscriptionId: util.Ptr(model.SubscriptionIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - SubscriptionId: util.Ptr(model.SubscriptionIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.SubscriptionManagementEntryListDataType{ - SubscriptionManagementEntryData: []model.SubscriptionManagementEntryDataType{ - { - SubscriptionId: util.Ptr(model.SubscriptionIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.SubscriptionManagementEntryData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.SubscriptionId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.SubscriptionId)) - assert.Equal(t, "new", string(*item2.Description)) -} diff --git a/spine/model/supplyconditions.go b/spine/model/supplyconditions.go deleted file mode 100644 index 91cbf63c..00000000 --- a/spine/model/supplyconditions.go +++ /dev/null @@ -1,112 +0,0 @@ -package model - -type ConditionIdType uint - -type SupplyConditionEventTypeType string - -const ( - SupplyConditionEventTypeTypeThesholdExceeded SupplyConditionEventTypeType = "thesholdExceeded" - SupplyConditionEventTypeTypeFallenBelowThreshold SupplyConditionEventTypeType = "fallenBelowThreshold" - SupplyConditionEventTypeTypeSupplyInterrupt SupplyConditionEventTypeType = "supplyInterrupt" - SupplyConditionEventTypeTypeReleaseOfLimitations SupplyConditionEventTypeType = "releaseOfLimitations" - SupplyConditionEventTypeTypeOtherProblem SupplyConditionEventTypeType = "otherProblem" - SupplyConditionEventTypeTypeGridConditionUpdate SupplyConditionEventTypeType = "gridConditionUpdate" -) - -type SupplyConditionOriginatorType string - -const ( - SupplyConditionOriginatorTypeExternDSO SupplyConditionOriginatorType = "externDSO" - SupplyConditionOriginatorTypeExternSupplier SupplyConditionOriginatorType = "externSupplier" - SupplyConditionOriginatorTypeInternalLimit SupplyConditionOriginatorType = "internalLimit" - SupplyConditionOriginatorTypeInternalService SupplyConditionOriginatorType = "internalService" - SupplyConditionOriginatorTypeInternalUser SupplyConditionOriginatorType = "internalUser" -) - -type GridConditionType string - -const ( - GridConditionTypeConsumptionRed GridConditionType = "consumptionRed" - GridConditionTypeConsumptionYellow GridConditionType = "consumptionYellow" - GridConditionTypeGood GridConditionType = "good" - GridConditionTypeProductionRed GridConditionType = "productionRed" - GridConditionTypeProductionYellow GridConditionType = "productionYellow" -) - -type SupplyConditionDataType struct { - ConditionId *ConditionIdType `json:"conditionId,omitempty" eebus:"key"` - Timestamp *AbsoluteOrRelativeTimeType `json:"timestamp,omitempty"` - EventType *SupplyConditionEventTypeType `json:"eventType,omitempty"` - Originator *SupplyConditionOriginatorType `json:"originator,omitempty"` - ThresholdId *ThresholdIdType `json:"thresholdId,omitempty"` - ThresholdPercentage *ScaledNumberType `json:"thresholdPercentage,omitempty"` - RelevantPeriod *TimePeriodType `json:"relevantPeriod,omitempty"` - Description *DescriptionType `json:"description,omitempty"` - GridCondition *GridConditionType `json:"gridCondition,omitempty"` -} - -type SupplyConditionDataElementsType struct { - ConditionId *ElementTagType `json:"conditionId,omitempty"` - Timestamp *ElementTagType `json:"timestamp,omitempty"` - EventType *ElementTagType `json:"eventType,omitempty"` - Originator *ElementTagType `json:"originator,omitempty"` - ThresholdId *ElementTagType `json:"thresholdId,omitempty"` - ThresholdPercentage *ScaledNumberElementsType `json:"thresholdPercentage,omitempty"` - RelevantPeriod *TimePeriodElementsType `json:"relevantPeriod,omitempty"` - Description *ElementTagType `json:"description,omitempty"` - GridCondition *ElementTagType `json:"gridCondition,omitempty"` -} - -type SupplyConditionListDataType struct { - SupplyConditionData []SupplyConditionDataType `json:"supplyConditionData,omitempty"` -} - -type SupplyConditionListDataSelectorsType struct { - ConditionId *ConditionIdType `json:"conditionId,omitempty"` - TimestampInterval *TimestampIntervalType `json:"timestampInterval,omitempty"` - EventType *SupplyConditionEventTypeType `json:"eventType,omitempty"` - Originator *SupplyConditionOriginatorType `json:"originator,omitempty"` -} - -type SupplyConditionDescriptionDataType struct { - ConditionId *ConditionIdType `json:"conditionId,omitempty" eebus:"key"` - CommodityType *CommodityTypeType `json:"commodityType,omitempty"` - PositiveEnergyDirection *EnergyDirectionType `json:"positiveEnergyDirection,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type SupplyConditionDescriptionDataElementsType struct { - ConditionId *ElementTagType `json:"conditionId,omitempty"` - CommodityType *ElementTagType `json:"commodityType,omitempty"` - PositiveEnergyDirection *ElementTagType `json:"positiveEnergyDirection,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type SupplyConditionDescriptionListDataType struct { - SupplyConditionDescriptionData []SupplyConditionDescriptionDataType `json:"supplyConditionDescriptionData,omitempty"` -} - -type SupplyConditionDescriptionListDataSelectorsType struct { - ConditionId *ConditionIdType `json:"conditionId,omitempty"` -} - -type SupplyConditionThresholdRelationDataType struct { - ConditionId *ConditionIdType `json:"conditionId,omitempty" eebus:"key"` - ThresholdId []ThresholdIdType `json:"thresholdId,omitempty"` -} - -type SupplyConditionThresholdRelationDataElementsType struct { - ConditionId *ElementTagType `json:"conditionId,omitempty"` - ThresholdId *ElementTagType `json:"thresholdId,omitempty"` -} - -type SupplyConditionThresholdRelationListDataType struct { - SupplyConditionThresholdRelationData []SupplyConditionThresholdRelationDataType `json:"SupplyConditionThresholdRelationDataType,omitempty"` -} - -type SupplyConditionThresholdRelationListDataSelectorsType struct { - ConditionId *ConditionIdType `json:"conditionId,omitempty"` - ThresholdId *ThresholdIdType `json:"thresholdId,omitempty"` -} diff --git a/spine/model/supplyconditions_additions.go b/spine/model/supplyconditions_additions.go deleted file mode 100644 index 70aa92e8..00000000 --- a/spine/model/supplyconditions_additions.go +++ /dev/null @@ -1,40 +0,0 @@ -package model - -// SupplyConditionListDataType - -var _ Updater = (*SupplyConditionListDataType)(nil) - -func (r *SupplyConditionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []SupplyConditionDataType - if newList != nil { - newData = newList.(*SupplyConditionListDataType).SupplyConditionData - } - - r.SupplyConditionData = UpdateList(r.SupplyConditionData, newData, filterPartial, filterDelete) -} - -// SupplyConditionDescriptionListDataType - -var _ Updater = (*SupplyConditionDescriptionListDataType)(nil) - -func (r *SupplyConditionDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []SupplyConditionDescriptionDataType - if newList != nil { - newData = newList.(*SupplyConditionDescriptionListDataType).SupplyConditionDescriptionData - } - - r.SupplyConditionDescriptionData = UpdateList(r.SupplyConditionDescriptionData, newData, filterPartial, filterDelete) -} - -// SupplyConditionThresholdRelationListDataType - -var _ Updater = (*SupplyConditionThresholdRelationListDataType)(nil) - -func (r *SupplyConditionThresholdRelationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []SupplyConditionThresholdRelationDataType - if newList != nil { - newData = newList.(*SupplyConditionThresholdRelationListDataType).SupplyConditionThresholdRelationData - } - - r.SupplyConditionThresholdRelationData = UpdateList(r.SupplyConditionThresholdRelationData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/supplyconditions_additions_test.go b/spine/model/supplyconditions_additions_test.go deleted file mode 100644 index 615b7de2..00000000 --- a/spine/model/supplyconditions_additions_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestSupplyConditionListDataType_Update(t *testing.T) { - sut := model.SupplyConditionListDataType{ - SupplyConditionData: []model.SupplyConditionDataType{ - { - ConditionId: util.Ptr(model.ConditionIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - ConditionId: util.Ptr(model.ConditionIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.SupplyConditionListDataType{ - SupplyConditionData: []model.SupplyConditionDataType{ - { - ConditionId: util.Ptr(model.ConditionIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.SupplyConditionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.ConditionId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.ConditionId)) - assert.Equal(t, "new", string(*item2.Description)) -} - -func TestSupplyConditionDescriptionListDataType_Update(t *testing.T) { - sut := model.SupplyConditionDescriptionListDataType{ - SupplyConditionDescriptionData: []model.SupplyConditionDescriptionDataType{ - { - ConditionId: util.Ptr(model.ConditionIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - ConditionId: util.Ptr(model.ConditionIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.SupplyConditionDescriptionListDataType{ - SupplyConditionDescriptionData: []model.SupplyConditionDescriptionDataType{ - { - ConditionId: util.Ptr(model.ConditionIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.SupplyConditionDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.ConditionId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.ConditionId)) - assert.Equal(t, "new", string(*item2.Description)) -} - -func TestSupplyConditionThresholdRelationListDataType_Update(t *testing.T) { - sut := model.SupplyConditionThresholdRelationListDataType{ - SupplyConditionThresholdRelationData: []model.SupplyConditionThresholdRelationDataType{ - { - ConditionId: util.Ptr(model.ConditionIdType(0)), - ThresholdId: []model.ThresholdIdType{0}, - }, - { - ConditionId: util.Ptr(model.ConditionIdType(1)), - ThresholdId: []model.ThresholdIdType{0}, - }, - }, - } - - newData := model.SupplyConditionThresholdRelationListDataType{ - SupplyConditionThresholdRelationData: []model.SupplyConditionThresholdRelationDataType{ - { - ConditionId: util.Ptr(model.ConditionIdType(1)), - ThresholdId: []model.ThresholdIdType{1}, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.SupplyConditionThresholdRelationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.ConditionId)) - assert.Equal(t, 0, int(item1.ThresholdId[0])) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.ConditionId)) - assert.Equal(t, 1, int(item2.ThresholdId[0])) -} diff --git a/spine/model/tariffinformation.go b/spine/model/tariffinformation.go deleted file mode 100644 index 9e2155a2..00000000 --- a/spine/model/tariffinformation.go +++ /dev/null @@ -1,370 +0,0 @@ -package model - -type TariffIdType uint - -type TariffCountType TariffIdType - -type TierBoundaryIdType uint - -type TierBoundaryCountType TierBoundaryIdType - -type TierBoundaryTypeType string - -const ( - TierBoundaryTypeTypePowerBoundary TierBoundaryTypeType = "powerBoundary" - TierBoundaryTypeTypeEnergyBoundary TierBoundaryTypeType = "energyBoundary" - TierBoundaryTypeTypeCountBoundary TierBoundaryTypeType = "countBoundary" -) - -type CommodityIdType uint - -type TierIdType uint - -type TierCountType TierIdType - -type TierTypeType string - -const ( - TierTypeTypeFixedCost TierTypeType = "fixedCost" - TierTypeTypeDynamicCost TierTypeType = "dynamicCost" -) - -type IncentiveIdType uint - -type IncentiveCountType IncentiveIdType - -type IncentiveTypeType string - -const ( - IncentiveTypeTypeAbsoluteCost IncentiveTypeType = "absoluteCost" - IncentiveTypeTypeRelativeCost IncentiveTypeType = "relativeCost" - IncentiveTypeTypeRenewableEnergyPercentage IncentiveTypeType = "renewableEnergyPercentage" - IncentiveTypeTypeCo2Emission IncentiveTypeType = "co2Emission" -) - -type IncentivePriorityType uint - -type IncentiveValueTypeType string - -const ( - IncentiveValueTypeTypeValue IncentiveValueTypeType = "value" - IncentiveValueTypeTypeAverageValue IncentiveValueTypeType = "averageValue" - IncentiveValueTypeTypeMinvalue IncentiveValueTypeType = "minValue" - IncentiveValueTypeTypeMaxvalue IncentiveValueTypeType = "maxValue" -) - -type TariffOverallConstraintsDataType struct { - MaxTariffCount *TariffCountType `json:"maxTariffCount,omitempty"` - MaxBoundaryCount *TierBoundaryCountType `json:"maxBoundaryCount,omitempty"` - MaxTierCount *TierCountType `json:"maxTierCount,omitempty"` - MaxIncentiveCount *IncentiveCountType `json:"maxIncentiveCount,omitempty"` - MaxBoundariesPerTariff *TierBoundaryCountType `json:"maxBoundariesPerTariff,omitempty"` - MaxTiersPerTariff *TierCountType `json:"maxTiersPerTariff,omitempty"` - MaxBoundariesPerTier *TierBoundaryCountType `json:"maxBoundariesPerTier,omitempty"` - MaxIncentivesPerTier *IncentiveCountType `json:"maxIncentivesPerTier,omitempty"` -} - -type TariffOverallConstraintsDataElementsType struct { - MaxTariffCount *ElementTagType `json:"maxTariffCount,omitempty"` - MaxBoundaryCount *ElementTagType `json:"maxBoundaryCount,omitempty"` - MaxTierCount *ElementTagType `json:"maxTierCount,omitempty"` - MaxIncentiveCount *ElementTagType `json:"maxIncentiveCount,omitempty"` - MaxBoundariesPerTariff *ElementTagType `json:"maxBoundariesPerTariff,omitempty"` - MaxTiersPerTariff *ElementTagType `json:"maxTiersPerTariff,omitempty"` - MaxBoundariesPerTier *ElementTagType `json:"maxBoundariesPerTier,omitempty"` - MaxIncentivesPerTier *ElementTagType `json:"maxIncentivesPerTier,omitempty"` -} - -type TariffDataType struct { - TariffId *TariffIdType `json:"tariffId,omitempty" eebus:"key"` - ActiveTierId []TierIdType `json:"activeTierId,omitempty"` -} - -type TariffDataElementsType struct { - TariffId *ElementTagType `json:"tariffId,omitempty"` - ActiveTierId *ElementTagType `json:"activeTierId,omitempty"` -} - -type TariffListDataType struct { - TariffData []TariffDataType `json:"tariffData,omitempty"` -} - -type TariffListDataSelectorsType struct { - TariffId *TariffIdType `json:"tariffId,omitempty"` - ActiveTierId *TierIdType `json:"activeTierId,omitempty"` -} - -type TariffTierRelationDataType struct { - TariffId *TariffIdType `json:"tariffId,omitempty" eebus:"key"` - TierId []TierIdType `json:"tierId,omitempty"` -} - -type TariffTierRelationDataElementsType struct { - TariffId *ElementTagType `json:"tariffId,omitempty"` - TierId *ElementTagType `json:"tierId,omitempty"` -} - -type TariffTierRelationListDataType struct { - TariffTierRelationData []TariffTierRelationDataType `json:"tariffTierRelationData,omitempty"` -} - -type TariffTierRelationListDataSelectorsType struct { - TariffId *TariffIdType `json:"tariffId,omitempty"` - TierId *TierIdType `json:"tierId,omitempty"` -} - -type TariffBoundaryRelationDataType struct { - TariffId *TariffIdType `json:"tariffId,omitempty" eebus:"key"` - BoundaryId []TierBoundaryIdType `json:"boundaryId,omitempty"` -} - -type TariffBoundaryRelationDataElementsType struct { - TariffId *ElementTagType `json:"tariffId,omitempty"` - BoundaryId *ElementTagType `json:"boundaryId,omitempty"` -} - -type TariffBoundaryRelationListDataType struct { - TariffBoundaryRelationData []TariffBoundaryRelationDataType `json:"tariffBoundaryRelationData,omitempty"` -} - -type TariffBoundaryRelationListDataSelectorsType struct { - TariffId *TariffIdType `json:"tariffId,omitempty"` - BoundaryId *TierBoundaryIdType `json:"boundaryId,omitempty"` -} - -type TariffDescriptionDataType struct { - TariffId *TariffIdType `json:"tariffId,omitempty" eebus:"key"` - CommodityId *CommodityIdType `json:"commodityId,omitempty"` - MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` - TariffWriteable *bool `json:"tariffWriteable,omitempty"` - UpdateRequired *bool `json:"updateRequired,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` - SlotIdSupport *bool `json:"slotIdSupport,omitempty"` -} - -type TariffDescriptionDataElementsType struct { - TariffId *ElementTagType `json:"tariffId,omitempty"` - CommodityId *ElementTagType `json:"commodityId,omitempty"` - MeasurementId *ElementTagType `json:"measurementId,omitempty"` - TariffWriteable *ElementTagType `json:"tariffWriteable,omitempty"` - UpdateRequired *ElementTagType `json:"updateRequired,omitempty"` - ScopeType *ElementTagType `json:"scopeType,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` - SlotIdSupport *ElementTagType `json:"slotIdSupport,omitempty"` -} - -type TariffDescriptionListDataType struct { - TariffDescriptionData []TariffDescriptionDataType `json:"tariffDescriptionData,omitempty"` -} - -type TariffDescriptionListDataSelectorsType struct { - TariffId *TariffIdType `json:"tariffId,omitempty"` - CommodityId *CommodityIdType `json:"commodityId,omitempty"` - MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` -} - -type TierBoundaryDataType struct { - BoundaryId *TierBoundaryIdType `json:"boundaryId,omitempty" eebus:"key"` - TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` - TimeTableId *TimeTableIdType `json:"timeTableId,omitempty"` - LowerBoundaryValue *ScaledNumberType `json:"lowerBoundaryValue,omitempty"` - UpperBoundaryValue *ScaledNumberType `json:"upperBoundaryValue,omitempty"` -} - -type TierBoundaryDataElementsType struct { - BoundaryId *ElementTagType `json:"boundaryId,omitempty"` - TimePeriod *TimePeriodElementsType `json:"timePeriod,omitempty"` - TimeTableId *ElementTagType `json:"timeTableId,omitempty"` - LowerBoundaryValue *ScaledNumberElementsType `json:"lowerBoundaryValue,omitempty"` - UpperBoundaryValue *ScaledNumberElementsType `json:"upperBoundaryValue,omitempty"` -} - -type TierBoundaryListDataType struct { - TierBoundaryData []TierBoundaryDataType `json:"tierBoundaryData,omitempty"` -} - -type TierBoundaryListDataSelectorsType struct { - BoundaryId *TierBoundaryIdType `json:"boundaryId,omitempty"` -} - -type TierBoundaryDescriptionDataType struct { - BoundaryId *TierBoundaryIdType `json:"boundaryId,omitempty" eebus:"key"` - BoundaryType *TierBoundaryTypeType `json:"boundaryType,omitempty"` - ValidForTierId *TierIdType `json:"validForTierId,omitempty"` - SwitchToTierIdWhenLower *TierIdType `json:"switchToTierIdWhenLower,omitempty"` - SwitchToTierIdWhenHigher *TierIdType `json:"switchToTierIdWhenHigher,omitempty"` - BoundaryUnit *UnitOfMeasurementType `json:"boundaryUnit,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type TierBoundaryDescriptionDataElementsType struct { - BoundaryId *ElementTagType `json:"boundaryId,omitempty"` - BoundaryType *ElementTagType `json:"boundaryType,omitempty"` - ValidForTierId *ElementTagType `json:"validForTierId,omitempty"` - SwitchToTierIdWhenLower *ElementTagType `json:"switchToTierIdWhenLower,omitempty"` - SwitchToTierIdWhenHigher *ElementTagType `json:"switchToTierIdWhenHigher,omitempty"` - BoundaryUnit *ElementTagType `json:"boundaryUnit,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type TierBoundaryDescriptionListDataType struct { - TierBoundaryDescriptionData []TierBoundaryDescriptionDataType `json:"tierBoundaryDescriptionData,omitempty"` -} - -type TierBoundaryDescriptionListDataSelectorsType struct { - BoundaryId *TierBoundaryIdType `json:"boundaryId,omitempty"` - BoundaryType *TierBoundaryTypeType `json:"boundaryType,omitempty"` -} - -type CommodityDataType struct { - CommodityId *CommodityIdType `json:"commodityId,omitempty" eebus:"key"` - CommodityType *CommodityTypeType `json:"commodityType,omitempty"` - PositiveEnergyDirection *EnergyDirectionType `json:"positiveEnergyDirection,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type CommodityDataElementsType struct { - CommodityId *ElementTagType `json:"commodityId,omitempty"` - CommodityType *ElementTagType `json:"commodityType,omitempty"` - PositiveEnergyDirection *ElementTagType `json:"positiveEnergyDirection,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type CommodityListDataType struct { - CommodityData []CommodityDataType `json:"commodityData,omitempty"` -} - -type CommodityListDataSelectorsType struct { - CommodityId *CommodityIdType `json:"commodityId,omitempty"` - CommodityType *CommodityTypeType `json:"commodityType,omitempty"` -} - -type TierDataType struct { - TierId *TierIdType `json:"tierId,omitempty" eebus:"key"` - TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` - TimeTableId *TimeTableIdType `json:"timeTableId,omitempty"` - ActiveIncentiveId []IncentiveIdType `json:"activeIncentiveId,omitempty"` -} - -type TierDataElementsType struct { - TierId *ElementTagType `json:"tierId,omitempty"` - TimePeriod *ElementTagType `json:"timePeriod,omitempty"` - TimeTableId *ElementTagType `json:"timeTableId,omitempty"` - ActiveIncentiveId *ElementTagType `json:"activeIncentiveId,omitempty"` -} - -type TierListDataType struct { - TierData []TierDataType `json:"tierData,omitempty"` -} - -type TierListDataSelectorsType struct { - TierId *TierIdType `json:"tierId,omitempty"` - ActiveIncentiveId *IncentiveIdType `json:"activeIncentiveId,omitempty"` -} - -type TierIncentiveRelationDataType struct { - TierId *TierIdType `json:"tierId,omitempty" eebus:"key"` - IncentiveId []IncentiveIdType `json:"incentiveId,omitempty"` -} - -type TierIncentiveRelationDataElementsType struct { - TierId *ElementTagType `json:"tierId,omitempty"` - IncentiveId *ElementTagType `json:"incentiveId,omitempty"` -} - -type TierIncentiveRelationListDataType struct { - TierIncentiveRelationData []TierIncentiveRelationDataType `json:"tierIncentiveRelationData,omitempty"` -} - -type TierIncentiveRelationListDataSelectorsType struct { - TierId *TierIdType `json:"tierId,omitempty"` - IncentiveId *IncentiveIdType `json:"incentiveId,omitempty"` -} - -type TierDescriptionDataType struct { - TierId *TierIdType `json:"tierId,omitempty" eebus:"key"` - TierType *TierTypeType `json:"tierType,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type TierDescriptionDataElementsType struct { - TierId *ElementTagType `json:"tierId,omitempty"` - TierType *ElementTagType `json:"tierType,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type TierDescriptionListDataType struct { - TierDescriptionData []TierDescriptionDataType `json:"tierDescriptionData,omitempty"` -} - -type TierDescriptionListDataSelectorsType struct { - TierId *TierIdType `json:"tierId,omitempty"` - TierType *TierTypeType `json:"tierType,omitempty"` -} - -type IncentiveDataType struct { - IncentiveId *IncentiveIdType `json:"incentiveId,omitempty" eebus:"key"` - ValueType *IncentiveValueTypeType `json:"valueType,omitempty"` - Timestamp *AbsoluteOrRelativeTimeType `json:"timestamp,omitempty"` - TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` - TimeTableId *TimeTableIdType `json:"timeTableId,omitempty"` - Value *ScaledNumberType `json:"value,omitempty"` -} - -type IncentiveDataElementsType struct { - IncentiveId *ElementTagType `json:"incentiveId,omitempty"` - ValueType *ElementTagType `json:"valueType,omitempty"` - Timestamp *ElementTagType `json:"timestamp,omitempty"` - TimePeriod *TimePeriodElementsType `json:"timePeriod,omitempty"` - TimeTableId *ElementTagType `json:"timeTableId,omitempty"` - Value *ScaledNumberElementsType `json:"value,omitempty"` -} - -type IncentiveListDataType struct { - IncentiveData []IncentiveDataType `json:"incentiveData,omitempty"` -} - -type IncentiveListDataSelectorsType struct { - IncentiveId *IncentiveIdType `json:"incentiveId,omitempty"` - ValueType *IncentiveValueTypeType `json:"valueType,omitempty"` - TimestampInterval *TimestampIntervalType `json:"timestampInterval,omitempty"` -} - -type IncentiveDescriptionDataType struct { - IncentiveId *IncentiveIdType `json:"incentiveId,omitempty" eebus:"key"` - IncentiveType *IncentiveTypeType `json:"incentiveType,omitempty"` - IncentivePriority *IncentivePriorityType `json:"incentivePriority,omitempty"` - Currency *CurrencyType `json:"currency,omitempty"` - Unit *UnitOfMeasurementType `json:"unit,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type IncentiveDescriptionDataElementsType struct { - IncentiveId *ElementTagType `json:"incentiveId,omitempty"` - IncentiveType *ElementTagType `json:"incentiveType,omitempty"` - IncentivePriority *ElementTagType `json:"incentivePriority,omitempty"` - Currency *ElementTagType `json:"currency,omitempty"` - Unit *ElementTagType `json:"unit,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type IncentiveDescriptionListDataType struct { - IncentiveDescriptionData []IncentiveDescriptionDataType `json:"incentiveDescriptionData,omitempty"` -} - -type IncentiveDescriptionListDataSelectorsType struct { - IncentiveId *IncentiveIdType `json:"incentiveId,omitempty"` - IncentiveType *IncentiveTypeType `json:"incentiveType,omitempty"` -} diff --git a/spine/model/tariffinformation_additions.go b/spine/model/tariffinformation_additions.go deleted file mode 100644 index e05e5a70..00000000 --- a/spine/model/tariffinformation_additions.go +++ /dev/null @@ -1,157 +0,0 @@ -package model - -// TariffListDataType - -var _ Updater = (*TariffListDataType)(nil) - -func (r *TariffListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TariffDataType - if newList != nil { - newData = newList.(*TariffListDataType).TariffData - } - - r.TariffData = UpdateList(r.TariffData, newData, filterPartial, filterDelete) -} - -// TariffTierRelationListDataType - -var _ Updater = (*TariffTierRelationListDataType)(nil) - -func (r *TariffTierRelationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TariffTierRelationDataType - if newList != nil { - newData = newList.(*TariffTierRelationListDataType).TariffTierRelationData - } - - r.TariffTierRelationData = UpdateList(r.TariffTierRelationData, newData, filterPartial, filterDelete) -} - -// TariffBoundaryRelationListDataType - -var _ Updater = (*TariffBoundaryRelationListDataType)(nil) - -func (r *TariffBoundaryRelationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TariffBoundaryRelationDataType - if newList != nil { - newData = newList.(*TariffBoundaryRelationListDataType).TariffBoundaryRelationData - } - - r.TariffBoundaryRelationData = UpdateList(r.TariffBoundaryRelationData, newData, filterPartial, filterDelete) -} - -// TariffDescriptionListDataType - -var _ Updater = (*TariffDescriptionListDataType)(nil) - -func (r *TariffDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TariffDescriptionDataType - if newList != nil { - newData = newList.(*TariffDescriptionListDataType).TariffDescriptionData - } - - r.TariffDescriptionData = UpdateList(r.TariffDescriptionData, newData, filterPartial, filterDelete) -} - -// TierBoundaryListDataType - -var _ Updater = (*TierBoundaryListDataType)(nil) - -func (r *TierBoundaryListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TierBoundaryDataType - if newList != nil { - newData = newList.(*TierBoundaryListDataType).TierBoundaryData - } - - r.TierBoundaryData = UpdateList(r.TierBoundaryData, newData, filterPartial, filterDelete) -} - -// TierBoundaryDescriptionListDataType - -var _ Updater = (*TierBoundaryDescriptionListDataType)(nil) - -func (r *TierBoundaryDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TierBoundaryDescriptionDataType - if newList != nil { - newData = newList.(*TierBoundaryDescriptionListDataType).TierBoundaryDescriptionData - } - - r.TierBoundaryDescriptionData = UpdateList(r.TierBoundaryDescriptionData, newData, filterPartial, filterDelete) -} - -// CommodityListDataType - -var _ Updater = (*CommodityListDataType)(nil) - -func (r *CommodityListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []CommodityDataType - if newList != nil { - newData = newList.(*CommodityListDataType).CommodityData - } - - r.CommodityData = UpdateList(r.CommodityData, newData, filterPartial, filterDelete) -} - -// TierListDataType - -var _ Updater = (*TierListDataType)(nil) - -func (r *TierListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TierDataType - if newList != nil { - newData = newList.(*TierListDataType).TierData - } - - r.TierData = UpdateList(r.TierData, newData, filterPartial, filterDelete) -} - -// TierIncentiveRelationListDataType - -var _ Updater = (*TierIncentiveRelationListDataType)(nil) - -func (r *TierIncentiveRelationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TierIncentiveRelationDataType - if newList != nil { - newData = newList.(*TierIncentiveRelationListDataType).TierIncentiveRelationData - } - - r.TierIncentiveRelationData = UpdateList(r.TierIncentiveRelationData, newData, filterPartial, filterDelete) -} - -// TierDescriptionListDataType - -var _ Updater = (*TierDescriptionListDataType)(nil) - -func (r *TierDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TierDescriptionDataType - if newList != nil { - newData = newList.(*TierDescriptionListDataType).TierDescriptionData - } - - r.TierDescriptionData = UpdateList(r.TierDescriptionData, newData, filterPartial, filterDelete) -} - -// IncentiveListDataType - -var _ Updater = (*IncentiveListDataType)(nil) - -func (r *IncentiveListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []IncentiveDataType - if newList != nil { - newData = newList.(*IncentiveListDataType).IncentiveData - } - - r.IncentiveData = UpdateList(r.IncentiveData, newData, filterPartial, filterDelete) -} - -// IncentiveDescriptionListDataType - -var _ Updater = (*IncentiveDescriptionListDataType)(nil) - -func (r *IncentiveDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []IncentiveDescriptionDataType - if newList != nil { - newData = newList.(*IncentiveDescriptionListDataType).IncentiveDescriptionData - } - - r.IncentiveDescriptionData = UpdateList(r.IncentiveDescriptionData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/tariffinformation_additions_test.go b/spine/model/tariffinformation_additions_test.go deleted file mode 100644 index e590d5dd..00000000 --- a/spine/model/tariffinformation_additions_test.go +++ /dev/null @@ -1,465 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestTariffListDataType_Update(t *testing.T) { - sut := model.TariffListDataType{ - TariffData: []model.TariffDataType{ - { - TariffId: util.Ptr(model.TariffIdType(0)), - ActiveTierId: []model.TierIdType{0}, - }, - { - TariffId: util.Ptr(model.TariffIdType(1)), - ActiveTierId: []model.TierIdType{0}, - }, - }, - } - - newData := model.TariffListDataType{ - TariffData: []model.TariffDataType{ - { - TariffId: util.Ptr(model.TariffIdType(1)), - ActiveTierId: []model.TierIdType{1}, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TariffData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TariffId)) - assert.Equal(t, 0, int(item1.ActiveTierId[0])) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TariffId)) - assert.Equal(t, 1, int(item2.ActiveTierId[0])) -} - -func TestTariffTierRelationListDataType_Update(t *testing.T) { - sut := model.TariffTierRelationListDataType{ - TariffTierRelationData: []model.TariffTierRelationDataType{ - { - TariffId: util.Ptr(model.TariffIdType(0)), - TierId: []model.TierIdType{0}, - }, - { - TariffId: util.Ptr(model.TariffIdType(1)), - TierId: []model.TierIdType{0}, - }, - }, - } - - newData := model.TariffTierRelationListDataType{ - TariffTierRelationData: []model.TariffTierRelationDataType{ - { - TariffId: util.Ptr(model.TariffIdType(1)), - TierId: []model.TierIdType{1}, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TariffTierRelationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TariffId)) - assert.Equal(t, 0, int(item1.TierId[0])) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TariffId)) - assert.Equal(t, 1, int(item2.TierId[0])) -} - -func TestTariffBoundaryRelationListDataType_Update(t *testing.T) { - sut := model.TariffBoundaryRelationListDataType{ - TariffBoundaryRelationData: []model.TariffBoundaryRelationDataType{ - { - TariffId: util.Ptr(model.TariffIdType(0)), - BoundaryId: []model.TierBoundaryIdType{0}, - }, - { - TariffId: util.Ptr(model.TariffIdType(1)), - BoundaryId: []model.TierBoundaryIdType{0}, - }, - }, - } - - newData := model.TariffBoundaryRelationListDataType{ - TariffBoundaryRelationData: []model.TariffBoundaryRelationDataType{ - { - TariffId: util.Ptr(model.TariffIdType(1)), - BoundaryId: []model.TierBoundaryIdType{1}, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TariffBoundaryRelationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TariffId)) - assert.Equal(t, 0, int(item1.BoundaryId[0])) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TariffId)) - assert.Equal(t, 1, int(item2.BoundaryId[0])) -} - -func TestTariffDescriptionListDataType_Update(t *testing.T) { - sut := model.TariffDescriptionListDataType{ - TariffDescriptionData: []model.TariffDescriptionDataType{ - { - TariffId: util.Ptr(model.TariffIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - TariffId: util.Ptr(model.TariffIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.TariffDescriptionListDataType{ - TariffDescriptionData: []model.TariffDescriptionDataType{ - { - TariffId: util.Ptr(model.TariffIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TariffDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TariffId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TariffId)) - assert.Equal(t, "new", string(*item2.Description)) -} - -func TestTierBoundaryListDataType_Update(t *testing.T) { - sut := model.TierBoundaryListDataType{ - TierBoundaryData: []model.TierBoundaryDataType{ - { - BoundaryId: util.Ptr(model.TierBoundaryIdType(0)), - LowerBoundaryValue: model.NewScaledNumberType(1), - }, - { - BoundaryId: util.Ptr(model.TierBoundaryIdType(1)), - LowerBoundaryValue: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.TierBoundaryListDataType{ - TierBoundaryData: []model.TierBoundaryDataType{ - { - BoundaryId: util.Ptr(model.TierBoundaryIdType(1)), - LowerBoundaryValue: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TierBoundaryData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.BoundaryId)) - assert.Equal(t, 1.0, item1.LowerBoundaryValue.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.BoundaryId)) - assert.Equal(t, 10.0, item2.LowerBoundaryValue.GetValue()) -} - -func TestTierBoundaryDescriptionListDataType_Update(t *testing.T) { - sut := model.TierBoundaryDescriptionListDataType{ - TierBoundaryDescriptionData: []model.TierBoundaryDescriptionDataType{ - { - BoundaryId: util.Ptr(model.TierBoundaryIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - BoundaryId: util.Ptr(model.TierBoundaryIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.TierBoundaryDescriptionListDataType{ - TierBoundaryDescriptionData: []model.TierBoundaryDescriptionDataType{ - { - BoundaryId: util.Ptr(model.TierBoundaryIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TierBoundaryDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.BoundaryId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.BoundaryId)) - assert.Equal(t, "new", string(*item2.Description)) -} - -func TestCommodityListDataType_Update(t *testing.T) { - sut := model.CommodityListDataType{ - CommodityData: []model.CommodityDataType{ - { - CommodityId: util.Ptr(model.CommodityIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - CommodityId: util.Ptr(model.CommodityIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.CommodityListDataType{ - CommodityData: []model.CommodityDataType{ - { - CommodityId: util.Ptr(model.CommodityIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.CommodityData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.CommodityId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.CommodityId)) - assert.Equal(t, "new", string(*item2.Description)) -} - -func TestTierListDataType_Update(t *testing.T) { - sut := model.TierListDataType{ - TierData: []model.TierDataType{ - { - TierId: util.Ptr(model.TierIdType(0)), - ActiveIncentiveId: []model.IncentiveIdType{0}, - }, - { - TierId: util.Ptr(model.TierIdType(1)), - ActiveIncentiveId: []model.IncentiveIdType{0}, - }, - }, - } - - newData := model.TierListDataType{ - TierData: []model.TierDataType{ - { - TierId: util.Ptr(model.TierIdType(1)), - ActiveIncentiveId: []model.IncentiveIdType{1}, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TierData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TierId)) - assert.Equal(t, 0, int(item1.ActiveIncentiveId[0])) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TierId)) - assert.Equal(t, 1, int(item2.ActiveIncentiveId[0])) -} - -func TestTierIncentiveRelationListDataType_Update(t *testing.T) { - sut := model.TierIncentiveRelationListDataType{ - TierIncentiveRelationData: []model.TierIncentiveRelationDataType{ - { - TierId: util.Ptr(model.TierIdType(0)), - IncentiveId: []model.IncentiveIdType{0}, - }, - { - TierId: util.Ptr(model.TierIdType(1)), - IncentiveId: []model.IncentiveIdType{0}, - }, - }, - } - - newData := model.TierIncentiveRelationListDataType{ - TierIncentiveRelationData: []model.TierIncentiveRelationDataType{ - { - TierId: util.Ptr(model.TierIdType(1)), - IncentiveId: []model.IncentiveIdType{1}, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TierIncentiveRelationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TierId)) - assert.Equal(t, 0, int(item1.IncentiveId[0])) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TierId)) - assert.Equal(t, 1, int(item2.IncentiveId[0])) -} - -func TestTierDescriptionListDataType_Update(t *testing.T) { - sut := model.TierDescriptionListDataType{ - TierDescriptionData: []model.TierDescriptionDataType{ - { - TierId: util.Ptr(model.TierIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - TierId: util.Ptr(model.TierIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.TierDescriptionListDataType{ - TierDescriptionData: []model.TierDescriptionDataType{ - { - TierId: util.Ptr(model.TierIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TierDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TierId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TierId)) - assert.Equal(t, "new", string(*item2.Description)) -} - -func TestIncentiveListDataType_Update(t *testing.T) { - sut := model.IncentiveListDataType{ - IncentiveData: []model.IncentiveDataType{ - { - IncentiveId: util.Ptr(model.IncentiveIdType(0)), - Value: model.NewScaledNumberType(1), - }, - { - IncentiveId: util.Ptr(model.IncentiveIdType(1)), - Value: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.IncentiveListDataType{ - IncentiveData: []model.IncentiveDataType{ - { - IncentiveId: util.Ptr(model.IncentiveIdType(1)), - Value: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.IncentiveData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.IncentiveId)) - assert.Equal(t, 1.0, item1.Value.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.IncentiveId)) - assert.Equal(t, 10.0, item2.Value.GetValue()) -} - -func TestIncentiveDescriptionListDataType_Update(t *testing.T) { - sut := model.IncentiveDescriptionListDataType{ - IncentiveDescriptionData: []model.IncentiveDescriptionDataType{ - { - IncentiveId: util.Ptr(model.IncentiveIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - IncentiveId: util.Ptr(model.IncentiveIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.IncentiveDescriptionListDataType{ - IncentiveDescriptionData: []model.IncentiveDescriptionDataType{ - { - IncentiveId: util.Ptr(model.IncentiveIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.IncentiveDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.IncentiveId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.IncentiveId)) - assert.Equal(t, "new", string(*item2.Description)) -} diff --git a/spine/model/taskmanagement.go b/spine/model/taskmanagement.go deleted file mode 100644 index 73886d3f..00000000 --- a/spine/model/taskmanagement.go +++ /dev/null @@ -1,159 +0,0 @@ -package model - -type TaskManagementJobIdType uint - -type TaskManagementJobStateType string - -const ( - // DirectControlActivityStateType - TaskManagementJobStateTypeRunning TaskManagementJobStateType = "Running" - TaskManagementJobStateTypePaused TaskManagementJobStateType = "paused" - TaskManagementJobStateTypeInactive TaskManagementJobStateType = "inactive" - - // HvacOverrunStatusType - TaskManagementJobStateTypeActive TaskManagementJobStateType = "active" - TaskManagementJobStateTypeFinished TaskManagementJobStateType = "finished" - - // LoadControlEventStateType - TaskManagementJobStateTypeEventAccepted TaskManagementJobStateType = "eventAccepted" - TaskManagementJobStateTypeEventStarted TaskManagementJobStateType = "eventStarted" - TaskManagementJobStateTypeEventStopped TaskManagementJobStateType = "eventStopped" - TaskManagementJobStateTypeEventRejected TaskManagementJobStateType = "eventRejected" - TaskManagementJobStateTypeEventCancelled TaskManagementJobStateType = "eventCancelled" - TaskManagementJobStateTypeEventError TaskManagementJobStateType = "eventError" - - // PowerSequenceStateType - TaskManagementJobStateTypeScheduled TaskManagementJobStateType = "scheduled" - TaskManagementJobStateTypeScheduledPaused TaskManagementJobStateType = "scheduledPaused" - TaskManagementJobStateTypePending TaskManagementJobStateType = "pending" - TaskManagementJobStateTypeCompleted TaskManagementJobStateType = "completed" - TaskManagementJobStateTypeInvalid TaskManagementJobStateType = "invalid" -) - -type TaskManagementJobSourceType string - -const ( - TaskManagementJobSourceTypeInternalMechanism TaskManagementJobSourceType = "InternalMechanism" - TaskManagementJobSourceTypeUserInteraction TaskManagementJobSourceType = "UserInteraction" - TaskManagementJobSourceTypeExternalConfiguration TaskManagementJobSourceType = "ExternalConfiguration" -) - -type TaskManagementDirectControlRelatedType struct{} - -type TaskManagementDirectControlRelatedElementsType struct{} - -type TaskManagementHvacRelatedType struct { - OverrunId *HvacOverrunIdType `json:"overrunId,omitempty"` -} - -type TaskManagementHvacRelatedElementsType struct { - OverrunId *ElementTagType `json:"overrunId,omitempty"` -} - -type TaskManagementLoadControlReleatedType struct { - EventId *LoadControlEventIdType `json:"eventId,omitempty"` -} - -type TaskManagementLoadControlReleatedElementsType struct { - EventId *ElementTagType `json:"eventId,omitempty"` -} - -type TaskManagementPowerSequencesRelatedType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type TaskManagementPowerSequencesRelatedElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` -} - -type TaskManagementSmartEnergyManagementPsRelatedType struct { - SequenceId *PowerSequenceIdType `json:"sequenceId,omitempty"` -} - -type TaskManagementSmartEnergyManagementPsRelatedElementsType struct { - SequenceId *ElementTagType `json:"sequenceId,omitempty"` -} - -type TaskManagementJobDataType struct { - JobId *TaskManagementJobIdType `json:"jobId,omitempty" eebus:"key"` - Timestamp *AbsoluteOrRelativeTimeType `json:"timestamp,omitempty"` - JobState *TaskManagementJobStateType `json:"jobState,omitempty"` - ElapsedTime *DurationType `json:"elapsedTime,omitempty"` - RemainingTime *DurationType `json:"remainingTime,omitempty"` -} - -type TaskManagementJobDataElementsType struct { - JobId *ElementTagType `json:"jobId,omitempty"` - Timestamp *ElementTagType `json:"timestamp,omitempty"` - JobState *ElementTagType `json:"jobState,omitempty"` - ElapsedTime *ElementTagType `json:"elapsedTime,omitempty"` - RemainingTime *ElementTagType `json:"remainingTime,omitempty"` -} - -type TaskManagementJobListDataType struct { - TaskManagementJobData []TaskManagementJobDataType `json:"taskManagementJobData,omitempty"` -} - -type TaskManagementJobListDataSelectorsType struct { - JobId *TaskManagementJobIdType `json:"jobId,omitempty"` - JobState *TaskManagementJobStateType `json:"jobState,omitempty"` -} - -type TaskManagementJobRelationDataType struct { - JobId *TaskManagementJobIdType `json:"jobId,omitempty" eebus:"key"` - DirectControlRelated *TaskManagementDirectControlRelatedType `json:"directControlRelated,omitempty"` - HvacRelated *TaskManagementHvacRelatedType `json:"hvacRelated,omitempty"` - LoadControlReleated *TaskManagementLoadControlReleatedType `json:"loadControlReleated,omitempty"` - PowerSequencesRelated *TaskManagementPowerSequencesRelatedType `json:"powerSequencesRelated,omitempty"` - SmartEnergyManagementPsRelated *TaskManagementSmartEnergyManagementPsRelatedType `json:"smartEnergyManagementPsRelated,omitempty"` -} - -type TaskManagementJobRelationDataElementsType struct { - JobId *ElementTagType `json:"jobId,omitempty"` - DirectControlRelated *TaskManagementDirectControlRelatedElementsType `json:"directControlRelated,omitempty"` - HvacRelated *TaskManagementHvacRelatedElementsType `json:"hvacRelated,omitempty"` - LoadControlReleated *TaskManagementLoadControlReleatedElementsType `json:"loadControlReleated,omitempty"` - PowerSequencesRelated *TaskManagementPowerSequencesRelatedElementsType `json:"powerSequencesRelated,omitempty"` - SmartEnergyManagementPsRelated *TaskManagementSmartEnergyManagementPsRelatedElementsType `json:"smartEnergyManagementPsRelated,omitempty"` -} - -type TaskManagementJobRelationListDataType struct { - TaskManagementJobRelationData []TaskManagementJobRelationDataType `json:"taskManagementJobRelationData,omitempty"` -} - -type TaskManagementJobRelationListDataSelectorsType struct { - JobId *TaskManagementJobIdType `json:"jobId,omitempty"` -} - -type TaskManagementJobDescriptionDataType struct { - JobId *TaskManagementJobIdType `json:"jobId,omitempty" eebus:"key"` - JobSource *TaskManagementJobSourceType `json:"jobSource,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type TaskManagementJobDescriptionDataElementsType struct { - JobId *ElementTagType `json:"jobId,omitempty"` - JobSource *ElementTagType `json:"jobSource,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type TaskManagementJobDescriptionListDataType struct { - TaskManagementJobDescriptionData []TaskManagementJobDescriptionDataType `json:"taskManagementJobDescriptionData,omitempty"` -} - -type TaskManagementJobDescriptionListDataSelectorsType struct { - JobId *TaskManagementJobIdType `json:"jobId,omitempty"` - JobSource *TaskManagementJobSourceType `json:"jobSource,omitempty"` -} - -type TaskManagementOverviewDataType struct { - RemoteControllable *bool `json:"remoteControllable,omitempty"` - JobsActive *bool `json:"jobsActive,omitempty"` -} - -type TaskManagementOverviewDataElementsType struct { - RemoteControllable *ElementTagType `json:"remoteControllable,omitempty"` - JobsActive *ElementTagType `json:"jobsActive,omitempty"` -} diff --git a/spine/model/taskmanagement_additions.go b/spine/model/taskmanagement_additions.go deleted file mode 100644 index 966b31cb..00000000 --- a/spine/model/taskmanagement_additions.go +++ /dev/null @@ -1,40 +0,0 @@ -package model - -// TaskManagementJobListDataType - -var _ Updater = (*TaskManagementJobListDataType)(nil) - -func (r *TaskManagementJobListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TaskManagementJobDataType - if newList != nil { - newData = newList.(*TaskManagementJobListDataType).TaskManagementJobData - } - - r.TaskManagementJobData = UpdateList(r.TaskManagementJobData, newData, filterPartial, filterDelete) -} - -// TaskManagementJobRelationListDataType - -var _ Updater = (*TaskManagementJobRelationListDataType)(nil) - -func (r *TaskManagementJobRelationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TaskManagementJobRelationDataType - if newList != nil { - newData = newList.(*TaskManagementJobRelationListDataType).TaskManagementJobRelationData - } - - r.TaskManagementJobRelationData = UpdateList(r.TaskManagementJobRelationData, newData, filterPartial, filterDelete) -} - -// TaskManagementJobDescriptionListDataType - -var _ Updater = (*TaskManagementJobDescriptionListDataType)(nil) - -func (r *TaskManagementJobDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TaskManagementJobDescriptionDataType - if newList != nil { - newData = newList.(*TaskManagementJobDescriptionListDataType).TaskManagementJobDescriptionData - } - - r.TaskManagementJobDescriptionData = UpdateList(r.TaskManagementJobDescriptionData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/taskmanagement_additions_test.go b/spine/model/taskmanagement_additions_test.go deleted file mode 100644 index 39251682..00000000 --- a/spine/model/taskmanagement_additions_test.go +++ /dev/null @@ -1,129 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestTaskManagementJobListDataType_Update(t *testing.T) { - sut := model.TaskManagementJobListDataType{ - TaskManagementJobData: []model.TaskManagementJobDataType{ - { - JobId: util.Ptr(model.TaskManagementJobIdType(0)), - JobState: util.Ptr(model.TaskManagementJobStateTypeActive), - }, - { - JobId: util.Ptr(model.TaskManagementJobIdType(1)), - JobState: util.Ptr(model.TaskManagementJobStateTypeActive), - }, - }, - } - - newData := model.TaskManagementJobListDataType{ - TaskManagementJobData: []model.TaskManagementJobDataType{ - { - JobId: util.Ptr(model.TaskManagementJobIdType(1)), - JobState: util.Ptr(model.TaskManagementJobStateTypeCompleted), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TaskManagementJobData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.JobId)) - assert.Equal(t, model.TaskManagementJobStateTypeActive, *item1.JobState) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.JobId)) - assert.Equal(t, model.TaskManagementJobStateTypeCompleted, *item2.JobState) -} - -func TestTaskManagementJobRelationListDataType_Update(t *testing.T) { - sut := model.TaskManagementJobRelationListDataType{ - TaskManagementJobRelationData: []model.TaskManagementJobRelationDataType{ - { - JobId: util.Ptr(model.TaskManagementJobIdType(0)), - LoadControlReleated: &model.TaskManagementLoadControlReleatedType{ - EventId: util.Ptr(model.LoadControlEventIdType(0)), - }, - }, - { - JobId: util.Ptr(model.TaskManagementJobIdType(1)), - LoadControlReleated: &model.TaskManagementLoadControlReleatedType{ - EventId: util.Ptr(model.LoadControlEventIdType(0)), - }, - }, - }, - } - - newData := model.TaskManagementJobRelationListDataType{ - TaskManagementJobRelationData: []model.TaskManagementJobRelationDataType{ - { - JobId: util.Ptr(model.TaskManagementJobIdType(1)), - LoadControlReleated: &model.TaskManagementLoadControlReleatedType{ - EventId: util.Ptr(model.LoadControlEventIdType(1)), - }, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TaskManagementJobRelationData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.JobId)) - assert.Equal(t, 0, int(*item1.LoadControlReleated.EventId)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.JobId)) - assert.Equal(t, 1, int(*item2.LoadControlReleated.EventId)) -} - -func TestTaskManagementJobDescriptionListDataType_Update(t *testing.T) { - sut := model.TaskManagementJobDescriptionListDataType{ - TaskManagementJobDescriptionData: []model.TaskManagementJobDescriptionDataType{ - { - JobId: util.Ptr(model.TaskManagementJobIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - JobId: util.Ptr(model.TaskManagementJobIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.TaskManagementJobDescriptionListDataType{ - TaskManagementJobDescriptionData: []model.TaskManagementJobDescriptionDataType{ - { - JobId: util.Ptr(model.TaskManagementJobIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TaskManagementJobDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.JobId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.JobId)) - assert.Equal(t, "new", string(*item2.Description)) -} diff --git a/spine/model/threshold.go b/spine/model/threshold.go deleted file mode 100644 index 574bbf59..00000000 --- a/spine/model/threshold.go +++ /dev/null @@ -1,85 +0,0 @@ -package model - -type ThresholdIdType uint - -type ThresholdTypeType string - -const ( - ThresholdTypeTypeGoodAbove ThresholdTypeType = "goodAbove" - ThresholdTypeTypeBadAbove ThresholdTypeType = "badAbove" - ThresholdTypeTypeGoodBelow ThresholdTypeType = "goodBelow" - ThresholdTypeTypeBadBelow ThresholdTypeType = "badBelow" - ThresholdTypeTypeMinValueThreshold ThresholdTypeType = "minValueThreshold" - ThresholdTypeTypeMaxValueThreshold ThresholdTypeType = "maxValueThreshold" - ThresholdTypeTypeMinValueThresholdExtreme ThresholdTypeType = "minValueThresholdExtreme" - ThresholdTypeTypeMaxValueThresholdExtreme ThresholdTypeType = "maxValueThresholdExtreme" - ThresholdTypeTypeSagThreshold ThresholdTypeType = "sagThreshold" - ThresholdTypeTypeSwellThreshold ThresholdTypeType = "swellThreshold" -) - -type ThresholdDataType struct { - ThresholdId *ThresholdIdType `json:"thresholdId,omitempty" eebus:"key"` - ThresholdValue *ScaledNumberType `json:"thresholdValue,omitempty"` -} - -type ThresholdDataElementsType struct { - ThresholdId *ElementTagType `json:"thresholdId,omitempty"` - ThresholdValue *ScaledNumberElementsType `json:"thresholdValue,omitempty"` -} - -type ThresholdListDataType struct { - ThresholdData []ThresholdDataType `json:"thresholdData,omitempty"` -} - -type ThresholdListDataSelectorsType struct { - ThresholdId *ThresholdIdType `json:"thresholdId,omitempty"` -} - -type ThresholdConstraintsDataType struct { - ThresholdId *ThresholdIdType `json:"thresholdId,omitempty" eebus:"key"` - ThresholdRangeMin *ScaledNumberType `json:"thresholdRangeMin,omitempty"` - ThresholdRangeMax *ScaledNumberType `json:"thresholdRangeMax,omitempty"` - ThresholdStepSize *ScaledNumberType `json:"thresholdStepSize,omitempty"` -} - -type ThresholdConstraintsDataElementsType struct { - ThresholdId *ElementTagType `json:"thresholdId,omitempty"` - ThresholdRangeMin *ScaledNumberElementsType `json:"thresholdRangeMin,omitempty"` - ThresholdRangeMax *ScaledNumberElementsType `json:"thresholdRangeMax,omitempty"` - ThresholdStepSize *ScaledNumberElementsType `json:"thresholdStepSize,omitempty"` -} - -type ThresholdConstraintsListDataType struct { - ThresholdConstraintsData []ThresholdConstraintsDataType `json:"thresholdConstraintsData,omitempty"` -} - -type ThresholdConstraintsListDataSelectorsType struct { - ThresholdId *ThresholdIdType `json:"thresholdId,omitempty"` -} - -type ThresholdDescriptionDataType struct { - ThresholdId *ThresholdIdType `json:"thresholdId,omitempty" eebus:"key"` - ThresholdType *ThresholdTypeType `json:"thresholdType,omitempty"` - Unit *UnitOfMeasurementType `json:"unit,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type ThresholdDescriptionDataElementsType struct { - ThresholdId *ElementTagType `json:"thresholdId,omitempty"` - ThresholdType *ElementTagType `json:"thresholdType,omitempty"` - Unit *ElementTagType `json:"unit,omitempty"` - ScopeType *ElementTagType `json:"scopeType,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type ThresholdDescriptionListDataType struct { - ThresholdDescriptionData []ThresholdDescriptionDataType `json:"thresholdDescriptionData,omitempty"` -} - -type ThresholdDescriptionListDataSelectorsType struct { - ThresholdId *ThresholdIdType `json:"thresholdId,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` -} diff --git a/spine/model/threshold_additions.go b/spine/model/threshold_additions.go deleted file mode 100644 index 07299222..00000000 --- a/spine/model/threshold_additions.go +++ /dev/null @@ -1,40 +0,0 @@ -package model - -// ThresholdListDataType - -var _ Updater = (*ThresholdListDataType)(nil) - -func (r *ThresholdListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []ThresholdDataType - if newList != nil { - newData = newList.(*ThresholdListDataType).ThresholdData - } - - r.ThresholdData = UpdateList(r.ThresholdData, newData, filterPartial, filterDelete) -} - -// ThresholdConstraintsListDataType - -var _ Updater = (*ThresholdConstraintsListDataType)(nil) - -func (r *ThresholdConstraintsListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []ThresholdConstraintsDataType - if newList != nil { - newData = newList.(*ThresholdConstraintsListDataType).ThresholdConstraintsData - } - - r.ThresholdConstraintsData = UpdateList(r.ThresholdConstraintsData, newData, filterPartial, filterDelete) -} - -// ThresholdDescriptionListDataType - -var _ Updater = (*ThresholdDescriptionListDataType)(nil) - -func (r *ThresholdDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []ThresholdDescriptionDataType - if newList != nil { - newData = newList.(*ThresholdDescriptionListDataType).ThresholdDescriptionData - } - - r.ThresholdDescriptionData = UpdateList(r.ThresholdDescriptionData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/threshold_additions_test.go b/spine/model/threshold_additions_test.go deleted file mode 100644 index 81662d77..00000000 --- a/spine/model/threshold_additions_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestThresholdListDataType_Update(t *testing.T) { - sut := model.ThresholdListDataType{ - ThresholdData: []model.ThresholdDataType{ - { - ThresholdId: util.Ptr(model.ThresholdIdType(0)), - ThresholdValue: model.NewScaledNumberType(1), - }, - { - ThresholdId: util.Ptr(model.ThresholdIdType(1)), - ThresholdValue: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.ThresholdListDataType{ - ThresholdData: []model.ThresholdDataType{ - { - ThresholdId: util.Ptr(model.ThresholdIdType(1)), - ThresholdValue: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.ThresholdData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.ThresholdId)) - assert.Equal(t, 1.0, item1.ThresholdValue.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.ThresholdId)) - assert.Equal(t, 10.0, item2.ThresholdValue.GetValue()) -} - -func TestThresholdConstraintsListDataType_Update(t *testing.T) { - sut := model.ThresholdConstraintsListDataType{ - ThresholdConstraintsData: []model.ThresholdConstraintsDataType{ - { - ThresholdId: util.Ptr(model.ThresholdIdType(0)), - ThresholdRangeMin: model.NewScaledNumberType(1), - }, - { - ThresholdId: util.Ptr(model.ThresholdIdType(1)), - ThresholdRangeMin: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.ThresholdConstraintsListDataType{ - ThresholdConstraintsData: []model.ThresholdConstraintsDataType{ - { - ThresholdId: util.Ptr(model.ThresholdIdType(1)), - ThresholdRangeMin: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.ThresholdConstraintsData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.ThresholdId)) - assert.Equal(t, 1.0, item1.ThresholdRangeMin.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.ThresholdId)) - assert.Equal(t, 10.0, item2.ThresholdRangeMin.GetValue()) -} - -func TestThresholdDescriptionListDataType_Update(t *testing.T) { - sut := model.ThresholdDescriptionListDataType{ - ThresholdDescriptionData: []model.ThresholdDescriptionDataType{ - { - ThresholdId: util.Ptr(model.ThresholdIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - ThresholdId: util.Ptr(model.ThresholdIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.ThresholdDescriptionListDataType{ - ThresholdDescriptionData: []model.ThresholdDescriptionDataType{ - { - ThresholdId: util.Ptr(model.ThresholdIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.ThresholdDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.ThresholdId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.ThresholdId)) - assert.Equal(t, "new", string(*item2.Description)) -} diff --git a/spine/model/timeinformation.go b/spine/model/timeinformation.go deleted file mode 100644 index 1d8e606d..00000000 --- a/spine/model/timeinformation.go +++ /dev/null @@ -1,41 +0,0 @@ -package model - -type TimeInformationDataType struct { - Utc *DateTimeType `json:"utc,omitempty"` - UtcOffset *DurationType `json:"utcOffset,omitempty"` - DayOfWeek *DayOfWeekType `json:"dayOfWeek,omitempty"` - CalendarWeek *CalendarWeekType `json:"calendarWeek,omitempty"` -} - -type TimeInformationDataElementsType struct { - Utc *ElementTagType `json:"utc,omitempty"` - UtcOffset *ElementTagType `json:"utcOffset,omitempty"` - DayOfWeek *ElementTagType `json:"dayOfWeek,omitempty"` - CalendarWeek *ElementTagType `json:"calendarWeek,omitempty"` -} - -type TimeDistributorDataType struct { - IsTimeDistributor *bool `json:"isTimeDistributor,omitempty"` - DistributorPriority *uint `json:"distributorPriority,omitempty"` -} - -type TimeDistributorDataElementsType struct { - IsTimeDistributor *ElementTagType `json:"isTimeDistributor,omitempty"` - DistributorPriority *ElementTagType `json:"distributorPriority,omitempty"` -} - -type TimePrecisionDataType struct { - IsSynchronised *bool `json:"isSynchronised,omitempty"` - LastSyncAt *DateTimeType `json:"lastSyncAt,omitempty"` - ClockDrift *int `json:"clockDrift,omitempty"` -} - -type TimePrecisionDataElementsType struct { - IsSynchronised *ElementTagType `json:"isSynchronised,omitempty"` - LastSyncAt *ElementTagType `json:"lastSyncAt,omitempty"` - ClockDrift *ElementTagType `json:"clockDrift,omitempty"` -} - -type TimeDistributorEnquiryCallType struct{} - -type TimeDistributorEnquiryCallElementsType struct{} diff --git a/spine/model/timeseries.go b/spine/model/timeseries.go deleted file mode 100644 index 8d2b0c54..00000000 --- a/spine/model/timeseries.go +++ /dev/null @@ -1,129 +0,0 @@ -package model - -type TimeSeriesIdType uint - -type TimeSeriesSlotIdType uint - -type TimeSeriesSlotCountType TimeSeriesSlotIdType - -type TimeSeriesTypeType string - -const ( - TimeSeriesTypeTypePlan TimeSeriesTypeType = "plan" - TimeSeriesTypeTypeSingleDemand TimeSeriesTypeType = "singleDemand" - TimeSeriesTypeTypeConstraints TimeSeriesTypeType = "constraints" -) - -type TimeSeriesSlotType struct { - TimeSeriesSlotId *TimeSeriesSlotIdType `json:"timeSeriesSlotId,omitempty"` - TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` - Duration *DurationType `json:"duration,omitempty"` - RecurrenceInformation *AbsoluteOrRecurringTimeType `json:"recurrenceInformation,omitempty"` - Value *ScaledNumberType `json:"value,omitempty"` - MinValue *ScaledNumberType `json:"minValue,omitempty"` - MaxValue *ScaledNumberType `json:"maxValue,omitempty"` -} - -type TimeSeriesSlotElementsType struct { - TimeSeriesSlotId *ElementTagType `json:"timeSeriesSlotId,omitempty"` - TimePeriod *ElementTagType `json:"timePeriod,omitempty"` - Duration *ElementTagType `json:"duration,omitempty"` - RecurrenceInformation *AbsoluteOrRecurringTimeElementsType `json:"recurrenceInformation,omitempty"` - Value *ScaledNumberElementsType `json:"value,omitempty"` - MinValue *ScaledNumberElementsType `json:"minValue,omitempty"` - MaxValue *ScaledNumberElementsType `json:"maxValue,omitempty"` -} - -type TimeSeriesDataType struct { - TimeSeriesId *TimeSeriesIdType `json:"timeSeriesId,omitempty" eebus:"key"` - TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` - TimeSeriesSlot []TimeSeriesSlotType `json:"timeSeriesSlot"` -} - -type TimeSeriesDataElementsType struct { - TimeSeriesId *ElementTagType `json:"timeSeriesId,omitempty"` - TimePeriod *TimePeriodElementsType `json:"timePeriod,omitempty"` - TimeSeriesSlot *TimeSeriesSlotElementsType `json:"timeSeriesSlot"` -} - -type TimeSeriesListDataType struct { - TimeSeriesData []TimeSeriesDataType `json:"timeSeriesData,omitempty"` -} - -type TimeSeriesListDataSelectorsType struct { - TimeSeriesId *TimeSeriesIdType `json:"timeSeriesId,omitempty"` - TimeSeriesSlotId *TimeSeriesSlotIdType `json:"timeSeriesSlotId,omitempty"` -} - -type TimeSeriesDescriptionDataType struct { - TimeSeriesId *TimeSeriesIdType `json:"timeSeriesId,omitempty" eebus:"key"` - TimeSeriesType *TimeSeriesTypeType `json:"timeSeriesType,omitempty"` - TimeSeriesWriteable *bool `json:"timeSeriesWriteable,omitempty"` - UpdateRequired *bool `json:"updateRequired,omitempty"` - MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` - Currency *CurrencyType `json:"currency,omitempty"` - Unit *UnitOfMeasurementType `json:"unit,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` -} - -type TimeSeriesDescriptionDataElementsType struct { - TimeSeriesId *ElementTagType `json:"timeSeriesId,omitempty"` - TimeSeriesType *ElementTagType `json:"timeSeriesType,omitempty"` - TimeSeriesWriteable *ElementTagType `json:"timeSeriesWriteable,omitempty"` - UpdateRequired *ElementTagType `json:"updateRequired,omitempty"` - MeasurementId *ElementTagType `json:"measurementId,omitempty"` - Currency *ElementTagType `json:"currency,omitempty"` - Unit *ElementTagType `json:"unit,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` - ScopeType *ElementTagType `json:"scopeType,omitempty"` -} - -type TimeSeriesDescriptionListDataType struct { - TimeSeriesDescriptionData []TimeSeriesDescriptionDataType `json:"timeSeriesDescriptionData,omitempty"` -} - -type TimeSeriesDescriptionListDataSelectorsType struct { - TimeSeriesId *TimeSeriesIdType `json:"timeSeriesId,omitempty"` - TimeSeriesType *TimeSeriesTypeType `json:"timeSeriesType,omitempty"` - MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` - ScopeType *ScopeTypeType `json:"scopeType,omitempty"` -} - -type TimeSeriesConstraintsDataType struct { - TimeSeriesId *TimeSeriesIdType `json:"timeSeriesId,omitempty" eebus:"key"` - SlotCountMin *TimeSeriesSlotCountType `json:"slotCountMin,omitempty"` - SlotCountMax *TimeSeriesSlotCountType `json:"slotCountMax,omitempty"` - SlotDurationMin *DurationType `json:"slotDurationMin,omitempty"` - SlotDurationMax *DurationType `json:"slotDurationMax,omitempty"` - SlotDurationStepSize *DurationType `json:"slotDurationStepSize,omitempty"` - EarliestTimeSeriesStartTime *AbsoluteOrRelativeTimeType `json:"earliestTimeSeriesStartTime,omitempty"` - LatestTimeSeriesEndTime *AbsoluteOrRelativeTimeType `json:"latestTimeSeriesEndTime,omitempty"` - SlotValueMin *ScaledNumberType `json:"slotValueMin,omitempty"` - SlotValueMax *ScaledNumberType `json:"slotValueMax,omitempty"` - SlotValueStepSize *ScaledNumberType `json:"slotValueStepSize,omitempty"` -} - -type TimeSeriesConstraintsDataElementsType struct { - TimeSeriesId *ElementTagType `json:"timeSeriesId,omitempty"` - SlotCountMin *ElementTagType `json:"slotCountMin,omitempty"` - SlotCountMax *ElementTagType `json:"slotCountMax,omitempty"` - SlotDurationMin *ElementTagType `json:"slotDurationMin,omitempty"` - SlotDurationMax *ElementTagType `json:"slotDurationMax,omitempty"` - SlotDurationStepSize *ElementTagType `json:"slotDurationStepSize,omitempty"` - EarliestTimeSeriesStartTime *ElementTagType `json:"earliestTimeSeriesStartTime,omitempty"` - LatestTimeSeriesEndTime *ElementTagType `json:"latestTimeSeriesEndTime,omitempty"` - SlotValueMin *ElementTagType `json:"slotValueMin,omitempty"` - SlotValueMax *ElementTagType `json:"slotValueMax,omitempty"` - SlotValueStepSize *ElementTagType `json:"slotValueStepSize,omitempty"` -} - -type TimeSeriesConstraintsListDataType struct { - TimeSeriesConstraintsData []TimeSeriesConstraintsDataType `json:"timeSeriesConstraintsData,omitempty"` -} - -type TimeSeriesConstraintsListDataSelectorsType struct { - TimeSeriesId *TimeSeriesIdType `json:"timeSeriesId,omitempty"` -} diff --git a/spine/model/timeseries_additions.go b/spine/model/timeseries_additions.go deleted file mode 100644 index 06c1f79e..00000000 --- a/spine/model/timeseries_additions.go +++ /dev/null @@ -1,40 +0,0 @@ -package model - -// TimeSeriesListDataType - -var _ Updater = (*TimeSeriesListDataType)(nil) - -func (r *TimeSeriesListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TimeSeriesDataType - if newList != nil { - newData = newList.(*TimeSeriesListDataType).TimeSeriesData - } - - r.TimeSeriesData = UpdateList(r.TimeSeriesData, newData, filterPartial, filterDelete) -} - -// TimeSeriesDescriptionListDataType - -var _ Updater = (*TimeSeriesDescriptionListDataType)(nil) - -func (r *TimeSeriesDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TimeSeriesDescriptionDataType - if newList != nil { - newData = newList.(*TimeSeriesDescriptionListDataType).TimeSeriesDescriptionData - } - - r.TimeSeriesDescriptionData = UpdateList(r.TimeSeriesDescriptionData, newData, filterPartial, filterDelete) -} - -// TimeSeriesConstraintsListDataType - -var _ Updater = (*TimeSeriesConstraintsListDataType)(nil) - -func (r *TimeSeriesConstraintsListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TimeSeriesConstraintsDataType - if newList != nil { - newData = newList.(*TimeSeriesConstraintsListDataType).TimeSeriesConstraintsData - } - - r.TimeSeriesConstraintsData = UpdateList(r.TimeSeriesConstraintsData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/timeseries_additions_test.go b/spine/model/timeseries_additions_test.go deleted file mode 100644 index 688c0645..00000000 --- a/spine/model/timeseries_additions_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestTimeSeriesListDataType_Update(t *testing.T) { - sut := model.TimeSeriesListDataType{ - TimeSeriesData: []model.TimeSeriesDataType{ - { - TimeSeriesId: util.Ptr(model.TimeSeriesIdType(0)), - TimeSeriesSlot: []model.TimeSeriesSlotType{ - { - TimeSeriesSlotId: util.Ptr(model.TimeSeriesSlotIdType(0)), - }, - }, - }, - { - TimeSeriesId: util.Ptr(model.TimeSeriesIdType(1)), - TimeSeriesSlot: []model.TimeSeriesSlotType{ - { - TimeSeriesSlotId: util.Ptr(model.TimeSeriesSlotIdType(0)), - }, - }, - }, - }, - } - - newData := model.TimeSeriesListDataType{ - TimeSeriesData: []model.TimeSeriesDataType{ - { - TimeSeriesId: util.Ptr(model.TimeSeriesIdType(1)), - TimeSeriesSlot: []model.TimeSeriesSlotType{ - { - TimeSeriesSlotId: util.Ptr(model.TimeSeriesSlotIdType(1)), - }, - }, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TimeSeriesData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TimeSeriesId)) - assert.Equal(t, 0, int(*item1.TimeSeriesSlot[0].TimeSeriesSlotId)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TimeSeriesId)) - assert.Equal(t, 1, int(*item2.TimeSeriesSlot[0].TimeSeriesSlotId)) -} - -func TestTimeSeriesDescriptionListDataType_Update(t *testing.T) { - sut := model.TimeSeriesDescriptionListDataType{ - TimeSeriesDescriptionData: []model.TimeSeriesDescriptionDataType{ - { - TimeSeriesId: util.Ptr(model.TimeSeriesIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - TimeSeriesId: util.Ptr(model.TimeSeriesIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.TimeSeriesDescriptionListDataType{ - TimeSeriesDescriptionData: []model.TimeSeriesDescriptionDataType{ - { - TimeSeriesId: util.Ptr(model.TimeSeriesIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TimeSeriesDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TimeSeriesId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TimeSeriesId)) - assert.Equal(t, "new", string(*item2.Description)) -} - -func TestTimeSeriesConstraintsListDataType_Update(t *testing.T) { - sut := model.TimeSeriesConstraintsListDataType{ - TimeSeriesConstraintsData: []model.TimeSeriesConstraintsDataType{ - { - TimeSeriesId: util.Ptr(model.TimeSeriesIdType(0)), - SlotValueMin: model.NewScaledNumberType(1), - }, - { - TimeSeriesId: util.Ptr(model.TimeSeriesIdType(1)), - SlotValueMin: model.NewScaledNumberType(1), - }, - }, - } - - newData := model.TimeSeriesConstraintsListDataType{ - TimeSeriesConstraintsData: []model.TimeSeriesConstraintsDataType{ - { - TimeSeriesId: util.Ptr(model.TimeSeriesIdType(1)), - SlotValueMin: model.NewScaledNumberType(10), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TimeSeriesConstraintsData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TimeSeriesId)) - assert.Equal(t, 1.0, item1.SlotValueMin.GetValue()) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TimeSeriesId)) - assert.Equal(t, 10.0, item2.SlotValueMin.GetValue()) -} diff --git a/spine/model/timetable.go b/spine/model/timetable.go deleted file mode 100644 index 2a0dbfde..00000000 --- a/spine/model/timetable.go +++ /dev/null @@ -1,96 +0,0 @@ -package model - -type TimeTableIdType uint - -type TimeSlotIdType uint - -type TimeSlotCountType TimeSlotIdType - -type TimeSlotTimeModeType string - -const ( - TimeSlotTimeModeTypeAbsolute TimeSlotTimeModeType = "absolute" - TimeSlotTimeModeTypeRecurring TimeSlotTimeModeType = "recurring" - TimeSlotTimeModeTypeBoth TimeSlotTimeModeType = "both" -) - -type TimeTableDataType struct { - TimeTableId *TimeTableIdType `json:"timeTableId,omitempty" eebus:"key"` - TimeSlotId *TimeSlotIdType `json:"timeSlotId,omitempty"` - RecurrenceInformation *RecurrenceInformationType `json:"recurrenceInformation,omitempty"` - StartTime *AbsoluteOrRecurringTimeType `json:"startTime,omitempty"` - EndTime *AbsoluteOrRecurringTimeType `json:"endTime,omitempty"` -} - -type TimeTableDataElementsType struct { - TimeTableId *ElementTagType `json:"timeTableId,omitempty"` - TimeSlotId *ElementTagType `json:"timeSlotId,omitempty"` - RecurrenceInformation *RecurrenceInformationElementsType `json:"recurrenceInformation,omitempty"` - StartTime *AbsoluteOrRecurringTimeElementsType `json:"startTime,omitempty"` - EndTime *AbsoluteOrRecurringTimeElementsType `json:"endTime,omitempty"` -} - -type TimeTableListDataType struct { - TimeTableData []TimeTableDataType `json:"timeTableData,omitempty"` -} - -type TimeTableListDataSelectorsType struct { - TimeTableId *TimeTableIdType `json:"timeTableId,omitempty"` - TimeSlotId *TimeSlotIdType `json:"timeSlotId,omitempty"` -} - -type TimeTableConstraintsDataType struct { - TimeTableId *TimeTableIdType `json:"timeTableId,omitempty" eebus:"key"` - SlotCountMin *TimeSlotCountType `json:"slotCountMin,omitempty"` - SlotCountMax *TimeSlotCountType `json:"slotCountMax,omitempty"` - SlotDurationMin *DurationType `json:"slotDurationMin,omitempty"` - SlotDurationMax *DurationType `json:"slotDurationMax,omitempty"` - SlotDurationStepSize *DurationType `json:"slotDurationStepSize,omitempty"` - SlotShiftStepSize *DurationType `json:"slotShiftStepSize,omitempty"` - FirstSlotBeginsAt *TimeType `json:"firstSlotBeginsAt,omitempty"` -} - -type TimeTableConstraintsDataElementsType struct { - TimeTableId *ElementTagType `json:"timeTableId,omitempty"` - SlotCountMin *ElementTagType `json:"slotCountMin,omitempty"` - SlotCountMax *ElementTagType `json:"slotCountMax,omitempty"` - SlotDurationMin *ElementTagType `json:"slotDurationMin,omitempty"` - SlotDurationMax *ElementTagType `json:"slotDurationMax,omitempty"` - SlotDurationStepSize *ElementTagType `json:"slotDurationStepSize,omitempty"` - SlotShiftStepSize *ElementTagType `json:"slotShiftStepSize,omitempty"` - FirstSlotBeginsAt *ElementTagType `json:"firstSlotBeginsAt,omitempty"` -} - -type TimeTableConstraintsListDataType struct { - TimeTableConstraintsData []TimeTableConstraintsDataType `json:"timeTableConstraintsData,omitempty"` -} - -type TimeTableConstraintsListDataSelectorsType struct { - TimeTableId *TimeTableIdType `json:"timeTableId,omitempty"` -} - -type TimeTableDescriptionDataType struct { - TimeTableId *TimeTableIdType `json:"timeTableId,omitempty" eebus:"key"` - TimeSlotCountChangeable *bool `json:"timeSlotCountChangeable,omitempty"` - TimeSlotTimesChangeable *bool `json:"timeSlotTimesChangeable,omitempty"` - TimeSlotTimeMode *TimeSlotTimeModeType `json:"timeSlotTimeMode,omitempty"` - Label *LabelType `json:"label,omitempty"` - Description *DescriptionType `json:"description,omitempty"` -} - -type TimeTableDescriptionDataElementsType struct { - TimeTableId *ElementTagType `json:"timeTableId,omitempty"` - TimeSlotCountChangeable *ElementTagType `json:"timeSlotCountChangeable,omitempty"` - TimeSlotTimesChangeable *ElementTagType `json:"timeSlotTimesChangeable,omitempty"` - TimeSlotTimeMode *ElementTagType `json:"timeSlotTimeMode,omitempty"` - Label *ElementTagType `json:"label,omitempty"` - Description *ElementTagType `json:"description,omitempty"` -} - -type TimeTableDescriptionListDataType struct { - TimeTableDescriptionData []TimeTableDescriptionDataType `json:"timeTableDescriptionData,omitempty"` -} - -type TimeTableDescriptionListDataSelectorsType struct { - TimeTableId *TimeTableIdType `json:"timeTableId,omitempty"` -} diff --git a/spine/model/timetable_additions.go b/spine/model/timetable_additions.go deleted file mode 100644 index 2b336b82..00000000 --- a/spine/model/timetable_additions.go +++ /dev/null @@ -1,40 +0,0 @@ -package model - -// TimeTableListDataType - -var _ Updater = (*TimeTableListDataType)(nil) - -func (r *TimeTableListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TimeTableDataType - if newList != nil { - newData = newList.(*TimeTableListDataType).TimeTableData - } - - r.TimeTableData = UpdateList(r.TimeTableData, newData, filterPartial, filterDelete) -} - -// TimeTableConstraintsListDataType - -var _ Updater = (*TimeTableConstraintsListDataType)(nil) - -func (r *TimeTableConstraintsListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TimeTableConstraintsDataType - if newList != nil { - newData = newList.(*TimeTableConstraintsListDataType).TimeTableConstraintsData - } - - r.TimeTableConstraintsData = UpdateList(r.TimeTableConstraintsData, newData, filterPartial, filterDelete) -} - -// TimeTableDescriptionListDataType - -var _ Updater = (*TimeTableDescriptionListDataType)(nil) - -func (r *TimeTableDescriptionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []TimeTableDescriptionDataType - if newList != nil { - newData = newList.(*TimeTableDescriptionListDataType).TimeTableDescriptionData - } - - r.TimeTableDescriptionData = UpdateList(r.TimeTableDescriptionData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/timetable_additions_test.go b/spine/model/timetable_additions_test.go deleted file mode 100644 index 9f6afc42..00000000 --- a/spine/model/timetable_additions_test.go +++ /dev/null @@ -1,129 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -func TestTimeTableListDataType_Update(t *testing.T) { - sut := model.TimeTableListDataType{ - TimeTableData: []model.TimeTableDataType{ - { - TimeTableId: util.Ptr(model.TimeTableIdType(0)), - RecurrenceInformation: &model.RecurrenceInformationType{ - ExecutionCount: util.Ptr(uint(1)), - }, - }, - { - TimeTableId: util.Ptr(model.TimeTableIdType(1)), - RecurrenceInformation: &model.RecurrenceInformationType{ - ExecutionCount: util.Ptr(uint(1)), - }, - }, - }, - } - - newData := model.TimeTableListDataType{ - TimeTableData: []model.TimeTableDataType{ - { - TimeTableId: util.Ptr(model.TimeTableIdType(1)), - RecurrenceInformation: &model.RecurrenceInformationType{ - ExecutionCount: util.Ptr(uint(10)), - }, - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TimeTableData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TimeTableId)) - assert.Equal(t, 1, int(*item1.RecurrenceInformation.ExecutionCount)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TimeTableId)) - assert.Equal(t, 10, int(*item2.RecurrenceInformation.ExecutionCount)) -} - -func TestTimeTableConstraintsListDataType_Update(t *testing.T) { - sut := model.TimeTableConstraintsListDataType{ - TimeTableConstraintsData: []model.TimeTableConstraintsDataType{ - { - TimeTableId: util.Ptr(model.TimeTableIdType(0)), - SlotCountMin: util.Ptr(model.TimeSlotCountType(1)), - }, - { - TimeTableId: util.Ptr(model.TimeTableIdType(1)), - SlotCountMin: util.Ptr(model.TimeSlotCountType(1)), - }, - }, - } - - newData := model.TimeTableConstraintsListDataType{ - TimeTableConstraintsData: []model.TimeTableConstraintsDataType{ - { - TimeTableId: util.Ptr(model.TimeTableIdType(1)), - SlotCountMin: util.Ptr(model.TimeSlotCountType(10)), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TimeTableConstraintsData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TimeTableId)) - assert.Equal(t, 1, int(*item1.SlotCountMin)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TimeTableId)) - assert.Equal(t, 10, int(*item2.SlotCountMin)) -} - -func TestTimeTableDescriptionListDataType_Update(t *testing.T) { - sut := model.TimeTableDescriptionListDataType{ - TimeTableDescriptionData: []model.TimeTableDescriptionDataType{ - { - TimeTableId: util.Ptr(model.TimeTableIdType(0)), - Description: util.Ptr(model.DescriptionType("old")), - }, - { - TimeTableId: util.Ptr(model.TimeTableIdType(1)), - Description: util.Ptr(model.DescriptionType("old")), - }, - }, - } - - newData := model.TimeTableDescriptionListDataType{ - TimeTableDescriptionData: []model.TimeTableDescriptionDataType{ - { - TimeTableId: util.Ptr(model.TimeTableIdType(1)), - Description: util.Ptr(model.DescriptionType("new")), - }, - }, - } - - // Act - sut.UpdateList(&newData, model.NewFilterTypePartial(), nil) - - data := sut.TimeTableDescriptionData - // check the non changing items - assert.Equal(t, 2, len(data)) - item1 := data[0] - assert.Equal(t, 0, int(*item1.TimeTableId)) - assert.Equal(t, "old", string(*item1.Description)) - // check properties of updated item - item2 := data[1] - assert.Equal(t, 1, int(*item2.TimeTableId)) - assert.Equal(t, "new", string(*item2.Description)) -} diff --git a/spine/model/update.go b/spine/model/update.go deleted file mode 100644 index 6eea837a..00000000 --- a/spine/model/update.go +++ /dev/null @@ -1,297 +0,0 @@ -package model - -import ( - "reflect" - "sort" - - "github.com/enbility/eebus-go/util" -) - -type Updater interface { - UpdateList(newList any, filterPartial, filterDelete *FilterType) -} - -// Generates a new list of function items by applying the rules mentioned in the spec -// (EEBus_SPINE_TS_ProtocolSpecification.pdf; chapter "5.3.4 Restricted function exchange with cmdOptions"). -// The given data provider is used the get the current items and the items and the filters in the payload. -func UpdateList[T any](existingData []T, newData []T, filterPartial, filterDelete *FilterType) []T { - // process delete filter (with selectors and elements) - if filterDelete != nil { - if filterData, err := filterDelete.Data(); err == nil { - existingData = deleteFilteredData(existingData, filterData) - } - } - - // process update filter (with selectors and elements) - if filterPartial != nil { - if filterData, err := filterPartial.Data(); err == nil { - return copyToSelectedData(existingData, filterData, &newData[0]) - } - } - - // check if items have no identifiers - // Currently all fields marked as key are required - // TODO: check how to handle if only one identifier is provided - if len(newData) > 0 && !HasIdentifiers(newData[0]) { - // no identifiers specified --> copy data to all existing items - // (see EEBus_SPINE_TS_ProtocolSpecification.pdf, Table 7: Considered cmdOptions combinations for classifier "notify") - return copyToAllData(existingData, &newData[0]) - } - - result := Merge(existingData, newData) - - result = SortData(result) - - return result -} - -// return a list of field names that have the eebus tag "key" -func keyFieldNames(item any) []string { - var result []string - - v := reflect.ValueOf(item) - t := reflect.TypeOf(item) - - for i := 0; i < v.NumField(); i++ { - f := v.Field(i) - if f.Kind() != reflect.Ptr { - continue - } - - sf := v.Type().Field(i) - eebusTags := EEBusTags(sf) - _, exists := eebusTags[EEBusTagKey] - if !exists { - continue - } - - fieldName := t.Field(i).Name - result = append(result, fieldName) - } - - return result -} - -func HasIdentifiers(data any) bool { - keys := keyFieldNames(data) - - v := reflect.ValueOf(data) - - for _, fieldName := range keys { - f := v.FieldByName(fieldName) - - if f.IsNil() || !f.IsValid() { - return false - } - } - - return true -} - -// sort slices by fields that have eebus tag "key" -func SortData[T any](data []T) []T { - if len(data) == 0 { - return data - } - - keys := keyFieldNames(data[0]) - - if len(keys) == 0 { - return data - } - - sort.Slice(data, func(i, j int) bool { - item1 := data[i] - item2 := data[j] - - item1V := reflect.ValueOf(item1) - item2V := reflect.ValueOf(item2) - - // if the fields don't match, don't do anything - if item1V.NumField() != item2V.NumField() { - return false - } - - for _, fieldName := range keys { - f1 := item1V.FieldByName(fieldName) - f2 := item2V.FieldByName(fieldName) - if f1.Type().Kind() != reflect.Ptr || f2.Type().Kind() != reflect.Ptr { - return false - } - - if f1.IsNil() || f2.IsNil() || !f1.IsValid() || !f2.IsValid() { - return false - } - - if f1.Elem().Kind() != reflect.Uint || f2.Elem().Kind() != reflect.Uint { - return false - } - - value1 := f1.Elem().Uint() - value2 := f2.Elem().Uint() - - if value1 != value2 { - return value1 < value2 - } - } - - return false - }) - - return data -} - -func copyToSelectedData[T any](existingData []T, filterData *FilterData, newData *T) []T { - if filterData.Selector == nil { - return existingData - } - - for i := range existingData { - if filterData.SelectorMatch(util.Ptr(existingData[i])) { - CopyNonNilDataFromItemToItem(newData, &existingData[i]) - break - } - } - return existingData -} - -func copyToAllData[T any](existingData []T, newData *T) []T { - for i := range existingData { - CopyNonNilDataFromItemToItem(newData, &existingData[i]) - } - return existingData -} - -func deleteFilteredData[T any](existingData []T, filterData *FilterData) []T { - if filterData.Elements == nil && filterData.Selector == nil { - return existingData - } - - result := []T{} - for i := range existingData { - if filterData.Selector != nil && filterData.Elements != nil { - // selector and elements filter - - // remove the fields defined in element if the item matches - if filterData.SelectorMatch(util.Ptr(existingData[i])) { - RemoveElementFromItem(&existingData[i], filterData.Elements) - result = append(result, existingData[i]) - } else { - result = append(result, existingData[i]) - } - } else if filterData.Selector != nil { - // only selector filter - - // remove the whole item if the item matches - if !filterData.SelectorMatch(util.Ptr(existingData[i])) { - result = append(result, existingData[i]) - } - } else { - // only elements filter - - // remove the fields defined in element - RemoveElementFromItem(&existingData[i], filterData.Elements) - result = append(result, existingData[i]) - } - } - return result -} - -func isFieldValueNil(field interface{}) bool { - if field == nil { - return true - } - - switch reflect.TypeOf(field).Kind() { - case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice: - return reflect.ValueOf(field).IsNil() - } - return false -} - -func nonNilElementNames(element any) []string { - var result []string - - v := reflect.ValueOf(element).Elem() - t := reflect.TypeOf(element).Elem() - for i := 0; i < v.NumField(); i++ { - isNil := isFieldValueNil(v.Field(i).Interface()) - if !isNil { - name := t.Field(i).Name - result = append(result, name) - } - } - - return result -} - -func isStringValueInSlice(value string, list []string) bool { - for _, item := range list { - if item == value { - return true - } - } - return false -} - -func RemoveElementFromItem[T any, E any](item *T, element E) { - fieldNamesToBeRemoved := nonNilElementNames(element) - - eV := reflect.ValueOf(element).Elem() - eT := reflect.TypeOf(element).Elem() - iV := reflect.ValueOf(item).Elem() - - // if the fields don't match, don't do anything - if eV.NumField() != iV.NumField() { - return - } - - for i := 0; i < eV.NumField(); i++ { - fieldName := eT.Field(i).Name - if isStringValueInSlice(fieldName, fieldNamesToBeRemoved) { - f := iV.FieldByName(fieldName) - if !f.IsValid() { - continue - } - if !f.CanSet() { - continue - } - - f.Set(reflect.Zero(f.Type())) - } - } -} - -func CopyNonNilDataFromItemToItem[T any](source *T, destination *T) { - if source == nil || destination == nil { - return - } - - sV := reflect.ValueOf(source).Elem() - sT := reflect.TypeOf(source).Elem() - dV := reflect.ValueOf(destination).Elem() - - // if the fields don't match, don't do anything - if sV.NumField() != dV.NumField() { - return - } - - for i := 0; i < sV.NumField(); i++ { - value := sV.Field(i) - if value.IsNil() { - continue - } - - fieldName := sT.Field(i).Name - f := dV.FieldByName(fieldName) - - if !f.IsValid() { - continue - } - if !f.CanSet() { - continue - } - - f.Set(value) - } -} diff --git a/spine/model/update_test.go b/spine/model/update_test.go deleted file mode 100644 index 2ef5a267..00000000 --- a/spine/model/update_test.go +++ /dev/null @@ -1,121 +0,0 @@ -package model_test - -import ( - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -type TestUpdateData struct { - Id *uint `eebus:"key"` - DataItem *int -} - -type TestUpdater struct { - // updateSelectorHashKey *string - // deleteSelectorHashKey *string -} - -func TestUpdateList_NewItem(t *testing.T) { - existingData := []TestUpdateData{{Id: util.Ptr(uint(1)), DataItem: util.Ptr(int(1))}} - newData := []TestUpdateData{{Id: util.Ptr(uint(2)), DataItem: util.Ptr(int(2))}} - - expectedResult := []TestUpdateData{{Id: util.Ptr(uint(1)), DataItem: util.Ptr(int(1))}, {Id: util.Ptr(uint(2)), DataItem: util.Ptr(int(2))}} - - // Act - result := model.UpdateList(existingData, newData, nil, nil) - - assert.Equal(t, expectedResult, result) -} - -func TestUpdateList_ChangedItem(t *testing.T) { - existingData := []TestUpdateData{{Id: util.Ptr(uint(1)), DataItem: util.Ptr(int(1))}} - newData := []TestUpdateData{{Id: util.Ptr(uint(1)), DataItem: util.Ptr(int(2))}} - - expectedResult := []TestUpdateData{{Id: util.Ptr(uint(1)), DataItem: util.Ptr(int(2))}} - - // Act - result := model.UpdateList(existingData, newData, nil, nil) - - assert.Equal(t, expectedResult, result) -} - -func TestUpdateList_NewAndChangedItem(t *testing.T) { - existingData := []TestUpdateData{{Id: util.Ptr(uint(1)), DataItem: util.Ptr(int(1))}} - newData := []TestUpdateData{{Id: util.Ptr(uint(1)), DataItem: util.Ptr(int(2))}, {Id: util.Ptr(uint(3)), DataItem: util.Ptr(int(3))}} - - expectedResult := []TestUpdateData{{Id: util.Ptr(uint(1)), DataItem: util.Ptr(int(2))}, {Id: util.Ptr(uint(3)), DataItem: util.Ptr(int(3))}} - - // Act - result := model.UpdateList(existingData, newData, nil, nil) - - assert.Equal(t, expectedResult, result) -} - -func TestUpdateList_ItemWithNoIdentifier(t *testing.T) { - existingData := []TestUpdateData{{Id: util.Ptr(uint(1)), DataItem: util.Ptr(int(1))}, {Id: util.Ptr(uint(2)), DataItem: util.Ptr(int(2))}} - newData := []TestUpdateData{{DataItem: util.Ptr(int(3))}} - - expectedResult := []TestUpdateData{{Id: util.Ptr(uint(1)), DataItem: util.Ptr(int(3))}, {Id: util.Ptr(uint(2)), DataItem: util.Ptr(int(3))}} - - // Act - result := model.UpdateList(existingData, newData, nil, nil) - - assert.Equal(t, expectedResult, result) -} - -func TestRemoveFieldFromType(t *testing.T) { - items := &model.LoadControlLimitListDataType{ - LoadControlLimitData: []model.LoadControlLimitDataType{ - { - LimitId: util.Ptr(model.LoadControlLimitIdType(1)), - Value: model.NewScaledNumberType(16.0), - }, - }, - } - - elements := &model.LoadControlLimitDataElementsType{ - Value: &model.ScaledNumberElementsType{}, - } - - model.RemoveElementFromItem(&items.LoadControlLimitData[0], elements) - - var nilValue *model.ScaledNumberType - - assert.Equal(t, nilValue, items.LoadControlLimitData[0].Value) -} - -// TODO: Fix, as these tests won't work right now as TestUpdater doesn't use FilterProvider and its data structure -/* -func TestUpdateList_UpdateSelector(t *testing.T) { - existingData := []TestUpdateData{{Id: util.Ptr(1), DataItem: 1}, {Id: util.Ptr(2), DataItem: 2}} - newData := []TestUpdateData{{DataItem: 3}} - - dataProvider := &TestUpdater{ - updateSelectorHashKey: util.Ptr("1"), - } - expectedResult := []TestUpdateData{{Id: util.Ptr(1), DataItem: 3}, {Id: util.Ptr(2), DataItem: 2}} - - // Act - result := model.UpdateList[TestUpdateData](existingData, newData, dataProvider) - - assert.Equal(t, expectedResult, result) -} - -func TestUpdateList_DeleteSelector(t *testing.T) { - existingData := []TestUpdateData{{Id: util.Ptr(1), DataItem: 1}, {Id: util.Ptr(2), DataItem: 2}} - newData := []TestUpdateData{{Id: util.Ptr(0), DataItem: 0}} - - dataProvider := &TestUpdater{ - deleteSelectorHashKey: util.Ptr("1"), - } - expectedResult := []TestUpdateData{{Id: util.Ptr(2), DataItem: 2}} - - // Act - result := model.UpdateList[TestUpdateData](existingData, newData, dataProvider) - - assert.Equal(t, expectedResult, result) -} -*/ diff --git a/spine/model/usecaseinformation.go b/spine/model/usecaseinformation.go deleted file mode 100644 index 8e531fb2..00000000 --- a/spine/model/usecaseinformation.go +++ /dev/null @@ -1,107 +0,0 @@ -package model - -type UseCaseActorType string - -const ( - UseCaseActorTypeBatterySystem UseCaseActorType = "BatterySystem" - UseCaseActorTypeCEM UseCaseActorType = "CEM" - UseCaseActorTypeConfigurationAppliance UseCaseActorType = "ConfigurationAppliance" - UseCaseActorTypeCompressor UseCaseActorType = "Compressor" - UseCaseActorTypeControllableSystem UseCaseActorType = "ControllableSystem" - UseCaseActorTypeDHWCircuit UseCaseActorType = "DHWCircuit" - UseCaseActorTypeEnergyGuard UseCaseActorType = "EnergyGuard" - UseCaseActorTypeEVSE UseCaseActorType = "EVSE" - UseCaseActorTypeEV UseCaseActorType = "EV" - UseCaseActorTypeGridConnectionPoint UseCaseActorType = "GridConnectionPoint" - UseCaseActorTypeHeatPump UseCaseActorType = "HeatPump" - UseCaseActorTypeHeatingCircuit UseCaseActorType = "HeatingCircuit" - UseCaseActorTypeHeatingZone UseCaseActorType = "HeatingZone" - UseCaseActorTypeHVACRoom UseCaseActorType = "HVACRoom" - UseCaseActorTypeMonitoredUnit UseCaseActorType = "MonitoredUnit" - UseCaseActorTypeMonitoringAppliance UseCaseActorType = "MonitoringAppliance" - UseCaseActorTypePVSystem UseCaseActorType = "PVSystem" - UseCaseActorTypeVisualizationAppliance UseCaseActorType = "VisualizationAppliance" -) - -type UseCaseNameType string - -const ( - UseCaseNameTypeConfigurationOfDhwSystemFunction UseCaseNameType = "configurationOfDhwSystemFunction" - UseCaseNameTypeConfigurationOfDhwTemperature UseCaseNameType = "configurationOfDhwTemperature" - UseCaseNameTypeConfigurationOfRoomCoolingSystemFunction UseCaseNameType = "configurationOfRoomCoolingSystemFunction" - UseCaseNameTypeConfigurationOfRoomCoolingTemperature UseCaseNameType = "configurationOfRoomCoolingTemperature" - UseCaseNameTypeConfigurationOfRoomHeatingSystemFunction UseCaseNameType = "configurationOfRoomHeatingSystemFunction" - UseCaseNameTypeConfigurationOfRoomHeatingTemperature UseCaseNameType = "configurationOfRoomHeatingTemperature" - UseCaseNameTypeControlOfBattery UseCaseNameType = "controlOfBattery" - UseCaseNameTypeCoordinatedEVCharging UseCaseNameType = "coordinatedEvCharging" - UseCaseNameTypeEVChargingSummary UseCaseNameType = "evChargingSummary" - UseCaseNameTypeEVCommissioningAndConfiguration UseCaseNameType = "evCommissioningAndConfiguration" - UseCaseNameTypeEVSECommissioningAndConfiguration UseCaseNameType = "evseCommissioningAndConfiguration" - UseCaseNameTypeEVStateOfCharge UseCaseNameType = "evStateOfCharge" - UseCaseNameTypeLimitationOfPowerConsumption UseCaseNameType = "limitationOfPowerConsumption" - UseCaseNameTypeLimitationOfPowerProduction UseCaseNameType = "limitationOfPowerProduction" - UseCaseNameTypeIncentiveTableBasedPowerConsumptionManagement UseCaseNameType = "incentiveTableBasedPowerConsumptionManagement" - UseCaseNameTypeMeasurementOfElectricityDuringEVCharging UseCaseNameType = "measurementOfElectricityDuringEvCharging" - UseCaseNameTypeMonitoringAndControlOfSmartGridReadyConditions UseCaseNameType = "monitoringAndControlOfSmartGridReadyConditions" - UseCaseNameTypeMonitoringOfBattery UseCaseNameType = "monitoringOfBattery" - UseCaseNameTypeMonitoringOfDhwSystemFunction UseCaseNameType = "monitoringOfDhwSystemFunction" - UseCaseNameTypeMonitoringOfDhwTemperature UseCaseNameType = "monitoringOfDhwTemperature" - UseCaseNameTypeMonitoringOfGridConnectionPoint UseCaseNameType = "monitoringOfGridConnectionPoint" - UseCaseNameTypeMonitoringOfInverter UseCaseNameType = "monitoringOfInverter" - UseCaseNameTypeMonitoringOfOutdoorTemperature UseCaseNameType = "monitoringOfOutdoorTemperature" - UseCaseNameTypeMonitoringOfPowerConsumption UseCaseNameType = "monitoringOfPowerConsumption" - UseCaseNameTypeMonitoringOfPvString UseCaseNameType = "monitoringOfPvString" - UseCaseNameTypeMonitoringOfRoomCoolingSystemFunction UseCaseNameType = "monitoringOfRoomCoolingSystemFunction" - UseCaseNameTypeMonitoringOfRoomHeatingSystemFunction UseCaseNameType = "monitoringOfRoomHeatingSystemFunction" - UseCaseNameTypeMonitoringOfRoomTemperature UseCaseNameType = "monitoringOfRoomTemperature" - UseCaseNameTypeOptimizationOfSelfConsumptionByHeatPumpCompressorFlexibility UseCaseNameType = "optimizationOfSelfConsumptionByHeatPumpCompressorFlexibility" - UseCaseNameTypeOptimizationOfSelfConsumptionDuringEVCharging UseCaseNameType = "optimizationOfSelfConsumptionDuringEvCharging" - UseCaseNameTypeOverloadProtectionByEVChargingCurrentCurtailment UseCaseNameType = "overloadProtectionByEvChargingCurrentCurtailment" - UseCaseNameTypeVisualizationOfAggregatedBatteryData UseCaseNameType = "visualizationOfAggregatedBatteryData" - UseCaseNameTypeVisualizationOfAggregatedPhotovoltaicData UseCaseNameType = "visualizationOfAggregatedPhotovoltaicData" - UseCaseNameTypeVisualizationOfHeatingAreaName UseCaseNameType = "visualizationOfHeatingAreaName" -) - -type UseCaseScenarioSupportType uint - -type UseCaseSupportType struct { - UseCaseName *UseCaseNameType `json:"useCaseName,omitempty"` - UseCaseVersion *SpecificationVersionType `json:"useCaseVersion,omitempty"` - UseCaseAvailable *bool `json:"useCaseAvailable,omitempty"` - ScenarioSupport []UseCaseScenarioSupportType `json:"scenarioSupport,omitempty"` -} - -type UseCaseSupportElementsType struct { - UseCaseName *ElementTagType `json:"useCaseName,omitempty"` - UseCaseVersion *ElementTagType `json:"useCaseVersion,omitempty"` - UseCaseAvailable *ElementTagType `json:"useCaseAvailable,omitempty"` - ScenarioSupport *ElementTagType `json:"scenarioSupport,omitempty"` -} - -type UseCaseSupportSelectorsType struct { - UseCaseName *UseCaseNameType `json:"useCaseName,omitempty"` - UseCaseVersion *SpecificationVersionType `json:"useCaseVersion,omitempty"` - ScenarioSupport *UseCaseScenarioSupportType `json:"scenarioSupport,omitempty"` -} - -type UseCaseInformationDataType struct { - Address *FeatureAddressType `json:"address,omitempty"` - Actor *UseCaseActorType `json:"actor,omitempty"` - UseCaseSupport []UseCaseSupportType `json:"useCaseSupport,omitempty"` -} - -type UseCaseInformationDataElementsType struct { - Address *ElementTagType `json:"address,omitempty"` - Actor *ElementTagType `json:"actor,omitempty"` - UseCaseSupport *ElementTagType `json:"useCaseSupport,omitempty"` -} - -type UseCaseInformationListDataType struct { - UseCaseInformationData []UseCaseInformationDataType `json:"useCaseInformationData,omitempty"` -} - -type UseCaseInformationListDataSelectorsType struct { - Address *FeatureAddressType `json:"address,omitempty"` - Actor *UseCaseActorType `json:"actor,omitempty"` - UseCaseSupport *UseCaseSupportSelectorsType `json:"useCaseSupport,omitempty"` -} diff --git a/spine/model/usecaseinformation_additions.go b/spine/model/usecaseinformation_additions.go deleted file mode 100644 index 45e70f65..00000000 --- a/spine/model/usecaseinformation_additions.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -// UseCaseInformationListDataType - -var _ Updater = (*UseCaseInformationListDataType)(nil) - -func (r *UseCaseInformationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []UseCaseInformationDataType - if newList != nil { - newData = newList.(*UseCaseInformationListDataType).UseCaseInformationData - } - - r.UseCaseInformationData = UpdateList(r.UseCaseInformationData, newData, filterPartial, filterDelete) -} diff --git a/spine/model/version.go b/spine/model/version.go deleted file mode 100644 index f5920776..00000000 --- a/spine/model/version.go +++ /dev/null @@ -1,11 +0,0 @@ -package model - -type SpecificationVersionDataType SpecificationVersionType - -type SpecificationVersionDataElementsType struct{} - -type SpecificationVersionListDataType struct { - SpecificationVersionData []SpecificationVersionDataType `json:"specificationVersionData,omitempty"` -} - -type SpecificationVersionListDataSelectorsType struct{} diff --git a/spine/model/version_additions.go b/spine/model/version_additions.go deleted file mode 100644 index 9c96c823..00000000 --- a/spine/model/version_additions.go +++ /dev/null @@ -1,14 +0,0 @@ -package model - -// SpecificationVersionListDataType - -var _ Updater = (*SpecificationVersionListDataType)(nil) - -func (r *SpecificationVersionListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { - var newData []SpecificationVersionDataType - if newList != nil { - newData = newList.(*SpecificationVersionListDataType).SpecificationVersionData - } - - r.SpecificationVersionData = UpdateList(r.SpecificationVersionData, newData, filterPartial, filterDelete) -} diff --git a/spine/nodemanagement.go b/spine/nodemanagement.go deleted file mode 100644 index f6f61e60..00000000 --- a/spine/nodemanagement.go +++ /dev/null @@ -1,111 +0,0 @@ -package spine - -import ( - "fmt" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -const NodeManagementFeatureId uint = 0 - -func NodeManagementAddress(deviceAdress *model.AddressDeviceType) *model.FeatureAddressType { - return &model.FeatureAddressType{ - Entity: []model.AddressEntityType{0}, - Feature: util.Ptr(model.AddressFeatureType(NodeManagementFeatureId)), - Device: deviceAdress, - } -} - -type NodeManagementImpl struct { - *FeatureLocalImpl - entity *EntityLocalImpl -} - -func NewNodeManagementImpl(id uint, entity *EntityLocalImpl) *NodeManagementImpl { - f := &NodeManagementImpl{ - FeatureLocalImpl: NewFeatureLocalImpl( - id, entity, - model.FeatureTypeTypeNodeManagement, - model.RoleTypeSpecial), - entity: entity, - } - - f.AddFunctionType(model.FunctionTypeNodeManagementDetailedDiscoveryData, true, false) - f.AddFunctionType(model.FunctionTypeNodeManagementUseCaseData, true, false) - f.AddFunctionType(model.FunctionTypeNodeManagementSubscriptionData, true, false) - f.AddFunctionType(model.FunctionTypeNodeManagementSubscriptionRequestCall, false, false) - f.AddFunctionType(model.FunctionTypeNodeManagementSubscriptionDeleteCall, false, false) - f.AddFunctionType(model.FunctionTypeNodeManagementBindingData, true, false) - f.AddFunctionType(model.FunctionTypeNodeManagementBindingRequestCall, false, false) - f.AddFunctionType(model.FunctionTypeNodeManagementBindingDeleteCall, false, false) - if f.Device().FeatureSet() != nil && *f.Device().FeatureSet() != model.NetworkManagementFeatureSetTypeSimple { - f.AddFunctionType(model.FunctionTypeNodeManagementDestinationListData, true, false) - } - - return f -} - -func (r *NodeManagementImpl) Device() *DeviceLocalImpl { - return r.entity.Device() -} - -func (r *NodeManagementImpl) HandleMessage(message *Message) *ErrorType { - switch { - case message.Cmd.ResultData != nil: - if err := r.processResult(message); err != nil { - _ = r.pendingRequests.Remove(message.DeviceRemote.ski, *message.RequestHeader.MsgCounterReference) - return err - } - - case message.Cmd.NodeManagementDetailedDiscoveryData != nil: - if err := r.handleMsgDetailedDiscoveryData(message, message.Cmd.NodeManagementDetailedDiscoveryData); err != nil { - return NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) - } - - case message.Cmd.NodeManagementSubscriptionRequestCall != nil: - if err := r.handleMsgSubscriptionRequestCall(message, message.Cmd.NodeManagementSubscriptionRequestCall); err != nil { - return NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) - } - - case message.Cmd.NodeManagementSubscriptionDeleteCall != nil: - if err := r.handleMsgSubscriptionDeleteCall(message, message.Cmd.NodeManagementSubscriptionDeleteCall); err != nil { - return NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) - } - - case message.Cmd.NodeManagementSubscriptionData != nil: - if err := r.handleMsgSubscriptionData(message); err != nil { - return NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) - } - - case message.Cmd.NodeManagementBindingRequestCall != nil: - if err := r.handleMsgBindingRequestCall(message, message.Cmd.NodeManagementBindingRequestCall); err != nil { - return NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) - } - - case message.Cmd.NodeManagementBindingDeleteCall != nil: - if err := r.handleMsgBindingDeleteCall(message, message.Cmd.NodeManagementBindingDeleteCall); err != nil { - return NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) - } - - case message.Cmd.NodeManagementBindingData != nil: - if err := r.handleMsgBindingData(message); err != nil { - return NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) - } - - case message.Cmd.NodeManagementUseCaseData != nil: - if err := r.handleMsgUseCaseData(message, message.Cmd.NodeManagementUseCaseData); err != nil { - return NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) - } - - case message.Cmd.NodeManagementDestinationListData != nil: - if err := r.handleMsgDestinationListData(message, message.Cmd.NodeManagementDestinationListData); err != nil { - return NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) - } - - default: - return NewErrorType(model.ErrorNumberTypeCommandNotSupported, fmt.Sprintf("nodemanagement.Handle: Cmd data not implemented: %s", message.Cmd.DataName())) - } - - return nil -} diff --git a/spine/nodemanagement_binding.go b/spine/nodemanagement_binding.go deleted file mode 100644 index c8633a03..00000000 --- a/spine/nodemanagement_binding.go +++ /dev/null @@ -1,71 +0,0 @@ -package spine - -import ( - "fmt" - - "github.com/ahmetb/go-linq/v3" - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -func NewNodeManagementBindingRequestCallType(clientAddress *model.FeatureAddressType, serverAddress *model.FeatureAddressType, featureType model.FeatureTypeType) *model.NodeManagementBindingRequestCallType { - return &model.NodeManagementBindingRequestCallType{ - BindingRequest: &model.BindingManagementRequestCallType{ - ClientAddress: clientAddress, - ServerAddress: serverAddress, - ServerFeatureType: &featureType, - }, - } -} - -// route bindings request calls to the appropriate feature implementation and add the bindings to the current list -func (r *NodeManagementImpl) processReadBindingData(message *Message) error { - - var remoteDeviceBindings []model.BindingManagementEntryDataType - remoteDeviceBindingEntries := r.Device().BindingManager().Bindings(message.FeatureRemote.Device()) - linq.From(remoteDeviceBindingEntries).SelectT(func(s *BindingEntry) model.BindingManagementEntryDataType { - return model.BindingManagementEntryDataType{ - BindingId: util.Ptr(model.BindingIdType(s.id)), - ServerAddress: s.serverFeature.Address(), - ClientAddress: s.clientFeature.Address(), - } - }).ToSlice(&remoteDeviceBindings) - - cmd := model.CmdType{ - NodeManagementBindingData: &model.NodeManagementBindingDataType{ - BindingEntry: remoteDeviceBindings, - }, - } - - return message.FeatureRemote.Sender().Reply(message.RequestHeader, r.Address(), cmd) -} - -func (r *NodeManagementImpl) handleMsgBindingData(message *Message) error { - switch message.CmdClassifier { - case model.CmdClassifierTypeCall: - return r.processReadBindingData(message) - - default: - return fmt.Errorf("nodemanagement.handleBindingDeleteCall: NodeManagementBindingRequestCall CmdClassifierType not implemented: %s", message.CmdClassifier) - } -} - -func (r *NodeManagementImpl) handleMsgBindingRequestCall(message *Message, data *model.NodeManagementBindingRequestCallType) error { - switch message.CmdClassifier { - case model.CmdClassifierTypeCall: - return r.Device().BindingManager().AddBinding(r.Device(), message.FeatureRemote.Device(), *data.BindingRequest) - - default: - return fmt.Errorf("nodemanagement.handleBindingRequestCall: NodeManagementBindingRequestCall CmdClassifierType not implemented: %s", message.CmdClassifier) - } -} - -func (r *NodeManagementImpl) handleMsgBindingDeleteCall(message *Message, data *model.NodeManagementBindingDeleteCallType) error { - switch message.CmdClassifier { - case model.CmdClassifierTypeCall: - return r.Device().BindingManager().RemoveBinding(*data.BindingDelete, message.FeatureRemote.Device()) - - default: - return fmt.Errorf("nodemanagement.handleBindingDeleteCall: NodeManagementBindingRequestCall CmdClassifierType not implemented: %s", message.CmdClassifier) - } -} diff --git a/spine/nodemanagement_defaileddiscovery.go b/spine/nodemanagement_defaileddiscovery.go deleted file mode 100644 index 98ad1567..00000000 --- a/spine/nodemanagement_defaileddiscovery.go +++ /dev/null @@ -1,257 +0,0 @@ -package spine - -import ( - "errors" - "fmt" - - "github.com/enbility/eebus-go/spine/model" -) - -// request detailed discovery data from a remote device -func (r *NodeManagementImpl) RequestDetailedDiscovery(remoteDeviceSki string, remoteDeviceAddress *model.AddressDeviceType, sender Sender) (*model.MsgCounterType, *ErrorType) { - rfAdress := featureAddressType(NodeManagementFeatureId, EntityAddressType(remoteDeviceAddress, DeviceInformationAddressEntity)) - cmd := model.CmdType{ - NodeManagementDetailedDiscoveryData: &model.NodeManagementDetailedDiscoveryDataType{}, - } - return r.RequestDataBySenderAddress(cmd, sender, remoteDeviceSki, rfAdress, defaultMaxResponseDelay) -} - -// handle incoming detailed discovery read call -func (r *NodeManagementImpl) processReadDetailedDiscoveryData(deviceRemote *DeviceRemoteImpl, requestHeader *model.HeaderType) error { - if deviceRemote == nil { - return errors.New("nodemanagement.readDetailedDiscoveryData: invalid deviceRemote") - } - - var entityInformation []model.NodeManagementDetailedDiscoveryEntityInformationType - var featureInformation []model.NodeManagementDetailedDiscoveryFeatureInformationType - - for _, e := range r.Device().Entities() { - entityInformation = append(entityInformation, *e.Information()) - - for _, f := range e.Features() { - featureInformation = append(featureInformation, *f.Information()) - } - } - - cmd := model.CmdType{ - NodeManagementDetailedDiscoveryData: &model.NodeManagementDetailedDiscoveryDataType{ - SpecificationVersionList: &model.NodeManagementSpecificationVersionListType{ - SpecificationVersion: []model.SpecificationVersionDataType{model.SpecificationVersionDataType(SpecificationVersion)}, - }, - DeviceInformation: r.Device().Information(), - EntityInformation: entityInformation, - FeatureInformation: featureInformation, - }, - } - - return deviceRemote.Sender().Reply(requestHeader, r.Address(), cmd) -} - -// handle incoming detailed discovery reply data -func (r *NodeManagementImpl) processReplyDetailedDiscoveryData(message *Message, data *model.NodeManagementDetailedDiscoveryDataType) error { - remoteDevice := message.DeviceRemote - - deviceDescription := data.DeviceInformation.Description - if deviceDescription == nil { - return errors.New("nodemanagement.replyDetailedDiscoveryData: invalid DeviceInformation.Description") - } - - remoteDevice.UpdateDevice(deviceDescription) - entities, err := remoteDevice.AddEntityAndFeatures(true, data) - if err != nil { - return err - } - - // publish event for remote device added - payload := EventPayload{ - Ski: remoteDevice.ski, - EventType: EventTypeDeviceChange, - ChangeType: ElementChangeAdd, - Device: remoteDevice, - Feature: message.FeatureRemote, - Data: data, - } - Events.Publish(payload) - - // publish event for each added remote entity - for _, entity := range entities { - payload := EventPayload{ - Ski: remoteDevice.ski, - EventType: EventTypeEntityChange, - ChangeType: ElementChangeAdd, - Device: remoteDevice, - Entity: entity, - Data: data, - } - Events.Publish(payload) - } - - return nil -} - -// handle incoming detailed discovery notify data -func (r *NodeManagementImpl) processNotifyDetailedDiscoveryData(message *Message, data *model.NodeManagementDetailedDiscoveryDataType) error { - // is this a partial request? - if message.FilterPartial == nil { - return errors.New("the received NodeManagementDetailedDiscovery.notify dataset should be partial") - } - - if data.EntityInformation == nil || len(data.EntityInformation) == 0 || data.EntityInformation[0].Description == nil || data.EntityInformation[0].Description.LastStateChange == nil { - return errors.New("the received NodeManagementDetailedDiscovery.notify dataset is incomplete") - } - - lastStateChange := *data.EntityInformation[0].Description.LastStateChange - remoteDevice := message.FeatureRemote.Device() - - // addition example: - // {"data":[{"header":[{"protocolId":"ee1.0"}]},{"payload":{"datagram":[{"header":[{"specificationVersion":"1.1.1"},{"addressSource":[{"device":"d:_i:19667_PorscheEVSE-00016544"},{"entity":[0]},{"feature":0}]},{"addressDestination":[{"device":"EVCC_HEMS"},{"entity":[0]},{"feature":0}]},{"msgCounter":926685},{"cmdClassifier":"notify"}]},{"payload":[{"cmd":[[{"function":"nodeManagementDetailedDiscoveryData"},{"filter":[[{"cmdControl":[{"partial":[]}]}]]},{"nodeManagementDetailedDiscoveryData":[{"deviceInformation":[{"description":[{"deviceAddress":[{"device":"d:_i:19667_PorscheEVSE-00016544"}]}]}]},{"entityInformation":[[{"description":[{"entityAddress":[{"entity":[1,1]}]},{"entityType":"EV"},{"lastStateChange":"added"},{"description":"Electric Vehicle"}]}]]},{"featureInformation":[[{"description":[{"featureAddress":[{"entity":[1,1]},{"feature":1}]},{"featureType":"LoadControl"},{"role":"server"},{"supportedFunction":[[{"function":"loadControlLimitDescriptionListData"},{"possibleOperations":[{"read":[]}]}],[{"function":"loadControlLimitListData"},{"possibleOperations":[{"read":[]},{"write":[]}]}]]},{"description":"Load Control"}]}],[{"description":[{"featureAddress":[{"entity":[1,1]},{"feature":2}]},{"featureType":"ElectricalConnection"},{"role":"server"},{"supportedFunction":[[{"function":"electricalConnectionParameterDescriptionListData"},{"possibleOperations":[{"read":[]}]}],[{"function":"electricalConnectionDescriptionListData"},{"possibleOperations":[{"read":[]}]}],[{"function":"electricalConnectionPermittedValueSetListData"},{"possibleOperations":[{"read":[]}]}]]},{"description":"Electrical Connection"}]}],[{"description":[{"featureAddress":[{"entity":[1,1]},{"feature":3}]},{"featureType":"Measurement"},{"specificUsage":["Electrical"]},{"role":"server"},{"supportedFunction":[[{"function":"measurementListData"},{"possibleOperations":[{"read":[]}]}],[{"function":"measurementDescriptionListData"},{"possibleOperations":[{"read":[]}]}]]},{"description":"Measurements"}]}],[{"description":[{"featureAddress":[{"entity":[1,1]},{"feature":5}]},{"featureType":"DeviceConfiguration"},{"role":"server"},{"supportedFunction":[[{"function":"deviceConfigurationKeyValueDescriptionListData"},{"possibleOperations":[{"read":[]}]}],[{"function":"deviceConfigurationKeyValueListData"},{"possibleOperations":[{"read":[]}]}]]},{"description":"Device Configuration EV"}]}],[{"description":[{"featureAddress":[{"entity":[1,1]},{"feature":6}]},{"featureType":"DeviceClassification"},{"role":"server"},{"supportedFunction":[[{"function":"deviceClassificationManufacturerData"},{"possibleOperations":[{"read":[]}]}]]},{"description":"Device Classification for EV"}]}],[{"description":[{"featureAddress":[{"entity":[1,1]},{"feature":7}]},{"featureType":"TimeSeries"},{"role":"server"},{"supportedFunction":[[{"function":"timeSeriesConstraintsListData"},{"possibleOperations":[{"read":[]}]}],[{"function":"timeSeriesDescriptionListData"},{"possibleOperations":[{"read":[]}]}],[{"function":"timeSeriesListData"},{"possibleOperations":[{"read":[]},{"write":[]}]}]]},{"description":"Time Series"}]}],[{"description":[{"featureAddress":[{"entity":[1,1]},{"feature":8}]},{"featureType":"IncentiveTable"},{"role":"server"},{"supportedFunction":[[{"function":"incentiveTableConstraintsData"},{"possibleOperations":[{"read":[]}]}],[{"function":"incentiveTableData"},{"possibleOperations":[{"read":[]},{"write":[]}]}],[{"function":"incentiveTableDescriptionData"},{"possibleOperations":[{"read":[]},{"write":[]}]}]]},{"description":"Incentive Table"}]}],[{"description":[{"featureAddress":[{"entity":[1,1]},{"feature":9}]},{"featureType":"DeviceDiagnosis"},{"role":"server"},{"supportedFunction":[[{"function":"deviceDiagnosisStateData"},{"possibleOperations":[{"read":[]}]}]]},{"description":"Device Diagnosis EV"}]}],[{"description":[{"featureAddress":[{"entity":[1,1]},{"feature":10}]},{"featureType":"Identification"},{"role":"server"},{"supportedFunction":[[{"function":"identificationListData"},{"possibleOperations":[{"read":[]}]}]]},{"description":"Identification for EV"}]}]]}]}]]}]}]}}]} - // { - // "cmd":[[ - // {"function":"nodeManagementDetailedDiscoveryData"}, - // {"filter":[[{"cmdControl":[{"partial":[]}]}]]}, - // {"nodeManagementDetailedDiscoveryData":[ - // {"deviceInformation":[{"description":[{"deviceAddress":[{"device":"d:_i:19667_PorscheEVSE-00016544"}]}]}]}, - // {"entityInformation":[[ - // {"description":[ - // {"entityAddress":[{"entity":[1,1]}]}, - // {"entityType":"EV"}, - // {"lastStateChange":"added"}, - // {"description":"Electric Vehicle"} - // ]} - // ]]}, - // {"featureInformation":[ - // [{"description":[ - // {"featureAddress":[{"entity":[1,1]},{"feature":1}]}, - // {"featureType":"LoadControl"}, - // {"role":"server"}, - // {"supportedFunction":[ - // [{"function":"loadControlLimitDescriptionListData"},{"possibleOperations":[{"read":[]}]}], - // [{"function":"loadControlLimitListData"},{"possibleOperations":[{"read":[]},{"write":[]}]}] - // ]}, - // {"description":"Load Control"} - // ]}], - // ... - - // is this addition? - if lastStateChange == model.NetworkManagementStateChangeTypeAdded { - entities, err := remoteDevice.AddEntityAndFeatures(false, data) - if err != nil { - return err - } - - // publish event for each added remote entity - for _, entity := range entities { - payload := EventPayload{ - Ski: remoteDevice.ski, - EventType: EventTypeEntityChange, - ChangeType: ElementChangeAdd, - Device: remoteDevice, - Entity: entity, - Data: data, - } - Events.Publish(payload) - } - } - - // removal example: - // {"data":[{"header":[{"protocolId":"ee1.0"}]},{"payload":{"datagram":[{"header":[{"specificationVersion":"1.1.1"},{"addressSource":[{"device":"d:_i:19667_PorscheEVSE-00016544"},{"entity":[0]},{"feature":0}]},{"addressDestination":[{"device":"EVCC_HEMS"},{"entity":[0]},{"feature":0}]},{"msgCounter":4835},{"cmdClassifier":"notify"}]},{"payload":[{"cmd":[[{"function":"nodeManagementDetailedDiscoveryData"},{"filter":[[{"cmdControl":[{"partial":[]}]}]]},{"nodeManagementDetailedDiscoveryData":[{"deviceInformation":[{"description":[{"deviceAddress":[{"device":"d:_i:19667_PorscheEVSE-00016544"}]}]}]},{"entityInformation":[[{"description":[{"entityAddress":[{"entity":[1,1]}]},{"lastStateChange":"removed"}]}]]}]}]]}]}]}}]} - // { - // "cmd": [[ - // {"function": "nodeManagementDetailedDiscoveryData"}, - // {"filter": [[{"cmdControl": [{"partial": []}]}]]}, - // {"nodeManagementDetailedDiscoveryData": [ - // {"deviceInformation": [{"description": [{"deviceAddress": [{"device": "d:_i:19667_PorscheEVSE-00016544"}]}]}]}, - // {"entityInformation": [[ - // { - // "description": [ - // {"entityAddress": [{"entity": [1,1]}]}, - // {"lastStateChange": "removed"} - // ... - - // is this removal? - if lastStateChange == model.NetworkManagementStateChangeTypeRemoved { - for _, ei := range data.EntityInformation { - if err := remoteDevice.CheckEntityInformation(false, ei); err != nil { - return err - } - - entityAddress := ei.Description.EntityAddress.Entity - removedEntity := remoteDevice.RemoveByAddress(entityAddress) - - // only continue if the entity existed - if removedEntity == nil { - continue - } - - payload := EventPayload{ - Ski: remoteDevice.ski, - EventType: EventTypeEntityChange, - ChangeType: ElementChangeRemove, - Device: remoteDevice, - Entity: removedEntity, - Data: data, - } - Events.Publish(payload) - - // remove all subscriptions for this entity - r.Device().SubscriptionManager().RemoveSubscriptionsForEntity(removedEntity) - } - } - - return nil -} - -// func (f *NodeManagement) announceFeatureDiscovery(e spine.Entity) error { -// entity := f.Entity() -// if entity == nil { -// return errors.New("announceFeatureDiscovery: entity not found") -// } -// device := entity.Device() -// if device == nil { -// return errors.New("announceFeatureDiscovery: device not found") -// } -// entities := device.Entities() -// if entities == nil { -// return errors.New("announceFeatureDiscovery: entities not found") -// } - -// for _, le := range entities { -// for _, lf := range le.Features() { - -// // connect client to server features -// for _, rf := range e.Features() { -// lr := lf.Role() -// rr := rf.Role() -// rolesValid := (lr == model.RoleTypeSpecial && rr == model.RoleTypeSpecial) || (lr == model.RoleTypeClient && rr == model.RoleTypeServer) -// if lf.Type() == rf.Type() && rolesValid { -// if cf, ok := lf.(spine.ClientFeature); ok { -// if err := cf.ServerFound(rf); err != nil { -// return err -// } -// } -// } -// } -// } -// } - -// return nil -// } - -func (r *NodeManagementImpl) handleMsgDetailedDiscoveryData(message *Message, data *model.NodeManagementDetailedDiscoveryDataType) error { - switch message.CmdClassifier { - case model.CmdClassifierTypeRead: - return r.processReadDetailedDiscoveryData(message.DeviceRemote, message.RequestHeader) - - case model.CmdClassifierTypeReply: - if err := r.pendingRequests.Remove(message.DeviceRemote.ski, *message.RequestHeader.MsgCounterReference); err != nil { - return errors.New(err.String()) - } - return r.processReplyDetailedDiscoveryData(message, data) - - case model.CmdClassifierTypeNotify: - return r.processNotifyDetailedDiscoveryData(message, data) - - default: - return fmt.Errorf("nodemanagement.handleDetailedDiscoveryData: NodeManagementDetailedDiscoveryData CmdClassifierType not implemented: %s", message.CmdClassifier) - } -} diff --git a/spine/nodemanagement_destinationlist.go b/spine/nodemanagement_destinationlist.go deleted file mode 100644 index e5ba0e03..00000000 --- a/spine/nodemanagement_destinationlist.go +++ /dev/null @@ -1,50 +0,0 @@ -package spine - -import ( - "errors" - "fmt" - - "github.com/enbility/eebus-go/spine/model" -) - -func (r *NodeManagementImpl) RequestDestinationListData(remoteDeviceAddress *model.AddressDeviceType, sender Sender) (*model.MsgCounterType, *ErrorType) { - return nil, NewErrorTypeFromString("Not implemented") -} - -func (r *NodeManagementImpl) processReadDestinationListData(featureRemote *FeatureRemoteImpl, requestHeader *model.HeaderType) error { - data := []model.NodeManagementDestinationDataType{ - r.Device().DestinationData(), - } - // add other remote devices here - - cmd := model.CmdType{ - NodeManagementDestinationListData: &model.NodeManagementDestinationListDataType{ - NodeManagementDestinationData: data, - }, - } - - return featureRemote.Sender().Reply(requestHeader, r.Address(), cmd) -} - -func (r *NodeManagementImpl) processReplyDestinationListData(message *Message, data model.NodeManagementDestinationListDataType) error { - return errors.New("Not implemented") -} - -func (r *NodeManagementImpl) handleMsgDestinationListData(message *Message, data *model.NodeManagementDestinationListDataType) error { - switch message.CmdClassifier { - case model.CmdClassifierTypeRead: - return r.processReadDestinationListData(message.FeatureRemote, message.RequestHeader) - - case model.CmdClassifierTypeReply: - if err := r.pendingRequests.Remove(message.DeviceRemote.ski, *message.RequestHeader.MsgCounterReference); err != nil { - return errors.New(err.String()) - } - return r.processReplyDestinationListData(message, *data) - - case model.CmdClassifierTypeNotify: - return r.processReplyDestinationListData(message, *data) - - default: - return fmt.Errorf("nodemanagement.handleMsgDestinationListData: NodeManagementDestinationListDataType CmdClassifierType not implemented: %s", message.CmdClassifier) - } -} diff --git a/spine/nodemanagement_subscription.go b/spine/nodemanagement_subscription.go deleted file mode 100644 index 2f5631c7..00000000 --- a/spine/nodemanagement_subscription.go +++ /dev/null @@ -1,71 +0,0 @@ -package spine - -import ( - "fmt" - - "github.com/ahmetb/go-linq/v3" - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -func NewNodeManagementSubscriptionRequestCallType(clientAddress *model.FeatureAddressType, serverAddress *model.FeatureAddressType, featureType model.FeatureTypeType) *model.NodeManagementSubscriptionRequestCallType { - return &model.NodeManagementSubscriptionRequestCallType{ - SubscriptionRequest: &model.SubscriptionManagementRequestCallType{ - ClientAddress: clientAddress, - ServerAddress: serverAddress, - ServerFeatureType: &featureType, - }, - } -} - -// route subscription request calls to the appropriate feature implementation and add the subscription to the current list -func (r *NodeManagementImpl) processReadSubscriptionData(message *Message) error { - - var remoteDeviceSubscriptions []model.SubscriptionManagementEntryDataType - remoteDeviceSubscriptionEntries := r.Device().SubscriptionManager().Subscriptions(message.FeatureRemote.Device()) - linq.From(remoteDeviceSubscriptionEntries).SelectT(func(s *SubscriptionEntry) model.SubscriptionManagementEntryDataType { - return model.SubscriptionManagementEntryDataType{ - SubscriptionId: util.Ptr(model.SubscriptionIdType(s.id)), - ServerAddress: s.serverFeature.Address(), - ClientAddress: s.clientFeature.Address(), - } - }).ToSlice(&remoteDeviceSubscriptions) - - cmd := model.CmdType{ - NodeManagementSubscriptionData: &model.NodeManagementSubscriptionDataType{ - SubscriptionEntry: remoteDeviceSubscriptions, - }, - } - - return message.FeatureRemote.Sender().Reply(message.RequestHeader, r.Address(), cmd) -} - -func (r *NodeManagementImpl) handleMsgSubscriptionData(message *Message) error { - switch message.CmdClassifier { - case model.CmdClassifierTypeCall: - return r.processReadSubscriptionData(message) - - default: - return fmt.Errorf("nodemanagement.handleSubscriptionDeleteCall: NodeManagementSubscriptionRequestCall CmdClassifierType not implemented: %s", message.CmdClassifier) - } -} - -func (r *NodeManagementImpl) handleMsgSubscriptionRequestCall(message *Message, data *model.NodeManagementSubscriptionRequestCallType) error { - switch message.CmdClassifier { - case model.CmdClassifierTypeCall: - return r.Device().SubscriptionManager().AddSubscription(r.Device(), message.FeatureRemote.Device(), *data.SubscriptionRequest) - - default: - return fmt.Errorf("nodemanagement.handleSubscriptionRequestCall: NodeManagementSubscriptionRequestCall CmdClassifierType not implemented: %s", message.CmdClassifier) - } -} - -func (r *NodeManagementImpl) handleMsgSubscriptionDeleteCall(message *Message, data *model.NodeManagementSubscriptionDeleteCallType) error { - switch message.CmdClassifier { - case model.CmdClassifierTypeCall: - return r.Device().SubscriptionManager().RemoveSubscription(*data.SubscriptionDelete, message.FeatureRemote.Device()) - - default: - return fmt.Errorf("nodemanagement.handleSubscriptionDeleteCall: NodeManagementSubscriptionRequestCall CmdClassifierType not implemented: %s", message.CmdClassifier) - } -} diff --git a/spine/nodemanagement_test.go b/spine/nodemanagement_test.go deleted file mode 100644 index 1ecf33ba..00000000 --- a/spine/nodemanagement_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package spine_test - -import ( - "reflect" - "testing" - - "github.com/enbility/eebus-go/spine" - "github.com/enbility/eebus-go/spine/mocks" - "github.com/enbility/eebus-go/spine/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestNodemanagement_SubscriptionRequestCall(t *testing.T) { - - // const serverName = "Server" - // const clientName = "Client" - - const subscriptionEntityId uint = 1 - //const subscriptionFeatureId uint = 2 - const featureType = model.FeatureTypeTypeDeviceClassification - - senderMock := mocks.NewSender(t) - - //localDevice := NewDeviceLocalImpl(model.AddressDeviceType("server")) - - serverFeature := CreateLocalDeviceAndFeature(subscriptionEntityId, featureType, model.RoleTypeServer) - clientFeature := spine.CreateRemoteDeviceAndFeature(subscriptionEntityId, featureType, model.RoleTypeClient, senderMock) - - // serverAddress := featureAddress(serverName, subscriptionEntityId, subscriptionFeatureId) - // clientAddress := featureAddress(clientName, subscriptionEntityId, subscriptionFeatureId) - senderMock.On("Reply", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - cmd := args.Get(2).(model.CmdType) - assert.Equal(t, 1, len(cmd.NodeManagementSubscriptionData.SubscriptionEntry)) - assert.True(t, reflect.DeepEqual(cmd.NodeManagementSubscriptionData.SubscriptionEntry[0].ClientAddress, clientFeature.Address())) - assert.True(t, reflect.DeepEqual(cmd.NodeManagementSubscriptionData.SubscriptionEntry[0].ServerAddress, serverFeature.Address())) - - }).Return(nil).Once() - - // serverFeatureMock := newFeatureLocalMock(serverAddress, model.RoleTypeServer, featureType, senderMock) - // clientFeatureMock := newFeatureRemoteMock(clientAddress, model.RoleTypeClient, featureType) - - requestMsg := spine.Message{ - Cmd: model.CmdType{ - NodeManagementSubscriptionRequestCall: spine.NewNodeManagementSubscriptionRequestCallType( - clientFeature.Address(), serverFeature.Address(), featureType), - }, - CmdClassifier: model.CmdClassifierTypeCall, - FeatureRemote: clientFeature, - } - - sut := spine.NewNodeManagementImpl(0, serverFeature.Entity()) - - // Act - err := sut.HandleMessage(&requestMsg) - if assert.Nil(t, err) { - - dataMsg := spine.Message{ - Cmd: model.CmdType{ - NodeManagementSubscriptionData: &model.NodeManagementSubscriptionDataType{}, - }, - CmdClassifier: model.CmdClassifierTypeCall, - FeatureRemote: clientFeature, - } - err = sut.HandleMessage(&dataMsg) - assert.Nil(t, err) - } -} - -// func newFeatureLocalMock(address *model.FeatureAddressType, role model.RoleType, ftype model.FeatureTypeType, sender spine.Sender) *mocks.FeatureLocal { -// deviceMock := new(mocks.DeviceLocal) -// entityMock := new(mocks.EntityLocal) -// featureMock := new(mocks.FeatureLocal) - -// deviceMock.On("FeatureByAddress", address).Return(featureMock) -// deviceMock.On("Address").Return(address.Device) -// deviceMock.On("Sender").Return(sender) - -// entityMock.On("Device").Return(deviceMock) -// entityMock.On("Address").Return(address.Entity) - -// featureMock.On("Role").Return(role) -// featureMock.On("Type").Return(model.FeatureTypeEnumType(ftype)) -// featureMock.On("Device").Return(deviceMock) -// featureMock.On("Entity").Return(entityMock) - -// return featureMock -// } - -// func newFeatureRemoteMock(address *model.FeatureAddressType, role model.RoleType, ftype model.FeatureTypeType) *mocks.FeatureRemote { -// deviceMock := new(mocks.DeviceRemote) -// entityMock := new(mocks.EntityRemote) -// featureMock := new(mocks.FeatureRemote) - -// deviceMock.On("FeatureByAddress", address).Return(featureMock) -// deviceMock.On("Address").Return(address.Device) -// //deviceMock.On("Sender").Return(sender) - -// entityMock.On("Device").Return(deviceMock) -// entityMock.On("Address").Return(address.Entity) - -// featureMock.On("Role").Return(role) -// featureMock.On("Type").Return(model.FeatureTypeEnumType(ftype)) -// featureMock.On("Device").Return(deviceMock) -// featureMock.On("Entity").Return(entityMock) - -// return featureMock -// } diff --git a/spine/nodemanagement_usecase.go b/spine/nodemanagement_usecase.go deleted file mode 100644 index f5907b5f..00000000 --- a/spine/nodemanagement_usecase.go +++ /dev/null @@ -1,97 +0,0 @@ -package spine - -import ( - "errors" - "fmt" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/spine/model" -) - -func (r *NodeManagementImpl) RequestUseCaseData(remoteDeviceSki string, remoteDeviceAddress *model.AddressDeviceType, sender Sender) (*model.MsgCounterType, *ErrorType) { - rfAdress := featureAddressType(NodeManagementFeatureId, EntityAddressType(remoteDeviceAddress, DeviceInformationAddressEntity)) - cmd := model.CmdType{ - NodeManagementUseCaseData: &model.NodeManagementUseCaseDataType{}, - } - return r.RequestDataBySenderAddress(cmd, sender, remoteDeviceSki, rfAdress, defaultMaxResponseDelay) -} - -func (r *NodeManagementImpl) processReadUseCaseData(featureRemote *FeatureRemoteImpl, requestHeader *model.HeaderType) error { - - cmd := model.CmdType{ - NodeManagementUseCaseData: &model.NodeManagementUseCaseDataType{ - UseCaseInformation: r.entity.Device().UseCaseManager().UseCaseInformation(), - }, - } - - return featureRemote.Sender().Reply(requestHeader, r.Address(), cmd) -} - -func (r *NodeManagementImpl) processReplyUseCaseData(message *Message, data model.NodeManagementUseCaseDataType) error { - useCaseInformation := data.UseCaseInformation - if useCaseInformation == nil { - return errors.New("nodemanagement.replyUseCaseData: invalid UseCaseInformation") - } - - remoteUseCaseManager := message.FeatureRemote.Device().UseCaseManager() - for _, useCaseInfo := range useCaseInformation { - // this is mandatory - var actor model.UseCaseActorType - if useCaseInfo.Actor != nil { - actor = model.UseCaseActorType(*useCaseInfo.Actor) - } else { - logging.Log.Debug("actor is missing in useCaseInformation") - break - } - - for _, useCaseSupport := range useCaseInfo.UseCaseSupport { - - // this is mandatory - var useCaseName model.UseCaseNameType - if useCaseSupport.UseCaseName != nil { - useCaseName = model.UseCaseNameType(*useCaseSupport.UseCaseName) - } else { - logging.Log.Debug("useCaseName is missing in useCaseSupport") - continue - } - - // this is optional - var useCaseVersion model.SpecificationVersionType - if useCaseSupport.UseCaseVersion != nil { - useCaseVersion = model.SpecificationVersionType(*useCaseSupport.UseCaseVersion) - } - - if useCaseSupport.ScenarioSupport == nil { - logging.Log.Errorf("scenarioSupport is missing in useCaseSupport %s", useCaseName) - continue - } - - remoteUseCaseManager.Add( - actor, - useCaseName, - useCaseVersion, - useCaseSupport.ScenarioSupport) - } - } - - return nil -} - -func (r *NodeManagementImpl) handleMsgUseCaseData(message *Message, data *model.NodeManagementUseCaseDataType) error { - switch message.CmdClassifier { - case model.CmdClassifierTypeRead: - return r.processReadUseCaseData(message.FeatureRemote, message.RequestHeader) - - case model.CmdClassifierTypeReply: - if err := r.pendingRequests.Remove(message.DeviceRemote.ski, *message.RequestHeader.MsgCounterReference); err != nil { - return errors.New(err.String()) - } - return r.processReplyUseCaseData(message, *data) - - case model.CmdClassifierTypeNotify: - return r.processReplyUseCaseData(message, *data) - - default: - return fmt.Errorf("nodemanagement.handleUseCaseData: NodeManagementUseCaseData CmdClassifierType not implemented: %s", message.CmdClassifier) - } -} diff --git a/spine/operations.go b/spine/operations.go deleted file mode 100644 index 504e344b..00000000 --- a/spine/operations.go +++ /dev/null @@ -1,39 +0,0 @@ -package spine - -import ( - "github.com/enbility/eebus-go/spine/model" -) - -type Operations struct { - Read, Write bool -} - -func NewOperations(read, write bool) *Operations { - return &Operations{ - Read: read, - Write: write, - } -} - -func (r *Operations) String() string { - switch { - case r.Read && !r.Write: - return "RO" - case r.Read && r.Write: - return "RW" - default: - return "--" - } -} - -func (r *Operations) Information() *model.PossibleOperationsType { - res := new(model.PossibleOperationsType) - if r.Read { - res.Read = &model.PossibleOperationsReadType{} - } - if r.Write { - res.Write = &model.PossibleOperationsWriteType{} - } - - return res -} diff --git a/spine/pending_requests.go b/spine/pending_requests.go deleted file mode 100644 index abe10246..00000000 --- a/spine/pending_requests.go +++ /dev/null @@ -1,120 +0,0 @@ -package spine - -import ( - "fmt" - "sync" - "time" - - "github.com/enbility/eebus-go/spine/model" -) - -type PendingRequests interface { - Add(ski string, counter model.MsgCounterType, maxDelay time.Duration) - SetData(ski string, counter model.MsgCounterType, data any) *ErrorType - SetResult(ski string, counter model.MsgCounterType, errorResult *ErrorType) *ErrorType - GetData(ski string, counter model.MsgCounterType) (any, *ErrorType) - Remove(ski string, counter model.MsgCounterType) *ErrorType -} - -type dataErrorPair struct { - data any - errorResult *ErrorType -} - -type request struct { - ski string // can not use device, as this is not available for the very first requests! - counter model.MsgCounterType - countdown *time.Timer - response chan *dataErrorPair -} - -func (r *request) setTimeoutResult() { - if len(r.response) == 0 { - errorResult := NewErrorType(model.ErrorNumberTypeTimeout, fmt.Sprintf("the request with the message counter '%s' timed out", r.counter.String())) - r.response <- &dataErrorPair{data: nil, errorResult: errorResult} - } -} - -type PendingRequestsImpl struct { - requestMap sync.Map -} - -func NewPendingRequest() PendingRequests { - return &PendingRequestsImpl{ - requestMap: sync.Map{}, - } -} - -func (r *PendingRequestsImpl) Add(ski string, counter model.MsgCounterType, maxDelay time.Duration) { - newRequest := &request{ - ski: ski, - counter: counter, - // could be a performance problem in case of many requests - response: make(chan *dataErrorPair, 1), // buffered, so that SetData will not block, - } - newRequest.countdown = time.AfterFunc(maxDelay, func() { newRequest.setTimeoutResult() }) - - r.requestMap.Store(r.mapKey(ski, counter), newRequest) -} - -func (r *PendingRequestsImpl) SetData(ski string, counter model.MsgCounterType, data any) *ErrorType { - return r.setResponse(ski, counter, data, nil) -} - -func (r *PendingRequestsImpl) SetResult(ski string, counter model.MsgCounterType, errorResult *ErrorType) *ErrorType { - return r.setResponse(ski, counter, nil, errorResult) -} - -func (r *PendingRequestsImpl) GetData(ski string, counter model.MsgCounterType) (any, *ErrorType) { - request, err := r.getRequest(ski, counter) - if err != nil { - return nil, err - } - - data := <-request.response - r.removeRequest(request) - - return data.data, data.errorResult -} - -func (r *PendingRequestsImpl) Remove(ski string, counter model.MsgCounterType) *ErrorType { - request, err := r.getRequest(ski, counter) - if err != nil { - return err - } - r.removeRequest(request) - return nil -} - -func (r *PendingRequestsImpl) mapKey(ski string, counter model.MsgCounterType) string { - return fmt.Sprintf("%s:%d", ski, counter) -} - -func (r *PendingRequestsImpl) removeRequest(request *request) { - request.countdown.Stop() - r.requestMap.Delete(r.mapKey(request.ski, request.counter)) -} - -func (r *PendingRequestsImpl) getRequest(ski string, counter model.MsgCounterType) (*request, *ErrorType) { - rq, exists := r.requestMap.Load(r.mapKey(ski, counter)) - if !exists { - return nil, NewErrorTypeFromString(fmt.Sprintf("No pending request with message counter '%s' found", counter.String())) - } - - return rq.(*request), nil -} - -func (r *PendingRequestsImpl) setResponse(ski string, counter model.MsgCounterType, data any, errorResult *ErrorType) *ErrorType { - - request, err := r.getRequest(ski, counter) - if err != nil { - return err - } - if len(request.response) > 0 { - return NewErrorTypeFromString(fmt.Sprintf("the Data or Result for the request (MsgCounter: %s) was already set!", &counter)) - } - - request.countdown.Stop() - request.response <- &dataErrorPair{data: data, errorResult: errorResult} - return nil -} diff --git a/spine/pending_requests_test.go b/spine/pending_requests_test.go deleted file mode 100644 index b148b683..00000000 --- a/spine/pending_requests_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package spine - -import ( - "testing" - "time" - - "github.com/enbility/eebus-go/spine/model" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type PendingRequestsTestSuite struct { - suite.Suite - sut PendingRequests - ski string - counter model.MsgCounterType -} - -func TestPendingRequestsSuite(t *testing.T) { - suite.Run(t, new(PendingRequestsTestSuite)) -} - -func (suite *PendingRequestsTestSuite) SetupSuite() { - suite.counter = model.MsgCounterType(1) - suite.sut = NewPendingRequest() - suite.ski = "test" -} - -func (suite *PendingRequestsTestSuite) SetupTest() { - suite.sut.Add(suite.ski, suite.counter, defaultMaxResponseDelay) -} - -func (suite *PendingRequestsTestSuite) TestPendingRequests_Timeout() { - _ = suite.sut.Remove(suite.ski, suite.counter) - suite.sut.Add(suite.ski, suite.counter, time.Duration(time.Millisecond*10)) - - time.Sleep(time.Duration(time.Millisecond * 20)) - - // Act - data, err := suite.sut.GetData(suite.ski, suite.counter) - assert.Nil(suite.T(), data) - assert.NotNil(suite.T(), err) - assert.Equal(suite.T(), model.ErrorNumberTypeTimeout, err.ErrorNumber) - assert.Equal(suite.T(), "the request with the message counter '1' timed out", string(*err.Description)) -} - -func (suite *PendingRequestsTestSuite) TestPendingRequests_Remove() { - // Act - err := suite.sut.Remove(suite.ski, suite.counter) - assert.Nil(suite.T(), err) -} - -func (suite *PendingRequestsTestSuite) TestPendingRequests_Remove_GetData() { - _ = suite.sut.Remove(suite.ski, suite.counter) - - // Act - _, err := suite.sut.GetData(suite.ski, suite.counter) - assert.NotNil(suite.T(), err) -} - -func (suite *PendingRequestsTestSuite) TestPendingRequests_SetData() { - // Act - err := suite.sut.SetData(suite.ski, suite.counter, 1) - assert.Nil(suite.T(), err) -} - -func (suite *PendingRequestsTestSuite) TestPendingRequests_SetData_UnknownCounter() { - // Act - err := suite.sut.SetData(suite.ski, model.MsgCounterType(2), 1) - assert.NotNil(suite.T(), err) - assert.Equal(suite.T(), "No pending request with message counter '2' found", string(*err.Description)) -} - -func (suite *PendingRequestsTestSuite) TestPendingRequests_SetData_SetData() { - _ = suite.sut.SetData(suite.ski, suite.counter, 1) - // Act - err := suite.sut.SetData(suite.ski, suite.counter, 2) - assert.NotNil(suite.T(), err) -} - -func (suite *PendingRequestsTestSuite) TestPendingRequests_SetResult() { - // Act - err := suite.sut.SetResult(suite.ski, suite.counter, NewErrorTypeFromString("unknown error")) - assert.Nil(suite.T(), err) -} - -func (suite *PendingRequestsTestSuite) TestPendingRequests_SetResult_SetResult() { - _ = suite.sut.SetResult(suite.ski, suite.counter, NewErrorTypeFromString("unknown error")) - // Act - err := suite.sut.SetResult(suite.ski, suite.counter, NewErrorTypeFromString("unknown error")) - assert.NotNil(suite.T(), err) -} - -func (suite *PendingRequestsTestSuite) TestPendingRequests_SetData_SetResult() { - _ = suite.sut.SetData(suite.ski, suite.counter, 1) - // Act - err := suite.sut.SetResult(suite.ski, suite.counter, NewErrorTypeFromString("unknown error")) - assert.NotNil(suite.T(), err) -} - -func (suite *PendingRequestsTestSuite) TestPendingRequests_SetData_GetData() { - data := 1 - _ = suite.sut.SetData(suite.ski, suite.counter, data) - - // Act - result, err := suite.sut.GetData(suite.ski, suite.counter) - assert.Nil(suite.T(), err) - assert.NotNil(suite.T(), result) - assert.Equal(suite.T(), data, result) -} - -func (suite *PendingRequestsTestSuite) TestPendingRequests_SetResult_GetData() { - errNo := model.ErrorNumberTypeTimeout - errDesc := "Timeout occurred" - _ = suite.sut.SetResult(suite.ski, suite.counter, NewErrorType(errNo, errDesc)) - - // Act - result, err := suite.sut.GetData(suite.ski, suite.counter) - assert.Nil(suite.T(), result) - assert.NotNil(suite.T(), err) - assert.Equal(suite.T(), errNo, err.ErrorNumber) - assert.Equal(suite.T(), errDesc, string(*err.Description)) -} diff --git a/spine/sender.go b/spine/sender.go deleted file mode 100644 index 9d0b4c0f..00000000 --- a/spine/sender.go +++ /dev/null @@ -1,253 +0,0 @@ -//go:generate mockery --name=Sender -package spine - -import ( - "encoding/json" - "errors" - "sync/atomic" - - "github.com/enbility/eebus-go/logging" - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" -) - -type ComControl interface { - // This must be connected to the correct remote device !! - SendSpineMessage(datagram model.DatagramType) error -} - -type Sender interface { - // Sends a read cmd to request some data - Request(cmdClassifier model.CmdClassifierType, senderAddress, destinationAddress *model.FeatureAddressType, ackRequest bool, cmd []model.CmdType) (*model.MsgCounterType, error) - // Sends a result cmd with no error to indicate that a message was processed successfully - ResultSuccess(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType) error - // Sends a result cmd with error information to indicate that a message processing failed - ResultError(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType, err *ErrorType) error - // Sends a reply cmd to response to a read cmd - Reply(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType, cmd model.CmdType) error - // Sends a call cmd with a subscription request - Subscribe(senderAddress, destinationAddress *model.FeatureAddressType, serverFeatureType model.FeatureTypeType) (*model.MsgCounterType, error) - // Sends a call cmd with a binding request - Bind(senderAddress, destinationAddress *model.FeatureAddressType, serverFeatureType model.FeatureTypeType) (*model.MsgCounterType, error) - // Sends a notify cmd to indicate that a subscribed feature changed - Notify(senderAddress, destinationAddress *model.FeatureAddressType, cmd model.CmdType) (*model.MsgCounterType, error) - // Sends a write cmd, setting properties of remote features - Write(senderAddress, destinationAddress *model.FeatureAddressType, cmd model.CmdType) (*model.MsgCounterType, error) -} - -type SenderImpl struct { - msgNum uint64 // 64bit values need to be defined on top of the struct to make atomic commands work on 32bit systems - - writeHandler SpineDataConnection -} - -var _ Sender = (*SenderImpl)(nil) - -func NewSender(writeI SpineDataConnection) Sender { - return &SenderImpl{ - writeHandler: writeI, - } -} - -func (c *SenderImpl) sendSpineMessage(datagram model.DatagramType) error { - // pack into datagram - data := model.Datagram{ - Datagram: datagram, - } - - // marshal - msg, err := json.Marshal(data) - if err != nil { - return err - } - - if c.writeHandler == nil { - return errors.New("outgoing interface implementation not set") - } - - if msg == nil { - return errors.New("message is nil") - } - - logging.Log.Debug(datagram.PrintMessageOverview(true, "", "")) - - // write to channel - c.writeHandler.WriteSpineMessage(msg) - - return nil -} - -// Sends request -func (c *SenderImpl) Request(cmdClassifier model.CmdClassifierType, senderAddress, destinationAddress *model.FeatureAddressType, ackRequest bool, cmd []model.CmdType) (*model.MsgCounterType, error) { - msgCounter := c.getMsgCounter() - - datagram := model.DatagramType{ - Header: model.HeaderType{ - SpecificationVersion: &SpecificationVersion, - AddressSource: senderAddress, - AddressDestination: destinationAddress, - MsgCounter: msgCounter, - CmdClassifier: &cmdClassifier, - }, - Payload: model.PayloadType{ - Cmd: cmd, - }, - } - - if ackRequest { - datagram.Header.AckRequest = &ackRequest - } - - return msgCounter, c.sendSpineMessage(datagram) -} - -func (c *SenderImpl) ResultSuccess(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType) error { - return c.result(requestHeader, senderAddress, nil) -} - -func (c *SenderImpl) ResultError(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType, err *ErrorType) error { - return c.result(requestHeader, senderAddress, err) -} - -// sends a result for a request -func (c *SenderImpl) result(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType, err *ErrorType) error { - cmdClassifier := model.CmdClassifierTypeResult - - addressSource := *requestHeader.AddressDestination - addressSource.Device = senderAddress.Device - - var resultData model.ResultDataType - if err != nil { - resultData = model.ResultDataType{ - ErrorNumber: &err.ErrorNumber, - Description: err.Description, - } - } else { - resultData = model.ResultDataType{ - ErrorNumber: util.Ptr(model.ErrorNumberTypeNoError), - } - } - - cmd := model.CmdType{ - ResultData: &resultData, - } - - datagram := model.DatagramType{ - Header: model.HeaderType{ - SpecificationVersion: &SpecificationVersion, - AddressSource: &addressSource, - AddressDestination: requestHeader.AddressSource, - MsgCounter: c.getMsgCounter(), - MsgCounterReference: requestHeader.MsgCounter, - CmdClassifier: &cmdClassifier, - }, - Payload: model.PayloadType{ - Cmd: []model.CmdType{cmd}, - }, - } - - return c.sendSpineMessage(datagram) -} - -// Reply sends reply to original sender -func (c *SenderImpl) Reply(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType, cmd model.CmdType) error { - cmdClassifier := model.CmdClassifierTypeReply - - addressSource := *requestHeader.AddressDestination - addressSource.Device = senderAddress.Device - - datagram := model.DatagramType{ - Header: model.HeaderType{ - SpecificationVersion: &SpecificationVersion, - AddressSource: &addressSource, - AddressDestination: requestHeader.AddressSource, - MsgCounter: c.getMsgCounter(), - MsgCounterReference: requestHeader.MsgCounter, - CmdClassifier: &cmdClassifier, - }, - Payload: model.PayloadType{ - Cmd: []model.CmdType{cmd}, - }, - } - - return c.sendSpineMessage(datagram) -} - -// Notify sends notification to destination -func (c *SenderImpl) Notify(senderAddress, destinationAddress *model.FeatureAddressType, cmd model.CmdType) (*model.MsgCounterType, error) { - msgCounter := c.getMsgCounter() - - cmdClassifier := model.CmdClassifierTypeNotify - - datagram := model.DatagramType{ - Header: model.HeaderType{ - SpecificationVersion: &SpecificationVersion, - AddressSource: senderAddress, - AddressDestination: destinationAddress, - MsgCounter: msgCounter, - CmdClassifier: &cmdClassifier, - }, - Payload: model.PayloadType{ - Cmd: []model.CmdType{cmd}, - }, - } - - return msgCounter, c.sendSpineMessage(datagram) -} - -// Write sends notification to destination -func (c *SenderImpl) Write(senderAddress, destinationAddress *model.FeatureAddressType, cmd model.CmdType) (*model.MsgCounterType, error) { - msgCounter := c.getMsgCounter() - - cmdClassifier := model.CmdClassifierTypeWrite - ackRequest := true - - datagram := model.DatagramType{ - Header: model.HeaderType{ - SpecificationVersion: &SpecificationVersion, - AddressSource: senderAddress, - AddressDestination: destinationAddress, - MsgCounter: msgCounter, - CmdClassifier: &cmdClassifier, - AckRequest: &ackRequest, - }, - Payload: model.PayloadType{ - Cmd: []model.CmdType{cmd}, - }, - } - - return msgCounter, c.sendSpineMessage(datagram) -} - -// Send a subscription request to a remote server feature -func (c *SenderImpl) Subscribe(senderAddress, destinationAddress *model.FeatureAddressType, serverFeatureType model.FeatureTypeType) (*model.MsgCounterType, error) { - - cmd := model.CmdType{ - NodeManagementSubscriptionRequestCall: NewNodeManagementSubscriptionRequestCallType(senderAddress, destinationAddress, serverFeatureType), - } - - // we always send it to the remote NodeManagment feature, which always is at entity:[0],feature:0 - localAddress := NodeManagementAddress(senderAddress.Device) - remoteAddress := NodeManagementAddress(destinationAddress.Device) - - return c.Request(model.CmdClassifierTypeCall, localAddress, remoteAddress, true, []model.CmdType{cmd}) -} - -// Send a binding request to a remote server feature -func (c *SenderImpl) Bind(senderAddress, destinationAddress *model.FeatureAddressType, serverFeatureType model.FeatureTypeType) (*model.MsgCounterType, error) { - cmd := model.CmdType{ - NodeManagementBindingRequestCall: NewNodeManagementBindingRequestCallType(senderAddress, destinationAddress, serverFeatureType), - } - - // we always send it to the remote NodeManagment feature, which always is at entity:[0],feature:0 - localAddress := NodeManagementAddress(senderAddress.Device) - remoteAddress := NodeManagementAddress(destinationAddress.Device) - - return c.Request(model.CmdClassifierTypeCall, localAddress, remoteAddress, true, []model.CmdType{cmd}) -} - -func (c *SenderImpl) getMsgCounter() *model.MsgCounterType { - // TODO: persistence - i := model.MsgCounterType(atomic.AddUint64(&c.msgNum, 1)) - return &i -} diff --git a/spine/sender_test.go b/spine/sender_test.go deleted file mode 100644 index 776454e5..00000000 --- a/spine/sender_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package spine - -import ( - "encoding/json" - "sync" - "testing" - - "github.com/enbility/eebus-go/spine/model" - "github.com/enbility/eebus-go/util" - "github.com/stretchr/testify/assert" -) - -type WriteMessageHandler struct { - sentMessage []byte - - mux sync.Mutex -} - -var _ SpineDataConnection = (*WriteMessageHandler)(nil) - -func (t *WriteMessageHandler) WriteSpineMessage(message []byte) { - t.mux.Lock() - defer t.mux.Unlock() - - t.sentMessage = message -} - -func TestSender_Notify_MsgCounter(t *testing.T) { - temp := &WriteMessageHandler{} - sut := NewSender(temp) - - senderAddress := featureAddressType(1, NewEntityAddressType("Sender", []uint{1})) - destinationAddress := featureAddressType(2, NewEntityAddressType("destination", []uint{1})) - cmd := model.CmdType{ - ResultData: &model.ResultDataType{ErrorNumber: util.Ptr(model.ErrorNumberType(model.ErrorNumberTypeNoError))}, - } - - _, err := sut.Notify(senderAddress, destinationAddress, cmd) - assert.NoError(t, err) - - // Act - _, err = sut.Notify(senderAddress, destinationAddress, cmd) - assert.NoError(t, err) - expectedMsgCounter := 2 //because Notify was called twice - - sentBytes := temp.sentMessage - var sentDatagram model.Datagram - assert.NoError(t, json.Unmarshal(sentBytes, &sentDatagram)) - assert.Equal(t, expectedMsgCounter, int(*sentDatagram.Datagram.Header.MsgCounter)) -} diff --git a/spine/subscription_manager.go b/spine/subscription_manager.go deleted file mode 100644 index 281051ad..00000000 --- a/spine/subscription_manager.go +++ /dev/null @@ -1,195 +0,0 @@ -package spine - -import ( - "errors" - "fmt" - "reflect" - "sync/atomic" - - "github.com/ahmetb/go-linq/v3" - "github.com/enbility/eebus-go/spine/model" -) - -type SubscriptionManager interface { - AddSubscription(localDevice *DeviceLocalImpl, remoteDevice *DeviceRemoteImpl, data model.SubscriptionManagementRequestCallType) error - RemoveSubscription(data model.SubscriptionManagementDeleteCallType, remoteDevice *DeviceRemoteImpl) error - RemoveSubscriptionsForEntity(remoteEntity *EntityRemoteImpl) - Subscriptions(remoteDevice *DeviceRemoteImpl) []*SubscriptionEntry - SubscriptionsOnFeature(featureAddress model.FeatureAddressType) []*SubscriptionEntry -} - -type SubscriptionEntry struct { - id uint64 - serverFeature FeatureLocal - clientFeature *FeatureRemoteImpl -} - -type SubscriptionManagerImpl struct { - subscriptionNum uint64 - subscriptionEntries []*SubscriptionEntry - // TODO: add persistence -} - -func NewSubscriptionManager() SubscriptionManager { - c := &SubscriptionManagerImpl{ - subscriptionNum: 0, - } - - return c -} - -// is sent from the client (remote device) to the server (local device) -func (c *SubscriptionManagerImpl) AddSubscription(localDevice *DeviceLocalImpl, remoteDevice *DeviceRemoteImpl, data model.SubscriptionManagementRequestCallType) error { - - serverFeature := localDevice.FeatureByAddress(data.ServerAddress) - if serverFeature == nil { - return fmt.Errorf("server feature '%s' in local device '%s' not found", data.ServerAddress, *localDevice.Address()) - } - if err := c.checkRoleAndType(serverFeature, model.RoleTypeServer, *data.ServerFeatureType); err != nil { - return err - } - - clientFeature := remoteDevice.FeatureByAddress(data.ClientAddress) - if clientFeature == nil { - return fmt.Errorf("client feature '%s' in remote device '%s' not found", data.ClientAddress, *remoteDevice.Address()) - } - if err := c.checkRoleAndType(clientFeature, model.RoleTypeClient, *data.ServerFeatureType); err != nil { - return err - } - - subscriptionEntry := &SubscriptionEntry{ - id: c.subscriptionId(), - serverFeature: serverFeature, - clientFeature: clientFeature, - } - - for _, item := range c.subscriptionEntries { - if reflect.DeepEqual(item.serverFeature, serverFeature) && reflect.DeepEqual(item.clientFeature, clientFeature) { - return fmt.Errorf("requested subscription is already present") - } - } - - c.subscriptionEntries = append(c.subscriptionEntries, subscriptionEntry) - - payload := EventPayload{ - Ski: remoteDevice.ski, - EventType: EventTypeSubscriptionChange, - ChangeType: ElementChangeAdd, - Data: data, - Feature: clientFeature, - } - Events.Publish(payload) - - return nil -} - -// Remove a specific subscription that is provided by a delete message from a remote device -func (c *SubscriptionManagerImpl) RemoveSubscription(data model.SubscriptionManagementDeleteCallType, remoteDevice *DeviceRemoteImpl) error { - // TODO: test this!!! - - var newSubscriptionEntries []*SubscriptionEntry - - // according to the spec 7.4.4 - // a. The absence of "subscriptionDelete. clientAddress. device" SHALL be treated as if it was - // present and set to the sender's "device" address part. - // b. The absence of "subscriptionDelete. serverAddress. device" SHALL be treated as if it was - // present and set to the recipient's "device" address part. - - clientAddress := data.ClientAddress - if data.ClientAddress.Device == nil { - clientAddress.Device = remoteDevice.Address() - } - - clientFeature := remoteDevice.FeatureByAddress(data.ClientAddress) - if clientFeature == nil { - return fmt.Errorf("client feature '%s' in remote device '%s' not found", data.ClientAddress, *remoteDevice.Address()) - } - - for _, item := range c.subscriptionEntries { - if !reflect.DeepEqual(item.clientFeature.Address(), clientAddress) { - newSubscriptionEntries = append(newSubscriptionEntries, item) - } - } - - if len(newSubscriptionEntries) == len(c.subscriptionEntries) { - return errors.New("could not find requested SubscriptionId to be removed") - } - - c.subscriptionEntries = newSubscriptionEntries - - payload := EventPayload{ - Ski: remoteDevice.ski, - EventType: EventTypeSubscriptionChange, - ChangeType: ElementChangeRemove, - Data: data, - Device: remoteDevice, - Feature: clientFeature, - } - Events.Publish(payload) - - return nil -} - -// Remove all existing subscriptions for a given remote device entity -func (c *SubscriptionManagerImpl) RemoveSubscriptionsForEntity(remoteEntity *EntityRemoteImpl) { - if remoteEntity == nil { - return - } - - var newSubscriptionEntries []*SubscriptionEntry - for _, item := range c.subscriptionEntries { - if !reflect.DeepEqual(item.clientFeature.Address().Entity, remoteEntity.Address().Entity) { - newSubscriptionEntries = append(newSubscriptionEntries, item) - continue - } - - clientFeature := remoteEntity.Feature(item.clientFeature.address.Feature) - payload := EventPayload{ - Ski: remoteEntity.Device().ski, - EventType: EventTypeSubscriptionChange, - ChangeType: ElementChangeRemove, - Entity: remoteEntity, - Feature: clientFeature, - } - Events.Publish(payload) - } - - c.subscriptionEntries = newSubscriptionEntries -} - -func (c *SubscriptionManagerImpl) Subscriptions(remoteDevice *DeviceRemoteImpl) []*SubscriptionEntry { - var result []*SubscriptionEntry - - linq.From(c.subscriptionEntries).WhereT(func(s *SubscriptionEntry) bool { - return s.clientFeature.Device().Ski() == remoteDevice.Ski() - }).ToSlice(&result) - - return result -} - -func (c *SubscriptionManagerImpl) SubscriptionsOnFeature(featureAddress model.FeatureAddressType) []*SubscriptionEntry { - var result []*SubscriptionEntry - - linq.From(c.subscriptionEntries).WhereT(func(s *SubscriptionEntry) bool { - return reflect.DeepEqual(*s.serverFeature.Address(), featureAddress) - }).ToSlice(&result) - - return result -} - -func (c *SubscriptionManagerImpl) subscriptionId() uint64 { - i := atomic.AddUint64(&c.subscriptionNum, 1) - return i -} - -func (c *SubscriptionManagerImpl) checkRoleAndType(feature Feature, role model.RoleType, featureType model.FeatureTypeType) error { - if feature.Role() != model.RoleTypeSpecial && feature.Role() != role { - return fmt.Errorf("found feature %s is not matching required role %s", feature.Type(), role) - } - - if feature.Type() != featureType && feature.Type() != model.FeatureTypeTypeGeneric { - return fmt.Errorf("found feature %s is not matching required type %s", feature.Type(), featureType) - } - - return nil -} diff --git a/spine/types.go b/spine/types.go deleted file mode 100644 index 36c4543c..00000000 --- a/spine/types.go +++ /dev/null @@ -1,17 +0,0 @@ -package spine - -import "github.com/enbility/eebus-go/spine/model" - -// Used to pass an incoming SPINE message from a SHIP connection to the proper DeviceRemoteImpl -// -// Implemented by DeviceRemoteImpl, used by ShipConnection -type SpineDataProcessing interface { - HandleIncomingSpineMesssage(message []byte) (*model.MsgCounterType, error) -} - -// Used to pass an outgoing SPINE message from a DeviceLocalImpl to the SHIP connection -// -// Implemented by ShipConnection, used by DeviceLocalImpl -type SpineDataConnection interface { - WriteSpineMessage(message []byte) -} diff --git a/spine/usecase.go b/spine/usecase.go deleted file mode 100644 index b99e0885..00000000 --- a/spine/usecase.go +++ /dev/null @@ -1,88 +0,0 @@ -package spine - -import ( - "fmt" - - "github.com/ahmetb/go-linq/v3" - "github.com/enbility/eebus-go/spine/model" -) - -var entityTypeActorMap = map[model.EntityTypeType]model.UseCaseActorType{ - model.EntityTypeTypeEV: model.UseCaseActorTypeEV, - model.EntityTypeTypeEVSE: model.UseCaseActorTypeEVSE, - model.EntityTypeTypeCEM: model.UseCaseActorTypeCEM, - model.EntityTypeTypeGridConnectionPointOfPremises: model.UseCaseActorTypeMonitoringAppliance, - model.EntityTypeTypeElectricityStorageSystem: model.UseCaseActorTypeBatterySystem, - model.EntityTypeTypeElectricityGenerationSystem: model.UseCaseActorTypePVSystem, -} - -var useCaseValidActorsMap = map[model.UseCaseNameType][]model.UseCaseActorType{ - model.UseCaseNameTypeCoordinatedEVCharging: {model.UseCaseActorTypeEV, model.UseCaseActorTypeCEM}, - model.UseCaseNameTypeEVSECommissioningAndConfiguration: {model.UseCaseActorTypeEVSE, model.UseCaseActorTypeCEM}, - model.UseCaseNameTypeEVChargingSummary: {model.UseCaseActorTypeEV, model.UseCaseActorTypeCEM}, - model.UseCaseNameTypeEVCommissioningAndConfiguration: {model.UseCaseActorTypeEV, model.UseCaseActorTypeCEM}, - model.UseCaseNameTypeEVStateOfCharge: {model.UseCaseActorTypeEV, model.UseCaseActorTypeCEM}, - model.UseCaseNameTypeMeasurementOfElectricityDuringEVCharging: {model.UseCaseActorTypeEV, model.UseCaseActorTypeCEM}, - model.UseCaseNameTypeOptimizationOfSelfConsumptionDuringEVCharging: {model.UseCaseActorTypeEV, model.UseCaseActorTypeCEM}, - model.UseCaseNameTypeOverloadProtectionByEVChargingCurrentCurtailment: {model.UseCaseActorTypeEV, model.UseCaseActorTypeCEM}, - model.UseCaseNameTypeMonitoringOfPowerConsumption: {model.UseCaseActorTypeCEM, model.UseCaseActorTypeHeatPump}, - model.UseCaseNameTypeMonitoringAndControlOfSmartGridReadyConditions: {model.UseCaseActorTypeCEM, model.UseCaseActorTypeHeatPump}, - model.UseCaseNameTypeMonitoringOfGridConnectionPoint: {model.UseCaseActorTypeCEM, model.UseCaseActorTypeMonitoringAppliance}, - model.UseCaseNameTypeVisualizationOfAggregatedBatteryData: {model.UseCaseActorTypeCEM, model.UseCaseActorTypeBatterySystem, model.UseCaseActorTypeVisualizationAppliance}, - model.UseCaseNameTypeVisualizationOfAggregatedPhotovoltaicData: {model.UseCaseActorTypeCEM, model.UseCaseActorTypePVSystem, model.UseCaseActorTypeVisualizationAppliance}, -} - -type UseCaseImpl struct { - Entity *EntityLocalImpl - Actor model.UseCaseActorType - - name model.UseCaseNameType - useCaseVersion model.SpecificationVersionType - scenarioSupport []model.UseCaseScenarioSupportType -} - -func NewUseCase(entity *EntityLocalImpl, ucEnumType model.UseCaseNameType, useCaseVersion model.SpecificationVersionType, scenarioSupport []model.UseCaseScenarioSupportType) *UseCaseImpl { - actor := entityTypeActorMap[entity.EntityType()] - - return NewUseCaseWithActor(entity, actor, ucEnumType, useCaseVersion, scenarioSupport) -} - -func NewUseCaseWithActor(entity *EntityLocalImpl, actor model.UseCaseActorType, ucEnumType model.UseCaseNameType, useCaseVersion model.SpecificationVersionType, scenarioSupport []model.UseCaseScenarioSupportType) *UseCaseImpl { - checkArguments(*entity.EntityImpl, ucEnumType) - - ucManager := entity.Device().UseCaseManager() - ucManager.Add(actor, ucEnumType, useCaseVersion, scenarioSupport) - - return &UseCaseImpl{ - Entity: entity, - Actor: actor, - name: model.UseCaseNameType(ucEnumType), - useCaseVersion: useCaseVersion, - scenarioSupport: scenarioSupport, - } -} - -func checkArguments(entity EntityImpl, ucEnumType model.UseCaseNameType) { - actor := entityTypeActorMap[entity.EntityType()] - if actor == "" { - panic(fmt.Errorf("cannot derive actor for entity type '%s'", entity.EntityType())) - } - - if !linq.From(useCaseValidActorsMap[ucEnumType]).Contains(actor) { - panic(fmt.Errorf("the actor '%s' is not valid for the use case '%s'", actor, ucEnumType)) - } -} - -/* -// This is not yet used, might be removed? -func waitForRequest[T any](c chan T, maxDelay time.Duration) *T { - timeout := time.After(maxDelay) - - select { - case data := <-c: - return &data - case <-timeout: - return nil - } -} -*/ diff --git a/spine/usecase_manager.go b/spine/usecase_manager.go deleted file mode 100644 index 8926fcac..00000000 --- a/spine/usecase_manager.go +++ /dev/null @@ -1,44 +0,0 @@ -package spine - -import "github.com/enbility/eebus-go/spine/model" - -type UseCaseManager struct { - useCaseInformationMap map[model.UseCaseActorType][]model.UseCaseSupportType -} - -func NewUseCaseManager() *UseCaseManager { - return &UseCaseManager{ - useCaseInformationMap: make(map[model.UseCaseActorType][]model.UseCaseSupportType), - } -} - -func (r *UseCaseManager) Add(actor model.UseCaseActorType, useCaseName model.UseCaseNameType, useCaseVersion model.SpecificationVersionType, scenarios []model.UseCaseScenarioSupportType) { - useCaseSupport := model.UseCaseSupportType{ - UseCaseVersion: &useCaseVersion, - UseCaseName: &useCaseName, - ScenarioSupport: scenarios, - } - - useCaseInfo, exists := r.useCaseInformationMap[actor] - if !exists { - useCaseInfo = make([]model.UseCaseSupportType, 0) - } - useCaseInfo = append(useCaseInfo, useCaseSupport) - - r.useCaseInformationMap[actor] = useCaseInfo -} - -func (r *UseCaseManager) UseCaseInformation() []model.UseCaseInformationDataType { - var result []model.UseCaseInformationDataType - - for actor, useCaseSupport := range r.useCaseInformationMap { - useCaseInfo := model.UseCaseInformationDataType{ - //Address: r.address, // TODO: which address ??? - Actor: &actor, - UseCaseSupport: useCaseSupport, - } - result = append(result, useCaseInfo) - } - - return result -} diff --git a/util/channel.go b/util/channel.go deleted file mode 100644 index 5419193f..00000000 --- a/util/channel.go +++ /dev/null @@ -1,24 +0,0 @@ -package util - -import "time" - -func ReceiveWithTimeout[T any](c chan T, maxDelay time.Duration) T { - timeout := time.After(maxDelay) - - select { - case data := <-c: - return data - case <-timeout: - return Zero[T]() - } -} - -// check if a provided channel is closed -func IsChannelClosed[T any](ch <-chan T) bool { - select { - case <-ch: - return false - default: - return true - } -} diff --git a/util/helper.go b/util/helper.go deleted file mode 100644 index 4c5aef9c..00000000 --- a/util/helper.go +++ /dev/null @@ -1,12 +0,0 @@ -package util - -import "strings" - -// standardize the provided SKI strings -func NormalizeSKI(ski string) string { - ski = strings.ReplaceAll(ski, " ", "") - ski = strings.ReplaceAll(ski, "-", "") - ski = strings.ToLower(ski) - - return ski -} diff --git a/util/type.go b/util/type.go deleted file mode 100644 index 44478bf3..00000000 --- a/util/type.go +++ /dev/null @@ -1,13 +0,0 @@ -package util - -import "reflect" - -func Type[T any]() reflect.Type { - return reflect.TypeOf((*T)(nil)).Elem() -} - -// checks if type T implements interface I -func Implements[T any, I any]() bool { - _, supported := any((*T)(nil)).(I) - return supported -} diff --git a/util/zero.go b/util/zero.go deleted file mode 100644 index a74a149a..00000000 --- a/util/zero.go +++ /dev/null @@ -1,15 +0,0 @@ -package util - -import "reflect" - -func Zero[T any]() (ret T) { - return -} - -func IsZero[T comparable](v T) bool { - return v == *new(T) -} - -func IsNil[T any](v T) bool { - return !reflect.ValueOf(v).IsValid() -}