Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: arduino/arduino-cloud-cli
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: arduino/arduino-cloud-cli
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: mass-device-provisioning
Choose a head ref
Able to merge. These branches can be automatically merged.
  • 6 commits
  • 8 files changed
  • 1 contributor

Commits on Feb 7, 2024

  1. Copy the full SHA
    61a4b67 View commit details

Commits on Feb 8, 2024

  1. Refactored strcuture

    rjtokenring committed Feb 8, 2024
    Copy the full SHA
    1770dfb View commit details
  2. Code cleaning

    rjtokenring committed Feb 8, 2024
    Copy the full SHA
    04958b9 View commit details
  3. name provisioning

    rjtokenring committed Feb 8, 2024
    Copy the full SHA
    42638df View commit details
  4. added filtering

    rjtokenring committed Feb 8, 2024
    Copy the full SHA
    7a7fa2c View commit details

Commits on Feb 16, 2024

  1. Copy the full SHA
    46f1546 View commit details
Showing with 252 additions and 39 deletions.
  1. +1 −0 cli/device/device.go
  2. +125 −0 cli/device/masscreate.go
  3. +17 −17 command/device/board.go
  4. +9 −9 command/device/board_test.go
  5. +3 −3 command/device/create.go
  6. +6 −6 command/device/createlora.go
  7. +87 −0 command/device/masscreate.go
  8. +4 −4 command/device/provision.go
1 change: 1 addition & 0 deletions cli/device/device.go
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ func NewCommand() *cobra.Command {
}

deviceCommand.AddCommand(initCreateCommand())
deviceCommand.AddCommand(initMassCreateCommand())
deviceCommand.AddCommand(initListCommand())
deviceCommand.AddCommand(initDeleteCommand())
deviceCommand.AddCommand(tag.InitCreateTagsCommand())
125 changes: 125 additions & 0 deletions cli/device/masscreate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// This file is part of arduino-cloud-cli.
//
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package device

import (
"context"
"fmt"
"os"

"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cloud-cli/command/device"
"github.com/arduino/arduino-cloud-cli/config"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"go.bug.st/cleanup"
)

type massCreateFlags struct {
name string
fqbn string
}

