Skip to content

tedge-dot 0.0.18

Choose a tag to compare

@reubenmiller reubenmiller released this 09 Nov 21:59
e25e40a

Two interchangeable packages, one binary: tedge-dot-c (C, the default: small, a glibc 2.17
floor, every protocol including the PROFIBUS-DP preview) and tedge-dot-rs (Rust, for the few features
only it has). Whether both remain in the final product is not decided yet; configs and flows work
with either. Install one of them from the thin-edge.io community repository:

sudo apt-get install -y tedge-dot-c    # or tedge-dot-rs

Install & upgrade guide
· README
· Changelog
· SHA256SUMS covers every asset below.

This release also delivers 0.0.17, which was tagged but never published.

Highlights

tedge-dot-c is now the recommended package

The documentation now recommends tedge-dot-c by default: it is about 25 times smaller,
runs down to glibc 2.17 and ships every protocol, including the PROFIBUS-DP preview. Choose tedge-dot-rs
when you need one of the features only the Rust build has (SNMPv3 with SHA-2 or AES-192/256,
OPC UA structured values, the deprecated Basic128Rsa15 policy, CAN FD); the
package picker helps you decide.

  • Nothing changes for an existing install: both packages are still built and released, and a
    config, a flow or a cloud integration works unchanged with either.
  • Whether both packages remain in the final product is not decided yet.

A documentation site

tedge-dot now has a documentation site at https://thin-edge.github.io/tedge-dot/: task-first
guides for every protocol, the reference pages rendered from doc/, and three tools that run in
the browser:

  • a config builder that writes a connector config and checks it against the contract schema
    as you type;
  • a package picker that says whether tedge-dot-rs or tedge-dot-c suits your gateway, and
    why;
  • a report-policy playground that shows what a report table publishes on a signal of your
    choice, using the same rules (and test vectors) as the connectors.

The Markdown in the repository stays the source: edit doc/ and the site follows.

CAN bus, CANopen and PROFIBUS-DP are marked as previews

The CAN bus, CANopen and PROFIBUS-DP connectors are now labelled preview in the README and
the documentation. They are tested in CI against simulators (a virtual SocketCAN bus and a
PROFIBUS-DP slave simulator) but not yet on real equipment, so expect rough edges and changes to
their configuration.

If you run one of them on real hardware, please
tell us how it went.

Measurement output: batched measurements from the connector

A connector can now publish thin-edge measurements itself, hundreds of readings per message,
instead of one sample per reading for the ot-measurement flow to convert. Set
output = "measurements" in the [connector] table. No flow runs for a measurement, which takes
most of the work off the mapper at high reading rates. See
doc/measurement-output.md.

  • Opt-in: without output, a connector publishes samples exactly as before.
  • batch = { group_by = ... } chooses how readings with different timestamps are grouped:
    "time" (default, nothing moved or lost), "frame" (a window) or "sample" (a fixed rate).
  • Samples are still published for points with alarms, events or parameters, and for points with
    sample = true.
  • The OT Connector Contract is now version 0.2.0 (§5.4, §5.5, measured, outputs). The
    additions are optional and do not appear in the default output.

