github.com/arduino/arduino-cloud-cli@v0.0.0-20240517070944-e7a449561083/command/device/create.go (about) 1 // This file is part of arduino-cloud-cli. 2 // 3 // Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/) 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published 7 // by the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <https://www.gnu.org/licenses/>. 17 18 package device 19 20 import ( 21 "context" 22 "errors" 23 "fmt" 24 25 "github.com/arduino/arduino-cloud-cli/arduino/cli" 26 "github.com/arduino/arduino-cloud-cli/config" 27 "github.com/arduino/arduino-cloud-cli/internal/iot" 28 "github.com/sirupsen/logrus" 29 ) 30 31 // CreateParams contains the parameters needed 32 // to find the device to be provisioned. 33 type CreateParams struct { 34 Name string // Device name 35 Port *string // Serial port - Optional - If omitted then each serial port is analyzed 36 FQBN *string // Board FQBN - Optional - If omitted then the first device found gets selected 37 ConnectionType *string // Connection type - Optional - If omitted then the default connection type (depends on the board type) get selected 38 } 39 40 // Create command is used to provision a new arduino device 41 // and to add it to Arduino IoT Cloud. 42 func Create(ctx context.Context, params *CreateParams, cred *config.Credentials) (*DeviceInfo, error) { 43 comm, err := cli.NewCommander() 44 if err != nil { 45 return nil, err 46 } 47 48 ports, err := comm.BoardList(ctx) 49 if err != nil { 50 return nil, err 51 } 52 board := boardFromPorts(ports, params) 53 if board == nil { 54 err = errors.New("no board found") 55 return nil, err 56 } 57 58 if !board.isCrypto() { 59 return nil, fmt.Errorf( 60 "board with fqbn %s found at port %s is not a device with a supported crypto-chip.\n"+ 61 "Try the 'create-lora' command instead if it's a LoRa device"+ 62 " or 'create-generic' otherwise", 63 board.fqbn, 64 board.address, 65 ) 66 } 67 68 iotClient, err := iot.NewClient(cred) 69 if err != nil { 70 return nil, err 71 } 72 73 logrus.Info("Creating a new device on the cloud") 74 dev, err := iotClient.DeviceCreate(ctx, board.fqbn, params.Name, board.serial, board.dType, params.ConnectionType) 75 if err != nil { 76 return nil, err 77 } 78 79 prov := &provision{ 80 Commander: comm, 81 cert: iotClient, 82 board: board, 83 id: dev.Id, 84 } 85 if err = prov.run(ctx); err != nil { 86 // Don't use the passed context for the cleanup because it could be cancelled. 87 if errDel := iotClient.DeviceDelete(context.Background(), dev.Id); errDel != nil { 88 return nil, fmt.Errorf( 89 "device was NOT successfully provisioned but " + 90 "now we can't delete it from the cloud - please check " + 91 "it on the web application.\n\nProvision error: " + err.Error() + 92 "\nDeletion error: " + errDel.Error(), 93 ) 94 } 95 return nil, fmt.Errorf("cannot provision device: %w", err) 96 } 97 98 devInfo := &DeviceInfo{ 99 Name: dev.Name, 100 ID: dev.Id, 101 Board: dev.Type, 102 Serial: dev.Serial, 103 FQBN: dev.Fqbn, 104 } 105 return devInfo, nil 106 }