Formula 1 Racing sensor

OK cool, would it be difficult to make that option a choice as well as the number of message history limit that the user could select when re-configuring the F1 Sensor? I can manually edit the sensor.py and the entity.py but would have to make the changes every time you updated the integration.

I will add it to the features list and investigate the possibility. It would really help if you could create one or two issues about this as a feature on GitHub.

Until then, you can use the File native integration to write the state to a file. I have been using that for testing purposes and it works very well.

Thanx I will take a look and also familiarise myself with the feature request on GitHub.

For the team here is my latest and updated “Race Control Message Board” this version will display a default of the last 10 messages, with a counter at the top let stating how many session messages are in total and a toggle to display all session messages if you want to review the post session messages. Added a clear button to clear ONLY the board messages and leaves the sensor history untouched.

I created a new dashboard view and select the “Panel (single card)” option, then add any of the available card options (or add a manual card), select the edit in yaml at the bottom left and then paste in the below code:

type: custom:html-template-card
ignore_line_breaks: true
content: >
  <style>
    @keyframes f1-pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:0.3;transform:scale(0.6)}}
    #rc-toggle{display:none;}
    #rc-clear{display:none;}
    #rc-extra-msgs{display:none;flex-direction:column;gap:5px;padding:0 12px 5px 12px;}
    #rc-toggle:checked ~ #rc-card #rc-extra-msgs{display:flex;}
    #rc-toggle:checked ~ #rc-card #rc-btn-show{display:none;}
    #rc-toggle:checked ~ #rc-card #rc-btn-hide{display:inline-block;}
    #rc-btn-hide{display:none;}
    #rc-clear:checked ~ #rc-card #rc-messages{display:none;}
    #rc-clear:checked ~ #rc-card #rc-cleared-msg{display:block;}
    #rc-clear:checked ~ #rc-card #rc-btn-show{display:none;}
    #rc-clear:checked ~ #rc-card #rc-btn-hide{display:none;}
    #rc-clear:checked ~ #rc-card #rc-btn-clear{display:none;}
    #rc-cleared-msg{display:none;}
  </style>

  {% set raw          = states('sensor.f1_race_control') %}
  {% set msgs = state_attr('sensor.f1_race_control', 'history') or [] %}
  {% set session      = states('sensor.f1_session_status') | lower %}
  {% set session_name = states('sensor.f1_current_session') %}
  {% set meeting_name = state_attr('sensor.f1_session_status', 'meeting_name') | default('') %}
  {% set location     = state_attr('sensor.f1_session_status', 'meeting_location') | default('') %}
  {% set country      = state_attr('sensor.f1_session_status', 'meeting_country') | default('') %}
  {% set circuit      = state_attr('sensor.f1_session_status', 'circuit_short_name') | default('') %}
  {% set sorted_msgs  = msgs | sort(attribute='utc') %}
  {% set total        = sorted_msgs | length %}
  {% set limit        = 10 %}

  {% set show_session = session_name not in ['unknown', 'unavailable', 'none', ''] %}

  {% if session == 'live' %}
    {% set badge_color  = '#00FF88' %}
    {% set badge_bg     = 'rgba(0,0,0,0.3)' %}
    {% set badge_border = 'rgba(255,255,255,0.3)' %}
    {% set badge_text   = '#FFFFFF' %}
    {% set badge_label  = 'LIVE' %}
    {% set dot_anim     = 'animation:f1-pulse 1.4s ease-in-out infinite;' %}
    {% set name_opacity = '1' %}
  {% elif session == 'suspended' %}
    {% set badge_color  = '#FFD700' %}
    {% set badge_bg     = 'rgba(255,215,0,0.1)' %}
    {% set badge_border = 'rgba(255,215,0,0.4)' %}
    {% set badge_text   = '#FFD700' %}
    {% set badge_label  = 'SUSPENDED' %}
    {% set dot_anim     = 'animation:f1-pulse 2s ease-in-out infinite;' %}
    {% set name_opacity = '0.6' %}
  {% elif session == 'break' %}
    {% set badge_color  = '#FF8000' %}
    {% set badge_bg     = 'rgba(255,128,0,0.1)' %}
    {% set badge_border = 'rgba(255,128,0,0.4)' %}
    {% set badge_text   = '#FF8000' %}
    {% set badge_label  = 'BREAK' %}
    {% set dot_anim     = '' %}
    {% set name_opacity = '0.6' %}
  {% elif session == 'pre' %}
    {% set badge_color  = '#4488FF' %}
    {% set badge_bg     = 'rgba(68,136,255,0.1)' %}
    {% set badge_border = 'rgba(68,136,255,0.4)' %}
    {% set badge_text   = '#4488FF' %}
    {% set badge_label  = 'PRE-SESSION' %}
    {% set dot_anim     = '' %}
    {% set name_opacity = '0.6' %}
  {% elif session in ['finished', 'finalised', 'ended'] %}
    {% set badge_color  = '#444455' %}
    {% set badge_bg     = 'rgba(0,0,0,0.2)' %}
    {% set badge_border = 'rgba(255,255,255,0.1)' %}
    {% set badge_text   = '#606070' %}
    {% set badge_label  = session | upper %}
    {% set dot_anim     = '' %}
    {% set name_opacity = '0.4' %}
  {% else %}
    {% set badge_color  = '#444455' %}
    {% set badge_bg     = 'rgba(0,0,0,0.2)' %}
    {% set badge_border = 'rgba(255,255,255,0.1)' %}
    {% set badge_text   = '#606070' %}
    {% set badge_label  = session | upper if session else 'OFFLINE' %}
    {% set dot_anim     = '' %}
    {% set name_opacity = '0.4' %}
  {% endif %}

  <input type="checkbox" id="rc-toggle">
  <input type="checkbox" id="rc-clear">

  <div id="rc-card" style="background:#08080A;border-radius:8px;overflow:hidden;padding-bottom:16px;font-family:'F1Regular',sans-serif;">

    <div style="background:#E8002D;display:flex;align-items:center;gap:16px;padding:12px 20px 12px 16px;margin-bottom:0;">
      <div style="display:flex;flex-direction:column;align-items:center;justify-content:center;flex-shrink:0;width:52px;">
        <div style="font-family:'F1Bold',sans-serif;font-size:48px;line-height:1;color:#fff;letter-spacing:-1px;">F<span style="color:#fff;">1</span></div>
      </div>
      <div style="flex:1;display:flex;flex-direction:column;gap:2px;">
        <div style="display:flex;align-items:baseline;gap:10px;">
          <div style="font-family:'F1Bold',sans-serif;font-size:22px;color:#ffffff;line-height:1;text-shadow:0 2px 4px rgba(0,0,0,0.3);">RACE CONTROL</div>
          {% if show_session %}
          <div style="font-family:'F1Bold',sans-serif;font-size:11px;letter-spacing:2px;color:rgba(255,255,255,0.6);text-transform:uppercase;white-space:nowrap;">{{ session_name | upper }}</div>
          {% endif %}
        </div>
        {% if meeting_name %}
        <div style="font-family:'F1Wide',sans-serif;font-size:12px;color:rgba(255,255,255,{{ name_opacity }});line-height:1.3;letter-spacing:0.5px;">{{ meeting_name }}</div>
        {% endif %}
        {% if location or country %}
        <div style="font-family:'F1Regular',sans-serif;font-size:11px;color:rgba(255,255,255,0.65);line-height:1.2;letter-spacing:0.3px;">{{ circuit if circuit else '' }}{% if circuit and (location or country) %} ¡ {% endif %}{{ location if location else country }}</div>
        {% endif %}
      </div>
      <div style="display:flex;align-items:center;gap:6px;background:{{ badge_bg }};border:1px solid {{ badge_border }};border-radius:2px;padding:5px 11px;flex-shrink:0;">
        <div style="width:7px;height:7px;border-radius:50%;background:{{ badge_color }};flex-shrink:0;{{ dot_anim }}"></div>
        <span style="font-family:'F1Bold',sans-serif;font-size:11px;letter-spacing:2px;color:{{ badge_text }};">{{ badge_label }}</span>
      </div>
    </div>

    <div style="height:3px;background:linear-gradient(90deg,#E8002D,rgba(255,107,107,0.27),transparent);margin-bottom:14px;"></div>

    <div style="display:flex;justify-content:space-between;align-items:center;padding:0 16px 10px;">
      <div style="display:flex;align-items:center;gap:10px;">
        <span style="font-family:'F1Regular',sans-serif;font-size:11px;letter-spacing:2px;text-transform:uppercase;color:#606070;">
          {% if raw == 'unavailable' %}LAST SESSION ¡ {% endif %}{{ [total, limit] | min }} of {{ total }} message{% if total != 1 %}s{% endif %}
        </span>
        {% if total > limit %}
        <label id="rc-btn-show" for="rc-toggle" style="font-family:'F1Bold',sans-serif;font-size:9px;letter-spacing:2px;text-transform:uppercase;color:#E8002D;background:rgba(232,0,45,0.08);border:1px solid rgba(232,0,45,0.3);border-radius:2px;padding:4px 10px;cursor:pointer;">SHOW ALL</label>
        <label id="rc-btn-hide" for="rc-toggle" style="font-family:'F1Bold',sans-serif;font-size:9px;letter-spacing:2px;text-transform:uppercase;color:#E8002D;background:rgba(232,0,45,0.08);border:1px solid rgba(232,0,45,0.3);border-radius:2px;padding:4px 10px;cursor:pointer;">SHOW LATEST</label>
        {% endif %}
        {% if total > 0 %}
        <label id="rc-btn-clear" for="rc-clear" style="font-family:'F1Bold',sans-serif;font-size:9px;letter-spacing:2px;text-transform:uppercase;color:#606070;background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.1);border-radius:2px;padding:4px 10px;cursor:pointer;">CLEAR</label>
        {% endif %}
      </div>
      
    </div>

    {% if raw == 'unknown' and total == 0 %}
      <div style="margin:12px;background:rgba(232,0,45,0.08);border:1px solid rgba(232,0,45,0.3);border-radius:2px;padding:14px 18px;font-family:'F1Regular',sans-serif;font-size:13px;letter-spacing:1px;color:#FF6B6B;">
        🏁 Awaiting race control transmissions
      </div>
    {% elif total == 0 %}
      <div style="text-align:center;padding:48px 20px;font-family:'F1Regular',sans-serif;letter-spacing:3px;text-transform:uppercase;font-size:14px;color:#2A2A32;">
        🏁 Awaiting race control transmissions
      </div>
    {% else %}

      <div id="rc-cleared-msg" style="text-align:center;padding:48px 20px;font-family:'F1Regular',sans-serif;letter-spacing:3px;text-transform:uppercase;font-size:14px;color:#2A2A32;">
        🏁 Board cleared
      </div>

      <div id="rc-messages">

        {% macro render_msg(msg, idx) %}
          {% set txt      = msg.message | default('') %}
          {% set ts       = msg.utc | default('') %}
          {% set category = msg.category | default('') %}
          {% set flag     = msg.flag | default('') | upper %}
          {% set tu       = txt | upper %}
          {% if flag == 'RED' or 'RED FLAG' in tu %}
            {% set bcolor = '#FF2222' %} {% set cat_label = 'Red Flag' %} {% set cat_color = '#FF4444' %} {% set bg = 'rgba(255,0,0,0.06)' %}
          {% elif flag == 'YELLOW' or ('YELLOW' in tu and 'GREEN' not in tu) %}
            {% set bcolor = '#FFD700' %} {% set cat_label = 'Yellow Flag' %} {% set cat_color = '#FFD700' %} {% set bg = 'rgba(255,215,0,0.04)' %}
          {% elif flag == 'GREEN' or 'GREEN' in tu %}
            {% set bcolor = '#00D2BE' %} {% set cat_label = 'Green Flag' %} {% set cat_color = '#00D2BE' %} {% set bg = '#15151A' %}
          {% elif 'SAFETY CAR' in tu %}
            {% set bcolor = '#FFD700' %} {% set cat_label = 'Safety Car' %} {% set cat_color = '#FFD700' %} {% set bg = '#15151A' %}
          {% elif 'VIRTUAL SAFETY' in tu or 'VSC' in tu %}
            {% set bcolor = '#FFD700' %} {% set cat_label = 'Virtual Safety Car' %} {% set cat_color = '#FFD700' %} {% set bg = '#15151A' %}
          {% elif 'DRS' in tu %}
            {% set bcolor = '#00D2BE' %} {% set cat_label = 'DRS' %} {% set cat_color = '#00D2BE' %} {% set bg = '#15151A' %}
          {% elif 'PENALTY' in tu or 'DRIVE THROUGH' in tu or 'STOP AND GO' in tu %}
            {% set bcolor = '#FF8000' %} {% set cat_label = 'Penalty' %} {% set cat_color = '#FF8000' %} {% set bg = '#15151A' %}
          {% elif 'INVESTIGATION' in tu or 'STEWARD' in tu or 'NOTED' in tu %}
            {% set bcolor = '#FF8000' %} {% set cat_label = 'Stewards' %} {% set cat_color = '#FF8000' %} {% set bg = '#15151A' %}
          {% elif 'CHEQUERED' in tu or 'SESSION END' in tu or 'RACE END' in tu %}
            {% set bcolor = '#0067FF' %} {% set cat_label = 'Session End' %} {% set cat_color = '#0067FF' %} {% set bg = '#15151A' %}
          {% elif 'OVERTAKE' in tu or 'PIT' in tu or 'RESUME' in tu %}
            {% set bcolor = '#0067FF' %} {% set cat_label = category if category else 'Info' %} {% set cat_color = '#4488FF' %} {% set bg = '#15151A' %}
          {% else %}
            {% set bcolor = '#2A2A32' %} {% set cat_label = category if category else 'Message' %} {% set cat_color = '#606070' %} {% set bg = '#15151A' %}
          {% endif %}
          {% if ts | length >= 19 %}
            {% set time_display = ts[11:19] %}
          {% elif ts | length > 0 %}
            {% set time_display = ts %}
          {% else %}
            {% set time_display = '--:--:--' %}
          {% endif %}
          <div style="background:{{ bg }};border:1px solid #2A2A32;border-left:3px solid {{ bcolor }};border-radius:2px;padding:10px 14px;display:flex;gap:12px;align-items:flex-start;">
            <div style="font-family:'F1Regular',sans-serif;font-weight:700;font-size:10px;color:#606070;min-width:24px;padding-top:2px;">#{{ '%02d' % idx }}</div>
            <div style="font-family:'F1Regular',sans-serif;font-size:13px;color:#E8002D;min-width:64px;white-space:nowrap;padding-top:1px;font-variant-numeric:tabular-nums;">{{ time_display }}</div>
            <div style="flex:1;">
              <div style="font-family:'F1Bold',sans-serif;font-size:9px;letter-spacing:2px;text-transform:uppercase;margin-bottom:2px;color:{{ cat_color }};">{{ cat_label }}</div>
              <div style="font-family:'F1Regular',sans-serif;font-size:13px;color:#FFFFFF;line-height:1.5;">{{ txt }}</div>
            </div>
          </div>
        {% endmacro %}

        {% if total > limit %}
        <div id="rc-extra-msgs">
          {% for msg in sorted_msgs[:(total - limit)] %}
            {{ render_msg(msg, loop.index) }}
          {% endfor %}
        </div>
        {% endif %}

        <div style="display:flex;flex-direction:column;gap:5px;padding:0 12px;">
          {% for msg in sorted_msgs[-limit:] %}
            {{ render_msg(msg, (total - limit + loop.index) if total > limit else loop.index) }}
          {% endfor %}
        </div>

      </div>

    {% endif %}

  </div>

