External TimescaleDB SQL
If you want to store telemetry in your own TimescaleDB (in addition to or instead of Internal DB), use the PostgreSQL output in a rule. This page gives the schema and the template mapping for a single SenFlat v1 message.
Download timescaledb-eksternal.sql (hypertables, compression, and views; safe to run again). Run it as the database owner:
psql "$URL" -f timescaledb-eksternal.sqlTwo tables, one rule per table, because the PostgreSQL output writes one row per message in the normal mode. For many rows per message see Rule to PostgreSQL: many rows.
Setup in the Rules editor
Section titled “Setup in the Rules editor”- Channel Subscriber: the channel with the devices. The subtopic
+/telemetryfor the telemetry rule;+/eventand+/statusfor the events table. - Logic: a Comparison that forwards SenFlat messages, for example
message.payload.fequalsflat. Without this filter,configandcmdmessages are processed too and fail in the template. - PostgreSQL output: host, port, user, password, database,
sslmodeaccording to the server (requireby default), Schemaiot, and the Table as below.- Use a dedicated user that only has
INSERT(an exampleCREATE ROLEandGRANTare at the end of the SQL file). - A server on a private network is refused by the network guard unless the administrator enables
RULES_ALLOW_PRIVATE_TARGETS.
- Use a dedicated user that only has
An empty template result becomes NULL, so a metric the device did not send is automatically NULL; numbers and booleans are converted by PostgreSQL to the column type.
The table iot.device_telemetry
Section titled “The table iot.device_telemetry”| Column | Template |
|---|---|
time |
{{.Message.created}} |
device_ts |
{{with .Message.payload.t}}{{printf "%.3f" .}}{{end}} |
device_id |
{{with .Message.payload.id}}{{.}}{{else}}{{.Message.publisher}}{{end}} |
channel_id |
{{.Message.channel}} |
publisher |
{{.Message.publisher}} |
subtopic |
{{.Message.subtopic}} |
temp_inlet, temp_outlet, temp_ambient, humidity |
{{.Message.payload.m.temp_inlet}} (the same metric name) |
voltage, current, power_draw, energy, frequency, power_factor |
{{.Message.payload.m.voltage}} |
uptime, heap_free, door_front_open, door_rear_open |
{{.Message.payload.m.uptime}} |
metrics |
{{json .Message.payload.m}} |
The table iot.device_events
Section titled “The table iot.device_events”| Column | Template |
|---|---|
time, device_ts, device_id, channel_id, publisher, subtopic |
The same as above |
state |
{{.Message.payload.m.state}} |
fw |
{{.Message.payload.m.fw}} |
ip |
{{.Message.payload.m.ip}} |
metrics |
{{json .Message.payload.m}} |
The full content of an event (for example {"door_front_open":true}) is in the metrics column:
SELECT * FROM iot.device_events_v WHERE kind = 'event' AND metrics ? 'door_front_open';timeis the receive time at the broker. The device’s measurement time (t) is stored indevice_tsand is available asdevice_timein the*_vviews.- A new metric from the firmware does not require changing the rule: it goes into
metrics(jsonb). For your own column:ALTER TABLE iot.device_telemetry ADD COLUMN name double precision;then add one column row on the output. - One output has at most 30 columns.
- The output rate limit: a burst of 100 rows and 50 rows per second per output. For many devices with short intervals, watch for errors in the Executions tab.
- This output reads messages that are a single SenFlat object. A combined array or SenML needs a different rule and template.