diff --git a/README.md b/README.md index c2422bb6..e4c3de8f 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,12 @@ Use this command to provision a device: `$ arduino-cloud-cli device create --name --port --fqbn ` +####LoRa + +The list of supported LoRa frequency plans can be retrieved with: + +`$ arduino-cloud-cli device list-frequency-plans` + ## Device commands Devices can be deleted using the device delete command. This command accepts two mutually exclusive flags: `--id` and `--tags`. Only one of them must be passed. When the `--id` is passed, the device having such ID gets deleted: diff --git a/cli/device/device.go b/cli/device/device.go index 51a894ec..988bff19 100644 --- a/cli/device/device.go +++ b/cli/device/device.go @@ -34,6 +34,7 @@ func NewCommand() *cobra.Command { deviceCommand.AddCommand(initDeleteCommand()) deviceCommand.AddCommand(tag.InitCreateTagsCommand()) deviceCommand.AddCommand(tag.InitDeleteTagsCommand()) + deviceCommand.AddCommand(initListFrequencyPlansCommand()) return deviceCommand } diff --git a/cli/device/listfrequency.go b/cli/device/listfrequency.go new file mode 100644 index 00000000..32140dc9 --- /dev/null +++ b/cli/device/listfrequency.go @@ -0,0 +1,75 @@ +// 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 . + +package device + +import ( + "os" + + "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/feedback" + "github.com/arduino/arduino-cli/table" + "github.com/arduino/arduino-cloud-cli/command/device" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func initListFrequencyPlansCommand() *cobra.Command { + listCommand := &cobra.Command{ + Use: "list-frequency-plans", + Short: "List LoRa frequency plans", + Long: "List all supported LoRa frequency plans", + Run: runListFrequencyPlansCommand, + } + return listCommand +} + +func runListFrequencyPlansCommand(cmd *cobra.Command, args []string) { + logrus.Info("Listing supported frequency plans") + + freqs, err := device.ListFrequencyPlans() + if err != nil { + feedback.Errorf("Error during device list-frequency-plans: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + + feedback.PrintResult(listFrequencyPlansResult{freqs}) +} + +type listFrequencyPlansResult struct { + freqs []device.FrequencyPlanInfo +} + +func (r listFrequencyPlansResult) Data() interface{} { + return r.freqs +} + +func (r listFrequencyPlansResult) String() string { + if len(r.freqs) == 0 { + return "No frequency plan found." + } + t := table.New() + t.SetHeader("ID", "Name", "Advanced") + for _, freq := range r.freqs { + t.AddRow( + freq.ID, + freq.Name, + freq.Advanced, + ) + } + return t.Render() +} diff --git a/command/device/listfrequency.go b/command/device/listfrequency.go new file mode 100644 index 00000000..8f92973e --- /dev/null +++ b/command/device/listfrequency.go @@ -0,0 +1,62 @@ +// 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 . + +package device + +import ( + "fmt" + + "github.com/arduino/arduino-cloud-cli/internal/config" + "github.com/arduino/arduino-cloud-cli/internal/iot" +) + +// FrequencyPlanInfo describes a LoRa frequency plan. +type FrequencyPlanInfo struct { + Name string `json:"name"` + ID string `json:"id"` + Advanced string `json:"advanced"` +} + +// ListFrequencyPlans command is used to list +// the supported LoRa frequency plans. +func ListFrequencyPlans() ([]FrequencyPlanInfo, error) { + conf, err := config.Retrieve() + if err != nil { + return nil, err + } + iotClient, err := iot.NewClient(conf.Client, conf.Secret) + if err != nil { + return nil, err + } + + foundFreqs, err := iotClient.LoraFrequencyPlansList() + if err != nil { + return nil, err + } + + freqs := make([]FrequencyPlanInfo, 0, len(foundFreqs)) + for _, f := range foundFreqs { + freq := FrequencyPlanInfo{ + Name: f.Name, + ID: f.Id, + Advanced: fmt.Sprintf("%v",f.Advanced), + } + freqs = append(freqs, freq) + } + + return freqs, nil +} diff --git a/internal/iot/client.go b/internal/iot/client.go index db238523..166ac783 100644 --- a/internal/iot/client.go +++ b/internal/iot/client.go @@ -35,6 +35,7 @@ type Client interface { DeviceOTA(id string, file *os.File, expireMins int) error DeviceTagsCreate(id string, tags map[string]string) error DeviceTagsDelete(id string, keys []string) error + LoraFrequencyPlansList() ([]iotclient.ArduinoLorafreqplanv1, error) CertificateCreate(id, csr string) (*iotclient.ArduinoCompressedv2, error) ThingCreate(thing *iotclient.ThingCreate, force bool) (*iotclient.ArduinoThing, error) ThingUpdate(id string, thing *iotclient.ThingUpdate, force bool) error @@ -166,6 +167,17 @@ func (cl *client) DeviceTagsDelete(id string, keys []string) error { return nil } +// LoraFrequencyPlansList retrieves and returns the list of all supported +// LoRa frequency plans. +func (cl *client) LoraFrequencyPlansList() ([]iotclient.ArduinoLorafreqplanv1, error) { + freqs, _, err := cl.api.LoraFreqPlanV1Api.LoraFreqPlanV1List(cl.ctx) + if err != nil { + err = fmt.Errorf("listing lora frequency plans: %w", errorDetail(err)) + return nil, err + } + return freqs.FrequencyPlans, nil +} + // CertificateCreate allows to upload a certificate on Arduino IoT Cloud. // It returns the certificate parameters populated by the cloud. func (cl *client) CertificateCreate(id, csr string) (*iotclient.ArduinoCompressedv2, error) { diff --git a/internal/iot/mocks/Client.go b/internal/iot/mocks/Client.go index d83af81b..e6d7151b 100644 --- a/internal/iot/mocks/Client.go +++ b/internal/iot/mocks/Client.go @@ -245,6 +245,29 @@ func (_m *Client) DeviceTagsDelete(id string, keys []string) error { return r0 } +// LoraFrequencyPlansList provides a mock function with given fields: +func (_m *Client) LoraFrequencyPlansList() ([]iot.ArduinoLorafreqplanv1, error) { + ret := _m.Called() + + var r0 []iot.ArduinoLorafreqplanv1 + if rf, ok := ret.Get(0).(func() []iot.ArduinoLorafreqplanv1); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]iot.ArduinoLorafreqplanv1) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // ThingCreate provides a mock function with given fields: thing, force func (_m *Client) ThingCreate(thing *iot.ThingCreate, force bool) (*iot.ArduinoThing, error) { ret := _m.Called(thing, force)