Skip to content

Commit

Permalink
Added option to show race info in countdown card (#96)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcokreeft87 authored Jan 21, 2023
1 parent c427dd1 commit 7572060
Show file tree
Hide file tree
Showing 18 changed files with 240 additions and 152 deletions.
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ or added by clicking the "Add to lovelace" button on the HACS dashboard after in
| date_locale | string | | Override the locale used for the date and time formatting |
| image_clickable | boolean | `false` | Click on image leads to wikipedia, or not |
| show_carnumber | boolean | `false` | Show the number of the car |
| show_raceinfo | boolean | `false` | Show the info of the race in the countdown card |
| location_clickable| boolean | `false` | Click on the location leads to wikipedia |
| previous_race | enum | | Hide/strikethrough or make the past races italic options are (hide, strikethrough or italic) |
| standings | object | | Configuration for the driver standings card |
Expand Down Expand Up @@ -126,18 +127,18 @@ The following texts can be translated or altered.
| Card type(s) | Key | Default value |
| ----------------------------------- | ------------- | ----------------------------------- |
| next_race, schedule | date | 'Date' |
| next_race | practice1 | 'Practice 1' |
| next_race | practice2 | 'Practice 2' |
| next_race | practice3 | 'Practice 3' |
| next_race, schedule | race' | 'Race' |
| next_race | racename | 'Race name' |
| next_race | circuitname | 'Circuit name' |
| next_race, schedule | location' | 'Location' |
| next_race | city | 'City' |
| next_race | racetime | 'Race' |
| next_race | sprint | 'Sprint' |
| next_race | qualifying | 'Qualifying' |
| next_race, schedule | endofseason | 'Season is over. See you next year!' |
| next_race, countdown | practice1 | 'Practice 1' |
| next_race, countdown | practice2 | 'Practice 2' |
| next_race, countdown | practice3 | 'Practice 3' |
| next_race, countdown, schedule | race' | 'Race' |
| next_race, countdown | racename | 'Race name' |
| next_race, countdown | circuitname | 'Circuit name' |
| next_race, countdown, schedule | location' | 'Location' |
| next_race, countdown | city | 'City' |
| next_race, countdown | racetime | 'Race' |
| next_race, countdown | sprint | 'Sprint' |
| next_race, countdown | qualifying | 'Qualifying' |
| next_race, countdown, schedule | endofseason | 'Season is over. See you next year!' |
| constructor_standings | constructor | 'Constructor' |
| constructor_standings, driver_standings, last_result | points | 'Pts' |
| constructor_standings, driver_standings | wins | 'Wins' |
Expand Down
40 changes: 21 additions & 19 deletions formulaone-card.js

Large diffs are not rendered by default.

Binary file modified formulaone-card.js.gz
Binary file not shown.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "formulaone-card",
"version": "0.5.1",
"version": "0.5.2",
"description": "Frontend card for Home Assistant to display Formula One data",
"main": "index.js",
"scripts": {
Expand Down
38 changes: 34 additions & 4 deletions src/cards/countdown.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,50 @@
import { html, HTMLTemplateResult } from "lit-html";
import { until } from 'lit-html/directives/until.js';
import { getApiErrorMessage, getApiLoadingMessage, getCountryFlagByName, getEndOfSeasonMessage } from "../utils";
import { getApiErrorMessage, getApiLoadingMessage, getCountryFlagByName, getEndOfSeasonMessage, renderHeader, renderRaceInfo } from "../utils";
import { BaseCard } from "./base-card";
import { asyncReplace } from 'lit/directives/async-replace.js';
import { Race } from "../api/models";
import { HomeAssistant } from "custom-card-helpers";
import { FormulaOneCardConfig } from "../types/formulaone-card-types";

export default class Countdown extends BaseCard {
hass: HomeAssistant;
defaultTranslations = {
'days' : 'd',
'hours' : 'h',
'minutes' : 'm',
'seconds' : 's',
'endofseason' : 'Season is over. See you next year!',
'racenow' : 'We are racing!'
'racenow' : 'We are racing!',
'date' : 'Date',
'practice1' : 'Practice 1',
'practice2' : 'Practice 2',
'practice3' : 'Practice 3',
'race' : 'Race',
'racename' : 'Race name',
'circuitname' : 'Circuit name',
'location' : 'Location',
'city': 'City',
'racetime' : 'Race',
'sprint' : 'Sprint',
'qualifying' : 'Qualifying'
};

constructor(hass: HomeAssistant, config: FormulaOneCardConfig) {
super(config);

this.hass = hass;
}

cardSize(): number {
return 6;
return this.config.show_raceinfo ? 12 : 6;
}

renderHeader(race: Race): HTMLTemplateResult {
return this.config.show_raceinfo ?
html`<table><tr><td colspan="5">${renderHeader(this.config, race, true)}</td></tr>
${renderRaceInfo(this.hass, this.config, race, this)}</table>`
: null;
}

async *countDownTillDate(raceDateTime: Date) {
Expand Down Expand Up @@ -71,7 +100,8 @@ export default class Countdown extends BaseCard {
<h1>${asyncReplace(timer)}</h1>
</td>
</tr>
</table>`;
</table>
${this.renderHeader(nextRace)}`;
}),
html`${getApiLoadingMessage()}`
Expand Down
18 changes: 4 additions & 14 deletions src/cards/last-result.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { html, HTMLTemplateResult } from "lit-html";
import { until } from 'lit-html/directives/until.js';
import { Race, Result } from "../api/models";
import { Result } from "../api/models";
import { FormulaOneCardConfig } from "../types/formulaone-card-types";
import { getApiErrorMessage, getApiLoadingMessage, getCircuitName, getCountryFlagByName, getDriverName } from "../utils";
import { getApiErrorMessage, getApiLoadingMessage, getDriverName, renderHeader } from "../utils";
import { BaseCard } from "./base-card";

export default class LastResult extends BaseCard {
Expand Down Expand Up @@ -31,17 +31,7 @@ export default class LastResult extends BaseCard {
<td class="width-60 text-center">${result.points}</td>
<td class="width-50 text-center">${result.status}</td>
</tr>`;
}

renderHeader(data: Race): HTMLTemplateResult {

const countryDashed = data.Circuit.Location.country.replace(" ","-");
const circuitName = getCircuitName(countryDashed);
const imageHtml = html`<img width="100%" src="https://www.formula1.com/content/dam/fom-website/2018-redesign-assets/Circuit%20maps%2016x9/${circuitName}_Circuit.png.transform/7col/image.png">`;
const imageWithLinkHtml = this.config.image_clickable ? html`<a target="_new" href="${data.Circuit.url}">${imageHtml}</a>` : imageHtml;

return html`<h2><img height="25" src="${getCountryFlagByName(data.Circuit.Location.country)}">&nbsp; ${data.round} : ${data.raceName}</h2>${imageWithLinkHtml}<br> `
}
}

render() : HTMLTemplateResult {

Expand All @@ -50,7 +40,7 @@ export default class LastResult extends BaseCard {
? html`
<table>
<tr>
<td>${this.renderHeader(response)}</td>
<td>${renderHeader(this.config, response)}</td>
</tr>
</table>
<table>
Expand Down
39 changes: 6 additions & 33 deletions src/cards/next-race.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { HomeAssistant } from "custom-card-helpers";
import { html, HTMLTemplateResult } from "lit-html";
import { until } from 'lit-html/directives/until.js';
import { Race } from "../api/models";
import { formatDateNumeric } from "../lib/format_date";
import { formatDateTimeRaceInfo } from "../lib/format_date_time";
import { FormulaOneCardConfig } from "../types/formulaone-card-types";
import { getApiErrorMessage, getApiLoadingMessage, getCircuitName, getCountryFlagByName, getEndOfSeasonMessage } from "../utils";
import { getApiErrorMessage, getApiLoadingMessage, getEndOfSeasonMessage, renderHeader, renderRaceInfo } from "../utils";
import { BaseCard } from "./base-card";

export default class NextRace extends BaseCard {
Expand Down Expand Up @@ -35,17 +32,6 @@ export default class NextRace extends BaseCard {
cardSize(): number {
return 8;
}

renderHeader(race: Race): HTMLTemplateResult {

const countryDashed = race.Circuit.Location.country.replace(" ","-")
const circuitName = getCircuitName(countryDashed);

const imageHtml = html`<img width="100%" src="https://www.formula1.com/content/dam/fom-website/2018-redesign-assets/Circuit%20maps%2016x9/${circuitName}_Circuit.png.transform/7col/image.png">`;
const imageWithLinkHtml = this.config.image_clickable ? html`<a target="_new" href="${race.Circuit.url}">${imageHtml}</a>` : imageHtml;

return html`<h2><img height="25" src="${getCountryFlagByName(race.Circuit.Location.country)}">&nbsp; ${race.round} : ${race.raceName}</h2>${imageWithLinkHtml}<br> `
}

render() : HTMLTemplateResult {

Expand All @@ -55,33 +41,20 @@ export default class NextRace extends BaseCard {
return html`${getApiErrorMessage('next race')}`
}
const next_race = response.filter(race => {
const nextRace = response.filter(race => {
return new Date(race.date + 'T' + race.time) >= new Date();
})[0];
if(!next_race) {
if(!nextRace) {
return getEndOfSeasonMessage(this.translation('endofseason'));
}
const raceDate = new Date(next_race.date + 'T' + next_race.time);
const freePractice1 = formatDateTimeRaceInfo(new Date(next_race.FirstPractice.date + 'T' + next_race.FirstPractice.time), this.hass.locale);
const freePractice2 = formatDateTimeRaceInfo(new Date(next_race.SecondPractice.date + 'T' + next_race.SecondPractice.time), this.hass.locale);
const freePractice3 = next_race.ThirdPractice !== undefined ? formatDateTimeRaceInfo(new Date(next_race.ThirdPractice.date + 'T' + next_race.ThirdPractice.time), this.hass.locale) : '-';
const raceDateFormatted = formatDateTimeRaceInfo(raceDate, this.hass.locale);
const qualifyingDate = formatDateTimeRaceInfo(new Date(next_race.Qualifying.date + 'T' + next_race.Qualifying.time), this.hass.locale);
const sprintDate = next_race.Sprint !== undefined ? formatDateTimeRaceInfo(new Date(next_race.Sprint.date + 'T' + next_race.Sprint.time), this.hass.locale) : '-';
return html`<table>
<tbody>
<tr>
<td colspan="5">${this.renderHeader(next_race)}</td>
<td colspan="5">${renderHeader(this.config, nextRace)}</td>
</tr>
<tr><td>${this.translation('date')}</td><td>${formatDateNumeric(raceDate, this.hass.locale, this.config.date_locale)}</td><td>&nbsp;</td><td>${this.translation('practice1')}</td><td align="right">${freePractice1}</td></tr>
<tr><td>${this.translation('race')}</td><td>${next_race.round}</td><td>&nbsp;</td><td>${this.translation('practice2')}</td><td align="right">${freePractice2}</td></tr>
<tr><td>${this.translation('racename')}</td><td>${next_race.raceName}</td><td>&nbsp;</td><td>${this.translation('practice3')}</td><td align="right">${freePractice3}</td></tr>
<tr><td>${this.translation('circuitname')}</td><td>${next_race.Circuit.circuitName}</td><td>&nbsp;</td><td>${this.translation('qualifying')}</td><td align="right">${qualifyingDate}</td></tr>
<tr><td>${this.translation('location')}</td><td>${next_race.Circuit.Location.country}</td><td>&nbsp;</td><td>${this.translation('sprint')}</td><td align="right">${sprintDate}</td></tr>
<tr><td>${this.translation('city')}</td><td>${next_race.Circuit.Location.locality}</td><td>&nbsp;</td><td>${this.translation('racetime')}</td><td align="right">${raceDateFormatted}</td></tr>
${renderRaceInfo( this.hass, this.config, nextRace, this)}
</tbody>
</table>`
}),
Expand Down
10 changes: 2 additions & 8 deletions src/cards/results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { until } from 'lit-html/directives/until.js';
import FormulaOneCard from "..";
import { Race, Result } from "../api/models";
import { CardProperties, FormulaOneCardConfig } from "../types/formulaone-card-types";
import { getApiErrorMessage, getApiLoadingMessage, getCircuitName, getCountryFlagByName, getDriverName } from "../utils";
import { getApiErrorMessage, getApiLoadingMessage, getDriverName, renderHeader } from "../utils";
import { BaseCard } from "./base-card";

export default class Results extends BaseCard {
Expand Down Expand Up @@ -48,13 +48,7 @@ export default class Results extends BaseCard {
return null;
}

const data = race;
const countryDashed = data.Circuit.Location.country.replace(" ","-");
const circuitName = getCircuitName(countryDashed);
const imageHtml = html`<img width="100%" src="https://www.formula1.com/content/dam/fom-website/2018-redesign-assets/Circuit%20maps%2016x9/${circuitName}_Circuit.png.transform/7col/image.png">`;
const imageWithLinkHtml = this.config.image_clickable ? html`<a target="_new" href="${data.Circuit.url}">${imageHtml}</a>` : imageHtml;

return html`<h2><img height="25" src="${getCountryFlagByName(data.Circuit.Location.country)}">&nbsp; ${data.round} : ${data.raceName}</h2>${imageWithLinkHtml}<br> `
return renderHeader(this.config, race);
}

render() : HTMLTemplateResult {
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export default class FormulaOneCard extends LitElement {
this.card = new LastResult(this.config);
break;
case FormulaOneCardType.Countdown:
this.card = new Countdown(this.config);
this.card = new Countdown(this._hass, this.config);
break;
case FormulaOneCardType.Results:
this.card = new Results(this.config, this);
Expand Down
1 change: 1 addition & 0 deletions src/types/formulaone-card-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface FormulaOneCardConfig extends LovelaceCardConfig {
previous_race?: PreviousRaceDisplay;
standings?: StandingDisplayOptions;
translations?: Translation;
show_raceinfo?: boolean;
}

export interface Translation {
Expand Down
36 changes: 34 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { html, PropertyValues } from "lit";
import { html, HTMLTemplateResult, PropertyValues } from "lit";
import { FormulaOneCardConfig, LocalStorageItem } from "./types/formulaone-card-types";
import * as countries from './data/countries.json';
import { Driver, Root } from "./api/models";
import { Driver, Race, Root } from "./api/models";
import FormulaOneCard from ".";
import { BaseCard } from "./cards/base-card";
import { formatDateTimeRaceInfo } from "./lib/format_date_time";
import { HomeAssistant } from "custom-card-helpers";
import { formatDateNumeric } from "./lib/format_date";

export const hasConfigOrCardValuesChanged = (node: FormulaOneCard, changedProps: PropertyValues) => {
if (changedProps.has('config')) {
Expand Down Expand Up @@ -90,6 +93,35 @@ export const getApiLoadingMessage = () => {

export const getEndOfSeasonMessage = (message: string) => {
return html`<table><tr><td class="text-center"><ha-icon icon="mdi:flag-checkered"></ha-icon><strong>${message}</strong><ha-icon icon="mdi:flag-checkered"></ha-icon></td></tr></table>`;
}

export const renderHeader = (config: FormulaOneCardConfig, race: Race, hide_racename?: boolean): HTMLTemplateResult => {

const countryDashed = race.Circuit.Location.country.replace(" ","-")
const circuitName = getCircuitName(countryDashed);

const imageHtml = html`<img width="100%" src="https://www.formula1.com/content/dam/fom-website/2018-redesign-assets/Circuit%20maps%2016x9/${circuitName}_Circuit.png.transform/7col/image.png">`;
const imageWithLinkHtml = config.image_clickable ? html`<a target="_new" href="${race.Circuit.url}">${imageHtml}</a>` : imageHtml;
const raceName = html`<h2><img height="25" src="${getCountryFlagByName(race.Circuit.Location.country)}">&nbsp; ${race.round} : ${race.raceName}</h2>`;

return html`${(hide_racename ? html`` : raceName)} ${imageWithLinkHtml}<br>`;
}

export const renderRaceInfo = (hass: HomeAssistant, config: FormulaOneCardConfig, race: Race, card: BaseCard) => {
const raceDate = new Date(race.date + 'T' + race.time);
const freePractice1 = formatDateTimeRaceInfo(new Date(race.FirstPractice.date + 'T' + race.FirstPractice.time), hass.locale);
const freePractice2 = formatDateTimeRaceInfo(new Date(race.SecondPractice.date + 'T' + race.SecondPractice.time), hass.locale);
const freePractice3 = race.ThirdPractice !== undefined ? formatDateTimeRaceInfo(new Date(race.ThirdPractice.date + 'T' + race.ThirdPractice.time), hass.locale) : '-';
const raceDateFormatted = formatDateTimeRaceInfo(raceDate, hass.locale);
const qualifyingDate = formatDateTimeRaceInfo(new Date(race.Qualifying.date + 'T' + race.Qualifying.time), hass.locale);
const sprintDate = race.Sprint !== undefined ? formatDateTimeRaceInfo(new Date(race.Sprint.date + 'T' + race.Sprint.time), hass.locale) : '-';

return html`<tr><td>${card.translation('date')}</td><td>${formatDateNumeric(raceDate, hass.locale, config.date_locale)}</td><td>&nbsp;</td><td>${card.translation('practice1')}</td><td align="right">${freePractice1}</td></tr>
<tr><td>${card.translation('race')}</td><td>${race.round}</td><td>&nbsp;</td><td>${card.translation('practice2')}</td><td align="right">${freePractice2}</td></tr>
<tr><td>${card.translation('racename')}</td><td>${race.raceName}</td><td>&nbsp;</td><td>${card.translation('practice3')}</td><td align="right">${freePractice3}</td></tr>
<tr><td>${card.translation('circuitname')}</td><td>${race.Circuit.circuitName}</td><td>&nbsp;</td><td>${card.translation('qualifying')}</td><td align="right">${qualifyingDate}</td></tr>
<tr><td>${card.translation('location')}</td><td>${race.Circuit.Location.country}</td><td>&nbsp;</td><td>${card.translation('sprint')}</td><td align="right">${sprintDate}</td></tr>
<tr><td>${card.translation('city')}</td><td>${race.Circuit.Location.locality}</td><td>&nbsp;</td><td>${card.translation('racetime')}</td><td align="right">${raceDateFormatted}</td></tr>`;
}

export const getRefreshTime = (endpoint: string) => {
Expand Down
Loading

0 comments on commit 7572060

Please sign in to comment.