Telemetry: MQTT, RFID, GPS, sensors
Four connectors read physical telemetry: a sensor bus, a tag reader, a fleet
tracker and a fixed probe gateway. Every protocol is implemented natively
against its wire format. MQTT 3.1.1 packets, LLRP inventory rounds, Modbus-TCP
register reads and NMEA 0183 sentences are written in FACE, with no third-party
protocol library. All four emit one row type, SensorReading.
Plant equipment normally lives on private networks, so these connectors allow
internal addresses by default. Set allow_internal_network=false on a
connection to refuse them. The cloud instance-metadata address, multicast and the
unspecified address are always refused. See Networking.
Common rules
- An empty batch is not a success. A connector that connected and received
nothing returns
Success=falsewith<type> connector reached <what> and received no readings. A silent reader is reported as silent, never as “no excursions”. - Zero means “use the default” for every window and cap below. It never means “collect nothing”. Values above a maximum are reduced to the maximum.
- Readings are sorted by observed time, then asset, then metric.
- What Test does not establish. A successful probe does not establish that a sensor is publishing, that an antenna is attached or aimed, that a probe is calibrated, or that any readings exist.
MQTT (sensor bus)
| Type spellings | mqtt, mqtts, iot, iothub, sensorbus, messagebus, iottelemetry (iot_telemetry) |
| Config message | MQTTConnectionConfig, or legacy IoTConnectionConfig with endpoint plus a comma-separated topics property |
| Protocol | MQTT 3.1.1 (protocol level 4): CONNECT, SUBSCRIBE, PUBLISH/PUBACK, PING, DISCONNECT |
| Setting | Meaning |
|---|---|
broker_url | tcp://host:1883, tls://host:8883 (also ssl, mqtts), or a bare host:port. The default port is 1883, or 8883 with TLS. |
topics | Topic filters. Required: an empty list is an error, and FACE never subscribes to # by default. A query can override the list with comma-separated filters. |
qos | 0 or 1 (FACE subscribes at QoS 1). 2 is refused. |
client_id | The default is a stable id derived from the connection id |
username | A setting. The password is a credential. |
collect_seconds | The listening window: default 15 s, maximum 5 min |
max_messages | Default 500, maximum 20,000 |
protocol_version | 4 or 0. 5 and 3 are refused with an explanation. |
use_tls, insecure_skip_verify | TLS, and an explicit opt-in to skip certificate verification |
property asset_topic_segment | The topic segment index that holds the asset id |
Credentials: password (also mqtt_password, api_key, token); username
may also come from the bundle.
- Test dials the broker and completes CONNECT/CONNACK within 10 s, then disconnects. It does not subscribe.
- Execute subscribes, listens for the window, and decodes each message:
- JSON objects, arrays, numbers, booleans and numeric strings become readings.
- When a JSON value names no metric, the metric comes from the topic’s last segment.
- Non-JSON payloads are kept as rows with
payload_kindand a short sample. - Topic, QoS and retained flags go into
attributes.
- WebSocket transport, MQTT 5, QoS 2 delivery and persistent sessions are not
implemented. A legacy
iotconnection that declares a non-MQTT protocol (such as AMQP) is refused by name. - Explore returns
supported=false. MQTT has no catalogue call.
RFID (LLRP and vendor REST)
| Type spellings | rfid, epc, llrp, tagreader |
| Config message | RFIDConnectionConfig |
| Setting | Meaning |
|---|---|
protocol | llrp (default, also llrps) or http (also https, rest) |
endpoint | LLRP: host or host:5084. HTTP: the reader’s event API base URL. |
reader_id | Carried onto every reading. It defaults to the endpoint. |
location | Where the reader physically is. It is carried onto every reading. |
antenna_ports | Antennas to enable (1–65535). Empty means all. |
collect_seconds | The inventory round: default 10 s, maximum 2 min |
max_reads | Default 1,000, maximum 50,000 |
report_duplicates | Report every sighting instead of first/last seen per EPC |
use_tls | TLS. It is also implied by https:// or llrps://. |
property api_key_header | The header for an API key (default X-API-Key) |
Credentials for HTTP readers, tried in order:
token→Authorization: Bearerapi_key→ the API-key headerpasswordwith theusernameproperty → HTTP Basic
- Test for LLRP connects and waits for the reader’s connection-attempt event.
For HTTP, it makes one
GETto the event API within 8 s. - Execute runs an inventory round and returns one reading per tag sighting.
EPC, antenna, RSSI and read count go into
attributeswhen the reader states them. HTTP event bodies are capped at 16 MiB, and an over-cap stream is refused rather than reported as a short round. - Explore returns
supported=false.
GPS and telematics
| Type spellings | gps, telematics, eld, nmea, tracker |
| Config message | GPSConnectionConfig |
| Setting | Meaning |
|---|---|
provider | samsara, geotab, generic_rest (also generic, rest, http, https) or nmea (nmea0183). If it is empty and the endpoint is http(s)://, generic_rest is used. |
endpoint | A REST base URL, or host:port for NMEA. Required. |
asset_ids | Restrict to these vehicles or assets. A query may narrow further, but only within this set. |
lookback_minutes | Default 60, maximum 7 days |
collect_seconds | The NMEA listening window: default 15 s, maximum 5 min |
include_sensors | Also request reefer and cargo sensor channels where the provider has them |
property carrier / fleet | Carried onto readings |
Credentials by provider:
| Provider | Credentials |
|---|---|
| Samsara | api_key, token or bearer_token |
| Geotab | database, username, password (or session_id) |
| Generic REST | bearer_token / token, or api_key, or username + password |
| NMEA | None |
- Test:
- Samsara: one
GET /fleet/vehicles/stats?types=gps&limit=1 - Geotab: a
Getof oneDevice - Generic REST: one request
- NMEA: a TCP connect
- Samsara: one
- Execute returns position fixes as readings (
latitude,longitude,geo_stated), with speed and heading inattributes. It also returns sensor channels where requested.- At most 5,000 readings and 20 pages. Truncation is stated in the message.
- REST bodies are capped at 8 MiB.
- NMEA reads
RMC,GGAandVTGsentences, with lines capped at 8,192 bytes. - Units are taken from the provider (for example Geotab’s unit-of-measure ids) and never assumed.
- Explore returns
supported=false.
Sensor gateway (Modbus-TCP and HTTP)
| Type spellings | sensorgateway (sensor_gateway), sensor, modbus, temperature, infrared, thermal, probe |
| Config message | SensorGatewayConnectionConfig with one or more SensorChannel |
| Setting | Meaning |
|---|---|
transport | modbus_tcp (default) or http. mqtt is refused here: use an MQTT connection, which emits the same rows. |
endpoint | Modbus: host:502, or port 802 by default with use_tls. HTTP: a base URL. |
unit_id | The Modbus unit (slave) id |
channels | Required. There is no safe default register. |
collect_seconds | The sampling pass: default 15 s, maximum 5 min |
poll_interval_seconds | The interval between polls: default 5 s. It is carried as sampling_interval_seconds. |
use_tls | Modbus/TCP Security, or HTTPS |
Each SensorChannel states its own mapping:
| Field | Meaning |
|---|---|
asset_id, device_id | What is measured, and by which device |
metric | temperature, infrared, humidity, shock, door or battery. It is written verbatim to the reading. |
address | Modbus: the starting register. HTTP: the JSON path of the value. |
register_type | holding (default), input, coil or discrete |
data_type | int16 (default), uint16, int32, uint32 or float32. Word-swapped variants are accepted. |
scale, offset | value = raw * scale + offset. A scale of 0 means 1. |
unit | Written to the reading’s unit, for example C, F, %RH or g |
threshold_min / _stated, threshold_max / _stated, threshold_source | The band the product spec states, and where it is stated. Leave these unset when nobody stated one. |
HTTP credentials: token, api_key, or username + password.
- Test connects and reads the first channel. For HTTP, it fetches the document and resolves the first channel’s path. A failure names the channel, register and unit. A Modbus exception response is reported as the device’s own refusal.
- Execute polls every channel at the interval for the whole pass. The raw
register and count go into
attributes. - Explore returns
supported=false. Modbus has no register map, so the channel list you configure is the schema.
The SensorReading row
Every telemetry connector, and the Flipper edge reader, returns rows with these columns, in this order:
| Column | Meaning |
|---|---|
asset_id | The thing measured, for example REEFER-12 |
device_id | The thing measuring |
reading_id, window_id | The reading id, and the monitoring run it belongs to |
reference, carrier | Shipment or monitoring reference and carrier, only when the source states them |
observed_at | RFC 3339, UTC |
observed_at_source | Whose clock: device, gateway, or received (receipt time, used when the wire carries no timestamp) |
metric, value, value_stated, unit | The measurement. value_stated=false marks a row with no numeric payload (a heartbeat, a door event, a tag sighting). Such rows are kept, because a gap in a feed is evidence too. |
threshold_min, threshold_min_stated, threshold_max, threshold_max_stated, threshold_source | The band the source stated, and where |
sampling_interval_seconds | The configured cadence. 0 means the source did not say. |
max_excursion_minutes, max_excursion_minutes_stated | The excursion allowance stated by the spec |
load_reference, load_value, load_value_stated | The load on the asset, where named |
location, latitude, longitude, geo_stated | Where the reading was taken |
source, transport | The connection type and the protocol actually spoken |
quality | The source’s own quality flag. FACE never computes it. |
attributes | Everything else the protocol knew, such as EPC and antenna, speed and heading, register and raw count, or topic |
The *Stated fields
In the protocol format FACE uses, “the probe read 0 °C” and “the row has no
reading” look the same, and in a cold chain they are opposite facts. So every
connector sets a *_stated flag from whether the source carried the field,
never from whether the value is non-zero:
- A threshold is never assumed. FACE does not assume 2–8 °C because an asset is called REEFER. A band that no one stated stays unstated, and analysis reports that the threshold was not stated.
- A unit that is absent stays absent. FACE never assumes Celsius.
- A position without
geo_statedis not a position.
Consumers must read a value only when its *_stated flag is true. See
/docs/analysis/ for how these rows feed temperature-excursion
and claims evidence.