Home Assistant Custom Integration to pull SA CFS Fire Danger Ratings and Fire Ban information.
This integration is still in development and rapid changes may break things!
It's also almost 99% generated by LLM's, so likely a bit sloppy.
If you're here, you've probably been sent the link to test for me, or you're very very lost.
Install as a custom repository in HACS, and the config flow will let you select which districts you want to monitor. v0.1.3 adds a custom card for the single gauge.
At the moment it scrapes the data every 60 mins, and stores the last update time as the status of sensor.sa_cfs_fire_danger.
Whilst it normally returns 5 days worth of data, for some reason at certain times the CFS XML will have duplicate data for day 1 and 2. The code will cycle through and ignore duplicate data is present, and move days forward - leaving day 5 as N/A sometimes. I had considered whether to just drop day 5 completely but for now it remains.
Still working on when it refreshes officially, as it sometimes has 5 days worth, and other times day 1 is repeated twice.
- Adelaide Metropolitan
- Mount Lofty Ranges
- Kangaroo Island
- Mid North
- Yorke Peninsula
- Murraylands
- Riverland
- Upper South East
- Lower South East
- Flinders
- North East Pastoral
- Eastern Eyre Peninsula
- North West Pastoral
- Lower Eyre Peninsula
- West Coast
The AFDRS has 5 levels of rating:
- No Rating
- Moderate
- High
- Extreme
- Catastrophic
By default this integration will create a sensor called sensor.sa_cfs_fire_danger, with the state of the last update (in hh:mm dd/mm/yyyy format), and the following attributes:
| Attribute | Example Data | Comments |
|---|---|---|
icon |
mdi:fire-alert | |
friendly_name |
SA CFS Fire Danger | |
district_count |
15 | Internal, used when cycling data |
day_1_name |
Saturday | Used for config-template-card variables |
day_1_date |
04/10 | Used for config-template-card variables |
day_2_name |
Sunday | Used for config-template-card variables |
day_2_date |
05/10 | Used for config-template-card variables |
day_3_name |
Monday | Used for config-template-card variables |
day_3_date |
06/10 | Used for config-template-card variables |
day_4_name |
Tuesday | Used for config-template-card variables |
day_4_date |
07/10 | Used for config-template-card variables |
day_5_name |
Wednesday | Used for config-template-card variables |
day_5_date |
08/10 | Used for config-template-card variables |
It then creates three attributes for each of the 15 CFS Fire Danger districts:
| Attribute | Example Data | Comments |
|---|---|---|
adelaide_metropolitan_rating |
No Rating | |
adelaide_metropolitan_fbi |
0 | |
adelaide_metropolitan_fireban |
No |
During the config flow, you can select none, or any number of specific districts to monitor, this will then create a new sensor sensor.sa_cfs_DISTRICTNAME with the state as the current Fire Danger Rating, and the following attributes:
| Attribute | Example Data | Comments |
|---|---|---|
district_name |
Flinders | |
day_1_rating |
Moderate | |
day_1_fbi |
15 | |
day_1_fireban |
No | |
day_1_name |
Saturday | Now in main sensor, possibly to be removed from here |
day_1_date |
04/10 | Now in main sensor, possibly to be removed from here |
day_2_rating |
Moderate | |
day_2_fbi |
20 | |
day_2_fireban |
No | |
day_2_name |
Sunday | Now in main sensor, possibly to be removed from here |
day_2_date |
05/10 | Now in main sensor, possibly to be removed from here |
day_3_rating |
No Rating | |
day_3_fbi |
10 | |
day_3_fireban |
No | |
day_3_name |
Monday | Now in main sensor, possibly to be removed from here |
day_3_date |
06/10 | Now in main sensor, possibly to be removed from here |
day_4_rating |
No Rating | |
day_4_fbi |
8 | |
day_4_fireban |
No | |
day_4_name |
Tuesday | Now in main sensor, possibly to be removed from here |
day_4_date |
07/10 | Now in main sensor, possibly to be removed from here |
day_5_rating |
No Rating | |
day_5_fbi |
10 | |
day_5_fireban |
No | |
day_5_name |
Wednesday | Now in main sensor, possibly to be removed from here |
day_5_date |
08/10 | Now in main sensor, possibly to be removed from here |
icon |
mdi:map-marker-alert-outline | Possibly change to mdi:fire-alert to match main sensor |
friendly_name |
SA CFS Flinders |
Example code shows Flinders district, and possibly a few Sections specific configurations as these were pulled from my test setup.
Same as the original picture entity card with fire ban overlay - now has a custom card and GUI config to set it up:

