Skip to content

Commit 83a780d

Browse files
authored
Add device network configuration (#175)
* add device network configuration command * add test for configuration and provisioning protocol * fix licenses * add comments
1 parent 88de618 commit 83a780d

File tree

24 files changed

+2842
-290
lines changed

24 files changed

+2842
-290
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
name: github.com/fxamacker/cbor/v2
3+
version: v2.8.0
4+
type: go
5+
summary: Package cbor is a modern CBOR codec (RFC 8949 & RFC 8742) with CBOR tags,
6+
Go struct tag options (toarray/keyasint/omitempty/omitzero), Core Deterministic
7+
Encoding, CTAP2, Canonical CBOR, float64->32->16, and duplicate map key detection.
8+
homepage: https://pkg.go.dev/github.com/fxamacker/cbor/v2
9+
license: mit
10+
licenses:
11+
- sources: LICENSE
12+
text: |-
13+
MIT License
14+
15+
Copyright (c) 2019-present Faye Amacker
16+
17+
Permission is hereby granted, free of charge, to any person obtaining a copy
18+
of this software and associated documentation files (the "Software"), to deal
19+
in the Software without restriction, including without limitation the rights
20+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21+
copies of the Software, and to permit persons to whom the Software is
22+
furnished to do so, subject to the following conditions:
23+
24+
The above copyright notice and this permission notice shall be included in all
25+
copies or substantial portions of the Software.
26+
27+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33+
SOFTWARE.
34+
- sources: README.md
35+
text: |-
36+
Copyright © 2019-2024 [Faye Amacker](https://github.com/fxamacker).
37+
38+
fxamacker/cbor is licensed under the MIT License. See [LICENSE](LICENSE) for the full license text.
39+
40+
<hr>
41+
notices: []
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
name: github.com/x448/float16
3+
version: v0.8.4
4+
type: go
5+
summary:
6+
homepage: https://pkg.go.dev/github.com/x448/float16
7+
license: mit
8+
licenses:
9+
- sources: LICENSE
10+
text: |+
11+
MIT License
12+
13+
Copyright (c) 2019 Montgomery Edwards⁴⁴⁸ and Faye Amacker
14+
15+
Permission is hereby granted, free of charge, to any person obtaining a copy
16+
of this software and associated documentation files (the "Software"), to deal
17+
in the Software without restriction, including without limitation the rights
18+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19+
copies of the Software, and to permit persons to whom the Software is
20+
furnished to do so, subject to the following conditions:
21+
22+
The above copyright notice and this permission notice shall be included in all
23+
copies or substantial portions of the Software.
24+
25+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31+
SOFTWARE.
32+
33+
- sources: README.md
34+
text: |-
35+
Copyright (c) 2019 Montgomery Edwards⁴⁴⁸ and Faye Amacker
36+
37+
Licensed under [MIT License](LICENSE)
38+
notices: []

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)