Hurricane Tracking

OK, here’s the first part of being able to filter for just Atlantic Storms. You can update your STORM COUNT template to get sub counts for each region.

    ############################
    #  Hurricane Storm Count
    ############################
    - name: "Storm Count"
      unique_id: storm_count
      state: >-
        {{ state_attr('sensor.current_storm_data','activeStorms') | map(attribute='id') | list | count }}
      attributes:
        atlantic: >-
          {{ state_attr('sensor.current_storm_data','activeStorms') | map(attribute='binNumber') | list | regex_findall(find='AT.', ignorecase=False) | count }}
        eastern_pacific: >-
          {{ state_attr('sensor.current_storm_data','activeStorms') | map(attribute='binNumber') | list | regex_findall(find='EP.', ignorecase=False) | count }}
        central_pacific: >-
          {{ state_attr('sensor.current_storm_data','activeStorms') | map(attribute='binNumber') | list | regex_findall(find='CP.', ignorecase=False) | count }}
      icon: mdi:weather-hurricane
    #

Next task is to add the filtering to the storm sensors. I think its gonna look a lot like this:
(DEMO ONLY. Working on code and will update soon.)

    ################################
    #  Hurricane Storm Coordinates
    ################################
    - name: "Atlantic Storm 1"
      unique_id: atlantic_storm_1
      state: >-
        {% set storms = state_attr('sensor.current_storm_data','activeStorms') %}
        ^^^ This code will get updated to JUST ATLANTIC OR PACIFIC  STORMS. 
        {% set winds = (storms[0]['intensity']|int*1.151)|round(2) %}
        {% if winds < 34 %}
        {% set intensity = 'TD' %}
        {% elif winds >= 34 and winds <= 73 %}
        {% set intensity = 'TS' %}

After a lot of digging, reading and research I have come to the conclusion that there is no good way to split the storm data (Atlantic/Pacific) AFTER the JSON file is read in at the Rest Sensor. Yes, it can be filtered and split prior to parsing the JSON, but then you’d have two (or 3) sensors; Atlantic, Eastern Pacific & Central Pacific or just Atlantic and Pacific. Either way, it would increase the coding, sensors and workload to where I felt it just didn’t make sense. Therefore, I have adopted the addition of the [binNumber] to each storms attributes, truncated to just the first two characters (ie: AT, EP & CP). This will allow end users to filter on that attribute to only show selected regions of storms. It’s not exactly what @jlrosssc was looking for BUT it should meet his needs in terms of excluding Pacific based storms. What follows is the code changes to the templates. (NOTE!! There have been some naming variations that may require you to select a standard nomenclature, but the code is otherwise perfectly workable.)

For EACH STORM you want to track:

    ################################
    #  Hurricane Storm Coordinates
    ################################
    - name: "Storm 1"   < Note the name change!!!
      unique_id: storm_1   < Note the name change!!!
      state: >-
        {% set storms = state_attr('sensor.current_storm_data','activeStorms') %}
        {% set winds = (storms[0]['intensity']|int*1.151)|round(2) %}
        {% if winds < 34 %}
        {% set intensity = 'TD' %}
        {% elif winds >= 34 and winds <= 73 %}
        {% set intensity = 'TS' %}
        {% elif 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 %}
        {{ storms[0]['name'] }}, {{intensity }}
      attributes:
        storm_name: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ storms[0]['name'] }}
        classification: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ storms[0]['classification'] }}
        pressure: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ (storms[0]['pressure']|float/33.864)|round(2) }}
        intensity: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ storms[0]['intensity'] }}
        max_winds: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ (storms[0]['intensity']|int*1.151)|round(2) }} MPH
        heading: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ storms[0]['movementDir'] }}
        heading_text: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {% set windbearing = ((storms[0]['movementDir']|float(default=0)+22.5)/45)|int|round %}
          {% if windbearing > 7 %}{%  set windbearing = 0 %}{% endif %}
          {% set winddir = ['North', 'North East','East','South East','South','South West','West','North West'] %}
          {{ winddir[windbearing]|default('Unknown')}}
        movement_speed: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ storms[0]['movementSpeed'] }}
        distance: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ ((distance (storms[0]['latitudeNumeric'], storms[0]['longitudeNumeric'])))|round(2) }} miles
        latitude: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ storms[0]['latitudeNumeric'] }}
        longitude: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ storms[0]['longitudeNumeric'] }}
