Перейти до вмісту

Parameter value types

Цей контент ще не доступний вашою мовою.

A parameter’s valueType turns the bytes its source supplies into the parameter’s value, and a value you write back into bytes. Every value is a string of at most 1,024 characters; numbers, booleans, and labels also carry their numeric form, except a number too large to hold exactly (see wide integers). name selects the type:

nameValue
strText, or the bytes as base64 or hex
intA whole number, or its label from repr
numA decimal number with ., formatted per decimalPlaces
bool"true" or "false", or the labels from repr
bigintAn integer of any size, as decimal digits
datetimeAn ISO 8601 date and time
ipaddrA dotted IPv4 or colon IPv6 address
macaddraa:bb:cc:dd:ee:ff
geo"lat,lon" in decimal degrees, such as "46.466667,30.716667"

fromBytes (byteRelation on bigint, ipaddr and macaddr) reorders or filters the source bytes to match the device’s byte order before they are decoded:

FieldValues
filterBytesleave-first-byte-in-word or leave-last-byte-in-word
swapBytesInWordstrue exchanges the two bytes of every two-byte word
swapbytes reverses all bytes; words reverses the word order

Numbers are decoded big-endian: the most significant byte comes first. With an empty relation {}, nothing is reordered. Modbus registers arrive in addresses order, each high byte first, so a 32-bit value that the manual lays out high word first, with the addresses listed in that order, needs no swap.

When the addresses supply more bytes than a number needs, num and int use the last bytes. On read, the relation applies in this order:

  1. filterBytes keeps the first or last byte of each two-byte word: for Modbus registers, the high or the low byte.
  2. swapBytesInWords: true exchanges the two bytes within every word.
  3. swap: "bytes" reverses the whole byte sequence; swap: "words" reverses the order of the words and keeps the bytes within each word. A last unpaired byte stays in place.

For source bytes A B C D (registers AB, then CD), with no filter:

RelationBytes decoded
{}A B C D
{ "swap": "bytes" }D C B A
{ "swap": "words" }C D A B
{ "swapBytesInWords": true }B A D C
{ "swapBytesInWords": true, "swap": "words" }D C B A

An unsigned 32-bit integer is int or num with composition.byteLength: 4 and composition.packing: "unsigned-int"; composition.fromBytes is {} for registers sent high word first and { "swap": "words" } for low word first. A 32-bit float is num with composition.packing: "float32" and composition.byteLength: 4, with the same word order rules. When the manual does not state the word order, compare a reading with a value you know.

Two parameters on the same register with leave-first-byte-in-word and leave-last-byte-in-word give its high and low bytes, such as a firmware’s major and minor version. Writes apply the operations in reverse; filtered-out bytes are written as zero.

num, int and bigint scale the decoded number:

value = raw * multiplier + shift

For non-linear scaling, use a transform.

num, int and bigint may set:

{ "transform": { "fromRead": "x * 0.1 - 40", "toWrite": "(x + 40) * 10" } }