Picture Entity to show the coloured wheel. 3 different style SVG's I've found are included, or use your own.
Change the images to gauge1 / gauge2 / gauge3 as needed for the different styles.
type: picture-entity
entity: sensor.sa_cfs_flinders
fit_mode: contain
show_state: false
show_name: false
state_image:
unknown: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-unavailable.svg
No Rating: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-norating.svg
Moderate: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-moderate.svg
High: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-high.svg
Extreme: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-extreme.svg
Catastrophic: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-catastrophic.svgPicture Entity to show the coloured wheel as above, but with a WIP overlay icon if today is a fire ban. This is currently a bit hacky as requires a Template binary sensor with the specific region set.
{{ state_attr('sensor.sa_cfs_flinders', 'day_1_fireban') == 'Yes' }}
type: picture-elements
image: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-norating.svg
elements:
- type: image
entity: sensor.sa_cfs_flinders
state_image:
unknown: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-unavailable.svg
No Rating: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-norating.svg
Moderate: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-moderate.svg
High: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-high.svg
Extreme: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-extreme.svg
Catastrophic: /hacsfiles/sa_cfs_fire_danger/afdr-gauge1-catastrophic.svg
tap_action: none
hold_action: none
style:
left: 50%
top: 50%
width: 100%
height: 100%
- type: conditional
conditions:
- entity: binary_sensor.fire_ban_today
state: "on"
elements:
- type: image
entity: binary_sensor.fire_ban_today
state_image:
"on": /hacsfiles/sa_cfs_fire_danger/fire_ban.svg
tap_action: none
hold_action: none
style:
transform: none
left: 0%
top: 0%
width: 25%
height: 100%Requires config-template-card to pull the actual day names from the sensor.
type: custom:config-template-card
variables:
DAY1_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_1_name
DAY2_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_2_name
DAY3_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_3_name
DAY4_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_4_name
DAY5_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_5_name
entities:
- sensor.sa_cfs_flinders
card:
type: entities
title: Flinders District
entities:
- entity: sensor.sa_cfs_flinders
type: custom:multiple-entity-row
show_state: false
name: ${DAY1_NAME}
entities:
- attribute: day_1_rating
name: Rating
- attribute: day_1_fbi
name: FBI
- attribute: day_1_fireban
name: Fire Ban
- entity: sensor.sa_cfs_flinders
type: custom:multiple-entity-row
show_state: false
name: ${DAY2_NAME}
entities:
- attribute: day_2_rating
name: Rating
- attribute: day_2_fbi
name: FBI
- attribute: day_2_fireban
name: Fire Ban
- entity: sensor.sa_cfs_flinders
type: custom:multiple-entity-row
show_state: false
name: ${DAY3_NAME}
entities:
- attribute: day_3_rating
name: Rating
- attribute: day_3_fbi
name: FBI
- attribute: day_3_fireban
name: Fire Ban
- entity: sensor.sa_cfs_flinders
type: custom:multiple-entity-row
show_state: false
name: ${DAY4_NAME}
entities:
- attribute: day_4_rating
name: Rating
- attribute: day_4_fbi
name: FBI
- attribute: day_4_fireban
name: Fire BanRequires flex-table-card and config-template-card.
type: custom:config-template-card
variables:
DAY1_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_1_name
DAY2_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_2_name
DAY3_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_3_name
DAY4_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_4_name
DAY5_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_5_name
DAY1_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_1_date
DAY2_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_2_date
DAY3_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_3_date
DAY4_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_4_date
DAY5_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_5_date
entities:
- sensor.sa_cfs_fire_danger
card:
type: custom:flex-table-card
title: SA CFS Fire Danger Ratings
entities:
include: sensor.sa_cfs*
exclude: sensor.sa_cfs_fire_danger
columns:
- data: district_name
name: District
- data: day_1_rating
name: Today
align: center
modify: |-
if (x == "No Rating")
"No Rating"
else if (x == "Moderate")
'<div style="background-color:#64bf30;">Moderate</div>'
else if (x == "High")
'<div style="background-color:#fedd3a;">High</div>'
else if (x == "Extreme")
'<div style="background-color:#f78100;">Extreme</div>'
else if (x == "Catastrophic")
'<div style="background-color:#ad0909;color:#FFFFFF;">Catastrophic</div>'
else x
- data: day_1_fbi
name: ""
align: center
- data: day_2_rating
name: Tomorrow
align: center
modify: |-
if (x == "No Rating")
"No Rating"
else if (x == "Moderate")
'<div style="background-color:#64bf30;">Moderate</div>'
else if (x == "High")
'<div style="background-color:#fedd3a;">High</div>'
else if (x == "Extreme")
'<div style="background-color:#f78100;">Extreme</div>'
else if (x == "Catastrophic")
'<div style="background-color:#ad0909;color:#FFFFFF;">Catastrophic</div>'
else x
- data: day_2_fbi
name: ""
align: center
- data: day_3_rating
name: ${DAY3_DATE}
align: center
modify: |-
if (x == "No Rating")
"No Rating"
else if (x == "Moderate")
'<div style="background-color:#64bf30;">Moderate</div>'
else if (x == "High")
'<div style="background-color:#fedd3a;">High</div>'
else if (x == "Extreme")
'<div style="background-color:#f78100;">Extreme</div>'
else if (x == "Catastrophic")
'<div style="background-color:#ad0909;color:#FFFFFF;">Catastrophic</div>'
else x
- data: day_3_fbi
name: ""
align: center
- data: day_4_rating
name: ${DAY4_DATE}
align: center
modify: |-
if (x == "No Rating")
"No Rating"
else if (x == "Moderate")
'<div style="background-color:#64bf30;">Moderate</div>'
else if (x == "High")
'<div style="background-color:#fedd3a;">High</div>'
else if (x == "Extreme")
'<div style="background-color:#f78100;">Extreme</div>'
else if (x == "Catastrophic")
'<div style="background-color:#ad0909;color:#FFFFFF;">Catastrophic</div>'
else x
- data: day_4_fbi
name: ""
align: center
grid_options:
columns: 24Requires flex-table-card and config-template-card. Does some wonky line spacing if one day in the row has a fire ban - or if the district doesn't have any all week. Haven't looked into it much yet.
type: custom:config-template-card
variables:
DAY1_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_1_name
DAY2_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_2_name
DAY3_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_3_name
DAY4_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_4_name
DAY5_NAME: states['sensor.sa_cfs_fire_danger'].attributes.day_5_name
DAY1_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_1_date
DAY2_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_2_date
DAY3_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_3_date
DAY4_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_4_date
DAY5_DATE: states['sensor.sa_cfs_fire_danger'].attributes.day_5_date
entities:
- sensor.sa_cfs_fire_danger
card:
type: custom:flex-table-card
title: SA CFS Fire Danger Ratings
entities:
include: sensor.sa_cfs*
exclude: sensor.sa_cfs_fire_danger
columns:
- data: district_name
name: District
- data: day_1_rating, day_1_fireban
name: Today
align: center
multi_delimiter: ","
modify: |-
var value1=String(x.split(',')[0]);
var value2=String(x.split(',')[1]);
if (value2 == "Yes")
if (value1 == "No Rating")
'No Rating<br><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "Moderate")
'<div style="background-color:#64bf30;">Moderate</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "High")
'<div style="background-color:#fedd3a;">High</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "Extreme")
'<div style="background-color:#f78100;">Extreme</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "Catastrophic")
'<div style="background-color:#ad0909;color:#FFFFFF;">Catastrophic</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else value1
else if (value2 == "No")
if (value1 == "No Rating")
"No Rating"
else if (value1 == "Moderate")
'<div style="background-color:#64bf30;color:#000000;">Moderate</div>'
else if (value1 == "High")
'<div style="background-color:#fedd3a;color:#000000;">High</div>'
else if (value1 == "Extreme")
'<div style="background-color:#f78100;color:#000000;">Extreme</div>'
else if (value1 == "Catastrophic")
'<div style="background-color:#ad0909;color:#FFFFFF;">Catastrophic</div>'
else x
else x
- data: day_1_fbi
name: ""
align: center
- data: day_2_rating, day_2_fireban
name: Tomorrow
align: center
multi_delimiter: ","
modify: |-
var value1=String(x.split(',')[0]);
var value2=String(x.split(',')[1]);
if (value2 == "Yes")
if (value1 == "No Rating")
'No Rating<br><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "Moderate")
'<div style="background-color:#64bf30;">Moderate</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "High")
'<div style="background-color:#fedd3a;">High</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "Extreme")
'<div style="background-color:#f78100;">Extreme</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "Catastrophic")
'<div style="background-color:#ad0909;color:#FFFFFF;">Catastrophic</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else value1
else if (value2 == "No")
if (value1 == "No Rating")
"No Rating"
else if (value1 == "Moderate")
'<div style="background-color:#64bf30;">Moderate</div>'
else if (value1 == "High")
'<div style="background-color:#fedd3a;">High</div>'
else if (value1 == "Extreme")
'<div style="background-color:#f78100;">Extreme</div>'
else if (value1 == "Catastrophic")
'<div style="background-color:#ad0909;color:#FFFFFF;">Catastrophic</div>'
else x
else x
- data: day_2_fbi
name: ""
align: center
- data: day_3_rating, day_3_fireban
name: ${DAY3_DATE}
align: center
multi_delimiter: ","
modify: |-
var value1=String(x.split(',')[0]);
var value2=String(x.split(',')[1]);
if (value2 == "Yes")
if (value1 == "No Rating")
'No Rating<br><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "Moderate")
'<div style="background-color:#64bf30;">Moderate</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "High")
'<div style="background-color:#fedd3a;">High</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "Extreme")
'<div style="background-color:#f78100;">Extreme</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "Catastrophic")
'<div style="background-color:#ad0909;color:#FFFFFF;">Catastrophic</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else value1
else if (value2 == "No")
if (value1 == "No Rating")
"No Rating"
else if (value1 == "Moderate")
'<div style="background-color:#64bf30;">Moderate</div>'
else if (value1 == "High")
'<div style="background-color:#fedd3a;">High</div>'
else if (value1 == "Extreme")
'<div style="background-color:#f78100;">Extreme</div>'
else if (value1 == "Catastrophic")
'<div style="background-color:#ad0909;color:#FFFFFF;">Catastrophic</div>'
else x
else x
- data: day_3_fbi
name: ""
align: center
- data: day_4_rating, day_4_fireban
name: ${DAY4_DATE}
align: center
multi_delimiter: ","
modify: |-
var value1=String(x.split(',')[0]);
var value2=String(x.split(',')[1]);
if (value2 == "Yes")
if (value1 == "No Rating")
'No Rating<br><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "Moderate")
'<div style="background-color:#64bf30;">Moderate</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "High")
'<div style="background-color:#fedd3a;">High</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "Extreme")
'<div style="background-color:#f78100;">Extreme</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else if (value1 == "Catastrophic")
'<div style="background-color:#ad0909;color:#FFFFFF;">Catastrophic</div><div style="background-color:#ff0000;">FIRE BAN</div>'
else value1
else if (value2 == "No")
if (value1 == "No Rating")
"No Rating"
else if (value1 == "Moderate")
'<div style="background-color:#64bf30;">Moderate</div>'
else if (value1 == "High")
'<div style="background-color:#fedd3a;">High</div>'
else if (value1 == "Extreme")
'<div style="background-color:#f78100;">Extreme</div>'
else if (value1 == "Catastrophic")
'<div style="background-color:#ad0909;color:#FFFFFF;">Catastrophic</div>'
else x
else x
- data: day_4_fbi
name: ""
align: center
grid_options:
columns: 24