-
-
Notifications
You must be signed in to change notification settings - Fork 4
Add ota upload command #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
acd718a
Import ota generator
polldo 6d032de
Implement ota generation
polldo b86b4c6
Add ota upload command
polldo 58ec5ef
Adapt to format-output changes
polldo 3c6bb55
Fix typos
polldo 6a84477
Improve ota upload help
polldo d19303a
Add deferred option
polldo 9e8ddb8
Improve deferred ota
polldo 890be53
Update readme
polldo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package ota | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func NewCommand() *cobra.Command { | ||
otaCommand := &cobra.Command{ | ||
Use: "ota", | ||
Short: "Over The Air.", | ||
Long: "Over The Air firmware update.", | ||
} | ||
|
||
otaCommand.AddCommand(initUploadCommand()) | ||
|
||
return otaCommand | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package ota | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/arduino/arduino-cli/cli/errorcodes" | ||
"github.com/arduino/arduino-cli/cli/feedback" | ||
"github.com/arduino/iot-cloud-cli/command/ota" | ||
"github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var uploadFlags struct { | ||
deviceID string | ||
file string | ||
deferred bool | ||
} | ||
|
||
func initUploadCommand() *cobra.Command { | ||
uploadCommand := &cobra.Command{ | ||
Use: "upload", | ||
Short: "OTA upload", | ||
Long: "OTA upload on a device of Arduino IoT Cloud", | ||
Run: runUploadCommand, | ||
} | ||
|
||
uploadCommand.Flags().StringVarP(&uploadFlags.deviceID, "device-id", "d", "", "Device ID") | ||
uploadCommand.Flags().StringVarP(&uploadFlags.file, "file", "", "", "Binary file (.bin) to be uploaded") | ||
uploadCommand.Flags().BoolVar(&uploadFlags.deferred, "deferred", false, "Perform a deferred OTA. It can take up to 1 week.") | ||
|
||
uploadCommand.MarkFlagRequired("device-id") | ||
uploadCommand.MarkFlagRequired("file") | ||
return uploadCommand | ||
} | ||
|
||
func runUploadCommand(cmd *cobra.Command, args []string) { | ||
logrus.Infof("Uploading binary %s to device %s", uploadFlags.file, uploadFlags.deviceID) | ||
|
||
params := &ota.UploadParams{ | ||
DeviceID: uploadFlags.deviceID, | ||
File: uploadFlags.file, | ||
} | ||
err := ota.Upload(params) | ||
if err != nil { | ||
feedback.Errorf("Error during ota upload: %v", err) | ||
os.Exit(errorcodes.ErrGeneric) | ||
} | ||
|
||
logrus.Info("Upload successfully started") | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package ota | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"io/ioutil" | ||
"os" | ||
|
||
inota "github.com/arduino/iot-cloud-cli/internal/ota" | ||
) | ||
|
||
var ( | ||
arduinoVendorID = "2341" | ||
fqbnToPID = map[string]string{ | ||
"arduino:samd:nano_33_iot": "8057", | ||
"arduino:samd:mkr1000": "804E", | ||
"arduino:samd:mkrgsm1400": "8052", | ||
"arduino:samd:mkrnb1500": "8055", | ||
"arduino:samd:mkrwifi1010": "8054", | ||
"arduino:mbed_nano:nanorp2040connect": "005E", | ||
"arduino:mbed_portenta:envie_m7": "025B", | ||
} | ||
) | ||
|
||
// Generate takes a .bin file and generates a .ota file. | ||
func Generate(binFile string, outFile string, fqbn string) error { | ||
productID, ok := fqbnToPID[fqbn] | ||
if !ok { | ||
return errors.New("fqbn not valid") | ||
} | ||
|
||
data, err := ioutil.ReadFile(binFile) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var w bytes.Buffer | ||
otaWriter := inota.NewWriter(&w, arduinoVendorID, productID) | ||
_, err = otaWriter.Write(data) | ||
if err != nil { | ||
return err | ||
} | ||
otaWriter.Close() | ||
|
||
err = ioutil.WriteFile(outFile, w.Bytes(), os.FileMode(0644)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package ota | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/arduino/iot-cloud-cli/internal/config" | ||
"github.com/arduino/iot-cloud-cli/internal/iot" | ||
) | ||
|
||
const ( | ||
// default ota should complete in 10 mins | ||
otaExpirationMins = 10 | ||
// deferred ota can take up to 1 week (equal to 10080 minutes) | ||
otaDeferredExpirationMins = 10080 | ||
) | ||
|
||
// UploadParams contains the parameters needed to | ||
// perform an OTA upload. | ||
type UploadParams struct { | ||
DeviceID string | ||
File string | ||
Deferred bool | ||
} | ||
|
||
// Upload command is used to upload a firmware OTA, | ||
// on a device of Arduino IoT Cloud. | ||
func Upload(params *UploadParams) error { | ||
conf, err := config.Retrieve() | ||
if err != nil { | ||
return err | ||
} | ||
iotClient, err := iot.NewClient(conf.Client, conf.Secret) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
dev, err := iotClient.DeviceShow(params.DeviceID) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
otaDir, err := ioutil.TempDir("", "") | ||
if err != nil { | ||
return fmt.Errorf("%s: %w", "cannot create temporary folder", err) | ||
} | ||
otaFile := filepath.Join(otaDir, "temp.ota") | ||
defer os.RemoveAll(otaDir) | ||
|
||
err = Generate(params.File, otaFile, dev.Fqbn) | ||
if err != nil { | ||
return fmt.Errorf("%s: %w", "cannot generate .ota file", err) | ||
} | ||
|
||
file, err := os.Open(otaFile) | ||
if err != nil { | ||
return fmt.Errorf("%s: %w", "cannot open ota file", err) | ||
} | ||
|
||
expiration := otaExpirationMins | ||
if params.Deferred { | ||
expiration = otaDeferredExpirationMins | ||
} | ||
|
||
err = iotClient.DeviceOTA(params.DeviceID, file, expiration) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we generate the file directly in the generic temporary directory? Also, I think it could be useful to not delete the binary in case we (or some sophisticated user) want to look at it for debugging purposes.
If I'm not wrong it should be regularly deleted by the OS anyway (I know this happens at least on Ubuntu). Or we could give the possibility to decide this behaviour with a
--debug
flag.What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean? It is generated in the temp directory
here I see two reasons for not doing this:
.ota
exists, so leaving a compressed binary would be also dangerous.ota
file, we should add a specificota generate
command.ota
files is risky. Each ota file is valid only for a specific board, if a user tries to upload it to a different board then the firmware will not be applied and the user is not notified of the causes..ota
files are compressed.bin
files with the addition of an header, for debug purposes the.bin
file should be analyzedin conclusion I don't see any benefits in letting the user see or know about a
.ota
fileThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean replacing lines 37-41 with:
So that we don't create a temporary directory but just a file.
Ok, you convinced me 😛 (we or the sophisticated user can always edit the source code to accomplish it)