Hurricane Tracking

I’m looking for a way to show the coordinates of active hurricanes to show on an map and alert if the coordinates are within a certain distance. Once I have the coordinates, calculating the distance and the automation to alert me are not difficult, but is anyone aware of an integration or a way that would allow me to get updated coordinates of any tropical storm or hurricane to use for maps and automatons?

1 Like

Hi, this all depends on where you live and if there is any service in your area that you can use/integrate.

USA. NHC has the feed (https://www.nhc.noaa.gov/CurrentStorms.json) but it’s beyond my ability to pull this in and parse it.

Have you seen this thread Severe Weather Alerts from the US National Weather Service

Yes, I have that and it works great but I was trying to specifically break out hurricanes and tropical storms so I can set up automatons from the coordinates and show them on a map.

Maybe with? GeoJSON - Home Assistant
But I can’t help you with that, maybe a search on the forum with (geo)json & weather… :thinking:

I case anyone else cares for this information, I have made some success with the code below. Next, I want to display these on a map…


- platform: rest
  name: Current Storms Data
  resource: https://www.nhc.noaa.gov/CurrentStorms.json
  method: GET
  value_template: "{{ value_json.storms }}"
  json_attributes:
   - activeStorms
  scan_interval: 3600  



- platform: template
  sensors:
    storm_coordinates:
      friendly_name: 'Storm Coordinates'
      value_template: >
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}

          {{storms[i]['name']}} - Coordinates ({{storms[i]['latitudeNumeric']}},{{storms[i]['longitudeNumeric']}}), Distance {{((distance (storms[i]['latitudeNumeric'], storms[i]['longitudeNumeric'])))|round(2) }} miles.
        {% endfor %}
      entity_id:
        - sensor.current_storms_data
      icon_template: mdi:hurricane

1 Like

Here you go. I made a couple changes to your code, so pasting all my code as used.
In Rest Sensors:

#  *******************************************************************************
#  Get current Hurricane Data
#  *******************************************************************************
- platform: rest
  name: Current Storms Data
  unique_id: current_storms_data
  resource: https://www.nhc.noaa.gov/CurrentStorms.json
  method: GET
  value_template: "{{ value_json.storms }}"
  json_attributes:
   - activeStorms
  scan_interval: 3600  
#

In Templates:

  ############################
  #  Hurricane Storm Coordinates
  ############################
  - name: "Storm Coordinates"
    unique_id: storm_coordinates
    state: >-
      {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
      {% for i in range(0, storms | count ) %}
      {% endfor %}
      {{storms[i] | count + 1 }}
    attributes:
      storm_name: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['name']}}
        {% endfor %}
      latitude: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['latitudeNumeric']}}
        {% endfor %}
      longitude: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['longitudeNumeric']}}
        {% endfor %}
      distance: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{((distance (storms[i]['latitudeNumeric'], storms[i]['longitudeNumeric'])))|round(2) }} miles.
        {% endfor %}
    icon: mdi:hurricane
#
############################
#  Hurricane Tracker
############################
  - name: "Hurricane 1"
    unique_id: hurricane_1
    state: >-
      {{ state_attr('sensor.storm_coordinates', "storm_name") }}
    attributes:
      latitude: >-
        {{ state_attr('sensor.storm_coordinates', "latitude") }}
      longitude: >-
        {{ state_attr('sensor.storm_coordinates', "longitude") }}
      last_updated: >-
        {{states('sensor.date_time')}}
#

In Your MAP:

type: map
entities:
  - entity: sensor.map_atlantic_blvd_gas
    label_mode: state
    focus: false
  - entity: sensor.hurricane_1
    label_mode: state
    focus: false
geo_location_sources: []
default_zoom: 22
hours_to_show: 12
theme_mode: auto

As you can see from my code. I already display gas prices on the map, using scrape sensor and GPS coordinates, so porting your rest sensor code to this was pretty easy.
You can add as many hurricane_# entities as you care to track, and Im sure there is a more elegant way of doing it, but this works

If you make any improvements please share them here so everyone can use.

And just for completeness here is how I track the gas prices:

############################
#  BJs Gas Atlantic Blvd
############################
  - name: "Map Atlantic Blvd Gas"
    unique_id: map_atlantic_blvd_gas
    state: >-
      {{states('sensor.bjs_atlantic_blvd_gas')}}
    attributes:
      latitude: '30.318081378839146'
      longitude: '-81.48622455824521'
      last_updated: >-
        {{states('sensor.date_time')}}
#

Added wind speed/Category to map badge

############################
#  Hurricane Storm Coordinates
############################
  - name: "Storm Coordinates"
    unique_id: storm_coordinates
    state: >-
      {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
      {% for i in range(0, storms | count ) %}
      {% endfor %}
      {{storms[i] | count + 1 }}
    attributes:
      storm_name: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['name']}}
        {% endfor %}
      latitude: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['latitudeNumeric']}}
        {% endfor %}
      longitude: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['longitudeNumeric']}}
        {% endfor %}
      distance: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{((distance (storms[i]['latitudeNumeric'], storms[i]['longitudeNumeric'])))|round(2) }} miles.
        {% endfor %}
      intensity: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['intensity']}}
        {% endfor %}
    icon: mdi:hurricane
#

and 

############################
#  Hurricane Tracker
############################
  - name: "Hurricane 1"
    unique_id: hurricane_1
    state: >-
      {% set winds = state_attr('sensor.storm_coordinates', "intensity")|int %}
      {% if winds >= 74 and winds <= 95 %}
      {% set intensity = 'Cat 1' %}
      {% elif winds >= 96 and winds <= 110 %}
      {% set intensity = 'Cat 2' %}
      {% elif winds >= 111 and winds <= 129 %}
      {% set intensity = 'Cat 3' %}
      {% elif winds >= 130 and winds <= 156 %}
      {% set intensity = 'Cat 4' %}
      {% elif winds >= 157 %}
      {% set intensity = 'Cat 5' %}
      {% else %}
      {% set intensity = winds %} & ' MPH' 
      {% endif %}
      {{ state_attr('sensor.storm_coordinates', "storm_name") }}, {{ intensity }}
    attributes:
      latitude: >-
        {{ state_attr('sensor.storm_coordinates', "latitude") }}
      longitude: >-
        {{ state_attr('sensor.storm_coordinates', "longitude") }}
      last_updated: >-
        {{states('sensor.date_time')}}
#

Enjoy!

1 Like

Here’s what I did: I added the Rest Sensor to my sensors.yaml and get a sensor.current_storms_data.

I did not previously use any templates so I uncommented template: !include templates.yaml in configuration.yaml and added your storm_coordinates template information to templates.yaml. I get no YAML errors but do not get storm_coordinates even after restarting HAS and rebooting the server. Naturally, the map icon does not work without that. Any thoughts?

Without seeing all your code the first thought I had was that all !include files need to start with the correct declaration like this:

sensor:

#############################################################
#                    Templates Sensors                      #
#############################################################
- sensor:
################################
#  Current and Future Conditions
################################
  - name: "Current Forecast"
    unique_id: current_forecast
    state: >-

Like many, I split my config files and use lots of includes and YAML files within each folder section. It’s easy to overlook that initial declaration when using other peoples code.

When I coded this earlier today I did not need to restart HA, simply reload the template option from the YAML tab of the developer tools page.

If this doesn’t work let me know and I can send you the full text of all the related code.

I did not have the -sensor: declaration, but when I added it, still no change.

Here is all that is in my templates.yaml file:


- sensor:   
 ############################
  #  Hurricane Storm Coordinates
  ############################
  - name: "Storm Coordinates"
    unique_id: storm_coordinates
    state: >-
      {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
      {% for i in range(0, storms | count ) %}
      {% endfor %}
      {{storms[i] | count + 1 }}
    attributes:
      storm_name: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['name']}}
        {% endfor %}
      latitude: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['latitudeNumeric']}}
        {% endfor %}
      longitude: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['longitudeNumeric']}}
        {% endfor %}
      distance: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{((distance (storms[i]['latitudeNumeric'], storms[i]['longitudeNumeric'])))|round(2) }} miles.
        {% endfor %}
    icon: mdi:hurricane
#
############################
#  Hurricane Tracker
############################
  - name: "Hurricane 1"
    unique_id: hurricane_1
    state: >-
      {{ state_attr('sensor.storm_coordinates', "storm_name") }}
    attributes:
      latitude: >-
        {{ state_attr('sensor.storm_coordinates', "latitude") }}
      longitude: >-
        {{ state_attr('sensor.storm_coordinates', "longitude") }}
      last_updated: >-
        {{states('sensor.date_time')}}
