node-red-contrib-zwave-js 8.0.0-beta.4 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/package.json +4 -4
- package/resources/MeshMap/maprender.js +10 -0
- package/resources/UITab/client.js +153 -145
- package/resources/UITab/styles.css +15 -1
- package/validation_result.json +1 -1
- package/zwave-js/zwave-js.html +22 -20
- package/zwave-js/zwave-js.js +37 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
]
|
|
12
12
|
```
|
|
13
13
|
previously this was ```[<number>, <Desired Value>, <Number>]```
|
|
14
|
+
- **ValueAPI** is now default on the CMD Factory node.
|
|
15
|
+
If you have problems with this node after the update, please open it up, and select your API, then save.
|
|
14
16
|
|
|
15
17
|
**New Features**
|
|
16
18
|
- Default scales can now be applied inside the controller config
|
|
@@ -19,6 +21,9 @@
|
|
|
19
21
|
- 2 new event types have been added : **ALIVE**, **DEAD** - these allow you to monitor if a device has been marked dead
|
|
20
22
|
or alive accordingly.
|
|
21
23
|
- Added a color chooser for color input types in the UI
|
|
24
|
+
- Added a new **Driver** function **getLastEvents**
|
|
25
|
+
- Device last seen timestamp is now shown in the UI
|
|
26
|
+
- Node list now contains the date when the device was last seen.
|
|
22
27
|
|
|
23
28
|
**Bug Fixes**
|
|
24
29
|
- Modal alerts are now rendering HTML content once again
|
|
@@ -30,6 +35,7 @@
|
|
|
30
35
|
- Current Value(s) who's type is an object have been changed to prompt for a double click in the UI
|
|
31
36
|
- Association Management has been updated, and changes are now applied in batch.
|
|
32
37
|
- For battery operated devices, certain UI actions now ask you to wake up said device before anything is comitted.
|
|
38
|
+
- Various performance boosts in the UI
|
|
33
39
|
- Bump ZWave JS to V10
|
|
34
40
|
- Bump Winston
|
|
35
41
|
- Bump ESlint
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-zwave-js",
|
|
3
|
-
"version": "8.0.0
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "The most powerful, high performing and highly polished Z-Wave node for Node-RED based on Z-Wave JS. If you want a fully featured Z-Wave framework in your Node-RED instance, you have found it.",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"limiter": "^2.1.0",
|
|
8
8
|
"lodash": "^4.17.21",
|
|
9
9
|
"serialport": "^10.4.0",
|
|
10
|
-
"winston": "^3.8.
|
|
10
|
+
"winston": "^3.8.2",
|
|
11
11
|
"winston-transport": "^4.5.0",
|
|
12
|
-
"zwave-js": "^10.0
|
|
12
|
+
"zwave-js": "^10.2.0"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"eslint": "^8.
|
|
15
|
+
"eslint": "^8.23.1",
|
|
16
16
|
"prettier": "^2.7.1"
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
@@ -27,6 +27,7 @@ function Render(Base) {
|
|
|
27
27
|
name: 'Controller',
|
|
28
28
|
nameOnly: `Controller`,
|
|
29
29
|
location: `Hopefully away from interference.`,
|
|
30
|
+
lastSeen: '0',
|
|
30
31
|
fontSize: '12px',
|
|
31
32
|
icon: `${Base}/Stick.png`,
|
|
32
33
|
powerSource: { type: 'bus' },
|
|
@@ -52,6 +53,12 @@ function Render(Base) {
|
|
|
52
53
|
path: []
|
|
53
54
|
}
|
|
54
55
|
};
|
|
56
|
+
if(N.lastSeen > 0){
|
|
57
|
+
EL.data.lastSeen = new Date(N.lastSeen).toLocaleString();
|
|
58
|
+
}
|
|
59
|
+
else{
|
|
60
|
+
EL.data.lastSeen = 'Never';
|
|
61
|
+
}
|
|
55
62
|
|
|
56
63
|
Elements.push(EL);
|
|
57
64
|
|
|
@@ -308,6 +315,9 @@ function LoadData() {
|
|
|
308
315
|
$(`<li>Timeouts: ${this.data('statistics').timeoutResponse}</li>`).appendTo(
|
|
309
316
|
NetStatsDetails
|
|
310
317
|
);
|
|
318
|
+
|
|
319
|
+
// Node details addition
|
|
320
|
+
$(`<li>Last Seen: ${this.data('lastSeen')}</li>`).appendTo(NodeDetails);
|
|
311
321
|
}
|
|
312
322
|
|
|
313
323
|
$('#Details').html(Data);
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
/*eslint no-undef: "warn"*/
|
|
4
4
|
/*eslint no-unused-vars: "warn"*/
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
/* UI Inclusion Functions */
|
|
8
7
|
let StartInclusionExclusion;
|
|
9
8
|
let StartReplace;
|
|
@@ -208,6 +207,11 @@ const DCs = {
|
|
|
208
207
|
name: 'getValueMetadata',
|
|
209
208
|
noWait: false
|
|
210
209
|
},
|
|
210
|
+
getValueDB: {
|
|
211
|
+
API: 'DriverAPI',
|
|
212
|
+
name: 'getValueDB',
|
|
213
|
+
noWait: false
|
|
214
|
+
},
|
|
211
215
|
getAvailableFirmwareUpdates: {
|
|
212
216
|
API: 'ControllerAPI',
|
|
213
217
|
name: 'getAvailableFirmwareUpdates',
|
|
@@ -539,6 +543,14 @@ const ZwaveJsUI = (function () {
|
|
|
539
543
|
}
|
|
540
544
|
|
|
541
545
|
async function PerformUpdate() {
|
|
546
|
+
const CurrentFWMode = $('#tabs').tabs('option', 'active');
|
|
547
|
+
|
|
548
|
+
if (CurrentFWMode === 0) {
|
|
549
|
+
const SelectedFW = $('#NODE_FWCV').find(':selected').data('FWTarget');
|
|
550
|
+
PerformUpdateFromService(SelectedFW.node, SelectedFW.file);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
|
|
542
554
|
const FE = $('#FILE_FW')[0].files[0];
|
|
543
555
|
const NID = parseInt($('#NODE_FW option:selected').val());
|
|
544
556
|
const Target = $('#TARGET_FW').val();
|
|
@@ -992,6 +1004,7 @@ const ZwaveJsUI = (function () {
|
|
|
992
1004
|
const _Node = {
|
|
993
1005
|
controller: N.isControllerNode,
|
|
994
1006
|
nodeId: N.nodeId,
|
|
1007
|
+
lastSeen: N.lastSeen,
|
|
995
1008
|
name: N.name,
|
|
996
1009
|
location: N.location,
|
|
997
1010
|
powerSource: N.powerSource,
|
|
@@ -2621,7 +2634,6 @@ const ZwaveJsUI = (function () {
|
|
|
2621
2634
|
|
|
2622
2635
|
CheckForUpdate = async () => {
|
|
2623
2636
|
const Node = parseInt($('#NODE_FWC option:selected').val());
|
|
2624
|
-
|
|
2625
2637
|
const nodeRow = $('#zwave-js-node-list').find(`[data-nodeid='${Node}']`);
|
|
2626
2638
|
|
|
2627
2639
|
if (nodeRow.data().info.status.toUpperCase() === 'ASLEEP') {
|
|
@@ -2631,6 +2643,13 @@ const ZwaveJsUI = (function () {
|
|
|
2631
2643
|
}
|
|
2632
2644
|
}
|
|
2633
2645
|
|
|
2646
|
+
const Wait = modalPrompt(
|
|
2647
|
+
'Querying Firmware Update Service..',
|
|
2648
|
+
'Please wait...',
|
|
2649
|
+
{},
|
|
2650
|
+
false
|
|
2651
|
+
);
|
|
2652
|
+
|
|
2634
2653
|
ControllerCMD(
|
|
2635
2654
|
DCs.getAvailableFirmwareUpdates.API,
|
|
2636
2655
|
DCs.getAvailableFirmwareUpdates.name,
|
|
@@ -2639,86 +2658,54 @@ const ZwaveJsUI = (function () {
|
|
|
2639
2658
|
DCs.getAvailableFirmwareUpdates.noWait
|
|
2640
2659
|
)
|
|
2641
2660
|
.then(({ object }) => {
|
|
2661
|
+
Wait.dialog('destroy');
|
|
2662
|
+
|
|
2663
|
+
const ShowCL = function () {
|
|
2664
|
+
const SelectedFW = $('#NODE_FWCV')
|
|
2665
|
+
.find(':selected')
|
|
2666
|
+
.data('FWTarget');
|
|
2667
|
+
const List = $('<ul>');
|
|
2668
|
+
for (let i = 0; i < SelectedFW.cl.length; i++) {
|
|
2669
|
+
List.append(`<li>${SelectedFW.cl[i]}</li>`);
|
|
2670
|
+
}
|
|
2642
2671
|
|
|
2643
|
-
|
|
2644
|
-
$(
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
const FWs = object;
|
|
2648
|
-
FWs.forEach((FW) =>{
|
|
2649
|
-
|
|
2650
|
-
const Current = nodeRow.data().info.firmwareVersion.toString() === FW.version.toString() ? "(Current)" : "";
|
|
2651
|
-
|
|
2652
|
-
FWList.append(`<h3>${FW.version} ${Current}</h3>`);
|
|
2653
|
-
const ChangeLog = FW.changelog.split('\n');
|
|
2654
|
-
|
|
2655
|
-
const Content = $("<div>");
|
|
2656
|
-
const CL = $("<ul>");
|
|
2657
|
-
|
|
2658
|
-
ChangeLog.forEach((CLE) =>{
|
|
2659
|
-
CL.append(`<li>${CLE}</li>`);
|
|
2660
|
-
})
|
|
2661
|
-
Content.append(CL);
|
|
2662
|
-
|
|
2663
|
-
FW.files.forEach((F) =>{
|
|
2664
|
-
const B = $(`<label for="Target_${F.target}">Target ${F.target}</label> <input type="radio" name="fw_target" value="${F.target}" id="Target_${F.target}"> `);
|
|
2665
|
-
B.data('FWTarget',{file:F,node:Node});
|
|
2666
|
-
Content.append(B)
|
|
2667
|
-
//B.checkboxradio();
|
|
2668
|
-
})
|
|
2669
|
-
FWList.append(Content);
|
|
2670
|
-
})
|
|
2671
|
-
|
|
2672
|
-
$(`button:contains('Check For Update')`).parent().append(FWList);
|
|
2673
|
-
FWList.accordion();
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
/*
|
|
2678
|
-
//
|
|
2679
|
-
const Container = $('<div>');
|
|
2680
|
-
Container.append(
|
|
2681
|
-
`Current Version <strong>${
|
|
2682
|
-
nodeRow.data().info.firmwareVersion
|
|
2683
|
-
}</strong> New Version <strong>${
|
|
2684
|
-
object[0].version
|
|
2685
|
-
}</strong><br /><br />`
|
|
2686
|
-
);
|
|
2672
|
+
$('#ChangeLog').empty();
|
|
2673
|
+
$('#ChangeLog').append(List);
|
|
2674
|
+
};
|
|
2687
2675
|
|
|
2688
|
-
|
|
2676
|
+
$('#ChangeLog').empty();
|
|
2677
|
+
$('#NODE_FWCV').empty();
|
|
2678
|
+
$('#NODE_FWCV').append('<option>Select Version & File...</option>');
|
|
2679
|
+
$('#NODE_FWCV').off('change');
|
|
2680
|
+
$('#NODE_FWCV').change(ShowCL);
|
|
2689
2681
|
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2682
|
+
//
|
|
2683
|
+
if (object.length > 0) {
|
|
2684
|
+
const FWs = object;
|
|
2685
|
+
FWs.forEach((FW) => {
|
|
2686
|
+
const VG = $(`<optgroup label=' --- ${FW.version} --- '>`);
|
|
2687
|
+
FW.files.forEach((F) => {
|
|
2688
|
+
const FWF = $(`<option>`);
|
|
2689
|
+
FWF.data('FWTarget', {
|
|
2690
|
+
file: F,
|
|
2691
|
+
node: Node,
|
|
2692
|
+
cl: FW.changelog.split('\n')
|
|
2693
|
+
});
|
|
2694
|
+
FWF.text(`${FW.version} -> Target : ${F.target}`);
|
|
2695
|
+
VG.append(FWF);
|
|
2696
|
+
});
|
|
2697
|
+
$('#NODE_FWCV').append(VG);
|
|
2694
2698
|
});
|
|
2695
|
-
CLL.appendTo(Container);
|
|
2696
|
-
|
|
2697
|
-
const Buttons = {};
|
|
2698
|
-
|
|
2699
|
-
for (let i = 0; i < object[0].files.length; i++) {
|
|
2700
|
-
const File = object[0].files[i];
|
|
2701
|
-
Buttons[`Update (Target ${File.target})`] = function () {
|
|
2702
|
-
PerformUpdateFromService(Node, File);
|
|
2703
|
-
};
|
|
2704
|
-
}
|
|
2705
|
-
|
|
2706
|
-
modalPrompt(
|
|
2707
|
-
Container,
|
|
2708
|
-
'Firmware Update Available',
|
|
2709
|
-
Buttons,
|
|
2710
|
-
true,
|
|
2711
|
-
true
|
|
2712
|
-
);
|
|
2713
|
-
*/
|
|
2714
2699
|
} else {
|
|
2715
2700
|
modalAlert(
|
|
2716
2701
|
'No firmware updates are available for this Node.',
|
|
2717
2702
|
'Firmware update check'
|
|
2718
2703
|
);
|
|
2719
2704
|
}
|
|
2705
|
+
//
|
|
2720
2706
|
})
|
|
2721
2707
|
.catch((err) => {
|
|
2708
|
+
Wait.dialog('destroy');
|
|
2722
2709
|
modalAlert(
|
|
2723
2710
|
err.responseText || err.message,
|
|
2724
2711
|
'Could not check for updates'
|
|
@@ -3302,6 +3289,17 @@ const ZwaveJsUI = (function () {
|
|
|
3302
3289
|
}
|
|
3303
3290
|
|
|
3304
3291
|
function renderNode(node) {
|
|
3292
|
+
const NameCol = $('<div>')
|
|
3293
|
+
.html(node.name)
|
|
3294
|
+
.addClass('zwave-js-node-row-name');
|
|
3295
|
+
|
|
3296
|
+
if (node.lastSeen !== 0) {
|
|
3297
|
+
const DT = new Date(node.lastSeen);
|
|
3298
|
+
RED.popover.tooltip(NameCol, `Last seen: ${DT.toLocaleString()}`);
|
|
3299
|
+
} else {
|
|
3300
|
+
RED.popover.tooltip(NameCol, `Last seen: Never`);
|
|
3301
|
+
}
|
|
3302
|
+
|
|
3305
3303
|
return $('<div>')
|
|
3306
3304
|
.addClass('red-ui-treeList-label zwave-js-node-row')
|
|
3307
3305
|
.attr('data-nodeid', node.nodeId)
|
|
@@ -3332,7 +3330,7 @@ const ZwaveJsUI = (function () {
|
|
|
3332
3330
|
})
|
|
3333
3331
|
.append(
|
|
3334
3332
|
$('<div>').html(node.nodeId).addClass('zwave-js-node-row-id'),
|
|
3335
|
-
|
|
3333
|
+
NameCol,
|
|
3336
3334
|
$('<div>')
|
|
3337
3335
|
.html(renderStatusIcon(node.status.toUpperCase()))
|
|
3338
3336
|
.addClass('zwave-js-node-row-status'),
|
|
@@ -3510,13 +3508,13 @@ const ZwaveJsUI = (function () {
|
|
|
3510
3508
|
updateNodeFetchStatus('Fetching properties...');
|
|
3511
3509
|
|
|
3512
3510
|
ControllerCMD(
|
|
3513
|
-
DCs.
|
|
3514
|
-
DCs.
|
|
3515
|
-
selectedNode,
|
|
3511
|
+
DCs.getValueDB.API,
|
|
3512
|
+
DCs.getValueDB.name,
|
|
3516
3513
|
undefined,
|
|
3517
|
-
|
|
3514
|
+
[selectedNode],
|
|
3515
|
+
DCs.getValueDB.noWait
|
|
3518
3516
|
)
|
|
3519
|
-
.then(({ object }) => buildPropertyTree(object))
|
|
3517
|
+
.then(({ object }) => buildPropertyTree(object[0].values))
|
|
3520
3518
|
.catch((err) => {
|
|
3521
3519
|
modalAlert(
|
|
3522
3520
|
err.responseText || err.message,
|
|
@@ -3542,27 +3540,50 @@ const ZwaveJsUI = (function () {
|
|
|
3542
3540
|
}
|
|
3543
3541
|
updateNodeFetchStatus('');
|
|
3544
3542
|
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
children: propsInCC.map((valueId) => {
|
|
3558
|
-
return { element: renderPropertyElement(valueId) };
|
|
3559
|
-
})
|
|
3560
|
-
};
|
|
3543
|
+
const CCList = uniqBy(valueIdList, 'commandClass');
|
|
3544
|
+
CCList.sort((a, b) => a.commandClassName.localeCompare(b.commandClassName));
|
|
3545
|
+
|
|
3546
|
+
const Data = [];
|
|
3547
|
+
CCList.forEach((CC) => {
|
|
3548
|
+
Data.push({
|
|
3549
|
+
element: renderCommandClassElement(
|
|
3550
|
+
CC.commandClass,
|
|
3551
|
+
CC.commandClassName
|
|
3552
|
+
),
|
|
3553
|
+
expanded: false,
|
|
3554
|
+
children: []
|
|
3561
3555
|
});
|
|
3556
|
+
});
|
|
3562
3557
|
|
|
3563
|
-
// Step 3: Render tree
|
|
3564
3558
|
const propertyList = $('#zwave-js-node-properties');
|
|
3565
|
-
propertyList.treeList('data',
|
|
3559
|
+
propertyList.treeList('data', Data);
|
|
3560
|
+
|
|
3561
|
+
let Index = 0;
|
|
3562
|
+
CCList.forEach((V) => {
|
|
3563
|
+
const CCProps = valueIdList.filter(
|
|
3564
|
+
(VID) => VID.commandClass === V.commandClass
|
|
3565
|
+
);
|
|
3566
|
+
CCProps.forEach((Prop) => {
|
|
3567
|
+
const Type = Prop.metadata.type;
|
|
3568
|
+
const Writeable = Prop.metadata.writeable;
|
|
3569
|
+
const CV = Prop.currentValue;
|
|
3570
|
+
|
|
3571
|
+
const Child = renderPropertyElement(Prop);
|
|
3572
|
+
propertyList
|
|
3573
|
+
.treeList('data')
|
|
3574
|
+
[Index].treeList.addChild({ element: Child });
|
|
3575
|
+
|
|
3576
|
+
if (Writeable && Type !== 'any') {
|
|
3577
|
+
const icon = Child.prev();
|
|
3578
|
+
icon.empty();
|
|
3579
|
+
$('<i>')
|
|
3580
|
+
.addClass('fa fa-pencil zwave-js-node-property-edit-button')
|
|
3581
|
+
.click(() => showEditor(Prop, CV))
|
|
3582
|
+
.appendTo(icon);
|
|
3583
|
+
}
|
|
3584
|
+
});
|
|
3585
|
+
Index++;
|
|
3586
|
+
});
|
|
3566
3587
|
|
|
3567
3588
|
// Step 4: Add endpoint numbers where applicable
|
|
3568
3589
|
propertyList
|
|
@@ -3619,7 +3640,25 @@ const ZwaveJsUI = (function () {
|
|
|
3619
3640
|
return el;
|
|
3620
3641
|
}
|
|
3621
3642
|
|
|
3643
|
+
function splitObject(valueId) {
|
|
3644
|
+
// delete normalizedObject
|
|
3645
|
+
delete valueId.normalizedObject;
|
|
3646
|
+
|
|
3647
|
+
// Value
|
|
3648
|
+
const Value = valueId.currentValue;
|
|
3649
|
+
delete valueId.currentValue;
|
|
3650
|
+
|
|
3651
|
+
// Meta
|
|
3652
|
+
const MetaData = JSON.parse(JSON.stringify(valueId.metadata));
|
|
3653
|
+
delete valueId.metadata;
|
|
3654
|
+
|
|
3655
|
+
return { valueId: valueId, currentValue: Value, metadata: MetaData };
|
|
3656
|
+
}
|
|
3657
|
+
|
|
3622
3658
|
function renderPropertyElement(valueId) {
|
|
3659
|
+
const Split = splitObject(valueId);
|
|
3660
|
+
valueId = Split.valueId;
|
|
3661
|
+
|
|
3623
3662
|
const el = $('<div>')
|
|
3624
3663
|
.addClass('zwave-js-node-property')
|
|
3625
3664
|
.attr('data-endpoint', valueId.endpoint)
|
|
@@ -3640,7 +3679,7 @@ const ZwaveJsUI = (function () {
|
|
|
3640
3679
|
.text(label)
|
|
3641
3680
|
.appendTo(el);
|
|
3642
3681
|
$('<span>').addClass('zwave-js-node-property-value').appendTo(el);
|
|
3643
|
-
getValue(valueId);
|
|
3682
|
+
getValue(valueId, Split.metadata, Split.currentValue, el);
|
|
3644
3683
|
el.dblclick(function () {
|
|
3645
3684
|
const data = $(this).data();
|
|
3646
3685
|
const valueData = $(this).find('.zwave-js-node-property-value').data();
|
|
@@ -3679,44 +3718,12 @@ const ZwaveJsUI = (function () {
|
|
|
3679
3718
|
return el;
|
|
3680
3719
|
}
|
|
3681
3720
|
|
|
3682
|
-
function getValue(valueId) {
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
DCs.getValue.noWait
|
|
3689
|
-
)
|
|
3690
|
-
.then(({ node, object }) => {
|
|
3691
|
-
if (node != selectedNode) {
|
|
3692
|
-
return;
|
|
3693
|
-
}
|
|
3694
|
-
updateValue({ ...valueId, currentValue: object.currentValue });
|
|
3695
|
-
ControllerCMD(
|
|
3696
|
-
DCs.getValueMetadata.API,
|
|
3697
|
-
DCs.getValueMetadata.name,
|
|
3698
|
-
selectedNode,
|
|
3699
|
-
[valueId],
|
|
3700
|
-
DCs.getValueMetadata.noWait
|
|
3701
|
-
)
|
|
3702
|
-
.then(({ node, object }) => {
|
|
3703
|
-
if (!object.metadata || node != selectedNode) {
|
|
3704
|
-
return;
|
|
3705
|
-
}
|
|
3706
|
-
updateMeta(valueId, object.metadata);
|
|
3707
|
-
})
|
|
3708
|
-
.catch((err) => {
|
|
3709
|
-
modalAlert(
|
|
3710
|
-
err.responseText || err.message,
|
|
3711
|
-
'Could not fetch value Metadata.'
|
|
3712
|
-
);
|
|
3713
|
-
throw new Error(err.responseText || err.message);
|
|
3714
|
-
});
|
|
3715
|
-
})
|
|
3716
|
-
.catch((err) => {
|
|
3717
|
-
modalAlert(err.responseText || err.message, 'Could not fetch value.');
|
|
3718
|
-
throw new Error(err.responseText || err.message);
|
|
3719
|
-
});
|
|
3721
|
+
function getValue(valueId, metadata, currentValue, el) {
|
|
3722
|
+
updateValue({ ...valueId, currentValue }, el);
|
|
3723
|
+
if (metadata === undefined) {
|
|
3724
|
+
return;
|
|
3725
|
+
}
|
|
3726
|
+
updateMeta(valueId, metadata, el);
|
|
3720
3727
|
}
|
|
3721
3728
|
|
|
3722
3729
|
function handleBattery(topic, data) {
|
|
@@ -3753,9 +3760,9 @@ const ZwaveJsUI = (function () {
|
|
|
3753
3760
|
}
|
|
3754
3761
|
}
|
|
3755
3762
|
|
|
3756
|
-
function updateValue(valueId) {
|
|
3763
|
+
function updateValue(valueId, El) {
|
|
3757
3764
|
// Assumes you already checked if this applies to selectedNode
|
|
3758
|
-
const propertyRow = getPropertyRow(valueId);
|
|
3765
|
+
const propertyRow = El || getPropertyRow(valueId);
|
|
3759
3766
|
|
|
3760
3767
|
if (!propertyRow) {
|
|
3761
3768
|
// AHHH!!! What do we do now?!
|
|
@@ -3828,10 +3835,10 @@ const ZwaveJsUI = (function () {
|
|
|
3828
3835
|
propertyValue.data('value', value);
|
|
3829
3836
|
}
|
|
3830
3837
|
|
|
3831
|
-
function updateMeta(valueId, meta = {}) {
|
|
3838
|
+
function updateMeta(valueId, meta = {}, El) {
|
|
3832
3839
|
// Assumes you already checked if this applies to selectedNode
|
|
3833
3840
|
|
|
3834
|
-
const propertyRow = getPropertyRow(valueId);
|
|
3841
|
+
const propertyRow = El || getPropertyRow(valueId);
|
|
3835
3842
|
const propertyValue = propertyRow.find('.zwave-js-node-property-value');
|
|
3836
3843
|
|
|
3837
3844
|
propertyRow.data('meta', meta);
|
|
@@ -3855,14 +3862,15 @@ const ZwaveJsUI = (function () {
|
|
|
3855
3862
|
propertyValue.text(`${value} ${meta.unit}`);
|
|
3856
3863
|
}
|
|
3857
3864
|
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3865
|
+
if (El === undefined) {
|
|
3866
|
+
const icon = propertyRow.prev();
|
|
3867
|
+
icon.empty();
|
|
3868
|
+
if (meta.writeable && meta.type !== 'any')
|
|
3869
|
+
$('<i>')
|
|
3870
|
+
.addClass('fa fa-pencil zwave-js-node-property-edit-button')
|
|
3871
|
+
.click(() => showEditor(valueId, value))
|
|
3872
|
+
.appendTo(icon);
|
|
3873
|
+
}
|
|
3866
3874
|
}
|
|
3867
3875
|
|
|
3868
3876
|
function showEditor(valueId, value) {
|
|
@@ -166,6 +166,7 @@
|
|
|
166
166
|
border-color: rgb(75, 75, 75);
|
|
167
167
|
border-style: solid;
|
|
168
168
|
}
|
|
169
|
+
|
|
169
170
|
.zwave-js-ac i {
|
|
170
171
|
font-size: 16px !important;
|
|
171
172
|
color: #666;
|
|
@@ -216,7 +217,7 @@
|
|
|
216
217
|
margin-top: 50px;
|
|
217
218
|
}
|
|
218
219
|
|
|
219
|
-
.progressbar
|
|
220
|
+
.progressbar>div {
|
|
220
221
|
background-color: gray;
|
|
221
222
|
width: 0%;
|
|
222
223
|
height: 20px;
|
|
@@ -302,3 +303,16 @@ table#zwave-js-associations-table tr:first-of-type {
|
|
|
302
303
|
.ui-slider-range {
|
|
303
304
|
background: rgba(200, 200, 200, 0.3);
|
|
304
305
|
}
|
|
306
|
+
|
|
307
|
+
#FWForm #tabs ul {
|
|
308
|
+
background-color: #fff !important;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
#FWForm #tabs ul li.ui-tabs-active {
|
|
312
|
+
background-color: #fff !important;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
#FWForm #tabs ul li.ui-tabs-active a {
|
|
316
|
+
color: #555 !important;
|
|
317
|
+
font-weight: bold !important;
|
|
318
|
+
}
|
package/validation_result.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"package":{"name":"node-red-contrib-zwave-js","version":"8.0.0"},"P01":{"test":true,"license":"MIT"},"P03":{"test":true},"P04":{"test":true},"P08":{"test":true},"P05":{"test":true},"P06":{"test":true,"versions":["3.0.
|
|
1
|
+
{"package":{"name":"node-red-contrib-zwave-js","version":"8.0.0"},"P01":{"test":true,"license":"MIT"},"P03":{"test":true},"P04":{"test":true},"P08":{"test":true},"P05":{"test":true},"P06":{"test":true,"versions":["3.0.2","2.2.3"]},"P07":{"test":false,"version":">=14.13.0"},"N01":{"test":true},"N02":{"test":true,"nodes":["zwave-js","zwave-device","event-filter","cmd-factory"]},"D01":{"test":true,"total":6},"D02":{"test":true},"D03":{"test":true}}
|
package/zwave-js/zwave-js.html
CHANGED
|
@@ -726,16 +726,17 @@
|
|
|
726
726
|
>
|
|
727
727
|
<div id="tabs">
|
|
728
728
|
<ul>
|
|
729
|
-
<li><a href="#tabs-1">
|
|
730
|
-
<li><a href="#tabs-2">
|
|
731
|
-
|
|
732
|
-
|
|
729
|
+
<li><a href="#tabs-1">Firmware Update Service</a></li>
|
|
730
|
+
<li><a href="#tabs-2">Local File</a></li>
|
|
731
|
+
|
|
732
|
+
</ul>
|
|
733
|
+
<div id="tabs-1" style="padding:20px">
|
|
733
734
|
<table>
|
|
734
735
|
<tbody>
|
|
735
736
|
<tr>
|
|
736
737
|
<td>Target Node</td>
|
|
737
738
|
<td>
|
|
738
|
-
<select id='
|
|
739
|
+
<select id='NODE_FWC' onchange="CheckForUpdate()">
|
|
739
740
|
<option>Select Node...</option>
|
|
740
741
|
{{#each nodes}}
|
|
741
742
|
{{#if this.length}}
|
|
@@ -750,25 +751,24 @@
|
|
|
750
751
|
</td>
|
|
751
752
|
</tr>
|
|
752
753
|
<tr>
|
|
753
|
-
<td>Firmware
|
|
754
|
+
<td>Firmware Version</td>
|
|
754
755
|
<td>
|
|
755
|
-
<
|
|
756
|
+
<select id='NODE_FWCV'>
|
|
757
|
+
<option>Select Version & File...</option>
|
|
758
|
+
</select>
|
|
756
759
|
</td>
|
|
757
760
|
</tr>
|
|
758
|
-
<tr>
|
|
759
|
-
<td>Firmware Update File</td>
|
|
760
|
-
<td><input type='file' id='FILE_FW' /></td>
|
|
761
|
-
</tr>
|
|
762
761
|
</tbody>
|
|
763
762
|
</table>
|
|
764
|
-
|
|
763
|
+
<div id="ChangeLog"></div>
|
|
764
|
+
</div>
|
|
765
765
|
<div id="tabs-2" style="padding:20px">
|
|
766
766
|
<table>
|
|
767
767
|
<tbody>
|
|
768
768
|
<tr>
|
|
769
769
|
<td>Target Node</td>
|
|
770
770
|
<td>
|
|
771
|
-
<select id='
|
|
771
|
+
<select id='NODE_FW'>
|
|
772
772
|
<option>Select Node...</option>
|
|
773
773
|
{{#each nodes}}
|
|
774
774
|
{{#if this.length}}
|
|
@@ -783,16 +783,18 @@
|
|
|
783
783
|
</td>
|
|
784
784
|
</tr>
|
|
785
785
|
<tr>
|
|
786
|
-
<td
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
786
|
+
<td>Firmware Update Target</td>
|
|
787
|
+
<td>
|
|
788
|
+
<input type='number' value='0' min='0' id='TARGET_FW' />
|
|
789
|
+
</td>
|
|
790
|
+
</tr>
|
|
791
|
+
<tr>
|
|
792
|
+
<td>Firmware Update File</td>
|
|
793
|
+
<td><input type='file' id='FILE_FW' /></td>
|
|
792
794
|
</tr>
|
|
793
795
|
</tbody>
|
|
794
796
|
</table>
|
|
795
|
-
|
|
797
|
+
</div>
|
|
796
798
|
</div>
|
|
797
799
|
|
|
798
800
|
<div class='progressbar' id='FWProgress'><div></div></div>
|
package/zwave-js/zwave-js.js
CHANGED
|
@@ -57,7 +57,7 @@ module.exports = function (RED) {
|
|
|
57
57
|
'heal network progress'
|
|
58
58
|
);
|
|
59
59
|
const FWK =
|
|
60
|
-
'
|
|
60
|
+
'127c49b6f2928a6579e82ecab64a83fc94a6436f03d5cb670b8ac44412687b75f0667843';
|
|
61
61
|
|
|
62
62
|
SetupGlobals(RED);
|
|
63
63
|
|
|
@@ -1028,6 +1028,7 @@ module.exports = function (RED) {
|
|
|
1028
1028
|
isControllerNode: N.isControllerNode,
|
|
1029
1029
|
supportsBeaming: N.supportsBeaming,
|
|
1030
1030
|
keepAwake: N.keepAwake,
|
|
1031
|
+
lastSeen: N.ZWNR_lastSeen || 0,
|
|
1031
1032
|
powerSource: {
|
|
1032
1033
|
type: N.supportsCC(CommandClasses.Battery)
|
|
1033
1034
|
? 'battery'
|
|
@@ -1402,6 +1403,25 @@ module.exports = function (RED) {
|
|
|
1402
1403
|
);
|
|
1403
1404
|
|
|
1404
1405
|
switch (Method) {
|
|
1406
|
+
case 'getLastEvents':
|
|
1407
|
+
const PL = [];
|
|
1408
|
+
Driver.controller.nodes.forEach((N) => {
|
|
1409
|
+
if(N.isControllerNode){
|
|
1410
|
+
return;
|
|
1411
|
+
}
|
|
1412
|
+
const I = {
|
|
1413
|
+
node: N.id,
|
|
1414
|
+
nodeName: getNodeInfoForPayload(N.id, 'name'),
|
|
1415
|
+
nodeLocation: getNodeInfoForPayload(N.id, 'location'),
|
|
1416
|
+
timestamp: N.ZWNR_lastSeen || 0,
|
|
1417
|
+
event: N.ZWNR_lastEvent,
|
|
1418
|
+
object: N.ZWNR_lastObject
|
|
1419
|
+
};
|
|
1420
|
+
PL.push(I);
|
|
1421
|
+
});
|
|
1422
|
+
Send(undefined, 'LAST_EVENTS_RESULT', PL, send);
|
|
1423
|
+
break;
|
|
1424
|
+
|
|
1405
1425
|
case 'checkLifelineHealth':
|
|
1406
1426
|
const NID = Params[0];
|
|
1407
1427
|
const Rounds = Params[1] || undefined;
|
|
@@ -1472,12 +1492,14 @@ module.exports = function (RED) {
|
|
|
1472
1492
|
};
|
|
1473
1493
|
const VIDs = Driver.controller.nodes.get(NID).getDefinedValueIDs();
|
|
1474
1494
|
VIDs.forEach((VID) => {
|
|
1495
|
+
const M = Driver.controller.nodes.get(NID).getValueMetadata(VID);
|
|
1475
1496
|
const V = Driver.controller.nodes.get(NID).getValue(VID);
|
|
1476
1497
|
const VI = {
|
|
1477
1498
|
...VID,
|
|
1478
1499
|
currentValue: V
|
|
1479
1500
|
};
|
|
1480
1501
|
VI.normalizedObject = buildNormalized(VI, NID);
|
|
1502
|
+
VI.metadata = M;
|
|
1481
1503
|
G.values.push(VI);
|
|
1482
1504
|
});
|
|
1483
1505
|
Result.push(G);
|
|
@@ -1828,6 +1850,20 @@ module.exports = function (RED) {
|
|
|
1828
1850
|
'GET_VALUE_METADATA_RESPONSE'
|
|
1829
1851
|
];
|
|
1830
1852
|
|
|
1853
|
+
const TimestampSubjects = [
|
|
1854
|
+
'VALUE_NOTIFICATION',
|
|
1855
|
+
'NOTIFICATION',
|
|
1856
|
+
'VALUE_UPDATED',
|
|
1857
|
+
'WAKE_UP',
|
|
1858
|
+
'ALIVE'
|
|
1859
|
+
];
|
|
1860
|
+
|
|
1861
|
+
if (TimestampSubjects.includes(Subject)) {
|
|
1862
|
+
Driver.controller.nodes.get(Node.id).ZWNR_lastSeen = PL.timestamp;
|
|
1863
|
+
Driver.controller.nodes.get(Node.id).ZWNR_lastEvent = PL.event;
|
|
1864
|
+
Driver.controller.nodes.get(Node.id).ZWNR_lastObject = PL.object;
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1831
1867
|
if (AllowedSubjectsForDNs.includes(Subject) && SendDNs) {
|
|
1832
1868
|
if (IsolatedNodeId !== undefined) {
|
|
1833
1869
|
Log(
|