threat-zone-detection
threat-zone-detection measures the distance between one target entity and each tracked entity over time. It emits alternating safe-zone and threat-zone phases as a responseTime channel for the ResponseTime widget.
Entity-state records are the JSON records array that hydrate-protobuf-v2 emits with extractionTarget: EntityState. For every frame the node computes the great-circle distance from the target to each tracked entity. Distances at or below thresholdKm are a threat phase. Distances above it are a safe phase. Crossing times are interpolated linearly between the two frames either side of the crossing.
The output is one Channel inside a data service payload. It is not a map. Pair it with entity-state-to-mapdisplay when you also want to see the tracks.
When to use
Use this node when a dashboard needs a timeline of how long each tracked entity spent inside a distance band around a target.
Pipeline position
hydrate-protobuf-v2 (EntityState) -> threat-zone-detection -> json-merge -> dashboard-v2The node reads the latest output of one parent.
Configuration
Configuration is required.
The node’s validation requires realmMapping and also requires entriesPath, timeField, entitiesPath and entityNameField to be present as strings. Set all of them explicitly, even when you use the default values. realmMapping is not declared in the runner manifest schema today.
| Key | Type | Required | Default | Description |
|---|---|---|---|---|
entriesPath | string | Yes (see note) | records[*] | JMESPath (a query language for JSON) to the array of time-ordered records. |
timeField | string | Yes (see note) | simulation_time_seconds | Dotted path from each record to its simulation time. |
entitiesPath | string | Yes (see note) | entity_state.entity | JMESPath from each record to its entity object or array of objects. |
entityNameField | string | Yes (see note) | name | Dotted path from each entity to its name. |
threatEntity | string | Yes | none | Name of the target entity that defines the zone. |
alliedEntities | array of string | Yes | none | Names of the tracked entities to measure against the target. At least one. |
realmMapping | object | Yes | none | Maps each name in alliedEntities to a label. The label, capitalised, becomes the row (x) for that entity’s phases. |
latField | string | Yes | none | JMESPath from each entity to its latitude. |
lonField | string | Yes | none | JMESPath from each entity to its longitude. |
thresholdKm | number | No | 20 | Distance in kilometres. At or below this value is a threat phase. |
Output
A data service payload with one responseTime channel in the overview realm. The channel id is rt-threat-zones and the group id is responseTime. Phases for every tracked entity share one rangeData entry, and each phase names its row through x.
{
"$heat-dataservice": {
"version": "1.0",
"groups": [{ "id": "responseTime", "name": "Response Time" }],
"realms": [
{
"name": "overview",
"channels": [
{
"id": "rt-threat-zones",
"name": "rt-threat-zones",
"groupId": "responseTime",
"shape": "responseTime",
"data": {
"code": "response-time",
"description": "Response Time",
"barHeight": "16px",
"legend": {
"items": [
{ "label": "Safe Zone", "order": 0, "line": 1, "code": null, "min": null, "max": null },
{ "label": "Threat Zone", "order": 1, "line": 1, "code": null, "min": null, "max": null }
]
},
"rangeData": [
{
"groupName": "Status",
"data": [
{ "name": "Threat Zone", "x": "Alpha", "y": ["2026-05-01T18:26:50Z", "2026-05-01T18:26:55.557Z"], "fillColor": "#DB2828" },
{ "name": "Safe Zone", "x": "Alpha", "y": ["2026-05-01T18:26:55.557Z", "2026-05-01T18:27:17.035Z"], "fillColor": "#21BA45" }
]
}
]
}
}
]
}
]
},
"dashboard_users": []
}Time handling: the value at timeField is treated as Unix epoch seconds and converted to an ISO 8601 UTC string.
Edge cases:
- All frames safe or all frames threat produce one phase spanning the whole run.
- A frame without the target entity is skipped for every tracked entity.
- A frame without one tracked entity is skipped for that entity only.
- Missing or non-numeric positions skip that entity for that frame.
Limitations
- One parent, latest output only.
simulation_time_secondsmust already be epoch seconds. There is no base time stamp offset.- Distance is the great-circle distance on a sphere of radius 6371 km. Altitude is ignored.
- The node fails when no valid frame remains after filtering.
Related
- ResponseTime (Next) renders the channel.
- entity-state-to-mapdisplay shows the same entities on a map.
- json-merge combines this payload with other channels before
dashboard-v2.