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
Allow DFU flashing devices by Device ID #566
Allow DFU flashing devices by Device ID #566
Conversation
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.
some notes otherwise the big blocker is missing tests 👍
.then(() => dfu.findCompatibleDFU()) | ||
.then(async () => { | ||
targetDevice = await dfu.findCompatibleDFU({ deviceId: device }); | ||
}) |
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.
nit: i've been holding off on async
/ await
to avoid this king of wackiness. i'd prefer either keeping old-school promises or refactoring the entire method instead of mixing things like this.
if (files.length > 0) { | ||
// If both a device and a binary were provided, the binary will come in as the | ||
// first element in the files array | ||
binary = files[0]; |
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.
this is ambiguous at best and likely inaccurate. i've been adding tests like this to help clarify similar behavior.
|
||
// Lookup the Device ID based on the provided Device Name | ||
if (device && !isDeviceId(device)) { | ||
const api = new ParticleApi(settings.apiUrl, { accessToken: settings.access_token }).api; |
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.
at some point i think we're going to have to insist on device IDs across the board as this type of thing leads to confusion - e.g. "why am i getting 4xx errors when flashing locally?!" etc
Would be good to add some notes in this PR for how this new feature works. Or a link to a Docs PR. |
The 2 relevant CLI docs pages are: |
d89d2a9
to
4a155ab
Compare
I've got a lot more work to do on this before it's ready to merge. I'll make this PR a draft until I'm closer to the mark. |
5ff2f73
to
7416d9f
Compare
7416d9f
to
8b411d6
Compare
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.
a few more notes - none of which really speak to the elephant in the room 🤗
to that end, i'm thinking we should take a step back and think about how this all could be simplified - e.g. always target by id so we don't need to worry about non -S
usage? use particle-usb
and related to grab device id? add some special / isolated command namespace to host this functionality? other?
re: testing - extending the e2e
suite to expect two devices connected via USB is probably going to be a major pain (mainly b/c other CLI commands don't handle multiple devices well) so as a first step what i'd want to see is solid testing around the happy path (one device) to ensure we aren't breaking existing functionality.
as always, happy to help on both fronts. thanks again for pulling all of this together - sorry for the pain 🙏👍
@@ -73,6 +76,9 @@ module.exports = ({ commandProcessor, root }) => { | |||
number: true, | |||
description: 'Port number of the server to add to the key' | |||
}, | |||
'device': { | |||
description: 'Device ID of the target device', | |||
}, |
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.
we have a number of commands in this same namespace that accept deviceID
as a parameter - e.g.
Lines 56 to 63 in 5659edf
commandProcessor.createCommand(keys, 'doctor', 'Creates and assigns a new key to your device, and uploads it to the cloud', { | |
params: '<deviceID>', | |
options: protocolOption, | |
handler: (args) => { | |
const KeysCommand = require('../cmd/keys'); | |
return new KeysCommand().keyDoctor(args); | |
} | |
}); |
i think we should either support that call signature (total pain, requires manual arg checking / juggling, etc) - OR - we rename the option (flag) to --deviceID
. in both cases we want to be more explicit about the expected input (since device
means id
or name
across the rest of the CLI commands)
|
||
let deviceInfo; | ||
try { | ||
deviceInfo = await getDevice({ id: device, api, auth: settings.access_token }); |
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.
getDevice()
from device-util
doesn't really do anything special - i'd love it if we could just use the ParticleApi
bits directly so eventually i can just remove device-util
entirely.
return prompt([question]) | ||
.then((ans) => { | ||
const dfuId = ans.device; | ||
module.exports.dfuId = dfuId; |
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.
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.
(for clarity, i'm referring to our exports
usage here not that this line changed 🤗)
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.
Ha! Yeah. Not sure I've ever seen module.exports
used quite like that. I guess that's one way to force private members?
In any case, it makes refactoring DFU related code tricky.
Sorry, this is a bit of a rant, but I've been working this over in my head for a bit and need to put my thoughts somewhere...
Maintaining backwards compatibility with DFU is difficult. The DFU serial numbers used by older bootloaders don't match the Device ID nor are they even unique between devices. 😞 User intervention is required in cases where more than one older device is in DFU mode at a time. That said, we do need a better way to host this functionality. If nothing else, we need better separation of concerns between the commands themselves and the DFU implementation. Currently, both the commands AND the command-specific implementations in the DFU module have a good portion of code duplication. Because of that duplication, I don't think an isolated command namespace would help.
Indeed! While manually testing this, I was just about to commit when I happened to plug in three devices and found new bugs. 🤕 Honestly, DFU isn't going away. While I can think In my mind, that means it needs to be restructured. It needs to not lean so heavily on the I've been sitting on this because we have no immediate need for this functionality... but I think this is a really good example of how we might want to tackle other areas of the CLI. My intention is to draw a line in the sand, isolate all refactoring to the lower implementation details while also leaving as much of the existing code in place as possible since that starts quite a yak shave through a bunch of other code. My planned approach has been loosely this:
If nothing else, just for readability. But more importantly, that adventure will explicitly call out the It would be a good thing to move towards using an Object (or Class) which has a scope we can explicitly manipulate for things like... I don't know, storing data? Writing software? Fixing the world?... as well as moving us towards a way to build test fixtures that don't depend on the internal workings of Node's export implementation for our tests to function. :huff:
That approach should (in theory) let us keep the majority of the calling code as is while we iterate on a refactored implementation/interface. As we go, it will be more apparent where the calling code has to move and whether we need to back track on our implementation to handle unexpected issues. Obviously, this is all just noise until I sit down and open the editor, but I see a path through the trees! |
in what sense? can it be rectified by shipping different toolchains? versioning an interface?
agree. we simply must be able to write to our devices 100% reliably.
absolutely agree. we have this problem throughout this codebase. lots of intermingled
👌
thanks for describing the refactors - i agree it needs some tending to but at this point you've probably stared at the code longer than i have. my big concern is simply not breaking what we have today... or if we do, that the thing we replace it with is known-good (solid tests). i'll schedule some time for us to chat.
with you up until this minor bit. can you elaborate? this is actually i pattern i use a lot and i'm not aware of any unmet expectations..? i was referring to setting the exports object asynchronously - that code for sure breaks in our slowly approaching esm future. everything else, 👍
nice! that counts 👍 |
…lity to flash by Device ID when multiple DFU devices are connected.
…ands as they also use DFU under the hood.
8b411d6
to
f6b693b
Compare
Closing this story as this work is stale and is not an often enough requested feature. |
Story details: https://app.clubhouse.io/particle/story/51961
Yet another CLI PR I should write tests for!