-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcreate.go
136 lines (122 loc) · 3.39 KB
/
create.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package device
import (
"errors"
"fmt"
"strings"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/iot-cloud-cli/arduino/cli"
"github.com/arduino/iot-cloud-cli/internal/config"
"github.com/arduino/iot-cloud-cli/internal/iot"
"github.com/sirupsen/logrus"
)
// CreateParams contains the parameters needed
// to find the device to be provisioned.
type CreateParams struct {
Name string // Device name
Port *string // Serial port - Optional - If omitted then each serial port is analyzed
Fqbn *string // Board FQBN - Optional - If omitted then the first device found gets selected
}
type board struct {
fqbn string
serial string
dType string
port string
}
// Create command is used to provision a new arduino device
// and to add it to Arduino IoT Cloud.
func Create(params *CreateParams) (*DeviceInfo, error) {
comm, err := cli.NewCommander()
if err != nil {
return nil, err
}
ports, err := comm.BoardList()
if err != nil {
return nil, err
}
board := boardFromPorts(ports, params)
if board == nil {
err = errors.New("no board found")
return nil, err
}
conf, err := config.Retrieve()
if err != nil {
return nil, err
}
iotClient, err := iot.NewClient(conf.Client, conf.Secret)
if err != nil {
return nil, err
}
logrus.Info("Creating a new device on the cloud")
dev, err := iotClient.DeviceCreate(board.fqbn, params.Name, board.serial, board.dType)
if err != nil {
return nil, err
}
prov := &provision{
Commander: comm,
Client: iotClient,
board: board,
id: dev.Id,
}
if err = prov.run(); err != nil {
// TODO: retry to delete the device if it returns an error.
// In alternative: encapsulate also this error.
iotClient.DeviceDelete(dev.Id)
err = fmt.Errorf("%s: %w", "cannot provision device", err)
return nil, err
}
devInfo := &DeviceInfo{
Name: dev.Name,
ID: dev.Id,
Board: dev.Type,
Serial: dev.Serial,
FQBN: dev.Fqbn,
}
return devInfo, nil
}
// boardFromPorts returns a board that matches all the criteria
// passed in. If no criteria are passed, it returns the first board found.
func boardFromPorts(ports []*rpc.DetectedPort, params *CreateParams) *board {
for _, port := range ports {
if portFilter(port, params) {
continue
}
boardFound := boardFilter(port.Boards, params)
if boardFound != nil {
t := strings.Split(boardFound.Fqbn, ":")[2]
b := &board{boardFound.Fqbn, port.SerialNumber, t, port.Address}
return b
}
}
return nil
}
// portFilter filters out the given port in the following cases:
// - if the port parameter does not match the actual port address.
// - if the the detected port does not contain any board.
// It returns:
// true -> to skip the port
// false -> to keep the port
func portFilter(port *rpc.DetectedPort, params *CreateParams) bool {
if len(port.Boards) == 0 {
return true
}
if params.Port != nil && *params.Port != port.Address {
return true
}
return false
}
// boardFilter looks for a board which has the same fqbn passed as parameter.
// If fqbn parameter is nil, then the first board found is returned.
// It returns:
// - a board if it is found.
// - nil if no board matching the fqbn parameter is found.
func boardFilter(boards []*rpc.BoardListItem, params *CreateParams) (board *rpc.BoardListItem) {
if params.Fqbn == nil {
return boards[0]
}
for _, b := range boards {
if b.Fqbn == *params.Fqbn {
return b
}
}
return
}