979 lines
24 KiB
JavaScript
979 lines
24 KiB
JavaScript
const LitElement = customElements.get("hui-masonry-view")
|
|
? Object.getPrototypeOf(customElements.get("hui-masonry-view"))
|
|
: Object.getPrototypeOf(customElements.get("hui-view"));
|
|
const html = LitElement.prototype.html;
|
|
const css = LitElement.prototype.css;
|
|
|
|
const weatherIconsDay = {
|
|
clear: "day",
|
|
"clear-night": "night",
|
|
cloudy: "cloudy",
|
|
fog: "fog",
|
|
hail: "rainy-7",
|
|
lightning: "thunder",
|
|
"lightning-rainy": "lightning-rainy",
|
|
partlycloudy: "cloudy-day-3",
|
|
pouring: "rainy-6",
|
|
rainy: "rainy-5",
|
|
snowy: "snowy-6",
|
|
"snowy-rainy": "snowy-rainy",
|
|
sunny: "day",
|
|
windy: "windy",
|
|
"windy-variant": "windy",
|
|
exceptional: "!!",
|
|
};
|
|
|
|
const DefaultSensors = [
|
|
["cloudCoverEntity", "_cloud_cover"],
|
|
["rainChanceEntity", "_rain_chance"],
|
|
["freezeChanceEntity", "_freeze_chance"],
|
|
["snowChanceEntity", "_snow_chance"],
|
|
["uvEntity", "_uv"],
|
|
["rainForecastEntity", "_next_rain"],
|
|
];
|
|
|
|
const weatherIconsNight = {
|
|
...weatherIconsDay,
|
|
clear: "night",
|
|
sunny: "night",
|
|
partlycloudy: "cloudy-night-3",
|
|
};
|
|
|
|
const windDirections = [
|
|
"N",
|
|
"NNE",
|
|
"NE",
|
|
"ENE",
|
|
"E",
|
|
"ESE",
|
|
"SE",
|
|
"SSE",
|
|
"S",
|
|
"SSO",
|
|
"SO",
|
|
"OSO",
|
|
"O",
|
|
"ONO",
|
|
"NO",
|
|
"NNO",
|
|
"N",
|
|
];
|
|
|
|
const phenomenaText = {
|
|
clear: "Ciel dégagé",
|
|
"clear-night": "Nuit claire",
|
|
cloudy: "Nuageux",
|
|
fog: "Brouillard",
|
|
hail: "Risque de grèle",
|
|
lightning: "Orages",
|
|
"lightning-rainy": "Pluies orageuses",
|
|
partlycloudy: "Eclaircies",
|
|
pouring: "Pluie forte",
|
|
rainy: "Pluie",
|
|
snowy: "Neige",
|
|
"snowy-rainy": "Pluie verglaçante",
|
|
sunny: "Ensoleillé",
|
|
windy: "Venteux",
|
|
"windy-variant": "Venteux variable",
|
|
exceptional: "Exceptionnel",
|
|
};
|
|
|
|
const phenomenaNightText = {
|
|
...phenomenaText,
|
|
sunny: "Nuit claire",
|
|
};
|
|
|
|
const rainForecastValues = new Map([
|
|
["Pas de valeur", 0.1],
|
|
["Temps sec", 0.1],
|
|
["Pluie faible", 0.4],
|
|
["Pluie modérée", 0.7],
|
|
["Pluie forte", 1],
|
|
]);
|
|
|
|
window.customCards = window.customCards || [];
|
|
window.customCards.push({
|
|
type: "meteofrance-weather-card",
|
|
name: "Carte Météo France par HACF",
|
|
description: "Carte pour l'intégration Météo France.",
|
|
preview: true,
|
|
documentationURL:
|
|
"https://github.com/hacf-fr/lovelace-meteofrance-weather-card",
|
|
});
|
|
|
|
const fireEvent = (node, type, detail, options) => {
|
|
options = options || {};
|
|
detail = detail === null || detail === undefined ? {} : detail;
|
|
const event = new Event(type, {
|
|
bubbles: options.bubbles === undefined ? true : options.bubbles,
|
|
cancelable: Boolean(options.cancelable),
|
|
composed: options.composed === undefined ? true : options.composed,
|
|
});
|
|
event.detail = detail;
|
|
node.dispatchEvent(event);
|
|
return event;
|
|
};
|
|
|
|
function hasConfigOrEntityChanged(element, changedProps) {
|
|
if (changedProps.has("_config")) {
|
|
return true;
|
|
}
|
|
|
|
const oldHass = changedProps.get("hass");
|
|
if (oldHass) {
|
|
const entityName = element._config.entity.split(".")[1];
|
|
return (
|
|
oldHass.states[element._config.entity] !==
|
|
element.hass.states[element._config.entity] ||
|
|
oldHass.states["sun.sun"] !== element.hass.states["sun.sun"] ||
|
|
!DefaultSensors.every((sensor) => {
|
|
const sensorName = "sensor." + entityName + sensor[1];
|
|
oldHass.states[sensorName] == element.hass.states[sensorName];
|
|
})
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
class MeteofranceWeatherCard extends LitElement {
|
|
static get properties() {
|
|
return {
|
|
_config: {},
|
|
hass: {},
|
|
};
|
|
}
|
|
|
|
static async getConfigElement() {
|
|
await import("./meteofrance-weather-card-editor.js");
|
|
return document.createElement("meteofrance-weather-card-editor");
|
|
}
|
|
|
|
static getStubConfig(hass, unusedEntities, allEntities) {
|
|
let entity = this.getDefaultWeatherEntity(unusedEntities, allEntities);
|
|
let entities = { entity };
|
|
|
|
if (entity) {
|
|
let sensors = this.getWeatherEntitiesFromEntity(
|
|
hass,
|
|
entity.split(".")[1],
|
|
allEntities
|
|
);
|
|
entities = {
|
|
...entities,
|
|
...sensors,
|
|
};
|
|
}
|
|
return entities;
|
|
}
|
|
|
|
static getDefaultWeatherEntity(unusedEntities, allEntities) {
|
|
let entity = unusedEntities.find((eid) => eid.split(".")[0] === "weather");
|
|
if (!entity) {
|
|
entity = allEntities.find((eid) => eid.split(".")[0] === "weather");
|
|
}
|
|
return entity;
|
|
}
|
|
|
|
static getWeatherEntitiesFromEntity(hass, entityName, allEntities) {
|
|
let entities = {};
|
|
DefaultSensors.forEach((sensor) => {
|
|
const sensorName = "sensor." + entityName + sensor[0];
|
|
if (hass.states[sensorName] !== undefined) {
|
|
let sensor = allEntities[sensorName];
|
|
if (!sensor) {
|
|
entities = {
|
|
...entities,
|
|
[sensor[1]]: sensorName,
|
|
};
|
|
}
|
|
}
|
|
});
|
|
return entities;
|
|
}
|
|
|
|
setConfig(config) {
|
|
if (!config.entity) {
|
|
throw new Error("Please define a weather entity");
|
|
}
|
|
this._config = config;
|
|
}
|
|
|
|
shouldUpdate(changedProps) {
|
|
return hasConfigOrEntityChanged(this, changedProps);
|
|
}
|
|
|
|
isSelected(option) {
|
|
return option === undefined || option === true;
|
|
}
|
|
|
|
render() {
|
|
if (!this._config || !this.hass) {
|
|
return html``;
|
|
}
|
|
|
|
this.numberElements = 0;
|
|
|
|
const stateObj = this.hass.states[this._config.entity];
|
|
|
|
if (!stateObj) {
|
|
return html`
|
|
<style>
|
|
.not-found {
|
|
flex: 1;
|
|
background-color: yellow;
|
|
padding: 8px;
|
|
}
|
|
</style>
|
|
<ha-card>
|
|
<div class="not-found">
|
|
Entity not available: ${this._config.entity}
|
|
</div>
|
|
</ha-card>
|
|
`;
|
|
}
|
|
|
|
return html`
|
|
<ha-card @click="${this._handleClick}">
|
|
${this.isSelected(this._config.current)
|
|
? this.renderCurrent(stateObj)
|
|
: ""}
|
|
${this.isSelected(this._config.details)
|
|
? this.renderDetails(stateObj)
|
|
: ""}
|
|
${this.isSelected(this._config.alert_forecast)
|
|
? this.renderAlertForecast()
|
|
: ""}
|
|
${this.isSelected(this._config.one_hour_forecast)
|
|
? this.renderOneHourForecast()
|
|
: ""}
|
|
${this.isSelected(this._config.forecast)
|
|
? this.renderForecast(stateObj.attributes.forecast)
|
|
: ""}
|
|
</ha-card>
|
|
`;
|
|
}
|
|
|
|
renderCurrent(stateObj) {
|
|
this.numberElements++;
|
|
return html`
|
|
<ul class="flow-row current">
|
|
<li
|
|
style="background: none, url('${this.getWeatherIcon(
|
|
stateObj.state.toLowerCase(),
|
|
this.isNightTime()
|
|
)}') no-repeat; background-size: contain;"
|
|
></li>
|
|
<li>
|
|
${this.getPhenomenaText(stateObj.state, this.isNightTime())}
|
|
${this._config.name ? html` <div>${this._config.name}</div>` : ""}
|
|
</li>
|
|
<li>
|
|
${this.getUnit("temperature") == "°F"
|
|
? Math.round(stateObj.attributes.temperature)
|
|
: stateObj.attributes.temperature}
|
|
<sup>${this.getUnit("temperature")}</sup>
|
|
<ul>
|
|
${this.renderMeteoFranceDetail(
|
|
this.hass.states[this._config.detailEntity]
|
|
)}
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
`;
|
|
}
|
|
|
|
renderDetails(stateObj) {
|
|
const sun = this.hass.states["sun.sun"];
|
|
let next_rising;
|
|
let next_setting;
|
|
|
|
if (sun) {
|
|
next_rising = new Date(sun.attributes.next_rising);
|
|
next_setting = new Date(sun.attributes.next_setting);
|
|
}
|
|
|
|
this.numberElements++;
|
|
|
|
return html`
|
|
<ul class="flow-row details ${this.numberElements > 1 ? " spacer" : ""}">
|
|
<!-- Cloudy -->
|
|
${this.renderMeteoFranceDetail(
|
|
this.hass.states[this._config.cloudCoverEntity]
|
|
)}
|
|
<!-- Wind -->
|
|
${this.renderDetail(
|
|
(stateObj.attributes.wind_bearing == undefined
|
|
? " "
|
|
: windDirections[
|
|
parseInt((stateObj.attributes.wind_bearing + 11.25) / 22.5)
|
|
] + " ") + stateObj.attributes.wind_speed,
|
|
"Vent",
|
|
"mdi:weather-windy",
|
|
this.getUnit("speed")
|
|
)}
|
|
<!-- Rain -->
|
|
${this.renderMeteoFranceDetail(
|
|
this.hass.states[this._config.rainChanceEntity]
|
|
)}
|
|
<!-- Humidity -->
|
|
${this.renderDetail(
|
|
stateObj.attributes.humidity,
|
|
"Humidité",
|
|
"mdi:water-percent",
|
|
"%"
|
|
)}
|
|
<!-- Freeze -->
|
|
${this.renderMeteoFranceDetail(
|
|
this.hass.states[this._config.freezeChanceEntity]
|
|
)}
|
|
<!-- Pressure -->
|
|
${this.renderDetail(
|
|
stateObj.attributes.pressure,
|
|
"Pression atmosphérique",
|
|
"mdi:gauge",
|
|
this.getUnit("air_pressure")
|
|
)}
|
|
<!-- Snow -->
|
|
${this.renderMeteoFranceDetail(
|
|
this.hass.states[this._config.snowChanceEntity]
|
|
)}
|
|
<!-- UV -->
|
|
${this.renderMeteoFranceDetail(this.hass.states[this._config.uvEntity])}
|
|
</ul>
|
|
<ul class="flow-row details">
|
|
<!-- Sunset up -->
|
|
${next_rising
|
|
? this.renderDetail(
|
|
next_rising.toLocaleTimeString(),
|
|
"Heure de lever",
|
|
"mdi:weather-sunset-up"
|
|
)
|
|
: ""}
|
|
<!-- Sunset down -->
|
|
${next_setting
|
|
? this.renderDetail(
|
|
next_setting.toLocaleTimeString(),
|
|
"Heure de coucher",
|
|
"mdi:weather-sunset-down"
|
|
)
|
|
: ""}
|
|
</ul>
|
|
`;
|
|
}
|
|
|
|
renderMeteoFranceDetail(entity) {
|
|
return entity !== undefined
|
|
? this.renderDetail(
|
|
entity.state,
|
|
entity.attributes.friendly_name,
|
|
entity.attributes.icon,
|
|
entity.attributes.unit_of_measurement
|
|
)
|
|
: "";
|
|
}
|
|
|
|
renderDetail(state, label, icon, unit) {
|
|
return html`
|
|
<li>
|
|
<ha-icon icon="${icon}" title="${label}"></ha-icon>
|
|
${state} ${unit ? html`${unit}` : ""}
|
|
</li>
|
|
`;
|
|
}
|
|
|
|
renderOneHourForecast() {
|
|
const rainForecast = this.hass.states[this._config.rainForecastEntity];
|
|
|
|
if (!rainForecast || rainForecast.length === 0) {
|
|
return html``;
|
|
}
|
|
|
|
this.numberElements++;
|
|
|
|
let [startTime, endTime] = this.getOneHourForecastTime(rainForecast);
|
|
|
|
return html` <ul
|
|
class="flow-row oneHourHeader ${this.numberElements > 1
|
|
? " spacer"
|
|
: ""}"
|
|
>
|
|
<li>${startTime}</li>
|
|
<li>${this.getOneHourNextRainText(rainForecast)}</li>
|
|
<li>${endTime}</li>
|
|
</ul>
|
|
<ul class="flow-row oneHour">
|
|
${html`
|
|
${this.getOneHourForecast(rainForecast).map(
|
|
(forecast) => html` <li
|
|
class="rain-${forecast[0]}min"
|
|
style="opacity: ${forecast[1]}"
|
|
title="${forecast[2]}"
|
|
></li>`
|
|
)}
|
|
`}
|
|
</ul>
|
|
<ul class="flow-row oneHourLabel">
|
|
<li></li>
|
|
<li>10</li>
|
|
<li>20</li>
|
|
<li>30</li>
|
|
<li>40</li>
|
|
<li>50</li>
|
|
</ul>`;
|
|
}
|
|
|
|
renderAlertForecast() {
|
|
const alertForecast = this.hass.states[this._config.alertEntity];
|
|
|
|
if (!alertForecast) {
|
|
return html``;
|
|
}
|
|
|
|
const alerts = this.getAlertForecast(alertForecast);
|
|
|
|
if (alerts.length == 0) return html``;
|
|
|
|
this.numberElements++;
|
|
|
|
return html` <div
|
|
class="flow-row alertForecast ${this.numberElements > 1 ? " spacer" : ""}"
|
|
>
|
|
${alerts.map(
|
|
(phenomenon) => html` <div class="alertForecast${phenomenon.color}">
|
|
<ha-icon
|
|
icon="${phenomenon.icon}"
|
|
title="${phenomenon.name}"
|
|
></ha-icon>
|
|
</div>`
|
|
)}
|
|
</div>`;
|
|
}
|
|
|
|
renderForecast(forecast) {
|
|
if (!forecast || forecast.length === 0) {
|
|
return html``;
|
|
}
|
|
|
|
const lang = this.hass.selectedLanguage || this.hass.language;
|
|
const isDaily = this.isDailyForecast(forecast);
|
|
|
|
this.numberElements++;
|
|
return html` <ul
|
|
class="flow-row forecast ${this.numberElements > 1 ? " spacer" : ""}"
|
|
>
|
|
${forecast
|
|
.slice(
|
|
0,
|
|
this._config.number_of_forecasts
|
|
? this._config.number_of_forecasts
|
|
: 5
|
|
)
|
|
.map((daily) => this.renderDailyForecast(daily, lang, isDaily))}
|
|
</ul>`;
|
|
}
|
|
|
|
renderDailyForecast(daily, lang, isDaily) {
|
|
return html` <li>
|
|
<ul class="flow-column day">
|
|
<li>
|
|
${isDaily
|
|
? new Date(daily.datetime).toLocaleDateString(lang, {
|
|
weekday: "short",
|
|
})
|
|
: new Date(daily.datetime).toLocaleTimeString(lang, {
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
})}
|
|
</li>
|
|
<li
|
|
class="icon"
|
|
style="background: none, url('${this.getWeatherIcon(
|
|
daily.condition.toLowerCase(),
|
|
!isDaily && this.isNightTime(daily.datetime)
|
|
)}') no-repeat; background-size: contain"
|
|
></li>
|
|
<li class="highTemp">
|
|
${daily.temperature}${this.getUnit("temperature")}
|
|
</li>
|
|
${daily.templow !== undefined
|
|
? html`
|
|
<li class="lowTemp">
|
|
${daily.templow}${this.getUnit("temperature")}
|
|
</li>
|
|
`
|
|
: ""}
|
|
${!this._config.hide_precipitation &&
|
|
daily.precipitation !== undefined &&
|
|
daily.precipitation !== null
|
|
? html`
|
|
<li class="precipitation">
|
|
${Math.round(daily.precipitation * 10) / 10}
|
|
${this.getUnit("precipitation")}
|
|
</li>
|
|
`
|
|
: ""}
|
|
${!this._config.hide_precipitation &&
|
|
daily.precipitation_probability !== undefined &&
|
|
daily.precipitation_probability !== null
|
|
? html`
|
|
<li class="precipitation_probability">
|
|
${Math.round(daily.precipitation_probability)}
|
|
${this.getUnit("precipitation_probability")}
|
|
</li>
|
|
`
|
|
: ""}
|
|
${daily.wind_speed !== undefined && daily.wind_speed !== null
|
|
? html`
|
|
<li class="wind_speed">
|
|
${Math.round(daily.wind_speed)} ${this.getUnit("speed")}
|
|
</li>
|
|
`
|
|
: ""}
|
|
</ul>
|
|
</li>`;
|
|
}
|
|
|
|
isDailyForecast(forecast) {
|
|
const diff =
|
|
new Date(forecast[1].datetime) - new Date(forecast[0].datetime);
|
|
return diff > 3600000;
|
|
}
|
|
|
|
isNightTime(datetimehourly) {
|
|
const sun = this.hass.states["sun.sun"];
|
|
if (!sun) {
|
|
return false;
|
|
}
|
|
|
|
let nextrising = new Date(sun.attributes.next_rising);
|
|
let nextsetting = new Date(sun.attributes.next_setting);
|
|
|
|
const thistime = datetimehourly ? new Date(datetimehourly) : new Date();
|
|
|
|
return (
|
|
(thistime > nextsetting && thistime < nextrising) ||
|
|
(thistime < nextsetting &&
|
|
thistime < nextrising &&
|
|
nextrising < nextsetting)
|
|
);
|
|
}
|
|
|
|
getOneHourForecast(rainForecastEntity) {
|
|
let rainForecastList = [];
|
|
for (let [time, value] of Object.entries(
|
|
rainForecastEntity.attributes["1_hour_forecast"]
|
|
)) {
|
|
if (time != undefined && time.match(/[0-9]*min/g)) {
|
|
time = time.replace("min", "").trim();
|
|
rainForecastList.push([time, rainForecastValues.get(value), value]);
|
|
}
|
|
}
|
|
|
|
return rainForecastList;
|
|
}
|
|
|
|
getOneHourForecastTime(rainForecastEntity) {
|
|
let rainForecastTimeRef = new Date(
|
|
rainForecastEntity.attributes["forecast_time_ref"]
|
|
);
|
|
let rainForecastStartTime = rainForecastTimeRef.toLocaleTimeString([], {
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
});
|
|
rainForecastTimeRef.setHours(rainForecastTimeRef.getHours() + 1);
|
|
let rainForecastEndTime = rainForecastTimeRef.toLocaleTimeString([], {
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
});
|
|
|
|
return [rainForecastStartTime, rainForecastEndTime];
|
|
}
|
|
|
|
getOneHourNextRainText(rainForecastEntity) {
|
|
for (let [time, value] of Object.entries(
|
|
rainForecastEntity.attributes["1_hour_forecast"]
|
|
)) {
|
|
if (time != undefined && rainForecastValues.get(value) > 0.1) {
|
|
let timeStr = time.replace(/([345])5/g, "$10");
|
|
return (
|
|
value +
|
|
(time == "0 min" ? " actuellement." : " dans " + timeStr + ".")
|
|
);
|
|
}
|
|
}
|
|
|
|
return "Pas de pluie dans l'heure.";
|
|
}
|
|
|
|
getAlertForecast(alertEntity) {
|
|
let phenomenaList = [];
|
|
|
|
if (alertEntity == undefined) {
|
|
return [];
|
|
}
|
|
|
|
if (
|
|
!this._config.hide_alertVentViolent &&
|
|
alertEntity.attributes["Vent violent"]
|
|
) {
|
|
phenomenaList.push({
|
|
name: "Vent violent",
|
|
icon: "mdi:weather-windy",
|
|
color: alertEntity.attributes["Vent violent"],
|
|
});
|
|
}
|
|
|
|
if (
|
|
!this._config.hide_alertPluieInondation &&
|
|
alertEntity.attributes["Pluie-inondation"]
|
|
) {
|
|
phenomenaList.push({
|
|
name: "Pluie-inondation",
|
|
icon: "mdi:weather-pouring",
|
|
color: alertEntity.attributes["Pluie-inondation"],
|
|
});
|
|
}
|
|
|
|
if (!this._config.hide_alertOrages && alertEntity.attributes["Orages"]) {
|
|
phenomenaList.push({
|
|
name: "Orages",
|
|
icon: "mdi:weather-lightning",
|
|
color: alertEntity.attributes["Orages"],
|
|
});
|
|
}
|
|
|
|
if (
|
|
!this._config.hide_alertInondation &&
|
|
alertEntity.attributes["Inondation"]
|
|
) {
|
|
phenomenaList.push({
|
|
name: "Inondation",
|
|
icon: "mdi:home-flood",
|
|
color: alertEntity.attributes["Inondation"],
|
|
});
|
|
}
|
|
|
|
if (
|
|
!this._config.hide_alertNeigeVerglas &&
|
|
alertEntity.attributes["Neige-verglas"]
|
|
) {
|
|
phenomenaList.push({
|
|
name: "Neige-verglas",
|
|
icon: "mdi:weather-snowy-heavy",
|
|
color: alertEntity.attributes["Neige-verglas"],
|
|
});
|
|
}
|
|
|
|
if (
|
|
!this._config.hide_alertCanicule &&
|
|
alertEntity.attributes["Canicule"]
|
|
) {
|
|
phenomenaList.push({
|
|
name: "Canicule",
|
|
icon: "mdi:weather-sunny-alert",
|
|
color: alertEntity.attributes["Canicule"],
|
|
});
|
|
}
|
|
|
|
if (
|
|
!this._config.hide_alertGrandFroid &&
|
|
alertEntity.attributes["Grand-froid"]
|
|
) {
|
|
phenomenaList.push({
|
|
name: "Grand-froid",
|
|
icon: "mdi:snowflake",
|
|
color: alertEntity.attributes["Grand-froid"],
|
|
});
|
|
}
|
|
|
|
if (
|
|
!this._config.hide_alertAvalanches &&
|
|
alertEntity.attributes["Avalanches"]
|
|
) {
|
|
phenomenaList.push({
|
|
name: "Avalanches",
|
|
icon: "mdi:image-filter-hdr",
|
|
color: alertEntity.attributes["Avalanches"],
|
|
});
|
|
}
|
|
|
|
if (
|
|
!this._config.hide_alertVaguesSubmersion &&
|
|
alertEntity.attributes["Vagues-submersion"]
|
|
) {
|
|
phenomenaList.push({
|
|
name: "Vagues-submersion",
|
|
icon: "mdi:waves",
|
|
color: alertEntity.attributes["Vagues-submersion"],
|
|
});
|
|
}
|
|
|
|
return phenomenaList;
|
|
}
|
|
|
|
getWeatherIcon(condition, isNight) {
|
|
return `${
|
|
this._config.icons
|
|
? this._config.icons
|
|
: "/local/community/lovelace-meteofrance-weather-card/icons/"
|
|
}${isNight ? weatherIconsNight[condition] : weatherIconsDay[condition]}${
|
|
this.isSelected(this._config.animated_icons) ? "" : "-static"
|
|
}.svg`;
|
|
}
|
|
|
|
getPhenomenaText(phenomena, isNight) {
|
|
return `${
|
|
isNight ? phenomenaNightText[phenomena] : phenomenaText[phenomena]
|
|
}`;
|
|
}
|
|
|
|
getUnit(measure) {
|
|
const lengthUnit = this.hass.config.unit_system.length;
|
|
switch (measure) {
|
|
case "air_pressure":
|
|
return lengthUnit === "km" ? "hPa" : "inHg";
|
|
case "length":
|
|
return lengthUnit;
|
|
case "precipitation":
|
|
return lengthUnit === "km" ? "mm" : "in";
|
|
case "precipitation_probability":
|
|
return "%";
|
|
case "speed":
|
|
return lengthUnit === "km" ? "km/h" : "mph";
|
|
default:
|
|
return this.hass.config.unit_system[measure] || "";
|
|
}
|
|
}
|
|
|
|
_handleClick() {
|
|
fireEvent(this, "hass-more-info", { entityId: this._config.entity });
|
|
}
|
|
|
|
getCardSize() {
|
|
return 3;
|
|
}
|
|
|
|
static get styles() {
|
|
return css`
|
|
ha-card {
|
|
cursor: pointer;
|
|
margin: auto;
|
|
overflow: hidden;
|
|
padding: 0.5em 1em;
|
|
position: relative;
|
|
}
|
|
|
|
ha-card ul {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.spacer {
|
|
padding-top: 1em;
|
|
}
|
|
|
|
.clear {
|
|
clear: both;
|
|
}
|
|
|
|
.flow-row {
|
|
display: flex;
|
|
flex-flow: row wrap;
|
|
}
|
|
|
|
.flow-column {
|
|
display: flex;
|
|
flex-flow: column wrap;
|
|
}
|
|
|
|
.ha-icon {
|
|
height: 0.8em;
|
|
margin-right: 5px;
|
|
color: var(--paper-item-icon-color);
|
|
}
|
|
|
|
/* Current Forecast */
|
|
.current {
|
|
flex-wrap: nowrap;
|
|
}
|
|
|
|
.current > *:first-child {
|
|
min-width: 100px;
|
|
height: 100px;
|
|
margin-right: 10px;
|
|
}
|
|
|
|
.current > *:last-child {
|
|
margin-left: auto;
|
|
min-width: max-content;
|
|
text-align: right;
|
|
}
|
|
|
|
.current > *:last-child sup {
|
|
font-size: initial;
|
|
}
|
|
|
|
.current > li {
|
|
font-size: 2em;
|
|
line-height: 1.2;
|
|
align-self: center;
|
|
}
|
|
|
|
.current > li > *:last-child {
|
|
line-height: 1;
|
|
font-size: 0.6em;
|
|
color: var(--secondary-text-color);
|
|
}
|
|
|
|
/* Details */
|
|
.details {
|
|
justify-content: space-between;
|
|
font-weight: 300;
|
|
}
|
|
|
|
.details ha-icon {
|
|
height: 22px;
|
|
margin-right: 5px;
|
|
color: var(--paper-item-icon-color);
|
|
}
|
|
|
|
.details > li {
|
|
flex-basis: auto;
|
|
width: 50%;
|
|
}
|
|
|
|
.details > li:nth-child(2n) {
|
|
text-align: right;
|
|
}
|
|
|
|
.details > li:nth-child(2n) ha-icon {
|
|
margin-right: 0;
|
|
margin-left: 8px;
|
|
float: right;
|
|
}
|
|
|
|
/* One Hour Forecast */
|
|
.oneHour {
|
|
height: 1em;
|
|
}
|
|
|
|
.oneHour > li {
|
|
background-color: var(--paper-item-icon-color);
|
|
border-right: 1px solid
|
|
var(--lovelace-background, var(--primary-background-color));
|
|
}
|
|
|
|
.oneHour > li:first-child {
|
|
border-top-left-radius: 5px;
|
|
border-bottom-left-radius: 5px;
|
|
}
|
|
|
|
.oneHour > li:last-child {
|
|
border-top-right-radius: 5px;
|
|
border-bottom-right-radius: 5px;
|
|
border: 0;
|
|
}
|
|
|
|
/* One Hour Labels */
|
|
.rain-0min,
|
|
.rain-5min,
|
|
.rain-10min,
|
|
.rain-15min,
|
|
.rain-20min,
|
|
.rain-25min {
|
|
flex: 1 1 0;
|
|
}
|
|
|
|
.rain-35min,
|
|
.rain-45min,
|
|
.rain-55min {
|
|
flex: 2 1 0;
|
|
}
|
|
|
|
.oneHourLabel > li {
|
|
flex: 1 1 0;
|
|
}
|
|
|
|
/* One Hour Header */
|
|
.oneHourHeader {
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.oneHourHeader li:last-child {
|
|
text-align: right;
|
|
}
|
|
|
|
/* Alert */
|
|
.alertForecast {
|
|
text-align: center;
|
|
flex-wrap: nowrap;
|
|
}
|
|
|
|
.alertForecast > div {
|
|
flex: 1;
|
|
color: var(--paper-item-icon-color);
|
|
color: grey;
|
|
border: 0;
|
|
border-radius: 5px;
|
|
margin-left: 1px;
|
|
margin-right: 1px;
|
|
}
|
|
|
|
.alertForecastVert {
|
|
}
|
|
|
|
.alertForecastJaune {
|
|
background-color: yellow;
|
|
}
|
|
|
|
.alertForecastOrange {
|
|
background-color: orange;
|
|
}
|
|
|
|
.alertForecastRouge {
|
|
background-color: red;
|
|
}
|
|
|
|
/* Forecast */
|
|
.forecast {
|
|
justify-content: space-between;
|
|
flex-wrap: nowrap;
|
|
}
|
|
|
|
.forecast > li {
|
|
flex: 1;
|
|
border-right: 0.1em solid #d9d9d9;
|
|
}
|
|
|
|
.forecast > *:last-child {
|
|
border-right: 0;
|
|
}
|
|
|
|
.forecast ul.day {
|
|
align-items: center;
|
|
}
|
|
|
|
.forecast ul.day > *:first-child {
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.forecast ul.day .highTemp {
|
|
font-weight: bold;
|
|
}
|
|
|
|
.forecast ul.day .lowTemp {
|
|
color: var(--secondary-text-color);
|
|
}
|
|
|
|
.forecast ul.day .icon {
|
|
width: 50px;
|
|
height: 50px;
|
|
margin-right: 5px;
|
|
}
|
|
`;
|
|
}
|
|
}
|
|
customElements.define("meteofrance-weather-card", MeteofranceWeatherCard);
|