Options
All
  • Public
  • Public/Protected
  • All
Menu

elk-message

styled with prettier Greenkeeper badge Travis Coveralls Dev Dependencies

A module for parsing and generating messages for the Elk M1 security system.

Fully* implements the Elk M1 RS232 ASCII protocol revision 1.84 (Feb 26, 2016).

*Section 4.3 describes a message called "Send ASCII String To IP Address", with the command "AP". Upper-case commands are supposed to be responses from the M1, but the documentation for this makes it sound like this is a command that can be sent to the M1. I've decided to include it as a response, but haven't fully implemented it because of the unclear documentation.

Usage

Install with NPM or Yarn

npm install elk-message
// or
yarn add elk-message
import {
  Arm, 
  ArmingLevel, 
  EthernetModuleTest, 
  UnknownElkResponse, 
  parse,
} from 'elk-message';

// Parse a message

const message = parse('16XK2636115020605110006F\r\n');

if (message instanceof EthernetModuleTest) {
  // EthernetModuleTest is sent every 30 seconds by the M1
  console.log(`M1 ping @ ${message.date}`);
} else if (message instanceof UnknownElkResponse) {
  console.warn(`Recieved unknown command "${message.command}" from M1!`);
}

// Create a message to arm area 1 using code "3456"
const arm = new Arm(ArmingLevel.ArmedAway, 1, '3456');

API

The base interface for all messages sent to or received from the Elk M1 implement ElkMessage.

Messages are either "commands" (ElkCommand) sent to the control panel, or "responses" (ElkResponse) received from it.

See the API documentation for more details on each type of message. Each message in the documentation also includes the section in the protocol specification document where it is officially documented.

Commands

Commands are instantiated directly with specific parameters depending on the type of command. Some commands expect the control panel to return a response, others do not.

  • AlarmByZoneRequest
  • AlarmReportAcknowledge
  • AlarmReportTestAcknowledge
  • Arm
  • ArmingStatusRequest
  • AudioCommandIncoming
  • AudioDataRequest
  • ControlOutputOff
  • ControlOutputOn
  • ControlOutputStatusRequest
  • ControlOutputToggle
  • CounterValueRead
  • CounterValueWrite
  • CustomValueRead
  • CustomValueWrite
  • CustomValuesReadAll
  • DisplayTextOnScreen
  • ElkCommand
  • EthernetModuleTestAcknowledge
  • InsteonLightingDeviceProgramRequest
  • InsteonLightingDeviceStatusRequest
  • KeypadAreaAssigmentsRequest
  • KeypadFunctionKeyPressRequest
  • KeypadFunctionKeyStatusRequest
  • LightingDeviceStatusRequest
  • Omnistat2Request
  • PlcDeviceControl
  • PlcDeviceOff
  • PlcDeviceOn
  • PlcDeviceStatusRequest
  • PlcDeviceToggle
  • RealTimeClockDataRequest
  • RealTimeClockDataWrite
  • SpeakPhrase
  • SpeakWord
  • SystemLogDataReadRequest
  • SystemLogDataWriteRequest
  • SystemTroubleStatusRequest
  • TaskActivation
  • TemperatureDataRequest
  • TemperatureRequest
  • TextDescriptionRequest
  • ThermostatDataRequest
  • ThermostatSet
  • ThermostatSetCoolSetPoint
  • ThermostatSetFan
  • ThermostatSetHeatSetPoint
  • ThermostatSetHold
  • ThermostatSetMode
  • UserCodeAreasRequest
  • UserCodeChangeRequest
  • VersionNumberRequest
  • ZoneBypassRequest
  • ZoneDefinitionRequest
  • ZonePartitionRequest
  • ZoneStatusRequest
  • ZoneTrigger
  • ZoneVoltageRequest

Responses

