-
Notifications
You must be signed in to change notification settings - Fork 83
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
Feature Page Phase 2 #1482
Feature Page Phase 2 #1482
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.
Great job @ethanzhouyc !!!!!
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.
Will need some more time to go through this because of its size.
@@ -2046,6 +2048,50 @@ async function selectNonManufacturerSpecificCommandDetailsFromAllEndpointTypesAn | |||
) | |||
} | |||
|
|||
/** | |||
* Get all commands in an endpoint type cluster | |||
* Non-required commands are not loaded into ENDPOINT_TYPE_COMMAND table, |
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.
Are non-required attributes loaded into endpoint_type_attribute table? I don't see deviceTypeClusterId being used in selectAttributesByEndpointTypeClusterId
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, if you create an endpoint and check ENDPOINT_TYPE_ATTRIBUTE table, there will be attributes with INCLUDED = 0, so deviceTypeClusterId is not needed here
mandatoryFeaturesOnEndpointTypeAndCluster.map((f) => f.featureBit) | ||
// only set featureMap bit to 1 for mandatory features | ||
let featureMapBitsToBeEnabled = featuresOnEndpointTypeAndCluster | ||
.filter((f) => f.conformance == 'M') |
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 do we filter for just Mandatory? Were we doing something wrong before?
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.
Before, we only loaded mandatory features to the database so there is no need to filter. Now features with all types of conformance exist
src-electron/db/query-feature.js
Outdated
f.BIT, | ||
f.DEFAULT_VALUE, | ||
f.DESCRIPTION | ||
d.DESCRIPTION AS DEVICE_TYPE_NAME, |
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.
Fix the formatting here.
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 format is in good shape if you view the actual file instead of PR diff. Github is displaying it weirdly
New changes:
|
cb06253
to
665b0f7
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.
Lost of stuff..... I marked some obvious things, including some typos.
async function getFeaturesByDeviceTypeRefs( | ||
db, | ||
deviceTypeRefs, | ||
endpointTypeRef |
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 don't understand why "get feature by device type" needs an "endpoint type" all of suddenly?
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.
ENDPOINT_TYPE_ATTRIBUTE and ATTRIBUTE table is joined to get info on:
- featureMap value related to the feature, deciding if the feature is enabled
- attribute id of featureMap, which is needed when updating the featureMap after toggling a feature
src-electron/rest/user-data.js
Outdated
* @param {*} db | ||
* @returns callback for the express uri registration | ||
*/ | ||
function httpPostSetRequiredElements(db) { |
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 confused with the name of this function..... Why do you need to POST the required elements? Aren't the required elements calculated on the back-end and at best sent over to the front-end as result of some "POST" that sets feature bits or something like that?
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.
You are right. I changed it to a GET request as it only gets resources from backend and not change them
src-electron/rest/user-data.js
Outdated
return async (request, response) => { | ||
let resp = await querySessionNotification.setRequiredElementWarning( | ||
db, | ||
request.body, |
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 seems unsafe and suspicious to post the whole request body straight into the query. This feels wrong somehow.
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 improved this by only getting relevant variables passed from frontend, creating a new object out of them, and passing the new object to backend
if (operand.mandatoryConform) { | ||
let insideTerm = operand.mandatoryConform[0] | ||
// Recurse further if insideTerm is not empty | ||
if (insideTerm && Object.keys(insideTerm).toString() != '$') { | ||
return parseFeatureConformance(operand.mandatoryConform[0]) | ||
return parseConformanceRecursively(operand.mandatoryConform[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.
I generally like to pass a "depth" to any recursive function. You start with "depth = 0" and then whenever you call recursively, you call it with "depth+1". When depth gets to like 200, you know you're doing something wrong, you blow up with a clear exception, instead of some stupid stack overflow which is hard to track down.
But I'm possibly old school....
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.
That's great advice for keeping recursive functions safe, but this function is already safeguarded against infinite recursion levels, as:
- each recursive call moves one layer deeper into the xml data object
- the
if/else if/else
structure ensures that all cases have a return value
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.
You are not guarding against yourself. You are guarding against a future developer, who might add things to this function, that would mistakenly cause this to end up in stack overflow.
Generally, be always aware who you're developing for:
1.) For you, TODAY.
2.) For you, TOMORROW.
3.) For a random guy that has no clue and shows up here TOMORROW.
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.
Not a terribly big deal though, not something to hold this up for.
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 added a max depth check on the recursive function as you said so someone in the future would get an error if they blow up
All typos and SQL related comments are addressed |
// process andTerm and orTerm in the same logic | ||
// when joining multiple orTerms inside andTerms, we need to | ||
// surround them with '()', vice versa for andTerms inside orTerms | ||
// e.g. A & (B | C) or A | (B & C) |
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.
You should use antlr for these kid of things in the future.
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 we could switch to ANTLR if conformance parsing became too complicated to be parsed one day
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.
Merge this in. There are things that are a bit weird, but we shouldn't hold this up.
You can clean up later.
Generally:
1.) Break up these large reworks into multiple PRs. There is nothing, for example, stopping you to do a smaller PR, that just updates the DB schema, then push that in. While we review that, you work on the next PR for middleware, and then up to the UI. Or whatever direction you want, but layer by layer.
2.) Large things like this are nicely developed if you have a toplevel preference option to turn these features on and off. That protects you, for example, in Zigbee case, where you can simply keep this off, and not even enable it, then Zigbee doesn't fall victim to your bugs.
There will be future cleanup PR to separate feature related code from Zigbee |
7984454
to
c92cdc6
Compare
New Features:
1. Enable toggle of device type features
featureMap
attribute for the cluster of toggled feature2. Add conformance warning to elements
3. Other improvements:
featureMap
attributeExample Use Cases:
1. Enable
HS
feature in an endpoint withExtended Color Light
device type2. After enabling
HS
, disabling attributeCurrentHue
that conforms toHS
will cause conformance warnings