1 Like

I’m either blind or the feature doesn’t exist. Is it possible to “fast forward” in replay mode?

Not at the moment

1 Like

would be something id really be looking for as well, had played around myself with a script until i saw there was know exposed seek/position control

This is so amazing, thank you for doing this. I have my light set up and built and anxious to try our tonight during qualifying. I am using this connected up to a WLED RGB strip. I’m wondering if it would be possible to offer a variation of your code that can call out a WLED playlist preset rather than a solid color?

Started making my dashboard. Need to play around with it. I’ve set it up, so it shows slightly different on small (such as mobiles) and larger (tablets, laptops etc) screens to accommodate space. I am using 4.1.0-beta.1 of F1 Sensor, and 1.3.0-beta.1 of F1 Sensor Live Data Card. You also require to have layout-card installed from HACS.
Code is at the bottom

Smaller Screens

Larger Screens

type: custom:layout-card
layout_type: custom:grid-layout
layout:
  grid-template-columns: repeat(12, minmax(0, 1fr))
  grid-template-rows: auto
  grid-gap: 8px
  width: 100%
  max_width: 100%
  margin: 0
  card_margin: 0
  grid-template-areas: >
    "card1 card1 card1 card1 card1 card1 card1 card1 card1 card1 card1 card1"
    "card2 card2 card2 card2 card2 card2 card2 card2 card2 card2 card2 card2"
    "card3 card3 card3 card3 card4 card4 card4 card4 card4 card4 card4 card4"
    "card5 card5 card5 card5 card5 card5 card6 card6 card6 card6 card6 card6"
  mediaquery:
    "(max-width: 768px)":
      grid-template-columns: minmax(0, 1fr)
      grid-template-areas: |
        "card1"
        "card2"
        "card3"
        "card4"
        "card5"
        "card6"
