dsc-itv2-client 1.0.20 → 1.0.22

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsc-itv2-client",
3
3
  "author": "fajitacat",
4
- "version": "1.0.20",
4
+ "version": "1.0.22",
5
5
  "description": "Reverse engineered DSC ITV2 Protocol Client Library for TL280R Communicator - Monitor and control DSC alarm panels",
6
6
  "main": "src/index.js",
7
7
  "type": "module",
package/src/ITV2Client.js CHANGED
@@ -210,13 +210,26 @@ export class ITV2Client extends EventEmitter {
210
210
  // ==================== Authentication Methods ====================
211
211
 
212
212
  /**
213
- * Authenticate with access code to enable privileged commands (0x0400)
214
- * May be required before status queries work
213
+ * Authenticate with access code - simple format (0x0400)
214
+ * Uses 6-digit ASCII format matching interactive CLI
215
+ * @param {string} code - User/master code (e.g., "5555")
216
+ */
217
+ authenticate(code) {
218
+ if (!this._checkEstablished()) return;
219
+ const codeStr = (code || this.masterCode).toString().padStart(6, '0').slice(0, 6);
220
+ const payload = Buffer.from(codeStr, 'ascii');
221
+ const packet = this.session.buildCommand(0x0400, payload);
222
+ this._sendPacket(packet);
223
+ }
224
+
225
+ /**
226
+ * Authenticate with access code - extended format (0x0400)
227
+ * Includes partition and access level metadata
215
228
  * @param {number} partition - Partition number (1-8, or 0 for all)
216
229
  * @param {string} code - User/master code (e.g., "5555")
217
230
  * @param {number} accessLevel - 0=User, 1=Installer, 2=Master
218
231
  */
219
- authenticate(partition = 1, code, accessLevel = 0) {
232
+ authenticateExtended(partition = 1, code, accessLevel = 0) {
220
233
  if (!this._checkEstablished()) return;
221
234
  const packet = this.session.buildAccessLevelEnter(
222
235
  code || this.masterCode,
@@ -756,67 +756,121 @@ export class ITv2Session {
756
756
  return this.buildCommand(CMD.REQUEST_ACCESS, payload);
757
757
  }
758
758
 
759
+ // ==================== VarBytes Encoding ====================
760
+
759
761
  /**
760
- * Build status request command
761
- * @param {number} statusType - Type of status to request:
762
- * 0x10 = Global Status (0x0810)
763
- * 0x11 = Zone Status (0x0811)
764
- * 0x12 = Partition Status (0x0812)
765
- * 0x13 = Zone Bypass Status (0x0813)
766
- * 0x14 = System Trouble Status (0x0814)
767
- * 0x15 = Alarm Memory Info (0x0815)
768
- * 0x16 = Bus Status (0x0816)
769
- * 0x17 = Trouble Detail (0x0817)
770
- * 0x19 = Door Chime Status (0x0819)
771
- * @param {number} partitionOrZone - Partition or zone number (0 = all)
762
+ * Encode a value as VarBytes (DSC protocol variable-length integer)
763
+ * Format: [length byte][value bytes in little-endian]
764
+ * @param {number} value - Value to encode
765
+ * @returns {Buffer} - VarBytes encoded buffer
772
766
  */
773
- buildStatusRequest(statusType, partitionOrZone = 0) {
774
- // Payload: [status type byte][partition/zone number]
775
- const payload = Buffer.from([statusType, partitionOrZone]);
767
+ encodeVarBytes(value) {
768
+ if (value < 0x100) {
769
+ // 1 byte value
770
+ return Buffer.from([0x01, value & 0xFF]);
771
+ } else if (value < 0x10000) {
772
+ // 2 byte value (little-endian)
773
+ return Buffer.from([0x02, value & 0xFF, (value >> 8) & 0xFF]);
774
+ } else if (value < 0x1000000) {
775
+ // 3 byte value (little-endian)
776
+ return Buffer.from([0x03, value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF]);
777
+ } else {
778
+ // 4 byte value (little-endian)
779
+ return Buffer.from([0x04, value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF, (value >> 24) & 0xFF]);
780
+ }
781
+ }
782
+
783
+ // ==================== 0x0800 Command Request Wrapper ====================
784
+
785
+ /**
786
+ * Build a 0x0800 Command Request wrapper
787
+ * This wraps inner commands for status queries - required by the DSC protocol
788
+ * Format: [AppSeqNum 1B][CommandToRequest 2B LE][InnerPayload...]
789
+ * @param {number} innerCommand - The command code to request (e.g., 0x0811)
790
+ * @param {Buffer} innerPayload - The payload for the inner command
791
+ * @returns {Buffer} - Complete packet ready to send
792
+ */
793
+ buildCommandRequest(innerCommand, innerPayload = Buffer.alloc(0)) {
794
+ // Get next application sequence number
795
+ const appSeq = this.appSequence;
796
+ this.appSequence = (this.appSequence + 1) & 0xFF;
797
+
798
+ // Build 0x0800 payload: [AppSeqNum][CommandToRequest LE][InnerPayload]
799
+ const payload = Buffer.alloc(3 + innerPayload.length);
800
+ payload[0] = appSeq;
801
+ payload.writeUInt16LE(innerCommand, 1); // Command in little-endian
802
+ innerPayload.copy(payload, 3);
803
+
804
+ this.log(`[Session] Building 0x0800 Command Request: innerCmd=0x${innerCommand.toString(16)}, appSeq=${appSeq}`);
805
+ this.log(`[Session] Inner payload: ${innerPayload.toString('hex')}`);
806
+
776
807
  return this.buildCommand(CMD.STATUS_REQUEST, payload);
777
808
  }
778
809
 
810
+ // ==================== Status Query Methods (0x0800 Wrapped) ====================
811
+
779
812
  /**
780
- * Build global status request
813
+ * Build global status request (0x0810 wrapped in 0x0800)
781
814
  */
782
815
  buildGlobalStatusRequest() {
783
- // Send GLOBAL_STATUS (0x0810) command directly, not wrapped in STATUS_REQUEST
784
- return this.buildCommand(CMD.GLOBAL_STATUS);
816
+ // 0x0810 has no payload
817
+ return this.buildCommandRequest(CMD.GLOBAL_STATUS, Buffer.alloc(0));
785
818
  }
786
819
 
787
820
  /**
788
- * Build zone status request
789
- * @param {number} zone - Zone number (0 = all zones)
821
+ * Build zone status request (0x0811 wrapped in 0x0800)
822
+ * @param {number} startZone - Starting zone number (0 = first zone)
823
+ * @param {number} numZones - Number of zones to query (default 128)
790
824
  */
791
- buildZoneStatusRequest(zone = 0) {
792
- // Send ZONE_STATUS (0x0811) command directly with zone number
793
- const payload = zone > 0 ? Buffer.from([zone]) : Buffer.alloc(0);
794
- return this.buildCommand(CMD.ZONE_STATUS, payload);
825
+ buildZoneStatusRequest(startZone = 0, numZones = 128) {
826
+ // 0x0811 payload: [ZoneNumber VarBytes][NumberOfZones VarBytes]
827
+ const zoneBytes = this.encodeVarBytes(startZone);
828
+ const countBytes = this.encodeVarBytes(numZones);
829
+ const payload = Buffer.concat([zoneBytes, countBytes]);
830
+ return this.buildCommandRequest(CMD.ZONE_STATUS, payload);
795
831
  }
796
832
 
797
833
  /**
798
- * Build partition status request
834
+ * Build partition status request (0x0812 wrapped in 0x0800)
799
835
  * @param {number} partition - Partition number (0 = all partitions)
836
+ * @param {number} numPartitions - Number of partitions to query (default 8)
800
837
  */
801
- buildPartitionStatusRequest(partition = 0) {
802
- // Send PARTITION_STATUS (0x0812) command directly with partition number
803
- const payload = partition > 0 ? Buffer.from([partition]) : Buffer.alloc(0);
804
- return this.buildCommand(CMD.PARTITION_STATUS, payload);
838
+ buildPartitionStatusRequest(partition = 0, numPartitions = 8) {
839
+ // 0x0812 payload: [Partition VarBytes][NumberOfPartitions VarBytes]
840
+ const partBytes = this.encodeVarBytes(partition);
841
+ const countBytes = this.encodeVarBytes(numPartitions);
842
+ const payload = Buffer.concat([partBytes, countBytes]);
843
+ return this.buildCommandRequest(CMD.PARTITION_STATUS, payload);
805
844
  }
806
845
 
807
846
  /**
808
- * Build zone bypass status request
847
+ * Build zone bypass status request (0x0813 wrapped in 0x0800)
809
848
  * @param {number} zone - Zone number (0 = all zones)
849
+ * @param {number} numZones - Number of zones (default 128)
810
850
  */
811
- buildZoneBypassStatusRequest(zone = 0) {
812
- return this.buildStatusRequest(0x13, zone);
851
+ buildZoneBypassStatusRequest(zone = 0, numZones = 128) {
852
+ const zoneBytes = this.encodeVarBytes(zone);
853
+ const countBytes = this.encodeVarBytes(numZones);
854
+ const payload = Buffer.concat([zoneBytes, countBytes]);
855
+ return this.buildCommandRequest(CMD.ZONE_BYPASS_STATUS, payload);
813
856
  }
814
857
 
815
858
  /**
816
- * Build system trouble status request
859
+ * Build system trouble status request (0x0814 wrapped in 0x0800)
817
860
  */
818
861
  buildTroubleStatusRequest() {
819
- return this.buildStatusRequest(0x14, 0);
862
+ // 0x0814 typically has no payload or minimal payload
863
+ return this.buildCommandRequest(CMD.SYSTEM_TROUBLE_STATUS, Buffer.alloc(0));
864
+ }
865
+
866
+ /**
867
+ * Build status request command (legacy - simple format)
868
+ * @deprecated Use buildCommandRequest() with specific inner commands instead
869
+ */
870
+ buildStatusRequest(statusType, partitionOrZone = 0) {
871
+ // Legacy format - kept for backwards compatibility
872
+ const payload = Buffer.from([statusType, partitionOrZone]);
873
+ return this.buildCommand(CMD.STATUS_REQUEST, payload);
820
874
  }
821
875
 
822
876
  /**