ekmiostack

EKM ioStack Serial API.

Data messages on the serial line are limited to 256 bytes to keep a single device from saturating the RS485 bus, so data reads are divided into several functions, each returning slightly different data.

Generally, the read_a() and read_b() are sufficient to get all relevant data. The other read functions have smaller message payloads so may be faster if only a subset of the data is required.

class StatusCode(value)[source]

Command status codes.

These values are returned by functions that return a status code. If an IOStackCommandError exception is raised the status code will be available via the exception object.

Status codes are a single byte. Error status codes have bit 7 set.

OK = 0

Command successful.

OK_CLEARED = 1

Command successful, cleared previous watch.

CRC_ERR = 129

Command message body has invalid CRC value.

CMD_UNKNOWN = 130

Invalid command.

CMD_LEN_ERR = 131

Invalid command body length.

CMD_SECURITY_ERR = 132

Invalid password.

CMD_PARAM_ERR = 133

Invalid command parameter.

CMD_DI_INCREMENT_ERR = 134

DI count increment too large.

CMD_UNAVAILABLE = 135

Command is not implemented.

NO_WATCH_FOUND = 145

No watch assigned to pin. This is technically not an error.

NO_WAVE_FOUND = 146

No waveform assigned to pin. This is technically not an error.

DO_BUSY = 147

Requested digital out pin is busy.

DI_BUSY = 148

Requested digital input pin is busy.

UFW_BLOCK_ERR = 149

Firmware update block error.

NVRAM_VERIFY_ERR = 251

NVRAM verify-before-write failed.

NVRAM_UPDATE_ERR = 252

NVRAM write failure.

PROCESS_ERR = 253

Error processing command.

INTERNAL_ERR = 254

Unrecoverable internal error.

class OwnerType(value)[source]

Pin watch owner id types.

DO_WAVE = 16

Digital output waveform.

DI_COUNT = 32

Digital input count watch.

DI_LEVEL = 48

Digital input level watch.

DI_RATE = 64

Digital input rate watch.

AI_LEVEL = 80

Analog input level watch.

exception IOStackCommandError(cmd: int, status: StatusCode, note: str | None = None)[source]

IOStack command failed.

status_code

Command failure status code.

Type:

ekmdevice.ekmiostack.StatusCode

exception IOStackBusyError(cmd: int, status: StatusCode, busy_info: Tuple[int, int] | Tuple[Tuple[int, int], ...])[source]

One or more requested pins are busy.

pin

Busy pin number.

Type:

int

owner_id

Watch owner id.

Type:

int

busy_info

A tuple containing one or more tuples containing the busy pin number and the watch owner id, of the form ((pin, owner_id), …). There can be more than one in the case of set_do_levels().

Type:

Tuple[Tuple[int, int], …] | None

See set_do_waveform().

exception IOStackBlockError(cmd: int, status: StatusCode, block_count: int)[source]

FW update block error.