cards:
  - show_flag: true
    show_lap_progress: true
    show_track_status: true
    show_weather: true
    show_time_remaining: true
    show_time_elapsed: true
    type: custom:f1-live-session-card
    view_layout:
      grid-area: card1
    session_entity: sensor.f1_current_session
    session_status_entity: sensor.f1_session_status
    formation_start_entity: binary_sensor.f1_formation_start
    lap_count_entity: sensor.f1_race_lap_count
    track_status_entity: sensor.f1_track_status
    next_race_entity: sensor.f1_next_race
    session_time_remaining_entity: sensor.f1_session_session_time_remaining
    session_time_elapsed_entity: sensor.f1_session_session_time_elapsed
    overtake_mode_entity: binary_sensor.f1_session_overtake_mode
    straight_mode_entity: sensor.f1_session_straight_mode
    weather_entity: sensor.f1_track_weather
  - show_fia_logo: true
    min_display_time: 3
    type: custom:f1-race-control-card
    view_layout:
      grid-area: card2
    entity: sensor.f1_race_control
  - type: custom:f1-pitstop-overview-card
    view_layout:
      grid-area: card3
    drivers_entity: sensor.f1_driver_list
    positions_entity: sensor.f1_driver_positions
    tyres_entity: sensor.f1_current_tyres
    pitstops_entity: sensor.f1_pitstops
    title: Pit Stops & Tyres
    show_header: true
    show_table_header: true
    show_tla: true
    show_team_logo: false
    show_status: true
    show_tyre: true
    show_pit_count: true
    show_pit_time: true
    show_pit_lane_time: true
    show_pit_delta: true
  - type: custom:f1-driver-lap-times-card
    view_layout:
      grid-area: card4
      show:
        mediaquery: "(min-width: 769px)"
    drivers_entity: sensor.f1_driver_list
    positions_entity: sensor.f1_driver_positions
    title: Driver Lap Times
    show_lap_history: true
    show_lap_trend: true
    show_best_lap: true
    show_last_lap: false
    show_status: false
    show_tla: true
    show_team_logo: true
    show_table_header: true
    show_header: true
    show_position: true
    lap_history_limit: 3
  - type: custom:f1-driver-lap-times-card
    view_layout:
      grid-area: card4
      show:
        mediaquery: "(max-width: 768px)"
    drivers_entity: sensor.f1_driver_list
    positions_entity: sensor.f1_driver_positions
    title: Driver Lap Times
    show_lap_history: true
    show_lap_trend: true
    show_best_lap: true
    show_last_lap: false
    show_status: false
    show_tla: true
    show_team_logo: true
    show_table_header: true
    show_header: true
    show_position: true
    lap_history_limit: 1
  - type: custom:f1-sensor-live-data-card
    view_layout:
      grid-area: card5
    entity: sensor.f1_tyre_statistics
    drivers_entity: sensor.f1_driver_list
    title: Tyres Statistics
    show_tyre_image: true
    show_compound_name: false
    show_best_times: true
    show_stats: true
    show_delta: true
    show_team_logo: false
    show_header: true
  - type: custom:f1-track-limits-card
    view_layout:
      grid-area: card6
    track_limits_entity: sensor.f1_track_limits
    drivers_entity: sensor.f1_driver_list
    positions_entity: sensor.f1_driver_positions
    title: Track Limits
    show_team_logo: true
    show_table_header: false
    show_all_drivers: false