#     

OK,
Im gonna lay out my file structure and all relevant files you’ll need to make it work.
First is my folder structure within Home Assistant


Then in configuration.yaml

# ******************************************************************************
#    Included Files
# ******************************************************************************
alarm_control_panel: !include includes/alarm_cp.yaml
anniversaries: !include includes/anniversary.yaml
# next line is old way. turned off 11-06-2021
# automation: !include_dir_merge_list automations
automation manual: !include_dir_merge_list automations
automation ui: !include automations.yaml
# ^^ uses both the UI editor and YAML mode
binary_sensor: !include_dir_merge_list binary_sensors
camera: !include_dir_merge_list cameras
calendar: !include includes/calendars.yaml
command_line: !include includes/command_lines.yaml
counter: !include includes/counters.yaml
cover: !include includes/covers.yaml
# fan: !include includes/fans.yaml
group: !include_dir_merge_named groups
# history: !include includes/history_cfgs.yaml  (remove included file as well)
# influxdb: !include includes/influxdbs.yaml
input_boolean: !include includes/input_booleans.yaml
input_button: !include includes/input_buttons.yaml
input_datetime: !include includes/input_datetimes.yaml
input_number: !include includes/input_numbers.yaml
input_select: !include includes/input_selects.yaml
input_text: !include includes/input_texts.yaml
# light: !include includes/lights.yaml  | Flux LED only
# media_player: !include includes/media_players.yaml
multiscrape: !include includes/multi_scrape.yaml
mqtt: !include includes/mqtts.yaml
notify: !include_dir_merge_list notify
# proximity: !include includes/proximity.yaml
recorder: !include includes/recorders.yaml
# scene: !include_dir_list scenes > moved to scripts for simplicity
script: !include_dir_merge_named scripts
sensor: !include_dir_merge_list sensors
shell_command: !include includes/shell_commands.yaml
# siren: !include includes/sirens.yaml
# sql: !include includes/sql_queries.yaml
switch: !include includes/switches.yaml
template: !include_dir_merge_list templates
timer: !include includes/timers.yaml
tts: !include includes/txt2spk.yaml
utility_meter: !include includes/utility_meters.yaml
var: !include includes/vars.yaml
# variable: !include includes/vars_hist.yaml
# webostv: !include includes/webostvs.yaml
weather: !include includes/weather_cfg.yaml
yahoofinance: !include includes/yahoo_finance.yaml

If you need to modify your config file, do that then restart.

Next, in /sensors/rest.yaml (truncated for brevity)

#########################
#    REST Sensors                  #
#########################
#
#  *******************************************************************************
#  Get current Hurricane Data
#  *******************************************************************************
- platform: rest
  name: Current Storms Data
  unique_id: current_storms_data
  resource: https://www.nhc.noaa.gov/CurrentStorms.json
  method: GET
  value_template: "{{ value_json.storms }}"
  json_attributes:
   - activeStorms
  scan_interval: 3600  
#

Then in /templates/weather_sensors_tmpl.yaml (truncated for brevity)

#############################################################
#                    Templates Sensors                      #
#############################################################
- sensor:
############################
#  Hurricane Storm Coordinates
############################
  - name: "Storm Coordinates"
    unique_id: storm_coordinates
    state: >-
      {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
      {% for i in range(0, storms | count ) %}
      {% endfor %}
      {{storms[i] | count + 1 }}
    attributes:
      storm_name: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['name']}}
        {% endfor %}
      latitude: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['latitudeNumeric']}}
        {% endfor %}
      longitude: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['longitudeNumeric']}}
        {% endfor %}
      distance: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{((distance (storms[i]['latitudeNumeric'], storms[i]['longitudeNumeric'])))|round(2) }} miles.
        {% endfor %}
      intensity: >-
        {% set storms = state_attr('sensor.current_storms_data','activeStorms')%}
        {% for i in range(0, storms | count ) %}
          {{storms[i]['intensity']}}
        {% endfor %}
    icon: mdi:hurricane
#

I split my template code into relevant sections so the final part of the code is at
/templates/zone_tmpl.yaml but could be added to the above with no ill effects. In this code I left one of the gas trackers listed so you can see how the structure works.

