Skip to content

Commit 1111ba6

Browse files
committed
Refactor thing (#27)
adapt cloud-cli thing templates to the already established concept of template: - extracted templates are more "compliant" with the already known templates - standard cloud thing templates can now be used to create new things * Adapt template extraction remove properties_count, max_value, min_value, persist and tag fields add template name field change helper to remark that a template is being extracted instead of a thing. * Adapt thing creation to rfc thing create command has been split in two commands: - thing create -> create a thing from a template. name parameter is optional and, if it's present, it overrides the name provided by the template - thing clone -> create a thing from an existing thing. name parameter of the new thing is mandatory thing templates have been aligned with general iot cloud templates concept now templates like this: https://github.com/bcmi-labs/cloud-templates/blob/main/templates/home-security-alarm/resources/thing.yml can be directly used to create new things. * Replace Properties with Variables * Update readme
1 parent 2987e76 commit 1111ba6

File tree

10 files changed

+186
-116
lines changed

10 files changed

+186
-116
lines changed

Diff for: README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,22 @@ Devices currently present on Arduino IoT Cloud can be retrieved by using this co
4343

4444
## Thing commands
4545

46-
Things can be created starting from a template or by cloning another thing. Additionally, a thing name should be specified.
46+
Things can be created starting from a template or by cloning another thing.
4747

48-
Create a thing from a template:
48+
Create a thing from a thing template. The name parameter is optional. If it is provided then it overrides the name retrieved from the template:
4949

5050
`$ iot-cloud-cli thing create --name <thingName> --template <template.json>`
5151

52-
Create a thing by cloning another thing:
52+
Create a thing by cloning another thing, here the *name is mandatory*:
5353

54-
`$ iot-cloud-cli thing create --name <thingName> --clone-id <thingToCloneID>`
54+
`$ iot-cloud-cli thing clone --name <thingName> --clone-id <thingToCloneID>`
5555

5656

5757
Things can be printed thanks to a list command.
5858

59-
Print a list of available things and their properties by using this command:
59+
Print a list of available things and their variables by using this command:
6060

61-
`$ iot-cloud-cli thing list --properties`
61+
`$ iot-cloud-cli thing list --show-variables`
6262

6363
Print a *filtered* list of available things, print only things belonging to the ids list:
6464

Diff for: cli/thing/clone.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package thing
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/arduino/iot-cloud-cli/command/thing"
7+
"github.com/spf13/cobra"
8+
)
9+
10+
var cloneFlags struct {
11+
name string
12+
cloneID string
13+
}
14+
15+
func initCloneCommand() *cobra.Command {
16+
cloneCommand := &cobra.Command{
17+
Use: "clone",
18+
Short: "Clone a thing",
19+
Long: "Clone a thing for Arduino IoT Cloud",
20+
RunE: runCloneCommand,
21+
}
22+
cloneCommand.Flags().StringVarP(&cloneFlags.name, "name", "n", "", "Thing name")
23+
cloneCommand.Flags().StringVarP(&cloneFlags.cloneID, "clone-id", "c", "", "ID of Thing to be cloned")
24+
cloneCommand.MarkFlagRequired("name")
25+
cloneCommand.MarkFlagRequired("clone-id")
26+
return cloneCommand
27+
}
28+
29+
func runCloneCommand(cmd *cobra.Command, args []string) error {
30+
fmt.Printf("Cloning thing %s into a new thing called %s\n", cloneFlags.cloneID, cloneFlags.name)
31+
32+
params := &thing.CloneParams{
33+
Name: cloneFlags.name,
34+
CloneID: cloneFlags.cloneID,
35+
}
36+
37+
thingID, err := thing.Clone(params)
38+
if err != nil {
39+
return err
40+
}
41+
42+
fmt.Printf("IoT Cloud thing created with ID: %s\n", thingID)
43+
return nil
44+
}

Diff for: cli/thing/create.go