2 Likes

Interesting that track status during quali goes from Red > Clear > Yellow while the session is suspended. Is that just how the data reports from F1?

Probably. The track status is constantly updated during a session which is from the start of Q1 till the end of Q3. If they clear the red flag, but it’s still a yellow, it’ll probably do that. However I don’t know exactly, as I haven’t looked at the API

I dunno why…
But dd try to test the lights today on practice and qualify…
But it failed totally…
Is it because the new core updates etc? ?
It did work always for me…

Update: after reinstall everything to the latest beta’s etc
I gotta it kind of working…
But it’s not 100% yet…
Yay

The lights automation kinda worked for me, except for triggering a few to many times

@Stimo and anyone who is using or willing to use GitHub, I’ve created a discussion thread there to have a central place to put things that happened during this weekend’s Australian GP. This includes, but is not limited to:

  • Any interesting findings with data
  • Bugs report links (please do not put full bug reports here, but you’re welcome to link to them)
  • Cool things you’ve created, such as dashboards or automations

Findings, Bugs and Cool things during the Australian GP weekend (GitHub)

1 Like

Wow, so much work has been done. Nice and thx Profile - Stimo - Home Assistant Community !

1 Like

I love the info in the card “F1 Live Session Status card” and therefor like all information shown. If I do that the flag and elapsed time pushes out the track status and other mode information. Would it be possible to make this fit by adding this info in extra rows? Thx in advance.

