Skip to content

Commit f2555c3

Browse files
committed
add device network configuration command
1 parent 88de618 commit f2555c3

File tree

17 files changed

+2181
-188
lines changed

17 files changed

+2181
-188
lines changed

cli/device/configure.go

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
// This file is part of arduino-cloud-cli.
2+
//
3+
// Copyright (C) 2025 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+
"encoding/json"
23+
"errors"
24+
"fmt"
25+
"net"
26+
"os"
27+
"strings"
28+
29+
"github.com/arduino/arduino-cli/cli/errorcodes"
30+
"github.com/arduino/arduino-cli/cli/feedback"
31+
"github.com/arduino/arduino-cloud-cli/command/device"
32+
"github.com/sirupsen/logrus"
33+
"github.com/spf13/cobra"
34+
"go.bug.st/cleanup"
35+
)
36+
37+
type netConfigurationFlags struct {
38+
port string
39+
connectionType int32
40+
fqbn string
41+
configFile string
42+
}
43+
44+
func initConfigureCommand() *cobra.Command {
45+
flags := &netConfigurationFlags{}
46+
createCommand := &cobra.Command{
47+
Use: "configure",
48+
Short: "Configure the network settings of a device running a sketch with the Network Configurator lib enabled",
49+
Long: "Configure the network settings of a device running a sketch with the Network Configurator lib enabled",
50+
Run: func(cmd *cobra.Command, args []string) {
51+
if err := runConfigureCommand(flags); err != nil {
52+
feedback.Errorf("Error during device configuration: %v", err)
53+
os.Exit(errorcodes.ErrGeneric)
54+
}
55+
},
56+
}
57+
createCommand.Flags().StringVarP(&flags.port, "port", "p", "", "Device port")
58+
createCommand.Flags().StringVarP(&flags.fqbn, "fqbn", "b", "", "Device fqbn")
59+
createCommand.Flags().Int32VarP(&flags.connectionType, "connection", "c", 0, "Device connection type (1: WiFi, 2: Ethernet, 3: NB-IoT, 4: GSM, 5: LoRaWan, 6:CAT-M1, 7: Cellular)")
60+
createCommand.Flags().StringVarP(&flags.configFile, "config-file", "f", "", "Path to the configuration file (optional). View online documentation for the format")
61+
createCommand.MarkFlagRequired("connection")
62+
63+
return createCommand
64+
}
65+
66+
func runConfigureCommand(flags *netConfigurationFlags) error {
67+
logrus.Infof("Configuring device with connection type %d", flags.connectionType)
68+
69+
netParams := &device.NetConfig{
70+
Type: flags.connectionType,
71+
}
72+
73+
if flags.configFile != "" {
74+
file, err := os.ReadFile(flags.configFile)
75+
if err != nil {
76+
logrus.Errorf("Error reading file %s: %v", flags.configFile, err)
77+
return err
78+
}
79+
err = json.Unmarshal(file, &netParams)
80+
if err != nil {
81+
logrus.Errorf("Error parsing JSON from file %s: %v", flags.configFile, err)
82+
return err
83+
}
84+
} else {
85+
feedback.Print("Insert network configuration")
86+
getInputFromMenu(netParams)
87+
}
88+
89+
boardFilterParams := &device.CreateParams{}
90+
91+
if flags.port != "" {
92+
boardFilterParams.Port = &flags.port
93+
}
94+
if flags.fqbn != "" {
95+
boardFilterParams.FQBN = &flags.fqbn
96+
}
97+
98+
ctx, cancel := cleanup.InterruptableContext(context.Background())
99+
defer cancel()
100+
feedback.Print("Starting network configuration...")
101+
err := device.NetConfigure(ctx, boardFilterParams, netParams)
102+
if err != nil {
103+
return err
104+
}
105+
feedback.Print("Network configuration successfully completed.")
106+
return nil
107+
}
108+
109+
func getInputFromMenu(config *device.NetConfig) error {
110+
111+
switch config.Type {
112+
case 1:
113+
config.WiFi = getWiFiSetting()
114+
case 2:
115+
config.Eth = getEthernetSetting()
116+
case 3:
117+
config.NB = getCellularSetting()
118+
case 4:
119+
config.GSM = getCellularSetting()
120+
case 5:
121+
config.Lora = getLoraSetting()
122+
case 6:
123+
config.CATM1 = getCatM1Setting()
124+
case 7:
125+
config.CellularSetting = getCellularSetting()
126+
default:
127+
return errors.New("invalid connection type, please try again")
128+
}
129+
return nil
130+
}
131+
132+
func getWiFiSetting() device.WiFiSetting {
133+
var wifi device.WiFiSetting
134+
fmt.Print("Enter SSID: ")
135+
fmt.Scanln(&wifi.SSID)
136+
fmt.Print("Enter Password: ")
137+
fmt.Scanln(&wifi.PWD)
138+
return wifi
139+
}
140+
141+
func getEthernetSetting() device.EthernetSetting {
142+
var eth device.EthernetSetting
143+
fmt.Println("Do you want to use DHCP? (yes/no): ")
144+
var useDHCP string
145+
fmt.Scanln(&useDHCP)
146+
if useDHCP == "yes" || useDHCP == "y" {
147+
eth.IP = device.IPAddr{Type: 0, Bytes: [16]byte{}}
148+
eth.Gateway = device.IPAddr{Type: 0, Bytes: [16]byte{}}
149+
eth.Netmask = device.IPAddr{Type: 0, Bytes: [16]byte{}}
150+
eth.DNS = device.IPAddr{Type: 0, Bytes: [16]byte{}}
151+
} else {
152+
fmt.Println("Enter IP Address: ")
153+
eth.IP = getIPAddr()
154+
fmt.Println("Enter DNS: ")
155+
eth.DNS = getIPAddr()
156+
fmt.Println("Enter Gateway: ")
157+
eth.Gateway = getIPAddr()
158+
fmt.Println("Enter Netmask: ")
159+
eth.Netmask = getIPAddr()
160+
}
161+
162+
return eth
163+
}
164+
165+
func getIPAddr() device.IPAddr {
166+
var ip device.IPAddr
167+
var ipString string
168+
fmt.Scanln(&ipString)
169+
if ipString == "" {
170+
return ip
171+
}
172+
if strings.Count(ipString, ":") > 0 {
173+
ip.Type = 1 // IPv6
174+
} else {
175+
ip.Type = 0 // IPv4
176+
}
177+
ip.Bytes = [16]byte(net.ParseIP(ipString).To16())
178+
return ip
179+
}
180+
181+
func getCellularSetting() device.CellularSetting {
182+
var cellular device.CellularSetting
183+
fmt.Println("Enter PIN: ")
184+
fmt.Scanln(&cellular.PIN)
185+
fmt.Print("Enter APN: ")
186+
fmt.Scanln(&cellular.APN)
187+
fmt.Print("Enter Login: ")
188+
fmt.Scanln(&cellular.Login)
189+
fmt.Print("Enter Password: ")
190+
fmt.Scanln(&cellular.Pass)
191+
return cellular
192+
}
193+
194+
func getCatM1Setting() device.CATM1Setting {
195+
var catm1 device.CATM1Setting
196+
fmt.Print("Enter PIN: ")
197+
fmt.Scanln(&catm1.PIN)
198+
fmt.Print("Enter APN: ")
199+
fmt.Scanln(&catm1.APN)
200+
fmt.Print("Enter Login: ")
201+
fmt.Scanln(&catm1.Login)
202+
fmt.Print("Enter Password: ")
203+
fmt.Scanln(&catm1.Pass)
204+
return catm1
205+
}
206+
207+
func getLoraSetting() device.LoraSetting {
208+
var lora device.LoraSetting
209+
fmt.Print("Enter AppEUI: ")
210+
fmt.Scanln(&lora.AppEUI)
211+
fmt.Print("Enter AppKey: ")
212+
fmt.Scanln(&lora.AppKey)
213+
fmt.Print("Enter Band (Byte hex format): ")
214+
fmt.Scanln(&lora.Band)
215+
fmt.Print("Enter Channel Mask: ")
216+
fmt.Scanln(&lora.ChannelMask)
217+
fmt.Print("Enter Device Class: ")
218+
fmt.Scanln(&lora.DeviceClass)
219+
return lora
220+
}

cli/device/device.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func NewCommand() *cobra.Command {
3030
}
3131

3232
deviceCommand.AddCommand(initCreateCommand())
33+
deviceCommand.AddCommand(initConfigureCommand())
3334
deviceCommand.AddCommand(initListCommand())
3435
deviceCommand.AddCommand(initShowCommand())
3536
deviceCommand.AddCommand(initDeleteCommand())

0 commit comments

Comments
 (0)