+4-10
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,28 @@ import (
99

1010
var createFlags struct {
1111
name string
12-
deviceID string
1312
template string
14-
cloneID string
1513
}
1614

1715
func initCreateCommand() *cobra.Command {
1816
createCommand := &cobra.Command{
1917
Use: "create",
20-
Short: "Create a thing",
21-
Long: "Create a thing for Arduino IoT Cloud",
18+
Short: "Create a thing from a template",
19+
Long: "Create a thing from a template for Arduino IoT Cloud",
2220
RunE: runCreateCommand,
2321
}
2422
createCommand.Flags().StringVarP(&createFlags.name, "name", "n", "", "Thing name")
25-
createCommand.Flags().StringVarP(&createFlags.deviceID, "device-id", "d", "", "ID of Device to bind to the new thing")
26-
createCommand.Flags().StringVarP(&createFlags.cloneID, "clone-id", "c", "", "ID of Thing to be cloned")
2723
createCommand.Flags().StringVarP(&createFlags.template, "template", "t", "", "File containing a thing template")
28-
createCommand.MarkFlagRequired("name")
24+
createCommand.MarkFlagRequired("template")
2925
return createCommand
3026
}
3127

3228
func runCreateCommand(cmd *cobra.Command, args []string) error {
33-
fmt.Printf("Creating thing with name %s\n", createFlags.name)
29+
fmt.Printf("Creating thing from template %s\n", createFlags.template)
3430

3531
params := &thing.CreateParams{
3632
Name: createFlags.name,
37-
DeviceID: createFlags.deviceID,
3833
Template: createFlags.template,
39-
CloneID: createFlags.cloneID,
4034
}
4135

4236
thingID, err := thing.Create(params)

Diff for: cli/thing/extract.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ var extractFlags struct {
1515
func initExtractCommand() *cobra.Command {
1616
extractCommand := &cobra.Command{
1717
Use: "extract",
18-
Short: "Extract and save a thing",
19-
Long: "Extract a thing from Arduino IoT Cloud and save it in a template file",
18+
Short: "Extract a template from a thing",
19+
Long: "Extract a template from a Arduino IoT Cloud thing and save it in a file",
2020
RunE: runExtractCommand,
2121
}
2222
extractCommand.Flags().StringVarP(&extractFlags.id, "id", "i", "", "Thing ID")
@@ -26,7 +26,7 @@ func initExtractCommand() *cobra.Command {
2626
}
2727

2828
func runExtractCommand(cmd *cobra.Command, args []string) error {
29-
fmt.Printf("Extracting thing %s\n", extractFlags.id)
29+
fmt.Printf("Extracting template from thing %s\n", extractFlags.id)
3030

3131
params := &thing.ExtractParams{ID: extractFlags.id}
3232
if extractFlags.outfile != "" {
@@ -38,6 +38,6 @@ func runExtractCommand(cmd *cobra.Command, args []string) error {
3838
return err
3939
}
4040

41-
fmt.Println("Thing successfully extracted")
41+
fmt.Println("Template successfully extracted")
4242
return nil
4343
}

Diff for: cli/thing/list.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import (
1111
)
1212

1313
var listFlags struct {
14-
ids []string
15-
deviceID string
16-
properties bool
14+
ids []string
15+
deviceID string
16+
variables bool
1717
}
1818

1919
func initListCommand() *cobra.Command {
@@ -27,16 +27,16 @@ func initListCommand() *cobra.Command {
2727
listCommand.Flags().StringSliceVarP(&listFlags.ids, "ids", "i", []string{}, "List of thing IDs to be retrieved")
2828
// list only the thing associated to the passed device id
2929
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")
30+
listCommand.Flags().BoolVarP(&listFlags.variables, "show-variables", "s", false, "Show thing variables")
3131
return listCommand
3232
}
3333

3434
func runListCommand(cmd *cobra.Command, args []string) error {
3535
fmt.Println("Listing things")
3636

3737
params := &thing.ListParams{
38-
IDs: listFlags.ids,
39-
Properties: listFlags.properties,
38+
IDs: listFlags.ids,
39+
Variables: listFlags.variables,
4040
}
4141
if listFlags.deviceID != "" {
4242
params.DeviceID = &listFlags.deviceID
@@ -66,15 +66,15 @@ func (r result) String() string {
6666
t := table.New()
6767

6868
h := []interface{}{"Name", "ID", "Device"}
69-
if listFlags.properties {
70-
h = append(h, "Properties")
69+
if listFlags.variables {
70+
h = append(h, "Variables")
7171
}
7272
t.SetHeader(h...)
7373

7474
for _, thing := range r.things {
7575
r := []interface{}{thing.Name, thing.ID, thing.DeviceID}
76-
if listFlags.properties {
77-
r = append(r, strings.Join(thing.Properties, ", "))
76+
if listFlags.variables {
77+
r = append(r, strings.Join(thing.Variables, ", "))
7878
}
7979
t.AddRow(r...)
8080
}

Diff for: 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(initCloneCommand())
1516
thingCommand.AddCommand(initListCommand())
1617
thingCommand.AddCommand(initDeleteCommand())
1718
thingCommand.AddCommand(initExtractCommand())

Diff for: command/thing/clone.go

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package thing
2+
3+
import (
4+
"fmt"
5+
6+
iotclient "github.com/arduino/iot-client-go"
7+
"github.com/arduino/iot-cloud-cli/internal/config"
8+
"github.com/arduino/iot-cloud-cli/internal/iot"
9+
)
10+
11+
// CloneParams contains the parameters needed to clone a thing.
12+
type CloneParams struct {
13+
// Mandatory - contains the name of the thing
14+
Name string
15+
// Mandatory - specifies ID of thing to be cloned
16+
CloneID string
17+
}
18+
19+
// Clone allows to create a new thing from an already existing one
20+
func Clone(params *CloneParams) (string, error) {
21+
conf, err := config.Retrieve()
22+
if err != nil {
23+
return "", err
24+
}
25+
iotClient, err := iot.NewClient(conf.Client, conf.Secret)
26+
if err != nil {
27+
return "", err
28+
}
29+
30+
thing, err := retrieve(iotClient, params.CloneID)
31+
if err != nil {
32+
return "", err
33+
}
34+
35+
thing.Name = params.Name
36+
force := true
37+
thingID, err := iotClient.AddThing(thing, force)
38+
if err != nil {
39+
return "", err
40+
}
41+
42+
return thingID, nil
43+
}
44+
45+
func retrieve(client iot.Client, thingID string) (*iotclient.Thing, error) {
46+
clone, err := client.GetThing(thingID)
47+
if err != nil {
48+
return nil, fmt.Errorf("%s: %w", "retrieving the thing to be cloned", err)
49+
}
50+
51+
thing := &iotclient.Thing{}
52+
53+
// Copy variables
54+
for _, p := range clone.Properties {
55+
thing.Properties = append(thing.Properties, iotclient.Property{
56+
Name: p.Name,
57+
Permission: p.Permission,
58+
UpdateParameter: p.UpdateParameter,
59+
UpdateStrategy: p.UpdateStrategy,
60+
Type: p.Type,
61+
VariableName: p.VariableName,
62+
})
63+
}
64+
65+
return thing, nil
66+
}

0 commit comments

Comments
 (0)