Skip to content

Latest commit

 

History

History
1510 lines (1241 loc) · 87.1 KB

API.md

File metadata and controls

1510 lines (1241 loc) · 87.1 KB

Table of Contents

EmcbUDPbroadcastCoordinator

EmcbUDPbroadcastCoordinator is the primary class exposed by require('emcbUDPcoordinator'). This class manages all UDP traffic to the EMCBs. It facilitates device discovery, EmcbUDPdeviceCoordinator creation and management, and holds the message queues, manages timeouts, etc. for both broadcast and unicast traffic.

In addition to the commands listed below, EmcbUDPbroadcastCoordinator extends the EventEmitter class and makes the events described in EventEmitter Cheat Sheet available to .on(), .once(), etc.

const { EmcbUDPbroadcastCoordinator } = require('emcbUDPcoordinator');
// or
const coordinator0 = require('emcbUDPcoordinator').EmcbUDPbroadcastCoordinator

EmcbUDPbroadcastCoordinator Properties

In addition to the functions described below, an EmcbUDPbroadcastCoordinator instance has the following properties available to access:

  • ipAddress (String): The local network broadcast IP Address used by the instance. This will be set asyncronously if no broadcastIPAddress is provided to the constructor
  • port (Number): The Destination UDP port number used by the instance and all EmcbUDPdeviceCoordinator instances.
  • devices (Object): An object indexed by individual EMCB device IP Addresses, which holds all EmcbUDPdeviceCoordinator instances for the discovered devices.
  • udpSocket (dgram.Socket): The Node.js udp4 Socket used for all local communication on the network.
  • unhandledMessages (Number): Integer number of times that we have received data from the network without an active message to process it against. In other words, this is the number of times EMCBs have provided data beyond the EmcbUDPbroadcastCoordinator instance's timeout for a message.

new EmcbUDPbroadcastCoordinator(args)

Creates an instance of the Broadcast Coordinator object.

  • args (Object)
    • broadcastUDPKey (Buffer): UDP Key for signing/validating all broadcast messages
    • unicastUDPKeys (Object): [Key]: Value pairs for unicast UDP Keys for signing/validating messages
      • $DEVICE_ID (Buffer): UDP Key for signing/validating all unicast messages for the particular device ID.
    • [broadcastIPAddress] (String): Optional broadcast IP address for the coordinator to use.
    • [ifaceName] (String): Optional interface name (i.e. in the keys provided by os.networkInterfaces()) to use as the network interface for UDP traffic. This will only be used if broadcastIPAddress is not provided. If this key is also not provided, the instance will try to determine the "default" network interface via local-ipv4-address (with the caveats described at the link)
    • [port] (String): Optional destination UDP port number to use for all communication. Defaults to EMCB_UDP_PORT.
    • [sequenceNumber] (Number): Optional "Next" Sequence Number that we will use when interacting with this device. Defaults to a random number within the legal UInt32 range of 0 <= x <= 0xFFFFFFFF. This value should be left undefined or retreived from non-volatile memory and set to the last highest sequence number used to maintain cybersecurity.
  • RETURNS instance (EmcbUDPbroadcastCoordinator): an instantiated EmcbUDPbroadcastCoordinator.
const { EmcbUDPbroadcastCoordinator } = require('./emcbUDPcoordinator');

var EMCBs = new EmcbUDPbroadcastCoordinator({
    broadcastUDPKey : Buffer.from("DD4253D8725A02A0C1FA3417D809686FE397CC8148EFF5328CE436644849A225", "hex"),
    unicastUDPKeys  : {
        "30000c2a690c7652" : Buffer.from("01C43A38DF5669F3D410602437EC2EF3DAEB12AED3C7EB3FA192D581D2AB9F20", "hex"),
    }
})

NOTE For the class to do anything useful, you need to provide keys for the devices on your local network gathered from the EMCB Cloud API.

updateBroadcastUDPkey(key)

Updates the broadcast UDP Key provisioned via the EMCB Cloud API.

  • key (Buffer): UDP Key for signing/validating all broadcast messages
const crypto = require("crypto")
EMCBs.updateBroadcastUDPkey(crypto.randomBytes(32))
// Don't expect to find any EMCBs this way due to the VERY low probability of randomly generating an in use key, but the API syntax should work :)

updateUnicastUDPkey(idDevice, key)

Updates the unicast UDP Key for a particular device provisioned via the EMCB Cloud API.

  • idDevice (String): Device ID using the unicast key
  • key (Buffer): UDP Key for signing/validating all unicast messages for this particular device ID.
EMCBs.updateUnicastUDPkey("30000c2a690c7652", Buffer.from("DD4253D8725A02A0C1FA3417D809686FE397CC8148EFF5328CE436644849A225", "hex")

getCoordinatorIPAddress()

Get the EmcbUDPdeviceCoordinator's ipAddress.

  • RETURNS Promise (Object): A promise that resolves with the following data or throws an Error:
    • ipAddress (String): The IP Address of the Coordinator's interface that is being used by the library.
console.log(EMCBs.getDevice("30000c2a690c7652").idDevice)
// 30000c2a690c7652

getDevice(ipAddressOrIdDevice)

Get the EmcbUDPdeviceCoordinator for the specified ipAddress or idDevice, assuming that it has been successfully discovered and is communicating with the EmcbUDPbroadcastCoordinator/EmcbUDPdeviceCoordinator.

  • ipAddressOrIdDevice (String): Local IP Address or Device ID of the device
  • RETURNS [instance] (EmcbUDPdeviceCoordinator | undefined): The EmcbUDPdeviceCoordinator for the given ipAddressOrIdDevice or undefined if none was found.
console.log(EMCBs.getDevice("30000c2a690c7652").idDevice)
// 30000c2a690c7652

discoverDevices([nonce])

Discover EMCBs on the local network using the provisioned UDP broadcast key. This is a convenience wrapper that performs 4 getNextSequenceNumber() commands and returns a Promise that will resolve with the list of all active devices within the EmcbUDPbroadcastCoordinator or reject with an Error if none have been found.

EmcbUDPbroadcastCoordinator will self call this function every 5 minutes to detect any devices that are added to the network.

  • [nonce] (Buffer): Optional 4 byte UInt32 held within a Buffer. Defaults to crypto.random(4). NOTE - nonce should NEVER be provided in production code (as a Cryptographically secure pseudorandom number is the safest thing to use here to prove device authenticity and prevent messages from being replayed) but is included in the API in order to allow developers control over the messages that they send for testing purposes.
  • RETURNS Promise (Object): A promise that resolves with the following data or throws an Error:
    • data (Object):

NOTE - If there are any valid responses, the return Promise will resolve. It will only reject in the event that no devices have ever been discovered. A resolve does NOT guarantee that devices on the network have been discovered.

EMCBs.discoverDevices()
    .then((devices) => {
        console.log("DISCOVER DEVICES COMPLETE - found " + Object.keys(devices).length + " EMCBs")

        var coloredDeviceArray = []

        for(var ipAddress in devices){
            var device = devices[ipAddress]
            coloredDeviceArray.push(chalk[device.chalkColor](device.idDevice));
        }

        console.log(coloredDeviceArray.join(chalk.reset(",")))
    })

// 3000d8c46a572cf2,3000d8c46a572d8a,3000d8c46a572d5c,3000d8c46a572af0,3000d8c46a572c34,3000d8c46a572b08,3000d8c46a572aba,3000d8c46a572b34
// **NOTE** this (and all logs from each specific device) will be colorized in terminals that support ANSI escape codes!

createDevice(idDevice, ipAddress, [unicastGetNextSequenceNumber])]

Creates an EmcbUDPdeviceCoordinator for a given idDevice at a given ipAddress (assuming its UDP Key is provided to new EmcbUDPbroadcastCoordinator(args)).

  • idDevice (String): Device ID.
  • ipAddress (String): The local network IP Address of the device.
  • [unicastGetNextSequenceNumber] (Boolean): Optional true/false to determine if the device's sequence number should be obtained via a unicast message. Defaults to true.
  • RETURNS - device (EmcbUDPdeviceCoordinator): The newly created EmcbUDPdeviceCoordinator instance.

