System: ARMAC Current Fire Threats Dashboard
Version: Based on scripts dated 2024-2026
Location: Fairhaven, Victoria, Australia
This is a summary almost entirely produced by AI Claude 4.5 based on the full set of scripts that currently produce the two dashboards Current Fire Threats and Current Fire Comparisons. I have added a post script on how it could be further developed.
by Claude 4.5
1. System Overview
The fire threat calculation system is a multi-layered analysis pipeline that integrates real-time fire event data, satellite thermal detections, burnt area mapping, and meteorological information to produce actionable threat assessments for property defense. The system runs within a Home Assistant automation platform and produces continuous updates on fire proximity, direction, and estimated time to impact.
Key Components
- VicEmergency Event Monitoring (
vic_events_compact.py) - DEA Satellite Hotspot Clustering (
dea_hotspot_cluster_front.py) - FFMVic Burnt Area Boundary Tracking (
ffm_burnt_area_front.py) - Fire Geometry Selection Logic (Home Assistant templates)
- Rate of Spread (ROS) Calculation (Home Assistant templates)
- Wind Alignment and Threat Assessment (Home Assistant templates)
- ETA Calculations (Home Assistant templates)
2. Data Sources and Inputs
2.1 VicEmergency Events (Primary Source)
Script: vic_events_compact.py
Data Source: https://emergency.vic.gov.au/public/events-geojson.json
Purpose: Identifies active fire incidents within a configurable radius of the home location.
Processing:
- Fetches GeoJSON data from VicEmergency API (5-minute polling interval with 2-minute cache)
- Filters incidents within
jf_relevance_radius_km(default: 200 km) of home - Excludes planned burns (identified by category or plannedBurn flag)
- Calculates minimum distance from home to fire geometry:
- For Polygon/MultiPolygon geometries: Distance to nearest polygon edge (0 if inside polygon)
- For Point geometries: Haversine distance from point to home
- Uses equirectangular projection for local distance calculations (accurate within few hundred km)
- Identifies fires as BUSHFIRE (bushFire, grassFire, forestFire event codes) or OTHER
- Maintains
burnt_edge_okflag for fires withinjf_burnt_edge_match_km(default: 10 km) - Returns up to 120 nearest incidents sorted by distance
Distance Calculation Method:
For Polygons: - Projects polygon boundary into local km coordinates (equirectangular) - Computes minimum distance from home (0,0) to each polygon edge segment - Uses ray-casting algorithm to determine if home is inside polygon - Returns 0 if inside, otherwise minimum edge distance For Points: - Uses haversine formula: d = 2R × arcsin(√(sin²(Δlat/2) + cos(lat1)×cos(lat2)×sin²(Δlon/2))) - R = 6371.0 km (Earth radius)
Key Outputs:
- List of fire incidents with: id, lat, lon, distance_km, burnt_edge_ok, geometry_kind, headline, location, status
2.2 DEA Satellite Hotspots (Active Fire Front Detection)
Script: dea_hotspot_cluster_front.py
Data Source: https://hotspots.dea.ga.gov.au/data/recent-hotspots.json (Digital Earth Australia)
Purpose: Identifies the active fire boundary using recent satellite thermal detections, providing a more current fire position than official burnt area polygons.
Processing:
- Fetches recent hotspot detections (last ~72 hours) with 2-minute caching
- Filters hotspots within configurable radius of home (default: 200 km)
- Further filters to hotspots within time window (default: 8 hours) of current time
- Performs density-based spatial clustering:
- Algorithm: Connected components using union-find data structure
- Edge threshold:
jf_hotspots_eps_km(default: 2.0 km) - two hotspots are connected if within this distance - Minimum cluster size:
jf_hotspots_min_points(default: 10 detections)
- Ranks significant clusters by proximity to anchor point (selected fire incident)
- For the best cluster, identifies the hotspot point nearest to home as the "active fire boundary"
Clustering Logic:
@] Given N hotspot points:
- Initialize union-find structure with N components
- For each pair of points (i,j):
- If haversine_distance(i,j) ≤ eps_km:
- Union(i, j) // Merge into same cluster
- If haversine_distance(i,j) ≤ eps_km:
- Collect clusters where size ≥ min_points
- Score clusters: closest-to-anchor → closest-to-home → newest
@]
Key Parameters:
jf_hotspots_query_radius_km: 200 km (search radius from home)jf_hotspots_time_window_hr: 8 hours (only recent detections)jf_hotspots_eps_km: 2.0 km (clustering distance threshold)jf_hotspots_min_points: 10 detections (minimum cluster size)jf_hotspots_anchor_match_km: 20 km (maximum distance from incident point to accept cluster)
Key Outputs:
- Distance to nearest hotspot in best cluster
- Coordinates of nearest hotspot point
- Cluster statistics (size, anchor distance, newest detection time)
2.3 FFMVic Burnt Area Mapping (Official Fire Perimeter)
Script: ffm_burnt_area_front.py
Data Source: https://maps.ffm.vic.gov.au/arcgis/rest/services/Incidents_all/MapServer/20/query
(FFMVic - Forest Fire Management Victoria)
Purpose: Provides official burnt area polygon boundaries for distance and bearing calculations to the confirmed fire edge.
Processing:
- Queries ArcGIS MapServer for SUBTYPE=2 (Current Burnt Area) polygons within radius of anchor point
- Performs two-stage query strategy:
- Query 1: Around selected fire incident point (default radius: 80 km)
- Query 2: Around home point (expanded radius: 120-250 km) if name match fails in Query 1
- Name-based matching:
- Normalizes incident names from VicEmergency and FFMVic (removes stopwords, common prefixes)
- Tokenizes names (e.g., "Grampians Bushfire" → ["grampians", "bushfire"])
- Requires minimum 2-token prefix match for association
- Strips generic terms: bushfire, grassfire, fire, warning, watch, advice, emergency, planned, burn
- Calculates nearest point on polygon boundary to home using segment-by-segment projection
- Selection logic (priority order):
- NAME_PREFIX: Incident name matches ≥2 tokens with FFMVic polygon name, closest to home
- NAME_PREFIX_HOME_FALLBACK: Name match found in expanded home-centric query
- RADIUS: No name match, uses closest polygon within 10 km of anchor point
Boundary Distance Calculation:
@] For each polygon ring:
- Convert polygon coordinates to equirectangular projection (km) centered at home
- For each edge segment (A,B):
- Compute closest point C on segment to origin (home at 0,0)
- t = -((A·v)/(v·v)) where v = B-A [parameterized closest point]
- t = clamp(t, 0, 1) [restrict to segment]
- C = A + t×v
- distance = |C|
- Return minimum distance across all segments
@]
Key Parameters:
jf_burnt_area_query_radius_km: 80 km (initial query radius from anchor)jf_burnt_edge_match_km: 10 km (maximum distance from anchor to accept polygon by proximity)NAME_MIN_PREFIX_TOKENS: 2 (minimum matching tokens for name association)HOME_FALLBACK_MIN_RADIUS_KM: 120 km (expanded search if initial query finds no name match)
Key Outputs:
- Distance to nearest burnt area edge
- Coordinates of nearest point on burnt area boundary
- Incident ID and name from FFMVic
- Match method used (NAME_PREFIX, RADIUS, etc.)
2.4 Meteorological Data (Wind and Weather)
Data Source: Bureau of Meteorology (BOM) - Aireys Inlet weather station
Parameters Collected:
- Wind speed (km/h)
- Wind direction (degrees, 0° = North)
- Wind gust speed (km/h)
- Air temperature (°C)
- Relative humidity (%)
- Dew point (°C)
Processing:
- REST API polling (5-minute intervals)
- Direct integration into Home Assistant sensors
- Used for: - Wind alignment calculations (downwind threat assessment) - Rate of spread (ROS) phase determination - Fire behavior modeling
3. Fire Geometry Selection Logic
Purpose: Determines which data source provides the most accurate and current fire position for threat calculations.
Selection Hierarchy (Priority Order):
3.1 HOTSPOT_CLUSTER_EDGE (Highest Priority)
Conditions:
- DEA hotspot cluster exists with valid distance
- Cluster's anchor point matches selected fire incident (within 0.001° ~111m)
- Cluster anchor distance ≤
jf_hotspots_anchor_match_km(20 km)
Rationale: Satellite thermal detections provide the most current active fire boundary, updated multiple times per day. Preferred when available as it represents actual burning, not just reported perimeter.
3.2 BURNT_AREA_EDGE (Medium Priority)
Conditions:
- FFMVic burnt area polygon exists with valid distance
- Polygon's anchor point matches selected fire incident (within 0.001°)
- Polygon anchor distance ≤
jf_burnt_edge_match_km(10 km) - No valid hotspot cluster available
Rationale: Official mapped burnt area provides accurate perimeter when hotspots are unavailable or cloud-obscured. Updated less frequently (hours to days) but represents confirmed fire boundary.
3.3 INCIDENT_POINT (Fallback)
Conditions:
- Neither hotspot cluster nor burnt area polygon meets criteria
- Uses VicEmergency incident point coordinates
Rationale: Least accurate but always available. Provides approximate fire location when dynamic boundaries unavailable.
Implementation: Template sensor JF Fire Geometry Source evaluates conditions and sets state to one of three values.
4. Fire Distance and Bearing Calculations
4.1 Fire Distance to Home
Sensor: sensor.jf_fire_distance_km
Calculation Logic:
@]python IF using HOTSPOT_CLUSTER_EDGE:
distance = hotspot_cluster_home_distance_km
\\ELIF using BURNT_AREA_EDGE:
distance = burnt_area_home_distance_km
\\ELSE (INCIDENT_POINT):
distance = haversine(fire_lat, fire_lon, home_lat, home_lon)
@]
Output: Distance in kilometers (2 decimal precision)
4.2 Fire Bearing to Home
Sensor: sensor.jf_fire_bearing_to_home_deg
Purpose: Calculates the compass bearing from the fire position to home. This is the direction the fire would need to travel to reach the property.
Calculation Method:
@] Uses spherical trigonometry (forward azimuth calculation):
Given:
fire_lat, fire_lon = Fire position home_lat, home_lon = Home position
Convert to radians:
lat1 = fire_lat × π/180 lat2 = home_lat × π/180 dlon = (home_lon - fire_lon) × π/180
Calculate bearing:
y = sin(dlon) × cos(lat2) x = cos(lat1) × sin(lat2) - sin(lat1) × cos(lat2) × cos(dlon) bearing_rad = atan2(y, x) bearing_deg = (bearing_rad × 180/π + 360) mod 360
Output: 0-360° where 0° = North, 90° = East, 180° = South, 270° = West @]
Coordinate Source by Geometry Type:
- HOTSPOT_CLUSTER_EDGE: Uses
home_near_lat,home_near_lonfrom hotspot cluster - BURNT_AREA_EDGE: Uses
home_near_lat,home_near_lonfrom burnt area boundary - INCIDENT_POINT: Uses
jf_fire_lat,jf_fire_lonfrom VicEmergency
5. Wind Alignment and Downwind Threat Assessment
5.1 Wind Direction Processing
Sensor: sensor.jf_wind_towards_deg
Purpose: Converts BOM wind "from" direction to "towards" direction (direction wind is blowing).
Calculation: @] wind_towards = (wind_from + 180) mod 360 @]
Example: Wind from 270° (West) → blowing towards 90° (East)
5.2 Downwind Offset Angle
Sensor: sensor.jf_downwind_offset_deg
Purpose: Calculates the angular difference between wind direction and fire-to-home bearing.
Calculation: @] diff = fire_bearing_to_home - wind_towards diff_normalized = ((diff + 180) mod 360) - 180 // Range: -180° to +180° downwind_offset = |diff_normalized| // Absolute angular separation @]
Interpretation:
- 0°: Fire directly upwind, wind blowing straight toward home
- 90°: Fire to the side, wind blowing perpendicular
- 180°: Fire downwind, wind blowing away from home
5.3 Downwind Threat Zone
Sensor: sensor.jf_is_home_downwind
Purpose: Boolean determination if home is within the primary fire spread cone.
Logic: @] half_angle = jf_downwind_half_angle_deg // Default: 40°
IF downwind_offset ≤ half_angle:
is_home_downwind = "YES"
ELSE:
is_home_downwind = "NO"
@]
Configuration Parameter: jf_downwind_half_angle_deg = 40° (default)
This creates an 80° cone (±40° from wind direction) representing the primary threat zone where the fire is most likely to spread.
6. Rate of Spread (ROS) Calculation
6.1 Fire Spread Phase Determination
Sensor: sensor.jf_fire_spread_phase
Purpose: Classifies fire behavior into three phases based on wind speed, using empirically-derived thresholds.
Wind Speed Thresholds:
jf_phase2_wind_kmh= 15 km/h (default)jf_phase3_wind_kmh= 25 km/h (default)
Phase Classification:
@] wind_speed = BOM Aireys wind speed (km/h)
IF wind_speed < 15 km/h:
Phase = I (Low wind - smoldering/backing fire)
\\ELIF wind_speed < 25 km/h:
Phase = II (Moderate wind - steady head fire)
\\ELSE:
Phase = III (High wind - running crown fire)
@]
6.2 Fire Front Rate of Spread (ROS)
Sensor: sensor.jf_fire_front_ros_kmh
Purpose: Estimates head fire spread rate using a piecewise-linear wind-ROS model with phase-dependent slopes.
Model Parameters:
jf_ros_k1= 0.02 (Phase I slope coefficient)jf_ros_k2= 0.06 (Phase II slope coefficient)jf_ros_k3= 0.08 (Phase III slope coefficient)jf_ros_min_kmh= 0.3 km/h (minimum ROS)jf_ros_phase1_max_kmh= 1.2 km/h (Phase I ceiling)
Calculation Algorithm:
@]python
Get wind speed and thresholds
w = wind_speed_kmh w2 = 15 # Phase II threshold w3 = 25 # Phase III threshold
Phase I: Linear with floor and ceiling
ros1 = k1 × w ros1 = max(ros1, ros_min) # Apply minimum ros1 = min(ros1, ros1_max) # Apply maximum clamp
Phase II: Ensure continuity at phase boundary
ros1_at_w2 = k1 × w2 ros1_at_w2 = max(ros1_at_w2, ros_min) ros1_at_w2 = min(ros1_at_w2, ros1_max)
ros2 = k2 × w ros2 = max(ros2, ros1_at_w2) # Enforce continuity
Phase III: Unrestricted linear growth
ros3 = k3 × w
Select ROS based on current wind speed
IF w < w2:
ROS = ros1
ELIF w < w3:
ROS = ros2
ELSE:
ROS = ros3
@]
Example Outputs:
- 10 km/h wind → Phase I → ~0.30 km/h (minimum)
- 20 km/h wind → Phase II → ~1.20 km/h
- 40 km/h wind → Phase III → ~3.20 km/h
- 60 km/h wind → Phase III → ~4.80 km/h
Model Rationale:
- Phase I represents backing/flanking fire with minimal wind influence
- Phase II represents active head fire with increasing wind coupling
- Phase III represents wind-driven crown fire with strong wind coupling
- Continuity enforced at phase boundaries prevents discontinuous jumps in ROS
6.3 Ember Attack Speed
Sensor: sensor.jf_ember_attack_speed_kmh
Purpose: Estimates the effective advance rate of embers and spotting ahead of the main fire front.
Calculation: @] ember_speed = spot_multiplier × fire_front_ros
Default: spot_multiplier = 3.0 @]
Rationale: Embers can travel ahead of the fire front by 1-5+ km depending on wind speed and fuel characteristics. The multiplier represents the ratio of ember advance rate to fire front advance rate.
Example:
- Fire front ROS: 2.0 km/h
- Multiplier: 3.0
- Ember attack speed: 6.0 km/h
7. Estimated Time of Arrival (ETA) Calculations
7.1 Preconditions for ETA Calculation
ETAs are only calculated when sensor.jf_is_home_downwind = "YES"
Logic: If home is not in the primary downwind cone, the fire is not expected to travel toward the property under current wind conditions.
7.2 ETA to Embers
Sensor: sensor.jf_eta_embers_hr
Purpose: Estimates time until ember attack begins at the property.
Calculation: @] IF is_home_downwind == "YES":
eta_embers = fire_distance_km / ember_attack_speed_kmh
\\ELSE:
eta_embers = None
@]
Example:
- Distance: 15 km
- Ember speed: 6.0 km/h
- ETA: 2.5 hours
7.3 ETA to Fire Front
Sensor: sensor.jf_eta_fire_front_hr
Purpose: Estimates time until main fire front reaches the property.
Calculation: @] IF is_home_downwind == "YES":
eta_fire_front = fire_distance_km / fire_front_ros_kmh
\\ELSE:
eta_fire_front = None
@]
Example:
- Distance: 15 km
- Fire front ROS: 2.0 km/h
- ETA: 7.5 hours
7.4 Rough ETA Range
Sensors:
sensor.jf_rough_eta_min_hr=sensor.jf_eta_embers_hrsensor.jf_rough_eta_max_hr=sensor.jf_eta_fire_front_hr
Purpose: Provides a time window for fire impact.
Interpretation:
- Min (Embers): Earliest likely impact - prepare defenses
- Max (Fire Front): Latest expected impact - main fire arrival
8. Fire Event Selection and Tracking
8.1 Automated Fire Selection
Script: jf_autoselect_nearest_watch_bushfire.py
Purpose: Automatically selects the nearest WATCH-level or higher bushfire incident for monitoring.
Selection Criteria (Priority Order):
- Status = "WATCH" AND kind = "BUSHFIRE"
- Status = "EMERGENCY WARNING" OR "WATCH AND ACT" AND kind = "BUSHFIRE"
- Any BUSHFIRE within watch zone radius
- Nearest fire of any kind within relevance radius
Latch Behavior: Once a WATCH bushfire is selected, it remains selected until:
- Fire is no longer present in VicEmergency feed
- User manually changes selection
- Fire status downgrades below ADVICE level
8.2 Manual Fire Selection
Interface: input_select.jf_vic_fire_event
Purpose: Allows manual override of automatic selection.
List Building: jf_vic_events_to_select.py
- Formats fires as dropdown options: "BUSHFIRE | WATCH | 12.5km | Grampians"
- Orders by: status severity → kind (bushfire first) → distance
- Updates every 5 minutes or when VicEmergency data refreshes
8.3 Fire Event State Propagation
Automation: "JF Apply Selected VicEmergency Fire Event"
Triggered by: Change in input_select.jf_vic_fire_event
Action: @]python Parse selected fire event:
- Extract: id, name, lat, lon, distance, status
Update input entities:
- input_text.jf_fire_name = name - input_text.jf_fire_source_id = id - input_number.jf_fire_lat = lat - input_number.jf_fire_lon = lon
@]
These coordinates become the "anchor point" for:
- DEA hotspot cluster queries
- FFMVic burnt area queries
- Distance and bearing calculations
9. MQTT Publishing for Remote Monitoring
9.1 Published Topics
The system publishes real-time threat data to MQTT broker for integration with remote monitoring systems, mobile apps, and alerting infrastructure.
Topic Structure: home/fire/[parameter]
Published Parameters:
| Topic | Sensor Source | Units | Update Rate |
home/fire/distance | jf_fire_distance_km | km | 5 min |
home/fire/bearing | jf_fire_bearing_to_home_deg | degrees | 5 min |
home/fire/downwind | jf_is_home_downwind | YES/NO | 5 min |
home/fire/ros | jf_fire_front_ros_kmh | km/h | 5 min |
home/fire/eta_min | jf_rough_eta_min_hr | hours | 5 min |
home/fire/eta_max | jf_rough_eta_max_hr | hours | 5 min |
home/fire/phase | jf_fire_spread_phase | I/II/III | 5 min |
home/fire/geometry_source | jf_fire_geometry_source | text | 5 min |
home/fire/name | jf_fire_name | text | on change |
home/wind/speed | bom_aireys_wind_speed | km/h | 30 min |
home/wind/direction | bom_aireys_wind_direction | degrees | 30 min |
9.2 Payload Format
All payloads are plain text (not JSON) for simplicity:
@] home/fire/distance → "15.23" home/fire/bearing → "087.5" home/fire/downwind → "YES" home/fire/ros → "2.10" home/fire/eta_min → "2.5" home/fire/eta_max → "7.3" @]
10. Caching and Performance Optimization
10.1 Cache Strategy
All three data-fetching scripts implement identical caching:
Cache Parameters:
- Cache duration: 120 seconds (2 minutes)
- Cache location:
/config/[script_name]_cache.json - Cache key: Includes query parameters to prevent stale data on parameter changes
Cache Behavior: @]python IF cache exists AND cache_age < 120 seconds AND cache_key matches:
RETURN cached_data
SET cached=True, cache_age_sec=[age]
ELSE:
FETCH fresh_data
WRITE cache
RETURN fresh_data
SET cached=False, cache_age_sec=0
@]
Fallback on Error: @]python TRY:
data = fetch_from_api()
EXCEPT Exception:
IF cache exists:
RETURN cached_data with error flag
ELSE:
RETURN empty result with error message
@]
10.2 Polling Intervals
| Component | Interval | Rationale |
| VicEmergency events | 300 sec (5 min) | Official updates every 5-15 min |
| DEA hotspots | 300 sec (5 min) | Satellite passes every 1-4 hours, cache handles rapid polls |
| FFMVic burnt area | 300 sec (5 min) | Updates hourly to daily |
| BOM wind data | 300-1800 sec | Weather station updates every 30 min |
| Template sensors | Event-driven | Recalculate when dependencies change |
10.3 Timeout Settings
- Web fetch timeout: 10-25 seconds (script-dependent)
- Command line sensor timeout: 10-20 seconds
- Short timeouts prevent dashboard freezing during data loading
11. Error Handling and Resilience
11.1 Graceful Degradation
The system is designed to continue operating with partial data:
Scenario: VicEmergency API Down
- Returns cached fire list (up to 2 min stale)
- User can still manually select previously detected fires
- Distance/bearing calculations continue if fire coordinates known
Scenario: DEA Hotspots Unavailable
- Falls back to FFMVic burnt area if available
- Falls back to incident point if neither boundary source works
- System continues threat assessment with reduced accuracy
Scenario: FFMVic API Down
- Uses DEA hotspots if available
- Falls back to incident point
- Distance calculations continue with alternate geometry
Scenario: BOM Wind API Down
- ROS calculations halt (returns None)
- ETAs become unavailable
- Historical wind data may be used if configured
11.2 Data Validation
Each script performs defensive validation:
@]python
Coordinate validation
IF lat is None OR lon is None OR lat < -90 OR lat > 90 OR lon < -180 OR lon > 180:
SKIP record / RETURN error
Distance validation
IF distance < 0 OR distance > max_reasonable_distance:
SKIP record / FLAG warning
Timestamp validation
IF timestamp > now + 1hour OR timestamp < now - 72hours:
SKIP record / Use fallback
@]
11.3 JSON Output Guarantees
All Python scripts guarantee valid JSON output even on catastrophic failure:
@]python TRY:
result = process_data()
print(json.dumps(result))
EXCEPT Exception as e:
print(json.dumps({
"ok": False,
"error": str(e),
"count": 0,
"features": [],
# ... other safe default fields
}))
@]
This ensures Home Assistant command_line sensors never fail due to parse errors.
12. Coordinate Systems and Projections
12.1 Geographic Coordinate System
Standard: WGS84 (EPSG:4326)
- All input coordinates in decimal degrees
- Latitude: -90° to +90° (negative = South)
- Longitude: -180° to +180° (negative = West)
12.2 Distance Calculation Methods
Haversine Formula (long-distance, point-to-point): @] R = 6371.0088 km (Earth mean radius) d = 2R × arcsin(√(sin²(Δlat/2) + cos(lat1)×cos(lat2)×sin²(Δlon/2))) @]
Accuracy: <0.5% error for distances <1000 km
Equirectangular Projection (local, for polygon operations): @] Centered at (lat0, lon0): x_km = (lon - lon0) × cos(lat0) × 111.32 y_km = (lat - lat0) × 110.574
Distance from origin: d = √(x² + y²) @]
Accuracy: <1% error for distances <200 km from origin Fast computation for polygon edge calculations
12.3 Bearing Calculation
Forward Azimuth (great circle initial bearing): @] y = sin(Δlon) × cos(lat2) x = cos(lat1) × sin(lat2) - sin(lat1) × cos(lat2) × cos(Δlon) bearing = atan2(y, x) bearing_deg = (bearing × 180/π + 360) mod 360 @]
Returns true bearing (0° = North, clockwise)
13. Configurable Parameters Reference
13.1 Spatial Parameters
| Parameter | Default | Range | Unit | Purpose |
jf_relevance_radius_km | 200 | 5-200 | km | Maximum distance to consider fires |
jf_watch_zone_km | 20 | 1-50 | km | Priority zone for WATCH fires |
jf_burnt_area_query_radius_km | 80 | 10-200 | km | FFMVic query radius |
jf_burnt_edge_match_km | 10 | 0-50 | km | Max distance to associate burnt area |
jf_hotspots_query_radius_km | 200 | 10-500 | km | DEA hotspot query radius |
jf_hotspots_anchor_match_km | 20 | 0-100 | km | Max distance to associate hotspot cluster |
13.2 Temporal Parameters
| Parameter | Default | Range | Unit | Purpose |
jf_hotspots_time_window_hr | 8 | 1-72 | hours | Hotspot recency filter |
13.3 Clustering Parameters
| Parameter | Default | Range | Unit | Purpose |
jf_hotspots_eps_km | 2.0 | 0.5-15 | km | Hotspot clustering distance |
jf_hotspots_min_points | 10 | 2-200 | count | Minimum cluster size |
13.4 Fire Spread Model Parameters
| Parameter | Default | Range | Unit | Purpose |
jf_phase2_wind_kmh | 15 | 0-80 | km/h | Phase I→II wind threshold |
jf_phase3_wind_kmh | 25 | 0-120 | km/h | Phase II→III wind threshold |
jf_ros_k1 | 0.02 | 0-0.20 | - | Phase I ROS slope |
jf_ros_k2 | 0.06 | 0-0.30 | - | Phase II ROS slope |
jf_ros_k3 | 0.08 | 0-0.40 | - | Phase III ROS slope |
jf_ros_min_kmh | 0.3 | 0-10 | km/h | Minimum ROS |
jf_ros_phase1_max_kmh | 1.2 | 0-10 | km/h | Phase I ROS ceiling |
jf_spot_multiplier | 3.0 | 1-10 | - | Ember speed multiplier |
jf_downwind_half_angle_deg | 40 | 5-90 | degrees | Threat cone half-angle |
14. Calculation Flow Summary
@] ┌─────────────────────────────────────────────────────────────────┐ │ DATA ACQUISITION (Every 5 minutes) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ VicEmergency API DEA Hotspots API │ │ ├─ Fire incidents ├─ Thermal detections │ │ ├─ Filter by radius ├─ Filter by time window │ │ ├─ Exclude planned burns ├─ Cluster by density │ │ └─ Calculate distances └─ Rank by anchor proximity │ │ │ │ FFMVic ArcGIS API BOM Weather API │ │ ├─ Burnt area polygons ├─ Wind speed │ │ ├─ Name matching ├─ Wind direction │ │ ├─ Boundary calculations └─ Temperature, humidity │ │ └─ Incident association │ │ │ └─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐ │ FIRE SELECTION (Event-driven) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 1. Build fire event list (sorted by priority) │ │ 2. Auto-select nearest WATCH bushfire (if enabled) │ │ 3. User can manually override selection │ │ 4. Set anchor coordinates (lat, lon) for selected fire │ │ │ └─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐ │ GEOMETRY SELECTION (Every calculation cycle) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ Priority 1: HOTSPOT_CLUSTER_EDGE │ │ ├─ IF: Hotspot cluster exists │ │ ├─ AND anchor matches selected fire │ │ ├─ AND anchor distance ≤ 20 km │ │ └─ USE: Nearest hotspot point to home │ │ │ │ Priority 2: BURNT_AREA_EDGE │ │ ├─ IF: Burnt area polygon exists │ │ ├─ AND anchor matches selected fire │ │ ├─ AND anchor distance ≤ 10 km │ │ └─ USE: Nearest polygon edge to home │ │ │ │ Priority 3: INCIDENT_POINT │ │ └─ USE: VicEmergency incident coordinates │ │ │ └─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐ │ SPATIAL CALCULATIONS (Real-time on data change) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ Fire Distance Fire Bearing to Home │ │ └─ Haversine / Edge distance └─ Forward azimuth calculation│ │ │ │ Wind Direction Conversion Downwind Offset │ │ └─ "From" → "Towards" └─ Angular diff (bearing-wind)│ │ │ │ Is Home Downwind? │ │ └─ IF offset ≤ 40° → YES, ELSE NO │ │ │ └─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐ │ FIRE BEHAVIOR MODELING (Real-time on wind change) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ Fire Spread Phase │ │ ├─ Phase I: wind < 15 km/h │ │ ├─ Phase II: 15 ≤ wind < 25 km/h │ │ └─ Phase III: wind ≥ 25 km/h │ │ │ │ Fire Front ROS (km/h) │ │ ├─ Phase I: ROS = k1 × wind (clamped 0.3-1.2 km/h) │ │ ├─ Phase II: ROS = k2 × wind (min continuity from Phase I) │ │ └─ Phase III: ROS = k3 × wind │ │ │ │ Ember Attack Speed (km/h) │ │ └─ speed = ROS × spot_multiplier (default: 3.0) │ │ │ └─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐ │ THREAT ASSESSMENT (Real-time on any input change) │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ IF is_home_downwind == "YES": │ │ │ │ ETA Embers (hours) │ │ └─ distance_km / ember_speed_kmh │ │ │ │ ETA Fire Front (hours) │ │ └─ distance_km / fire_front_ros_kmh │ │ │ │ Impact Window │ │ └─ Min = ETA Embers, Max = ETA Fire Front │ │ │ │ ELSE: │ │ └─ No direct threat (fire not approaching) │ │ │ └─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐ │ OUTPUT & DISPLAY │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ Home Assistant Dashboard MQTT Publishing │ │ ├─ Fire name & status ├─ Distance, bearing │ │ ├─ Distance & bearing ├─ Downwind status │ │ ├─ Geometry source ├─ ROS, phase │ │ ├─ Downwind status ├─ ETAs (min/max) │ │ ├─ ROS & spread phase └─ Wind data │ │ ├─ ETA range │ │ └─ Debug information │ │ │ │ Alerts & Notifications │ │ └─ Triggered by configurable thresholds │ │ │ └─────────────────────────────────────────────────────────────────┘ @]
15. Key Assumptions and Limitations
15.1 Model Assumptions
- Fire Spread is Wind-Driven: The model assumes head fire spread follows wind direction within a cone. Topographic effects, fuel discontinuities, and firebreaks are not modeled.
- Uniform Terrain: ROS calculations do not account for slope, which can significantly increase or decrease spread rates.
- Constant Conditions: ETAs assume current wind speed and direction persist. Actual fire behavior is highly variable.
- Linear Spread Model: The piecewise-linear ROS model is a simplified approximation. Real fires exhibit non-linear behavior, particularly during fire front intensification.
- Ember Transport: The spot multiplier is a rough empirical factor. Actual ember transport depends on fire intensity, fuel type, and atmospheric stability.
15.2 Data Limitations
- VicEmergency Update Latency: Official incident data updates every 5-15 minutes. Rapidly developing fires may not reflect current conditions.
- Satellite Overpass Frequency: DEA hotspots depend on satellite passes (1-4 hour intervals). Cloud cover prevents detection.
- Burnt Area Mapping Delay: FFMVic polygons are manually digitized and may lag actual fire progression by hours to days.
- Weather Station Representativeness: Single weather station (Aireys Inlet) may not capture local wind variations, particularly in complex terrain.
- Coordinate Accuracy: VicEmergency incident points are approximate (±1-5 km typical). Fire geometry sources provide more accurate positions.
15.3 Known Edge Cases
- Multiple Fires in Close Proximity: Name matching and proximity logic may incorrectly associate burnt areas or hotspots if multiple fires are within threshold distances.
- Erratic Fire Geometry Changes: Sudden jumps in reported fire position can cause temporary mismatches between data sources.
- Null/Missing Data: System designed to gracefully degrade but ETAs become unavailable if wind data is missing.
- Fire Behavior Changes: Model assumes relatively steady conditions. Sudden wind shifts, humidity changes, or fire-atmosphere coupling events are not predicted.
16. Validation and Calibration
16.1 Empirical Tuning
The ROS model parameters have been tuned based on:
- Historical fire progression data from Victorian fires
- Published fire behavior research (McArthur, CSIRO fire models)
- Local fuel type characteristics (coastal eucalypt forest)
- Observed fire runs during 2019-2020 fire season
16.2 Recommended Calibration Process
For site-specific tuning:
- Phase Thresholds: Observe local fire behavior transitions. Adjust
jf_phase2_wind_kmhandjf_phase3_wind_kmhif spread regime changes occur at different wind speeds. - ROS Slopes (k1, k2, k3): Compare predicted ETAs with actual fire progression. Increase/decrease slopes if model consistently under/over-predicts spread rates.
- Spot Multiplier: Observe ember attack timing relative to main fire front arrival. Adjust multiplier based on local fuel conditions and fire intensity.
- Downwind Cone Angle: If fire frequently spreads outside predicted threat zone, increase @@jf_downwind_half_angle_deg. Decrease if false alarms common.
16.3 Accuracy Assessment
Distance Calculations:
- Expected accuracy: ±500m (Hotspot/Burnt Area Edge)
- Expected accuracy: ±2-5 km (Incident Point fallback)
ROS Predictions:
- Typical accuracy: ±50% under steady conditions
- Accuracy degrades during rapid fire behavior changes
ETA Predictions:
- Useful for order-of-magnitude estimates (hours vs. days)
- NOT suitable for precise timing decisions
- Recommend 50% safety margin on minimum ETA
17. Future Enhancement Opportunities
- Fuel Type Integration: Incorporate vegetation/fuel mapping to refine ROS by fuel class.
- Topographic Corrections: Add slope-dependent ROS adjustments using DEM data.
- Fire Danger Rating Integration: Use official AFDRS (Australian Fire Danger Rating System) inputs.
- Ensemble Forecasting: Generate multiple ETAs using weather forecast ensembles.
- Historical Fire Progression Tracking: Log fire position over time to detect acceleration/deceleration trends.
- Machine Learning ROS Model: Train on historical fire progression data for improved predictions.
- Integration with Fire Simulation Models: Interface with Phoenix RapidFire or similar simulation tools.
- Real-Time Weather Radar: Incorporate radar reflectivity for smoke plume tracking and fire front detection.
- JF - or integrate with Vesta Mk 2 perhaps by: Starting with the GitHub Python translation (fastest runnable baseline - https://github.com/m-gale/ROS_evaluation). Cross-check line-by-line against the CSIRO user guide equations and thresholds (chrome-extension://efaidnbmnnnibpcajpcglclefindmkaj/https://research.csiro.au/vestamk2/wp-content/uploads/sites/443/2021/12/Vesta-Mk-2-users-guide-2021_a.pdf?utm_source=chatgpt.com). Use the Spark model-library code listing (https://research.csiro.au/spark/resources/model-library/dry-eucalypt-forest-vesta-mk-2/) as a second independent reference for implementation details (especially wind/moisture handling).
Document Metadata
Author: Technical documentation generated from ARMAC fire threat system codebase\\Date: February 2026\\Version: 1.0\\System Version: Based on scripts last modified January 2025\\Location: Fairhaven, Victoria, Australia (-38.463445°, 144.085157°)
END OF TECHNICAL DESCRIPTION << Testing Infrastructure and System Validation cont | | Development Notes >> |Table of Contents>