Behavior and API changes. These apply without output = "measurements":

  • Action needed if you use the measurement-series alarm or event (a series in the
    ot-alarm or ot-event params.toml): that mode moved to the new ot-alarm-series and
    ot-event-series flows, and ot-alarm and ot-event no longer subscribe to measurements.
    The package installs the new flow with your params file on upgrade; check that
    /etc/tedge/mappers/c8y/flows/ot-alarm-series/ (or ot-event-series/) exists. If you
    install the flows by hand, copy the new flow from /usr/share/tedge-dot/flows/.
  • Every sample of one read call now has the same ts, the time the call completed. In the C
    build, a module without read_points (Modbus, for example) uses one time per device pass.
    Points that were read together used to have times a few milliseconds apart.
  • Pushed OPC UA values in the C build now carry the server's source timestamp instead of the
    time they arrived, as in the Rust build.
  • For module authors: the Rust Sample has a new public field, source_ts. A module that builds
    a Sample with a struct literal must add source_ts: None (or the protocol's own time). The
    C tdot_sample_t has a new last member, source_ts_ms, so modules must be recompiled against
    the new header; modules that call tdot_sample_init need no source change.

Fewer measurement messages with group_by = "frame"

In measurement output, a frame no longer ends when a point changes twice within the window. The
second value goes into a second message of the same window, the third into a third, and all of
them are published when the window ends. A device with 1,000 changing points now publishes a few
messages per window instead of one for every 30 to 40 values, so a longer window now saves
mapper CPU. See doc/measurement-output.md.

  • Nothing to configure. The examples now use window = "500ms", which suits most pushed
    telemetry.
  • Behavior change for existing frame users: a repeated point's earlier value is published
    at the end of the window instead of at once, still within the window plus one pass.
  • Message times of one measurement topic now always increase. When source times jitter, a
    message can be stamped 1 ms after the previous one instead of with its first reading's time, so
    a point's values reach Cumulocity in the order they were read.
  • The OT Connector Contract is now version 0.2.1 (§5.5).

Mean, minimum and maximum per period in measurement output

A connector in measurement output can now publish, for every point and period, the time-weighted
mean, the minimum, the maximum or the last value, instead of one sampled reading. It accounts for
every reading of the period, so a spike or a drift between two published values still shows. See
doc/measurement-output.md.

[[device]]
name  = "line1"
batch = { aggregate = ["mean", "min", "max"], every = "1s" }   # temp_mean, temp_min, temp_max
  • aggregate = "mean" keeps the point's series name; a list publishes <series>_<aggregate>.
  • The mean is weighted by how long each value held, so change-only pushed data averages correctly.
  • An aggregated point cannot also have a report policy; the configuration is refused.
  • The OT Connector Contract is now version 0.3.0 (§5.5, batch.aggregate).

Devices read in parallel

A connector now reads its devices in parallel, and sends up to four Reads at once to an OPC UA
server, in both builds. A connector used to read one device after another, one request at a
time, so its throughput was set by the PLCs' round-trip times: with 20 ms per read it stopped at
about 22,000 readings/s (16,500 in the C build) while its CPU idled. Measured on the same host,
one connector now reads 64,000 readings/s from 64 devices in both builds, and one OPC UA device
with 20,000 nodes about 64,000 readings/s with the default budget, 80,000 with
max_inflight = 8. See doc/concurrent-reads.md.

  • New max_inflight (default 4) on [connector] or a device: requests in flight to one
    endpoint (a host and port, a serial port or a CAN bus), shared by every device on it. A bus
    always carries one request at a time. max_inflight_total (default 32) bounds all endpoints.
  • A server that answers busy (BadServerTooBusy) gets fewer requests, and the refused one is
    sent again.
  • Behavior change: devices on different endpoints are read in parallel, and OPC UA devices
    get up to four Reads at once. max_inflight = 1 sends one request at a time to each endpoint.
  • Polls now run on their interval's grid, so a 1 s poll no longer runs every 1.0 to 1.2 s.
  • The capability descriptor lists the endpoints (endpoints). The OT Connector Contract is now
    version 0.4.0 (§5.6).

Config workbench

The config builder and the report-policy playground are now one page, the
config workbench (the old links
redirect). Build a connector configuration and try it before you deploy it, in three steps that
share one state:

  1. Signals: up to four simulated signals, each with a behaviour and an optional outage, or
    one of the examples.
  2. Configuration: the config builder, for every protocol, with a point for each signal. Set
    report and batch on [connector] or on a point, and a point's poll_interval,
    sampling_interval or subscribe; a point inherits what it does not set, as on the gateway.
    A demo config runs as well: its point library (points_from) is resolved as the connector
    does. Points and less used sections fold away.
  3. Outcome: which package runs the configuration, what each point's effective report
    policy publishes, and how measurement output batches it: the
    three batch policies (time, frame and sample, with or without aggregates) side by
    side, which signals each measurement is missing, which samples are not sent, and the
    measurement Cumulocity stores.

Its report and batching engines pass the same test vectors as the Rust and C SDKs.

The config builder can now set output, max_inflight, max_inflight_total, batch (with
aggregate), and per point poll_interval, sampling_interval, subscribe, report and
batch.

AVEVA PI Web API connector (preview), and replayed history in the reporting policy

A new aveva-pi connector reads PI points and AF attributes from an AVEVA PI System through the
PI Web API, in both builds. It replaces the community
thin-edge-aveva-pi-connector.
See the AVEVA PI guide and
doc/connectors/aveva-pi-connector-spec.md.

The connector is a preview: it is tested in CI against the project's PI Web API simulator,
but not yet against a real PI System, so expect rough edges and changes to its configuration.
If you run it against a real server, please
tell us how it went.

  • Points are addressed by tag, PI point path, AF attribute path or WebId. WebIds are looked up
    once, and one request reads all of a device's points.
  • Values are pushed over the PI Web API Channels WebSocket with their PI timestamps, or polled
    from the archive (delivery = "recorded"), or read as current values (delivery = "snapshot").
  • After an outage or a restart, each pushed point catches up from the PI archive, from a cursor
    kept in /var/lib/tedge-dot/aveva-pi, bounded by backfill.max_age and backfill.max_events.
  • Writes post a value to the PI stream, so PI points can be Cumulocity device parameters.
  • TLS is verified by default. Authentication is Basic, Bearer or a client certificate, with
    secrets read from files that management commands cannot change, and never over plain HTTP.
    Kerberos is not supported.
  • The packages install /etc/tedge/plugins/ot/aveva-pi.toml with no devices. Users of the
    community plugin: see doc/migration/aveva-pi-plugin.md,
    which includes a script that converts its configuration.
  • Reporting policy (all connectors): a module can mark pushed samples as replayed history.
    min_interval and debounce then measure time on the samples' source time, so a backlog is
    reduced the way the live stream would have been instead of collapsing to two values. The OT
    Connector Contract gains rule 7 in §5.3.

AVEVA, PI System and PI Web API are trademarks of AVEVA Group Limited or its subsidiaries.


0.0.18 (2026-11-09)

Features

  • AVEVA PI Web API connector (aveva-pi) (#107) (462c9cd)
  • batched measurement output from the connector, and a performance harness (#103) (f1f0e45)
  • docs: config workbench, and the site keeps up with the product (#108) (5f61fb3)
  • docs: documentation site (Astro + Starlight) on GitHub Pages (#77) (1452296)
  • frame layers and per-period aggregates in measurement output (#105) (0c4d61f)
  • read devices concurrently within a per-endpoint budget (#106) (dddc707)

Bug Fixes

  • c: release resources on configuration and CLI errors (#111) (88cd602)
  • deps: bump rustls, webpki and site deps for security advisories (#110) (671987e)
  • opcua: a link lost mid-pass takes the link down at once (Rust) (24f9c2a), closes #97
  • opcua: check the retry interval before scanning every point (C) (8a471e9)
  • opcua: check the retry interval before scanning every point (C) (fa0e018)
  • sdk: resolve a point library in linear time (C and Rust) (#87) (4843b25)
  • sdk: stamp the stall heartbeat after every read (C) (93dd44f), closes #97

Performance

  • opcua: poll in blocks of at most MaxNodesPerRead (C and Rust) (9c1254d)
  • opcua: poll in blocks of at most MaxNodesPerRead (C) (a0add82), closes #97
  • opcua: poll in blocks of at most MaxNodesPerRead (Rust) (8858e5f), closes #97

0.0.17 (2026-10-13)

Bug Fixes

  • sdk: log link changes, failed writes and unreadable points (#74) (2d6efe4)