Skip to content

Real Array Datatypes

Stephen Chryn edited this page Aug 3, 2026 · 1 revision

Real Array Datatypes

REALARRAY and LREALARRAY share the RealArray template. They behave identically to the numeric array types with one important distinction: because floating-point values cannot be reliably compared to zero using ==, all empty-slot checks use a tolerance threshold of 1e-9. Any value with abs(v) < 1e-9 is considered an empty slot.

Type Accessor Element type Precision
REALARRAY actions.realarray REAL 32-bit IEEE 754 single
LREALARRAY actions.lrealarray LREAL 64-bit IEEE 754 double
from ethernetip_emulator.server.device import actions

# Tag definitions
("O_Temperatures", actions.type.REALARRAY([0.0, 0.0, 0.0, 0.0]))
("O_Pressures",    actions.type.LREALARRAY([0.0, 0.0, 0.0, 0.0]))

Slot Convention

Empty slots are identified by the _is_zero check: abs(v) < 1e-9. This means:

  • 0.0 is an empty slot ✓
  • 0.0000000001 is not empty (exceeds tolerance)
  • -0.0000000001 is not empty (exceeds tolerance)

This is intentional — it avoids false positives from floating-point arithmetic rounding. If you store legitimate values very close to zero, be aware they may be treated as empty slots by list operations.

Core Read / Write

get_val(name, key?)

Returns the full array or a sub-range as a list[float].

Parameter Type Default Description
name str — Tag name.
key slice | None full array Sub-range to read.
actions.realarray.get_val("O_Temperatures")               # → [23.5, 0.0, 18.1, 0.0]
actions.realarray.get_val("O_Temperatures", slice(0, 2))  # → [23.5, 0.0]

set_val(name, value, key?)

Writes a list of floats to the array or a sub-range.

Parameter Type Default Description
name str — Tag name.
value list[float] — Values to write.
key slice | None full array Sub-range to write.
actions.realarray.set_val("O_Temperatures", [23.5, 0.0, 18.1, 0.0])
actions.realarray.set_val("O_Temperatures", [99.9], slice(2, 3))  # write only index 2

Inspection

size(name)

Returns the total number of elements, or None if the tag does not exist.

actions.realarray.size("O_Temperatures")   # → 4

count(name, key?)

Returns the number of non-zero elements (using the 1e-9 tolerance).

# [23.5, 0.0, 18.1, 0.0]
actions.realarray.count("O_Temperatures")   # → 2

is_full(name, key?)

Returns True if every element is non-zero (outside tolerance).

actions.realarray.is_full("O_Temperatures")   # → False

is_empty(name, key?)

Returns True if every element is within 1e-9 of zero.

actions.realarray.is_empty("O_Temperatures")   # → False

find(name, value, key?)

Returns the zero-based index of the first element within 1e-9 of value, or None if not found.

# [23.5, 0.0, 18.1, 0.0]
actions.realarray.find("O_Temperatures", 18.1)   # → 2
actions.realarray.find("O_Temperatures", 99.9)   # → None

List Operations

append(name, value, key?)

Writes value into the first slot within tolerance of 0.0 (scanning left to right). Returns True on success, False if no empty slot is available.

# [23.5, 0.0, 18.1, 0.0]
actions.realarray.append("O_Temperatures", 21.0)   # → True
# [23.5, 21.0, 18.1, 0.0]

prepend(name, value, key?)

Writes value into the last slot within tolerance of 0.0 (scanning right to left). Returns True on success, False if no empty slot is available.

# [23.5, 21.0, 18.1, 0.0]
actions.realarray.prepend("O_Temperatures", 5.5)   # → True
# [23.5, 21.0, 18.1, 5.5]

pop(name, key?)

Clears (sets to 0.0) the last non-zero element and returns its value. Returns None if all elements are within tolerance of zero.

# [23.5, 21.0, 18.1, 5.5]
actions.realarray.pop("O_Temperatures")   # → 5.5
# [23.5, 21.0, 18.1, 0.0]

insert(name, index, value, key?)

Inserts value at index, shifting all subsequent elements one position to the right. The last element is lost if the array is full. Returns False if there is no room (last element is non-zero), True on success.

# [23.5, 21.0, 18.1, 0.0]
actions.realarray.insert("O_Temperatures", 1, 99.9)   # → True
# [23.5, 99.9, 21.0, 18.1]

remove(name, index, key?)

Removes the element at index, shifting subsequent elements one position to the left. The last element is set to 0.0. Returns the removed value, or None if the element at index was within tolerance of zero.

# [23.5, 99.9, 21.0, 18.1]
actions.realarray.remove("O_Temperatures", 1)   # → 99.9
# [23.5, 21.0, 18.1, 0.0]

Bulk Mutations

clear(name, key?)

Sets all elements (or a sub-range) to 0.0.

actions.realarray.clear("O_Temperatures")
# [0.0, 0.0, 0.0, 0.0]

Listening for Changes

on_change defaults to the full array slice when no key is provided.

# Fires when any element in the array is written
@actions.realarray.on_change("O_Temperatures")
def any_changed(attr, key, value):
    print(f"Temperatures updated: {actions.realarray.get_val('O_Temperatures')}")

# Fires only when index 0 is written
@actions.realarray.on_change("O_Temperatures", key=slice(0, 1))
def sensor_0_changed(attr, key, value):
    print(f"Sensor 0 reading: {value[0]:.2f}")

See Working with Actions for full documentation on key and defer.

Method Reference

Method Description
get_val(name, key?) Read the full array or a sub-range as list[float]
set_val(name, value, key?) Write a list of floats to the array or a sub-range
size(name) Return the total number of elements
count(name, key?) Count non-zero elements (tolerance: 1e-9)
is_full(name, key?) True if all elements are non-zero
is_empty(name, key?) True if all elements are within 1e-9 of zero
find(name, value, key?) Return the index of the first element within 1e-9 of value
append(name, value, key?) Write into the first zero slot
prepend(name, value, key?) Write into the last zero slot
pop(name, key?) Clear and return the last non-zero element
insert(name, index, value, key?) Insert at index, shifting right
remove(name, index, key?) Remove at index, shifting left
clear(name, key?) Set all elements to 0.0
on_change(name, callback?, key?, defer?) Register a change listener

Clone this wiki locally