npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ya-modbus/driver-sdk

v0.7.0

Published

Runtime SDK for ya-modbus device drivers with transformation utilities and helpers

Readme

@ya-modbus/driver-sdk

Runtime SDK for ya-modbus device drivers with transformation utilities and helpers.

Overview

This package provides reusable utilities for developing Modbus device drivers:

  • Codec functions: Read/write scaled integer values from/to register buffers
  • Validators: Type-safe configuration validation with TypeScript type narrowing
  • Error formatting: Consistent validation error messages

Installation

npm install @ya-modbus/driver-sdk

API Reference

Codec Functions

Utilities for reading and writing scaled integer values from Modbus register buffers.

readScaledUInt16BE(buffer, offset, scale)

Read and scale an unsigned 16-bit integer from a buffer.

Parameters:

  • buffer: Buffer - Buffer containing register data
  • offset: number - Byte offset to start reading from
  • scale: number - Scale factor (e.g., 10 for ×10 values)

Returns: number - Scaled floating-point value

Throws: Error if scale is not a finite positive number

Example:

import { readScaledUInt16BE } from '@ya-modbus/driver-sdk'

// Device stores temperature as integer ×10 (235 = 23.5°C)
const buffer = await transport.readInputRegisters(0, 1)
const temperature = readScaledUInt16BE(buffer, 0, 10)
// temperature = 23.5

readScaledInt16BE(buffer, offset, scale)

Read and scale a signed 16-bit integer from a buffer.

Parameters:

  • buffer: Buffer - Buffer containing register data
  • offset: number - Byte offset to start reading from
  • scale: number - Scale factor (e.g., 10 for ×10 values)

Returns: number - Scaled floating-point value

Throws: Error if scale is not a finite positive number

Example:

import { readScaledInt16BE } from '@ya-modbus/driver-sdk'

// Device stores correction offset as signed integer ×10 (-50 = -5.0°C)
const buffer = await transport.readHoldingRegisters(0x103, 1)
const correction = readScaledInt16BE(buffer, 0, 10)
// correction = -5.0

readScaledUInt32BE(buffer, offset, scale)

Read and scale an unsigned 32-bit integer from a buffer (2 consecutive registers).

Parameters:

  • buffer: Buffer - Buffer containing register data
  • offset: number - Byte offset to start reading from
  • scale: number - Scale factor (e.g., 100 for ×100 values)

Returns: number - Scaled floating-point value

Throws: Error if scale is not a finite positive number

Example:

import { readScaledUInt32BE } from '@ya-modbus/driver-sdk'

// Device stores total energy as 32-bit integer ×100 (1000000 = 10000.00 kWh)
const buffer = await transport.readHoldingRegisters(0x0007, 2)
const totalEnergy = readScaledUInt32BE(buffer, 0, 100)
// totalEnergy = 10000.0

writeScaledUInt16BE(value, scale)

Encode and scale a value to an unsigned 16-bit integer buffer.

Parameters:

  • value: number - Value to encode
  • scale: number - Scale factor (e.g., 10 for ×10 values)

Returns: Buffer - 2-byte buffer containing the scaled value

Throws: Error if value is not finite, scale is invalid, or scaled value exceeds uint16 range

Example:

import { writeScaledUInt16BE } from '@ya-modbus/driver-sdk'

// Write humidity correction of 5.5% (stored as 55)
const buffer = writeScaledUInt16BE(5.5, 10)
await transport.writeMultipleRegisters(0x104, buffer)

writeScaledInt16BE(value, scale)

Encode and scale a value to a signed 16-bit integer buffer.

Parameters:

  • value: number - Value to encode
  • scale: number - Scale factor (e.g., 10 for ×10 values)

Returns: Buffer - 2-byte buffer containing the scaled value

Throws: Error if value is not finite, scale is invalid, or scaled value exceeds int16 range

Example:

import { writeScaledInt16BE } from '@ya-modbus/driver-sdk'

// Write temperature correction of -3.5°C (stored as -35)
const buffer = writeScaledInt16BE(-3.5, 10)
await transport.writeMultipleRegisters(0x103, buffer)

Validation Functions

Type-safe validators for configuration values with proper TypeScript type narrowing.

createEnumValidator(values)

Create a type-safe enum validator function.

Parameters:

  • values: readonly T[] - Readonly array of valid enum values

Returns: (value: unknown) => value is T[number] - Type guard function

Example:

import { createEnumValidator, formatEnumError } from '@ya-modbus/driver-sdk'

