Skip to content

KV Host Link Node-RED API Reference

The public JavaScript entry point is lib/hostlink. HostLinkClient is the ordinary low-level client; there is no separate queued-client wrapper.

Connection contract

new HostLinkClient({ host, port, transport, timeout, plcProfile }) performs no network I/O. host is an IPv4 literal or a hostname with an IPv4 DNS result; IPv6 literals and IPv6-only names are unsupported. Bracketed IPv4 such as [127.0.0.1] is rejected before DNS or socket work; pass 127.0.0.1 instead. port and timeout are safe integers, transport is tcp or udp, and plcProfile must be one exact canonical value from PLC_PROFILES. Endpoint, timeout, transport, and profile are immutable snapshots for the lifetime of the client.

Call connect() before commands and again after close(), timeout, cancellation of active I/O, protocol/framing failure, or transport failure. Commands do not reconnect or retry. openAndConnect(options[, { signal }]) is the convenience constructor. close() immediately rejects active and waiting work and prevents that work from appearing on a later connection.

The ordinary client admits concurrent calls into one strict FIFO per client. Arguments are validated and copied at admission. A waiting call's timeout begins only when it becomes active. Most asynchronous operations accept a final { signal } option with an AbortSignal; canceling a waiting operation removes only that operation without a send. Different client instances are independent.

Once a request becomes active, one monotonic deadline covers the complete send, response framing/receive, and decode. Progress or partial bytes do not restart that deadline. One TCP request owns exactly one non-empty response line.

Client operations

Area Operations
Lifecycle connect, close, trafficStats
Raw/control sendRaw, changeMode, clearError, checkErrorNo, confirmOperatingMode, queryModel, setTime
Device access read, readConsecutive, write, writeConsecutive
Force/set values forcedSet, forcedReset, forcedSetConsecutive, forcedResetConsecutive, writeSetValue, writeSetValueConsecutive
Monitor registerMonitorBits, registerMonitorWords, readMonitorBits, readMonitorWords
Other readComments, readCommentBytes, switchBank, readExpansionUnitBuffer, writeExpansionUnitBuffer

sendRaw accepts one non-empty ASCII command body without CR or LF. The body is at most 65,506 bytes and the library appends one CR, producing a complete frame of at most 65,507 bytes for both TCP and UDP. An empty, CR/LF-containing, or 65,507-byte body fails before FIFO admission, connection state, DNS, socket work, traffic counters, or transport state change. Command-specific limits that are smaller than this absolute frame boundary still apply.

TCP reuses its connected stream. UDP also reuses a successfully connected physical socket, resolved IPv4 address, and local endpoint. Timeout, cancellation, socket/protocol failure, malformed or additional response data, or a datagram with no owning request retires that UDP socket. A later request creates one replacement from the saved IPv4 address without retrying the failed operation or repeating DNS resolution. Residual duplicate-datagram ambiguity after a subsequent request has already taken ownership remains inherent to UDP.

Low-level numeric operations take a base device plus .U, .S, .D, .L, or .H. Suffix-bearing low-level devices are rejected. Bare direct-bit operations use bit semantics. Numeric writes accept only exact finite JavaScript numbers in range. Direct-bit writes accept only JavaScript true or false; numbers and strings such as 1, 0, ON, and OFF are invalid write values. Response decoding may still recognize the documented PLC bit tokens.

For a formatted single read of a direct-bit device, the PLC returns one packed numeric token: .U, .S, and .H represent 16 bits, while .D and .L represent 32 bits. Signed .S and .L responses may include an explicit leading +. Bare direct-bit reads remain one bit token. A formatted response containing multiple tokens is a protocol error and retires the supplying transport generation.

A formatted T or C single read returns [status, current, preset]. The raw first token is structural status and must be exactly 0 or 1; the low-level result keeps it as numeric 0 or 1 for every format. Only current and preset are decoded and range-checked as .U, .S, .H, .D, or .L. Consequently, 0,270F,270F for .H becomes [0, "270F", "270F"], not a formatted status such as "0000". Missing or additional fields, a non-exact status, malformed current or preset, and numeric overflow are protocol errors that retire the supplying transport generation.

registerMonitorWords treats a bare direct-bit target specially because this is an MWS/MWR word-monitor operation. For example, "R5000" is transmitted as the exact bare token MWS R5000, while the matching MWR field is decoded as the unsigned 16-bit packed value for R5000 through R5015. Thus a response of 00013 returns JavaScript number 13. The field accepts one through five ASCII decimal digits with optional leading zeroes; the manual does not guarantee a fixed five-character width. This does not change bare scalar RD or MBS/MBR; those operations still accept only one bit token per target.

HostLinkClient.writeBitInWord and high-level writeBitInWord expose the same explicit Boolean-only, 16-bit word read-modify-write. The complete plan is validated before FIFO admission. One absolute deadline covers exactly one word read and one word write after activation in one client turn, even when the bit already has the requested value. The operation performs no fallback, retry, or success readback and is not PLC-atomic against PLC logic or another connection.

HostLinkClient.writeBitInExpansionUnitBuffer and high-level writeBitInExpansionUnitBuffer apply the same contract to one .U word on the existing URD/UWR unit/address route. The selected route remains immutable across both requests and never falls back to an ordinary device.

