-
Notifications
You must be signed in to change notification settings - Fork 64
New paradigm for handling attached devices #61
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
Conversation
src/colordistancesensor.ts
Outdated
this.on("newListener", (event) => { | ||
switch (event) { | ||
case "color": | ||
this.subscribe(0x00); |
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.
I wonder if we should avoid using hex notation as all const are in decimal and I see modes as almost const.
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.
In this case I don't mind either way. But for Consts.DeviceType
I would actually prefer to use hex literals as this is how they are listed in LWP doc.
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.
It's a good question. I think for the moment having the values hardcoded is a placeholder, I'd like to put all consts in a file somewhere. So - hex or decimal? Perhaps hex as @nutki suggests?
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.
Yes, like @nutki wrote hex make more sense regarding the doc. Even more if we had some const with all message headers and all.
Plus, the end users can use whatever format they want when they call methods.
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.
src/basicmotor.ts
Outdated
* @param {number} speed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | ||
* @returns {Promise} Resolved upon successful completion of command. | ||
*/ | ||
public setSpeed (speed: number) { |
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.
Since basic motors don't have a tachometer, this is actually setPower
. I guess this makes it easier for the API, but would you then have setSpeed
and setPower
for tacho motors or just setSpeed
?
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.
Good point. I guess I haven't liked power
as I think for most users speed
is a more appropriate term for what they want, even if it isn't exactly the same. I don't this library should attempt to exactly emulate LWP functionally, instead adding a user friendly layer on top of it.
Perhaps we could have setSpeed(50)
set power by default, however with an options object (such as setSpeed(50, { maxPower: 50 })
to switch to maintaining the speed with power?
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.
@nutki I've gone with setPower
and done a 180 on this. :) Will implement setSpeed
appropriately later.
src/device.ts
Outdated
this._portId = portId; | ||
this._type = type; | ||
this.hub.on("detach", (device) => { | ||
if (device.portId === this.portId) { |
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.
Wouldn't device === this
be better? This way old disconnected devices would not generate detach
events.
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.
Good catch. Will change this.
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.
Maybe a more straightforward approach would be to remove this listener on detach.
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.
@nutki Listener is now removed on detach.
src/device.ts
Outdated
} | ||
|
||
public send (data: Buffer, characteristic: string = Consts.BLECharacteristic.LPF2_ALL, callback?: () => void) { | ||
this.hub.send(data, characteristic, callback); |
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.
Doesn't this send LPF2_ALL
characteristic messages to WeDo2 hub? As a side note, I am not sure if continued support of the WeDo hub makes sense. The new devices will not be supported on it anyway since the FW is not updatable (according to a Lego designer) and it has limited availability (which also makes it expensive).
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.
Right now, yes, eventually I want to have each device method (ie. setSpeed
) switch characteristics and message based on hub type.
Regarding the WeDo 2.0 support - I've also been thinking about this recently, but I think I want to keep support personally, as I actually use a few WeDo 2.0 hubs myself. :) They are currently the only hub type that offers an AC adapter so it can run forever.
On the topic of firmware support, that's correct - however most newer devices can be supported on it in some way. See the compatibility matrix in the readme of this project.
Eventually I might drop it though - especially if Lego releases a hub with an AC adapter.
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.
Yeah, I understand that WeDo support is mostly for people who already own one. Iteresting about the AC adapter though, I have not heard about it. Is this stand alone or the one with rechargeable battery allows to bypass the battery? Long time ago I especially for that purpose bought Lego RCX with an AC plug, even though I already had 2 without :)
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.
Yeah, I understand that WeDo support is mostly for people who already own one. Iteresting about the AC adapter though, I have not heard about it. Is this stand alone or the one with rechargeable battery allows to bypass the battery? Long time ago I especially for that purpose bought Lego RCX with an AC plug, even though I already had 2 without :)
It's the rechargeable battery pack for the WeDo 2.0 hub - it has a built in port to plug in an AC adapter. :)
https://education.lego.com/en-us/products/wedo-2-0-add-on-power-pack-by-lego-education/5004838
That will allow you to keep a WeDo 2.0 hub running forever.
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.
I've implemented some WeDo2 support into some devices - it's actually on par with master feature wise, but I may implement some more modes, once I test to see what works and doesn't!
It's much simpler to implement WeDo2 support with each motor/sensor having its own device class.
src/hub.ts
Outdated
|
||
protected _ports: {[port: string]: Port} = {}; | ||
protected _virtualPorts: {[port: string]: Port} = {}; | ||
protected _attachedDevices: 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.
Given the current use I would say a map of portId to Device would make more sense than a flat array for _attachedDevices
.
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.
I think so too. But object literals don't accept numbers as key type, and I was hoping not to use ES6 maps. I guess we could though ("Just shut up and do it, Nathan!")
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.
I'm totally wrong - they do support numbers as keys/property names, just not in initializers. I'll change to use this. :)
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.
Do you mean initializes as in: ({0:'Test'})[0]
? It does work for me. What's wrong with ES6 Maps, btw? I strongly prefer them to using POJOs for maps, especially in Typescript.
src/pupremote.ts
Outdated
this.type = Consts.HubType.POWERED_UP_REMOTE; | ||
this._ports = { | ||
"LEFT": new Port("LEFT", 0), | ||
"RIGHT": new Port("RIGHT", 1) | ||
this._type = Consts.HubType.POWERED_UP_REMOTE; | ||
this._portNames = { | ||
"LEFT": 0, | ||
"RIGHT": 1 |
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 looks repetitive over hubs, does it make sense to use the same approach you have on devices ?
super(device, autosubscribe, Consts.HubType.POWERED_UP_REMOTE, {
"LEFT": 0,
"RIGHT": 1
});
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.
Yeah, perhaps so. To be honest I’ve barely touched the hub setup, I’ve been focused on the device abstraction. But they will get a revamp too.
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 also now done - #61 (comment)
examples/winter_village_train.js
Outdated
sensor = hub; | ||
|
||
sensor.on("distance", (_, distance) => { | ||
if (distance < 5 && !ramping) { | ||
await stopTrain(); | ||
} | ||
}); |
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 listen a device (sensor) event on the hub, does it mean we support device events at the hub level ?
If it does not call the same method on the device, it does not subscribe to the correct mode.
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.
Oops, I shouldn’t have committed that! :) It’s for my house - designed to run on the old code (master). But I haven’t though more about supporting that as of now.
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.
It makes a nice example !
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.
the new waitForDeviceByType
should allow you to migrate this to the new paradigm
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.
Yeah - it was an idea that only occurred to me last night while thinking about other stuff, but it solves a problem that many people have, ie. not knowing when to call getDeviceByType
without watching for an attach
event, by which point it's provided to you anyway. It just makes it easier to maintain a more sequential coding pattern, which is easier for a lot of people.
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.
It's also how I was thinking this could support internal motors/functions on a hub rather on device. ie. If a boost internal motor has a method setSpeed(speed)
, I can create a lightweight wrapper on the hub called setSpeed(port, speed)
, which simply passes through the values to the method on the device after using waitForDeviceByPort
.
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.
Awesome
src/boostmovehub.ts
Outdated
this._portNames = { | ||
"A": 0, | ||
"B": 1, | ||
"C": 2, | ||
"D": 3, | ||
"TILT": 58 |
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.
I've now created a const (exported under the hub namespace) for each hub, accessible via PoweredUP.WeDo2SmartHub.PortMap
, etc. This is also passed to the root hub object at constructor time. It's also available at runtime via a ports
getter, ie. hub.ports = ["A", "B", ...]
.
…weredup into feature/devices
…weredup into feature/devices
angle = normalizeAngle(angle); | ||
if (angle < -135) { | ||
return -180; | ||
} | ||
if (angle < -45) { | ||
return -90; | ||
} | ||
if (angle < 45) { | ||
return 0; | ||
} | ||
if (angle < 135) { | ||
return 90; | ||
} | ||
return -180; |
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.
I would go for a more mathematical approach :
export const roundAngleToNearest90 = (angle: number) => {
return normalizeAngle(Math.round(angle/90)*90);
}
I think at this point this PR has reached feature parity with what was there before. I'd love some help testing it before I end up approving it and merging it to master and pushing out a new release. I'm hoping to do this soon - especially as my copy of Spike Prime is scheduled to be delivered today, so I'll have some new devices to add support for shortly! :) |
… bluetooth example
… bluetooth example
Do you have any testing plan ? I have no idea where to start. Aslo, I can only test the web-bluetooth part with my current setup. |
My testing plan up until now has been quite simple - for every hub, try every sensor in every mode, and every motors output. :D It's not especially quick. Thus far I'm happy with this PR, though more testing (both similar to the plan and real-life application testing) I'm always thankful for! I think the main things I need to do now are update the documentation and JSDoc comments, and update the samples. |
This is a work in progress PR to implement some of the changes discussed in #49.
Currently, large swathes of code are commented out. The approach I'm taking for this is a bottom up approach - starting with minimal functionality and adding upon it, until feature parity is nearly reached.
Currently implemented:
In addition, this starts to implement an auto-subscribe mechanism (originally suggested by @nutki in #60). Currently it is a Big Ugly Switch Statement(TM), however my hope is that this can be reduced and automated with some of the logic implemented by @aileo in #60.
I've added a temporary example at
examples/new_device_test.js
to demonstrate how the new paradigm would work.