func initMassCreateCommand() *cobra.Command {
flags := &massCreateFlags{}
createCommand := &cobra.Command{
Use: "mass-create",
Short: "Mass create a set of devices provisioning the onboard secure element with a valid certificate",
Long: "Mass create a set of devices for Arduino IoT Cloud provisioning the onboard secure element with a valid certificate",
Run: func(cmd *cobra.Command, args []string) {
if err := runMassCreateCommand(flags); err != nil {
feedback.Errorf("Error during device create: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
},
}
createCommand.Flags().StringVarP(&flags.name, "name", "n", "", "Base device name")
createCommand.Flags().StringVarP(&flags.fqbn, "fqbn", "b", "", "Device fqbn")
createCommand.MarkFlagRequired("name")
return createCommand
}


func runMassCreateCommand(flags *massCreateFlags) error {
logrus.Infof("Mass provisioning devices. Base name: %s", flags.name)

cred, err := config.RetrieveCredentials()
if err != nil {
return fmt.Errorf("retrieving credentials: %w", err)
}

ctx, cancel := cleanup.InterruptableContext(context.Background())
defer cancel()

boards, err := device.ListAllConnectedBoardsWithCrypto(&flags.fqbn)
if err != nil {
return err
}
if len(boards) == 0 {
return fmt.Errorf("no boards of type %s detected", flags.fqbn)
}

var results []*device.DeviceInfo
for idx, board := range boards {
if len(board.Address) == 0{
continue
}
logrus.Infof("Provisioning board on port: %s", board.Address)
bname := fmt.Sprintf("%s-%d", flags.name, idx)
params := &device.CreateParams{
Name: bname,
Port: &board.Address,
FQBN: &board.Fqbn,
}

dev, err := device.Create(ctx, params, cred)
if err != nil {
return err
}

results = append(results, dev)
}

feedback.PrintResult(massCreateResult{results})

return nil
}

type massCreateResult struct {
devices []*device.DeviceInfo
}

func (r massCreateResult) Data() interface{} {
return r.devices
}

func (r massCreateResult) String() string {
var result string
for _, device := range r.devices {
result += fmt.Sprintf(
"name: %s\nid: %s\nboard: %s\nserial_number: %s\nfqbn: %s\n-------------\n",
device.Name,
device.ID,
device.Board,
device.Serial,
device.FQBN,
)
}
return result
}
34 changes: 17 additions & 17 deletions command/device/board.go
Original file line number Diff line number Diff line change
@@ -43,29 +43,29 @@ var (
)

// board contains details of a physical arduino board.
type board struct {
fqbn string
serial string
dType string
address string
protocol string
type Board struct {
Fqbn string
Serial string
DType string
Address string
Protocol string
}

// isCrypto checks if the board is a valid arduino board with a
// supported crypto-chip.
func (b *board) isCrypto() bool {
func (b *Board) isCrypto() bool {
for _, f := range cryptoFQBN {
if b.fqbn == f {
if b.Fqbn == f {
return true
}
}
return false
}

// isLora checks if the board is a valid LoRa arduino board.
func (b *board) isLora() bool {
func (b *Board) isLora() bool {
for _, f := range loraFQBN {
if b.fqbn == f {
if b.Fqbn == f {
return true
}
}
@@ -74,19 +74,19 @@ func (b *board) isLora() bool {

// 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 {
func boardFromPorts(ports []*rpc.DetectedPort, params *CreateParams) *Board {
for _, port := range ports {
if portFilter(port, params) {
continue
}
boardFound := boardFilter(port.MatchingBoards, params)
if boardFound != nil {
b := &board{
fqbn: boardFound.Fqbn,
serial: port.Port.Properties["serialNumber"],
dType: strings.Split(boardFound.Fqbn, ":")[2],
address: port.Port.Address,
protocol: port.Port.Protocol,
b := &Board{
Fqbn: boardFound.Fqbn,
Serial: port.Port.Properties["serialNumber"],
DType: strings.Split(boardFound.Fqbn, ":")[2],
Address: port.Port.Address,
Protocol: port.Port.Protocol,
}
return b
}
18 changes: 9 additions & 9 deletions command/device/board_test.go
Original file line number Diff line number Diff line change
@@ -61,21 +61,21 @@ func TestBoardFromPorts(t *testing.T) {
name string
filter *CreateParams
ports []*rpc.DetectedPort
want *board
want *Board
}{

{
name: "port-filter",
filter: &CreateParams{FQBN: nil, Port: stringPointer("ACM1")},
ports: portsTwoBoards,
want: &board{fqbn: "arduino:avr:uno", address: "ACM1"},
want: &Board{Fqbn: "arduino:avr:uno", Address: "ACM1"},
},

{
name: "fqbn-filter",
filter: &CreateParams{FQBN: stringPointer("arduino:avr:uno"), Port: nil},
ports: portsTwoBoards,
want: &board{fqbn: "arduino:avr:uno", address: "ACM1"},
want: &Board{Fqbn: "arduino:avr:uno", Address: "ACM1"},
},

{
@@ -90,7 +90,7 @@ func TestBoardFromPorts(t *testing.T) {
filter: &CreateParams{FQBN: nil, Port: nil},
ports: portsTwoBoards,
// first board found is selected
want: &board{fqbn: "arduino:samd:nano_33_iot", address: "ACM0"},
want: &Board{Fqbn: "arduino:samd:nano_33_iot", Address: "ACM0"},
},

{
@@ -104,7 +104,7 @@ func TestBoardFromPorts(t *testing.T) {
name: "both-filter-found",
filter: &CreateParams{FQBN: stringPointer("arduino:avr:uno"), Port: stringPointer("ACM1")},
ports: portsTwoBoards,
want: &board{fqbn: "arduino:avr:uno", address: "ACM1"},
want: &Board{Fqbn: "arduino:avr:uno", Address: "ACM1"},
},

{
@@ -123,14 +123,14 @@ func TestBoardFromPorts(t *testing.T) {
return

} else if got != nil && tt.want == nil {
t.Errorf("Expected nil board, received not nil board with port %s and fqbn %s", got.address, got.fqbn)
t.Errorf("Expected nil board, received not nil board with port %s and fqbn %s", got.Address, got.Fqbn)

} else if got == nil && tt.want != nil {
t.Errorf("Expected not nil board with port %s and fqbn %s, received a nil board", tt.want.address, tt.want.fqbn)
t.Errorf("Expected not nil board with port %s and fqbn %s, received a nil board", tt.want.Address, tt.want.Fqbn)

} else if got.address != tt.want.address || got.fqbn != tt.want.fqbn {
} else if got.Address != tt.want.Address || got.Fqbn != tt.want.Fqbn {
t.Errorf("Expected board with port %s and fqbn %s, received board with port %s and fqbn %s",
tt.want.address, tt.want.fqbn, got.address, got.fqbn)
tt.want.Address, tt.want.Fqbn, got.Address, got.Fqbn)
}
})
}
6 changes: 3 additions & 3 deletions command/device/create.go
Original file line number Diff line number Diff line change
@@ -60,8 +60,8 @@ func Create(ctx context.Context, params *CreateParams, cred *config.Credentials)
"board with fqbn %s found at port %s is not a device with a supported crypto-chip.\n"+
"Try the 'create-lora' command instead if it's a LoRa device"+
" or 'create-generic' otherwise",
board.fqbn,
board.address,
board.Fqbn,
board.Address,
)
}

@@ -71,7 +71,7 @@ func Create(ctx context.Context, params *CreateParams, cred *config.Credentials)
}

logrus.Info("Creating a new device on the cloud")
dev, err := iotClient.DeviceCreate(ctx, board.fqbn, params.Name, board.serial, board.dType, params.ConnectionType)
dev, err := iotClient.DeviceCreate(ctx, board.Fqbn, params.Name, board.Serial, board.DType, params.ConnectionType)
if err != nil {
return nil, err
}
12 changes: 6 additions & 6 deletions command/device/createlora.go
Original file line number Diff line number Diff line change
@@ -84,26 +84,26 @@ func CreateLora(ctx context.Context, params *CreateLoraParams, cred *config.Cred
"board with fqbn %s found at port %s is not a LoRa device."+
" Try the 'create' command instead if it's a device with a supported crypto-chip"+
" or 'create-generic' otherwise",
board.fqbn,
board.address,
board.Fqbn,
board.Address,
)
}

bin, err := downloadProvisioningFile(ctx, board.fqbn)
bin, err := downloadProvisioningFile(ctx, board.Fqbn)
if err != nil {
return nil, err
}

logrus.Infof("%s", "Uploading deveui sketch on the LoRa board")
errMsg := "Error while uploading the LoRa provisioning binary"
err = retry(ctx, deveuiUploadAttempts, deveuiUploadWait*time.Millisecond, errMsg, func() error {
return comm.UploadBin(ctx, board.fqbn, bin, board.address, board.protocol)
return comm.UploadBin(ctx, board.Fqbn, bin, board.Address, board.Protocol)
})
if err != nil {
return nil, fmt.Errorf("failed to upload LoRa provisioning binary: %w", err)
}

eui, err := extractEUI(ctx, board.address)
eui, err := extractEUI(ctx, board.Address)
if err != nil {
return nil, err
}
@@ -114,7 +114,7 @@ func CreateLora(ctx context.Context, params *CreateLoraParams, cred *config.Cred
}

logrus.Info("Creating a new device on the cloud")
dev, err := iotClient.DeviceLoraCreate(ctx, params.Name, board.serial, board.dType, eui, params.FrequencyPlan)
dev, err := iotClient.DeviceLoraCreate(ctx, params.Name, board.Serial, board.DType, eui, params.FrequencyPlan)
if err != nil {
return nil, err
}
Loading