From 1c0c25d91140521cd0d753ab5cb2259992b62aef Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 14 Jan 2024 20:43:30 +0100 Subject: [PATCH] Initial commit - Based on dev branch of github.com/enbility/eebus-go - Adjusted and improved to work as a independant go package --- .github/workflows/default.yml | 45 + .gitignore | 21 + LICENSE | 22 + README.md | 16 + api/.mockery.yaml | 9 + api/api.go | 296 ++++ api/binding.go | 7 + api/events.go | 39 + api/message.go | 23 + api/subscription.go | 7 + go.mod | 23 + go.sum | 34 + integration_tests/devicediagnosis_test.go | 54 + .../electricalconnection_test.go | 149 ++ integration_tests/helper_test.go | 156 ++ integration_tests/measurement_test.go | 164 ++ .../dd_subscriptionRequestCall_recv.json | 41 + .../ec_descriptionListData_recv_reply.json | 37 + ...rameterDescriptionListData_recv_reply.json | 67 + ...dvaluesetlistdata_recv_notify_partial.json | 98 ++ ...c_subscriptionRequestCall_recv_result.json | 33 + .../m_descriptionListData_recv_reply.json | 52 + .../m_measurementListData_recv_notify.json | 60 + mocks/BindingManager.go | 293 ++++ mocks/ComControl.go | 81 + mocks/Device.go | 221 +++ mocks/DeviceLocal.go | 1090 ++++++++++++++ mocks/DeviceRemote.go | 930 ++++++++++++ mocks/Entity.go | 252 ++++ mocks/EntityLocal.go | 742 +++++++++ mocks/EntityRemote.go | 461 ++++++ mocks/EventHandler.go | 68 + mocks/Feature.go | 379 +++++ mocks/FeatureLocal.go | 1321 +++++++++++++++++ mocks/FeatureRemote.go | 751 ++++++++++ mocks/FeatureResult.go | 68 + mocks/FunctionData.go | 162 ++ mocks/FunctionDataCmd.go | 352 +++++ mocks/HeartbeatManager.go | 223 +++ mocks/NodeManagement.go | 1321 +++++++++++++++++ mocks/Operations.go | 127 ++ mocks/PendingRequests.go | 282 ++++ mocks/Sender.go | 654 ++++++++ mocks/SpineDataConnection.go | 29 + mocks/SubscriptionManager.go | 293 ++++ model/actuatorlevel.go | 36 + model/actuatorswitch.go | 27 + model/alarm.go | 44 + model/alarm_additions.go | 14 + model/alarm_additions_test.go | 46 + model/bill.go | 157 ++ model/bill_additions.go | 40 + model/bill_additions_test.go | 122 ++ model/bindingmanagement.go | 53 + model/bindingmanagement_additions.go | 14 + model/bindingmanagement_additions_test.go | 46 + model/collection_operations.go | 122 ++ model/collection_operations_test.go | 62 + model/commandframe.go | 426 ++++++ model/commandframe_additions.go | 297 ++++ model/commandframe_additions_test.go | 141 ++ model/commondatatypes.go | 988 ++++++++++++ model/commondatatypes_additions.go | 234 +++ model/commondatatypes_additions_test.go | 282 ++++ model/custom.go | 47 + model/custom_test.go | 62 + model/datagram.go | 26 + model/datagram_additions.go | 42 + model/datagram_additions_test.go | 116 ++ model/datatunneling.go | 27 + model/deviceclassification.go | 55 + model/deviceconfiguration.go | 150 ++ model/deviceconfiguration_additions.go | 40 + model/deviceconfiguration_additions_test.go | 134 ++ model/devicediagnosis.go | 76 + model/directcontrol.go | 55 + model/eebus_tags.go | 46 + model/electricalconnection.go | 241 +++ model/electricalconnection_additions.go | 66 + model/electricalconnection_additions_test.go | 1188 +++++++++++++++ model/hvac.go | 222 +++ model/hvac_additions.go | 105 ++ model/hvac_additions_test.go | 312 ++++ model/identification.go | 82 + model/identification_additions.go | 40 + model/identification_additions_test.go | 46 + model/incentivetable.go | 103 ++ model/loadcontrol.go | 185 +++ model/loadcontrol_additions.go | 66 + model/loadcontrol_additions_test.go | 198 +++ model/measurement.go | 222 +++ model/measurement_additions.go | 66 + model/measurement_additions_test.go | 207 +++ model/messaging.go | 39 + model/messaging_additions.go | 14 + model/messaging_additions_test.go | 46 + model/networkmanagement.go | 239 +++ model/networkmanagement_additions.go | 40 + model/nodemanagement.go | 136 ++ model/nodemanagement_additions.go | 143 ++ model/nodemanagement_additions_test.go | 123 ++ model/operatingconstraints.go | 143 ++ model/operatingconstraints_additions.go | 79 + model/operatingconstraints_additions_test.go | 239 +++ model/powersequences.go | 331 +++++ model/powersequences_additions.go | 131 ++ model/powersequences_additions_test.go | 391 +++++ model/result.go | 21 + model/sensing.go | 99 ++ model/sensing_additions.go | 14 + model/setpoint.go | 98 ++ model/setpoint_additions.go | 27 + model/setpoint_additions_test.go | 84 ++ model/smartenergymanagementps.go | 104 ++ model/stateinformation.go | 115 ++ model/stateinformation_additions.go | 14 + model/subscriptionmanagement.go | 53 + model/subscriptionmanagement_additions.go | 14 + .../subscriptionmanagement_additions_test.go | 46 + model/supplyconditions.go | 112 ++ model/supplyconditions_additions.go | 40 + model/supplyconditions_additions_test.go | 122 ++ model/tariffinformation.go | 370 +++++ model/tariffinformation_additions.go | 157 ++ model/tariffinformation_additions_test.go | 464 ++++++ model/taskmanagement.go | 159 ++ model/taskmanagement_additions.go | 40 + model/taskmanagement_additions_test.go | 128 ++ model/threshold.go | 85 ++ model/threshold_additions.go | 40 + model/threshold_additions_test.go | 122 ++ model/timeinformation.go | 41 + model/timeseries.go | 133 ++ model/timeseries_additions.go | 40 + model/timeseries_additions_test.go | 239 +++ model/timetable.go | 96 ++ model/timetable_additions.go | 40 + model/timetable_additions_test.go | 128 ++ model/update.go | 301 ++++ model/update_test.go | 120 ++ model/usecaseinformation.go | 118 ++ model/usecaseinformation_additions.go | 53 + model/usecaseinformation_additions_test.go | 47 + .../usecaseinformation_additions_test.go_temp | 86 ++ model/version.go | 11 + model/version_additions.go | 14 + model/version_additions_test.go | 48 + spine/binding_manager.go | 221 +++ spine/binding_manager_test.go | 109 ++ spine/const.go | 5 + spine/device.go | 54 + spine/device_local.go | 432 ++++++ spine/device_local_test.go | 237 +++ spine/device_remote.go | 361 +++++ spine/device_remote_test.go | 276 ++++ spine/entity.go | 87 ++ spine/entity_local.go | 165 ++ spine/entity_local_test.go | 80 + spine/entity_remote.go | 46 + spine/events.go | 105 ++ spine/feature.go | 74 + spine/feature_local.go | 466 ++++++ spine/feature_local_test.go | 191 +++ spine/feature_remote.go | 115 ++ spine/function_data.go | 83 ++ spine/function_data_cmd.go | 121 ++ spine/function_data_cmd_test.go | 1140 ++++++++++++++ spine/function_data_factory.go | 319 ++++ spine/function_data_factory_test.go | 97 ++ spine/function_data_test.go | 79 + spine/heartbeat_manager.go | 148 ++ spine/heartbeat_manager_test.go | 139 ++ spine/helper_test.go | 197 +++ spine/nodemanagement.go | 114 ++ spine/nodemanagement_binding.go | 81 + spine/nodemanagement_destinationlist.go | 51 + spine/nodemanagement_detaileddiscovery.go | 266 ++++ .../nodemanagement_detaileddiscovery_test.go | 193 +++ spine/nodemanagement_subscription.go | 94 ++ spine/nodemanagement_test.go | 156 ++ spine/nodemanagement_usecase.go | 74 + spine/operations.go | 50 + spine/operations_test.go | 36 + spine/pending_requests.go | 113 ++ spine/pending_requests_test.go | 124 ++ spine/send.go | 274 ++++ spine/send_test.go | 177 +++ spine/subscription_manager.go | 222 +++ spine/subscription_manager_test.go | 97 ++ .../nm_destinationListData_recv_read.json | 29 + ...stinationListData_send_reply_expected.json | 43 + .../nm_detaileddiscoverydata_recv_read.json | 29 + ...m_detaileddiscoverydata_recv_read_ack.json | 30 + ...aileddiscoverydata_send_read_expected.json | 29 + ...ileddiscoverydata_send_reply_expected.json | 143 ++ ...leddiscoverydata_send_result_expected.json | 33 + .../nm_subscriptionRequestCall_recv_call.json | 48 + ...ptionRequestCall_send_result_expected.json | 33 + ...usecaseinformationlistdata_recv_reply.json | 120 ++ ...box_detaileddiscoverydata_recv_notify.json | 376 +++++ ...lbox_detaileddiscoverydata_recv_reply.json | 187 +++ util/helper.go | 11 + util/ptr.go | 5 + util/type.go | 13 + 204 files changed, 33664 insertions(+) create mode 100644 .github/workflows/default.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 api/.mockery.yaml create mode 100644 api/api.go create mode 100644 api/binding.go create mode 100644 api/events.go create mode 100644 api/message.go create mode 100644 api/subscription.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 integration_tests/devicediagnosis_test.go create mode 100644 integration_tests/electricalconnection_test.go create mode 100644 integration_tests/helper_test.go create mode 100644 integration_tests/measurement_test.go create mode 100644 integration_tests/testdata/dd_subscriptionRequestCall_recv.json create mode 100644 integration_tests/testdata/ec_descriptionListData_recv_reply.json create mode 100644 integration_tests/testdata/ec_parameterDescriptionListData_recv_reply.json create mode 100644 integration_tests/testdata/ec_permittedvaluesetlistdata_recv_notify_partial.json create mode 100644 integration_tests/testdata/ec_subscriptionRequestCall_recv_result.json create mode 100644 integration_tests/testdata/m_descriptionListData_recv_reply.json create mode 100644 integration_tests/testdata/m_measurementListData_recv_notify.json create mode 100644 mocks/BindingManager.go create mode 100644 mocks/ComControl.go create mode 100644 mocks/Device.go create mode 100644 mocks/DeviceLocal.go create mode 100644 mocks/DeviceRemote.go create mode 100644 mocks/Entity.go create mode 100644 mocks/EntityLocal.go create mode 100644 mocks/EntityRemote.go create mode 100644 mocks/EventHandler.go create mode 100644 mocks/Feature.go create mode 100644 mocks/FeatureLocal.go create mode 100644 mocks/FeatureRemote.go create mode 100644 mocks/FeatureResult.go create mode 100644 mocks/FunctionData.go create mode 100644 mocks/FunctionDataCmd.go create mode 100644 mocks/HeartbeatManager.go create mode 100644 mocks/NodeManagement.go create mode 100644 mocks/Operations.go create mode 100644 mocks/PendingRequests.go create mode 100644 mocks/Sender.go create mode 100644 mocks/SpineDataConnection.go create mode 100644 mocks/SubscriptionManager.go create mode 100644 model/actuatorlevel.go create mode 100644 model/actuatorswitch.go create mode 100644 model/alarm.go create mode 100644 model/alarm_additions.go create mode 100644 model/alarm_additions_test.go create mode 100644 model/bill.go create mode 100644 model/bill_additions.go create mode 100644 model/bill_additions_test.go create mode 100644 model/bindingmanagement.go create mode 100644 model/bindingmanagement_additions.go create mode 100644 model/bindingmanagement_additions_test.go create mode 100644 model/collection_operations.go create mode 100644 model/collection_operations_test.go create mode 100644 model/commandframe.go create mode 100644 model/commandframe_additions.go create mode 100644 model/commandframe_additions_test.go create mode 100644 model/commondatatypes.go create mode 100644 model/commondatatypes_additions.go create mode 100644 model/commondatatypes_additions_test.go create mode 100644 model/custom.go create mode 100644 model/custom_test.go create mode 100644 model/datagram.go create mode 100644 model/datagram_additions.go create mode 100644 model/datagram_additions_test.go create mode 100644 model/datatunneling.go create mode 100644 model/deviceclassification.go create mode 100644 model/deviceconfiguration.go create mode 100644 model/deviceconfiguration_additions.go create mode 100644 model/deviceconfiguration_additions_test.go create mode 100644 model/devicediagnosis.go create mode 100644 model/directcontrol.go create mode 100644 model/eebus_tags.go create mode 100644 model/electricalconnection.go create mode 100644 model/electricalconnection_additions.go create mode 100644 model/electricalconnection_additions_test.go create mode 100644 model/hvac.go create mode 100644 model/hvac_additions.go create mode 100644 model/hvac_additions_test.go create mode 100644 model/identification.go create mode 100644 model/identification_additions.go create mode 100644 model/identification_additions_test.go create mode 100644 model/incentivetable.go create mode 100644 model/loadcontrol.go create mode 100644 model/loadcontrol_additions.go create mode 100644 model/loadcontrol_additions_test.go create mode 100644 model/measurement.go create mode 100644 model/measurement_additions.go create mode 100644 model/measurement_additions_test.go create mode 100644 model/messaging.go create mode 100644 model/messaging_additions.go create mode 100644 model/messaging_additions_test.go create mode 100644 model/networkmanagement.go create mode 100644 model/networkmanagement_additions.go create mode 100644 model/nodemanagement.go create mode 100644 model/nodemanagement_additions.go create mode 100644 model/nodemanagement_additions_test.go create mode 100644 model/operatingconstraints.go create mode 100644 model/operatingconstraints_additions.go create mode 100644 model/operatingconstraints_additions_test.go create mode 100644 model/powersequences.go create mode 100644 model/powersequences_additions.go create mode 100644 model/powersequences_additions_test.go create mode 100644 model/result.go create mode 100644 model/sensing.go create mode 100644 model/sensing_additions.go create mode 100644 model/setpoint.go create mode 100644 model/setpoint_additions.go create mode 100644 model/setpoint_additions_test.go create mode 100644 model/smartenergymanagementps.go create mode 100644 model/stateinformation.go create mode 100644 model/stateinformation_additions.go create mode 100644 model/subscriptionmanagement.go create mode 100644 model/subscriptionmanagement_additions.go create mode 100644 model/subscriptionmanagement_additions_test.go create mode 100644 model/supplyconditions.go create mode 100644 model/supplyconditions_additions.go create mode 100644 model/supplyconditions_additions_test.go create mode 100644 model/tariffinformation.go create mode 100644 model/tariffinformation_additions.go create mode 100644 model/tariffinformation_additions_test.go create mode 100644 model/taskmanagement.go create mode 100644 model/taskmanagement_additions.go create mode 100644 model/taskmanagement_additions_test.go create mode 100644 model/threshold.go create mode 100644 model/threshold_additions.go create mode 100644 model/threshold_additions_test.go create mode 100644 model/timeinformation.go create mode 100644 model/timeseries.go create mode 100644 model/timeseries_additions.go create mode 100644 model/timeseries_additions_test.go create mode 100644 model/timetable.go create mode 100644 model/timetable_additions.go create mode 100644 model/timetable_additions_test.go create mode 100644 model/update.go create mode 100644 model/update_test.go create mode 100644 model/usecaseinformation.go create mode 100644 model/usecaseinformation_additions.go create mode 100644 model/usecaseinformation_additions_test.go create mode 100644 model/usecaseinformation_additions_test.go_temp create mode 100644 model/version.go create mode 100644 model/version_additions.go create mode 100644 model/version_additions_test.go create mode 100644 spine/binding_manager.go create mode 100644 spine/binding_manager_test.go create mode 100644 spine/const.go create mode 100644 spine/device.go create mode 100644 spine/device_local.go create mode 100644 spine/device_local_test.go create mode 100644 spine/device_remote.go create mode 100644 spine/device_remote_test.go create mode 100644 spine/entity.go create mode 100644 spine/entity_local.go create mode 100644 spine/entity_local_test.go create mode 100644 spine/entity_remote.go create mode 100644 spine/events.go create mode 100644 spine/feature.go create mode 100644 spine/feature_local.go create mode 100644 spine/feature_local_test.go create mode 100644 spine/feature_remote.go create mode 100644 spine/function_data.go create mode 100644 spine/function_data_cmd.go create mode 100644 spine/function_data_cmd_test.go create mode 100644 spine/function_data_factory.go create mode 100644 spine/function_data_factory_test.go create mode 100644 spine/function_data_test.go create mode 100644 spine/heartbeat_manager.go create mode 100644 spine/heartbeat_manager_test.go create mode 100644 spine/helper_test.go create mode 100644 spine/nodemanagement.go create mode 100644 spine/nodemanagement_binding.go create mode 100644 spine/nodemanagement_destinationlist.go create mode 100644 spine/nodemanagement_detaileddiscovery.go create mode 100644 spine/nodemanagement_detaileddiscovery_test.go create mode 100644 spine/nodemanagement_subscription.go create mode 100644 spine/nodemanagement_test.go create mode 100644 spine/nodemanagement_usecase.go create mode 100644 spine/operations.go create mode 100644 spine/operations_test.go create mode 100644 spine/pending_requests.go create mode 100644 spine/pending_requests_test.go create mode 100644 spine/send.go create mode 100644 spine/send_test.go create mode 100644 spine/subscription_manager.go create mode 100644 spine/subscription_manager_test.go create mode 100644 spine/testdata/nm_destinationListData_recv_read.json create mode 100644 spine/testdata/nm_destinationListData_send_reply_expected.json create mode 100644 spine/testdata/nm_detaileddiscoverydata_recv_read.json create mode 100644 spine/testdata/nm_detaileddiscoverydata_recv_read_ack.json create mode 100644 spine/testdata/nm_detaileddiscoverydata_send_read_expected.json create mode 100644 spine/testdata/nm_detaileddiscoverydata_send_reply_expected.json create mode 100644 spine/testdata/nm_detaileddiscoverydata_send_result_expected.json create mode 100644 spine/testdata/nm_subscriptionRequestCall_recv_call.json create mode 100644 spine/testdata/nm_subscriptionRequestCall_send_result_expected.json create mode 100644 spine/testdata/nm_usecaseinformationlistdata_recv_reply.json create mode 100644 spine/testdata/wallbox_detaileddiscoverydata_recv_notify.json create mode 100644 spine/testdata/wallbox_detaileddiscoverydata_recv_reply.json create mode 100644 util/helper.go create mode 100644 util/ptr.go create mode 100644 util/type.go diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml new file mode 100644 index 0000000..7cad577 --- /dev/null +++ b/.github/workflows/default.yml @@ -0,0 +1,45 @@ +name: Default + +env: + ACTION_ENVIRONMENT: CI + +on: + push: + branches: + - dev + - main + pull_request: + workflow_call: + +jobs: + build: + name: Build + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: ^1.18 + + - name: Build + run: go build -v ./... + + - name: Lint + uses: golangci/golangci-lint-action@v3 + with: + version: latest + skip-pkg-cache: true + skip-build-cache: true + args: --timeout=3m --issues-exit-code=0 ./... + + - name: Test + run: go test -race -v -coverprofile=coverage.out -covermode=atomic ./... + + - name: Send coverage + uses: shogo82148/actions-goveralls@v1 + with: + path-to-profile: coverage.out \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..968d485 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +# VS Code +.vscode diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..56a7aad --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT license + +Copyright (c) 2022 Andreas Linde & Timo Vogel +Copyright (c) 2022-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 +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..390fc4f --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# spine-go + +[![Build Status](https://github.com/enbility/spine-go/actions/workflows/default.yml/badge.svg?branch=dev)](https://github.com/enbility/spine-go/actions/workflows/default.yml/badge.svg?branch=dev) +[![GoDoc](https://img.shields.io/badge/godoc-reference-5272B4)](https://godoc.org/github.com/enbility/spine-go) +[![Coverage Status](https://coveralls.io/repos/github/enbility/spine-go/badge.svg?branch=dev)](https://coveralls.io/github/enbility/eebus-go?branch=dev) +[![Go report](https://goreportcard.com/badge/github.com/enbility/spine-go)](https://goreportcard.com/report/github.com/enbility/spine-go) + +## Introduction + +This library provides an implementation of SPINE 1.3 in [go](https://golang.org), which is part of the [EEBUS](https://eebus.org) specification. + +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/). + +This repository was started as part of the [eebus-go](https://github.com/enbility/eebus-go) before it was moved into its own repository and this separate go package. + +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/). diff --git a/api/.mockery.yaml b/api/.mockery.yaml new file mode 100644 index 0000000..179d748 --- /dev/null +++ b/api/.mockery.yaml @@ -0,0 +1,9 @@ +with-expecter: True +inpackage: false +dir: ../mocks/{{ replaceAll .InterfaceDirRelative "internal" "internal_" }} +mockname: "{{.InterfaceName}}" +outpkg: "mocks" +filename: "{{.InterfaceName}}.go" +all: True +packages: + github.com/enbility/spine-go/api: diff --git a/api/api.go b/api/api.go new file mode 100644 index 0000000..b24bb52 --- /dev/null +++ b/api/api.go @@ -0,0 +1,296 @@ +package api + +import ( + "time" + + shipapi "github.com/enbility/ship-go/api" + "github.com/enbility/spine-go/model" +) + +//go:generate mockery + +type EventHandler interface { + HandleEvent(EventPayload) +} + +/* Device */ + +type Device interface { + Address() *model.AddressDeviceType + DeviceType() *model.DeviceTypeType + FeatureSet() *model.NetworkManagementFeatureSetType + DestinationData() model.NodeManagementDestinationDataType +} + +type DeviceLocal interface { + Device + RemoveRemoteDeviceConnection(ski string) + AddRemoteDeviceForSki(ski string, rDevice DeviceRemote) + SetupRemoteDevice(ski string, writeI shipapi.SpineDataConnection) shipapi.SpineDataProcessing + RemoveRemoteDevice(ski string) + RemoteDevices() []DeviceRemote + RemoteDeviceForAddress(address model.AddressDeviceType) DeviceRemote + RemoteDeviceForSki(ski string) DeviceRemote + ProcessCmd(datagram model.DatagramType, remoteDevice DeviceRemote) error + NodeManagement() NodeManagement + SubscriptionManager() SubscriptionManager + BindingManager() BindingManager + HeartbeatManager() HeartbeatManager + AddEntity(entity EntityLocal) + RemoveEntity(entity EntityLocal) + Entities() []EntityLocal + Entity(id []model.AddressEntityType) EntityLocal + EntityForType(entityType model.EntityTypeType) EntityLocal + FeatureByAddress(address *model.FeatureAddressType) FeatureLocal + NotifySubscribers(featureAddress *model.FeatureAddressType, cmd model.CmdType) + Information() *model.NodeManagementDetailedDiscoveryDeviceInformationType +} + +type DeviceRemote interface { + Device + Ski() string + SetAddress(address *model.AddressDeviceType) + HandleSpineMesssage(message []byte) (*model.MsgCounterType, error) + Sender() Sender + Entity(id []model.AddressEntityType) EntityRemote + Entities() []EntityRemote + FeatureByAddress(address *model.FeatureAddressType) FeatureRemote + RemoveByAddress(addr []model.AddressEntityType) EntityRemote + FeatureByEntityTypeAndRole(entity EntityRemote, featureType model.FeatureTypeType, role model.RoleType) FeatureRemote + UpdateDevice(description *model.NetworkManagementDeviceDescriptionDataType) + AddEntityAndFeatures(initialData bool, data *model.NodeManagementDetailedDiscoveryDataType) ([]EntityRemote, error) + AddEntity(entity EntityRemote) EntityRemote + UseCases() []model.UseCaseInformationDataType + VerifyUseCaseScenariosAndFeaturesSupport( + usecaseActor model.UseCaseActorType, + usecaseName model.UseCaseNameType, + scenarios []model.UseCaseScenarioSupportType, + serverFeatures []model.FeatureTypeType, + ) bool + CheckEntityInformation(initialData bool, entity model.NodeManagementDetailedDiscoveryEntityInformationType) error +} + +/* Entity */ + +type Entity interface { + EntityType() model.EntityTypeType + Address() *model.EntityAddressType + Description() *model.DescriptionType + SetDescription(d *model.DescriptionType) + NextFeatureId() uint +} + +type EntityLocal interface { + Entity + Device() DeviceLocal + AddFeature(f FeatureLocal) + GetOrAddFeature(featureType model.FeatureTypeType, role model.RoleType) FeatureLocal + FeatureOfTypeAndRole(featureType model.FeatureTypeType, role model.RoleType) FeatureLocal + Features() []FeatureLocal + Feature(addressFeature *model.AddressFeatureType) FeatureLocal + Information() *model.NodeManagementDetailedDiscoveryEntityInformationType + AddUseCaseSupport( + actor model.UseCaseActorType, + useCaseName model.UseCaseNameType, + useCaseVersion model.SpecificationVersionType, + useCaseDocumemtSubRevision string, + useCaseAvailable bool, + scenarios []model.UseCaseScenarioSupportType, + ) + RemoveUseCaseSupport( + actor model.UseCaseActorType, + useCaseName model.UseCaseNameType, + ) + RemoveAllUseCaseSupports() + RemoveAllSubscriptions() + RemoveAllBindings() +} + +type EntityRemote interface { + Entity + Device() DeviceRemote + AddFeature(f FeatureRemote) + Features() []FeatureRemote + Feature(addressFeature *model.AddressFeatureType) FeatureRemote + RemoveAllFeatures() +} + +/* Feature */ + +type Feature interface { + Address() *model.FeatureAddressType + Type() model.FeatureTypeType + Role() model.RoleType + Operations() map[model.FunctionType]Operations + Description() *model.DescriptionType + SetDescription(desc *model.DescriptionType) + SetDescriptionString(s string) + String() string +} + +type FeatureRemote interface { + Feature + DataCopy(function model.FunctionType) any + SetData(function model.FunctionType, data any) + UpdateData(function model.FunctionType, data any, filterPartial *model.FilterType, filterDelete *model.FilterType) + Sender() Sender + Device() DeviceRemote + Entity() EntityRemote + SetOperations(functions []model.FunctionPropertyType) + SetMaxResponseDelay(delay *model.MaxResponseDelayType) + MaxResponseDelayDuration() time.Duration +} + +type FeatureLocal interface { + Feature + Device() DeviceLocal + Entity() EntityLocal + DataCopy(function model.FunctionType) any + SetData(function model.FunctionType, data any) + AddResultHandler(handler FeatureResult) + AddResultCallback(msgCounterReference model.MsgCounterType, function func(msg ResultMessage)) + Information() *model.NodeManagementDetailedDiscoveryFeatureInformationType + AddFunctionType(function model.FunctionType, read, write bool) + RequestData( + function model.FunctionType, + selector any, + elements any, + destination FeatureRemote) (*model.MsgCounterType, *model.ErrorType) + RequestDataBySenderAddress( + cmd model.CmdType, + sender Sender, + destinationSki string, + destinationAddress *model.FeatureAddressType, + maxDelay time.Duration) (*model.MsgCounterType, *model.ErrorType) + FetchRequestData( + msgCounter model.MsgCounterType, + destination FeatureRemote) (any, *model.ErrorType) + Subscribe(remoteAdress *model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType) + // SubscribeAndWait(remoteDevice DeviceRemote, remoteAdress *model.FeatureAddressType) *ErrorType // Subscribes the local feature to the given destination feature; the go routine will block until the response is processed + RemoveSubscription(remoteAddress *model.FeatureAddressType) + RemoveAllSubscriptions() + Bind(remoteAdress *model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType) + // BindAndWait(remoteDevice DeviceRemote, remoteAddress *model.FeatureAddressType) *ErrorType + RemoveBinding(remoteAddress *model.FeatureAddressType) + RemoveAllBindings() + NotifyData( + function model.FunctionType, + deleteSelector, partialSelector any, + partialWithoutSelector bool, + deleteElements any, + destination FeatureRemote) (*model.MsgCounterType, *model.ErrorType) + WriteData( + function model.FunctionType, + deleteSelector, partialSelector any, + deleteElements any, + destination FeatureRemote) (*model.MsgCounterType, *model.ErrorType) + HandleMessage(message *Message) *model.ErrorType +} + +type NodeManagement interface { + FeatureLocal +} + +type FeatureResult interface { + HandleResult(ResultMessage) +} + +/* Functions */ + +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 +} + +type FunctionData interface { + Function() model.FunctionType + DataCopyAny() any + UpdateDataAny(data any, filterPartial *model.FilterType, filterDelete *model.FilterType) +} + +/* Sender */ + +type ComControl interface { + // This must be connected to the correct remote device !! + SendSpineMessage(datagram model.DatagramType) error +} + +//go:generate mockery --name=Sender + +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 *model.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 subscription delete request + Unsubscribe(senderAddress, destinationAddress *model.FeatureAddressType) (*model.MsgCounterType, error) + // Sends a call cmd with a binding request + Bind(senderAddress, destinationAddress *model.FeatureAddressType, serverFeatureType model.FeatureTypeType) (*model.MsgCounterType, error) + // Sends a call cmd with a binding delte request + Unbind(senderAddress, destinationAddress *model.FeatureAddressType) (*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) + // return the datagram for a given msgCounter (only availbe for Notify messasges!), error if not found + DatagramForMsgCounter(msgCounter model.MsgCounterType) (model.DatagramType, error) +} + +/* PendingRequests */ + +type PendingRequests interface { + Add(ski string, counter model.MsgCounterType, maxDelay time.Duration) + SetData(ski string, counter model.MsgCounterType, data any) *model.ErrorType + SetResult(ski string, counter model.MsgCounterType, errorResult *model.ErrorType) *model.ErrorType + GetData(ski string, counter model.MsgCounterType) (any, *model.ErrorType) + Remove(ski string, counter model.MsgCounterType) *model.ErrorType +} + +/* Bindings */ + +// implemented by BindingManagerImpl +type BindingManager interface { + AddBinding(remoteDevice DeviceRemote, data model.BindingManagementRequestCallType) error + RemoveBinding(data model.BindingManagementDeleteCallType, remoteDevice DeviceRemote) error + RemoveBindingsForDevice(remoteDevice DeviceRemote) + RemoveBindingsForEntity(remoteEntity EntityRemote) + Bindings(remoteDevice DeviceRemote) []*BindingEntry + BindingsOnFeature(featureAddress model.FeatureAddressType) []*BindingEntry +} + +/* Subscription Manager */ + +type SubscriptionManager interface { + AddSubscription(remoteDevice DeviceRemote, data model.SubscriptionManagementRequestCallType) error + RemoveSubscription(data model.SubscriptionManagementDeleteCallType, remoteDevice DeviceRemote) error + RemoveSubscriptionsForDevice(remoteDevice DeviceRemote) + RemoveSubscriptionsForEntity(remoteEntity EntityRemote) + Subscriptions(remoteDevice DeviceRemote) []*SubscriptionEntry + SubscriptionsOnFeature(featureAddress model.FeatureAddressType) []*SubscriptionEntry +} + +/* Heartbeats */ + +type HeartbeatManager interface { + IsHeartbeatRunning() bool + UpdateHeartbeatOnSubscriptions() + SetLocalFeature(entity EntityLocal, feature FeatureLocal) + StartHeartbeat() error + StopHeartbeat() +} + +type Operations interface { + Write() bool + Read() bool + String() string + Information() *model.PossibleOperationsType +} diff --git a/api/binding.go b/api/binding.go new file mode 100644 index 0000000..14a41b6 --- /dev/null +++ b/api/binding.go @@ -0,0 +1,7 @@ +package api + +type BindingEntry struct { + Id uint64 + ServerFeature FeatureLocal + ClientFeature FeatureRemote +} diff --git a/api/events.go b/api/events.go new file mode 100644 index 0000000..f8cf236 --- /dev/null +++ b/api/events.go @@ -0,0 +1,39 @@ +package api + +import "github.com/enbility/spine-go/model" + +type EventHandlerLevel uint + +const ( + EventHandlerLevelCore EventHandlerLevel = iota // Shall only be used by the core stack + EventHandlerLevelApplication // Shall only be used by applications +) + +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 DeviceRemote // required for DetailedDiscovery Call + Entity EntityRemote // required for DetailedDiscovery Call and Notify + Feature FeatureRemote + CmdClassifier *model.CmdClassifierType // optional, used together with EventType EventTypeDataChange + Data any +} diff --git a/api/message.go b/api/message.go new file mode 100644 index 0000000..9ed68b3 --- /dev/null +++ b/api/message.go @@ -0,0 +1,23 @@ +package api + +import "github.com/enbility/spine-go/model" + +type Message struct { + RequestHeader *model.HeaderType + CmdClassifier model.CmdClassifierType + Cmd model.CmdType + FilterPartial *model.FilterType + FilterDelete *model.FilterType + FeatureRemote FeatureRemote + EntityRemote EntityRemote + DeviceRemote DeviceRemote +} + +type ResultMessage struct { + MsgCounterReference model.MsgCounterType // required + Result *model.ResultDataType // required, may not be nil + FeatureLocal FeatureLocal // required, may not be nil + FeatureRemote FeatureRemote // required, may not be nil + EntityRemote EntityRemote // required, may not be nil + DeviceRemote DeviceRemote // required, may not be nil +} diff --git a/api/subscription.go b/api/subscription.go new file mode 100644 index 0000000..bff2170 --- /dev/null +++ b/api/subscription.go @@ -0,0 +1,7 @@ +package api + +type SubscriptionEntry struct { + Id uint64 + ServerFeature FeatureLocal + ClientFeature FeatureRemote +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c7537f3 --- /dev/null +++ b/go.mod @@ -0,0 +1,23 @@ +module github.com/enbility/spine-go + +go 1.18 + +require ( + github.com/ahmetb/go-linq/v3 v3.2.0 + github.com/enbility/ship-go v0.0.0 + github.com/google/go-cmp v0.6.0 + github.com/hashicorp/golang-lru/v2 v2.0.7 + github.com/rickb777/date v1.20.5 + github.com/stretchr/testify v1.8.4 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rickb777/plural v1.4.1 // indirect + github.com/stretchr/objx v0.5.1 // indirect + golang.org/x/text v0.14.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/enbility/ship-go => ../ship-go diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2ab938a --- /dev/null +++ b/go.sum @@ -0,0 +1,34 @@ +github.com/ahmetb/go-linq/v3 v3.2.0 h1:BEuMfp+b59io8g5wYzNoFe9pWPalRklhlhbiU3hYZDE= +github.com/ahmetb/go-linq/v3 v3.2.0/go.mod h1:haQ3JfOeWK8HpVxMtHHEMPVgBKiYyQ+f1/kLZh/cj9U= +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/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +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.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/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/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= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +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= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integration_tests/devicediagnosis_test.go b/integration_tests/devicediagnosis_test.go new file mode 100644 index 0000000..b488e5e --- /dev/null +++ b/integration_tests/devicediagnosis_test.go @@ -0,0 +1,54 @@ +package integrationtests + +import ( + "testing" + + "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 ( + 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 api.DeviceLocal + + remoteSki string + + remoteDevice api.DeviceRemote + writeHandler *WriteMessageHandler +} + +func (s *DeviceDiagnosisSuite) BeforeTest(suiteName, testName string) { + s.sut, s.remoteSki, s.remoteDevice, s.writeHandler = beforeTest(suiteName, testName, 1, model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeServer) + + // f.AddFunctionType(model.FunctionTypeDeviceDiagnosisHeartbeatData, true, false) + + initialCommunication(s.T(), s.remoteDevice, s.writeHandler) +} + +func (s *DeviceDiagnosisSuite) TestHeartbeatSubscription_RecvNotify() { + // Act + msgCounter, _ := s.remoteDevice.HandleSpineMesssage(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 new file mode 100644 index 0000000..d909a02 --- /dev/null +++ b/integration_tests/electricalconnection_test.go @@ -0,0 +1,149 @@ +package integrationtests + +import ( + "testing" + + "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 ( + 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 api.DeviceLocal + + remoteSki string + + remoteDevice api.DeviceRemote + writeHandler *WriteMessageHandler +} + +func (s *ElectricalConnectionSuite) SetupSuite() { +} + +func (s *ElectricalConnectionSuite) BeforeTest(suiteName, testName string) { + s.sut, s.remoteSki, s.remoteDevice, s.writeHandler = beforeTest(suiteName, testName, 1, model.FeatureTypeTypeElectricalConnection, model.RoleTypeClient) + initialCommunication(s.T(), s.remoteDevice, s.writeHandler) +} + +func (s *ElectricalConnectionSuite) AfterTest(suiteName, testName string) { +} + +func (s *ElectricalConnectionSuite) TestDescriptionListData_RecvReply() { + // Act + msgCounter, _ := s.remoteDevice.HandleSpineMesssage(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.DataCopy(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.remoteDevice.HandleSpineMesssage(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.DataCopy(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.remoteDevice.HandleSpineMesssage(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.DataCopy(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/helper_test.go b/integration_tests/helper_test.go new file mode 100644 index 0000000..71abca8 --- /dev/null +++ b/integration_tests/helper_test.go @@ -0,0 +1,156 @@ +package integrationtests + +import ( + "encoding/json" + "fmt" + "os" + "sync" + "testing" + "time" + + shipapi "github.com/enbility/ship-go/api" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/spine" +) + +const ( + wallbox_detaileddiscoverydata_recv_reply_file_path = "../spine/testdata/wallbox_detaileddiscoverydata_recv_reply.json" + wallbox_detaileddiscoverydata_recv_notify_file_path = "../spine/testdata/wallbox_detaileddiscoverydata_recv_notify.json" +) + +type WriteMessageHandler struct { + sentMessages [][]byte + + mux sync.Mutex +} + +var _ shipapi.SpineDataConnection = (*WriteMessageHandler)(nil) + +func (t *WriteMessageHandler) WriteSpineMessage(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 beforeTest( + suiteName, testName string, fId uint, ftype model.FeatureTypeType, + frole model.RoleType) (api.DeviceLocal, string, api.DeviceRemote, *WriteMessageHandler) { + sut := spine.NewDeviceLocalImpl("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode", + "TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + 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{} + _ = sut.SetupRemoteDevice(remoteSki, writeHandler) + remoteDevice := sut.RemoteDeviceForSki(remoteSki) + + return sut, remoteSki, remoteDevice, writeHandler +} + +func initialCommunication(t *testing.T, remoteDevice api.DeviceRemote, writeHandler *WriteMessageHandler) { + // Initial generic communication + + _, _ = remoteDevice.HandleSpineMesssage(loadFileData(t, wallbox_detaileddiscoverydata_recv_reply_file_path)) + + // Act + 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) + if err != nil { + t.Fatal(err) + } + + return fileData +} + +func waitForAck(t *testing.T, msgCounterReference *model.MsgCounterType, writeHandler *WriteMessageHandler) { + var datagram model.Datagram + + msg := writeHandler.ResultWithReference(msgCounterReference) + if msg == nil { + t.Fatal("acknowledge message was not sent!!") + } + + if err := json.Unmarshal(msg, &datagram); err != nil { + t.Fatal(err) + } + + cmd := datagram.Datagram.Payload.Cmd[0] + if cmd.ResultData != nil { + if cmd.ResultData.ErrorNumber != nil && uint(*cmd.ResultData.ErrorNumber) != uint(model.ErrorNumberTypeNoError) { + t.Fatal(fmt.Errorf("error '%d' result data received", uint(*cmd.ResultData.ErrorNumber))) + } + } +} diff --git a/integration_tests/measurement_test.go b/integration_tests/measurement_test.go new file mode 100644 index 0000000..61532a0 --- /dev/null +++ b/integration_tests/measurement_test.go @@ -0,0 +1,164 @@ +package integrationtests + +import ( + "testing" + "time" + + "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_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 api.DeviceLocal + + remoteSki string + + remoteDevice api.DeviceRemote + writeHandler *WriteMessageHandler +} + +func (s *MeasurementSuite) SetupSuite() { +} + +func (s *MeasurementSuite) BeforeTest(suiteName, testName string) { + s.sut, s.remoteSki, s.remoteDevice, s.writeHandler = beforeTest(suiteName, testName, 2, model.FeatureTypeTypeMeasurement, model.RoleTypeClient) + initialCommunication(s.T(), s.remoteDevice, s.writeHandler) +} + +func (s *MeasurementSuite) AfterTest(suiteName, testName string) { +} + +func (s *MeasurementSuite) TestDescriptionList_Recv() { + // Act + msgCounter, _ := s.remoteDevice.HandleSpineMesssage(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.DataCopy(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.remoteDevice.HandleSpineMesssage(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.DataCopy(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.remoteDevice.HandleSpineMesssage(loadFileData(s.T(), m_descriptionListData_recv_reply_file_path)) + waitForAck(s.T(), msgCounter, s.writeHandler) + + // Act + msgCounter, _ = s.remoteDevice.HandleSpineMesssage(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.DataCopy(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.DataCopy(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/testdata/dd_subscriptionRequestCall_recv.json b/integration_tests/testdata/dd_subscriptionRequestCall_recv.json new file mode 100644 index 0000000..599641a --- /dev/null +++ b/integration_tests/testdata/dd_subscriptionRequestCall_recv.json @@ -0,0 +1,41 @@ +{ + "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 new file mode 100644 index 0000000..12e06b0 --- /dev/null +++ b/integration_tests/testdata/ec_descriptionListData_recv_reply.json @@ -0,0 +1,37 @@ +{ + "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_parameterDescriptionListData_recv_reply.json b/integration_tests/testdata/ec_parameterDescriptionListData_recv_reply.json new file mode 100644 index 0000000..ab1202d --- /dev/null +++ b/integration_tests/testdata/ec_parameterDescriptionListData_recv_reply.json @@ -0,0 +1,67 @@ +{ + "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": [ + { + "electricalConnectionParameterDescriptionListData": { + "electricalConnectionParameterDescriptionData": [ + { + "electricalConnectionId": 0, + "parameterId": 1, + "measurementId": 1, + "voltageType": "ac", + "acMeasuredPhases": "a", + "acMeasuredInReferenceTo": "neutral", + "acMeasurementType": "real", + "acMeasurementVariant": "rms" + }, + { + "electricalConnectionId": 0, + "parameterId": 2, + "measurementId": 4, + "voltageType": "ac", + "acMeasuredPhases": "a", + "acMeasuredInReferenceTo": "neutral", + "acMeasurementType": "real", + "acMeasurementVariant": "rms" + }, + { + "electricalConnectionId": 0, + "parameterId": 3, + "measurementId": 7, + "voltageType": "ac", + "acMeasuredPhases": "a", + "acMeasuredInReferenceTo": "neutral", + "acMeasurementType": "real", + "acMeasurementVariant": "rms" + }, + { + "electricalConnectionId": 0, + "parameterId": 8, + "acMeasuredPhases": "a", + "scopeType": "acPowerTotal" + } + ] + } + } + ] + } + } +} diff --git a/integration_tests/testdata/ec_permittedvaluesetlistdata_recv_notify_partial.json b/integration_tests/testdata/ec_permittedvaluesetlistdata_recv_notify_partial.json new file mode 100644 index 0000000..e7fe307 --- /dev/null +++ b/integration_tests/testdata/ec_permittedvaluesetlistdata_recv_notify_partial.json @@ -0,0 +1,98 @@ +{ + "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 new file mode 100644 index 0000000..8186803 --- /dev/null +++ b/integration_tests/testdata/ec_subscriptionRequestCall_recv_result.json @@ -0,0 +1,33 @@ +{ + "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/m_descriptionListData_recv_reply.json b/integration_tests/testdata/m_descriptionListData_recv_reply.json new file mode 100644 index 0000000..42c0e99 --- /dev/null +++ b/integration_tests/testdata/m_descriptionListData_recv_reply.json @@ -0,0 +1,52 @@ +{ + "datagram": { + "header": { + "specificationVersion": "1.1.1", + "addressSource": { + "device": "Wallbox", + "entity": [1,1], + "feature": 11 + }, + "addressDestination": { + "device": "HEMS", + "entity": [1], + "feature": 2 + }, + "msgCounter": 10, + "msgCounterReference": 10, + "cmdClassifier": "reply", + "ackRequest":true + }, + "payload": { + "cmd": [ + { + "measurementDescriptionListData": { + "measurementDescriptionData": [ + { + "measurementId": 1, + "measurementType": "current", + "commodityType": "electricity", + "unit": "A", + "scopeType": "acCurrent" + }, + { + "measurementId": 4, + "measurementType": "power", + "commodityType": "electricity", + "unit": "W", + "scopeType": "acPower" + }, + { + "measurementId": 7, + "measurementType": "energy", + "commodityType": "electricity", + "unit": "Wh", + "scopeType": "charge" + } + ] + } + } + ] + } + } +} diff --git a/integration_tests/testdata/m_measurementListData_recv_notify.json b/integration_tests/testdata/m_measurementListData_recv_notify.json new file mode 100644 index 0000000..423ce09 --- /dev/null +++ b/integration_tests/testdata/m_measurementListData_recv_notify.json @@ -0,0 +1,60 @@ +{ + "datagram": { + "header": { + "specificationVersion": "1.1.1", + "addressSource": { + "device": "Wallbox", + "entity": [1,1], + "feature": 11 + }, + "addressDestination": { + "device": "HEMS", + "entity": [1], + "feature": 2 + }, + "msgCounter": 10, + "cmdClassifier": "notify", + "ackRequest":true + }, + "payload": { + "cmd": [ + { + "measurementListData": { + "measurementData": [ + { + "measurementId": 1, + "valueType": "value", + "timestamp": "2022-11-19T15:21:50.003Z", + "value": { + "number": 5, + "scale": 0 + }, + "valueSource": "measuredValue" + }, + { + "measurementId": 4, + "valueType": "value", + "timestamp": "2022-11-19T15:21:50.003Z", + "value": { + "number": 1185, + "scale": 0 + }, + "valueSource": "measuredValue" + }, + { + "measurementId": 7, + "valueType": "value", + "timestamp": "2022-11-19T15:21:50.003Z", + "value": { + "number": 1825, + "scale": 0 + }, + "valueSource": "measuredValue" + } + ] + } + } + ] + } + } +} diff --git a/mocks/BindingManager.go b/mocks/BindingManager.go new file mode 100644 index 0000000..66fac6d --- /dev/null +++ b/mocks/BindingManager.go @@ -0,0 +1,293 @@ +// Code generated by mockery v2.40.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" +) + +// BindingManager is an autogenerated mock type for the BindingManager type +type BindingManager struct { + mock.Mock +} + +type BindingManager_Expecter struct { + mock *mock.Mock +} + +func (_m *BindingManager) EXPECT() *BindingManager_Expecter { + return &BindingManager_Expecter{mock: &_m.Mock} +} + +// AddBinding provides a mock function with given fields: remoteDevice, data +func (_m *BindingManager) AddBinding(remoteDevice api.DeviceRemote, data model.BindingManagementRequestCallType) error { + ret := _m.Called(remoteDevice, data) + + if len(ret) == 0 { + panic("no return value specified for AddBinding") + } + + var r0 error + if rf, ok := ret.Get(0).(func(api.DeviceRemote, model.BindingManagementRequestCallType) error); ok { + r0 = rf(remoteDevice, data) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// BindingManager_AddBinding_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddBinding' +type BindingManager_AddBinding_Call struct { + *mock.Call +} + +// AddBinding is a helper method to define mock.On call +// - remoteDevice api.DeviceRemote +// - data model.BindingManagementRequestCallType +func (_e *BindingManager_Expecter) AddBinding(remoteDevice interface{}, data interface{}) *BindingManager_AddBinding_Call { + return &BindingManager_AddBinding_Call{Call: _e.mock.On("AddBinding", remoteDevice, data)} +} + +func (_c *BindingManager_AddBinding_Call) Run(run func(remoteDevice api.DeviceRemote, data model.BindingManagementRequestCallType)) *BindingManager_AddBinding_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.DeviceRemote), args[1].(model.BindingManagementRequestCallType)) + }) + return _c +} + +func (_c *BindingManager_AddBinding_Call) Return(_a0 error) *BindingManager_AddBinding_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *BindingManager_AddBinding_Call) RunAndReturn(run func(api.DeviceRemote, model.BindingManagementRequestCallType) error) *BindingManager_AddBinding_Call { + _c.Call.Return(run) + return _c +} + +// Bindings provides a mock function with given fields: remoteDevice +func (_m *BindingManager) Bindings(remoteDevice api.DeviceRemote) []*api.BindingEntry { + ret := _m.Called(remoteDevice) + + if len(ret) == 0 { + panic("no return value specified for Bindings") + } + + var r0 []*api.BindingEntry + if rf, ok := ret.Get(0).(func(api.DeviceRemote) []*api.BindingEntry); ok { + r0 = rf(remoteDevice) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*api.BindingEntry) + } + } + + return r0 +} + +// BindingManager_Bindings_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Bindings' +type BindingManager_Bindings_Call struct { + *mock.Call +} + +// Bindings is a helper method to define mock.On call +// - remoteDevice api.DeviceRemote +func (_e *BindingManager_Expecter) Bindings(remoteDevice interface{}) *BindingManager_Bindings_Call { + return &BindingManager_Bindings_Call{Call: _e.mock.On("Bindings", remoteDevice)} +} + +func (_c *BindingManager_Bindings_Call) Run(run func(remoteDevice api.DeviceRemote)) *BindingManager_Bindings_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.DeviceRemote)) + }) + return _c +} + +func (_c *BindingManager_Bindings_Call) Return(_a0 []*api.BindingEntry) *BindingManager_Bindings_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *BindingManager_Bindings_Call) RunAndReturn(run func(api.DeviceRemote) []*api.BindingEntry) *BindingManager_Bindings_Call { + _c.Call.Return(run) + return _c +} + +// BindingsOnFeature provides a mock function with given fields: featureAddress +func (_m *BindingManager) BindingsOnFeature(featureAddress model.FeatureAddressType) []*api.BindingEntry { + ret := _m.Called(featureAddress) + + if len(ret) == 0 { + panic("no return value specified for BindingsOnFeature") + } + + var r0 []*api.BindingEntry + if rf, ok := ret.Get(0).(func(model.FeatureAddressType) []*api.BindingEntry); ok { + r0 = rf(featureAddress) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*api.BindingEntry) + } + } + + return r0 +} + +// BindingManager_BindingsOnFeature_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BindingsOnFeature' +type BindingManager_BindingsOnFeature_Call struct { + *mock.Call +} + +// BindingsOnFeature is a helper method to define mock.On call +// - featureAddress model.FeatureAddressType +func (_e *BindingManager_Expecter) BindingsOnFeature(featureAddress interface{}) *BindingManager_BindingsOnFeature_Call { + return &BindingManager_BindingsOnFeature_Call{Call: _e.mock.On("BindingsOnFeature", featureAddress)} +} + +func (_c *BindingManager_BindingsOnFeature_Call) Run(run func(featureAddress model.FeatureAddressType)) *BindingManager_BindingsOnFeature_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FeatureAddressType)) + }) + return _c +} + +func (_c *BindingManager_BindingsOnFeature_Call) Return(_a0 []*api.BindingEntry) *BindingManager_BindingsOnFeature_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *BindingManager_BindingsOnFeature_Call) RunAndReturn(run func(model.FeatureAddressType) []*api.BindingEntry) *BindingManager_BindingsOnFeature_Call { + _c.Call.Return(run) + return _c +} + +// RemoveBinding provides a mock function with given fields: data, remoteDevice +func (_m *BindingManager) RemoveBinding(data model.BindingManagementDeleteCallType, remoteDevice api.DeviceRemote) error { + ret := _m.Called(data, remoteDevice) + + if len(ret) == 0 { + panic("no return value specified for RemoveBinding") + } + + var r0 error + if rf, ok := ret.Get(0).(func(model.BindingManagementDeleteCallType, api.DeviceRemote) error); ok { + r0 = rf(data, remoteDevice) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// BindingManager_RemoveBinding_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveBinding' +type BindingManager_RemoveBinding_Call struct { + *mock.Call +} + +// RemoveBinding is a helper method to define mock.On call +// - data model.BindingManagementDeleteCallType +// - remoteDevice api.DeviceRemote +func (_e *BindingManager_Expecter) RemoveBinding(data interface{}, remoteDevice interface{}) *BindingManager_RemoveBinding_Call { + return &BindingManager_RemoveBinding_Call{Call: _e.mock.On("RemoveBinding", data, remoteDevice)} +} + +func (_c *BindingManager_RemoveBinding_Call) Run(run func(data model.BindingManagementDeleteCallType, remoteDevice api.DeviceRemote)) *BindingManager_RemoveBinding_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.BindingManagementDeleteCallType), args[1].(api.DeviceRemote)) + }) + return _c +} + +func (_c *BindingManager_RemoveBinding_Call) Return(_a0 error) *BindingManager_RemoveBinding_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *BindingManager_RemoveBinding_Call) RunAndReturn(run func(model.BindingManagementDeleteCallType, api.DeviceRemote) error) *BindingManager_RemoveBinding_Call { + _c.Call.Return(run) + return _c +} + +// RemoveBindingsForDevice provides a mock function with given fields: remoteDevice +func (_m *BindingManager) RemoveBindingsForDevice(remoteDevice api.DeviceRemote) { + _m.Called(remoteDevice) +} + +// BindingManager_RemoveBindingsForDevice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveBindingsForDevice' +type BindingManager_RemoveBindingsForDevice_Call struct { + *mock.Call +} + +// RemoveBindingsForDevice is a helper method to define mock.On call +// - remoteDevice api.DeviceRemote +func (_e *BindingManager_Expecter) RemoveBindingsForDevice(remoteDevice interface{}) *BindingManager_RemoveBindingsForDevice_Call { + return &BindingManager_RemoveBindingsForDevice_Call{Call: _e.mock.On("RemoveBindingsForDevice", remoteDevice)} +} + +func (_c *BindingManager_RemoveBindingsForDevice_Call) Run(run func(remoteDevice api.DeviceRemote)) *BindingManager_RemoveBindingsForDevice_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.DeviceRemote)) + }) + return _c +} + +func (_c *BindingManager_RemoveBindingsForDevice_Call) Return() *BindingManager_RemoveBindingsForDevice_Call { + _c.Call.Return() + return _c +} + +func (_c *BindingManager_RemoveBindingsForDevice_Call) RunAndReturn(run func(api.DeviceRemote)) *BindingManager_RemoveBindingsForDevice_Call { + _c.Call.Return(run) + return _c +} + +// RemoveBindingsForEntity provides a mock function with given fields: remoteEntity +func (_m *BindingManager) RemoveBindingsForEntity(remoteEntity api.EntityRemote) { + _m.Called(remoteEntity) +} + +// BindingManager_RemoveBindingsForEntity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveBindingsForEntity' +type BindingManager_RemoveBindingsForEntity_Call struct { + *mock.Call +} + +// RemoveBindingsForEntity is a helper method to define mock.On call +// - remoteEntity api.EntityRemote +func (_e *BindingManager_Expecter) RemoveBindingsForEntity(remoteEntity interface{}) *BindingManager_RemoveBindingsForEntity_Call { + return &BindingManager_RemoveBindingsForEntity_Call{Call: _e.mock.On("RemoveBindingsForEntity", remoteEntity)} +} + +func (_c *BindingManager_RemoveBindingsForEntity_Call) Run(run func(remoteEntity api.EntityRemote)) *BindingManager_RemoveBindingsForEntity_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.EntityRemote)) + }) + return _c +} + +func (_c *BindingManager_RemoveBindingsForEntity_Call) Return() *BindingManager_RemoveBindingsForEntity_Call { + _c.Call.Return() + return _c +} + +func (_c *BindingManager_RemoveBindingsForEntity_Call) RunAndReturn(run func(api.EntityRemote)) *BindingManager_RemoveBindingsForEntity_Call { + _c.Call.Return(run) + return _c +} + +// NewBindingManager creates a new instance of BindingManager. 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 NewBindingManager(t interface { + mock.TestingT + Cleanup(func()) +}) *BindingManager { + mock := &BindingManager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/ComControl.go b/mocks/ComControl.go new file mode 100644 index 0000000..811d72e --- /dev/null +++ b/mocks/ComControl.go @@ -0,0 +1,81 @@ +// Code generated by mockery v2.40.1. DO NOT EDIT. + +package mocks + +import ( + model "github.com/enbility/spine-go/model" + mock "github.com/stretchr/testify/mock" +) + +// ComControl is an autogenerated mock type for the ComControl type +type ComControl struct { + mock.Mock +} + +type ComControl_Expecter struct { + mock *mock.Mock +} + +func (_m *ComControl) EXPECT() *ComControl_Expecter { + return &ComControl_Expecter{mock: &_m.Mock} +} + +// SendSpineMessage provides a mock function with given fields: datagram +func (_m *ComControl) SendSpineMessage(datagram model.DatagramType) error { + ret := _m.Called(datagram) + + if len(ret) == 0 { + panic("no return value specified for SendSpineMessage") + } + + var r0 error + if rf, ok := ret.Get(0).(func(model.DatagramType) error); ok { + r0 = rf(datagram) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ComControl_SendSpineMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendSpineMessage' +type ComControl_SendSpineMessage_Call struct { + *mock.Call +} + +// SendSpineMessage is a helper method to define mock.On call +// - datagram model.DatagramType +func (_e *ComControl_Expecter) SendSpineMessage(datagram interface{}) *ComControl_SendSpineMessage_Call { + return &ComControl_SendSpineMessage_Call{Call: _e.mock.On("SendSpineMessage", datagram)} +} + +func (_c *ComControl_SendSpineMessage_Call) Run(run func(datagram model.DatagramType)) *ComControl_SendSpineMessage_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.DatagramType)) + }) + return _c +} + +func (_c *ComControl_SendSpineMessage_Call) Return(_a0 error) *ComControl_SendSpineMessage_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ComControl_SendSpineMessage_Call) RunAndReturn(run func(model.DatagramType) error) *ComControl_SendSpineMessage_Call { + _c.Call.Return(run) + return _c +} + +// NewComControl creates a new instance of ComControl. 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 NewComControl(t interface { + mock.TestingT + Cleanup(func()) +}) *ComControl { + mock := &ComControl{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/Device.go b/mocks/Device.go new file mode 100644 index 0000000..e0757a7 --- /dev/null +++ b/mocks/Device.go @@ -0,0 +1,221 @@ +// Code generated by mockery v2.40.1. DO NOT EDIT. + +package mocks + +import ( + model "github.com/enbility/spine-go/model" + mock "github.com/stretchr/testify/mock" +) + +// Device is an autogenerated mock type for the Device type +type Device struct { + mock.Mock +} + +type Device_Expecter struct { + mock *mock.Mock +} + +func (_m *Device) EXPECT() *Device_Expecter { + return &Device_Expecter{mock: &_m.Mock} +} + +// Address provides a mock function with given fields: +func (_m *Device) Address() *model.AddressDeviceType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Address") + } + + var r0 *model.AddressDeviceType + if rf, ok := ret.Get(0).(func() *model.AddressDeviceType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.AddressDeviceType) + } + } + + return r0 +} + +// Device_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address' +type Device_Address_Call struct { + *mock.Call +} + +// Address is a helper method to define mock.On call +func (_e *Device_Expecter) Address() *Device_Address_Call { + return &Device_Address_Call{Call: _e.mock.On("Address")} +} + +func (_c *Device_Address_Call) Run(run func()) *Device_Address_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Device_Address_Call) Return(_a0 *model.AddressDeviceType) *Device_Address_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Device_Address_Call) RunAndReturn(run func() *model.AddressDeviceType) *Device_Address_Call { + _c.Call.Return(run) + return _c +} + +// DestinationData provides a mock function with given fields: +func (_m *Device) DestinationData() model.NodeManagementDestinationDataType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DestinationData") + } + + var r0 model.NodeManagementDestinationDataType + if rf, ok := ret.Get(0).(func() model.NodeManagementDestinationDataType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.NodeManagementDestinationDataType) + } + + return r0 +} + +// Device_DestinationData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DestinationData' +type Device_DestinationData_Call struct { + *mock.Call +} + +// DestinationData is a helper method to define mock.On call +func (_e *Device_Expecter) DestinationData() *Device_DestinationData_Call { + return &Device_DestinationData_Call{Call: _e.mock.On("DestinationData")} +} + +func (_c *Device_DestinationData_Call) Run(run func()) *Device_DestinationData_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Device_DestinationData_Call) Return(_a0 model.NodeManagementDestinationDataType) *Device_DestinationData_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Device_DestinationData_Call) RunAndReturn(run func() model.NodeManagementDestinationDataType) *Device_DestinationData_Call { + _c.Call.Return(run) + return _c +} + +// DeviceType provides a mock function with given fields: +func (_m *Device) DeviceType() *model.DeviceTypeType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DeviceType") + } + + var r0 *model.DeviceTypeType + if rf, ok := ret.Get(0).(func() *model.DeviceTypeType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.DeviceTypeType) + } + } + + return r0 +} + +// Device_DeviceType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeviceType' +type Device_DeviceType_Call struct { + *mock.Call +} + +// DeviceType is a helper method to define mock.On call +func (_e *Device_Expecter) DeviceType() *Device_DeviceType_Call { + return &Device_DeviceType_Call{Call: _e.mock.On("DeviceType")} +} + +func (_c *Device_DeviceType_Call) Run(run func()) *Device_DeviceType_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Device_DeviceType_Call) Return(_a0 *model.DeviceTypeType) *Device_DeviceType_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Device_DeviceType_Call) RunAndReturn(run func() *model.DeviceTypeType) *Device_DeviceType_Call { + _c.Call.Return(run) + return _c +} + +// FeatureSet provides a mock function with given fields: +func (_m *Device) FeatureSet() *model.NetworkManagementFeatureSetType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for FeatureSet") + } + + var r0 *model.NetworkManagementFeatureSetType + if rf, ok := ret.Get(0).(func() *model.NetworkManagementFeatureSetType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.NetworkManagementFeatureSetType) + } + } + + return r0 +} + +// Device_FeatureSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FeatureSet' +type Device_FeatureSet_Call struct { + *mock.Call +} + +// FeatureSet is a helper method to define mock.On call +func (_e *Device_Expecter) FeatureSet() *Device_FeatureSet_Call { + return &Device_FeatureSet_Call{Call: _e.mock.On("FeatureSet")} +} + +func (_c *Device_FeatureSet_Call) Run(run func()) *Device_FeatureSet_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Device_FeatureSet_Call) Return(_a0 *model.NetworkManagementFeatureSetType) *Device_FeatureSet_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Device_FeatureSet_Call) RunAndReturn(run func() *model.NetworkManagementFeatureSetType) *Device_FeatureSet_Call { + _c.Call.Return(run) + return _c +} + +// NewDevice creates a new instance of Device. 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 NewDevice(t interface { + mock.TestingT + Cleanup(func()) +}) *Device { + mock := &Device{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/DeviceLocal.go b/mocks/DeviceLocal.go new file mode 100644 index 0000000..49824ff --- /dev/null +++ b/mocks/DeviceLocal.go @@ -0,0 +1,1090 @@ +// Code generated by mockery v2.40.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" + + ship_goapi "github.com/enbility/ship-go/api" +) + +// DeviceLocal is an autogenerated mock type for the DeviceLocal type +type DeviceLocal struct { + mock.Mock +} + +type DeviceLocal_Expecter struct { + mock *mock.Mock +} + +func (_m *DeviceLocal) EXPECT() *DeviceLocal_Expecter { + return &DeviceLocal_Expecter{mock: &_m.Mock} +} + +// AddEntity provides a mock function with given fields: entity +func (_m *DeviceLocal) AddEntity(entity api.EntityLocal) { + _m.Called(entity) +} + +// DeviceLocal_AddEntity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddEntity' +type DeviceLocal_AddEntity_Call struct { + *mock.Call +} + +// AddEntity is a helper method to define mock.On call +// - entity api.EntityLocal +func (_e *DeviceLocal_Expecter) AddEntity(entity interface{}) *DeviceLocal_AddEntity_Call { + return &DeviceLocal_AddEntity_Call{Call: _e.mock.On("AddEntity", entity)} +} + +func (_c *DeviceLocal_AddEntity_Call) Run(run func(entity api.EntityLocal)) *DeviceLocal_AddEntity_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.EntityLocal)) + }) + return _c +} + +func (_c *DeviceLocal_AddEntity_Call) Return() *DeviceLocal_AddEntity_Call { + _c.Call.Return() + return _c +} + +func (_c *DeviceLocal_AddEntity_Call) RunAndReturn(run func(api.EntityLocal)) *DeviceLocal_AddEntity_Call { + _c.Call.Return(run) + return _c +} + +// AddRemoteDeviceForSki provides a mock function with given fields: ski, rDevice +func (_m *DeviceLocal) AddRemoteDeviceForSki(ski string, rDevice api.DeviceRemote) { + _m.Called(ski, rDevice) +} + +// DeviceLocal_AddRemoteDeviceForSki_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddRemoteDeviceForSki' +type DeviceLocal_AddRemoteDeviceForSki_Call struct { + *mock.Call +} + +// AddRemoteDeviceForSki is a helper method to define mock.On call +// - ski string +// - rDevice api.DeviceRemote +func (_e *DeviceLocal_Expecter) AddRemoteDeviceForSki(ski interface{}, rDevice interface{}) *DeviceLocal_AddRemoteDeviceForSki_Call { + return &DeviceLocal_AddRemoteDeviceForSki_Call{Call: _e.mock.On("AddRemoteDeviceForSki", ski, rDevice)} +} + +func (_c *DeviceLocal_AddRemoteDeviceForSki_Call) Run(run func(ski string, rDevice api.DeviceRemote)) *DeviceLocal_AddRemoteDeviceForSki_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(api.DeviceRemote)) + }) + return _c +} + +func (_c *DeviceLocal_AddRemoteDeviceForSki_Call) Return() *DeviceLocal_AddRemoteDeviceForSki_Call { + _c.Call.Return() + return _c +} + +func (_c *DeviceLocal_AddRemoteDeviceForSki_Call) RunAndReturn(run func(string, api.DeviceRemote)) *DeviceLocal_AddRemoteDeviceForSki_Call { + _c.Call.Return(run) + return _c +} + +// Address provides a mock function with given fields: +func (_m *DeviceLocal) Address() *model.AddressDeviceType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Address") + } + + var r0 *model.AddressDeviceType + if rf, ok := ret.Get(0).(func() *model.AddressDeviceType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.AddressDeviceType) + } + } + + return r0 +} + +// DeviceLocal_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address' +type DeviceLocal_Address_Call struct { + *mock.Call +} + +// Address is a helper method to define mock.On call +func (_e *DeviceLocal_Expecter) Address() *DeviceLocal_Address_Call { + return &DeviceLocal_Address_Call{Call: _e.mock.On("Address")} +} + +func (_c *DeviceLocal_Address_Call) Run(run func()) *DeviceLocal_Address_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceLocal_Address_Call) Return(_a0 *model.AddressDeviceType) *DeviceLocal_Address_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_Address_Call) RunAndReturn(run func() *model.AddressDeviceType) *DeviceLocal_Address_Call { + _c.Call.Return(run) + return _c +} + +// BindingManager provides a mock function with given fields: +func (_m *DeviceLocal) BindingManager() api.BindingManager { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for BindingManager") + } + + var r0 api.BindingManager + if rf, ok := ret.Get(0).(func() api.BindingManager); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.BindingManager) + } + } + + return r0 +} + +// DeviceLocal_BindingManager_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BindingManager' +type DeviceLocal_BindingManager_Call struct { + *mock.Call +} + +// BindingManager is a helper method to define mock.On call +func (_e *DeviceLocal_Expecter) BindingManager() *DeviceLocal_BindingManager_Call { + return &DeviceLocal_BindingManager_Call{Call: _e.mock.On("BindingManager")} +} + +func (_c *DeviceLocal_BindingManager_Call) Run(run func()) *DeviceLocal_BindingManager_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceLocal_BindingManager_Call) Return(_a0 api.BindingManager) *DeviceLocal_BindingManager_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_BindingManager_Call) RunAndReturn(run func() api.BindingManager) *DeviceLocal_BindingManager_Call { + _c.Call.Return(run) + return _c +} + +// DestinationData provides a mock function with given fields: +func (_m *DeviceLocal) DestinationData() model.NodeManagementDestinationDataType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DestinationData") + } + + var r0 model.NodeManagementDestinationDataType + if rf, ok := ret.Get(0).(func() model.NodeManagementDestinationDataType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.NodeManagementDestinationDataType) + } + + return r0 +} + +// DeviceLocal_DestinationData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DestinationData' +type DeviceLocal_DestinationData_Call struct { + *mock.Call +} + +// DestinationData is a helper method to define mock.On call +func (_e *DeviceLocal_Expecter) DestinationData() *DeviceLocal_DestinationData_Call { + return &DeviceLocal_DestinationData_Call{Call: _e.mock.On("DestinationData")} +} + +func (_c *DeviceLocal_DestinationData_Call) Run(run func()) *DeviceLocal_DestinationData_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceLocal_DestinationData_Call) Return(_a0 model.NodeManagementDestinationDataType) *DeviceLocal_DestinationData_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_DestinationData_Call) RunAndReturn(run func() model.NodeManagementDestinationDataType) *DeviceLocal_DestinationData_Call { + _c.Call.Return(run) + return _c +} + +// DeviceType provides a mock function with given fields: +func (_m *DeviceLocal) DeviceType() *model.DeviceTypeType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DeviceType") + } + + var r0 *model.DeviceTypeType + if rf, ok := ret.Get(0).(func() *model.DeviceTypeType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.DeviceTypeType) + } + } + + return r0 +} + +// DeviceLocal_DeviceType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeviceType' +type DeviceLocal_DeviceType_Call struct { + *mock.Call +} + +// DeviceType is a helper method to define mock.On call +func (_e *DeviceLocal_Expecter) DeviceType() *DeviceLocal_DeviceType_Call { + return &DeviceLocal_DeviceType_Call{Call: _e.mock.On("DeviceType")} +} + +func (_c *DeviceLocal_DeviceType_Call) Run(run func()) *DeviceLocal_DeviceType_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceLocal_DeviceType_Call) Return(_a0 *model.DeviceTypeType) *DeviceLocal_DeviceType_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_DeviceType_Call) RunAndReturn(run func() *model.DeviceTypeType) *DeviceLocal_DeviceType_Call { + _c.Call.Return(run) + return _c +} + +// Entities provides a mock function with given fields: +func (_m *DeviceLocal) Entities() []api.EntityLocal { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Entities") + } + + var r0 []api.EntityLocal + if rf, ok := ret.Get(0).(func() []api.EntityLocal); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]api.EntityLocal) + } + } + + return r0 +} + +// DeviceLocal_Entities_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Entities' +type DeviceLocal_Entities_Call struct { + *mock.Call +} + +// Entities is a helper method to define mock.On call +func (_e *DeviceLocal_Expecter) Entities() *DeviceLocal_Entities_Call { + return &DeviceLocal_Entities_Call{Call: _e.mock.On("Entities")} +} + +func (_c *DeviceLocal_Entities_Call) Run(run func()) *DeviceLocal_Entities_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceLocal_Entities_Call) Return(_a0 []api.EntityLocal) *DeviceLocal_Entities_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_Entities_Call) RunAndReturn(run func() []api.EntityLocal) *DeviceLocal_Entities_Call { + _c.Call.Return(run) + return _c +} + +// Entity provides a mock function with given fields: id +func (_m *DeviceLocal) Entity(id []model.AddressEntityType) api.EntityLocal { + ret := _m.Called(id) + + if len(ret) == 0 { + panic("no return value specified for Entity") + } + + var r0 api.EntityLocal + if rf, ok := ret.Get(0).(func([]model.AddressEntityType) api.EntityLocal); ok { + r0 = rf(id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.EntityLocal) + } + } + + return r0 +} + +// DeviceLocal_Entity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Entity' +type DeviceLocal_Entity_Call struct { + *mock.Call +} + +// Entity is a helper method to define mock.On call +// - id []model.AddressEntityType +func (_e *DeviceLocal_Expecter) Entity(id interface{}) *DeviceLocal_Entity_Call { + return &DeviceLocal_Entity_Call{Call: _e.mock.On("Entity", id)} +} + +func (_c *DeviceLocal_Entity_Call) Run(run func(id []model.AddressEntityType)) *DeviceLocal_Entity_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]model.AddressEntityType)) + }) + return _c +} + +func (_c *DeviceLocal_Entity_Call) Return(_a0 api.EntityLocal) *DeviceLocal_Entity_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_Entity_Call) RunAndReturn(run func([]model.AddressEntityType) api.EntityLocal) *DeviceLocal_Entity_Call { + _c.Call.Return(run) + return _c +} + +// EntityForType provides a mock function with given fields: entityType +func (_m *DeviceLocal) EntityForType(entityType model.EntityTypeType) api.EntityLocal { + ret := _m.Called(entityType) + + if len(ret) == 0 { + panic("no return value specified for EntityForType") + } + + var r0 api.EntityLocal + if rf, ok := ret.Get(0).(func(model.EntityTypeType) api.EntityLocal); ok { + r0 = rf(entityType) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.EntityLocal) + } + } + + return r0 +} + +// DeviceLocal_EntityForType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EntityForType' +type DeviceLocal_EntityForType_Call struct { + *mock.Call +} + +// EntityForType is a helper method to define mock.On call +// - entityType model.EntityTypeType +func (_e *DeviceLocal_Expecter) EntityForType(entityType interface{}) *DeviceLocal_EntityForType_Call { + return &DeviceLocal_EntityForType_Call{Call: _e.mock.On("EntityForType", entityType)} +} + +func (_c *DeviceLocal_EntityForType_Call) Run(run func(entityType model.EntityTypeType)) *DeviceLocal_EntityForType_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.EntityTypeType)) + }) + return _c +} + +func (_c *DeviceLocal_EntityForType_Call) Return(_a0 api.EntityLocal) *DeviceLocal_EntityForType_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_EntityForType_Call) RunAndReturn(run func(model.EntityTypeType) api.EntityLocal) *DeviceLocal_EntityForType_Call { + _c.Call.Return(run) + return _c +} + +// FeatureByAddress provides a mock function with given fields: address +func (_m *DeviceLocal) FeatureByAddress(address *model.FeatureAddressType) api.FeatureLocal { + ret := _m.Called(address) + + if len(ret) == 0 { + panic("no return value specified for FeatureByAddress") + } + + var r0 api.FeatureLocal + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType) api.FeatureLocal); ok { + r0 = rf(address) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.FeatureLocal) + } + } + + return r0 +} + +// DeviceLocal_FeatureByAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FeatureByAddress' +type DeviceLocal_FeatureByAddress_Call struct { + *mock.Call +} + +// FeatureByAddress is a helper method to define mock.On call +// - address *model.FeatureAddressType +func (_e *DeviceLocal_Expecter) FeatureByAddress(address interface{}) *DeviceLocal_FeatureByAddress_Call { + return &DeviceLocal_FeatureByAddress_Call{Call: _e.mock.On("FeatureByAddress", address)} +} + +func (_c *DeviceLocal_FeatureByAddress_Call) Run(run func(address *model.FeatureAddressType)) *DeviceLocal_FeatureByAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *DeviceLocal_FeatureByAddress_Call) Return(_a0 api.FeatureLocal) *DeviceLocal_FeatureByAddress_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_FeatureByAddress_Call) RunAndReturn(run func(*model.FeatureAddressType) api.FeatureLocal) *DeviceLocal_FeatureByAddress_Call { + _c.Call.Return(run) + return _c +} + +// FeatureSet provides a mock function with given fields: +func (_m *DeviceLocal) FeatureSet() *model.NetworkManagementFeatureSetType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for FeatureSet") + } + + var r0 *model.NetworkManagementFeatureSetType + if rf, ok := ret.Get(0).(func() *model.NetworkManagementFeatureSetType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.NetworkManagementFeatureSetType) + } + } + + return r0 +} + +// DeviceLocal_FeatureSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FeatureSet' +type DeviceLocal_FeatureSet_Call struct { + *mock.Call +} + +// FeatureSet is a helper method to define mock.On call +func (_e *DeviceLocal_Expecter) FeatureSet() *DeviceLocal_FeatureSet_Call { + return &DeviceLocal_FeatureSet_Call{Call: _e.mock.On("FeatureSet")} +} + +func (_c *DeviceLocal_FeatureSet_Call) Run(run func()) *DeviceLocal_FeatureSet_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceLocal_FeatureSet_Call) Return(_a0 *model.NetworkManagementFeatureSetType) *DeviceLocal_FeatureSet_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_FeatureSet_Call) RunAndReturn(run func() *model.NetworkManagementFeatureSetType) *DeviceLocal_FeatureSet_Call { + _c.Call.Return(run) + return _c +} + +// HeartbeatManager provides a mock function with given fields: +func (_m *DeviceLocal) HeartbeatManager() api.HeartbeatManager { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for HeartbeatManager") + } + + var r0 api.HeartbeatManager + if rf, ok := ret.Get(0).(func() api.HeartbeatManager); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.HeartbeatManager) + } + } + + return r0 +} + +// DeviceLocal_HeartbeatManager_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HeartbeatManager' +type DeviceLocal_HeartbeatManager_Call struct { + *mock.Call +} + +// HeartbeatManager is a helper method to define mock.On call +func (_e *DeviceLocal_Expecter) HeartbeatManager() *DeviceLocal_HeartbeatManager_Call { + return &DeviceLocal_HeartbeatManager_Call{Call: _e.mock.On("HeartbeatManager")} +} + +func (_c *DeviceLocal_HeartbeatManager_Call) Run(run func()) *DeviceLocal_HeartbeatManager_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceLocal_HeartbeatManager_Call) Return(_a0 api.HeartbeatManager) *DeviceLocal_HeartbeatManager_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_HeartbeatManager_Call) RunAndReturn(run func() api.HeartbeatManager) *DeviceLocal_HeartbeatManager_Call { + _c.Call.Return(run) + return _c +} + +// Information provides a mock function with given fields: +func (_m *DeviceLocal) Information() *model.NodeManagementDetailedDiscoveryDeviceInformationType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Information") + } + + var r0 *model.NodeManagementDetailedDiscoveryDeviceInformationType + if rf, ok := ret.Get(0).(func() *model.NodeManagementDetailedDiscoveryDeviceInformationType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.NodeManagementDetailedDiscoveryDeviceInformationType) + } + } + + return r0 +} + +// DeviceLocal_Information_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Information' +type DeviceLocal_Information_Call struct { + *mock.Call +} + +// Information is a helper method to define mock.On call +func (_e *DeviceLocal_Expecter) Information() *DeviceLocal_Information_Call { + return &DeviceLocal_Information_Call{Call: _e.mock.On("Information")} +} + +func (_c *DeviceLocal_Information_Call) Run(run func()) *DeviceLocal_Information_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceLocal_Information_Call) Return(_a0 *model.NodeManagementDetailedDiscoveryDeviceInformationType) *DeviceLocal_Information_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_Information_Call) RunAndReturn(run func() *model.NodeManagementDetailedDiscoveryDeviceInformationType) *DeviceLocal_Information_Call { + _c.Call.Return(run) + return _c +} + +// NodeManagement provides a mock function with given fields: +func (_m *DeviceLocal) NodeManagement() api.NodeManagement { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for NodeManagement") + } + + var r0 api.NodeManagement + if rf, ok := ret.Get(0).(func() api.NodeManagement); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.NodeManagement) + } + } + + return r0 +} + +// DeviceLocal_NodeManagement_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NodeManagement' +type DeviceLocal_NodeManagement_Call struct { + *mock.Call +} + +// NodeManagement is a helper method to define mock.On call +func (_e *DeviceLocal_Expecter) NodeManagement() *DeviceLocal_NodeManagement_Call { + return &DeviceLocal_NodeManagement_Call{Call: _e.mock.On("NodeManagement")} +} + +func (_c *DeviceLocal_NodeManagement_Call) Run(run func()) *DeviceLocal_NodeManagement_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceLocal_NodeManagement_Call) Return(_a0 api.NodeManagement) *DeviceLocal_NodeManagement_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_NodeManagement_Call) RunAndReturn(run func() api.NodeManagement) *DeviceLocal_NodeManagement_Call { + _c.Call.Return(run) + return _c +} + +// NotifySubscribers provides a mock function with given fields: featureAddress, cmd +func (_m *DeviceLocal) NotifySubscribers(featureAddress *model.FeatureAddressType, cmd model.CmdType) { + _m.Called(featureAddress, cmd) +} + +// DeviceLocal_NotifySubscribers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NotifySubscribers' +type DeviceLocal_NotifySubscribers_Call struct { + *mock.Call +} + +// NotifySubscribers is a helper method to define mock.On call +// - featureAddress *model.FeatureAddressType +// - cmd model.CmdType +func (_e *DeviceLocal_Expecter) NotifySubscribers(featureAddress interface{}, cmd interface{}) *DeviceLocal_NotifySubscribers_Call { + return &DeviceLocal_NotifySubscribers_Call{Call: _e.mock.On("NotifySubscribers", featureAddress, cmd)} +} + +func (_c *DeviceLocal_NotifySubscribers_Call) Run(run func(featureAddress *model.FeatureAddressType, cmd model.CmdType)) *DeviceLocal_NotifySubscribers_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType), args[1].(model.CmdType)) + }) + return _c +} + +func (_c *DeviceLocal_NotifySubscribers_Call) Return() *DeviceLocal_NotifySubscribers_Call { + _c.Call.Return() + return _c +} + +func (_c *DeviceLocal_NotifySubscribers_Call) RunAndReturn(run func(*model.FeatureAddressType, model.CmdType)) *DeviceLocal_NotifySubscribers_Call { + _c.Call.Return(run) + return _c +} + +// ProcessCmd provides a mock function with given fields: datagram, remoteDevice +func (_m *DeviceLocal) ProcessCmd(datagram model.DatagramType, remoteDevice api.DeviceRemote) error { + ret := _m.Called(datagram, remoteDevice) + + if len(ret) == 0 { + panic("no return value specified for ProcessCmd") + } + + var r0 error + if rf, ok := ret.Get(0).(func(model.DatagramType, api.DeviceRemote) error); ok { + r0 = rf(datagram, remoteDevice) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeviceLocal_ProcessCmd_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ProcessCmd' +type DeviceLocal_ProcessCmd_Call struct { + *mock.Call +} + +// ProcessCmd is a helper method to define mock.On call +// - datagram model.DatagramType +// - remoteDevice api.DeviceRemote +func (_e *DeviceLocal_Expecter) ProcessCmd(datagram interface{}, remoteDevice interface{}) *DeviceLocal_ProcessCmd_Call { + return &DeviceLocal_ProcessCmd_Call{Call: _e.mock.On("ProcessCmd", datagram, remoteDevice)} +} + +func (_c *DeviceLocal_ProcessCmd_Call) Run(run func(datagram model.DatagramType, remoteDevice api.DeviceRemote)) *DeviceLocal_ProcessCmd_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.DatagramType), args[1].(api.DeviceRemote)) + }) + return _c +} + +func (_c *DeviceLocal_ProcessCmd_Call) Return(_a0 error) *DeviceLocal_ProcessCmd_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_ProcessCmd_Call) RunAndReturn(run func(model.DatagramType, api.DeviceRemote) error) *DeviceLocal_ProcessCmd_Call { + _c.Call.Return(run) + return _c +} + +// RemoteDeviceForAddress provides a mock function with given fields: address +func (_m *DeviceLocal) RemoteDeviceForAddress(address model.AddressDeviceType) api.DeviceRemote { + ret := _m.Called(address) + + if len(ret) == 0 { + panic("no return value specified for RemoteDeviceForAddress") + } + + var r0 api.DeviceRemote + if rf, ok := ret.Get(0).(func(model.AddressDeviceType) api.DeviceRemote); ok { + r0 = rf(address) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.DeviceRemote) + } + } + + return r0 +} + +// DeviceLocal_RemoteDeviceForAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteDeviceForAddress' +type DeviceLocal_RemoteDeviceForAddress_Call struct { + *mock.Call +} + +// RemoteDeviceForAddress is a helper method to define mock.On call +// - address model.AddressDeviceType +func (_e *DeviceLocal_Expecter) RemoteDeviceForAddress(address interface{}) *DeviceLocal_RemoteDeviceForAddress_Call { + return &DeviceLocal_RemoteDeviceForAddress_Call{Call: _e.mock.On("RemoteDeviceForAddress", address)} +} + +func (_c *DeviceLocal_RemoteDeviceForAddress_Call) Run(run func(address model.AddressDeviceType)) *DeviceLocal_RemoteDeviceForAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.AddressDeviceType)) + }) + return _c +} + +func (_c *DeviceLocal_RemoteDeviceForAddress_Call) Return(_a0 api.DeviceRemote) *DeviceLocal_RemoteDeviceForAddress_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_RemoteDeviceForAddress_Call) RunAndReturn(run func(model.AddressDeviceType) api.DeviceRemote) *DeviceLocal_RemoteDeviceForAddress_Call { + _c.Call.Return(run) + return _c +} + +// RemoteDeviceForSki provides a mock function with given fields: ski +func (_m *DeviceLocal) RemoteDeviceForSki(ski string) api.DeviceRemote { + ret := _m.Called(ski) + + if len(ret) == 0 { + panic("no return value specified for RemoteDeviceForSki") + } + + var r0 api.DeviceRemote + if rf, ok := ret.Get(0).(func(string) api.DeviceRemote); ok { + r0 = rf(ski) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.DeviceRemote) + } + } + + return r0 +} + +// DeviceLocal_RemoteDeviceForSki_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteDeviceForSki' +type DeviceLocal_RemoteDeviceForSki_Call struct { + *mock.Call +} + +// RemoteDeviceForSki is a helper method to define mock.On call +// - ski string +func (_e *DeviceLocal_Expecter) RemoteDeviceForSki(ski interface{}) *DeviceLocal_RemoteDeviceForSki_Call { + return &DeviceLocal_RemoteDeviceForSki_Call{Call: _e.mock.On("RemoteDeviceForSki", ski)} +} + +func (_c *DeviceLocal_RemoteDeviceForSki_Call) Run(run func(ski string)) *DeviceLocal_RemoteDeviceForSki_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *DeviceLocal_RemoteDeviceForSki_Call) Return(_a0 api.DeviceRemote) *DeviceLocal_RemoteDeviceForSki_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_RemoteDeviceForSki_Call) RunAndReturn(run func(string) api.DeviceRemote) *DeviceLocal_RemoteDeviceForSki_Call { + _c.Call.Return(run) + return _c +} + +// RemoteDevices provides a mock function with given fields: +func (_m *DeviceLocal) RemoteDevices() []api.DeviceRemote { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for RemoteDevices") + } + + var r0 []api.DeviceRemote + if rf, ok := ret.Get(0).(func() []api.DeviceRemote); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]api.DeviceRemote) + } + } + + return r0 +} + +// DeviceLocal_RemoteDevices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoteDevices' +type DeviceLocal_RemoteDevices_Call struct { + *mock.Call +} + +// RemoteDevices is a helper method to define mock.On call +func (_e *DeviceLocal_Expecter) RemoteDevices() *DeviceLocal_RemoteDevices_Call { + return &DeviceLocal_RemoteDevices_Call{Call: _e.mock.On("RemoteDevices")} +} + +func (_c *DeviceLocal_RemoteDevices_Call) Run(run func()) *DeviceLocal_RemoteDevices_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceLocal_RemoteDevices_Call) Return(_a0 []api.DeviceRemote) *DeviceLocal_RemoteDevices_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_RemoteDevices_Call) RunAndReturn(run func() []api.DeviceRemote) *DeviceLocal_RemoteDevices_Call { + _c.Call.Return(run) + return _c +} + +// RemoveEntity provides a mock function with given fields: entity +func (_m *DeviceLocal) RemoveEntity(entity api.EntityLocal) { + _m.Called(entity) +} + +// DeviceLocal_RemoveEntity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveEntity' +type DeviceLocal_RemoveEntity_Call struct { + *mock.Call +} + +// RemoveEntity is a helper method to define mock.On call +// - entity api.EntityLocal +func (_e *DeviceLocal_Expecter) RemoveEntity(entity interface{}) *DeviceLocal_RemoveEntity_Call { + return &DeviceLocal_RemoveEntity_Call{Call: _e.mock.On("RemoveEntity", entity)} +} + +func (_c *DeviceLocal_RemoveEntity_Call) Run(run func(entity api.EntityLocal)) *DeviceLocal_RemoveEntity_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.EntityLocal)) + }) + return _c +} + +func (_c *DeviceLocal_RemoveEntity_Call) Return() *DeviceLocal_RemoveEntity_Call { + _c.Call.Return() + return _c +} + +func (_c *DeviceLocal_RemoveEntity_Call) RunAndReturn(run func(api.EntityLocal)) *DeviceLocal_RemoveEntity_Call { + _c.Call.Return(run) + return _c +} + +// RemoveRemoteDevice provides a mock function with given fields: ski +func (_m *DeviceLocal) RemoveRemoteDevice(ski string) { + _m.Called(ski) +} + +// DeviceLocal_RemoveRemoteDevice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveRemoteDevice' +type DeviceLocal_RemoveRemoteDevice_Call struct { + *mock.Call +} + +// RemoveRemoteDevice is a helper method to define mock.On call +// - ski string +func (_e *DeviceLocal_Expecter) RemoveRemoteDevice(ski interface{}) *DeviceLocal_RemoveRemoteDevice_Call { + return &DeviceLocal_RemoveRemoteDevice_Call{Call: _e.mock.On("RemoveRemoteDevice", ski)} +} + +func (_c *DeviceLocal_RemoveRemoteDevice_Call) Run(run func(ski string)) *DeviceLocal_RemoveRemoteDevice_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *DeviceLocal_RemoveRemoteDevice_Call) Return() *DeviceLocal_RemoveRemoteDevice_Call { + _c.Call.Return() + return _c +} + +func (_c *DeviceLocal_RemoveRemoteDevice_Call) RunAndReturn(run func(string)) *DeviceLocal_RemoveRemoteDevice_Call { + _c.Call.Return(run) + return _c +} + +// RemoveRemoteDeviceConnection provides a mock function with given fields: ski +func (_m *DeviceLocal) RemoveRemoteDeviceConnection(ski string) { + _m.Called(ski) +} + +// DeviceLocal_RemoveRemoteDeviceConnection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveRemoteDeviceConnection' +type DeviceLocal_RemoveRemoteDeviceConnection_Call struct { + *mock.Call +} + +// RemoveRemoteDeviceConnection is a helper method to define mock.On call +// - ski string +func (_e *DeviceLocal_Expecter) RemoveRemoteDeviceConnection(ski interface{}) *DeviceLocal_RemoveRemoteDeviceConnection_Call { + return &DeviceLocal_RemoveRemoteDeviceConnection_Call{Call: _e.mock.On("RemoveRemoteDeviceConnection", ski)} +} + +func (_c *DeviceLocal_RemoveRemoteDeviceConnection_Call) Run(run func(ski string)) *DeviceLocal_RemoveRemoteDeviceConnection_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *DeviceLocal_RemoveRemoteDeviceConnection_Call) Return() *DeviceLocal_RemoveRemoteDeviceConnection_Call { + _c.Call.Return() + return _c +} + +func (_c *DeviceLocal_RemoveRemoteDeviceConnection_Call) RunAndReturn(run func(string)) *DeviceLocal_RemoveRemoteDeviceConnection_Call { + _c.Call.Return(run) + return _c +} + +// SetupRemoteDevice provides a mock function with given fields: ski, writeI +func (_m *DeviceLocal) SetupRemoteDevice(ski string, writeI ship_goapi.SpineDataConnection) ship_goapi.SpineDataProcessing { + ret := _m.Called(ski, writeI) + + if len(ret) == 0 { + panic("no return value specified for SetupRemoteDevice") + } + + var r0 ship_goapi.SpineDataProcessing + if rf, ok := ret.Get(0).(func(string, ship_goapi.SpineDataConnection) ship_goapi.SpineDataProcessing); ok { + r0 = rf(ski, writeI) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(ship_goapi.SpineDataProcessing) + } + } + + return r0 +} + +// DeviceLocal_SetupRemoteDevice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetupRemoteDevice' +type DeviceLocal_SetupRemoteDevice_Call struct { + *mock.Call +} + +// SetupRemoteDevice is a helper method to define mock.On call +// - ski string +// - writeI ship_goapi.SpineDataConnection +func (_e *DeviceLocal_Expecter) SetupRemoteDevice(ski interface{}, writeI interface{}) *DeviceLocal_SetupRemoteDevice_Call { + return &DeviceLocal_SetupRemoteDevice_Call{Call: _e.mock.On("SetupRemoteDevice", ski, writeI)} +} + +func (_c *DeviceLocal_SetupRemoteDevice_Call) Run(run func(ski string, writeI ship_goapi.SpineDataConnection)) *DeviceLocal_SetupRemoteDevice_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(ship_goapi.SpineDataConnection)) + }) + return _c +} + +func (_c *DeviceLocal_SetupRemoteDevice_Call) Return(_a0 ship_goapi.SpineDataProcessing) *DeviceLocal_SetupRemoteDevice_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_SetupRemoteDevice_Call) RunAndReturn(run func(string, ship_goapi.SpineDataConnection) ship_goapi.SpineDataProcessing) *DeviceLocal_SetupRemoteDevice_Call { + _c.Call.Return(run) + return _c +} + +// SubscriptionManager provides a mock function with given fields: +func (_m *DeviceLocal) SubscriptionManager() api.SubscriptionManager { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for SubscriptionManager") + } + + var r0 api.SubscriptionManager + if rf, ok := ret.Get(0).(func() api.SubscriptionManager); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.SubscriptionManager) + } + } + + return r0 +} + +// DeviceLocal_SubscriptionManager_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscriptionManager' +type DeviceLocal_SubscriptionManager_Call struct { + *mock.Call +} + +// SubscriptionManager is a helper method to define mock.On call +func (_e *DeviceLocal_Expecter) SubscriptionManager() *DeviceLocal_SubscriptionManager_Call { + return &DeviceLocal_SubscriptionManager_Call{Call: _e.mock.On("SubscriptionManager")} +} + +func (_c *DeviceLocal_SubscriptionManager_Call) Run(run func()) *DeviceLocal_SubscriptionManager_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceLocal_SubscriptionManager_Call) Return(_a0 api.SubscriptionManager) *DeviceLocal_SubscriptionManager_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceLocal_SubscriptionManager_Call) RunAndReturn(run func() api.SubscriptionManager) *DeviceLocal_SubscriptionManager_Call { + _c.Call.Return(run) + return _c +} + +// NewDeviceLocal creates a new instance of DeviceLocal. 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 NewDeviceLocal(t interface { + mock.TestingT + Cleanup(func()) +}) *DeviceLocal { + mock := &DeviceLocal{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/DeviceRemote.go b/mocks/DeviceRemote.go new file mode 100644 index 0000000..75f66b3 --- /dev/null +++ b/mocks/DeviceRemote.go @@ -0,0 +1,930 @@ +// Code generated by mockery v2.40.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" +) + +// DeviceRemote is an autogenerated mock type for the DeviceRemote type +type DeviceRemote struct { + mock.Mock +} + +type DeviceRemote_Expecter struct { + mock *mock.Mock +} + +func (_m *DeviceRemote) EXPECT() *DeviceRemote_Expecter { + return &DeviceRemote_Expecter{mock: &_m.Mock} +} + +// AddEntity provides a mock function with given fields: entity +func (_m *DeviceRemote) AddEntity(entity api.EntityRemote) api.EntityRemote { + ret := _m.Called(entity) + + if len(ret) == 0 { + panic("no return value specified for AddEntity") + } + + var r0 api.EntityRemote + if rf, ok := ret.Get(0).(func(api.EntityRemote) api.EntityRemote); ok { + r0 = rf(entity) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.EntityRemote) + } + } + + return r0 +} + +// DeviceRemote_AddEntity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddEntity' +type DeviceRemote_AddEntity_Call struct { + *mock.Call +} + +// AddEntity is a helper method to define mock.On call +// - entity api.EntityRemote +func (_e *DeviceRemote_Expecter) AddEntity(entity interface{}) *DeviceRemote_AddEntity_Call { + return &DeviceRemote_AddEntity_Call{Call: _e.mock.On("AddEntity", entity)} +} + +func (_c *DeviceRemote_AddEntity_Call) Run(run func(entity api.EntityRemote)) *DeviceRemote_AddEntity_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.EntityRemote)) + }) + return _c +} + +func (_c *DeviceRemote_AddEntity_Call) Return(_a0 api.EntityRemote) *DeviceRemote_AddEntity_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_AddEntity_Call) RunAndReturn(run func(api.EntityRemote) api.EntityRemote) *DeviceRemote_AddEntity_Call { + _c.Call.Return(run) + return _c +} + +// AddEntityAndFeatures provides a mock function with given fields: initialData, data +func (_m *DeviceRemote) AddEntityAndFeatures(initialData bool, data *model.NodeManagementDetailedDiscoveryDataType) ([]api.EntityRemote, error) { + ret := _m.Called(initialData, data) + + if len(ret) == 0 { + panic("no return value specified for AddEntityAndFeatures") + } + + var r0 []api.EntityRemote + var r1 error + if rf, ok := ret.Get(0).(func(bool, *model.NodeManagementDetailedDiscoveryDataType) ([]api.EntityRemote, error)); ok { + return rf(initialData, data) + } + if rf, ok := ret.Get(0).(func(bool, *model.NodeManagementDetailedDiscoveryDataType) []api.EntityRemote); ok { + r0 = rf(initialData, data) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]api.EntityRemote) + } + } + + if rf, ok := ret.Get(1).(func(bool, *model.NodeManagementDetailedDiscoveryDataType) error); ok { + r1 = rf(initialData, data) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DeviceRemote_AddEntityAndFeatures_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddEntityAndFeatures' +type DeviceRemote_AddEntityAndFeatures_Call struct { + *mock.Call +} + +// AddEntityAndFeatures is a helper method to define mock.On call +// - initialData bool +// - data *model.NodeManagementDetailedDiscoveryDataType +func (_e *DeviceRemote_Expecter) AddEntityAndFeatures(initialData interface{}, data interface{}) *DeviceRemote_AddEntityAndFeatures_Call { + return &DeviceRemote_AddEntityAndFeatures_Call{Call: _e.mock.On("AddEntityAndFeatures", initialData, data)} +} + +func (_c *DeviceRemote_AddEntityAndFeatures_Call) Run(run func(initialData bool, data *model.NodeManagementDetailedDiscoveryDataType)) *DeviceRemote_AddEntityAndFeatures_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(bool), args[1].(*model.NodeManagementDetailedDiscoveryDataType)) + }) + return _c +} + +func (_c *DeviceRemote_AddEntityAndFeatures_Call) Return(_a0 []api.EntityRemote, _a1 error) *DeviceRemote_AddEntityAndFeatures_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *DeviceRemote_AddEntityAndFeatures_Call) RunAndReturn(run func(bool, *model.NodeManagementDetailedDiscoveryDataType) ([]api.EntityRemote, error)) *DeviceRemote_AddEntityAndFeatures_Call { + _c.Call.Return(run) + return _c +} + +// Address provides a mock function with given fields: +func (_m *DeviceRemote) Address() *model.AddressDeviceType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Address") + } + + var r0 *model.AddressDeviceType + if rf, ok := ret.Get(0).(func() *model.AddressDeviceType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.AddressDeviceType) + } + } + + return r0 +} + +// DeviceRemote_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address' +type DeviceRemote_Address_Call struct { + *mock.Call +} + +// Address is a helper method to define mock.On call +func (_e *DeviceRemote_Expecter) Address() *DeviceRemote_Address_Call { + return &DeviceRemote_Address_Call{Call: _e.mock.On("Address")} +} + +func (_c *DeviceRemote_Address_Call) Run(run func()) *DeviceRemote_Address_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceRemote_Address_Call) Return(_a0 *model.AddressDeviceType) *DeviceRemote_Address_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_Address_Call) RunAndReturn(run func() *model.AddressDeviceType) *DeviceRemote_Address_Call { + _c.Call.Return(run) + return _c +} + +// CheckEntityInformation provides a mock function with given fields: initialData, entity +func (_m *DeviceRemote) CheckEntityInformation(initialData bool, entity model.NodeManagementDetailedDiscoveryEntityInformationType) error { + ret := _m.Called(initialData, entity) + + if len(ret) == 0 { + panic("no return value specified for CheckEntityInformation") + } + + var r0 error + if rf, ok := ret.Get(0).(func(bool, model.NodeManagementDetailedDiscoveryEntityInformationType) error); ok { + r0 = rf(initialData, entity) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeviceRemote_CheckEntityInformation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckEntityInformation' +type DeviceRemote_CheckEntityInformation_Call struct { + *mock.Call +} + +// CheckEntityInformation is a helper method to define mock.On call +// - initialData bool +// - entity model.NodeManagementDetailedDiscoveryEntityInformationType +func (_e *DeviceRemote_Expecter) CheckEntityInformation(initialData interface{}, entity interface{}) *DeviceRemote_CheckEntityInformation_Call { + return &DeviceRemote_CheckEntityInformation_Call{Call: _e.mock.On("CheckEntityInformation", initialData, entity)} +} + +func (_c *DeviceRemote_CheckEntityInformation_Call) Run(run func(initialData bool, entity model.NodeManagementDetailedDiscoveryEntityInformationType)) *DeviceRemote_CheckEntityInformation_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(bool), args[1].(model.NodeManagementDetailedDiscoveryEntityInformationType)) + }) + return _c +} + +func (_c *DeviceRemote_CheckEntityInformation_Call) Return(_a0 error) *DeviceRemote_CheckEntityInformation_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_CheckEntityInformation_Call) RunAndReturn(run func(bool, model.NodeManagementDetailedDiscoveryEntityInformationType) error) *DeviceRemote_CheckEntityInformation_Call { + _c.Call.Return(run) + return _c +} + +// DestinationData provides a mock function with given fields: +func (_m *DeviceRemote) DestinationData() model.NodeManagementDestinationDataType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DestinationData") + } + + var r0 model.NodeManagementDestinationDataType + if rf, ok := ret.Get(0).(func() model.NodeManagementDestinationDataType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.NodeManagementDestinationDataType) + } + + return r0 +} + +// DeviceRemote_DestinationData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DestinationData' +type DeviceRemote_DestinationData_Call struct { + *mock.Call +} + +// DestinationData is a helper method to define mock.On call +func (_e *DeviceRemote_Expecter) DestinationData() *DeviceRemote_DestinationData_Call { + return &DeviceRemote_DestinationData_Call{Call: _e.mock.On("DestinationData")} +} + +func (_c *DeviceRemote_DestinationData_Call) Run(run func()) *DeviceRemote_DestinationData_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceRemote_DestinationData_Call) Return(_a0 model.NodeManagementDestinationDataType) *DeviceRemote_DestinationData_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_DestinationData_Call) RunAndReturn(run func() model.NodeManagementDestinationDataType) *DeviceRemote_DestinationData_Call { + _c.Call.Return(run) + return _c +} + +// DeviceType provides a mock function with given fields: +func (_m *DeviceRemote) DeviceType() *model.DeviceTypeType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DeviceType") + } + + var r0 *model.DeviceTypeType + if rf, ok := ret.Get(0).(func() *model.DeviceTypeType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.DeviceTypeType) + } + } + + return r0 +} + +// DeviceRemote_DeviceType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeviceType' +type DeviceRemote_DeviceType_Call struct { + *mock.Call +} + +// DeviceType is a helper method to define mock.On call +func (_e *DeviceRemote_Expecter) DeviceType() *DeviceRemote_DeviceType_Call { + return &DeviceRemote_DeviceType_Call{Call: _e.mock.On("DeviceType")} +} + +func (_c *DeviceRemote_DeviceType_Call) Run(run func()) *DeviceRemote_DeviceType_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceRemote_DeviceType_Call) Return(_a0 *model.DeviceTypeType) *DeviceRemote_DeviceType_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_DeviceType_Call) RunAndReturn(run func() *model.DeviceTypeType) *DeviceRemote_DeviceType_Call { + _c.Call.Return(run) + return _c +} + +// Entities provides a mock function with given fields: +func (_m *DeviceRemote) Entities() []api.EntityRemote { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Entities") + } + + var r0 []api.EntityRemote + if rf, ok := ret.Get(0).(func() []api.EntityRemote); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]api.EntityRemote) + } + } + + return r0 +} + +// DeviceRemote_Entities_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Entities' +type DeviceRemote_Entities_Call struct { + *mock.Call +} + +// Entities is a helper method to define mock.On call +func (_e *DeviceRemote_Expecter) Entities() *DeviceRemote_Entities_Call { + return &DeviceRemote_Entities_Call{Call: _e.mock.On("Entities")} +} + +func (_c *DeviceRemote_Entities_Call) Run(run func()) *DeviceRemote_Entities_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceRemote_Entities_Call) Return(_a0 []api.EntityRemote) *DeviceRemote_Entities_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_Entities_Call) RunAndReturn(run func() []api.EntityRemote) *DeviceRemote_Entities_Call { + _c.Call.Return(run) + return _c +} + +// Entity provides a mock function with given fields: id +func (_m *DeviceRemote) Entity(id []model.AddressEntityType) api.EntityRemote { + ret := _m.Called(id) + + if len(ret) == 0 { + panic("no return value specified for Entity") + } + + var r0 api.EntityRemote + if rf, ok := ret.Get(0).(func([]model.AddressEntityType) api.EntityRemote); ok { + r0 = rf(id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.EntityRemote) + } + } + + return r0 +} + +// DeviceRemote_Entity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Entity' +type DeviceRemote_Entity_Call struct { + *mock.Call +} + +// Entity is a helper method to define mock.On call +// - id []model.AddressEntityType +func (_e *DeviceRemote_Expecter) Entity(id interface{}) *DeviceRemote_Entity_Call { + return &DeviceRemote_Entity_Call{Call: _e.mock.On("Entity", id)} +} + +func (_c *DeviceRemote_Entity_Call) Run(run func(id []model.AddressEntityType)) *DeviceRemote_Entity_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]model.AddressEntityType)) + }) + return _c +} + +func (_c *DeviceRemote_Entity_Call) Return(_a0 api.EntityRemote) *DeviceRemote_Entity_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_Entity_Call) RunAndReturn(run func([]model.AddressEntityType) api.EntityRemote) *DeviceRemote_Entity_Call { + _c.Call.Return(run) + return _c +} + +// FeatureByAddress provides a mock function with given fields: address +func (_m *DeviceRemote) FeatureByAddress(address *model.FeatureAddressType) api.FeatureRemote { + ret := _m.Called(address) + + if len(ret) == 0 { + panic("no return value specified for FeatureByAddress") + } + + var r0 api.FeatureRemote + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType) api.FeatureRemote); ok { + r0 = rf(address) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.FeatureRemote) + } + } + + return r0 +} + +// DeviceRemote_FeatureByAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FeatureByAddress' +type DeviceRemote_FeatureByAddress_Call struct { + *mock.Call +} + +// FeatureByAddress is a helper method to define mock.On call +// - address *model.FeatureAddressType +func (_e *DeviceRemote_Expecter) FeatureByAddress(address interface{}) *DeviceRemote_FeatureByAddress_Call { + return &DeviceRemote_FeatureByAddress_Call{Call: _e.mock.On("FeatureByAddress", address)} +} + +func (_c *DeviceRemote_FeatureByAddress_Call) Run(run func(address *model.FeatureAddressType)) *DeviceRemote_FeatureByAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *DeviceRemote_FeatureByAddress_Call) Return(_a0 api.FeatureRemote) *DeviceRemote_FeatureByAddress_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_FeatureByAddress_Call) RunAndReturn(run func(*model.FeatureAddressType) api.FeatureRemote) *DeviceRemote_FeatureByAddress_Call { + _c.Call.Return(run) + return _c +} + +// FeatureByEntityTypeAndRole provides a mock function with given fields: entity, featureType, role +func (_m *DeviceRemote) FeatureByEntityTypeAndRole(entity api.EntityRemote, featureType model.FeatureTypeType, role model.RoleType) api.FeatureRemote { + ret := _m.Called(entity, featureType, role) + + if len(ret) == 0 { + panic("no return value specified for FeatureByEntityTypeAndRole") + } + + var r0 api.FeatureRemote + if rf, ok := ret.Get(0).(func(api.EntityRemote, model.FeatureTypeType, model.RoleType) api.FeatureRemote); ok { + r0 = rf(entity, featureType, role) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.FeatureRemote) + } + } + + return r0 +} + +// DeviceRemote_FeatureByEntityTypeAndRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FeatureByEntityTypeAndRole' +type DeviceRemote_FeatureByEntityTypeAndRole_Call struct { + *mock.Call +} + +// FeatureByEntityTypeAndRole is a helper method to define mock.On call +// - entity api.EntityRemote +// - featureType model.FeatureTypeType +// - role model.RoleType +func (_e *DeviceRemote_Expecter) FeatureByEntityTypeAndRole(entity interface{}, featureType interface{}, role interface{}) *DeviceRemote_FeatureByEntityTypeAndRole_Call { + return &DeviceRemote_FeatureByEntityTypeAndRole_Call{Call: _e.mock.On("FeatureByEntityTypeAndRole", entity, featureType, role)} +} + +func (_c *DeviceRemote_FeatureByEntityTypeAndRole_Call) Run(run func(entity api.EntityRemote, featureType model.FeatureTypeType, role model.RoleType)) *DeviceRemote_FeatureByEntityTypeAndRole_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.EntityRemote), args[1].(model.FeatureTypeType), args[2].(model.RoleType)) + }) + return _c +} + +func (_c *DeviceRemote_FeatureByEntityTypeAndRole_Call) Return(_a0 api.FeatureRemote) *DeviceRemote_FeatureByEntityTypeAndRole_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_FeatureByEntityTypeAndRole_Call) RunAndReturn(run func(api.EntityRemote, model.FeatureTypeType, model.RoleType) api.FeatureRemote) *DeviceRemote_FeatureByEntityTypeAndRole_Call { + _c.Call.Return(run) + return _c +} + +// FeatureSet provides a mock function with given fields: +func (_m *DeviceRemote) FeatureSet() *model.NetworkManagementFeatureSetType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for FeatureSet") + } + + var r0 *model.NetworkManagementFeatureSetType + if rf, ok := ret.Get(0).(func() *model.NetworkManagementFeatureSetType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.NetworkManagementFeatureSetType) + } + } + + return r0 +} + +// DeviceRemote_FeatureSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FeatureSet' +type DeviceRemote_FeatureSet_Call struct { + *mock.Call +} + +// FeatureSet is a helper method to define mock.On call +func (_e *DeviceRemote_Expecter) FeatureSet() *DeviceRemote_FeatureSet_Call { + return &DeviceRemote_FeatureSet_Call{Call: _e.mock.On("FeatureSet")} +} + +func (_c *DeviceRemote_FeatureSet_Call) Run(run func()) *DeviceRemote_FeatureSet_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceRemote_FeatureSet_Call) Return(_a0 *model.NetworkManagementFeatureSetType) *DeviceRemote_FeatureSet_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_FeatureSet_Call) RunAndReturn(run func() *model.NetworkManagementFeatureSetType) *DeviceRemote_FeatureSet_Call { + _c.Call.Return(run) + return _c +} + +// HandleSpineMesssage provides a mock function with given fields: message +func (_m *DeviceRemote) HandleSpineMesssage(message []byte) (*model.MsgCounterType, error) { + ret := _m.Called(message) + + if len(ret) == 0 { + panic("no return value specified for HandleSpineMesssage") + } + + var r0 *model.MsgCounterType + var r1 error + if rf, ok := ret.Get(0).(func([]byte) (*model.MsgCounterType, error)); ok { + return rf(message) + } + if rf, ok := ret.Get(0).(func([]byte) *model.MsgCounterType); ok { + r0 = rf(message) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func([]byte) error); ok { + r1 = rf(message) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DeviceRemote_HandleSpineMesssage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HandleSpineMesssage' +type DeviceRemote_HandleSpineMesssage_Call struct { + *mock.Call +} + +// HandleSpineMesssage is a helper method to define mock.On call +// - message []byte +func (_e *DeviceRemote_Expecter) HandleSpineMesssage(message interface{}) *DeviceRemote_HandleSpineMesssage_Call { + return &DeviceRemote_HandleSpineMesssage_Call{Call: _e.mock.On("HandleSpineMesssage", message)} +} + +func (_c *DeviceRemote_HandleSpineMesssage_Call) Run(run func(message []byte)) *DeviceRemote_HandleSpineMesssage_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]byte)) + }) + return _c +} + +func (_c *DeviceRemote_HandleSpineMesssage_Call) Return(_a0 *model.MsgCounterType, _a1 error) *DeviceRemote_HandleSpineMesssage_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *DeviceRemote_HandleSpineMesssage_Call) RunAndReturn(run func([]byte) (*model.MsgCounterType, error)) *DeviceRemote_HandleSpineMesssage_Call { + _c.Call.Return(run) + return _c +} + +// RemoveByAddress provides a mock function with given fields: addr +func (_m *DeviceRemote) RemoveByAddress(addr []model.AddressEntityType) api.EntityRemote { + ret := _m.Called(addr) + + if len(ret) == 0 { + panic("no return value specified for RemoveByAddress") + } + + var r0 api.EntityRemote + if rf, ok := ret.Get(0).(func([]model.AddressEntityType) api.EntityRemote); ok { + r0 = rf(addr) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.EntityRemote) + } + } + + return r0 +} + +// DeviceRemote_RemoveByAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveByAddress' +type DeviceRemote_RemoveByAddress_Call struct { + *mock.Call +} + +// RemoveByAddress is a helper method to define mock.On call +// - addr []model.AddressEntityType +func (_e *DeviceRemote_Expecter) RemoveByAddress(addr interface{}) *DeviceRemote_RemoveByAddress_Call { + return &DeviceRemote_RemoveByAddress_Call{Call: _e.mock.On("RemoveByAddress", addr)} +} + +func (_c *DeviceRemote_RemoveByAddress_Call) Run(run func(addr []model.AddressEntityType)) *DeviceRemote_RemoveByAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]model.AddressEntityType)) + }) + return _c +} + +func (_c *DeviceRemote_RemoveByAddress_Call) Return(_a0 api.EntityRemote) *DeviceRemote_RemoveByAddress_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_RemoveByAddress_Call) RunAndReturn(run func([]model.AddressEntityType) api.EntityRemote) *DeviceRemote_RemoveByAddress_Call { + _c.Call.Return(run) + return _c +} + +// Sender provides a mock function with given fields: +func (_m *DeviceRemote) Sender() api.Sender { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Sender") + } + + var r0 api.Sender + if rf, ok := ret.Get(0).(func() api.Sender); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.Sender) + } + } + + return r0 +} + +// DeviceRemote_Sender_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Sender' +type DeviceRemote_Sender_Call struct { + *mock.Call +} + +// Sender is a helper method to define mock.On call +func (_e *DeviceRemote_Expecter) Sender() *DeviceRemote_Sender_Call { + return &DeviceRemote_Sender_Call{Call: _e.mock.On("Sender")} +} + +func (_c *DeviceRemote_Sender_Call) Run(run func()) *DeviceRemote_Sender_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceRemote_Sender_Call) Return(_a0 api.Sender) *DeviceRemote_Sender_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_Sender_Call) RunAndReturn(run func() api.Sender) *DeviceRemote_Sender_Call { + _c.Call.Return(run) + return _c +} + +// SetAddress provides a mock function with given fields: address +func (_m *DeviceRemote) SetAddress(address *model.AddressDeviceType) { + _m.Called(address) +} + +// DeviceRemote_SetAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetAddress' +type DeviceRemote_SetAddress_Call struct { + *mock.Call +} + +// SetAddress is a helper method to define mock.On call +// - address *model.AddressDeviceType +func (_e *DeviceRemote_Expecter) SetAddress(address interface{}) *DeviceRemote_SetAddress_Call { + return &DeviceRemote_SetAddress_Call{Call: _e.mock.On("SetAddress", address)} +} + +func (_c *DeviceRemote_SetAddress_Call) Run(run func(address *model.AddressDeviceType)) *DeviceRemote_SetAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.AddressDeviceType)) + }) + return _c +} + +func (_c *DeviceRemote_SetAddress_Call) Return() *DeviceRemote_SetAddress_Call { + _c.Call.Return() + return _c +} + +func (_c *DeviceRemote_SetAddress_Call) RunAndReturn(run func(*model.AddressDeviceType)) *DeviceRemote_SetAddress_Call { + _c.Call.Return(run) + return _c +} + +// Ski provides a mock function with given fields: +func (_m *DeviceRemote) Ski() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Ski") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// DeviceRemote_Ski_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Ski' +type DeviceRemote_Ski_Call struct { + *mock.Call +} + +// Ski is a helper method to define mock.On call +func (_e *DeviceRemote_Expecter) Ski() *DeviceRemote_Ski_Call { + return &DeviceRemote_Ski_Call{Call: _e.mock.On("Ski")} +} + +func (_c *DeviceRemote_Ski_Call) Run(run func()) *DeviceRemote_Ski_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceRemote_Ski_Call) Return(_a0 string) *DeviceRemote_Ski_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_Ski_Call) RunAndReturn(run func() string) *DeviceRemote_Ski_Call { + _c.Call.Return(run) + return _c +} + +// UpdateDevice provides a mock function with given fields: description +func (_m *DeviceRemote) UpdateDevice(description *model.NetworkManagementDeviceDescriptionDataType) { + _m.Called(description) +} + +// DeviceRemote_UpdateDevice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateDevice' +type DeviceRemote_UpdateDevice_Call struct { + *mock.Call +} + +// UpdateDevice is a helper method to define mock.On call +// - description *model.NetworkManagementDeviceDescriptionDataType +func (_e *DeviceRemote_Expecter) UpdateDevice(description interface{}) *DeviceRemote_UpdateDevice_Call { + return &DeviceRemote_UpdateDevice_Call{Call: _e.mock.On("UpdateDevice", description)} +} + +func (_c *DeviceRemote_UpdateDevice_Call) Run(run func(description *model.NetworkManagementDeviceDescriptionDataType)) *DeviceRemote_UpdateDevice_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.NetworkManagementDeviceDescriptionDataType)) + }) + return _c +} + +func (_c *DeviceRemote_UpdateDevice_Call) Return() *DeviceRemote_UpdateDevice_Call { + _c.Call.Return() + return _c +} + +func (_c *DeviceRemote_UpdateDevice_Call) RunAndReturn(run func(*model.NetworkManagementDeviceDescriptionDataType)) *DeviceRemote_UpdateDevice_Call { + _c.Call.Return(run) + return _c +} + +// UseCases provides a mock function with given fields: +func (_m *DeviceRemote) UseCases() []model.UseCaseInformationDataType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for UseCases") + } + + var r0 []model.UseCaseInformationDataType + if rf, ok := ret.Get(0).(func() []model.UseCaseInformationDataType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]model.UseCaseInformationDataType) + } + } + + return r0 +} + +// DeviceRemote_UseCases_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UseCases' +type DeviceRemote_UseCases_Call struct { + *mock.Call +} + +// UseCases is a helper method to define mock.On call +func (_e *DeviceRemote_Expecter) UseCases() *DeviceRemote_UseCases_Call { + return &DeviceRemote_UseCases_Call{Call: _e.mock.On("UseCases")} +} + +func (_c *DeviceRemote_UseCases_Call) Run(run func()) *DeviceRemote_UseCases_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeviceRemote_UseCases_Call) Return(_a0 []model.UseCaseInformationDataType) *DeviceRemote_UseCases_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_UseCases_Call) RunAndReturn(run func() []model.UseCaseInformationDataType) *DeviceRemote_UseCases_Call { + _c.Call.Return(run) + return _c +} + +// VerifyUseCaseScenariosAndFeaturesSupport provides a mock function with given fields: usecaseActor, usecaseName, scenarios, serverFeatures +func (_m *DeviceRemote) VerifyUseCaseScenariosAndFeaturesSupport(usecaseActor model.UseCaseActorType, usecaseName model.UseCaseNameType, scenarios []model.UseCaseScenarioSupportType, serverFeatures []model.FeatureTypeType) bool { + ret := _m.Called(usecaseActor, usecaseName, scenarios, serverFeatures) + + if len(ret) == 0 { + panic("no return value specified for VerifyUseCaseScenariosAndFeaturesSupport") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(model.UseCaseActorType, model.UseCaseNameType, []model.UseCaseScenarioSupportType, []model.FeatureTypeType) bool); ok { + r0 = rf(usecaseActor, usecaseName, scenarios, serverFeatures) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// DeviceRemote_VerifyUseCaseScenariosAndFeaturesSupport_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifyUseCaseScenariosAndFeaturesSupport' +type DeviceRemote_VerifyUseCaseScenariosAndFeaturesSupport_Call struct { + *mock.Call +} + +// VerifyUseCaseScenariosAndFeaturesSupport is a helper method to define mock.On call +// - usecaseActor model.UseCaseActorType +// - usecaseName model.UseCaseNameType +// - scenarios []model.UseCaseScenarioSupportType +// - serverFeatures []model.FeatureTypeType +func (_e *DeviceRemote_Expecter) VerifyUseCaseScenariosAndFeaturesSupport(usecaseActor interface{}, usecaseName interface{}, scenarios interface{}, serverFeatures interface{}) *DeviceRemote_VerifyUseCaseScenariosAndFeaturesSupport_Call { + return &DeviceRemote_VerifyUseCaseScenariosAndFeaturesSupport_Call{Call: _e.mock.On("VerifyUseCaseScenariosAndFeaturesSupport", usecaseActor, usecaseName, scenarios, serverFeatures)} +} + +func (_c *DeviceRemote_VerifyUseCaseScenariosAndFeaturesSupport_Call) Run(run func(usecaseActor model.UseCaseActorType, usecaseName model.UseCaseNameType, scenarios []model.UseCaseScenarioSupportType, serverFeatures []model.FeatureTypeType)) *DeviceRemote_VerifyUseCaseScenariosAndFeaturesSupport_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.UseCaseActorType), args[1].(model.UseCaseNameType), args[2].([]model.UseCaseScenarioSupportType), args[3].([]model.FeatureTypeType)) + }) + return _c +} + +func (_c *DeviceRemote_VerifyUseCaseScenariosAndFeaturesSupport_Call) Return(_a0 bool) *DeviceRemote_VerifyUseCaseScenariosAndFeaturesSupport_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeviceRemote_VerifyUseCaseScenariosAndFeaturesSupport_Call) RunAndReturn(run func(model.UseCaseActorType, model.UseCaseNameType, []model.UseCaseScenarioSupportType, []model.FeatureTypeType) bool) *DeviceRemote_VerifyUseCaseScenariosAndFeaturesSupport_Call { + _c.Call.Return(run) + return _c +} + +// NewDeviceRemote creates a new instance of DeviceRemote. 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 NewDeviceRemote(t interface { + mock.TestingT + Cleanup(func()) +}) *DeviceRemote { + mock := &DeviceRemote{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/Entity.go b/mocks/Entity.go new file mode 100644 index 0000000..9955dcf --- /dev/null +++ b/mocks/Entity.go @@ -0,0 +1,252 @@ +// Code generated by mockery v2.40.1. DO NOT EDIT. + +package mocks + +import ( + model "github.com/enbility/spine-go/model" + mock "github.com/stretchr/testify/mock" +) + +// Entity is an autogenerated mock type for the Entity type +type Entity struct { + mock.Mock +} + +type Entity_Expecter struct { + mock *mock.Mock +} + +func (_m *Entity) EXPECT() *Entity_Expecter { + return &Entity_Expecter{mock: &_m.Mock} +} + +// Address provides a mock function with given fields: +func (_m *Entity) Address() *model.EntityAddressType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Address") + } + + var r0 *model.EntityAddressType + if rf, ok := ret.Get(0).(func() *model.EntityAddressType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.EntityAddressType) + } + } + + return r0 +} + +// Entity_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address' +type Entity_Address_Call struct { + *mock.Call +} + +// Address is a helper method to define mock.On call +func (_e *Entity_Expecter) Address() *Entity_Address_Call { + return &Entity_Address_Call{Call: _e.mock.On("Address")} +} + +func (_c *Entity_Address_Call) Run(run func()) *Entity_Address_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Entity_Address_Call) Return(_a0 *model.EntityAddressType) *Entity_Address_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Entity_Address_Call) RunAndReturn(run func() *model.EntityAddressType) *Entity_Address_Call { + _c.Call.Return(run) + return _c +} + +// Description provides a mock function with given fields: +func (_m *Entity) Description() *model.DescriptionType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Description") + } + + var r0 *model.DescriptionType + if rf, ok := ret.Get(0).(func() *model.DescriptionType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.DescriptionType) + } + } + + return r0 +} + +// Entity_Description_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Description' +type Entity_Description_Call struct { + *mock.Call +} + +// Description is a helper method to define mock.On call +func (_e *Entity_Expecter) Description() *Entity_Description_Call { + return &Entity_Description_Call{Call: _e.mock.On("Description")} +} + +func (_c *Entity_Description_Call) Run(run func()) *Entity_Description_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Entity_Description_Call) Return(_a0 *model.DescriptionType) *Entity_Description_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Entity_Description_Call) RunAndReturn(run func() *model.DescriptionType) *Entity_Description_Call { + _c.Call.Return(run) + return _c +} + +// EntityType provides a mock function with given fields: +func (_m *Entity) EntityType() model.EntityTypeType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for EntityType") + } + + var r0 model.EntityTypeType + if rf, ok := ret.Get(0).(func() model.EntityTypeType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.EntityTypeType) + } + + return r0 +} + +// Entity_EntityType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EntityType' +type Entity_EntityType_Call struct { + *mock.Call +} + +// EntityType is a helper method to define mock.On call +func (_e *Entity_Expecter) EntityType() *Entity_EntityType_Call { + return &Entity_EntityType_Call{Call: _e.mock.On("EntityType")} +} + +func (_c *Entity_EntityType_Call) Run(run func()) *Entity_EntityType_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Entity_EntityType_Call) Return(_a0 model.EntityTypeType) *Entity_EntityType_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Entity_EntityType_Call) RunAndReturn(run func() model.EntityTypeType) *Entity_EntityType_Call { + _c.Call.Return(run) + return _c +} + +// NextFeatureId provides a mock function with given fields: +func (_m *Entity) NextFeatureId() uint { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for NextFeatureId") + } + + var r0 uint + if rf, ok := ret.Get(0).(func() uint); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint) + } + + return r0 +} + +// Entity_NextFeatureId_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NextFeatureId' +type Entity_NextFeatureId_Call struct { + *mock.Call +} + +// NextFeatureId is a helper method to define mock.On call +func (_e *Entity_Expecter) NextFeatureId() *Entity_NextFeatureId_Call { + return &Entity_NextFeatureId_Call{Call: _e.mock.On("NextFeatureId")} +} + +func (_c *Entity_NextFeatureId_Call) Run(run func()) *Entity_NextFeatureId_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Entity_NextFeatureId_Call) Return(_a0 uint) *Entity_NextFeatureId_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Entity_NextFeatureId_Call) RunAndReturn(run func() uint) *Entity_NextFeatureId_Call { + _c.Call.Return(run) + return _c +} + +// SetDescription provides a mock function with given fields: d +func (_m *Entity) SetDescription(d *model.DescriptionType) { + _m.Called(d) +} + +// Entity_SetDescription_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDescription' +type Entity_SetDescription_Call struct { + *mock.Call +} + +// SetDescription is a helper method to define mock.On call +// - d *model.DescriptionType +func (_e *Entity_Expecter) SetDescription(d interface{}) *Entity_SetDescription_Call { + return &Entity_SetDescription_Call{Call: _e.mock.On("SetDescription", d)} +} + +func (_c *Entity_SetDescription_Call) Run(run func(d *model.DescriptionType)) *Entity_SetDescription_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.DescriptionType)) + }) + return _c +} + +func (_c *Entity_SetDescription_Call) Return() *Entity_SetDescription_Call { + _c.Call.Return() + return _c +} + +func (_c *Entity_SetDescription_Call) RunAndReturn(run func(*model.DescriptionType)) *Entity_SetDescription_Call { + _c.Call.Return(run) + return _c +} + +// NewEntity creates a new instance of Entity. 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 NewEntity(t interface { + mock.TestingT + Cleanup(func()) +}) *Entity { + mock := &Entity{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/EntityLocal.go b/mocks/EntityLocal.go new file mode 100644 index 0000000..f363466 --- /dev/null +++ b/mocks/EntityLocal.go @@ -0,0 +1,742 @@ +// Code generated by mockery v2.40.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" +) + +// EntityLocal is an autogenerated mock type for the EntityLocal type +type EntityLocal struct { + mock.Mock +} + +type EntityLocal_Expecter struct { + mock *mock.Mock +} + +func (_m *EntityLocal) EXPECT() *EntityLocal_Expecter { + return &EntityLocal_Expecter{mock: &_m.Mock} +} + +// AddFeature provides a mock function with given fields: f +func (_m *EntityLocal) AddFeature(f api.FeatureLocal) { + _m.Called(f) +} + +// EntityLocal_AddFeature_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddFeature' +type EntityLocal_AddFeature_Call struct { + *mock.Call +} + +// AddFeature is a helper method to define mock.On call +// - f api.FeatureLocal +func (_e *EntityLocal_Expecter) AddFeature(f interface{}) *EntityLocal_AddFeature_Call { + return &EntityLocal_AddFeature_Call{Call: _e.mock.On("AddFeature", f)} +} + +func (_c *EntityLocal_AddFeature_Call) Run(run func(f api.FeatureLocal)) *EntityLocal_AddFeature_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.FeatureLocal)) + }) + return _c +} + +func (_c *EntityLocal_AddFeature_Call) Return() *EntityLocal_AddFeature_Call { + _c.Call.Return() + return _c +} + +func (_c *EntityLocal_AddFeature_Call) RunAndReturn(run func(api.FeatureLocal)) *EntityLocal_AddFeature_Call { + _c.Call.Return(run) + return _c +} + +// AddUseCaseSupport provides a mock function with given fields: actor, useCaseName, useCaseVersion, useCaseDocumemtSubRevision, useCaseAvailable, scenarios +func (_m *EntityLocal) AddUseCaseSupport(actor model.UseCaseActorType, useCaseName model.UseCaseNameType, useCaseVersion model.SpecificationVersionType, useCaseDocumemtSubRevision string, useCaseAvailable bool, scenarios []model.UseCaseScenarioSupportType) { + _m.Called(actor, useCaseName, useCaseVersion, useCaseDocumemtSubRevision, useCaseAvailable, scenarios) +} + +// EntityLocal_AddUseCaseSupport_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddUseCaseSupport' +type EntityLocal_AddUseCaseSupport_Call struct { + *mock.Call +} + +// AddUseCaseSupport is a helper method to define mock.On call +// - actor model.UseCaseActorType +// - useCaseName model.UseCaseNameType +// - useCaseVersion model.SpecificationVersionType +// - useCaseDocumemtSubRevision string +// - useCaseAvailable bool +// - scenarios []model.UseCaseScenarioSupportType +func (_e *EntityLocal_Expecter) AddUseCaseSupport(actor interface{}, useCaseName interface{}, useCaseVersion interface{}, useCaseDocumemtSubRevision interface{}, useCaseAvailable interface{}, scenarios interface{}) *EntityLocal_AddUseCaseSupport_Call { + return &EntityLocal_AddUseCaseSupport_Call{Call: _e.mock.On("AddUseCaseSupport", actor, useCaseName, useCaseVersion, useCaseDocumemtSubRevision, useCaseAvailable, scenarios)} +} + +func (_c *EntityLocal_AddUseCaseSupport_Call) Run(run func(actor model.UseCaseActorType, useCaseName model.UseCaseNameType, useCaseVersion model.SpecificationVersionType, useCaseDocumemtSubRevision string, useCaseAvailable bool, scenarios []model.UseCaseScenarioSupportType)) *EntityLocal_AddUseCaseSupport_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.UseCaseActorType), args[1].(model.UseCaseNameType), args[2].(model.SpecificationVersionType), args[3].(string), args[4].(bool), args[5].([]model.UseCaseScenarioSupportType)) + }) + return _c +} + +func (_c *EntityLocal_AddUseCaseSupport_Call) Return() *EntityLocal_AddUseCaseSupport_Call { + _c.Call.Return() + return _c +} + +func (_c *EntityLocal_AddUseCaseSupport_Call) RunAndReturn(run func(model.UseCaseActorType, model.UseCaseNameType, model.SpecificationVersionType, string, bool, []model.UseCaseScenarioSupportType)) *EntityLocal_AddUseCaseSupport_Call { + _c.Call.Return(run) + return _c +} + +// Address provides a mock function with given fields: +func (_m *EntityLocal) Address() *model.EntityAddressType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Address") + } + + var r0 *model.EntityAddressType + if rf, ok := ret.Get(0).(func() *model.EntityAddressType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.EntityAddressType) + } + } + + return r0 +} + +// EntityLocal_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address' +type EntityLocal_Address_Call struct { + *mock.Call +} + +// Address is a helper method to define mock.On call +func (_e *EntityLocal_Expecter) Address() *EntityLocal_Address_Call { + return &EntityLocal_Address_Call{Call: _e.mock.On("Address")} +} + +func (_c *EntityLocal_Address_Call) Run(run func()) *EntityLocal_Address_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityLocal_Address_Call) Return(_a0 *model.EntityAddressType) *EntityLocal_Address_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityLocal_Address_Call) RunAndReturn(run func() *model.EntityAddressType) *EntityLocal_Address_Call { + _c.Call.Return(run) + return _c +} + +// Description provides a mock function with given fields: +func (_m *EntityLocal) Description() *model.DescriptionType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Description") + } + + var r0 *model.DescriptionType + if rf, ok := ret.Get(0).(func() *model.DescriptionType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.DescriptionType) + } + } + + return r0 +} + +// EntityLocal_Description_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Description' +type EntityLocal_Description_Call struct { + *mock.Call +} + +// Description is a helper method to define mock.On call +func (_e *EntityLocal_Expecter) Description() *EntityLocal_Description_Call { + return &EntityLocal_Description_Call{Call: _e.mock.On("Description")} +} + +func (_c *EntityLocal_Description_Call) Run(run func()) *EntityLocal_Description_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityLocal_Description_Call) Return(_a0 *model.DescriptionType) *EntityLocal_Description_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityLocal_Description_Call) RunAndReturn(run func() *model.DescriptionType) *EntityLocal_Description_Call { + _c.Call.Return(run) + return _c +} + +// Device provides a mock function with given fields: +func (_m *EntityLocal) Device() api.DeviceLocal { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Device") + } + + var r0 api.DeviceLocal + if rf, ok := ret.Get(0).(func() api.DeviceLocal); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.DeviceLocal) + } + } + + return r0 +} + +// EntityLocal_Device_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Device' +type EntityLocal_Device_Call struct { + *mock.Call +} + +// Device is a helper method to define mock.On call +func (_e *EntityLocal_Expecter) Device() *EntityLocal_Device_Call { + return &EntityLocal_Device_Call{Call: _e.mock.On("Device")} +} + +func (_c *EntityLocal_Device_Call) Run(run func()) *EntityLocal_Device_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityLocal_Device_Call) Return(_a0 api.DeviceLocal) *EntityLocal_Device_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityLocal_Device_Call) RunAndReturn(run func() api.DeviceLocal) *EntityLocal_Device_Call { + _c.Call.Return(run) + return _c +} + +// EntityType provides a mock function with given fields: +func (_m *EntityLocal) EntityType() model.EntityTypeType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for EntityType") + } + + var r0 model.EntityTypeType + if rf, ok := ret.Get(0).(func() model.EntityTypeType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.EntityTypeType) + } + + return r0 +} + +// EntityLocal_EntityType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EntityType' +type EntityLocal_EntityType_Call struct { + *mock.Call +} + +// EntityType is a helper method to define mock.On call +func (_e *EntityLocal_Expecter) EntityType() *EntityLocal_EntityType_Call { + return &EntityLocal_EntityType_Call{Call: _e.mock.On("EntityType")} +} + +func (_c *EntityLocal_EntityType_Call) Run(run func()) *EntityLocal_EntityType_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityLocal_EntityType_Call) Return(_a0 model.EntityTypeType) *EntityLocal_EntityType_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityLocal_EntityType_Call) RunAndReturn(run func() model.EntityTypeType) *EntityLocal_EntityType_Call { + _c.Call.Return(run) + return _c +} + +// Feature provides a mock function with given fields: addressFeature +func (_m *EntityLocal) Feature(addressFeature *model.AddressFeatureType) api.FeatureLocal { + ret := _m.Called(addressFeature) + + if len(ret) == 0 { + panic("no return value specified for Feature") + } + + var r0 api.FeatureLocal + if rf, ok := ret.Get(0).(func(*model.AddressFeatureType) api.FeatureLocal); ok { + r0 = rf(addressFeature) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.FeatureLocal) + } + } + + return r0 +} + +// EntityLocal_Feature_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Feature' +type EntityLocal_Feature_Call struct { + *mock.Call +} + +// Feature is a helper method to define mock.On call +// - addressFeature *model.AddressFeatureType +func (_e *EntityLocal_Expecter) Feature(addressFeature interface{}) *EntityLocal_Feature_Call { + return &EntityLocal_Feature_Call{Call: _e.mock.On("Feature", addressFeature)} +} + +func (_c *EntityLocal_Feature_Call) Run(run func(addressFeature *model.AddressFeatureType)) *EntityLocal_Feature_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.AddressFeatureType)) + }) + return _c +} + +func (_c *EntityLocal_Feature_Call) Return(_a0 api.FeatureLocal) *EntityLocal_Feature_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityLocal_Feature_Call) RunAndReturn(run func(*model.AddressFeatureType) api.FeatureLocal) *EntityLocal_Feature_Call { + _c.Call.Return(run) + return _c +} + +// FeatureOfTypeAndRole provides a mock function with given fields: featureType, role +func (_m *EntityLocal) FeatureOfTypeAndRole(featureType model.FeatureTypeType, role model.RoleType) api.FeatureLocal { + ret := _m.Called(featureType, role) + + if len(ret) == 0 { + panic("no return value specified for FeatureOfTypeAndRole") + } + + var r0 api.FeatureLocal + if rf, ok := ret.Get(0).(func(model.FeatureTypeType, model.RoleType) api.FeatureLocal); ok { + r0 = rf(featureType, role) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.FeatureLocal) + } + } + + return r0 +} + +// EntityLocal_FeatureOfTypeAndRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FeatureOfTypeAndRole' +type EntityLocal_FeatureOfTypeAndRole_Call struct { + *mock.Call +} + +// FeatureOfTypeAndRole is a helper method to define mock.On call +// - featureType model.FeatureTypeType +// - role model.RoleType +func (_e *EntityLocal_Expecter) FeatureOfTypeAndRole(featureType interface{}, role interface{}) *EntityLocal_FeatureOfTypeAndRole_Call { + return &EntityLocal_FeatureOfTypeAndRole_Call{Call: _e.mock.On("FeatureOfTypeAndRole", featureType, role)} +} + +func (_c *EntityLocal_FeatureOfTypeAndRole_Call) Run(run func(featureType model.FeatureTypeType, role model.RoleType)) *EntityLocal_FeatureOfTypeAndRole_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FeatureTypeType), args[1].(model.RoleType)) + }) + return _c +} + +func (_c *EntityLocal_FeatureOfTypeAndRole_Call) Return(_a0 api.FeatureLocal) *EntityLocal_FeatureOfTypeAndRole_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityLocal_FeatureOfTypeAndRole_Call) RunAndReturn(run func(model.FeatureTypeType, model.RoleType) api.FeatureLocal) *EntityLocal_FeatureOfTypeAndRole_Call { + _c.Call.Return(run) + return _c +} + +// Features provides a mock function with given fields: +func (_m *EntityLocal) Features() []api.FeatureLocal { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Features") + } + + var r0 []api.FeatureLocal + if rf, ok := ret.Get(0).(func() []api.FeatureLocal); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]api.FeatureLocal) + } + } + + return r0 +} + +// EntityLocal_Features_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Features' +type EntityLocal_Features_Call struct { + *mock.Call +} + +// Features is a helper method to define mock.On call +func (_e *EntityLocal_Expecter) Features() *EntityLocal_Features_Call { + return &EntityLocal_Features_Call{Call: _e.mock.On("Features")} +} + +func (_c *EntityLocal_Features_Call) Run(run func()) *EntityLocal_Features_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityLocal_Features_Call) Return(_a0 []api.FeatureLocal) *EntityLocal_Features_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityLocal_Features_Call) RunAndReturn(run func() []api.FeatureLocal) *EntityLocal_Features_Call { + _c.Call.Return(run) + return _c +} + +// GetOrAddFeature provides a mock function with given fields: featureType, role +func (_m *EntityLocal) GetOrAddFeature(featureType model.FeatureTypeType, role model.RoleType) api.FeatureLocal { + ret := _m.Called(featureType, role) + + if len(ret) == 0 { + panic("no return value specified for GetOrAddFeature") + } + + var r0 api.FeatureLocal + if rf, ok := ret.Get(0).(func(model.FeatureTypeType, model.RoleType) api.FeatureLocal); ok { + r0 = rf(featureType, role) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.FeatureLocal) + } + } + + return r0 +} + +// EntityLocal_GetOrAddFeature_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOrAddFeature' +type EntityLocal_GetOrAddFeature_Call struct { + *mock.Call +} + +// GetOrAddFeature is a helper method to define mock.On call +// - featureType model.FeatureTypeType +// - role model.RoleType +func (_e *EntityLocal_Expecter) GetOrAddFeature(featureType interface{}, role interface{}) *EntityLocal_GetOrAddFeature_Call { + return &EntityLocal_GetOrAddFeature_Call{Call: _e.mock.On("GetOrAddFeature", featureType, role)} +} + +func (_c *EntityLocal_GetOrAddFeature_Call) Run(run func(featureType model.FeatureTypeType, role model.RoleType)) *EntityLocal_GetOrAddFeature_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FeatureTypeType), args[1].(model.RoleType)) + }) + return _c +} + +func (_c *EntityLocal_GetOrAddFeature_Call) Return(_a0 api.FeatureLocal) *EntityLocal_GetOrAddFeature_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityLocal_GetOrAddFeature_Call) RunAndReturn(run func(model.FeatureTypeType, model.RoleType) api.FeatureLocal) *EntityLocal_GetOrAddFeature_Call { + _c.Call.Return(run) + return _c +} + +// Information provides a mock function with given fields: +func (_m *EntityLocal) Information() *model.NodeManagementDetailedDiscoveryEntityInformationType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Information") + } + + var r0 *model.NodeManagementDetailedDiscoveryEntityInformationType + if rf, ok := ret.Get(0).(func() *model.NodeManagementDetailedDiscoveryEntityInformationType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.NodeManagementDetailedDiscoveryEntityInformationType) + } + } + + return r0 +} + +// EntityLocal_Information_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Information' +type EntityLocal_Information_Call struct { + *mock.Call +} + +// Information is a helper method to define mock.On call +func (_e *EntityLocal_Expecter) Information() *EntityLocal_Information_Call { + return &EntityLocal_Information_Call{Call: _e.mock.On("Information")} +} + +func (_c *EntityLocal_Information_Call) Run(run func()) *EntityLocal_Information_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityLocal_Information_Call) Return(_a0 *model.NodeManagementDetailedDiscoveryEntityInformationType) *EntityLocal_Information_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityLocal_Information_Call) RunAndReturn(run func() *model.NodeManagementDetailedDiscoveryEntityInformationType) *EntityLocal_Information_Call { + _c.Call.Return(run) + return _c +} + +// NextFeatureId provides a mock function with given fields: +func (_m *EntityLocal) NextFeatureId() uint { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for NextFeatureId") + } + + var r0 uint + if rf, ok := ret.Get(0).(func() uint); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint) + } + + return r0 +} + +// EntityLocal_NextFeatureId_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NextFeatureId' +type EntityLocal_NextFeatureId_Call struct { + *mock.Call +} + +// NextFeatureId is a helper method to define mock.On call +func (_e *EntityLocal_Expecter) NextFeatureId() *EntityLocal_NextFeatureId_Call { + return &EntityLocal_NextFeatureId_Call{Call: _e.mock.On("NextFeatureId")} +} + +func (_c *EntityLocal_NextFeatureId_Call) Run(run func()) *EntityLocal_NextFeatureId_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityLocal_NextFeatureId_Call) Return(_a0 uint) *EntityLocal_NextFeatureId_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityLocal_NextFeatureId_Call) RunAndReturn(run func() uint) *EntityLocal_NextFeatureId_Call { + _c.Call.Return(run) + return _c +} + +// RemoveAllBindings provides a mock function with given fields: +func (_m *EntityLocal) RemoveAllBindings() { + _m.Called() +} + +// EntityLocal_RemoveAllBindings_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveAllBindings' +type EntityLocal_RemoveAllBindings_Call struct { + *mock.Call +} + +// RemoveAllBindings is a helper method to define mock.On call +func (_e *EntityLocal_Expecter) RemoveAllBindings() *EntityLocal_RemoveAllBindings_Call { + return &EntityLocal_RemoveAllBindings_Call{Call: _e.mock.On("RemoveAllBindings")} +} + +func (_c *EntityLocal_RemoveAllBindings_Call) Run(run func()) *EntityLocal_RemoveAllBindings_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityLocal_RemoveAllBindings_Call) Return() *EntityLocal_RemoveAllBindings_Call { + _c.Call.Return() + return _c +} + +func (_c *EntityLocal_RemoveAllBindings_Call) RunAndReturn(run func()) *EntityLocal_RemoveAllBindings_Call { + _c.Call.Return(run) + return _c +} + +// RemoveAllSubscriptions provides a mock function with given fields: +func (_m *EntityLocal) RemoveAllSubscriptions() { + _m.Called() +} + +// EntityLocal_RemoveAllSubscriptions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveAllSubscriptions' +type EntityLocal_RemoveAllSubscriptions_Call struct { + *mock.Call +} + +// RemoveAllSubscriptions is a helper method to define mock.On call +func (_e *EntityLocal_Expecter) RemoveAllSubscriptions() *EntityLocal_RemoveAllSubscriptions_Call { + return &EntityLocal_RemoveAllSubscriptions_Call{Call: _e.mock.On("RemoveAllSubscriptions")} +} + +func (_c *EntityLocal_RemoveAllSubscriptions_Call) Run(run func()) *EntityLocal_RemoveAllSubscriptions_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityLocal_RemoveAllSubscriptions_Call) Return() *EntityLocal_RemoveAllSubscriptions_Call { + _c.Call.Return() + return _c +} + +func (_c *EntityLocal_RemoveAllSubscriptions_Call) RunAndReturn(run func()) *EntityLocal_RemoveAllSubscriptions_Call { + _c.Call.Return(run) + return _c +} + +// RemoveAllUseCaseSupports provides a mock function with given fields: +func (_m *EntityLocal) RemoveAllUseCaseSupports() { + _m.Called() +} + +// EntityLocal_RemoveAllUseCaseSupports_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveAllUseCaseSupports' +type EntityLocal_RemoveAllUseCaseSupports_Call struct { + *mock.Call +} + +// RemoveAllUseCaseSupports is a helper method to define mock.On call +func (_e *EntityLocal_Expecter) RemoveAllUseCaseSupports() *EntityLocal_RemoveAllUseCaseSupports_Call { + return &EntityLocal_RemoveAllUseCaseSupports_Call{Call: _e.mock.On("RemoveAllUseCaseSupports")} +} + +func (_c *EntityLocal_RemoveAllUseCaseSupports_Call) Run(run func()) *EntityLocal_RemoveAllUseCaseSupports_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityLocal_RemoveAllUseCaseSupports_Call) Return() *EntityLocal_RemoveAllUseCaseSupports_Call { + _c.Call.Return() + return _c +} + +func (_c *EntityLocal_RemoveAllUseCaseSupports_Call) RunAndReturn(run func()) *EntityLocal_RemoveAllUseCaseSupports_Call { + _c.Call.Return(run) + return _c +} + +// RemoveUseCaseSupport provides a mock function with given fields: actor, useCaseName +func (_m *EntityLocal) RemoveUseCaseSupport(actor model.UseCaseActorType, useCaseName model.UseCaseNameType) { + _m.Called(actor, useCaseName) +} + +// EntityLocal_RemoveUseCaseSupport_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveUseCaseSupport' +type EntityLocal_RemoveUseCaseSupport_Call struct { + *mock.Call +} + +// RemoveUseCaseSupport is a helper method to define mock.On call +// - actor model.UseCaseActorType +// - useCaseName model.UseCaseNameType +func (_e *EntityLocal_Expecter) RemoveUseCaseSupport(actor interface{}, useCaseName interface{}) *EntityLocal_RemoveUseCaseSupport_Call { + return &EntityLocal_RemoveUseCaseSupport_Call{Call: _e.mock.On("RemoveUseCaseSupport", actor, useCaseName)} +} + +func (_c *EntityLocal_RemoveUseCaseSupport_Call) Run(run func(actor model.UseCaseActorType, useCaseName model.UseCaseNameType)) *EntityLocal_RemoveUseCaseSupport_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.UseCaseActorType), args[1].(model.UseCaseNameType)) + }) + return _c +} + +func (_c *EntityLocal_RemoveUseCaseSupport_Call) Return() *EntityLocal_RemoveUseCaseSupport_Call { + _c.Call.Return() + return _c +} + +func (_c *EntityLocal_RemoveUseCaseSupport_Call) RunAndReturn(run func(model.UseCaseActorType, model.UseCaseNameType)) *EntityLocal_RemoveUseCaseSupport_Call { + _c.Call.Return(run) + return _c +} + +// SetDescription provides a mock function with given fields: d +func (_m *EntityLocal) SetDescription(d *model.DescriptionType) { + _m.Called(d) +} + +// EntityLocal_SetDescription_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDescription' +type EntityLocal_SetDescription_Call struct { + *mock.Call +} + +// SetDescription is a helper method to define mock.On call +// - d *model.DescriptionType +func (_e *EntityLocal_Expecter) SetDescription(d interface{}) *EntityLocal_SetDescription_Call { + return &EntityLocal_SetDescription_Call{Call: _e.mock.On("SetDescription", d)} +} + +func (_c *EntityLocal_SetDescription_Call) Run(run func(d *model.DescriptionType)) *EntityLocal_SetDescription_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.DescriptionType)) + }) + return _c +} + +func (_c *EntityLocal_SetDescription_Call) Return() *EntityLocal_SetDescription_Call { + _c.Call.Return() + return _c +} + +func (_c *EntityLocal_SetDescription_Call) RunAndReturn(run func(*model.DescriptionType)) *EntityLocal_SetDescription_Call { + _c.Call.Return(run) + return _c +} + +// NewEntityLocal creates a new instance of EntityLocal. 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 NewEntityLocal(t interface { + mock.TestingT + Cleanup(func()) +}) *EntityLocal { + mock := &EntityLocal{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/EntityRemote.go b/mocks/EntityRemote.go new file mode 100644 index 0000000..33cab01 --- /dev/null +++ b/mocks/EntityRemote.go @@ -0,0 +1,461 @@ +// Code generated by mockery v2.40.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" +) + +// EntityRemote is an autogenerated mock type for the EntityRemote type +type EntityRemote struct { + mock.Mock +} + +type EntityRemote_Expecter struct { + mock *mock.Mock +} + +func (_m *EntityRemote) EXPECT() *EntityRemote_Expecter { + return &EntityRemote_Expecter{mock: &_m.Mock} +} + +// AddFeature provides a mock function with given fields: f +func (_m *EntityRemote) AddFeature(f api.FeatureRemote) { + _m.Called(f) +} + +// EntityRemote_AddFeature_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddFeature' +type EntityRemote_AddFeature_Call struct { + *mock.Call +} + +// AddFeature is a helper method to define mock.On call +// - f api.FeatureRemote +func (_e *EntityRemote_Expecter) AddFeature(f interface{}) *EntityRemote_AddFeature_Call { + return &EntityRemote_AddFeature_Call{Call: _e.mock.On("AddFeature", f)} +} + +func (_c *EntityRemote_AddFeature_Call) Run(run func(f api.FeatureRemote)) *EntityRemote_AddFeature_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.FeatureRemote)) + }) + return _c +} + +func (_c *EntityRemote_AddFeature_Call) Return() *EntityRemote_AddFeature_Call { + _c.Call.Return() + return _c +} + +func (_c *EntityRemote_AddFeature_Call) RunAndReturn(run func(api.FeatureRemote)) *EntityRemote_AddFeature_Call { + _c.Call.Return(run) + return _c +} + +// Address provides a mock function with given fields: +func (_m *EntityRemote) Address() *model.EntityAddressType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Address") + } + + var r0 *model.EntityAddressType + if rf, ok := ret.Get(0).(func() *model.EntityAddressType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.EntityAddressType) + } + } + + return r0 +} + +// EntityRemote_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address' +type EntityRemote_Address_Call struct { + *mock.Call +} + +// Address is a helper method to define mock.On call +func (_e *EntityRemote_Expecter) Address() *EntityRemote_Address_Call { + return &EntityRemote_Address_Call{Call: _e.mock.On("Address")} +} + +func (_c *EntityRemote_Address_Call) Run(run func()) *EntityRemote_Address_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityRemote_Address_Call) Return(_a0 *model.EntityAddressType) *EntityRemote_Address_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityRemote_Address_Call) RunAndReturn(run func() *model.EntityAddressType) *EntityRemote_Address_Call { + _c.Call.Return(run) + return _c +} + +// Description provides a mock function with given fields: +func (_m *EntityRemote) Description() *model.DescriptionType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Description") + } + + var r0 *model.DescriptionType + if rf, ok := ret.Get(0).(func() *model.DescriptionType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.DescriptionType) + } + } + + return r0 +} + +// EntityRemote_Description_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Description' +type EntityRemote_Description_Call struct { + *mock.Call +} + +// Description is a helper method to define mock.On call +func (_e *EntityRemote_Expecter) Description() *EntityRemote_Description_Call { + return &EntityRemote_Description_Call{Call: _e.mock.On("Description")} +} + +func (_c *EntityRemote_Description_Call) Run(run func()) *EntityRemote_Description_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityRemote_Description_Call) Return(_a0 *model.DescriptionType) *EntityRemote_Description_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityRemote_Description_Call) RunAndReturn(run func() *model.DescriptionType) *EntityRemote_Description_Call { + _c.Call.Return(run) + return _c +} + +// Device provides a mock function with given fields: +func (_m *EntityRemote) Device() api.DeviceRemote { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Device") + } + + var r0 api.DeviceRemote + if rf, ok := ret.Get(0).(func() api.DeviceRemote); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.DeviceRemote) + } + } + + return r0 +} + +// EntityRemote_Device_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Device' +type EntityRemote_Device_Call struct { + *mock.Call +} + +// Device is a helper method to define mock.On call +func (_e *EntityRemote_Expecter) Device() *EntityRemote_Device_Call { + return &EntityRemote_Device_Call{Call: _e.mock.On("Device")} +} + +func (_c *EntityRemote_Device_Call) Run(run func()) *EntityRemote_Device_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityRemote_Device_Call) Return(_a0 api.DeviceRemote) *EntityRemote_Device_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityRemote_Device_Call) RunAndReturn(run func() api.DeviceRemote) *EntityRemote_Device_Call { + _c.Call.Return(run) + return _c +} + +// EntityType provides a mock function with given fields: +func (_m *EntityRemote) EntityType() model.EntityTypeType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for EntityType") + } + + var r0 model.EntityTypeType + if rf, ok := ret.Get(0).(func() model.EntityTypeType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.EntityTypeType) + } + + return r0 +} + +// EntityRemote_EntityType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EntityType' +type EntityRemote_EntityType_Call struct { + *mock.Call +} + +// EntityType is a helper method to define mock.On call +func (_e *EntityRemote_Expecter) EntityType() *EntityRemote_EntityType_Call { + return &EntityRemote_EntityType_Call{Call: _e.mock.On("EntityType")} +} + +func (_c *EntityRemote_EntityType_Call) Run(run func()) *EntityRemote_EntityType_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityRemote_EntityType_Call) Return(_a0 model.EntityTypeType) *EntityRemote_EntityType_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityRemote_EntityType_Call) RunAndReturn(run func() model.EntityTypeType) *EntityRemote_EntityType_Call { + _c.Call.Return(run) + return _c +} + +// Feature provides a mock function with given fields: addressFeature +func (_m *EntityRemote) Feature(addressFeature *model.AddressFeatureType) api.FeatureRemote { + ret := _m.Called(addressFeature) + + if len(ret) == 0 { + panic("no return value specified for Feature") + } + + var r0 api.FeatureRemote + if rf, ok := ret.Get(0).(func(*model.AddressFeatureType) api.FeatureRemote); ok { + r0 = rf(addressFeature) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.FeatureRemote) + } + } + + return r0 +} + +// EntityRemote_Feature_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Feature' +type EntityRemote_Feature_Call struct { + *mock.Call +} + +// Feature is a helper method to define mock.On call +// - addressFeature *model.AddressFeatureType +func (_e *EntityRemote_Expecter) Feature(addressFeature interface{}) *EntityRemote_Feature_Call { + return &EntityRemote_Feature_Call{Call: _e.mock.On("Feature", addressFeature)} +} + +func (_c *EntityRemote_Feature_Call) Run(run func(addressFeature *model.AddressFeatureType)) *EntityRemote_Feature_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.AddressFeatureType)) + }) + return _c +} + +func (_c *EntityRemote_Feature_Call) Return(_a0 api.FeatureRemote) *EntityRemote_Feature_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityRemote_Feature_Call) RunAndReturn(run func(*model.AddressFeatureType) api.FeatureRemote) *EntityRemote_Feature_Call { + _c.Call.Return(run) + return _c +} + +// Features provides a mock function with given fields: +func (_m *EntityRemote) Features() []api.FeatureRemote { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Features") + } + + var r0 []api.FeatureRemote + if rf, ok := ret.Get(0).(func() []api.FeatureRemote); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]api.FeatureRemote) + } + } + + return r0 +} + +// EntityRemote_Features_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Features' +type EntityRemote_Features_Call struct { + *mock.Call +} + +// Features is a helper method to define mock.On call +func (_e *EntityRemote_Expecter) Features() *EntityRemote_Features_Call { + return &EntityRemote_Features_Call{Call: _e.mock.On("Features")} +} + +func (_c *EntityRemote_Features_Call) Run(run func()) *EntityRemote_Features_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityRemote_Features_Call) Return(_a0 []api.FeatureRemote) *EntityRemote_Features_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityRemote_Features_Call) RunAndReturn(run func() []api.FeatureRemote) *EntityRemote_Features_Call { + _c.Call.Return(run) + return _c +} + +// NextFeatureId provides a mock function with given fields: +func (_m *EntityRemote) NextFeatureId() uint { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for NextFeatureId") + } + + var r0 uint + if rf, ok := ret.Get(0).(func() uint); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint) + } + + return r0 +} + +// EntityRemote_NextFeatureId_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NextFeatureId' +type EntityRemote_NextFeatureId_Call struct { + *mock.Call +} + +// NextFeatureId is a helper method to define mock.On call +func (_e *EntityRemote_Expecter) NextFeatureId() *EntityRemote_NextFeatureId_Call { + return &EntityRemote_NextFeatureId_Call{Call: _e.mock.On("NextFeatureId")} +} + +func (_c *EntityRemote_NextFeatureId_Call) Run(run func()) *EntityRemote_NextFeatureId_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityRemote_NextFeatureId_Call) Return(_a0 uint) *EntityRemote_NextFeatureId_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityRemote_NextFeatureId_Call) RunAndReturn(run func() uint) *EntityRemote_NextFeatureId_Call { + _c.Call.Return(run) + return _c +} + +// RemoveAllFeatures provides a mock function with given fields: +func (_m *EntityRemote) RemoveAllFeatures() { + _m.Called() +} + +// EntityRemote_RemoveAllFeatures_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveAllFeatures' +type EntityRemote_RemoveAllFeatures_Call struct { + *mock.Call +} + +// RemoveAllFeatures is a helper method to define mock.On call +func (_e *EntityRemote_Expecter) RemoveAllFeatures() *EntityRemote_RemoveAllFeatures_Call { + return &EntityRemote_RemoveAllFeatures_Call{Call: _e.mock.On("RemoveAllFeatures")} +} + +func (_c *EntityRemote_RemoveAllFeatures_Call) Run(run func()) *EntityRemote_RemoveAllFeatures_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *EntityRemote_RemoveAllFeatures_Call) Return() *EntityRemote_RemoveAllFeatures_Call { + _c.Call.Return() + return _c +} + +func (_c *EntityRemote_RemoveAllFeatures_Call) RunAndReturn(run func()) *EntityRemote_RemoveAllFeatures_Call { + _c.Call.Return(run) + return _c +} + +// SetDescription provides a mock function with given fields: d +func (_m *EntityRemote) SetDescription(d *model.DescriptionType) { + _m.Called(d) +} + +// EntityRemote_SetDescription_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDescription' +type EntityRemote_SetDescription_Call struct { + *mock.Call +} + +// SetDescription is a helper method to define mock.On call +// - d *model.DescriptionType +func (_e *EntityRemote_Expecter) SetDescription(d interface{}) *EntityRemote_SetDescription_Call { + return &EntityRemote_SetDescription_Call{Call: _e.mock.On("SetDescription", d)} +} + +func (_c *EntityRemote_SetDescription_Call) Run(run func(d *model.DescriptionType)) *EntityRemote_SetDescription_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.DescriptionType)) + }) + return _c +} + +func (_c *EntityRemote_SetDescription_Call) Return() *EntityRemote_SetDescription_Call { + _c.Call.Return() + return _c +} + +func (_c *EntityRemote_SetDescription_Call) RunAndReturn(run func(*model.DescriptionType)) *EntityRemote_SetDescription_Call { + _c.Call.Return(run) + return _c +} + +// NewEntityRemote creates a new instance of EntityRemote. 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 NewEntityRemote(t interface { + mock.TestingT + Cleanup(func()) +}) *EntityRemote { + mock := &EntityRemote{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/EventHandler.go b/mocks/EventHandler.go new file mode 100644 index 0000000..777e78c --- /dev/null +++ b/mocks/EventHandler.go @@ -0,0 +1,68 @@ +// Code generated by mockery v2.40.1. DO NOT EDIT. + +package mocks + +import ( + api "github.com/enbility/spine-go/api" + mock "github.com/stretchr/testify/mock" +) + +// EventHandler is an autogenerated mock type for the EventHandler type +type EventHandler struct { + mock.Mock +} + +type EventHandler_Expecter struct { + mock *mock.Mock +} + +func (_m *EventHandler) EXPECT() *EventHandler_Expecter { + return &EventHandler_Expecter{mock: &_m.Mock} +} + +// HandleEvent provides a mock function with given fields: _a0 +func (_m *EventHandler) HandleEvent(_a0 api.EventPayload) { + _m.Called(_a0) +} + +// EventHandler_HandleEvent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HandleEvent' +type EventHandler_HandleEvent_Call struct { + *mock.Call +} + +// HandleEvent is a helper method to define mock.On call +// - _a0 api.EventPayload +func (_e *EventHandler_Expecter) HandleEvent(_a0 interface{}) *EventHandler_HandleEvent_Call { + return &EventHandler_HandleEvent_Call{Call: _e.mock.On("HandleEvent", _a0)} +} + +func (_c *EventHandler_HandleEvent_Call) Run(run func(_a0 api.EventPayload)) *EventHandler_HandleEvent_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.EventPayload)) + }) + return _c +} + +func (_c *EventHandler_HandleEvent_Call) Return() *EventHandler_HandleEvent_Call { + _c.Call.Return() + return _c +} + +func (_c *EventHandler_HandleEvent_Call) RunAndReturn(run func(api.EventPayload)) *EventHandler_HandleEvent_Call { + _c.Call.Return(run) + return _c +} + +// NewEventHandler creates a new instance of EventHandler. 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 NewEventHandler(t interface { + mock.TestingT + Cleanup(func()) +}) *EventHandler { + mock := &EventHandler{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/Feature.go b/mocks/Feature.go new file mode 100644 index 0000000..7c2b360 --- /dev/null +++ b/mocks/Feature.go @@ -0,0 +1,379 @@ +// Code generated by mockery v2.40.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" +) + +// Feature is an autogenerated mock type for the Feature type +type Feature struct { + mock.Mock +} + +type Feature_Expecter struct { + mock *mock.Mock +} + +func (_m *Feature) EXPECT() *Feature_Expecter { + return &Feature_Expecter{mock: &_m.Mock} +} + +// Address provides a mock function with given fields: +func (_m *Feature) Address() *model.FeatureAddressType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Address") + } + + var r0 *model.FeatureAddressType + if rf, ok := ret.Get(0).(func() *model.FeatureAddressType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.FeatureAddressType) + } + } + + return r0 +} + +// Feature_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address' +type Feature_Address_Call struct { + *mock.Call +} + +// Address is a helper method to define mock.On call +func (_e *Feature_Expecter) Address() *Feature_Address_Call { + return &Feature_Address_Call{Call: _e.mock.On("Address")} +} + +func (_c *Feature_Address_Call) Run(run func()) *Feature_Address_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Feature_Address_Call) Return(_a0 *model.FeatureAddressType) *Feature_Address_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Feature_Address_Call) RunAndReturn(run func() *model.FeatureAddressType) *Feature_Address_Call { + _c.Call.Return(run) + return _c +} + +// Description provides a mock function with given fields: +func (_m *Feature) Description() *model.DescriptionType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Description") + } + + var r0 *model.DescriptionType + if rf, ok := ret.Get(0).(func() *model.DescriptionType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.DescriptionType) + } + } + + return r0 +} + +// Feature_Description_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Description' +type Feature_Description_Call struct { + *mock.Call +} + +// Description is a helper method to define mock.On call +func (_e *Feature_Expecter) Description() *Feature_Description_Call { + return &Feature_Description_Call{Call: _e.mock.On("Description")} +} + +func (_c *Feature_Description_Call) Run(run func()) *Feature_Description_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Feature_Description_Call) Return(_a0 *model.DescriptionType) *Feature_Description_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Feature_Description_Call) RunAndReturn(run func() *model.DescriptionType) *Feature_Description_Call { + _c.Call.Return(run) + return _c +} + +// Operations provides a mock function with given fields: +func (_m *Feature) Operations() map[model.FunctionType]api.Operations { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Operations") + } + + var r0 map[model.FunctionType]api.Operations + if rf, ok := ret.Get(0).(func() map[model.FunctionType]api.Operations); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[model.FunctionType]api.Operations) + } + } + + return r0 +} + +// Feature_Operations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Operations' +type Feature_Operations_Call struct { + *mock.Call +} + +// Operations is a helper method to define mock.On call +func (_e *Feature_Expecter) Operations() *Feature_Operations_Call { + return &Feature_Operations_Call{Call: _e.mock.On("Operations")} +} + +func (_c *Feature_Operations_Call) Run(run func()) *Feature_Operations_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Feature_Operations_Call) Return(_a0 map[model.FunctionType]api.Operations) *Feature_Operations_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Feature_Operations_Call) RunAndReturn(run func() map[model.FunctionType]api.Operations) *Feature_Operations_Call { + _c.Call.Return(run) + return _c +} + +// Role provides a mock function with given fields: +func (_m *Feature) Role() model.RoleType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Role") + } + + var r0 model.RoleType + if rf, ok := ret.Get(0).(func() model.RoleType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.RoleType) + } + + return r0 +} + +// Feature_Role_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Role' +type Feature_Role_Call struct { + *mock.Call +} + +// Role is a helper method to define mock.On call +func (_e *Feature_Expecter) Role() *Feature_Role_Call { + return &Feature_Role_Call{Call: _e.mock.On("Role")} +} + +func (_c *Feature_Role_Call) Run(run func()) *Feature_Role_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Feature_Role_Call) Return(_a0 model.RoleType) *Feature_Role_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Feature_Role_Call) RunAndReturn(run func() model.RoleType) *Feature_Role_Call { + _c.Call.Return(run) + return _c +} + +// SetDescription provides a mock function with given fields: desc +func (_m *Feature) SetDescription(desc *model.DescriptionType) { + _m.Called(desc) +} + +// Feature_SetDescription_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDescription' +type Feature_SetDescription_Call struct { + *mock.Call +} + +// SetDescription is a helper method to define mock.On call +// - desc *model.DescriptionType +func (_e *Feature_Expecter) SetDescription(desc interface{}) *Feature_SetDescription_Call { + return &Feature_SetDescription_Call{Call: _e.mock.On("SetDescription", desc)} +} + +func (_c *Feature_SetDescription_Call) Run(run func(desc *model.DescriptionType)) *Feature_SetDescription_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.DescriptionType)) + }) + return _c +} + +func (_c *Feature_SetDescription_Call) Return() *Feature_SetDescription_Call { + _c.Call.Return() + return _c +} + +func (_c *Feature_SetDescription_Call) RunAndReturn(run func(*model.DescriptionType)) *Feature_SetDescription_Call { + _c.Call.Return(run) + return _c +} + +// SetDescriptionString provides a mock function with given fields: s +func (_m *Feature) SetDescriptionString(s string) { + _m.Called(s) +} + +// Feature_SetDescriptionString_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDescriptionString' +type Feature_SetDescriptionString_Call struct { + *mock.Call +} + +// SetDescriptionString is a helper method to define mock.On call +// - s string +func (_e *Feature_Expecter) SetDescriptionString(s interface{}) *Feature_SetDescriptionString_Call { + return &Feature_SetDescriptionString_Call{Call: _e.mock.On("SetDescriptionString", s)} +} + +func (_c *Feature_SetDescriptionString_Call) Run(run func(s string)) *Feature_SetDescriptionString_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *Feature_SetDescriptionString_Call) Return() *Feature_SetDescriptionString_Call { + _c.Call.Return() + return _c +} + +func (_c *Feature_SetDescriptionString_Call) RunAndReturn(run func(string)) *Feature_SetDescriptionString_Call { + _c.Call.Return(run) + return _c +} + +// String provides a mock function with given fields: +func (_m *Feature) String() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for String") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Feature_String_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'String' +type Feature_String_Call struct { + *mock.Call +} + +// String is a helper method to define mock.On call +func (_e *Feature_Expecter) String() *Feature_String_Call { + return &Feature_String_Call{Call: _e.mock.On("String")} +} + +func (_c *Feature_String_Call) Run(run func()) *Feature_String_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Feature_String_Call) Return(_a0 string) *Feature_String_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Feature_String_Call) RunAndReturn(run func() string) *Feature_String_Call { + _c.Call.Return(run) + return _c +} + +// Type provides a mock function with given fields: +func (_m *Feature) Type() model.FeatureTypeType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Type") + } + + var r0 model.FeatureTypeType + if rf, ok := ret.Get(0).(func() model.FeatureTypeType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.FeatureTypeType) + } + + return r0 +} + +// Feature_Type_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Type' +type Feature_Type_Call struct { + *mock.Call +} + +// Type is a helper method to define mock.On call +func (_e *Feature_Expecter) Type() *Feature_Type_Call { + return &Feature_Type_Call{Call: _e.mock.On("Type")} +} + +func (_c *Feature_Type_Call) Run(run func()) *Feature_Type_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Feature_Type_Call) Return(_a0 model.FeatureTypeType) *Feature_Type_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Feature_Type_Call) RunAndReturn(run func() model.FeatureTypeType) *Feature_Type_Call { + _c.Call.Return(run) + return _c +} + +// NewFeature creates a new instance of Feature. 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 NewFeature(t interface { + mock.TestingT + Cleanup(func()) +}) *Feature { + mock := &Feature{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/FeatureLocal.go b/mocks/FeatureLocal.go new file mode 100644 index 0000000..661307b --- /dev/null +++ b/mocks/FeatureLocal.go @@ -0,0 +1,1321 @@ +// Code generated by mockery v2.40.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" + + time "time" +) + +// FeatureLocal is an autogenerated mock type for the FeatureLocal type +type FeatureLocal struct { + mock.Mock +} + +type FeatureLocal_Expecter struct { + mock *mock.Mock +} + +func (_m *FeatureLocal) EXPECT() *FeatureLocal_Expecter { + return &FeatureLocal_Expecter{mock: &_m.Mock} +} + +// AddFunctionType provides a mock function with given fields: function, read, write +func (_m *FeatureLocal) AddFunctionType(function model.FunctionType, read bool, write bool) { + _m.Called(function, read, write) +} + +// FeatureLocal_AddFunctionType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddFunctionType' +type FeatureLocal_AddFunctionType_Call struct { + *mock.Call +} + +// AddFunctionType is a helper method to define mock.On call +// - function model.FunctionType +// - read bool +// - write bool +func (_e *FeatureLocal_Expecter) AddFunctionType(function interface{}, read interface{}, write interface{}) *FeatureLocal_AddFunctionType_Call { + return &FeatureLocal_AddFunctionType_Call{Call: _e.mock.On("AddFunctionType", function, read, write)} +} + +func (_c *FeatureLocal_AddFunctionType_Call) Run(run func(function model.FunctionType, read bool, write bool)) *FeatureLocal_AddFunctionType_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType), args[1].(bool), args[2].(bool)) + }) + return _c +} + +func (_c *FeatureLocal_AddFunctionType_Call) Return() *FeatureLocal_AddFunctionType_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureLocal_AddFunctionType_Call) RunAndReturn(run func(model.FunctionType, bool, bool)) *FeatureLocal_AddFunctionType_Call { + _c.Call.Return(run) + return _c +} + +// AddResultCallback provides a mock function with given fields: msgCounterReference, function +func (_m *FeatureLocal) AddResultCallback(msgCounterReference model.MsgCounterType, function func(api.ResultMessage)) { + _m.Called(msgCounterReference, function) +} + +// FeatureLocal_AddResultCallback_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddResultCallback' +type FeatureLocal_AddResultCallback_Call struct { + *mock.Call +} + +// AddResultCallback is a helper method to define mock.On call +// - msgCounterReference model.MsgCounterType +// - function func(api.ResultMessage) +func (_e *FeatureLocal_Expecter) AddResultCallback(msgCounterReference interface{}, function interface{}) *FeatureLocal_AddResultCallback_Call { + return &FeatureLocal_AddResultCallback_Call{Call: _e.mock.On("AddResultCallback", msgCounterReference, function)} +} + +func (_c *FeatureLocal_AddResultCallback_Call) Run(run func(msgCounterReference model.MsgCounterType, function func(api.ResultMessage))) *FeatureLocal_AddResultCallback_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.MsgCounterType), args[1].(func(api.ResultMessage))) + }) + return _c +} + +func (_c *FeatureLocal_AddResultCallback_Call) Return() *FeatureLocal_AddResultCallback_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureLocal_AddResultCallback_Call) RunAndReturn(run func(model.MsgCounterType, func(api.ResultMessage))) *FeatureLocal_AddResultCallback_Call { + _c.Call.Return(run) + return _c +} + +// AddResultHandler provides a mock function with given fields: handler +func (_m *FeatureLocal) AddResultHandler(handler api.FeatureResult) { + _m.Called(handler) +} + +// FeatureLocal_AddResultHandler_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddResultHandler' +type FeatureLocal_AddResultHandler_Call struct { + *mock.Call +} + +// AddResultHandler is a helper method to define mock.On call +// - handler api.FeatureResult +func (_e *FeatureLocal_Expecter) AddResultHandler(handler interface{}) *FeatureLocal_AddResultHandler_Call { + return &FeatureLocal_AddResultHandler_Call{Call: _e.mock.On("AddResultHandler", handler)} +} + +func (_c *FeatureLocal_AddResultHandler_Call) Run(run func(handler api.FeatureResult)) *FeatureLocal_AddResultHandler_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.FeatureResult)) + }) + return _c +} + +func (_c *FeatureLocal_AddResultHandler_Call) Return() *FeatureLocal_AddResultHandler_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureLocal_AddResultHandler_Call) RunAndReturn(run func(api.FeatureResult)) *FeatureLocal_AddResultHandler_Call { + _c.Call.Return(run) + return _c +} + +// Address provides a mock function with given fields: +func (_m *FeatureLocal) Address() *model.FeatureAddressType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Address") + } + + var r0 *model.FeatureAddressType + if rf, ok := ret.Get(0).(func() *model.FeatureAddressType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.FeatureAddressType) + } + } + + return r0 +} + +// FeatureLocal_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address' +type FeatureLocal_Address_Call struct { + *mock.Call +} + +// Address is a helper method to define mock.On call +func (_e *FeatureLocal_Expecter) Address() *FeatureLocal_Address_Call { + return &FeatureLocal_Address_Call{Call: _e.mock.On("Address")} +} + +func (_c *FeatureLocal_Address_Call) Run(run func()) *FeatureLocal_Address_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureLocal_Address_Call) Return(_a0 *model.FeatureAddressType) *FeatureLocal_Address_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureLocal_Address_Call) RunAndReturn(run func() *model.FeatureAddressType) *FeatureLocal_Address_Call { + _c.Call.Return(run) + return _c +} + +// Bind provides a mock function with given fields: remoteAdress +func (_m *FeatureLocal) Bind(remoteAdress *model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType) { + ret := _m.Called(remoteAdress) + + if len(ret) == 0 { + panic("no return value specified for Bind") + } + + var r0 *model.MsgCounterType + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType)); ok { + return rf(remoteAdress) + } + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType) *model.MsgCounterType); ok { + r0 = rf(remoteAdress) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(*model.FeatureAddressType) *model.ErrorType); ok { + r1 = rf(remoteAdress) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// FeatureLocal_Bind_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Bind' +type FeatureLocal_Bind_Call struct { + *mock.Call +} + +// Bind is a helper method to define mock.On call +// - remoteAdress *model.FeatureAddressType +func (_e *FeatureLocal_Expecter) Bind(remoteAdress interface{}) *FeatureLocal_Bind_Call { + return &FeatureLocal_Bind_Call{Call: _e.mock.On("Bind", remoteAdress)} +} + +func (_c *FeatureLocal_Bind_Call) Run(run func(remoteAdress *model.FeatureAddressType)) *FeatureLocal_Bind_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *FeatureLocal_Bind_Call) Return(_a0 *model.MsgCounterType, _a1 *model.ErrorType) *FeatureLocal_Bind_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FeatureLocal_Bind_Call) RunAndReturn(run func(*model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType)) *FeatureLocal_Bind_Call { + _c.Call.Return(run) + return _c +} + +// DataCopy provides a mock function with given fields: function +func (_m *FeatureLocal) DataCopy(function model.FunctionType) interface{} { + ret := _m.Called(function) + + if len(ret) == 0 { + panic("no return value specified for DataCopy") + } + + var r0 interface{} + if rf, ok := ret.Get(0).(func(model.FunctionType) interface{}); ok { + r0 = rf(function) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + return r0 +} + +// FeatureLocal_DataCopy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DataCopy' +type FeatureLocal_DataCopy_Call struct { + *mock.Call +} + +// DataCopy is a helper method to define mock.On call +// - function model.FunctionType +func (_e *FeatureLocal_Expecter) DataCopy(function interface{}) *FeatureLocal_DataCopy_Call { + return &FeatureLocal_DataCopy_Call{Call: _e.mock.On("DataCopy", function)} +} + +func (_c *FeatureLocal_DataCopy_Call) Run(run func(function model.FunctionType)) *FeatureLocal_DataCopy_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType)) + }) + return _c +} + +func (_c *FeatureLocal_DataCopy_Call) Return(_a0 interface{}) *FeatureLocal_DataCopy_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureLocal_DataCopy_Call) RunAndReturn(run func(model.FunctionType) interface{}) *FeatureLocal_DataCopy_Call { + _c.Call.Return(run) + return _c +} + +// Description provides a mock function with given fields: +func (_m *FeatureLocal) Description() *model.DescriptionType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Description") + } + + var r0 *model.DescriptionType + if rf, ok := ret.Get(0).(func() *model.DescriptionType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.DescriptionType) + } + } + + return r0 +} + +// FeatureLocal_Description_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Description' +type FeatureLocal_Description_Call struct { + *mock.Call +} + +// Description is a helper method to define mock.On call +func (_e *FeatureLocal_Expecter) Description() *FeatureLocal_Description_Call { + return &FeatureLocal_Description_Call{Call: _e.mock.On("Description")} +} + +func (_c *FeatureLocal_Description_Call) Run(run func()) *FeatureLocal_Description_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureLocal_Description_Call) Return(_a0 *model.DescriptionType) *FeatureLocal_Description_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureLocal_Description_Call) RunAndReturn(run func() *model.DescriptionType) *FeatureLocal_Description_Call { + _c.Call.Return(run) + return _c +} + +// Device provides a mock function with given fields: +func (_m *FeatureLocal) Device() api.DeviceLocal { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Device") + } + + var r0 api.DeviceLocal + if rf, ok := ret.Get(0).(func() api.DeviceLocal); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.DeviceLocal) + } + } + + return r0 +} + +// FeatureLocal_Device_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Device' +type FeatureLocal_Device_Call struct { + *mock.Call +} + +// Device is a helper method to define mock.On call +func (_e *FeatureLocal_Expecter) Device() *FeatureLocal_Device_Call { + return &FeatureLocal_Device_Call{Call: _e.mock.On("Device")} +} + +func (_c *FeatureLocal_Device_Call) Run(run func()) *FeatureLocal_Device_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureLocal_Device_Call) Return(_a0 api.DeviceLocal) *FeatureLocal_Device_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureLocal_Device_Call) RunAndReturn(run func() api.DeviceLocal) *FeatureLocal_Device_Call { + _c.Call.Return(run) + return _c +} + +// Entity provides a mock function with given fields: +func (_m *FeatureLocal) Entity() api.EntityLocal { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Entity") + } + + var r0 api.EntityLocal + if rf, ok := ret.Get(0).(func() api.EntityLocal); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.EntityLocal) + } + } + + return r0 +} + +// FeatureLocal_Entity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Entity' +type FeatureLocal_Entity_Call struct { + *mock.Call +} + +// Entity is a helper method to define mock.On call +func (_e *FeatureLocal_Expecter) Entity() *FeatureLocal_Entity_Call { + return &FeatureLocal_Entity_Call{Call: _e.mock.On("Entity")} +} + +func (_c *FeatureLocal_Entity_Call) Run(run func()) *FeatureLocal_Entity_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureLocal_Entity_Call) Return(_a0 api.EntityLocal) *FeatureLocal_Entity_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureLocal_Entity_Call) RunAndReturn(run func() api.EntityLocal) *FeatureLocal_Entity_Call { + _c.Call.Return(run) + return _c +} + +// FetchRequestData provides a mock function with given fields: msgCounter, destination +func (_m *FeatureLocal) FetchRequestData(msgCounter model.MsgCounterType, destination api.FeatureRemote) (interface{}, *model.ErrorType) { + ret := _m.Called(msgCounter, destination) + + if len(ret) == 0 { + panic("no return value specified for FetchRequestData") + } + + var r0 interface{} + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(model.MsgCounterType, api.FeatureRemote) (interface{}, *model.ErrorType)); ok { + return rf(msgCounter, destination) + } + if rf, ok := ret.Get(0).(func(model.MsgCounterType, api.FeatureRemote) interface{}); ok { + r0 = rf(msgCounter, destination) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + if rf, ok := ret.Get(1).(func(model.MsgCounterType, api.FeatureRemote) *model.ErrorType); ok { + r1 = rf(msgCounter, destination) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// FeatureLocal_FetchRequestData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FetchRequestData' +type FeatureLocal_FetchRequestData_Call struct { + *mock.Call +} + +// FetchRequestData is a helper method to define mock.On call +// - msgCounter model.MsgCounterType +// - destination api.FeatureRemote +func (_e *FeatureLocal_Expecter) FetchRequestData(msgCounter interface{}, destination interface{}) *FeatureLocal_FetchRequestData_Call { + return &FeatureLocal_FetchRequestData_Call{Call: _e.mock.On("FetchRequestData", msgCounter, destination)} +} + +func (_c *FeatureLocal_FetchRequestData_Call) Run(run func(msgCounter model.MsgCounterType, destination api.FeatureRemote)) *FeatureLocal_FetchRequestData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.MsgCounterType), args[1].(api.FeatureRemote)) + }) + return _c +} + +func (_c *FeatureLocal_FetchRequestData_Call) Return(_a0 interface{}, _a1 *model.ErrorType) *FeatureLocal_FetchRequestData_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FeatureLocal_FetchRequestData_Call) RunAndReturn(run func(model.MsgCounterType, api.FeatureRemote) (interface{}, *model.ErrorType)) *FeatureLocal_FetchRequestData_Call { + _c.Call.Return(run) + return _c +} + +// HandleMessage provides a mock function with given fields: message +func (_m *FeatureLocal) HandleMessage(message *api.Message) *model.ErrorType { + ret := _m.Called(message) + + if len(ret) == 0 { + panic("no return value specified for HandleMessage") + } + + var r0 *model.ErrorType + if rf, ok := ret.Get(0).(func(*api.Message) *model.ErrorType); ok { + r0 = rf(message) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.ErrorType) + } + } + + return r0 +} + +// FeatureLocal_HandleMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HandleMessage' +type FeatureLocal_HandleMessage_Call struct { + *mock.Call +} + +// HandleMessage is a helper method to define mock.On call +// - message *api.Message +func (_e *FeatureLocal_Expecter) HandleMessage(message interface{}) *FeatureLocal_HandleMessage_Call { + return &FeatureLocal_HandleMessage_Call{Call: _e.mock.On("HandleMessage", message)} +} + +func (_c *FeatureLocal_HandleMessage_Call) Run(run func(message *api.Message)) *FeatureLocal_HandleMessage_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*api.Message)) + }) + return _c +} + +func (_c *FeatureLocal_HandleMessage_Call) Return(_a0 *model.ErrorType) *FeatureLocal_HandleMessage_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureLocal_HandleMessage_Call) RunAndReturn(run func(*api.Message) *model.ErrorType) *FeatureLocal_HandleMessage_Call { + _c.Call.Return(run) + return _c +} + +// Information provides a mock function with given fields: +func (_m *FeatureLocal) Information() *model.NodeManagementDetailedDiscoveryFeatureInformationType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Information") + } + + var r0 *model.NodeManagementDetailedDiscoveryFeatureInformationType + if rf, ok := ret.Get(0).(func() *model.NodeManagementDetailedDiscoveryFeatureInformationType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.NodeManagementDetailedDiscoveryFeatureInformationType) + } + } + + return r0 +} + +// FeatureLocal_Information_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Information' +type FeatureLocal_Information_Call struct { + *mock.Call +} + +// Information is a helper method to define mock.On call +func (_e *FeatureLocal_Expecter) Information() *FeatureLocal_Information_Call { + return &FeatureLocal_Information_Call{Call: _e.mock.On("Information")} +} + +func (_c *FeatureLocal_Information_Call) Run(run func()) *FeatureLocal_Information_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureLocal_Information_Call) Return(_a0 *model.NodeManagementDetailedDiscoveryFeatureInformationType) *FeatureLocal_Information_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureLocal_Information_Call) RunAndReturn(run func() *model.NodeManagementDetailedDiscoveryFeatureInformationType) *FeatureLocal_Information_Call { + _c.Call.Return(run) + return _c +} + +// NotifyData provides a mock function with given fields: function, deleteSelector, partialSelector, partialWithoutSelector, deleteElements, destination +func (_m *FeatureLocal) NotifyData(function model.FunctionType, deleteSelector interface{}, partialSelector interface{}, partialWithoutSelector bool, deleteElements interface{}, destination api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType) { + ret := _m.Called(function, deleteSelector, partialSelector, partialWithoutSelector, deleteElements, destination) + + if len(ret) == 0 { + panic("no return value specified for NotifyData") + } + + var r0 *model.MsgCounterType + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(model.FunctionType, interface{}, interface{}, bool, interface{}, api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType)); ok { + return rf(function, deleteSelector, partialSelector, partialWithoutSelector, deleteElements, destination) + } + if rf, ok := ret.Get(0).(func(model.FunctionType, interface{}, interface{}, bool, interface{}, api.FeatureRemote) *model.MsgCounterType); ok { + r0 = rf(function, deleteSelector, partialSelector, partialWithoutSelector, deleteElements, destination) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(model.FunctionType, interface{}, interface{}, bool, interface{}, api.FeatureRemote) *model.ErrorType); ok { + r1 = rf(function, deleteSelector, partialSelector, partialWithoutSelector, deleteElements, destination) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// FeatureLocal_NotifyData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NotifyData' +type FeatureLocal_NotifyData_Call struct { + *mock.Call +} + +// NotifyData is a helper method to define mock.On call +// - function model.FunctionType +// - deleteSelector interface{} +// - partialSelector interface{} +// - partialWithoutSelector bool +// - deleteElements interface{} +// - destination api.FeatureRemote +func (_e *FeatureLocal_Expecter) NotifyData(function interface{}, deleteSelector interface{}, partialSelector interface{}, partialWithoutSelector interface{}, deleteElements interface{}, destination interface{}) *FeatureLocal_NotifyData_Call { + return &FeatureLocal_NotifyData_Call{Call: _e.mock.On("NotifyData", function, deleteSelector, partialSelector, partialWithoutSelector, deleteElements, destination)} +} + +func (_c *FeatureLocal_NotifyData_Call) Run(run func(function model.FunctionType, deleteSelector interface{}, partialSelector interface{}, partialWithoutSelector bool, deleteElements interface{}, destination api.FeatureRemote)) *FeatureLocal_NotifyData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType), args[1].(interface{}), args[2].(interface{}), args[3].(bool), args[4].(interface{}), args[5].(api.FeatureRemote)) + }) + return _c +} + +func (_c *FeatureLocal_NotifyData_Call) Return(_a0 *model.MsgCounterType, _a1 *model.ErrorType) *FeatureLocal_NotifyData_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FeatureLocal_NotifyData_Call) RunAndReturn(run func(model.FunctionType, interface{}, interface{}, bool, interface{}, api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType)) *FeatureLocal_NotifyData_Call { + _c.Call.Return(run) + return _c +} + +// Operations provides a mock function with given fields: +func (_m *FeatureLocal) Operations() map[model.FunctionType]api.Operations { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Operations") + } + + var r0 map[model.FunctionType]api.Operations + if rf, ok := ret.Get(0).(func() map[model.FunctionType]api.Operations); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[model.FunctionType]api.Operations) + } + } + + return r0 +} + +// FeatureLocal_Operations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Operations' +type FeatureLocal_Operations_Call struct { + *mock.Call +} + +// Operations is a helper method to define mock.On call +func (_e *FeatureLocal_Expecter) Operations() *FeatureLocal_Operations_Call { + return &FeatureLocal_Operations_Call{Call: _e.mock.On("Operations")} +} + +func (_c *FeatureLocal_Operations_Call) Run(run func()) *FeatureLocal_Operations_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureLocal_Operations_Call) Return(_a0 map[model.FunctionType]api.Operations) *FeatureLocal_Operations_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureLocal_Operations_Call) RunAndReturn(run func() map[model.FunctionType]api.Operations) *FeatureLocal_Operations_Call { + _c.Call.Return(run) + return _c +} + +// RemoveAllBindings provides a mock function with given fields: +func (_m *FeatureLocal) RemoveAllBindings() { + _m.Called() +} + +// FeatureLocal_RemoveAllBindings_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveAllBindings' +type FeatureLocal_RemoveAllBindings_Call struct { + *mock.Call +} + +// RemoveAllBindings is a helper method to define mock.On call +func (_e *FeatureLocal_Expecter) RemoveAllBindings() *FeatureLocal_RemoveAllBindings_Call { + return &FeatureLocal_RemoveAllBindings_Call{Call: _e.mock.On("RemoveAllBindings")} +} + +func (_c *FeatureLocal_RemoveAllBindings_Call) Run(run func()) *FeatureLocal_RemoveAllBindings_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureLocal_RemoveAllBindings_Call) Return() *FeatureLocal_RemoveAllBindings_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureLocal_RemoveAllBindings_Call) RunAndReturn(run func()) *FeatureLocal_RemoveAllBindings_Call { + _c.Call.Return(run) + return _c +} + +// RemoveAllSubscriptions provides a mock function with given fields: +func (_m *FeatureLocal) RemoveAllSubscriptions() { + _m.Called() +} + +// FeatureLocal_RemoveAllSubscriptions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveAllSubscriptions' +type FeatureLocal_RemoveAllSubscriptions_Call struct { + *mock.Call +} + +// RemoveAllSubscriptions is a helper method to define mock.On call +func (_e *FeatureLocal_Expecter) RemoveAllSubscriptions() *FeatureLocal_RemoveAllSubscriptions_Call { + return &FeatureLocal_RemoveAllSubscriptions_Call{Call: _e.mock.On("RemoveAllSubscriptions")} +} + +func (_c *FeatureLocal_RemoveAllSubscriptions_Call) Run(run func()) *FeatureLocal_RemoveAllSubscriptions_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureLocal_RemoveAllSubscriptions_Call) Return() *FeatureLocal_RemoveAllSubscriptions_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureLocal_RemoveAllSubscriptions_Call) RunAndReturn(run func()) *FeatureLocal_RemoveAllSubscriptions_Call { + _c.Call.Return(run) + return _c +} + +// RemoveBinding provides a mock function with given fields: remoteAddress +func (_m *FeatureLocal) RemoveBinding(remoteAddress *model.FeatureAddressType) { + _m.Called(remoteAddress) +} + +// FeatureLocal_RemoveBinding_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveBinding' +type FeatureLocal_RemoveBinding_Call struct { + *mock.Call +} + +// RemoveBinding is a helper method to define mock.On call +// - remoteAddress *model.FeatureAddressType +func (_e *FeatureLocal_Expecter) RemoveBinding(remoteAddress interface{}) *FeatureLocal_RemoveBinding_Call { + return &FeatureLocal_RemoveBinding_Call{Call: _e.mock.On("RemoveBinding", remoteAddress)} +} + +func (_c *FeatureLocal_RemoveBinding_Call) Run(run func(remoteAddress *model.FeatureAddressType)) *FeatureLocal_RemoveBinding_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *FeatureLocal_RemoveBinding_Call) Return() *FeatureLocal_RemoveBinding_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureLocal_RemoveBinding_Call) RunAndReturn(run func(*model.FeatureAddressType)) *FeatureLocal_RemoveBinding_Call { + _c.Call.Return(run) + return _c +} + +// RemoveSubscription provides a mock function with given fields: remoteAddress +func (_m *FeatureLocal) RemoveSubscription(remoteAddress *model.FeatureAddressType) { + _m.Called(remoteAddress) +} + +// FeatureLocal_RemoveSubscription_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveSubscription' +type FeatureLocal_RemoveSubscription_Call struct { + *mock.Call +} + +// RemoveSubscription is a helper method to define mock.On call +// - remoteAddress *model.FeatureAddressType +func (_e *FeatureLocal_Expecter) RemoveSubscription(remoteAddress interface{}) *FeatureLocal_RemoveSubscription_Call { + return &FeatureLocal_RemoveSubscription_Call{Call: _e.mock.On("RemoveSubscription", remoteAddress)} +} + +func (_c *FeatureLocal_RemoveSubscription_Call) Run(run func(remoteAddress *model.FeatureAddressType)) *FeatureLocal_RemoveSubscription_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *FeatureLocal_RemoveSubscription_Call) Return() *FeatureLocal_RemoveSubscription_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureLocal_RemoveSubscription_Call) RunAndReturn(run func(*model.FeatureAddressType)) *FeatureLocal_RemoveSubscription_Call { + _c.Call.Return(run) + return _c +} + +// RequestData provides a mock function with given fields: function, selector, elements, destination +func (_m *FeatureLocal) RequestData(function model.FunctionType, selector interface{}, elements interface{}, destination api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType) { + ret := _m.Called(function, selector, elements, destination) + + if len(ret) == 0 { + panic("no return value specified for RequestData") + } + + var r0 *model.MsgCounterType + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(model.FunctionType, interface{}, interface{}, api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType)); ok { + return rf(function, selector, elements, destination) + } + if rf, ok := ret.Get(0).(func(model.FunctionType, interface{}, interface{}, api.FeatureRemote) *model.MsgCounterType); ok { + r0 = rf(function, selector, elements, destination) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(model.FunctionType, interface{}, interface{}, api.FeatureRemote) *model.ErrorType); ok { + r1 = rf(function, selector, elements, destination) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// FeatureLocal_RequestData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestData' +type FeatureLocal_RequestData_Call struct { + *mock.Call +} + +// RequestData is a helper method to define mock.On call +// - function model.FunctionType +// - selector interface{} +// - elements interface{} +// - destination api.FeatureRemote +func (_e *FeatureLocal_Expecter) RequestData(function interface{}, selector interface{}, elements interface{}, destination interface{}) *FeatureLocal_RequestData_Call { + return &FeatureLocal_RequestData_Call{Call: _e.mock.On("RequestData", function, selector, elements, destination)} +} + +func (_c *FeatureLocal_RequestData_Call) Run(run func(function model.FunctionType, selector interface{}, elements interface{}, destination api.FeatureRemote)) *FeatureLocal_RequestData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType), args[1].(interface{}), args[2].(interface{}), args[3].(api.FeatureRemote)) + }) + return _c +} + +func (_c *FeatureLocal_RequestData_Call) Return(_a0 *model.MsgCounterType, _a1 *model.ErrorType) *FeatureLocal_RequestData_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FeatureLocal_RequestData_Call) RunAndReturn(run func(model.FunctionType, interface{}, interface{}, api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType)) *FeatureLocal_RequestData_Call { + _c.Call.Return(run) + return _c +} + +// RequestDataBySenderAddress provides a mock function with given fields: cmd, sender, destinationSki, destinationAddress, maxDelay +func (_m *FeatureLocal) RequestDataBySenderAddress(cmd model.CmdType, sender api.Sender, destinationSki string, destinationAddress *model.FeatureAddressType, maxDelay time.Duration) (*model.MsgCounterType, *model.ErrorType) { + ret := _m.Called(cmd, sender, destinationSki, destinationAddress, maxDelay) + + if len(ret) == 0 { + panic("no return value specified for RequestDataBySenderAddress") + } + + var r0 *model.MsgCounterType + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(model.CmdType, api.Sender, string, *model.FeatureAddressType, time.Duration) (*model.MsgCounterType, *model.ErrorType)); ok { + return rf(cmd, sender, destinationSki, destinationAddress, maxDelay) + } + if rf, ok := ret.Get(0).(func(model.CmdType, api.Sender, string, *model.FeatureAddressType, time.Duration) *model.MsgCounterType); ok { + r0 = rf(cmd, sender, destinationSki, destinationAddress, maxDelay) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(model.CmdType, api.Sender, string, *model.FeatureAddressType, time.Duration) *model.ErrorType); ok { + r1 = rf(cmd, sender, destinationSki, destinationAddress, maxDelay) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// FeatureLocal_RequestDataBySenderAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestDataBySenderAddress' +type FeatureLocal_RequestDataBySenderAddress_Call struct { + *mock.Call +} + +// RequestDataBySenderAddress is a helper method to define mock.On call +// - cmd model.CmdType +// - sender api.Sender +// - destinationSki string +// - destinationAddress *model.FeatureAddressType +// - maxDelay time.Duration +func (_e *FeatureLocal_Expecter) RequestDataBySenderAddress(cmd interface{}, sender interface{}, destinationSki interface{}, destinationAddress interface{}, maxDelay interface{}) *FeatureLocal_RequestDataBySenderAddress_Call { + return &FeatureLocal_RequestDataBySenderAddress_Call{Call: _e.mock.On("RequestDataBySenderAddress", cmd, sender, destinationSki, destinationAddress, maxDelay)} +} + +func (_c *FeatureLocal_RequestDataBySenderAddress_Call) Run(run func(cmd model.CmdType, sender api.Sender, destinationSki string, destinationAddress *model.FeatureAddressType, maxDelay time.Duration)) *FeatureLocal_RequestDataBySenderAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.CmdType), args[1].(api.Sender), args[2].(string), args[3].(*model.FeatureAddressType), args[4].(time.Duration)) + }) + return _c +} + +func (_c *FeatureLocal_RequestDataBySenderAddress_Call) Return(_a0 *model.MsgCounterType, _a1 *model.ErrorType) *FeatureLocal_RequestDataBySenderAddress_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FeatureLocal_RequestDataBySenderAddress_Call) RunAndReturn(run func(model.CmdType, api.Sender, string, *model.FeatureAddressType, time.Duration) (*model.MsgCounterType, *model.ErrorType)) *FeatureLocal_RequestDataBySenderAddress_Call { + _c.Call.Return(run) + return _c +} + +// Role provides a mock function with given fields: +func (_m *FeatureLocal) Role() model.RoleType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Role") + } + + var r0 model.RoleType + if rf, ok := ret.Get(0).(func() model.RoleType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.RoleType) + } + + return r0 +} + +// FeatureLocal_Role_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Role' +type FeatureLocal_Role_Call struct { + *mock.Call +} + +// Role is a helper method to define mock.On call +func (_e *FeatureLocal_Expecter) Role() *FeatureLocal_Role_Call { + return &FeatureLocal_Role_Call{Call: _e.mock.On("Role")} +} + +func (_c *FeatureLocal_Role_Call) Run(run func()) *FeatureLocal_Role_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureLocal_Role_Call) Return(_a0 model.RoleType) *FeatureLocal_Role_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureLocal_Role_Call) RunAndReturn(run func() model.RoleType) *FeatureLocal_Role_Call { + _c.Call.Return(run) + return _c +} + +// SetData provides a mock function with given fields: function, data +func (_m *FeatureLocal) SetData(function model.FunctionType, data interface{}) { + _m.Called(function, data) +} + +// FeatureLocal_SetData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetData' +type FeatureLocal_SetData_Call struct { + *mock.Call +} + +// SetData is a helper method to define mock.On call +// - function model.FunctionType +// - data interface{} +func (_e *FeatureLocal_Expecter) SetData(function interface{}, data interface{}) *FeatureLocal_SetData_Call { + return &FeatureLocal_SetData_Call{Call: _e.mock.On("SetData", function, data)} +} + +func (_c *FeatureLocal_SetData_Call) Run(run func(function model.FunctionType, data interface{})) *FeatureLocal_SetData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType), args[1].(interface{})) + }) + return _c +} + +func (_c *FeatureLocal_SetData_Call) Return() *FeatureLocal_SetData_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureLocal_SetData_Call) RunAndReturn(run func(model.FunctionType, interface{})) *FeatureLocal_SetData_Call { + _c.Call.Return(run) + return _c +} + +// SetDescription provides a mock function with given fields: desc +func (_m *FeatureLocal) SetDescription(desc *model.DescriptionType) { + _m.Called(desc) +} + +// FeatureLocal_SetDescription_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDescription' +type FeatureLocal_SetDescription_Call struct { + *mock.Call +} + +// SetDescription is a helper method to define mock.On call +// - desc *model.DescriptionType +func (_e *FeatureLocal_Expecter) SetDescription(desc interface{}) *FeatureLocal_SetDescription_Call { + return &FeatureLocal_SetDescription_Call{Call: _e.mock.On("SetDescription", desc)} +} + +func (_c *FeatureLocal_SetDescription_Call) Run(run func(desc *model.DescriptionType)) *FeatureLocal_SetDescription_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.DescriptionType)) + }) + return _c +} + +func (_c *FeatureLocal_SetDescription_Call) Return() *FeatureLocal_SetDescription_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureLocal_SetDescription_Call) RunAndReturn(run func(*model.DescriptionType)) *FeatureLocal_SetDescription_Call { + _c.Call.Return(run) + return _c +} + +// SetDescriptionString provides a mock function with given fields: s +func (_m *FeatureLocal) SetDescriptionString(s string) { + _m.Called(s) +} + +// FeatureLocal_SetDescriptionString_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDescriptionString' +type FeatureLocal_SetDescriptionString_Call struct { + *mock.Call +} + +// SetDescriptionString is a helper method to define mock.On call +// - s string +func (_e *FeatureLocal_Expecter) SetDescriptionString(s interface{}) *FeatureLocal_SetDescriptionString_Call { + return &FeatureLocal_SetDescriptionString_Call{Call: _e.mock.On("SetDescriptionString", s)} +} + +func (_c *FeatureLocal_SetDescriptionString_Call) Run(run func(s string)) *FeatureLocal_SetDescriptionString_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *FeatureLocal_SetDescriptionString_Call) Return() *FeatureLocal_SetDescriptionString_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureLocal_SetDescriptionString_Call) RunAndReturn(run func(string)) *FeatureLocal_SetDescriptionString_Call { + _c.Call.Return(run) + return _c +} + +// String provides a mock function with given fields: +func (_m *FeatureLocal) String() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for String") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// FeatureLocal_String_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'String' +type FeatureLocal_String_Call struct { + *mock.Call +} + +// String is a helper method to define mock.On call +func (_e *FeatureLocal_Expecter) String() *FeatureLocal_String_Call { + return &FeatureLocal_String_Call{Call: _e.mock.On("String")} +} + +func (_c *FeatureLocal_String_Call) Run(run func()) *FeatureLocal_String_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureLocal_String_Call) Return(_a0 string) *FeatureLocal_String_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureLocal_String_Call) RunAndReturn(run func() string) *FeatureLocal_String_Call { + _c.Call.Return(run) + return _c +} + +// Subscribe provides a mock function with given fields: remoteAdress +func (_m *FeatureLocal) Subscribe(remoteAdress *model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType) { + ret := _m.Called(remoteAdress) + + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + + var r0 *model.MsgCounterType + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType)); ok { + return rf(remoteAdress) + } + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType) *model.MsgCounterType); ok { + r0 = rf(remoteAdress) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(*model.FeatureAddressType) *model.ErrorType); ok { + r1 = rf(remoteAdress) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// FeatureLocal_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe' +type FeatureLocal_Subscribe_Call struct { + *mock.Call +} + +// Subscribe is a helper method to define mock.On call +// - remoteAdress *model.FeatureAddressType +func (_e *FeatureLocal_Expecter) Subscribe(remoteAdress interface{}) *FeatureLocal_Subscribe_Call { + return &FeatureLocal_Subscribe_Call{Call: _e.mock.On("Subscribe", remoteAdress)} +} + +func (_c *FeatureLocal_Subscribe_Call) Run(run func(remoteAdress *model.FeatureAddressType)) *FeatureLocal_Subscribe_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *FeatureLocal_Subscribe_Call) Return(_a0 *model.MsgCounterType, _a1 *model.ErrorType) *FeatureLocal_Subscribe_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FeatureLocal_Subscribe_Call) RunAndReturn(run func(*model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType)) *FeatureLocal_Subscribe_Call { + _c.Call.Return(run) + return _c +} + +// Type provides a mock function with given fields: +func (_m *FeatureLocal) Type() model.FeatureTypeType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Type") + } + + var r0 model.FeatureTypeType + if rf, ok := ret.Get(0).(func() model.FeatureTypeType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.FeatureTypeType) + } + + return r0 +} + +// FeatureLocal_Type_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Type' +type FeatureLocal_Type_Call struct { + *mock.Call +} + +// Type is a helper method to define mock.On call +func (_e *FeatureLocal_Expecter) Type() *FeatureLocal_Type_Call { + return &FeatureLocal_Type_Call{Call: _e.mock.On("Type")} +} + +func (_c *FeatureLocal_Type_Call) Run(run func()) *FeatureLocal_Type_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureLocal_Type_Call) Return(_a0 model.FeatureTypeType) *FeatureLocal_Type_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureLocal_Type_Call) RunAndReturn(run func() model.FeatureTypeType) *FeatureLocal_Type_Call { + _c.Call.Return(run) + return _c +} + +// WriteData provides a mock function with given fields: function, deleteSelector, partialSelector, deleteElements, destination +func (_m *FeatureLocal) WriteData(function model.FunctionType, deleteSelector interface{}, partialSelector interface{}, deleteElements interface{}, destination api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType) { + ret := _m.Called(function, deleteSelector, partialSelector, deleteElements, destination) + + if len(ret) == 0 { + panic("no return value specified for WriteData") + } + + var r0 *model.MsgCounterType + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(model.FunctionType, interface{}, interface{}, interface{}, api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType)); ok { + return rf(function, deleteSelector, partialSelector, deleteElements, destination) + } + if rf, ok := ret.Get(0).(func(model.FunctionType, interface{}, interface{}, interface{}, api.FeatureRemote) *model.MsgCounterType); ok { + r0 = rf(function, deleteSelector, partialSelector, deleteElements, destination) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(model.FunctionType, interface{}, interface{}, interface{}, api.FeatureRemote) *model.ErrorType); ok { + r1 = rf(function, deleteSelector, partialSelector, deleteElements, destination) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// FeatureLocal_WriteData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WriteData' +type FeatureLocal_WriteData_Call struct { + *mock.Call +} + +// WriteData is a helper method to define mock.On call +// - function model.FunctionType +// - deleteSelector interface{} +// - partialSelector interface{} +// - deleteElements interface{} +// - destination api.FeatureRemote +func (_e *FeatureLocal_Expecter) WriteData(function interface{}, deleteSelector interface{}, partialSelector interface{}, deleteElements interface{}, destination interface{}) *FeatureLocal_WriteData_Call { + return &FeatureLocal_WriteData_Call{Call: _e.mock.On("WriteData", function, deleteSelector, partialSelector, deleteElements, destination)} +} + +func (_c *FeatureLocal_WriteData_Call) Run(run func(function model.FunctionType, deleteSelector interface{}, partialSelector interface{}, deleteElements interface{}, destination api.FeatureRemote)) *FeatureLocal_WriteData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType), args[1].(interface{}), args[2].(interface{}), args[3].(interface{}), args[4].(api.FeatureRemote)) + }) + return _c +} + +func (_c *FeatureLocal_WriteData_Call) Return(_a0 *model.MsgCounterType, _a1 *model.ErrorType) *FeatureLocal_WriteData_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *FeatureLocal_WriteData_Call) RunAndReturn(run func(model.FunctionType, interface{}, interface{}, interface{}, api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType)) *FeatureLocal_WriteData_Call { + _c.Call.Return(run) + return _c +} + +// NewFeatureLocal creates a new instance of FeatureLocal. 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 NewFeatureLocal(t interface { + mock.TestingT + Cleanup(func()) +}) *FeatureLocal { + mock := &FeatureLocal{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/FeatureRemote.go b/mocks/FeatureRemote.go new file mode 100644 index 0000000..8ab69a7 --- /dev/null +++ b/mocks/FeatureRemote.go @@ -0,0 +1,751 @@ +// Code generated by mockery v2.40.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" + + time "time" +) + +// FeatureRemote is an autogenerated mock type for the FeatureRemote type +type FeatureRemote struct { + mock.Mock +} + +type FeatureRemote_Expecter struct { + mock *mock.Mock +} + +func (_m *FeatureRemote) EXPECT() *FeatureRemote_Expecter { + return &FeatureRemote_Expecter{mock: &_m.Mock} +} + +// Address provides a mock function with given fields: +func (_m *FeatureRemote) Address() *model.FeatureAddressType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Address") + } + + var r0 *model.FeatureAddressType + if rf, ok := ret.Get(0).(func() *model.FeatureAddressType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.FeatureAddressType) + } + } + + return r0 +} + +// FeatureRemote_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address' +type FeatureRemote_Address_Call struct { + *mock.Call +} + +// Address is a helper method to define mock.On call +func (_e *FeatureRemote_Expecter) Address() *FeatureRemote_Address_Call { + return &FeatureRemote_Address_Call{Call: _e.mock.On("Address")} +} + +func (_c *FeatureRemote_Address_Call) Run(run func()) *FeatureRemote_Address_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureRemote_Address_Call) Return(_a0 *model.FeatureAddressType) *FeatureRemote_Address_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureRemote_Address_Call) RunAndReturn(run func() *model.FeatureAddressType) *FeatureRemote_Address_Call { + _c.Call.Return(run) + return _c +} + +// DataCopy provides a mock function with given fields: function +func (_m *FeatureRemote) DataCopy(function model.FunctionType) interface{} { + ret := _m.Called(function) + + if len(ret) == 0 { + panic("no return value specified for DataCopy") + } + + var r0 interface{} + if rf, ok := ret.Get(0).(func(model.FunctionType) interface{}); ok { + r0 = rf(function) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + return r0 +} + +// FeatureRemote_DataCopy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DataCopy' +type FeatureRemote_DataCopy_Call struct { + *mock.Call +} + +// DataCopy is a helper method to define mock.On call +// - function model.FunctionType +func (_e *FeatureRemote_Expecter) DataCopy(function interface{}) *FeatureRemote_DataCopy_Call { + return &FeatureRemote_DataCopy_Call{Call: _e.mock.On("DataCopy", function)} +} + +func (_c *FeatureRemote_DataCopy_Call) Run(run func(function model.FunctionType)) *FeatureRemote_DataCopy_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType)) + }) + return _c +} + +func (_c *FeatureRemote_DataCopy_Call) Return(_a0 interface{}) *FeatureRemote_DataCopy_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureRemote_DataCopy_Call) RunAndReturn(run func(model.FunctionType) interface{}) *FeatureRemote_DataCopy_Call { + _c.Call.Return(run) + return _c +} + +// Description provides a mock function with given fields: +func (_m *FeatureRemote) Description() *model.DescriptionType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Description") + } + + var r0 *model.DescriptionType + if rf, ok := ret.Get(0).(func() *model.DescriptionType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.DescriptionType) + } + } + + return r0 +} + +// FeatureRemote_Description_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Description' +type FeatureRemote_Description_Call struct { + *mock.Call +} + +// Description is a helper method to define mock.On call +func (_e *FeatureRemote_Expecter) Description() *FeatureRemote_Description_Call { + return &FeatureRemote_Description_Call{Call: _e.mock.On("Description")} +} + +func (_c *FeatureRemote_Description_Call) Run(run func()) *FeatureRemote_Description_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureRemote_Description_Call) Return(_a0 *model.DescriptionType) *FeatureRemote_Description_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureRemote_Description_Call) RunAndReturn(run func() *model.DescriptionType) *FeatureRemote_Description_Call { + _c.Call.Return(run) + return _c +} + +// Device provides a mock function with given fields: +func (_m *FeatureRemote) Device() api.DeviceRemote { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Device") + } + + var r0 api.DeviceRemote + if rf, ok := ret.Get(0).(func() api.DeviceRemote); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.DeviceRemote) + } + } + + return r0 +} + +// FeatureRemote_Device_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Device' +type FeatureRemote_Device_Call struct { + *mock.Call +} + +// Device is a helper method to define mock.On call +func (_e *FeatureRemote_Expecter) Device() *FeatureRemote_Device_Call { + return &FeatureRemote_Device_Call{Call: _e.mock.On("Device")} +} + +func (_c *FeatureRemote_Device_Call) Run(run func()) *FeatureRemote_Device_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureRemote_Device_Call) Return(_a0 api.DeviceRemote) *FeatureRemote_Device_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureRemote_Device_Call) RunAndReturn(run func() api.DeviceRemote) *FeatureRemote_Device_Call { + _c.Call.Return(run) + return _c +} + +// Entity provides a mock function with given fields: +func (_m *FeatureRemote) Entity() api.EntityRemote { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Entity") + } + + var r0 api.EntityRemote + if rf, ok := ret.Get(0).(func() api.EntityRemote); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.EntityRemote) + } + } + + return r0 +} + +// FeatureRemote_Entity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Entity' +type FeatureRemote_Entity_Call struct { + *mock.Call +} + +// Entity is a helper method to define mock.On call +func (_e *FeatureRemote_Expecter) Entity() *FeatureRemote_Entity_Call { + return &FeatureRemote_Entity_Call{Call: _e.mock.On("Entity")} +} + +func (_c *FeatureRemote_Entity_Call) Run(run func()) *FeatureRemote_Entity_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureRemote_Entity_Call) Return(_a0 api.EntityRemote) *FeatureRemote_Entity_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureRemote_Entity_Call) RunAndReturn(run func() api.EntityRemote) *FeatureRemote_Entity_Call { + _c.Call.Return(run) + return _c +} + +// MaxResponseDelayDuration provides a mock function with given fields: +func (_m *FeatureRemote) MaxResponseDelayDuration() time.Duration { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for MaxResponseDelayDuration") + } + + var r0 time.Duration + if rf, ok := ret.Get(0).(func() time.Duration); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(time.Duration) + } + + return r0 +} + +// FeatureRemote_MaxResponseDelayDuration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MaxResponseDelayDuration' +type FeatureRemote_MaxResponseDelayDuration_Call struct { + *mock.Call +} + +// MaxResponseDelayDuration is a helper method to define mock.On call +func (_e *FeatureRemote_Expecter) MaxResponseDelayDuration() *FeatureRemote_MaxResponseDelayDuration_Call { + return &FeatureRemote_MaxResponseDelayDuration_Call{Call: _e.mock.On("MaxResponseDelayDuration")} +} + +func (_c *FeatureRemote_MaxResponseDelayDuration_Call) Run(run func()) *FeatureRemote_MaxResponseDelayDuration_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureRemote_MaxResponseDelayDuration_Call) Return(_a0 time.Duration) *FeatureRemote_MaxResponseDelayDuration_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureRemote_MaxResponseDelayDuration_Call) RunAndReturn(run func() time.Duration) *FeatureRemote_MaxResponseDelayDuration_Call { + _c.Call.Return(run) + return _c +} + +// Operations provides a mock function with given fields: +func (_m *FeatureRemote) Operations() map[model.FunctionType]api.Operations { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Operations") + } + + var r0 map[model.FunctionType]api.Operations + if rf, ok := ret.Get(0).(func() map[model.FunctionType]api.Operations); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[model.FunctionType]api.Operations) + } + } + + return r0 +} + +// FeatureRemote_Operations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Operations' +type FeatureRemote_Operations_Call struct { + *mock.Call +} + +// Operations is a helper method to define mock.On call +func (_e *FeatureRemote_Expecter) Operations() *FeatureRemote_Operations_Call { + return &FeatureRemote_Operations_Call{Call: _e.mock.On("Operations")} +} + +func (_c *FeatureRemote_Operations_Call) Run(run func()) *FeatureRemote_Operations_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureRemote_Operations_Call) Return(_a0 map[model.FunctionType]api.Operations) *FeatureRemote_Operations_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureRemote_Operations_Call) RunAndReturn(run func() map[model.FunctionType]api.Operations) *FeatureRemote_Operations_Call { + _c.Call.Return(run) + return _c +} + +// Role provides a mock function with given fields: +func (_m *FeatureRemote) Role() model.RoleType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Role") + } + + var r0 model.RoleType + if rf, ok := ret.Get(0).(func() model.RoleType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.RoleType) + } + + return r0 +} + +// FeatureRemote_Role_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Role' +type FeatureRemote_Role_Call struct { + *mock.Call +} + +// Role is a helper method to define mock.On call +func (_e *FeatureRemote_Expecter) Role() *FeatureRemote_Role_Call { + return &FeatureRemote_Role_Call{Call: _e.mock.On("Role")} +} + +func (_c *FeatureRemote_Role_Call) Run(run func()) *FeatureRemote_Role_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureRemote_Role_Call) Return(_a0 model.RoleType) *FeatureRemote_Role_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureRemote_Role_Call) RunAndReturn(run func() model.RoleType) *FeatureRemote_Role_Call { + _c.Call.Return(run) + return _c +} + +// Sender provides a mock function with given fields: +func (_m *FeatureRemote) Sender() api.Sender { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Sender") + } + + var r0 api.Sender + if rf, ok := ret.Get(0).(func() api.Sender); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.Sender) + } + } + + return r0 +} + +// FeatureRemote_Sender_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Sender' +type FeatureRemote_Sender_Call struct { + *mock.Call +} + +// Sender is a helper method to define mock.On call +func (_e *FeatureRemote_Expecter) Sender() *FeatureRemote_Sender_Call { + return &FeatureRemote_Sender_Call{Call: _e.mock.On("Sender")} +} + +func (_c *FeatureRemote_Sender_Call) Run(run func()) *FeatureRemote_Sender_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureRemote_Sender_Call) Return(_a0 api.Sender) *FeatureRemote_Sender_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureRemote_Sender_Call) RunAndReturn(run func() api.Sender) *FeatureRemote_Sender_Call { + _c.Call.Return(run) + return _c +} + +// SetData provides a mock function with given fields: function, data +func (_m *FeatureRemote) SetData(function model.FunctionType, data interface{}) { + _m.Called(function, data) +} + +// FeatureRemote_SetData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetData' +type FeatureRemote_SetData_Call struct { + *mock.Call +} + +// SetData is a helper method to define mock.On call +// - function model.FunctionType +// - data interface{} +func (_e *FeatureRemote_Expecter) SetData(function interface{}, data interface{}) *FeatureRemote_SetData_Call { + return &FeatureRemote_SetData_Call{Call: _e.mock.On("SetData", function, data)} +} + +func (_c *FeatureRemote_SetData_Call) Run(run func(function model.FunctionType, data interface{})) *FeatureRemote_SetData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType), args[1].(interface{})) + }) + return _c +} + +func (_c *FeatureRemote_SetData_Call) Return() *FeatureRemote_SetData_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureRemote_SetData_Call) RunAndReturn(run func(model.FunctionType, interface{})) *FeatureRemote_SetData_Call { + _c.Call.Return(run) + return _c +} + +// SetDescription provides a mock function with given fields: desc +func (_m *FeatureRemote) SetDescription(desc *model.DescriptionType) { + _m.Called(desc) +} + +// FeatureRemote_SetDescription_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDescription' +type FeatureRemote_SetDescription_Call struct { + *mock.Call +} + +// SetDescription is a helper method to define mock.On call +// - desc *model.DescriptionType +func (_e *FeatureRemote_Expecter) SetDescription(desc interface{}) *FeatureRemote_SetDescription_Call { + return &FeatureRemote_SetDescription_Call{Call: _e.mock.On("SetDescription", desc)} +} + +func (_c *FeatureRemote_SetDescription_Call) Run(run func(desc *model.DescriptionType)) *FeatureRemote_SetDescription_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.DescriptionType)) + }) + return _c +} + +func (_c *FeatureRemote_SetDescription_Call) Return() *FeatureRemote_SetDescription_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureRemote_SetDescription_Call) RunAndReturn(run func(*model.DescriptionType)) *FeatureRemote_SetDescription_Call { + _c.Call.Return(run) + return _c +} + +// SetDescriptionString provides a mock function with given fields: s +func (_m *FeatureRemote) SetDescriptionString(s string) { + _m.Called(s) +} + +// FeatureRemote_SetDescriptionString_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDescriptionString' +type FeatureRemote_SetDescriptionString_Call struct { + *mock.Call +} + +// SetDescriptionString is a helper method to define mock.On call +// - s string +func (_e *FeatureRemote_Expecter) SetDescriptionString(s interface{}) *FeatureRemote_SetDescriptionString_Call { + return &FeatureRemote_SetDescriptionString_Call{Call: _e.mock.On("SetDescriptionString", s)} +} + +func (_c *FeatureRemote_SetDescriptionString_Call) Run(run func(s string)) *FeatureRemote_SetDescriptionString_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *FeatureRemote_SetDescriptionString_Call) Return() *FeatureRemote_SetDescriptionString_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureRemote_SetDescriptionString_Call) RunAndReturn(run func(string)) *FeatureRemote_SetDescriptionString_Call { + _c.Call.Return(run) + return _c +} + +// SetMaxResponseDelay provides a mock function with given fields: delay +func (_m *FeatureRemote) SetMaxResponseDelay(delay *model.MaxResponseDelayType) { + _m.Called(delay) +} + +// FeatureRemote_SetMaxResponseDelay_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetMaxResponseDelay' +type FeatureRemote_SetMaxResponseDelay_Call struct { + *mock.Call +} + +// SetMaxResponseDelay is a helper method to define mock.On call +// - delay *model.MaxResponseDelayType +func (_e *FeatureRemote_Expecter) SetMaxResponseDelay(delay interface{}) *FeatureRemote_SetMaxResponseDelay_Call { + return &FeatureRemote_SetMaxResponseDelay_Call{Call: _e.mock.On("SetMaxResponseDelay", delay)} +} + +func (_c *FeatureRemote_SetMaxResponseDelay_Call) Run(run func(delay *model.MaxResponseDelayType)) *FeatureRemote_SetMaxResponseDelay_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.MaxResponseDelayType)) + }) + return _c +} + +func (_c *FeatureRemote_SetMaxResponseDelay_Call) Return() *FeatureRemote_SetMaxResponseDelay_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureRemote_SetMaxResponseDelay_Call) RunAndReturn(run func(*model.MaxResponseDelayType)) *FeatureRemote_SetMaxResponseDelay_Call { + _c.Call.Return(run) + return _c +} + +// SetOperations provides a mock function with given fields: functions +func (_m *FeatureRemote) SetOperations(functions []model.FunctionPropertyType) { + _m.Called(functions) +} + +// FeatureRemote_SetOperations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetOperations' +type FeatureRemote_SetOperations_Call struct { + *mock.Call +} + +// SetOperations is a helper method to define mock.On call +// - functions []model.FunctionPropertyType +func (_e *FeatureRemote_Expecter) SetOperations(functions interface{}) *FeatureRemote_SetOperations_Call { + return &FeatureRemote_SetOperations_Call{Call: _e.mock.On("SetOperations", functions)} +} + +func (_c *FeatureRemote_SetOperations_Call) Run(run func(functions []model.FunctionPropertyType)) *FeatureRemote_SetOperations_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]model.FunctionPropertyType)) + }) + return _c +} + +func (_c *FeatureRemote_SetOperations_Call) Return() *FeatureRemote_SetOperations_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureRemote_SetOperations_Call) RunAndReturn(run func([]model.FunctionPropertyType)) *FeatureRemote_SetOperations_Call { + _c.Call.Return(run) + return _c +} + +// String provides a mock function with given fields: +func (_m *FeatureRemote) String() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for String") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// FeatureRemote_String_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'String' +type FeatureRemote_String_Call struct { + *mock.Call +} + +// String is a helper method to define mock.On call +func (_e *FeatureRemote_Expecter) String() *FeatureRemote_String_Call { + return &FeatureRemote_String_Call{Call: _e.mock.On("String")} +} + +func (_c *FeatureRemote_String_Call) Run(run func()) *FeatureRemote_String_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureRemote_String_Call) Return(_a0 string) *FeatureRemote_String_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureRemote_String_Call) RunAndReturn(run func() string) *FeatureRemote_String_Call { + _c.Call.Return(run) + return _c +} + +// Type provides a mock function with given fields: +func (_m *FeatureRemote) Type() model.FeatureTypeType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Type") + } + + var r0 model.FeatureTypeType + if rf, ok := ret.Get(0).(func() model.FeatureTypeType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.FeatureTypeType) + } + + return r0 +} + +// FeatureRemote_Type_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Type' +type FeatureRemote_Type_Call struct { + *mock.Call +} + +// Type is a helper method to define mock.On call +func (_e *FeatureRemote_Expecter) Type() *FeatureRemote_Type_Call { + return &FeatureRemote_Type_Call{Call: _e.mock.On("Type")} +} + +func (_c *FeatureRemote_Type_Call) Run(run func()) *FeatureRemote_Type_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FeatureRemote_Type_Call) Return(_a0 model.FeatureTypeType) *FeatureRemote_Type_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FeatureRemote_Type_Call) RunAndReturn(run func() model.FeatureTypeType) *FeatureRemote_Type_Call { + _c.Call.Return(run) + return _c +} + +// UpdateData provides a mock function with given fields: function, data, filterPartial, filterDelete +func (_m *FeatureRemote) UpdateData(function model.FunctionType, data interface{}, filterPartial *model.FilterType, filterDelete *model.FilterType) { + _m.Called(function, data, filterPartial, filterDelete) +} + +// FeatureRemote_UpdateData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateData' +type FeatureRemote_UpdateData_Call struct { + *mock.Call +} + +// UpdateData is a helper method to define mock.On call +// - function model.FunctionType +// - data interface{} +// - filterPartial *model.FilterType +// - filterDelete *model.FilterType +func (_e *FeatureRemote_Expecter) UpdateData(function interface{}, data interface{}, filterPartial interface{}, filterDelete interface{}) *FeatureRemote_UpdateData_Call { + return &FeatureRemote_UpdateData_Call{Call: _e.mock.On("UpdateData", function, data, filterPartial, filterDelete)} +} + +func (_c *FeatureRemote_UpdateData_Call) Run(run func(function model.FunctionType, data interface{}, filterPartial *model.FilterType, filterDelete *model.FilterType)) *FeatureRemote_UpdateData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType), args[1].(interface{}), args[2].(*model.FilterType), args[3].(*model.FilterType)) + }) + return _c +} + +func (_c *FeatureRemote_UpdateData_Call) Return() *FeatureRemote_UpdateData_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureRemote_UpdateData_Call) RunAndReturn(run func(model.FunctionType, interface{}, *model.FilterType, *model.FilterType)) *FeatureRemote_UpdateData_Call { + _c.Call.Return(run) + return _c +} + +// NewFeatureRemote creates a new instance of FeatureRemote. 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 NewFeatureRemote(t interface { + mock.TestingT + Cleanup(func()) +}) *FeatureRemote { + mock := &FeatureRemote{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/FeatureResult.go b/mocks/FeatureResult.go new file mode 100644 index 0000000..f9d30ad --- /dev/null +++ b/mocks/FeatureResult.go @@ -0,0 +1,68 @@ +// Code generated by mockery v2.40.1. DO NOT EDIT. + +package mocks + +import ( + api "github.com/enbility/spine-go/api" + mock "github.com/stretchr/testify/mock" +) + +// FeatureResult is an autogenerated mock type for the FeatureResult type +type FeatureResult struct { + mock.Mock +} + +type FeatureResult_Expecter struct { + mock *mock.Mock +} + +func (_m *FeatureResult) EXPECT() *FeatureResult_Expecter { + return &FeatureResult_Expecter{mock: &_m.Mock} +} + +// HandleResult provides a mock function with given fields: _a0 +func (_m *FeatureResult) HandleResult(_a0 api.ResultMessage) { + _m.Called(_a0) +} + +// FeatureResult_HandleResult_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HandleResult' +type FeatureResult_HandleResult_Call struct { + *mock.Call +} + +// HandleResult is a helper method to define mock.On call +// - _a0 api.ResultMessage +func (_e *FeatureResult_Expecter) HandleResult(_a0 interface{}) *FeatureResult_HandleResult_Call { + return &FeatureResult_HandleResult_Call{Call: _e.mock.On("HandleResult", _a0)} +} + +func (_c *FeatureResult_HandleResult_Call) Run(run func(_a0 api.ResultMessage)) *FeatureResult_HandleResult_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.ResultMessage)) + }) + return _c +} + +func (_c *FeatureResult_HandleResult_Call) Return() *FeatureResult_HandleResult_Call { + _c.Call.Return() + return _c +} + +func (_c *FeatureResult_HandleResult_Call) RunAndReturn(run func(api.ResultMessage)) *FeatureResult_HandleResult_Call { + _c.Call.Return(run) + return _c +} + +// NewFeatureResult creates a new instance of FeatureResult. 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 NewFeatureResult(t interface { + mock.TestingT + Cleanup(func()) +}) *FeatureResult { + mock := &FeatureResult{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/FunctionData.go b/mocks/FunctionData.go new file mode 100644 index 0000000..e43891b --- /dev/null +++ b/mocks/FunctionData.go @@ -0,0 +1,162 @@ +// Code generated by mockery v2.40.1. DO NOT EDIT. + +package mocks + +import ( + model "github.com/enbility/spine-go/model" + mock "github.com/stretchr/testify/mock" +) + +// FunctionData is an autogenerated mock type for the FunctionData type +type FunctionData struct { + mock.Mock +} + +type FunctionData_Expecter struct { + mock *mock.Mock +} + +func (_m *FunctionData) EXPECT() *FunctionData_Expecter { + return &FunctionData_Expecter{mock: &_m.Mock} +} + +// DataCopyAny provides a mock function with given fields: +func (_m *FunctionData) DataCopyAny() interface{} { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DataCopyAny") + } + + var r0 interface{} + if rf, ok := ret.Get(0).(func() interface{}); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + return r0 +} + +// FunctionData_DataCopyAny_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DataCopyAny' +type FunctionData_DataCopyAny_Call struct { + *mock.Call +} + +// DataCopyAny is a helper method to define mock.On call +func (_e *FunctionData_Expecter) DataCopyAny() *FunctionData_DataCopyAny_Call { + return &FunctionData_DataCopyAny_Call{Call: _e.mock.On("DataCopyAny")} +} + +func (_c *FunctionData_DataCopyAny_Call) Run(run func()) *FunctionData_DataCopyAny_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FunctionData_DataCopyAny_Call) Return(_a0 interface{}) *FunctionData_DataCopyAny_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FunctionData_DataCopyAny_Call) RunAndReturn(run func() interface{}) *FunctionData_DataCopyAny_Call { + _c.Call.Return(run) + return _c +} + +// Function provides a mock function with given fields: +func (_m *FunctionData) Function() model.FunctionType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Function") + } + + var r0 model.FunctionType + if rf, ok := ret.Get(0).(func() model.FunctionType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.FunctionType) + } + + return r0 +} + +// FunctionData_Function_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Function' +type FunctionData_Function_Call struct { + *mock.Call +} + +// Function is a helper method to define mock.On call +func (_e *FunctionData_Expecter) Function() *FunctionData_Function_Call { + return &FunctionData_Function_Call{Call: _e.mock.On("Function")} +} + +func (_c *FunctionData_Function_Call) Run(run func()) *FunctionData_Function_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FunctionData_Function_Call) Return(_a0 model.FunctionType) *FunctionData_Function_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FunctionData_Function_Call) RunAndReturn(run func() model.FunctionType) *FunctionData_Function_Call { + _c.Call.Return(run) + return _c +} + +// UpdateDataAny provides a mock function with given fields: data, filterPartial, filterDelete +func (_m *FunctionData) UpdateDataAny(data interface{}, filterPartial *model.FilterType, filterDelete *model.FilterType) { + _m.Called(data, filterPartial, filterDelete) +} + +// FunctionData_UpdateDataAny_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateDataAny' +type FunctionData_UpdateDataAny_Call struct { + *mock.Call +} + +// UpdateDataAny is a helper method to define mock.On call +// - data interface{} +// - filterPartial *model.FilterType +// - filterDelete *model.FilterType +func (_e *FunctionData_Expecter) UpdateDataAny(data interface{}, filterPartial interface{}, filterDelete interface{}) *FunctionData_UpdateDataAny_Call { + return &FunctionData_UpdateDataAny_Call{Call: _e.mock.On("UpdateDataAny", data, filterPartial, filterDelete)} +} + +func (_c *FunctionData_UpdateDataAny_Call) Run(run func(data interface{}, filterPartial *model.FilterType, filterDelete *model.FilterType)) *FunctionData_UpdateDataAny_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{}), args[1].(*model.FilterType), args[2].(*model.FilterType)) + }) + return _c +} + +func (_c *FunctionData_UpdateDataAny_Call) Return() *FunctionData_UpdateDataAny_Call { + _c.Call.Return() + return _c +} + +func (_c *FunctionData_UpdateDataAny_Call) RunAndReturn(run func(interface{}, *model.FilterType, *model.FilterType)) *FunctionData_UpdateDataAny_Call { + _c.Call.Return(run) + return _c +} + +// NewFunctionData creates a new instance of FunctionData. 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 NewFunctionData(t interface { + mock.TestingT + Cleanup(func()) +}) *FunctionData { + mock := &FunctionData{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/FunctionDataCmd.go b/mocks/FunctionDataCmd.go new file mode 100644 index 0000000..b6f887e --- /dev/null +++ b/mocks/FunctionDataCmd.go @@ -0,0 +1,352 @@ +// Code generated by mockery v2.40.1. DO NOT EDIT. + +package mocks + +import ( + model "github.com/enbility/spine-go/model" + mock "github.com/stretchr/testify/mock" +) + +// FunctionDataCmd is an autogenerated mock type for the FunctionDataCmd type +type FunctionDataCmd struct { + mock.Mock +} + +type FunctionDataCmd_Expecter struct { + mock *mock.Mock +} + +func (_m *FunctionDataCmd) EXPECT() *FunctionDataCmd_Expecter { + return &FunctionDataCmd_Expecter{mock: &_m.Mock} +} + +// DataCopyAny provides a mock function with given fields: +func (_m *FunctionDataCmd) DataCopyAny() interface{} { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DataCopyAny") + } + + var r0 interface{} + if rf, ok := ret.Get(0).(func() interface{}); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + return r0 +} + +// FunctionDataCmd_DataCopyAny_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DataCopyAny' +type FunctionDataCmd_DataCopyAny_Call struct { + *mock.Call +} + +// DataCopyAny is a helper method to define mock.On call +func (_e *FunctionDataCmd_Expecter) DataCopyAny() *FunctionDataCmd_DataCopyAny_Call { + return &FunctionDataCmd_DataCopyAny_Call{Call: _e.mock.On("DataCopyAny")} +} + +func (_c *FunctionDataCmd_DataCopyAny_Call) Run(run func()) *FunctionDataCmd_DataCopyAny_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FunctionDataCmd_DataCopyAny_Call) Return(_a0 interface{}) *FunctionDataCmd_DataCopyAny_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FunctionDataCmd_DataCopyAny_Call) RunAndReturn(run func() interface{}) *FunctionDataCmd_DataCopyAny_Call { + _c.Call.Return(run) + return _c +} + +// Function provides a mock function with given fields: +func (_m *FunctionDataCmd) Function() model.FunctionType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Function") + } + + var r0 model.FunctionType + if rf, ok := ret.Get(0).(func() model.FunctionType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.FunctionType) + } + + return r0 +} + +// FunctionDataCmd_Function_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Function' +type FunctionDataCmd_Function_Call struct { + *mock.Call +} + +// Function is a helper method to define mock.On call +func (_e *FunctionDataCmd_Expecter) Function() *FunctionDataCmd_Function_Call { + return &FunctionDataCmd_Function_Call{Call: _e.mock.On("Function")} +} + +func (_c *FunctionDataCmd_Function_Call) Run(run func()) *FunctionDataCmd_Function_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *FunctionDataCmd_Function_Call) Return(_a0 model.FunctionType) *FunctionDataCmd_Function_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FunctionDataCmd_Function_Call) RunAndReturn(run func() model.FunctionType) *FunctionDataCmd_Function_Call { + _c.Call.Return(run) + return _c +} + +// NotifyCmdType provides a mock function with given fields: deleteSelector, partialSelector, partialWithoutSelector, deleteElements +func (_m *FunctionDataCmd) NotifyCmdType(deleteSelector interface{}, partialSelector interface{}, partialWithoutSelector bool, deleteElements interface{}) model.CmdType { + ret := _m.Called(deleteSelector, partialSelector, partialWithoutSelector, deleteElements) + + if len(ret) == 0 { + panic("no return value specified for NotifyCmdType") + } + + var r0 model.CmdType + if rf, ok := ret.Get(0).(func(interface{}, interface{}, bool, interface{}) model.CmdType); ok { + r0 = rf(deleteSelector, partialSelector, partialWithoutSelector, deleteElements) + } else { + r0 = ret.Get(0).(model.CmdType) + } + + return r0 +} + +// FunctionDataCmd_NotifyCmdType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NotifyCmdType' +type FunctionDataCmd_NotifyCmdType_Call struct { + *mock.Call +} + +// NotifyCmdType is a helper method to define mock.On call +// - deleteSelector interface{} +// - partialSelector interface{} +// - partialWithoutSelector bool +// - deleteElements interface{} +func (_e *FunctionDataCmd_Expecter) NotifyCmdType(deleteSelector interface{}, partialSelector interface{}, partialWithoutSelector interface{}, deleteElements interface{}) *FunctionDataCmd_NotifyCmdType_Call { + return &FunctionDataCmd_NotifyCmdType_Call{Call: _e.mock.On("NotifyCmdType", deleteSelector, partialSelector, partialWithoutSelector, deleteElements)} +} + +func (_c *FunctionDataCmd_NotifyCmdType_Call) Run(run func(deleteSelector interface{}, partialSelector interface{}, partialWithoutSelector bool, deleteElements interface{})) *FunctionDataCmd_NotifyCmdType_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{}), args[1].(interface{}), args[2].(bool), args[3].(interface{})) + }) + return _c +} + +func (_c *FunctionDataCmd_NotifyCmdType_Call) Return(_a0 model.CmdType) *FunctionDataCmd_NotifyCmdType_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FunctionDataCmd_NotifyCmdType_Call) RunAndReturn(run func(interface{}, interface{}, bool, interface{}) model.CmdType) *FunctionDataCmd_NotifyCmdType_Call { + _c.Call.Return(run) + return _c +} + +// ReadCmdType provides a mock function with given fields: partialSelector, elements +func (_m *FunctionDataCmd) ReadCmdType(partialSelector interface{}, elements interface{}) model.CmdType { + ret := _m.Called(partialSelector, elements) + + if len(ret) == 0 { + panic("no return value specified for ReadCmdType") + } + + var r0 model.CmdType + if rf, ok := ret.Get(0).(func(interface{}, interface{}) model.CmdType); ok { + r0 = rf(partialSelector, elements) + } else { + r0 = ret.Get(0).(model.CmdType) + } + + return r0 +} + +// FunctionDataCmd_ReadCmdType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadCmdType' +type FunctionDataCmd_ReadCmdType_Call struct { + *mock.Call +} + +// ReadCmdType is a helper method to define mock.On call +// - partialSelector interface{} +// - elements interface{} +func (_e *FunctionDataCmd_Expecter) ReadCmdType(partialSelector interface{}, elements interface{}) *FunctionDataCmd_ReadCmdType_Call { + return &FunctionDataCmd_ReadCmdType_Call{Call: _e.mock.On("ReadCmdType", partialSelector, elements)} +} + +func (_c *FunctionDataCmd_ReadCmdType_Call) Run(run func(partialSelector interface{}, elements interface{})) *FunctionDataCmd_ReadCmdType_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{}), args[1].(interface{})) + }) + return _c +} + +func (_c *FunctionDataCmd_ReadCmdType_Call) Return(_a0 model.CmdType) *FunctionDataCmd_ReadCmdType_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FunctionDataCmd_ReadCmdType_Call) RunAndReturn(run func(interface{}, interface{}) model.CmdType) *FunctionDataCmd_ReadCmdType_Call { + _c.Call.Return(run) + return _c +} + +// ReplyCmdType provides a mock function with given fields: partial +func (_m *FunctionDataCmd) ReplyCmdType(partial bool) model.CmdType { + ret := _m.Called(partial) + + if len(ret) == 0 { + panic("no return value specified for ReplyCmdType") + } + + var r0 model.CmdType + if rf, ok := ret.Get(0).(func(bool) model.CmdType); ok { + r0 = rf(partial) + } else { + r0 = ret.Get(0).(model.CmdType) + } + + return r0 +} + +// FunctionDataCmd_ReplyCmdType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReplyCmdType' +type FunctionDataCmd_ReplyCmdType_Call struct { + *mock.Call +} + +// ReplyCmdType is a helper method to define mock.On call +// - partial bool +func (_e *FunctionDataCmd_Expecter) ReplyCmdType(partial interface{}) *FunctionDataCmd_ReplyCmdType_Call { + return &FunctionDataCmd_ReplyCmdType_Call{Call: _e.mock.On("ReplyCmdType", partial)} +} + +func (_c *FunctionDataCmd_ReplyCmdType_Call) Run(run func(partial bool)) *FunctionDataCmd_ReplyCmdType_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(bool)) + }) + return _c +} + +func (_c *FunctionDataCmd_ReplyCmdType_Call) Return(_a0 model.CmdType) *FunctionDataCmd_ReplyCmdType_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FunctionDataCmd_ReplyCmdType_Call) RunAndReturn(run func(bool) model.CmdType) *FunctionDataCmd_ReplyCmdType_Call { + _c.Call.Return(run) + return _c +} + +// UpdateDataAny provides a mock function with given fields: data, filterPartial, filterDelete +func (_m *FunctionDataCmd) UpdateDataAny(data interface{}, filterPartial *model.FilterType, filterDelete *model.FilterType) { + _m.Called(data, filterPartial, filterDelete) +} + +// FunctionDataCmd_UpdateDataAny_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateDataAny' +type FunctionDataCmd_UpdateDataAny_Call struct { + *mock.Call +} + +// UpdateDataAny is a helper method to define mock.On call +// - data interface{} +// - filterPartial *model.FilterType +// - filterDelete *model.FilterType +func (_e *FunctionDataCmd_Expecter) UpdateDataAny(data interface{}, filterPartial interface{}, filterDelete interface{}) *FunctionDataCmd_UpdateDataAny_Call { + return &FunctionDataCmd_UpdateDataAny_Call{Call: _e.mock.On("UpdateDataAny", data, filterPartial, filterDelete)} +} + +func (_c *FunctionDataCmd_UpdateDataAny_Call) Run(run func(data interface{}, filterPartial *model.FilterType, filterDelete *model.FilterType)) *FunctionDataCmd_UpdateDataAny_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{}), args[1].(*model.FilterType), args[2].(*model.FilterType)) + }) + return _c +} + +func (_c *FunctionDataCmd_UpdateDataAny_Call) Return() *FunctionDataCmd_UpdateDataAny_Call { + _c.Call.Return() + return _c +} + +func (_c *FunctionDataCmd_UpdateDataAny_Call) RunAndReturn(run func(interface{}, *model.FilterType, *model.FilterType)) *FunctionDataCmd_UpdateDataAny_Call { + _c.Call.Return(run) + return _c +} + +// WriteCmdType provides a mock function with given fields: deleteSelector, partialSelector, deleteElements +func (_m *FunctionDataCmd) WriteCmdType(deleteSelector interface{}, partialSelector interface{}, deleteElements interface{}) model.CmdType { + ret := _m.Called(deleteSelector, partialSelector, deleteElements) + + if len(ret) == 0 { + panic("no return value specified for WriteCmdType") + } + + var r0 model.CmdType + if rf, ok := ret.Get(0).(func(interface{}, interface{}, interface{}) model.CmdType); ok { + r0 = rf(deleteSelector, partialSelector, deleteElements) + } else { + r0 = ret.Get(0).(model.CmdType) + } + + return r0 +} + +// FunctionDataCmd_WriteCmdType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WriteCmdType' +type FunctionDataCmd_WriteCmdType_Call struct { + *mock.Call +} + +// WriteCmdType is a helper method to define mock.On call +// - deleteSelector interface{} +// - partialSelector interface{} +// - deleteElements interface{} +func (_e *FunctionDataCmd_Expecter) WriteCmdType(deleteSelector interface{}, partialSelector interface{}, deleteElements interface{}) *FunctionDataCmd_WriteCmdType_Call { + return &FunctionDataCmd_WriteCmdType_Call{Call: _e.mock.On("WriteCmdType", deleteSelector, partialSelector, deleteElements)} +} + +func (_c *FunctionDataCmd_WriteCmdType_Call) Run(run func(deleteSelector interface{}, partialSelector interface{}, deleteElements interface{})) *FunctionDataCmd_WriteCmdType_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{}), args[1].(interface{}), args[2].(interface{})) + }) + return _c +} + +func (_c *FunctionDataCmd_WriteCmdType_Call) Return(_a0 model.CmdType) *FunctionDataCmd_WriteCmdType_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *FunctionDataCmd_WriteCmdType_Call) RunAndReturn(run func(interface{}, interface{}, interface{}) model.CmdType) *FunctionDataCmd_WriteCmdType_Call { + _c.Call.Return(run) + return _c +} + +// NewFunctionDataCmd creates a new instance of FunctionDataCmd. 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 NewFunctionDataCmd(t interface { + mock.TestingT + Cleanup(func()) +}) *FunctionDataCmd { + mock := &FunctionDataCmd{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/HeartbeatManager.go b/mocks/HeartbeatManager.go new file mode 100644 index 0000000..c4b0759 --- /dev/null +++ b/mocks/HeartbeatManager.go @@ -0,0 +1,223 @@ +// Code generated by mockery v2.40.1. DO NOT EDIT. + +package mocks + +import ( + api "github.com/enbility/spine-go/api" + mock "github.com/stretchr/testify/mock" +) + +// HeartbeatManager is an autogenerated mock type for the HeartbeatManager type +type HeartbeatManager struct { + mock.Mock +} + +type HeartbeatManager_Expecter struct { + mock *mock.Mock +} + +func (_m *HeartbeatManager) EXPECT() *HeartbeatManager_Expecter { + return &HeartbeatManager_Expecter{mock: &_m.Mock} +} + +// IsHeartbeatRunning provides a mock function with given fields: +func (_m *HeartbeatManager) IsHeartbeatRunning() bool { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for IsHeartbeatRunning") + } + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// HeartbeatManager_IsHeartbeatRunning_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsHeartbeatRunning' +type HeartbeatManager_IsHeartbeatRunning_Call struct { + *mock.Call +} + +// IsHeartbeatRunning is a helper method to define mock.On call +func (_e *HeartbeatManager_Expecter) IsHeartbeatRunning() *HeartbeatManager_IsHeartbeatRunning_Call { + return &HeartbeatManager_IsHeartbeatRunning_Call{Call: _e.mock.On("IsHeartbeatRunning")} +} + +func (_c *HeartbeatManager_IsHeartbeatRunning_Call) Run(run func()) *HeartbeatManager_IsHeartbeatRunning_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *HeartbeatManager_IsHeartbeatRunning_Call) Return(_a0 bool) *HeartbeatManager_IsHeartbeatRunning_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *HeartbeatManager_IsHeartbeatRunning_Call) RunAndReturn(run func() bool) *HeartbeatManager_IsHeartbeatRunning_Call { + _c.Call.Return(run) + return _c +} + +// SetLocalFeature provides a mock function with given fields: entity, feature +func (_m *HeartbeatManager) SetLocalFeature(entity api.EntityLocal, feature api.FeatureLocal) { + _m.Called(entity, feature) +} + +// HeartbeatManager_SetLocalFeature_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetLocalFeature' +type HeartbeatManager_SetLocalFeature_Call struct { + *mock.Call +} + +// SetLocalFeature is a helper method to define mock.On call +// - entity api.EntityLocal +// - feature api.FeatureLocal +func (_e *HeartbeatManager_Expecter) SetLocalFeature(entity interface{}, feature interface{}) *HeartbeatManager_SetLocalFeature_Call { + return &HeartbeatManager_SetLocalFeature_Call{Call: _e.mock.On("SetLocalFeature", entity, feature)} +} + +func (_c *HeartbeatManager_SetLocalFeature_Call) Run(run func(entity api.EntityLocal, feature api.FeatureLocal)) *HeartbeatManager_SetLocalFeature_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.EntityLocal), args[1].(api.FeatureLocal)) + }) + return _c +} + +func (_c *HeartbeatManager_SetLocalFeature_Call) Return() *HeartbeatManager_SetLocalFeature_Call { + _c.Call.Return() + return _c +} + +func (_c *HeartbeatManager_SetLocalFeature_Call) RunAndReturn(run func(api.EntityLocal, api.FeatureLocal)) *HeartbeatManager_SetLocalFeature_Call { + _c.Call.Return(run) + return _c +} + +// StartHeartbeat provides a mock function with given fields: +func (_m *HeartbeatManager) StartHeartbeat() error { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for StartHeartbeat") + } + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// HeartbeatManager_StartHeartbeat_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StartHeartbeat' +type HeartbeatManager_StartHeartbeat_Call struct { + *mock.Call +} + +// StartHeartbeat is a helper method to define mock.On call +func (_e *HeartbeatManager_Expecter) StartHeartbeat() *HeartbeatManager_StartHeartbeat_Call { + return &HeartbeatManager_StartHeartbeat_Call{Call: _e.mock.On("StartHeartbeat")} +} + +func (_c *HeartbeatManager_StartHeartbeat_Call) Run(run func()) *HeartbeatManager_StartHeartbeat_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *HeartbeatManager_StartHeartbeat_Call) Return(_a0 error) *HeartbeatManager_StartHeartbeat_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *HeartbeatManager_StartHeartbeat_Call) RunAndReturn(run func() error) *HeartbeatManager_StartHeartbeat_Call { + _c.Call.Return(run) + return _c +} + +// StopHeartbeat provides a mock function with given fields: +func (_m *HeartbeatManager) StopHeartbeat() { + _m.Called() +} + +// HeartbeatManager_StopHeartbeat_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StopHeartbeat' +type HeartbeatManager_StopHeartbeat_Call struct { + *mock.Call +} + +// StopHeartbeat is a helper method to define mock.On call +func (_e *HeartbeatManager_Expecter) StopHeartbeat() *HeartbeatManager_StopHeartbeat_Call { + return &HeartbeatManager_StopHeartbeat_Call{Call: _e.mock.On("StopHeartbeat")} +} + +func (_c *HeartbeatManager_StopHeartbeat_Call) Run(run func()) *HeartbeatManager_StopHeartbeat_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *HeartbeatManager_StopHeartbeat_Call) Return() *HeartbeatManager_StopHeartbeat_Call { + _c.Call.Return() + return _c +} + +func (_c *HeartbeatManager_StopHeartbeat_Call) RunAndReturn(run func()) *HeartbeatManager_StopHeartbeat_Call { + _c.Call.Return(run) + return _c +} + +// UpdateHeartbeatOnSubscriptions provides a mock function with given fields: +func (_m *HeartbeatManager) UpdateHeartbeatOnSubscriptions() { + _m.Called() +} + +// HeartbeatManager_UpdateHeartbeatOnSubscriptions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateHeartbeatOnSubscriptions' +type HeartbeatManager_UpdateHeartbeatOnSubscriptions_Call struct { + *mock.Call +} + +// UpdateHeartbeatOnSubscriptions is a helper method to define mock.On call +func (_e *HeartbeatManager_Expecter) UpdateHeartbeatOnSubscriptions() *HeartbeatManager_UpdateHeartbeatOnSubscriptions_Call { + return &HeartbeatManager_UpdateHeartbeatOnSubscriptions_Call{Call: _e.mock.On("UpdateHeartbeatOnSubscriptions")} +} + +func (_c *HeartbeatManager_UpdateHeartbeatOnSubscriptions_Call) Run(run func()) *HeartbeatManager_UpdateHeartbeatOnSubscriptions_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *HeartbeatManager_UpdateHeartbeatOnSubscriptions_Call) Return() *HeartbeatManager_UpdateHeartbeatOnSubscriptions_Call { + _c.Call.Return() + return _c +} + +func (_c *HeartbeatManager_UpdateHeartbeatOnSubscriptions_Call) RunAndReturn(run func()) *HeartbeatManager_UpdateHeartbeatOnSubscriptions_Call { + _c.Call.Return(run) + return _c +} + +// NewHeartbeatManager creates a new instance of HeartbeatManager. 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 NewHeartbeatManager(t interface { + mock.TestingT + Cleanup(func()) +}) *HeartbeatManager { + mock := &HeartbeatManager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/NodeManagement.go b/mocks/NodeManagement.go new file mode 100644 index 0000000..25ba591 --- /dev/null +++ b/mocks/NodeManagement.go @@ -0,0 +1,1321 @@ +// Code generated by mockery v2.40.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" + + time "time" +) + +// NodeManagement is an autogenerated mock type for the NodeManagement type +type NodeManagement struct { + mock.Mock +} + +type NodeManagement_Expecter struct { + mock *mock.Mock +} + +func (_m *NodeManagement) EXPECT() *NodeManagement_Expecter { + return &NodeManagement_Expecter{mock: &_m.Mock} +} + +// AddFunctionType provides a mock function with given fields: function, read, write +func (_m *NodeManagement) AddFunctionType(function model.FunctionType, read bool, write bool) { + _m.Called(function, read, write) +} + +// NodeManagement_AddFunctionType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddFunctionType' +type NodeManagement_AddFunctionType_Call struct { + *mock.Call +} + +// AddFunctionType is a helper method to define mock.On call +// - function model.FunctionType +// - read bool +// - write bool +func (_e *NodeManagement_Expecter) AddFunctionType(function interface{}, read interface{}, write interface{}) *NodeManagement_AddFunctionType_Call { + return &NodeManagement_AddFunctionType_Call{Call: _e.mock.On("AddFunctionType", function, read, write)} +} + +func (_c *NodeManagement_AddFunctionType_Call) Run(run func(function model.FunctionType, read bool, write bool)) *NodeManagement_AddFunctionType_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType), args[1].(bool), args[2].(bool)) + }) + return _c +} + +func (_c *NodeManagement_AddFunctionType_Call) Return() *NodeManagement_AddFunctionType_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeManagement_AddFunctionType_Call) RunAndReturn(run func(model.FunctionType, bool, bool)) *NodeManagement_AddFunctionType_Call { + _c.Call.Return(run) + return _c +} + +// AddResultCallback provides a mock function with given fields: msgCounterReference, function +func (_m *NodeManagement) AddResultCallback(msgCounterReference model.MsgCounterType, function func(api.ResultMessage)) { + _m.Called(msgCounterReference, function) +} + +// NodeManagement_AddResultCallback_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddResultCallback' +type NodeManagement_AddResultCallback_Call struct { + *mock.Call +} + +// AddResultCallback is a helper method to define mock.On call +// - msgCounterReference model.MsgCounterType +// - function func(api.ResultMessage) +func (_e *NodeManagement_Expecter) AddResultCallback(msgCounterReference interface{}, function interface{}) *NodeManagement_AddResultCallback_Call { + return &NodeManagement_AddResultCallback_Call{Call: _e.mock.On("AddResultCallback", msgCounterReference, function)} +} + +func (_c *NodeManagement_AddResultCallback_Call) Run(run func(msgCounterReference model.MsgCounterType, function func(api.ResultMessage))) *NodeManagement_AddResultCallback_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.MsgCounterType), args[1].(func(api.ResultMessage))) + }) + return _c +} + +func (_c *NodeManagement_AddResultCallback_Call) Return() *NodeManagement_AddResultCallback_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeManagement_AddResultCallback_Call) RunAndReturn(run func(model.MsgCounterType, func(api.ResultMessage))) *NodeManagement_AddResultCallback_Call { + _c.Call.Return(run) + return _c +} + +// AddResultHandler provides a mock function with given fields: handler +func (_m *NodeManagement) AddResultHandler(handler api.FeatureResult) { + _m.Called(handler) +} + +// NodeManagement_AddResultHandler_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddResultHandler' +type NodeManagement_AddResultHandler_Call struct { + *mock.Call +} + +// AddResultHandler is a helper method to define mock.On call +// - handler api.FeatureResult +func (_e *NodeManagement_Expecter) AddResultHandler(handler interface{}) *NodeManagement_AddResultHandler_Call { + return &NodeManagement_AddResultHandler_Call{Call: _e.mock.On("AddResultHandler", handler)} +} + +func (_c *NodeManagement_AddResultHandler_Call) Run(run func(handler api.FeatureResult)) *NodeManagement_AddResultHandler_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.FeatureResult)) + }) + return _c +} + +func (_c *NodeManagement_AddResultHandler_Call) Return() *NodeManagement_AddResultHandler_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeManagement_AddResultHandler_Call) RunAndReturn(run func(api.FeatureResult)) *NodeManagement_AddResultHandler_Call { + _c.Call.Return(run) + return _c +} + +// Address provides a mock function with given fields: +func (_m *NodeManagement) Address() *model.FeatureAddressType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Address") + } + + var r0 *model.FeatureAddressType + if rf, ok := ret.Get(0).(func() *model.FeatureAddressType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.FeatureAddressType) + } + } + + return r0 +} + +// NodeManagement_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address' +type NodeManagement_Address_Call struct { + *mock.Call +} + +// Address is a helper method to define mock.On call +func (_e *NodeManagement_Expecter) Address() *NodeManagement_Address_Call { + return &NodeManagement_Address_Call{Call: _e.mock.On("Address")} +} + +func (_c *NodeManagement_Address_Call) Run(run func()) *NodeManagement_Address_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *NodeManagement_Address_Call) Return(_a0 *model.FeatureAddressType) *NodeManagement_Address_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *NodeManagement_Address_Call) RunAndReturn(run func() *model.FeatureAddressType) *NodeManagement_Address_Call { + _c.Call.Return(run) + return _c +} + +// Bind provides a mock function with given fields: remoteAdress +func (_m *NodeManagement) Bind(remoteAdress *model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType) { + ret := _m.Called(remoteAdress) + + if len(ret) == 0 { + panic("no return value specified for Bind") + } + + var r0 *model.MsgCounterType + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType)); ok { + return rf(remoteAdress) + } + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType) *model.MsgCounterType); ok { + r0 = rf(remoteAdress) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(*model.FeatureAddressType) *model.ErrorType); ok { + r1 = rf(remoteAdress) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// NodeManagement_Bind_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Bind' +type NodeManagement_Bind_Call struct { + *mock.Call +} + +// Bind is a helper method to define mock.On call +// - remoteAdress *model.FeatureAddressType +func (_e *NodeManagement_Expecter) Bind(remoteAdress interface{}) *NodeManagement_Bind_Call { + return &NodeManagement_Bind_Call{Call: _e.mock.On("Bind", remoteAdress)} +} + +func (_c *NodeManagement_Bind_Call) Run(run func(remoteAdress *model.FeatureAddressType)) *NodeManagement_Bind_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *NodeManagement_Bind_Call) Return(_a0 *model.MsgCounterType, _a1 *model.ErrorType) *NodeManagement_Bind_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *NodeManagement_Bind_Call) RunAndReturn(run func(*model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType)) *NodeManagement_Bind_Call { + _c.Call.Return(run) + return _c +} + +// DataCopy provides a mock function with given fields: function +func (_m *NodeManagement) DataCopy(function model.FunctionType) interface{} { + ret := _m.Called(function) + + if len(ret) == 0 { + panic("no return value specified for DataCopy") + } + + var r0 interface{} + if rf, ok := ret.Get(0).(func(model.FunctionType) interface{}); ok { + r0 = rf(function) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + return r0 +} + +// NodeManagement_DataCopy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DataCopy' +type NodeManagement_DataCopy_Call struct { + *mock.Call +} + +// DataCopy is a helper method to define mock.On call +// - function model.FunctionType +func (_e *NodeManagement_Expecter) DataCopy(function interface{}) *NodeManagement_DataCopy_Call { + return &NodeManagement_DataCopy_Call{Call: _e.mock.On("DataCopy", function)} +} + +func (_c *NodeManagement_DataCopy_Call) Run(run func(function model.FunctionType)) *NodeManagement_DataCopy_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType)) + }) + return _c +} + +func (_c *NodeManagement_DataCopy_Call) Return(_a0 interface{}) *NodeManagement_DataCopy_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *NodeManagement_DataCopy_Call) RunAndReturn(run func(model.FunctionType) interface{}) *NodeManagement_DataCopy_Call { + _c.Call.Return(run) + return _c +} + +// Description provides a mock function with given fields: +func (_m *NodeManagement) Description() *model.DescriptionType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Description") + } + + var r0 *model.DescriptionType + if rf, ok := ret.Get(0).(func() *model.DescriptionType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.DescriptionType) + } + } + + return r0 +} + +// NodeManagement_Description_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Description' +type NodeManagement_Description_Call struct { + *mock.Call +} + +// Description is a helper method to define mock.On call +func (_e *NodeManagement_Expecter) Description() *NodeManagement_Description_Call { + return &NodeManagement_Description_Call{Call: _e.mock.On("Description")} +} + +func (_c *NodeManagement_Description_Call) Run(run func()) *NodeManagement_Description_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *NodeManagement_Description_Call) Return(_a0 *model.DescriptionType) *NodeManagement_Description_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *NodeManagement_Description_Call) RunAndReturn(run func() *model.DescriptionType) *NodeManagement_Description_Call { + _c.Call.Return(run) + return _c +} + +// Device provides a mock function with given fields: +func (_m *NodeManagement) Device() api.DeviceLocal { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Device") + } + + var r0 api.DeviceLocal + if rf, ok := ret.Get(0).(func() api.DeviceLocal); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.DeviceLocal) + } + } + + return r0 +} + +// NodeManagement_Device_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Device' +type NodeManagement_Device_Call struct { + *mock.Call +} + +// Device is a helper method to define mock.On call +func (_e *NodeManagement_Expecter) Device() *NodeManagement_Device_Call { + return &NodeManagement_Device_Call{Call: _e.mock.On("Device")} +} + +func (_c *NodeManagement_Device_Call) Run(run func()) *NodeManagement_Device_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *NodeManagement_Device_Call) Return(_a0 api.DeviceLocal) *NodeManagement_Device_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *NodeManagement_Device_Call) RunAndReturn(run func() api.DeviceLocal) *NodeManagement_Device_Call { + _c.Call.Return(run) + return _c +} + +// Entity provides a mock function with given fields: +func (_m *NodeManagement) Entity() api.EntityLocal { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Entity") + } + + var r0 api.EntityLocal + if rf, ok := ret.Get(0).(func() api.EntityLocal); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(api.EntityLocal) + } + } + + return r0 +} + +// NodeManagement_Entity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Entity' +type NodeManagement_Entity_Call struct { + *mock.Call +} + +// Entity is a helper method to define mock.On call +func (_e *NodeManagement_Expecter) Entity() *NodeManagement_Entity_Call { + return &NodeManagement_Entity_Call{Call: _e.mock.On("Entity")} +} + +func (_c *NodeManagement_Entity_Call) Run(run func()) *NodeManagement_Entity_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *NodeManagement_Entity_Call) Return(_a0 api.EntityLocal) *NodeManagement_Entity_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *NodeManagement_Entity_Call) RunAndReturn(run func() api.EntityLocal) *NodeManagement_Entity_Call { + _c.Call.Return(run) + return _c +} + +// FetchRequestData provides a mock function with given fields: msgCounter, destination +func (_m *NodeManagement) FetchRequestData(msgCounter model.MsgCounterType, destination api.FeatureRemote) (interface{}, *model.ErrorType) { + ret := _m.Called(msgCounter, destination) + + if len(ret) == 0 { + panic("no return value specified for FetchRequestData") + } + + var r0 interface{} + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(model.MsgCounterType, api.FeatureRemote) (interface{}, *model.ErrorType)); ok { + return rf(msgCounter, destination) + } + if rf, ok := ret.Get(0).(func(model.MsgCounterType, api.FeatureRemote) interface{}); ok { + r0 = rf(msgCounter, destination) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + if rf, ok := ret.Get(1).(func(model.MsgCounterType, api.FeatureRemote) *model.ErrorType); ok { + r1 = rf(msgCounter, destination) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// NodeManagement_FetchRequestData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FetchRequestData' +type NodeManagement_FetchRequestData_Call struct { + *mock.Call +} + +// FetchRequestData is a helper method to define mock.On call +// - msgCounter model.MsgCounterType +// - destination api.FeatureRemote +func (_e *NodeManagement_Expecter) FetchRequestData(msgCounter interface{}, destination interface{}) *NodeManagement_FetchRequestData_Call { + return &NodeManagement_FetchRequestData_Call{Call: _e.mock.On("FetchRequestData", msgCounter, destination)} +} + +func (_c *NodeManagement_FetchRequestData_Call) Run(run func(msgCounter model.MsgCounterType, destination api.FeatureRemote)) *NodeManagement_FetchRequestData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.MsgCounterType), args[1].(api.FeatureRemote)) + }) + return _c +} + +func (_c *NodeManagement_FetchRequestData_Call) Return(_a0 interface{}, _a1 *model.ErrorType) *NodeManagement_FetchRequestData_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *NodeManagement_FetchRequestData_Call) RunAndReturn(run func(model.MsgCounterType, api.FeatureRemote) (interface{}, *model.ErrorType)) *NodeManagement_FetchRequestData_Call { + _c.Call.Return(run) + return _c +} + +// HandleMessage provides a mock function with given fields: message +func (_m *NodeManagement) HandleMessage(message *api.Message) *model.ErrorType { + ret := _m.Called(message) + + if len(ret) == 0 { + panic("no return value specified for HandleMessage") + } + + var r0 *model.ErrorType + if rf, ok := ret.Get(0).(func(*api.Message) *model.ErrorType); ok { + r0 = rf(message) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.ErrorType) + } + } + + return r0 +} + +// NodeManagement_HandleMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HandleMessage' +type NodeManagement_HandleMessage_Call struct { + *mock.Call +} + +// HandleMessage is a helper method to define mock.On call +// - message *api.Message +func (_e *NodeManagement_Expecter) HandleMessage(message interface{}) *NodeManagement_HandleMessage_Call { + return &NodeManagement_HandleMessage_Call{Call: _e.mock.On("HandleMessage", message)} +} + +func (_c *NodeManagement_HandleMessage_Call) Run(run func(message *api.Message)) *NodeManagement_HandleMessage_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*api.Message)) + }) + return _c +} + +func (_c *NodeManagement_HandleMessage_Call) Return(_a0 *model.ErrorType) *NodeManagement_HandleMessage_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *NodeManagement_HandleMessage_Call) RunAndReturn(run func(*api.Message) *model.ErrorType) *NodeManagement_HandleMessage_Call { + _c.Call.Return(run) + return _c +} + +// Information provides a mock function with given fields: +func (_m *NodeManagement) Information() *model.NodeManagementDetailedDiscoveryFeatureInformationType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Information") + } + + var r0 *model.NodeManagementDetailedDiscoveryFeatureInformationType + if rf, ok := ret.Get(0).(func() *model.NodeManagementDetailedDiscoveryFeatureInformationType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.NodeManagementDetailedDiscoveryFeatureInformationType) + } + } + + return r0 +} + +// NodeManagement_Information_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Information' +type NodeManagement_Information_Call struct { + *mock.Call +} + +// Information is a helper method to define mock.On call +func (_e *NodeManagement_Expecter) Information() *NodeManagement_Information_Call { + return &NodeManagement_Information_Call{Call: _e.mock.On("Information")} +} + +func (_c *NodeManagement_Information_Call) Run(run func()) *NodeManagement_Information_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *NodeManagement_Information_Call) Return(_a0 *model.NodeManagementDetailedDiscoveryFeatureInformationType) *NodeManagement_Information_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *NodeManagement_Information_Call) RunAndReturn(run func() *model.NodeManagementDetailedDiscoveryFeatureInformationType) *NodeManagement_Information_Call { + _c.Call.Return(run) + return _c +} + +// NotifyData provides a mock function with given fields: function, deleteSelector, partialSelector, partialWithoutSelector, deleteElements, destination +func (_m *NodeManagement) NotifyData(function model.FunctionType, deleteSelector interface{}, partialSelector interface{}, partialWithoutSelector bool, deleteElements interface{}, destination api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType) { + ret := _m.Called(function, deleteSelector, partialSelector, partialWithoutSelector, deleteElements, destination) + + if len(ret) == 0 { + panic("no return value specified for NotifyData") + } + + var r0 *model.MsgCounterType + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(model.FunctionType, interface{}, interface{}, bool, interface{}, api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType)); ok { + return rf(function, deleteSelector, partialSelector, partialWithoutSelector, deleteElements, destination) + } + if rf, ok := ret.Get(0).(func(model.FunctionType, interface{}, interface{}, bool, interface{}, api.FeatureRemote) *model.MsgCounterType); ok { + r0 = rf(function, deleteSelector, partialSelector, partialWithoutSelector, deleteElements, destination) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(model.FunctionType, interface{}, interface{}, bool, interface{}, api.FeatureRemote) *model.ErrorType); ok { + r1 = rf(function, deleteSelector, partialSelector, partialWithoutSelector, deleteElements, destination) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// NodeManagement_NotifyData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NotifyData' +type NodeManagement_NotifyData_Call struct { + *mock.Call +} + +// NotifyData is a helper method to define mock.On call +// - function model.FunctionType +// - deleteSelector interface{} +// - partialSelector interface{} +// - partialWithoutSelector bool +// - deleteElements interface{} +// - destination api.FeatureRemote +func (_e *NodeManagement_Expecter) NotifyData(function interface{}, deleteSelector interface{}, partialSelector interface{}, partialWithoutSelector interface{}, deleteElements interface{}, destination interface{}) *NodeManagement_NotifyData_Call { + return &NodeManagement_NotifyData_Call{Call: _e.mock.On("NotifyData", function, deleteSelector, partialSelector, partialWithoutSelector, deleteElements, destination)} +} + +func (_c *NodeManagement_NotifyData_Call) Run(run func(function model.FunctionType, deleteSelector interface{}, partialSelector interface{}, partialWithoutSelector bool, deleteElements interface{}, destination api.FeatureRemote)) *NodeManagement_NotifyData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType), args[1].(interface{}), args[2].(interface{}), args[3].(bool), args[4].(interface{}), args[5].(api.FeatureRemote)) + }) + return _c +} + +func (_c *NodeManagement_NotifyData_Call) Return(_a0 *model.MsgCounterType, _a1 *model.ErrorType) *NodeManagement_NotifyData_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *NodeManagement_NotifyData_Call) RunAndReturn(run func(model.FunctionType, interface{}, interface{}, bool, interface{}, api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType)) *NodeManagement_NotifyData_Call { + _c.Call.Return(run) + return _c +} + +// Operations provides a mock function with given fields: +func (_m *NodeManagement) Operations() map[model.FunctionType]api.Operations { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Operations") + } + + var r0 map[model.FunctionType]api.Operations + if rf, ok := ret.Get(0).(func() map[model.FunctionType]api.Operations); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[model.FunctionType]api.Operations) + } + } + + return r0 +} + +// NodeManagement_Operations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Operations' +type NodeManagement_Operations_Call struct { + *mock.Call +} + +// Operations is a helper method to define mock.On call +func (_e *NodeManagement_Expecter) Operations() *NodeManagement_Operations_Call { + return &NodeManagement_Operations_Call{Call: _e.mock.On("Operations")} +} + +func (_c *NodeManagement_Operations_Call) Run(run func()) *NodeManagement_Operations_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *NodeManagement_Operations_Call) Return(_a0 map[model.FunctionType]api.Operations) *NodeManagement_Operations_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *NodeManagement_Operations_Call) RunAndReturn(run func() map[model.FunctionType]api.Operations) *NodeManagement_Operations_Call { + _c.Call.Return(run) + return _c +} + +// RemoveAllBindings provides a mock function with given fields: +func (_m *NodeManagement) RemoveAllBindings() { + _m.Called() +} + +// NodeManagement_RemoveAllBindings_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveAllBindings' +type NodeManagement_RemoveAllBindings_Call struct { + *mock.Call +} + +// RemoveAllBindings is a helper method to define mock.On call +func (_e *NodeManagement_Expecter) RemoveAllBindings() *NodeManagement_RemoveAllBindings_Call { + return &NodeManagement_RemoveAllBindings_Call{Call: _e.mock.On("RemoveAllBindings")} +} + +func (_c *NodeManagement_RemoveAllBindings_Call) Run(run func()) *NodeManagement_RemoveAllBindings_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *NodeManagement_RemoveAllBindings_Call) Return() *NodeManagement_RemoveAllBindings_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeManagement_RemoveAllBindings_Call) RunAndReturn(run func()) *NodeManagement_RemoveAllBindings_Call { + _c.Call.Return(run) + return _c +} + +// RemoveAllSubscriptions provides a mock function with given fields: +func (_m *NodeManagement) RemoveAllSubscriptions() { + _m.Called() +} + +// NodeManagement_RemoveAllSubscriptions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveAllSubscriptions' +type NodeManagement_RemoveAllSubscriptions_Call struct { + *mock.Call +} + +// RemoveAllSubscriptions is a helper method to define mock.On call +func (_e *NodeManagement_Expecter) RemoveAllSubscriptions() *NodeManagement_RemoveAllSubscriptions_Call { + return &NodeManagement_RemoveAllSubscriptions_Call{Call: _e.mock.On("RemoveAllSubscriptions")} +} + +func (_c *NodeManagement_RemoveAllSubscriptions_Call) Run(run func()) *NodeManagement_RemoveAllSubscriptions_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *NodeManagement_RemoveAllSubscriptions_Call) Return() *NodeManagement_RemoveAllSubscriptions_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeManagement_RemoveAllSubscriptions_Call) RunAndReturn(run func()) *NodeManagement_RemoveAllSubscriptions_Call { + _c.Call.Return(run) + return _c +} + +// RemoveBinding provides a mock function with given fields: remoteAddress +func (_m *NodeManagement) RemoveBinding(remoteAddress *model.FeatureAddressType) { + _m.Called(remoteAddress) +} + +// NodeManagement_RemoveBinding_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveBinding' +type NodeManagement_RemoveBinding_Call struct { + *mock.Call +} + +// RemoveBinding is a helper method to define mock.On call +// - remoteAddress *model.FeatureAddressType +func (_e *NodeManagement_Expecter) RemoveBinding(remoteAddress interface{}) *NodeManagement_RemoveBinding_Call { + return &NodeManagement_RemoveBinding_Call{Call: _e.mock.On("RemoveBinding", remoteAddress)} +} + +func (_c *NodeManagement_RemoveBinding_Call) Run(run func(remoteAddress *model.FeatureAddressType)) *NodeManagement_RemoveBinding_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *NodeManagement_RemoveBinding_Call) Return() *NodeManagement_RemoveBinding_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeManagement_RemoveBinding_Call) RunAndReturn(run func(*model.FeatureAddressType)) *NodeManagement_RemoveBinding_Call { + _c.Call.Return(run) + return _c +} + +// RemoveSubscription provides a mock function with given fields: remoteAddress +func (_m *NodeManagement) RemoveSubscription(remoteAddress *model.FeatureAddressType) { + _m.Called(remoteAddress) +} + +// NodeManagement_RemoveSubscription_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveSubscription' +type NodeManagement_RemoveSubscription_Call struct { + *mock.Call +} + +// RemoveSubscription is a helper method to define mock.On call +// - remoteAddress *model.FeatureAddressType +func (_e *NodeManagement_Expecter) RemoveSubscription(remoteAddress interface{}) *NodeManagement_RemoveSubscription_Call { + return &NodeManagement_RemoveSubscription_Call{Call: _e.mock.On("RemoveSubscription", remoteAddress)} +} + +func (_c *NodeManagement_RemoveSubscription_Call) Run(run func(remoteAddress *model.FeatureAddressType)) *NodeManagement_RemoveSubscription_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *NodeManagement_RemoveSubscription_Call) Return() *NodeManagement_RemoveSubscription_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeManagement_RemoveSubscription_Call) RunAndReturn(run func(*model.FeatureAddressType)) *NodeManagement_RemoveSubscription_Call { + _c.Call.Return(run) + return _c +} + +// RequestData provides a mock function with given fields: function, selector, elements, destination +func (_m *NodeManagement) RequestData(function model.FunctionType, selector interface{}, elements interface{}, destination api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType) { + ret := _m.Called(function, selector, elements, destination) + + if len(ret) == 0 { + panic("no return value specified for RequestData") + } + + var r0 *model.MsgCounterType + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(model.FunctionType, interface{}, interface{}, api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType)); ok { + return rf(function, selector, elements, destination) + } + if rf, ok := ret.Get(0).(func(model.FunctionType, interface{}, interface{}, api.FeatureRemote) *model.MsgCounterType); ok { + r0 = rf(function, selector, elements, destination) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(model.FunctionType, interface{}, interface{}, api.FeatureRemote) *model.ErrorType); ok { + r1 = rf(function, selector, elements, destination) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// NodeManagement_RequestData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestData' +type NodeManagement_RequestData_Call struct { + *mock.Call +} + +// RequestData is a helper method to define mock.On call +// - function model.FunctionType +// - selector interface{} +// - elements interface{} +// - destination api.FeatureRemote +func (_e *NodeManagement_Expecter) RequestData(function interface{}, selector interface{}, elements interface{}, destination interface{}) *NodeManagement_RequestData_Call { + return &NodeManagement_RequestData_Call{Call: _e.mock.On("RequestData", function, selector, elements, destination)} +} + +func (_c *NodeManagement_RequestData_Call) Run(run func(function model.FunctionType, selector interface{}, elements interface{}, destination api.FeatureRemote)) *NodeManagement_RequestData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType), args[1].(interface{}), args[2].(interface{}), args[3].(api.FeatureRemote)) + }) + return _c +} + +func (_c *NodeManagement_RequestData_Call) Return(_a0 *model.MsgCounterType, _a1 *model.ErrorType) *NodeManagement_RequestData_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *NodeManagement_RequestData_Call) RunAndReturn(run func(model.FunctionType, interface{}, interface{}, api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType)) *NodeManagement_RequestData_Call { + _c.Call.Return(run) + return _c +} + +// RequestDataBySenderAddress provides a mock function with given fields: cmd, sender, destinationSki, destinationAddress, maxDelay +func (_m *NodeManagement) RequestDataBySenderAddress(cmd model.CmdType, sender api.Sender, destinationSki string, destinationAddress *model.FeatureAddressType, maxDelay time.Duration) (*model.MsgCounterType, *model.ErrorType) { + ret := _m.Called(cmd, sender, destinationSki, destinationAddress, maxDelay) + + if len(ret) == 0 { + panic("no return value specified for RequestDataBySenderAddress") + } + + var r0 *model.MsgCounterType + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(model.CmdType, api.Sender, string, *model.FeatureAddressType, time.Duration) (*model.MsgCounterType, *model.ErrorType)); ok { + return rf(cmd, sender, destinationSki, destinationAddress, maxDelay) + } + if rf, ok := ret.Get(0).(func(model.CmdType, api.Sender, string, *model.FeatureAddressType, time.Duration) *model.MsgCounterType); ok { + r0 = rf(cmd, sender, destinationSki, destinationAddress, maxDelay) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(model.CmdType, api.Sender, string, *model.FeatureAddressType, time.Duration) *model.ErrorType); ok { + r1 = rf(cmd, sender, destinationSki, destinationAddress, maxDelay) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// NodeManagement_RequestDataBySenderAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestDataBySenderAddress' +type NodeManagement_RequestDataBySenderAddress_Call struct { + *mock.Call +} + +// RequestDataBySenderAddress is a helper method to define mock.On call +// - cmd model.CmdType +// - sender api.Sender +// - destinationSki string +// - destinationAddress *model.FeatureAddressType +// - maxDelay time.Duration +func (_e *NodeManagement_Expecter) RequestDataBySenderAddress(cmd interface{}, sender interface{}, destinationSki interface{}, destinationAddress interface{}, maxDelay interface{}) *NodeManagement_RequestDataBySenderAddress_Call { + return &NodeManagement_RequestDataBySenderAddress_Call{Call: _e.mock.On("RequestDataBySenderAddress", cmd, sender, destinationSki, destinationAddress, maxDelay)} +} + +func (_c *NodeManagement_RequestDataBySenderAddress_Call) Run(run func(cmd model.CmdType, sender api.Sender, destinationSki string, destinationAddress *model.FeatureAddressType, maxDelay time.Duration)) *NodeManagement_RequestDataBySenderAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.CmdType), args[1].(api.Sender), args[2].(string), args[3].(*model.FeatureAddressType), args[4].(time.Duration)) + }) + return _c +} + +func (_c *NodeManagement_RequestDataBySenderAddress_Call) Return(_a0 *model.MsgCounterType, _a1 *model.ErrorType) *NodeManagement_RequestDataBySenderAddress_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *NodeManagement_RequestDataBySenderAddress_Call) RunAndReturn(run func(model.CmdType, api.Sender, string, *model.FeatureAddressType, time.Duration) (*model.MsgCounterType, *model.ErrorType)) *NodeManagement_RequestDataBySenderAddress_Call { + _c.Call.Return(run) + return _c +} + +// Role provides a mock function with given fields: +func (_m *NodeManagement) Role() model.RoleType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Role") + } + + var r0 model.RoleType + if rf, ok := ret.Get(0).(func() model.RoleType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.RoleType) + } + + return r0 +} + +// NodeManagement_Role_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Role' +type NodeManagement_Role_Call struct { + *mock.Call +} + +// Role is a helper method to define mock.On call +func (_e *NodeManagement_Expecter) Role() *NodeManagement_Role_Call { + return &NodeManagement_Role_Call{Call: _e.mock.On("Role")} +} + +func (_c *NodeManagement_Role_Call) Run(run func()) *NodeManagement_Role_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *NodeManagement_Role_Call) Return(_a0 model.RoleType) *NodeManagement_Role_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *NodeManagement_Role_Call) RunAndReturn(run func() model.RoleType) *NodeManagement_Role_Call { + _c.Call.Return(run) + return _c +} + +// SetData provides a mock function with given fields: function, data +func (_m *NodeManagement) SetData(function model.FunctionType, data interface{}) { + _m.Called(function, data) +} + +// NodeManagement_SetData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetData' +type NodeManagement_SetData_Call struct { + *mock.Call +} + +// SetData is a helper method to define mock.On call +// - function model.FunctionType +// - data interface{} +func (_e *NodeManagement_Expecter) SetData(function interface{}, data interface{}) *NodeManagement_SetData_Call { + return &NodeManagement_SetData_Call{Call: _e.mock.On("SetData", function, data)} +} + +func (_c *NodeManagement_SetData_Call) Run(run func(function model.FunctionType, data interface{})) *NodeManagement_SetData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType), args[1].(interface{})) + }) + return _c +} + +func (_c *NodeManagement_SetData_Call) Return() *NodeManagement_SetData_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeManagement_SetData_Call) RunAndReturn(run func(model.FunctionType, interface{})) *NodeManagement_SetData_Call { + _c.Call.Return(run) + return _c +} + +// SetDescription provides a mock function with given fields: desc +func (_m *NodeManagement) SetDescription(desc *model.DescriptionType) { + _m.Called(desc) +} + +// NodeManagement_SetDescription_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDescription' +type NodeManagement_SetDescription_Call struct { + *mock.Call +} + +// SetDescription is a helper method to define mock.On call +// - desc *model.DescriptionType +func (_e *NodeManagement_Expecter) SetDescription(desc interface{}) *NodeManagement_SetDescription_Call { + return &NodeManagement_SetDescription_Call{Call: _e.mock.On("SetDescription", desc)} +} + +func (_c *NodeManagement_SetDescription_Call) Run(run func(desc *model.DescriptionType)) *NodeManagement_SetDescription_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.DescriptionType)) + }) + return _c +} + +func (_c *NodeManagement_SetDescription_Call) Return() *NodeManagement_SetDescription_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeManagement_SetDescription_Call) RunAndReturn(run func(*model.DescriptionType)) *NodeManagement_SetDescription_Call { + _c.Call.Return(run) + return _c +} + +// SetDescriptionString provides a mock function with given fields: s +func (_m *NodeManagement) SetDescriptionString(s string) { + _m.Called(s) +} + +// NodeManagement_SetDescriptionString_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDescriptionString' +type NodeManagement_SetDescriptionString_Call struct { + *mock.Call +} + +// SetDescriptionString is a helper method to define mock.On call +// - s string +func (_e *NodeManagement_Expecter) SetDescriptionString(s interface{}) *NodeManagement_SetDescriptionString_Call { + return &NodeManagement_SetDescriptionString_Call{Call: _e.mock.On("SetDescriptionString", s)} +} + +func (_c *NodeManagement_SetDescriptionString_Call) Run(run func(s string)) *NodeManagement_SetDescriptionString_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *NodeManagement_SetDescriptionString_Call) Return() *NodeManagement_SetDescriptionString_Call { + _c.Call.Return() + return _c +} + +func (_c *NodeManagement_SetDescriptionString_Call) RunAndReturn(run func(string)) *NodeManagement_SetDescriptionString_Call { + _c.Call.Return(run) + return _c +} + +// String provides a mock function with given fields: +func (_m *NodeManagement) String() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for String") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// NodeManagement_String_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'String' +type NodeManagement_String_Call struct { + *mock.Call +} + +// String is a helper method to define mock.On call +func (_e *NodeManagement_Expecter) String() *NodeManagement_String_Call { + return &NodeManagement_String_Call{Call: _e.mock.On("String")} +} + +func (_c *NodeManagement_String_Call) Run(run func()) *NodeManagement_String_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *NodeManagement_String_Call) Return(_a0 string) *NodeManagement_String_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *NodeManagement_String_Call) RunAndReturn(run func() string) *NodeManagement_String_Call { + _c.Call.Return(run) + return _c +} + +// Subscribe provides a mock function with given fields: remoteAdress +func (_m *NodeManagement) Subscribe(remoteAdress *model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType) { + ret := _m.Called(remoteAdress) + + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + + var r0 *model.MsgCounterType + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType)); ok { + return rf(remoteAdress) + } + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType) *model.MsgCounterType); ok { + r0 = rf(remoteAdress) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(*model.FeatureAddressType) *model.ErrorType); ok { + r1 = rf(remoteAdress) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// NodeManagement_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe' +type NodeManagement_Subscribe_Call struct { + *mock.Call +} + +// Subscribe is a helper method to define mock.On call +// - remoteAdress *model.FeatureAddressType +func (_e *NodeManagement_Expecter) Subscribe(remoteAdress interface{}) *NodeManagement_Subscribe_Call { + return &NodeManagement_Subscribe_Call{Call: _e.mock.On("Subscribe", remoteAdress)} +} + +func (_c *NodeManagement_Subscribe_Call) Run(run func(remoteAdress *model.FeatureAddressType)) *NodeManagement_Subscribe_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *NodeManagement_Subscribe_Call) Return(_a0 *model.MsgCounterType, _a1 *model.ErrorType) *NodeManagement_Subscribe_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *NodeManagement_Subscribe_Call) RunAndReturn(run func(*model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType)) *NodeManagement_Subscribe_Call { + _c.Call.Return(run) + return _c +} + +// Type provides a mock function with given fields: +func (_m *NodeManagement) Type() model.FeatureTypeType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Type") + } + + var r0 model.FeatureTypeType + if rf, ok := ret.Get(0).(func() model.FeatureTypeType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(model.FeatureTypeType) + } + + return r0 +} + +// NodeManagement_Type_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Type' +type NodeManagement_Type_Call struct { + *mock.Call +} + +// Type is a helper method to define mock.On call +func (_e *NodeManagement_Expecter) Type() *NodeManagement_Type_Call { + return &NodeManagement_Type_Call{Call: _e.mock.On("Type")} +} + +func (_c *NodeManagement_Type_Call) Run(run func()) *NodeManagement_Type_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *NodeManagement_Type_Call) Return(_a0 model.FeatureTypeType) *NodeManagement_Type_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *NodeManagement_Type_Call) RunAndReturn(run func() model.FeatureTypeType) *NodeManagement_Type_Call { + _c.Call.Return(run) + return _c +} + +// WriteData provides a mock function with given fields: function, deleteSelector, partialSelector, deleteElements, destination +func (_m *NodeManagement) WriteData(function model.FunctionType, deleteSelector interface{}, partialSelector interface{}, deleteElements interface{}, destination api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType) { + ret := _m.Called(function, deleteSelector, partialSelector, deleteElements, destination) + + if len(ret) == 0 { + panic("no return value specified for WriteData") + } + + var r0 *model.MsgCounterType + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(model.FunctionType, interface{}, interface{}, interface{}, api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType)); ok { + return rf(function, deleteSelector, partialSelector, deleteElements, destination) + } + if rf, ok := ret.Get(0).(func(model.FunctionType, interface{}, interface{}, interface{}, api.FeatureRemote) *model.MsgCounterType); ok { + r0 = rf(function, deleteSelector, partialSelector, deleteElements, destination) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(model.FunctionType, interface{}, interface{}, interface{}, api.FeatureRemote) *model.ErrorType); ok { + r1 = rf(function, deleteSelector, partialSelector, deleteElements, destination) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// NodeManagement_WriteData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WriteData' +type NodeManagement_WriteData_Call struct { + *mock.Call +} + +// WriteData is a helper method to define mock.On call +// - function model.FunctionType +// - deleteSelector interface{} +// - partialSelector interface{} +// - deleteElements interface{} +// - destination api.FeatureRemote +func (_e *NodeManagement_Expecter) WriteData(function interface{}, deleteSelector interface{}, partialSelector interface{}, deleteElements interface{}, destination interface{}) *NodeManagement_WriteData_Call { + return &NodeManagement_WriteData_Call{Call: _e.mock.On("WriteData", function, deleteSelector, partialSelector, deleteElements, destination)} +} + +func (_c *NodeManagement_WriteData_Call) Run(run func(function model.FunctionType, deleteSelector interface{}, partialSelector interface{}, deleteElements interface{}, destination api.FeatureRemote)) *NodeManagement_WriteData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FunctionType), args[1].(interface{}), args[2].(interface{}), args[3].(interface{}), args[4].(api.FeatureRemote)) + }) + return _c +} + +func (_c *NodeManagement_WriteData_Call) Return(_a0 *model.MsgCounterType, _a1 *model.ErrorType) *NodeManagement_WriteData_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *NodeManagement_WriteData_Call) RunAndReturn(run func(model.FunctionType, interface{}, interface{}, interface{}, api.FeatureRemote) (*model.MsgCounterType, *model.ErrorType)) *NodeManagement_WriteData_Call { + _c.Call.Return(run) + return _c +} + +// NewNodeManagement creates a new instance of NodeManagement. 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 NewNodeManagement(t interface { + mock.TestingT + Cleanup(func()) +}) *NodeManagement { + mock := &NodeManagement{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/Operations.go b/mocks/Operations.go new file mode 100644 index 0000000..718fb6d --- /dev/null +++ b/mocks/Operations.go @@ -0,0 +1,127 @@ +// Code generated by mockery v2.40.1. DO NOT EDIT. + +package mocks + +import ( + model "github.com/enbility/spine-go/model" + mock "github.com/stretchr/testify/mock" +) + +// Operations is an autogenerated mock type for the Operations type +type Operations struct { + mock.Mock +} + +type Operations_Expecter struct { + mock *mock.Mock +} + +func (_m *Operations) EXPECT() *Operations_Expecter { + return &Operations_Expecter{mock: &_m.Mock} +} + +// Information provides a mock function with given fields: +func (_m *Operations) Information() *model.PossibleOperationsType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Information") + } + + var r0 *model.PossibleOperationsType + if rf, ok := ret.Get(0).(func() *model.PossibleOperationsType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.PossibleOperationsType) + } + } + + return r0 +} + +// Operations_Information_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Information' +type Operations_Information_Call struct { + *mock.Call +} + +// Information is a helper method to define mock.On call +func (_e *Operations_Expecter) Information() *Operations_Information_Call { + return &Operations_Information_Call{Call: _e.mock.On("Information")} +} + +func (_c *Operations_Information_Call) Run(run func()) *Operations_Information_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Operations_Information_Call) Return(_a0 *model.PossibleOperationsType) *Operations_Information_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Operations_Information_Call) RunAndReturn(run func() *model.PossibleOperationsType) *Operations_Information_Call { + _c.Call.Return(run) + return _c +} + +// String provides a mock function with given fields: +func (_m *Operations) String() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for String") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Operations_String_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'String' +type Operations_String_Call struct { + *mock.Call +} + +// String is a helper method to define mock.On call +func (_e *Operations_Expecter) String() *Operations_String_Call { + return &Operations_String_Call{Call: _e.mock.On("String")} +} + +func (_c *Operations_String_Call) Run(run func()) *Operations_String_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Operations_String_Call) Return(_a0 string) *Operations_String_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Operations_String_Call) RunAndReturn(run func() string) *Operations_String_Call { + _c.Call.Return(run) + return _c +} + +// NewOperations creates a new instance of Operations. 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 NewOperations(t interface { + mock.TestingT + Cleanup(func()) +}) *Operations { + mock := &Operations{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/PendingRequests.go b/mocks/PendingRequests.go new file mode 100644 index 0000000..90b890f --- /dev/null +++ b/mocks/PendingRequests.go @@ -0,0 +1,282 @@ +// Code generated by mockery v2.40.1. DO NOT EDIT. + +package mocks + +import ( + model "github.com/enbility/spine-go/model" + mock "github.com/stretchr/testify/mock" + + time "time" +) + +// PendingRequests is an autogenerated mock type for the PendingRequests type +type PendingRequests struct { + mock.Mock +} + +type PendingRequests_Expecter struct { + mock *mock.Mock +} + +func (_m *PendingRequests) EXPECT() *PendingRequests_Expecter { + return &PendingRequests_Expecter{mock: &_m.Mock} +} + +// Add provides a mock function with given fields: ski, counter, maxDelay +func (_m *PendingRequests) Add(ski string, counter model.MsgCounterType, maxDelay time.Duration) { + _m.Called(ski, counter, maxDelay) +} + +// PendingRequests_Add_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Add' +type PendingRequests_Add_Call struct { + *mock.Call +} + +// Add is a helper method to define mock.On call +// - ski string +// - counter model.MsgCounterType +// - maxDelay time.Duration +func (_e *PendingRequests_Expecter) Add(ski interface{}, counter interface{}, maxDelay interface{}) *PendingRequests_Add_Call { + return &PendingRequests_Add_Call{Call: _e.mock.On("Add", ski, counter, maxDelay)} +} + +func (_c *PendingRequests_Add_Call) Run(run func(ski string, counter model.MsgCounterType, maxDelay time.Duration)) *PendingRequests_Add_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(model.MsgCounterType), args[2].(time.Duration)) + }) + return _c +} + +func (_c *PendingRequests_Add_Call) Return() *PendingRequests_Add_Call { + _c.Call.Return() + return _c +} + +func (_c *PendingRequests_Add_Call) RunAndReturn(run func(string, model.MsgCounterType, time.Duration)) *PendingRequests_Add_Call { + _c.Call.Return(run) + return _c +} + +// GetData provides a mock function with given fields: ski, counter +func (_m *PendingRequests) GetData(ski string, counter model.MsgCounterType) (interface{}, *model.ErrorType) { + ret := _m.Called(ski, counter) + + if len(ret) == 0 { + panic("no return value specified for GetData") + } + + var r0 interface{} + var r1 *model.ErrorType + if rf, ok := ret.Get(0).(func(string, model.MsgCounterType) (interface{}, *model.ErrorType)); ok { + return rf(ski, counter) + } + if rf, ok := ret.Get(0).(func(string, model.MsgCounterType) interface{}); ok { + r0 = rf(ski, counter) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(interface{}) + } + } + + if rf, ok := ret.Get(1).(func(string, model.MsgCounterType) *model.ErrorType); ok { + r1 = rf(ski, counter) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.ErrorType) + } + } + + return r0, r1 +} + +// PendingRequests_GetData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetData' +type PendingRequests_GetData_Call struct { + *mock.Call +} + +// GetData is a helper method to define mock.On call +// - ski string +// - counter model.MsgCounterType +func (_e *PendingRequests_Expecter) GetData(ski interface{}, counter interface{}) *PendingRequests_GetData_Call { + return &PendingRequests_GetData_Call{Call: _e.mock.On("GetData", ski, counter)} +} + +func (_c *PendingRequests_GetData_Call) Run(run func(ski string, counter model.MsgCounterType)) *PendingRequests_GetData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(model.MsgCounterType)) + }) + return _c +} + +func (_c *PendingRequests_GetData_Call) Return(_a0 interface{}, _a1 *model.ErrorType) *PendingRequests_GetData_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *PendingRequests_GetData_Call) RunAndReturn(run func(string, model.MsgCounterType) (interface{}, *model.ErrorType)) *PendingRequests_GetData_Call { + _c.Call.Return(run) + return _c +} + +// Remove provides a mock function with given fields: ski, counter +func (_m *PendingRequests) Remove(ski string, counter model.MsgCounterType) *model.ErrorType { + ret := _m.Called(ski, counter) + + if len(ret) == 0 { + panic("no return value specified for Remove") + } + + var r0 *model.ErrorType + if rf, ok := ret.Get(0).(func(string, model.MsgCounterType) *model.ErrorType); ok { + r0 = rf(ski, counter) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.ErrorType) + } + } + + return r0 +} + +// PendingRequests_Remove_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Remove' +type PendingRequests_Remove_Call struct { + *mock.Call +} + +// Remove is a helper method to define mock.On call +// - ski string +// - counter model.MsgCounterType +func (_e *PendingRequests_Expecter) Remove(ski interface{}, counter interface{}) *PendingRequests_Remove_Call { + return &PendingRequests_Remove_Call{Call: _e.mock.On("Remove", ski, counter)} +} + +func (_c *PendingRequests_Remove_Call) Run(run func(ski string, counter model.MsgCounterType)) *PendingRequests_Remove_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(model.MsgCounterType)) + }) + return _c +} + +func (_c *PendingRequests_Remove_Call) Return(_a0 *model.ErrorType) *PendingRequests_Remove_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *PendingRequests_Remove_Call) RunAndReturn(run func(string, model.MsgCounterType) *model.ErrorType) *PendingRequests_Remove_Call { + _c.Call.Return(run) + return _c +} + +// SetData provides a mock function with given fields: ski, counter, data +func (_m *PendingRequests) SetData(ski string, counter model.MsgCounterType, data interface{}) *model.ErrorType { + ret := _m.Called(ski, counter, data) + + if len(ret) == 0 { + panic("no return value specified for SetData") + } + + var r0 *model.ErrorType + if rf, ok := ret.Get(0).(func(string, model.MsgCounterType, interface{}) *model.ErrorType); ok { + r0 = rf(ski, counter, data) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.ErrorType) + } + } + + return r0 +} + +// PendingRequests_SetData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetData' +type PendingRequests_SetData_Call struct { + *mock.Call +} + +// SetData is a helper method to define mock.On call +// - ski string +// - counter model.MsgCounterType +// - data interface{} +func (_e *PendingRequests_Expecter) SetData(ski interface{}, counter interface{}, data interface{}) *PendingRequests_SetData_Call { + return &PendingRequests_SetData_Call{Call: _e.mock.On("SetData", ski, counter, data)} +} + +func (_c *PendingRequests_SetData_Call) Run(run func(ski string, counter model.MsgCounterType, data interface{})) *PendingRequests_SetData_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(model.MsgCounterType), args[2].(interface{})) + }) + return _c +} + +func (_c *PendingRequests_SetData_Call) Return(_a0 *model.ErrorType) *PendingRequests_SetData_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *PendingRequests_SetData_Call) RunAndReturn(run func(string, model.MsgCounterType, interface{}) *model.ErrorType) *PendingRequests_SetData_Call { + _c.Call.Return(run) + return _c +} + +// SetResult provides a mock function with given fields: ski, counter, errorResult +func (_m *PendingRequests) SetResult(ski string, counter model.MsgCounterType, errorResult *model.ErrorType) *model.ErrorType { + ret := _m.Called(ski, counter, errorResult) + + if len(ret) == 0 { + panic("no return value specified for SetResult") + } + + var r0 *model.ErrorType + if rf, ok := ret.Get(0).(func(string, model.MsgCounterType, *model.ErrorType) *model.ErrorType); ok { + r0 = rf(ski, counter, errorResult) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.ErrorType) + } + } + + return r0 +} + +// PendingRequests_SetResult_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetResult' +type PendingRequests_SetResult_Call struct { + *mock.Call +} + +// SetResult is a helper method to define mock.On call +// - ski string +// - counter model.MsgCounterType +// - errorResult *model.ErrorType +func (_e *PendingRequests_Expecter) SetResult(ski interface{}, counter interface{}, errorResult interface{}) *PendingRequests_SetResult_Call { + return &PendingRequests_SetResult_Call{Call: _e.mock.On("SetResult", ski, counter, errorResult)} +} + +func (_c *PendingRequests_SetResult_Call) Run(run func(ski string, counter model.MsgCounterType, errorResult *model.ErrorType)) *PendingRequests_SetResult_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(model.MsgCounterType), args[2].(*model.ErrorType)) + }) + return _c +} + +func (_c *PendingRequests_SetResult_Call) Return(_a0 *model.ErrorType) *PendingRequests_SetResult_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *PendingRequests_SetResult_Call) RunAndReturn(run func(string, model.MsgCounterType, *model.ErrorType) *model.ErrorType) *PendingRequests_SetResult_Call { + _c.Call.Return(run) + return _c +} + +// NewPendingRequests creates a new instance of PendingRequests. 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 NewPendingRequests(t interface { + mock.TestingT + Cleanup(func()) +}) *PendingRequests { + mock := &PendingRequests{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/Sender.go b/mocks/Sender.go new file mode 100644 index 0000000..50c3345 --- /dev/null +++ b/mocks/Sender.go @@ -0,0 +1,654 @@ +// Code generated by mockery v2.40.1. DO NOT EDIT. + +package mocks + +import ( + model "github.com/enbility/spine-go/model" + mock "github.com/stretchr/testify/mock" +) + +// Sender is an autogenerated mock type for the Sender type +type Sender struct { + mock.Mock +} + +type Sender_Expecter struct { + mock *mock.Mock +} + +func (_m *Sender) EXPECT() *Sender_Expecter { + return &Sender_Expecter{mock: &_m.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) + + 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.FeatureAddressType, *model.FeatureAddressType, model.FeatureTypeType) (*model.MsgCounterType, error)); ok { + return rf(senderAddress, destinationAddress, serverFeatureType) + } + 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) + } + } + + 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 +} + +// Sender_Bind_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Bind' +type Sender_Bind_Call struct { + *mock.Call +} + +// Bind is a helper method to define mock.On call +// - senderAddress *model.FeatureAddressType +// - destinationAddress *model.FeatureAddressType +// - serverFeatureType model.FeatureTypeType +func (_e *Sender_Expecter) Bind(senderAddress interface{}, destinationAddress interface{}, serverFeatureType interface{}) *Sender_Bind_Call { + return &Sender_Bind_Call{Call: _e.mock.On("Bind", senderAddress, destinationAddress, serverFeatureType)} +} + +func (_c *Sender_Bind_Call) Run(run func(senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType, serverFeatureType model.FeatureTypeType)) *Sender_Bind_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType), args[1].(*model.FeatureAddressType), args[2].(model.FeatureTypeType)) + }) + return _c +} + +func (_c *Sender_Bind_Call) Return(_a0 *model.MsgCounterType, _a1 error) *Sender_Bind_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Sender_Bind_Call) RunAndReturn(run func(*model.FeatureAddressType, *model.FeatureAddressType, model.FeatureTypeType) (*model.MsgCounterType, error)) *Sender_Bind_Call { + _c.Call.Return(run) + return _c +} + +// DatagramForMsgCounter provides a mock function with given fields: msgCounter +func (_m *Sender) DatagramForMsgCounter(msgCounter model.MsgCounterType) (model.DatagramType, error) { + ret := _m.Called(msgCounter) + + if len(ret) == 0 { + panic("no return value specified for DatagramForMsgCounter") + } + + var r0 model.DatagramType + var r1 error + if rf, ok := ret.Get(0).(func(model.MsgCounterType) (model.DatagramType, error)); ok { + return rf(msgCounter) + } + if rf, ok := ret.Get(0).(func(model.MsgCounterType) model.DatagramType); ok { + r0 = rf(msgCounter) + } else { + r0 = ret.Get(0).(model.DatagramType) + } + + if rf, ok := ret.Get(1).(func(model.MsgCounterType) error); ok { + r1 = rf(msgCounter) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Sender_DatagramForMsgCounter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DatagramForMsgCounter' +type Sender_DatagramForMsgCounter_Call struct { + *mock.Call +} + +// DatagramForMsgCounter is a helper method to define mock.On call +// - msgCounter model.MsgCounterType +func (_e *Sender_Expecter) DatagramForMsgCounter(msgCounter interface{}) *Sender_DatagramForMsgCounter_Call { + return &Sender_DatagramForMsgCounter_Call{Call: _e.mock.On("DatagramForMsgCounter", msgCounter)} +} + +func (_c *Sender_DatagramForMsgCounter_Call) Run(run func(msgCounter model.MsgCounterType)) *Sender_DatagramForMsgCounter_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.MsgCounterType)) + }) + return _c +} + +func (_c *Sender_DatagramForMsgCounter_Call) Return(_a0 model.DatagramType, _a1 error) *Sender_DatagramForMsgCounter_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Sender_DatagramForMsgCounter_Call) RunAndReturn(run func(model.MsgCounterType) (model.DatagramType, error)) *Sender_DatagramForMsgCounter_Call { + _c.Call.Return(run) + return _c +} + +// 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) + + if len(ret) == 0 { + panic("no return value specified for Notify") + } + + var r0 *model.MsgCounterType + var r1 error + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType, *model.FeatureAddressType, model.CmdType) (*model.MsgCounterType, error)); ok { + return rf(senderAddress, destinationAddress, cmd) + } + 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) + } + } + + 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 +} + +// Sender_Notify_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Notify' +type Sender_Notify_Call struct { + *mock.Call +} + +// Notify is a helper method to define mock.On call +// - senderAddress *model.FeatureAddressType +// - destinationAddress *model.FeatureAddressType +// - cmd model.CmdType +func (_e *Sender_Expecter) Notify(senderAddress interface{}, destinationAddress interface{}, cmd interface{}) *Sender_Notify_Call { + return &Sender_Notify_Call{Call: _e.mock.On("Notify", senderAddress, destinationAddress, cmd)} +} + +func (_c *Sender_Notify_Call) Run(run func(senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType, cmd model.CmdType)) *Sender_Notify_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType), args[1].(*model.FeatureAddressType), args[2].(model.CmdType)) + }) + return _c +} + +func (_c *Sender_Notify_Call) Return(_a0 *model.MsgCounterType, _a1 error) *Sender_Notify_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Sender_Notify_Call) RunAndReturn(run func(*model.FeatureAddressType, *model.FeatureAddressType, model.CmdType) (*model.MsgCounterType, error)) *Sender_Notify_Call { + _c.Call.Return(run) + return _c +} + +// 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) + + if len(ret) == 0 { + panic("no return value specified for Reply") + } + + 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 +} + +// Sender_Reply_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Reply' +type Sender_Reply_Call struct { + *mock.Call +} + +// Reply is a helper method to define mock.On call +// - requestHeader *model.HeaderType +// - senderAddress *model.FeatureAddressType +// - cmd model.CmdType +func (_e *Sender_Expecter) Reply(requestHeader interface{}, senderAddress interface{}, cmd interface{}) *Sender_Reply_Call { + return &Sender_Reply_Call{Call: _e.mock.On("Reply", requestHeader, senderAddress, cmd)} +} + +func (_c *Sender_Reply_Call) Run(run func(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType, cmd model.CmdType)) *Sender_Reply_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.HeaderType), args[1].(*model.FeatureAddressType), args[2].(model.CmdType)) + }) + return _c +} + +func (_c *Sender_Reply_Call) Return(_a0 error) *Sender_Reply_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Sender_Reply_Call) RunAndReturn(run func(*model.HeaderType, *model.FeatureAddressType, model.CmdType) error) *Sender_Reply_Call { + _c.Call.Return(run) + return _c +} + +// 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) + + if len(ret) == 0 { + panic("no return value specified for Request") + } + + var r0 *model.MsgCounterType + var r1 error + if rf, ok := ret.Get(0).(func(model.CmdClassifierType, *model.FeatureAddressType, *model.FeatureAddressType, bool, []model.CmdType) (*model.MsgCounterType, error)); ok { + return rf(cmdClassifier, senderAddress, destinationAddress, ackRequest, cmd) + } + 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) + } + } + + 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 +} + +// Sender_Request_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Request' +type Sender_Request_Call struct { + *mock.Call +} + +// Request is a helper method to define mock.On call +// - cmdClassifier model.CmdClassifierType +// - senderAddress *model.FeatureAddressType +// - destinationAddress *model.FeatureAddressType +// - ackRequest bool +// - cmd []model.CmdType +func (_e *Sender_Expecter) Request(cmdClassifier interface{}, senderAddress interface{}, destinationAddress interface{}, ackRequest interface{}, cmd interface{}) *Sender_Request_Call { + return &Sender_Request_Call{Call: _e.mock.On("Request", cmdClassifier, senderAddress, destinationAddress, ackRequest, cmd)} +} + +func (_c *Sender_Request_Call) Run(run func(cmdClassifier model.CmdClassifierType, senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType, ackRequest bool, cmd []model.CmdType)) *Sender_Request_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.CmdClassifierType), args[1].(*model.FeatureAddressType), args[2].(*model.FeatureAddressType), args[3].(bool), args[4].([]model.CmdType)) + }) + return _c +} + +func (_c *Sender_Request_Call) Return(_a0 *model.MsgCounterType, _a1 error) *Sender_Request_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Sender_Request_Call) RunAndReturn(run func(model.CmdClassifierType, *model.FeatureAddressType, *model.FeatureAddressType, bool, []model.CmdType) (*model.MsgCounterType, error)) *Sender_Request_Call { + _c.Call.Return(run) + return _c +} + +// ResultError provides a mock function with given fields: requestHeader, senderAddress, err +func (_m *Sender) ResultError(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType, err *model.ErrorType) error { + ret := _m.Called(requestHeader, senderAddress, err) + + if len(ret) == 0 { + panic("no return value specified for ResultError") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*model.HeaderType, *model.FeatureAddressType, *model.ErrorType) error); ok { + r0 = rf(requestHeader, senderAddress, err) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Sender_ResultError_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResultError' +type Sender_ResultError_Call struct { + *mock.Call +} + +// ResultError is a helper method to define mock.On call +// - requestHeader *model.HeaderType +// - senderAddress *model.FeatureAddressType +// - err *model.ErrorType +func (_e *Sender_Expecter) ResultError(requestHeader interface{}, senderAddress interface{}, err interface{}) *Sender_ResultError_Call { + return &Sender_ResultError_Call{Call: _e.mock.On("ResultError", requestHeader, senderAddress, err)} +} + +func (_c *Sender_ResultError_Call) Run(run func(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType, err *model.ErrorType)) *Sender_ResultError_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.HeaderType), args[1].(*model.FeatureAddressType), args[2].(*model.ErrorType)) + }) + return _c +} + +func (_c *Sender_ResultError_Call) Return(_a0 error) *Sender_ResultError_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Sender_ResultError_Call) RunAndReturn(run func(*model.HeaderType, *model.FeatureAddressType, *model.ErrorType) error) *Sender_ResultError_Call { + _c.Call.Return(run) + return _c +} + +// 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) + + if len(ret) == 0 { + panic("no return value specified for ResultSuccess") + } + + 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 +} + +// Sender_ResultSuccess_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResultSuccess' +type Sender_ResultSuccess_Call struct { + *mock.Call +} + +// ResultSuccess is a helper method to define mock.On call +// - requestHeader *model.HeaderType +// - senderAddress *model.FeatureAddressType +func (_e *Sender_Expecter) ResultSuccess(requestHeader interface{}, senderAddress interface{}) *Sender_ResultSuccess_Call { + return &Sender_ResultSuccess_Call{Call: _e.mock.On("ResultSuccess", requestHeader, senderAddress)} +} + +func (_c *Sender_ResultSuccess_Call) Run(run func(requestHeader *model.HeaderType, senderAddress *model.FeatureAddressType)) *Sender_ResultSuccess_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.HeaderType), args[1].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *Sender_ResultSuccess_Call) Return(_a0 error) *Sender_ResultSuccess_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Sender_ResultSuccess_Call) RunAndReturn(run func(*model.HeaderType, *model.FeatureAddressType) error) *Sender_ResultSuccess_Call { + _c.Call.Return(run) + return _c +} + +// 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) + + 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.FeatureAddressType, *model.FeatureAddressType, model.FeatureTypeType) (*model.MsgCounterType, error)); ok { + return rf(senderAddress, destinationAddress, serverFeatureType) + } + 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) + } + } + + 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 +} + +// Sender_Subscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscribe' +type Sender_Subscribe_Call struct { + *mock.Call +} + +// Subscribe is a helper method to define mock.On call +// - senderAddress *model.FeatureAddressType +// - destinationAddress *model.FeatureAddressType +// - serverFeatureType model.FeatureTypeType +func (_e *Sender_Expecter) Subscribe(senderAddress interface{}, destinationAddress interface{}, serverFeatureType interface{}) *Sender_Subscribe_Call { + return &Sender_Subscribe_Call{Call: _e.mock.On("Subscribe", senderAddress, destinationAddress, serverFeatureType)} +} + +func (_c *Sender_Subscribe_Call) Run(run func(senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType, serverFeatureType model.FeatureTypeType)) *Sender_Subscribe_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType), args[1].(*model.FeatureAddressType), args[2].(model.FeatureTypeType)) + }) + return _c +} + +func (_c *Sender_Subscribe_Call) Return(_a0 *model.MsgCounterType, _a1 error) *Sender_Subscribe_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Sender_Subscribe_Call) RunAndReturn(run func(*model.FeatureAddressType, *model.FeatureAddressType, model.FeatureTypeType) (*model.MsgCounterType, error)) *Sender_Subscribe_Call { + _c.Call.Return(run) + return _c +} + +// Unbind provides a mock function with given fields: senderAddress, destinationAddress +func (_m *Sender) Unbind(senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType) (*model.MsgCounterType, error) { + ret := _m.Called(senderAddress, destinationAddress) + + if len(ret) == 0 { + panic("no return value specified for Unbind") + } + + var r0 *model.MsgCounterType + var r1 error + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType, *model.FeatureAddressType) (*model.MsgCounterType, error)); ok { + return rf(senderAddress, destinationAddress) + } + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType, *model.FeatureAddressType) *model.MsgCounterType); ok { + r0 = rf(senderAddress, destinationAddress) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(*model.FeatureAddressType, *model.FeatureAddressType) error); ok { + r1 = rf(senderAddress, destinationAddress) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Sender_Unbind_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unbind' +type Sender_Unbind_Call struct { + *mock.Call +} + +// Unbind is a helper method to define mock.On call +// - senderAddress *model.FeatureAddressType +// - destinationAddress *model.FeatureAddressType +func (_e *Sender_Expecter) Unbind(senderAddress interface{}, destinationAddress interface{}) *Sender_Unbind_Call { + return &Sender_Unbind_Call{Call: _e.mock.On("Unbind", senderAddress, destinationAddress)} +} + +func (_c *Sender_Unbind_Call) Run(run func(senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType)) *Sender_Unbind_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType), args[1].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *Sender_Unbind_Call) Return(_a0 *model.MsgCounterType, _a1 error) *Sender_Unbind_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Sender_Unbind_Call) RunAndReturn(run func(*model.FeatureAddressType, *model.FeatureAddressType) (*model.MsgCounterType, error)) *Sender_Unbind_Call { + _c.Call.Return(run) + return _c +} + +// Unsubscribe provides a mock function with given fields: senderAddress, destinationAddress +func (_m *Sender) Unsubscribe(senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType) (*model.MsgCounterType, error) { + ret := _m.Called(senderAddress, destinationAddress) + + if len(ret) == 0 { + panic("no return value specified for Unsubscribe") + } + + var r0 *model.MsgCounterType + var r1 error + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType, *model.FeatureAddressType) (*model.MsgCounterType, error)); ok { + return rf(senderAddress, destinationAddress) + } + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType, *model.FeatureAddressType) *model.MsgCounterType); ok { + r0 = rf(senderAddress, destinationAddress) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.MsgCounterType) + } + } + + if rf, ok := ret.Get(1).(func(*model.FeatureAddressType, *model.FeatureAddressType) error); ok { + r1 = rf(senderAddress, destinationAddress) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Sender_Unsubscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unsubscribe' +type Sender_Unsubscribe_Call struct { + *mock.Call +} + +// Unsubscribe is a helper method to define mock.On call +// - senderAddress *model.FeatureAddressType +// - destinationAddress *model.FeatureAddressType +func (_e *Sender_Expecter) Unsubscribe(senderAddress interface{}, destinationAddress interface{}) *Sender_Unsubscribe_Call { + return &Sender_Unsubscribe_Call{Call: _e.mock.On("Unsubscribe", senderAddress, destinationAddress)} +} + +func (_c *Sender_Unsubscribe_Call) Run(run func(senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType)) *Sender_Unsubscribe_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType), args[1].(*model.FeatureAddressType)) + }) + return _c +} + +func (_c *Sender_Unsubscribe_Call) Return(_a0 *model.MsgCounterType, _a1 error) *Sender_Unsubscribe_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Sender_Unsubscribe_Call) RunAndReturn(run func(*model.FeatureAddressType, *model.FeatureAddressType) (*model.MsgCounterType, error)) *Sender_Unsubscribe_Call { + _c.Call.Return(run) + return _c +} + +// 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) + + if len(ret) == 0 { + panic("no return value specified for Write") + } + + var r0 *model.MsgCounterType + var r1 error + if rf, ok := ret.Get(0).(func(*model.FeatureAddressType, *model.FeatureAddressType, model.CmdType) (*model.MsgCounterType, error)); ok { + return rf(senderAddress, destinationAddress, cmd) + } + 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) + } + } + + 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 +} + +// Sender_Write_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Write' +type Sender_Write_Call struct { + *mock.Call +} + +// Write is a helper method to define mock.On call +// - senderAddress *model.FeatureAddressType +// - destinationAddress *model.FeatureAddressType +// - cmd model.CmdType +func (_e *Sender_Expecter) Write(senderAddress interface{}, destinationAddress interface{}, cmd interface{}) *Sender_Write_Call { + return &Sender_Write_Call{Call: _e.mock.On("Write", senderAddress, destinationAddress, cmd)} +} + +func (_c *Sender_Write_Call) Run(run func(senderAddress *model.FeatureAddressType, destinationAddress *model.FeatureAddressType, cmd model.CmdType)) *Sender_Write_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*model.FeatureAddressType), args[1].(*model.FeatureAddressType), args[2].(model.CmdType)) + }) + return _c +} + +func (_c *Sender_Write_Call) Return(_a0 *model.MsgCounterType, _a1 error) *Sender_Write_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Sender_Write_Call) RunAndReturn(run func(*model.FeatureAddressType, *model.FeatureAddressType, model.CmdType) (*model.MsgCounterType, error)) *Sender_Write_Call { + _c.Call.Return(run) + return _c +} + +// 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. +// The first argument is typically a *testing.T value. +func NewSender(t interface { + mock.TestingT + Cleanup(func()) +}) *Sender { + mock := &Sender{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/SpineDataConnection.go b/mocks/SpineDataConnection.go new file mode 100644 index 0000000..5be34a6 --- /dev/null +++ b/mocks/SpineDataConnection.go @@ -0,0 +1,29 @@ +// Code generated by mockery v2.39.1. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// SpineDataConnection is an autogenerated mock type for the SpineDataConnection type +type SpineDataConnection struct { + mock.Mock +} + +// WriteSpineMessage provides a mock function with given fields: message +func (_m *SpineDataConnection) WriteSpineMessage(message []byte) { + _m.Called(message) +} + +// NewSpineDataConnection creates a new instance of SpineDataConnection. 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 NewSpineDataConnection(t interface { + mock.TestingT + Cleanup(func()) +}) *SpineDataConnection { + mock := &SpineDataConnection{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/SubscriptionManager.go b/mocks/SubscriptionManager.go new file mode 100644 index 0000000..b4accd4 --- /dev/null +++ b/mocks/SubscriptionManager.go @@ -0,0 +1,293 @@ +// Code generated by mockery v2.40.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" +) + +// SubscriptionManager is an autogenerated mock type for the SubscriptionManager type +type SubscriptionManager struct { + mock.Mock +} + +type SubscriptionManager_Expecter struct { + mock *mock.Mock +} + +func (_m *SubscriptionManager) EXPECT() *SubscriptionManager_Expecter { + return &SubscriptionManager_Expecter{mock: &_m.Mock} +} + +// AddSubscription provides a mock function with given fields: remoteDevice, data +func (_m *SubscriptionManager) AddSubscription(remoteDevice api.DeviceRemote, data model.SubscriptionManagementRequestCallType) error { + ret := _m.Called(remoteDevice, data) + + if len(ret) == 0 { + panic("no return value specified for AddSubscription") + } + + var r0 error + if rf, ok := ret.Get(0).(func(api.DeviceRemote, model.SubscriptionManagementRequestCallType) error); ok { + r0 = rf(remoteDevice, data) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SubscriptionManager_AddSubscription_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddSubscription' +type SubscriptionManager_AddSubscription_Call struct { + *mock.Call +} + +// AddSubscription is a helper method to define mock.On call +// - remoteDevice api.DeviceRemote +// - data model.SubscriptionManagementRequestCallType +func (_e *SubscriptionManager_Expecter) AddSubscription(remoteDevice interface{}, data interface{}) *SubscriptionManager_AddSubscription_Call { + return &SubscriptionManager_AddSubscription_Call{Call: _e.mock.On("AddSubscription", remoteDevice, data)} +} + +func (_c *SubscriptionManager_AddSubscription_Call) Run(run func(remoteDevice api.DeviceRemote, data model.SubscriptionManagementRequestCallType)) *SubscriptionManager_AddSubscription_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.DeviceRemote), args[1].(model.SubscriptionManagementRequestCallType)) + }) + return _c +} + +func (_c *SubscriptionManager_AddSubscription_Call) Return(_a0 error) *SubscriptionManager_AddSubscription_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *SubscriptionManager_AddSubscription_Call) RunAndReturn(run func(api.DeviceRemote, model.SubscriptionManagementRequestCallType) error) *SubscriptionManager_AddSubscription_Call { + _c.Call.Return(run) + return _c +} + +// RemoveSubscription provides a mock function with given fields: data, remoteDevice +func (_m *SubscriptionManager) RemoveSubscription(data model.SubscriptionManagementDeleteCallType, remoteDevice api.DeviceRemote) error { + ret := _m.Called(data, remoteDevice) + + if len(ret) == 0 { + panic("no return value specified for RemoveSubscription") + } + + var r0 error + if rf, ok := ret.Get(0).(func(model.SubscriptionManagementDeleteCallType, api.DeviceRemote) error); ok { + r0 = rf(data, remoteDevice) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SubscriptionManager_RemoveSubscription_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveSubscription' +type SubscriptionManager_RemoveSubscription_Call struct { + *mock.Call +} + +// RemoveSubscription is a helper method to define mock.On call +// - data model.SubscriptionManagementDeleteCallType +// - remoteDevice api.DeviceRemote +func (_e *SubscriptionManager_Expecter) RemoveSubscription(data interface{}, remoteDevice interface{}) *SubscriptionManager_RemoveSubscription_Call { + return &SubscriptionManager_RemoveSubscription_Call{Call: _e.mock.On("RemoveSubscription", data, remoteDevice)} +} + +func (_c *SubscriptionManager_RemoveSubscription_Call) Run(run func(data model.SubscriptionManagementDeleteCallType, remoteDevice api.DeviceRemote)) *SubscriptionManager_RemoveSubscription_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.SubscriptionManagementDeleteCallType), args[1].(api.DeviceRemote)) + }) + return _c +} + +func (_c *SubscriptionManager_RemoveSubscription_Call) Return(_a0 error) *SubscriptionManager_RemoveSubscription_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *SubscriptionManager_RemoveSubscription_Call) RunAndReturn(run func(model.SubscriptionManagementDeleteCallType, api.DeviceRemote) error) *SubscriptionManager_RemoveSubscription_Call { + _c.Call.Return(run) + return _c +} + +// RemoveSubscriptionsForDevice provides a mock function with given fields: remoteDevice +func (_m *SubscriptionManager) RemoveSubscriptionsForDevice(remoteDevice api.DeviceRemote) { + _m.Called(remoteDevice) +} + +// SubscriptionManager_RemoveSubscriptionsForDevice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveSubscriptionsForDevice' +type SubscriptionManager_RemoveSubscriptionsForDevice_Call struct { + *mock.Call +} + +// RemoveSubscriptionsForDevice is a helper method to define mock.On call +// - remoteDevice api.DeviceRemote +func (_e *SubscriptionManager_Expecter) RemoveSubscriptionsForDevice(remoteDevice interface{}) *SubscriptionManager_RemoveSubscriptionsForDevice_Call { + return &SubscriptionManager_RemoveSubscriptionsForDevice_Call{Call: _e.mock.On("RemoveSubscriptionsForDevice", remoteDevice)} +} + +func (_c *SubscriptionManager_RemoveSubscriptionsForDevice_Call) Run(run func(remoteDevice api.DeviceRemote)) *SubscriptionManager_RemoveSubscriptionsForDevice_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.DeviceRemote)) + }) + return _c +} + +func (_c *SubscriptionManager_RemoveSubscriptionsForDevice_Call) Return() *SubscriptionManager_RemoveSubscriptionsForDevice_Call { + _c.Call.Return() + return _c +} + +func (_c *SubscriptionManager_RemoveSubscriptionsForDevice_Call) RunAndReturn(run func(api.DeviceRemote)) *SubscriptionManager_RemoveSubscriptionsForDevice_Call { + _c.Call.Return(run) + return _c +} + +// RemoveSubscriptionsForEntity provides a mock function with given fields: remoteEntity +func (_m *SubscriptionManager) RemoveSubscriptionsForEntity(remoteEntity api.EntityRemote) { + _m.Called(remoteEntity) +} + +// SubscriptionManager_RemoveSubscriptionsForEntity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveSubscriptionsForEntity' +type SubscriptionManager_RemoveSubscriptionsForEntity_Call struct { + *mock.Call +} + +// RemoveSubscriptionsForEntity is a helper method to define mock.On call +// - remoteEntity api.EntityRemote +func (_e *SubscriptionManager_Expecter) RemoveSubscriptionsForEntity(remoteEntity interface{}) *SubscriptionManager_RemoveSubscriptionsForEntity_Call { + return &SubscriptionManager_RemoveSubscriptionsForEntity_Call{Call: _e.mock.On("RemoveSubscriptionsForEntity", remoteEntity)} +} + +func (_c *SubscriptionManager_RemoveSubscriptionsForEntity_Call) Run(run func(remoteEntity api.EntityRemote)) *SubscriptionManager_RemoveSubscriptionsForEntity_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.EntityRemote)) + }) + return _c +} + +func (_c *SubscriptionManager_RemoveSubscriptionsForEntity_Call) Return() *SubscriptionManager_RemoveSubscriptionsForEntity_Call { + _c.Call.Return() + return _c +} + +func (_c *SubscriptionManager_RemoveSubscriptionsForEntity_Call) RunAndReturn(run func(api.EntityRemote)) *SubscriptionManager_RemoveSubscriptionsForEntity_Call { + _c.Call.Return(run) + return _c +} + +// Subscriptions provides a mock function with given fields: remoteDevice +func (_m *SubscriptionManager) Subscriptions(remoteDevice api.DeviceRemote) []*api.SubscriptionEntry { + ret := _m.Called(remoteDevice) + + if len(ret) == 0 { + panic("no return value specified for Subscriptions") + } + + var r0 []*api.SubscriptionEntry + if rf, ok := ret.Get(0).(func(api.DeviceRemote) []*api.SubscriptionEntry); ok { + r0 = rf(remoteDevice) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*api.SubscriptionEntry) + } + } + + return r0 +} + +// SubscriptionManager_Subscriptions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Subscriptions' +type SubscriptionManager_Subscriptions_Call struct { + *mock.Call +} + +// Subscriptions is a helper method to define mock.On call +// - remoteDevice api.DeviceRemote +func (_e *SubscriptionManager_Expecter) Subscriptions(remoteDevice interface{}) *SubscriptionManager_Subscriptions_Call { + return &SubscriptionManager_Subscriptions_Call{Call: _e.mock.On("Subscriptions", remoteDevice)} +} + +func (_c *SubscriptionManager_Subscriptions_Call) Run(run func(remoteDevice api.DeviceRemote)) *SubscriptionManager_Subscriptions_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(api.DeviceRemote)) + }) + return _c +} + +func (_c *SubscriptionManager_Subscriptions_Call) Return(_a0 []*api.SubscriptionEntry) *SubscriptionManager_Subscriptions_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *SubscriptionManager_Subscriptions_Call) RunAndReturn(run func(api.DeviceRemote) []*api.SubscriptionEntry) *SubscriptionManager_Subscriptions_Call { + _c.Call.Return(run) + return _c +} + +// SubscriptionsOnFeature provides a mock function with given fields: featureAddress +func (_m *SubscriptionManager) SubscriptionsOnFeature(featureAddress model.FeatureAddressType) []*api.SubscriptionEntry { + ret := _m.Called(featureAddress) + + if len(ret) == 0 { + panic("no return value specified for SubscriptionsOnFeature") + } + + var r0 []*api.SubscriptionEntry + if rf, ok := ret.Get(0).(func(model.FeatureAddressType) []*api.SubscriptionEntry); ok { + r0 = rf(featureAddress) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*api.SubscriptionEntry) + } + } + + return r0 +} + +// SubscriptionManager_SubscriptionsOnFeature_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscriptionsOnFeature' +type SubscriptionManager_SubscriptionsOnFeature_Call struct { + *mock.Call +} + +// SubscriptionsOnFeature is a helper method to define mock.On call +// - featureAddress model.FeatureAddressType +func (_e *SubscriptionManager_Expecter) SubscriptionsOnFeature(featureAddress interface{}) *SubscriptionManager_SubscriptionsOnFeature_Call { + return &SubscriptionManager_SubscriptionsOnFeature_Call{Call: _e.mock.On("SubscriptionsOnFeature", featureAddress)} +} + +func (_c *SubscriptionManager_SubscriptionsOnFeature_Call) Run(run func(featureAddress model.FeatureAddressType)) *SubscriptionManager_SubscriptionsOnFeature_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.FeatureAddressType)) + }) + return _c +} + +func (_c *SubscriptionManager_SubscriptionsOnFeature_Call) Return(_a0 []*api.SubscriptionEntry) *SubscriptionManager_SubscriptionsOnFeature_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *SubscriptionManager_SubscriptionsOnFeature_Call) RunAndReturn(run func(model.FeatureAddressType) []*api.SubscriptionEntry) *SubscriptionManager_SubscriptionsOnFeature_Call { + _c.Call.Return(run) + return _c +} + +// NewSubscriptionManager creates a new instance of SubscriptionManager. 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 NewSubscriptionManager(t interface { + mock.TestingT + Cleanup(func()) +}) *SubscriptionManager { + mock := &SubscriptionManager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/model/actuatorlevel.go b/model/actuatorlevel.go new file mode 100644 index 0000000..64e4077 --- /dev/null +++ b/model/actuatorlevel.go @@ -0,0 +1,36 @@ +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/model/actuatorswitch.go b/model/actuatorswitch.go new file mode 100644 index 0000000..cd76d39 --- /dev/null +++ b/model/actuatorswitch.go @@ -0,0 +1,27 @@ +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/model/alarm.go b/model/alarm.go new file mode 100644 index 0000000..7158fce --- /dev/null +++ b/model/alarm.go @@ -0,0 +1,44 @@ +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/model/alarm_additions.go b/model/alarm_additions.go new file mode 100644 index 0000000..80e85b7 --- /dev/null +++ b/model/alarm_additions.go @@ -0,0 +1,14 @@ +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/model/alarm_additions_test.go b/model/alarm_additions_test.go new file mode 100644 index 0000000..f8ccd26 --- /dev/null +++ b/model/alarm_additions_test.go @@ -0,0 +1,46 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestAlarmListDataType_Update(t *testing.T) { + sut := AlarmListDataType{ + AlarmListData: []AlarmDataType{ + { + AlarmId: util.Ptr(AlarmIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + AlarmId: util.Ptr(AlarmIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := AlarmListDataType{ + AlarmListData: []AlarmDataType{ + { + AlarmId: util.Ptr(AlarmIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/bill.go b/model/bill.go new file mode 100644 index 0000000..1d876d4 --- /dev/null +++ b/model/bill.go @@ -0,0 +1,157 @@ +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"` + SessionId *SessionIdType `json:"sessionId,omitempty"` +} + +type BillDescriptionDataElementsType struct { + BillId *ElementTagType `json:"billId,omitempty"` + BillWriteable *ElementTagType `json:"billWriteable,omitempty"` + UpdateRequired *ElementTagType `json:"updateRequired,omitempty"` + SupportedBillType *ElementTagType `json:"supportedBillType,omitempty"` + SessionId *ElementTagType `json:"sessionId,omitempty"` +} + +type BillDescriptionListDataType struct { + BillDescriptionData []BillDescriptionDataType `json:"billDescriptionData,omitempty"` +} + +type BillDescriptionListDataSelectorsType struct { + BillId *BillIdType `json:"billId,omitempty"` +} diff --git a/model/bill_additions.go b/model/bill_additions.go new file mode 100644 index 0000000..8e08654 --- /dev/null +++ b/model/bill_additions.go @@ -0,0 +1,40 @@ +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/model/bill_additions_test.go b/model/bill_additions_test.go new file mode 100644 index 0000000..291f422 --- /dev/null +++ b/model/bill_additions_test.go @@ -0,0 +1,122 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestBillListDataType_Update(t *testing.T) { + sut := BillListDataType{ + BillData: []BillDataType{ + { + BillId: util.Ptr(BillIdType(0)), + ScopeType: util.Ptr(ScopeTypeTypeACCurrent), + }, + { + BillId: util.Ptr(BillIdType(1)), + ScopeType: util.Ptr(ScopeTypeTypeACCurrent), + }, + }, + } + + newData := BillListDataType{ + BillData: []BillDataType{ + { + BillId: util.Ptr(BillIdType(1)), + ScopeType: util.Ptr(ScopeTypeTypeACPower), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, ScopeTypeTypeACCurrent, *item1.ScopeType) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.BillId)) + assert.Equal(t, ScopeTypeTypeACPower, *item2.ScopeType) +} + +func TestBillConstraintsListDataType_Update(t *testing.T) { + sut := BillConstraintsListDataType{ + BillConstraintsData: []BillConstraintsDataType{ + { + BillId: util.Ptr(BillIdType(0)), + PositionCountMin: util.Ptr(BillPositionCountType(0)), + }, + { + BillId: util.Ptr(BillIdType(1)), + PositionCountMin: util.Ptr(BillPositionCountType(0)), + }, + }, + } + + newData := BillConstraintsListDataType{ + BillConstraintsData: []BillConstraintsDataType{ + { + BillId: util.Ptr(BillIdType(1)), + PositionCountMin: util.Ptr(BillPositionCountType(1)), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := BillDescriptionListDataType{ + BillDescriptionData: []BillDescriptionDataType{ + { + BillId: util.Ptr(BillIdType(0)), + UpdateRequired: util.Ptr(false), + }, + { + BillId: util.Ptr(BillIdType(1)), + UpdateRequired: util.Ptr(false), + }, + }, + } + + newData := BillDescriptionListDataType{ + BillDescriptionData: []BillDescriptionDataType{ + { + BillId: util.Ptr(BillIdType(1)), + UpdateRequired: util.Ptr(true), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/bindingmanagement.go b/model/bindingmanagement.go new file mode 100644 index 0000000..719d671 --- /dev/null +++ b/model/bindingmanagement.go @@ -0,0 +1,53 @@ +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/model/bindingmanagement_additions.go b/model/bindingmanagement_additions.go new file mode 100644 index 0000000..c7d31e9 --- /dev/null +++ b/model/bindingmanagement_additions.go @@ -0,0 +1,14 @@ +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/model/bindingmanagement_additions_test.go b/model/bindingmanagement_additions_test.go new file mode 100644 index 0000000..8905ffc --- /dev/null +++ b/model/bindingmanagement_additions_test.go @@ -0,0 +1,46 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestBindingManagementEntryListDataType_Update(t *testing.T) { + sut := BindingManagementEntryListDataType{ + BindingManagementEntryData: []BindingManagementEntryDataType{ + { + BindingId: util.Ptr(BindingIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + BindingId: util.Ptr(BindingIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := BindingManagementEntryListDataType{ + BindingManagementEntryData: []BindingManagementEntryDataType{ + { + BindingId: util.Ptr(BindingIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/collection_operations.go b/model/collection_operations.go new file mode 100644 index 0000000..84d6ccc --- /dev/null +++ b/model/collection_operations.go @@ -0,0 +1,122 @@ +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/model/collection_operations_test.go b/model/collection_operations_test.go new file mode 100644 index 0000000..4ce26a2 --- /dev/null +++ b/model/collection_operations_test.go @@ -0,0 +1,62 @@ +package model + +import ( + "fmt" + "testing" + + "github.com/enbility/spine-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 := 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 := 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/model/commandframe.go b/model/commandframe.go new file mode 100644 index 0000000..537e207 --- /dev/null +++ b/model/commandframe.go @@ -0,0 +1,426 @@ +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"` + ElectricalConnectionCharacteristicListDataSelectors *ElectricalConnectionCharacteristicListDataSelectorsType `json:"electricalConnectionCharacteristicListDataSelectors,omitempty" eebus:"typ:selector,fct:electricalConnectionCharacteristicListData"` + 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"` + MeasurementSeriesListDataSelectors *MeasurementSeriesListDataSelectorsType `json:"measurementSeriesListDataSelectors,omitempty" eebus:"measurementSeriesListData"` + 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"` + SessionIdentificationListDataSelectors *SessionIdentificationListDataSelectorsType `json:"sessionIdentificationListDataSelectors,omitempty" eebus:"typ:selector,fct:sessionIdentificationListData"` + SessionMeasurementRelationListDataSelectors *SessionMeasurementRelationListDataSelectorsType `json:"sessionMeasurementRelationListDataSelectors,omitempty" eebus:"typ:selector,fct:sessionMeasurementRelationListData"` + 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"` + StateInformationListDataSelectors *StateInformationListDataSelectorsType `json:"stateInformationListDataSelectors,omitempty" eebus:"typ:selector,fct:stateInformationListData"` + 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"` + ElectricalConnectionCharacteristicDataElements *ElectricalConnectionCharacteristicDataElementsType `json:"electricalConnectionCharacteristicDataElements,omitempty" eebus:"typ:elements,fct:electricalConnectionCharacteristicListData"` + 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"` + MeasurementSeriesDataElements *MeasurementSeriesDataElementsType `json:"measurementSeriesDataElements,omitempty" eebus:"typ:elements,fct:measurementSeriesListData"` + 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"` + SessionIdentificationDataElements *SessionIdentificationDataElementsType `json:"sessionIdentificationDataElements,omitempty" eebus:"typ:elements,fct:sessionIdentificationData"` + SessionMeasurementRelationDataElements *SessionMeasurementRelationDataElementsType `json:"sessionMeasurementRelationDataElements,omitempty" eebus:"typ:elements,fct:sessionMeasurementRelationData"` + 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"` + StateInformationDataElements *StateInformationDataElementsType `json:"stateInformationDataElements,omitempty" eebus:"typ:elements,fct:stateInformationListData"` + 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"` + ElectricalConnectionCharacteristicData *ElectricalConnectionCharacteristicDataType `json:"electricalConnectionCharacteristicData,omitempty" eebus:"fct:electricalConnectionCharacteristicData"` + ElectricalConnectionCharacteristicListData *ElectricalConnectionCharacteristicListDataType `json:"electricalConnectionCharacteristicListData,omitempty" eebus:"fct:electricalConnectionCharacteristicListData"` + 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"` + MeasurementSeriesListData *MeasurementSeriesListDataType `json:"measurementSeriesListData,omitempty" eebus:"fct:measurementSeriesListData"` + 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"` + SessionIdentificationListData *SessionIdentificationListDataType `json:"sessionIdentificationListData,omitempty" eebus:"fct:sessionIdentificationListData"` + SessionMeasurementRelationListData *SessionMeasurementRelationListDataType `json:"sessionMeasurementRelationListData,omitempty" eebus:"fct:sessionMeasurementRelationListData"` + 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"` + StateInformationListData *StateInformationListDataType `json:"stateInformationListData,omitempty" eebus:"fct:stateInformationListData"` + 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/model/commandframe_additions.go b/model/commandframe_additions.go new file mode 100644 index 0000000..8d771db --- /dev/null +++ b/model/commandframe_additions.go @@ -0,0 +1,297 @@ +package model + +import ( + "errors" + "fmt" + "reflect" + + "github.com/enbility/spine-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 field for a given functionType +func (f *FilterType) SetDataForFunction(tagType EEBusTagTypeType, fct FunctionType, data any) { + if data == nil || reflect.ValueOf(data).Kind() != reflect.Ptr { + return + } + + v := reflect.ValueOf(*f) + dv := reflect.ValueOf(f).Elem() + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + if field.Kind() != reflect.Ptr { + continue + } + + sf := v.Type().Field(i) + // Exclude the generic fields + if sf.Name == "CmdControl" || sf.Name == "FilterId" { + continue + } + + eebusTags := EEBusTags(sf) + function, exists := eebusTags[EEBusTagFunction] + if !exists { + continue + } + typ, exists := eebusTags[EEBusTagType] + if !exists || len(typ) == 0 { + continue + } + if typ != string(tagType) { + continue + } + + if fct != FunctionType(function) { + continue + } + + n := v.Type().Field(i).Name + ff := dv.FieldByName(n) + + if !ff.CanSet() { + break + } + + if reflect.ValueOf(data).IsNil() { + typ := reflect.TypeOf(data).Elem() + ff.Set(reflect.New(typ)) + return + } + + dataV := reflect.ValueOf(data) + dataC := dataV.Convert(ff.Type()) + ff.Set(dataC) + return + } +} + +// 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 field for a given functionType +func (cmd *CmdType) SetDataForFunction(fct FunctionType, data any) { + if data == nil || reflect.ValueOf(data).Kind() != reflect.Ptr { + return + } + + v := reflect.ValueOf(*cmd) + dv := reflect.ValueOf(cmd).Elem() + for i := 0; i < v.NumField(); i++ { + f := v.Field(i) + if f.Kind() != reflect.Ptr { + 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 + } + + if fct != FunctionType(function) { + continue + } + + n := v.Type().Field(i).Name + ff := dv.FieldByName(n) + + if !ff.CanSet() { + break + } + + if reflect.ValueOf(data).IsNil() { + typ := reflect.TypeOf(data).Elem() + ff.Set(reflect.New(typ)) + return + } + + dataV := reflect.ValueOf(data) + dataC := dataV.Convert(ff.Type()) + ff.Set(dataC) + return + } +} + +// 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/model/commandframe_additions_test.go b/model/commandframe_additions_test.go new file mode 100644 index 0000000..0bbd25a --- /dev/null +++ b/model/commandframe_additions_test.go @@ -0,0 +1,141 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestFilterType_Selector_Data(t *testing.T) { + data := &ElectricalConnectionDescriptionListDataSelectorsType{ + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(1)), + ScopeType: util.Ptr(ScopeTypeTypeACPower), + } + + sut := &FilterType{ + ElectricalConnectionDescriptionListDataSelectors: data, + } + + // Act + cmdData, err := sut.Data() + assert.Nil(t, err) + assert.NotNil(t, cmdData) + assert.Equal(t, FunctionTypeElectricalConnectionDescriptionListData, *cmdData.Function) + assert.Equal(t, data, cmdData.Selector) +} + +func TestFilterType_Selector_SetDataForFunction(t *testing.T) { + cmd := FilterType{} + cmd.SetDataForFunction(EEBusTagTypeTypeSelector, FunctionTypeElectricalConnectionDescriptionListData, &ElectricalConnectionDescriptionListDataSelectorsType{}) + assert.NotNil(t, cmd.ElectricalConnectionDescriptionListDataSelectors) + + cmd = FilterType{} + cmd.SetDataForFunction(EEBusTagTypeTypeSelector, FunctionTypeElectricalConnectionDescriptionListData, nil) + assert.Nil(t, cmd.ElectricalConnectionDescriptionListDataSelectors) + + var test *ElectricalConnectionDescriptionListDataSelectorsType + cmd = FilterType{} + cmd.SetDataForFunction(EEBusTagTypeTypeSelector, FunctionTypeElectricalConnectionDescriptionListData, test) + assert.NotNil(t, cmd.ElectricalConnectionDescriptionListDataSelectors) +} + +func TestFilterType_Elements_Data(t *testing.T) { + data := &ElectricalConnectionDescriptionDataElementsType{ + ElectricalConnectionId: util.Ptr(ElementTagType{}), + } + + sut := &FilterType{ + ElectricalConnectionDescriptionDataElements: data, + } + + // Act + cmdData, err := sut.Data() + assert.Nil(t, err) + assert.NotNil(t, cmdData) + assert.Equal(t, FunctionTypeElectricalConnectionDescriptionListData, *cmdData.Function) + assert.Equal(t, data, cmdData.Elements) +} + +func TestFilterType_Elements_SetDataForFunction(t *testing.T) { + cmd := FilterType{} + cmd.SetDataForFunction(EEbusTagTypeTypeElements, FunctionTypeElectricalConnectionDescriptionListData, &ElectricalConnectionDescriptionDataElementsType{}) + assert.NotNil(t, cmd.ElectricalConnectionDescriptionDataElements) + + cmd = FilterType{} + cmd.SetDataForFunction(EEbusTagTypeTypeElements, FunctionTypeElectricalConnectionDescriptionListData, nil) + assert.Nil(t, cmd.ElectricalConnectionDescriptionDataElements) + + var test *ElectricalConnectionDescriptionDataElementsType + cmd = FilterType{} + cmd.SetDataForFunction(EEbusTagTypeTypeElements, FunctionTypeElectricalConnectionDescriptionListData, test) + assert.NotNil(t, cmd.ElectricalConnectionDescriptionDataElements) +} + +func TestCmdType_Data(t *testing.T) { + data := &NodeManagementDetailedDiscoveryDataType{ + SpecificationVersionList: &NodeManagementSpecificationVersionListType{[]SpecificationVersionDataType{SpecificationVersionDataType("dummy")}}, + } + + sut := &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, FunctionTypeNodeManagementDetailedDiscoveryData, *cmdData.Function) + assert.Equal(t, data, cmdData.Value) +} + +func TestCmdType_SetDataForFunction(t *testing.T) { + cmd := CmdType{} + cmd.SetDataForFunction(FunctionTypeElectricalConnectionDescriptionListData, &ElectricalConnectionDescriptionListDataType{}) + assert.NotNil(t, cmd.ElectricalConnectionDescriptionListData) + + cmd = CmdType{} + cmd.SetDataForFunction(FunctionTypeElectricalConnectionDescriptionListData, nil) + assert.Nil(t, cmd.ElectricalConnectionDescriptionListData) + + var test *ElectricalConnectionDescriptionListDataType + cmd = CmdType{} + cmd.SetDataForFunction(FunctionTypeElectricalConnectionDescriptionListData, test) + assert.NotNil(t, cmd.ElectricalConnectionDescriptionListData) +} + +func TestCmdType_ExtractFilter_NoFilter(t *testing.T) { + sut := &CmdType{ + NodeManagementDetailedDiscoveryData: &NodeManagementDetailedDiscoveryDataType{}, + } + + // Act + filterPartial, filterDelete := sut.ExtractFilter() + assert.Nil(t, filterPartial) + assert.Nil(t, filterDelete) +} + +func TestCmdType_ExtractFilter_FilterPartialDelete(t *testing.T) { + + filterP := FilterType{ + CmdControl: &CmdControlType{Partial: &ElementTagType{}}, + NodeManagementDetailedDiscoveryDataSelectors: &NodeManagementDetailedDiscoveryDataSelectorsType{}, + } + filterD := FilterType{ + CmdControl: &CmdControlType{Delete: &ElementTagType{}}, + NodeManagementDetailedDiscoveryDataSelectors: &NodeManagementDetailedDiscoveryDataSelectorsType{}, + } + + sut := &CmdType{ + Filter: []FilterType{filterD, filterP}, + NodeManagementDetailedDiscoveryData: &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/model/commondatatypes.go b/model/commondatatypes.go new file mode 100644 index 0000000..f7d6c95 --- /dev/null +++ b/model/commondatatypes.go @@ -0,0 +1,988 @@ +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" + ScopeTypeTypeStateOfHealth ScopeTypeType = "stateOfHealth" + ScopeTypeTypeTravelRange ScopeTypeType = "travelRange" + ScopeTypeTypeNominalEnergyCapacity ScopeTypeType = "nominalEnergyCapacity" + ScopeTypeTypeAcPowerReal ScopeTypeType = "acPowerReal" + ScopeTypeTypeAcPowerApparent ScopeTypeType = "acPowerApparent" + ScopeTypeTypeAcPowerReactive ScopeTypeType = "acPowerReactive" + ScopeTypeTypeAcYieldMonth ScopeTypeType = "acYieldMonth" + ScopeTypeTypeAcYieldYear ScopeTypeType = "acYieldYear" + ScopeTypeTypeAcFrequency ScopeTypeType = "acFrequency" + ScopeTypeTypeAcCosPhi ScopeTypeType = "acCosPhi" + ScopeTypeTypeDcEnergy ScopeTypeType = "dcEnergy" + ScopeTypeTypeInsulationResistance ScopeTypeType = "insulationResistance" + ScopeTypeTypeStateOfEnergy ScopeTypeType = "stateOfEnergy" + ScopeTypeTypeUseableCapacity ScopeTypeType = "useableCapacity" + ScopeTypeTypeDcChargeEnergy ScopeTypeType = "dcChargeEnergy" + ScopeTypeTypeDcDischargeEnergy ScopeTypeType = "dcDischargeEnergy" + ScopeTypeTypeLoadCycleCount ScopeTypeType = "loadCycleCount" + ScopeTypeTypeComponentTemperature ScopeTypeType = "componentTemperature" + ScopeTypeTypeGridLimit ScopeTypeType = "gridLimit" + ScopeTypeTypeGridLimitFallback ScopeTypeType = "gridLimitFallback" + ScopeTypeTypeAcPowerApparentTotal ScopeTypeType = "acPowerApparentTotal" + ScopeTypeTypeAcPowerReactiveTotal ScopeTypeType = "acPowerReactiveTotal" + ScopeTypeTypeAcCurrentTotal ScopeTypeType = "acCurrentTotal" + ScopeTypeTypeAcEnergyConsumed ScopeTypeType = "acEnergyConsumed" + ScopeTypeTypeAcEnergyProduced ScopeTypeType = "acEnergyProduced" + ScopeTypeTypeBatteryAcPower ScopeTypeType = "batteryAcPower" + ScopeTypeTypeBatteryAcPowerPhaseSpecific ScopeTypeType = "batteryAcPowerPhaseSpecific" + ScopeTypeTypeBatteryDcPower ScopeTypeType = "batteryDcPower" + ScopeTypeTypePccPower ScopeTypeType = "pccPower" + ScopeTypeTypeActivePowerLimit ScopeTypeType = "activePowerLimit" + ScopeTypeTypeActivePowerLimitPercentage ScopeTypeType = "activePowerLimitPercentage" + ScopeTypeTypeSimpleCommittedIncentiveTable ScopeTypeType = "simpleCommittedIncentiveTable" + ScopeTypeTypeSimplePreliminaryIncentiveTable ScopeTypeType = "simplePreliminaryIncentiveTable" + ScopeTypeTypeCommittedPowerPlan ScopeTypeType = "committedPowerPlan" + ScopeTypeTypePreliminaryPowerPlan ScopeTypeType = "preliminaryPowerPlan" + ScopeTypeTypeIncentiveTableEnConsWithPoETF ScopeTypeType = "incentiveTableEnConsWithPoETF" + ScopeTypeTypeIncentiveTableEnProdWithPoETF ScopeTypeType = "incentiveTableEnProdWithPoETF" + ScopeTypeTypeIncentiveTableEnConsWithPoE ScopeTypeType = "incentiveTableEnConsWithPoE" + ScopeTypeTypeIncentiveTableEnProdWithPoE ScopeTypeType = "incentiveTableEnProdWithPoE" + ScopeTypeTypeIncentiveTableEnConsWithTF ScopeTypeType = "incentiveTableEnConsWithTF" + ScopeTypeTypeIncentiveTableEnProdWithTF ScopeTypeType = "incentiveTableEnProdWithTF" + ScopeTypeTypeActivePowerForecast ScopeTypeType = "activePowerForecast" +) + +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" + EntityTypeTypePV EntityTypeType = "PV" + EntityTypeTypePVESHybrid EntityTypeType = "PVESHybrid" + EntityTypeTypeElectricalStorage EntityTypeType = "ElectricalStorage" + EntityTypeTypePVString EntityTypeType = "PVString" + EntityTypeTypeGridGuard EntityTypeType = "GridGuard" + EntityTypeTypeControllableSystem EntityTypeType = "ControllableSystem" +) + +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" + FeatureTypeTypeStateInformation FeatureTypeType = "StateInformation" +) + +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" + FunctionTypeSessionIdentificationListData FunctionType = "sessionIdentificationListData" + FunctionTypeSessionMeasurementRelationListData FunctionType = "sessionMeasurementRelationListData" + 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" + FunctionTypeMeasurementSeriesListData FunctionType = "measurementSeriesListData" + FunctionTypeElectricalConnectionCharacteristicData FunctionType = "electricalConnectionCharacteristicData" + FunctionTypeElectricalConnectionCharacteristicListData FunctionType = "electricalConnectionCharacteristicListData" + FunctionTypeStateInformationListData FunctionType = "stateInformationListData" +) + +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/model/commondatatypes_additions.go b/model/commondatatypes_additions.go new file mode 100644 index 0000000..59838ba --- /dev/null +++ b/model/commondatatypes_additions.go @@ -0,0 +1,234 @@ +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 t, nil + } + + // Check if this is a relative time + d, err := getTimeDurationFromString(string(*a)) + if err != nil { + return time.Time{}, err + } + r := time.Now().Add(d) + return r, 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/model/commondatatypes_additions_test.go b/model/commondatatypes_additions_test.go new file mode 100644 index 0000000..b29efbf --- /dev/null +++ b/model/commondatatypes_additions_test.go @@ -0,0 +1,282 @@ +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/model/custom.go b/model/custom.go new file mode 100644 index 0000000..19eb91a --- /dev/null +++ b/model/custom.go @@ -0,0 +1,47 @@ +package model + +import ( + "fmt" + + "github.com/enbility/spine-go/util" +) + +type ErrorType struct { + ErrorNumber ErrorNumberType + Description *DescriptionType +} + +func NewErrorType(errorNumber ErrorNumberType, description string) *ErrorType { + return &ErrorType{ + ErrorNumber: errorNumber, + Description: util.Ptr(DescriptionType(description)), + } +} + +func NewErrorTypeFromNumber(errorNumber ErrorNumberType) *ErrorType { + return &ErrorType{ + ErrorNumber: errorNumber, + } +} + +func NewErrorTypeFromString(description string) *ErrorType { + return NewErrorType(ErrorNumberTypeGeneralError, description) +} + +func NewErrorTypeFromResult(result *ResultDataType) *ErrorType { + if result.ErrorNumber == nil || *result.ErrorNumber == 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/model/custom_test.go b/model/custom_test.go new file mode 100644 index 0000000..6130b2b --- /dev/null +++ b/model/custom_test.go @@ -0,0 +1,62 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestErrorTypeSuite(t *testing.T) { + suite.Run(t, new(ErrorTypeSuite)) +} + +type ErrorTypeSuite struct { + suite.Suite +} + +func (s *ErrorTypeSuite) SetupSuite() {} +func (s *ErrorTypeSuite) TearDownTest() {} + +func (s *ErrorTypeSuite) BeforeTest(suiteName, testName string) {} + +func (s *ErrorTypeSuite) Test_NewErrorType() { + result := NewErrorType(ErrorNumberTypeNoError, "") + assert.NotNil(s.T(), result) +} + +func (s *ErrorTypeSuite) Test_NewErrorTypeFromNumber() { + result := NewErrorTypeFromNumber(ErrorNumberTypeCommandRejected) + assert.NotNil(s.T(), result) +} + +func (s *ErrorTypeSuite) Test_NewErrorTypeFromString() { + result := NewErrorTypeFromString("error") + assert.NotNil(s.T(), result) + + assert.NotEqual(s.T(), 0, len(result.String())) +} + +func (s *ErrorTypeSuite) Test_NewErrorTypeFromResult() { + input := &ResultDataType{} + + result := NewErrorTypeFromResult(input) + assert.Nil(s.T(), result) + + input = &ResultDataType{ + ErrorNumber: util.Ptr(ErrorNumberTypeNoError), + } + + result = NewErrorTypeFromResult(input) + assert.Nil(s.T(), result) + + input = &ResultDataType{ + ErrorNumber: util.Ptr(ErrorNumberTypeCommandNotSupported), + } + + result = NewErrorTypeFromResult(input) + assert.NotNil(s.T(), result) + + assert.NotEqual(s.T(), 0, len(result.String())) +} diff --git a/model/datagram.go b/model/datagram.go new file mode 100644 index 0000000..d51a9c7 --- /dev/null +++ b/model/datagram.go @@ -0,0 +1,26 @@ +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/model/datagram_additions.go b/model/datagram_additions.go new file mode 100644 index 0000000..9898cbe --- /dev/null +++ b/model/datagram_additions.go @@ -0,0 +1,42 @@ +package model + +import ( + "fmt" +) + +func (d *DatagramType) PrintMessageOverview(send bool, localFeature, remoteFeature string) string { + var result string + + transmission := "Send" + device := "" + if d.Header.AddressDestination != nil && 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/model/datagram_additions_test.go b/model/datagram_additions_test.go new file mode 100644 index 0000000..d1071b5 --- /dev/null +++ b/model/datagram_additions_test.go @@ -0,0 +1,116 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" +) + +func TestPrintMessageOverview_Read_Send(t *testing.T) { + datagram := &DatagramType{ + Header: HeaderType{ + AddressSource: &FeatureAddressType{ + Device: util.Ptr(AddressDeviceType("localdevice")), + }, + AddressDestination: &FeatureAddressType{ + Device: util.Ptr(AddressDeviceType("localdevice")), + }, + MsgCounter: util.Ptr(MsgCounterType(1)), + CmdClassifier: util.Ptr(CmdClassifierTypeRead), + }, + Payload: PayloadType{ + Cmd: []CmdType{ + {}, + }, + }, + } + + datagram.PrintMessageOverview(false, "", "") +} + +func TestPrintMessageOverview_Read_Recv(t *testing.T) { + datagram := &DatagramType{ + Header: HeaderType{ + AddressSource: &FeatureAddressType{}, + AddressDestination: &FeatureAddressType{ + Device: util.Ptr(AddressDeviceType("localdevice")), + }, + MsgCounter: util.Ptr(MsgCounterType(1)), + CmdClassifier: util.Ptr(CmdClassifierTypeRead), + }, + Payload: PayloadType{ + Cmd: []CmdType{ + {}, + }, + }, + } + + datagram.PrintMessageOverview(true, "", "") +} + +func TestPrintMessageOverview_Reply_Recv(t *testing.T) { + datagram := &DatagramType{ + Header: HeaderType{ + AddressSource: &FeatureAddressType{}, + AddressDestination: &FeatureAddressType{ + Device: util.Ptr(AddressDeviceType("localdevice")), + }, + MsgCounter: util.Ptr(MsgCounterType(1)), + MsgCounterReference: util.Ptr(MsgCounterType(1)), + CmdClassifier: util.Ptr(CmdClassifierTypeReply), + }, + Payload: PayloadType{ + Cmd: []CmdType{ + {}, + }, + }, + } + + datagram.PrintMessageOverview(true, "", "") +} + +func TestPrintMessageOverview_Result_Recv(t *testing.T) { + datagram := &DatagramType{ + Header: HeaderType{ + AddressSource: &FeatureAddressType{}, + AddressDestination: &FeatureAddressType{ + Device: util.Ptr(AddressDeviceType("localdevice")), + }, + MsgCounter: util.Ptr(MsgCounterType(1)), + MsgCounterReference: util.Ptr(MsgCounterType(1)), + CmdClassifier: util.Ptr(CmdClassifierTypeResult), + }, + Payload: PayloadType{ + Cmd: []CmdType{ + { + ResultData: &ResultDataType{ + ErrorNumber: util.Ptr(ErrorNumberType(1)), + }, + }, + }, + }, + } + + datagram.PrintMessageOverview(true, "", "") +} + +func TestPrintMessageOverview_Write_Recv(t *testing.T) { + datagram := &DatagramType{ + Header: HeaderType{ + AddressSource: &FeatureAddressType{}, + AddressDestination: &FeatureAddressType{ + Device: util.Ptr(AddressDeviceType("localdevice")), + }, + MsgCounter: util.Ptr(MsgCounterType(1)), + MsgCounterReference: util.Ptr(MsgCounterType(1)), + CmdClassifier: util.Ptr(CmdClassifierTypeWrite), + }, + Payload: PayloadType{ + Cmd: []CmdType{ + {}, + }, + }, + } + + datagram.PrintMessageOverview(true, "", "") +} diff --git a/model/datatunneling.go b/model/datatunneling.go new file mode 100644 index 0000000..7246c98 --- /dev/null +++ b/model/datatunneling.go @@ -0,0 +1,27 @@ +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/model/deviceclassification.go b/model/deviceclassification.go new file mode 100644 index 0000000..51e8427 --- /dev/null +++ b/model/deviceclassification.go @@ -0,0 +1,55 @@ +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/model/deviceconfiguration.go b/model/deviceconfiguration.go new file mode 100644 index 0000000..967ea33 --- /dev/null +++ b/model/deviceconfiguration.go @@ -0,0 +1,150 @@ +package model + +type DeviceConfigurationKeyIdType uint + +type DeviceConfigurationKeyValueStringType string + +type DeviceConfigurationKeyNameType string + +const ( + DeviceConfigurationKeyNameTypePeakPowerOfPVSystem DeviceConfigurationKeyNameType = "peakPowerOfPvSystem" + DeviceConfigurationKeyNameTypePvCurtailmentLimitFactor DeviceConfigurationKeyNameType = "pvCurtailmentLimitFactor" + DeviceConfigurationKeyNameTypeAsymmetricChargingSupported DeviceConfigurationKeyNameType = "asymmetricChargingSupported" + DeviceConfigurationKeyNameTypeCommunicationsStandard DeviceConfigurationKeyNameType = "communicationsStandard" + DeviceConfigurationKeyNameTypeInverterGridCode DeviceConfigurationKeyNameType = "inverterGridCode" + DeviceConfigurationKeyNameTypePvStringAvailabilityStatus DeviceConfigurationKeyNameType = "pvStringAvailabilityStatus" + DeviceConfigurationKeyNameTypeBatteryAvailabilityStatus DeviceConfigurationKeyNameType = "batteryAvailabilityStatus" + DeviceConfigurationKeyNameTypeGridConnectionStatus DeviceConfigurationKeyNameType = "gridConnectionStatus" + DeviceConfigurationKeyNameTypeTimeToAcChargePowerMax DeviceConfigurationKeyNameType = "timeToAcChargePowerMax" + DeviceConfigurationKeyNameTypeTimeToAcDischargePowerMax DeviceConfigurationKeyNameType = "timeToAcDischargePowerMax" + DeviceConfigurationKeyNameTypeTilt DeviceConfigurationKeyNameType = "tilt" + DeviceConfigurationKeyNameTypeAzimuth DeviceConfigurationKeyNameType = "azimuth" + DeviceConfigurationKeyNameTypeBatteryType DeviceConfigurationKeyNameType = "batteryType" + DeviceConfigurationKeyNameTypeMaxCycleCountPerDay DeviceConfigurationKeyNameType = "maxCycleCountPerDay" + DeviceConfigurationKeyNameTypeFailsafeConsumptionActivePowerLimit DeviceConfigurationKeyNameType = "failsafeConsumptionActivePowerLimit" + DeviceConfigurationKeyNameTypeFailsafeProductionActivePowerLimit DeviceConfigurationKeyNameType = "failsafeProductionActivePowerLimit" + DeviceConfigurationKeyNameTypeFailsafePositiveReactivePowerLimit DeviceConfigurationKeyNameType = "failsafePositiveReactivePowerLimit" + DeviceConfigurationKeyNameTypeFailsafeNegativeReactivePowerLimit DeviceConfigurationKeyNameType = "failsafeNegativeReactivePowerLimit" + DeviceConfigurationKeyNameTypeFailsafePositiveCosPhiLimit DeviceConfigurationKeyNameType = "failsafePositiveCosPhiLimit" + DeviceConfigurationKeyNameTypeFailsafeNegativeCosPhiLimit DeviceConfigurationKeyNameType = "failsafeNegativeCosPhiLimit" + DeviceConfigurationKeyNameTypeMaxAcChargePower DeviceConfigurationKeyNameType = "maxAcChargePower" + DeviceConfigurationKeyNameTypeMaxAcDischargePower DeviceConfigurationKeyNameType = "maxAcDischargePower" + DeviceConfigurationKeyNameTypeMaxDcChargePower DeviceConfigurationKeyNameType = "maxDcChargePower" + DeviceConfigurationKeyNameTypeMaxDcDischargePower DeviceConfigurationKeyNameType = "maxDcDischargePower" + DeviceConfigurationKeyNameTypeBatteryActiveControlMode DeviceConfigurationKeyNameType = "batteryActiveControlMode" + DeviceConfigurationKeyNameTypeDefaultAcPower DeviceConfigurationKeyNameType = "defaultAcPower" + DeviceConfigurationKeyNameTypeDefaultDcPower DeviceConfigurationKeyNameType = "defaultDcPower" + DeviceConfigurationKeyNameTypeDefaultPccPower DeviceConfigurationKeyNameType = "defaultPccPower" + DeviceConfigurationKeyNameTypeFailsafeAcPowerSetpoint DeviceConfigurationKeyNameType = "failsafeAcPowerSetpoint" + DeviceConfigurationKeyNameTypeFailsafeDcPowerSetpoint DeviceConfigurationKeyNameType = "failsafeDcPowerSetpoint" + DeviceConfigurationKeyNameTypeFailsafePccPowerSetpoint DeviceConfigurationKeyNameType = "failsafePccPowerSetpoint" + DeviceConfigurationKeyNameTypeFailsafeDurationMinimum DeviceConfigurationKeyNameType = "failsafeDurationMinimum" + DeviceConfigurationKeyNameTypeDischargingBelowTargetEnergyRequestPermitted DeviceConfigurationKeyNameType = "dischargingBelowTargetEnergyRequestPermitted" + DeviceConfigurationKeyNameTypeIncentivesSimulationCyclesMax DeviceConfigurationKeyNameType = "incentivesSimulationCyclesMax" + DeviceConfigurationKeyNameTypeIncentivesSimulationConcurrent DeviceConfigurationKeyNameType = "incentivesSimulationConcurrent" + DeviceConfigurationKeyNameTypeIncentivesTimeoutIncentiveRequest DeviceConfigurationKeyNameType = "incentivesTimeoutIncentiveRequest" + DeviceConfigurationKeyNameTypeIncentivesWaitIncentiveWriteable DeviceConfigurationKeyNameType = "incentivesWaitIncentiveWriteable" +) + +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" + DeviceConfigurationKeyValueTypeTypeInteger DeviceConfigurationKeyValueTypeType = "integer" +) + +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"` + Integer *int64 `json:"integer,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/model/deviceconfiguration_additions.go b/model/deviceconfiguration_additions.go new file mode 100644 index 0000000..07cc247 --- /dev/null +++ b/model/deviceconfiguration_additions.go @@ -0,0 +1,40 @@ +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/model/deviceconfiguration_additions_test.go b/model/deviceconfiguration_additions_test.go new file mode 100644 index 0000000..5d0a0db --- /dev/null +++ b/model/deviceconfiguration_additions_test.go @@ -0,0 +1,134 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestDeviceConfigurationKeyValueListDataType_Update(t *testing.T) { + sut := DeviceConfigurationKeyValueListDataType{ + DeviceConfigurationKeyValueData: []DeviceConfigurationKeyValueDataType{ + { + KeyId: util.Ptr(DeviceConfigurationKeyIdType(0)), + Value: &DeviceConfigurationKeyValueValueType{ + Boolean: util.Ptr(true), + }, + }, + { + KeyId: util.Ptr(DeviceConfigurationKeyIdType(1)), + Value: &DeviceConfigurationKeyValueValueType{ + Boolean: util.Ptr(true), + }, + }, + }, + } + + newData := DeviceConfigurationKeyValueListDataType{ + DeviceConfigurationKeyValueData: []DeviceConfigurationKeyValueDataType{ + { + KeyId: util.Ptr(DeviceConfigurationKeyIdType(1)), + Value: &DeviceConfigurationKeyValueValueType{ + Boolean: util.Ptr(false), + }, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := DeviceConfigurationKeyValueDescriptionListDataType{ + DeviceConfigurationKeyValueDescriptionData: []DeviceConfigurationKeyValueDescriptionDataType{ + { + KeyId: util.Ptr(DeviceConfigurationKeyIdType(0)), + ValueType: util.Ptr(DeviceConfigurationKeyValueTypeTypeBoolean), + }, + { + KeyId: util.Ptr(DeviceConfigurationKeyIdType(1)), + ValueType: util.Ptr(DeviceConfigurationKeyValueTypeTypeBoolean), + }, + }, + } + + newData := DeviceConfigurationKeyValueDescriptionListDataType{ + DeviceConfigurationKeyValueDescriptionData: []DeviceConfigurationKeyValueDescriptionDataType{ + { + KeyId: util.Ptr(DeviceConfigurationKeyIdType(1)), + ValueType: util.Ptr(DeviceConfigurationKeyValueTypeTypeString), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, DeviceConfigurationKeyValueTypeTypeBoolean, *item1.ValueType) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.KeyId)) + assert.Equal(t, DeviceConfigurationKeyValueTypeTypeString, *item2.ValueType) +} + +func TestDeviceConfigurationKeyValueConstraintsListDataType_Update(t *testing.T) { + sut := DeviceConfigurationKeyValueConstraintsListDataType{ + DeviceConfigurationKeyValueConstraintsData: []DeviceConfigurationKeyValueConstraintsDataType{ + { + KeyId: util.Ptr(DeviceConfigurationKeyIdType(0)), + ValueStepSize: &DeviceConfigurationKeyValueValueType{ + Boolean: util.Ptr(true), + }, + }, + { + KeyId: util.Ptr(DeviceConfigurationKeyIdType(1)), + ValueStepSize: &DeviceConfigurationKeyValueValueType{ + Boolean: util.Ptr(true), + }, + }, + }, + } + + newData := DeviceConfigurationKeyValueConstraintsListDataType{ + DeviceConfigurationKeyValueConstraintsData: []DeviceConfigurationKeyValueConstraintsDataType{ + { + KeyId: util.Ptr(DeviceConfigurationKeyIdType(1)), + ValueStepSize: &DeviceConfigurationKeyValueValueType{ + Boolean: util.Ptr(false), + }, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/devicediagnosis.go b/model/devicediagnosis.go new file mode 100644 index 0000000..da5faba --- /dev/null +++ b/model/devicediagnosis.go @@ -0,0 +1,76 @@ +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" + DeviceDiagnosisOperatingStateTypeTemporarilyNotReady DeviceDiagnosisOperatingStateType = "temporarilyNotReady" + DeviceDiagnosisOperatingStateTypeOff DeviceDiagnosisOperatingStateType = "off" +) + +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/model/directcontrol.go b/model/directcontrol.go new file mode 100644 index 0000000..47ab26f --- /dev/null +++ b/model/directcontrol.go @@ -0,0 +1,55 @@ +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/model/eebus_tags.go b/model/eebus_tags.go new file mode 100644 index 0000000..7952292 --- /dev/null +++ b/model/eebus_tags.go @@ -0,0 +1,46 @@ +package model + +import ( + "reflect" + "strings" + + "github.com/enbility/ship-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/model/electricalconnection.go b/model/electricalconnection.go new file mode 100644 index 0000000..95be03e --- /dev/null +++ b/model/electricalconnection.go @@ -0,0 +1,241 @@ +package model + +type ElectricalConnectionIdType uint + +type ElectricalConnectionParameterIdType uint + +type ElectricalConnectionCharaceteristicsIdType 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 ElectricalConnectionCharacteristicIdType uint + +type ElectricalConnectionCharacteristicContextType string + +const ( + ElectricalConnectionCharacteristicContextTypeDevice ElectricalConnectionCharacteristicContextType = "device" + ElectricalConnectionCharacteristicContextTypeEntity ElectricalConnectionCharacteristicContextType = "entity" + ElectricalConnectionCharacteristicContextTypeInverter ElectricalConnectionCharacteristicContextType = "inverter" + ElectricalConnectionCharacteristicContextTypePvString ElectricalConnectionCharacteristicContextType = "pvString" + ElectricalConnectionCharacteristicContextTypeBattery ElectricalConnectionCharacteristicContextType = "battery" +) + +type ElectricalConnectionCharacteristicTypeType string + +const ( + ElectricalConnectionCharacteristicTypeTypePowerConsumptionMin ElectricalConnectionCharacteristicTypeType = "powerConsumptionMin" + ElectricalConnectionCharacteristicTypeTypePowerConsumptionMax ElectricalConnectionCharacteristicTypeType = "powerConsumptionMax" + ElectricalConnectionCharacteristicTypeTypePowerConsumptionNominalMin ElectricalConnectionCharacteristicTypeType = "powerConsumptionNominalMin" + ElectricalConnectionCharacteristicTypeTypePowerConsumptionNominalMax ElectricalConnectionCharacteristicTypeType = "powerConsumptionNominalMax" + ElectricalConnectionCharacteristicTypeTypePowerProductionMin ElectricalConnectionCharacteristicTypeType = "powerProductionMin" + ElectricalConnectionCharacteristicTypeTypePowerProductionMax ElectricalConnectionCharacteristicTypeType = "powerProductionMax" + ElectricalConnectionCharacteristicTypeTypePowerProductionNominalMin ElectricalConnectionCharacteristicTypeType = "powerProductionNominalMin" + ElectricalConnectionCharacteristicTypeTypePowerProductionNominalMax ElectricalConnectionCharacteristicTypeType = "powerProductionNominalMax" + ElectricalConnectionCharacteristicTypeTypeEnergyCapacityNominalMax ElectricalConnectionCharacteristicTypeType = "energyCapacityNominalMax" + ElectricalConnectionCharacteristicTypeTypeContractualConsumptionNominalMax ElectricalConnectionCharacteristicTypeType = "contractualConsumptionNominalMax" + ElectricalConnectionCharacteristicTypeTypeContracutalProductionNominalMax ElectricalConnectionCharacteristicTypeType = "contractualProductionNominalMax" + ElectricalConnectionCharacteristicTypeTypeApparentPowerProductionNominalMax ElectricalConnectionCharacteristicTypeType = "apparentPowerProductionNominalMax" + ElectricalConnectionCharacteristicTypeTypeApparentPowerConsumptionNominalMax ElectricalConnectionCharacteristicTypeType = "apparentPowerConsumptionNominalMax" +) + +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"` +} + +type ElectricalConnectionCharacteristicDataType struct { + ElectricalConnectionId *ElectricalConnectionIdType `json:"electricalConnectionId,omitempty" eebus:"key"` + ParameterId *ElectricalConnectionParameterIdType `json:"parameterId,omitempty" eebus:"key"` + CharacteristicId *ElectricalConnectionCharaceteristicsIdType `json:"characteristicId,omitempty" eebus:"key"` + CharacteristicContext *ElectricalConnectionCharacteristicContextType `json:"characteristicContext,omitempty"` + CharacteristicType *ElectricalConnectionCharacteristicTypeType `json:"characteristicType,omitempty"` + Value *ScaledNumberType `json:"value,omitempty"` + Unit *UnitOfMeasurementType `json:"unit,omitempty"` +} + +type ElectricalConnectionCharacteristicDataElementsType struct { + ElectricalConnectionId *ElementTagType `json:"electricalConnectionId,omitempty"` + ParameterId *ElementTagType `json:"parameterId,omitempty"` + CharacteristicId *ElementTagType `json:"characteristicId,omitempty"` + CharacteristicContext *ElementTagType `json:"characteristicContext,omitempty"` + CharacteristicType *ElementTagType `json:"characteristicType,omitempty"` + Value *ScaledNumberElementsType `json:"value,omitempty"` + Unit *ElementTagType `json:"unit,omitempty"` +} + +type ElectricalConnectionCharacteristicListDataType struct { + ElectricalConnectionCharacteristicListData []ElectricalConnectionCharacteristicDataType `json:"electricalConnectionCharacteristicListData,omitempty"` +} + +type ElectricalConnectionCharacteristicListDataSelectorsType struct { + ElectricalConnectionId *ElectricalConnectionIdType `json:"electricalConnectionId,omitempty"` + ParameterId *ElectricalConnectionParameterIdType `json:"parameterId,omitempty"` + CharacteristicId *ElectricalConnectionCharaceteristicsIdType `json:"characteristicId,omitempty"` + CharacteristicContext *ElectricalConnectionCharacteristicContextType `json:"characteristicContext,omitempty"` + CharacteristicType *ElectricalConnectionCharacteristicTypeType `json:"characteristicType,omitempty"` +} diff --git a/model/electricalconnection_additions.go b/model/electricalconnection_additions.go new file mode 100644 index 0000000..52e9e8d --- /dev/null +++ b/model/electricalconnection_additions.go @@ -0,0 +1,66 @@ +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) +} + +// ElectricalConnectionCharacteristicListDataType + +var _ Updater = (*ElectricalConnectionCharacteristicListDataType)(nil) + +func (r *ElectricalConnectionCharacteristicListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { + var newData []ElectricalConnectionCharacteristicDataType + if newList != nil { + newData = newList.(*ElectricalConnectionCharacteristicListDataType).ElectricalConnectionCharacteristicListData + } + + r.ElectricalConnectionCharacteristicListData = UpdateList(r.ElectricalConnectionCharacteristicListData, 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/model/electricalconnection_additions_test.go b/model/electricalconnection_additions_test.go new file mode 100644 index 0000000..343922b --- /dev/null +++ b/model/electricalconnection_additions_test.go @@ -0,0 +1,1188 @@ +package model + +import ( + "encoding/json" + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestElectricalConnectionStateListDataType_Update(t *testing.T) { + sut := ElectricalConnectionStateListDataType{ + ElectricalConnectionStateData: []ElectricalConnectionStateDataType{ + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(0)), + CurrentEnergyMode: util.Ptr(EnergyModeTypeProduce), + }, + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(1)), + CurrentEnergyMode: util.Ptr(EnergyModeTypeProduce), + }, + }, + } + + newData := ElectricalConnectionStateListDataType{ + ElectricalConnectionStateData: []ElectricalConnectionStateDataType{ + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(1)), + CurrentEnergyMode: util.Ptr(EnergyModeTypeConsume), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, EnergyModeTypeProduce, *item1.CurrentEnergyMode) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.ElectricalConnectionId)) + assert.Equal(t, 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 := ElectricalConnectionPermittedValueSetListDataType{ + ElectricalConnectionPermittedValueSetData: []ElectricalConnectionPermittedValueSetDataType{ + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(0)), + ParameterId: util.Ptr(ElectricalConnectionParameterIdType(0)), + PermittedValueSet: []ScaledNumberSetType{ + { + Range: []ScaledNumberRangeType{ + { + Min: NewScaledNumberType(1), + }, + }, + }, + }, + }, + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(0)), + ParameterId: util.Ptr(ElectricalConnectionParameterIdType(1)), + PermittedValueSet: []ScaledNumberSetType{ + { + Range: []ScaledNumberRangeType{ + { + Min: NewScaledNumberType(6), + Max: NewScaledNumberType(16), + }, + }, + }, + }, + }, + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(0)), + ParameterId: util.Ptr(ElectricalConnectionParameterIdType(2)), + PermittedValueSet: []ScaledNumberSetType{ + { + Range: []ScaledNumberRangeType{ + { + Min: NewScaledNumberType(6), + Max: NewScaledNumberType(16), + }, + }, + }, + }, + }, + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(0)), + ParameterId: util.Ptr(ElectricalConnectionParameterIdType(3)), + PermittedValueSet: []ScaledNumberSetType{ + { + Range: []ScaledNumberRangeType{ + { + Min: NewScaledNumberType(6), + Max: NewScaledNumberType(16), + }, + }, + }, + }, + }, + }, + } + + newData := ElectricalConnectionPermittedValueSetListDataType{ + ElectricalConnectionPermittedValueSetData: []ElectricalConnectionPermittedValueSetDataType{ + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(0)), + ParameterId: util.Ptr(ElectricalConnectionParameterIdType(1)), + PermittedValueSet: []ScaledNumberSetType{ + { + Range: []ScaledNumberRangeType{ + { + Min: NewScaledNumberType(2), + Max: NewScaledNumberType(16), + }, + }, + }, + }, + }, + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(0)), + ParameterId: util.Ptr(ElectricalConnectionParameterIdType(2)), + PermittedValueSet: []ScaledNumberSetType{ + { + Range: []ScaledNumberRangeType{ + { + Min: NewScaledNumberType(2), + Max: NewScaledNumberType(16), + }, + }, + }, + }, + }, + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(0)), + ParameterId: util.Ptr(ElectricalConnectionParameterIdType(3)), + PermittedValueSet: []ScaledNumberSetType{ + { + Range: []ScaledNumberRangeType{ + { + Min: NewScaledNumberType(2), + Max: NewScaledNumberType(16), + }, + }, + }, + }, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 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 ElectricalConnectionPermittedValueSetListDataType + err = json.Unmarshal([]byte(newDataJson), &newData) + if assert.Nil(t, err) == false { + return + } + + partial := &FilterType{ + CmdControl: &CmdControlType{ + Partial: &ElementTagType{}, + }, + ElectricalConnectionPermittedValueSetListDataSelectors: &ElectricalConnectionPermittedValueSetListDataSelectorsType{ + ElectricalConnectionId: util.Ptr[ElectricalConnectionIdType](0), + ParameterId: util.Ptr[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 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 ElectricalConnectionPermittedValueSetListDataType + err = json.Unmarshal([]byte(newDataJson), &newData) + if assert.Nil(t, err) == false { + return + } + + delete := &FilterType{ + CmdControl: &CmdControlType{ + Delete: &ElementTagType{}, + }, + ElectricalConnectionPermittedValueSetListDataSelectors: &ElectricalConnectionPermittedValueSetListDataSelectorsType{ + ElectricalConnectionId: util.Ptr[ElectricalConnectionIdType](0), + ParameterId: util.Ptr[ElectricalConnectionParameterIdType](0), + }, + } + + // Act + sut.UpdateList(&newData, 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 ElectricalConnectionPermittedValueSetListDataType + err := json.Unmarshal([]byte(existingDataJson), &sut) + if assert.Nil(t, err) == false { + return + } + + delete := &FilterType{ + CmdControl: &CmdControlType{ + Delete: &ElementTagType{}, + }, + ElectricalConnectionPermittedValueSetListDataSelectors: &ElectricalConnectionPermittedValueSetListDataSelectorsType{ + ElectricalConnectionId: util.Ptr[ElectricalConnectionIdType](0), + ParameterId: util.Ptr[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 ElectricalConnectionPermittedValueSetListDataType + err := json.Unmarshal([]byte(existingDataJson), &sut) + if assert.Nil(t, err) == false { + return + } + + delete := &FilterType{ + CmdControl: &CmdControlType{ + Delete: &ElementTagType{}, + }, + ElectricalConnectionPermittedValueSetDataElements: &ElectricalConnectionPermittedValueSetDataElementsType{ + PermittedValueSet: &ElementTagType{}, + }, + ElectricalConnectionPermittedValueSetListDataSelectors: &ElectricalConnectionPermittedValueSetListDataSelectorsType{ + ElectricalConnectionId: util.Ptr[ElectricalConnectionIdType](0), + ParameterId: util.Ptr[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 []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 ElectricalConnectionPermittedValueSetListDataType + err := json.Unmarshal([]byte(existingDataJson), &sut) + if assert.Nil(t, err) == false { + return + } + + delete := &FilterType{ + CmdControl: &CmdControlType{ + Delete: &ElementTagType{}, + }, + ElectricalConnectionPermittedValueSetDataElements: &ElectricalConnectionPermittedValueSetDataElementsType{ + PermittedValueSet: &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 []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 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 ElectricalConnectionPermittedValueSetListDataType + err = json.Unmarshal([]byte(newDataJson), &newData) + if assert.Nil(t, err) == false { + return + } + + delete := &FilterType{ + CmdControl: &CmdControlType{ + Delete: &ElementTagType{}, + }, + ElectricalConnectionPermittedValueSetListDataSelectors: &ElectricalConnectionPermittedValueSetListDataSelectorsType{ + ElectricalConnectionId: util.Ptr[ElectricalConnectionIdType](0), + ParameterId: util.Ptr[ElectricalConnectionParameterIdType](0), + }, + } + + // Act + sut.UpdateList(&newData, 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 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 ElectricalConnectionPermittedValueSetListDataType + err = json.Unmarshal([]byte(newDataJson), &newData) + if assert.Nil(t, err) == false { + return + } + + // Act + sut.UpdateList(&newData, 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 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 ElectricalConnectionPermittedValueSetListDataType + err = json.Unmarshal([]byte(newDataJson), &newData) + if assert.Nil(t, err) == false { + return + } + + // Act + sut.UpdateList(&newData, 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 := ElectricalConnectionDescriptionListDataType{ + ElectricalConnectionDescriptionData: []ElectricalConnectionDescriptionDataType{ + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(0)), + PowerSupplyType: util.Ptr(ElectricalConnectionVoltageTypeTypeAc), + }, + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(1)), + PowerSupplyType: util.Ptr(ElectricalConnectionVoltageTypeTypeAc), + }, + }, + } + + newData := ElectricalConnectionDescriptionListDataType{ + ElectricalConnectionDescriptionData: []ElectricalConnectionDescriptionDataType{ + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(1)), + PowerSupplyType: util.Ptr(ElectricalConnectionVoltageTypeTypeDc), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, ElectricalConnectionVoltageTypeTypeAc, *item1.PowerSupplyType) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.ElectricalConnectionId)) + assert.Equal(t, ElectricalConnectionVoltageTypeTypeDc, *item2.PowerSupplyType) +} + +func TestElectricalConnectionParameterDescriptionListDataType_Update(t *testing.T) { + sut := ElectricalConnectionParameterDescriptionListDataType{ + ElectricalConnectionParameterDescriptionData: []ElectricalConnectionParameterDescriptionDataType{ + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(0)), + ParameterId: util.Ptr(ElectricalConnectionParameterIdType(0)), + VoltageType: util.Ptr(ElectricalConnectionVoltageTypeTypeAc), + }, + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(1)), + ParameterId: util.Ptr(ElectricalConnectionParameterIdType(0)), + MeasurementId: util.Ptr(MeasurementIdType(0)), + VoltageType: util.Ptr(ElectricalConnectionVoltageTypeTypeAc), + }, + }, + } + + newData := ElectricalConnectionParameterDescriptionListDataType{ + ElectricalConnectionParameterDescriptionData: []ElectricalConnectionParameterDescriptionDataType{ + { + ElectricalConnectionId: util.Ptr(ElectricalConnectionIdType(1)), + ParameterId: util.Ptr(ElectricalConnectionParameterIdType(0)), + VoltageType: util.Ptr(ElectricalConnectionVoltageTypeTypeDc), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, ElectricalConnectionVoltageTypeTypeAc, *item1.VoltageType) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.ElectricalConnectionId)) + assert.Equal(t, ElectricalConnectionVoltageTypeTypeDc, *item2.VoltageType) +} diff --git a/model/hvac.go b/model/hvac.go new file mode 100644 index 0000000..060d3d5 --- /dev/null +++ b/model/hvac.go @@ -0,0 +1,222 @@ +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/model/hvac_additions.go b/model/hvac_additions.go new file mode 100644 index 0000000..a62824b --- /dev/null +++ b/model/hvac_additions.go @@ -0,0 +1,105 @@ +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/model/hvac_additions_test.go b/model/hvac_additions_test.go new file mode 100644 index 0000000..2336784 --- /dev/null +++ b/model/hvac_additions_test.go @@ -0,0 +1,312 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestHvacSystemFunctionListDataType_Update(t *testing.T) { + sut := HvacSystemFunctionListDataType{ + HvacSystemFunctionData: []HvacSystemFunctionDataType{ + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(0)), + IsOverrunActive: util.Ptr(false), + }, + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(1)), + IsOverrunActive: util.Ptr(false), + }, + }, + } + + newData := HvacSystemFunctionListDataType{ + HvacSystemFunctionData: []HvacSystemFunctionDataType{ + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(1)), + IsOverrunActive: util.Ptr(true), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := HvacSystemFunctionOperationModeRelationListDataType{ + HvacSystemFunctionOperationModeRelationData: []HvacSystemFunctionOperationModeRelationDataType{ + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(0)), + OperationModeId: util.Ptr(HvacOperationModeIdType(0)), + }, + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(1)), + OperationModeId: util.Ptr(HvacOperationModeIdType(0)), + }, + }, + } + + newData := HvacSystemFunctionOperationModeRelationListDataType{ + HvacSystemFunctionOperationModeRelationData: []HvacSystemFunctionOperationModeRelationDataType{ + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(1)), + OperationModeId: util.Ptr(HvacOperationModeIdType(1)), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := HvacSystemFunctionSetpointRelationListDataType{ + HvacSystemFunctionSetpointRelationData: []HvacSystemFunctionSetpointRelationDataType{ + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(0)), + OperationModeId: util.Ptr(HvacOperationModeIdType(0)), + }, + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(1)), + OperationModeId: util.Ptr(HvacOperationModeIdType(0)), + }, + }, + } + + newData := HvacSystemFunctionSetpointRelationListDataType{ + HvacSystemFunctionSetpointRelationData: []HvacSystemFunctionSetpointRelationDataType{ + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(1)), + OperationModeId: util.Ptr(HvacOperationModeIdType(1)), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := HvacSystemFunctionPowerSequenceRelationListDataType{ + HvacSystemFunctionPowerSequenceRelationData: []HvacSystemFunctionPowerSequenceRelationDataType{ + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(0)), + SequenceId: []PowerSequenceIdType{0}, + }, + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(1)), + SequenceId: []PowerSequenceIdType{0}, + }, + }, + } + + newData := HvacSystemFunctionPowerSequenceRelationListDataType{ + HvacSystemFunctionPowerSequenceRelationData: []HvacSystemFunctionPowerSequenceRelationDataType{ + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(1)), + SequenceId: []PowerSequenceIdType{1}, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := HvacSystemFunctionDescriptionListDataType{ + HvacSystemFunctionDescriptionData: []HvacSystemFunctionDescriptionDataType{ + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := HvacSystemFunctionDescriptionListDataType{ + HvacSystemFunctionDescriptionData: []HvacSystemFunctionDescriptionDataType{ + { + SystemFunctionId: util.Ptr(HvacSystemFunctionIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := HvacOperationModeDescriptionListDataType{ + HvacOperationModeDescriptionData: []HvacOperationModeDescriptionDataType{ + { + OperationModeId: util.Ptr(HvacOperationModeIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + OperationModeId: util.Ptr(HvacOperationModeIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := HvacOperationModeDescriptionListDataType{ + HvacOperationModeDescriptionData: []HvacOperationModeDescriptionDataType{ + { + OperationModeId: util.Ptr(HvacOperationModeIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := HvacOverrunListDataType{ + HvacOverrunData: []HvacOverrunDataType{ + { + OverrunId: util.Ptr(HvacOverrunIdType(0)), + IsOverrunStatusChangeable: util.Ptr(false), + }, + { + OverrunId: util.Ptr(HvacOverrunIdType(1)), + IsOverrunStatusChangeable: util.Ptr(false), + }, + }, + } + + newData := HvacOverrunListDataType{ + HvacOverrunData: []HvacOverrunDataType{ + { + OverrunId: util.Ptr(HvacOverrunIdType(1)), + IsOverrunStatusChangeable: util.Ptr(true), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := HvacOverrunDescriptionListDataType{ + HvacOverrunDescriptionData: []HvacOverrunDescriptionDataType{ + { + OverrunId: util.Ptr(HvacOverrunIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + OverrunId: util.Ptr(HvacOverrunIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := HvacOverrunDescriptionListDataType{ + HvacOverrunDescriptionData: []HvacOverrunDescriptionDataType{ + { + OverrunId: util.Ptr(HvacOverrunIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/identification.go b/model/identification.go new file mode 100644 index 0000000..6e84329 --- /dev/null +++ b/model/identification.go @@ -0,0 +1,82 @@ +package model + +type IdentificationIdType uint + +type IdentificationTypeType string + +const ( + IdentificationTypeTypeEui48 IdentificationTypeType = "eui48" + IdentificationTypeTypeEui64 IdentificationTypeType = "eui64" + IdentificationTypeTypeUserrfidtag IdentificationTypeType = "userRfidTag" +) + +type IdentificationValueType string + +type SessionIdType uint + +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"` +} + +type SessionIdentificationDataType struct { + SessionId *SessionIdType `json:"sessionId,omitempty" eebus:"key"` + IdentificationId *IdentificationIdType `json:"identificationId,omitempty"` + IsLatestSession *bool `json:"isLatestSession,omitempty"` + TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` +} + +type SessionIdentificationDataElementsType struct { + SessionId *ElementTagType `json:"sessionId,omitempty"` + IdentificationId *ElementTagType `json:"identificationId,omitempty"` + IsLatestSession *ElementTagType `json:"isLatestSession,omitempty"` + TimePeriod *TimePeriodElementsType `json:"timePeriod,omitempty"` +} + +type SessionIdentificationListDataType struct { + SessionIdentificationData []SessionIdentificationDataType `json:"sessionIdentificationData,omitempty"` +} + +type SessionIdentificationListDataSelectorsType struct { + SessionId *SessionIdType `json:"sessionId,omitempty"` + IdentificationId *IdentificationIdType `json:"identificationId,omitempty"` + IsLatestSession *bool `json:"isLatestSession,omitempty"` + TimePeriod *TimePeriodType `json:"timePeriod,omitempty"` +} + +type SessionMeasurementRelationDataType struct { + SessionId *SessionIdType `json:"sessionId,omitempty" eebus:"key"` + MeasurementId []MeasurementIdType `json:"measurementId,omitempty"` +} + +type SessionMeasurementRelationDataElementsType struct { + SessionId *ElementTagType `json:"sessionId,omitempty"` + MeasurementId *ElementTagType `json:"measurementId,omitempty"` +} + +type SessionMeasurementRelationListDataType struct { + SessionMeasurementRelationData []SessionMeasurementRelationDataType `json:"sessionMeasurementRelationData,omitempty"` +} + +type SessionMeasurementRelationListDataSelectorsType struct { + SessionId *SessionIdType `json:"sessionId,omitempty"` + MeasurementId *MeasurementIdType `json:"measurementId,omitempty"` +} diff --git a/model/identification_additions.go b/model/identification_additions.go new file mode 100644 index 0000000..d2ee37c --- /dev/null +++ b/model/identification_additions.go @@ -0,0 +1,40 @@ +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) +} + +// SessionIdentificationListDataType + +var _ Updater = (*SessionIdentificationListDataType)(nil) + +func (r *SessionIdentificationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { + var newData []SessionIdentificationDataType + if newList != nil { + newData = newList.(*SessionIdentificationListDataType).SessionIdentificationData + } + + r.SessionIdentificationData = UpdateList(r.SessionIdentificationData, newData, filterPartial, filterDelete) +} + +// SessionMeasurementRelationListDataType + +var _ Updater = (*SessionMeasurementRelationListDataType)(nil) + +func (r *SessionMeasurementRelationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { + var newData []SessionMeasurementRelationDataType + if newList != nil { + newData = newList.(*SessionMeasurementRelationListDataType).SessionMeasurementRelationData + } + + r.SessionMeasurementRelationData = UpdateList(r.SessionMeasurementRelationData, newData, filterPartial, filterDelete) +} diff --git a/model/identification_additions_test.go b/model/identification_additions_test.go new file mode 100644 index 0000000..e846b64 --- /dev/null +++ b/model/identification_additions_test.go @@ -0,0 +1,46 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestIdentificationListDataType_Update(t *testing.T) { + sut := IdentificationListDataType{ + IdentificationData: []IdentificationDataType{ + { + IdentificationId: util.Ptr(IdentificationIdType(0)), + IdentificationType: util.Ptr(IdentificationTypeTypeEui48), + }, + { + IdentificationId: util.Ptr(IdentificationIdType(1)), + IdentificationType: util.Ptr(IdentificationTypeTypeEui48), + }, + }, + } + + newData := IdentificationListDataType{ + IdentificationData: []IdentificationDataType{ + { + IdentificationId: util.Ptr(IdentificationIdType(1)), + IdentificationType: util.Ptr(IdentificationTypeTypeEui64), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, IdentificationTypeTypeEui48, *item1.IdentificationType) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.IdentificationId)) + assert.Equal(t, IdentificationTypeTypeEui64, *item2.IdentificationType) +} diff --git a/model/incentivetable.go b/model/incentivetable.go new file mode 100644 index 0000000..c5cacb0 --- /dev/null +++ b/model/incentivetable.go @@ -0,0 +1,103 @@ +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/model/loadcontrol.go b/model/loadcontrol.go new file mode 100644 index 0000000..a9d0b8f --- /dev/null +++ b/model/loadcontrol.go @@ -0,0 +1,185 @@ +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" + LoadControlLimitTypeTypeSignDependentAbsValueLimit LoadControlLimitTypeType = "signDependentAbsValueLimit" +) + +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/model/loadcontrol_additions.go b/model/loadcontrol_additions.go new file mode 100644 index 0000000..4b05559 --- /dev/null +++ b/model/loadcontrol_additions.go @@ -0,0 +1,66 @@ +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/model/loadcontrol_additions_test.go b/model/loadcontrol_additions_test.go new file mode 100644 index 0000000..878aedd --- /dev/null +++ b/model/loadcontrol_additions_test.go @@ -0,0 +1,198 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestLoadControlEventListDataType_Update(t *testing.T) { + sut := LoadControlEventListDataType{ + LoadControlEventData: []LoadControlEventDataType{ + { + EventId: util.Ptr(LoadControlEventIdType(0)), + EventActionConsume: util.Ptr(LoadControlEventActionTypeNormal), + }, + { + EventId: util.Ptr(LoadControlEventIdType(1)), + EventActionConsume: util.Ptr(LoadControlEventActionTypeNormal), + }, + }, + } + + newData := LoadControlEventListDataType{ + LoadControlEventData: []LoadControlEventDataType{ + { + EventId: util.Ptr(LoadControlEventIdType(1)), + EventActionConsume: util.Ptr(LoadControlEventActionTypeIncrease), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, LoadControlEventActionTypeNormal, *item1.EventActionConsume) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.EventId)) + assert.Equal(t, LoadControlEventActionTypeIncrease, *item2.EventActionConsume) +} + +func TestLoadControlStateListDataType_Update(t *testing.T) { + sut := LoadControlStateListDataType{ + LoadControlStateData: []LoadControlStateDataType{ + { + EventId: util.Ptr(LoadControlEventIdType(0)), + EventStateConsume: util.Ptr(LoadControlEventStateTypeEventAccepted), + }, + { + EventId: util.Ptr(LoadControlEventIdType(1)), + EventStateConsume: util.Ptr(LoadControlEventStateTypeEventAccepted), + }, + }, + } + + newData := LoadControlStateListDataType{ + LoadControlStateData: []LoadControlStateDataType{ + { + EventId: util.Ptr(LoadControlEventIdType(1)), + EventStateConsume: util.Ptr(LoadControlEventStateTypeEventStopped), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, LoadControlEventStateTypeEventAccepted, *item1.EventStateConsume) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.EventId)) + assert.Equal(t, LoadControlEventStateTypeEventStopped, *item2.EventStateConsume) +} + +func TestLoadControlLimitListDataType_Update(t *testing.T) { + sut := LoadControlLimitListDataType{ + LoadControlLimitData: []LoadControlLimitDataType{ + { + LimitId: util.Ptr(LoadControlLimitIdType(0)), + IsLimitChangeable: util.Ptr(false), + }, + { + LimitId: util.Ptr(LoadControlLimitIdType(1)), + IsLimitChangeable: util.Ptr(false), + }, + }, + } + + newData := LoadControlLimitListDataType{ + LoadControlLimitData: []LoadControlLimitDataType{ + { + LimitId: util.Ptr(LoadControlLimitIdType(1)), + IsLimitChangeable: util.Ptr(true), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := LoadControlLimitConstraintsListDataType{ + LoadControlLimitConstraintsData: []LoadControlLimitConstraintsDataType{ + { + LimitId: util.Ptr(LoadControlLimitIdType(0)), + ValueStepSize: NewScaledNumberType(1), + }, + { + LimitId: util.Ptr(LoadControlLimitIdType(1)), + ValueStepSize: NewScaledNumberType(1), + }, + }, + } + + newData := LoadControlLimitConstraintsListDataType{ + LoadControlLimitConstraintsData: []LoadControlLimitConstraintsDataType{ + { + LimitId: util.Ptr(LoadControlLimitIdType(1)), + ValueStepSize: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := LoadControlLimitDescriptionListDataType{ + LoadControlLimitDescriptionData: []LoadControlLimitDescriptionDataType{ + { + LimitId: util.Ptr(LoadControlLimitIdType(0)), + LimitCategory: util.Ptr(LoadControlCategoryTypeObligation), + }, + { + LimitId: util.Ptr(LoadControlLimitIdType(1)), + LimitCategory: util.Ptr(LoadControlCategoryTypeObligation), + }, + }, + } + + newData := LoadControlLimitDescriptionListDataType{ + LoadControlLimitDescriptionData: []LoadControlLimitDescriptionDataType{ + { + LimitId: util.Ptr(LoadControlLimitIdType(1)), + LimitCategory: util.Ptr(LoadControlCategoryTypeOptimization), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, LoadControlCategoryTypeObligation, *item1.LimitCategory) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.LimitId)) + assert.Equal(t, LoadControlCategoryTypeOptimization, *item2.LimitCategory) +} diff --git a/model/measurement.go b/model/measurement.go new file mode 100644 index 0000000..c41e57e --- /dev/null +++ b/model/measurement.go @@ -0,0 +1,222 @@ +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 MeasurementSeriesDataType 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 MeasurementSeriesDataElementsType 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 MeasurementSeriesListDataType struct { + MeasurementSeriesData []MeasurementSeriesDataType `json:"measurementSeriesData,omitempty"` +} + +type MeasurementSeriesListDataSelectorsType 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/model/measurement_additions.go b/model/measurement_additions.go new file mode 100644 index 0000000..87cb905 --- /dev/null +++ b/model/measurement_additions.go @@ -0,0 +1,66 @@ +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) +} + +// MeasurementSeriesListDataType + +var _ Updater = (*MeasurementSeriesListDataType)(nil) + +func (r *MeasurementSeriesListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { + var newData []MeasurementSeriesDataType + if newList != nil { + newData = newList.(*MeasurementSeriesListDataType).MeasurementSeriesData + } + + r.MeasurementSeriesData = UpdateList(r.MeasurementSeriesData, 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/model/measurement_additions_test.go b/model/measurement_additions_test.go new file mode 100644 index 0000000..32ba2df --- /dev/null +++ b/model/measurement_additions_test.go @@ -0,0 +1,207 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestMeasurementListDataType_Update_Add(t *testing.T) { + sut := MeasurementListDataType{ + MeasurementData: []MeasurementDataType{ + { + MeasurementId: util.Ptr(MeasurementIdType(0)), + ValueType: util.Ptr(MeasurementValueTypeTypeAverageValue), + Value: NewScaledNumberType(1), + }, + { + MeasurementId: util.Ptr(MeasurementIdType(1)), + ValueType: util.Ptr(MeasurementValueTypeTypeAverageValue), + Value: NewScaledNumberType(1), + }, + }, + } + + newData := MeasurementListDataType{ + MeasurementData: []MeasurementDataType{ + { + MeasurementId: util.Ptr(MeasurementIdType(1)), + ValueType: util.Ptr(MeasurementValueTypeTypeValue), + Value: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, MeasurementValueTypeTypeAverageValue, *item1.ValueType) + assert.Equal(t, 1.0, item1.Value.GetValue()) + item2 := data[1] + assert.Equal(t, 1, int(*item2.MeasurementId)) + assert.Equal(t, MeasurementValueTypeTypeAverageValue, *item2.ValueType) + assert.Equal(t, 1.0, item2.Value.GetValue()) +} + +func TestMeasurementListDataType_Update_Replace(t *testing.T) { + sut := MeasurementListDataType{ + MeasurementData: []MeasurementDataType{ + { + MeasurementId: util.Ptr(MeasurementIdType(0)), + ValueType: util.Ptr(MeasurementValueTypeTypeAverageValue), + Value: NewScaledNumberType(1), + }, + { + MeasurementId: util.Ptr(MeasurementIdType(1)), + ValueType: util.Ptr(MeasurementValueTypeTypeValue), + Value: NewScaledNumberType(1), + }, + }, + } + + newData := MeasurementListDataType{ + MeasurementData: []MeasurementDataType{ + { + MeasurementId: util.Ptr(MeasurementIdType(1)), + ValueType: util.Ptr(MeasurementValueTypeTypeValue), + Value: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, 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, MeasurementValueTypeTypeValue, *item2.ValueType) + assert.Equal(t, 10.0, item2.Value.GetValue()) +} + +func TestMeasurementConstraintsListDataType_Update(t *testing.T) { + sut := MeasurementConstraintsListDataType{ + MeasurementConstraintsData: []MeasurementConstraintsDataType{ + { + MeasurementId: util.Ptr(MeasurementIdType(0)), + ValueStepSize: NewScaledNumberType(1), + }, + { + MeasurementId: util.Ptr(MeasurementIdType(1)), + ValueStepSize: NewScaledNumberType(1), + }, + }, + } + + newData := MeasurementConstraintsListDataType{ + MeasurementConstraintsData: []MeasurementConstraintsDataType{ + { + MeasurementId: util.Ptr(MeasurementIdType(1)), + ValueStepSize: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := MeasurementDescriptionListDataType{ + MeasurementDescriptionData: []MeasurementDescriptionDataType{ + { + MeasurementId: util.Ptr(MeasurementIdType(0)), + ScopeType: util.Ptr(ScopeTypeTypeACCurrent), + }, + { + MeasurementId: util.Ptr(MeasurementIdType(1)), + ScopeType: util.Ptr(ScopeTypeTypeACCurrent), + }, + }, + } + + newData := MeasurementDescriptionListDataType{ + MeasurementDescriptionData: []MeasurementDescriptionDataType{ + { + MeasurementId: util.Ptr(MeasurementIdType(1)), + ScopeType: util.Ptr(ScopeTypeTypeACPower), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, ScopeTypeTypeACCurrent, *item1.ScopeType) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.MeasurementId)) + assert.Equal(t, ScopeTypeTypeACPower, *item2.ScopeType) +} + +func TestMeasurementThresholdRelationListDataType_Update(t *testing.T) { + sut := MeasurementThresholdRelationListDataType{ + MeasurementThresholdRelationData: []MeasurementThresholdRelationDataType{ + { + MeasurementId: util.Ptr(MeasurementIdType(0)), + ThresholdId: []ThresholdIdType{ThresholdIdType(0)}, + }, + { + MeasurementId: util.Ptr(MeasurementIdType(1)), + ThresholdId: []ThresholdIdType{ThresholdIdType(0)}, + }, + }, + } + + newData := MeasurementThresholdRelationListDataType{ + MeasurementThresholdRelationData: []MeasurementThresholdRelationDataType{ + { + MeasurementId: util.Ptr(MeasurementIdType(1)), + ThresholdId: []ThresholdIdType{ThresholdIdType(1)}, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/messaging.go b/model/messaging.go new file mode 100644 index 0000000..07c606d --- /dev/null +++ b/model/messaging.go @@ -0,0 +1,39 @@ +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/model/messaging_additions.go b/model/messaging_additions.go new file mode 100644 index 0000000..d8b89a0 --- /dev/null +++ b/model/messaging_additions.go @@ -0,0 +1,14 @@ +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/model/messaging_additions_test.go b/model/messaging_additions_test.go new file mode 100644 index 0000000..c234ce7 --- /dev/null +++ b/model/messaging_additions_test.go @@ -0,0 +1,46 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestMessagingListDataType_Update(t *testing.T) { + sut := MessagingListDataType{ + MessagingData: []MessagingDataType{ + { + MessagingNumber: util.Ptr(MessagingNumberType(0)), + Text: util.Ptr(MessagingDataTextType("old")), + }, + { + MessagingNumber: util.Ptr(MessagingNumberType(1)), + Text: util.Ptr(MessagingDataTextType("old")), + }, + }, + } + + newData := MessagingListDataType{ + MessagingData: []MessagingDataType{ + { + MessagingNumber: util.Ptr(MessagingNumberType(1)), + Text: util.Ptr(MessagingDataTextType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/networkmanagement.go b/model/networkmanagement.go new file mode 100644 index 0000000..7c6d37c --- /dev/null +++ b/model/networkmanagement.go @@ -0,0 +1,239 @@ +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/model/networkmanagement_additions.go b/model/networkmanagement_additions.go new file mode 100644 index 0000000..fbca8e8 --- /dev/null +++ b/model/networkmanagement_additions.go @@ -0,0 +1,40 @@ +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/model/nodemanagement.go b/model/nodemanagement.go new file mode 100644 index 0000000..afbd6e4 --- /dev/null +++ b/model/nodemanagement.go @@ -0,0 +1,136 @@ +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/model/nodemanagement_additions.go b/model/nodemanagement_additions.go new file mode 100644 index 0000000..1ad61bc --- /dev/null +++ b/model/nodemanagement_additions.go @@ -0,0 +1,143 @@ +package model + +import ( + "reflect" + "sync" +) + +var nmMux sync.Mutex + +// 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) +} + +// NodeManagementUseCaseDataType + +// find the matching UseCaseInformation index for +// a given FeatureAddressType, UseCaseActorType and UseCaseNameType +// +// if UseCaseActorType and UseCaseNameType are empty they are ignored, +// and the first matching UseCaseInformation item is returned +func (n *NodeManagementUseCaseDataType) useCaseInformationIndex( + address FeatureAddressType, + actor UseCaseActorType, + useCaseName UseCaseNameType, +) (int, bool) { + + // get the element with the same entity + for index, item := range n.UseCaseInformation { + if item.Address.Device == nil || + item.Address.Entity == nil || + !reflect.DeepEqual(item.Address.Device, address.Device) || + !reflect.DeepEqual(item.Address.Entity, address.Entity) { + continue + } + + if len(actor) == 0 && len(useCaseName) == 0 { + return index, true + } + + if len(actor) > 0 { + if item.Actor == nil || *item.Actor != actor { + continue + } + + } + + if len(useCaseName) == 0 { + return index, true + } + + if _, ok := item.useCaseSupportIndex(useCaseName); ok { + return index, true + } + } + + return -1, false +} + +// add a new UseCaseSupportType +func (n *NodeManagementUseCaseDataType) AddUseCaseSupport( + address FeatureAddressType, + actor UseCaseActorType, + useCaseName UseCaseNameType, + useCaseVersion SpecificationVersionType, + useCaseDocumemtSubRevision string, + useCaseAvailable bool, + scenarios []UseCaseScenarioSupportType, +) { + nmMux.Lock() + defer nmMux.Unlock() + + useCaseSupport := UseCaseSupportType{ + UseCaseName: &useCaseName, + UseCaseVersion: &useCaseVersion, + UseCaseAvailable: &useCaseAvailable, + ScenarioSupport: scenarios, + UseCaseDocumentSubRevision: &useCaseDocumemtSubRevision, + } + + // is there an entry for the entity address and actor + usecaseIndex, ok := n.useCaseInformationIndex(address, actor, "") + + if ok { + n.UseCaseInformation[usecaseIndex].Add(useCaseSupport) + } else { + // create a new element for this entity + useCaseInformation := UseCaseInformationDataType{ + Address: &FeatureAddressType{ + Device: address.Device, + Entity: address.Entity, + }, + Actor: &actor, + UseCaseSupport: []UseCaseSupportType{useCaseSupport}, + } + n.UseCaseInformation = append(n.UseCaseInformation, useCaseInformation) + } +} + +// Remove a UseCaseSupportType with +// a provided FeatureAddressType, UseCaseActorType and UseCaseNameType +func (n *NodeManagementUseCaseDataType) RemoveUseCaseSupport( + address FeatureAddressType, + actor UseCaseActorType, + useCaseName UseCaseNameType, +) { + nmMux.Lock() + defer nmMux.Unlock() + + // is there an entry for the entity address, actor and usecase name + usecaseIndex, ok := n.useCaseInformationIndex(address, actor, useCaseName) + if !ok { + return + } + + var usecaseInfo []UseCaseInformationDataType + + for index, item := range n.UseCaseInformation { + if index != usecaseIndex { + usecaseInfo = append(usecaseInfo, item) + continue + } + + item.Remove(useCaseName) + + // only add the item if there are any usecases left + if len(item.UseCaseSupport) == 0 { + continue + } + + usecaseInfo = append(usecaseInfo, item) + } + + n.UseCaseInformation = usecaseInfo +} diff --git a/model/nodemanagement_additions_test.go b/model/nodemanagement_additions_test.go new file mode 100644 index 0000000..3a47115 --- /dev/null +++ b/model/nodemanagement_additions_test.go @@ -0,0 +1,123 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestNodeManagementUseCaseDataTypeSuite(t *testing.T) { + suite.Run(t, new(NodeManagementUseCaseDataTypeSuite)) +} + +type NodeManagementUseCaseDataTypeSuite struct { + suite.Suite +} + +func (s *NodeManagementUseCaseDataTypeSuite) SetupSuite() {} +func (s *NodeManagementUseCaseDataTypeSuite) TearDownTest() {} + +func (s *NodeManagementUseCaseDataTypeSuite) BeforeTest(suiteName, testName string) {} + +func (s *NodeManagementUseCaseDataTypeSuite) Test_AdditionsAndRemovals() { + ucs := &NodeManagementUseCaseDataType{} + assert.NotNil(s.T(), ucs) + assert.Equal(s.T(), 0, len(ucs.UseCaseInformation)) + + address := FeatureAddressType{ + Device: util.Ptr(AddressDeviceType("test")), + Entity: []AddressEntityType{1}, + } + ucs.AddUseCaseSupport( + address, + UseCaseActorTypeCEM, + UseCaseNameTypeControlOfBattery, + SpecificationVersionType(""), + "", + true, + []UseCaseScenarioSupportType{}, + ) + assert.Equal(s.T(), 1, len(ucs.UseCaseInformation)) + assert.Equal(s.T(), 1, len(ucs.UseCaseInformation[0].UseCaseSupport)) + + ucs.AddUseCaseSupport( + address, + UseCaseActorTypeCEM, + UseCaseNameTypeEVSECommissioningAndConfiguration, + SpecificationVersionType(""), + "", + true, + []UseCaseScenarioSupportType{}, + ) + assert.Equal(s.T(), 1, len(ucs.UseCaseInformation)) + assert.Equal(s.T(), 2, len(ucs.UseCaseInformation[0].UseCaseSupport)) + + ucs.AddUseCaseSupport( + address, + UseCaseActorTypeCEM, + UseCaseNameTypeEVSECommissioningAndConfiguration, + SpecificationVersionType(""), + "", + true, + []UseCaseScenarioSupportType{}, + ) + assert.Equal(s.T(), 1, len(ucs.UseCaseInformation)) + assert.Equal(s.T(), 2, len(ucs.UseCaseInformation[0].UseCaseSupport)) + + ucs.AddUseCaseSupport( + address, + UseCaseActorTypeEnergyGuard, + UseCaseNameTypeLimitationOfPowerConsumption, + SpecificationVersionType(""), + "", + true, + []UseCaseScenarioSupportType{}, + ) + assert.Equal(s.T(), 2, len(ucs.UseCaseInformation)) + assert.Equal(s.T(), 2, len(ucs.UseCaseInformation[0].UseCaseSupport)) + assert.Equal(s.T(), 1, len(ucs.UseCaseInformation[1].UseCaseSupport)) + + ucs.RemoveUseCaseSupport( + address, + UseCaseActorTypeCEM, + UseCaseNameTypeEVChargingSummary, + ) + assert.Equal(s.T(), 2, len(ucs.UseCaseInformation)) + assert.Equal(s.T(), 2, len(ucs.UseCaseInformation[0].UseCaseSupport)) + + ucs.RemoveUseCaseSupport( + address, + UseCaseActorTypeCEM, + UseCaseNameTypeControlOfBattery, + ) + assert.Equal(s.T(), 2, len(ucs.UseCaseInformation)) + assert.Equal(s.T(), 1, len(ucs.UseCaseInformation[0].UseCaseSupport)) + + ucs.RemoveUseCaseSupport( + address, + UseCaseActorTypeCEM, + UseCaseNameTypeEVSECommissioningAndConfiguration, + ) + assert.Equal(s.T(), 1, len(ucs.UseCaseInformation)) + + ucs.RemoveUseCaseSupport( + address, + "", + "", + ) + assert.Equal(s.T(), 1, len(ucs.UseCaseInformation)) + + invalidAddress := FeatureAddressType{ + Device: util.Ptr(AddressDeviceType("test")), + Entity: []AddressEntityType{2}, + } + ucs.RemoveUseCaseSupport( + invalidAddress, + UseCaseActorTypeCEM, + UseCaseNameTypeEVSECommissioningAndConfiguration, + ) + assert.Equal(s.T(), 1, len(ucs.UseCaseInformation)) + +} diff --git a/model/operatingconstraints.go b/model/operatingconstraints.go new file mode 100644 index 0000000..5d76048 --- /dev/null +++ b/model/operatingconstraints.go @@ -0,0 +1,143 @@ +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/model/operatingconstraints_additions.go b/model/operatingconstraints_additions.go new file mode 100644 index 0000000..7070c1b --- /dev/null +++ b/model/operatingconstraints_additions.go @@ -0,0 +1,79 @@ +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/model/operatingconstraints_additions_test.go b/model/operatingconstraints_additions_test.go new file mode 100644 index 0000000..d89ac19 --- /dev/null +++ b/model/operatingconstraints_additions_test.go @@ -0,0 +1,239 @@ +package model + +import ( + "testing" + "time" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestOperatingConstraintsInterruptListDataType_Update(t *testing.T) { + sut := OperatingConstraintsInterruptListDataType{ + OperatingConstraintsInterruptData: []OperatingConstraintsInterruptDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + IsPausable: util.Ptr(false), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + IsPausable: util.Ptr(false), + }, + }, + } + + newData := OperatingConstraintsInterruptListDataType{ + OperatingConstraintsInterruptData: []OperatingConstraintsInterruptDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + IsPausable: util.Ptr(true), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := OperatingConstraintsDurationListDataType{ + OperatingConstraintsDurationData: []OperatingConstraintsDurationDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + ActiveDurationMin: NewDurationType(1 * time.Second), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + ActiveDurationMin: NewDurationType(1 * time.Second), + }, + }, + } + + newData := OperatingConstraintsDurationListDataType{ + OperatingConstraintsDurationData: []OperatingConstraintsDurationDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + ActiveDurationMin: NewDurationType(10 * time.Second), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := OperatingConstraintsPowerDescriptionListDataType{ + OperatingConstraintsPowerDescriptionData: []OperatingConstraintsPowerDescriptionDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + PositiveEnergyDirection: util.Ptr(EnergyDirectionTypeConsume), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + PositiveEnergyDirection: util.Ptr(EnergyDirectionTypeConsume), + }, + }, + } + + newData := OperatingConstraintsPowerDescriptionListDataType{ + OperatingConstraintsPowerDescriptionData: []OperatingConstraintsPowerDescriptionDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + PositiveEnergyDirection: util.Ptr(EnergyDirectionTypeProduce), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, EnergyDirectionTypeConsume, *item1.PositiveEnergyDirection) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.SequenceId)) + assert.Equal(t, EnergyDirectionTypeProduce, *item2.PositiveEnergyDirection) +} + +func TestOperatingConstraintsPowerRangeListDataType_Update(t *testing.T) { + sut := OperatingConstraintsPowerRangeListDataType{ + OperatingConstraintsPowerRangeData: []OperatingConstraintsPowerRangeDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + PowerMin: NewScaledNumberType(1), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + PowerMin: NewScaledNumberType(1), + }, + }, + } + + newData := OperatingConstraintsPowerRangeListDataType{ + OperatingConstraintsPowerRangeData: []OperatingConstraintsPowerRangeDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + PowerMin: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := OperatingConstraintsPowerLevelListDataType{ + OperatingConstraintsPowerLevelData: []OperatingConstraintsPowerLevelDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + Power: NewScaledNumberType(1), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + Power: NewScaledNumberType(1), + }, + }, + } + + newData := OperatingConstraintsPowerLevelListDataType{ + OperatingConstraintsPowerLevelData: []OperatingConstraintsPowerLevelDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + Power: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := OperatingConstraintsResumeImplicationListDataType{ + OperatingConstraintsResumeImplicationData: []OperatingConstraintsResumeImplicationDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + ResumeEnergyEstimated: NewScaledNumberType(1), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + ResumeEnergyEstimated: NewScaledNumberType(1), + }, + }, + } + + newData := OperatingConstraintsResumeImplicationListDataType{ + OperatingConstraintsResumeImplicationData: []OperatingConstraintsResumeImplicationDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + ResumeEnergyEstimated: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/powersequences.go b/model/powersequences.go new file mode 100644 index 0000000..8ac515e --- /dev/null +++ b/model/powersequences.go @@ -0,0 +1,331 @@ +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/model/powersequences_additions.go b/model/powersequences_additions.go new file mode 100644 index 0000000..f232959 --- /dev/null +++ b/model/powersequences_additions.go @@ -0,0 +1,131 @@ +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/model/powersequences_additions_test.go b/model/powersequences_additions_test.go new file mode 100644 index 0000000..82359c5 --- /dev/null +++ b/model/powersequences_additions_test.go @@ -0,0 +1,391 @@ +package model + +import ( + "testing" + "time" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestPowerTimeSlotScheduleListDataType_Update(t *testing.T) { + sut := PowerTimeSlotScheduleListDataType{ + PowerTimeSlotScheduleData: []PowerTimeSlotScheduleDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + SlotActivated: util.Ptr(false), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + SlotActivated: util.Ptr(false), + }, + }, + } + + newData := PowerTimeSlotScheduleListDataType{ + PowerTimeSlotScheduleData: []PowerTimeSlotScheduleDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + SlotActivated: util.Ptr(true), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := PowerTimeSlotValueListDataType{ + PowerTimeSlotValueData: []PowerTimeSlotValueDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + Value: NewScaledNumberType(1), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + Value: NewScaledNumberType(1), + }, + }, + } + + newData := PowerTimeSlotValueListDataType{ + PowerTimeSlotValueData: []PowerTimeSlotValueDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + Value: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := PowerTimeSlotScheduleConstraintsListDataType{ + PowerTimeSlotScheduleConstraintsData: []PowerTimeSlotScheduleConstraintsDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + MinDuration: NewDurationType(1 * time.Second), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + MinDuration: NewDurationType(1 * time.Second), + }, + }, + } + + newData := PowerTimeSlotScheduleConstraintsListDataType{ + PowerTimeSlotScheduleConstraintsData: []PowerTimeSlotScheduleConstraintsDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + MinDuration: NewDurationType(10 * time.Second), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := PowerSequenceAlternativesRelationListDataType{ + PowerSequenceAlternativesRelationData: []PowerSequenceAlternativesRelationDataType{ + { + AlternativeId: util.Ptr(AlternativesIdType(0)), + SequenceId: []PowerSequenceIdType{0}, + }, + { + AlternativeId: util.Ptr(AlternativesIdType(1)), + SequenceId: []PowerSequenceIdType{0}, + }, + }, + } + + newData := PowerSequenceAlternativesRelationListDataType{ + PowerSequenceAlternativesRelationData: []PowerSequenceAlternativesRelationDataType{ + { + AlternativeId: util.Ptr(AlternativesIdType(1)), + SequenceId: []PowerSequenceIdType{1}, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := PowerSequenceDescriptionListDataType{ + PowerSequenceDescriptionData: []PowerSequenceDescriptionDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + PositiveEnergyDirection: util.Ptr(EnergyDirectionTypeConsume), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + PositiveEnergyDirection: util.Ptr(EnergyDirectionTypeConsume), + }, + }, + } + + newData := PowerSequenceDescriptionListDataType{ + PowerSequenceDescriptionData: []PowerSequenceDescriptionDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + PositiveEnergyDirection: util.Ptr(EnergyDirectionTypeProduce), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, EnergyDirectionTypeConsume, *item1.PositiveEnergyDirection) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.SequenceId)) + assert.Equal(t, EnergyDirectionTypeProduce, *item2.PositiveEnergyDirection) +} + +func TestPowerSequenceStateListDataType_Update(t *testing.T) { + sut := PowerSequenceStateListDataType{ + PowerSequenceStateData: []PowerSequenceStateDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + State: util.Ptr(PowerSequenceStateTypeRunning), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + State: util.Ptr(PowerSequenceStateTypeRunning), + }, + }, + } + + newData := PowerSequenceStateListDataType{ + PowerSequenceStateData: []PowerSequenceStateDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + State: util.Ptr(PowerSequenceStateTypeCompleted), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, PowerSequenceStateTypeRunning, *item1.State) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.SequenceId)) + assert.Equal(t, PowerSequenceStateTypeCompleted, *item2.State) +} + +func TestPowerSequenceScheduleListDataType_Update(t *testing.T) { + sut := PowerSequenceScheduleListDataType{ + PowerSequenceScheduleData: []PowerSequenceScheduleDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + EndTime: NewAbsoluteOrRelativeTimeType("PT2H"), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + EndTime: NewAbsoluteOrRelativeTimeType("PT2H"), + }, + }, + } + + newData := PowerSequenceScheduleListDataType{ + PowerSequenceScheduleData: []PowerSequenceScheduleDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + EndTime: NewAbsoluteOrRelativeTimeType("PT4H"), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := PowerSequenceScheduleConstraintsListDataType{ + PowerSequenceScheduleConstraintsData: []PowerSequenceScheduleConstraintsDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + EarliestEndTime: NewAbsoluteOrRelativeTimeType("PT2H"), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + EarliestEndTime: NewAbsoluteOrRelativeTimeType("PT2H"), + }, + }, + } + + newData := PowerSequenceScheduleConstraintsListDataType{ + PowerSequenceScheduleConstraintsData: []PowerSequenceScheduleConstraintsDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + EarliestEndTime: NewAbsoluteOrRelativeTimeType("PT4H"), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := PowerSequencePriceListDataType{ + PowerSequencePriceData: []PowerSequencePriceDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + Price: NewScaledNumberType(1), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + Price: NewScaledNumberType(1), + }, + }, + } + + newData := PowerSequencePriceListDataType{ + PowerSequencePriceData: []PowerSequencePriceDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + Price: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := PowerSequenceSchedulePreferenceListDataType{ + PowerSequenceSchedulePreferenceData: []PowerSequenceSchedulePreferenceDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(0)), + Cheapest: util.Ptr(false), + }, + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + Cheapest: util.Ptr(false), + }, + }, + } + + newData := PowerSequenceSchedulePreferenceListDataType{ + PowerSequenceSchedulePreferenceData: []PowerSequenceSchedulePreferenceDataType{ + { + SequenceId: util.Ptr(PowerSequenceIdType(1)), + Cheapest: util.Ptr(true), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/result.go b/model/result.go new file mode 100644 index 0000000..59c2bcd --- /dev/null +++ b/model/result.go @@ -0,0 +1,21 @@ +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/model/sensing.go b/model/sensing.go new file mode 100644 index 0000000..e19ba3d --- /dev/null +++ b/model/sensing.go @@ -0,0 +1,99 @@ +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/model/sensing_additions.go b/model/sensing_additions.go new file mode 100644 index 0000000..b79094d --- /dev/null +++ b/model/sensing_additions.go @@ -0,0 +1,14 @@ +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/model/setpoint.go b/model/setpoint.go new file mode 100644 index 0000000..deea519 --- /dev/null +++ b/model/setpoint.go @@ -0,0 +1,98 @@ +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"` + IsSetpointChangeable *bool `json:"isSetpointChangeable,omitempty"` + IsSetpointActive *bool `json:"isSetpointActive,omitempty"` + TimePeriod *TimePeriodType `json:"timePeriod,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"` + IsSetpointChangeable *ElementTagType `json:"isSetpointChangeable,omitempty"` + IsSetpointActive *ElementTagType `json:"isSetpointActive,omitempty"` + TimePeriod *TimePeriodElementsType `json:"timePeriod,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/model/setpoint_additions.go b/model/setpoint_additions.go new file mode 100644 index 0000000..8ab7915 --- /dev/null +++ b/model/setpoint_additions.go @@ -0,0 +1,27 @@ +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/model/setpoint_additions_test.go b/model/setpoint_additions_test.go new file mode 100644 index 0000000..254519a --- /dev/null +++ b/model/setpoint_additions_test.go @@ -0,0 +1,84 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestSetpointListDataType_Update(t *testing.T) { + sut := SetpointListDataType{ + SetpointData: []SetpointDataType{ + { + SetpointId: util.Ptr(SetpointIdType(0)), + Value: NewScaledNumberType(1), + }, + { + SetpointId: util.Ptr(SetpointIdType(1)), + Value: NewScaledNumberType(1), + }, + }, + } + + newData := SetpointListDataType{ + SetpointData: []SetpointDataType{ + { + SetpointId: util.Ptr(SetpointIdType(1)), + Value: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := SetpointDescriptionListDataType{ + SetpointDescriptionData: []SetpointDescriptionDataType{ + { + SetpointId: util.Ptr(SetpointIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + SetpointId: util.Ptr(SetpointIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := SetpointDescriptionListDataType{ + SetpointDescriptionData: []SetpointDescriptionDataType{ + { + SetpointId: util.Ptr(SetpointIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/smartenergymanagementps.go b/model/smartenergymanagementps.go new file mode 100644 index 0000000..7f95c00 --- /dev/null +++ b/model/smartenergymanagementps.go @@ -0,0 +1,104 @@ +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/model/stateinformation.go b/model/stateinformation.go new file mode 100644 index 0000000..795f303 --- /dev/null +++ b/model/stateinformation.go @@ -0,0 +1,115 @@ +package model + +type StateInformationIdType uint + +type StateInformationType string + +// union StateInformationFunctionalityType StateInformationFunctionalityType +const ( + StateInformationTypeExternalOverrideFromGrid StateInformationType = "externalOverrideFromGrid" + StateInformationTypeAutonomousGridSupport StateInformationType = "autonomousGridSupport" + StateInformationTypeIslandingMode StateInformationType = "islandingMode" + StateInformationTypeBalancing StateInformationType = "balancing" + StateInformationTypeTrickleCharging StateInformationType = "trickleCharging" + StateInformationTypeCalibration StateInformationType = "calibration" + StateInformationTypeCommissioningMissing StateInformationType = "commissioningMissing" + StateInformationTypeSleeping StateInformationType = "sleeping" + StateInformationTypeStarting StateInformationType = "starting" + StateInformationTypeMppt StateInformationType = "mppt" + StateInformationTypeThrottled StateInformationType = "throttled" + StateInformationTypeShuttingDown StateInformationType = "shuttingDown" + StateInformationTypeManualShutdown StateInformationType = "manualShutdown" + StateInformationTypeInverterDefective StateInformationType = "inverterDefective" + StateInformationTypeBatteryOvercurrentProtection StateInformationType = "batteryOvercurrentProtection" + StateInformationTypePvStringOvercurrentProtection StateInformationType = "pvStringOvercurrentProtection" + StateInformationTypeGridFault StateInformationType = "gridFault" + StateInformationTypeGroundFault StateInformationType = "groundFault" + StateInformationTypeAcDisconnected StateInformationType = "acDisconnected" + StateInformationTypeDcDisconnected StateInformationType = "dcDisconnected" + StateInformationTypeCabinetOpen StateInformationType = "cabinetOpen" + StateInformationTypeOverTemperature StateInformationType = "overTemperature" + StateInformationTypeUnderTemperature StateInformationType = "underTemperature" + StateInformationTypeFrequencyAboveLimit StateInformationType = "frequencyAboveLimit" + StateInformationTypeFrequencyBelowLimit StateInformationType = "frequencyBelowLimit" + StateInformationTypeAcVoltageAboveLimit StateInformationType = "acVoltageAboveLimit" + StateInformationTypeAcVoltageBelowLimit StateInformationType = "acVoltageBelowLimit" + StateInformationTypeDcVoltageAboveLimit StateInformationType = "dcVoltageAboveLimit" + StateInformationTypeDcVoltageBelowLimit StateInformationType = "dcVoltageBelowLimit" + StateInformationTypeHardwareTestFailure StateInformationType = "hardwareTestFailure" + StateInformationTypeGenericInternalError StateInformationType = "genericInternalError" +) + +type StateInformationFunctionalityType string + +const ( + StateInformationFunctionalityTypeExternalOverrideFromGrid StateInformationFunctionalityType = "externalOverrideFromGrid" + StateInformationFunctionalityTypeAutonomousGridSupport StateInformationFunctionalityType = "autonomousGridSupport" + StateInformationFunctionalityTypeIslandingMode StateInformationFunctionalityType = "islandingMode" + StateInformationFunctionalityTypeBalancing StateInformationFunctionalityType = "balancing" + StateInformationFunctionalityTypeTrickleCharging StateInformationFunctionalityType = "trickleCharging" + StateInformationFunctionalityTypeCalibration StateInformationFunctionalityType = "calibration" + StateInformationFunctionalityTypeCommissioningMissing StateInformationFunctionalityType = "commissioningMissing" + StateInformationFunctionalityTypeSleeping StateInformationFunctionalityType = "sleeping" + StateInformationFunctionalityTypeStarting StateInformationFunctionalityType = "starting" + StateInformationFunctionalityTypeMppt StateInformationFunctionalityType = "mppt" + StateInformationFunctionalityTypeThrottled StateInformationFunctionalityType = "throttled" + StateInformationFunctionalityTypeShuttingDown StateInformationFunctionalityType = "shuttingDown" + StateInformationFunctionalityTypeManualShutdown StateInformationFunctionalityType = "manualShutdown" +) + +type StateInformationFailureType string + +const ( + StateInformationFailureTypeInverterDefective StateInformationFailureType = "inverterDefective" + StateInformationFailureTypeBatteryOvercurrentProtection StateInformationFailureType = "batteryOvercurrentProtection" + StateInformationFailureTypePvStringOvercurrentProtection StateInformationFailureType = "pvStringOvercurrentProtection" + StateInformationFailureTypeGridFault StateInformationFailureType = "gridFault" + StateInformationFailureTypeGroundFault StateInformationFailureType = "groundFault" + StateInformationFailureTypeAcDisconnected StateInformationFailureType = "acDisconnected" + StateInformationFailureTypeDcDisconnected StateInformationFailureType = "dcDisconnected" + StateInformationFailureTypeCabinetOpen StateInformationFailureType = "cabinetOpen" + StateInformationFailureTypeOverTemperature StateInformationFailureType = "overTemperature" + StateInformationFailureTypeUnderTemperature StateInformationFailureType = "underTemperature" + StateInformationFailureTypeFrequencyAboveLimit StateInformationFailureType = "frequencyAboveLimit" + StateInformationFailureTypeFrequencyBelowLimit StateInformationFailureType = "frequencyBelowLimit" + StateInformationFailureTypeAcVoltageAboveLimit StateInformationFailureType = "acVoltageAboveLimit" + StateInformationFailureTypeAcVoltageBelowLimit StateInformationFailureType = "acVoltageBelowLimit" + StateInformationFailureTypeDcVoltageAboveLimit StateInformationFailureType = "dcVoltageAboveLimit" + StateInformationFailureTypeDcVoltageBelowLimit StateInformationFailureType = "dcVoltageBelowLimit" + StateInformationFailureTypeHardwareTestFailure StateInformationFailureType = "hardwareTestFailure" + StateInformationFailureTypeGenericInternalError StateInformationFailureType = "genericInternalError" +) + +type StateInformationCategoryType string + +const ( + StateInformationCategoryTypeFunctionality StateInformationCategoryType = "functionality" + StateInformationCategoryTypeFailure StateInformationCategoryType = "failure" +) + +type StateInformationDataType struct { + StateInformationId *StateInformationIdType `json:"stateInformationId,omitempty" eebus:"key"` + StateInformation *StateInformationType `json:"stateInformation,omitempty"` + IsActive *bool `json:"isActive,omitempty"` + Category *StateInformationCategoryType `json:"category,omitempty"` + TimeOfLastChange *AbsoluteOrRelativeTimeType `json:"timeOfLastChange,omitempty"` +} + +type StateInformationDataElementsType struct { + StateInformationId *ElementTagType `json:"stateInformationId,omitempty"` + StateInformation *ElementTagType `json:"stateInformation,omitempty"` + IsActive *ElementTagType `json:"isActive,omitempty"` + Category *ElementTagType `json:"category,omitempty"` + TimeOfLastChange *ElementTagType `json:"timeOfLastChange,omitempty"` +} + +type StateInformationListDataType struct { + StateInformationData []StateInformationDataType `json:"stateInformationData,omitempty"` +} + +type StateInformationListDataSelectorsType struct { + StateInformationId *StateInformationIdType `json:"stateInformationId,omitempty"` + StateInformation *StateInformationType `json:"stateInformation,omitempty"` + IsActive *bool `json:"isActive,omitempty"` + Category *StateInformationCategoryType `json:"category,omitempty"` +} diff --git a/model/stateinformation_additions.go b/model/stateinformation_additions.go new file mode 100644 index 0000000..458e497 --- /dev/null +++ b/model/stateinformation_additions.go @@ -0,0 +1,14 @@ +package model + +// StateInformationListDataType + +var _ Updater = (*StateInformationListDataType)(nil) + +func (r *StateInformationListDataType) UpdateList(newList any, filterPartial, filterDelete *FilterType) { + var newData []StateInformationDataType + if newList != nil { + newData = newList.(*StateInformationListDataType).StateInformationData + } + + r.StateInformationData = UpdateList(r.StateInformationData, newData, filterPartial, filterDelete) +} diff --git a/model/subscriptionmanagement.go b/model/subscriptionmanagement.go new file mode 100644 index 0000000..d571400 --- /dev/null +++ b/model/subscriptionmanagement.go @@ -0,0 +1,53 @@ +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/model/subscriptionmanagement_additions.go b/model/subscriptionmanagement_additions.go new file mode 100644 index 0000000..e923d34 --- /dev/null +++ b/model/subscriptionmanagement_additions.go @@ -0,0 +1,14 @@ +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/model/subscriptionmanagement_additions_test.go b/model/subscriptionmanagement_additions_test.go new file mode 100644 index 0000000..0febcf3 --- /dev/null +++ b/model/subscriptionmanagement_additions_test.go @@ -0,0 +1,46 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestSubscriptionManagementEntryListDataType_Update(t *testing.T) { + sut := SubscriptionManagementEntryListDataType{ + SubscriptionManagementEntryData: []SubscriptionManagementEntryDataType{ + { + SubscriptionId: util.Ptr(SubscriptionIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + SubscriptionId: util.Ptr(SubscriptionIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := SubscriptionManagementEntryListDataType{ + SubscriptionManagementEntryData: []SubscriptionManagementEntryDataType{ + { + SubscriptionId: util.Ptr(SubscriptionIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/supplyconditions.go b/model/supplyconditions.go new file mode 100644 index 0000000..91cbf63 --- /dev/null +++ b/model/supplyconditions.go @@ -0,0 +1,112 @@ +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/model/supplyconditions_additions.go b/model/supplyconditions_additions.go new file mode 100644 index 0000000..70aa92e --- /dev/null +++ b/model/supplyconditions_additions.go @@ -0,0 +1,40 @@ +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/model/supplyconditions_additions_test.go b/model/supplyconditions_additions_test.go new file mode 100644 index 0000000..38a283a --- /dev/null +++ b/model/supplyconditions_additions_test.go @@ -0,0 +1,122 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestSupplyConditionListDataType_Update(t *testing.T) { + sut := SupplyConditionListDataType{ + SupplyConditionData: []SupplyConditionDataType{ + { + ConditionId: util.Ptr(ConditionIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + ConditionId: util.Ptr(ConditionIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := SupplyConditionListDataType{ + SupplyConditionData: []SupplyConditionDataType{ + { + ConditionId: util.Ptr(ConditionIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := SupplyConditionDescriptionListDataType{ + SupplyConditionDescriptionData: []SupplyConditionDescriptionDataType{ + { + ConditionId: util.Ptr(ConditionIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + ConditionId: util.Ptr(ConditionIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := SupplyConditionDescriptionListDataType{ + SupplyConditionDescriptionData: []SupplyConditionDescriptionDataType{ + { + ConditionId: util.Ptr(ConditionIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := SupplyConditionThresholdRelationListDataType{ + SupplyConditionThresholdRelationData: []SupplyConditionThresholdRelationDataType{ + { + ConditionId: util.Ptr(ConditionIdType(0)), + ThresholdId: []ThresholdIdType{0}, + }, + { + ConditionId: util.Ptr(ConditionIdType(1)), + ThresholdId: []ThresholdIdType{0}, + }, + }, + } + + newData := SupplyConditionThresholdRelationListDataType{ + SupplyConditionThresholdRelationData: []SupplyConditionThresholdRelationDataType{ + { + ConditionId: util.Ptr(ConditionIdType(1)), + ThresholdId: []ThresholdIdType{1}, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/tariffinformation.go b/model/tariffinformation.go new file mode 100644 index 0000000..9e2155a --- /dev/null +++ b/model/tariffinformation.go @@ -0,0 +1,370 @@ +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/model/tariffinformation_additions.go b/model/tariffinformation_additions.go new file mode 100644 index 0000000..e05e5a7 --- /dev/null +++ b/model/tariffinformation_additions.go @@ -0,0 +1,157 @@ +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/model/tariffinformation_additions_test.go b/model/tariffinformation_additions_test.go new file mode 100644 index 0000000..c3dcb4a --- /dev/null +++ b/model/tariffinformation_additions_test.go @@ -0,0 +1,464 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestTariffListDataType_Update(t *testing.T) { + sut := TariffListDataType{ + TariffData: []TariffDataType{ + { + TariffId: util.Ptr(TariffIdType(0)), + ActiveTierId: []TierIdType{0}, + }, + { + TariffId: util.Ptr(TariffIdType(1)), + ActiveTierId: []TierIdType{0}, + }, + }, + } + + newData := TariffListDataType{ + TariffData: []TariffDataType{ + { + TariffId: util.Ptr(TariffIdType(1)), + ActiveTierId: []TierIdType{1}, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := TariffTierRelationListDataType{ + TariffTierRelationData: []TariffTierRelationDataType{ + { + TariffId: util.Ptr(TariffIdType(0)), + TierId: []TierIdType{0}, + }, + { + TariffId: util.Ptr(TariffIdType(1)), + TierId: []TierIdType{0}, + }, + }, + } + + newData := TariffTierRelationListDataType{ + TariffTierRelationData: []TariffTierRelationDataType{ + { + TariffId: util.Ptr(TariffIdType(1)), + TierId: []TierIdType{1}, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := TariffBoundaryRelationListDataType{ + TariffBoundaryRelationData: []TariffBoundaryRelationDataType{ + { + TariffId: util.Ptr(TariffIdType(0)), + BoundaryId: []TierBoundaryIdType{0}, + }, + { + TariffId: util.Ptr(TariffIdType(1)), + BoundaryId: []TierBoundaryIdType{0}, + }, + }, + } + + newData := TariffBoundaryRelationListDataType{ + TariffBoundaryRelationData: []TariffBoundaryRelationDataType{ + { + TariffId: util.Ptr(TariffIdType(1)), + BoundaryId: []TierBoundaryIdType{1}, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := TariffDescriptionListDataType{ + TariffDescriptionData: []TariffDescriptionDataType{ + { + TariffId: util.Ptr(TariffIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + TariffId: util.Ptr(TariffIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := TariffDescriptionListDataType{ + TariffDescriptionData: []TariffDescriptionDataType{ + { + TariffId: util.Ptr(TariffIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := TierBoundaryListDataType{ + TierBoundaryData: []TierBoundaryDataType{ + { + BoundaryId: util.Ptr(TierBoundaryIdType(0)), + LowerBoundaryValue: NewScaledNumberType(1), + }, + { + BoundaryId: util.Ptr(TierBoundaryIdType(1)), + LowerBoundaryValue: NewScaledNumberType(1), + }, + }, + } + + newData := TierBoundaryListDataType{ + TierBoundaryData: []TierBoundaryDataType{ + { + BoundaryId: util.Ptr(TierBoundaryIdType(1)), + LowerBoundaryValue: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := TierBoundaryDescriptionListDataType{ + TierBoundaryDescriptionData: []TierBoundaryDescriptionDataType{ + { + BoundaryId: util.Ptr(TierBoundaryIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + BoundaryId: util.Ptr(TierBoundaryIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := TierBoundaryDescriptionListDataType{ + TierBoundaryDescriptionData: []TierBoundaryDescriptionDataType{ + { + BoundaryId: util.Ptr(TierBoundaryIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := CommodityListDataType{ + CommodityData: []CommodityDataType{ + { + CommodityId: util.Ptr(CommodityIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + CommodityId: util.Ptr(CommodityIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := CommodityListDataType{ + CommodityData: []CommodityDataType{ + { + CommodityId: util.Ptr(CommodityIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := TierListDataType{ + TierData: []TierDataType{ + { + TierId: util.Ptr(TierIdType(0)), + ActiveIncentiveId: []IncentiveIdType{0}, + }, + { + TierId: util.Ptr(TierIdType(1)), + ActiveIncentiveId: []IncentiveIdType{0}, + }, + }, + } + + newData := TierListDataType{ + TierData: []TierDataType{ + { + TierId: util.Ptr(TierIdType(1)), + ActiveIncentiveId: []IncentiveIdType{1}, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := TierIncentiveRelationListDataType{ + TierIncentiveRelationData: []TierIncentiveRelationDataType{ + { + TierId: util.Ptr(TierIdType(0)), + IncentiveId: []IncentiveIdType{0}, + }, + { + TierId: util.Ptr(TierIdType(1)), + IncentiveId: []IncentiveIdType{0}, + }, + }, + } + + newData := TierIncentiveRelationListDataType{ + TierIncentiveRelationData: []TierIncentiveRelationDataType{ + { + TierId: util.Ptr(TierIdType(1)), + IncentiveId: []IncentiveIdType{1}, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := TierDescriptionListDataType{ + TierDescriptionData: []TierDescriptionDataType{ + { + TierId: util.Ptr(TierIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + TierId: util.Ptr(TierIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := TierDescriptionListDataType{ + TierDescriptionData: []TierDescriptionDataType{ + { + TierId: util.Ptr(TierIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := IncentiveListDataType{ + IncentiveData: []IncentiveDataType{ + { + IncentiveId: util.Ptr(IncentiveIdType(0)), + Value: NewScaledNumberType(1), + }, + { + IncentiveId: util.Ptr(IncentiveIdType(1)), + Value: NewScaledNumberType(1), + }, + }, + } + + newData := IncentiveListDataType{ + IncentiveData: []IncentiveDataType{ + { + IncentiveId: util.Ptr(IncentiveIdType(1)), + Value: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := IncentiveDescriptionListDataType{ + IncentiveDescriptionData: []IncentiveDescriptionDataType{ + { + IncentiveId: util.Ptr(IncentiveIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + IncentiveId: util.Ptr(IncentiveIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := IncentiveDescriptionListDataType{ + IncentiveDescriptionData: []IncentiveDescriptionDataType{ + { + IncentiveId: util.Ptr(IncentiveIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/taskmanagement.go b/model/taskmanagement.go new file mode 100644 index 0000000..73886d3 --- /dev/null +++ b/model/taskmanagement.go @@ -0,0 +1,159 @@ +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/model/taskmanagement_additions.go b/model/taskmanagement_additions.go new file mode 100644 index 0000000..966b31c --- /dev/null +++ b/model/taskmanagement_additions.go @@ -0,0 +1,40 @@ +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/model/taskmanagement_additions_test.go b/model/taskmanagement_additions_test.go new file mode 100644 index 0000000..5e54881 --- /dev/null +++ b/model/taskmanagement_additions_test.go @@ -0,0 +1,128 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestTaskManagementJobListDataType_Update(t *testing.T) { + sut := TaskManagementJobListDataType{ + TaskManagementJobData: []TaskManagementJobDataType{ + { + JobId: util.Ptr(TaskManagementJobIdType(0)), + JobState: util.Ptr(TaskManagementJobStateTypeActive), + }, + { + JobId: util.Ptr(TaskManagementJobIdType(1)), + JobState: util.Ptr(TaskManagementJobStateTypeActive), + }, + }, + } + + newData := TaskManagementJobListDataType{ + TaskManagementJobData: []TaskManagementJobDataType{ + { + JobId: util.Ptr(TaskManagementJobIdType(1)), + JobState: util.Ptr(TaskManagementJobStateTypeCompleted), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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, TaskManagementJobStateTypeActive, *item1.JobState) + // check properties of updated item + item2 := data[1] + assert.Equal(t, 1, int(*item2.JobId)) + assert.Equal(t, TaskManagementJobStateTypeCompleted, *item2.JobState) +} + +func TestTaskManagementJobRelationListDataType_Update(t *testing.T) { + sut := TaskManagementJobRelationListDataType{ + TaskManagementJobRelationData: []TaskManagementJobRelationDataType{ + { + JobId: util.Ptr(TaskManagementJobIdType(0)), + LoadControlReleated: &TaskManagementLoadControlReleatedType{ + EventId: util.Ptr(LoadControlEventIdType(0)), + }, + }, + { + JobId: util.Ptr(TaskManagementJobIdType(1)), + LoadControlReleated: &TaskManagementLoadControlReleatedType{ + EventId: util.Ptr(LoadControlEventIdType(0)), + }, + }, + }, + } + + newData := TaskManagementJobRelationListDataType{ + TaskManagementJobRelationData: []TaskManagementJobRelationDataType{ + { + JobId: util.Ptr(TaskManagementJobIdType(1)), + LoadControlReleated: &TaskManagementLoadControlReleatedType{ + EventId: util.Ptr(LoadControlEventIdType(1)), + }, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := TaskManagementJobDescriptionListDataType{ + TaskManagementJobDescriptionData: []TaskManagementJobDescriptionDataType{ + { + JobId: util.Ptr(TaskManagementJobIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + JobId: util.Ptr(TaskManagementJobIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := TaskManagementJobDescriptionListDataType{ + TaskManagementJobDescriptionData: []TaskManagementJobDescriptionDataType{ + { + JobId: util.Ptr(TaskManagementJobIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/threshold.go b/model/threshold.go new file mode 100644 index 0000000..574bbf5 --- /dev/null +++ b/model/threshold.go @@ -0,0 +1,85 @@ +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/model/threshold_additions.go b/model/threshold_additions.go new file mode 100644 index 0000000..0729922 --- /dev/null +++ b/model/threshold_additions.go @@ -0,0 +1,40 @@ +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/model/threshold_additions_test.go b/model/threshold_additions_test.go new file mode 100644 index 0000000..270b6b0 --- /dev/null +++ b/model/threshold_additions_test.go @@ -0,0 +1,122 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestThresholdListDataType_Update(t *testing.T) { + sut := ThresholdListDataType{ + ThresholdData: []ThresholdDataType{ + { + ThresholdId: util.Ptr(ThresholdIdType(0)), + ThresholdValue: NewScaledNumberType(1), + }, + { + ThresholdId: util.Ptr(ThresholdIdType(1)), + ThresholdValue: NewScaledNumberType(1), + }, + }, + } + + newData := ThresholdListDataType{ + ThresholdData: []ThresholdDataType{ + { + ThresholdId: util.Ptr(ThresholdIdType(1)), + ThresholdValue: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := ThresholdConstraintsListDataType{ + ThresholdConstraintsData: []ThresholdConstraintsDataType{ + { + ThresholdId: util.Ptr(ThresholdIdType(0)), + ThresholdRangeMin: NewScaledNumberType(1), + }, + { + ThresholdId: util.Ptr(ThresholdIdType(1)), + ThresholdRangeMin: NewScaledNumberType(1), + }, + }, + } + + newData := ThresholdConstraintsListDataType{ + ThresholdConstraintsData: []ThresholdConstraintsDataType{ + { + ThresholdId: util.Ptr(ThresholdIdType(1)), + ThresholdRangeMin: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := ThresholdDescriptionListDataType{ + ThresholdDescriptionData: []ThresholdDescriptionDataType{ + { + ThresholdId: util.Ptr(ThresholdIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + ThresholdId: util.Ptr(ThresholdIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := ThresholdDescriptionListDataType{ + ThresholdDescriptionData: []ThresholdDescriptionDataType{ + { + ThresholdId: util.Ptr(ThresholdIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/timeinformation.go b/model/timeinformation.go new file mode 100644 index 0000000..1d8e606 --- /dev/null +++ b/model/timeinformation.go @@ -0,0 +1,41 @@ +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/model/timeseries.go b/model/timeseries.go new file mode 100644 index 0000000..91cae18 --- /dev/null +++ b/model/timeseries.go @@ -0,0 +1,133 @@ +package model + +type TimeSeriesIdType uint + +type TimeSeriesSlotIdType uint + +type TimeSeriesSlotCountType TimeSeriesSlotIdType + +type TimeSeriesTypeType string + +const ( + TimeSeriesTypeTypePlan TimeSeriesTypeType = "plan" + TimeSeriesTypeTypeSingleDemand TimeSeriesTypeType = "singleDemand" + TimeSeriesTypeTypeConstraints TimeSeriesTypeType = "constraints" + TimeSeriesTypeTypeEnergyRequest TimeSeriesTypeType = "energyRequest" + TimeSeriesTypeTypeDischargingEnergyRequest TimeSeriesTypeType = "dischargingEnergyRequest" + TimeSeriesTypeTypeConsumptionLimitCurve TimeSeriesTypeType = "consumptionLimitCurve" + TimeSeriesTypeTypeProductionLimitCurve TimeSeriesTypeType = "productionLimitCurve" +) + +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/model/timeseries_additions.go b/model/timeseries_additions.go new file mode 100644 index 0000000..06c1f79 --- /dev/null +++ b/model/timeseries_additions.go @@ -0,0 +1,40 @@ +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/model/timeseries_additions_test.go b/model/timeseries_additions_test.go new file mode 100644 index 0000000..5c6262a --- /dev/null +++ b/model/timeseries_additions_test.go @@ -0,0 +1,239 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestTimeSeriesListDataType_Update(t *testing.T) { + sut := TimeSeriesListDataType{ + TimeSeriesData: []TimeSeriesDataType{ + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(0)), + TimeSeriesSlot: []TimeSeriesSlotType{ + { + TimeSeriesSlotId: util.Ptr(TimeSeriesSlotIdType(0)), + }, + }, + }, + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(1)), + TimeSeriesSlot: []TimeSeriesSlotType{ + { + TimeSeriesSlotId: util.Ptr(TimeSeriesSlotIdType(0)), + }, + }, + }, + }, + } + + newData := TimeSeriesListDataType{ + TimeSeriesData: []TimeSeriesDataType{ + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(1)), + TimeSeriesSlot: []TimeSeriesSlotType{ + { + TimeSeriesSlotId: util.Ptr(TimeSeriesSlotIdType(1)), + }, + }, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 TestTimeSeriesListDataType_Update_02(t *testing.T) { + sut := TimeSeriesListDataType{ + TimeSeriesData: []TimeSeriesDataType{ + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(1)), + TimePeriod: &TimePeriodType{ + StartTime: util.Ptr(AbsoluteOrRelativeTimeType("PT0S")), + EndTime: util.Ptr(AbsoluteOrRelativeTimeType("P6D")), + }, + TimeSeriesSlot: []TimeSeriesSlotType{ + { + TimeSeriesSlotId: util.Ptr(TimeSeriesSlotIdType(0)), + TimePeriod: &TimePeriodType{ + StartTime: util.Ptr(AbsoluteOrRelativeTimeType("PT0S")), + EndTime: util.Ptr(AbsoluteOrRelativeTimeType("P6D")), + }, + MaxValue: NewScaledNumberType(10000), + }, + }, + }, + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(2)), + TimePeriod: &TimePeriodType{ + StartTime: util.Ptr(AbsoluteOrRelativeTimeType("PT0S")), + }, + TimeSeriesSlot: []TimeSeriesSlotType{ + { + TimeSeriesSlotId: util.Ptr(TimeSeriesSlotIdType(0)), + Duration: util.Ptr(DurationType("P1DT6H46M33S")), + MaxValue: NewScaledNumberType(0), + }, + { + TimeSeriesSlotId: util.Ptr(TimeSeriesSlotIdType(1)), + Duration: util.Ptr(DurationType("PT7H37M53S")), + MaxValue: NewScaledNumberType(4410), + }, + { + TimeSeriesSlotId: util.Ptr(TimeSeriesSlotIdType(2)), + Duration: util.Ptr(DurationType("PT38M")), + MaxValue: NewScaledNumberType(0), + }, + { + TimeSeriesSlotId: util.Ptr(TimeSeriesSlotIdType(3)), + Duration: util.Ptr(DurationType("PT32M")), + MaxValue: NewScaledNumberType(4410), + }, + { + TimeSeriesSlotId: util.Ptr(TimeSeriesSlotIdType(4)), + Duration: util.Ptr(DurationType("P1D")), + MaxValue: NewScaledNumberType(0), + }, + }, + }, + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(3)), + TimePeriod: &TimePeriodType{ + StartTime: util.Ptr(AbsoluteOrRelativeTimeType("PT0S")), + }, + TimeSeriesSlot: []TimeSeriesSlotType{ + { + TimeSeriesSlotId: util.Ptr(TimeSeriesSlotIdType(1)), + Duration: util.Ptr(DurationType("P1DT15H24M57S")), + Value: NewScaledNumberType(44229), + MaxValue: NewScaledNumberType(49629), + }, + }, + }, + }, + } + + newData := TimeSeriesListDataType{ + TimeSeriesData: []TimeSeriesDataType{ + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(3)), + TimePeriod: &TimePeriodType{ + StartTime: util.Ptr(AbsoluteOrRelativeTimeType("PT0S")), + }, + TimeSeriesSlot: []TimeSeriesSlotType{ + { + TimeSeriesSlotId: util.Ptr(TimeSeriesSlotIdType(1)), + Duration: util.Ptr(DurationType("P1DT15H16M50S")), + Value: NewScaledNumberType(11539), + MaxValue: NewScaledNumberType(49629), + }, + }, + }, + }, + } + + // Act + sut.UpdateList(&newData, NewFilterTypePartial(), nil) + + data := sut.TimeSeriesData + // check the non changing items + assert.Equal(t, 3, len(data)) + item1 := data[0] + assert.Equal(t, 1, int(*item1.TimeSeriesId)) + assert.Equal(t, 0, int(*item1.TimeSeriesSlot[0].TimeSeriesSlotId)) + // check properties of updated item + item2 := data[2] + assert.Equal(t, 3, int(*item2.TimeSeriesId)) + assert.Equal(t, 1, int(*item2.TimeSeriesSlot[0].TimeSeriesSlotId)) + assert.Equal(t, 11539, int(item2.TimeSeriesSlot[0].Value.GetValue())) +} + +func TestTimeSeriesDescriptionListDataType_Update(t *testing.T) { + sut := TimeSeriesDescriptionListDataType{ + TimeSeriesDescriptionData: []TimeSeriesDescriptionDataType{ + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := TimeSeriesDescriptionListDataType{ + TimeSeriesDescriptionData: []TimeSeriesDescriptionDataType{ + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := TimeSeriesConstraintsListDataType{ + TimeSeriesConstraintsData: []TimeSeriesConstraintsDataType{ + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(0)), + SlotValueMin: NewScaledNumberType(1), + }, + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(1)), + SlotValueMin: NewScaledNumberType(1), + }, + }, + } + + newData := TimeSeriesConstraintsListDataType{ + TimeSeriesConstraintsData: []TimeSeriesConstraintsDataType{ + { + TimeSeriesId: util.Ptr(TimeSeriesIdType(1)), + SlotValueMin: NewScaledNumberType(10), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/timetable.go b/model/timetable.go new file mode 100644 index 0000000..2a0dbfd --- /dev/null +++ b/model/timetable.go @@ -0,0 +1,96 @@ +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/model/timetable_additions.go b/model/timetable_additions.go new file mode 100644 index 0000000..2b336b8 --- /dev/null +++ b/model/timetable_additions.go @@ -0,0 +1,40 @@ +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/model/timetable_additions_test.go b/model/timetable_additions_test.go new file mode 100644 index 0000000..8d46670 --- /dev/null +++ b/model/timetable_additions_test.go @@ -0,0 +1,128 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestTimeTableListDataType_Update(t *testing.T) { + sut := TimeTableListDataType{ + TimeTableData: []TimeTableDataType{ + { + TimeTableId: util.Ptr(TimeTableIdType(0)), + RecurrenceInformation: &RecurrenceInformationType{ + ExecutionCount: util.Ptr(uint(1)), + }, + }, + { + TimeTableId: util.Ptr(TimeTableIdType(1)), + RecurrenceInformation: &RecurrenceInformationType{ + ExecutionCount: util.Ptr(uint(1)), + }, + }, + }, + } + + newData := TimeTableListDataType{ + TimeTableData: []TimeTableDataType{ + { + TimeTableId: util.Ptr(TimeTableIdType(1)), + RecurrenceInformation: &RecurrenceInformationType{ + ExecutionCount: util.Ptr(uint(10)), + }, + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := TimeTableConstraintsListDataType{ + TimeTableConstraintsData: []TimeTableConstraintsDataType{ + { + TimeTableId: util.Ptr(TimeTableIdType(0)), + SlotCountMin: util.Ptr(TimeSlotCountType(1)), + }, + { + TimeTableId: util.Ptr(TimeTableIdType(1)), + SlotCountMin: util.Ptr(TimeSlotCountType(1)), + }, + }, + } + + newData := TimeTableConstraintsListDataType{ + TimeTableConstraintsData: []TimeTableConstraintsDataType{ + { + TimeTableId: util.Ptr(TimeTableIdType(1)), + SlotCountMin: util.Ptr(TimeSlotCountType(10)), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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 := TimeTableDescriptionListDataType{ + TimeTableDescriptionData: []TimeTableDescriptionDataType{ + { + TimeTableId: util.Ptr(TimeTableIdType(0)), + Description: util.Ptr(DescriptionType("old")), + }, + { + TimeTableId: util.Ptr(TimeTableIdType(1)), + Description: util.Ptr(DescriptionType("old")), + }, + }, + } + + newData := TimeTableDescriptionListDataType{ + TimeTableDescriptionData: []TimeTableDescriptionDataType{ + { + TimeTableId: util.Ptr(TimeTableIdType(1)), + Description: util.Ptr(DescriptionType("new")), + }, + }, + } + + // Act + sut.UpdateList(&newData, 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/model/update.go b/model/update.go new file mode 100644 index 0000000..f408070 --- /dev/null +++ b/model/update.go @@ -0,0 +1,301 @@ +package model + +import ( + "reflect" + "sort" + + "github.com/enbility/spine-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) + + if v.Kind() != reflect.Struct { + return result + } + + 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/model/update_test.go b/model/update_test.go new file mode 100644 index 0000000..bc25f08 --- /dev/null +++ b/model/update_test.go @@ -0,0 +1,120 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-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 := 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 := 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 := 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 := UpdateList(existingData, newData, nil, nil) + + assert.Equal(t, expectedResult, result) +} + +func TestRemoveFieldFromType(t *testing.T) { + items := &LoadControlLimitListDataType{ + LoadControlLimitData: []LoadControlLimitDataType{ + { + LimitId: util.Ptr(LoadControlLimitIdType(1)), + Value: NewScaledNumberType(16.0), + }, + }, + } + + elements := &LoadControlLimitDataElementsType{ + Value: &ScaledNumberElementsType{}, + } + + RemoveElementFromItem(&items.LoadControlLimitData[0], elements) + + var nilValue *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 := 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 := UpdateList[TestUpdateData](existingData, newData, dataProvider) + + assert.Equal(t, expectedResult, result) +} +*/ diff --git a/model/usecaseinformation.go b/model/usecaseinformation.go new file mode 100644 index 0000000..4fcb86f --- /dev/null +++ b/model/usecaseinformation.go @@ -0,0 +1,118 @@ +package model + +type UseCaseActorType string + +const ( + UseCaseActorTypeBattery UseCaseActorType = "Battery" + UseCaseActorTypeBatterySystem UseCaseActorType = "BatterySystem" + UseCaseActorTypeCEM UseCaseActorType = "CEM" + UseCaseActorTypeConfigurationAppliance UseCaseActorType = "ConfigurationAppliance" + UseCaseActorTypeCompressor UseCaseActorType = "Compressor" + UseCaseActorTypeControllableSystem UseCaseActorType = "ControllableSystem" + UseCaseActorTypeDHWCircuit UseCaseActorType = "DHWCircuit" + UseCaseActorTypeEnergyBroker UseCaseActorType = "EnergyBroker" + UseCaseActorTypeEnergyConsumer UseCaseActorType = "EnergyConsumer" + UseCaseActorTypeEnergyGuard UseCaseActorType = "EnergyGuard" + UseCaseActorTypeEVSE UseCaseActorType = "EVSE" + UseCaseActorTypeEV UseCaseActorType = "EV" + UseCaseActorTypeGridConnectionPoint UseCaseActorType = "GridConnectionPoint" + UseCaseActorTypeHeatPump UseCaseActorType = "HeatPump" + UseCaseActorTypeHeatingCircuit UseCaseActorType = "HeatingCircuit" + UseCaseActorTypeHeatingZone UseCaseActorType = "HeatingZone" + UseCaseActorTypeHVACRoom UseCaseActorType = "HVACRoom" + UseCaseActorTypeInverter UseCaseActorType = "Inverter" + UseCaseActorTypeMonitoredUnit UseCaseActorType = "MonitoredUnit" + UseCaseActorTypeMonitoringAppliance UseCaseActorType = "MonitoringAppliance" + UseCaseActorTypeOutdoorTemperatureSensor UseCaseActorType = "OutdoorTemperatureSensor" + UseCaseActorTypePVString UseCaseActorType = "PVString" + UseCaseActorTypePVSystem UseCaseActorType = "PVSystem" + UseCaseActorTypeSmartAppliance UseCaseActorType = "SmartAppliance" + 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" + UseCaseNameTypeFlexibleLoad UseCaseNameType = "flexibleLoad" + UseCaseNameTypeFlexibleStartForWhiteGoods UseCaseNameType = "flexibleStartForWhiteGoods" + 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"` + UseCaseDocumentSubRevision *string `json:"useCaseDocumentSubRevision,omitempty"` +} + +type UseCaseSupportElementsType struct { + UseCaseName *ElementTagType `json:"useCaseName,omitempty"` + UseCaseVersion *ElementTagType `json:"useCaseVersion,omitempty"` + UseCaseAvailable *ElementTagType `json:"useCaseAvailable,omitempty"` + ScenarioSupport *ElementTagType `json:"scenarioSupport,omitempty"` + UseCaseDocumentSubRevision *ElementTagType `json:"useCaseDocumentSubRevision,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/model/usecaseinformation_additions.go b/model/usecaseinformation_additions.go new file mode 100644 index 0000000..d30bc5a --- /dev/null +++ b/model/usecaseinformation_additions.go @@ -0,0 +1,53 @@ +package model + +import "sync" + +var uciMux sync.Mutex + +// UseCaseInformationDataType + +// find the matching UseCaseSupport index for a UseCaseNameType +func (u *UseCaseInformationDataType) useCaseSupportIndex(useCaseName UseCaseNameType) (int, bool) { + // get the element with the same entity + for index, item := range u.UseCaseSupport { + if item.UseCaseName != nil && *item.UseCaseName == useCaseName { + return index, true + } + } + + return -1, false +} + +// add a new UseCaseSupportType +func (u *UseCaseInformationDataType) Add(useCase UseCaseSupportType) { + uciMux.Lock() + defer uciMux.Unlock() + + if useCase.UseCaseName == nil { + return + } + + // only add it if it does not exist yet + if _, ok := u.useCaseSupportIndex(*useCase.UseCaseName); ok { + return + } + + u.UseCaseSupport = append(u.UseCaseSupport, useCase) +} + +// remove a UseCaseSupportType with a given UseCaseNameType +func (u *UseCaseInformationDataType) Remove(useCaseName UseCaseNameType) { + uciMux.Lock() + defer uciMux.Unlock() + + var usecases []UseCaseSupportType + + for _, item := range u.UseCaseSupport { + if item.UseCaseName != nil && *item.UseCaseName != useCaseName { + usecases = append(usecases, item) + } + + } + + u.UseCaseSupport = usecases +} diff --git a/model/usecaseinformation_additions_test.go b/model/usecaseinformation_additions_test.go new file mode 100644 index 0000000..3beadb6 --- /dev/null +++ b/model/usecaseinformation_additions_test.go @@ -0,0 +1,47 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestUseCaseInformationDataTypeSuite(t *testing.T) { + suite.Run(t, new(UseCaseInformationDataTypeSuite)) +} + +type UseCaseInformationDataTypeSuite struct { + suite.Suite +} + +func (s *UseCaseInformationDataTypeSuite) SetupSuite() {} +func (s *UseCaseInformationDataTypeSuite) TearDownTest() {} + +func (s *UseCaseInformationDataTypeSuite) BeforeTest(suiteName, testName string) {} + +func (s *UseCaseInformationDataTypeSuite) Test_AdditionsAndRemovals() { + ucs := &UseCaseInformationDataType{} + assert.NotNil(s.T(), ucs) + assert.Equal(s.T(), 0, len(ucs.UseCaseSupport)) + + uc := UseCaseSupportType{} + ucs.Add(uc) + assert.Equal(s.T(), 0, len(ucs.UseCaseSupport)) + + uc = UseCaseSupportType{ + UseCaseName: util.Ptr(UseCaseNameTypeControlOfBattery), + } + ucs.Add(uc) + assert.Equal(s.T(), 1, len(ucs.UseCaseSupport)) + + ucs.Add(uc) + assert.Equal(s.T(), 1, len(ucs.UseCaseSupport)) + + ucs.Remove(UseCaseNameTypeCoordinatedEVCharging) + assert.Equal(s.T(), 1, len(ucs.UseCaseSupport)) + + ucs.Remove(UseCaseNameTypeControlOfBattery) + assert.Equal(s.T(), 0, len(ucs.UseCaseSupport)) +} diff --git a/model/usecaseinformation_additions_test.go_temp b/model/usecaseinformation_additions_test.go_temp new file mode 100644 index 0000000..a0a8b66 --- /dev/null +++ b/model/usecaseinformation_additions_test.go_temp @@ -0,0 +1,86 @@ +package model + +import ( + "testing" + + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestUsecaseInformationSuite(t *testing.T) { + suite.Run(t, new(UsecaseInformationSuite)) +} + +type UsecaseInformationSuite struct { + suite.Suite +} + +func (s *UsecaseInformationSuite) SetupSuite() {} +func (s *UsecaseInformationSuite) TearDownTest() {} + +func (s *UsecaseInformationSuite) BeforeTest(suiteName, testName string) {} + +func (s *UsecaseInformationSuite) Test_UpdateList() { + sut := UseCaseInformationListDataType{ + UseCaseInformationData: []UseCaseInformationDataType{ + { + Actor: util.Ptr(UseCaseActorTypeEVSE), + UseCaseSupport: []UseCaseSupportType{ + { + UseCaseName: util.Ptr(UseCaseNameTypeEVSECommissioningAndConfiguration), + UseCaseVersion: util.Ptr(SpecificationVersionType("1.0.0")), + UseCaseAvailable: util.Ptr(true), + ScenarioSupport: []UseCaseScenarioSupportType{ + 1, 2, 3, 4, 5, + }, + }, + }, + }, + }, + } + + newData := UseCaseInformationListDataType{ + UseCaseInformationData: []UseCaseInformationDataType{ + { + Actor: util.Ptr(UseCaseActorTypeEVSE), + UseCaseSupport: []UseCaseSupportType{ + { + UseCaseName: util.Ptr(UseCaseNameTypeEVSECommissioningAndConfiguration), + UseCaseVersion: util.Ptr(SpecificationVersionType("1.0.1")), + UseCaseAvailable: util.Ptr(true), + ScenarioSupport: []UseCaseScenarioSupportType{ + 1, 2, 3, 4, 5, + }, + }, + }, + }, + { + Actor: util.Ptr(UseCaseActorTypeEV), + UseCaseSupport: []UseCaseSupportType{ + { + UseCaseName: util.Ptr(UseCaseNameTypeEVCommissioningAndConfiguration), + UseCaseVersion: util.Ptr(SpecificationVersionType("1.0.0")), + UseCaseAvailable: util.Ptr(true), + ScenarioSupport: []UseCaseScenarioSupportType{ + 1, 2, 3, 4, 5, + }, + }, + }, + }, + }, + } + + data := sut.UseCaseInformationData + // check properties of updated item + item1 := data[0] + assert.NotNil(s.T(), item1) + + // Act + sut.UpdateList(&newData, NewFilterTypePartial(), nil) + + data = sut.UseCaseInformationData + // check properties of updated item + item1 = data[0] + assert.NotNil(s.T(), item1) +} diff --git a/model/version.go b/model/version.go new file mode 100644 index 0000000..f592077 --- /dev/null +++ b/model/version.go @@ -0,0 +1,11 @@ +package model + +type SpecificationVersionDataType SpecificationVersionType + +type SpecificationVersionDataElementsType struct{} + +type SpecificationVersionListDataType struct { + SpecificationVersionData []SpecificationVersionDataType `json:"specificationVersionData,omitempty"` +} + +type SpecificationVersionListDataSelectorsType struct{} diff --git a/model/version_additions.go b/model/version_additions.go new file mode 100644 index 0000000..9c96c82 --- /dev/null +++ b/model/version_additions.go @@ -0,0 +1,14 @@ +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/model/version_additions_test.go b/model/version_additions_test.go new file mode 100644 index 0000000..7cf49df --- /dev/null +++ b/model/version_additions_test.go @@ -0,0 +1,48 @@ +package model + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestVersionSuite(t *testing.T) { + suite.Run(t, new(VersionSuite)) +} + +type VersionSuite struct { + suite.Suite +} + +func (s *VersionSuite) SetupSuite() {} +func (s *VersionSuite) TearDownTest() {} + +func (s *VersionSuite) BeforeTest(suiteName, testName string) {} + +func (s *VersionSuite) Test_UpdateList() { + sut := SpecificationVersionListDataType{ + SpecificationVersionData: []SpecificationVersionDataType{ + SpecificationVersionDataType("1.0.0"), + }, + } + + newData := SpecificationVersionListDataType{ + SpecificationVersionData: []SpecificationVersionDataType{ + SpecificationVersionDataType("1.0.1"), + }, + } + + data := sut.SpecificationVersionData + // check properties of updated item + item1 := data[0] + assert.Equal(s.T(), "1.0.0", string(item1)) + + // Act + sut.UpdateList(&newData, NewFilterTypePartial(), nil) + + data = sut.SpecificationVersionData + // check properties of updated item + item1 = data[0] + assert.Equal(s.T(), "1.0.1", string(item1)) +} diff --git a/spine/binding_manager.go b/spine/binding_manager.go new file mode 100644 index 0000000..3d9031e --- /dev/null +++ b/spine/binding_manager.go @@ -0,0 +1,221 @@ +package spine + +import ( + "errors" + "fmt" + "reflect" + "sync" + "sync/atomic" + + "github.com/ahmetb/go-linq/v3" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" +) + +type BindingManagerImpl struct { + localDevice api.DeviceLocal + + bindingNum uint64 + bindingEntries []*api.BindingEntry + + mux sync.Mutex + // TODO: add persistence +} + +func NewBindingManager(localDevice api.DeviceLocal) *BindingManagerImpl { + c := &BindingManagerImpl{ + bindingNum: 0, + localDevice: localDevice, + } + + return c +} + +// is sent from the client (remote device) to the server (local device) +func (c *BindingManagerImpl) AddBinding(remoteDevice api.DeviceRemote, data model.BindingManagementRequestCallType) error { + + serverFeature := c.localDevice.FeatureByAddress(data.ServerAddress) + if serverFeature == nil { + return fmt.Errorf("server feature '%s' in local device '%s' not found", data.ServerAddress, *c.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 := &api.BindingEntry{ + Id: c.bindingId(), + ServerFeature: serverFeature, + ClientFeature: clientFeature, + } + + c.mux.Lock() + defer c.mux.Unlock() + + for _, item := range c.bindingEntries { + if reflect.DeepEqual(item.ServerFeature, serverFeature) && reflect.DeepEqual(item.ClientFeature, clientFeature) { + return fmt.Errorf("requested binding is already present") + } + } + + c.bindingEntries = append(c.bindingEntries, bindingEntry) + + payload := api.EventPayload{ + Ski: remoteDevice.Ski(), + EventType: api.EventTypeBindingChange, + ChangeType: api.ElementChangeAdd, + Data: data, + Feature: clientFeature, + } + Events.Publish(payload) + + return nil +} + +func (c *BindingManagerImpl) RemoveBinding(data model.BindingManagementDeleteCallType, remoteDevice api.DeviceRemote) error { + var newBindingEntries []*api.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. + + var clientAddress model.FeatureAddressType + util.DeepCopy(data.ClientAddress, &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()) + } + + serverFeature := c.localDevice.FeatureByAddress(data.ServerAddress) + if serverFeature == nil { + return fmt.Errorf("server feature '%s' in local device '%s' not found", data.ServerAddress, *c.localDevice.Address()) + } + + c.mux.Lock() + defer c.mux.Unlock() + + for _, item := range c.bindingEntries { + itemAddress := item.ClientFeature.Address() + + if !reflect.DeepEqual(*itemAddress, clientAddress) && + !reflect.DeepEqual(item.ServerFeature, serverFeature) { + newBindingEntries = append(newBindingEntries, item) + } + } + + if len(newBindingEntries) == len(c.bindingEntries) { + return errors.New("could not find requested BindingId to be removed") + } + + c.bindingEntries = newBindingEntries + + payload := api.EventPayload{ + Ski: remoteDevice.Ski(), + EventType: api.EventTypeBindingChange, + ChangeType: api.ElementChangeRemove, + Data: data, + Device: remoteDevice, + Feature: clientFeature, + } + Events.Publish(payload) + + return nil +} + +// Remove all existing bindings for a given remote device +func (c *BindingManagerImpl) RemoveBindingsForDevice(remoteDevice api.DeviceRemote) { + if remoteDevice == nil { + return + } + + for _, entity := range remoteDevice.Entities() { + c.RemoveBindingsForEntity(entity) + } +} + +// Remove all existing bindings for a given remote device entity +func (c *BindingManagerImpl) RemoveBindingsForEntity(remoteEntity api.EntityRemote) { + if remoteEntity == nil { + return + } + + c.mux.Lock() + defer c.mux.Unlock() + + var newBindingEntries []*api.BindingEntry + for _, item := range c.bindingEntries { + if !reflect.DeepEqual(item.ClientFeature.Address().Entity, remoteEntity.Address().Entity) { + newBindingEntries = append(newBindingEntries, item) + continue + } + + clientFeature := remoteEntity.Feature(item.ClientFeature.Address().Feature) + payload := api.EventPayload{ + Ski: remoteEntity.Device().Ski(), + EventType: api.EventTypeBindingChange, + ChangeType: api.ElementChangeRemove, + Entity: remoteEntity, + Feature: clientFeature, + } + Events.Publish(payload) + } + + c.bindingEntries = newBindingEntries +} + +func (c *BindingManagerImpl) Bindings(remoteDevice api.DeviceRemote) []*api.BindingEntry { + var result []*api.BindingEntry + + c.mux.Lock() + defer c.mux.Unlock() + + linq.From(c.bindingEntries).WhereT(func(s *api.BindingEntry) bool { + return s.ClientFeature.Device().Ski() == remoteDevice.Ski() + }).ToSlice(&result) + + return result +} + +func (c *BindingManagerImpl) BindingsOnFeature(featureAddress model.FeatureAddressType) []*api.BindingEntry { + var result []*api.BindingEntry + + c.mux.Lock() + defer c.mux.Unlock() + + linq.From(c.bindingEntries).WhereT(func(s *api.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 api.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/binding_manager_test.go b/spine/binding_manager_test.go new file mode 100644 index 0000000..daebd49 --- /dev/null +++ b/spine/binding_manager_test.go @@ -0,0 +1,109 @@ +package spine + +import ( + "testing" + "time" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestBindingManagerSuite(t *testing.T) { + suite.Run(t, new(BindingManagerSuite)) +} + +type BindingManagerSuite struct { + suite.Suite + + localDevice api.DeviceLocal + writeHandler *WriteMessageHandler + remoteDevice api.DeviceRemote + + sut api.BindingManager +} + +func (s *BindingManagerSuite) BeforeTest(suiteName, testName string) { + s.localDevice = NewDeviceLocalImpl("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode", + "TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + remoteSki := "TestRemoteSki" + + s.writeHandler = &WriteMessageHandler{} + + sender := NewSender(s.writeHandler) + s.remoteDevice = NewDeviceRemoteImpl(s.localDevice, remoteSki, sender) + + s.sut = NewBindingManager(s.localDevice) +} + +func (suite *BindingManagerSuite) Test_Bindings() { + entity := NewEntityLocalImpl(suite.localDevice, model.EntityTypeTypeCEM, []model.AddressEntityType{1}) + suite.localDevice.AddEntity(entity) + + localFeature := entity.GetOrAddFeature(model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeServer) + + remoteEntity := NewEntityRemoteImpl(suite.remoteDevice, model.EntityTypeTypeEVSE, []model.AddressEntityType{1}) + suite.remoteDevice.AddEntity(remoteEntity) + + remoteFeature := NewFeatureRemoteImpl(remoteEntity.NextFeatureId(), remoteEntity, model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeClient) + remoteFeature.Address().Device = util.Ptr(model.AddressDeviceType("remoteDevice")) + remoteEntity.AddFeature(remoteFeature) + + bindingRequest := model.BindingManagementRequestCallType{ + ClientAddress: remoteFeature.Address(), + ServerAddress: localFeature.Address(), + ServerFeatureType: util.Ptr(model.FeatureTypeTypeDeviceDiagnosis), + } + + bindingMgr := suite.localDevice.BindingManager() + err := bindingMgr.AddBinding(suite.remoteDevice, bindingRequest) + assert.Nil(suite.T(), err) + + subs := bindingMgr.Bindings(suite.remoteDevice) + assert.Equal(suite.T(), 1, len(subs)) + + err = bindingMgr.AddBinding(suite.remoteDevice, bindingRequest) + assert.NotNil(suite.T(), err) + + subs = bindingMgr.Bindings(suite.remoteDevice) + assert.Equal(suite.T(), 1, len(subs)) + + address := model.FeatureAddressType{ + Device: entity.Device().Address(), + Entity: entity.Address().Entity, + Feature: util.Ptr(model.AddressFeatureType(10)), + } + entries := bindingMgr.BindingsOnFeature(address) + assert.Equal(suite.T(), 0, len(entries)) + + address.Feature = localFeature.Address().Feature + entries = bindingMgr.BindingsOnFeature(address) + assert.Equal(suite.T(), 1, len(entries)) + + bindingDelete := model.BindingManagementDeleteCallType{ + ClientAddress: remoteFeature.Address(), + ServerAddress: localFeature.Address(), + } + + err = bindingMgr.RemoveBinding(bindingDelete, suite.remoteDevice) + assert.Nil(suite.T(), err) + + subs = bindingMgr.Bindings(suite.remoteDevice) + assert.Equal(suite.T(), 0, len(subs)) + + err = bindingMgr.RemoveBinding(bindingDelete, suite.remoteDevice) + assert.NotNil(suite.T(), err) + + err = bindingMgr.AddBinding(suite.remoteDevice, bindingRequest) + assert.Nil(suite.T(), err) + + subs = bindingMgr.Bindings(suite.remoteDevice) + assert.Equal(suite.T(), 1, len(subs)) + + bindingMgr.RemoveBindingsForDevice(suite.remoteDevice) + + subs = bindingMgr.Bindings(suite.remoteDevice) + assert.Equal(suite.T(), 0, len(subs)) +} diff --git a/spine/const.go b/spine/const.go new file mode 100644 index 0000000..9f527e3 --- /dev/null +++ b/spine/const.go @@ -0,0 +1,5 @@ +package spine + +import "github.com/enbility/spine-go/model" + +var SpecificationVersion model.SpecificationVersionType = "1.3.0" diff --git a/spine/device.go b/spine/device.go new file mode 100644 index 0000000..c730c30 --- /dev/null +++ b/spine/device.go @@ -0,0 +1,54 @@ +package spine + +import "github.com/enbility/spine-go/model" + +type DeviceImpl struct { + address *model.AddressDeviceType + dType *model.DeviceTypeType + featureSet *model.NetworkManagementFeatureSetType +} + +// 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{} + + 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) 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 new file mode 100644 index 0000000..4c831af --- /dev/null +++ b/spine/device_local.go @@ -0,0 +1,432 @@ +package spine + +import ( + "errors" + "fmt" + "reflect" + "sync" + "time" + + shipapi "github.com/enbility/ship-go/api" + "github.com/enbility/ship-go/logging" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" +) + +var _ api.DeviceLocal = (*DeviceLocalImpl)(nil) + +type DeviceLocalImpl struct { + *DeviceImpl + entities []api.EntityLocal + subscriptionManager api.SubscriptionManager + bindingManager api.BindingManager + heartbeatManager api.HeartbeatManager + nodeManagement *NodeManagementImpl + + remoteDevices map[string]api.DeviceRemote + + 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, + heartbeatTimeout time.Duration) *DeviceLocalImpl { + address := model.AddressDeviceType(deviceAddress) + + var fSet *model.NetworkManagementFeatureSetType + if len(featureSet) != 0 { + fSet = &featureSet + } + + res := &DeviceLocalImpl{ + DeviceImpl: NewDeviceImpl(&address, &deviceType, fSet), + remoteDevices: make(map[string]api.DeviceRemote), + brandName: brandName, + deviceModel: deviceModel, + serialNumber: serialNumber, + deviceCode: deviceCode, + } + + res.subscriptionManager = NewSubscriptionManager(res) + res.bindingManager = NewBindingManager(res) + res.heartbeatManager = NewHeartbeatManager(res, res.subscriptionManager, heartbeatTimeout) + + res.addDeviceInformation() + return res +} + +func (r *DeviceLocalImpl) RemoveRemoteDeviceConnection(ski string) { + remoteDevice := r.RemoteDeviceForSki(ski) + + r.RemoveRemoteDevice(ski) + + // inform about the disconnection + payload := api.EventPayload{ + Ski: ski, + EventType: api.EventTypeDeviceChange, + ChangeType: api.ElementChangeRemove, + Device: remoteDevice, + } + Events.Publish(payload) +} + +// Helper method used by tests and AddRemoteDevice +func (r *DeviceLocalImpl) AddRemoteDeviceForSki(ski string, rDevice api.DeviceRemote) { + r.mux.Lock() + r.remoteDevices[ski] = rDevice + r.mux.Unlock() +} + +// Setup a new remote device with a given SKI and triggers SPINE requesting device details +func (r *DeviceLocalImpl) SetupRemoteDevice(ski string, writeI shipapi.SpineDataConnection) shipapi.SpineDataProcessing { + sender := NewSender(writeI) + rDevice := NewDeviceRemoteImpl(r, ski, sender) + + 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(api.EventHandlerLevelCore, r) + + return rDevice +} + +// React to some specific events +func (r *DeviceLocalImpl) HandleEvent(payload api.EventPayload) { + // Subscribe to NodeManagment after DetailedDiscovery is received + if payload.EventType != api.EventTypeDeviceChange || payload.ChangeType != api.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.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 + } + + // remove all subscriptions for this device + subscriptionMgr := r.SubscriptionManager() + subscriptionMgr.RemoveSubscriptionsForDevice(r.remoteDevices[ski]) + + // make sure Heartbeat Manager is up to date + r.HeartbeatManager().UpdateHeartbeatOnSubscriptions() + + // remove all bindings for this device + bindingMgr := r.BindingManager() + bindingMgr.RemoveBindingsForDevice(r.remoteDevices[ski]) + + delete(r.remoteDevices, ski) + + // only unsubscribe if we don't have any remote devices left + if len(r.remoteDevices) == 0 { + _ = Events.unsubscribe(api.EventHandlerLevelCore, r) + } +} + +func (r *DeviceLocalImpl) RemoteDevices() []api.DeviceRemote { + r.mux.Lock() + defer r.mux.Unlock() + + res := make([]api.DeviceRemote, 0) + for _, rDevice := range r.remoteDevices { + res = append(res, rDevice) + } + + return res +} + +func (r *DeviceLocalImpl) RemoteDeviceForAddress(address model.AddressDeviceType) api.DeviceRemote { + r.mux.Lock() + defer r.mux.Unlock() + + for _, item := range r.remoteDevices { + if *item.Address() == address { + return item + } + } + + return nil +} + +func (r *DeviceLocalImpl) RemoteDeviceForSki(ski string) api.DeviceRemote { + r.mux.Lock() + defer r.mux.Unlock() + + return r.remoteDevices[ski] +} + +func (r *DeviceLocalImpl) ProcessCmd(datagram model.DatagramType, remoteDevice api.DeviceRemote) 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 := &api.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, model.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) NodeManagement() api.NodeManagement { + return r.nodeManagement +} + +func (r *DeviceLocalImpl) SubscriptionManager() api.SubscriptionManager { + return r.subscriptionManager +} + +func (r *DeviceLocalImpl) BindingManager() api.BindingManager { + return r.bindingManager +} + +func (r *DeviceLocalImpl) HeartbeatManager() api.HeartbeatManager { + return r.heartbeatManager +} + +func (r *DeviceLocalImpl) AddEntity(entity api.EntityLocal) { + r.mux.Lock() + defer r.mux.Unlock() + + r.entities = append(r.entities, entity) + + r.notifySubscribersOfEntity(entity, model.NetworkManagementStateChangeTypeAdded) +} + +func (r *DeviceLocalImpl) RemoveEntity(entity api.EntityLocal) { + entity.RemoveAllUseCaseSupports() + entity.RemoveAllSubscriptions() + entity.RemoveAllBindings() + + r.mux.Lock() + defer r.mux.Unlock() + + var entities []api.EntityLocal + for _, e := range r.entities { + if e != entity { + entities = append(entities, e) + } + } + + r.entities = entities +} + +func (r *DeviceLocalImpl) Entities() []api.EntityLocal { + r.mux.Lock() + defer r.mux.Unlock() + + return r.entities +} + +func (r *DeviceLocalImpl) Entity(id []model.AddressEntityType) api.EntityLocal { + r.mux.Lock() + defer r.mux.Unlock() + + for _, e := range r.entities { + if reflect.DeepEqual(id, e.Address().Entity) { + return e + } + } + return nil +} + +func (r *DeviceLocalImpl) EntityForType(entityType model.EntityTypeType) api.EntityLocal { + r.mux.Lock() + defer r.mux.Unlock() + + for _, e := range r.entities { + if e.EntityType() == entityType { + return e + } + } + return nil +} + +func (r *DeviceLocalImpl) FeatureByAddress(address *model.FeatureAddressType) api.FeatureLocal { + entity := r.Entity(address.Entity) + if entity != nil { + return entity.Feature(address.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 +} + +// send a notify message to all remote devices +func (r *DeviceLocalImpl) NotifyUseCaseData() { + r.mux.Lock() + defer r.mux.Unlock() + + for _, remoteDevice := range r.remoteDevices { + // TODO: add error management + _, _ = r.nodeManagement.NotifyUseCaseData(remoteDevice) + } +} + +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 api.EntityLocal, 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 new file mode 100644 index 0000000..1968fc6 --- /dev/null +++ b/spine/device_local_test.go @@ -0,0 +1,237 @@ +package spine + +import ( + "testing" + "time" + + shipapi "github.com/enbility/ship-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-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 _ shipapi.SpineDataConnection = (*DeviceLocalTestSuite)(nil) + +func (d *DeviceLocalTestSuite) WriteSpineMessage([]byte) {} + +func (d *DeviceLocalTestSuite) Test_RemoveRemoteDevice() { + sut := NewDeviceLocalImpl("brand", "model", "serial", "code", "address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + + ski := "test" + _ = sut.SetupRemoteDevice(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 := NewDeviceLocalImpl("brand", "model", "serial", "code", "address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + localEntity := NewEntityLocalImpl(sut, model.EntityTypeTypeCEM, NewAddressEntityType([]uint{1})) + sut.AddEntity(localEntity) + + f := NewFeatureLocalImpl(1, localEntity, model.FeatureTypeTypeElectricalConnection, model.RoleTypeClient) + localEntity.AddFeature(f) + f = 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.SetupRemoteDevice(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 := localEntity.FeatureOfTypeAndRole(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 := NewDeviceLocalImpl("brand", "model", "serial", "code", "address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + localEntity := NewEntityLocalImpl(sut, model.EntityTypeTypeCEM, NewAddressEntityType([]uint{1})) + sut.AddEntity(localEntity) + + ski := "test" + _ = sut.SetupRemoteDevice(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 := NewDeviceLocalImpl("brand", "model", "serial", "code", "address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + localEntity := NewEntityLocalImpl(sut, model.EntityTypeTypeCEM, NewAddressEntityType([]uint{1})) + sut.AddEntity(localEntity) + + f := NewFeatureLocalImpl(1, localEntity, model.FeatureTypeTypeElectricalConnection, model.RoleTypeClient) + localEntity.AddFeature(f) + f = NewFeatureLocalImpl(2, localEntity, model.FeatureTypeTypeMeasurement, model.RoleTypeClient) + localEntity.AddFeature(f) + f = NewFeatureLocalImpl(3, localEntity, model.FeatureTypeTypeElectricalConnection, model.RoleTypeServer) + localEntity.AddFeature(f) + + ski := "test" + remoteDeviceName := "remote" + _ = sut.SetupRemoteDevice(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 new file mode 100644 index 0000000..b522765 --- /dev/null +++ b/spine/device_remote.go @@ -0,0 +1,361 @@ +package spine + +import ( + "encoding/json" + "errors" + "reflect" + "slices" + "sync" + + shipapi "github.com/enbility/ship-go/api" + "github.com/enbility/ship-go/logging" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" +) + +var _ api.DeviceRemote = (*DeviceRemoteImpl)(nil) + +type DeviceRemoteImpl struct { + *DeviceImpl + + ski string + + entities []api.EntityRemote + entitiesMutex sync.Mutex + + sender api.Sender + + localDevice api.DeviceLocal +} + +var _ shipapi.SpineDataProcessing = (*DeviceRemoteImpl)(nil) + +func NewDeviceRemoteImpl(localDevice api.DeviceLocal, ski string, sender api.Sender) *DeviceRemoteImpl { + res := DeviceRemoteImpl{ + DeviceImpl: NewDeviceImpl(nil, nil, nil), + ski: ski, + localDevice: localDevice, + sender: sender, + } + res.addNodeManagement() + + return &res +} + +// return the device SKI +func (d *DeviceRemoteImpl) Ski() string { + return d.ski +} + +func (d *DeviceRemoteImpl) SetAddress(address *model.AddressDeviceType) { + d.address = address +} + +func (d *DeviceRemoteImpl) HandleSpineMesssage(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 +} + +// processing incoming SPINE message from the associated SHIP connection +func (d *DeviceRemoteImpl) HandleIncomingSpineMesssage(message []byte) { + _, _ = d.HandleSpineMesssage(message) +} + +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() api.Sender { + return d.sender +} + +// Return an entity with a given address +func (d *DeviceRemoteImpl) Entity(id []model.AddressEntityType) api.EntityRemote { + 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() []api.EntityRemote { + return d.entities +} + +// Return the feature for a given address +func (d *DeviceRemoteImpl) FeatureByAddress(address *model.FeatureAddressType) api.FeatureRemote { + 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) api.EntityRemote { + entityForRemoval := d.Entity(addr) + if entityForRemoval == nil { + return nil + } + + d.entitiesMutex.Lock() + defer d.entitiesMutex.Unlock() + + var newEntities []api.EntityRemote + 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 api.EntityRemote, featureType model.FeatureTypeType, role model.RoleType) api.FeatureRemote { + 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) ([]api.EntityRemote, error) { + rEntites := make([]api.EntityRemote, 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, ok := unmarshalFeature(entity, fi); ok { + 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) api.EntityRemote { + newEntity := NewEntityRemoteImpl(d, eType, address) + return d.AddEntity(newEntity) +} + +func (d *DeviceRemoteImpl) AddEntity(entity api.EntityRemote) api.EntityRemote { + d.entitiesMutex.Lock() + defer d.entitiesMutex.Unlock() + + d.entities = append(d.entities, entity) + + return entity +} + +func (d *DeviceRemoteImpl) UseCases() []model.UseCaseInformationDataType { + entity := d.Entity(DeviceInformationAddressEntity) + + nodemgmt := d.FeatureByEntityTypeAndRole(entity, model.FeatureTypeTypeNodeManagement, model.RoleTypeSpecial) + + data := nodemgmt.DataCopy(model.FunctionTypeNodeManagementUseCaseData).(*model.NodeManagementUseCaseDataType) + if data != nil { + return data.UseCaseInformation + } + + return nil +} + +// Checks if the given actor, usecasename and provided server features are available +// Note: the server features are expected to be in a single entity and entity 0 is not checked! +func (d *DeviceRemoteImpl) VerifyUseCaseScenariosAndFeaturesSupport( + usecaseActor model.UseCaseActorType, + usecaseName model.UseCaseNameType, + scenarios []model.UseCaseScenarioSupportType, + serverFeatures []model.FeatureTypeType, +) bool { + entity := d.Entity(DeviceInformationAddressEntity) + + nodemgmt := d.FeatureByEntityTypeAndRole(entity, model.FeatureTypeTypeNodeManagement, model.RoleTypeSpecial) + + usecases := nodemgmt.DataCopy(model.FunctionTypeNodeManagementUseCaseData).(*model.NodeManagementUseCaseDataType) + + if usecases == nil || len(usecases.UseCaseInformation) == 0 { + return false + } + + usecaseAndScenariosFound := false + for _, usecase := range usecases.UseCaseInformation { + if usecase.Actor == nil || *usecase.Actor != usecaseActor { + continue + } + + for _, support := range usecase.UseCaseSupport { + if support.UseCaseName == nil || *support.UseCaseName != usecaseName { + continue + } + + var foundScenarios []model.UseCaseScenarioSupportType + for _, scenario := range support.ScenarioSupport { + if slices.Contains(scenarios, scenario) { + foundScenarios = append(foundScenarios, scenario) + } + } + + if len(foundScenarios) == len(scenarios) { + usecaseAndScenariosFound = true + break + } + } + + if usecaseAndScenariosFound { + break + } + } + + if !usecaseAndScenariosFound { + return false + } + + entities := d.Entities() + if len(entities) < 2 { + return false + } + + entityWithServerFeaturesFound := false + + for index, entity := range entities { + // ignore NodeManagement entity + if index == 0 { + continue + } + + var foundServerFeatures []model.FeatureTypeType + for _, feature := range entity.Features() { + if feature.Role() != model.RoleTypeServer { + continue + } + + if slices.Contains(serverFeatures, feature.Type()) { + foundServerFeatures = append(foundServerFeatures, feature.Type()) + } + } + + if len(serverFeatures) == len(foundServerFeatures) { + entityWithServerFeaturesFound = true + break + } + } + + return entityWithServerFeaturesFound +} + +func unmarshalFeature(entity api.EntityRemote, + featureData model.NodeManagementDetailedDiscoveryFeatureInformationType, +) (api.FeatureRemote, bool) { + var result api.FeatureRemote + + fid := featureData.Description + + if fid == nil { + return nil, false + } + + 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, true +} diff --git a/spine/device_remote_test.go b/spine/device_remote_test.go new file mode 100644 index 0000000..6cf2bbc --- /dev/null +++ b/spine/device_remote_test.go @@ -0,0 +1,276 @@ +package spine + +import ( + "testing" + "time" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +const ( + nm_usecaseinformationlistdata_recv_reply_file_path = "../spine/testdata/nm_usecaseinformationlistdata_recv_reply.json" +) + +func TestDeviceRemoteSuite(t *testing.T) { + suite.Run(t, new(DeviceRemoteSuite)) +} + +type DeviceRemoteSuite struct { + suite.Suite + + localDevice api.DeviceLocal + remoteDevice api.DeviceRemote + remoteEntity api.EntityRemote +} + +func (s *DeviceRemoteSuite) WriteSpineMessage([]byte) {} + +func (s *DeviceRemoteSuite) SetupSuite() {} + +func (s *DeviceRemoteSuite) BeforeTest(suiteName, testName string) { + s.localDevice = NewDeviceLocalImpl("brand", "model", "serial", "code", "address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + + ski := "test" + sender := NewSender(s) + s.remoteDevice = NewDeviceRemoteImpl(s.localDevice, ski, sender) + s.remoteDevice.SetAddress(util.Ptr(model.AddressDeviceType("test"))) + _ = s.localDevice.SetupRemoteDevice(ski, s) + + s.remoteEntity = NewEntityRemoteImpl(s.remoteDevice, model.EntityTypeTypeEVSE, []model.AddressEntityType{1}) + + feature := NewFeatureRemoteImpl(0, s.remoteEntity, model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeServer) + s.remoteEntity.AddFeature(feature) + + s.remoteDevice.AddEntity(s.remoteEntity) +} + +func (s *DeviceRemoteSuite) Test_RemoveByAddress() { + assert.Equal(s.T(), 2, len(s.remoteDevice.Entities())) + + s.remoteDevice.RemoveByAddress([]model.AddressEntityType{2}) + assert.Equal(s.T(), 2, len(s.remoteDevice.Entities())) + + s.remoteDevice.RemoveByAddress([]model.AddressEntityType{1}) + assert.Equal(s.T(), 1, len(s.remoteDevice.Entities())) +} + +func (s *DeviceRemoteSuite) Test_FeatureByEntityTypeAndRole() { + entity := s.remoteDevice.Entity([]model.AddressEntityType{1}) + assert.NotNil(s.T(), entity) + + assert.Equal(s.T(), 1, len(entity.Features())) + + feature := s.remoteDevice.FeatureByEntityTypeAndRole(entity, model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeClient) + assert.Nil(s.T(), feature) + + feature = s.remoteDevice.FeatureByEntityTypeAndRole(entity, model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeServer) + assert.NotNil(s.T(), feature) + + s.remoteDevice.RemoveByAddress([]model.AddressEntityType{1}) + assert.Equal(s.T(), 1, len(s.remoteDevice.Entities())) + + _ = s.remoteDevice.Entity([]model.AddressEntityType{0}) + s.remoteDevice.RemoveByAddress([]model.AddressEntityType{0}) + assert.Equal(s.T(), 0, len(s.remoteDevice.Entities())) + + feature = s.remoteDevice.FeatureByEntityTypeAndRole(entity, model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeServer) + assert.Nil(s.T(), feature) +} + +func (s *DeviceRemoteSuite) Test_Usecases() { + uc := s.remoteDevice.UseCases() + assert.Nil(s.T(), uc) + + _, _ = s.remoteDevice.HandleSpineMesssage(loadFileData(s.T(), nm_usecaseinformationlistdata_recv_reply_file_path)) + + uc = s.remoteDevice.UseCases() + assert.NotNil(s.T(), uc) +} + +func (s *DeviceRemoteSuite) Test_VerifyUseCaseScenariosAndFeaturesSupport_ElliJSON() { + _, _ = s.remoteDevice.HandleSpineMesssage(loadFileData(s.T(), nm_usecaseinformationlistdata_recv_reply_file_path)) + + result := s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeBatterySystem, + model.UseCaseNameTypeControlOfBattery, + []model.UseCaseScenarioSupportType{}, + []model.FeatureTypeType{}, + ) + assert.Equal(s.T(), false, result) + + result = s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + []model.UseCaseScenarioSupportType{}, + []model.FeatureTypeType{}, + ) + assert.Equal(s.T(), true, result) +} + +func (s *DeviceRemoteSuite) Test_VerifyUseCaseScenariosAndFeaturesSupport() { + result := s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + []model.UseCaseScenarioSupportType{}, + []model.FeatureTypeType{}, + ) + assert.Equal(s.T(), false, result) + + nodeMgmtEntity := s.remoteDevice.Entity(DeviceInformationAddressEntity) + nodeMgmt := nodeMgmtEntity.Feature(util.Ptr(model.AddressFeatureType(NodeManagementFeatureId))) + + // initialize with empty data + newData := &model.NodeManagementUseCaseDataType{ + UseCaseInformation: []model.UseCaseInformationDataType{}, + } + nodeMgmt.UpdateData(model.FunctionTypeNodeManagementUseCaseData, newData, nil, nil) + + data := nodeMgmt.DataCopy(model.FunctionTypeNodeManagementUseCaseData).(*model.NodeManagementUseCaseDataType) + + address := model.FeatureAddressType{ + Device: s.remoteDevice.Address(), + Entity: s.remoteEntity.Address().Entity, + } + + data.AddUseCaseSupport( + address, + model.UseCaseActorTypeBatterySystem, + model.UseCaseNameTypeControlOfBattery, + model.SpecificationVersionType("1.0.0"), + "", + true, + []model.UseCaseScenarioSupportType{1}, + ) + nodeMgmt.SetData(model.FunctionTypeNodeManagementUseCaseData, data) + data = nodeMgmt.DataCopy(model.FunctionTypeNodeManagementUseCaseData).(*model.NodeManagementUseCaseDataType) + + result = s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + nil, + nil, + ) + assert.Equal(s.T(), false, result) + + data.AddUseCaseSupport( + address, + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVCommissioningAndConfiguration, + model.SpecificationVersionType("1.0.0"), + "", + true, + []model.UseCaseScenarioSupportType{1}, + ) + nodeMgmt.SetData(model.FunctionTypeNodeManagementUseCaseData, data) + data = nodeMgmt.DataCopy(model.FunctionTypeNodeManagementUseCaseData).(*model.NodeManagementUseCaseDataType) + + result = s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + nil, + nil, + ) + assert.Equal(s.T(), false, result) + + data.AddUseCaseSupport( + address, + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + model.SpecificationVersionType("1.0.0"), + "", + false, + []model.UseCaseScenarioSupportType{1}, + ) + nodeMgmt.SetData(model.FunctionTypeNodeManagementUseCaseData, data) + data = nodeMgmt.DataCopy(model.FunctionTypeNodeManagementUseCaseData).(*model.NodeManagementUseCaseDataType) + + result = s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + nil, + nil, + ) + assert.Equal(s.T(), true, result) + + data.AddUseCaseSupport( + address, + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + model.SpecificationVersionType("1.0.0"), + "", + true, + []model.UseCaseScenarioSupportType{1}, + ) + nodeMgmt.SetData(model.FunctionTypeNodeManagementUseCaseData, data) + + result = s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + nil, + nil, + ) + assert.Equal(s.T(), true, result) + + result = s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + []model.UseCaseScenarioSupportType{2}, + nil, + ) + assert.Equal(s.T(), false, result) + + result = s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + []model.UseCaseScenarioSupportType{1}, + nil, + ) + assert.Equal(s.T(), true, result) + + result = s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + []model.UseCaseScenarioSupportType{1}, + []model.FeatureTypeType{model.FeatureTypeTypeElectricalConnection}, + ) + assert.Equal(s.T(), false, result) + + entity := s.remoteDevice.Entity([]model.AddressEntityType{1}) + assert.NotNil(s.T(), entity) + + feature := NewFeatureRemoteImpl(0, entity, model.FeatureTypeTypeElectricalConnection, model.RoleTypeClient) + entity.AddFeature(feature) + + result = s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + []model.UseCaseScenarioSupportType{1}, + []model.FeatureTypeType{model.FeatureTypeTypeElectricalConnection}, + ) + assert.Equal(s.T(), false, result) + + feature = NewFeatureRemoteImpl(0, entity, model.FeatureTypeTypeElectricalConnection, model.RoleTypeServer) + entity.AddFeature(feature) + + result = s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + []model.UseCaseScenarioSupportType{1}, + []model.FeatureTypeType{model.FeatureTypeTypeElectricalConnection}, + ) + assert.Equal(s.T(), true, result) + + s.remoteDevice.RemoveByAddress(feature.Address().Entity) + + result = s.remoteDevice.VerifyUseCaseScenariosAndFeaturesSupport( + model.UseCaseActorTypeEVSE, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + []model.UseCaseScenarioSupportType{1}, + []model.FeatureTypeType{model.FeatureTypeTypeElectricalConnection}, + ) + assert.Equal(s.T(), false, result) +} diff --git a/spine/entity.go b/spine/entity.go new file mode 100644 index 0000000..f334a71 --- /dev/null +++ b/spine/entity.go @@ -0,0 +1,87 @@ +package spine + +import ( + "github.com/ahmetb/go-linq/v3" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-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 +} + +var _ api.Entity = (*EntityImpl)(nil) + +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) Description() *model.DescriptionType { + return r.description +} + +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 new file mode 100644 index 0000000..2dc0b90 --- /dev/null +++ b/spine/entity_local.go @@ -0,0 +1,165 @@ +package spine + +import ( + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" +) + +var _ api.EntityLocal = (*EntityLocalImpl)(nil) + +type EntityLocalImpl struct { + *EntityImpl + device api.DeviceLocal + features []api.FeatureLocal +} + +func NewEntityLocalImpl(device api.DeviceLocal, eType model.EntityTypeType, entityAddress []model.AddressEntityType) *EntityLocalImpl { + return &EntityLocalImpl{ + EntityImpl: NewEntity(eType, device.Address(), entityAddress), + device: device, + } +} + +func (r *EntityLocalImpl) Device() api.DeviceLocal { + return r.device +} + +// Add a feature to the entity if it is not already added +func (r *EntityLocalImpl) AddFeature(f api.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) api.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) + + if role == model.RoleTypeServer && featureType == model.FeatureTypeTypeDeviceDiagnosis { + // Update HeartbeatManagerImpl + r.device.HeartbeatManager().SetLocalFeature(r, f) + } + + return f +} + +func (r *EntityLocalImpl) FeatureOfTypeAndRole(featureType model.FeatureTypeType, role model.RoleType) api.FeatureLocal { + for _, f := range r.features { + if f.Type() == featureType && f.Role() == role { + return f + } + } + return nil +} + +func (r *EntityLocalImpl) Features() []api.FeatureLocal { + return r.features +} + +func (r *EntityLocalImpl) Feature(addressFeature *model.AddressFeatureType) api.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 +} + +// add a new usecase +func (r *EntityLocalImpl) AddUseCaseSupport( + actor model.UseCaseActorType, + useCaseName model.UseCaseNameType, + useCaseVersion model.SpecificationVersionType, + useCaseDocumemtSubRevision string, + useCaseAvailable bool, + scenarios []model.UseCaseScenarioSupportType, +) { + nodeMgmt := r.device.NodeManagement() + + data := nodeMgmt.DataCopy(model.FunctionTypeNodeManagementUseCaseData).(*model.NodeManagementUseCaseDataType) + if data == nil { + data = &model.NodeManagementUseCaseDataType{} + } + + address := model.FeatureAddressType{ + Device: r.address.Device, + Entity: r.address.Entity, + } + + data.AddUseCaseSupport(address, actor, useCaseName, useCaseVersion, useCaseDocumemtSubRevision, useCaseAvailable, scenarios) + + nodeMgmt.SetData(model.FunctionTypeNodeManagementUseCaseData, data) +} + +// Remove a usecase with a given actor ans usecase name +func (r *EntityLocalImpl) RemoveUseCaseSupport( + actor model.UseCaseActorType, + useCaseName model.UseCaseNameType, +) { + nodeMgmt := r.device.NodeManagement() + + data := nodeMgmt.DataCopy(model.FunctionTypeNodeManagementUseCaseData).(*model.NodeManagementUseCaseDataType) + if data == nil { + return + } + + address := model.FeatureAddressType{ + Device: r.address.Device, + Entity: r.address.Entity, + } + + data.RemoveUseCaseSupport(address, actor, useCaseName) + + nodeMgmt.SetData(model.FunctionTypeNodeManagementUseCaseData, data) +} + +// Remove all usecases +func (r *EntityLocalImpl) RemoveAllUseCaseSupports() { + r.RemoveUseCaseSupport("", "") +} + +// Remove all subscriptions +func (r *EntityLocalImpl) RemoveAllSubscriptions() { + for _, item := range r.features { + item.RemoveAllSubscriptions() + } +} + +// Remove all bindings +func (r *EntityLocalImpl) RemoveAllBindings() { + for _, item := range r.features { + item.RemoveAllBindings() + } +} diff --git a/spine/entity_local_test.go b/spine/entity_local_test.go new file mode 100644 index 0000000..3e0f0ee --- /dev/null +++ b/spine/entity_local_test.go @@ -0,0 +1,80 @@ +package spine + +import ( + "testing" + "time" + + "github.com/enbility/spine-go/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestEntityLocalSuite(t *testing.T) { + suite.Run(t, new(EntityLocalTestSuite)) +} + +type EntityLocalTestSuite struct { + suite.Suite +} + +func (suite *EntityLocalTestSuite) Test_Entity() { + device := NewDeviceLocalImpl("brand", "model", "serial", "code", "address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + entity := NewEntityLocalImpl(device, model.EntityTypeTypeCEM, NewAddressEntityType([]uint{1})) + device.AddEntity(entity) + + f := NewFeatureLocalImpl(1, entity, model.FeatureTypeTypeElectricalConnection, model.RoleTypeClient) + entity.AddFeature(f) + assert.Equal(suite.T(), 1, len(entity.Features())) + + entity.AddFeature(f) + assert.Equal(suite.T(), 1, len(entity.Features())) + + f1 := entity.Feature(nil) + assert.Nil(suite.T(), f1) + + f1 = entity.Feature(f.Address().Feature) + assert.NotNil(suite.T(), f1) + + fakeAddress := model.AddressFeatureType(5) + f1 = entity.Feature(&fakeAddress) + assert.Nil(suite.T(), f1) + + f2 := entity.GetOrAddFeature(model.FeatureTypeTypeMeasurement, model.RoleTypeClient) + assert.NotNil(suite.T(), f2) + + assert.Equal(suite.T(), 2, len(entity.Features())) + + f3 := entity.GetOrAddFeature(model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeServer) + assert.NotNil(suite.T(), f3) + + assert.Equal(suite.T(), 3, len(entity.Features())) + + f4 := entity.GetOrAddFeature(model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeServer) + assert.NotNil(suite.T(), f4) + + assert.Equal(suite.T(), 3, len(entity.Features())) + + entity.RemoveAllUseCaseSupports() + + entity.AddUseCaseSupport( + model.UseCaseActorTypeCEM, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + model.SpecificationVersionType("1.0.0"), + "", + true, + []model.UseCaseScenarioSupportType{1, 2}, + ) + + entity.AddUseCaseSupport( + model.UseCaseActorTypeCEM, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + model.SpecificationVersionType("1.0.0"), + "", + true, + []model.UseCaseScenarioSupportType{1, 2}, + ) + + entity.RemoveAllUseCaseSupports() + entity.RemoveAllBindings() + entity.RemoveAllSubscriptions() +} diff --git a/spine/entity_remote.go b/spine/entity_remote.go new file mode 100644 index 0000000..329ebbe --- /dev/null +++ b/spine/entity_remote.go @@ -0,0 +1,46 @@ +package spine + +import ( + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" +) + +var _ api.EntityRemote = (*EntityRemoteImpl)(nil) + +type EntityRemoteImpl struct { + *EntityImpl + device api.DeviceRemote + features []api.FeatureRemote +} + +func NewEntityRemoteImpl(device api.DeviceRemote, eType model.EntityTypeType, entityAddress []model.AddressEntityType) *EntityRemoteImpl { + return &EntityRemoteImpl{ + EntityImpl: NewEntity(eType, device.Address(), entityAddress), + device: device, + } +} + +func (r *EntityRemoteImpl) Device() api.DeviceRemote { + return r.device +} + +func (r *EntityRemoteImpl) AddFeature(f api.FeatureRemote) { + r.features = append(r.features, f) +} + +func (r *EntityRemoteImpl) Features() []api.FeatureRemote { + return r.features +} + +func (r *EntityRemoteImpl) Feature(addressFeature *model.AddressFeatureType) api.FeatureRemote { + 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/events.go b/spine/events.go new file mode 100644 index 0000000..da0237a --- /dev/null +++ b/spine/events.go @@ -0,0 +1,105 @@ +package spine + +import ( + "sync" + + "github.com/enbility/spine-go/api" +) + +var Events events + +type eventHandlerItem struct { + Level api.EventHandlerLevel + Handler api.EventHandler +} + +type events struct { + mu sync.Mutex + muHandle sync.Mutex + + handlers []eventHandlerItem // event handling outside of the core stack +} + +// will be used in EEBUS core directly to access the level EventHandlerLevelCore +func (r *events) subscribe(level api.EventHandlerLevel, handler api.EventHandler) error { + r.mu.Lock() + defer r.mu.Unlock() + + exists := false + for _, item := range r.handlers { + if item.Level == level && item.Handler == handler { + exists = true + break + } + } + + if !exists { + newHandlerItem := eventHandlerItem{ + Level: level, + Handler: handler, + } + r.handlers = append(r.handlers, newHandlerItem) + } + + return nil +} + +// Subscribe to message events and handle them in +// the Eventhandler interface implementation +// +// returns an error if EventHandlerLevelCore is used as +// that is only allowed for internal use +func (r *events) Subscribe(handler api.EventHandler) error { + return r.subscribe(api.EventHandlerLevelApplication, handler) +} + +// will be used in EEBUS core directly to access the level EventHandlerLevelCore +func (r *events) unsubscribe(level api.EventHandlerLevel, handler api.EventHandler) error { + r.mu.Lock() + defer r.mu.Unlock() + + var newHandlers []eventHandlerItem + for _, item := range r.handlers { + if item.Level != level && item.Handler != handler { + newHandlers = append(newHandlers, item) + } + } + + r.handlers = newHandlers + + return nil +} + +// Unsubscribe from getting events +func (r *events) Unsubscribe(handler api.EventHandler) error { + return r.unsubscribe(api.EventHandlerLevelApplication, handler) +} + +// Publish an event to all subscribers +func (r *events) Publish(payload api.EventPayload) { + r.mu.Lock() + var handler []eventHandlerItem + copy(r.handlers, handler) + r.mu.Unlock() + + // Use different locks, so unpublish is possible in the event handlers + r.muHandle.Lock() + // process subscribers by level + handlerLevels := []api.EventHandlerLevel{ + api.EventHandlerLevelCore, + api.EventHandlerLevelApplication, + } + + for _, level := range handlerLevels { + for _, item := range r.handlers { + if item.Level != level { + continue + } + + // do not run this asynchronously, to make sure all required + // and expected actions are taken + item.Handler.HandleEvent(payload) + } + } + r.muHandle.Unlock() +} diff --git a/spine/feature.go b/spine/feature.go new file mode 100644 index 0000000..f8f76d1 --- /dev/null +++ b/spine/feature.go @@ -0,0 +1,74 @@ +package spine + +import ( + "fmt" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" +) + +type FeatureImpl struct { + address *model.FeatureAddressType + ftype model.FeatureTypeType + description *model.DescriptionType + role model.RoleType + operations map[model.FunctionType]api.Operations +} + +var _ api.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]api.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 new file mode 100644 index 0000000..3ae1a30 --- /dev/null +++ b/spine/feature_local.go @@ -0,0 +1,466 @@ +package spine + +import ( + "fmt" + "reflect" + "sync" + "time" + + "github.com/enbility/ship-go/logging" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" +) + +var _ api.FeatureLocal = (*FeatureLocalImpl)(nil) + +type FeatureLocalImpl struct { + *FeatureImpl + + muxResultCB sync.Mutex + entity api.EntityLocal + functionDataMap map[model.FunctionType]api.FunctionDataCmd + pendingRequests api.PendingRequests + resultHandler []api.FeatureResult + resultCallback map[model.MsgCounterType]func(result api.ResultMessage) + + bindings []*model.FeatureAddressType + subscriptions []*model.FeatureAddressType + + mux sync.Mutex +} + +func NewFeatureLocalImpl(id uint, entity api.EntityLocal, ftype model.FeatureTypeType, role model.RoleType) *FeatureLocalImpl { + res := &FeatureLocalImpl{ + FeatureImpl: NewFeatureImpl( + featureAddressType(id, entity.Address()), + ftype, + role), + entity: entity, + functionDataMap: make(map[model.FunctionType]api.FunctionDataCmd), + pendingRequests: NewPendingRequest(), + resultCallback: make(map[model.MsgCounterType]func(result api.ResultMessage)), + } + + for _, fd := range CreateFunctionData[api.FunctionDataCmd](ftype) { + res.functionDataMap[fd.Function()] = fd + } + res.operations = make(map[model.FunctionType]api.Operations) + + return res +} + +func (r *FeatureLocalImpl) Device() api.DeviceLocal { + return r.entity.Device() +} + +func (r *FeatureLocalImpl) Entity() api.EntityLocal { + 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) DataCopy(function model.FunctionType) any { + r.mux.Lock() + defer r.mux.Unlock() + + return r.functionData(function).DataCopyAny() +} + +func (r *FeatureLocalImpl) SetData(function model.FunctionType, data any) { + r.mux.Lock() + + fd := r.functionData(function) + fd.UpdateDataAny(data, nil, nil) + + r.mux.Unlock() + + r.Device().NotifySubscribers(r.Address(), fd.NotifyCmdType(nil, nil, false, nil)) +} + +func (r *FeatureLocalImpl) AddResultHandler(handler api.FeatureResult) { + r.resultHandler = append(r.resultHandler, handler) +} + +func (r *FeatureLocalImpl) AddResultCallback(msgCounterReference model.MsgCounterType, function func(msg api.ResultMessage)) { + r.muxResultCB.Lock() + defer r.muxResultCB.Unlock() + + r.resultCallback[msgCounterReference] = function +} + +func (r *FeatureLocalImpl) processResultCallbacks(msgCounterReference model.MsgCounterType, msg api.ResultMessage) { + r.muxResultCB.Lock() + defer r.muxResultCB.Unlock() + + cb, ok := r.resultCallback[msgCounterReference] + if !ok { + return + } + + go cb(msg) + + delete(r.resultCallback, msgCounterReference) +} + +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 api.FeatureRemote) (*model.MsgCounterType, *model.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 api.Sender, + deviceSki string, + destinationAddress *model.FeatureAddressType, + maxDelay time.Duration) (*model.MsgCounterType, *model.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, model.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 api.FeatureRemote) (any, *model.ErrorType) { + + return r.pendingRequests.GetData(destination.Device().Ski(), msgCounter) +} + +// Subscribe to a remote feature +func (r *FeatureLocalImpl) Subscribe(remoteAddress *model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType) { + if remoteAddress.Device == nil { + return nil, model.NewErrorTypeFromString("device not found") + } + remoteDevice := r.entity.Device().RemoteDeviceForAddress(*remoteAddress.Device) + if remoteDevice == nil { + return nil, model.NewErrorTypeFromString("device not found") + } + + if r.Role() == model.RoleTypeServer { + return nil, model.NewErrorTypeFromString(fmt.Sprintf("the server feature '%s' cannot request a subscription", r)) + } + + msgCounter, err := remoteDevice.Sender().Subscribe(r.Address(), remoteAddress, r.ftype) + if err != nil { + return nil, model.NewErrorTypeFromString(err.Error()) + } + + r.mux.Lock() + r.subscriptions = append(r.subscriptions, remoteAddress) + r.mux.Unlock() + + return msgCounter, nil +} + +// Remove a subscriptions to a remote feature +func (r *FeatureLocalImpl) RemoveSubscription(remoteAddress *model.FeatureAddressType) { + remoteDevice := r.entity.Device().RemoteDeviceForAddress(*remoteAddress.Device) + if remoteDevice == nil { + return + } + + if _, err := remoteDevice.Sender().Unsubscribe(r.Address(), remoteAddress); err != nil { + return + } + + var subscriptions []*model.FeatureAddressType + + r.mux.Lock() + defer r.mux.Unlock() + + for _, item := range r.subscriptions { + if reflect.DeepEqual(item, remoteAddress) { + continue + } + + subscriptions = append(subscriptions, item) + } + + r.subscriptions = subscriptions +} + +// Remove all subscriptions to remote features +func (r *FeatureLocalImpl) RemoveAllSubscriptions() { + for _, item := range r.subscriptions { + r.RemoveSubscription(item) + } +} + +// Bind to a remote feature +func (r *FeatureLocalImpl) Bind(remoteAddress *model.FeatureAddressType) (*model.MsgCounterType, *model.ErrorType) { + remoteDevice := r.entity.Device().RemoteDeviceForAddress(*remoteAddress.Device) + if remoteDevice == nil { + return nil, model.NewErrorTypeFromString("device not found") + } + + if r.Role() == model.RoleTypeServer { + return nil, model.NewErrorTypeFromString(fmt.Sprintf("the server feature '%s' cannot request a binding", r)) + } + + msgCounter, err := remoteDevice.Sender().Bind(r.Address(), remoteAddress, r.ftype) + if err != nil { + return nil, model.NewErrorTypeFromString(err.Error()) + } + + r.mux.Lock() + r.bindings = append(r.bindings, remoteAddress) + r.mux.Unlock() + + return msgCounter, nil +} + +// Remove a binding to a remote feature +func (r *FeatureLocalImpl) RemoveBinding(remoteAddress *model.FeatureAddressType) { + remoteDevice := r.entity.Device().RemoteDeviceForAddress(*remoteAddress.Device) + if remoteDevice == nil { + return + } + + if _, err := remoteDevice.Sender().Unbind(r.Address(), remoteAddress); err != nil { + return + } + + var bindings []*model.FeatureAddressType + + r.mux.Lock() + defer r.mux.Unlock() + + for _, item := range r.bindings { + if reflect.DeepEqual(item, remoteAddress) { + continue + } + + bindings = append(bindings, item) + } + + r.bindings = bindings +} + +// Remove all subscriptions to remote features +func (r *FeatureLocalImpl) RemoveAllBindings() { + for _, item := range r.bindings { + r.RemoveBinding(item) + } +} + +// 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 api.FeatureRemote) (*model.MsgCounterType, *model.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, model.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 api.FeatureRemote) (*model.MsgCounterType, *model.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, model.NewErrorTypeFromString(err.Error()) + } + + return msgCounter, nil +} + +func (r *FeatureLocalImpl) HandleMessage(message *api.Message) *model.ErrorType { + if message.Cmd.ResultData != nil { + return r.processResult(message) + } + + cmdData, err := message.Cmd.Data() + if err != nil { + return model.NewErrorType(model.ErrorNumberTypeCommandNotSupported, err.Error()) + } + if cmdData.Function == nil { + return model.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.FilterPartial, message.FilterDelete, 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 model.NewErrorTypeFromString(fmt.Sprintf("CmdClassifier not implemented: %s", message.CmdClassifier)) + } + + return nil +} + +func (r *FeatureLocalImpl) processResult(message *api.Message) *model.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, model.NewErrorTypeFromResult(message.Cmd.ResultData)) + + if message.RequestHeader.MsgCounterReference == nil { + return nil + } + + // call the Features Error Handler + errorMsg := api.ResultMessage{ + MsgCounterReference: *message.RequestHeader.MsgCounterReference, + Result: message.Cmd.ResultData, + FeatureLocal: r, + FeatureRemote: message.FeatureRemote, + DeviceRemote: message.DeviceRemote, + } + + if r.resultHandler != nil { + for _, item := range r.resultHandler { + go item.HandleResult(errorMsg) + } + } + + r.processResultCallbacks(*message.RequestHeader.MsgCounterReference, errorMsg) + + return nil + + default: + return model.NewErrorType( + model.ErrorNumberTypeGeneralError, + fmt.Sprintf("ResultData CmdClassifierType %s not implemented", message.CmdClassifier)) + } +} + +func (r *FeatureLocalImpl) processRead(function model.FunctionType, requestHeader *model.HeaderType, featureRemote api.FeatureRemote) *model.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 model.NewErrorTypeFromNumber(model.ErrorNumberTypeCommandRejected) + } + + cmd := r.functionData(function).ReplyCmdType(false) + if err := featureRemote.Sender().Reply(requestHeader, r.Address(), cmd); err != nil { + return model.NewErrorTypeFromString(err.Error()) + } + + return nil +} + +func (r *FeatureLocalImpl) processReply(function model.FunctionType, data any, filterPartial *model.FilterType, filterDelete *model.FilterType, requestHeader *model.HeaderType, featureRemote api.FeatureRemote) *model.ErrorType { + featureRemote.UpdateData(function, data, filterPartial, filterDelete) + _ = 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 := api.EventPayload{ + Ski: featureRemote.Device().Ski(), + EventType: api.EventTypeDataChange, + ChangeType: api.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 api.FeatureRemote) *model.ErrorType { + featureRemote.UpdateData(function, data, filterPartial, filterDelete) + + payload := api.EventPayload{ + Ski: featureRemote.Device().Ski(), + EventType: api.EventTypeDataChange, + ChangeType: api.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) api.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 new file mode 100644 index 0000000..f0c2dfc --- /dev/null +++ b/spine/feature_local_test.go @@ -0,0 +1,191 @@ +package spine + +import ( + "testing" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/mocks" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-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, subFeatureType model.FeatureTypeType + msgCounter model.MsgCounterType + remoteFeature, remoteSubFeature api.FeatureRemote + localFeature api.FeatureLocal + localServerFeature api.FeatureLocal +} + +func (suite *DeviceClassificationTestSuite) BeforeTest(suiteName, testName string) { + suite.senderMock = mocks.NewSender(suite.T()) + suite.function = model.FunctionTypeDeviceClassificationManufacturerData + suite.featureType = model.FeatureTypeTypeDeviceClassification + suite.subFeatureType = model.FeatureTypeTypeMeasurement + suite.msgCounter = model.MsgCounterType(1) + + _, suite.remoteFeature = createRemoteDeviceAndFeature(1, suite.featureType, suite.senderMock) + _, suite.remoteSubFeature = createRemoteDeviceAndFeature(2, suite.subFeatureType, suite.senderMock) + suite.localFeature, suite.localServerFeature = createLocalDeviceAndFeature(1, suite.featureType) +} + +func (suite *DeviceClassificationTestSuite) TestDeviceClassification_Request_Reply() { + suite.senderMock.On("Request", model.CmdClassifierTypeRead, suite.localFeature.Address(), suite.remoteFeature.Address(), false, mock.AnythingOfType("[]model.CmdType")).Return(&suite.msgCounter, nil) + + // send data request + msgCounter, err := suite.localFeature.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 := api.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.localFeature.HandleMessage(&replyMsg) + if assert.Nil(suite.T(), msgErr) { + remoteData := suite.remoteFeature.DataCopy(suite.function) + assert.IsType(suite.T(), &model.DeviceClassificationManufacturerDataType{}, remoteData, "Data has wrong type") + } + + // Act + result, err := suite.localFeature.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.localFeature.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.localFeature.RequestData(suite.function, nil, nil, suite.remoteFeature) + assert.Nil(suite.T(), err) + + replyMsg := api.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.localFeature.HandleMessage(&replyMsg) + if assert.Nil(suite.T(), msgErr) { + remoteData := suite.remoteFeature.DataCopy(suite.function) + assert.Nil(suite.T(), remoteData) + } + + // Act + result, err := suite.localFeature.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 (suite *DeviceClassificationTestSuite) TestDeviceClassification_Subscribiptions() { + suite.senderMock.On("Subscribe", mock.Anything, mock.Anything, mock.Anything).Return(&suite.msgCounter, nil) + suite.senderMock.On("Unsubscribe", mock.Anything, mock.Anything, mock.Anything).Return(&suite.msgCounter, nil) + + msgCounter, err := suite.localFeature.Subscribe(suite.remoteFeature.Address()) + assert.NotNil(suite.T(), err) + assert.Nil(suite.T(), msgCounter) + + suite.localFeature.RemoveSubscription(suite.remoteFeature.Address()) + + suite.localFeature.Device().AddRemoteDeviceForSki(suite.remoteFeature.Device().Ski(), suite.remoteFeature.Device()) + + msgCounter, err = suite.localServerFeature.Subscribe(suite.remoteFeature.Address()) + assert.NotNil(suite.T(), err) + assert.Nil(suite.T(), msgCounter) + + suite.localFeature.RemoveSubscription(suite.remoteFeature.Address()) + + msgCounter, err = suite.localFeature.Subscribe(suite.remoteFeature.Address()) + assert.Nil(suite.T(), err) + assert.NotNil(suite.T(), msgCounter) + + msgCounter, err = suite.localFeature.Subscribe(suite.remoteSubFeature.Address()) + assert.Nil(suite.T(), err) + assert.NotNil(suite.T(), msgCounter) + + suite.localFeature.RemoveSubscription(suite.remoteFeature.Address()) + + suite.localFeature.RemoveAllSubscriptions() +} + +func (suite *DeviceClassificationTestSuite) TestDeviceClassification_Bindings() { + suite.senderMock.On("Bind", mock.Anything, mock.Anything, mock.Anything).Return(&suite.msgCounter, nil) + suite.senderMock.On("Unbind", mock.Anything, mock.Anything, mock.Anything).Return(&suite.msgCounter, nil) + + msgCounter, err := suite.localFeature.Bind(suite.remoteFeature.Address()) + assert.NotNil(suite.T(), err) + assert.Nil(suite.T(), msgCounter) + + suite.localFeature.RemoveBinding(suite.remoteFeature.Address()) + + suite.localFeature.Device().AddRemoteDeviceForSki(suite.remoteFeature.Device().Ski(), suite.remoteFeature.Device()) + + msgCounter, err = suite.localServerFeature.Bind(suite.remoteFeature.Address()) + assert.NotNil(suite.T(), err) + assert.Nil(suite.T(), msgCounter) + + suite.localFeature.RemoveBinding(suite.remoteFeature.Address()) + + msgCounter, err = suite.localFeature.Bind(suite.remoteFeature.Address()) + assert.Nil(suite.T(), err) + assert.NotNil(suite.T(), msgCounter) + + msgCounter, err = suite.localFeature.Bind(suite.remoteSubFeature.Address()) + assert.Nil(suite.T(), err) + assert.NotNil(suite.T(), msgCounter) + + suite.localFeature.RemoveBinding(suite.remoteFeature.Address()) + + suite.localFeature.RemoveAllBindings() +} diff --git a/spine/feature_remote.go b/spine/feature_remote.go new file mode 100644 index 0000000..4da2cc9 --- /dev/null +++ b/spine/feature_remote.go @@ -0,0 +1,115 @@ +package spine + +import ( + "fmt" + "sync" + "time" + + "github.com/enbility/ship-go/logging" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" + "github.com/rickb777/date/period" +) + +const defaultMaxResponseDelay = time.Duration(time.Second * 10) + +var _ api.FeatureRemote = (*FeatureRemoteImpl)(nil) + +type FeatureRemoteImpl struct { + *FeatureImpl + + entity api.EntityRemote + functionDataMap map[model.FunctionType]api.FunctionData + maxResponseDelay *time.Duration + + mux sync.Mutex +} + +func NewFeatureRemoteImpl(id uint, entity api.EntityRemote, ftype model.FeatureTypeType, role model.RoleType) *FeatureRemoteImpl { + res := &FeatureRemoteImpl{ + FeatureImpl: NewFeatureImpl( + featureAddressType(id, entity.Address()), + ftype, + role), + entity: entity, + functionDataMap: make(map[model.FunctionType]api.FunctionData), + } + for _, fd := range CreateFunctionData[api.FunctionData](ftype) { + res.functionDataMap[fd.Function()] = fd + } + + res.operations = make(map[model.FunctionType]api.Operations) + + return res +} + +func (r *FeatureRemoteImpl) DataCopy(function model.FunctionType) any { + r.mux.Lock() + defer r.mux.Unlock() + + return r.functionData(function).DataCopyAny() +} + +func (r *FeatureRemoteImpl) SetData(function model.FunctionType, data any) { + r.mux.Lock() + + fd := r.functionData(function) + fd.UpdateDataAny(data, nil, nil) + + r.mux.Unlock() +} + +func (r *FeatureRemoteImpl) UpdateData(function model.FunctionType, data any, filterPartial *model.FilterType, filterDelete *model.FilterType) { + r.mux.Lock() + defer r.mux.Unlock() + + r.functionData(function).UpdateDataAny(data, filterPartial, filterDelete) + // TODO: fire event +} + +func (r *FeatureRemoteImpl) Sender() api.Sender { + return r.Device().Sender() +} + +func (r *FeatureRemoteImpl) Device() api.DeviceRemote { + return r.entity.Device() +} + +func (r *FeatureRemoteImpl) Entity() api.EntityRemote { + return r.entity +} + +func (r *FeatureRemoteImpl) SetOperations(functions []model.FunctionPropertyType) { + r.operations = make(map[model.FunctionType]api.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) api.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/function_data.go b/spine/function_data.go new file mode 100644 index 0000000..c95749d --- /dev/null +++ b/spine/function_data.go @@ -0,0 +1,83 @@ +package spine + +import ( + "fmt" + "sync" + + "github.com/enbility/ship-go/logging" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" +) + +var _ api.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]) DataCopy() *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) *model.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 model.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]) DataCopyAny() any { + return r.DataCopy() +} + +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 new file mode 100644 index 0000000..0c3dfeb --- /dev/null +++ b/spine/function_data_cmd.go @@ -0,0 +1,121 @@ +package spine + +import ( + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" +) + +var _ api.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 + + result.SetDataForFunction(model.EEBusTagTypeTypeSelector, function, data) + + return result +} + +func addElementToFilter[T any](filter model.FilterType, function model.FunctionType, data *T) model.FilterType { + result := filter + + result.SetDataForFunction(model.EEbusTagTypeTypeElements, function, data) + + return result +} + +func createCmd[T any](function model.FunctionType, data *T) model.CmdType { + result := model.CmdType{} + + result.SetDataForFunction(function, data) + + return result +} diff --git a/spine/function_data_cmd_test.go b/spine/function_data_cmd_test.go new file mode 100644 index 0000000..90bdfc2 --- /dev/null +++ b/spine/function_data_cmd_test.go @@ -0,0 +1,1140 @@ +package spine + +import ( + "testing" + + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-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 new file mode 100644 index 0000000..13947e3 --- /dev/null +++ b/spine/function_data_factory.go @@ -0,0 +1,319 @@ +package spine + +import ( + "fmt" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" +) + +func CreateFunctionData[F any](featureType model.FeatureTypeType) []F { + // 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.FeatureTypeTypeNodeManagement { + result = []F{ + createFunctionData[model.NodeManagementDestinationListDataType, F](model.FunctionTypeNodeManagementDestinationListData), + createFunctionData[model.NodeManagementDetailedDiscoveryDataType, F](model.FunctionTypeNodeManagementDetailedDiscoveryData), + createFunctionData[model.NodeManagementUseCaseDataType, F](model.FunctionTypeNodeManagementUseCaseData), + } + + return result + } + + 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), + createFunctionData[model.ElectricalConnectionCharacteristicDataType, F](model.FunctionTypeElectricalConnectionCharacteristicListData), + createFunctionData[model.ElectricalConnectionCharacteristicListDataType, F](model.FunctionTypeElectricalConnectionCharacteristicListData), + }...) + } + + 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), + createFunctionData[model.SessionIdentificationListDataType, F](model.FunctionTypeSessionIdentificationListData), + createFunctionData[model.SessionMeasurementRelationListDataType, F](model.FunctionTypeSessionMeasurementRelationListData), + }...) + } + + 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), + createFunctionData[model.MeasurementSeriesListDataType, F](model.FunctionTypeMeasurementSeriesListData), + }...) + } + + 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.FeatureTypeTypeStateInformation || featureType == model.FeatureTypeTypeGeneric { + result = append(result, []F{ + createFunctionData[model.StateInformationListDataType, F](model.FunctionTypeStateInformationListData), + }...) + } + + 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 *api.FunctionDataCmd: + return any(NewFunctionDataCmd[T](functionType)).(F) + case *api.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 new file mode 100644 index 0000000..9ac4df2 --- /dev/null +++ b/spine/function_data_factory_test.go @@ -0,0 +1,97 @@ +package spine + +import ( + "testing" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/stretchr/testify/assert" +) + +func TestFunctionDataFactory_FunctionData(t *testing.T) { + result := CreateFunctionData[api.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[api.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[api.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[api.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[api.FunctionData](model.FeatureTypeTypeElectricalConnection) + assert.Equal(t, 6, 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[api.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[api.FunctionData](model.FeatureTypeTypeIdentification) + assert.Equal(t, 3, len(result)) + assert.IsType(t, &FunctionDataImpl[model.IdentificationListDataType]{}, result[0]) + + result = CreateFunctionData[api.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[api.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[api.FunctionData](model.FeatureTypeTypeMeasurement) + assert.Equal(t, 5, 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[api.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[api.FunctionData](model.FeatureTypeTypeGeneric) + assert.Equal(t, 124, len(result)) +} + +func TestFunctionDataFactory_FunctionDataCmd(t *testing.T) { + result := CreateFunctionData[api.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[api.FunctionDataCmd](model.FeatureTypeTypeNodeManagement) + assert.Equal(t, 3, 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 new file mode 100644 index 0000000..ece0207 --- /dev/null +++ b/spine/function_data_test.go @@ -0,0 +1,79 @@ +package spine + +import ( + "testing" + + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-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.DataCopy() + + 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.DataCopy() + + 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.DataCopy() + 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_manager.go b/spine/heartbeat_manager.go new file mode 100644 index 0000000..2ee1283 --- /dev/null +++ b/spine/heartbeat_manager.go @@ -0,0 +1,148 @@ +package spine + +import ( + "errors" + "sync" + "sync/atomic" + "time" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" +) + +type HeartbeatManagerImpl struct { + localDevice api.DeviceLocal + localEntity api.EntityLocal + localFeature api.FeatureLocal + + heartBeatNum uint64 // see https://github.com/golang/go/issues/11891 + stopHeartbeatC chan struct{} + stopMux sync.Mutex + + subscriptionManager api.SubscriptionManager + heartBeatTimeout *model.DurationType +} + +// Create a new Heartbeat Manager which handles sending of heartbeats +func NewHeartbeatManager(localDevice api.DeviceLocal, subscriptionManager api.SubscriptionManager, timeout time.Duration) *HeartbeatManagerImpl { + h := &HeartbeatManagerImpl{ + localDevice: localDevice, + subscriptionManager: subscriptionManager, + heartBeatTimeout: model.NewDurationType(timeout), + } + + return h +} + +func (c *HeartbeatManagerImpl) IsHeartbeatRunning() bool { + c.stopMux.Lock() + defer c.stopMux.Unlock() + + if c.stopHeartbeatC != nil && !c.isHeartbeatClosed() { + return true + } + + return false +} + +// check if there are any heartbeat subscriptions left, otherwise stop creating new ones +// or start creating heartbeats again if needed +func (c *HeartbeatManagerImpl) UpdateHeartbeatOnSubscriptions() { + if c.localEntity == nil { + return + } + + featureAddr := c.localEntity.FeatureOfTypeAndRole(model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeServer) + if featureAddr == nil { + return + } + + subscriptions := c.subscriptionManager.SubscriptionsOnFeature(*featureAddr.Address()) + if len(subscriptions) == 0 { + // stop creating heartbeats + c.StopHeartbeat() + } else if !c.IsHeartbeatRunning() { + // resume creating heartbeats + _ = c.StartHeartbeat() + } +} + +func (c *HeartbeatManagerImpl) SetLocalFeature(entity api.EntityLocal, feature api.FeatureLocal) { + c.localEntity = entity + c.localFeature = feature +} + +// Start setting heartbeat data +// Make sure the a required FeatureTypeTypeDeviceDiagnosis with the role server is present +// otherwise this will end with an error +// Note: Remote features need to have a subscription to get notifications +func (c *HeartbeatManagerImpl) StartHeartbeat() error { + if c.localEntity == nil { + return errors.New("unknown entity") + } + + timeout, err := c.heartBeatTimeout.GetTimeDuration() + if err != nil { + return err + } + + // stop an already running heartbeat + c.StopHeartbeat() + + c.stopHeartbeatC = make(chan struct{}) + + go c.updateHearbeatData(c.stopHeartbeatC, timeout) + + return nil +} + +// Stop updating heartbeat data +// Note: No active subscribers will get any further notifications! +func (c *HeartbeatManagerImpl) StopHeartbeat() { + if c.IsHeartbeatRunning() { + close(c.stopHeartbeatC) + } +} + +func (c *HeartbeatManagerImpl) heartbeatData(t time.Time, counter *uint64) *model.DeviceDiagnosisHeartbeatDataType { + timestamp := t.UTC().Format(time.RFC3339) + + return &model.DeviceDiagnosisHeartbeatDataType{ + Timestamp: ×tamp, + HeartbeatCounter: counter, + HeartbeatTimeout: c.heartBeatTimeout, + } +} + +func (c *HeartbeatManagerImpl) updateHearbeatData(stopC chan struct{}, d time.Duration) { + ticker := time.NewTicker(d) + for { + select { + case <-ticker.C: + + heartbeatData := c.heartbeatData(time.Now(), c.heartBeatCounter()) + + // updating the data will automatically notify all subscribed remote features + c.localFeature.SetData(model.FunctionTypeDeviceDiagnosisHeartbeatData, heartbeatData) + + case <-stopC: + return + } + } +} + +func (c *HeartbeatManagerImpl) 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 *HeartbeatManagerImpl) heartBeatCounter() *uint64 { + i := atomic.AddUint64(&c.heartBeatNum, 1) + return &i +} diff --git a/spine/heartbeat_manager_test.go b/spine/heartbeat_manager_test.go new file mode 100644 index 0000000..26b1eba --- /dev/null +++ b/spine/heartbeat_manager_test.go @@ -0,0 +1,139 @@ +package spine + +import ( + "testing" + "time" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestHeartbeatManagerSuite(t *testing.T) { + suite.Run(t, new(HeartBeatManagerSuite)) +} + +type HeartBeatManagerSuite struct { + suite.Suite + + localDevice api.DeviceLocal + remoteDevice api.DeviceRemote + sut api.HeartbeatManager +} + +func (suite *HeartBeatManagerSuite) WriteSpineMessage([]byte) {} + +func (suite *HeartBeatManagerSuite) SetupSuite() { + suite.localDevice = NewDeviceLocalImpl("brand", "model", "serial", "code", "address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + + ski := "test" + sender := NewSender(suite) + suite.remoteDevice = NewDeviceRemoteImpl(suite.localDevice, ski, sender) + + _ = suite.localDevice.SetupRemoteDevice(ski, suite) + + suite.sut = suite.localDevice.HeartbeatManager() +} + +func (suite *HeartBeatManagerSuite) Test_HeartbeatFailure() { + err := suite.sut.StartHeartbeat() + assert.NotNil(suite.T(), err) +} + +func (suite *HeartBeatManagerSuite) Test_HeartbeatSuccess() { + entity := NewEntityLocalImpl(suite.localDevice, model.EntityTypeTypeCEM, []model.AddressEntityType{1}) + suite.localDevice.AddEntity(entity) + + localFeature := entity.GetOrAddFeature(model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeServer) + entity.AddFeature(localFeature) + + remoteEntity := NewEntityRemoteImpl(suite.remoteDevice, model.EntityTypeTypeEVSE, []model.AddressEntityType{1}) + suite.remoteDevice.AddEntity(remoteEntity) + + remoteFeature := NewFeatureRemoteImpl(remoteEntity.NextFeatureId(), remoteEntity, model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeClient) + remoteEntity.AddFeature(remoteFeature) + + subscrRequest := &model.SubscriptionManagementRequestCallType{ + ClientAddress: remoteFeature.Address(), + ServerAddress: localFeature.Address(), + ServerFeatureType: util.Ptr(model.FeatureTypeTypeDeviceDiagnosis), + } + + datagram := model.DatagramType{ + Header: model.HeaderType{ + SpecificationVersion: &SpecificationVersion, + AddressSource: &model.FeatureAddressType{ + Device: suite.remoteDevice.Address(), + Entity: []model.AddressEntityType{0}, + Feature: util.Ptr(model.AddressFeatureType(0)), + }, + AddressDestination: &model.FeatureAddressType{ + Device: suite.localDevice.Address(), + Entity: []model.AddressEntityType{0}, + Feature: util.Ptr(model.AddressFeatureType(0)), + }, + MsgCounter: util.Ptr(model.MsgCounterType(1000)), + CmdClassifier: util.Ptr(model.CmdClassifierTypeCall), + }, + Payload: model.PayloadType{ + Cmd: []model.CmdType{ + { + NodeManagementSubscriptionRequestCall: &model.NodeManagementSubscriptionRequestCallType{ + SubscriptionRequest: subscrRequest, + }, + }, + }, + }, + } + err := suite.localDevice.ProcessCmd(datagram, suite.remoteDevice) + assert.Nil(suite.T(), err) + + data := localFeature.DataCopy(model.FunctionTypeDeviceDiagnosisHeartbeatData) + assert.Nil(suite.T(), data) + + running := suite.sut.IsHeartbeatRunning() + assert.Equal(suite.T(), true, running) + + err = suite.sut.StartHeartbeat() + assert.Nil(suite.T(), err) + + time.Sleep(time.Second * 5) + + running = suite.sut.IsHeartbeatRunning() + assert.Equal(suite.T(), true, running) + + data = localFeature.DataCopy(model.FunctionTypeDeviceDiagnosisHeartbeatData) + assert.NotNil(suite.T(), data) + + fctData := data.(*model.DeviceDiagnosisHeartbeatDataType) + var resultCounter uint64 = 1 + assert.Equal(suite.T(), resultCounter, *fctData.HeartbeatCounter) + resultTimeout, err := fctData.HeartbeatTimeout.GetTimeDuration() + assert.Nil(suite.T(), err) + assert.Equal(suite.T(), time.Second*4, resultTimeout) + + subscrDelRequest := &model.SubscriptionManagementDeleteCallType{ + ClientAddress: remoteFeature.Address(), + ServerAddress: localFeature.Address(), + } + + datagram.Payload = model.PayloadType{ + Cmd: []model.CmdType{ + { + NodeManagementSubscriptionDeleteCall: &model.NodeManagementSubscriptionDeleteCallType{ + SubscriptionDelete: subscrDelRequest, + }, + }, + }, + } + + err = suite.localDevice.ProcessCmd(datagram, suite.remoteDevice) + assert.Nil(suite.T(), err) + + isHeartbeatRunning := suite.sut.IsHeartbeatRunning() + assert.Equal(suite.T(), false, isHeartbeatRunning) + + suite.sut.StopHeartbeat() +} diff --git a/spine/helper_test.go b/spine/helper_test.go new file mode 100644 index 0000000..ea299ae --- /dev/null +++ b/spine/helper_test.go @@ -0,0 +1,197 @@ +package spine + +import ( + "encoding/json" + "fmt" + "os" + "sync" + "testing" + "time" + + shipapi "github.com/enbility/ship-go/api" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/stretchr/testify/assert" +) + +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" +) + +type WriteMessageHandler struct { + sentMessages [][]byte + + mux sync.Mutex +} + +var _ shipapi.SpineDataConnection = (*WriteMessageHandler)(nil) + +func (t *WriteMessageHandler) WriteSpineMessage(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 loadFileData(t *testing.T, fileName string) []byte { + fileData, err := os.ReadFile(fileName) + if err != nil { + t.Fatal(err) + } + + 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 + + msg := writeHandler.ResultWithReference(msgCounterReference) + if msg == nil { + t.Fatal("acknowledge message was not sent!!") + } + + if err := json.Unmarshal(msg, &datagram); err != nil { + t.Fatal(err) + } + + cmd := datagram.Datagram.Payload.Cmd[0] + if cmd.ResultData != nil { + if cmd.ResultData.ErrorNumber != nil && uint(*cmd.ResultData.ErrorNumber) != uint(model.ErrorNumberTypeNoError) { + t.Fatal(fmt.Errorf("error '%d' result data received", uint(*cmd.ResultData.ErrorNumber))) + } + } +} + +func createLocalDeviceAndFeature(entityId uint, featureType model.FeatureTypeType) (api.FeatureLocal, api.FeatureLocal) { + localDevice := NewDeviceLocalImpl("Vendor", "DeviceName", "SerialNumber", "DeviceCode", "Address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + localDevice.address = util.Ptr(model.AddressDeviceType("Address")) + localEntity := NewEntityLocalImpl(localDevice, model.EntityTypeTypeEVSE, []model.AddressEntityType{model.AddressEntityType(entityId)}) + localDevice.AddEntity(localEntity) + localFeature := NewFeatureLocalImpl(localEntity.NextFeatureId(), localEntity, featureType, model.RoleTypeClient) + localEntity.AddFeature(localFeature) + localServerFeature := NewFeatureLocalImpl(localEntity.NextFeatureId(), localEntity, featureType, model.RoleTypeServer) + localEntity.AddFeature(localServerFeature) + + return localFeature, localServerFeature +} + +func createRemoteDeviceAndFeature(entityId uint, featureType model.FeatureTypeType, sender api.Sender) (api.FeatureRemote, api.FeatureRemote) { + localDevice := NewDeviceLocalImpl("Vendor", "DeviceName", "SerialNumber", "DeviceCode", "Address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + + remoteDevice := NewDeviceRemoteImpl(localDevice, "ski", sender) + remoteDevice.address = util.Ptr(model.AddressDeviceType("Address")) + remoteEntity := NewEntityRemoteImpl(remoteDevice, model.EntityTypeTypeEVSE, []model.AddressEntityType{model.AddressEntityType(entityId)}) + remoteDevice.AddEntity(remoteEntity) + remoteFeature := NewFeatureRemoteImpl(remoteEntity.NextFeatureId(), remoteEntity, featureType, model.RoleTypeClient) + remoteEntity.AddFeature(remoteFeature) + remoteServerFeature := NewFeatureRemoteImpl(remoteEntity.NextFeatureId(), remoteEntity, featureType, model.RoleTypeServer) + remoteEntity.AddFeature(remoteServerFeature) + + return remoteFeature, remoteServerFeature +} diff --git a/spine/nodemanagement.go b/spine/nodemanagement.go new file mode 100644 index 0000000..fcbeee7 --- /dev/null +++ b/spine/nodemanagement.go @@ -0,0 +1,114 @@ +package spine + +import ( + "fmt" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-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, + } +} + +var _ api.NodeManagement = (*NodeManagementImpl)(nil) + +type NodeManagementImpl struct { + *FeatureLocalImpl + entity api.EntityLocal +} + +func NewNodeManagementImpl(id uint, entity api.EntityLocal) *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() api.DeviceLocal { + return r.entity.Device() +} + +func (r *NodeManagementImpl) HandleMessage(message *api.Message) *model.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 model.NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) + } + + case message.Cmd.NodeManagementSubscriptionRequestCall != nil: + if err := r.handleMsgSubscriptionRequestCall(message, message.Cmd.NodeManagementSubscriptionRequestCall); err != nil { + return model.NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) + } + + case message.Cmd.NodeManagementSubscriptionDeleteCall != nil: + if err := r.handleMsgSubscriptionDeleteCall(message, message.Cmd.NodeManagementSubscriptionDeleteCall); err != nil { + return model.NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) + } + + case message.Cmd.NodeManagementSubscriptionData != nil: + if err := r.handleMsgSubscriptionData(message); err != nil { + return model.NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) + } + + case message.Cmd.NodeManagementBindingRequestCall != nil: + if err := r.handleMsgBindingRequestCall(message, message.Cmd.NodeManagementBindingRequestCall); err != nil { + return model.NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) + } + + case message.Cmd.NodeManagementBindingDeleteCall != nil: + if err := r.handleMsgBindingDeleteCall(message, message.Cmd.NodeManagementBindingDeleteCall); err != nil { + return model.NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) + } + + case message.Cmd.NodeManagementBindingData != nil: + if err := r.handleMsgBindingData(message); err != nil { + return model.NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) + } + + case message.Cmd.NodeManagementUseCaseData != nil: + if err := r.handleMsgUseCaseData(message, message.Cmd.NodeManagementUseCaseData); err != nil { + return model.NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) + } + + case message.Cmd.NodeManagementDestinationListData != nil: + if err := r.handleMsgDestinationListData(message, message.Cmd.NodeManagementDestinationListData); err != nil { + return model.NewErrorType(model.ErrorNumberTypeGeneralError, err.Error()) + } + + default: + return model.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 new file mode 100644 index 0000000..b07c6a7 --- /dev/null +++ b/spine/nodemanagement_binding.go @@ -0,0 +1,81 @@ +package spine + +import ( + "fmt" + + "github.com/ahmetb/go-linq/v3" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-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, + }, + } +} + +func NewNodeManagementBindingDeleteCallType(clientAddress *model.FeatureAddressType, serverAddress *model.FeatureAddressType) *model.NodeManagementBindingDeleteCallType { + return &model.NodeManagementBindingDeleteCallType{ + BindingDelete: &model.BindingManagementDeleteCallType{ + ClientAddress: clientAddress, + ServerAddress: serverAddress, + }, + } +} + +// route bindings request calls to the appropriate feature implementation and add the bindings to the current list +func (r *NodeManagementImpl) processReadBindingData(message *api.Message) error { + + var remoteDeviceBindings []model.BindingManagementEntryDataType + remoteDeviceBindingEntries := r.Device().BindingManager().Bindings(message.FeatureRemote.Device()) + linq.From(remoteDeviceBindingEntries).SelectT(func(s *api.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 *api.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 *api.Message, data *model.NodeManagementBindingRequestCallType) error { + switch message.CmdClassifier { + case model.CmdClassifierTypeCall: + return r.Device().BindingManager().AddBinding(message.FeatureRemote.Device(), *data.BindingRequest) + + default: + return fmt.Errorf("nodemanagement.handleBindingRequestCall: NodeManagementBindingRequestCall CmdClassifierType not implemented: %s", message.CmdClassifier) + } +} + +func (r *NodeManagementImpl) handleMsgBindingDeleteCall(message *api.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_destinationlist.go b/spine/nodemanagement_destinationlist.go new file mode 100644 index 0000000..a22e171 --- /dev/null +++ b/spine/nodemanagement_destinationlist.go @@ -0,0 +1,51 @@ +package spine + +import ( + "errors" + "fmt" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" +) + +func (r *NodeManagementImpl) RequestDestinationListData(remoteDeviceAddress *model.AddressDeviceType, sender api.Sender) (*model.MsgCounterType, *model.ErrorType) { + return nil, model.NewErrorTypeFromString("Not implemented") +} + +func (r *NodeManagementImpl) processReadDestinationListData(featureRemote api.FeatureRemote, 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 *api.Message, data model.NodeManagementDestinationListDataType) error { + return errors.New("Not implemented") +} + +func (r *NodeManagementImpl) handleMsgDestinationListData(message *api.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_detaileddiscovery.go b/spine/nodemanagement_detaileddiscovery.go new file mode 100644 index 0000000..96ea6f5 --- /dev/null +++ b/spine/nodemanagement_detaileddiscovery.go @@ -0,0 +1,266 @@ +package spine + +import ( + "errors" + "fmt" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" +) + +// request detailed discovery data from a remote device +func (r *NodeManagementImpl) RequestDetailedDiscovery(remoteDeviceSki string, remoteDeviceAddress *model.AddressDeviceType, sender api.Sender) (*model.MsgCounterType, *model.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 api.DeviceRemote, 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 *api.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 := api.EventPayload{ + Ski: remoteDevice.Ski(), + EventType: api.EventTypeDeviceChange, + ChangeType: api.ElementChangeAdd, + Device: remoteDevice, + Feature: message.FeatureRemote, + Data: data, + } + Events.Publish(payload) + + // publish event for each added remote entity + for _, entity := range entities { + payload := api.EventPayload{ + Ski: remoteDevice.Ski(), + EventType: api.EventTypeEntityChange, + ChangeType: api.ElementChangeAdd, + Device: remoteDevice, + Entity: entity, + Data: data, + } + Events.Publish(payload) + } + + return nil +} + +// handle incoming detailed discovery notify data +func (r *NodeManagementImpl) processNotifyDetailedDiscoveryData(message *api.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 := api.EventPayload{ + Ski: remoteDevice.Ski(), + EventType: api.EventTypeEntityChange, + ChangeType: api.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 := api.EventPayload{ + Ski: remoteDevice.Ski(), + EventType: api.EventTypeEntityChange, + ChangeType: api.ElementChangeRemove, + Device: remoteDevice, + Entity: removedEntity, + Data: data, + } + Events.Publish(payload) + + // remove all subscriptions for this entity + subscriptionMgr := r.Device().SubscriptionManager() + subscriptionMgr.RemoveSubscriptionsForEntity(removedEntity) + + // make sure Heartbeat Manager is up to date + r.Device().HeartbeatManager().UpdateHeartbeatOnSubscriptions() + + // remove all bindings for this entity + bindingMgr := r.Device().BindingManager() + bindingMgr.RemoveBindingsForEntity(removedEntity) + } + } + + return nil +} + +// func (f *NodeManagement) announceFeatureDiscovery(e 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.(ClientFeature); ok { +// if err := cf.ServerFound(rf); err != nil { +// return err +// } +// } +// } +// } +// } +// } + +// return nil +// } + +func (r *NodeManagementImpl) handleMsgDetailedDiscoveryData(message *api.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_detaileddiscovery_test.go b/spine/nodemanagement_detaileddiscovery_test.go new file mode 100644 index 0000000..063ab66 --- /dev/null +++ b/spine/nodemanagement_detaileddiscovery_test.go @@ -0,0 +1,193 @@ +package spine + +import ( + "testing" + "time" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/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 api.DeviceLocal + + remoteSki string + + writeHandler *WriteMessageHandler + remoteDevice api.DeviceRemote +} + +func (s *NodeManagementSuite) BeforeTest(suiteName, testName string) { + s.sut = NewDeviceLocalImpl("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode", + "TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + s.remoteSki = "TestRemoteSki" + + s.writeHandler = &WriteMessageHandler{} + _ = s.sut.SetupRemoteDevice(s.remoteSki, s.writeHandler) + s.remoteDevice = s.sut.RemoteDeviceForSki(s.remoteSki) +} + +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.remoteDevice.HandleSpineMesssage(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.remoteDevice.HandleSpineMesssage(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[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(), 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.remoteDevice.HandleSpineMesssage(loadFileData(s.T(), wallbox_detaileddiscoverydata_recv_reply_file_path)) + + // Act + msgCounter, _ := s.remoteDevice.HandleSpineMesssage(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[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.remoteDevice.HandleSpineMesssage(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.remoteDevice.HandleSpineMesssage(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(*NodeManagementAddress(s.sut.Address())) + assert.Equal(s.T(), 1, len(subscriptionsOnFeature)) +} + +func (s *NodeManagementSuite) TestDestinationList_SendReply() { + // Act + msgCounter, _ := s.remoteDevice.HandleSpineMesssage(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/spine/nodemanagement_subscription.go b/spine/nodemanagement_subscription.go new file mode 100644 index 0000000..675e513 --- /dev/null +++ b/spine/nodemanagement_subscription.go @@ -0,0 +1,94 @@ +package spine + +import ( + "fmt" + + "github.com/ahmetb/go-linq/v3" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-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, + }, + } +} + +func NewNodeManagementSubscriptionDeleteCallType(clientAddress *model.FeatureAddressType, serverAddress *model.FeatureAddressType) *model.NodeManagementSubscriptionDeleteCallType { + return &model.NodeManagementSubscriptionDeleteCallType{ + SubscriptionDelete: &model.SubscriptionManagementDeleteCallType{ + ClientAddress: clientAddress, + ServerAddress: serverAddress, + }, + } +} + +// route subscription request calls to the appropriate feature implementation and add the subscription to the current list +func (r *NodeManagementImpl) processReadSubscriptionData(message *api.Message) error { + + var remoteDeviceSubscriptions []model.SubscriptionManagementEntryDataType + remoteDeviceSubscriptionEntries := r.Device().SubscriptionManager().Subscriptions(message.FeatureRemote.Device()) + linq.From(remoteDeviceSubscriptionEntries).SelectT(func(s *api.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 *api.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 *api.Message, data *model.NodeManagementSubscriptionRequestCallType) error { + switch message.CmdClassifier { + case model.CmdClassifierTypeCall: + subscriptionMgr := r.Device().SubscriptionManager() + + err := subscriptionMgr.AddSubscription(message.FeatureRemote.Device(), *data.SubscriptionRequest) + if err == nil { + r.Device().HeartbeatManager().UpdateHeartbeatOnSubscriptions() + } + + return err + + default: + return fmt.Errorf("nodemanagement.handleSubscriptionRequestCall: NodeManagementSubscriptionRequestCall CmdClassifierType not implemented: %s", message.CmdClassifier) + } +} + +func (r *NodeManagementImpl) handleMsgSubscriptionDeleteCall(message *api.Message, data *model.NodeManagementSubscriptionDeleteCallType) error { + switch message.CmdClassifier { + case model.CmdClassifierTypeCall: + subscriptionMgr := r.Device().SubscriptionManager() + + err := subscriptionMgr.RemoveSubscription(*data.SubscriptionDelete, message.FeatureRemote.Device()) + if err == nil { + r.Device().HeartbeatManager().UpdateHeartbeatOnSubscriptions() + } + + return err + 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 new file mode 100644 index 0000000..774df2c --- /dev/null +++ b/spine/nodemanagement_test.go @@ -0,0 +1,156 @@ +package spine + +import ( + "reflect" + "testing" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/mocks" + "github.com/enbility/spine-go/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestNodemanagement_BindingCalls(t *testing.T) { + const bindingEntityId uint = 1 + const featureType = model.FeatureTypeTypeLoadControl + + senderMock := mocks.NewSender(t) + + _, serverFeature := createLocalDeviceAndFeature(bindingEntityId, featureType) + clientFeature, _ := createRemoteDeviceAndFeature(bindingEntityId, featureType, senderMock) + + 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.NodeManagementBindingData.BindingEntry)) + assert.True(t, reflect.DeepEqual(cmd.NodeManagementBindingData.BindingEntry[0].ClientAddress, clientFeature.Address())) + assert.True(t, reflect.DeepEqual(cmd.NodeManagementBindingData.BindingEntry[0].ServerAddress, serverFeature.Address())) + }).Return(nil).Once() + + requestMsg := api.Message{ + Cmd: model.CmdType{ + NodeManagementBindingRequestCall: NewNodeManagementBindingRequestCallType( + clientFeature.Address(), serverFeature.Address(), featureType), + }, + CmdClassifier: model.CmdClassifierTypeCall, + FeatureRemote: clientFeature, + } + + sut := NewNodeManagementImpl(0, serverFeature.Entity()) + + // Act + err := sut.HandleMessage(&requestMsg) + if assert.Nil(t, err) { + + dataMsg := api.Message{ + Cmd: model.CmdType{ + NodeManagementBindingData: &model.NodeManagementBindingDataType{}, + }, + CmdClassifier: model.CmdClassifierTypeCall, + FeatureRemote: clientFeature, + } + err = sut.HandleMessage(&dataMsg) + assert.Nil(t, err) + } + + senderMock.On("Reply", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + cmd := args.Get(2).(model.CmdType) + assert.Equal(t, 0, len(cmd.NodeManagementBindingData.BindingEntry)) + }).Return(nil).Once() + + deleteMsg := api.Message{ + Cmd: model.CmdType{ + NodeManagementBindingDeleteCall: NewNodeManagementBindingDeleteCallType( + clientFeature.Address(), serverFeature.Address()), + }, + CmdClassifier: model.CmdClassifierTypeCall, + FeatureRemote: clientFeature, + } + + // Act + err = sut.HandleMessage(&deleteMsg) + if assert.Nil(t, err) { + + dataMsg := api.Message{ + Cmd: model.CmdType{ + NodeManagementBindingData: &model.NodeManagementBindingDataType{}, + }, + CmdClassifier: model.CmdClassifierTypeCall, + FeatureRemote: clientFeature, + } + err = sut.HandleMessage(&dataMsg) + assert.Nil(t, err) + } +} + +func TestNodemanagement_SubscriptionCalls(t *testing.T) { + const subscriptionEntityId uint = 1 + const featureType = model.FeatureTypeTypeDeviceClassification + + senderMock := mocks.NewSender(t) + + _, serverFeature := createLocalDeviceAndFeature(subscriptionEntityId, featureType) + clientFeature, _ := createRemoteDeviceAndFeature(subscriptionEntityId, featureType, senderMock) + + 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() + + requestMsg := api.Message{ + Cmd: model.CmdType{ + NodeManagementSubscriptionRequestCall: NewNodeManagementSubscriptionRequestCallType( + clientFeature.Address(), serverFeature.Address(), featureType), + }, + CmdClassifier: model.CmdClassifierTypeCall, + FeatureRemote: clientFeature, + } + + sut := NewNodeManagementImpl(0, serverFeature.Entity()) + + // Act + err := sut.HandleMessage(&requestMsg) + if assert.Nil(t, err) { + + dataMsg := api.Message{ + Cmd: model.CmdType{ + NodeManagementSubscriptionData: &model.NodeManagementSubscriptionDataType{}, + }, + CmdClassifier: model.CmdClassifierTypeCall, + FeatureRemote: clientFeature, + } + err = sut.HandleMessage(&dataMsg) + assert.Nil(t, err) + } + + senderMock.On("Reply", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + cmd := args.Get(2).(model.CmdType) + assert.Equal(t, 0, len(cmd.NodeManagementSubscriptionData.SubscriptionEntry)) + }).Return(nil).Once() + + deleteMsg := api.Message{ + Cmd: model.CmdType{ + NodeManagementSubscriptionDeleteCall: NewNodeManagementSubscriptionDeleteCallType( + clientFeature.Address(), serverFeature.Address()), + }, + CmdClassifier: model.CmdClassifierTypeCall, + FeatureRemote: clientFeature, + } + + // Act + err = sut.HandleMessage(&deleteMsg) + if assert.Nil(t, err) { + + dataMsg := api.Message{ + Cmd: model.CmdType{ + NodeManagementSubscriptionData: &model.NodeManagementSubscriptionDataType{}, + }, + CmdClassifier: model.CmdClassifierTypeCall, + FeatureRemote: clientFeature, + } + err = sut.HandleMessage(&dataMsg) + assert.Nil(t, err) + } +} diff --git a/spine/nodemanagement_usecase.go b/spine/nodemanagement_usecase.go new file mode 100644 index 0000000..db88188 --- /dev/null +++ b/spine/nodemanagement_usecase.go @@ -0,0 +1,74 @@ +package spine + +import ( + "errors" + "fmt" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" +) + +func (r *NodeManagementImpl) RequestUseCaseData(remoteDeviceSki string, remoteDeviceAddress *model.AddressDeviceType, sender api.Sender) (*model.MsgCounterType, *model.ErrorType) { + rfAdress := featureAddressType(NodeManagementFeatureId, EntityAddressType(remoteDeviceAddress, DeviceInformationAddressEntity)) + cmd := model.CmdType{ + NodeManagementUseCaseData: &model.NodeManagementUseCaseDataType{}, + } + return r.RequestDataBySenderAddress(cmd, sender, remoteDeviceSki, rfAdress, defaultMaxResponseDelay) +} + +func (r *NodeManagementImpl) NotifyUseCaseData(remoteDevice api.DeviceRemote) (*model.MsgCounterType, error) { + rfAdress := featureAddressType(NodeManagementFeatureId, EntityAddressType(remoteDevice.Address(), DeviceInformationAddressEntity)) + rEntity := remoteDevice.Entity([]model.AddressEntityType{model.AddressEntityType(DeviceInformationEntityId)}) + + featureRemote := remoteDevice.FeatureByEntityTypeAndRole(rEntity, model.FeatureTypeTypeNodeManagement, model.RoleTypeSpecial) + + fd := r.functionData(model.FunctionTypeNodeManagementUseCaseData) + cmd := fd.NotifyCmdType(nil, nil, false, nil) + + return featureRemote.Sender().Notify(r.Address(), rfAdress, cmd) +} + +func (r *NodeManagementImpl) processReadUseCaseData(featureRemote api.FeatureRemote, requestHeader *model.HeaderType) error { + cmd := r.functionData(model.FunctionTypeNodeManagementUseCaseData).ReplyCmdType(false) + + return featureRemote.Sender().Reply(requestHeader, r.Address(), cmd) +} + +func (r *NodeManagementImpl) processReplyUseCaseData(message *api.Message, data *model.NodeManagementUseCaseDataType) error { + message.FeatureRemote.UpdateData(model.FunctionTypeNodeManagementUseCaseData, data, nil, nil) + + // the data was updated, so send an event, other event handlers may watch out for this as well + payload := api.EventPayload{ + Ski: message.FeatureRemote.Device().Ski(), + EventType: api.EventTypeDataChange, + ChangeType: api.ElementChangeUpdate, + Feature: message.FeatureRemote, + Device: message.FeatureRemote.Device(), + Entity: message.FeatureRemote.Entity(), + CmdClassifier: util.Ptr(message.CmdClassifier), + Data: data, + } + Events.Publish(payload) + + return nil +} + +func (r *NodeManagementImpl) handleMsgUseCaseData(message *api.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 new file mode 100644 index 0000000..5868d8d --- /dev/null +++ b/spine/operations.go @@ -0,0 +1,50 @@ +package spine + +import ( + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" +) + +type Operations struct { + read, write bool +} + +var _ api.Operations = (*Operations)(nil) + +func NewOperations(read, write bool) *Operations { + return &Operations{ + read: read, + write: write, + } +} + +func (r *Operations) Read() bool { + return r.read +} + +func (r *Operations) Write() bool { + return r.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/operations_test.go b/spine/operations_test.go new file mode 100644 index 0000000..b9cbdbe --- /dev/null +++ b/spine/operations_test.go @@ -0,0 +1,36 @@ +package spine + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestOperations(t *testing.T) { + operations := NewOperations(true, false) + assert.NotNil(t, operations) + + text := operations.String() + assert.NotEqual(t, 0, len(text)) + + data := operations.Information() + assert.NotNil(t, data) + + operations2 := NewOperations(true, true) + assert.NotNil(t, operations2) + + text = operations2.String() + assert.NotEqual(t, 0, len(text)) + + data = operations2.Information() + assert.NotNil(t, data) + + operations3 := NewOperations(false, false) + assert.NotNil(t, operations3) + + text = operations3.String() + assert.NotEqual(t, 0, len(text)) + + data = operations3.Information() + assert.NotNil(t, data) +} diff --git a/spine/pending_requests.go b/spine/pending_requests.go new file mode 100644 index 0000000..139a724 --- /dev/null +++ b/spine/pending_requests.go @@ -0,0 +1,113 @@ +package spine + +import ( + "fmt" + "sync" + "time" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" +) + +type dataErrorPair struct { + data any + errorResult *model.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 := model.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() api.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) *model.ErrorType { + return r.setResponse(ski, counter, data, nil) +} + +func (r *PendingRequestsImpl) SetResult(ski string, counter model.MsgCounterType, errorResult *model.ErrorType) *model.ErrorType { + return r.setResponse(ski, counter, nil, errorResult) +} + +func (r *PendingRequestsImpl) GetData(ski string, counter model.MsgCounterType) (any, *model.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) *model.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, *model.ErrorType) { + rq, exists := r.requestMap.Load(r.mapKey(ski, counter)) + if !exists { + return nil, model.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 *model.ErrorType) *model.ErrorType { + + request, err := r.getRequest(ski, counter) + if err != nil { + return err + } + if len(request.response) > 0 { + return model.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 new file mode 100644 index 0000000..64f503c --- /dev/null +++ b/spine/pending_requests_test.go @@ -0,0 +1,124 @@ +package spine + +import ( + "testing" + "time" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +type PendingRequestsTestSuite struct { + suite.Suite + sut api.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, model.NewErrorTypeFromString("unknown error")) + assert.Nil(suite.T(), err) +} + +func (suite *PendingRequestsTestSuite) TestPendingRequests_SetResult_SetResult() { + _ = suite.sut.SetResult(suite.ski, suite.counter, model.NewErrorTypeFromString("unknown error")) + // Act + err := suite.sut.SetResult(suite.ski, suite.counter, model.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, model.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, model.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/send.go b/spine/send.go new file mode 100644 index 0000000..5bd9d74 --- /dev/null +++ b/spine/send.go @@ -0,0 +1,274 @@ +package spine + +import ( + "encoding/json" + "errors" + "sync/atomic" + + shipapi "github.com/enbility/ship-go/api" + "github.com/enbility/ship-go/logging" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" + lru "github.com/hashicorp/golang-lru/v2" +) + +type SenderImpl struct { + msgNum uint64 // 64bit values need to be defined on top of the struct to make atomic commands work on 32bit systems + + // we cache the last 100 notify messages, so we can find the matching item for result errors being returned + datagramNotifyCache *lru.Cache[model.MsgCounterType, model.DatagramType] + + writeHandler shipapi.SpineDataConnection +} + +var _ api.Sender = (*SenderImpl)(nil) + +func NewSender(writeI shipapi.SpineDataConnection) api.Sender { + cache, _ := lru.New[model.MsgCounterType, model.DatagramType](100) + return &SenderImpl{ + datagramNotifyCache: cache, + writeHandler: writeI, + } +} + +// return the datagram for a given msgCounter (only availbe for Notify messasges!), error if not found +func (c *SenderImpl) DatagramForMsgCounter(msgCounter model.MsgCounterType) (model.DatagramType, error) { + if datagram, ok := c.datagramNotifyCache.Get(msgCounter); ok { + return datagram, nil + } + + return model.DatagramType{}, errors.New("msgCounter not found") +} + +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 *model.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 *model.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}, + }, + } + + c.datagramNotifyCache.Add(*msgCounter, datagram) + + 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 subscription deletion request to a remote server feature +func (c *SenderImpl) Unsubscribe(senderAddress, destinationAddress *model.FeatureAddressType) (*model.MsgCounterType, error) { + + cmd := model.CmdType{ + NodeManagementSubscriptionDeleteCall: NewNodeManagementSubscriptionDeleteCallType(senderAddress, destinationAddress), + } + + // 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}) +} + +// Send a binding request to a remote server feature +func (c *SenderImpl) Unbind(senderAddress, destinationAddress *model.FeatureAddressType) (*model.MsgCounterType, error) { + cmd := model.CmdType{ + NodeManagementBindingDeleteCall: NewNodeManagementBindingDeleteCallType(senderAddress, destinationAddress), + } + + // 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/send_test.go b/spine/send_test.go new file mode 100644 index 0000000..443c893 --- /dev/null +++ b/spine/send_test.go @@ -0,0 +1,177 @@ +package spine + +import ( + "encoding/json" + "testing" + + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" +) + +func TestSender_Reply_MsgCounter(t *testing.T) { + temp := &WriteMessageHandler{} + sut := NewSender(temp) + + senderAddress := featureAddressType(1, NewEntityAddressType("Sender", []uint{1})) + destinationAddress := featureAddressType(2, NewEntityAddressType("destination", []uint{1})) + requestHeader := &model.HeaderType{ + AddressSource: senderAddress, + AddressDestination: destinationAddress, + MsgCounter: util.Ptr(model.MsgCounterType(10)), + } + cmd := model.CmdType{ + ResultData: &model.ResultDataType{ErrorNumber: util.Ptr(model.ErrorNumberType(model.ErrorNumberTypeNoError))}, + } + + err := sut.Reply(requestHeader, senderAddress, cmd) + assert.NoError(t, err) + + // Act + err = sut.Reply(requestHeader, senderAddress, cmd) + assert.NoError(t, err) + expectedMsgCounter := 2 //because Notify was called twice + + sentBytes := temp.LastMessage() + var sentDatagram model.Datagram + assert.NoError(t, json.Unmarshal(sentBytes, &sentDatagram)) + assert.Equal(t, expectedMsgCounter, int(*sentDatagram.Datagram.Header.MsgCounter)) +} + +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.LastMessage() + var sentDatagram model.Datagram + assert.NoError(t, json.Unmarshal(sentBytes, &sentDatagram)) + assert.Equal(t, expectedMsgCounter, int(*sentDatagram.Datagram.Header.MsgCounter)) + + _, err = sut.DatagramForMsgCounter(model.MsgCounterType(2)) + assert.NoError(t, err) + + _, err = sut.DatagramForMsgCounter(model.MsgCounterType(3)) + assert.Error(t, err) +} + +func TestSender_Write_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.Write(senderAddress, destinationAddress, cmd) + assert.NoError(t, err) + + // Act + _, err = sut.Write(senderAddress, destinationAddress, cmd) + assert.NoError(t, err) + expectedMsgCounter := 2 //because Write was called twice + + sentBytes := temp.LastMessage() + var sentDatagram model.Datagram + assert.NoError(t, json.Unmarshal(sentBytes, &sentDatagram)) + assert.Equal(t, expectedMsgCounter, int(*sentDatagram.Datagram.Header.MsgCounter)) +} + +func TestSender_Subscribe_MsgCounter(t *testing.T) { + temp := &WriteMessageHandler{} + sut := NewSender(temp) + + senderAddress := featureAddressType(1, NewEntityAddressType("Sender", []uint{1})) + destinationAddress := featureAddressType(2, NewEntityAddressType("destination", []uint{1})) + + _, err := sut.Subscribe(senderAddress, destinationAddress, model.FeatureTypeTypeLoadControl) + assert.NoError(t, err) + + // Act + _, err = sut.Subscribe(senderAddress, destinationAddress, model.FeatureTypeTypeLoadControl) + assert.NoError(t, err) + expectedMsgCounter := 2 //because Write was called twice + + sentBytes := temp.LastMessage() + var sentDatagram model.Datagram + assert.NoError(t, json.Unmarshal(sentBytes, &sentDatagram)) + assert.Equal(t, expectedMsgCounter, int(*sentDatagram.Datagram.Header.MsgCounter)) +} + +func TestSender_Unsubscribe_MsgCounter(t *testing.T) { + temp := &WriteMessageHandler{} + sut := NewSender(temp) + + senderAddress := featureAddressType(1, NewEntityAddressType("Sender", []uint{1})) + destinationAddress := featureAddressType(2, NewEntityAddressType("destination", []uint{1})) + + _, err := sut.Unsubscribe(senderAddress, destinationAddress) + assert.NoError(t, err) + + // Act + _, err = sut.Unsubscribe(senderAddress, destinationAddress) + assert.NoError(t, err) + expectedMsgCounter := 2 //because Write was called twice + + sentBytes := temp.LastMessage() + var sentDatagram model.Datagram + assert.NoError(t, json.Unmarshal(sentBytes, &sentDatagram)) + assert.Equal(t, expectedMsgCounter, int(*sentDatagram.Datagram.Header.MsgCounter)) +} + +func TestSender_Bind_MsgCounter(t *testing.T) { + temp := &WriteMessageHandler{} + sut := NewSender(temp) + + senderAddress := featureAddressType(1, NewEntityAddressType("Sender", []uint{1})) + destinationAddress := featureAddressType(2, NewEntityAddressType("destination", []uint{1})) + + _, err := sut.Bind(senderAddress, destinationAddress, model.FeatureTypeTypeLoadControl) + assert.NoError(t, err) + + // Act + _, err = sut.Bind(senderAddress, destinationAddress, model.FeatureTypeTypeLoadControl) + assert.NoError(t, err) + expectedMsgCounter := 2 //because Write was called twice + + sentBytes := temp.LastMessage() + var sentDatagram model.Datagram + assert.NoError(t, json.Unmarshal(sentBytes, &sentDatagram)) + assert.Equal(t, expectedMsgCounter, int(*sentDatagram.Datagram.Header.MsgCounter)) +} + +func TestSender_Unbind_MsgCounter(t *testing.T) { + temp := &WriteMessageHandler{} + sut := NewSender(temp) + + senderAddress := featureAddressType(1, NewEntityAddressType("Sender", []uint{1})) + destinationAddress := featureAddressType(2, NewEntityAddressType("destination", []uint{1})) + + _, err := sut.Unbind(senderAddress, destinationAddress) + assert.NoError(t, err) + + // Act + _, err = sut.Unbind(senderAddress, destinationAddress) + assert.NoError(t, err) + expectedMsgCounter := 2 //because Write was called twice + + sentBytes := temp.LastMessage() + 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 new file mode 100644 index 0000000..63515ed --- /dev/null +++ b/spine/subscription_manager.go @@ -0,0 +1,222 @@ +package spine + +import ( + "errors" + "fmt" + "reflect" + "sync" + "sync/atomic" + + "github.com/ahmetb/go-linq/v3" + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" +) + +type SubscriptionManagerImpl struct { + localDevice api.DeviceLocal + + subscriptionNum uint64 + subscriptionEntries []*api.SubscriptionEntry + + mux sync.Mutex + // TODO: add persistence +} + +func NewSubscriptionManager(localDevice api.DeviceLocal) *SubscriptionManagerImpl { + c := &SubscriptionManagerImpl{ + subscriptionNum: 0, + localDevice: localDevice, + } + + return c +} + +// is sent from the client (remote device) to the server (local device) +func (c *SubscriptionManagerImpl) AddSubscription(remoteDevice api.DeviceRemote, data model.SubscriptionManagementRequestCallType) error { + + serverFeature := c.localDevice.FeatureByAddress(data.ServerAddress) + if serverFeature == nil { + return fmt.Errorf("server feature '%s' in local device '%s' not found", data.ServerAddress, *c.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 := &api.SubscriptionEntry{ + Id: c.subscriptionId(), + ServerFeature: serverFeature, + ClientFeature: clientFeature, + } + + c.mux.Lock() + defer c.mux.Unlock() + + 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 := api.EventPayload{ + Ski: remoteDevice.Ski(), + EventType: api.EventTypeSubscriptionChange, + ChangeType: api.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 api.DeviceRemote) error { + var newSubscriptionEntries []*api.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. + + var clientAddress model.FeatureAddressType + util.DeepCopy(data.ClientAddress, &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()) + } + + serverFeature := c.localDevice.FeatureByAddress(data.ServerAddress) + if serverFeature == nil { + return fmt.Errorf("server feature '%s' in local device '%s' not found", data.ServerAddress, *c.localDevice.Address()) + } + + c.mux.Lock() + defer c.mux.Unlock() + + for _, item := range c.subscriptionEntries { + itemAddress := item.ClientFeature.Address() + + if !reflect.DeepEqual(*itemAddress, clientAddress) && + !reflect.DeepEqual(item.ServerFeature, serverFeature) { + 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 := api.EventPayload{ + Ski: remoteDevice.Ski(), + EventType: api.EventTypeSubscriptionChange, + ChangeType: api.ElementChangeRemove, + Data: data, + Device: remoteDevice, + Feature: clientFeature, + } + Events.Publish(payload) + + return nil +} + +// Remove all existing subscriptions for a given remote device +func (c *SubscriptionManagerImpl) RemoveSubscriptionsForDevice(remoteDevice api.DeviceRemote) { + if remoteDevice == nil { + return + } + + for _, entity := range remoteDevice.Entities() { + c.RemoveSubscriptionsForEntity(entity) + } +} + +// Remove all existing subscriptions for a given remote device entity +func (c *SubscriptionManagerImpl) RemoveSubscriptionsForEntity(remoteEntity api.EntityRemote) { + if remoteEntity == nil { + return + } + + c.mux.Lock() + defer c.mux.Unlock() + + var newSubscriptionEntries []*api.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 := api.EventPayload{ + Ski: remoteEntity.Device().Ski(), + EventType: api.EventTypeSubscriptionChange, + ChangeType: api.ElementChangeRemove, + Entity: remoteEntity, + Feature: clientFeature, + } + Events.Publish(payload) + } + + c.subscriptionEntries = newSubscriptionEntries +} + +func (c *SubscriptionManagerImpl) Subscriptions(remoteDevice api.DeviceRemote) []*api.SubscriptionEntry { + var result []*api.SubscriptionEntry + + c.mux.Lock() + defer c.mux.Unlock() + + linq.From(c.subscriptionEntries).WhereT(func(s *api.SubscriptionEntry) bool { + return s.ClientFeature.Device().Ski() == remoteDevice.Ski() + }).ToSlice(&result) + + return result +} + +func (c *SubscriptionManagerImpl) SubscriptionsOnFeature(featureAddress model.FeatureAddressType) []*api.SubscriptionEntry { + var result []*api.SubscriptionEntry + + c.mux.Lock() + defer c.mux.Unlock() + + linq.From(c.subscriptionEntries).WhereT(func(s *api.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 api.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/subscription_manager_test.go b/spine/subscription_manager_test.go new file mode 100644 index 0000000..524abf7 --- /dev/null +++ b/spine/subscription_manager_test.go @@ -0,0 +1,97 @@ +package spine + +import ( + "testing" + "time" + + "github.com/enbility/spine-go/api" + "github.com/enbility/spine-go/model" + "github.com/enbility/spine-go/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +func TestSubscriptionManagerSuite(t *testing.T) { + suite.Run(t, new(SubscriptionManagerSuite)) +} + +type SubscriptionManagerSuite struct { + suite.Suite + + localDevice api.DeviceLocal + remoteDevice api.DeviceRemote + sut api.SubscriptionManager +} + +func (suite *SubscriptionManagerSuite) WriteSpineMessage([]byte) {} + +func (suite *SubscriptionManagerSuite) SetupSuite() { + suite.localDevice = NewDeviceLocalImpl("brand", "model", "serial", "code", "address", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4) + + ski := "test" + sender := NewSender(suite) + suite.remoteDevice = NewDeviceRemoteImpl(suite.localDevice, ski, sender) + + _ = suite.localDevice.SetupRemoteDevice(ski, suite) + + suite.sut = NewSubscriptionManager(suite.localDevice) +} + +func (suite *SubscriptionManagerSuite) Test_Subscriptions() { + entity := NewEntityLocalImpl(suite.localDevice, model.EntityTypeTypeCEM, []model.AddressEntityType{1}) + suite.localDevice.AddEntity(entity) + + localFeature := entity.GetOrAddFeature(model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeServer) + + remoteEntity := NewEntityRemoteImpl(suite.remoteDevice, model.EntityTypeTypeEVSE, []model.AddressEntityType{1}) + suite.remoteDevice.AddEntity(remoteEntity) + + remoteFeature := NewFeatureRemoteImpl(remoteEntity.NextFeatureId(), remoteEntity, model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeClient) + remoteFeature.Address().Device = util.Ptr(model.AddressDeviceType("remoteDevice")) + remoteEntity.AddFeature(remoteFeature) + + subscrRequest := model.SubscriptionManagementRequestCallType{ + ClientAddress: remoteFeature.Address(), + ServerAddress: localFeature.Address(), + ServerFeatureType: util.Ptr(model.FeatureTypeTypeDeviceDiagnosis), + } + + subMgr := suite.localDevice.SubscriptionManager() + err := subMgr.AddSubscription(suite.remoteDevice, subscrRequest) + assert.Nil(suite.T(), err) + + subs := subMgr.Subscriptions(suite.remoteDevice) + assert.Equal(suite.T(), 1, len(subs)) + + err = subMgr.AddSubscription(suite.remoteDevice, subscrRequest) + assert.NotNil(suite.T(), err) + + subs = subMgr.Subscriptions(suite.remoteDevice) + assert.Equal(suite.T(), 1, len(subs)) + + subscrDelete := model.SubscriptionManagementDeleteCallType{ + ClientAddress: remoteFeature.Address(), + ServerAddress: localFeature.Address(), + } + + err = subMgr.RemoveSubscription(subscrDelete, suite.remoteDevice) + assert.Nil(suite.T(), err) + + subs = subMgr.Subscriptions(suite.remoteDevice) + assert.Equal(suite.T(), 0, len(subs)) + + err = subMgr.RemoveSubscription(subscrDelete, suite.remoteDevice) + assert.NotNil(suite.T(), err) + + subMgr = suite.localDevice.SubscriptionManager() + err = subMgr.AddSubscription(suite.remoteDevice, subscrRequest) + assert.Nil(suite.T(), err) + + subs = subMgr.Subscriptions(suite.remoteDevice) + assert.Equal(suite.T(), 1, len(subs)) + + subMgr.RemoveSubscriptionsForDevice(suite.remoteDevice) + + subs = subMgr.Subscriptions(suite.remoteDevice) + assert.Equal(suite.T(), 0, len(subs)) +} diff --git a/spine/testdata/nm_destinationListData_recv_read.json b/spine/testdata/nm_destinationListData_recv_read.json new file mode 100644 index 0000000..9c4c1f6 --- /dev/null +++ b/spine/testdata/nm_destinationListData_recv_read.json @@ -0,0 +1,29 @@ +{ + "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/spine/testdata/nm_destinationListData_send_reply_expected.json b/spine/testdata/nm_destinationListData_send_reply_expected.json new file mode 100644 index 0000000..f5c89a4 --- /dev/null +++ b/spine/testdata/nm_destinationListData_send_reply_expected.json @@ -0,0 +1,43 @@ +{ + "datagram": { + "header": { + "specificationVersion": "1.3.0", + "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/spine/testdata/nm_detaileddiscoverydata_recv_read.json b/spine/testdata/nm_detaileddiscoverydata_recv_read.json new file mode 100644 index 0000000..536b5d3 --- /dev/null +++ b/spine/testdata/nm_detaileddiscoverydata_recv_read.json @@ -0,0 +1,29 @@ +{ + "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/spine/testdata/nm_detaileddiscoverydata_recv_read_ack.json b/spine/testdata/nm_detaileddiscoverydata_recv_read_ack.json new file mode 100644 index 0000000..fc16954 --- /dev/null +++ b/spine/testdata/nm_detaileddiscoverydata_recv_read_ack.json @@ -0,0 +1,30 @@ +{ + "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/spine/testdata/nm_detaileddiscoverydata_send_read_expected.json b/spine/testdata/nm_detaileddiscoverydata_send_read_expected.json new file mode 100644 index 0000000..02d814c --- /dev/null +++ b/spine/testdata/nm_detaileddiscoverydata_send_read_expected.json @@ -0,0 +1,29 @@ +{ + "datagram": { + "header": { + "specificationVersion": "1.3.0", + "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/spine/testdata/nm_detaileddiscoverydata_send_reply_expected.json b/spine/testdata/nm_detaileddiscoverydata_send_reply_expected.json new file mode 100644 index 0000000..bc36322 --- /dev/null +++ b/spine/testdata/nm_detaileddiscoverydata_send_reply_expected.json @@ -0,0 +1,143 @@ +{ + "datagram": { + "header": { + "specificationVersion": "1.3.0", + "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.3.0" + ] + }, + "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/spine/testdata/nm_detaileddiscoverydata_send_result_expected.json b/spine/testdata/nm_detaileddiscoverydata_send_result_expected.json new file mode 100644 index 0000000..3384839 --- /dev/null +++ b/spine/testdata/nm_detaileddiscoverydata_send_result_expected.json @@ -0,0 +1,33 @@ +{ + "datagram": { + "header": { + "specificationVersion": "1.3.0", + "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/spine/testdata/nm_subscriptionRequestCall_recv_call.json b/spine/testdata/nm_subscriptionRequestCall_recv_call.json new file mode 100644 index 0000000..3061f94 --- /dev/null +++ b/spine/testdata/nm_subscriptionRequestCall_recv_call.json @@ -0,0 +1,48 @@ +{ + "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/spine/testdata/nm_subscriptionRequestCall_send_result_expected.json b/spine/testdata/nm_subscriptionRequestCall_send_result_expected.json new file mode 100644 index 0000000..9c369b6 --- /dev/null +++ b/spine/testdata/nm_subscriptionRequestCall_send_result_expected.json @@ -0,0 +1,33 @@ +{ + "datagram": { + "header": { + "specificationVersion": "1.3.0", + "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/spine/testdata/nm_usecaseinformationlistdata_recv_reply.json b/spine/testdata/nm_usecaseinformationlistdata_recv_reply.json new file mode 100644 index 0000000..14d8696 --- /dev/null +++ b/spine/testdata/nm_usecaseinformationlistdata_recv_reply.json @@ -0,0 +1,120 @@ +{ + "datagram": { + "header": { + "specificationVersion": "1.3.0", + "addressSource": { + "device": "TestDeviceAddress", + "entity": [ + 0 + ], + "feature": 0 + }, + "addressDestination": { + "device": "HEMS", + "entity": [ + 0 + ], + "feature": 0 + }, + "msgCounter": 2, + "msgCounterReference": 1, + "cmdClassifier": "reply" + }, + "payload": { + "cmd": [ + { + "nodeManagementUseCaseData": { + "useCaseInformation": [ + { + "address": { + "device": "d:_i:47859_Elli-Wallbox-xxxxxxxxxx" + }, + "actor": "EVSE", + "useCaseSupport": [ + { + "useCaseName": "evseCommissioningAndConfiguration", + "useCaseVersion": "1.0.1", + "scenarioSupport": [ + 1, + 2 + ] + }, + { + "useCaseName": "evChargingSummary", + "useCaseVersion": "1.0.1", + "scenarioSupport": [ + 1 + ] + } + ] + }, + { + "address": { + "device": "d:_i:47859_Elli-Wallbox-2041A0ZW5R" + }, + "actor": "EV", + "useCaseSupport": [ + { + "useCaseName": "evCommissioningAndConfiguration", + "useCaseVersion": "1.0.1", + "scenarioSupport": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + { + "useCaseName": "overloadProtectionByEvChargingCurrentCurtailment", + "useCaseVersion": "1.0.1", + "scenarioSupport": [ + 1, + 2, + 3 + ] + }, + { + "useCaseName": "coordinatedEvCharging", + "useCaseVersion": "1.0.1", + "scenarioSupport": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + { + "useCaseName": "measurementOfElectricityDuringEvCharging", + "useCaseVersion": "1.0.1", + "scenarioSupport": [ + 1, + 2, + 3 + ] + }, + { + "useCaseName": "optimizationOfSelfConsumptionDuringEvCharging", + "useCaseVersion": "1.0.1", + "scenarioSupport": [ + 1, + 2, + 3 + ] + } + ] + } + ] + } + } + ] + } + } +} \ No newline at end of file diff --git a/spine/testdata/wallbox_detaileddiscoverydata_recv_notify.json b/spine/testdata/wallbox_detaileddiscoverydata_recv_notify.json new file mode 100644 index 0000000..3964c5e --- /dev/null +++ b/spine/testdata/wallbox_detaileddiscoverydata_recv_notify.json @@ -0,0 +1,376 @@ +{ + "datagram": { + "header": { + "specificationVersion": "1.3.0", + "addressSource": { + "device": "Wallbox", + "entity": [ + 0 + ], + "feature": 0 + }, + "addressDestination": { + "device": "HEMS", + "entity": [ + 0 + ], + "feature": 0 + }, + "msgCounter": 3, + "cmdClassifier": "notify", + "ackRequest":true + }, + "payload": { + "cmd": [ + { + "function": "nodeManagementDetailedDiscoveryData", + "filter": [ + { + "cmdControl": { + "partial": {} + } + } + ], + "nodeManagementDetailedDiscoveryData": { + "deviceInformation": { + "description": { + "deviceAddress": { + "device": "Wallbox" + } + } + }, + "entityInformation": [ + { + "description": { + "entityAddress": { + "entity": [ + 1, + 1 + ] + }, + "entityType": "EV", + "lastStateChange": "added" + } + } + ], + "featureInformation": [ + { + "description": { + "featureAddress": { + "entity": [ + 1, + 1 + ], + "feature": 4 + }, + "featureType": "DeviceClassification", + "role": "server", + "supportedFunction": [ + { + "function": "deviceClassificationManufacturerData", + "possibleOperations": { + "read": { + "partial": {} + } + } + } + ] + } + }, + { + "description": { + "featureAddress": { + "entity": [ + 1, + 1 + ], + "feature": 5 + }, + "featureType": "DeviceDiagnosis", + "role": "server", + "supportedFunction": [ + { + "function": "deviceDiagnosisStateData", + "possibleOperations": { + "read": { + "partial": {} + } + } + } + ] + } + }, + { + "description": { + "featureAddress": { + "entity": [ + 1, + 1 + ], + "feature": 7 + }, + "featureType": "ElectricalConnection", + "role": "server", + "supportedFunction": [ + { + "function": "electricalConnectionParameterDescriptionListData", + "possibleOperations": { + "read": { + "partial": {} + } + } + }, + { + "function": "electricalConnectionPermittedValueSetListData", + "possibleOperations": { + "read": { + "partial": {} + } + } + }, + { + "function": "electricalConnectionDescriptionListData", + "possibleOperations": { + "read": { + "partial": {} + } + } + } + ] + } + }, + { + "description": { + "featureAddress": { + "entity": [ + 1, + 1 + ], + "feature": 10 + }, + "featureType": "LoadControl", + "role": "server", + "supportedFunction": [ + { + "function": "loadControlLimitDescriptionListData", + "possibleOperations": { + "read": { + "partial": {} + } + } + }, + { + "function": "loadControlLimitListData", + "possibleOperations": { + "read": { + "partial": {} + }, + "write": { + "partial": {} + } + } + } + ] + } + }, + { + "description": { + "featureAddress": { + "entity": [ + 1, + 1 + ], + "feature": 11 + }, + "featureType": "Measurement", + "role": "server", + "supportedFunction": [ + { + "function": "measurementConstraintsListData", + "possibleOperations": { + "read": { + "partial": {} + } + } + }, + { + "function": "measurementDescriptionListData", + "possibleOperations": { + "read": { + "partial": {} + } + } + }, + { + "function": "measurementListData", + "possibleOperations": { + "read": { + "partial": {} + } + } + } + ] + } + }, + { + "description": { + "featureAddress": { + "entity": [ + 1, + 1 + ], + "feature": 24 + }, + "featureType": "DeviceConfiguration", + "role": "server", + "supportedFunction": [ + { + "function": "deviceConfigurationKeyValueDescriptionListData", + "possibleOperations": { + "read": { + "partial": {} + } + } + }, + { + "function": "deviceConfigurationKeyValueListData", + "possibleOperations": { + "read": { + "partial": {} + } + } + } + ] + } + }, + { + "description": { + "featureAddress": { + "entity": [ + 1, + 1 + ], + "feature": 26 + }, + "featureType": "TimeSeries", + "role": "server", + "supportedFunction": [ + { + "function": "timeSeriesConstraintsListData", + "possibleOperations": { + "read": { + "partial": {} + } + } + }, + { + "function": "timeSeriesDescriptionListData", + "possibleOperations": { + "read": { + "partial": {} + } + } + }, + { + "function": "timeSeriesListData", + "possibleOperations": { + "read": { + "partial": {} + }, + "write": { + "partial": {} + } + } + } + ] + } + }, + { + "description": { + "featureAddress": { + "entity": [ + 1, + 1 + ], + "feature": 28 + }, + "featureType": "IncentiveTable", + "role": "server", + "supportedFunction": [ + { + "function": "incentiveTableConstraintsData", + "possibleOperations": { + "read": { + "partial": {} + } + } + }, + { + "function": "incentiveTableData", + "possibleOperations": { + "read": { + "partial": {} + }, + "write": { + "partial": {} + } + } + }, + { + "function": "incentiveTableDescriptionData", + "possibleOperations": { + "read": { + "partial": {} + }, + "write": { + "partial": {} + } + } + } + ] + } + }, + { + "description": { + "featureAddress": { + "entity": [ + 1, + 1 + ], + "feature": 30 + }, + "featureType": "Identification", + "role": "server", + "supportedFunction": [ + { + "function": "identificationListData", + "possibleOperations": { + "read": { + "partial": {} + } + } + } + ] + } + }, + { + "description": { + "featureAddress": { + "entity": [ + 1, + 1 + ], + "feature": 1001 + }, + "featureType": "Generic", + "role": "client", + "description": "Heartbeat device diagnosis client feature" + } + } + ] + } + } + ] + } + } +} \ No newline at end of file diff --git a/spine/testdata/wallbox_detaileddiscoverydata_recv_reply.json b/spine/testdata/wallbox_detaileddiscoverydata_recv_reply.json new file mode 100644 index 0000000..9b2f572 --- /dev/null +++ b/spine/testdata/wallbox_detaileddiscoverydata_recv_reply.json @@ -0,0 +1,187 @@ +{ + "datagram": { + "header": { + "specificationVersion": "1.1.1", + "addressSource": { + "device": "Wallbox", + "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": "Wallbox" + }, + "deviceType": "ChargingStation", + "networkFeatureSet": "smart" + } + }, + "entityInformation": [ + { + "description": { + "entityAddress": { + "device": "Wallbox", + "entity": [ + 0 + ] + }, + "entityType": "DeviceInformation" + } + }, + { + "description": { + "entityAddress": { + "device": "Wallbox", + "entity": [ + 1 + ] + }, + "entityType": "EVSE" + } + } + ], + "featureInformation": [ + { + "description": { + "featureAddress": { + "device": "Wallbox", + "entity": [ + 0 + ], + "feature": 0 + }, + "featureType": "NodeManagement", + "role": "special", + "supportedFunction": [ + { + "function": "nodeManagementSubscriptionDeleteCall", + "possibleOperations": {} + }, + { + "function": "nodeManagementBindingData", + "possibleOperations": { + "read": {} + } + }, + { + "function": "nodeManagementBindingRequestCall", + "possibleOperations": {} + }, + { + "function": "nodeManagementBindingDeleteCall", + "possibleOperations": {} + }, + { + "function": "nodeManagementDetailedDiscoveryData", + "possibleOperations": { + "read": {} + } + }, + { + "function": "nodeManagementUseCaseData", + "possibleOperations": { + "read": {} + } + }, + { + "function": "nodeManagementSubscriptionData", + "possibleOperations": { + "read": {} + } + }, + { + "function": "nodeManagementSubscriptionRequestCall", + "possibleOperations": {} + } + ] + } + }, + { + "description": { + "featureAddress": { + "device": "Wallbox", + "entity": [ + 0 + ], + "feature": 1 + }, + "featureType": "DeviceClassification", + "role": "server", + "supportedFunction": [ + { + "function": "deviceClassificationManufacturerData", + "possibleOperations": { + "read": {} + } + } + ] + } + }, + { + "description": { + "featureAddress": { + "device": "Wallbox", + "entity": [ + 1 + ], + "feature": 1 + }, + "featureType": "DeviceClassification", + "role": "client" + } + }, + { + "description": { + "featureAddress": { + "device": "Wallbox", + "entity": [ + 1 + ], + "feature": 2 + }, + "featureType": "DeviceDiagnosis", + "role": "client" + } + }, + { + "description": { + "featureAddress": { + "device": "Wallbox", + "entity": [ + 1 + ], + "feature": 3 + }, + "featureType": "ElectricalConnection", + "role": "server" + } + } + ] + } + } + ] + } + } +} diff --git a/util/helper.go b/util/helper.go new file mode 100644 index 0000000..b67faff --- /dev/null +++ b/util/helper.go @@ -0,0 +1,11 @@ +package util + +import ( + "encoding/json" +) + +// quick way to a struct into another +func DeepCopy[A any](source, dest A) { + byt, _ := json.Marshal(source) + _ = json.Unmarshal(byt, dest) +} diff --git a/util/ptr.go b/util/ptr.go new file mode 100644 index 0000000..e82ce5d --- /dev/null +++ b/util/ptr.go @@ -0,0 +1,5 @@ +package util + +func Ptr[T any](v T) *T { + return &v +} diff --git a/util/type.go b/util/type.go new file mode 100644 index 0000000..44478bf --- /dev/null +++ b/util/type.go @@ -0,0 +1,13 @@ +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 +}