Skip to content

Report strategy overwrites original telemetry timestamp with current time on periodic resend #2119

@tijn-hedgehog

Description

@tijn-hedgehog

Description

When using ON_REPORT_PERIOD or ON_CHANGE_OR_REPORT_PERIOD report strategies, the periodic reporting thread overwrites the original telemetry timestamp with int(time() * 1000) (current wall-clock time) before re-sending. This makes it impossible for downstream consumers to detect stale data. The timestamp always looks fresh even if the source device stopped updating hours ago.

Where

thingsboard_gateway/gateway/report_strategy_service.py, in __periodical_reporting():

if report_strategy_data_record.is_telemetry():
    # data_entry.add_to_telemetry(TelemetryEntry({key: value}, report_strategy_data_record.get_ts())) # Can be used to keep first ts, instead of overwriting it with current ts # noqa
    current_ts = int(time() * 1000)
    data_entry.add_to_telemetry(TelemetryEntry({key: value}, current_ts))
    report_strategy_data_record.update_ts(current_ts)

The commented-out line preserves the original timestamp, but the active code replaces it.

Impact

With ON_CHANGE_OR_REPORT_PERIOD, if an OPC-UA node or MQTT device goes stale (stops updating its value), the gateway keeps re-sending the last cached value with a fresh timestamp every report period. ThingsBoard shows the telemetry as recently updated, so there's no way to tell the device is actually offline or stuck.

This breaks any staleness detection on the ThingsBoard side (dashboards, rule chains, frontends checking ts age).

Expected behavior

Periodic resends should preserve the original telemetry timestamp from when the value was last actually received from the device. The receivedTs in metadata already tracks when the gateway forwarded it, so that covers the "last forwarded" use case.

Suggested fix

if report_strategy_data_record.is_telemetry():
    data_entry.add_to_telemetry(TelemetryEntry({key: value}, report_strategy_data_record.get_ts()))

Remove the current_ts override and the update_ts(current_ts) call. This way:

  • Periodic resends keep the original source timestamp → staleness is detectable
  • Value changes still get a fresh timestamp via filter_datapoint_and_cache
  • receivedTs in metadata still reflects when the gateway last forwarded

Reproduction

  1. Configure a device with ON_CHANGE_OR_REPORT_PERIOD strategy (e.g. 60s report period)
  2. Send one telemetry value, then stop the device
  3. Observe ThingsBoard latest telemetry — the ts keeps updating every 60s even though the device is offline

Version

Latest main branch (also present in 3.x releases)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions