From 443e50115e100bb19c01067b1d3ba7bb68029607 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Mon, 23 Aug 2021 18:37:58 +0200 Subject: [PATCH 1/4] Add thing list command --- cli/thing/list.go | 82 ++++++++++++++++++++++++++++++++++++++++++ cli/thing/thing.go | 1 + command/thing/list.go | 61 +++++++++++++++++++++++++++++++ internal/iot/client.go | 22 ++++++++++++ 4 files changed, 166 insertions(+) create mode 100644 cli/thing/list.go create mode 100644 command/thing/list.go diff --git a/cli/thing/list.go b/cli/thing/list.go new file mode 100644 index 00000000..cf0c3a5d --- /dev/null +++ b/cli/thing/list.go @@ -0,0 +1,82 @@ +package thing + +import ( + "fmt" + "strings" + + "github.com/arduino/arduino-cli/cli/feedback" + "github.com/arduino/arduino-cli/table" + "github.com/arduino/iot-cloud-cli/command/thing" + "github.com/spf13/cobra" +) + +var listFlags struct { + ids []string + deviceID string + properties bool +} + +func initListCommand() *cobra.Command { + listCommand := &cobra.Command{ + Use: "list", + Short: "List things", + Long: "List things on Arduino IoT Cloud", + RunE: runListCommand, + } + // list only the things corresponding to the passed ids + listCommand.Flags().StringSliceVarP(&listFlags.ids, "ids", "i", []string{}, "List of thing IDs to be retrieved") + // list only the things associated to the passed device id + listCommand.Flags().StringVarP(&listFlags.deviceID, "device", "d", "", "ID of Device associated to the thing to be retrieved") + listCommand.Flags().BoolVarP(&listFlags.properties, "properties", "p", false, "Show thing properties") + return listCommand +} + +func runListCommand(cmd *cobra.Command, args []string) error { + fmt.Println("Listing devices") + + params := &thing.ListParams{ + IDs: listFlags.ids, + Properties: listFlags.properties, + } + if listFlags.deviceID != "" { + params.DeviceID = &listFlags.deviceID + } + + things, err := thing.List(params) + if err != nil { + return err + } + + feedback.PrintResult(result{things}) + return nil +} + +type result struct { + things []thing.ThingInfo +} + +func (r result) Data() interface{} { + return r.things +} + +func (r result) String() string { + if len(r.things) == 0 { + return "No things found." + } + t := table.New() + + h := []interface{}{"Name", "ID", "Device"} + if listFlags.properties { + h = append(h, "Properties") + } + t.SetHeader(h...) + + for _, thing := range r.things { + r := []interface{}{thing.Name, thing.ID, thing.DeviceID} + if listFlags.properties { + r = append(r, strings.Join(thing.Properties, ", ")) + } + t.AddRow(r...) + } + return t.Render() +} diff --git a/cli/thing/thing.go b/cli/thing/thing.go index a1ccce9e..a0ab4259 100644 --- a/cli/thing/thing.go +++ b/cli/thing/thing.go @@ -12,6 +12,7 @@ func NewCommand() *cobra.Command { } thingCommand.AddCommand(initCreateCommand()) + thingCommand.AddCommand(initListCommand()) return thingCommand } diff --git a/command/thing/list.go b/command/thing/list.go new file mode 100644 index 00000000..caa21286 --- /dev/null +++ b/command/thing/list.go @@ -0,0 +1,61 @@ +package thing + +import ( + "github.com/arduino/iot-cloud-cli/internal/config" + "github.com/arduino/iot-cloud-cli/internal/iot" +) + +// ThingInfo contains the main parameters of +// an Arduino IoT Cloud thing. +type ThingInfo struct { + Name string + ID string + DeviceID string + Properties []string +} + +// ListParams contains the optional parameters needed +// to filter the things to be listed. +// If IDs is valid, only things belonging to that list are listed. +// If DeviceID is provided, only things associated to that device are listed. +// If Properties is true, properties names are retrieved. +type ListParams struct { + IDs []string + DeviceID *string + Properties bool +} + +// List command is used to list +// the things of Arduino IoT Cloud. +func List(params *ListParams) ([]ThingInfo, error) { + conf, err := config.Retrieve() + if err != nil { + return nil, err + } + iotClient, err := iot.NewClient(conf.Client, conf.Secret) + if err != nil { + return nil, err + } + + foundThings, err := iotClient.ListThings(params.IDs, params.DeviceID, params.Properties) + if err != nil { + return nil, err + } + + var things []ThingInfo + for _, foundThing := range foundThings { + var props []string + for _, p := range foundThing.Properties { + props = append(props, p.Name) + } + th := ThingInfo{ + Name: foundThing.Name, + ID: foundThing.Id, + DeviceID: foundThing.DeviceId, + Properties: props, + } + things = append(things, th) + } + + return things, nil +} diff --git a/internal/iot/client.go b/internal/iot/client.go index c8ee311c..f4b7d463 100644 --- a/internal/iot/client.go +++ b/internal/iot/client.go @@ -17,6 +17,7 @@ type Client interface { AddCertificate(id, csr string) (*iotclient.ArduinoCompressedv2, error) AddThing(thing *iotclient.Thing, force bool) (string, error) GetThing(id string) (*iotclient.ArduinoThing, error) + ListThings(ids []string, device *string, props bool) ([]iotclient.ArduinoThing, error) } type client struct { @@ -117,6 +118,27 @@ func (cl *client) GetThing(id string) (*iotclient.ArduinoThing, error) { return &thing, nil } +// ListThings returns a list of things on Arduino IoT Cloud. +func (cl *client) ListThings(ids []string, device *string, props bool) ([]iotclient.ArduinoThing, error) { + opts := &iotclient.ThingsV2ListOpts{} + opts.ShowProperties = optional.NewBool(props) + + if ids != nil { + opts.Ids = optional.NewInterface(ids) + } + + if device != nil { + opts.DeviceId = optional.NewString(*device) + } + + things, _, err := cl.api.ThingsV2Api.ThingsV2List(cl.ctx, opts) + if err != nil { + err = fmt.Errorf("retrieving things, %w", err) + return nil, err + } + return things, nil +} + func (cl *client) setup(client, secret string) error { // Get the access token in exchange of client_id and client_secret tok, err := token(client, secret) From cfe9dfdc518cfe0956d89c95a1d364e46038b2a1 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 25 Aug 2021 16:50:52 +0200 Subject: [PATCH 2/4] fix thing list typo --- cli/thing/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/thing/list.go b/cli/thing/list.go index cf0c3a5d..ae60e30e 100644 --- a/cli/thing/list.go +++ b/cli/thing/list.go @@ -32,7 +32,7 @@ func initListCommand() *cobra.Command { } func runListCommand(cmd *cobra.Command, args []string) error { - fmt.Println("Listing devices") + fmt.Println("Listing things") params := &thing.ListParams{ IDs: listFlags.ids, From 61ddc8cb9999464218c8f1b6effa1147da5f7e68 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Thu, 26 Aug 2021 11:36:28 +0200 Subject: [PATCH 3/4] fix thing list - improve flags --- cli/thing/list.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/thing/list.go b/cli/thing/list.go index ae60e30e..5212af2c 100644 --- a/cli/thing/list.go +++ b/cli/thing/list.go @@ -25,8 +25,8 @@ func initListCommand() *cobra.Command { } // list only the things corresponding to the passed ids listCommand.Flags().StringSliceVarP(&listFlags.ids, "ids", "i", []string{}, "List of thing IDs to be retrieved") - // list only the things associated to the passed device id - listCommand.Flags().StringVarP(&listFlags.deviceID, "device", "d", "", "ID of Device associated to the thing to be retrieved") + // list only the thing associated to the passed device id + listCommand.Flags().StringVarP(&listFlags.deviceID, "device-id", "d", "", "ID of Device associated to the thing to be retrieved") listCommand.Flags().BoolVarP(&listFlags.properties, "properties", "p", false, "Show thing properties") return listCommand } From 1fdc75a5ab9d9cb00fc04bd117ac7cbf366d2e2c Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Thu, 26 Aug 2021 14:22:22 +0200 Subject: [PATCH 4/4] Update readme --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index a412f297..f40e446f 100644 --- a/README.md +++ b/README.md @@ -52,3 +52,18 @@ Create a thing from a template: Create a thing by cloning another thing: `$ iot-cloud-cli thing create --name --clone-id ` + + +Things can be printed thanks to a list command. + +Print a list of available things and their properties by using this command: + +`$ iot-cloud-cli thing list --properties` + +Print a *filtered* list of available things, print only things belonging to the ids list: + +`$ iot-cloud-cli thing list --ids ,` + +Print only the thing associated to the passed device: + +`$ iot-cloud-cli thing list --device-id ` \ No newline at end of file