readComments(device, encoding[, options]) requires exact encoding utf8 or cp932. cp932 uses the Windows-31J-compatible mapping commonly described by KEYENCE as Shift_JIS; there is no separate strict Shift_JIS selection or alias. Malformed bytes raise HostLinkProtocolError without replacement or fallback. readCommentBytes(device[, options]) returns the exact RDC body Buffer without CR/LF and preserves trailing padding. Raw and comment-byte results are independent caller-owned Buffers; mutating one does not alter transport state or another result. At protocol level, decodeCommentResponse(raw, encoding) and decodeCommentBytes(raw) provide the same text/raw split. Text decoding does not strip a leading Unicode BOM from the payload; UTF-8 EF BB BF decodes as U+FEFF. CP932 bytes 00 through 7F map to the identical ASCII code points, while 80, A0, and FD through FF are invalid; half-width and double-byte code units decode strictly.

High-level helpers

Area Public API
Address syntax parseAddress, formatParsedAddress, normalizeAddress, normalizeAddressList
Device syntax parseDevice, deviceToString, parseDeviceText, normalizeSuffix
Typed access readTyped, writeTyped, readWords, readDWords
Explicit bit-in-word write HostLinkClient.writeBitInWord, writeBitInWord
Expansion-buffer bit write HostLinkClient.writeBitInExpansionUnitBuffer, writeBitInExpansionUnitBuffer
Timer/counter readTimerCounter, readTimer, readCounter
Named access readNamed, writeNamed, poll
Comments readComments, readCommentBytes

Float32 F uses the canonical device metadata and is available only when the device family's normal Host Link shape is one .U word with ordinary consecutive two-word access. DM0:F remains valid. R0:F, T0:F, C0:F, and AT0:F fail in parsing, normalization, formatting, typed access, named access, and polling before FIFO admission or transport. A hand-constructed formatter object cannot bypass this check.

readNamed validates and snapshots the whole input before FIFO admission and occupies one FIFO turn. Compatible device groups execute in the order each group first appears in the input. Within a group, addresses are sorted ascending, contiguous ranges are merged, and protocol limits are split at the minimum valid boundaries. Public result mapping still follows input order. A scalar, dword, float, array, or other declared entry is never torn between requests. The call stops at the first failure and returns no partial result. Multiple requests are not a coherent PLC snapshot because the PLC may change between them. Use one protocol request or a PLC-side consistency handshake when coherence matters.

Named keys must be semantically unique after parsing device family, numeric address, dtype, bit index, and count. Case, leading zeros, and an explicit ,1 do not make a second key; different dtypes, bit indexes, or merely overlapping spans remain valid. Successful results retain each original input spelling. normalizeAddressList validates delimited strings, JavaScript arrays, and JSON arrays identically while returning each valid trimmed spelling.

poll requires an integer interval from 1 through 2147483647 milliseconds. Zero is not a maximum-speed mode, and larger values are outside the native Node.js timer range. It compiles the immutable named-read plan once at polling start, uses one aggregate FIFO turn per cycle, then waits the interval outside that turn. It does not publish a partial cycle.

When a readNamed/poll plan contains :COMMENT, its options must contain commentOutput: "text" plus commentEncoding: "utf8" | "cp932", or commentOutput: "buffer" with no encoding. Missing/contradictory comment options reject the complete plan before FIFO admission or send. Comment options on a plan without :COMMENT are also rejected instead of being ignored.

writeNamed validates and snapshots the complete update set. It is accepted only when the plan is one wire request. Any state-changing plan that would require two or more requests, including an implicit bit-in-word read-modify-write, fails before connection or transport. The library never auto-splits or retries writes.

Direct BIT entries for the decimal sixteen-bit bank families R, MR, LR, and CR are consecutive by logical bit number. Thus R115:BIT followed in insertion order by R200:BIT produces one writeConsecutive request whose displayed start remains R115. Within-bank behavior is unchanged. Gaps, duplicates, reverse order, mixed families, mixed dtypes, invalid display-bit positions, and more than 1000 bit values reject the complete update before transport; the planner never sorts or deduplicates entries.

Error contract

Error Meaning
ValueError Invalid local value/configuration; no request is sent.
HostLinkNotConnectedError Explicit connect() is required.
HostLinkCanceledError Caller cancellation; active I/O retires that connection generation.
HostLinkTimeoutError The absolute connection/transaction deadline expired.
HostLinkClosedError Explicit close rejected active or waiting work.
HostLinkConnectionError DNS, socket, or transport failure.
HostLinkProtocolError Invalid framing, decoding, or semantic response shape.
HostLinkError A complete PLC E0 through E9 response; code is the PLC code.
HostLinkOperationOutcomeUnknownError A state-changing request may have reached the PLC. Inspect reason and cause.

Read-only calls can be retried by application policy after an explicit reconnect. Do not automatically retry HostLinkOperationOutcomeUnknownError: first reconcile PLC/application state because repeating a change can duplicate it.

Public symbol index

CR, HostLinkBaseError, HostLinkCanceledError, HostLinkClient, HostLinkClosedError, HostLinkConnectionError, HostLinkError, HostLinkNotConnectedError, HostLinkOperationOutcomeUnknownError, HostLinkProtocolError, HostLinkTimeoutError, MODEL_CODES, PLC_PROFILES, ValueError, availablePlcProfiles, buildFrame, decodeCommentBytes, decodeCommentResponse, decodeResponse, deviceToString, displayName, ensureSuccess, formatParsedAddress, normalizeAddress, normalizeAddressList, normalizePlcProfile, normalizeSuffix, openAndConnect, parseAddress, parseDataTokens, parseDevice, parseDeviceText, parseScalarToken, poll, profileDescriptors, profileFromName, readCommentBytes, readComments, readCounter, readDWords, readNamed, readTimer, readTimerCounter, readTyped, readWords, splitDataTokens, writeNamed, writeTyped.

Traffic statistics

trafficStats() returns a frozen lifetime { requestCount, txBytes, rxBytes } snapshot. TCP receive bytes include the body and first terminator; UDP counts the accepted datagram. Close/reconnect does not reset the counters.