Skip to content
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

RFC - connection aging #292

Merged
merged 7 commits into from
Apr 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"scanChannels": 8190,
"allowFTDISerial": false,
"allowAMASerial": false,
"showBattery": false,
"showAging": false,
"debug": ""
},
"schema": {
Expand All @@ -39,15 +39,15 @@
"type": "boolean",
"default": false
},
"showBattery": {
"type": "boolean",
"title": "Show Battery Percentage",
"description": "experimental: Show the 'batteryPercentageRemaining' attribute as a property. Note that this attribute is reported from a power constrained device with possibly low quality consumer-grade batteries. Therefore, it may not represent what you expect. Particularly, it may drop in large increments and may suddenly go from, say, 50% to 1%. This attribute is reported very infrequently, maybe as little as once a day, so may take a while to appear after being enabled."
},
"debug": {
"type": "string",
"default": ""
},
"showAging": {
"type": "boolean",
"title": "Show Aging",
"description": "experimental - Creates an additional 'Last seen' property to show when each device was last active on the Zigbee network"
},
"zigbee2mqtt": {
"title": "Zigbee2Mqtt",
"type": "object",
Expand Down
27 changes: 27 additions & 0 deletions src/zb-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,9 @@ class ZigbeeAdapter extends Adapter {
// the ZHA protocol.
const node = this.nodes[frame.remote64];
if (node) {
if (typeof node.updateLastSeen === 'function') {
node.updateLastSeen();
}
for (const property of node.properties.values()) {
if (DEBUG_flow) {
console.error(node.addr64, 'bind failed - setting fireAndForget to true');
Expand Down Expand Up @@ -506,6 +509,9 @@ class ZigbeeAdapter extends Adapter {
}
const node = this.findNodeFromRxFrame(frame);
if (node) {
if (typeof node.updateLastSeen === 'function') {
node.updateLastSeen();
}
node.handleZhaResponse(frame);
} else {
console.log('Node:', frame.remote64, frame.remote16, 'not found');
Expand Down Expand Up @@ -605,6 +611,11 @@ class ZigbeeAdapter extends Adapter {
if (!node) {
return;
}

if (typeof node.updateLastSeen === 'function') {
node.updateLastSeen();
}

if (this.scanning) {
if (DEBUG_flow) {
console.log('Ignoring Match Descriptor Request - scanning in progress');
Expand Down Expand Up @@ -731,6 +742,9 @@ class ZigbeeAdapter extends Adapter {
this.activeEndpointResponseCount++;
const node = this.nodes[frame.remote64];
if (node) {
if (typeof node.updateLastSeen === 'function') {
node.updateLastSeen();
}
for (const endpointNum of frame.activeEndpoints) {
if (!(endpointNum in node.activeEndpoints)) {
node.activeEndpoints[endpointNum] = {};
Expand Down Expand Up @@ -792,6 +806,10 @@ class ZigbeeAdapter extends Adapter {
}
const node = this.createNodeIfRequired(frame.remote64, frame.remote16);

if (node && typeof node.updateLastSeen === 'function') {
node.updateLastSeen();
}

for (let i = 0; i < frame.numEntriesThisResponse; i++) {
const neighborIndex = frame.startIndex + i;
const neighbor = frame.neighbors[i];
Expand Down Expand Up @@ -943,6 +961,11 @@ class ZigbeeAdapter extends Adapter {
if (!node) {
return;
}

if (typeof node.updateLastSeen === 'function') {
node.updateLastSeen();
}

const endpoint = node.activeEndpoints[frame.endpoint];
if (endpoint) {
endpoint.queryingSimpleDescriptor = false;
Expand Down Expand Up @@ -1029,6 +1052,10 @@ class ZigbeeAdapter extends Adapter {
return;
}

if (typeof node.updateLastSeen === 'function') {
node.updateLastSeen();
}

if (DEBUG_flow) {
console.log('handleManagementLeaveResponse: Removing node:', node.addr64);
}
Expand Down
38 changes: 37 additions & 1 deletion src/zb-classifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,6 @@ class ZigbeeClassifier {
maximum: 100,
multipleOf: 0.5,
readOnly: true,
visible: !!node.driver.config.showBattery,
},
PROFILE_ID.ZHA, // profileId
genPowerCfgEndpoint, // endpoint
Expand Down Expand Up @@ -1808,6 +1807,41 @@ class ZigbeeClassifier {
}
}

addLastSeenProperty(node) {
if (node.driver.config.showAging) {
const lastSeen = new ZigbeeProperty(
node,
'lastSeen', // name
{
type: 'string',
readOnly: true,
label: 'Last seen',
},
'', // profileId
'', // endPoint
'', // clusterId
'', // attr
null, // setAttrFromValue
null // parseValueFromAttr
);
node.properties.set('lastSeen', lastSeen);
lastSeen.value = '';
lastSeen.fireAndForget = true;

node.updateLastSeen = () => {
const d = new Date();
// there's no easy way to construct an ISO date with local timezone, so do it the hard way
/* eslint-disable max-len */
// prettier-ignore
const s =
`${d.getFullYear()}-${(`0${d.getMonth() + 1}`).slice(-2)}-${(`0${d.getDate()}`).slice(-2)}
${(`0${d.getHours()}`).slice(-2)}:${(`0${d.getMinutes()}`).slice(-2)}:${(`0${d.getSeconds()}`).slice(-2)}`;
/* eslint-enable max-len */
lastSeen.setCachedValueAndNotify(s);
};
}
}

addProperty(
node,
name,
Expand Down Expand Up @@ -2083,6 +2117,8 @@ class ZigbeeClassifier {
if (genPowerCfgEndpoint) {
this.addPowerCfgVoltageProperty(node, genPowerCfgEndpoint);
}

this.addLastSeenProperty(node);
}

classify(node) {
Expand Down