- ${stateObj.state in weatherIcons
- ? html`
-
- `
- : ""}
-
- ${stateObj.attributes.temperature}
${this.getUnit("temperature")}
+
+ ${stateObj.state in weatherImages
+ ? html`
+

+ `
+ : html`
+
+ `}
+
+
+ ${this._config.name || computeStateName(stateObj)}
+
+
+ ${this.hass.localize(`state.weather.${stateObj.state}`) ||
+ stateObj.state}
-
- ${this._showValue(stateObj.attributes.pressure)
- ? html`
-
- ${this.hass.localize(
- "ui.card.weather.attributes.air_pressure"
- )}:
-
- ${stateObj.attributes.pressure}
- ${this.getUnit("air_pressure")}
-
-
- `
- : ""}
- ${this._showValue(stateObj.attributes.humidity)
- ? html`
-
- ${this.hass.localize(
- "ui.card.weather.attributes.humidity"
- )}:
- ${stateObj.attributes.humidity} %
-
- `
- : ""}
- ${this._showValue(stateObj.attributes.wind_speed)
- ? html`
-
- ${this.hass.localize(
- "ui.card.weather.attributes.wind_speed"
- )}:
-
- ${stateObj.attributes.wind_speed}
- ${this.getUnit("length")}/h
-
- ${this.getWindBearing(stateObj.attributes.wind_bearing)}
-
- `
- : ""}
+
+
+
+ ${stateObj.attributes.temperature}${getWeatherUnit(this.hass, "temperature")}
+
+
+ ${getSecondaryWeatherAttribute(this.hass, stateObj)}
- ${forecast
- ? html`
-
- ${forecast.map(
- (item) => html`
-
-
- ${new Date(item.datetime).toLocaleDateString(
- this.hass!.language,
- { weekday: "short" }
- )}
- ${!this._showValue(item.templow)
- ? html`
- ${new Date(item.datetime).toLocaleTimeString(
- this.hass!.language,
- {
- hour: "numeric",
- }
- )}
- `
- : ""}
-
- ${this._showValue(item.condition)
- ? html`
-
-
-
- `
- : ""}
- ${this._showValue(item.temperature)
- ? html`
-
- ${item.temperature}
- ${this.getUnit("temperature")}
-
- `
- : ""}
- ${this._showValue(item.templow)
- ? html`
-
- ${item.templow} ${this.getUnit("temperature")}
-
- `
- : ""}
- ${this._showValue(item.precipitation)
- ? html`
-
- ${item.precipitation}
- ${this.getUnit("precipitation")}
-
- `
- : ""}
-
- `
- )}
-
- `
- : ""}
+ ${forecast
+ ? html`
+
+ ${forecast.map(
+ (item) => html`
+
+
+ ${hourly
+ ? html`
+ ${new Date(item.datetime).toLocaleTimeString(
+ this.hass!.language,
+ {
+ hour: "numeric",
+ }
+ )}
+ `
+ : html`
+ ${new Date(item.datetime).toLocaleDateString(
+ this.hass!.language,
+ { weekday: "short" }
+ )}
+ `}
+
+ ${item.condition !== undefined && item.condition !== null
+ ? html`
+
+ ${item.condition in weatherImages
+ ? html`
+

+ `
+ : item.condition in weatherIcons
+ ? html`
+
+ `
+ : ""}
+
+ `
+ : ""}
+ ${item.temperature !== undefined &&
+ item.temperature !== null
+ ? html`
+
+ ${item.temperature}°
+
+ `
+ : ""}
+ ${item.templow !== undefined && item.templow !== null
+ ? html`
+
+ ${item.templow}°
+
+ `
+ : ""}
+
+ `
+ )}
+
+ `
+ : ""}
`;
}
@@ -292,177 +274,239 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
return hasConfigOrEntityChanged(this, changedProps);
}
+ protected firstUpdated(): void {
+ this._attachObserver();
+ }
+
private _handleAction(): void {
fireEvent(this, "hass-more-info", { entityId: this._config!.entity });
}
- private getUnit(measure: string): string {
- 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";
- default:
- return this.hass!.config.unit_system[measure] || "";
+ private _attachObserver(): void {
+ if (typeof ResizeObserver !== "function") {
+ import("resize-observer").then((modules) => {
+ modules.install();
+ this._attachObserver();
+ });
+ return;
}
+
+ this._resizeObserver = new ResizeObserver(
+ debounce(() => this._measureCard(), 250, false)
+ );
+
+ const card = this.shadowRoot!.querySelector("ha-card");
+ // If we show an error or warning there is no ha-card
+ if (!card) {
+ return;
+ }
+ this._resizeObserver.observe(card);
}
- private windBearingToText(degree: string): string {
- const degreenum = parseInt(degree, 10);
- if (isFinite(degreenum)) {
- // eslint-disable-next-line no-bitwise
- return cardinalDirections[(((degreenum + 11.25) / 22.5) | 0) % 16];
+ private _measureCard() {
+ this._narrow = this.offsetWidth < 375;
+ if (this.offsetWidth < 300) {
+ this.setAttribute("verynarrow", "");
+ } else {
+ this.removeAttribute("verynarrow");
}
- return degree;
- }
-
- private getWindBearing(bearing: string): string {
- if (bearing != null) {
- const cardinalDirection = this.windBearingToText(bearing);
- return `(${
- this.hass!.localize(
- `ui.card.weather.cardinal_direction.${cardinalDirection.toLowerCase()}`
- ) || cardinalDirection
- })`;
+ if (this.offsetWidth < 200) {
+ this.setAttribute("veryverynarrow", "");
+ } else {
+ this.removeAttribute("veryverynarrow");
}
- return ``;
- }
-
- private _showValue(item: string): boolean {
- return typeof item !== "undefined" && item !== null;
}
static get styles(): CSSResult {
return css`
:host {
+ display: block;
+ }
+
+ ha-card {
cursor: pointer;
+ padding: 16px;
}
.content {
- padding: 0 20px 20px;
- }
-
- ha-icon {
- color: var(--paper-item-icon-color);
- }
-
- .header {
- font-family: var(--paper-font-headline_-_font-family);
- -webkit-font-smoothing: var(
- --paper-font-headline_-_-webkit-font-smoothing
- );
- font-size: var(--paper-font-headline_-_font-size);
- font-weight: var(--paper-font-headline_-_font-weight);
- letter-spacing: var(--paper-font-headline_-_letter-spacing);
- line-height: var(--paper-font-headline_-_line-height);
- text-rendering: var(
- --paper-font-common-expensive-kerning_-_text-rendering
- );
- opacity: var(--dark-primary-opacity);
- padding: 24px 16px 16px;
display: flex;
- align-items: baseline;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+ align-items: center;
}
- .name {
- margin-left: 16px;
- font-size: 16px;
- color: var(--secondary-text-color);
+ .icon-info {
+ display: flex;
+ align-items: center;
+ min-width: 0;
+ flex: 1;
}
- :host([rtl]) .name {
- margin-left: 0px;
+ .weather-image,
+ .weather-icon {
+ flex: 0 0 66px;
margin-right: 16px;
}
- .now {
+ .weather-icon {
+ --iron-icon-width: 66px;
+ --iron-icon-height: 66px;
+ }
+
+ .info {
+ overflow: hidden;
+ }
+
+ .name {
+ font-size: 16px;
+ color: var(--secondary-text-color);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .state {
+ font-size: 28px;
+ line-height: 1.2;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .temp-attribute {
display: flex;
- justify-content: space-between;
- align-items: center;
- flex-wrap: wrap;
+ flex-direction: column;
+ align-items: flex-end;
}
- .main {
- display: flex;
- align-items: center;
- margin-right: 32px;
- }
-
- :host([rtl]) .main {
- margin-right: 0px;
- }
-
- .main ha-icon {
- --iron-icon-height: 72px;
- --iron-icon-width: 72px;
- margin-right: 8px;
- }
-
- :host([rtl]) .main ha-icon {
- margin-right: 0px;
- }
-
- .main .temp {
- font-size: 52px;
- line-height: 1em;
+ .temp-attribute .temp {
position: relative;
+ font-size: 38px;
+ line-height: 1;
+ margin-right: 24px;
}
- :host([rtl]) .main .temp {
- direction: ltr;
- margin-right: 28px;
- }
-
- .main .temp span {
- font-size: 24px;
- line-height: 1em;
+ .temp-attribute .temp span {
position: absolute;
+ font-size: 24px;
top: 4px;
}
- .measurand {
- display: inline-block;
- }
-
- :host([rtl]) .measurand {
- direction: ltr;
- }
-
.forecast {
- margin-top: 16px;
display: flex;
justify-content: space-between;
+ padding-top: 16px;
}
- .forecast div {
- flex: 0 0 auto;
+ .forecast > div {
text-align: center;
}
- .forecast .icon {
+ .forecast .icon,
+ .forecast .temp {
margin: 4px 0;
- text-align: center;
}
- :host([rtl]) .forecast .temp {
- direction: ltr;
+ .forecast .temp {
+ font-size: 16px;
}
- .weekday {
- font-weight: bold;
+ .forecast-image-icon {
+ padding-top: 4px;
+ padding-bottom: 4px;
}
- .attributes,
- .templow,
- .precipitation {
+ .forecast-image {
+ width: 40px;
+ }
+
+ .forecast-icon {
+ --iron-icon-width: 40px;
+ --iron-icon-height: 40px;
+ }
+
+ .attribute {
+ line-height: 1;
+ }
+
+ .attribute,
+ .templow {
color: var(--secondary-text-color);
}
- :host([rtl]) .precipitation {
- direction: ltr;
+ :host([narrow]) .weather-image {
+ flex: 0 0 58px;
+ }
+
+ :host([narrow]) .weather-icon {
+ --iron-icon-width: 58px;
+ --iron-icon-height: 58px;
+ }
+
+ :host([narrow]) .state {
+ font-size: 22px;
+ }
+
+ :host([narrow]) .temp-attribute .temp {
+ font-size: 44px;
+ margin-right: 18px;
+ }
+
+ :host([narrow]) .temp-attribute .temp span {
+ font-size: 18px;
+ top: 3px;
+ }
+
+ :host([narrow]) .attribute {
+ display: none;
+ }
+
+ :host([narrow]) .forecast {
+ justify-content: space-around;
+ }
+
+ :host([veryVeryNarrow]) .content {
+ flex-wrap: wrap;
+ justify-content: center;
+ }
+
+ :host([veryNarrow]) .icon-info {
+ flex: initial;
+ }
+
+ :host([narrow]) .weather-image {
+ flex: 0 0 48px;
+ }
+
+ :host([narrow]) .weather-icon {
+ --iron-icon-width: 48px;
+ --iron-icon-height: 48px;
+ }
+
+ :host([veryNarrow]) .info {
+ display: none;
+ }
+
+ :host([veryNarrow]) .temp-attribute .temp {
+ font-size: 36px;
+ }
+
+ :host([veryNarrow]) .temp-attribute .temp span {
+ top: 2px;
+ }
+
+ :host([veryVeryNarrow]) .temp-attribute {
+ padding-top: 4px;
+ }
+
+ .unavailable {
+ height: 100px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 16px;
+ padding: 10px 20px;
+ text-align: center;
}
`;
}
diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts
index 233cc65e3a..5dd1c46ac1 100644
--- a/src/panels/lovelace/cards/types.ts
+++ b/src/panels/lovelace/cards/types.ts
@@ -274,4 +274,5 @@ export interface ThermostatCardConfig extends LovelaceCardConfig {
export interface WeatherForecastCardConfig extends LovelaceCardConfig {
entity: string;
name?: string;
+ show_forecast?: boolean;
}
diff --git a/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts
index 2bf907a919..f8d8415bbe 100644
--- a/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts
+++ b/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts
@@ -7,12 +7,14 @@ import {
} from "lit-element";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/entity/ha-entity-picker";
+import "../../../../components/ha-switch";
+
+import { EntitiesEditorEvent, EditorTarget } from "../types";
import { HomeAssistant } from "../../../../types";
import { WeatherForecastCardConfig } from "../../cards/types";
import { struct } from "../../common/structs/struct";
import "../../components/hui-theme-select-editor";
import { LovelaceCardEditor } from "../../types";
-import { EditorTarget, EntitiesEditorEvent } from "../types";
import { configElementStyle } from "./config-elements-style";
const cardConfigStruct = struct({
@@ -20,6 +22,7 @@ const cardConfigStruct = struct({
entity: "string?",
name: "string?",
theme: "string?",
+ show_forecast: "boolean?",
});
@customElement("hui-weather-forecast-card-editor")
@@ -46,6 +49,10 @@ export class HuiWeatherForecastCardEditor extends LitElement
return this._config!.theme || "";
}
+ get _show_forecast(): boolean {
+ return this._config!.show_forecast || true;
+ }
+
protected render(): TemplateResult {
if (!this.hass || !this._config) {
return html``;
@@ -61,28 +68,36 @@ export class HuiWeatherForecastCardEditor extends LitElement
"ui.panel.lovelace.editor.card.config.required"
)})"
.hass=${this.hass}
- .value="${this._entity}"
+ .value=${this._entity}
.configValue=${"entity"}
- .include-domains=${["weather"]}
- @change="${this._valueChanged}"
+ .includeDomains=${["weather"]}
+ @change=${this._valueChanged}
allow-custom-entity
>
-
-
+
+
Show forecast
`;
}
@@ -101,7 +116,8 @@ export class HuiWeatherForecastCardEditor extends LitElement
} else {
this._config = {
...this._config,
- [target.configValue!]: target.value,
+ [target.configValue!]:
+ target.checked !== undefined ? target.checked : target.value,
};
}
}
diff --git a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts
index 794630aa76..dc1e526322 100644
--- a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts
@@ -14,11 +14,11 @@ import {
getWeatherUnit,
weatherIcons,
weatherImages,
+ getSecondaryWeatherAttribute,
} from "../../../data/weather";
import { HomeAssistant, WeatherEntity } from "../../../types";
import { EntitiesCardEntityConfig } from "../cards/types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
-import "../components/hui-warning";
import { LovelaceRow } from "./types";
@customElement("hui-weather-entity-row")
@@ -77,95 +77,13 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
`}
- ${!UNAVAILABLE_STATES.includes(stateObj.state)
- ? this._getSecondaryAttribute(stateObj)
- : ""}
+ ${getSecondaryWeatherAttribute(this.hass!, stateObj)}