const VALID_BAUD_RATES = [9600, 14400, 19200] as const
type ValidBaudRate = (typeof VALID_BAUD_RATES)[number]

const isValidBaudRate = createEnumValidator(VALID_BAUD_RATES)

if (!isValidBaudRate(value)) {
  throw new Error(formatEnumError('baud rate', VALID_BAUD_RATES))
}
// value is now typed as ValidBaudRate (9600 | 14400 | 19200)

createRangeValidator(min, max)

Create a numeric range validator function.

Parameters:

  • min: number - Minimum valid value (inclusive)
  • max: number - Maximum valid value (inclusive)

Returns: (value: unknown) => value is number - Validator function

Example:

import { createRangeValidator, formatRangeError } from '@ya-modbus/driver-sdk'

const isValidAddress = createRangeValidator(1, 247)

if (!isValidAddress(value)) {
  throw new Error(formatRangeError('device address', 1, 247))
}
// value is a finite number between 1 and 247

isValidInteger(value)

Validate that a value is a finite integer.

Parameters:

  • value: unknown - Value to validate

Returns: value is number - True if value is a finite integer

Example:

import { isValidInteger } from '@ya-modbus/driver-sdk'

if (!isValidInteger(value)) {
  throw new Error('Device address must be an integer')
}

Error Formatting

Utilities for consistent validation error messages.

formatRangeError(name, min, max)

Format a range validation error message.

Parameters:

  • name: string - Field name for the error message
  • min: number - Minimum valid value
  • max: number - Maximum valid value

Returns: string - Formatted error message

Example:

import { formatRangeError } from '@ya-modbus/driver-sdk'

formatRangeError('device address', 1, 247)
// => 'Invalid device address: must be between 1 and 247'

formatEnumError(name, values)

Format an enum validation error message.

Parameters:

  • name: string - Field name for the error message
  • values: readonly unknown[] - Valid enum values

Returns: string - Formatted error message

Example:

import { formatEnumError } from '@ya-modbus/driver-sdk'

formatEnumError('baud rate', [9600, 14400, 19200])
// => 'Invalid baud rate: must be one of 9600, 14400, 19200'

Edge Case Handling

All codec functions include comprehensive edge case validation:

  • Division by zero: Scale must be greater than 0
  • Non-finite values: NaN and Infinity are rejected
  • Integer overflow: Values exceeding uint16/int16 ranges throw errors
  • Negative scale: Scale must be positive

Example:

// Throws: Invalid scale: must be greater than 0
readScaledUInt16BE(buffer, 0, 0)

// Throws: Invalid value: must be a finite number
writeScaledUInt16BE(NaN, 10)

// Throws: Invalid scaled value: 65536 is outside uint16 range (0 to 65535)
writeScaledUInt16BE(6553.6, 10)

TypeScript Support

All functions include full TypeScript type definitions with type narrowing support:

const isValidBaudRate = createEnumValidator([9600, 14400, 19200] as const)

let value: unknown = getUserInput()

if (isValidBaudRate(value)) {
  // TypeScript knows: value is 9600 | 14400 | 19200
  const encoded = encodeBaudRate(value)
}

Usage in Drivers

Typical driver implementation pattern:

import type { DeviceDriver } from '@ya-modbus/driver-types'
import {
  readScaledUInt16BE,
  readScaledInt16BE,
  writeScaledUInt16BE,
  createEnumValidator,
  formatEnumError,
} from '@ya-modbus/driver-sdk'

const VALID_BAUD_RATES = [9600, 14400, 19200] as const
const isValidBaudRate = createEnumValidator(VALID_BAUD_RATES)

export const createDriver = async (config): Promise<DeviceDriver> => {
  // Validate configuration
  if (!isValidBaudRate(config.baudRate)) {
    throw new Error(formatEnumError('baud rate', VALID_BAUD_RATES))
  }

  return {
    name: 'my-device',

    async readDataPoint(id: string) {
      if (id === 'temperature') {
        const buffer = await transport.readInputRegisters(0, 1)
        return readScaledUInt16BE(buffer, 0, 10)
      }
      if (id === 'correction') {
        const buffer = await transport.readHoldingRegisters(0x103, 1)
        return readScaledInt16BE(buffer, 0, 10)
      }
    },

    async writeDataPoint(id: string, value: number) {
      if (id === 'correction') {
        const buffer = writeScaledInt16BE(value, 10)
        await transport.writeMultipleRegisters(0x103, buffer)
      }
    },
  }
}

See Also

License

GPL-3.0-or-later