Skip to content

Commit ca2a03a

Browse files
committed
Add thing extract command (#25)
Extract a template from an existing thing using this command: $ iot-cloud-cli thing extract --id <thingID> --outfile <templateFile.json> outfile parameter is optional, it specifies the json destination file for the template * Add thing extract command * Update readme
1 parent da9d34a commit ca2a03a

File tree

4 files changed

+135
-1
lines changed

4 files changed

+135
-1
lines changed

Diff for: README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,8 @@ Print only the thing associated to the passed device:
7070

7171
Delete a thing with the following command:
7272

73-
`$ iot-cloud-cli thing delete --device-id <deviceID>`
73+
`$ iot-cloud-cli thing delete --device-id <deviceID>`
74+
75+
Extract a template from an existing thing:
76+
77+
`$ iot-cloud-cli thing extract --id <thingID> --outfile <templateFile.json>`

Diff for: cli/thing/extract.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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 extractFlags struct {
11+
id string
12+
outfile string
13+
}
14+
15+
func initExtractCommand() *cobra.Command {
16+
extractCommand := &cobra.Command{
17+
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",
20+
RunE: runExtractCommand,
21+
}
22+
extractCommand.Flags().StringVarP(&extractFlags.id, "id", "i", "", "Thing ID")
23+
extractCommand.Flags().StringVarP(&extractFlags.outfile, "outfile", "o", "", "Template file destination path")
24+
extractCommand.MarkFlagRequired("id")
25+
return extractCommand
26+
}
27+
28+
func runExtractCommand(cmd *cobra.Command, args []string) error {
29+
fmt.Printf("Extracting thing %s\n", extractFlags.id)
30+
31+
params := &thing.ExtractParams{ID: extractFlags.id}
32+
if extractFlags.outfile != "" {
33+
params.Outfile = &extractFlags.outfile
34+
}
35+
36+
err := thing.Extract(params)
37+
if err != nil {
38+
return err
39+
}
40+
41+
fmt.Println("Thing successfully extracted")
42+
return nil
43+
}

Diff for: cli/thing/thing.go

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ func NewCommand() *cobra.Command {
1414
thingCommand.AddCommand(initCreateCommand())
1515
thingCommand.AddCommand(initListCommand())
1616
thingCommand.AddCommand(initDeleteCommand())
17+
thingCommand.AddCommand(initExtractCommand())
1718

1819
return thingCommand
1920
}

Diff for: command/thing/extract.go

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package thing
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io/ioutil"
7+
"os"
8+
9+
iotclient "github.com/arduino/iot-client-go"
10+
"github.com/arduino/iot-cloud-cli/internal/config"
11+
"github.com/arduino/iot-cloud-cli/internal/iot"
12+
)
13+
14+
// ExtractParams contains the parameters needed to
15+
// extract a thing from Arduino IoT Cloud and save it on local storage.
16+
// Output indicates the destination path of the extraction.
17+
type ExtractParams struct {
18+
ID string
19+
Outfile *string
20+
}
21+
22+
// Extract command is used to extract a thing template
23+
// from a thing on Arduino IoT Cloud.
24+
func Extract(params *ExtractParams) error {
25+
conf, err := config.Retrieve()
26+
if err != nil {
27+
return err
28+
}
29+
iotClient, err := iot.NewClient(conf.Client, conf.Secret)
30+
if err != nil {
31+
return err
32+
}
33+
34+
thing, err := iotClient.GetThing(params.ID)
35+
if err != nil {
36+
err = fmt.Errorf("%s: %w", "cannot extract thing: ", err)
37+
return err
38+
}
39+
40+
template, err := templateFromThing(thing)
41+
if err != nil {
42+
return err
43+
}
44+
45+
if params.Outfile == nil {
46+
outfile := thing.Name + "-template.json"
47+
params.Outfile = &outfile
48+
}
49+
err = ioutil.WriteFile(*params.Outfile, template, os.FileMode(0644))
50+
if err != nil {
51+
err = fmt.Errorf("%s: %w", "cannot write outfile: ", err)
52+
return err
53+
}
54+
55+
return nil
56+
}
57+
58+
func templateFromThing(thing *iotclient.ArduinoThing) ([]byte, error) {
59+
template := make(map[string]interface{})
60+
template["properties_count"] = thing.PropertiesCount
61+
62+
var props []map[string]interface{}
63+
for _, p := range thing.Properties {
64+
prop := make(map[string]interface{})
65+
prop["max_value"] = p.MaxValue
66+
prop["min_value"] = p.MinValue
67+
prop["name"] = p.Name
68+
prop["permission"] = p.Permission
69+
prop["persist"] = p.Persist
70+
prop["tag"] = p.Tag
71+
prop["type"] = p.Type
72+
prop["update_parameter"] = p.UpdateParameter
73+
prop["update_strategy"] = p.UpdateStrategy
74+
prop["variable_name"] = p.VariableName
75+
props = append(props, prop)
76+
}
77+
template["properties"] = props
78+
79+
// Extract json template from thing structure
80+
file, err := json.MarshalIndent(template, "", " ")
81+
if err != nil {
82+
err = fmt.Errorf("%s: %w", "thing marshal failure: ", err)
83+
return nil, err
84+
}
85+
return file, nil
86+
}

0 commit comments

Comments
 (0)