# New code added here
        region: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ storms[0]['binNumber'][:2] }}
# New code added here
        forecast_discussion: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ storms[0]['forecastDiscussion'].url }}
        forecast_graphics: >-
          {% set storms = state_attr('sensor.current_storm_data','activeStorms')%}
          {{ storms[0]['forecastGraphics'].url }}
      icon: mdi:weather-hurricane
    #
    - name: "Storm 2"   < Note the name change!!!
      unique_id: storm_2   < Note the name change!!!
    continue adding each additional sensor here..........

Remember to remove the comments!!!

My configuration is based off a Sidebar View. The main panel shows either a map of all user and current gas prices, OR a storm map if storms are active. I use a simple conditional card for both maps.

The sidebar has 3 cards as follows:

  1. Active storms with conditional entities
type: entities
entities:
  - entity: sensor.storm_count
    name: Active Storms
    secondary_info: last-updated
  - entity: sensor.storm_1
    secondary_info: last-changed
  - type: conditional
    conditions:
      - entity: sensor.storm_2
        state_not: unavailable
    row:
      entity: sensor.storm_2
      secondary_info: last-updated
  - type: conditional
    conditions:
      - entity: sensor.storm_3
        state_not: unavailable
    row:
      entity: sensor.storm_3
      secondary_info: last-updated
  - type: conditional
    conditions:
      - entity: sensor.storm_4
        state_not: unavailable
    row:
      entity: sensor.storm_4
  - type: conditional
    conditions:
      - entity: sensor.storm_5
        state_not: unavailable
    row:
      entity: sensor.storm_5
      secondary_info: last-updated
view_layout:
  position: sidebar
title: Tropical Storms
visibility:
  - condition: state
    entity: sensor.storm_count
    state_not: '0'
  1. Local Forecast - conditional markdown card ON when no storms are active.
type: markdown
content: |2
    It's currently {{states('sensor.vh_current_condition')}} and
    {{states('sensor.tw1_outside_temperature')}} degrees at home. 

    Today will be {{ state_attr('sensor.current_forecast', 'current_forecast') }}

    Tomorrow is expected to be {{ state_attr('sensor.future_forecast',
    'future_forecast') }}

    {% if state_attr("sensor.coastal_duval_alert_1","display_title") != None %}

    **NWS Warning**

    {{ state_attr("sensor.coastal_duval_alert_1","display_title") }}

    {% else %}

    There are no weather warnings at this time.

    {% endif %}
title: Local Forecast
view_layout:
  position: sidebar
visibility:
  - condition: state
    entity: sensor.storm_count
    state: '0'
  1. Storm Details conditional markdown card ON with active storms
