Repository navigation
Releases: otfabric/go-sparkplugb
Release list
go-sparkplugb v0.3.3
Date: 2026-11-01
Previous release: v0.3.2
Fixed
hostandappkeep an update stamped in the millisecond of the NBIRTH that follows it. Delivered before that NBIRTH, it was wiped with the state of the old session, and the value stayed stale until the next rebirth. Seen against srad on NanoMQ with delayed NBIRTHs.edgeno longer publishes an NBIRTH after its NDEATH.Disconnectkept the node online while it published the NDEATH, so a rebirth requested at that moment followed it and a host kept the node online. Seen with a Tahu host on EMQX. The session now ends first, and a message on its way goes out before the NDEATH; a publish after that returnsErrNotConnected. The state changes toDisconnectedbefore the NDEATH is published.
Tests
- A message in the millisecond of the next NBIRTH, for
hostandapp; a rebirth duringDisconnect, foredge.
go-sparkplugb v0.3.2
Date: 2026-11-01
Previous release: v0.3.1
Fixed
- An NBIRTH delivered just after the NDEATH of the same
bdSeqno longer brings a dead edge node back online. MQTT orders messages per topic only, so a will can overtake a rebirth that was in flight when the edge node died;hostandappthen showed the node online for good. For 250 ms after an NDEATH, an NBIRTH with itsbdSeqis dropped, and a rebirth is requested 2 seconds later. A node whose NDEATH had abdSeqahead of the known session goes offline on that NBIRTH. A DBIRTH on an offline node no longer puts the device online.
Changed
- An edge node that restarts within 250 ms with the
bdSeqof its NDEATH comes online only on the rebirth that follows, about 2 seconds later. srad and SparkplugNet start again atbdSeq0, and SparkplugNet does not answer that rebirth.
Tests
hostandapp: late NBIRTHs after an NDEATH, a will before its NBIRTH, a restart with the samebdSeq, and the limits of the 250 ms.
go-sparkplugb v0.3.1
Date: 2026-11-01
Previous release: v0.3.0
Fixed
hostandappkeep the sessions of an edge node apart when a broker reorders messages across topics. MQTT orders messages per topic only, and data messages carry no session number; with rebirths overlapping, as a reordering broker causes, the host took messages of one session for another. Three outcomes, all seen against srad on NanoMQ and reproduced with a unit test each: devices missing after the births until the next rebirth; a device with the values of an earlier session after a restart; and the state frozen, because held data of the ended session carriedseqpast the edge node's, after which every message was behind and held, and no rebirth was requested. Now a message held or arriving out of sequence that is older than the current NBIRTH is dropped, the newest of aseqheld twice is the one applied, and messages of the new session that were applied to the old one before its NBIRTH arrived are applied again after it.- A message behind the expected
seqrequests a rebirth when no NBIRTH follows within 2 seconds. It used to wait for that NBIRTH for ever. A duplicate delivered late now costs one rebirth.
Tests
- A simulated broker that keeps the order per topic only, and an edge node with overlapping rebirths, against
hostandapp: 400 seeds each. Before the fix about 11 in 100 ended without the edge node's state.
go-sparkplugb v0.3.0
Date: 2026-11-01
Previous release: v0.2.3
Changed
GetDataSetValuesandGetTemplateParameterValuereturn the Go type of the datatype, an API change. An Int8 cell or parameter is anint8, not the rawuint32; Int64 anint64, not auint64; the rest asGetValuereturns them. A DateTime cell is atime.Time, not auint64. Code with type assertions onuint32oruint64for those datatypes has to change. It compiles unchanged, and fails at run time.- Every integer out of its datatype's range is rejected, a behaviour change. Metrics (
GetValue), DataSet cells, template parameters and properties returnErrTypeMismatchfor a UInt8 above 255, a UInt16 above 65535, a UInt32 or Int32 that does not fit inlong_value, a DateTime abovemath.MaxInt64milliseconds and an Int8 or Int16 in neither wire form, and for an integer metric whose value is of another kind. Until now they were truncated, or read as 0. A peer that sends such values now gets an error fromGetValue. Valid values decode as before. NewDataSetandNewTemplateParametertake the Go type of the datatype (int8(-8)for an Int8). The rawuint32anduint64still work, but they have to be values of the datatype, which fails for a value out of range that was written before, and they go out in the canonical form: a width-sized Int8 is sign-extended.SetValuerefuses atime.Timebefore 1970 for DateTime and DateTimeArray, which wrapped around to a date far in the future.ErrTypeMismatch.GetDataSetValuesreturnsErrColumnMismatchfor a row with more cells than the DataSet has types.GetQualityreads the property as an Int32 and returns false for a value that is not one.
Added
NewPropertyValueandGetPropertyValue, with the same rules, for a metric's PropertySet.- DateTime in DataSet columns and template parameters, which
NewDataSetandNewTemplateParameterrefused.
Interoperability
- The interop suite pins sparkplugb-interop v0.3.0, which it had at v0.1.0. It runs the third update of
scalarsand the newcompositefixture: DataSets, templates and properties against Tahu, tahu-js and SparkplugNet edges and Tahu, SparkplugNet and sparkplughost hosts, with the form of each Int8 and Int16 checked on the wire. Exclusions and the two SparkplugNet findings are inINTEROPERABILITY.md.
Documentation
INTEROPERABILITY.md, section Integers: what the specification states, and what is this library's reading.
Tests
FuzzIntegerPathsholds the metric, DataSet cell, template parameter and PropertyValue paths to one statement of the rule. Table tests per path.
go-sparkplugb v0.2.3
Date: 2026-10-31
Previous release: v0.2.2
Changed
payload.GetValuerejects an Int8 or Int16 that is not a valid wire value, a behaviour change. It used to truncate every value to the width, so0x100read as Int8 0 and0xFFFFFF7Fas 127. It now accepts the width-sized form and the sign-extended one, which the specification leaves open, and returnsErrTypeMismatchfor anything else. Valid values decode as before. Negative Int8 and Int16 are still encoded sign-extended to 32 bits, as Eclipse Tahu does: nothing changes on the wire.
Documentation
- The Int8 and Int16 encoding is recorded as a specification ambiguity, not a defect of any stack (
INTEROPERABILITY.md,LIMITATIONS.md,docs/CONFORMANCE.md).
Tests
FuzzDecodeSignedInt. The interop suite checks which form each reference edge node has on the wire.
go-sparkplugb v0.2.2
Date: 2026-10-31
Previous release: v0.2.1
Fixed
PahoTransportPublish and Subscribe now honour ctx, fail at once when the connection ends, and stay withinPublishTimeout. paho could block for 30s in the call on a connection that had just dropped, and ctx was ignored.
go-sparkplugb v0.2.1
Date: 2026-10-31
Previous release: v0.2.0
Changed
- Policy 1.2: build output in
bin/andrelease/, a per-package coverage floor, and more tests and CI. No change in behaviour.
go-sparkplugb v0.2.0
Date: 2026-10-30
Previous release: v0.1.3
Summary
Broker logins without a custom transport, aliases that are checked to be unique, and string limits that are enforced.
Changes
Added
UsernameandPasswordinConfigofedge,hostandapp, passed toConnectOpts, so a broker that requires a login no longer needs a custommqtt.Transport. They are never logged.Newrefuses aPasswordwithout aUsername.payload.ErrStringTooLarge.
Fixed
edge: an alias that is not unique across the edge node is refused withErrDuplicateIDbyPublishBirthandPublishDeviceBirth; a later metric used to overwrite the earlier one without a word. A device repeating its birth keeps its aliases.payload.GetValueenforces its limits: a string or StringArray element aboveMaxStringBytesreturnsErrStringTooLarge, and a StringArray aboveMaxArrayElementsreturnsErrArrayTooLarge.MaxStringByteswas exported and unused.
Deprecated
edge.ErrInvalidState: never returned. It stays for source compatibility.
Documentation
- MQTT versions: the Paho adapter asks for 3.1.1 and falls back to 3.1, with no MQTT 5.
docs/LICENSING.mdno longer listspaho.golang, which is not a dependency, and lists the indirect ones. - New: API.md, ARCHITECTURE.md, OBSERVABILITY.md, TESTING.md, docs/FEATURE-STATUS.md.
Build
make e2e,make bench.
Dependencies
golang.org/x/net→ v0.62.0 (govulncheck).
go-sparkplugb v0.1.3
Date: 2026-10-27
Previous release: v0.1.2
Summary
A restarted edge node's DBIRTH delivered before its NBIRTH is no longer
lost; current dependencies and Go releases; and a README that compares
go-sparkplugb with the other Sparkplug B stacks it is tested against.
Changes
Fixed
hostandapp: a message behind the expectedseqis held for the node's next session and applied after its NBIRTH. When a node restarted, NanoMQ and HiveMQ CE sometimes delivered the new session's DBIRTH (seq 1) before its NBIRTH; the host took it for a gap in the old session and dropped it, so the device stayed offline unless a rebirth came. Found by the interop tests against pysparkplug on NanoMQ.
Changed
- Requires Go 1.26 or later (was 1.24):
golang.org/x/netv0.61.0 andgolang.org/x/syncv0.24.0, their latest releases, need it. CI tests Go 1.26 and 1.27, the releases the Go project supports.
Documentation
- README: a comparison with Eclipse Tahu, pysparkplug, SparkplugNet, srad and sparkplughost, from their source at the tested versions; the compatibility matrix by reference stack and broker; the configuration tables list every field (
BdSeqStore,RetryPolicy,Logger,Metrics,OnDeviceCmd) and no longer aUseAliasesfield that does not exist.
go-sparkplugb v0.1.2
Date: 2026-10-27
Previous release: v0.1.1
Summary
The host and the application no longer flood an edge node with rebirth
requests when a broker delivers its messages out of order. Found by the
interop tests against srad on HiveMQ CE.
Changes
Fixed
hostandapp: at most one rebirth request per edge node every 2 seconds, for a seq gap and a reorder timeout as already for a node without a birth. A broker that reorders messages across topics (HiveMQ CE, NanoMQ) made several messages in a row look out of sequence, each answered with its own rebirth request, so the node published one NBIRTH per request and the host was still applying them after the node's NDEATH.
Changed
- Interop tests: the reference roles get a 60 s MQTT connect timeout instead of the contract's 10 s: Eclipse Tahu on a busy runner sometimes did not reach a HiveMQ that had just started in time.