Formula 1 Racing sensor

I have made a Formula 1 Sensor, a custom integration specifically designed to leverage Home Assistant for automations, notifications, and advanced setups based around Formula 1 race events.

What does F1 Sensor provide?

This integration fetches detailed and timely data from the Jolpica-F1 API, creating sensors:

  • sensor.f1_next_race – Next race information (location, schedule, timings).
  • sensor.f1_season_calendar – Complete current season calendar.
  • sensor.f1_driver_standings – Current driver championship standings.
  • sensor.f1_constructor_standings – Current constructor championship standings.
  • sensor.f1_weather - Current weather and race-time forecast at the next race location.
7 Likes

New pre-release adding result sensors

1 Like

Hey, I find it very handy those separate sensors, a lot of freedom to make your own dashboard cards. I made the Resuls card here and will do the rest, so far without problems.
You can click on that chevron-up icon to make the map expand and show the rest of the race results.

Here the code for the Driver Standings
You need custom button card mod (use hacs)
And make a “input_boolean.f1_race_results” so you can expand the card when you click on it

type: custom:button-card
entity: sensor.f12025_driver_standings
icon: mdi:trophy-variant-outline
show_name: false
show_state: false
show_icon: false
layout: custom
tap_action:
  action: call-service
  service: input_boolean.toggle
  service_data:
    entity_id: input_boolean.f1_drivers_toggle
styles:
  grid:
    - grid-template-areas: |
        "header"
        "standings"
    - row-gap: 12px
  card:
    - padding: 12px
    - border-radius: 8px
    - background: linear-gradient(135deg,
    - color: white
    - font-family: sans-serif
    - box-shadow: 0px 4px 10px rgba(0,0,0,0.3)
  custom_fields:
    header:
      - padding-bottom: 6px
      - border-bottom: 1px solid rgba(255,255,255,0.2)
    standings:
      - font-size: 14px
      - line-height: 1.6
      - display: flex
      - flex-direction: column
      - gap: 6px
custom_fields:
  header: |
    [[[
      if (!entity?.attributes) return "Stand niet beschikbaar";
      const expanded = states['input_boolean.f1_drivers_toggle']?.state === 'on';
      const icon = expanded ? "mdi:chevron-up" : "mdi:chevron-down";
      return `
        <div style="width: 100%; text-align: center;">
          <div style="display: inline-flex; align-items: center; gap: 8px; cursor: pointer;">
            <span style="font-weight: 600; font-size: 17px;">
              🏁 ${entity.attributes.season} Driver Standings - Round ${entity.attributes.round}
            </span>
            <ha-icon icon="${icon}" style="--mdc-icon-size: 20px;"></ha-icon>
          </div>
        </div>
      `;
    ]]]
  standings: |
    [[[
      if (!entity?.attributes?.driver_standings) return "Geen gegevens";

      const expanded = states['input_boolean.f1_drivers_toggle']?.state === 'on';
      const standings = expanded 
        ? entity.attributes.driver_standings 
        : entity.attributes.driver_standings.slice(0, 10);

      const teamColors = {
        "Red Bull": "#1E41FF",
        "Ferrari": "#DC0000",
        "Mercedes": "#00D2BE",
        "McLaren": "#FF8700",
        "Aston Martin": "#006F62",
        "Alpine F1 Team": "#0090FF",
        "RB F1 Team": "#6699FF",
        "Haas F1 Team": "#B6BABD",
        "Williams": "#005AFF",
        "Sauber": "#52E252"
      };

      return standings.map((d, idx) => {
        const code = d.Driver.code;
        const name = `${d.Driver.givenName} ${d.Driver.familyName}`;
        const team = d.Constructors[0]?.name || '';
        const color = teamColors[team] || "#888";
        const points = d.points;

        const highlight = idx === 0 
          ? '<b style="color: gold">' + name + '</b>' 
          : name;

        const bg = idx % 2 === 0 ? 'rgba(255,255,255,0.04)' : 'rgba(255,255,255,0.08)';

        return `
          <div style="display: flex; align-items: center; background: ${bg}; padding: 6px 10px; border-radius: 4px;">
            <div style="width: 4px; height: 26px; background: ${color}; border-radius: 2px; margin-right: 10px;"></div>
            <div style="flex: 1">
              <div style="color: var(--primary-text-color); font-weight: 500;">
                <strong>${d.position}.</strong> <strong>${code}</strong> - ${highlight}
              </div>
              <div style="font-size: 12px; color: var(--secondary-text-color);">${team} • ${points} pt${points == 1 ? '' : 's'}</div>
            </div>
          </div>`;
      }).join('');
    ]]]

Thanks for the integration and will post some screenshots tomorrow.

3 Likes

Could you please share the code.
I have installed both the card and the generation of the sensors, but I am not good with cards, and I have not yet found a rewarding card

I have post the code in my first post