smart-bus 0.8.0 → 0.9.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 +9 -0
- package/lib/commands.js +132 -4
- package/package.json +1 -1
- package/test/fixtures/commands.js +95 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## 0.9.0
|
|
2
|
+
|
|
3
|
+
* Add Get Curtain Duration commands (`0xE800`, `0xE801`)
|
|
4
|
+
* Add Dry Contact Multi-Channel Status command (`0x6F00`)
|
|
5
|
+
* Add Dry Contact broadcast status commands (`0x15D0`, `0x15D1`)
|
|
6
|
+
* Fix `0xE3E3` Curtain Status to support optional duration field
|
|
7
|
+
* Add comprehensive test coverage for new commands
|
|
8
|
+
* Maintain 100% backward compatibility with existing implementations
|
|
9
|
+
|
|
1
10
|
## 0.8.0
|
|
2
11
|
|
|
3
12
|
* Update for Node.js v22 compatibility
|
package/lib/commands.js
CHANGED
|
@@ -921,14 +921,29 @@ module.exports = {
|
|
|
921
921
|
// FIXME: same as 0xE3E1
|
|
922
922
|
0xE3E3: {
|
|
923
923
|
parse: function(buffer) {
|
|
924
|
-
|
|
924
|
+
var data = {
|
|
925
925
|
curtain: buffer.readUInt8(0),
|
|
926
926
|
status: buffer.readUInt8(1)
|
|
927
927
|
};
|
|
928
|
+
// Duration field (4 bytes total) - in deciseconds (0.1 second units)
|
|
929
|
+
if (buffer.length >= 4) {
|
|
930
|
+
data.duration = buffer.readUInt16BE(2) / 10;
|
|
931
|
+
}
|
|
932
|
+
return data;
|
|
928
933
|
},
|
|
929
934
|
|
|
930
935
|
encode: function(data) {
|
|
931
|
-
|
|
936
|
+
// Support both 2-byte (legacy) and 4-byte (with duration) formats
|
|
937
|
+
if (data.duration !== undefined) {
|
|
938
|
+
var buffer = Buffer.allocUnsafe(4);
|
|
939
|
+
buffer.writeUInt8(data.curtain, 0);
|
|
940
|
+
buffer.writeUInt8(data.status, 1);
|
|
941
|
+
var duration = data.duration * 10;
|
|
942
|
+
buffer.writeUInt16BE(duration, 2);
|
|
943
|
+
return buffer;
|
|
944
|
+
} else {
|
|
945
|
+
return Buffer.from([data.curtain, data.status]);
|
|
946
|
+
}
|
|
932
947
|
}
|
|
933
948
|
},
|
|
934
949
|
|
|
@@ -966,6 +981,39 @@ module.exports = {
|
|
|
966
981
|
}
|
|
967
982
|
},
|
|
968
983
|
|
|
984
|
+
// 7.1.6 Get Curtain Duration Request
|
|
985
|
+
0xE800: {
|
|
986
|
+
parse: function(buffer) {
|
|
987
|
+
return {
|
|
988
|
+
channel: buffer.readUInt8(0)
|
|
989
|
+
};
|
|
990
|
+
},
|
|
991
|
+
|
|
992
|
+
encode: function(data) {
|
|
993
|
+
return Buffer.from([data.channel]);
|
|
994
|
+
},
|
|
995
|
+
|
|
996
|
+
response: 0xE801
|
|
997
|
+
},
|
|
998
|
+
|
|
999
|
+
// 7.1.7 Get Curtain Duration Response
|
|
1000
|
+
0xE801: {
|
|
1001
|
+
parse: function(buffer) {
|
|
1002
|
+
return {
|
|
1003
|
+
channel: buffer.readUInt8(0),
|
|
1004
|
+
duration: buffer.readUInt16BE(2)
|
|
1005
|
+
};
|
|
1006
|
+
},
|
|
1007
|
+
|
|
1008
|
+
encode: function(data) {
|
|
1009
|
+
var buffer = Buffer.allocUnsafe(4);
|
|
1010
|
+
buffer.writeUInt8(data.channel, 0);
|
|
1011
|
+
buffer.writeUInt8(0, 1); // Reserved
|
|
1012
|
+
buffer.writeUInt16BE(data.duration || 0, 2);
|
|
1013
|
+
return buffer;
|
|
1014
|
+
}
|
|
1015
|
+
},
|
|
1016
|
+
|
|
969
1017
|
/* 8. GPRS Control */
|
|
970
1018
|
|
|
971
1019
|
// 8.1.1 GPRS Control
|
|
@@ -1751,10 +1799,42 @@ module.exports = {
|
|
|
1751
1799
|
/* 16. Dry Contact */
|
|
1752
1800
|
|
|
1753
1801
|
// 16.1.1 Auto broadcast Dry Contact Status
|
|
1754
|
-
|
|
1802
|
+
0x15D0: {
|
|
1803
|
+
parse: function(buffer) {
|
|
1804
|
+
return {
|
|
1805
|
+
area: buffer.readUInt8(0),
|
|
1806
|
+
channel: buffer.readUInt8(1),
|
|
1807
|
+
status: buffer.readUInt8(2) === 0
|
|
1808
|
+
};
|
|
1809
|
+
},
|
|
1810
|
+
|
|
1811
|
+
encode: function(data) {
|
|
1812
|
+
var buffer = Buffer.allocUnsafe(3);
|
|
1813
|
+
buffer.writeUInt8(data.area, 0);
|
|
1814
|
+
buffer.writeUInt8(data.channel, 1);
|
|
1815
|
+
buffer.writeUInt8(data.status ? 0 : 1, 2);
|
|
1816
|
+
return buffer;
|
|
1817
|
+
}
|
|
1818
|
+
},
|
|
1755
1819
|
|
|
1756
1820
|
// 16.1.2 Response Auto broadcast Dry Contact Status
|
|
1757
|
-
|
|
1821
|
+
0x15D1: {
|
|
1822
|
+
parse: function(buffer) {
|
|
1823
|
+
return {
|
|
1824
|
+
area: buffer.readUInt8(0),
|
|
1825
|
+
channel: buffer.readUInt8(1),
|
|
1826
|
+
status: buffer.readUInt8(2) === 0
|
|
1827
|
+
};
|
|
1828
|
+
},
|
|
1829
|
+
|
|
1830
|
+
encode: function(data) {
|
|
1831
|
+
var buffer = Buffer.allocUnsafe(3);
|
|
1832
|
+
buffer.writeUInt8(data.area, 0);
|
|
1833
|
+
buffer.writeUInt8(data.channel, 1);
|
|
1834
|
+
buffer.writeUInt8(data.status ? 0 : 1, 2);
|
|
1835
|
+
return buffer;
|
|
1836
|
+
}
|
|
1837
|
+
},
|
|
1758
1838
|
|
|
1759
1839
|
// 16.1.3 Read Dry Contact Status
|
|
1760
1840
|
0x15CE: {
|
|
@@ -1798,6 +1878,54 @@ module.exports = {
|
|
|
1798
1878
|
}
|
|
1799
1879
|
},
|
|
1800
1880
|
|
|
1881
|
+
// 16.1.5 Dry Contact Multi-Channel Status
|
|
1882
|
+
0x6F00: {
|
|
1883
|
+
parse: function(buffer) {
|
|
1884
|
+
var data = {
|
|
1885
|
+
declaredChannels: buffer.readUInt8(1),
|
|
1886
|
+
statusMask: buffer.readUInt16BE(2),
|
|
1887
|
+
channels: []
|
|
1888
|
+
};
|
|
1889
|
+
|
|
1890
|
+
// Include subnet if present
|
|
1891
|
+
if (buffer.length >= 4) {
|
|
1892
|
+
data.subnet = buffer.readUInt8(0);
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
// Parse 16-bit mask for up to 16 channels
|
|
1896
|
+
var mask = data.statusMask;
|
|
1897
|
+
var channels = data.channels;
|
|
1898
|
+
|
|
1899
|
+
for (var i = 0; i < 16; i++) {
|
|
1900
|
+
channels.push({
|
|
1901
|
+
number: i + 1,
|
|
1902
|
+
status: !!(mask & (1 << i))
|
|
1903
|
+
});
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
return data;
|
|
1907
|
+
},
|
|
1908
|
+
|
|
1909
|
+
encode: function(data) {
|
|
1910
|
+
var buffer = Buffer.allocUnsafe(4);
|
|
1911
|
+
buffer.writeUInt8(data.subnet || 0, 0);
|
|
1912
|
+
buffer.writeUInt8(data.declaredChannels || 16, 1);
|
|
1913
|
+
|
|
1914
|
+
var mask = 0;
|
|
1915
|
+
var channels = data.channels || [];
|
|
1916
|
+
|
|
1917
|
+
for (var i = 0; i < channels.length; i++) {
|
|
1918
|
+
if (channels[i].status) {
|
|
1919
|
+
mask |= 1 << (i);
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
buffer.writeUInt16BE(mask, 2);
|
|
1924
|
+
|
|
1925
|
+
return buffer;
|
|
1926
|
+
}
|
|
1927
|
+
},
|
|
1928
|
+
|
|
1801
1929
|
/* 17. DLP Music Play Control Command */
|
|
1802
1930
|
|
|
1803
1931
|
// 17.1.1 Read Z-audio Current Status
|
package/package.json
CHANGED
|
@@ -293,7 +293,7 @@ module.exports = {
|
|
|
293
293
|
// 5.1.7 Response Read System Date and Time
|
|
294
294
|
'0xDA01': {
|
|
295
295
|
payload: Buffer.from('F812020C16020E01', 'hex'),
|
|
296
|
-
data: { success: true, date: new Date(2018, 1, 12, 22,
|
|
296
|
+
data: { success: true, date: new Date(2018, 1, 12, 22, 2, 14) }
|
|
297
297
|
},
|
|
298
298
|
|
|
299
299
|
// 5.1.8 Modify Read System Date and Time
|
|
@@ -374,7 +374,8 @@ module.exports = {
|
|
|
374
374
|
// 7.1.4 Response Read Status of Curtain Switch
|
|
375
375
|
'0xE3E3': [
|
|
376
376
|
{ payload: Buffer.from('0102', 'hex'), data: { curtain: 1, status: 2 } },
|
|
377
|
-
{ payload: Buffer.from('115A', 'hex'), data: { curtain: 17, status: 90 } }
|
|
377
|
+
{ payload: Buffer.from('115A', 'hex'), data: { curtain: 17, status: 90 } },
|
|
378
|
+
{ payload: Buffer.from('010201F4', 'hex'), data: { curtain: 1, status: 2, duration: 50.0 } }
|
|
378
379
|
],
|
|
379
380
|
|
|
380
381
|
// 7.1.5 Broadcast Status of Status of Curtain Switches
|
|
@@ -386,6 +387,18 @@ module.exports = {
|
|
|
386
387
|
] }
|
|
387
388
|
},
|
|
388
389
|
|
|
390
|
+
// 7.1.6 Get Curtain Duration Request
|
|
391
|
+
'0xE800': [
|
|
392
|
+
{ payload: Buffer.from('01', 'hex'), data: { channel: 1 } },
|
|
393
|
+
{ payload: Buffer.from('0A', 'hex'), data: { channel: 10 } }
|
|
394
|
+
],
|
|
395
|
+
|
|
396
|
+
// 7.1.7 Get Curtain Duration Response
|
|
397
|
+
'0xE801': [
|
|
398
|
+
{ payload: Buffer.from('01001388', 'hex'), data: { channel: 1, duration: 5000 } },
|
|
399
|
+
{ payload: Buffer.from('030007D0', 'hex'), data: { channel: 3, duration: 2000 } }
|
|
400
|
+
],
|
|
401
|
+
|
|
389
402
|
/* 9. Panel Control */
|
|
390
403
|
|
|
391
404
|
// 9.1.1 Panel Control
|
|
@@ -782,6 +795,30 @@ module.exports = {
|
|
|
782
795
|
}
|
|
783
796
|
],
|
|
784
797
|
|
|
798
|
+
// 16.1.1 Auto broadcast Dry Contact Status
|
|
799
|
+
'0x15D0': [
|
|
800
|
+
{
|
|
801
|
+
payload: Buffer.from('010200', 'hex'),
|
|
802
|
+
data: { area: 1, channel: 2, status: true }
|
|
803
|
+
},
|
|
804
|
+
{
|
|
805
|
+
payload: Buffer.from('020301', 'hex'),
|
|
806
|
+
data: { area: 2, channel: 3, status: false }
|
|
807
|
+
}
|
|
808
|
+
],
|
|
809
|
+
|
|
810
|
+
// 16.1.2 Response Auto broadcast Dry Contact Status
|
|
811
|
+
'0x15D1': [
|
|
812
|
+
{
|
|
813
|
+
payload: Buffer.from('010100', 'hex'),
|
|
814
|
+
data: { area: 1, channel: 1, status: true }
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
payload: Buffer.from('030401', 'hex'),
|
|
818
|
+
data: { area: 3, channel: 4, status: false }
|
|
819
|
+
}
|
|
820
|
+
],
|
|
821
|
+
|
|
785
822
|
// 16.1.3 Read Dry Contact Status
|
|
786
823
|
'0x15CE': {
|
|
787
824
|
payload: Buffer.from('0102', 'hex'),
|
|
@@ -800,6 +837,62 @@ module.exports = {
|
|
|
800
837
|
}
|
|
801
838
|
],
|
|
802
839
|
|
|
840
|
+
// 16.1.5 Dry Contact Multi-Channel Status
|
|
841
|
+
'0x6F00': [
|
|
842
|
+
{
|
|
843
|
+
payload: Buffer.from('01080F00', 'hex'),
|
|
844
|
+
data: {
|
|
845
|
+
subnet: 1,
|
|
846
|
+
declaredChannels: 8,
|
|
847
|
+
statusMask: 0x0F00,
|
|
848
|
+
channels: [
|
|
849
|
+
{ number: 1, status: false },
|
|
850
|
+
{ number: 2, status: false },
|
|
851
|
+
{ number: 3, status: false },
|
|
852
|
+
{ number: 4, status: false },
|
|
853
|
+
{ number: 5, status: false },
|
|
854
|
+
{ number: 6, status: false },
|
|
855
|
+
{ number: 7, status: false },
|
|
856
|
+
{ number: 8, status: false },
|
|
857
|
+
{ number: 9, status: true },
|
|
858
|
+
{ number: 10, status: true },
|
|
859
|
+
{ number: 11, status: true },
|
|
860
|
+
{ number: 12, status: true },
|
|
861
|
+
{ number: 13, status: false },
|
|
862
|
+
{ number: 14, status: false },
|
|
863
|
+
{ number: 15, status: false },
|
|
864
|
+
{ number: 16, status: false }
|
|
865
|
+
]
|
|
866
|
+
}
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
payload: Buffer.from('0216AA55', 'hex'),
|
|
870
|
+
data: {
|
|
871
|
+
subnet: 2,
|
|
872
|
+
declaredChannels: 22,
|
|
873
|
+
statusMask: 0xAA55,
|
|
874
|
+
channels: [
|
|
875
|
+
{ number: 1, status: true },
|
|
876
|
+
{ number: 2, status: false },
|
|
877
|
+
{ number: 3, status: true },
|
|
878
|
+
{ number: 4, status: false },
|
|
879
|
+
{ number: 5, status: true },
|
|
880
|
+
{ number: 6, status: false },
|
|
881
|
+
{ number: 7, status: true },
|
|
882
|
+
{ number: 8, status: false },
|
|
883
|
+
{ number: 9, status: false },
|
|
884
|
+
{ number: 10, status: true },
|
|
885
|
+
{ number: 11, status: false },
|
|
886
|
+
{ number: 12, status: true },
|
|
887
|
+
{ number: 13, status: false },
|
|
888
|
+
{ number: 14, status: true },
|
|
889
|
+
{ number: 15, status: false },
|
|
890
|
+
{ number: 16, status: true }
|
|
891
|
+
]
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
],
|
|
895
|
+
|
|
803
896
|
/* XX. Undocumented Operation Codes */
|
|
804
897
|
|
|
805
898
|
// XX.1 Panel
|