get_status(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Get device status.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

Returns:

The status data as a dictionary:

{
    'hw_type': int
    'model': int
    'version_major': int
    'version_minor': int
    'lifetime_ms': int
    'chip_id': str (hex)
    'rtc_period': int
    'rtc_offset': int
    'device_time': str
}

Raises:

IOStackCommandError – if the command failed.

echo(serial_port: Serial, address: str | SupportsInt | bytes, message: str | bytes) str | bytes[source]

Echo message to/from device.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • message – The message string or byte array to be echoed.

Returns:

The response message as a string if the input message was a string type, otherwise bytes.

Raises:

IOStackCommandError – if the command failed.

echo_test(serial_port: Serial, address: str | SupportsInt | bytes, message: str | bytes | None = None, size: int = 8) bool[source]

Simple connectivity test.

Send a message to the iostack and test if the returned bytes match.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • message – Optional message string to be echoed. By default a random message will be generated.

  • size – Length of random message. Default is 8.

Returns:

True if successful, otherwise False.

read_data(serial_port: Serial, address: str | SupportsInt | bytes, version: str | SupportsInt | bytes | None = None, include_b: bool = False, partial_ok: bool = False) Dict[str, Any][source]

Get current READ_A and optionally READ_B data values in EKM field format.

See:

https://api.ekmpush.com/help/iostackfields.html

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • version – The iostack protocol version. Currently ignored.

  • include_b – Include B data block if READ_A is successful. An extra READ_B request will be performed and the data will be merged with the READ_A data if True. Default is False and only READ_A data will be read.

  • partial_ok – Ignore READ_B errors if True and return only READ_A data.

Returns:

A dictionary of read data. See EKMAPI REST API documentation for field names and values.

Raises:

IOStackCommandError – if the command failed.

read_a(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a READ_A command.

Data contains:

  • The current AIn and DIn values for pin count, levels, and watch information.

  • Current DOut levels and owner ids for any pending DOut waveforms.

  • OneWire input values.

An AIn value of 0xFFFF indicates a problem calculating the AI pin value.

The wave owner id is described in get_do_waveform(), except that an owner id of 0x10 OR’ed with the DOut pin number is returned when there is no wave attached to the DOut pin.

Watch values are integers with a value of 0, 1, or 2:

  • 0 No watch.

  • 1 Pending watch.

  • 2 Watch has triggered at least once.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

Returns:

A dict containing the READ_A data:

{
    'hw_type': int,
    'model': int,
    'version_major': int,
    'version_minor': int,
    'version_patch': int, // Newer fw only
    'device_time': str,
    'lifetime_ms', int,
    'ai_count', int,
    'ai_values', [int, ...],
    'ai_watch', [int, ...],
    'di_count', int,
    'di_levels', int,
    'di_cwatch', [int, ...],
    'di_lwatch', [int, ...],
    'di_rwatch', [int, ...],
    'do_count', int,
    'do_levels', int,
    'do_owner', [int, ...],
    'ow_dio_count', int,
    'ow_dio': [
        {'slot': int, 'pio_a': int, 'pio_b': int},
        ...
    ],
    'ow_thl_count': int,
    'ow_thl', [
        {'slot': int, 'temp': int, 'humidity': int, 'lux': int},
        ...
    ],
}

Raises:

IOStackCommandError – if the command failed.

read_b(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a READ_B command.

Get the current values associated with DI pin numbers 0-3 and DOut pins. Returns the pin count, levels, and tracking information, plus the current DOut pin levels.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • model – Optional device model number if known. This is only useful for supporting deprecated READ_B responses from older devices.

Returns:

A dict containing the READ_B data:

{
    'version_major': int,
    'version_minor': int,
    'device_time': str,
    'lifetime_ms', int,
    'di_count', int,
    'di_levels', int,
    'di_hold_ms', [int, ...],
    'di_hi_ms_prev', [int, ...],
    'di_lo_ms_prev', [int, ...],
    'di_pulse_rst', [int, ...],
    'di_pulse_total', [int, ...],
    'di_hi_sec_total', [int, ...],
    'di_lo_sec_total', [int, ...],
    'do_count', int,
    'do_levels', int,
}

Raises:

IOStackCommandError – if the command failed.

read_c(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a READ_C.

Currently, this returns the same data as read_b, but this may change in the future.

Get the current values associated with DI pin numbers 0-3 and DOut pins. Returns the pin count, levels, and tracking information, plus the current DOut pin levels.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

Returns:

A dict containing the READ_C data.

read1(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a READ1 command.

Get current AI pin count, values, and watch information, along with the DI pin count, levels, and watch information, plus the chip’s lifetime millisecond count.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

Returns:

A dict containing the READ1 data:

{
    'ai_count': int,
    'ai_values': [int, ...],
    'ai_lwatch': [int, ...],
    'di_count': int,
    'di_values': [int, ...],
    'di_hold_ms': [int, ...],
    'di_cwatch': [int, ...],
    'di_lwatch': [int, ...],
    'di_rwatch': [int, ...],
    'do_values': [int, ...],
    'lifetime_ms': int,
}

read2(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a READ2.

Get current values for DI pin count, pin levels, and the millisecond length of the previous high period and low period for each pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

Returns:

A dict containing the READ2 data.

read3(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a READ3.

Get current values for DI pin count, pin levels, total resettable pulse count, and total lifetime pulse count for each pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

Returns:

A dict containing the READ3 data.

read4(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a READ4.

Get current values for DI pin count, pin levels, and the total seconds at high level and at low level for each pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

Returns:

A dict containing the READ4 data.

get_ai_values(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a AI_GET_VALUES command.

Gets the actual values from all four pins of the ADC (analog-digital conversion) input hardware.

Each 2-byte value contains a binary fraction that represents the voltage on a specific AI pin divided by the voltage on the chip’s VDD pin. The value for each pin will be between 0 and 4095 (0xFFF).

Specifically, if the voltage on AIn falls within the range of VDD to VSS, then the voltage on AIn is equal to VDD * value/4095. This means that the voltage on AIn is about (value * 3.331 / 4095).

A value of 0 indicates that the voltage on the AI pin was less than, equal to, or close to that on VSS. While a value of 0xFFF indicates that the voltage on AIn was greater than, equal to, or close to that on VDD.

Note that the chip’s VDD pins should be at a clean voltage-regulated +3.3 volts, and VDD is internally tied to VREFP while VSS is internally tied to VREFN.

Parameters:
  • serial_port (serial.Serial) – The serial port.

  • address (EKMAddress) – The iostack address (serial number).

Returns:

A dictionary containing the count of pins and their AI (analog input) values:

{
    'ai_count', int,
    'ai_values', [int, ...],
}

Raises:

IOStackCommandError – if the command failed.

clear_ai_level_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, password: str | SupportsInt | bytes = 0) bool[source]

Clear the current watch (if any) on the analog input pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – The AI pin number

  • password – Optional password

Returns:

True if a watch was cleared False if there was no watch assigned to the pin

Raises:

IOStackCommandError – if the command failed.

set_ai_level_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, min_threshold: int = 0, max_threshold: int = 0, min_true_sec: int = 0, min_false_sec: int = 0, restart: int = 0, do_pin: int = 0, hi_sec: int = 0, lo_sec: int = 0, cycles: int = 0, initial_level: int = 0, interim_level: int = 0, final_level: int = 0, password: str | SupportsInt | bytes = 0) StatusCode[source]

Perform a AI_SET_LEVEL_WATCH command.

Set a per-second watch on an analog input pin to compare the level to a range. It will trigger if the Ai_pin level is above min_threshold and below max_threshold for a minimum of min_true_sec seconds. When triggered, the specified waveform is activated on do_pin. If the Ai_pin level goes outside the min_threshold/max_threshold range for at least min_false_sec, the watch may restart.

The value of restart indicates whether to restart the watch (after the condition has been detected for min_true_sec and canceled by min_fals_sec):

  • restart = 0 clear the watch after entering then leaving the range

  • restart = 1 restart the watch after enter/leave, but not on chip reset

  • restart = 2 restart the watch after enter/leave, and after a chip reset

The maximum value for the max_threshold and min_threshold parameters is 0xFFF and one of them must be greater than zero.

A hit count is kept of the number of times the range condition is met, but it is only incremented when going from false to true. The hit count can be read anytime with the command get_ai_watch().

If do_pin=0xFF the hit count gets incremented, but with no waveform. Otherwise, a waveform described by hi_sec, lo_sec, and cycles is output on do_pin.

It repeats cycles times, or continuously if cycles == 0.

do_pin is set to initial_level while waiting for the first hit count. do_pin is set to interim_level after a Restart once the cycles have completed or if the AI pin level goes out of range for min_false_sec seconds.

Each time the hit count is incremented a fresh waveform is started. If the hit count is incremented after a restart, a fresh waveform is started immediately, even if the previous waveform is still cycling. do_pin is set to final_level after the final waveform cycles complete.

To clear the current watch for AI pin, set min_threshold=0xFFF and max_threshold=0. The other parameters are ignored.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – The AI pin number

  • min_threshold – Minimum threshold value

  • max_threshold – Maximum threshold value

  • min_true_sec – Minimum number of seconds in “true”/1 state

  • min_false_sec – Minimum number of seconds in “false”/0 state

  • restart – Clear/restart watch (see comments)

  • do_pin – DO waveform pin number

  • hi_sec – DO waveform level “high”/1 seconds

  • lo_sec – DO waveform level “low”/0 seconds

  • cycles – DO waveform number of cycles

  • initial_level – DO waveform initial pin level

  • interim_level – DO waveform interim pin level after restart

  • final_level – DO waveform final pin level

  • password – Optional password

Returns:

Status code

StatusCode.OK success

StatusCode.OK_CLEARED if a clear is requested and
    previous watch was cleared

StatusCode.NO_WATCH_FOUND if a clear is requested and
    there was no watch assigned to the pin

Raises:
get_ai_level_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int) dict[source]

Perform a AI_GET_LEVEL_WATCH command.

Get the current level-watch settings on an Analog-In pin. The returned values are the settings from the original command, except for hit count which gives the number of times the AI pin level has met the range condition. It is only incremented when going from false to true. If the value of hit count is 0xFFFF it may have overflowed.

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

  • pin – The analog input pin number (0-based)

Returns:

A dictionary of data.

{
    'ai_value': int,
    'min_threshold': int,
    'max_threshold': int,
    'min_true_sec': int,
    'min_false_sec': int,
    'restart': int,
    'do_pin': int,
    'hi_sec': int,
    'lo_sec': int,
    'cycles': int,
    'initial_level': int,
    'interim_level': int,
    'final_level': int,
    'hit_count': int,
}

Raises:

IOStackCommandError – if the command failed.

get_datetime_adjustment(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a DATETIME_ADJUST command.

Get the offset value of the Real Time Clock (RTC_TCR reg).

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

Returns:

Status code, and a dict with period and offset values.

Raises:

IOStackCommandError – if the command failed.

See:

set_datetime_adjustment()

set_datetime_adjustment(serial_port: Serial, address: str | SupportsInt | bytes, period: int, offset: int, password: str | SupportsInt | bytes | None = None) dict[source]

Perform a DATETIME_ADJUST command.

Set the offset value for the Real Time Clock (RTC_TCR reg).

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

  • period – The number of seconds skipped between applying the offset.

  • offset – The number of 30.517578125 nano second intervals subtracted or added to the RTC. Signed value from -128 to +127.

  • password – Optional password

Returns:

A dictionary containing new period and offset values.

Raises:

IOStackCommandError – if the command failed.

get_datetime(serial_port: Serial, address: str | SupportsInt | bytes) datetime[source]

Perform a DATETIME_GET command.

Get the current date and time from the Real Time Clock.

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

Returns:

A naive datetime object.

Raises:

IOStackCommandError – if the command failed.

set_datetime(serial_port: Serial, address: str | SupportsInt | bytes, dt: datetime) None[source]

Perform a DATETIME_SET command.

Set the Real Time Clock to the given date and time.

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

  • dt – datetime.datetime object

Raises:

IOStackCommandError – if the command failed.

list_twowire(serial_port: Serial, address: str | SupportsInt | bytes, bus: int) dict[source]

Perform a TWOWIRE_LIST command.

Scan the given TWI/I2C bus for each possible device address and returns a list of addresses that responded with an ACK; functionality is not checked. The I2C spec says that only addresses 8 to 119 are valid. But addresses 1-127 are scanned in case you have a rogue device. The report returns 7-bit addresses. Multiply by 2 to get the 8-bit address. Up to 127 addresses could be reported.

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

  • bus – Twowire bus index

Returns:

A dictionary containing a (possibly empty) list of connected twowire devices:

{
    'device_count': int,
    'devices': [
        {
            'address': int
        },
        ...
    ]
}

Raises:

IOStackCommandError – if the command failed.

scan_twowire(serial_port: Serial, address: str | SupportsInt | bytes, bus: int) dict[source]

Perform a TWOWIRE_SCAN command.

Scan the given TWI/I2C bus to look for recognized devices and attach them.

Each responding address is read to see if the device response is recognized. Recognized devices are assigned a TypeCode for the assumed device type. Returns a list with the address, type code, and associated name for each one. The I2C spec says that only addresses 8 to 119 are valid. But addresses 1-127 are scanned in case you have a rogue device. The report returns 7-bit addresses. Multiply by 2 to get the 8-bit address. Up to 9 entries of address/type/name could be reported.

The TypeCodes are:

  • 0x00 = Unknown Device

  • 0x01 = MCP9808 Temperature Sensor

  • 0x02 = INA219 Current/Power Monitor

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

  • bus – Twowire bus index

Returns:

A dictionary containing a (possibly empty) list of attached twowire devices:

{
    'device_count': int,
    'devices': [
        {
            'address': int,
            'type_code': int,
            'name': str,
        },
        ...
    }
}

Raises:

IOStackCommandError – if the command failed.

read_twowire(serial_port: Serial, address: str | SupportsInt | bytes, bus: int) dict[source]

Perform a TWOWIRE_READ command.

Read the TWI/I2C bus and returns 1 to 3 values from each attached device.

Up to 9 devices could be read.

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

  • bus – Twowire bus index

Returns:

A dictionary containing a (possibly empty) list of attached twowire devices:

{
    'device_count': int,
    'devices': [
        {
            'address': int,
            'type_code': int,
            'value_1': int,
            'value_2': int,
            'value_3': int,
        },
        ...
    }
}

Each value field is a 2-byte integer value. The meaning of each is based on the TypeCode:

TypeCode 1 - value_1 - signed degrees Celsius * 10
             value_2 - zero
             value_3 - zero

TypeCode 2 - value_1 - signed mv
             value_2 - unsigned mW (0's without config setting)
             value_3 - unsigned mA (0's without config setting)

Raises:

IOStackCommandError – if the command failed.

set_twowire_name(serial_port: Serial, address: str | SupportsInt | bytes, bus: int, tw_address: int, name: str, password: str | SupportsInt | bytes | None = None) None[source]

Perform a TWOWIRE_NAME_SET command.

Associate a name string with the given DeviceAddress on the given BusIndex. The BusIndex/DevAddress pair is the same one reported by TWOWIRE_SCAN and by TWOWIRE_READ. The NameString can be 1 to 10 characters long and must always be NULL terminated (must end in 0x00). The name string will remain associated with that particular device through reset or if the device is moved to a different TwoWire bus. If the first byte of NameString is 0 then any current association is deleted.

TWOWIRE_SCAN must be issued at least once before this command to provide the BusIndex/DevAddr pairs that map to specific devices.

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

  • bus – Bus index.

  • tw_address – Twowire device address.

  • name – Up to ten character name.

  • password – Optional password

Raises:

IOStackCommandError – if the command failed.

get_twowire_names(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a TWOWIRE_NAMES_GET command.

Get the BusIndex/DeviceAddress/AssociatedName for each attached device.

The BusIndex/DeviceAddress pair is same the one reported by TWOWIRE_SCAN and by TWOWIRE_READ. The returned AssociatedName is NULL terminated.

TWOWIRE_SCAN must be issued at least once before this command to build the list of recognized and attached devices.

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

Returns:

A dictionary:

{
    'device_count': int,
    'devices': [
        {
            'bus': int,
            'address': int,
            'name': str
        },
        ...
    ]
}

Up to 18 entries of bus/address/name can be reported.

Raises:

IOStackCommandError – if the command failed.

reset_twowire_names(serial_port: Serial, address: str | SupportsInt | bytes, password: str | SupportsInt | bytes | None = None) None[source]

Perform a TWOWIRE_NAMES_RESET command.

Restore the list of associated names for TwoWire devices to default names. The user-supplied names set by set_twowire_name() are all cleared.

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

  • password – Optional password

Raises:

IOStackCommandError – if the command failed.

set_namelist(serial_port: Serial, address: str | SupportsInt | bytes, board: str = 'ioStack', ai_0: str = 'AI0', ai_1: str = 'AI1', ai_2: str = 'AI2', ai_3: str = 'AI3', di_0: str = 'DI0', di_1: str = 'DI1', di_2: str = 'DI2', di_3: str = 'DI3', do_0: str = 'DO0', do_1: str = 'DO1', do_2: str = 'DO2', do_3: str = 'DO3') None[source]

Perform a NAMELIST_SET command.

Set the list of names assigned to the ioStack and the fixed interfaces.

Names have a maximum length of 10 bytes. Unicode strings will be truncated to ten bytes if longer.

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

  • board – Name of device. Default is ‘ioStack’.

  • ai_0 – Name of AI pin

  • ai_1 – Name of AI pin

  • ai_2 – Name of AI pin

  • ai_3 – Name of AI pin

  • di_0 – Name of DI pin

  • di_1 – Name of DI pin

  • di_2 – Name of DI pin

  • di_3 – Name of DI pin

  • do_0 – Name of DO pin

  • do_1 – Name of DO pin

  • do_2 – Name of DO pin

  • do_3 – Name of DO pin

Raises:

IOStackCommandError – if the command failed.

get_namelist(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a NAMELIST_GET command.

Gets the list of names assigned to the ioStack and the fixed interfaces. A name string starts every 11 bytes. Each one should be NULL(0) terminated.

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

Returns:

A dictionary containing name data:

{
    'board': str,
    'ai_0': str,
    'ai_1': str,
    'ai_2': str,
    'ai_3': str,
    'di_0': str,
    'di_1': str,
    'di_2': str,
    'di_3': str,
    'do_0': str,
    'do_1': str,
    'do_2': str,
    'do_3': str,
}

Raises:

IOStackCommandError – if the command failed.

get_do_level(serial_port: Serial, address: str | SupportsInt | bytes, pin: int) int[source]

Perform a DO_GET_LEVEL command.

Get current pin level (0 or 1).

Parameters:
  • serial_port – The serial port.

  • address – The ioStack address (serial number).

  • pin – The zero-based pin number.

Returns:

The pin level (0 or 1).

Raises:

IOStackCommandError – if the command failed.

clear_do_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, level: int = 0, password: str | SupportsInt | bytes = 0) int[source]

Clear watch assigned to DO <pin> if any.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – zero-based DIn/DOut pin number (0-3).

  • level – Optional pin level (0 or 1) to set. Default is 0.

  • password – Optional password

Returns:

The current wave/watch owner id or 0 if no wave/watch found.

Raises:

IOStackCommandError – if the command failed.

set_do_level_clear(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, level: int = 0, password: str | SupportsInt | bytes = 0) int[source]

Perform a DO_SET_LEVEL command.

Set the output state (0 or 1) for one DOut pin.

If the pin is currently assigned to a watch or wave it will be cleared.

This is basically a shorthand for :func:set_do_level with clear_watch=True.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – zero-based DIn/DOut pin number (0-3).

  • level – The digital level (0 or 1).

  • password – Optional password

Returns:

The current pin levels as a bitmap. Bit 0 is pin 0, etc.

Raises:

IOStackCommandError – if the command failed.

set_do_level(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, level: int = 0, clear_watch: bool = False, password: str | SupportsInt | bytes = 0) Tuple[int, int][source]

Perform a DO_SET_LEVEL command.

Set the output state (0 or 1) for one DOut pin.

The level is applied to the output pin and stored in NVRAM to be restored upon reset.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – zero-based DIn/DOut pin number (0-3).

  • level – The digital level (0 or 1).

  • clear_watch – Clear any watch associated with this pin.

  • password – Optional password

Returns:

A tuple containing the owner id of the cleared wave/watch or 0 if there was no wave/watch assigned, and the current pin levels as a bitmap. Bit 0 is pin 0, etc. See get_do_waveform() for a description of wave ids.

Raises:

IOStackCommandError – if the command failed.

get_do_levels(serial_port: Serial, address: str | SupportsInt | bytes) int[source]

Perform a DO_GET_LEVELS command.

Get the current level values for all DOut pins.

Parameters:
  • serial_port – The serial port.

  • address – The ioStack address (serial number).

Returns:

A single byte bitmap containing the current state of each pin (0=low, 1=high). Pin0 is bit0, pin1 is bit1, etc.

Raises:

IOStackCommandError – if the command failed.

set_do_levels(serial_port: Serial, address: str | SupportsInt | bytes, pins: int, do_levels: int, password: str | SupportsInt | bytes = 0) int[source]

Perform a DO_SET_LEVELS command.

Sets the output state (0 or 1) for one or more Digital-Out pins. The new level values are also stored in NVRAM to be restored upon reset. (e.g. pin_map==0x06 do_levels==0x04 sets pin1=0 and pin2=1; and the other pins are unchanged because only 2 bits of select_map are set). (e.g. pin_map==0x08 do_levels==0x0F sets pin3=1 and other pins are unchanged because only bit 3 in select_map is set; other do_levels bits are ignored). The one-byte bit map is always returned and it gives the current 0 or 1 level for all pins after applying the changes.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pins – Bitmap of pin(s) to change (bit 0 is pin 0, etc.)

  • do_levels – Bitmap of pin levels.

  • password – Optional password

Returns:

A bitmap of current pin levels (bit 0 is pin 0, etc.)

Raises:
  • IOStackBusyErr if any of the pins have a wave/watch assigned. – The list of busy pins can be retrieved from the exception object. (do_levels: int, [(busy_pin: int, owner_id: int), …])

  • IOStackCommandError – if the command failed.

get_do_waveform(serial_port: Serial, address: str | SupportsInt | bytes, pin: int) dict | None[source]

Perform a DO_GET_WAVEFORM command.

Gets the settings for any active or pending waveform on a Digital-Out pin.

The owner (source) of the waveform being driven is indicated by the owner_id. The owner_id is one of these ID-type values OR’ed with the owner’s pin number:

OwnerType.DO_WAVE  = 0x10    Digital-Out waveform command
OwnerType.DI_COUNT = 0x20    Digital-In count watch
OwnerType.DI_LEVEL = 0x30    Digital-In level watch
OwnerType.DI_RATE  = 0x40    Digital-In rate watch
OwnerType.AI_LEVEL = 0x50    Analog-In level watch

For a waveform setup by set_do_waveform(), the returned values are from the original command, except for active which is always 1, and cycle count.

For a waveform setup by a watch command, the returned values are from the original command, except for final_level, active, and count.

The value returned in final_level will be from the original command unless the command had restart > 0, in which case it will be the interim_level. The value returned in active will be 0 until the watch triggers and activates the waveform, then active will be 1. Count gives the number of completed cycles for the current activation. If the value of count is 0xFFFF it may have overflowed on continuous cycles.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – DO pin number

Returns:

A dictionary containing the wave attributes for the pin:

{
    owner_id: int,
    hi_sec: int,
    lo_sec: int,
    cycles: int,
    final_level: int,
    active: bool,
    count: int
}

Or None if no wave is assigned to the pin.

Raises:

IOStackCommandError – if the command failed.

set_do_waveform(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, hi_sec: int, lo_sec: int, cycles: int, final_level: int = 0, password: str | SupportsInt | bytes | None = 0) None[source]

Perform a DO_SET_WAVEFORM command.

Drive a repeatable waveform on a Digital-Out pin then set a final level. Drives pin high for hi_sec then low for lo_sec and repeats it cycles times, or continuously if cycles is zero. To drive a single level for a limited time, set that level’s _sec value and the opposite one to zero. Either hi_sec or lo_sec must be greater than one. do_pin will be set to final_level after (hi_sec + lo_Sec) * cycles seconds. To clear a waveform use set_do_level() with clear_watch == True.

Note

cycles also controls what happens on a chip reset (or power loss). If cycles > 0, then a chip reset causes do_pin to be set to final_level and any remaining waveform cycles cleared. If cycles == 0, then the hi_sec and lo_sec values will be used to resume the wave pattern. (Max seconds in 4 bytes is 49,710 days.)

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – DO pin number

  • hi_sec – Number of seconds to set pin level high

  • lo_sec – Number of seconds to set pin level low

  • cycles – Number of cycles

  • final_level – The final pin level after cycles cycles

  • password – Optional password

Raises:

IOStackCommandError – if the command failed.

get_di_levels(serial_port: Serial, address: str | SupportsInt | bytes) int[source]

Perform a DI_GET_LEVELS command.

Get the current level values for all DI pins.

Parameters:
  • serial_port – The serial port.

  • address – The ioStack address (serial number).

Returns:

A single byte bitmap containing the current state of each pin (0=low, 1=high), where pin 0 is bit 0, etc.

Raises:

IOStackCommandError – if the command failed.

get_di_pulse_info(serial_port: Serial, address: str | SupportsInt | bytes, pin: int) dict[source]

Perform a DI_GET_PULSE_INFO command.

Get pulse timing info for one DI pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – DI pin number

Returns:

A dictionary containing the current pin state, the timing info for the current state and previous pulse, the lifetime hi and low seconds, and the resettable pulse count.

Raises:

IOStackCommandError – if the command failed.

get_di_counts(serial_port: Serial, address: str | SupportsInt | bytes, pin: int) dict[source]

Perform a DI_GET_COUNTS command.

Get the lifetime count and resettable count info for one DI pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – DI pin number

Returns:

A tuple containing the response status code and data.

Raises:

IOStackCommandError – if the command failed.

reset_di_count(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, password: str | SupportsInt | bytes | None = 0) None[source]

Perform a DI_ZERO_RSTCOUNT command.

Zero the resettable pulse count for one DI pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – DI pin number

  • password – Optional password

Returns:

The response status code.

Raises:

IOStackCommandError – if the command failed.

get_di_count_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int) dict | None[source]

Perform a DI_GET_COUNT_WATCH command.

Get the status of any count-watch for a single DI pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – The DI pin number

Returns:

A dictionary containing the settings from set_di_count_watch() and pin_level which gives the current pin level and hit_count which is the number of times that count_incr has been achieved. None if no watch is assigned to pin.

Raises:

IOStackCommandError – if the command failed.

clear_di_count_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, password: str | SupportsInt | bytes = 0) bool[source]

Clear watch on AI pulse counter.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – The DI pin number

  • password – Optional password

Returns:

True if watch was cleared successfully. False if no watch found.

Raises:

IOStackCommandError – if the command failed.

set_di_count_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, count_incr: int, reload_watch: int = 0, restart: int = 0, do_pin: int = 0, hi_sec: int = 0, lo_sec: int = 0, cycles: int = 0, initial_level: int = 0, interim_level: int = 0, final_level: int = 0, password: str | SupportsInt | bytes = 0) StatusCode[source]

Perform a DI_SET_COUNT_WATCH command.

Set up a per-second watch on a Digital-In pin’s lifetime pulse counter.

The given count_incr is added to the current value of pin’s counter to create a count target.

When count target is hit, the specified waveform is activated on do_pin.

The watch may or may not reload itself, based on reload_watch. If reload_watch == 0, the watch stops and the waveform is allowed to play out. If reload_watch > 0, the watch will reload itself reload_watch times. If reload_watch == 0xFFFF, the watch will reload itself continuously. In the reload process a new countTarget is calculated and a new watch starts.

When the new count target is hit a fresh waveform is activated immediately. The total hit count can be read anytime with CMD_DI_GET_COUNT_WATCH. NOTE: when using reload_watch > 0, the user should define a waveform that will complete before the time expected for count_incr pulse counts.

If restart==1 the watch will be restarted after a chip reset; if countTarget was reached before the chip reset, the waveform will start immediately.

If pin=0xFF the detection count gets incremented, but with no waveform. Otherwise, a waveform described by hi_sec, lo_sec, and cycles is driven on do_pin. It repeats cycles times, or continuously if cycles`==0. :code:`do_pin is set to initial_level while waiting to hit the first countTarget. do_pin is set to interim_level while waiting to hit a reload_watch count target once the cycles have completed. If a reload_watch count target is hit while a wave is still cycling, a fresh waveform is started immediately. do_pin is set to final_level after the final waveform cycles complete.

To clear the current count-watch for Di_pin, set Di_countIncrement==0. The other parameters are ignored.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – The DI pin number

  • count_incr – Amount to add to pin counter to create count target.

  • reload_watch – Define reload behavior.

  • restart – Clear/restart watch (see comments)

  • do_pin – DO waveform pin number

  • hi_sec – DO waveform level “high”/1 seconds

  • lo_sec – DO waveform level “low”/0 seconds

  • cycles – DO waveform number of cycles

  • initial_level – DO waveform initial pin level

  • interim_level – DO waveform interim pin level after restart

  • final_level – DO waveform final pin level

  • password – Optional password

Returns:

StatusCode.OK Success

StatusCode.OK_CLEARED
    Clear requested and previous watch was cleared

StatusCode.NO_WATCH_FOUND
    Clear requested and no watch found

Raises:
get_di_level_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int) dict | None[source]

Perform a DI_GET_LEVEL_WATCH command.

Get the status of a level watch for a single DI pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – The DI pin number

Returns:

A dictionary containing the settings from set_di_count_watch() and pin_level which gives the current pin level and hit count which is the number of times that count_incr has been achieved. None if no watch is assigned to the pin.

Raises:

IOStackCommandError – if the command failed.

clear_di_level_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, password: str | SupportsInt | bytes = 0) bool[source]

Clear the level watch on the DI pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – The DI pin number

  • password – Optional password

Returns:

True if the pin was cleared.

Raises:

IOStackCommandError – if the command failed.

set_di_level_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, level: int, min_true_sec: int = 0, min_false_sec: int = 0, restart: int = 0, do_pin: int = 0, hi_sec: int = 0, lo_sec: int = 0, cycles: int = 0, initial_level: int = 0, interim_level: int = 0, final_level: int = 0, password: str | SupportsInt | bytes = 0) StatusCode[source]

Perform a DI_SET_LEVEL_WATCH command.

Set up a per-second watch on a Digital-In pin’s level to detect a high or low condition and then drive a Digital-Out pin with a specified waveform. The level on pin must match :code`level` for at least min_true_sec seconds. The value of restart indicates whether to restart the watch (after the level has matched for min_true_sec and then not-matched for min_false_sec):

  • restart = 0 stop the watch after the first match is detected

  • restart = 1 restart the watch after match/nomatch but not after a reset

  • restart = 2 restart the watch after match/nomatch and after a reset

A hit count is kept of the number of times the condition is detected. The hit count is only incremented when the condition goes from false to true. The hit count can be read anytime with the command CMD_DI_GET_LEVEL_WATCH.

If do_pin = 0xFF the hit count gets incremented, but with no waveform. Otherwise, a waveform described by hi_sec, lo_sec, and cycles is driven on do_pin. It repeats cycles times, or continuously if cycles = 0.

do_pin is set to initial_level while waiting for the first hit count. do_pin is set to interim_level while waiting for the next hit after a restart once the cycles have completed. If the watch restarts and detects while a wave is still cycling, a fresh waveform is started immediately. do_pin is set to final_level after the final waveform cycles complete.

To clear the current level-watch for DI pin, set min_true_sec = 0 and min_false_sec = 0. The other parameters are ignored.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – The DI pin number

  • level – The DI pin trigger level

  • min_true_sec – Minimum number of seconds in “true”/1 state

  • min_false_sec – Minimum number of seconds in “false”/0 state

  • restart – Clear/restart watch (see comments)

  • do_pin – DO waveform pin number

  • hi_sec – DO waveform level “high”/1 seconds

  • lo_sec – DO waveform level “low”/0 seconds

  • cycles – DO waveform number of cycles

  • initial_level – DO waveform initial pin level

  • interim_level – DO waveform interim pin level after restart

  • final_level – DO waveform final pin level

  • password – Optional password

Returns:

Status code

StatusCode.OK Success
StatusCode.OK_CLEARED
    Success and previous watch was cleared

Raises:
  • IOStackBusyError – with DO wave owner id if DI pin is busy.

  • IOStackCommandError – with status code StatusCode.DI_INCREMENT_ERR if current lifetime count plus count_incr is too big.

If a waveform is already setup for pin you will receive a response code of StatusCode.DO_BUSY and a wave owner id to indicate the owner id as described in the description for set_do_waveform().

Use set_do_level() to clear an unknown watch or waveform on do_pin.

get_di_rate_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int) dict | None[source]

Perform a DI_GET_RATE_WATCH command.

Get the status of a rate watch for a single DI (digital input) pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – The DI pin number

Returns:

A dictionary containing the settings from set_di_count_watch() and pin_level which gives the current pin level and hit_count which is the number of times that count_incr has been achieved. None if no watch is assigned to pin.

Raises:

IOStackCommandError – if the command failed.

clear_di_rate_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, password: str | SupportsInt | bytes = 0) bool[source]

Clear the DI rate watch on pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – The DI pin number

  • password – Optional device password.

Returns:

True if rate watch was cleared, otherwise False.

Raises:

IOStackCommandError – if the command failed.

set_di_rate_watch(serial_port: Serial, address: str | SupportsInt | bytes, pin: int, level: int, min_ms: int = 7, max_ms: int = 9, allowed_hits: int = 0, restart: int = 0, do_pin: int = 0, hi_sec: int = 0, lo_sec: int = 0, cycles: int = 0, initial_level: int = 0, interim_level: int = 0, final_level: int = 0, password: str | SupportsInt | bytes = 0) StatusCode[source]

Perform a DI_SET_RATE_WATCH command.

Set up a per-millisecond watch on a Digital-In pin to detect a slow or fast pulse rate and then drive a Digital-Out pin with a specified waveform. If the time between rising (low-to-high) edges on Di_pin is greater than max_ms or less than min_ms, then a max or min count is incremented. Each time a rising edge occurs within the Max/Min range, the counters are zeroed. Once per second the Max/Min counts are combined and if it exceeds AllowedHits the HitCount is incremented and the specified waveform is driven on do_pin. NOTE: Since Max/Min counts are only checked once per second, the HitCount can only increment once per second even if AllowedHits is exceeded more often; which can happen if the Di_pin pulse rate is faster than 1 Hz.

AllowedHits must be <= 0xFE. min_ms must be >= 7 and be <= 0xFFFFFFFD. max_ms must be >= 9 and be greater than min_ms + 1. The reciprocal of max_ms is the lower frequency trigger point. The reciprocal of min_ms is the upper frequency trigger point. So, the highest frequency for the upper end of the range is ~143Hz (min_ms = 7) and the highest frequency for the low end of the range is ~111Hz (max_ms = 9). The lowest trackable frequency is ~49.7 days (max_ms = 0xFFFFFFFF).

Restart indicates whether to restart the watch after HitCount is incremented:

  • restart = 0 idle the watch after the first detection

  • restart = 1 restart the watch after each detection but not after a reset

  • restart = 2 restart the watch after each detection and after a reset

The total hit count can be read anytime with CMD_DI_GET_RATE_WATCH.

If do_pin = 0xFF the detection count gets incremented, but with no waveform. Otherwise, a waveform described by hi_sec, lo_sec, and cycles is driven on do_pin. It repeats cycles times, or continuously if cycles`==0. :code:`do_pin is set to initial_level while waiting for the first detection. do_pin is set to interim_level while waiting for detection after a Restart once the cycles have completed. If the watch Restarts and detects while a wave is still cycling, a fresh waveform is started immediately. do_pin is set to final_level after the final waveform cycles complete.

To clear the current rate-watch for pin, set max_ms == min_ms ==0. The other parameters are ignored.

Use set_do_level() to clear an unknown watch or waveform on do_pin.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • pin – The DI pin number

  • level – DI pin trigger level

  • min_ms – Min milliseconds

  • max_ms – Max milliseconds

  • allowed_hits – Allowed hits

  • restart – Clear/restart watch (see comments)

  • do_pin – DO waveform pin number

  • hi_sec – DO waveform level “high”/1 seconds

  • lo_sec – DO waveform level “low”/0 seconds

  • cycles – DO waveform number of cycles

  • initial_level – DO waveform initial pin level

  • interim_level – DO waveform interim pin level after restart

  • final_level – DO waveform final pin level

  • password – Optional password

Returns:

Status code

StatusCode.OK Success
StatusCode.OK_CLEARED
    Success and previous watch was cleared

Raises:

IOStackCommandError – if the command failed.

scan_onewire(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a ONEWIRE_SCAN command.

Scans the four OneWire buses for recognized devices.

Up to 16 devices can be reported, with a maximum of 4 devices per bus. Extra devices are ignored.

Each device is described with a slot number and an assigned name string. The slot number is a single byte. The high four bits gives the bus ID(0-3) and the low four bits gives the scan order. The same slot numbers appear in the response to read_onewire() to associate each result with a device.

The slot number is also used with set_onewire_name() to change the name string assigned to a particular device. The family code is the value returned by the device for a Search ROM command. The name is the name string associated with a specific device. It starts with a default name and can be changed with set_onewire_name().

This should be called once after reset or after a device is attached or removed.

  • Family code 0x10 = DS18S20

  • Family code 0x22 = DS1822

  • Family code 0x26 = DS2438

  • Family code 0x28 = DS18B20/DS18B20-PAR/MAX31820

  • Family code 0x38 = DS1825 MAX31826 MAX31850 MAX31851

  • Family code 0xDD = DHT/AM2302

Note

This command takes a bit of time and requires a longer than normal serial port timeout value (at least five seconds).

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

Returns:

A dictionary containing the number of devices and a (possibly empty) array of device info:

{
    'device_count': int, # The number of onewire devices.
    'devices': [
        {
            'slot': int,
            'family': int,
            'name': str,
        },
        ...
    ]
}

Raises:

IOStackCommandError – if the command failed.

scan_onewire2(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a ONEWIRE_SCAN command.

Scans the OneWire buses for recognized devices and returns a report. A recognized device is one which responds with a valid ROM code that has a supported Family code. Up to 25 devices can be attached and reported. Extra devices are ignored. The report includes an entry for each responding device and gives the 1-byte handle, 8-byte unique device ID and 1-byte bus ID for each.

The 8-byte RomCode is a unique identifier for that physical device. Each device’s ROM code contains 8 bytes; FamilyCode[1] IdNumber[6] CRC[1] The Handle is a value 1-255 that’s assigned as shorthand for the ROM code and starts with a default Handle which can be changed with set_onewire_name(). The Handles are used to identify each device in other ONEWIRE commands and they are what appears in the response to read_onewire(). The bus ID is a 0 based index that tells which bus the device is connected to.

Each reset of the ioStack runs a scan to collect current connection status.

scan_onewire() must be called whenever a device connection is changed unless a reset or power cycle is performed.

The FamilyCode part of the ROM code partially indicates the type of device. Only a few FamilyCodes are supported.

FamilyCode 0x10 = DS18S20 FamilyCode 0x22 = DS1822 FamilyCode 0x26 = DS2438 FamilyCode 0x28 = DS18B20/DS18B20-PAR/MAX31820 FamilyCode 0x3A = DS2413 (dual IO) FamilyCode 0x3B = DS1825 MAX31826 (MAX31850-51 not supported) FamilyCode 0xDD = AM2302 (DHT22)

Request Code/BodyLength/Body:

CMD_ONEWIRE_SCAN[1], 0[1]

Response Body[variable]:

RespondingDeviceCount[1], Handle[1], RomCode[8], BusId[1]

… repeated 10-byte entries, one per recognized device

Note

This command takes a bit of time and requires a longer than normal serial port timeout value (at least five seconds).

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

Returns:

A dictionary containing the number of devices and a (possibly empty) array of device info:

{
    'device_count': int, # The number of onewire devices.
    'devices': [
        {
            'slot': int,
            'uid': bytes,  # 8 bytes
            'bus': int,
        },
        ...
    ]
}

Raises:

IOStackCommandError – if the command failed.

ow_is_disconnected(temp: int, humidity: int, lux: int) bool[source]

Return True if the onewire device is disconnected.

The temp, humidity, and lux values will all be special magic numbers if the onewire device is disconnected.

read_onewire(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a ONEWIRE_READ command.

Read data from the OneWire devices. Up to 16 devices can be reported.

A previous scan_onewire() must called once after reset or device changes.

  • Temperature is a signed 16-bit value giving degrees Celsius * 10.

  • Humidity is a single byte giving the Relative Humidity percentage.

  • Lux is an unsigned 16-bit value giving lumens per square meter.

If a device cannot report humidity, the Humidity value returned is 0xFF. If a device cannot report Lux, the Lux value returned is 0xFFFF. If a device that responded during scan_onewire() does not respond to this READ command then all five data bytes for that device are given as 0xEE.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

Returns:

A dictionary containing the device count and an array of device descriptions:

{
    'device_count': int, # The number of onewire devices.
    'devices': [
        {
            # The device slot number (0-15)
            'slot': int,
            # Temperature if available, otherwise 0xFFFF.
            # Or 0xEEEE if the onewire device does not respond.
            'temp': int,
            # Humidity if available, otherwise 0xFF.
            # Or 0xEE if the onewire device does not respond.
            'humidity': int,
            # Lux if available, otherwise 0xFFFF.
            # Or 0xEEEE if the onewire device does not respond,
            'lux': int,
        },
        ...
    ]
}

Raises:

IOStackCommandError – if the command failed.

read_onewire_io(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a ONEWIRE_READ_IO command.

Read data from DS2413 OneWire devices.

A code:ONEWIRE_SCAN must have been issued(once) after reset or device changes. The State byte has the GPIO pin level in bit[0] and drive level in bit[1]. If a device that responded during ONEWIRE_SCAN does not respond to this READ command then the State bytes for that device are given as 0xEE.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

Returns:

A tuple containing status code and a dictionary containing

the device count and an array of device data:

{
    'device_count': int, # The number of onewire devices.
    'devices': [
        {
            'slot': int,
            'pio_a': int,
            'pio_b': int,
        },
        ...
    ]
}

Up to 16 device entries may be returned

Raises:

IOStackCommandError – if the command failed.

write_onewire_io(serial_port: Serial, address: str | SupportsInt | bytes, slot: int, pio_a: int, pio_b: int) dict[source]

Perform a ONEWIRE_WRITE_IO command.

Sets a drive level for a DS2413 OneWire device. A ONEWIRE_SCAN must have been issued (once) after reset or device changes. The drive level byte for each pin level can be 0 or 1.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • slot – Slot id

  • pio_a – PIOA level (0, 1)

  • pio_b – PIOB level (0, 1)

  • password – Optional password

Returns:

A dict containing the current PIO values:

{'pio_a': int, 'pio_b': int}

Raises:

IOStackCommandError – if the command failed.

set_onewire_idmap(serial_port: Serial, address: str | SupportsInt | bytes, slot: int, uid: bytes, password: str | SupportsInt | bytes | None = None) None[source]

Perform a ONEWIRE_HANDLE_SET command.

Associates a name string to the onewire device sitting at the given SlotId. The SlotId is the one currently reported for that device by scan_onewire() and read_onewire(). The name can be up to 10 characters long. The name string will remain associated with that particular device through reset or if the device is moved to a different OneWire bus. If the name string is empty then any current association is deleted.

scan_onewire() must be called at least once before this command to provide the SlotId values that map to specific devices.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • slot – Slot(handle) value

  • uid – Device unique ID (ROM code)

  • password – Optional password

Raises:

IOStackCommandError – if the command failed.

get_onewire_idmap(serial_port: Serial, address: str | SupportsInt | bytes) dict[source]

Perform a ONEWIRE_HANDLES_GET command.

Returns the SlotId and AssociatedName for each of the attached devices. The SlotId is the one currently reported for that device by ONEWIRE_SCAN and by ONEWIRE_READ. The returned AssociatedName is NULL terminated.

ONEWIRE_SCAN must be issued at least once before this command to provide the SlotId values that map to specific devices.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

Returns:

A dictionary containing the device count and an array of device data:

{
    'device_count': int,
    'devices': [
        {
            'slot': int,
            'uid': bytes,
        },
        ...
    ]
}

Raises:

IOStackCommandError – if the command failed.

reset_onewire_idmap(serial_port: Serial, address: str | SupportsInt | bytes, password: str | SupportsInt | bytes | None = None) None[source]

Perform a ONEWIRE_HANDLES_RESET command.

Restores the list of AssociatedNames for OneWire devices to default names. The user-supplied names set by CMD_ONEWIRE_HANDLE_SET are all cleared.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • password – Optional password

Raises:

IOStackCommandError – if the command failed.

set_password(serial_port: Serial, address: str | SupportsInt | bytes, new_password: str | SupportsInt | bytes, password: str | SupportsInt | bytes) None[source]

Perform a SET_PW command.

Set the device password.

The current password is checked then the new password is written to NVRAM and read back to verify that it was written correctly. If verified, the RAM copy is also updated and StatusCode.OK is returned.

If the NVRAM write fails, an attempt is made to copy the current Password to NVRAM and an error exception is raised

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • new_password – The new password (an int or string of up to 8 decimal digits).

  • password – Current password.

Raises:

IOStackCommandError – with status code StatusCode.NVRAM_UPDATE_ERR - failed to update password StatusCode.INTERNAL_ERR - failed to update and restore password

set_address(serial_port: Serial, address: str | SupportsInt | bytes, new_address: str | SupportsInt | bytes, password: str | SupportsInt | bytes = 0) None[source]

Perform a SET_SN command.

Set the ioStack address (serial number) used to identify the device on a rs485 bus.

Parameters:
  • serial_port – The serial port

  • address – The iostack address (serial number)

  • new_address – The new iostack address

  • password – Optional password

Raises:

IOStackCommandError with status code – StatusCode.NVRAM_VERIFY_ERR - current NVRAM value not as expected StatusCode.NVRAM_UPDATE_ERR - NVRAM update failed, previous restored StatusCode.PROCESS_ERR - NVRAM update and restore attempt failed StatusCode.INTERNAL_ERR - The attempt to restore the SN failed

set_baudrate(serial_port: Serial, address: str | SupportsInt | bytes, baudrate: int, password: str | SupportsInt | bytes = 0) int[source]

Perform a SET_UART command.

Set the ioStack baud rate.

The serial port baud rate is unmodified so it should be configured after a successful request.

Supported rates are: 9600, 19200, 38400, 57600, 115200, 230400

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • baudrate – The new baud rate (must be one of the supported values).

  • password – The password associated with the device, if any.

Returns:

A the current baud rate as returned by the iostack.

Raises:

IOStackCommandError – if the command failed.

set_baudrate_checked(serial_port: Serial, address: str | SupportsInt | bytes, baudrate: int, check_echo: bool = True, password: str | SupportsInt | bytes = 0) bool[source]

Set and check the ioStack baud rate.

Attempt to set the ioStack baudrate and the serial port baud rate. If the ioStack cannot be set to the requested baud rate then this will try to set both the ioStack and serial port back to the initial default baud rate and return False.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • baudrate – The new baud rate (must be one of the supported values).

  • check_echo – Verify that the device is reachable first.

  • password – The password associated with the device, if any.

Returns:

True if successful. False if unable to set and/or verify the ioStack baud rate.

Raises:
recover_baudrate(serial_port: Serial, address: str | SupportsInt | bytes, baudrate: int = 9600, retries: int = 1, verbose: bool = False, password: str | SupportsInt | bytes = 0) bool[source]

Recover baud rate from unknown state.

Try to communicate with the iostack and reset the iostack baudrate and serial port baudrate to the specified baudrate.

Parameters:
  • serial_port – The serial port.

  • address – The iostack address (serial number).

  • baudrate – The new baud rate (must be one of the supported values). Default is 9600.

  • retries – Number of retries at a given baudrate. Default is 1.

  • verbose – Print serial debug information. Default is False.

  • password – Device password. Default is 0.

Returns:

True if successful.

Raises:
split_owner_id(owner_id: int) Tuple[OwnerType, int][source]

Split an owner_id value into the id type and pin number.

pinlevel(pinlevels: int, pin: int) int[source]

Get the level (0 or 1) of the specified digital I/O pin.

Pin numbers are zero-based (0-7 for a one byte (8 pin) level register).

For example if pinlevels = 0x13 and pin = 0, the return value would be 1 (the value of the right-most bit).

This is just a lexical convenience… Same as (pinlevels >> pin) & 0x01

Parameters:
  • pinlevels – Digital pin level bitmap.

  • pin – Pin number.

Returns:

An integer 0 or 1.

address_to_bytes(address: str | SupportsInt | bytes) bytes[source]

Convert an address to a byte array.

password_to_bytes(password: str | SupportsInt | bytes) bytes[source]

Convert a password to a byte array.

normalize_firmware_version(major: Any, minor: SupportsInt | None = None, patch: SupportsInt | None = None) str[source]

Create a canonicalized firmware version string.

Parameters:
  • major – If this is an integer it will be the major version number, otherwise it can be a float, string, byte array, or dict containing major, and optional minor and patch components.

  • minor – Optional minor version number if not None. Default is 0.

  • patch – Optional patch number if not None and greater than 0.

Returns:

A string of the form “<major>.<minor>”.

send_command(serial_port: Serial, address: str | SupportsInt | bytes, command: int, body: bytes = b'', password: str | SupportsInt | bytes | None = None, ok_status: StatusCode | Sequence | None = None) Tuple[StatusCode, bytes][source]

Write command data to a device and wait for a response.

Parameters:
  • serial_port – The serial port.

  • address – The iostack serial number.

  • command – The iostack command op code.

  • body – The command message body (optional).

  • password – Optional password required by some commands

  • ok_status – Optional list of status codes considered to be OK (non-failure) responses

Returns:

A tuple containing (response-code, response-body)

Raises:
data_to_json(response_data: Any, indent: int = 0) str[source]

Convert response data to JSON.

Converts bytes to hex strings and datetime objects to ISO date strings.