EdgexAgent/device-gps-go/pkg/models/commandvalue.go
2025-07-10 20:30:06 +08:00

544 lines
20 KiB
Go

// -*- Mode: Go; indent-tabs-mode: t -*-
//
// Copyright (C) 2018 Canonical Ltd
// Copyright (C) 2018-2021 IOTech Ltd
//
// SPDX-License-Identifier: Apache-2.0
package models
import (
"encoding/binary"
"fmt"
"github.com/edgexfoundry/go-mod-core-contracts/v4/common"
"github.com/edgexfoundry/go-mod-core-contracts/v4/errors"
)
const (
// Policy limits should be located in global config namespace
// Currently assigning 16MB (binary), 16 * 2^20 bytes
MaxBinaryBytes = 16777216
)
// CommandValue is the struct to represent the reading value of a Get command coming
// from ProtocolDrivers or the parameter of a Put command sending to ProtocolDrivers.
type CommandValue struct {
// DeviceResourceName is the name of Device Resource for this command
DeviceResourceName string
// Type indicates what type of value was returned from the ProtocolDriver instance in
// response to HandleCommand being called to handle a single ResourceOperation.
Type string
// Value holds value returned by a ProtocolDriver instance.
// The value can be converted to its native type by referring to ValueType.
Value interface{}
// Origin is an int64 value which indicates the time the reading
// contained in the CommandValue was read by the ProtocolDriver
// instance.
Origin int64
// Tags allows device service to add custom information to the Event in order to
// help identify its origin or otherwise label it before it is send to north side.
Tags map[string]string
}
// NewCommandValue create a CommandValue according to the valueType supplied.
func NewCommandValue(deviceResourceName string, valueType string, value interface{}) (*CommandValue, error) {
err := validate(valueType, value)
if err != nil {
return nil, errors.NewCommonEdgeX(errors.KindServerError, "failed to create CommandValue", err)
}
return &CommandValue{
DeviceResourceName: deviceResourceName,
Type: valueType,
Value: value,
Tags: make(map[string]string)}, nil
}
// NewCommandValueWithOrigin wraps NewCommandValue, create a CommandValue and add the Origin field.
func NewCommandValueWithOrigin(deviceResourceName string, valueType string, value interface{}, origin int64) (*CommandValue, error) {
cv, err := NewCommandValue(deviceResourceName, valueType, value)
if err != nil {
return nil, errors.NewCommonEdgeXWrapper(err)
}
cv.Origin = origin
return cv, nil
}
// ValueToString returns the string format of the value.
func (cv *CommandValue) ValueToString() string {
if cv.Type == common.ValueTypeBinary {
binaryValue := cv.Value.([]byte)
return fmt.Sprintf("Binary: [%v...]", string(binaryValue[:20]))
}
return fmt.Sprintf("%v", cv.Value)
}
// String returns a string representation of a CommandValue instance.
func (cv *CommandValue) String() string {
return fmt.Sprintf("DeviceResource: %s, %s: %s", cv.DeviceResourceName, cv.Type, cv.ValueToString())
}
// BoolValue returns the value in bool data type, and returns error if the Type is not Bool.
func (cv *CommandValue) BoolValue() (bool, error) {
var value bool
if cv.Type != common.ValueTypeBool {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeBool)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.(bool)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// BoolArrayValue returns the value in an array of bool type, and returns error if the Type is not BoolArray.
func (cv *CommandValue) BoolArrayValue() ([]bool, error) {
var value []bool
if cv.Type != common.ValueTypeBoolArray {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeBoolArray)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]bool)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// StringValue returns the value in string data type, and returns error if the Type is not String.
func (cv *CommandValue) StringValue() (string, error) {
var value string
if cv.Type != common.ValueTypeString {
errMsg := fmt.Sprintf("cannot convert CommandValue of %s to %s", cv.Type, common.ValueTypeString)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.(string)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// StringArrayValue returns the value in an array of bool type, and returns error if the Type is not BoolArray.
func (cv *CommandValue) StringArrayValue() ([]string, error) {
var value []string
if cv.Type != common.ValueTypeStringArray {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeStringArray)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]string)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Uint8Value returns the value in uint8 data type, and returns error if the Type is not Uint8.
func (cv *CommandValue) Uint8Value() (uint8, error) {
var value uint8
if cv.Type != common.ValueTypeUint8 {
errMsg := fmt.Sprintf("cannot convert CommandValue of %s to %s", cv.Type, common.ValueTypeUint8)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.(uint8)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Uint8ArrayValue returns the value in an array of uint8 type, and returns error if the Type is not Uint8Array.
func (cv *CommandValue) Uint8ArrayValue() ([]uint8, error) {
var value []uint8
if cv.Type != common.ValueTypeUint8Array {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeUint8Array)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]uint8)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Uint16Value returns the value in uint16 data type, and returns error if the Type is not Uint16.
func (cv *CommandValue) Uint16Value() (uint16, error) {
var value uint16
if cv.Type != common.ValueTypeUint16 {
errMsg := fmt.Sprintf("cannot convert CommandValue of %s to %s", cv.Type, common.ValueTypeUint16)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.(uint16)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Uint16ArrayValue returns the value in an array of uint16 type, and returns error if the Type is not Uint16Array.
func (cv *CommandValue) Uint16ArrayValue() ([]uint16, error) {
var value []uint16
if cv.Type != common.ValueTypeUint16Array {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeUint16Array)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]uint16)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Uint32Value returns the value in uint32 data type, and returns error if the Type is not Uint32.
func (cv *CommandValue) Uint32Value() (uint32, error) {
var value uint32
if cv.Type != common.ValueTypeUint32 {
errMsg := fmt.Sprintf("cannot convert CommandValue of %s to %s", cv.Type, common.ValueTypeUint32)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.(uint32)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Uint32ArrayValue returns the value in an array of uint32 type, and returns error if the Type is not Uint32Array.
func (cv *CommandValue) Uint32ArrayValue() ([]uint32, error) {
var value []uint32
if cv.Type != common.ValueTypeUint32Array {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeUint32Array)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]uint32)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Uint64Value returns the value in uint64 data type, and returns error if the Type is not Uint64.
func (cv *CommandValue) Uint64Value() (uint64, error) {
var value uint64
if cv.Type != common.ValueTypeUint64 {
errMsg := fmt.Sprintf("cannot convert CommandValue of %s to %s", cv.Type, common.ValueTypeUint64)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.(uint64)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Uint64ArrayValue returns the value in an array of uint64 type, and returns error if the Type is not Uint64Array.
func (cv *CommandValue) Uint64ArrayValue() ([]uint64, error) {
var value []uint64
if cv.Type != common.ValueTypeUint64Array {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeUint64Array)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]uint64)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Int8Value returns the value in int8 data type, and returns error if the Type is not Int8.
func (cv *CommandValue) Int8Value() (int8, error) {
var value int8
if cv.Type != common.ValueTypeInt8 {
errMsg := fmt.Sprintf("cannot convert CommandValue of %s to %s", cv.Type, common.ValueTypeInt8)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.(int8)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Int8ArrayValue returns the value in an array of int8 type, and returns error if the Type is not Int8Array.
func (cv *CommandValue) Int8ArrayValue() ([]int8, error) {
var value []int8
if cv.Type != common.ValueTypeInt8Array {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeInt8Array)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]int8)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Int16Value returns the value in int16 data type, and returns error if the Type is not Int16.
func (cv *CommandValue) Int16Value() (int16, error) {
var value int16
if cv.Type != common.ValueTypeInt16 {
errMsg := fmt.Sprintf("cannot convert CommandValue of %s to %s", cv.Type, common.ValueTypeInt16)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.(int16)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Int16ArrayValue returns the value in an array of int16 type, and returns error if the Type is not Int16Array.
func (cv *CommandValue) Int16ArrayValue() ([]int16, error) {
var value []int16
if cv.Type != common.ValueTypeInt16Array {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeInt16Array)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]int16)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Int32Value returns the value in int32 data type, and returns error if the Type is not Int32.
func (cv *CommandValue) Int32Value() (int32, error) {
var value int32
if cv.Type != common.ValueTypeInt32 {
errMsg := fmt.Sprintf("cannot convert CommandValue of %s to %s", cv.Type, common.ValueTypeInt32)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.(int32)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Int32ArrayValue returns the value in an array of int32 type, and returns error if the Type is not Int32Array.
func (cv *CommandValue) Int32ArrayValue() ([]int32, error) {
var value []int32
if cv.Type != common.ValueTypeInt32Array {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeInt32Array)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]int32)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Int64Value returns the value in int64 data type, and returns error if the Type is not Int64.
func (cv *CommandValue) Int64Value() (int64, error) {
var value int64
if cv.Type != common.ValueTypeInt64 {
errMsg := fmt.Sprintf("cannot convert CommandValue of %s to %s", cv.Type, common.ValueTypeInt64)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.(int64)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Int64ArrayValue returns the value in an array of int64 type, and returns error if the Type is not Int64Array.
func (cv *CommandValue) Int64ArrayValue() ([]int64, error) {
var value []int64
if cv.Type != common.ValueTypeInt64Array {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeInt64Array)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]int64)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Float32Value returns the value in float32 data type, and returns error if the Type is not Float32.
func (cv *CommandValue) Float32Value() (float32, error) {
var value float32
if cv.Type != common.ValueTypeFloat32 {
errMsg := fmt.Sprintf("cannot convert CommandValue of %s to %s", cv.Type, common.ValueTypeFloat32)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.(float32)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Float32ArrayValue returns the value in an array of float32 type, and returns error if the Type is not Float32Array.
func (cv *CommandValue) Float32ArrayValue() ([]float32, error) {
var value []float32
if cv.Type != common.ValueTypeFloat32Array {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeFloat32Array)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]float32)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Float64Value returns the value in float64 data type, and returns error if the Type is not Float64.
func (cv *CommandValue) Float64Value() (float64, error) {
var value float64
if cv.Type != common.ValueTypeFloat64 {
errMsg := fmt.Sprintf("cannot convert CommandValue of %s to %s", cv.Type, common.ValueTypeFloat64)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.(float64)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// Float64ArrayValue returns the value in an array of float64 type, and returns error if the Type is not Float64Array.
func (cv *CommandValue) Float64ArrayValue() ([]float64, error) {
var value []float64
if cv.Type != common.ValueTypeFloat64Array {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeFloat64Array)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]float64)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// BinaryValue returns the value in []byte data type, and returns error if the Type is not Binary.
func (cv *CommandValue) BinaryValue() ([]byte, error) {
if cv.Value == nil {
return nil, nil
}
var value []byte
if cv.Type != common.ValueTypeBinary {
errMsg := fmt.Sprintf("cannot convert %s to %s", cv.Type, common.ValueTypeBinary)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
value, ok := cv.Value.([]byte)
if !ok {
errMsg := fmt.Sprintf("failed to transfrom %v to %T", cv.Value, value)
return value, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return value, nil
}
// ObjectValue returns the value in object data type, and returns error if the Type is not Object.
func (cv *CommandValue) ObjectValue() (interface{}, error) {
if cv.Type != common.ValueTypeObject {
errMsg := fmt.Sprintf("cannot convert CommandValue of %s to %s", cv.Type, common.ValueTypeObject)
return nil, errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return cv.Value, nil
}
// validate checks if the given value can be converted to specified valueType by
// performing type assertion
func validate(valueType string, value interface{}) error {
if value == nil {
return nil // value can be nil, skip validation
}
var ok bool
switch valueType {
case common.ValueTypeString:
_, ok = value.(string)
case common.ValueTypeStringArray:
_, ok = value.([]string)
case common.ValueTypeBool:
_, ok = value.(bool)
case common.ValueTypeBoolArray:
_, ok = value.([]bool)
case common.ValueTypeUint8:
_, ok = value.(uint8)
case common.ValueTypeUint8Array:
_, ok = value.([]uint8)
case common.ValueTypeUint16:
_, ok = value.(uint16)
case common.ValueTypeUint16Array:
_, ok = value.([]uint16)
case common.ValueTypeUint32:
_, ok = value.(uint32)
case common.ValueTypeUint32Array:
_, ok = value.([]uint32)
case common.ValueTypeUint64:
_, ok = value.(uint64)
case common.ValueTypeUint64Array:
_, ok = value.([]uint64)
case common.ValueTypeInt8:
_, ok = value.(int8)
case common.ValueTypeInt8Array:
_, ok = value.([]int8)
case common.ValueTypeInt16:
_, ok = value.(int16)
case common.ValueTypeInt16Array:
_, ok = value.([]int16)
case common.ValueTypeInt32:
_, ok = value.(int32)
case common.ValueTypeInt32Array:
_, ok = value.([]int32)
case common.ValueTypeInt64:
_, ok = value.(int64)
case common.ValueTypeInt64Array:
_, ok = value.([]int64)
case common.ValueTypeFloat32:
_, ok = value.(float32)
case common.ValueTypeFloat32Array:
_, ok = value.([]float32)
case common.ValueTypeFloat64:
_, ok = value.(float64)
case common.ValueTypeFloat64Array:
_, ok = value.([]float64)
case common.ValueTypeBinary:
_, ok = value.([]byte)
if binary.Size(value) > MaxBinaryBytes {
errMsg := fmt.Sprintf("value payload exceeds limit for binary readings (%v bytes)", MaxBinaryBytes)
return errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
case common.ValueTypeObject:
_, ok = value.(interface{}) // nolint: gosimple
default:
return errors.NewCommonEdgeX(errors.KindServerError, "unrecognized value type", nil)
}
if !ok {
errMsg := fmt.Sprintf("failed to convert interface value %v to Type %s", value, valueType)
return errors.NewCommonEdgeX(errors.KindServerError, errMsg, nil)
}
return nil
}