UNPKG

@smartdcc/gbcs-parser

Version:
1,050 lines 56.3 kB
"use strict"; /* * * Original copyright holders for the GBCS message parser tool: * * Copyright (c) 2019 Andre B. Oliveira * 2019 Enrique Giraldo * 2019 Cristóbal Borrero * * Copyright for subsequent changes, including porting to NodeJS, * updating for TypeScript and refactor to support unit testing: * * Copyright (c) 2022 Smart DCC Limited * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.parseGbzPayload = parseGbzPayload; exports.parseGbzAlertPayload = parseGbzAlertPayload; exports.parseGbzMeterIntegrityIssueWarningAlert = parseGbzMeterIntegrityIssueWarningAlert; exports.parseGbzFutureDatedAlertPayload = parseGbzFutureDatedAlertPayload; exports.parseGbzFirmwareDistributionReceiptAlert = parseGbzFirmwareDistributionReceiptAlert; exports.parseGbzGcs53AlertPayload = parseGbzGcs53AlertPayload; const common_1 = require("./common"); const context_1 = require("./context"); const crypto_1 = require("./crypto"); const dlms_1 = require("./dlms"); const util_1 = require("./util"); // GBZ Payloads function parseGbzPayload(ctx, x) { (0, context_1.putBytes)(ctx, 'Profile ID', (0, util_1.getBytes)(x, 2)); const numberOfGbzComponents = x.input.byte(x.index); (0, context_1.putBytes)(ctx, 'Number of GBZ components', (0, util_1.getBytes)(x, 1), String(numberOfGbzComponents)); for (let i = 1; i <= numberOfGbzComponents; i++) { (0, context_1.putSeparator)(ctx, 'GBZ Component ' + i); parseGbzComponent(ctx, x); } } function parseGbzAlertPayload(ctx, x) { (0, context_1.putBytes)(ctx, 'Profile ID', (0, util_1.getBytes)(x, 2)); (0, context_1.putBytes)(ctx, 'Number of GBZ components', (0, util_1.getBytes)(x, 1)); parseGbzAlertCode(ctx, x); parseGbzTime(ctx, x, 'Time Stamp'); if (x.index < x.end) { (0, context_1.putBytes)(ctx, 'GBZ Use Case Specific Components', x); } } function parseGbzMeterIntegrityIssueWarningAlert(ctx, x) { (0, context_1.putBytes)(ctx, 'Profile ID', (0, util_1.getBytes)(x, 2)); (0, context_1.putBytes)(ctx, 'Number of GBZ components', (0, util_1.getBytes)(x, 1)); parseGbzAlertCode(ctx, x); parseGbzTime(ctx, x, 'Time Stamp'); (0, context_1.putBytes)(ctx, 'GBZ Use Case Specific Components', (0, util_1.getBytes)(x, 0)); (0, common_1.parseMeterIntegrityIssueWarning)(ctx, x, ' '); } function parseGbzFutureDatedAlertPayload(ctx, x) { (0, context_1.putBytes)(ctx, 'Profile ID', (0, util_1.getBytes)(x, 2)); (0, context_1.putBytes)(ctx, 'Number of GBZ components', (0, util_1.getBytes)(x, 1)); parseGbzAlertCode(ctx, x); parseGbzTime(ctx, x, 'Time Stamp'); (0, context_1.putBytes)(ctx, 'Future Dated Alert Payload', (0, util_1.getBytes)(x, 1)); (0, common_1.parseMessageCode)(ctx, 'Message Code', x); (0, common_1.parseCounter)(ctx, 'Originator Counter', x); const cluster = parseClusterId(ctx, x); const frameControl = x.input.byte(x.index); (0, context_1.putBytes)(ctx, 'Frame Control', (0, util_1.getBytes)(x, 1)); parseCommandId(ctx, x, '', frameControl, cluster); } function parseGbzFirmwareDistributionReceiptAlert(ctx, x) { (0, context_1.putBytes)(ctx, 'Profile ID', (0, util_1.getBytes)(x, 2)); (0, context_1.putBytes)(ctx, 'Number of GBZ components', (0, util_1.getBytes)(x, 1)); parseGbzAlertCode(ctx, x); parseGbzTime(ctx, x, 'Time Stamp'); (0, dlms_1.parseDlmsOctetString)(ctx, x, 'Calculated Manufacturer Hash', true); } function parseGbzGcs53AlertPayload(ctx, x) { (0, context_1.putBytes)(ctx, 'Profile ID', (0, util_1.getBytes)(x, 2)); (0, context_1.putBytes)(ctx, 'Number of GBZ components', (0, util_1.getBytes)(x, 1)); parseGbzAlertCode(ctx, x); parseGbzTime(ctx, x, 'Time Stamp'); parseGbzComponent(ctx, x); } function parseGbzAlertCode(ctx, x) { const alertCode = (0, common_1.parseNumber)(x, 2); (0, context_1.putBytes)(ctx, 'Alert Code', (0, util_1.getBytes)(x, 2), (0, util_1.getAlertCodeName)(alertCode)); } function parseGbzComponent(ctx, x) { const controlField = x.input.byte(x.index); if (controlField & 0x02) { (0, context_1.putBytes)(ctx, 'Control Field', (0, util_1.getBytes)(x, 1)); //, swapped) } else { (0, context_1.putBytes)(ctx, 'Control Field', (0, util_1.getBytes)(x, 1)); } const cluster = parseClusterId(ctx, x); // Extended Header GBZ Command Length const extendedLen = (0, common_1.parseNumber)(x, 2); (0, context_1.putBytes)(ctx, 'Length', (0, util_1.getBytes)(x, 2), String(extendedLen)); const y = (0, util_1.getBytes)(x, extendedLen); if (controlField & 0x02) { // encrypted content (0, context_1.putBytes)(ctx, 'Additional Header Control', (0, util_1.getBytes)(y, 1)); (0, context_1.putBytes)(ctx, 'Additional Header Frame Counter', (0, util_1.getBytes)(y, 1)); } else if (controlField & 0x10) { parseGbzTime(ctx, y, 'From Date Time'); } // ZCL Header const frameControl = y.input.byte(y.index); (0, context_1.putBytes)(ctx, 'ZCL Header', (0, util_1.getBytes)(y, 0)); (0, context_1.putBytes)(ctx, ' Frame Control', (0, util_1.getBytes)(y, 1)); (0, context_1.putBytes)(ctx, ' Sequence Number', (0, util_1.getBytes)(y, 1)); const command = parseCommandId(ctx, y, ' ', frameControl, cluster); if (controlField & 0x02) { // encrypted payload const len = (0, common_1.parseNumber)(y, 2); (0, context_1.putBytes)(ctx, 'Ciphered Information Length', (0, util_1.getBytes)(y, 2), String(len)); (0, context_1.putBytes)(ctx, 'Security Header', (0, util_1.getBytes)(y, 5)); const ciphertextAndTag = y.input.buffer.subarray(y.index, y.index + len - 5); (0, context_1.putBytes)(ctx, 'Encrypted ZCL Payload', (0, util_1.getBytes)(y, len - 5 - 12)); (0, context_1.putBytes)(ctx, 'AE MAC', (0, util_1.getBytes)(y, 12)); (0, crypto_1.decryptGbcsData)(ctx, ciphertextAndTag, function (yy) { if (command && command.parse) { (0, context_1.putBytes)(ctx, 'ZCL Payload', (0, util_1.getBytes)(x, 0), command.name); command.parse({ ctx, x: yy, cluster, frameControl, indent: ' ' }); } else { (0, context_1.putBytes)(ctx, 'ZCL Payload', yy); } (0, context_1.putUnparsedBytes)(yy); }); } else { // plaintext payload if (command && command.parse) { (0, context_1.putBytes)(ctx, 'ZCL Payload', (0, util_1.getBytes)(x, 0), command.name); command.parse({ ctx, x: y, cluster, frameControl, indent: ' ' }); } else { (0, context_1.putBytes)(ctx, 'ZCL Payload', y); } (0, context_1.putUnparsedBytes)(y); } } function parseClusterId(ctx, x) { const clusters = { 0x0000: { name: 'Basic', attributes: { 0x0003: 'HW Version', 0x0004: 'Manufacturer Name', 0x0005: 'Model Identifier', }, commands: {}, responses: {}, }, 0x0700: { name: 'Price', attributes: { 0x0100: 'Block 1 Threshold', 0x0101: 'Block 2 Threshold', 0x0102: 'Block 3 Threshold', 0x0202: 'Threshold Multiplier', 0x0203: 'Threshold Divisor', 0x0301: 'Standing Charge', 0x0302: 'Conversion Factor', 0x0303: 'Conversion Factor Trailing Digit', 0x0304: 'Calorific Value', 0x0305: 'Calorific Value Unit', 0x0306: 'Calorific Value Trailing Digit', 0x0400: 'No Tier Block 1 Price', 0x0401: 'No Tier Block 2 Price', 0x0402: 'No Tier Block 3 Price', 0x0403: 'No Tier Block 4 Price', 0x0410: 'Tier 1 Block 1 Price', 0x0420: 'Tier 2 Block 1 Price', 0x0430: 'Tier 3 Block 1 Price', 0x0440: 'Tier 4 Block 1 Price', 0x0615: 'Unit of Measure', 0x0616: 'Currency', 0x0617: 'Price Trailing Digits', }, commands: { 0: ['Get Current Price', parseZseGetCurrentPrice], 11: ['Get Billing Period', parseZseGetBillingPeriod], }, responses: { 0: ['Publish Price', parseZsePublishPrice], 1: ['Publish Block Period', parseZsePublishBlockPeriod], 2: ['Publish Conversion Factor', parseZsePublishConversionFactor], 3: ['Publish Calorific Value', parseZsePublishCalorificValue], 4: ['Publish Tariff Information', parseZsePublishTariffInformation], 5: ['Publish Price Matrix', parseZsePublishPriceMatrix], 6: ['Publish Block Thresholds', parseZsePublishBlockThresholds], 9: ['Publish Billing Period', parseZsePublishBillingPeriod], }, }, 0x0702: { name: 'Metering', attributes: { 0x0000: 'Current Summation Delivered', 0x0014: 'Supply Status', 0x0100: 'Current Tier 1 Summation Delivered', 0x0102: 'Current Tier 2 Summation Delivered', 0x0104: 'Current Tier 3 Summation Delivered', 0x0106: 'Current Tier 4 Summation Delivered', 0x0205: 'Remaining Battery Life in Days', 0x0206: 'Current Meter Id', 0x0300: 'Unit of Measure', 0x0301: 'Multiplier', 0x0302: 'Divisor', 0x0307: 'Site ID', 0x0607: 'Supply Tamper State', 0x0608: 'SupplyDepletionState', 0x0700: 'Current no Tier Block 1 Summation Delivered', 0x0701: 'Current no Tier Block 2 Summation Delivered', 0x0702: 'Current no Tier Block 3 Summation Delivered', 0x0703: 'Current no Tier Block 4 Summation Delivered', 0x0a00: 'Bill to Date Delivered', 0x0b10: 'Uncontrolled Flow Threshold', 0x0b11: 'Uncontrolled Flow Threshold Unit of Measure', 0x0b12: 'Uncontrolled Flow Multiplier', 0x0b13: 'Uncontrolled Flow Divisor', 0x0b14: 'Flow Stabilisation Period', 0x0b15: 'Flow Measurement Period', }, commands: { 6: ['Get Snapshot', parseZseGetSnapshot], 7: ['Start Sampling', parseZseStartSampling], 8: ['Get Sampled Data', parseZseGetSampledData], 11: ['Change Supply', parseZseChangeSupply], 13: ['Set Supply Status', parseZseSetSupplyStatus], 14: [ 'Set Uncontrolled Flow Threshold', parseZseSetUncontrolledFlowThreshold, ], }, responses: { 6: ['Publish Snapshot', parseZsePublishSnapshot], 7: ['Get Sampled Data Response', parseZseGetSampledDataResponse], 12: ['Supply Status Response', parseZseSupplyStatusResponse], 13: ['Start Sampling Response', parseZseStartSamplingResponse], }, }, 0x0703: { name: 'Messaging', attributes: {}, commands: {}, responses: { 0: ['Display Message', parseZseDisplayMessage], }, }, 0x0705: { name: 'Prepayment', attributes: { 0x0000: 'Payment Control Configuration', 0x0001: 'Credit Remaining', 0x0002: 'Emergency Credit Remaining', 0x0005: 'Accumulated Debt', 0x0006: 'Overall Debt Cap', 0x0010: 'Emergency Credit Limit', 0x0011: 'Emergency Credit Threshold', 0x0021: 'Max Credit Limit', 0x0022: 'Max Credit Per Top Up', 0x0031: 'Low Credit Warning Level', 0x0040: 'Cut Off Value', 0x0211: 'Debt Amount 1 (Time-Based Debt 1)', 0x0216: 'Debt Recovery Frequency 1', 0x0217: 'Debt Recovery Amount 1', 0x0221: 'Debt Amount 2 (Time-Based Debt 2)', 0x0226: 'Debt Recovery Frequency 2', 0x0227: 'Debt Recovery Amount 2', 0x0231: 'Debt Amount 3 (Payment-Based Debt)', 0x0239: 'Debt Recovery Top Up Percentage 3', }, commands: { 0: [ 'Select Available Emergency Credit', parseZseSelectAvailableEmergencyCredit, ], 2: ['Change Debt', parseZseChangeDebt], 3: ['Emergency Credit Setup', parseZseEmergencyCreditSetup], 4: ['Consumer Top Up', parseZseConsumerTopUp], 5: ['Credit Adjustment', parseZseCreditAdjustment], 6: ['Change Payment Mode', parseZseChangePaymentMode], 7: ['Get Prepay Snapshot', parseZseGetPrepaySnapshot], 8: ['Get Top Up Log', parseZseGetTopUpLog], 9: ['Set Low Credit Warning Level', parseZseSetLowCreditWarningLevel], 10: ['Get Debt Repayment Log', parseZseGetDebtRepaymentLog], 11: ['Set Maximum Credit Limit', parseZseSetMaximumCreditLimit], 12: ['Set Overall Debt Cap', parseZseSetOverallDebtCap], }, responses: { 1: ['Publish Prepay Snapshot', parseZsePublishPrepaySnapshot], // encrypted payload 2: ['Change Payment Mode Response', parseZseChangePaymentModeResponse], 3: ['Consumer Top Up Response', parseZseConsumerTopUpResponse], 5: ['Publish Top Up Log', parseZsePublishTopUpLog], 6: ['Publish Debt Log', parseZsePublishDebtLog], }, }, 0x0707: { name: 'Calendar', attributes: {}, commands: { 0: ['Get Calendar', parseZclNoop], 1: ['Get Day Profiles', parseZseGetDayProfiles], 2: ['Get Week Profiles', parseZseGetWeekProfiles], 3: ['Get Seasons', parseZseGetSeasons], 4: ['Get Special Days', parseZseGetSpecialDays], }, responses: { 0: ['Publish Calendar', parseZsePublishCalendar], 1: ['Publish Day Profile', parseZsePublishDayProfile], 2: ['Publish Week Profile', parseZsePublishWeekProfile], 3: ['Publish Seasons', parseZsePublishSeasons], 4: ['Publish Special Days', parseZsePublishSpecialDays], }, }, 0x0708: { name: 'Device Management', attributes: {}, commands: { 4: ['Report Event Configuration', parseZseReportEventConfiguration], }, responses: { 0: ['Publish Change of Tenancy', parseZsePublishChangeOfTenancy], 1: ['Publish Change of Supplier', parseZsePublishChangeOfSupplier], 2: [ 'Request New Password Response', parseZseRequestNewPasswordResponse, ], 3: ['Update Site Id', parseZseUpdateSiteId], 4: ['Set Event Configuration', parseZseSetEventConfiguration], 5: ['Get Event Configuration', parseZseGetEventConfiguration], 6: ['Update CIN', parseZseUpdateCin], }, }, 0x0709: { name: 'Events', attributes: {}, commands: { 0: ['Get Event Log', parseZseGetEventLog], 1: ['Clear Event Log Request', parseZseClearEventLogRequest], }, responses: { 1: ['Publish Event Log', parseZsePublishEventLog], 2: ['Clear Event Log Response', parseZseClearEventLogResponse], }, }, }; const clusterId = (0, common_1.parseNumber)(x, 2); const cluster = clusters[clusterId] || { name: '', attributes: {}, commands: {}, responses: {}, }; (0, context_1.putBytes)(ctx, 'Cluster Id', (0, util_1.getBytes)(x, 2), cluster.name); return cluster; } function parseCommandId(ctx, x, indent, frameControl, cluster) { let command = undefined; const commandId = x.input.byte(x.index); const frameType = frameControl & 3; if (frameType === 0) { const profileCommands = { 0: ['Read Attributes', parseZclReadAttributes], 1: ['Read Attributes Response', parseZclReadAttributesResponse], 11: ['Default Response', parseZclDefaultResponse], }; command = profileCommands[commandId]; } else if (frameType === 1) { const direction = frameControl & 8; if (direction === 0) { command = cluster.commands[commandId]; } else { command = cluster.responses[commandId]; } } if (!command) { throw new Error('unable to parse command id'); } const name = command[0]; (0, context_1.putBytes)(ctx, `${indent}Command Id`, (0, util_1.getBytes)(x, 1), name); return { name: command[0], parse: command[1] }; } // ZCL commands const parseZclNoop = () => undefined; function parseZclReadAttributes({ ctx, x, cluster, indent }) { let ctr = 0; while (x.index < x.end) { const id = (0, common_1.parseNumberLE)(x, 2); const name = cluster.attributes[id] || ''; (0, context_1.putBytes)(ctx, `${indent}Attribute Id ${ctr}`, (0, util_1.getBytes)(x, 2), name); ctr++; } } function parseZclReadAttributesResponse({ ctx, x, cluster, indent, }) { for (let i = 1; x.index < x.end; i++) { (0, context_1.putBytes)(ctx, `${indent}Attribute ${i}`, (0, util_1.getBytes)(x, 0)); const indent2 = ' ' + indent; const id = (0, common_1.parseNumberLE)(x, 2); const name = cluster.attributes[id] || ''; (0, context_1.putBytes)(ctx, `${indent2}Attribute Id`, (0, util_1.getBytes)(x, 2), name); const status = parseZclStatusCode(ctx, x, indent2); if (status === 0) { const typeName = `${indent2}Attribute Data Type`; const valueName = `${indent2}Attribute Data Value`; const type = x.input.byte(x.index); if (type === 0x18) { (0, context_1.putBytes)(ctx, typeName, (0, util_1.getBytes)(x, 1), `BITMAP8`); parseZclBitmap(ctx, 8, x, valueName); } else if (type === 0x19) { (0, context_1.putBytes)(ctx, typeName, (0, util_1.getBytes)(x, 1), `BITMAP16`); parseZclBitmap(ctx, 16, x, valueName); } else if (type === 0x20) { (0, context_1.putBytes)(ctx, typeName, (0, util_1.getBytes)(x, 1), `UINT8`); parseZclUint(ctx, 8, x, valueName); } else if (type === 0x21) { (0, context_1.putBytes)(ctx, typeName, (0, util_1.getBytes)(x, 1), `UINT16`); parseZclUint(ctx, 16, x, valueName); } else if (type === 0x22) { (0, context_1.putBytes)(ctx, typeName, (0, util_1.getBytes)(x, 1), `UINT24`); parseZclUint(ctx, 24, x, valueName); } else if (type === 0x23) { (0, context_1.putBytes)(ctx, typeName, (0, util_1.getBytes)(x, 1), `UINT32`); parseZclUint(ctx, 32, x, valueName); } else if (type === 0x25) { (0, context_1.putBytes)(ctx, typeName, (0, util_1.getBytes)(x, 1), `UINT48`); parseZclUint(ctx, 48, x, valueName); } else if (type === 0x2b) { (0, context_1.putBytes)(ctx, typeName, (0, util_1.getBytes)(x, 1), `INT32`); parseZclInt32(ctx, x, valueName); } else if (type === 0x30) { (0, context_1.putBytes)(ctx, typeName, (0, util_1.getBytes)(x, 1), `ENUM8`); parseZclEnum(ctx, 8, x, valueName); } else if (type === 0x41) { (0, context_1.putBytes)(ctx, typeName, (0, util_1.getBytes)(x, 1), `Octet String`); parseZclOctetString(ctx, x, valueName); } else if (type === 0x42) { (0, context_1.putBytes)(ctx, typeName, (0, util_1.getBytes)(x, 1), `Character String`); parseZclOctetString(ctx, x, valueName); } else { throw 'TODO: Read Attributes Response data type ' + type; } } } } function parseZclDefaultResponse({ ctx, x, cluster, frameControl, indent, }) { let command = undefined; const commandId = x.input.byte(x.index); const direction = frameControl & 8; if (direction === 0) { command = cluster.responses[commandId]; } else { command = cluster.commands[commandId]; } const name = (command && command[0]) || ''; (0, context_1.putBytes)(ctx, `${indent}Command Id`, (0, util_1.getBytes)(x, 1), name); parseZclStatusCode(ctx, x, indent); } // ZSE Price Cluster function parseZseGetCurrentPrice({ ctx, x, indent }) { parseZclUint(ctx, 8, x, `${indent}Command Options`); } function parseZseGetBillingPeriod({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Earliest Start Time`); parseZclUint(ctx, 32, x, `${indent}Minimum Issuer Event Id`); parseZclUint(ctx, 8, x, `${indent}Number of Commands`); parseZclBitmap(ctx, 8, x, `${indent}Tariff Type`); } function parseZsePublishPrice({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclOctetString(ctx, x, `${indent}Rate Label`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Current Time`); parseZclEnum(ctx, 8, x, `${indent}Unit of Measure`, { 0: 'kWh' }); parseZclUint(ctx, 16, x, `${indent}Currency`, { 826: 'GBP', 978: 'Euro' }); parseZclBitmap(ctx, 8, x, `${indent}Price Trailing Digit and Price Tier`); parseZclBitmap(ctx, 8, x, `${indent}Number of Price Tiers and Register Tier`); parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclUint(ctx, 16, x, `${indent}Duration in Minutes`); parseZclUint(ctx, 32, x, `${indent}Price`); // NOTE: the Response may contain an additional 19 octets after this // parameter. Those 19 octets do not contain meaningful information // and so, if present, should be ignored by all parties if (x.end - x.index === 19) { (0, context_1.putBytes)(ctx, `${indent}Meaningless Information`, x); } } function parseZsePublishBlockPeriod({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Block Period Start Time`); parseZclUint(ctx, 24, x, `${indent}Block Period Duration`); parseZclBitmap(ctx, 8, x, `${indent}Block Period Control`); parseZclBitmap(ctx, 8, x, `${indent}Block Period Duration Type`); parseZclBitmap(ctx, 8, x, `${indent}Tariff Type`); parseZclEnum(ctx, 8, x, `${indent}Tariff Resolution Period`); } function parseZsePublishConversionFactor({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclUint(ctx, 32, x, `${indent}Conversion Factor`); parseZclBitmap(ctx, 8, x, `${indent}Conversion Factor Trailing Digit`); } function parseZsePublishCalorificValue({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclUint(ctx, 32, x, `${indent}Calorific Value`); parseZclEnum(ctx, 8, x, `${indent}Calorific Value Unit`); parseZclBitmap(ctx, 8, x, `${indent}Calorific Value Trailing Digit`); } function parseZsePublishTariffInformation({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUint(ctx, 32, x, `${indent}Issuer Tariff Id`); parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclBitmap(ctx, 8, x, `${indent}Tariff Type / Charging Scheme`, { 0x00: 'TOU Tariff / Delivered Tariff', 0x10: 'Block Tariff / Delivered Tariff', }); parseZclOctetString(ctx, x, `${indent}Tariff Label`); parseZclUint(ctx, 8, x, `${indent}Number of Price Tiers in Use`); parseZclUint(ctx, 8, x, `${indent}Number of Block Thresholds in Use`); parseZclEnum(ctx, 8, x, `${indent}Unit of Measure`, { 0: 'kWh' }); parseZclUint(ctx, 16, x, `${indent}Currency`, { 826: 'GBP', 978: 'Euro' }); parseZclBitmap(ctx, 8, x, `${indent}Price Trailing Digit`); parseZclUint(ctx, 32, x, `${indent}Standing Charge`); parseZclUint(ctx, 8, x, `${indent}Tier Block Mode`); parseZclUint(ctx, 24, x, `${indent}Block Threshold Multiplier`); parseZclUint(ctx, 24, x, `${indent}Block Threshold Divisor`); } function parseZsePublishPriceMatrix({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclUint(ctx, 32, x, `${indent}Issuer Tariff Id`); parseZclUint(ctx, 8, x, `${indent}Command Index`); parseZclUint(ctx, 8, x, `${indent}Number of Commands`); parseZclBitmap(ctx, 8, x, `${indent}Sub-payload Control`, { 0: 'Block or Block/TOU', 1: 'TOU', }); for (let i = 1; x.index < x.end; i++) { parseZclUint(ctx, 8, x, `${indent}Tier / Block Id ` + i); parseZclUint(ctx, 32, x, `${indent}Price ` + i); } } function parseZsePublishBlockThresholds({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclUint(ctx, 32, x, `${indent}Issuer Tariff Id`); parseZclUint(ctx, 8, x, `${indent}Command Index`); parseZclUint(ctx, 8, x, `${indent}Number of Commands`); parseZclBitmap(ctx, 8, x, `${indent}Sub-payload Control`, { 1: 'Block thresholds apply to all TOU tiers / block only charging in operation', }); const n = parseZclUint(ctx, 8, x, `${indent}Number of Block Thresholds`); for (let i = 1; i <= n; i++) { parseZclUint(ctx, 48, x, `${indent}Block Threshold ${i}`); } } function parseZsePublishBillingPeriod({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Billing Period Start Time`); parseZclUint(ctx, 24, x, `${indent}Billing Period Duration`); parseZclUint(ctx, 8, x, `${indent}Billing Period Duration Type`); parseZclUint(ctx, 8, x, `${indent}Tariff Type`); } // ZSE Metering Cluster function parseZseGetSnapshot({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Earliest Start Time`); parseZclUtcTime(ctx, x, `${indent}Latest End Time`); parseZclUint(ctx, 8, x, `${indent}Snapshot Offset`); parseZclBitmap(ctx, 32, x, `${indent}Snapshot Cause`); } function parseZseStartSampling({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Start Sampling Time`); parseZclEnum(ctx, 8, x, `${indent}Sample Type`); parseZclUint(ctx, 16, x, `${indent}Sample Request Interval`); parseZclUint(ctx, 16, x, `${indent}Max Number of Samples`); } function parseZseGetSampledData({ ctx, x, indent }) { parseZclUint(ctx, 16, x, `${indent}Sample Id`); parseZclUtcTime(ctx, x, `${indent}Earliest Sample Time`); parseZclEnum(ctx, 8, x, `${indent}Sample Type`); parseZclUint(ctx, 16, x, `${indent}Number of Samples`); } function parseZseChangeSupply({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Request Date Time`); parseZclUtcTime(ctx, x, `${indent}Implementation Date Time`); parseZclEnum(ctx, 8, x, `${indent}Proposed Supply Status`); parseZclBitmap(ctx, 8, x, `${indent}Supply Control Bits`); } function parseZseSetSupplyStatus({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclEnum(ctx, 8, x, `${indent}Supply Tamper State`); parseZclEnum(ctx, 8, x, `${indent}Supply Depletion State`); parseZclEnum(ctx, 8, x, `${indent}Supply Uncontrolled Flow State`); parseZclEnum(ctx, 8, x, `${indent}Low Limit Supply State`); } function parseZseSetUncontrolledFlowThreshold({ ctx, x, indent, }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUint(ctx, 16, x, `${indent}Uncontrolled Flow Threshold`); parseZclEnum(ctx, 8, x, `${indent}Unit of Measure`, { 0: 'kWh' }); parseZclUint(ctx, 16, x, `${indent}Multiplier`); parseZclUint(ctx, 16, x, `${indent}Divisor`); parseZclUint(ctx, 8, x, `${indent}Stabilisation Period`); parseZclUint(ctx, 16, x, `${indent}Measurement Period`); } function parseZsePublishPrepaySnapshot({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Snapshot Id`); parseZclUtcTime(ctx, x, `${indent}Snapshot Time`); parseZclUint(ctx, 8, x, `${indent}Snapshots Found`); parseZclUint(ctx, 8, x, `${indent}Command Index`); parseZclUint(ctx, 8, x, `${indent}Number of Commands`); parseZclBitmap(ctx, 32, x, `${indent}Snapshot Cause`); parseZclEnum(ctx, 8, x, `${indent}Snapshot Payload Type`); (0, context_1.putBytes)(ctx, `${indent}Snapshot Sub-payload`, (0, util_1.getBytes)(x, 0)); // ZSE Accumulated Debt = SMETS Accumulated Debt Register; ZSE Type 1 Debt Remaining = SMETS Time Debt Registers [1]; ZSE Type 2 Debt Remaining = SMETS Time Debt Registers [2]; ZSE Type 3 Debt Remaining = SMETS Payment Debt Register; ZSE Emergency Credit Remaining = SMETS Emergency Credit Balance; ZSE Credit Remaining = SMETS Meter Balance parseZclInt32(ctx, x, `${indent} Accumulated Debt Register`); parseZclUint(ctx, 32, x, `${indent} Time Debt Registers [1]`); parseZclUint(ctx, 32, x, `${indent} Time Debt Registers [2]`); parseZclUint(ctx, 32, x, `${indent} Payment Debt Register`); parseZclUint(ctx, 32, x, `${indent} Emergency Credit Balance`); parseZclUint(ctx, 32, x, `${indent} Meter Balance`); } function parseZsePublishSnapshot({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Snapshot Id`); parseZclUtcTime(ctx, x, `${indent}Snapshot Time`); parseZclUint(ctx, 8, x, `${indent}Snapshots Found`); parseZclUint(ctx, 8, x, `${indent}Command Index`); parseZclUint(ctx, 8, x, `${indent}Number of Commands`); parseZclBitmap(ctx, 32, x, `${indent}Snapshot Cause`); parseZclEnum(ctx, 8, x, `${indent}Snapshot Payload Type`); // 6 (0, context_1.putBytes)(ctx, `${indent}Snapshot Sub-payload`, (0, util_1.getBytes)(x, 0)); parseZclUint(ctx, 48, x, `${indent} Current Summation Delivered`); parseZclUint(ctx, 8, x, `${indent} Number of Tiers in Use`); for (let i = 0; i < 4; i++) { parseZclUint(ctx, 48, x, `${indent} Tariff TOU Register Matrix [${i + 1}]`); } parseZclBitmap(ctx, 8, x, `${indent} Number of Tiers and Block Thresholds in Use`); for (let i = 0; i < 4; i++) { parseZclUint(ctx, 48, x, `${indent} Tariff TOU Block Counter Matrix [${i + 1}]`); } } function parseZseGetSampledDataResponse({ ctx, x, indent }) { parseZclUint(ctx, 16, x, `${indent}Sample Id`); parseZclUtcTime(ctx, x, `${indent}Sample Start Time`); parseZclEnum(ctx, 8, x, `${indent}Sample Type`); parseZclUint(ctx, 16, x, `${indent}Sample Request Interval`); const n = parseZclUint(ctx, 16, x, `${indent}Number of Samples`); for (let i = 1; i <= n; i++) { parseZclUint(ctx, 24, x, `${indent}Sample ${i}`); } } function parseZseSupplyStatusResponse({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Implementation Date Time`); parseZclEnum(ctx, 8, x, `${indent}Supply Status`); } function parseZseStartSamplingResponse({ ctx, x, indent }) { parseZclUint(ctx, 16, x, `${indent}Sample Id`); } // ZSE Messaging Cluster function parseZseDisplayMessage({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Message Id`); parseZclBitmap(ctx, 8, x, `${indent}Message Control`); parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclUint(ctx, 16, x, `${indent}Duration in Minutes`); parseZclOctetString(ctx, x, `${indent}Message`); if (x.index < x.end) { parseZclBitmap(ctx, 8, x, `${indent}Extended Message Control`); } } // ZSE Prepayment Cluster function parseZseSelectAvailableEmergencyCredit({ ctx, x, indent, }) { parseZclUtcTime(ctx, x, `${indent}Command Issue Date Time`); parseZclEnum(ctx, 8, x, `${indent}Originating Device`, { 0: 'Energy Service Interface', }); } function parseZseChangeDebt({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclOctetString(ctx, x, `${indent}Debt Label`); parseZclInt32(ctx, x, `${indent}Debt Amount`); parseZclUint(ctx, 8, x, `${indent}Debt Recovery Method`, { 0: 'Time-based debt', 1: 'Payment-based debt', }); parseZclEnum(ctx, 8, x, `${indent}Debt Amount Type`, { 1: 'Time-based debt (1) Incremental', 3: 'Time-based debt (2) Incremental', 5: 'Payment-based debt Incremental', }); parseZclUint(ctx, 32, x, `${indent}Debt Recovery Start Time`); parseZclUint(ctx, 16, x, `${indent}Debt Recovery Collection Time`); parseZclEnum(ctx, 8, x, `${indent}Debt Recovery Frequency`, { 0: 'Hourly', 1: 'Daily', }); parseZclInt32(ctx, x, `${indent}Debt Recovery Amount`); parseZclEnum(ctx, 16, x, `${indent}Debt Recovery Balance Percentage`); } function parseZseEmergencyCreditSetup({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclUint(ctx, 32, x, `${indent}Emergency Credit Limit`); parseZclUint(ctx, 32, x, `${indent}Emergency Credit Threshold`); } function parseZseConsumerTopUp({ ctx, x, indent }) { parseZclUint(ctx, 8, x, `${indent}Originating Device`); parseZclUtrn(ctx, x, `${indent}Top Up Code`); } function parseZseCreditAdjustment({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclUint(ctx, 8, x, `${indent}Credit Adjustment Type`); parseZclInt32(ctx, x, `${indent}Credit Adjustment Value`); } function parseZseChangePaymentMode({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Implementation Date Time`); parseZclUint(ctx, 16, x, `${indent}Proposed Payment Control Configuration`, { 0x0497: 'Prepayment mode<br>Suspend Debt Emergency = True<br>Suspend Debt Disabled = True', 0x0097: 'Prepayment mode<br>Suspend Debt Emergency = True<br>Suspend Debt Disabled = False', 0x0c97: 'Prepayment mode<br>Suspend Debt Emergency = False<br>Suspend Debt Disabled = True', 0x0897: 'Prepayment mode<br>Suspend Debt Emergency = False<br>Suspend Debt Disabled = False', 0x0c94: 'Credit mode', }); parseZclInt32(ctx, x, `${indent}Cut Off Value`); } function parseZseGetPrepaySnapshot({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Earliest Start Time`); parseZclUtcTime(ctx, x, `${indent}Latest End Time`); parseZclUint(ctx, 8, x, `${indent}Snapshot Offset`); parseZclBitmap(ctx, 32, x, `${indent}Snapshot Cause`, { 1: 'General' }); } function parseZseGetTopUpLog({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Latest End Time`); parseZclUint(ctx, 8, x, `${indent}Number of Records`); } function parseZseSetLowCreditWarningLevel({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Low Credit Warning Level`); } function parseZseGetDebtRepaymentLog({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Latest End Time`); parseZclUint(ctx, 8, x, `${indent}Number of Debts`); parseZclEnum(ctx, 8, x, `${indent}Debt Type`); } function parseZseSetMaximumCreditLimit({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Implementation Date Time`); parseZclUint(ctx, 32, x, `${indent}Maximum Credit Level`); parseZclUint(ctx, 32, x, `${indent}Maximum Credit Per Top Up`); } function parseZseSetOverallDebtCap({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Implementation Date Time`); parseZclInt32(ctx, x, `${indent}Overall Debt Cap`); } function parseZseChangePaymentModeResponse({ ctx, x, indent, }) { parseZclUint(ctx, 8, x, `${indent}Friendly Credit`); parseZclUint(ctx, 32, x, `${indent}Friendly Credit Calendar ID`); parseZclUint(ctx, 32, x, `${indent}Emergency Credit Limit`); parseZclUint(ctx, 32, x, `${indent}Emergency Credit Threshold`); } function parseZseConsumerTopUpResponse({ ctx, x, indent }) { parseZclUint(ctx, 8, x, `${indent}Result Type`); parseZclInt32(ctx, x, `${indent}Top Up Value`); parseZclUint(ctx, 8, x, `${indent}Source of Top Up`); parseZclInt32(ctx, x, `${indent}Credit Remaining`); } function parseZsePublishTopUpLog({ ctx, x, indent }) { parseZclUint(ctx, 8, x, `${indent}Command Index`); parseZclUint(ctx, 8, x, `${indent}Number of Commands`); for (let i = 1; x.index < x.end; i++) { parseZclUtrn(ctx, x, `${indent}Top Up Code ${i}`); parseZclInt32(ctx, x, `${indent}Top Up Amount ${i}`); parseZclUtcTime(ctx, x, `${indent}Top Up Time ${i}`); } } function parseZsePublishDebtLog({ ctx, x, indent }) { parseZclUint(ctx, 8, x, `${indent}Command Index`); parseZclUint(ctx, 8, x, `${indent}Number of Commands`); for (let i = 1; x.index < x.end; i++) { parseZclUtcTime(ctx, x, `${indent}Collection Time ${i}`); parseZclUint(ctx, 32, x, `${indent}Amount Collected ${i}`); parseZclEnum(ctx, 8, x, `${indent}Debt Type ${i}`); parseZclUint(ctx, 32, x, `${indent}Outstanding Debt ${i}`); } } // ZSE Calendar Cluster function parseZseGetDayProfiles({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUint(ctx, 32, x, `${indent}Issuer Calendar Id`); parseZclUint(ctx, 8, x, `${indent}Start Day Id`); parseZclUint(ctx, 8, x, `${indent}Number of Days`); } function parseZseGetWeekProfiles({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUint(ctx, 32, x, `${indent}Issuer Calendar Id`); parseZclUint(ctx, 8, x, `${indent}Start Week Id`); parseZclUint(ctx, 8, x, `${indent}Number of Weeks`); } function parseZseGetSeasons({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUint(ctx, 32, x, `${indent}Issuer Calendar Id`); } function parseZseGetSpecialDays({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclUint(ctx, 8, x, `${indent}Number of Events`); parseZclCalendarUint(ctx, 8, x, `${indent}Calendar Type`); parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUint(ctx, 32, x, `${indent}Issuer Calendar Id`); } function parseZsePublishCalendar({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUint(ctx, 32, x, `${indent}Issuer Calendar Id`); parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclCalendarUint(ctx, 8, x, `${indent}Calendar Type`); parseZclUint(ctx, 8, x, `${indent}Calendar Time Reference`); parseZclOctetString(ctx, x, `${indent}Calendar Name`); parseZclUint(ctx, 8, x, `${indent}Number of Seasons`); parseZclUint(ctx, 8, x, `${indent}Number of Week Profiles`); parseZclUint(ctx, 8, x, `${indent}Number of Day Profiles`); } function parseZsePublishDayProfile({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUint(ctx, 32, x, `${indent}Issuer Calendar Id`); parseZclUint(ctx, 8, x, `${indent}Day Id`); const entries = parseZclUint(ctx, 8, x, `${indent}Number of Schedule Entries`); parseZclUint(ctx, 8, x, `${indent}Command Index`); parseZclUint(ctx, 8, x, `${indent}Number of Commands`); const calendarType = parseZclCalendarUint(ctx, 8, x, `${indent}Calendar Type`); for (let i = 1; i <= entries; i++) { const dec = (0, common_1.parseNumberLE)(x, 2); let hour = Math.floor(dec / 60); if (hour < 10) hour = '0' + hour; let minute = Math.floor(dec % 60); if (minute < 10) minute = '0' + minute; const time = '' + hour + ':' + minute; (0, context_1.putBytes)(ctx, `${indent}Schedule Entry ${i} Start Time`, (0, util_1.getBytes)(x, 2), time); if (calendarType === 0x00) parseZclUint(ctx, 8, x, `${indent}Price Tier ${i}`); else parseZclUint(ctx, 8, x, `${indent}Friendly Credit Enable ${i}`); } } function parseZsePublishWeekProfile({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUint(ctx, 32, x, `${indent}Issuer Calendar Id`); parseZclUint(ctx, 8, x, `${indent}Week Id`); (0, context_1.putBytes)(ctx, `${indent}Day Id Refs (Monday to Sunday)`, (0, util_1.getBytes)(x, 7)); } function parseZsePublishSeasons({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUint(ctx, 32, x, `${indent}Issuer Calendar Id`); parseZclUint(ctx, 8, x, `${indent}Command Index`); parseZclUint(ctx, 8, x, `${indent}Number of Commands`); for (let i = 1; x.index < x.end; i++) { parseZclDate(ctx, x, `${indent}Season ${i} Start Date`); parseZclUint(ctx, 8, x, `${indent}Season ${i} Week Id Ref`); } } function parseZsePublishSpecialDays({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUint(ctx, 32, x, `${indent}Issuer Calendar Id`); parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclCalendarUint(ctx, 8, x, `${indent}Calendar Type`); const numberOfSpecialDays = parseZclUint(ctx, 8, x, `${indent}Number of Special Days`); parseZclUint(ctx, 8, x, `${indent}Command Index`); parseZclUint(ctx, 8, x, `${indent}Number of Commands`); for (let i = 1; i <= numberOfSpecialDays; i++) { parseZclDate(ctx, x, `${indent}Special Day ${i} Date`); parseZclUint(ctx, 8, x, `${indent}Special Day ${i} Day Id Ref`); } } // ZSE Device Management Cluster function parseZseReportEventConfiguration({ ctx, x, indent }) { parseZclUint(ctx, 8, x, `${indent}Command Index`); parseZclUint(ctx, 8, x, `${indent}Total Commands`); for (let i = 1; x.index < x.end; i++) { parseZclUint(ctx, 16, x, `${indent}Event Id ${i}`); parseZclBitmap(ctx, 8, x, `${indent}Event Configuration ${i}`); } } function parseZsePublishChangeOfTenancy({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclBitmap(ctx, 8, x, `${indent}Tariff Type`); parseZclUtcTime(ctx, x, `${indent}Implementation Date Time`); parseZclBitmap(ctx, 32, x, `${indent}Proposed Tenancy Change Control`); } function parseZsePublishChangeOfSupplier({ ctx, x, indent }) { parseZclUint(ctx, 32, x, `${indent}Current Provider Id`); parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclBitmap(ctx, 8, x, `${indent}Tariff Type`); parseZclUint(ctx, 32, x, `${indent}Proposed Provider Id`); parseZclUtcTime(ctx, x, `${indent}Provider Change Implementation Time`); parseZclBitmap(ctx, 32, x, `${indent}Provider Change Control`); parseZclOctetString(ctx, x, `${indent}Proposed Provider Name`); parseZclOctetString(ctx, x, `${indent}Proposed Provider Contact Details`); } function parseZseRequestNewPasswordResponse({ ctx, x, indent, }) { parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Implementation Date Time`); parseZclUint(ctx, 16, x, `${indent}Duration in Minutes`); parseZclEnum(ctx, 8, x, `${indent}Password Type`); parseZclOctetString(ctx, x, `${indent}Password`); } function parseZseUpdateSiteId({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Site Id Time`); parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclOctetString(ctx, x, `${indent}Site Id`); } function parseZseSetEventConfiguration({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}Start Date Time`); parseZclBitmap(ctx, 8, x, `${indent}Event Configuration`); parseZclEnum(ctx, 8, x, `${indent}Configuration Control`); // Event Configuration Payload (Apply by List) const n = parseZclUint(ctx, 8, x, `${indent}Number of Events`); for (let i = 1; i <= n; i++) { parseZclUint(ctx, 16, x, `${indent}Event Id ${i}`); } } function parseZseGetEventConfiguration({ ctx, x, indent }) { parseZclUint(ctx, 16, x, `${indent}Event Id`); } function parseZseUpdateCin({ ctx, x, indent }) { parseZclUtcTime(ctx, x, `${indent}Issuer Event Id`); parseZclUtcTime(ctx, x, `${indent}CIN Implementation Time`); parseZclUint(ctx, 32, x, `${indent}Provider Id`); parseZclOctetString(ctx, x, `${indent}Customer Id Number`); } // ZSE Event Cluster function parseZseGetEventLog({ ctx, x, indent }) { parseZclBitmap(ctx, 8, x, `${indent}Event Control / Log Id`); parseZclUint(ctx, 16, x, `${indent}Event Id`); parseZclUtcTime(ctx, x, `${indent}Start Time`); parseZclUtcTime(ctx, x, `${indent}End Time`); parseZclUint(ctx, 8, x, `${indent}Number of Events`); parseZclUint(ctx, 16, x, `${indent}Event Offset`); } function parseZseClearEventLogRequest({ ctx, x, indent }) { parseZclBitmap(ctx, 8, x, `${indent}Log Id`); } function parseZsePublishEventLog({ ctx, x, indent }) { parseZclUint(ctx, 16, x, `${indent}Number of Events`); parseZclUint(ctx, 8, x, `${indent}Command Index`); parseZclUint(ctx, 8, x, `${indent}Total Commands`); parseZclBitmap(ctx, 8, x, `${indent}Log Payload Control`); for (let i = 1; x.index < x.end; i++) { parseLogIdBitmap(ctx, 8, x, `${indent}Log Id ${i}`); parseZclUintHex(ctx, 16, x, `${indent}Event Id ${i}`); parseZclUtcTime(ctx, x, `${indent}Event Time ${i}`); parseZclOctetString(ctx, x, `${indent}Event Data ${i}`); } } function parseZseClearEventLogResponse({ ctx, x, indent }) { parseZclBitmap(ctx, 8, x, `${indent}Cleared Event Logs`); } // ZCL Types function parseZclUint(ctx, bits, x, name, values) { let value = 0; const bytes = bits / 8; value = (0, common_1.parseNumberLE)(x, bytes); (0, context_1.putBytes)(ctx, name, (0, util_1.getBytes)(x, bytes), values?.[value] ?? String(value)); return value; } function parseZclUintHex(ctx, bits, x, name) { let value = 0; const bytes = bits / 8; value = (0, common_1.parseNumberLE)(x, bytes); (0, context_1.putBytes)(ctx, name, (0, util_1.getBytes)(x, bytes), '0x' + value.toString(16)); return value; } function getCalendarTypeName(/*int*/ calendarType) { const names = { 0x00: 'Delivered Calendar', 0x01: 'Received Calendar', 0x02: 'Delivered and Received Calendar', 0x03: 'Friendly Credit Calendar', 0x04: 'Auxiliary Load Switch Calendar', }; if (calendarType <= 0x04) return names[calendarType]; else return 'Reserved'; } function parseZclCalendarUint(ctx, bits, x, name) { const bytes = bits / 8; //useless const calendarType = x.input.byte(x.index); (0, context_1.putBytes)(ctx, name, (0, util_1.getBytes)(x, bytes), getCalendarTypeName(calendarType)); return calendarType; } function parseZclInt32(ctx, x, name) { let value = (0, common_1.parseNumberLE)(x, 4); if (value > 0x7fffffff) value -= 0x100000000; (0, context_1.putBytes)(ctx, name, (0, util_1.getBytes)(x, 4), String(value)); return value; } function parseZclOctetString(ctx, x, name) { const leng