#############################################################
#                Zone Templates Sensors                      #
#############################################################
- sensor:
############################
#  BJs Gas Atlantic Blvd
############################
  - name: "Map Atlantic Blvd Gas"
    unique_id: map_atlantic_blvd_gas
    state: >-
      {{states('sensor.bjs_atlantic_blvd_gas')}}
    attributes:
      latitude: '30.318081378839146'
      longitude: '-81.48622455824521'
      last_updated: >-
        {{states('sensor.date_time')}}
#
############################
#  Hurricane Tracker
############################
  - name: "Hurricane 1"
    unique_id: hurricane_1
    state: >-
      {% set winds = state_attr('sensor.storm_coordinates', "intensity")|int %}
      {% if winds >= 74 and winds <= 95 %}
      {% set intensity = 'Cat 1' %}
      {% elif winds >= 96 and winds <= 110 %}
      {% set intensity = 'Cat 2' %}
      {% elif winds >= 111 and winds <= 129 %}
      {% set intensity = 'Cat 3' %}
      {% elif winds >= 130 and winds <= 156 %}
      {% set intensity = 'Cat 4' %}
      {% elif winds >= 157 %}
      {% set intensity = 'Cat 5' %}
      {% else %}
      {% set intensity = winds %} & ' MPH' 
      {% endif %}
      {{ state_attr('sensor.storm_coordinates', "storm_name") }}, {{ intensity }}
    attributes:
      latitude: >-
        {{ state_attr('sensor.storm_coordinates', "latitude") }}
      longitude: >-
        {{ state_attr('sensor.storm_coordinates', "longitude") }}
      last_updated: >-
        {{states('sensor.date_time')}}
#

Make sure the config is set up right!!!
Once all code is copied and pasted, go to Developer Tools > YAML > Template Entities and click. This will reload all templates. Make sure you MAP page has the hurricane entity defined and it should all work.

As you can see I spend a lot of time keeping my files and folders as structured as possible, and use lots of comments. I won’t use the UI simply because the YAML editing allows me to work 1) Faster, 2) with comments 3) with easy editing and 4) readily searched and bulk updated. Not putting down the UI way, just not my thing.
One last note, pay carful attention to spacing in yaml as it is very sensitive to even one bad space. I use VS Code Studio on a iMac for local editing and the add on VS Code Studio for remote updates if necessary. The add on LOVES to adjust spacing when you save a file, so watch out for that.

If you do everything as listed above it WILL work. If not, there is an errant (something) somewhere. Tracking it down is no fun but can be done if you introduce small chunks of code at a time until it fails, then you have a culprit chunk to troubbleshoot.

Good luck!!
(sorry this was such a long post)

1 Like

I really appreciate the detail. I’ve created the include file structure as indicated and copied the code directly with the same result. I have not doubt that it will work, I’ll just have to do through it line by line. The rest works fine but not he map. Should there be a sensor that I validate the state called storm_coordinates? That’s not showing, if so.

On the VS Code Studio - I assume you mean Microsoft VS Code Studio?

Here’s what mine looks like

And yes to Microsoft VS Code Studio. There is a Mac application standalone program and a HA Supervisor Add on. I use the add on on my iPad when away from home and the Mac program while home.

Thanks. I’m running Docker so I can’t install in in HA but I just downloaded to the Mac it and it’s very helpful. The iPad version will be nice too.

I’ll dig into each file and look for an error. Again, I really appreciate your taking my basic functionality and making it into exactly what I was looking for. Now if I can only make it work before hurricane season is over :).

If I have templates defined in the configuration.yaml file plus these new ones defined in the templates file, is that a problem?

I would consolidate all template code to one place. That said, you can see in my file structure that I use many template files all within the template folder. This allows me to separate code by useage or integrations. By using the include approach, HA will compile all the template code into a unified block of code. As a human, it would be a massive task to keep it organized, but an easy task for a computer.
I’m not 100% certain that the same is true for code placed in the config file and an included template file. It is easy to assume that it should work, but I’m not sure.

Well… that was it. I pulled all templates from configuration, created a new file based on your example and it’s all working now. It must not like templates in configuration and another yaml file.

Thanks again!!

Yeah!!! I’m glad that worked.