The formulas use the formula language and must give a number. In fromRead, x (or #1) is the decoded number after scaling; in toWrite, it is the written value, and the result is scaled back and encoded. Without toWrite, a write is scaled back and encoded as typed. A formula that does not compile is refused on save; a failure that depends on the value fails the read or write with formula_error. To split one register into two values, use filterBytes, not a transform.

Fractional scaling and transforms are exact only within ±9,007,199,254,740,991 (2⁵³ − 1). An eight-byte unsigned-int or signed-int can exceed that, as a large counter or fixed-point total does:

  • With a whole-number multiplier and shift and no fromRead, num and int scale exactly. A result beyond the limit is a decimal string with no numeric form.
  • With a fractional multiplier or shift, or a fromRead, a raw value beyond the limit fails the read with decode_error, even when the scaled value would fit.
  • bigint scales exactly at any size, by whole numbers only. Its transforms need a value within the limit and must give a whole number.

To show such a value in fractional units, read the raw count as bigint with multiplier "1" over the register span the device documents, and divide where it is shown with exact decimal arithmetic. For a totalizer counting 0.001 m³, raw 9007199254740993 is 9007199254740.993 m³; turning the string into a number first loses the last digit.

Some devices send a fixed raw value, such as 0x8000, when they have no reading. On num and int, readUnavailableValue names that raw value as an integer, after byte order and signedness but before scaling and transforms. A matching read fails with decode_error, reason value_unavailable, and is not recorded in history. For example, a signed 16-bit temperature that sends 0x8000 uses readUnavailableValue: -32768. Writes are not affected.

writeValidation sets the limits a written value must meet: min and max, a length, or a list of allowed values. Each of its members must be present; null means no limit. A value outside them fails with encode_error and a reason such as write_value_below_min, write_value_exceeds_max, write_invalid_number, write_value_not_allowed, write_value_too_short or write_value_too_long.

zones on num sets the thresholds where a value turns green, orange or red on screen: min, lowOrangeBegins, greenBegins, highOrangeBegins, highRedBegins and max. repr on int gives labels, each with an optional zone, to listed values; repr on bool gives labels to true and false. A label is one text or one per language. Zones only change how a value is shown; a label replaces the value, while the numeric form stays a number.

FieldNotes
fromBytesByte relation
encodingascii, utf8, utf16le, base64 or hex
nulTerminatedText stops at the first NUL byte; true by default
writeValidationminLength, maxLength, allowedValues, each required; null for no limit

nulTerminated applies to ascii, utf8 and utf16le; hex and base64 keep every byte. When it is false, only trailing NUL padding is removed. ASCII is strict: bytes above 0x7f read as the replacement character U+FFFD, and ASCII writes refuse other characters.

FieldNotes
composition.fromBytesByte relation
composition.byteLength1–8
composition.packingunsigned-int, signed-int, bcd-int, float32 or float64
multiplier, shiftScaling
decimalPlaces0–15, or null (the default)
readUnavailableValueOptional; see unavailable readings
transformOptional; see transforms
writeValidation.min / maxRequired numbers; null for no limit
zonesOptional; see zones and labels

With decimalPlaces set, the value always has that many decimals, trailing zeros included. With null, it is rounded to as many decimals as the multiplier has, and trailing zeros are dropped: a multiplier of 0.01 gives at most two decimals, and a multiplier of 1 gives whole numbers, also for a float32. The numeric form is not rounded.

The packings float16, decimal16, decimal32 and decimal64 cannot be read or written.

The composition is either:

  • from bytes: byteLength 1–8, packing unsigned-int, signed-int or bcd, and fromBytes; or
  • from bits: fromBits, a list of 1–53 bit indices (0–63, counted as for bool), and signed.

Also: multiplier, a whole-number shift, optional readUnavailableValue and transform, writeValidation with whole-number min and max, and optional repr: a list of { value, repr, zone }. When a reading matches a value, the parameter’s value is its label. Writes accept numbers and the labels in any language.

FieldNotes
bit0–63, or null: then any non-zero value is true
reprOptional { true, false } labels, each up to 100 characters

Writes accept "true", "false", and the labels in any language.

bit counts in the source bytes in address order: byte floor(bit / 8), then bit bit % 8 from that byte’s least significant bit. Bit 0 is the low bit of the first byte, and bit 8 the low bit of the second. A Modbus register arrives high byte first, so its least significant bit is bit 8.

Bit N of a register as a device manual numbers it (bit 0 the least significant) is bit N + 8 for N below 8, and bit N − 8 for N from 8 to 15. For a 32-bit value in two registers sent high word first, the value’s bit N is bit N XOR 24: bits 0–7 are bit 24–31, and bits 24–31 are bit 0–7.

byteRelation, signed, and multiplier and shift as whole-number strings (multiplier not "0"); an optional transform; and writeValidation with min, max and allowedValues as whole-number strings. The value is decimal digits with no numeric form, whatever its size. See wide integers.

composition.kind is one of:

KindBytes
timestamp-sec-32Unix time in seconds
timestamp-msec-32A 32-bit millisecond counter
timestamp-days-32 / timestamp-days-16A day counter
iso-8601-stringISO 8601 text
datetimeYear, month, day, hour, minute, second at byte or word positions, with optional timezone offset

Also: displayFormat (up to 100 characters; Setup suggests YYYY-MM-DD HH:mm:ss), shiftSeconds, and timezone, an IANA name, or null for UTC.

With timestamp-sec-32, composition.zeroIsUnavailable: true makes a raw zero mean “no date”: such a read fails with decode_error, reason timestamp_unavailable, and records nothing in history, and a write that would send zero is refused. Without it, zero reads as the Unix epoch, 1970-01-01.

The value is always ISO 8601. The app shows dates as YYYY-MM-DD HH:mm:ss in the browser’s timezone, and reports in the report’s timezone.

variant (ipv4 or ipv6) and byteRelation.

byteRelation only.

The value is "lat,lon" in decimal degrees. A write with a latitude outside −90…90 or a longitude outside −180…180 is refused. Setup and the live value editor show latitude and longitude as two fields. geo has no numeric form.

The composition’s encoding is one of:

  • scalar: latitude and longitude each have fromBytes, position, byteLength 1–8, packing unsigned-int, signed-int, float32 or float64, and multiplier and shift (degrees = raw * multiplier + shift). This covers floats and whole arcseconds (multiplier 1/3600).
  • dms: degrees, minutes and seconds byte fields for each axis, and a shared quadrant (0 NE, 1 NW, 2 SE, 3 SW).

decimalPlaces (0–15 or null) formats both axes like num. With null, scalar takes the decimals from each axis’s multiplier, and dms uses seven decimals.

The value type decodes the bytes its source supplies:

SourceBytes suppliedValue type that decodes them
Calc returnFormat: "int"4 bytes, signed 32-bit integer, big-endianint / num, byteLength: 4, signed-int
Calc returnFormat: "float"8 bytes, IEEE 754 binary64, big-endiannum, float64, byteLength: 8
One holding or input register2 bytes, high byte firstint / num, byteLength: 2
Two registers holding a float4 bytes in register ordernum, float32, with swap for the device’s word order
Coil or discrete input1 byte per address, 0x00 or 0xffbool (bit null or a specific bit)
Const textThe stored bytesstr with the stored encoding

A value type that does not match its source bytes usually saves and then fails at read or write time with decode_error or encode_error, so read the parameter once after you save it. A Modbus source with fewer addresses than a fixed-width value type needs is refused on save (modbus_source_too_short).

Switching the type’s name in Setup replaces the whole value type with the defaults of the new type.

A write sends the value as a string:

Value typevalue to send
num / intA decimal number ("21.5", "3"); int also accepts its labels
bool"true" or "false", or the labels
strThe text, encoded by the type’s encoding
bigintDecimal digits
datetimeISO 8601
ipaddr / macaddr / geoThe forms in the table at the top

A value that fails writeValidation fails with encode_error and a reason; a disabled parameter fails with param_disabled. See live value procedures.

A 32-bit float in two registers sent low word first, shown with two decimals, writable from −40 to 120:

{
"name": "num",
"composition": {
"fromBytes": { "swap": "words" },
"byteLength": 4,
"packing": "float32"
},
"multiplier": 1,
"shift": 0,
"decimalPlaces": 2,
"transform": null,
"writeValidation": { "min": -40, "max": 120 },
"zones": null
}