A fleet of identical devices
Every ACME meter of the same firmware has the same registers; only its address differs. Writing
the full point list into every [[device]] means copying it 50 times and fixing it 50 times. A
point library keeps that list in one file, and each device references it.
What you’ll build: a library for one device type, a configuration where each instance is four lines long, a site-specific adjustment that survives package upgrades, and a device added at runtime from its address alone.
How it fits together
Section titled “How it fits together”A point library is the point list of one device type, in its own TOML file, with no
connection information at all. It holds only a [library] table and [[point]] entries. A
device references one or more libraries with points_from, and declares only what is
per-instance:
[[device]]name = "plc-7"protocol_address = { transport = "tcp", host = "192.168.0.17", port = 502, unit_id = 1 }points_from = ["acme-meter-v2"] # points.d/modbus/acme-meter-v2.tomlReferences are resolved when the configuration is loaded. A protocol module, a flow and the samples see no difference between an inherited point and one written inline.
Write the library
Section titled “Write the library”-
Start from the
[library]table.protocolmust match the connector that loads it, andtypenames the device type the points describe. This is the header of the demo Modbus library that ships with the package:Viewdemo/points.d/modbus/demo-sim.toml [library]protocol = "modbus"# The device *type* this list describes (§3.1): it names the parameter sets of every# device that references this library, which is what keeps two device types on the# same protocol from sharing a (tenant-wide) Cumulocity identifier.type = "modbus-demo-sim"description = "pymodbus simulator, as seeded by demo/docker-compose.yaml's modbus-sim"version = "1"demo/points.d/modbus/demo-sim.tomlon GitHub -
Add the points, with exactly the fields a
[[device.point]]takes. Give them anameand adescription: declared once here, they reach every instance, the Cumulocity parameter UI and the connector’s retained capability descriptor. A sensible reporting policy for the device type belongs here too:Viewdemo/points.d/modbus/demo-sim.toml [[point]]id = "temp_scaled"name = "Boiler temperature"description = "Measured boiler loop temperature, scaled to °C"datatype = "uint16"address = { table = "holding", address = 3, count = 1 }transform = { decimal_shift = -3 }unit = "°C"report = { deadband = 0.5, min_interval = "10s" }demo/points.d/modbus/demo-sim.tomlon GitHub -
Install it where the connector looks. A name in
points_fromresolves to<dir>/<protocol>/<name>.toml, in each directory of the search path, first match winning:Directory For /etc/tedge/plugins/ot/points.dyour own libraries; they shadow packaged ones of the same name /usr/share/tedge-dot/points.dlibraries shipped by a package So a site’s ACME library goes to
/etc/tedge/plugins/ot/points.d/modbus/acme-meter-v2.toml.
Add the instances
Section titled “Add the instances”Each device needs a name, an address and the reference. The packaged Modbus default config documents the pattern, including a per-instance adjustment:
# ...or, when several devices share one device type's point list, keep that list# in a POINT LIBRARY and give the instance only its address:## [[device]]# name = "plc-2"# type = "acme-meter-v2" # optional here: the library below declares it# protocol_address = { transport = "tcp", host = "127.0.0.1", port = 502, unit_id = 2 }# points_from = ["acme-meter-v2"] # points.d/modbus/acme-meter-v2.toml## # An instance may still add or adjust points without touching the library:# # a repeated id patches it, and only the fields named here change.# [[device.point]]# id = "boiler_temp"# unit = "K"packaging/config/modbus.toml on GitHubThe demo configs work exactly this way: demo/config/modbus.toml
gives its device an address and points_from = ["demo-sim"], and nothing else.
Adjust a packaged list without editing it
Section titled “Adjust a packaged list without editing it”Points are collected in order: each library in points_from order, then the device’s own
[[device.point]] entries. A definition whose id already exists patches the earlier one:
meta,transformandreportmerge key by key, so one field changes without restating the rest;mapis replaced whole (map = {}removes an inherited map);- every other field,
addressincluded, is replaced when the override declares it; { id = "<point-id>", enabled = false }switches an inherited point off.
[[device]]name = "meter-3"points_from = ["acme-meter-v2"]protocol_address = { transport = "tcp", host = "192.168.0.13", port = 502, unit_id = 1 }
[[device.point]] id = "flow_rate" name = "Inlet flow" # only the label changes [[device.point]] id = "flow_rate" report = { deadband = "0.5%" } # other report keys stay as the library set them[[device]]name = "meter-3"points_from = ["acme-meter-v2", "site-extras"] # a second, untyped libraryBecause the device wins over its libraries, a packaged list can be extended and adjusted while
the file the package owns, which an upgrade replaces, stays untouched. To edit a packaged library
itself, copy it to /etc/tedge/plugins/ot/points.d/ under the same name: the packaged copy is
then no longer used. Give it another name if you want both.
Device types and parameter set names
Section titled “Device types and parameter set names”The library’s type is inherited by every device that references it (from the first library
in points_from that declares one; a type on the [[device]] wins). It does two jobs in the
cloud:
- Parameter set names. Writable points are Cumulocity device parameters, grouped into sets
named
<device type>_<group>_parameters, for exampleacme_meter_v2_control_parameters. These names are tenant-wide, so deriving them from the type is what lets two device types on the same protocol coexist. A device without a type falls back to<protocol>_control_parameters, andtedge-dot describewarns about it. - Entity type. The registered child device shows up as an
acme-meter-v2, not a genericmodbus-device.
A point picks its set with meta.parameter.group (relative to the type, and it may be a list
of groups), or names a set outright with meta.parameter.set. See
contract §5.2
and RFC 0005.
Add a device at runtime
Section titled “Add a device at runtime”Because the runtime keeps the reference rather than the expanded points, the define-device
management command can add an instance from its address alone. Whatever finds devices on your
network (mDNS, a subnet scan, an asset inventory) publishes one small command per instance:
tedge mqtt pub -r te/device/main/service/tedge-dot-modbus/ot/cmd/define-device/d1 '{ "status": "init", "device": { "name": "plc-7", "protocol_address": { "transport": "tcp", "host": "192.168.0.17", "port": 502, "unit_id": 1 }, "points_from": ["acme-meter-v2"] }}'The runtime patches the configuration file, which still says points_from = ["acme-meter-v2"]
rather than 200 expanded points, and applies it. A reference introduced by a command must be a
name, never a path. An unresolvable reference fails loudly, naming every path it looked
in: a device never comes up quietly with zero points.