syncDeviceSequenceNumbers()

Sends a unicast - setNextSequenceNumber command to each EmcbUDPdeviceCoordinator instance that the EmcbUDPbroadcastCoordinator has discovered in order to sync their sequence numbers together.

NOTE - this method should NOT be used in most applications. Specifically if you are using the EMCB_UDP_EVENT_QUEUE_DRAINED event for polling (which you should be using), the emcbUDPcoordinator library will automatically take care of keeping device sequence numbers in sync by monitoring for consecutive timeouts from discovered devices.

  • RETURNS Promise (Object): A promise that resolves on success or throws an Error.
EMCBs.syncDeviceSequenceNumbers()

getNextSequenceNumber([nonce])

Gets the next Sequence Number and device ID's of the EMCBs on the local network using the replayable Get Next Expected UDP Sequence Number Command with a sequence number of 0x0000 to facilitate device discovery and synchronization.

  • [nonce] (Buffer): Optional 4 byte UInt32 held within a Buffer. Defaults to crypto.random(4). NOTE - nonce should NEVER be provided in production code (as a Cryptographically secure pseudorandom number is the safest thing to use here to prove device authenticity and prevent messages from being replayed) but is included in the API in order to allow developers control over the messages that they send for testing purposes.
  • RETURNS Promise (Object): A promise that resolves with the following data if there are any valid responses. Otherwise it will throw the same data structure or an instance of an Error.
    • data (Object):
      • responses (Object): Optional object that will contain parsed responses by IP Address for valid responses
        • $IP_ADDRESS (Object):
          • device (EmcbUDPdeviceCoordinator): The EmcbUDPdeviceCoordinator for the response.
          • nextSequenceNumber (Number): UInt32 expected value of the Sequence Number in the next command to the device
          • idDevice (String): Device ID.
          • protocolRevision (): UInt32 protocol revision number.
      • errors (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any encountered errors, excluding timeouts
      • timeouts (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any timeouts

NOTE - If there are any valid responses, the return Promise will resolve. It will only reject in the event that ALL responses are errors or timeouts.

EMCBs.getNextSequenceNumber()
    .then((data) => {
        //data.responses[aParticularIPAddress] = {
        //   idDevice: '3000d8c46a572b08',
        //   nextSequenceNumber: 2286175166,
        //   protocolRevision: 1,
        //   device: {...}
        //  }
    })

getBreakerRemoteHandlePosition()

Gets the Remote Handle Position of the EMCB.

  • RETURNS Promise (Object): A promise that resolves with the following data if there are any valid responses. Otherwise it will throw the same data structure or an instance of an Error.
    • data (Object):
      • responses (Object): Optional object that will contain parsed responses by IP Address for valid responses
        • $IP_ADDRESS (Object):
          • device (EmcbUDPdeviceCoordinator): The EmcbUDPdeviceCoordinator for the response.
          • state (Number): UInt8 code representing the breaker's current Feedback State. One of EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_OPEN, EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_CLOSED, or EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_TOGGLE.
          • stateString (String): A human readable string representing the EMCB state. One of "Open", "Closed", or "Feedback Mismatch".
      • errors (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any encountered errors, excluding timeouts
      • timeouts (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any timeouts

NOTE - If there are any valid responses, the return Promise will resolve. It will only reject in the event that ALL responses are errors or timeouts.

async function logFeedbackState(){
    const feedbackStates = await EMCBs.getBreakerRemoteHandlePosition()

    for(var ipAddress in feedbackStates.responses){
        var device = feedbackStates.responses[ipAddress].device
        console.log(chalk[device.chalkColor](device.idDevice + " Remote Handle Position is " + feedbackStates.responses[ipAddress].stateString))
    }
}

logFeedbackState()
// 30000c2a69113173 Remote Handle Position is Open

getMeterData()

Gets the Current Metering Data for the EMCB.

NOTE - this function will return the data that is transmitted over the wire. However, the data may not be updated within the EMCB HW. It is the responsibility of the user to check the updateNum to determine if the data is "stale" or not. Alternatively, the EMCB_UDP_MESSAGE_CODE_GET_METER_TELEMETRY_DATA Event can be used, which will only be called when the data is fresh.

  • RETURNS Promise (Object): A promise that resolves with the following data if there are any valid responses. Otherwise it will throw the same data structure or an instance of an Error.
    • data (Object):
      • responses (Object): Optional object that will contain parsed responses by IP Address for valid responses
        • $IP_ADDRESS (Object):
          • device (EmcbUDPdeviceCoordinator): The EmcbUDPdeviceCoordinator for the response.
          • updateNum (Number): Integer Update number. Starts at 0 on boot and increments when periodic data is updated on the device.
          • frequency (Number): Integer Line frequency. mHz.
          • period (Number): Integer Period. The Number of milliseconds over which the returned data was accumulated.
          • mJp0 (Number): Int64 Phase 0 Cumulative active energy. milliJoules = milliWatt-Second.
          • mVARsp0 (Number): Int64 Phase 0 Cumulative reactive energy. mVARs.
          • mVAsp0 (Number): UInt64 Phase 0 Cumulative apparent energy. mVAs.
          • LNmVp0 (Number): Integer Phase 0 voltage RMS. mV.
          • mAp0 (Number): Integer Phase 0 current RMS. mA.
          • q1mJp0 (Number): UInt64 Quadrant 1 Phase 0 Cumulative Active energy. mJ.
          • q2mJp0 (Number): UInt64 Quadrant 2 Phase 0 Cumulative Active energy. mJ.
          • q3mJp0 (Number): UInt64 Quadrant 3 Phase 0 Cumulative Active energy. mJ.
          • q4mJp0 (Number): UInt64 Quadrant 4 Phase 0 Cumulative Active energy. mJ.
          • q1mVARsp0 (Number): UInt64 Quadrant 1 Phase 0 Cumulative Reactive energy. mVARs.
          • q2mVARsp0 (Number): UInt64 Quadrant 2 Phase 0 Cumulative Reactive energy. mVARs.
          • q3mVARsp0 (Number): UInt64 Quadrant 3 Phase 0 Cumulative Reactive energy. mVARs.
          • q4mVARsp0 (Number): UInt64 Quadrant 4 Phase 0 Cumulative Reactive energy. mVARs.
          • q1mVAsp0 (Number): UInt64 Quadrant 1 Phase 0 Cumulative Apparent energy. mVAs.
          • q2mVAsp0 (Number): UInt64 Quadrant 2 Phase 0 Cumulative Apparent energy. mVAs.
          • q3mVAsp0 (Number): UInt64 Quadrant 3 Phase 0 Cumulative Apparent energy. mVAs.
          • q4mVAsp0 (Number): UInt64 Quadrant 4 Phase 0 Cumulative Apparent energy. mVAs.
          • mJp1 (Number): Int64 Phase 1 Cumulative active energy. mJ.
          • mVARsp1 (Number): Int64 Phase 1 Cumulative reactive energy. mVARs.
          • mVAsp1 (Number): UInt64 Phase 1 Cumulative apparent energy. mVAs.
          • LNmVp1 (Number): Integer Phase 1 voltage RMS. mV.
          • mAp1 (Number): Integer Phase 1 current RMS. mA.
          • q1mJp1 (Number): UInt64 Quadrant 1 Phase 1 Cumulative Active energy. mJ.
          • q2mJp1 (Number): UInt64 Quadrant 2 Phase 1 Cumulative Active energy. mJ.
          • q3mJp1 (Number): UInt64 Quadrant 3 Phase 1 Cumulative Active energy. mJ.
          • q4mJp1 (Number): UInt64 Quadrant 4 Phase 1 Cumulative Active energy. mJ.
          • q1mVARsp1 (Number): UInt64 Quadrant 1 Phase 1 Cumulative Reactive energy. mVARs.
          • q2mVARsp1 (Number): UInt64 Quadrant 2 Phase 1 Cumulative Reactive energy. mVARs.
          • q3mVARsp1 (Number): UInt64 Quadrant 3 Phase 1 Cumulative Reactive energy. mVARs.
          • q4mVARsp1 (Number): UInt64 Quadrant 4 Phase 1 Cumulative Reactive energy. mVARs.
          • q1mVAsp1 (Number): UInt64 Quadrant 1 Phase 1 Cumulative Apparent energy. mVAs.
          • q2mVAsp1 (Number): UInt64 Quadrant 2 Phase 1 Cumulative Apparent energy. mVAs.
          • q3mVAsp1 (Number): UInt64 Quadrant 3 Phase 1 Cumulative Apparent energy. mVAs.
          • q4mVAsp1 (Number): UInt64 Quadrant 4 Phase 1 Cumulative Apparent energy. mVAs.
          • LLp01mV (Number): Integer Phase-phase voltage RMS. mV.
      • errors (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any encountered errors, excluding timeouts
      • timeouts (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any timeouts

NOTE - If there are any valid responses, the return Promise will resolve. It will only reject in the event that ALL responses are errors or timeouts.

async function logMeterData(){
    const meterData = await EMCBs.getMeterData()

    for(var ipAddress in meterData.responses){
        var data = meterData.responses[ipAddress]
        var device = data.device
        logger.info(chalk[device.chalkColor](`${device.idDevice}: updateNum=${data.updateNum.toString().padStart(3)}, LN-Volts-p0=${(data.LNmVp0/1000.0).toString().padEnd(7, "0")}, LN-Volts-p1=${(data.LNmVp1/1000.0).toString().padEnd(7, "0")}, Amps-p0=${(data.mAp0/1000.0).toString().padStart(7)}, Amps-p1=${(data.mAp1/1000.0).toString().padStart(7)}, Frequency-Hz=${(data.frequency/1000.0).toString().padEnd(6, "0")}`))
    }
}

logMeterData()
// 30000c2a69113173: updateNum=176, LN-Volts-p0=126.133, LN-Volts-p1=126.133, Amps-p0=  0.009, Amps-p1=  0.008, Frequency-Hz=60.030

getDeviceStatus()

Gets the Current Metering Data for the EMCB.

NOTE - this function will return the data that is transmitted over the wire. However, the metering data may not be updated within the EMCB HW. It is the responsibility of the user to check the updateNum to determine if the data is "stale" or not. Alternatively, the EMCB_UDP_MESSAGE_CODE_GET_METER_TELEMETRY_DATA Event can be used, which will only be called when the data is fresh.

  • RETURNS Promise (Object): A promise that resolves with the following data if there are any valid responses. Otherwise it will throw the same data structure or an instance of an Error.
    • data (Object):
      • responses (Object): Optional object that will contain parsed responses by IP Address for valid responses
        • $IP_ADDRESS (Object):
          • device (EmcbUDPdeviceCoordinator): The EmcbUDPdeviceCoordinator for the response.
          • breaker (Object):
            • state (Number): UInt8 code representing the breaker's current Feedback State. One of EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_OPEN, EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_CLOSED, or EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_TOGGLE.
            • stateString (String): A human readable string representing the EMCB state. One of "Open", "Closed", or "Feedback Mismatch".
          • meter (Object):
            • updateNum (Number): Integer Update number. Starts at 0 on boot and increments when periodic data is updated on the device.
            • frequency (Number): Integer Line frequency. mHz.
            • period (Number): Integer Period. The Number of seconds over which the returned was accumulated. // was a UInt8 in protocol version 1.07
            • mJp0 (Number): Int64 Phase 0 Cumulative active energy. milliJoules = milliWatt-Second.
            • mVARsp0 (Number): Int64 Phase 0 Cumulative reactive energy. mVARs.
            • mVAsp0 (Number): UInt64 Phase 0 Cumulative apparent energy. mVAs.
            • LNmVp0 (Number): Integer Phase 0 voltage RMS. mV.
            • mAp0 (Number): Integer Phase 0 current RMS. mA.
            • q1mJp0 (Number): UInt64 Quadrant 1 Phase 0 Cumulative Active energy. mJ.
            • q2mJp0 (Number): UInt64 Quadrant 2 Phase 0 Cumulative Active energy. mJ.
            • q3mJp0 (Number): UInt64 Quadrant 3 Phase 0 Cumulative Active energy. mJ.
            • q4mJp0 (Number): UInt64 Quadrant 4 Phase 0 Cumulative Active energy. mJ.
            • q1mVARsp0 (Number): UInt64 Quadrant 1 Phase 0 Cumulative Reactive energy. mVARs.
            • q2mVARsp0 (Number): UInt64 Quadrant 2 Phase 0 Cumulative Reactive energy. mVARs.
            • q3mVARsp0 (Number): UInt64 Quadrant 3 Phase 0 Cumulative Reactive energy. mVARs.
            • q4mVARsp0 (Number): UInt64 Quadrant 4 Phase 0 Cumulative Reactive energy. mVARs.
            • q1mVAsp0 (Number): UInt64 Quadrant 1 Phase 0 Cumulative Apparent energy. mVAs.
            • q2mVAsp0 (Number): UInt64 Quadrant 2 Phase 0 Cumulative Apparent energy. mVAs.
            • q3mVAsp0 (Number): UInt64 Quadrant 3 Phase 0 Cumulative Apparent energy. mVAs.
            • q4mVAsp0 (Number): UInt64 Quadrant 4 Phase 0 Cumulative Apparent energy. mVAs.
            • mJp1 (Number): Int64 Phase 1 Cumulative active energy. mJ.
            • mVARsp1 (Number): Int64 Phase 1 Cumulative reactive energy. mVARs.
            • mVAsp1 (Number): UInt64 Phase 1 Cumulative apparent energy. mVAs.
            • LNmVp1 (Number): Integer Phase 1 voltage RMS. mV.
            • mAp1 (Number): Integer Phase 1 current RMS. mA.
            • q1mJp1 (Number): UInt64 Quadrant 1 Phase 1 Cumulative Active energy. mJ.
            • q2mJp1 (Number): UInt64 Quadrant 2 Phase 1 Cumulative Active energy. mJ.
            • q3mJp1 (Number): UInt64 Quadrant 3 Phase 1 Cumulative Active energy. mJ.
            • q4mJp1 (Number): UInt64 Quadrant 4 Phase 1 Cumulative Active energy. mJ.
            • q1mVARsp1 (Number): UInt64 Quadrant 1 Phase 1 Cumulative Reactive energy. mVARs.
            • q2mVARsp1 (Number): UInt64 Quadrant 2 Phase 1 Cumulative Reactive energy. mVARs.
            • q3mVARsp1 (Number): UInt64 Quadrant 3 Phase 1 Cumulative Reactive energy. mVARs.
            • q4mVARsp1 (Number): UInt64 Quadrant 4 Phase 1 Cumulative Reactive energy. mVARs.
            • q1mVAsp1 (Number): UInt64 Quadrant 1 Phase 1 Cumulative Apparent energy. mVAs.
            • q2mVAsp1 (Number): UInt64 Quadrant 2 Phase 1 Cumulative Apparent energy. mVAs.
            • q3mVAsp1 (Number): UInt64 Quadrant 3 Phase 1 Cumulative Apparent energy. mVAs.
            • q4mVAsp1 (Number): UInt64 Quadrant 4 Phase 1 Cumulative Apparent energy. mVAs.
            • LLp01mV (Number): Integer Phase-phase voltage RMS. mV.
      • errors (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any encountered errors, excluding timeouts
      • timeouts (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any timeouts

NOTE - If there are any valid responses, the return Promise will resolve. It will only reject in the event that ALL responses are errors or timeouts.

async function logDeviceStatus(){
    const data = await EMCBs.getDeviceStatus()

    for(var ipAddress in data.responses){
        var status = data.responses[ipAddress]
        var device = status.device
        logger.info(chalk[device.chalkColor](`${device.idDevice}: Breaker State=${status.breaker.stateString}.  Meter Data: updateNum=${status.meter.updateNum.toString().padStart(3)}, LN-Volts-p0=${(status.meter.LNmVp0/1000.0).toString().padEnd(7, "0")}, LN-Volts-p1=${(status.meter.LNmVp1/1000.0).toString().padEnd(7, "0")}, Amps-p0=${(status.meter.mAp0/1000.0).toString().padStart(7)}, Amps-p1=${(status.meter.mAp1/1000.0).toString().padStart(7)}, Frequency-Hz=${(status.meter.frequency/1000.0).toString().padEnd(6, "0")}`))
    }
}

logDeviceStatus()
// 40000c2a69113173: Breaker State=Open.  Meter Data: updateNum=178, LN-Volts-p0=126.164, LN-Volts-p1=126.164, Amps-p0=   0.01, Amps-p1=  0.009, Frequency-Hz=60.030

setNextSequenceNumber(desiredNextSequenceNumber)

Sets the next Sequence Number to be used by the EMCBs. In order for this command to work, the getNextSequenceNumber must have successfully be ran for the EMCB in order for the library to know the Sequence Number that the device will currently accept.

NOTE - this method should NOT be used in most applications. Specifically if you are using the EMCB_UDP_EVENT_QUEUE_DRAINED event for polling (which you should be using), the emcbUDPcoordinator library will automatically take care of keeping device sequence numbers in sync by monitoring for consecutive timeouts from discovered devices.

  • desiredNextSequenceNumber (Number): The desired UInt32 value for the next Sequence Number between 0 and 0xFFFFFFFF.
  • RETURNS Promise (Object): A promise that resolves with the following data if ALL responses are valid. Otherwise, it will throw the same data structure or an instance of anError.
    • data (Object):
      • responses (Object): Optional object that will contain parsed responses by IP Address for valid responses
        • $IP_ADDRESS (Object):
          • device (EmcbUDPdeviceCoordinator): The EmcbUDPdeviceCoordinator for the response.
          • ack (Number): UInt8 ACK code provided by the device. A value of EMCB_UDP_ACK means the command was executed and the breaker confirmed it is in in desired state. Any other value is a NACK (and is likely enumerated as an EMCB_UDP_SET_NEXT_SEQUENCE_NUMBER_* Enum).
          • ackString (String | undefined): A human readable string representing ack value. One of "Acknowledged", "Rate Limited", "Bad Sequence Number", or undefined.
          • nextSequenceNumber (Number | undefined): UInt32 expected value of the Sequence Number in the next command to the device. This value will only be set if ack === EMCB_UDP_ACK.
      • errors (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any encountered errors, excluding timeouts
      • timeouts (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any timeouts

NOTE - The return Promise will resolve ONLY if all requests are successful. It will reject if ANY responses are errors or timeouts.

EMCBs.setNextSequenceNumber(crypto.randomBytes(4).readUInt32LE(0))

setBreakerState(desiredState[, maxAttempts])

Sets the desired breaker state. Will attempt to send the command successfully up to maxAttempts times (defaults to 3).

  • desiredState (ENUM): One of the following constants: EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_OPEN, EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_CLOSED, or EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_TOGGLE
  • maxAttempts (Number): Optional maximum number of attempts to set the breaker state. Defaults to 3 and allows values from 1-10.
  • RETURNS Promise (Object): A promise that resolves with the following data if ALL responses are valid. Otherwise, it will throw the same data structure or an instance of anError.
    • data (Object):
      • responses (Object): Optional object that will contain parsed responses by IP Address for valid responses
        • $IP_ADDRESS (Object):
          • device (EmcbUDPdeviceCoordinator): The EmcbUDPdeviceCoordinator for the response.
          • ack (Number): UInt8 ACK code provided by the device. A value of EMCB_UDP_ACK means the command was executed and the breaker confirmed it is in in desired state. Any other value is a NACK.
          • state (Number): UInt8 code representing the breaker's current Feedback State. One of EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_OPEN, EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_CLOSED, or EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_TOGGLE.
          • stateString (String): A human readable string representing the EMCB state. One of "Open", "Closed", or "Feedback Mismatch".
      • errors (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any encountered errors, excluding timeouts
      • timeouts (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any timeouts

NOTE - The return Promise will resolve ONLY if all requests are successful. It will reject if ANY responses are errors or timeouts.

function onSuccess(data, logger = console.log){
    var responses = []
    var errors = []
    var timeouts = []

    for(var ipAddress in data.responses){
        var device = data.responses[ipAddress].device
        data.responses[ipAddress].device = device.idDevice
        responses.push(chalk[device.chalkColor](util.inspect(data.responses[ipAddress])))
    }

    for(var ipAddress in data.timeouts){
        var errorString = data.timeouts[ipAddress].message
        var device = data.timeouts[ipAddress].device
        timeouts.push(chalk[device.chalkColor](device.idDevice + " - " + errorString))
    }

    for(var ipAddress in data.errors){
        var errorString = data.errors[ipAddress].message
        var device = data.errors[ipAddress].device
        errors.push(chalk[device.chalkColor](device.idDevice + " - " + errorString))
    }


    // Sort for consistent rainbow colors!
    responses.sort()
    errors.sort()
    timeouts.sort()

    var responseStr = responses.length > 0 ? chalk.reset("\nResponses:\n") + responses.join(chalk.reset(',\n')) : ""
    var errorStr = errors.length > 0 ? chalk.reset("\nErrors:\n") + errors.join(chalk.reset(',\n')) : ""
    var timeoutStr = timeouts.length > 0 ? chalk.reset("\nTimeouts:\n") + timeouts.join(chalk.reset(',\n')) : ""

    logger(responseStr + errorStr + timeoutStr + '\n')
}

function onError(err){
    onSuccess(err, console.error)
}

//3-shot Open
EMCBs.setBreakerState(EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_OPEN, 3).then(onSuccess).catch(onError)

// 1-shot Close
EMCBs.setBreakerState(EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_CLOSED, 1).then(onSuccess).catch(onError)

// 3-shot Toggle
EMCBs.setBreakerState(EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_TOGGLE).then(onSuccess).catch(onError)

// 3-shot Open to a specific device
EMCBs.getDevice("30000c2a690c7652").setBreakerState(EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_OPEN, 3).then(onSuccess).catch(onError)

setBargraphLEDToUserDefinedColor(enabled[, colorObj, blinking])

Set the EMCB Bargraph LEDs to specific color. This is a convenience function which leverages setBargraphLEDToUserDefinedColor under the hood.

  • enabled (Boolean): Controls if the User Defined Color control of the bargraph is enabled. If set to false, the Bargraph will return to normal operation and all other arguments will be ignored
  • colorObj (Array): An optional 5 element array containing the colors for each individual rgb segment of the Bargraph LEDs. Element 0 is the LED closest to the "bump" on the EMCB.
    • [0] (Object):
      • [red] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [green] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [blue] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [blinking] (Boolean) An optional value to control if the LED segment should blink or not.
    • [1] (Object):
      • [red] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [green] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [blue] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [blinking] (Boolean) An optional value to control if the LED segment should blink or not.
    • [2] (Object):
      • [red] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [green] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [blue] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [blinking] (Boolean) An optional value to control if the LED segment should blink or not.
    • [3] (Object):
      • [red] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [green] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [blue] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [blinking] (Boolean) An optional value to control if the LED segment should blink or not.
    • [4] (Object):
      • [red] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [green] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [blue] (Number): An optional UInt8 value (0-255) controlling the brightness for this led. Defaults to 0
      • [blinking] (Boolean) An optional value to control if the LED segment should blink or not.
  • duration (Number): Optional Integer with a value of 0 (the bargraph will stay this color until unset by the UDP API) or from 1-10737418 seconds that the bargraph will stay the set color. Defaults to 5 seconds.
  • RETURNS Promise (Object): A promise that resolves with the following data if ALL responses are valid. Otherwise, it will throw the same data structure or an instance of anError.
    • data (Object):
      • responses (Object): Optional object that will contain parsed responses by IP Address for valid responses
        • $IP_ADDRESS (Object):
          • device (EmcbUDPdeviceCoordinator): The EmcbUDPdeviceCoordinator for the response.
          • ack (Number): UInt8 ACK code provided by the device. A value of EMCB_UDP_ACK means the command was executed and the breaker confirmed it is in in desired state. Any other value is a NACK.
        • errors (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any encountered errors, excluding timeouts
        • $IP_ADDRESS (Error): An Error object describing the error.
      • timeouts (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any timeouts

NOTE - The return Promise will resolve ONLY if all requests are successful. It will reject if ANY responses are errors or timeouts.

var colorObj = new Array(5);
var color = {red: 0, green: 0, blue: 255, blinking: true},
colorObj.fill(color, 1, 4)

// Set the center 3 LEDs of the EMCB to blink blue until commanded differently
EMCBs.setBargraphLEDToUserDefinedColor(true, colorObj, 0)

setBargraphLEDToUserDefinedColorName(colorName[, duration, blinking])

Set the EMCB Bargraph LEDs to a specific named color. This is a convenience function which leverages setBargraphLEDToUserDefinedColor under the hood.

  • colorName (String): The named color to set the bargraph to. The library looks up colors using color-name-list. additionally, it supports all valid chalk colors as well as "off", "clear", and "reset" to disable the User Defined Color.
  • duration (Number): Optional Integer with a value of 0 (the bargraph will stay this color until unset by the UDP API) or from 1-10737418 seconds that the bargraph will stay the set color. Defaults to 5 seconds.
  • blinking (Boolean): Optional value to blink the LEDs on the EMCB.
  • RETURNS Promise (Object): A promise that resolves with the following data if ALL responses are valid. Otherwise, it will throw the same data structure or an instance of anError.
    • data (Object):
      • responses (Object): Optional object that will contain parsed responses by IP Address for valid responses
        • $IP_ADDRESS (Object):
          • device (EmcbUDPdeviceCoordinator): The EmcbUDPdeviceCoordinator for the response.
          • ack (Number): UInt8 ACK code provided by the device. A value of EMCB_UDP_ACK means the command was executed and the breaker confirmed it is in in desired state. Any other value is a NACK.
        • errors (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any encountered errors, excluding timeouts
        • $IP_ADDRESS (Error): An Error object describing the error.
      • timeouts (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any timeouts

NOTE - The return Promise will resolve ONLY if all requests are successful. It will reject if ANY responses are errors or timeouts.

for(var ipAddress in EMCBs.devices){
    var device = EMCBs.devices[ipAddress]

    // Blink the EMCB bargraph to the same color as what we are logging for 10 seconds!
    device.setBargraphLEDToUserDefinedColorName(device.chalkColor, 10, true)
}

getEvseAppliedControlSettings()

Gets the currently applied EVSE control settings (enabled, authorized, maxCurrentAmps, maxEnergyWatts). More information here

  • RETURNS Promise (Object): A promise that resolves with the following data if there are any valid responses. Otherwise it will throw the same data structure or an instance of an Error.
    • data (Object):
      • responses (Object): Optional object that will contain parsed responses by IP Address for valid responses
        • $IP_ADDRESS (Object):
          • device (EmcbUDPdeviceCoordinator): The EmcbUDPdeviceCoordinator for the response.
          • enabled (Number): UInt8 code representing if charging is enabled (0 for disabled, 1 for enabled, 255 for internal error). More information here
          • authorized (Number): UInt8 code representing if charging is authorized (0 for disabled, 1 for enabled, 255 for internal error). More information here
          • maxCurrentAmps (Number): The maximum current as a UInt8 the EV is allowed to consume in Amps. (0 for no configured limit (will use charger's max rating of 32Amps), 6 to 32 (inclusive) are valid current values)
          • maxEnergyWatts (Number): The maximum energy as an Int32 the EV is allowed to consume in watts. (0 for no configured limit, 1 to 200000 (inclusive) are valid energy values)
      • errors (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any encountered errors, excluding timeouts
      • timeouts (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any timeouts

NOTE - If there are any valid responses, the return Promise will resolve. It will only reject in the event that ALL responses are errors or timeouts.

async function logCurrentlyAppliedEvseControlSettings(){
    const controlSettings = await EMCBs.getEvseAppliedControlSettings()

    for(var ipAddress in controlSettings.responses){
        var response = controlSettings.responses[ipAddress];
        var device = response.device;
        var settingsString = "enabled: " + response.enabled + ", authorized: " + response.authorized + ", maxCurrentAmps: " + response.maxCurrentAmps + ", maxEnergyWatts: " + response.maxEnergyWatts;
        console.log(chalk[device.chalkColor](device.idDevice + " EVSE control settings:  " + settingsString));
    }
}

logCurrentlyAppliedEvseControlSettings()
// 30000c2a69113173 EVSE control settings:  enabled: 1, authorized: 1, maxCurrentAmps: 32, maxEnergyWatts: 0

getEvseDeviceState()

Gets the EVSE device state (state, permanentError, errorCode, errorData).

  • RETURNS Promise (Object): A promise that resolves with the following data if there are any valid responses. Otherwise it will throw the same data structure or an instance of an Error.
    • data (Object):
      • responses (Object): Optional object that will contain parsed responses by IP Address for valid responses
        • $IP_ADDRESS (Object):
          • device (EmcbUDPdeviceCoordinator): The EmcbUDPdeviceCoordinator for the response.
          • state (Number): J1772 EVSE state as a UInt8, (0 is "A", 1 is "B1", 2 is "B2", 3 is "C", 4 is "E", 5 is "F", 255 for internal error) See state explanations here
          • permanentError (Number): UInt8 code representing if EVSE has a permanent error (0 for no, 1 for yes, 255 for internal error).,
          • errorCode (Number): EVSE error code as a UInt8 see error code list here,
          • errorData (Array): Array of 4 UInt16s that contain additional data relating to the error. This data is not currenly documented, but it can help Eaton technical support diagnose issues.
      • errors (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any encountered errors, excluding timeouts
      • timeouts (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any timeouts

NOTE - If there are any valid responses, the return Promise will resolve. It will only reject in the event that ALL responses are errors or timeouts.

async function logEvseDeviceState(){
    const deviceState = await EMCBs.getEvseDeviceState()

    for(var ipAddress in deviceState.responses){
        var response = deviceState.responses[ipAddress];
        var device = response.device;
        var stateString = "state: " + response.state + ", permanentError: " + response.permanentError + ", errorCode: " + response.errorCode + ", errorData: " + util.inspect(response.errorData);
        console.log(chalk[device.chalkColor](device.idDevice + " EVSE device state:  " + stateString));
    }
}

logEvseDeviceState()
// 30000c2a69113173 EVSE device state:  enabled: 3, permanentError: 0, errorCode: 0, errorData: [0,0,0,0]

getEvseConfigSettingsAndMode()

Gets the EVSE configuration settings and EVSE charge mode (mode, offlineMode, apiConfiguration). More information here

  • RETURNS Promise (Object): A promise that resolves with the following data if there are any valid responses. Otherwise it will throw the same data structure or an instance of an Error.
    • data (Object):
      • responses (Object): Optional object that will contain parsed responses by IP Address for valid responses
        • $IP_ADDRESS (Object):
          • device (EmcbUDPdeviceCoordinator): The EmcbUDPdeviceCoordinator for the response.
          • mode (Number): UInt8 code representing the charge mode (1 : "no-restrictions", 2 : "offline-no-restrictions", 3 : "manual-override", 4 : "cloud-api", 5 : "charge-windows", 6 : "api-override-enable", 7 : "api-override-disable", 8 : "ocpp",). More information here
          • offlineMode (Number): UInt8 code representing the charging behavior when connection to the cloud is lost (1 : "no-restrictions", 2 : "no-change"). More information here
          • apiConfiguration (Object): Object that contains the configuration settings to be used while mode is "cloud-api" More information here
            • enabled (Number): UInt8 code representing if charging is enabled (0 for disabled, 1 for enabled, 255 for internal error). More information here
            • maxCurrentAmps (Number): The maximum current as a UInt8 the EV is allowed to consume in Amps. (0 for no configured limit (will use charger's max rating of 32Amps), 6 to 32 (inclusive) are valid current values)
            • maxEnergyWatts (Number): The maximum energy as an Int32 the EV is allowed to consume in watts. (0 for no configured limit, 1 to 200000 (inclusive) are valid energy values)
      • errors (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any encountered errors, excluding timeouts
      • timeouts (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any timeouts

NOTE - If there are any valid responses, the return Promise will resolve. It will only reject in the event that ALL responses are errors or timeouts.

async function logEvseConfigSettingsAndMode(){
    const settings = await EMCBs.getEvseConfigSettingsAndMode()

    for(var ipAddress in settings.responses){
        var response = settings.responses[ipAddress];
        var device = response.device;
        var stateString = "mode: " + response.mode + ", offlineMode: " + response.offlineMode + ", apiConfiguration: " + util.inspect(response.apiConfiguration);
        console.log(chalk[device.chalkColor](device.idDevice + " EVSE configuration settings and mode:  " + stateString));
    }
}

logEvseConfigSettingsAndMode()
// 30000c2a69113173 EVSE device mode: 1, offlineMode: 1, apiConfiguration: { "enabled" : 1, "maxCurrentAmps" : 32, "maxEnergyWatts" : 0 }

patchEvseConfigSettingsAndMode(options)

Sets the EVSE configuration settings and EVSE charge mode (mode, offlineMode, apiConfiguration). Note: not available while in OCPP mode. More information here

Warning: the device will wait until the new settings are applied before sending an ack. However it can take a bit longer for the internal state to update. This means that if you try to call getEvseAppliedControlSettings(), getEvseDeviceState(), or getEvseConfigSettingsAndMode immediently afterwards you may get older data. Currently the recommendation is to wait at least 2 seconds after receiving a reply before sending any of those commands to the same device. If you do not wait, it shouldn't cause any issues for the device, but it could confuse your program if not properly accounted for.

  • options (Object): configuration object. All keys are optional and any undefined values will not modify the existing value on the device
    • mode (Number): UInt8 code representing the charge mode (1 : "no-restrictions", 4 : "cloud-api", 5 : "charge-windows", 6 : "api-override-enable", 7 : "api-override-disable"). More information here
    • offlineMode (Number): UInt8 code representing the charging behavior when connection to the cloud is lost (1 : "no-restrictions", 2 : "no-change"). More information here
    • apiConfiguration (Object): Object that contains the configuration settings to be used while mode is "cloud-api" More information here
      • enabled (Number): UInt8 code representing if charging is enabled (0 for disabled, 1 for enabled, 255 for internal error). More information here
      • maxCurrentAmps (Number): The maximum current as a UInt8 the EV is allowed to consume in Amps. (0 for no configured limit (will use charger's max rating of 32Amps), 6 to 32 (inclusive) are valid current values)
      • maxEnergyWatts (Number): The maximum energy as an Int32 the EV is allowed to consume in watts. (0 for no configured limit, 1 to 200000 (inclusive) are valid energy values)
  • RETURNS Promise (Object): A promise that resolves with the following data if ALL responses are valid. Otherwise, it will throw the same data structure or an instance of anError.
    • data (Object):
      • responses (Object): Optional object that will contain parsed responses by IP Address for valid responses
        • $IP_ADDRESS (Object):
          • device (EmcbUDPdeviceCoordinator): The EmcbUDPdeviceCoordinator for the response.
          • ack (Number): UInt8 ACK code provided by the device. A value of EMCB_UDP_ACK means the command was executed and the breaker confirmed it is in in desired state. Any other value is a NACK.
        • errors (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any encountered errors, excluding timeouts
        • $IP_ADDRESS (Error): An Error object describing the error.
      • timeouts (Object): Optional object that will contain Error objects decorated with an additional device property, which is the relevant EmcbUDPdeviceCoordinator, by IP Address for any timeouts

NOTE - The return Promise will resolve ONLY if all requests are successful. It will reject if ANY responses are errors or timeouts.

for (var ipAddress in EMCBs.devices) {
    var device = EMCBs.devices[ipAddress];

    if (device.idDevice % 2 === 0) {
        device.patchEvseConfigSettingsAndMode({
            mode: "cloud-api",
            offlineMode: "no-change",
            apiConfiguration: {
                enabled: true,
                restrictions: {
                    maxCurrent: 32,
                    maxEnergy: 0
                }
            }
        })
    }
    else {
        device.patchEvseConfigSettingsAndMode({
            apiConfiguration: {
                restrictions: {
                    maxCurrent: 16,
                }
            }
        })
    }
}

EmcbUDPdeviceCoordinator

The EmcbUDPdeviceCoordinator exposes the same functionality as the EmcbUDPbroadcastCoordinator, but unicasts each command to a specific device/IP address rather than using the broadcast IP address. In addition to the commands listed below, EmcbUDPdeviceCoordinator also extends the EventEmitter class and makes the events described in EventEmitter Cheat Sheet available to .on(), .once(), etc.

Instances of this class are created and managed by the EmcbUDPbroadcastCoordinator (rather than being created directly) as a part of the Device Discovery process (and more accurately during getNextSequenceNumber responses). The instances can be obtained using the getDevice function or by accessing the EmcbUDPbroadcastCoordinator.devices property directly by the device's IP Address.

The following commands from the EmcbUDPbroadcastCoordinator are NOT available in EmcbUDPdeviceCoordinator instances:

These commands are identical to the EmcbUDPbroadcastCoordinator, except that they unicast the command to the specific idDevice ipAddress instead of broadcasting on the broadcast address

EmcbUDPdeviceCoordinator Properties

In addition to the functions listed above, an EmcbUDPdeviceCoordinator has 4 additional properties that are NOT available in EmcbUDPbroadcastCoordinator instances:

  • chalkColor (string): This is a color assigned to the device from the EMCB_UDP_DEVICE_COLORS array during EmcbUDPdeviceCoordinator instantiation. It can be used with chalk to help colorize logs.
  • idDevice (string): Device ID of the device
  • remoteHandlePosition (Number): UInt8 code representing the breaker's current Feedback State. One of EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_OPEN, EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_CLOSED, or EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_TOGGLE.
  • meterData (object): The latest meter data that has been obtained from the device. Identical to the return data.responses[$IP_ADDRESS] in getMeterData.

EventEmitter Cheat Sheet

Both EmcbUDPbroadcastCoordinator and EmcbUDPdeviceCoordinator extend the EventEmitter class. The following code will register for every event and provides some commentary for the circumstances under which events get called.

// Called whenever there is a response to a GET_NEXT_SEQUENCE_NUMBER command
EMCBs.on(EMCB_UDP_MESSAGE_CODE_GET_NEXT_SEQUENCE_NUMBER, data => {
    logger.info(chalk[data.device.chalkColor](`Sequence Number updated to 0x${data.nextSequenceNumber.toString(16).toUpperCase()} = ${data.nextSequenceNumber}`))
})

// Called whenever there is a response to a GET_DEVICE_STATUS command that contains fresh data
EMCBs.on(EMCB_UDP_MESSAGE_CODE_GET_DEVICE_STATUS, data => {
    logger.info(chalk[data.device.chalkColor](`Received GET_DEVICE_STATUS response from ${data.device.ipAddress} with Device ID ${data.device.idDevice}`))
})

// Called whenever the breaker feedback position changes - could be from a GET_BREAKER_REMOTE_HANDLE_POSITION, GET_DEVICE_STATUS, or SET_BREAKER_REMOTE_HANDLE_POSITION command)
EMCBs.on(EMCB_UDP_MESSAGE_CODE_GET_BREAKER_REMOTE_HANDLE_POSITION, function(data){
    logger.info(chalk[data.device.chalkColor](`Breaker Feedback Position changed from ${data.lastState} to ${data.state}`))
})

// Called whenever there is new EMCB Meter data (as detected by seeing an update to updateNum) - could be GET_DEVICE_STATUS or GET_METER_TELEMETRY_DATA
EMCBs.on(EMCB_UDP_MESSAGE_CODE_GET_METER_TELEMETRY_DATA, function(data){
    if(data.updateNum%5 === 0){
        logger.info(chalk[data.device.chalkColor](`${data.device.idDevice}: updateNum=${data.updateNum.toString().padStart(3)}, LN-Volts-p0=${(data.LNmVp0/1000.0).toString().padEnd(7, "0")}, LN-Volts-p1=${(data.LNmVp1/1000.0).toString().padEnd(7, "0")}, Amps-p0=${(data.mAp0/1000.0).toString().padStart(7)}, Amps-p1=${(data.mAp1/1000.0).toString().padStart(7)}, Frequency-Hz=${(data.frequency/1000.0).toString().padEnd(6, "0")}`))
    }
})

// Listening to an individual device instead of ALL devices works just fine too :)
// EMCBs.getDevice("10.130.116.50").on(EMCB_UDP_MESSAGE_CODE_GET_METER_TELEMETRY_DATA, function(meterData){
//     console.log(meterData)
// })

// Called for every successful SET_NEXT_SEQUENCE_NUMBER command
EMCBs.on(EMCB_UDP_MESSAGE_CODE_SET_NEXT_SEQUENCE_NUMBER, data => {
    logger.info(chalk[data.device.chalkColor](`SET_NEXT_SEQUENCE_NUMBER response "${data.ackString}" from ${data.device.ipAddress} with Device ID ${data.device.idDevice}.${data.ack === EMCB_UDP_ACK ? ` Sequence Number updated to 0x${data.nextSequenceNumber.toString(16).toUpperCase()} = ${data.nextSequenceNumber}` : ""}`))
})

// Called for every successful SET_BREAKER_REMOTE_HANDLE_POSITION command
EMCBs.on(EMCB_UDP_MESSAGE_CODE_SET_BREAKER_REMOTE_HANDLE_POSITION, data => {
    logger.info(chalk[data.device.chalkColor](`SET_BREAKER_REMOTE_HANDLE_POSITION command succeeded!`))
})

// Called for every successful SET_BARGRAPH_LED_TO_USER_DEFINED
EMCBs.on(EMCB_UDP_MESSAGE_CODE_SET_BARGRAPH_LED_TO_USER_DEFINED, data => {
    logger.info(chalk[data.device.chalkColor](`SET_BREAKER_REMOTE_HANDLE_POSITION command succeeded!`))
})

// Called every time a device is discovered on the local network
EMCBs.on(EMCB_UDP_EVENT_DEVICE_DISCOVERED, data => {
    logger.info(chalk[data.device.chalkColor](`Discovered EMCB ${data.device.idDevice} at ${data.device.ipAddress}!`))
})

// Called after 100 consecutive timeouts and multiple resync attempts with a particular device as we remove it from the list of devices currently "discovered" and available within the EmcbUDPbroadcastCoordinator
EMCBs.on(EMCB_UDP_EVENT_DEVICE_REMOVED, data => {
    logger.warn(chalk[data.device.chalkColor](`Removing EMCB at ${data.device.ipAddress} with with Device ID ${data.device.idDevice}...  Too many consecutive timeouts/errors.`))
})

// Called whenever a device IP address change is detected
EMCBs.on(EMCB_UDP_EVENT_DEVICE_IP_ADDRESS_CHANGED, data => {
    logger.info(chalk[data.device.chalkColor](`Device ID ${data.device.idDevice} moved from ${data.oldIPaddress} to ${data.newIPaddress}`))
})

// Called whenever there is a device timeout
EMCBs.on(EMCB_UDP_ERROR_TIMEOUT, data => {
    logger.warn(chalk[data.device.chalkColor](data.message))
})

// Called whenever there is a parser error - which can include a nack from the device, invalid number of bytes, etc.
EMCBs.on(EMCB_UDP_ERROR_PARSER, data => {
    logger.warn(chalk[data.device.chalkColor]("Parser Error - " + data.message))
})

// Whenever the message queue is drained, poll the devices' status as quickly as possible, in order to cause our events listeners above to fire!
EMCBs.on(EMCB_UDP_EVENT_QUEUE_DRAINED, () => {
    EMCBs.getDeviceStatus()
})

EMCBs.discoverDevices()
    .then((devices) => {
        console.log("DISCOVER DEVICES COMPLETE - found " + Object.keys(devices).length + " EMCBs")
    });

logger

These logs are written to both the console and to ./logs/ whenever the emcbUDPcoordinator is used to aid in debugging/understanding.

NOTE - Because the written files will contain colorized output via ANSI Escape codes, command line tools such as cat or SumblimeANSI are very useful in viewing the logs.

Constants

The following constants are exported by the module and available for application use and described below.

const {

    // Network Configuration
    EMCB_UDP_PORT,

    // Application Layer Constraints
    EMCB_UDP_IMPLEMENTED_PROTOCOL_VERSION,
    EMCB_UDP_MESSAGE_THROTTLE_TIME_MS,
    EMCB_UDP_LONGEST_IMPLEMENTED_MESSAGE_LENGTH,

    // Application Layer Header Constants
    EMCB_UDP_HEADER_START_COORDINATOR,
    EMCB_UDP_HEADER_START_NODE,

    // Application Layer GET Message Codes
    EMCB_UDP_MESSAGE_CODE_GET_NEXT_SEQUENCE_NUMBER,
    EMCB_UDP_MESSAGE_CODE_GET_DEVICE_STATUS,
    EMCB_UDP_MESSAGE_CODE_GET_BREAKER_REMOTE_HANDLE_POSITION,
    EMCB_UDP_MESSAGE_CODE_GET_METER_TELEMETRY_DATA,
    EMCB_UDP_MESSAGE_CODE_GET_EVSE_APPLIED_CONTROL_SETTINGS,
    EMCB_UDP_MESSAGE_CODE_GET_EVSE_DEVICE_STATE,
    EMCB_UDP_MESSAGE_CODE_GET_EVSE_CONFIG_SETTINGS

    // Application Layer SET Message Codes
    EMCB_UDP_MESSAGE_CODE_SET_NEXT_SEQUENCE_NUMBER,
    EMCB_UDP_MESSAGE_CODE_SET_BREAKER_REMOTE_HANDLE_POSITION,
    EMCB_UDP_MESSAGE_CODE_SET_BARGRAPH_LED_TO_USER_DEFINED,
    EMCB_UDP_MESSAGE_CODE_SET_EVSE_CONFIG_SETTINGS,

    // Application Layer Integer Message Codes to strings
    EMCB_UDP_MESSAGE_CODES,

    // Enums / Parsed Data Constants
    EMCB_UDP_ACK,

    EMCB_UDP_SET_NEXT_SEQUENCE_NUMBER_RATE_LIMITED,
    EMCB_UDP_SET_NEXT_SEQUENCE_NUMBER_BAD_SEQUENCE_NUMBER,

    EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_OPEN,
    EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_CLOSED,
    EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_FEEDBACK_MISMATCH,
    EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_TOGGLE,

    // Errors
    EMCB_UDP_ERROR_TIMEOUT,
    EMCB_UDP_ERROR_PARSER,
    EMCB_UDP_ERROR_INVALID_DATA_LENGTH,

    // EventEmitter Events
    EMCB_UDP_EVENT_QUEUE_DRAINED,
    EMCB_UDP_EVENT_DEVICE_DISCOVERED,
    EMCB_UDP_EVENT_DEVICE_REMOVED,
    EMCB_UDP_EVENT_DEVICE_IP_ADDRESS_CHANGED,


    // Others
    EMCB_UDP_DEVICE_COLORS

} = require('emcbUDPcoordinator');

Network Configuration

EMCB_UDP_PORT

The destination UDP port number that will be used by default by EmcbUDPbroadcastCoordinator and all created EmcbUDPdeviceCoordinator instances. This value is 32866 (or "EATON" on a phone keypad)

EMCB UDP Application Layer

EMCB_UDP_IMPLEMENTED_PROTOCOL_VERSION

The version of the EMCB UDP API Application Protocol that is implemented by the class and used to check against getNextSequenceNumber() responses to verify compatibility.

EMCB_UDP_MESSAGE_THROTTLE_TIME_MS

The fastest rate that messages will be sent over the local network in milliseconds.

EMCB_UDP_LONGEST_IMPLEMENTED_MESSAGE_LENGTH

The longest implemented message response supported by the class (to reduce processing time / buffer overruns in fuzz testing).

EMCB UDP Application Layer Header

EMCB_UDP_HEADER_START_COORDINATOR

Start Byte of all Coordinator->Node requests

EMCB_UDP_HEADER_START_NODE

Start Byte of all Node->Coordinator responses

Message Codes

GET Message Codes

EMCB_UDP_MESSAGE_CODE_GET_NEXT_SEQUENCE_NUMBER

The integer message code for the GET_NEXT_SEQUENCE_NUMBER command. This constant will also be emitted by the EmcbUDPbroadcastCoordinator and EmcbUDPdeviceCoordinator whenever a response to the command is successfully parsed.

EMCB_UDP_MESSAGE_CODE_GET_DEVICE_STATUS

The integer message code for the GET_DEVICE_STATUS command. This constant will also be emitted by the EmcbUDPbroadcastCoordinator and EmcbUDPdeviceCoordinator whenever a response to the command is successfully parsed.

EMCB_UDP_MESSAGE_CODE_GET_BREAKER_REMOTE_HANDLE_POSITION

The integer message code for the GET_BREAKER_REMOTE_HANDLE_POSITION command. This constant will also be emitted by the EmcbUDPbroadcastCoordinator and EmcbUDPdeviceCoordinator whenever a response to the command is successfully parsed.

EMCB_UDP_MESSAGE_CODE_GET_METER_TELEMETRY_DATA

The integer message code for the GET_METER_TELEMETRY_DATA command. This constant will also be emitted by the EmcbUDPbroadcastCoordinator and EmcbUDPdeviceCoordinator whenever a response to the command is successfully parsed.

EMCB_UDP_MESSAGE_CODE_GET_EVSE_APPLIED_CONTROL_SETTINGS

The integer message code for the EMCB_UDP_MESSAGE_CODE_GET_EVSE_APPLIED_CONTROL_SETTINGS command. Event emitting is not yet supported.

EMCB_UDP_MESSAGE_CODE_GET_EVSE_DEVICE_STATE

The integer message code for the EMCB_UDP_MESSAGE_CODE_GET_EVSE_DEVICE_STATE command. Event emitting is not yet supported.

EMCB_UDP_MESSAGE_CODE_GET_EVSE_CONFIG_SETTINGS

The integer message code for the EMCB_UDP_MESSAGE_CODE_GET_EVSE_CONFIG_SETTINGS command. Event emitting is not yet supported.

SET Message Codes

EMCB_UDP_MESSAGE_CODE_SET_NEXT_SEQUENCE_NUMBER

The integer message code for the SET_NEXT_SEQUENCE_NUMBER command. This constant will also be emitted by the EmcbUDPbroadcastCoordinator and EmcbUDPdeviceCoordinator whenever a response to the command is successfully parsed.

EMCB_UDP_MESSAGE_CODE_SET_BREAKER_REMOTE_HANDLE_POSITION

The integer message code for the SET_BREAKER_REMOTE_HANDLE_POSITION command. This constant will also be emitted by the EmcbUDPbroadcastCoordinator and EmcbUDPdeviceCoordinator whenever a response to the command is successfully parsed.

EMCB_UDP_MESSAGE_CODE_SET_BARGRAPH_LED_TO_USER_DEFINED

The integer message code for the SET_BARGRAPH_LED_TO_USER_DEFINED command. This constant will also be emitted by the EmcbUDPbroadcastCoordinator and EmcbUDPdeviceCoordinator whenever a response to the command is successfully parsed.

EMCB_UDP_MESSAGE_CODE_SET_EVSE_CONFIG_SETTINGS

The integer message code for the EMCB_UDP_MESSAGE_CODE_SET_EVSE_CONFIG_SETTINGS command. Event emitting is not yet supported.

EMCB_UDP_MESSAGE_CODES

A lookup table to convert the integer message codes back to human readable strings.

console.log(EMCB_UDP_MESSAGE_CODES[EMCB_UDP_MESSAGE_CODE_SET_BARGRAPH_LED_TO_USER_DEFINED])
// $ SET_BARGRAPH_LED_TO_USER_DEFINED

Enums and Parsed Data

EMCB_UDP_ACK

A response value defined in the EMCB UDP API to signify that the command was successfully acknowledged and performed by the device.

EMCB_UDP_SET_NEXT_SEQUENCE_NUMBER_RATE_LIMITED

A response value defined in the EMCB UDP API to signify that the setNextSequenceNumber command was rate limited and therefore not executed.

EMCB_UDP_SET_NEXT_SEQUENCE_NUMBER_BAD_SEQUENCE_NUMBER

A response value defined in the EMCB UDP API to signify that the setNextSequenceNumber command was not executed due to an invalid desiredSequenceNumber

EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_OPEN

A response/command value defined in the EMCB UDP API to signify that the EMCB remote handle is/should be in the open position

EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_CLOSED

A response/command value defined in the EMCB UDP API to signify that the EMCB remote handle is/should be in the closed position

EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_FEEDBACK_MISMATCH

A response value defined in the EMCB UDP API to signify that the EMCB remote handle feedback is mismatched on a 2-pole breaker (i.e. one pole is open and the other is closed).

EMCB_UDP_BREAKER_REMOTE_HANDLE_POSITION_TOGGLE

A command value defined in the EMCB UDP API to signify that the EMCB remote handle should toggle from its current state

Events

In addtion to the GET and SET Message codes, the following events will be emitted by EmcbUDPbroadcastCoordinator instances:

EMCB_UDP_EVENT_QUEUE_DRAINED

Emitted whenever the message queue for the broadcast coordinator is empty and the application should execute additional regular polling commands

 EMCBs.on(EMCB_UDP_EVENT_QUEUE_DRAINED, () => {
    EMCBs.getDeviceStatus()
 }

EMCB_UDP_EVENT_DEVICE_DISCOVERED

Emitted whenever a new EMCB is discovered as a part of a getNextSequenceNumber or discoverDevices() command

EMCB_UDP_EVENT_DEVICE_REMOVED

Emitted whenever an EMCB is removed from the EmcbUDPbroadcastCoordinator instance's list of devices, due to excessive consecutive timeouts.

EMCB_UDP_EVENT_DEVICE_IP_ADDRESS_CHANGED

Emitted whenever an EMCB device's IP address changes.

Errors

The following error constants are used by the application. Additional node.js Errors are thrown / returned as appropriate.

EMCB_UDP_ERROR_TIMEOUT

This error will be emitted and returned in the rejected promise whenever a device experiences a timeout.

EMCB_UDP_EVENT_PARSER_ERROR

This error will be emitted and returned in the rejected promise whenever a response parser throws an error (wrong number of bytes, nack from the device, etc.)

EMCB_UDP_ERROR_INVALID_DATA_LENGTH

This error will be returned in the rejected promise whenever a parser detects an invalid response length.

Others

EMCB_UDP_DEVICE_COLORS

This is an array of chalk colors to aid in logging/debugging of the application.