From 9b9013eaea6f5fb8a8c818582bf3287588e41c38 Mon Sep 17 00:00:00 2001 From: fbuedding <100070891+fbuedding@users.noreply.github.com> Date: Mon, 18 Mar 2024 10:59:33 +0100 Subject: [PATCH] Added documentation --- README.md | 55 ++++++++++++++++++- iota-config-group.go | 14 +++++ ...group_test.go => iota-config-group_test.go | 0 iota-device.go | 14 ++++- iota-sdk.go | 12 ++++ iota-types.go | 27 ++++++--- 6 files changed, 112 insertions(+), 10 deletions(-) rename iota-service-group_test.go => iota-config-group_test.go (100%) diff --git a/README.md b/README.md index d110279..9e8579a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,54 @@ [![Tests](https://github.com/fbuedding/fiware-iot-agent-sdk/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/fbuedding/fiware-iot-agent-sdk/actions/workflows/tests.yml) -# fiware-iot-agent-sdk - A IoT-Agent sdk for communicating with IoT-Agent using the IoT Agent node library +**iotagentsdk: Go SDK for IoT Agents** + +The `iotagentsdk` package is a Go software development kit (SDK) designed to facilitate interactions with IoT Agents in FIWARE-based systems. FIWARE is an open-source initiative aimed at providing a framework for the development of smart solutions in various domains, including smart cities, industrial IoT, and agriculture. + +**Features:** + +- **Config Group Management:** Allows you to manage configuration groups for devices, including creating, reading, updating, and deleting (CRUD) operations. + +- **Device Management:** Provides functionalities for managing devices, such as reading device information, checking device existence, listing devices, creating devices, updating device information, and deleting devices. + +**How to Use:** + +1. **Import the Package:** Import the `iotagentsdk` package into your Go project: + + ```go + import "github.com/fbuedding/fiware-iot-agent-sdk" + ``` + +2. **Initialize the IoTA Client:** Create an instance of the `IoTA` struct, providing the necessary configuration parameters such as host, port, and timeout. + + ```go + iotAgent := iotagentsdk.NewIoTA("localhost", 4041, 5000) + ``` + +3. **Interact with IoT Agents:** Use the methods provided by the `iotagentsdk` package to perform operations such as managing configuration groups and devices. + + ```go + // Example: Read device information + deviceID := "my-device" + deviceInfo, err := iotAgent.ReadDevice(myFiwareService, iotagentsdk.DeciveId(deviceID)) + if err != nil { + log.Fatal("Error reading device:", err) + } + fmt.Println("Device information:", deviceInfo) + ``` + +**Compatibility:** + +- The `iotagentsdk` package is compatible with Go versions 1.11 and higher. + +**Contributing:** + +Contributions to the `iotagentsdk` package are welcome! Feel free to submit bug reports, feature requests, or pull requests on GitHub. + +**License:** + +This package is licensed under the MIT License. See the LICENSE file for details. + +For more information and detailed usage instructions, please refer to the [documentation](https://github.com/yourusername/iotagentsdk). + +**Acknowledgments:** + +This package is developed based on the FIWARE architecture and specifications. We acknowledge the contributions of the FIWARE community and developers. diff --git a/iota-config-group.go b/iota-config-group.go index d90a519..8aa60d9 100644 --- a/iota-config-group.go +++ b/iota-config-group.go @@ -13,14 +13,17 @@ import ( "github.com/rs/zerolog/log" ) +// Constants const ( urlService = urlBase + "/iot/services" ) +// Error handling func (e *MissingFields) Error() string { return fmt.Sprintf("Error %s: %s", e.Message, e.Fields) } +// Function to validate the ConfigGroup func (sg ConfigGroup) Validate() error { mF := &MissingFields{make(vector.StringVector, 0), "Missing fields"} if sg.Apikey == "" { @@ -37,15 +40,18 @@ func (sg ConfigGroup) Validate() error { } } +// Response struct for reading ConfigGroup type RespReadConfigGroup struct { Count int `json:"count"` Services []ConfigGroup `json:"services"` } +// Request struct for creating ConfigGroup type ReqCreateConfigGroup struct { Services []ConfigGroup `json:"services"` } +// Method to read a ConfigGroup func (i IoTA) ReadConfigGroup(fs FiwareService, r Resource, a Apikey) (*RespReadConfigGroup, error) { url := urlService + fmt.Sprintf("?resource=%s&apikey=%s", r, a) @@ -86,6 +92,7 @@ func (i IoTA) ReadConfigGroup(fs FiwareService, r Resource, a Apikey) (*RespRead return &respReadConfigGroup, nil } +// Method to list ConfigGroups func (i IoTA) ListConfigGroups(fs FiwareService) (*RespReadConfigGroup, error) { url := urlService @@ -126,6 +133,7 @@ func (i IoTA) ListConfigGroups(fs FiwareService) (*RespReadConfigGroup, error) { return &respReadConfigGroup, nil } +// Method to check if a ConfigGroup exists func (i IoTA) ConfigGroupExists(fs FiwareService, r Resource, a Apikey) bool { tmp, err := i.ReadConfigGroup(fs, r, a) if err != nil { @@ -134,11 +142,13 @@ func (i IoTA) ConfigGroupExists(fs FiwareService, r Resource, a Apikey) bool { return tmp.Count > 0 } +// Method to create a ConfigGroup func (i IoTA) CreateConfigGroup(fs FiwareService, sg ConfigGroup) error { sgs := [1]ConfigGroup{sg} return i.CreateConfigGroups(fs, sgs[:]) } +// Method to create multiple ConfigGroups func (i IoTA) CreateConfigGroups(fs FiwareService, sgs []ConfigGroup) error { for _, sg := range sgs { err := sg.Validate() @@ -182,6 +192,7 @@ func (i IoTA) CreateConfigGroups(fs FiwareService, sgs []ConfigGroup) error { return nil } +// Method to update a ConfigGroup func (i IoTA) UpdateConfigGroup(fs FiwareService, r Resource, a Apikey, sg ConfigGroup) error { err := sg.Validate() if err != nil { @@ -225,6 +236,7 @@ func (i IoTA) UpdateConfigGroup(fs FiwareService, r Resource, a Apikey, sg Confi return nil } +// Method to delete a ConfigGroup func (i IoTA) DeleteConfigGroup(fs FiwareService, r Resource, a Apikey) error { url := urlService + fmt.Sprintf("?resource=%s&apikey=%s", r, a) @@ -258,6 +270,7 @@ func (i IoTA) DeleteConfigGroup(fs FiwareService, r Resource, a Apikey) error { return nil } +// Method to upsert a ConfigGroup func (i IoTA) UpsertConfigGroup(fs FiwareService, sg ConfigGroup) error { exists := i.ConfigGroupExists(fs, sg.Resource, sg.Apikey) if !exists { @@ -276,6 +289,7 @@ func (i IoTA) UpsertConfigGroup(fs FiwareService, sg ConfigGroup) error { return nil } +// Method to create a ConfigGroup, getting the created ConfigGroup and setting it. func (i IoTA) CreateConfigGroupWSE(fs FiwareService, sg *ConfigGroup) error { if sg == nil { return errors.New("Service group reference cannot be nil") diff --git a/iota-service-group_test.go b/iota-config-group_test.go similarity index 100% rename from iota-service-group_test.go rename to iota-config-group_test.go diff --git a/iota-device.go b/iota-device.go index 2c21d2f..4d7aa44 100644 --- a/iota-device.go +++ b/iota-device.go @@ -13,19 +13,23 @@ import ( log "github.com/rs/zerolog/log" ) +// Constants const ( urlDevice = urlBase + "/iot/devices" ) +// Request struct for creating a device type reqCreateDevice struct { Devices []Device `json:"devices"` } +// Response struct for listing devices type respListDevices struct { Count int `json:"count"` Devices []Device `json:"devices"` } +// Function to validate a Device func (d Device) Validate() error { mF := &MissingFields{make(vector.StringVector, 0), "Missing fields"} if d.Id == "" { @@ -39,6 +43,7 @@ func (d Device) Validate() error { } } +// Method to read a device func (i IoTA) ReadDevice(fs FiwareService, id DeciveId) (*Device, error) { url, err := u.JoinPath(fmt.Sprintf(urlDevice, i.Host, i.Port), u.PathEscape(string(id))) if err != nil { @@ -86,6 +91,7 @@ func (i IoTA) ReadDevice(fs FiwareService, id DeciveId) (*Device, error) { return &device, nil } +// Method to check if a device exists func (i IoTA) DeviceExists(fs FiwareService, id DeciveId) bool { _, err := i.ReadDevice(fs, id) if err != nil { @@ -94,6 +100,7 @@ func (i IoTA) DeviceExists(fs FiwareService, id DeciveId) bool { return true } +// Method to list devices func (i IoTA) ListDevices(fs FiwareService) (*respListDevices, error) { url := fmt.Sprintf(urlDevice, i.Host, i.Port) @@ -136,6 +143,7 @@ func (i IoTA) ListDevices(fs FiwareService) (*respListDevices, error) { return &respDevices, nil } +// Method to create a device func (i IoTA) CreateDevices(fs FiwareService, ds []Device) error { for _, sg := range ds { err := sg.Validate() @@ -179,11 +187,13 @@ func (i IoTA) CreateDevices(fs FiwareService, ds []Device) error { return nil } +// Method to create a device func (i IoTA) CreateDevice(fs FiwareService, d Device) error { ds := [1]Device{d} return i.CreateDevices(fs, ds[:]) } +// Method to update a device func (i IoTA) UpdateDevice(fs FiwareService, d Device) error { err := d.Validate() if err != nil { @@ -232,6 +242,7 @@ func (i IoTA) UpdateDevice(fs FiwareService, d Device) error { return nil } +// Method to delete a device func (i IoTA) DeleteDevice(fs FiwareService, id DeciveId) error { url, err := u.JoinPath(fmt.Sprintf(urlDevice, i.Host, i.Port), u.PathEscape(string(id))) if err != nil { @@ -265,6 +276,7 @@ func (i IoTA) DeleteDevice(fs FiwareService, id DeciveId) error { return nil } +// Method to upsert a device func (i IoTA) UpsertDevice(fs FiwareService, d Device) error { exists := i.DeviceExists(fs, d.Id) if !exists { @@ -294,7 +306,7 @@ func (i IoTA) UpsertDevice(fs FiwareService, d Device) error { return nil } -// Creates a device an updates the +// Creates a device an updates the given Device func (i IoTA) CreateDeviceWSE(fs FiwareService, d *Device) error { if d == nil { return errors.New("Device reference cannot be nil") diff --git a/iota-sdk.go b/iota-sdk.go index aac9091..57fd448 100644 --- a/iota-sdk.go +++ b/iota-sdk.go @@ -1,3 +1,4 @@ +// Package iotagentsdk provides an SDK for communicating with Fiware IoT Agents. package iotagentsdk import ( @@ -14,15 +15,19 @@ import ( log "github.com/rs/zerolog/log" ) +// Constants for the IoT Agent URL and Healthcheck URL. const ( urlBase = "http://%v:%d" urlHealthcheck = urlBase + "/iot/about" ) +// Error returns the error as a formatted string. func (e ApiError) Error() string { return fmt.Sprintf("%s: %s", e.Name, e.Message) } +// init initializes the logging level based on the "LOG_LEVEL" environment variable. +// By default, "panic" is used if no environment variable is set. func init() { logLvl := os.Getenv("LOG_LEVEL") if logLvl == "" { @@ -31,6 +36,7 @@ func init() { SetLogLevel(logLvl) } +// NewIoTAgent creates a new instance of the IoT Agent. func NewIoTAgent(host string, port int, timeout_ms int) *IoTA { iota := IoTA{ Host: host, @@ -41,6 +47,8 @@ func NewIoTAgent(host string, port int, timeout_ms int) *IoTA { return &iota } +// SetLogLevel sets the global logging level based on the given value. +// Possible values are: "trace", "debug", "info", "warning", "error", "fatal", "panic". func SetLogLevel(ll string) { ll = strings.ToLower(ll) switch ll { @@ -63,6 +71,7 @@ func SetLogLevel(ll string) { } } +// Healthcheck performs a health check of the IoT Agent and returns the result. func (i IoTA) Healthcheck() (*RespHealthcheck, error) { response, err := http.Get(fmt.Sprintf(urlHealthcheck, i.Host, i.Port)) if err != nil { @@ -83,6 +92,7 @@ func (i IoTA) Healthcheck() (*RespHealthcheck, error) { return &respHealth, nil } +// GetAllServicePathsForService returns all service paths for the specified service. func (i IoTA) GetAllServicePathsForService(service string) ([]string, error) { cgs, err := i.ListConfigGroups(FiwareService{service, "/*"}) if err != nil { @@ -103,6 +113,8 @@ func (i IoTA) GetAllServicePathsForService(service string) ([]string, error) { return servicePaths, nil } +// Client returns the HTTP client used for communication with the IoT Agent. +// If no client is present, a new one is created. func (i IoTA) Client() *http.Client { if i.client == nil { log.Debug().Msg("Creating http client") diff --git a/iota-types.go b/iota-types.go index babf9a0..4590273 100644 --- a/iota-types.go +++ b/iota-types.go @@ -7,6 +7,7 @@ import ( "github.com/niemeyer/golang/src/pkg/container/vector" ) +// IoTA represents an IoT Agent instance. type IoTA struct { Host string Port int @@ -14,23 +15,27 @@ type IoTA struct { client *http.Client } +// FiwareService represents a Fiware service and its associated service path. type FiwareService struct { Service string ServicePath string } +// RespHealthcheck represents the response of a health check request. type RespHealthcheck struct { LibVersion string `json:"libVersion"` Port string `json:"port"` BaseRoot string `json:"baseRoot"` Version string `json:"version"` } + +// ApiError represents an error in an API call. type ApiError struct { Name string `json:"name"` Message string `json:"message"` } -// these are nearly the same, but for typesafety differnt structs +// Attribute represents an attribute in the data model. type Attribute struct { ObjectID string `json:"object_id,omitempty" formam:"object_id"` Name string `json:"name" formam:"name"` @@ -42,6 +47,7 @@ type Attribute struct { Metadata map[string]Metadata `json:"metadata,omitempty" formam:"metadata"` } +// LazyAttribute represents a lazy attribute in the data model. type LazyAttribute struct { ObjectID string `json:"object_id,omitempty" formam:"object_id"` Name string `json:"name" formam:"name"` @@ -49,6 +55,7 @@ type LazyAttribute struct { Metadata map[string]Metadata `json:"metadata,omitempty" formam:"metadata"` } +// StaticAttribute represents a static attribute in the data model. type StaticAttribute struct { ObjectID string `json:"object_id,omitempty" formam:"object_id"` Name string `json:"name" formam:"name"` @@ -56,6 +63,7 @@ type StaticAttribute struct { Metadata map[string]Metadata `json:"metadata,omitempty" formam:"metadata"` } +// Command represents a command in the data model. type Command struct { ObjectID string `json:"object_id,omitempty" formam:"object_id"` Name string `json:"name" formam:"name"` @@ -66,18 +74,20 @@ type Command struct { Metadata map[string]Metadata `json:"metadata,omitempty" formam:"metadata"` } -// Extra type for x-form-data +// Metadata represents metadata for attributes and commands. type Metadata struct { Type string `json:"type" formam:"type"` Value string `json:"value" formam:"value"` } -type ( - Apikey string - Resource string -) +// Apikey represents an API key. +type Apikey string + +// Resource represents a resource. +type Resource string -// see https://iotagent-node-lib.readthedocs.io/en/latest/api.html#service-group-datamodel +// ConfigGroup represents a configuration group. +// See datamodel [Config Group]: https://iotagent-node-lib.readthedocs.io/en/latest/api.html#service-group-datamodel type ConfigGroup struct { Service string `json:"service,omitempty" formam:"service"` ServicePath string `json:"subservice,omitempty" formam:"subservice"` @@ -102,8 +112,11 @@ type ConfigGroup struct { Endpoint string `json:"endpoint,omitempty" formam:"endpoint"` } +// DeciveId represents a device ID. type DeciveId string +// Device represents a device. +// See datamodel [Device]: https://iotagent-node-lib.readthedocs.io/en/3.3.0/api.html#device-datamodel type Device struct { Id DeciveId `json:"device_id,omitempty" formam:"device_id"` Service string `json:"service,omitempty" formam:"service"`