Skip to content

Commit 571e307

Browse files
committed
Add thing list command (#23)
Things can be printed thanks to a list command. Also, properties belonging to the things can be printed, by passing the --properties flag to the list command. $ iot-cloud-cli thing list --properties The following parameters can be used to filter out the resulting list: - ids : is a list of thing IDs. Only the things belonging to this list will be printed out. - device-id : only the thing associated to this device will be printed. commits history: * Add thing list command * fix thing list typo * fix thing list - improve flags * Update readme
1 parent 59b290f commit 571e307

File tree

5 files changed

+181
-0
lines changed

5 files changed

+181
-0
lines changed

README.md

+15
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,18 @@ Create a thing from a template:
5252
Create a thing by cloning another thing:
5353

5454
`$ iot-cloud-cli thing create --name <thingName> --clone-id <thingToCloneID>`
55+
56+
57+
Things can be printed thanks to a list command.
58+
59+
Print a list of available things and their properties by using this command:
60+
61+
`$ iot-cloud-cli thing list --properties`
62+
63+
Print a *filtered* list of available things, print only things belonging to the ids list:
64+
65+
`$ iot-cloud-cli thing list --ids <thingOneID>,<thingTwoID>`
66+
67+
Print only the thing associated to the passed device:
68+
69+
`$ iot-cloud-cli thing list --device-id <deviceID>`

cli/thing/list.go

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package thing
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/arduino/arduino-cli/cli/feedback"
8+
"github.com/arduino/arduino-cli/table"
9+
"github.com/arduino/iot-cloud-cli/command/thing"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
var listFlags struct {
14+
ids []string
15+
deviceID string
16+
properties bool
17+
}
18+
19+
func initListCommand() *cobra.Command {
20+
listCommand := &cobra.Command{
21+
Use: "list",
22+
Short: "List things",
23+
Long: "List things on Arduino IoT Cloud",
24+
RunE: runListCommand,
25+
}
26+
// list only the things corresponding to the passed ids
27+
listCommand.Flags().StringSliceVarP(&listFlags.ids, "ids", "i", []string{}, "List of thing IDs to be retrieved")
28+
// list only the thing associated to the passed device id
29+
listCommand.Flags().StringVarP(&listFlags.deviceID, "device-id", "d", "", "ID of Device associated to the thing to be retrieved")
30+
listCommand.Flags().BoolVarP(&listFlags.properties, "properties", "p", false, "Show thing properties")
31+
return listCommand
32+
}
33+
34+
func runListCommand(cmd *cobra.Command, args []string) error {
35+
fmt.Println("Listing things")
36+
37+
params := &thing.ListParams{
38+
IDs: listFlags.ids,
39+
Properties: listFlags.properties,
40+
}
41+
if listFlags.deviceID != "" {
42+
params.DeviceID = &listFlags.deviceID
43+
}
44+
45+
things, err := thing.List(params)
46+
if err != nil {
47+
return err
48+
}
49+
50+
feedback.PrintResult(result{things})
51+
return nil
52+
}
53+
54+
type result struct {
55+
things []thing.ThingInfo
56+
}
57+
58+
func (r result) Data() interface{} {
59+
return r.things
60+
}
61+
62+
func (r result) String() string {
63+
if len(r.things) == 0 {
64+
return "No things found."
65+
}
66+
t := table.New()
67+
68+
h := []interface{}{"Name", "ID", "Device"}
69+
if listFlags.properties {
70+
h = append(h, "Properties")
71+
}
72+
t.SetHeader(h...)
73+
74+
for _, thing := range r.things {
75+
r := []interface{}{thing.Name, thing.ID, thing.DeviceID}
76+
if listFlags.properties {
77+
r = append(r, strings.Join(thing.Properties, ", "))
78+
}
79+
t.AddRow(r...)
80+
}
81+
return t.Render()
82+
}

cli/thing/thing.go

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ func NewCommand() *cobra.Command {
1212
}
1313

1414
thingCommand.AddCommand(initCreateCommand())
15+
thingCommand.AddCommand(initListCommand())
1516

1617
return thingCommand
1718
}

command/thing/list.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package thing
2+
3+
import (
4+
"github.com/arduino/iot-cloud-cli/internal/config"
5+
"github.com/arduino/iot-cloud-cli/internal/iot"
6+
)
7+
8+
// ThingInfo contains the main parameters of
9+
// an Arduino IoT Cloud thing.
10+
type ThingInfo struct {
11+
Name string
12+
ID string
13+
DeviceID string
14+
Properties []string
15+
}
16+
17+
// ListParams contains the optional parameters needed
18+
// to filter the things to be listed.
19+
// If IDs is valid, only things belonging to that list are listed.
20+
// If DeviceID is provided, only things associated to that device are listed.
21+
// If Properties is true, properties names are retrieved.
22+
type ListParams struct {
23+
IDs []string
24+
DeviceID *string
25+
Properties bool
26+
}
27+
28+
// List command is used to list
29+
// the things of Arduino IoT Cloud.
30+
func List(params *ListParams) ([]ThingInfo, error) {
31+
conf, err := config.Retrieve()
32+
if err != nil {
33+
return nil, err
34+
}
35+
iotClient, err := iot.NewClient(conf.Client, conf.Secret)
36+
if err != nil {
37+
return nil, err
38+
}
39+
40+
foundThings, err := iotClient.ListThings(params.IDs, params.DeviceID, params.Properties)
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
var things []ThingInfo
46+
for _, foundThing := range foundThings {
47+
var props []string
48+
for _, p := range foundThing.Properties {
49+
props = append(props, p.Name)
50+
}
51+
th := ThingInfo{
52+
Name: foundThing.Name,
53+
ID: foundThing.Id,
54+
DeviceID: foundThing.DeviceId,
55+
Properties: props,
56+
}
57+
things = append(things, th)
58+
}
59+
60+
return things, nil
61+
}

internal/iot/client.go

+22
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type Client interface {
1717
AddCertificate(id, csr string) (*iotclient.ArduinoCompressedv2, error)
1818
AddThing(thing *iotclient.Thing, force bool) (string, error)
1919
GetThing(id string) (*iotclient.ArduinoThing, error)
20+
ListThings(ids []string, device *string, props bool) ([]iotclient.ArduinoThing, error)
2021
}
2122

2223
type client struct {
@@ -117,6 +118,27 @@ func (cl *client) GetThing(id string) (*iotclient.ArduinoThing, error) {
117118
return &thing, nil
118119
}
119120

121+
// ListThings returns a list of things on Arduino IoT Cloud.
122+
func (cl *client) ListThings(ids []string, device *string, props bool) ([]iotclient.ArduinoThing, error) {
123+
opts := &iotclient.ThingsV2ListOpts{}
124+
opts.ShowProperties = optional.NewBool(props)
125+
126+
if ids != nil {
127+
opts.Ids = optional.NewInterface(ids)
128+
}
129+
130+
if device != nil {
131+
opts.DeviceId = optional.NewString(*device)
132+
}
133+
134+
things, _, err := cl.api.ThingsV2Api.ThingsV2List(cl.ctx, opts)
135+
if err != nil {
136+
err = fmt.Errorf("retrieving things, %w", err)
137+
return nil, err
138+
}
139+
return things, nil
140+
}
141+
120142
func (cl *client) setup(client, secret string) error {
121143
// Get the access token in exchange of client_id and client_secret
122144
tok, err := token(client, secret)

0 commit comments

Comments
 (0)