Responses are parsed from their raw packet data (as described in section 4 of the specification document.

A parse function is exported that will parse a packet and return it's associated response.

import { parse } from 'elk-message';

const dataPacket = '16XK2636115020605110006F';

// parse will return an instance of `EthernetModuleTest`
const ethernetModuleTest = parse(dataPacket);
assert(ethernetModuleTest instanceof EthernetModuleTest);

The parse function will return a UnknownElkResponse if the response type was unknown or could not be determined for some reason (malformed packet, undocumented response, etc...)

  • AlarmByZoneReport
  • AlarmMemoryUpdate
  • AlarmReport
  • AlarmReportTest
  • ArmingStatusReport
  • AudioCommandOutgoing
  • AudioDataReply
  • ControlOutputStatusReport
  • CounterValueReply
  • CustomValueReply
  • ElkResponse
  • ElkRPConnected
  • EmailSendTrigger
  • EntryExitTimer
  • EthernetModuleReset
  • EthernetModuleTest
  • InstallerModeExited
  • InsteonLightingDeviceProgrammed
  • InsteonLightingDeviceStatusReply
  • KeypadAreaAssignments
  • KeypadFunctionKeyPressReply
  • KeypadKeyChange
  • LightingDeviceDataReply
  • Omnistat2Reply
  • OutputChangeUpdate
  • PlcChangeUpdate
  • PlcDeviceStatusReply
  • RealTimeClockDataReply
  • SendASCIIStringToIPAddress
  • SystemLogDataUpdate
  • SystemTroubleStatusReply
  • TaskChangeUpdate
  • TemperatureData
  • TemperatureReply
  • TextDescriptionReply
  • ThermostatData
  • UnknownElkResponse
  • UserCodeAreasReply
  • UserCodeChangeReply
  • UserCodeEntry
  • VersionNumberReply
  • ZoneBypassReply
  • ZoneChangeUpdate
  • ZoneDefinitionData
  • ZonePartitionReport
  • ZoneStatusReport
  • ZoneVoltageData

Index

Enumerations

Classes

Interfaces

Variables

Functions

Object literals

Variables

Const ASCII_REGEX

ASCII_REGEX: RegExp = /^[\x00-\x7F]*$/

Const CHECKSUM_TESTS

CHECKSUM_TESTS: [string, string][] = [['06as00', '66'],['1EAS10000000400000003000000000', '0E'],['16AR123456113401001100', '85'],['07AT100', '73'],['06ar00', '67'],['06az00', '5F'],['0Fcd01020300000', 'AD'],['22IR0014123456ABCDEF987654A1B2C300', '6F'],['22ip0014123456ABCDEF987654A1B2C300', '31'],['47PS0011111111111111100000000000000000000000000000000000000000000000000', '53'],['CCAS10000000400000003000000000', 'FE'],['D6AZ000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000','82']]

Const CHECKSUM_WIDTH

CHECKSUM_WIDTH: 2 = 2

The number of characters used to represent the checksum in a message packet.

see

4.1.6

Const PACKET_LENGTH_WIDTH

PACKET_LENGTH_WIDTH: 2 = 2

The number of characters used to represent the packet length in a message packet.

see

4.1.1

Const PACKET_REGEX

PACKET_REGEX: RegExp = new RegExp(`^(\\S{${PACKET_LENGTH_WIDTH}})(\\S)(\\S)(.*)(\\S{${RESERVED_WIDTH}})(\\S{${CHECKSUM_WIDTH}})(${TERMINATOR}|${TERMINATOR[0]}|${TERMINATOR[1]})$`)

A regex expression that parses a raw message packet and captures:

  1. Packet length
  2. Message type
  3. Sub-message type
  4. Data
  5. Reserved
  6. Checksum
  7. Terminator

Const RESERVED_DEFAULT

RESERVED_DEFAULT: "00" = "00"

The default reserved characters for a message packet.

see

4.1.5

Const RESERVED_WIDTH

RESERVED_WIDTH: number = RESERVED_DEFAULT.length

The number of characters used to represent the reserved portion of a message packet.

see

4.1.5

Const SPLIT_ALL_REGEX

SPLIT_ALL_REGEX: RegExp = /.{1,6}/g

Const SPLIT_CHUNKS_REGEX

SPLIT_CHUNKS_REGEX: RegExp = /.{1,3}/g

Const SPLIT_DEVICE_IDS_REGEX

SPLIT_DEVICE_IDS_REGEX: RegExp = /.{1,6}/g

Const TERMINATOR

TERMINATOR: "" = ""

The message termination characters

see

4.1.7

Const TESTS

TESTS: [string, any][] = [['1EAS100000004000000030000000000E\r\n', ArmingStatusReport],['16AR12345611340100110085\r\n', AlarmReport],['07AT10073\r\n', AlarmReportTest],['16XK2636115020605110006F\r\n', EthernetModuleTest],['D6AZ00000000900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082\r\n',AlarmByZoneReport],['20CA0110205006004010500000000000C1\r\n', AudioDataReply],['0ACC003100E5\r\n', OutputChangeUpdate],['0FCD02030400000EA\r\n', AudioCommandOutgoing],['D6CS0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008F\r\n',ControlOutputStatusReport],['0ECR01001230000F\r\n', CustomValueReply],['09CU005000A\r\n', UserCodeChangeReply],['0DCV0100123003C\r\n', CounterValueReply],['0BDS001990094\r\n', LightingDeviceDataReply],['0FEE10060120100E5\r\n', ExntryExitTimer],['09EM0010014\r\n', EmailSendTrigger],['17IC0000030405060000100CC\r\n', UserCodeEntry],['06IE00AC\r\n', InstallerModeExited],['22IR0014123456ABCDEF987654A1B2C3006F\r\n', InsteonLightingDeviceStatusReply],['16KA12345678111111110081\r\n', KeypadAreaAssignments],['19KC01112010000200000000010\r\n', KeypadKeyChange],['11KF01C200000000087\r\n', KeypadFunctionKeyPressReply],['1CLD1193102119450607001505003F\r\n', SystemLogDataUpdate],['66LW108109000000000000000000000000000000000000000000000000000000000000000000000000000000000000130000007A\r\n',TemperatureData],['0BPCA01000099\r\n', PlcChangeUpdate],['47PS001111111111111110000000000000000000000000000000000000000000000000053\r\n',PlcDeviceStatusReply],['07RE00072\r\n', EthernetModuleReset],['08RP000036\r\n', ElkRPConnected],['16RR0059107251205110006E\r\n', RealTimeClockDataReply],['1BSD01001Front DoorKeypad0089\r\n', TextDescriptionReply],['28SS1000000000000000000000000000000000002F\r\n', SystemTroubleStatusReply],['0CST001135005C\r\n', TemperatureReply],['0ATC001000D7\r\n', TaskChangeUpdate],['13TR01200726875000000\r\n', ThermostatData],['2AT200000000000000000000000000000000000000C7\r\n', Omnistat2Reply],['36VN05010C0103020000000000000000000000000000000000000074\r\n', VersionNumberReply],['19UA123456C30000000041F00CA\r\n', UserCodeAreasReply],['0EAM110000110019\r\n', AlarmMemoryUpdate],['0AZC002200CE\r\n', ZoneChangeUpdate],['0AZB123100CC\r\n', ZoneBypassReply],['D6ZP20800000900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010068\r\n',ZonePartitionReport],['D6ZS20B000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000D0068\r\n',ZoneStatusReport],['D6ZD123456789:;<=>?@ABCDEFGHIJKLMNOPQRST000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000T00CA\r\n',ZoneDefinitionData],['0CZV123072004E\r\n', ZoneVoltageData],['0AIP001400D1\r\n', InsteonLightingDeviceProgrammed],['00ZZ0000000\r\n', UnknownElkResponse]]

Const TWOS_COMPLIMENT_TESTS

TWOS_COMPLIMENT_TESTS: [number, number][] = [[1, 255],[10, 246],[16, 240],[42, 214],[150, 106],[200, 56]]

Const USER_CODE_REGEX

USER_CODE_REGEX: RegExp = /^(0\d)(0\d)(0\d)(0\d)(0\d)(0\d)$/

Matches on a user-entered code.

Functions

calculateChecksum

  • calculateChecksum(input: string): string
  • Calculates the checksum for an elk message.

    see

    {M1-RS232-ASCII-Protocol} 4.1.6

    This is the hexadecimal two’s complement of the modulo-256 sum of the ASCII values of all characters in the message excluding the checksum itself and the CR-LF terminator at the end of the message. Permissible characters are ASCII 0-9 and upper case A-F. When all the characters are added to the Checksum, the value should equal 0.

    Parameters

    • input: string

    Returns string

encodeAreaNumbers

  • encodeAreaNumbers(areaNumbers?: number[]): string
  • Encodes selected area numbers.

    Two ASCII Hex characters, 0-9,A-F, using the Hex value of each character as the mask for 4 areas. Right most character is areas 1 to 4 with bit 0 equal to Area 1.

    Parameters

    • Optional areaNumbers: number[]

      An array of area numbers to encode

    Returns string

    The area numbers encoded as hex.

encodeLineData

  • encodeLineData(input?: string | null): string

generateData

  • generateData(userNumber: number, masterOrCurrentUserCode: string | UserCode, newUserCode: string | UserCode, areaNumbers?: number[]): string

isAscii

  • isAscii(input: string): boolean

numberToHex

  • numberToHex(value: number, width?: number): string
  • Converts a number to it's hexadecimal notation equivalent.

    Parameters

    • value: number

      The number to convert.

    • Default value width: number = 2

      The number of characters to pad the result to.

    Returns string

    A hexidecimal string representing the number provided.

parse

twosComplement

  • twosComplement(value: number): number
  • Returns the two's complement of a value between 0 and 255.

    throws

    {RAngeError} if the value is less than 0 or greater than 255.

    Parameters

    • value: number

      The value to calculate the two's compliment for.

    Returns number

    The two's complement of the value.

versionsToString

  • versionsToString(major: number, minor: number, patch: number): string

Object literals

Const RESPONSE_MAP

RESPONSE_MAP: object

[AlarmByZoneReport.COMMAND]

[AlarmByZoneReport.COMMAND]: AlarmByZoneReport = AlarmByZoneReport

[AlarmMemoryUpdate.COMMAND]

[AlarmMemoryUpdate.COMMAND]: AlarmMemoryUpdate = AlarmMemoryUpdate

[AlarmReport.COMMAND]

[AlarmReport.COMMAND]: AlarmReport = AlarmReport

[AlarmReportTest.COMMAND]

[AlarmReportTest.COMMAND]: AlarmReportTest = AlarmReportTest

[ArmingStatusReport.COMMAND]

[ArmingStatusReport.COMMAND]: ArmingStatusReport = ArmingStatusReport

[AudioCommandOutgoing.COMMAND]

[AudioCommandOutgoing.COMMAND]: AudioCommandOutgoing = AudioCommandOutgoing

[AudioDataReply.COMMAND]

[AudioDataReply.COMMAND]: AudioDataReply = AudioDataReply

[ControlOutputStatusReport.COMMAND]

[ControlOutputStatusReport.COMMAND]: ControlOutputStatusReport = ControlOutputStatusReport

[CounterValueReply.COMMAND]

[CounterValueReply.COMMAND]: CounterValueReply = CounterValueReply

[CustomValueReply.COMMAND]

[CustomValueReply.COMMAND]: CustomValueReply = CustomValueReply

[ElkRPConnected.COMMAND]

[ElkRPConnected.COMMAND]: ElkRPConnected = ElkRPConnected

[EmailSendTrigger.COMMAND]

[EmailSendTrigger.COMMAND]: EmailSendTrigger = EmailSendTrigger

[EntryExitTimer.COMMAND]

[EntryExitTimer.COMMAND]: ExntryExitTimer = EntryExitTimer

[EthernetModuleReset.COMMAND]

[EthernetModuleReset.COMMAND]: EthernetModuleReset = EthernetModuleReset

[EthernetModuleTest.COMMAND]

[EthernetModuleTest.COMMAND]: EthernetModuleTest = EthernetModuleTest

[InstallerModeExited.COMMAND]

[InstallerModeExited.COMMAND]: InstallerModeExited = InstallerModeExited

[InsteonLightingDeviceProgrammed.COMMAND]

[InsteonLightingDeviceProgrammed.COMMAND]: InsteonLightingDeviceProgrammed = InsteonLightingDeviceProgrammed

[InsteonLightingDeviceStatusReply.COMMAND]

[InsteonLightingDeviceStatusReply.COMMAND]: InsteonLightingDeviceStatusReply = InsteonLightingDeviceStatusReply

[KeypadAreaAssignments.COMMAND]

[KeypadAreaAssignments.COMMAND]: KeypadAreaAssignments = KeypadAreaAssignments

[KeypadFunctionKeyPressReply.COMMAND]

[KeypadFunctionKeyPressReply.COMMAND]: KeypadFunctionKeyPressReply = KeypadFunctionKeyPressReply

[KeypadKeyChange.COMMAND]

[KeypadKeyChange.COMMAND]: KeypadKeyChange = KeypadKeyChange

[LightingDeviceDataReply.COMMAND]

[LightingDeviceDataReply.COMMAND]: LightingDeviceDataReply = LightingDeviceDataReply

[Omnistat2Reply.COMMAND]

[Omnistat2Reply.COMMAND]: Omnistat2Reply = Omnistat2Reply

[OutputChangeUpdate.COMMAND]

[OutputChangeUpdate.COMMAND]: OutputChangeUpdate = OutputChangeUpdate

[PlcChangeUpdate.COMMAND]

[PlcChangeUpdate.COMMAND]: PlcChangeUpdate = PlcChangeUpdate

[PlcDeviceStatusReply.COMMAND]

[PlcDeviceStatusReply.COMMAND]: PlcDeviceStatusReply = PlcDeviceStatusReply

[RealTimeClockDataReply.COMMAND]

[RealTimeClockDataReply.COMMAND]: RealTimeClockDataReply = RealTimeClockDataReply

[SendASCIIStringToIPAddress.COMMAND]

[SendASCIIStringToIPAddress.COMMAND]: SendASCIIStringToIPAddress = SendASCIIStringToIPAddress

[SystemLogDataUpdate.COMMAND]

[SystemLogDataUpdate.COMMAND]: SystemLogDataUpdate = SystemLogDataUpdate

[SystemTroubleStatusReply.COMMAND]

[SystemTroubleStatusReply.COMMAND]: SystemTroubleStatusReply = SystemTroubleStatusReply

[TaskChangeUpdate.COMMAND]

[TaskChangeUpdate.COMMAND]: TaskChangeUpdate = TaskChangeUpdate

[TemperatureData.COMMAND]

[TemperatureData.COMMAND]: TemperatureData = TemperatureData

[TemperatureReply.COMMAND]

[TemperatureReply.COMMAND]: TemperatureReply = TemperatureReply

[TextDescriptionReply.COMMAND]

[TextDescriptionReply.COMMAND]: TextDescriptionReply = TextDescriptionReply

[ThermostatData.COMMAND]

[ThermostatData.COMMAND]: ThermostatData = ThermostatData

[UserCodeAreasReply.COMMAND]

[UserCodeAreasReply.COMMAND]: UserCodeAreasReply = UserCodeAreasReply

[UserCodeChangeReply.COMMAND]

[UserCodeChangeReply.COMMAND]: UserCodeChangeReply = UserCodeChangeReply

[UserCodeEntry.COMMAND]

[UserCodeEntry.COMMAND]: UserCodeEntry = UserCodeEntry

[VersionNumberReply.COMMAND]

[VersionNumberReply.COMMAND]: VersionNumberReply = VersionNumberReply

[ZoneBypassReply.COMMAND]

[ZoneBypassReply.COMMAND]: ZoneBypassReply = ZoneBypassReply

[ZoneChangeUpdate.COMMAND]

[ZoneChangeUpdate.COMMAND]: ZoneChangeUpdate = ZoneChangeUpdate

[ZoneDefinitionData.COMMAND]

[ZoneDefinitionData.COMMAND]: ZoneDefinitionData = ZoneDefinitionData

[ZonePartitionReport.COMMAND]

[ZonePartitionReport.COMMAND]: ZonePartitionReport = ZonePartitionReport

[ZoneStatusReport.COMMAND]

[ZoneStatusReport.COMMAND]: ZoneStatusReport = ZoneStatusReport

[ZoneVoltageData.COMMAND]

[ZoneVoltageData.COMMAND]: ZoneVoltageData = ZoneVoltageData

Const ZONE_STATUS_MAP

ZONE_STATUS_MAP: object

0

0: [Normal, Unconfigured] = [ZoneLogicalState.Normal, ZonePhysicalState.Unconfigured]

1

1: [Normal, Open] = [ZoneLogicalState.Normal, ZonePhysicalState.Open]

2

2: [Normal, EOL] = [ZoneLogicalState.Normal, ZonePhysicalState.EOL]

3

3: [Normal, Short] = [ZoneLogicalState.Normal, ZonePhysicalState.Short]

4

4: [Trouble, Unconfigured] = [ZoneLogicalState.Trouble, ZonePhysicalState.Unconfigured]

5

5: [Trouble, Open] = [ZoneLogicalState.Trouble, ZonePhysicalState.Open]

6

6: [Trouble, EOL] = [ZoneLogicalState.Trouble, ZonePhysicalState.EOL]

7

7: [Trouble, Short] = [ZoneLogicalState.Trouble, ZonePhysicalState.Short]

8

8: [Violated, Unconfigured] = [ZoneLogicalState.Violated, ZonePhysicalState.Unconfigured]

9

9: [Violated, Open] = [ZoneLogicalState.Violated, ZonePhysicalState.Open]

A

A: [Violated, EOL] = [ZoneLogicalState.Violated, ZonePhysicalState.EOL]

B

B: [Violated, Short] = [ZoneLogicalState.Violated, ZonePhysicalState.Short]

C

C: [Bypassed, Unconfigured] = [ZoneLogicalState.Bypassed, ZonePhysicalState.Unconfigured]

D

D: [Bypassed, Open] = [ZoneLogicalState.Bypassed, ZonePhysicalState.Open]

E

E: [Bypassed, EOL] = [ZoneLogicalState.Bypassed, ZonePhysicalState.EOL]

F

F: [Bypassed, Short] = [ZoneLogicalState.Bypassed, ZonePhysicalState.Short]

Legend

  • Constructor
  • Property
  • Method
  • Property
  • Method
  • Inherited constructor
  • Inherited property
  • Static property
  • Static method

Generated using TypeDoc