Rewatching the session this morning, it does appear this is how F1 reports it. The track status is red until all cars are off the track, then switches to yellow until crews have cleared the issue, flags waivers on the track confirm this in the broadcast.

here is the same but with a reversed order so the newest message is at the top and the oldeest at the bottom:

type: custom:html-template-card
ignore_line_breaks: true
content: >
  <style>
    @keyframes f1-pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:0.3;transform:scale(0.6)}}
    #rc-toggle{display:none;}
    #rc-clear{display:none;}
    #rc-extra-msgs{display:none;flex-direction:column;gap:5px;padding:0 12px 5px 12px;}
    #rc-toggle:checked ~ #rc-card #rc-extra-msgs{display:flex;}
    #rc-toggle:checked ~ #rc-card #rc-btn-show{display:none;}
    #rc-toggle:checked ~ #rc-card #rc-btn-hide{display:inline-block;}
    #rc-btn-hide{display:none;}
    #rc-clear:checked ~ #rc-card #rc-messages{display:none;}
    #rc-clear:checked ~ #rc-card #rc-cleared-msg{display:block;}
    #rc-clear:checked ~ #rc-card #rc-btn-show{display:none;}
    #rc-clear:checked ~ #rc-card #rc-btn-hide{display:none;}
    #rc-clear:checked ~ #rc-card #rc-btn-clear{display:none;}
    #rc-cleared-msg{display:none;}
  </style>

  {% set raw          = states('sensor.f1_race_control') %}
  {% set msgs         = state_attr('sensor.f1_race_control', 'history') or [] %}
  {% set session      = states('sensor.f1_session_status') | lower %}
  {% set session_name = states('sensor.f1_current_session') %}
  {% set meeting_name = state_attr('sensor.f1_session_status', 'meeting_name') | default('') %}
  {% set location     = state_attr('sensor.f1_session_status', 'meeting_location') | default('') %}
  {% set country      = state_attr('sensor.f1_session_status', 'meeting_country') | default('') %}
  {% set circuit      = state_attr('sensor.f1_session_status', 'circuit_short_name') | default('') %}
  {% set sorted_msgs  = msgs | sort(attribute='utc') %}
  {% set total        = sorted_msgs | length %}
  {% set limit        = 10 %}

  {% set show_session = session_name not in ['unknown', 'unavailable', 'none', ''] %}

  {% if session == 'live' %}
    {% set badge_color  = '#00FF88' %}
    {% set badge_bg     = 'rgba(0,0,0,0.3)' %}
    {% set badge_border = 'rgba(255,255,255,0.3)' %}
    {% set badge_text   = '#FFFFFF' %}
    {% set badge_label  = 'LIVE' %}
    {% set dot_anim     = 'animation:f1-pulse 1.4s ease-in-out infinite;' %}
    {% set name_opacity = '1' %}
  {% elif session == 'suspended' %}
    {% set badge_color  = '#FFD700' %}
    {% set badge_bg     = 'rgba(255,215,0,0.1)' %}
    {% set badge_border = 'rgba(255,215,0,0.4)' %}
    {% set badge_text   = '#FFD700' %}
    {% set badge_label  = 'SUSPENDED' %}
    {% set dot_anim     = 'animation:f1-pulse 2s ease-in-out infinite;' %}
    {% set name_opacity = '0.6' %}
  {% elif session == 'break' %}
    {% set badge_color  = '#FF8000' %}
    {% set badge_bg     = 'rgba(255,128,0,0.1)' %}
    {% set badge_border = 'rgba(255,128,0,0.4)' %}
    {% set badge_text   = '#FF8000' %}
    {% set badge_label  = 'BREAK' %}
    {% set dot_anim     = '' %}
    {% set name_opacity = '0.6' %}
  {% elif session == 'pre' %}
    {% set badge_color  = '#4488FF' %}
    {% set badge_bg     = 'rgba(68,136,255,0.1)' %}
    {% set badge_border = 'rgba(68,136,255,0.4)' %}
    {% set badge_text   = '#4488FF' %}
    {% set badge_label  = 'PRE-SESSION' %}
    {% set dot_anim     = '' %}
    {% set name_opacity = '0.6' %}
  {% elif session in ['finished', 'finalised', 'ended'] %}
    {% set badge_color  = '#444455' %}
    {% set badge_bg     = 'rgba(0,0,0,0.2)' %}
    {% set badge_border = 'rgba(255,255,255,0.1)' %}
    {% set badge_text   = '#606070' %}
    {% set badge_label  = session | upper %}
    {% set dot_anim     = '' %}
    {% set name_opacity = '0.4' %}
  {% else %}
    {% set badge_color  = '#444455' %}
    {% set badge_bg     = 'rgba(0,0,0,0.2)' %}
    {% set badge_border = 'rgba(255,255,255,0.1)' %}
    {% set badge_text   = '#606070' %}
    {% set badge_label  = session | upper if session else 'OFFLINE' %}
    {% set dot_anim     = '' %}
    {% set name_opacity = '0.4' %}
  {% endif %}

  <input type="checkbox" id="rc-toggle">
  <input type="checkbox" id="rc-clear">

  <div id="rc-card" style="background:#08080A;border-radius:8px;overflow:hidden;padding-bottom:16px;font-family:'F1Regular',sans-serif;">

    <div style="background:#E8002D;display:flex;align-items:center;gap:16px;padding:12px 20px 12px 16px;margin-bottom:0;">
      <div style="display:flex;flex-direction:column;align-items:center;justify-content:center;flex-shrink:0;width:52px;">
        <div style="font-family:'F1Bold',sans-serif;font-size:48px;line-height:1;color:#fff;letter-spacing:-1px;">F<span style="color:#fff;">1</span></div>
      </div>
      <div style="flex:1;display:flex;flex-direction:column;gap:2px;">
        <div style="display:flex;align-items:baseline;gap:10px;">
          <div style="font-family:'F1Bold',sans-serif;font-size:22px;color:#ffffff;line-height:1;text-shadow:0 2px 4px rgba(0,0,0,0.3);">RACE CONTROL</div>
          {% if show_session %}
          <div style="font-family:'F1Bold',sans-serif;font-size:11px;letter-spacing:2px;color:rgba(255,255,255,0.6);text-transform:uppercase;white-space:nowrap;">{{ session_name | upper }}</div>
          {% endif %}
        </div>
        {% if meeting_name %}
        <div style="font-family:'F1Wide',sans-serif;font-size:12px;color:rgba(255,255,255,{{ name_opacity }});line-height:1.3;letter-spacing:0.5px;">{{ meeting_name }}</div>
        {% endif %}
        {% if location or country %}
        <div style="font-family:'F1Regular',sans-serif;font-size:11px;color:rgba(255,255,255,0.65);line-height:1.2;letter-spacing:0.3px;">{{ circuit if circuit else '' }}{% if circuit and (location or country) %} ¡ {% endif %}{{ location if location else country }}</div>
        {% endif %}
      </div>
      <div style="display:flex;align-items:center;gap:6px;background:{{ badge_bg }};border:1px solid {{ badge_border }};border-radius:2px;padding:5px 11px;flex-shrink:0;">
        <div style="width:7px;height:7px;border-radius:50%;background:{{ badge_color }};flex-shrink:0;{{ dot_anim }}"></div>
        <span style="font-family:'F1Bold',sans-serif;font-size:11px;letter-spacing:2px;color:{{ badge_text }};">{{ badge_label }}</span>
      </div>
    </div>

    <div style="height:3px;background:linear-gradient(90deg,#E8002D,rgba(255,107,107,0.27),transparent);margin-bottom:14px;"></div>

    <div style="display:flex;justify-content:space-between;align-items:center;padding:0 16px 10px;">
      <div style="display:flex;align-items:center;gap:10px;">
        <span style="font-family:'F1Regular',sans-serif;font-size:11px;letter-spacing:2px;text-transform:uppercase;color:#606070;">
          {% if raw == 'unavailable' %}LAST SESSION ¡ {% endif %}{{ [total, limit] | min }} of {{ total }} message{% if total != 1 %}s{% endif %}
        </span>
        {% if total > limit %}
        <label id="rc-btn-show" for="rc-toggle" style="font-family:'F1Bold',sans-serif;font-size:9px;letter-spacing:2px;text-transform:uppercase;color:#E8002D;background:rgba(232,0,45,0.08);border:1px solid rgba(232,0,45,0.3);border-radius:2px;padding:4px 10px;cursor:pointer;">SHOW ALL</label>
        <label id="rc-btn-hide" for="rc-toggle" style="font-family:'F1Bold',sans-serif;font-size:9px;letter-spacing:2px;text-transform:uppercase;color:#E8002D;background:rgba(232,0,45,0.08);border:1px solid rgba(232,0,45,0.3);border-radius:2px;padding:4px 10px;cursor:pointer;">SHOW LATEST</label>
        {% endif %}
        {% if total > 0 %}
        <label id="rc-btn-clear" for="rc-clear" style="font-family:'F1Bold',sans-serif;font-size:9px;letter-spacing:2px;text-transform:uppercase;color:#606070;background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.1);border-radius:2px;padding:4px 10px;cursor:pointer;">CLEAR</label>
        {% endif %}
      </div>
    </div>

    {% if raw == 'unknown' and total == 0 %}
      <div style="margin:12px;background:rgba(232,0,45,0.08);border:1px solid rgba(232,0,45,0.3);border-radius:2px;padding:14px 18px;font-family:'F1Regular',sans-serif;font-size:13px;letter-spacing:1px;color:#FF6B6B;">
        🏁 Awaiting race control transmissions
      </div>
    {% elif total == 0 %}
      <div style="text-align:center;padding:48px 20px;font-family:'F1Regular',sans-serif;letter-spacing:3px;text-transform:uppercase;font-size:14px;color:#2A2A32;">
        🏁 Awaiting race control transmissions
      </div>
    {% else %}

      <div id="rc-cleared-msg" style="text-align:center;padding:48px 20px;font-family:'F1Regular',sans-serif;letter-spacing:3px;text-transform:uppercase;font-size:14px;color:#2A2A32;">
        🏁 Board cleared
      </div>

      <div id="rc-messages">

        {% macro render_msg(msg, idx) %}
          {% set txt      = msg.message | default('') %}
          {% set ts       = msg.utc | default('') %}
          {% set category = msg.category | default('') %}
          {% set flag     = msg.flag | default('') | upper %}
          {% set tu       = txt | upper %}
          {% if flag == 'RED' or 'RED FLAG' in tu %}
            {% set bcolor = '#FF2222' %} {% set cat_label = 'Red Flag' %} {% set cat_color = '#FF4444' %} {% set bg = 'rgba(255,0,0,0.06)' %}
          {% elif flag == 'YELLOW' or ('YELLOW' in tu and 'GREEN' not in tu) %}
            {% set bcolor = '#FFD700' %} {% set cat_label = 'Yellow Flag' %} {% set cat_color = '#FFD700' %} {% set bg = 'rgba(255,215,0,0.04)' %}
          {% elif flag == 'GREEN' or 'GREEN' in tu %}
            {% set bcolor = '#00D2BE' %} {% set cat_label = 'Green Flag' %} {% set cat_color = '#00D2BE' %} {% set bg = '#15151A' %}
          {% elif 'SAFETY CAR' in tu %}
            {% set bcolor = '#FFD700' %} {% set cat_label = 'Safety Car' %} {% set cat_color = '#FFD700' %} {% set bg = '#15151A' %}
          {% elif 'VIRTUAL SAFETY' in tu or 'VSC' in tu %}
            {% set bcolor = '#FFD700' %} {% set cat_label = 'Virtual Safety Car' %} {% set cat_color = '#FFD700' %} {% set bg = '#15151A' %}
          {% elif 'DRS' in tu %}
            {% set bcolor = '#00D2BE' %} {% set cat_label = 'DRS' %} {% set cat_color = '#00D2BE' %} {% set bg = '#15151A' %}
          {% elif 'PENALTY' in tu or 'DRIVE THROUGH' in tu or 'STOP AND GO' in tu %}
            {% set bcolor = '#FF8000' %} {% set cat_label = 'Penalty' %} {% set cat_color = '#FF8000' %} {% set bg = '#15151A' %}
          {% elif 'INVESTIGATION' in tu or 'STEWARD' in tu or 'NOTED' in tu %}
            {% set bcolor = '#FF8000' %} {% set cat_label = 'Stewards' %} {% set cat_color = '#FF8000' %} {% set bg = '#15151A' %}
          {% elif 'CHEQUERED' in tu or 'SESSION END' in tu or 'RACE END' in tu %}
            {% set bcolor = '#0067FF' %} {% set cat_label = 'Session End' %} {% set cat_color = '#0067FF' %} {% set bg = '#15151A' %}
          {% elif 'OVERTAKE' in tu or 'PIT' in tu or 'RESUME' in tu %}
            {% set bcolor = '#0067FF' %} {% set cat_label = category if category else 'Info' %} {% set cat_color = '#4488FF' %} {% set bg = '#15151A' %}
          {% else %}
            {% set bcolor = '#2A2A32' %} {% set cat_label = category if category else 'Message' %} {% set cat_color = '#606070' %} {% set bg = '#15151A' %}
          {% endif %}
          {% if ts | length >= 19 %}
            {% set time_display = ts[11:19] %}
          {% elif ts | length > 0 %}
            {% set time_display = ts %}
          {% else %}
            {% set time_display = '--:--:--' %}
          {% endif %}
          <div style="background:{{ bg }};border:1px solid #2A2A32;border-left:3px solid {{ bcolor }};border-radius:2px;padding:10px 14px;display:flex;gap:12px;align-items:flex-start;">
            <div style="font-family:'F1Regular',sans-serif;font-weight:700;font-size:10px;color:#606070;min-width:24px;padding-top:2px;">#{{ '%02d' % idx }}</div>
            <div style="font-family:'F1Regular',sans-serif;font-size:13px;color:#E8002D;min-width:64px;white-space:nowrap;padding-top:1px;font-variant-numeric:tabular-nums;">{{ time_display }}</div>
            <div style="flex:1;">
              <div style="font-family:'F1Bold',sans-serif;font-size:9px;letter-spacing:2px;text-transform:uppercase;margin-bottom:2px;color:{{ cat_color }};">{{ cat_label }}</div>
              <div style="font-family:'F1Regular',sans-serif;font-size:13px;color:#FFFFFF;line-height:1.5;">{{ txt }}</div>
            </div>
          </div>
        {% endmacro %}

        <!-- Latest messages: newest first at top -->
        <div style="display:flex;flex-direction:column;gap:5px;padding:0 12px 5px 12px;">
          {% for msg in sorted_msgs[-limit:] | reverse %}
            {{ render_msg(msg, total - loop.index0) }}
          {% endfor %}
        </div>

        <!-- Older messages: revealed by SHOW ALL, below latest -->
        {% if total > limit %}
        <div id="rc-extra-msgs">
          {% for msg in sorted_msgs[:(total - limit)] | reverse %}
            {{ render_msg(msg, total - limit - loop.index0) }}
          {% endfor %}
        </div>
        {% endif %}

      </div>

    {% endif %}

  </div>

C’mon, some feedback - youve got some real time data to work with over the last quarter hour - how is it going?

@Stimo

Great first race!! love the work that you have done to the integration. Coffee has been purchased for your great work.

Just one observation on the Driver and Lap card. It currently only shows the lap sector times but not the gap times from each car in front and the leader. Would it be possible to add this to the card? I checked all the F1 sensors for that attribute but couldn’t find it.

Here is the drive card as it appears now:

Here is the example from the f1-dash.com/dashboard:

On the tyre statistics, it looks like all the sensors went off line. or is it my set up? I searched for an updated sensor, but couldn’t find any:

I also note that the line height on the Driver & Lap times card is slightly smaller than on the Tyre card, which puts the bottom out of alighment when the two cards are stacked side by side. could you adjust the Driver & Lap times card to be the same line heights so they align?

My last bit of feedback, I see on the TV (F1TV) they showed a remaining battery and over take mode. Would you be able to add that one to your F1 sensors in a nice matching card?

On that note, would you consider using my Race Control message board to make it in to your integration and match the other F1 integration cards?


First things first, thanks for this awesome integration! I noticed my Session Track status is stuck at VSC since the last VSC.