type: markdown
content: >-
  **{{ state_attr('sensor.storm_1', 'storm_name') -}}**

  {%- if state_attr('sensor.storm_1', 'region') == 'AT' %} (Atlantic)

  {%- elif state_attr('sensor.storm_1', 'region') == 'EP' %} (Eastern Pacific)

  {%- elif state_attr('sensor.storm_1', 'region') == 'CP' %} (Central Pacific)

  {%- endif %}


  {% if state_attr('sensor.storm_1', 'classification') == 'HU' %} Hurricane

  {%- elif state_attr('sensor.storm_1', 'classification') == 'TS' %} Tropical
  Storm

  {%- elif state_attr('sensor.storm_1', 'classification') == 'TD' %} Tropical
  Depression

  {%- else %}

  {% endif %} {{ state_attr('sensor.storm_1', 'storm_name') }} is currently {{
  state_attr('sensor.storm_1', 'distance') }} away, moving {{
  state_attr('sensor.storm_1', 'heading_text') }} at {{
  state_attr('sensor.storm_1', 'movement_speed') }} MPH. Maximum sustained winds
  are {{ state_attr('sensor.storm_1', 'max_winds') }} with a pressure of {{
  state_attr('sensor.storm_1', 'pressure') }} in/hg.

  Detailed information can be found <a href="{{ state_attr('sensor.storm_1',
  'forecast_discussion') }}">HERE</a>.

  Storm track and other related graphics are <a href="{{
  state_attr('sensor.storm_1', 'forecast_graphics') }}">HERE</a>.


  {% if states('sensor.storm_count')|int > 1 %}


  **{{ state_attr('sensor.storm_2', 'storm_name') }}**

  {%- if state_attr('sensor.storm_2', 'region') == 'AT' %} (Atlantic)

  {%- elif state_attr('sensor.storm_2', 'region') == 'EP' %} (Eastern Pacific)

  {%- elif state_attr('sensor.storm_2', 'region') == 'CP' %} (Central Pacific)

  {%- endif %}


  {% if state_attr('sensor.storm_2', 'classification') == 'HU' %} Hurricane

  {%- elif state_attr('sensor.storm_2', 'classification') == 'TS' %} Tropical
  Storm

  {%- elif state_attr('sensor.storm_2', 'classification') == 'TD' %} Tropical
  Depression

  {%- else %}

  {% endif %} {{ state_attr('sensor.storm_2', 'storm_name') }} is currently {{
  state_attr('sensor.storm_2', 'distance') }} away, moving {{
  state_attr('sensor.storm_2', 'heading_text') }} at {{
  state_attr('sensor.storm_2', 'movement_speed') }} MPH. Maximum sustained winds
  are {{ state_attr('sensor.storm_2', 'max_winds') }} with a pressure of {{
  state_attr('sensor.storm_2', 'pressure') }} in/hg.

  Detailed information can be found <a href="{{ state_attr('sensor.storm_2',
  'forecast_discussion') }}">HERE</a>.

  Storm track and other related graphics are <a href="{{
  state_attr('sensor.storm_2', 'forecast_graphics') }}">HERE</a>.

  {% endif %}


  {% if states('sensor.storm_count')|int > 2 %}


  **{{ state_attr('sensor.storm_3', 'storm_name') }}**

  {%- if state_attr('sensor.storm_3', 'region') == 'AT' %} (Atlantic)

  {%- elif state_attr('sensor.storm_3', 'region') == 'EP' %} (Eastern Pacific)

  {%- elif state_attr('sensor.storm_3', 'region') == 'CP' %} (Central Pacific)

  {%- endif %}


  {% if state_attr('sensor.storm_3', 'classification') == 'HU' %} Hurricane

  {%- elif state_attr('sensor.storm_3', 'classification') == 'TS' %} Tropical
  Storm

  {%- elif state_attr('sensor.storm_3', 'classification') == 'TD' %} Tropical
  Depression

  {%- else %}

  {% endif %} {{ state_attr('sensor.storm_3', 'storm_name') }} is currently {{
  state_attr('sensor.storm_3', 'distance') }} away, moving {{
  state_attr('sensor.storm_3', 'heading_text') }} at {{
  state_attr('sensor.storm_3', 'movement_speed') }} MPH. Maximum sustained winds
  are {{ state_attr('sensor.storm_3', 'max_winds') }} with a pressure of {{
  state_attr('sensor.storm_3', 'pressure') }} in/hg.

  Detailed information can be found <a href="{{ state_attr('sensor.storm_3',
  'forecast_discussion') }}">HERE</a>.

  Storm track and other related graphics are <a href="{{
  state_attr('sensor.storm_3', 'forecast_graphics') }}">HERE</a>.

  {% endif %}


  {% if states('sensor.storm_count')|int > 3 %}


  **{{ state_attr('sensor.storm_4', 'storm_name') }}**

  {%- if state_attr('sensor.storm_4', 'region') == 'AT' %} (Atlantic)

  {%- elif state_attr('sensor.storm_4', 'region') == 'EP' %} (Eastern Pacific)

  {%- elif state_attr('sensor.storm_4', 'region') == 'CP' %} (Central Pacific)

  {%- endif %}


  {% if state_attr('sensor.storm_4', 'classification') == 'HU' %} Hurricane

  {%- elif state_attr('sensor.storm_4', 'classification') == 'TS' %} Tropical
  Storm

  {%- elif state_attr('sensor.storm_4', 'classification') == 'TD' %} Tropical
  Depression

  {%- else %}

  {% endif %} {{ state_attr('sensor.storm_4', 'storm_name') }} is currently {{
  state_attr('sensor.storm_4', 'distance') }} away, moving {{
  state_attr('sensor.atlantic_storm_4', 'heading_text') }} at {{
  state_attr('sensor.storm_4', 'movement_speed') }} MPH. Maximum sustained winds
  are {{ state_attr('sensor.storm_4', 'max_winds') }} with a pressure of {{
  state_attr('sensor.storm_4', 'pressure') }} in/hg.

  Detailed information can be found <a href="{{ state_attr('sensor.storm_4',
  'forecast_discussion') }}">HERE</a>.

  Storm track and other related graphics are <a href="{{
  state_attr('sensor.storm_4', 'forecast_graphics') }}">HERE</a>.

  {% endif %}


  {% if states('sensor.storm_count')|int > 4 %}


  **{{ state_attr('sensor.storm_5', 'storm_name') }}**

  {%- if state_attr('sensor.storm_5', 'region') == 'AT' %} (Atlantic)

  {%- elif state_attr('sensor.storm_5', 'region') == 'EP' %} (Eastern Pacific)

  {%- elif state_attr('sensor.storm_5', 'region') == 'CP' %} (Central Pacific)

  {%- endif %}


  {% if state_attr('sensor.storm_5', 'classification') == 'HU' %} Hurricane

  {%- elif state_attr('sensor.storm_5', 'classification') == 'TS' %} Tropical
  Storm

  {%- elif state_attr('sensor.storm_5', 'classification') == 'TD' %} Tropical
  Depression

  {%- else %}

  {% endif %} {{ state_attr('sensor.storm_5', 'storm_name') }} is currently {{
  state_attr('sensor.storm_5', 'distance') }} away, moving {{
  state_attr('sensor.atlantic_storm_5', 'heading_text') }} at {{
  state_attr('sensor.storm_5', 'movement_speed') }} MPH. Maximum sustained winds
  are {{ state_attr('sensor.storm_5', 'max_winds') }} with a pressure of {{
  state_attr('sensor.storm_5', 'pressure') }} in/hg.

  Detailed information can be found <a href="{{ state_attr('sensor.storm_5',
  'forecast_discussion') }}">HERE</a>.

  Storm track and other related graphics are <a href="{{
  state_attr('sensor.storm_5', 'forecast_graphics') }}">HERE</a>.

  {% endif %}
title: National Hurricane Center
view_layout:
  position: sidebar
visibility:
  - condition: state
    entity: sensor.storm_count
    state_not: '0'

I hope this helps anyone who has used the code and wants the ability to tweak it to their desired taste. At this time I don’t have plans to take this any further (in terms of making it an add-on or integration). The code is all publicly available and free to change to meet your needs. If you add something really useful, please post it here!

Enjoy. Art (aka kartcon)

Even better than what I was looking for, thanks all!

FWIW, was looking at the API docs for more information and found this reference for the format of this JSON file if anyone’s interested in the future:

1 Like

That helps. I added movementDir to mine as well