├── .npmignore ├── .eslintignore ├── dist ├── icons │ ├── background │ │ ├── day-clear.jpg │ │ ├── day-cloud-1.jpg │ │ ├── day-cloud-2.jpg │ │ └── day-cloud-3.jpg │ ├── animated │ │ ├── weather_sagittarius.svg │ │ ├── clear-day.svg │ │ ├── cloudy.svg │ │ ├── partly-cloudy-day.svg │ │ ├── weather_sunset.svg │ │ ├── clear-night.svg │ │ ├── partly-cloudy-night.svg │ │ ├── haze.svg │ │ ├── fog.svg │ │ ├── rainy-4.svg │ │ ├── rain.svg │ │ ├── wind.svg │ │ ├── snow.svg │ │ ├── rainy-5.svg │ │ ├── rainy-6.svg │ │ ├── rainy-7.svg │ │ └── snowy-4.svg │ └── static │ │ ├── weather_sagittarius.svg │ │ ├── clear-day.svg │ │ ├── clear-night.svg │ │ ├── cloudy.svg │ │ ├── weather_sunset.svg │ │ ├── partly-cloudy-day.svg │ │ ├── rainy-4.svg │ │ ├── partly-cloudy-night.svg │ │ ├── night.svg │ │ ├── rainy-5.svg │ │ ├── cloudy-original.svg │ │ ├── haze.svg │ │ ├── rainy-6.svg │ │ ├── rainy-7.svg │ │ ├── thunder.svg │ │ ├── fog.svg │ │ ├── snowy-4.svg │ │ ├── cloudy-night-1.svg │ │ ├── cloudy-night-2.svg │ │ ├── cloudy-night-3.svg │ │ ├── fair-night.svg │ │ ├── rain-and-sleet-mix.svg │ │ ├── rain-and-snow-mix.svg │ │ ├── rain.svg │ │ ├── day.svg │ │ ├── snowy-5.svg │ │ ├── severe-thunderstorm.svg │ │ ├── cloudy-day-1.svg │ │ ├── cloudy-day-3.svg │ │ ├── cloudy-day-2.svg │ │ ├── fair-day.svg │ │ ├── rainy-2.svg │ │ ├── snow-and-sleet-mix.svg │ │ ├── isolated-thunderstorms.svg │ │ ├── scattered-thunderstorms.svg │ │ ├── snowy-6.svg │ │ ├── tropical-storm.svg │ │ ├── rainy-3.svg │ │ ├── rainy-1.svg │ │ ├── hurricane.svg │ │ └── snowy-2.svg └── transl │ ├── es.json │ ├── cs.json │ ├── en.json │ ├── da.json │ ├── no-NO.json │ ├── pt.json │ ├── sr-latn.json │ ├── ru.json │ ├── it.json │ ├── nl.json │ ├── de.json │ └── fr.json ├── md.images ├── ha-card-weather-condition-1.png ├── ha-card-weather-condition-2.png ├── ha-card-weather-condition-sea.png ├── ha-card-weather-condition-alarms.png ├── ha-card-weather-condition-alert.png ├── ha-card-weather-condition-full.png ├── ha-card-weather-condition-pollen.png ├── ha-card-weather-condition-overview.png ├── ha-card-weather-condition-present.png ├── ha-card-weather-condition-summary.png ├── ha-card-weather-condition-air-quality.png ├── ha-card-weather-condition-ultraviolet.png ├── ha-card-weather-condition-daily-forecast.png ├── ha-card-weather-condition-hourly-forecast.png └── ha-card-weather-condition-marine-daily-forecast.png ├── backup ├── ha-card-weather-condition-present.png └── ha-card-weather-condition-summary.png ├── hacs.json ├── .gitignore ├── .vscode └── settings.json ├── src ├── css │ ├── css-camera.ts │ ├── css-present.ts │ ├── css-meteoalarm.ts │ ├── css-base-card.ts │ ├── css-pollen.ts │ ├── css-weather-forecast.ts │ └── css-ultraviolet.ts ├── iconmodels │ ├── im-darksky.ts │ ├── im-openweathermap.ts │ ├── im-hass.ts │ ├── im-buienradar.ts │ ├── im-climacell.ts │ └── im-pirateweather.ts ├── templates │ ├── t-camera.ts │ ├── t-meteoalarm.ts │ └── t-pollen.ts ├── builder │ ├── b-camera.ts │ ├── b-pollen.ts │ ├── b-summary.ts │ ├── b-ultraviolet.ts │ └── b-airquality.ts └── utils │ ├── const.ts │ ├── colors.ts │ ├── helper-render.ts │ └── config-schema.ts ├── tsconfig.json ├── .github └── workflows │ └── codeql.yml ├── LICENSE ├── .eslintrc.json ├── rollup.new.config.mjs ├── package.json └── CHANGELOG.md /.npmignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | backup -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | backup/ 2 | dist/ 3 | node_modules/ 4 | rollup.config.mjs 5 | rollup.config copy.js 6 | rollup.new.config.mjs -------------------------------------------------------------------------------- /dist/icons/background/day-clear.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/dist/icons/background/day-clear.jpg -------------------------------------------------------------------------------- /dist/icons/background/day-cloud-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/dist/icons/background/day-cloud-1.jpg -------------------------------------------------------------------------------- /dist/icons/background/day-cloud-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/dist/icons/background/day-cloud-2.jpg -------------------------------------------------------------------------------- /dist/icons/background/day-cloud-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/dist/icons/background/day-cloud-3.jpg -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-1.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-2.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-sea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-sea.png -------------------------------------------------------------------------------- /backup/ha-card-weather-condition-present.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/backup/ha-card-weather-condition-present.png -------------------------------------------------------------------------------- /backup/ha-card-weather-condition-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/backup/ha-card-weather-condition-summary.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-alarms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-alarms.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-alert.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-full.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-pollen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-pollen.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-overview.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-present.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-present.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-summary.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-air-quality.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-air-quality.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-ultraviolet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-ultraviolet.png -------------------------------------------------------------------------------- /hacs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "HA (Lovelace) Card Weather Conditions", 3 | "domains": ["weather"], 4 | "render_readme": false, 5 | "filename": "ha-card-weather-conditions.js" 6 | } -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-daily-forecast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-daily-forecast.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-hourly-forecast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-hourly-forecast.png -------------------------------------------------------------------------------- /md.images/ha-card-weather-condition-marine-daily-forecast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-renato/ha-card-weather-conditions/HEAD/md.images/ha-card-weather-condition-marine-daily-forecast.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ####### ####### ####### 2 | # Folders 3 | 4 | .idea 5 | __pycache__ 6 | /node_modules/ 7 | /.rpt2_cache/ 8 | /trash/ 9 | /backup/ 10 | 11 | # ####### ####### ####### 12 | # Files 13 | package-lock.json 14 | 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.enable": true, 3 | "eslint.validate": [ 4 | "javascript", 5 | "javascriptreact", 6 | "typescript", 7 | "typescriptreact" 8 | ], 9 | "editor.tabSize": 2, 10 | 11 | "ha_module_path": "/home/drp/homeassistant/www/community/ha-card-weather-conditions", 12 | "editor.wordWrap": "wordWrapColumn", 13 | "editor.wordWrapColumn": 120, 14 | } 15 | -------------------------------------------------------------------------------- /src/css/css-camera.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | const cameraStyle = css` 4 | .camera-container { 5 | margin-top: 10px; 6 | width: 100%; 7 | display: flex; 8 | align-items: stretch; 9 | } 10 | 11 | .camera-image { 12 | aspect-ratio: 16 / 9; 13 | width: 100%; 14 | position: relative; 15 | overflow: hidden; 16 | display: flex; 17 | align-items: center; 18 | justify-content: center; 19 | } 20 | 21 | .camera-image > img { 22 | width: 100%; 23 | height: 100%; 24 | object-fit: cover; 25 | } 26 | `; 27 | 28 | export default cameraStyle; 29 | -------------------------------------------------------------------------------- /src/iconmodels/im-darksky.ts: -------------------------------------------------------------------------------- 1 | export const cwcDarkskyDayIcons: { [key: string]: string; } = { 2 | clear: 'day', 3 | 'clear-day': 'day', 4 | rain: 'rainy-2', 5 | snow: 'snowy-2', 6 | sleet: 'rain-and-sleet-mix', 7 | wind: 'cloudy-day-1', 8 | fog: 'fog', 9 | cloudy: 'cloudy-original', 10 | 'partly-cloudy-day': 'cloudy-day-2', 11 | }; 12 | 13 | export const cwcDarkskyNightIcons: { [key: string]: string; } = { 14 | ...cwcDarkskyDayIcons, 15 | clear: 'night', 16 | 'clear-night': 'night', 17 | wind: 'cloudy-night-1', 18 | 'partly-cloudy-day': 'cloudy-night-2', 19 | 'partly-cloudy-night': 'cloudy-night-2', 20 | }; 21 | -------------------------------------------------------------------------------- /src/iconmodels/im-openweathermap.ts: -------------------------------------------------------------------------------- 1 | export const cwcOpenWeatherMapDayIcons: { [key: string]: string; } = { 2 | 'clear sky': 'day', 3 | 'few clouds': 'cloudy-day-1', 4 | 'scattered clouds': 'cloudy-day-2', 5 | 'broken clouds': 'cloudy-day-3', 6 | 'shower rain': 'rainy-3', 7 | rain: 'rainy-2', 8 | thunderstorm: 'tropical-storm', 9 | snow: 'snowy-2', 10 | mist: 'fog', 11 | }; 12 | 13 | export const cwcOpenWeatherMapNightIcons: { [key: string]: string; } = { 14 | ...cwcOpenWeatherMapDayIcons, 15 | 'clear sky': 'day-night', 16 | 'few clouds': 'cloudy-night-1', 17 | 'scattered clouds': 'cloudy-night-2', 18 | 'broken clouds': 'cloudy-night-3', 19 | }; 20 | -------------------------------------------------------------------------------- /src/templates/t-camera.ts: -------------------------------------------------------------------------------- 1 | import { html } from 'lit'; 2 | 3 | const renderCamera = ( 4 | handlePopup: (e: Event, entityId: string) => void, 5 | cameraId: string, 6 | cameraPicture: string, 7 | friendlyName: string, 8 | ) => { 9 | if (!cameraPicture) return html``; 10 | 11 | return html` 12 |
handlePopup(e, cameraId)} 15 | > 16 |
17 | ${friendlyName} 22 |
23 |
24 | `; 25 | }; 26 | 27 | export default renderCamera; 28 | -------------------------------------------------------------------------------- /src/iconmodels/im-hass.ts: -------------------------------------------------------------------------------- 1 | export const cwcDefaultHassDayIcons: { [key: string]: string } = { 2 | cloudy: 'cloudy-day-3', 3 | exceptional: 'severe-thunderstorm', 4 | fog: 'fog', 5 | hail: 'snow-and-sleet-mix', 6 | lightning: 'severe-thunderstorm', 7 | 'lightning-rainy': 'scattered-thunderstorms', 8 | partlycloudy: 'cloudy-day-3', 9 | pouring: 'rainy-6', 10 | rainy: 'rainy-5', 11 | snowy: 'snowy-6', 12 | 'snowy-rainy': 'snow-and-sleet-mix', 13 | sunny: 'clear-day', 14 | windy: 'wind', 15 | 'windy-variant': 'wind', 16 | }; 17 | 18 | export const cwcDefaultHassNightIcons: { [key: string]: string } = { 19 | ...cwcDefaultHassDayIcons, 20 | 'clear-night': 'clear-night', 21 | }; 22 | -------------------------------------------------------------------------------- /src/builder/b-camera.ts: -------------------------------------------------------------------------------- 1 | import { HomeAssistant } from 'custom-card-helpers/dist'; 2 | import { iTerms } from '../base/lovelace-base'; 3 | import renderCamera from '../templates/t-camera'; 4 | 5 | const buildCamera = ( 6 | hass: HomeAssistant, 7 | lang: string, 8 | terms: iTerms, 9 | handlePopup: (e: Event, entityId: string) => void, 10 | cameraId: string, 11 | ) => { 12 | const camera = cameraId && hass.states[cameraId]; 13 | 14 | const entityPicture = camera?.attributes?.entity_picture; 15 | const friendlyName = camera?.attributes?.friendly_name ?? cameraId; 16 | 17 | return renderCamera(handlePopup, cameraId, entityPicture, friendlyName); 18 | }; 19 | 20 | export default buildCamera; 21 | -------------------------------------------------------------------------------- /src/css/css-present.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | const presentStyle = css` 4 | .present-grid-container { 5 | display: flex; 6 | flex-direction: column; 7 | gap: 4px; 8 | } 9 | 10 | .present-row { 11 | display: flex; 12 | justify-content: space-between; 13 | gap: 16px; 14 | } 15 | 16 | .present-left, 17 | .present-right { 18 | flex: 1; 19 | } 20 | 21 | .present-left { 22 | display: flex; 23 | justify-content: flex-start; 24 | } 25 | 26 | .present-right { 27 | display: flex; 28 | justify-content: flex-end; 29 | } 30 | 31 | .present-value-block { 32 | display: flex; 33 | align-items: center; 34 | gap: 4px; 35 | } 36 | 37 | .present-unit { 38 | font-size: 0.9em; 39 | opacity: 0.8; 40 | } 41 | `; 42 | 43 | export default presentStyle; 44 | -------------------------------------------------------------------------------- /dist/icons/animated/weather_sagittarius.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Created with Sketch. 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /dist/icons/static/weather_sagittarius.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Created with Sketch. 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /dist/transl/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwcLocWindDirections": { 3 | "N": "N", 4 | "NNE": "NNE", 5 | "NE": "NE", 6 | "ENE": "ENE", 7 | "E": "E", 8 | "ESE": "ESE", 9 | "SE": "SE", 10 | "SSE": "SSE", 11 | "S": "S", 12 | "SSW": "SSO", 13 | "SW": "SO", 14 | "WSW": "OSO", 15 | "W": "O", 16 | "WNW": "ONO", 17 | "NW": "NO", 18 | "NNW": "NNO" 19 | }, 20 | 21 | "cwcTerms": { 22 | "Feels Like" : "Sensación térmica", 23 | "new_moon": "Luna nueva", 24 | "new": "Luna nueva", 25 | "waxing_crescent": "Luna creciente", 26 | "first_quarter": "Cuarto creciente", 27 | "waxing_gibbous": "Luna menguante gibosa", 28 | "full": "Luna llena", 29 | "full_moon": "Luna llena", 30 | "waning_gibbous": "Luna menguante gibosa", 31 | "third_quarter": "Media luna", 32 | "last_quarter": "Cuarto menguante", 33 | "waning_crescent": "Luna menguante" 34 | } 35 | } -------------------------------------------------------------------------------- /src/css/css-meteoalarm.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | const meteodcpalarmStyle = css` 4 | .meteodcpalarm-grid-container { 5 | display: flex; 6 | flex-wrap: wrap; 7 | justify-content: center; 8 | gap: 16px; 9 | padding: 12px; 10 | } 11 | 12 | .meteodcpalarm-group { 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | flex: 1 1 72px; /* 👈 cresce, ma non scende sotto i 72px */ 17 | max-width: 220px; /* 👈 opzionale: previene allargamento eccessivo */ 18 | text-align: center; 19 | } 20 | 21 | .meteodcpalarm-group ha-icon { 22 | --mdc-icon-size: 36px; 23 | } 24 | 25 | .meteodcpalarm-label { 26 | margin-top: 6px; 27 | font-size: 0.85em; 28 | color: var(--primary-text-color); 29 | } 30 | 31 | 32 | `; 33 | 34 | export default meteodcpalarmStyle; 35 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "lib": ["es2020", "dom", "dom.iterable"], 7 | "noEmit": true, 8 | "noUnusedLocals": false, 9 | "noUnusedParameters": false, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "strict": true, 13 | "noImplicitAny": false, 14 | "skipLibCheck": true, 15 | "resolveJsonModule": true, 16 | "experimentalDecorators": true, 17 | "strictNullChecks": false 18 | }, 19 | 20 | "include": ["src/**/*.ts"], 21 | "exclude": ["node_modules"], 22 | 23 | "scripts": { 24 | "start": "rollup -c --watch", 25 | "build": "npm run lint && npm run rollup", 26 | "lint": "eslint src/*.ts", 27 | "rollup": "rollup -c" 28 | } 29 | } -------------------------------------------------------------------------------- /dist/icons/static/clear-day.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | -------------------------------------------------------------------------------- /dist/transl/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwcLocWindDirections": { 3 | "N": "S", 4 | "NNE": "SSV", 5 | "NE": "SV", 6 | "ENE": "VSV", 7 | "E": "V", 8 | "ESE": "VJV", 9 | "SE": "JV", 10 | "SSE": "JJV", 11 | "S": "J", 12 | "SSW": "JJZ", 13 | "SW": "JZ", 14 | "WSW": "ZJZ", 15 | "W": "Z", 16 | "WNW": "ZSZ", 17 | "NW": "SZ", 18 | "NNW": "SSZ" 19 | }, 20 | 21 | "cwcTerms": { 22 | "Feels Like" : "Pocitová teplota", 23 | "new_moon": "Nov", 24 | "new": "Nov", 25 | "waxing_crescent": "Dorůstající srpek", 26 | "first_quarter": "První čtvrť", 27 | "waxing_gibbous": "Dorůstající měsíc", 28 | "full": "Úplněk", 29 | "full_moon": "Úplněk", 30 | "waning_gibbous": "Couvající měsíc", 31 | "third_quarter": "Třetí čtvrť", 32 | "last_quarter": "Poslední čtvrť", 33 | "waning_crescent": "Ubývající srpek" 34 | } 35 | } -------------------------------------------------------------------------------- /dist/transl/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwcLocWindDirections": { 3 | "N": "N", 4 | "NNE": "NNE", 5 | "NE": "NE", 6 | "ENE": "ENE", 7 | "E": "E", 8 | "ESE": "ESE", 9 | "SE": "SE", 10 | "SSE": "SSE", 11 | "S": "S", 12 | "SSW": "SSW", 13 | "SW": "SW", 14 | "WSW": "WSW", 15 | "W": "W", 16 | "WNW": "WNW", 17 | "NW": "NW", 18 | "NNW": "NNW" 19 | }, 20 | 21 | "cwcTerms": { 22 | "Feels Like" : "Feels Like", 23 | "new_moon": "New moon", 24 | "new": "New moon", 25 | "waxing_crescent": "Waxing crescent", 26 | "first_quarter": "First quarter", 27 | "waxing_gibbous": "Waxing Gibbous", 28 | "full": "Full", 29 | "full_moon": "Full", 30 | "waning_gibbous": "Waning Gibbous", 31 | "third_quarter": "Third Quarter", 32 | "last_quarter": "Last Quarter", 33 | "waning_crescent": "Waning Crescent" 34 | } 35 | } -------------------------------------------------------------------------------- /dist/transl/da.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwcLocWindDirections": { 3 | "N": "N", 4 | "NNE": "NNØ", 5 | "NE": "NØ", 6 | "ENE": "ØNØ", 7 | "E": "Ø", 8 | "ESE": "ØSØ", 9 | "SE": "SØ", 10 | "SSE": "SSØ", 11 | "S": "S", 12 | "SSW": "SSV", 13 | "SW": "SV", 14 | "WSW": "VSV", 15 | "W": "V", 16 | "WNW": "VNV", 17 | "NW": "NV", 18 | "NNW": "NNV" 19 | }, 20 | 21 | "cwcTerms": { 22 | "Feels Like" : "Føles som", 23 | "new_moon": "Nymåne", 24 | "new": "Nymåne", 25 | "waxing_crescent": "Tiltagende halvmåne", 26 | "first_quarter": "Første kvartal", 27 | "waxing_gibbous": "Tiltagende måne", 28 | "full": "Fuldmåne", 29 | "full_moon": "Fuldmåne", 30 | "waning_gibbous": "Aftagende måne", 31 | "third_quarter": "Tredje kvartal", 32 | "last_quarter": "Sidste kvartal", 33 | "waning_crescent": "Aftagende halvmåne" 34 | } 35 | } -------------------------------------------------------------------------------- /dist/transl/no-NO.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwcLocWindDirections": { 3 | "N": "N", 4 | "NNE": "NNØ", 5 | "NE": "NØ", 6 | "ENE": "ØNØ", 7 | "E": "Ø", 8 | "ESE": "ØSØ", 9 | "SE": "SØ", 10 | "SSE": "SSØ", 11 | "S": "S", 12 | "SSW": "SSV", 13 | "SW": "SV", 14 | "WSW": "VSV", 15 | "W": "V", 16 | "WNW": "VNV", 17 | "NW": "NV", 18 | "NNW": "NNV" 19 | }, 20 | 21 | "cwcTerms": { 22 | "Feels Like" : "Føles som", 23 | "new_moon": "Nymåne", 24 | "new": "Nymåne", 25 | "waxing_crescent": "Tiltagende halvmåne", 26 | "first_quarter": "Første kvartal", 27 | "waxing_gibbous": "Tiltagende måne", 28 | "full": "Fullmåne", 29 | "full_moon": "Fullmåne", 30 | "waning_gibbous": "Avtagende måne", 31 | "third_quarter": "Tredje kvartal", 32 | "last_quarter": "Sidste kvartal", 33 | "waning_crescent": "Avtagende halvmåne" 34 | } 35 | } -------------------------------------------------------------------------------- /dist/transl/pt.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwcLocWindDirections": { 3 | "N": "N", 4 | "NNE": "NNE", 5 | "NE": "NE", 6 | "ENE": "ENE", 7 | "E": "E", 8 | "ESE": "ESE", 9 | "SE": "SE", 10 | "SSE": "SSE", 11 | "S": "S", 12 | "SSW": "SSW", 13 | "SW": "SW", 14 | "WSW": "WSW", 15 | "W": "W", 16 | "WNW": "WNW", 17 | "NW": "NW", 18 | "NNW": "NNW" 19 | }, 20 | 21 | "cwcTerms": { 22 | "Feels Like" : "Sentida", 23 | "new_moon": "Lua Nova", 24 | "new": "Lua nova", 25 | "waxing_crescent": "Lua Crescente", 26 | "first_quarter": "Quarto Crescente", 27 | "waxing_gibbous": "Crescente Gibosa", 28 | "full": "Lua Cheia", 29 | "full_moon": "Lua Cheia", 30 | "waning_gibbous": "Minguante Gibosa", 31 | "third_quarter": "Quarto Minguante", 32 | "last_quarter": "Quarto Minguante", 33 | "waning_crescent": "Lua Minguante" 34 | } 35 | } -------------------------------------------------------------------------------- /dist/transl/sr-latn.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwcLocWindDirections": { 3 | "N": "S", 4 | "NNE": "SSI", 5 | "NE": "SI", 6 | "ENE": "ISI", 7 | "E": "I", 8 | "ESE": "IJI", 9 | "SE": "JI", 10 | "SSE": "JJI", 11 | "S": "J", 12 | "SSW": "JJZ", 13 | "SW": "JZ", 14 | "WSW": "ZSZ", 15 | "W": "Z", 16 | "WNW": "ZSZ", 17 | "NW": "SZ", 18 | "NNW": "SSZ" 19 | }, 20 | 21 | "cwcTerms": { 22 | "Feels Like" : "Subjektivni osećaj", 23 | "new_moon": "Mlad mesec", 24 | "new": "Mlad mesec", 25 | "waxing_crescent": "Prva osmina", 26 | "first_quarter": "Prva četvrt", 27 | "waxing_gibbous": "Treća osmina", 28 | "full": "Pun mesec", 29 | "full_moon": "Pun mesec", 30 | "waning_gibbous": "Peta osmina", 31 | "third_quarter": "Treća četvrtina", 32 | "last_quarter": "Zadnja četvrtina", 33 | "waning_crescent": "Sedma osmina" 34 | } 35 | } -------------------------------------------------------------------------------- /dist/transl/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwcLocWindDirections": { 3 | "N": "С", 4 | "NNE": "ССВ", 5 | "NE": "СВ", 6 | "ENE": "ВСВ", 7 | "E": "В", 8 | "ESE": "ВЮВ", 9 | "SE": "ЮВ", 10 | "SSE": "ЮЮВ", 11 | "S": "Ю", 12 | "SSW": "ЮЮЗ", 13 | "SW": "ЮЗ", 14 | "WSW": "ЗЮЗ", 15 | "W": "З", 16 | "WNW": "ЗСЗ", 17 | "NW": "СЗ", 18 | "NNW": "ССЗ" 19 | }, 20 | 21 | "cwcTerms": { 22 | "Feels Like" : "Ощущается как", 23 | "new_moon": "Новолуние", 24 | "new": "Новолуние", 25 | "waxing_crescent": "Растущий серп", 26 | "first_quarter": "Первая четверть", 27 | "waxing_gibbous": "Растущая луна", 28 | "full": "Полнолуние", 29 | "full_moon": "Полнолуние", 30 | "waning_gibbous": "Убывающая луна", 31 | "third_quarter": "Третья четверть", 32 | "last_quarter": "Последняя четверть", 33 | "waning_crescent": "Убывающая луна" 34 | } 35 | } -------------------------------------------------------------------------------- /dist/transl/it.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwcLocWindDirections": { 3 | "N": "N", 4 | "NNE": "NNE", 5 | "NE": "NE", 6 | "ENE": "ENE", 7 | "E": "E", 8 | "ESE": "ESE", 9 | "SE": "SE", 10 | "SSE": "SSE", 11 | "S": "S", 12 | "SSW": "SSO", 13 | "SW": "SO", 14 | "WSW": "OSO", 15 | "W": "O", 16 | "WNW": "ONO", 17 | "NW": "NO", 18 | "NNW": "NNO" 19 | }, 20 | 21 | "cwcTerms": { 22 | "Feels Like" : "Percepita", 23 | "new_moon": "Novilunio", 24 | "new": "Novilunio", 25 | "waxing_crescent": "Luna crescente", 26 | "first_quarter": "Primo Quarto", 27 | "waxing_gibbous": "Gibbosa crescente", 28 | "full": "Luna piena", 29 | "full_moon": "Luna piena", 30 | "waning_gibbous": "Gibbosa calante", 31 | "third_quarter": "Ultimo quarto", 32 | "last_quarter": "Ultimo quarto", 33 | "waning_crescent": "Luna calante" 34 | } 35 | } -------------------------------------------------------------------------------- /dist/transl/nl.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwcLocWindDirections": { 3 | "N": "N", 4 | "NNE": "NNO", 5 | "NE": "NO", 6 | "ENE": "ONO", 7 | "E": "O", 8 | "ESE": "OZO", 9 | "SE": "ZO", 10 | "SSE": "ZZO", 11 | "S": "Z", 12 | "SSW": "ZZW", 13 | "SW": "ZW", 14 | "WSW": "WZW", 15 | "W": "W", 16 | "WNW": "WNW", 17 | "NW": "NW", 18 | "NNW": "NNW" 19 | }, 20 | 21 | "cwcTerms": { 22 | "Feels Like": "Voelt Als", 23 | "new_moon": "Nieuwe maan", 24 | "new": "Nieuwe maan", 25 | "waxing_crescent": "Wassende halve maan", 26 | "first_quarter": "Eerste kwartier", 27 | "waxing_gibbous": "Wassende maan", 28 | "full": "Volle maan", 29 | "full_moon": "Volle maan", 30 | "waning_gibbous": "Afnemende maan", 31 | "third_quarter": "Derde Kwartier", 32 | "last_quarter": "Laatste Kwartier", 33 | "waning_crescent": "Afnemende halve maan" 34 | } 35 | } -------------------------------------------------------------------------------- /dist/transl/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwcLocWindDirections": { 3 | "N": "N", 4 | "NNE": "NNO", 5 | "NE": "NO", 6 | "ENE": "ONO", 7 | "E": "O", 8 | "ESE": "OSO", 9 | "SE": "SO", 10 | "SSE": "SSO", 11 | "S": "S", 12 | "SSW": "SSW", 13 | "SW": "SW", 14 | "WSW": "WSW", 15 | "W": "W", 16 | "WNW": "WNW", 17 | "NW": "NW", 18 | "NNW": "NNW" 19 | }, 20 | 21 | "cwcTerms": { 22 | "Feels Like" : "Gefühlt", 23 | "new_moon": "Neumond", 24 | "new": "Neumond", 25 | "waxing_crescent": "Zunehmende Sichel", 26 | "first_quarter": "Erstes Viertel", 27 | "waxing_gibbous": "Zunehmender Halbmond", 28 | "full": "Vollmond", 29 | "full_moon": "Vollmond", 30 | "waning_gibbous": "Abnehmender Halbmond", 31 | "third_quarter": "Drittes Viertel", 32 | "last_quarter": "Letztes Viertel", 33 | "waning_crescent": "Abnehmende Sichel" 34 | } 35 | } -------------------------------------------------------------------------------- /dist/transl/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "cwcLocWindDirections": { 3 | "N": "N", 4 | "NNE": "NNE", 5 | "NE": "NE", 6 | "ENE": "ENE", 7 | "E": "E", 8 | "ESE": "ESE", 9 | "SE": "SE", 10 | "SSE": "SSE", 11 | "S": "S", 12 | "SSW": "SSO", 13 | "SW": "SO", 14 | "WSW": "OSO", 15 | "W": "O", 16 | "WNW": "ONO", 17 | "NW": "NO", 18 | "NNW": "NNO" 19 | }, 20 | 21 | "cwcTerms": { 22 | "Feels Like" : "Ressentie", 23 | "new_moon": "Nouvelle lune", 24 | "new": "Nouvelle lune", 25 | "waxing_crescent": "Premier croissant", 26 | "first_quarter": "Premier quartier", 27 | "waxing_gibbous": "Gibbeuse croissante", 28 | "full": "Pleine lune", 29 | "full_moon": "Pleine lune", 30 | "waning_gibbous": "Gibbeuse décroissante", 31 | "third_quarter": "Dernier quartier", 32 | "last_quarter": "Dernier quartier", 33 | "waning_crescent": "Lune décroissante" 34 | } 35 | } -------------------------------------------------------------------------------- /dist/icons/animated/clear-day.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/templates/t-meteoalarm.ts: -------------------------------------------------------------------------------- 1 | import { html } from 'lit'; 2 | 3 | export interface iWeatherMeteoDPCAlarmDataInterface { 4 | event?: string, 5 | severity?: string, 6 | icon?: string, 7 | icon_color?: string, 8 | datetime?: string, 9 | } 10 | 11 | const renderMeteoDPCalarm = ( 12 | meteoDPCalarmData: Record | null, 13 | ) => { 14 | if (!meteoDPCalarmData || Object.keys(meteoDPCalarmData).length === 0) return html``; 15 | 16 | return html` 17 |
18 | ${Object.entries(meteoDPCalarmData).map(([key, data]) => html` 19 |
20 | 21 |
${data.datetime}
22 |
${data.event}
23 |
24 | `)} 25 |
26 | `; 27 | }; 28 | 29 | export default renderMeteoDPCalarm; 30 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | schedule: 9 | - cron: "22 7 * * 0" 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze 14 | runs-on: ubuntu-latest 15 | permissions: 16 | actions: read 17 | contents: read 18 | security-events: write 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | language: [ javascript ] 24 | 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v3 28 | 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v2 31 | with: 32 | languages: ${{ matrix.language }} 33 | queries: +security-and-quality 34 | 35 | - name: Autobuild 36 | uses: github/codeql-action/autobuild@v2 37 | 38 | - name: Perform CodeQL Analysis 39 | uses: github/codeql-action/analyze@v2 40 | with: 41 | category: "/language:${{ matrix.language }}" 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Renato Rossi, https://www.linkedin.com/in/renatorossi/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/builder/b-pollen.ts: -------------------------------------------------------------------------------- 1 | import { HomeAssistant } from 'custom-card-helpers/dist'; 2 | import { iPollen } from '../utils/config-schema'; 3 | import { getEntityRawValue, string2Number } from '../utils/helper'; 4 | import { iPollenData, renderPollen } from '../templates/t-pollen'; 5 | 6 | const buildPollen = (hass: HomeAssistant, lang: string, pollen: iPollen) => { 7 | const allItems: iPollenData[] = []; 8 | if (Array.isArray(pollen.entities) && pollen.entities.length > 0) { 9 | pollen.entities.forEach((item) => { 10 | const rawvalue = getEntityRawValue(hass, item.entity); 11 | if (rawvalue && rawvalue !== 'unknown' && rawvalue !== 'unavailable') { 12 | let value: number = string2Number(getEntityRawValue(hass, item.entity)); 13 | 14 | if (Number.isNaN(value) || value < pollen.min || value > pollen.max) { 15 | value = 0; 16 | } 17 | 18 | allItems.push({ 19 | name: item.name, 20 | value, 21 | }); 22 | } 23 | // console.log(`Nome: ${item.name}, Entità: ${item.entity}`); 24 | }); 25 | } 26 | 27 | return renderPollen(allItems, pollen.min, pollen.max); 28 | }; 29 | 30 | export default buildPollen; 31 | -------------------------------------------------------------------------------- /src/utils/const.ts: -------------------------------------------------------------------------------- 1 | export const logo: string = '%c WEATHER-CONDITION-CARD %c 2.0.0'; 2 | 3 | export const hacsImagePath: string = '/local/community/ha-card-weather-conditions/icons'; 4 | export const manImagePath: string = '/local/ha-card-weather-conditions/icons'; 5 | 6 | export const optConsoleParam1: string = 'color: white; background: green; font-weight: 700;'; 7 | export const optConsoleParam2: string = 'color: green; background: white; font-weight: 700;'; 8 | export const optConsoleParam3: string = 'color: black; background: white; font-weight: 700;'; 9 | 10 | export const iconTemperature: string = 'mdi:thermometer'; 11 | export const iconPrecipitation: string = 'mdi:weather-rainy'; 12 | 13 | export const cwcLocale = { 14 | en: 0, 15 | it: 1, 16 | nl: 2, 17 | es: 3, 18 | de: 4, 19 | fr: 5, 20 | 'sr-latn': 6, 21 | pt: 7, 22 | da: 8, 23 | 'no-no': 9, 24 | cs: 10, 25 | ru: 11, 26 | }; 27 | 28 | // 🌑 🌒 🌓 🌔 🌕 🌖 🌗 🌘 🌑 29 | export const cwcMoonPhaseIcons = { 30 | new_moon: '🌑', 31 | new: '🌑', 32 | waxing_crescent: '🌒', 33 | first_quarter: '🌓', 34 | waxing_gibbous: '🌔', 35 | full: '🌕', 36 | full_moon: '🌕', 37 | waning_gibbous: '🌖', 38 | third_quarter: '🌗', 39 | last_quarter: '🌗', 40 | waning_crescent: '🌘', 41 | }; 42 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 2022, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "extends": [ 12 | "eslint:recommended", 13 | "plugin:@typescript-eslint/recommended", 14 | "airbnb-base" 15 | ], 16 | "rules": { 17 | "operator-linebreak": "warn", 18 | "no-trailing-spaces": "warn", 19 | "one-var": "warn", 20 | "one-var-declaration-per-line": "warn", 21 | "dot-notation": "warn", 22 | "max-len": ["error", { "code": 150 }], 23 | "eol-last": ["error", "always"], 24 | "no-console": "off", 25 | "no-unused-vars": ["warn", { "args": "none", "ignoreRestSiblings": true }], 26 | "nonblock-statement-body-position": "warn", 27 | "@typescript-eslint/no-unused-vars": "warn", 28 | "max-classes-per-file": ["warn", 3], 29 | "import/extensions": ["warn", "ignorePackages", { 30 | "ts": "never", 31 | "js": "never" 32 | }] 33 | }, 34 | "settings": { 35 | "import/resolver": { 36 | "node": { 37 | "extensions": [".js", ".ts", ".jsx", ".tsx"] 38 | } 39 | } 40 | }, 41 | "env": { 42 | "browser": true, 43 | "es2022": true 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /dist/icons/static/clear-night.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | -------------------------------------------------------------------------------- /dist/icons/static/cloudy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /dist/icons/animated/cloudy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /dist/icons/animated/partly-cloudy-day.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/css/css-base-card.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | const cardStyle = css` 4 | ha-card { 5 | cursor: pointer; 6 | position: relative; 7 | width: 100%; 8 | } 9 | 10 | .ha-card-weather-conditions { 11 | width: 100%; 12 | box-sizing: border-box; 13 | background-color: var(--card-background-color, #1c1c1c); 14 | color: var(--primary-text-color, #ffffff); 15 | border-radius: var(--ha-card-border-radius, 12px); 16 | box-shadow: var(--ha-card-box-shadow, 0 2px 6px rgba(0, 0, 0, 0.2)); 17 | overflow: hidden; 18 | padding: 0; 19 | display: flex; 20 | flex-direction: column; 21 | } 22 | 23 | .nd-container { 24 | width: 100%; 25 | box-sizing: border-box; 26 | display: flex; 27 | flex-direction: column; 28 | padding: 16px 20px; /* ← padding orizzontale più ampio */ 29 | gap: 12px; 30 | background-size: cover; 31 | background-position: center; 32 | transition: background-image 0.3s ease-in-out; 33 | } 34 | 35 | /* Esempio di stile dinamico aggiuntivo se habgImage è una classe */ 36 | .nd-container.sunny { 37 | background-image: url('/local/images/sunny-bg.jpg'); 38 | } 39 | 40 | .nd-container.rainy { 41 | background-image: url('/local/images/rainy-bg.jpg'); 42 | } 43 | 44 | /* -------------- */ 45 | 46 | `; 47 | 48 | export default cardStyle; 49 | -------------------------------------------------------------------------------- /dist/icons/animated/weather_sunset.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | -------------------------------------------------------------------------------- /dist/icons/static/weather_sunset.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | -------------------------------------------------------------------------------- /dist/icons/static/partly-cloudy-day.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /rollup.new.config.mjs: -------------------------------------------------------------------------------- 1 | import resolve from '@rollup/plugin-node-resolve'; // ✅ nuovo package 2 | import typescript from '@rollup/plugin-typescript'; // ✅ moderno 3 | import babel from '@rollup/plugin-babel'; 4 | import terser from '@rollup/plugin-terser'; // ✅ va destrutturato 5 | import execute from 'rollup-plugin-execute'; // ancora valido 6 | import commonjs from '@rollup/plugin-commonjs'; // 👈 nuovo import 7 | 8 | export default { 9 | input: 'src/ha-weather-ecard.ts', 10 | output: { 11 | //dir: './dist', 12 | file: 'dist/ha-card-weather-conditions.js', // 👈 nome file forzato 13 | format: 'esm', 14 | sourcemap: 'inline', 15 | banner: false, 16 | // comments: false 17 | }, 18 | plugins: [ 19 | resolve({ 20 | browser: true, // 👈 molto importante per card frontend 21 | exportConditions: ['browser'] 22 | }), 23 | commonjs(), // 👈 serve per convertire eventuali commonjs a es6 24 | typescript({ 25 | tsconfig: './tsconfig.json' 26 | }), 27 | babel({ 28 | babelHelpers: 'bundled', 29 | exclude: 'node_modules/**', 30 | extensions: ['.js', '.ts'] 31 | }), 32 | terser(), 33 | execute([ 34 | `echo "$(date '+%d/%m/%Y %H:%M:%S') rollup done." ; echo -e '\\007'` 35 | ]) 36 | ] 37 | }; 38 | -------------------------------------------------------------------------------- /dist/icons/animated/clear-night.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/templates/t-pollen.ts: -------------------------------------------------------------------------------- 1 | import { html } from 'lit'; 2 | 3 | export interface iPollenData { 4 | name: string; 5 | value: number; 6 | } 7 | 8 | const LEVEL_NAMES = ['basso', 'moderato', 'alto', 'molto-alto', 'estremo']; 9 | 10 | const getLevelIndex = (value: number, levelMin: number, levelMax: number): number => { 11 | const range = levelMax - levelMin + 1; 12 | const step = range / LEVEL_NAMES.length; 13 | const index = Math.floor((value - levelMin) / step); 14 | return Math.min(index, LEVEL_NAMES.length - 1); 15 | }; 16 | 17 | export const renderPollen = (data: iPollenData[], levelMin: number, levelMax: number) => { 18 | const numLevels = levelMax - levelMin + 1; 19 | const levels = LEVEL_NAMES.slice(0, numLevels); 20 | 21 | if (data.length === 0) { 22 | return html``; 23 | } 24 | 25 | return html` 26 |
27 | ${data.map((item) => { 28 | const activeIndex = getLevelIndex(item.value, levelMin, levelMax); 29 | return html` 30 |
31 |
32 | ${levels.map((levelName, index) => html` 33 |
37 | `)} 38 |
39 |
${item.name}
40 |
41 | `; 42 | })} 43 |
44 | `; 45 | }; 46 | -------------------------------------------------------------------------------- /dist/icons/static/rainy-4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /dist/icons/animated/partly-cloudy-night.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /dist/icons/static/partly-cloudy-night.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/css/css-pollen.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | const pollenStyle = css` 4 | .pollen-grid-container { 5 | display: grid; 6 | grid-template-columns: repeat(auto-fit, minmax(48px, 1fr)); 7 | gap: 8px 12px; 8 | width: 100%; 9 | justify-items: center; 10 | align-items: end; 11 | padding: 8px 4px; 12 | box-sizing: border-box; 13 | } 14 | 15 | 16 | .pollen-stack { 17 | display: flex; 18 | flex-direction: column; 19 | align-items: center; 20 | gap: 4px; 21 | min-width: 48px; 22 | } 23 | 24 | 25 | .levels { 26 | display: flex; 27 | flex-direction: column-reverse; 28 | gap: clamp(1px, 0.2vw, 2px); 29 | } 30 | 31 | .level { 32 | width: clamp(16px, 3.5vw, 24px); 33 | height: clamp(5px, 0.7vw, 8px); /* 👈 anche in altezza */ 34 | border-radius: 3px; 35 | opacity: 0.3; 36 | transition: opacity 0.2s ease; 37 | } 38 | 39 | .level.active { 40 | opacity: 1; 41 | outline: 1px solid #333; 42 | } 43 | 44 | .molto-alto { 45 | background-color: #f44336; 46 | } 47 | 48 | .alto { 49 | background-color: #ff9800; 50 | } 51 | 52 | .moderato { 53 | background-color: #ffeb3b; 54 | } 55 | 56 | .basso { 57 | background-color: #4caf50; 58 | } 59 | 60 | .pollen-name { 61 | font-size: clamp(0.55em, 1.3vw, 0.85em); /* 👈 stringe di più */ 62 | // font-weight: 500; 63 | text-align: center; 64 | // color: #333; 65 | white-space: nowrap; 66 | } 67 | 68 | .label { 69 | width: 100%; 70 | text-align: center; 71 | font-size: clamp(0.55em, 1.3vw, 0.85em); 72 | // font-weight: 500; 73 | margin-top: clamp(4px, 0.5vw, 8px); 74 | } 75 | `; 76 | 77 | export default pollenStyle; 78 | -------------------------------------------------------------------------------- /dist/icons/static/night.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/css/css-weather-forecast.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | const weatherForecastStyle = css` 4 | 5 | .weather-forecast-grid-container { 6 | display: grid; 7 | grid-template-columns: repeat(auto-fit, minmax(78px, 1fr)); 8 | column-gap: 2px; /* spazio orizzontale tra i giorni */ 9 | row-gap: 6px; /* spazio verticale tra righe, se ci sono */ 10 | align-items: stretch; 11 | font-family: 'Segoe UI', sans-serif; 12 | width: 100%; 13 | } 14 | 15 | .weather-forecast-grid-wrapper { 16 | display: flex; 17 | flex-direction: column; 18 | align-items: center; /* centrare il titolo orizzontalmente */ 19 | } 20 | 21 | .weather-forecast-title { 22 | font-size: clamp(0.85em, 1vw, 0.95em); 23 | font-weight: bold; 24 | // margin-bottom: 0.5em; 25 | text-align: center; 26 | } 27 | 28 | .weather-forecast-slot { 29 | text-align: center; 30 | padding: 8px 4px; 31 | min-width: 0; 32 | overflow: hidden; 33 | } 34 | 35 | .weather-forecast-slot:last-child { 36 | border-right: none; 37 | } 38 | 39 | .weather-forecast-label-slot { 40 | font-size: 0.9em; 41 | font-weight: bold; 42 | margin-bottom: 6px; /* ridotto */ 43 | } 44 | 45 | .weather-forecast-icon { 46 | font-size: 1.6rem; /* ridotto */ 47 | /* margin: 6px 0; ridotto */ 48 | height: 32px; 49 | } 50 | 51 | .weather-forecast-temperature { 52 | font-size: clamp(0.8em, 1vw, 0.9em); /* leggermente più piccolo */ 53 | margin: 4px 0; /* meno margine */ 54 | } 55 | 56 | .weather-forecast-temperature .high { 57 | font-weight: bold; 58 | } 59 | 60 | .weather-forecast-precipitation { 61 | font-size: clamp(0.65em, 1vw, 0.75em); 62 | line-height: 1.2; /* compatta verticalmente */ 63 | } 64 | 65 | .weather-forecast-precipitation .mm { 66 | font-weight: bold; 67 | } 68 | `; 69 | 70 | export default weatherForecastStyle; 71 | -------------------------------------------------------------------------------- /dist/icons/static/rainy-5.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /dist/icons/static/cloudy-original.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /dist/icons/static/haze.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /dist/icons/static/rainy-6.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /dist/icons/static/rainy-7.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /dist/icons/static/thunder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /dist/icons/animated/haze.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /dist/icons/animated/fog.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /dist/icons/static/fog.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/builder/b-summary.ts: -------------------------------------------------------------------------------- 1 | import { HomeAssistant } from 'custom-card-helpers/dist'; 2 | 3 | import renderWeatherSummary from '../templates/t-summary'; 4 | import { 5 | getEntityNumericValue, 6 | getEntityRawValue, 7 | getEntityUnit, 8 | translate, 9 | } from '../utils/helper'; 10 | 11 | import { getMoonIcon, getWeatherIcon } from '../utils/helper-render'; 12 | import { iPresentData } from '../utils/config-schema'; 13 | import { iIconsConfig, iTerms } from '../base/lovelace-base'; 14 | 15 | const buildWeatherSummary = ( 16 | hass: HomeAssistant, 17 | language: string, 18 | terms: iTerms, 19 | iconsConfig: iIconsConfig, 20 | name: string, 21 | presentData: iPresentData, 22 | sunId: string, 23 | moonphase: string, 24 | ) => { 25 | const moonPhase = getEntityRawValue(hass, moonphase); 26 | const moonIcon: string = moonPhase ? getMoonIcon(moonPhase) : ''; 27 | const sun = getEntityRawValue(hass, sunId); 28 | const currentConditions = getEntityRawValue(hass, presentData.condition)?.toLowerCase() || 'na'; 29 | // eslint-disable-next-line max-len 30 | const temperature = presentData.temperature ? getEntityNumericValue({ entityId: presentData.temperature, hass, lang: language }) ?? undefined : undefined; 31 | // eslint-disable-next-line max-len 32 | const temperatureFeelsLike = presentData.temperature_feelslike ? getEntityNumericValue({ entityId: presentData.temperature_feelslike, hass, lang: language }) ?? undefined : undefined; 33 | const temperatureFeelsLikeIcon = hass.states[presentData.temperature_feelslike]?.attributes.icon ?? ''; 34 | 35 | return renderWeatherSummary({ 36 | title: name ?? undefined, // 'Verkhnenovokutlumbetyevo', 37 | moonText: (moonphase ? translate(moonPhase, terms.words) : undefined), 38 | moonIcon, 39 | conditionText: currentConditions, 40 | conditionIcon: getWeatherIcon(currentConditions, iconsConfig, sun), 41 | temperature, 42 | temperatureUnit: getEntityUnit(hass, presentData.temperature), 43 | feelsLikeTerm: translate('Feels Like', terms.words), 44 | temperatureFeelsLike, 45 | temperatureFeelsLikeIcon, 46 | }); 47 | }; 48 | 49 | export default buildWeatherSummary; 50 | -------------------------------------------------------------------------------- /dist/icons/static/snowy-4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ha-card-weather-conditions", 3 | "version": "2.0.0", 4 | "description": "Home Assistant lovelace card for display weather data.", 5 | "keywords": [ 6 | "home-assistant", 7 | "homeassistant", 8 | "hass", 9 | "automation", 10 | "lovelace", 11 | "custom-cards", 12 | "weather" 13 | ], 14 | "homepage": "https://github.com/r-renato/ha-card-weather-conditions#readme", 15 | "module": "ha-card-weather-conditions.js", 16 | "repository": { 17 | "type": "git", 18 | "url": "git+ssh://git@github.com/r-renato/ha-card-weather-conditions.git" 19 | }, 20 | "author": "Renato Rossi", 21 | "license": "MIT", 22 | "dependencies": { 23 | "@material/mwc-select": "^0.27.0", 24 | "@material/mwc-textfield": "^0.27.0", 25 | "color": "^4.2.3", 26 | "custom-card-helpers": "^1.0.8", 27 | "hammerjs": "^2.0.8", 28 | "home-assistant-js-websocket": "^9.4.0", 29 | "lit": "^3.2.1", 30 | "memoize-one": "^6.0.0", 31 | "object-hash": "^3.0.0", 32 | "sortablejs": "^1.15.6", 33 | "superstruct": "^2.0.2" 34 | }, 35 | "devDependencies": { 36 | "@babel/core": "^7.24.0", 37 | "@rollup/plugin-babel": "^6.0.4", 38 | "@rollup/plugin-commonjs": "^28.0.3", 39 | "@rollup/plugin-json": "^6.1.0", 40 | "@rollup/plugin-node-resolve": "^15.2.3", 41 | "@rollup/plugin-terser": "^0.4.4", 42 | "@rollup/plugin-typescript": "^11.1.5", 43 | "@typescript-eslint/eslint-plugin": "^6.21.0", 44 | "@typescript-eslint/parser": "^6.21.0", 45 | "eslint": "^8.56.0", 46 | "eslint-config-airbnb-base": "^15.0.0", 47 | "eslint-plugin-import": "^2.29.1", 48 | "prettier": "^3.2.5", 49 | "rollup": "^4.12.0", 50 | "rollup-plugin-execute": "^1.1.1", 51 | "typescript": "5.3.3" 52 | }, 53 | "bugs": { 54 | "url": "https://github.com/r-renato/ha-card-weather-conditions/issues" 55 | }, 56 | "main": "index.js", 57 | "scripts": { 58 | "watch": "rollup -c --watch", 59 | "build": "npm run lint && npm run rollup -- --config rollup.config.mjs", 60 | "build:new": "npm run lint && npm run rollup -- --config rollup.new.config.mjs", 61 | "lint": "eslint src/*.ts", 62 | "rollup": "rollup --no-compact " 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /dist/icons/static/cloudy-night-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /dist/icons/static/cloudy-night-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /dist/icons/static/cloudy-night-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /dist/icons/static/fair-night.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/css/css-ultraviolet.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | 3 | const ultravioletStyle = css` 4 | .ultraviolet-grid-container { 5 | display: flex; 6 | flex-direction: column; 7 | gap: 4px; 8 | } 9 | 10 | .ultraviolet-row { 11 | display: flex; 12 | justify-content: space-between; 13 | gap: 16px; 14 | } 15 | 16 | .ultraviolet-left, 17 | .present-right { 18 | flex: 1; 19 | } 20 | 21 | .ultraviolet-left { 22 | display: flex; 23 | justify-content: flex-start; 24 | } 25 | 26 | .ultraviolet-right { 27 | display: flex; 28 | justify-content: flex-end; 29 | } 30 | 31 | .ultraviolet-value-block { 32 | display: flex; 33 | align-items: center; 34 | gap: 4px; 35 | } 36 | 37 | .ultraviolet-unit { 38 | font-size: 0.9em; 39 | opacity: 0.8; 40 | } 41 | 42 | ------------------------------------------------------------------ 43 | 44 | // .ultraviolet-grid-container { 45 | // display: flex; 46 | // flex-direction: column; 47 | // gap: 12px; 48 | // } 49 | 50 | // .ultraviolet-row { 51 | // display: flex; 52 | // justify-content: space-between; 53 | // padding: 4px 0; 54 | // } 55 | 56 | // .ultraviolet-value-block { 57 | // display: flex; 58 | // align-items: center; 59 | // gap: 4px; 60 | // } 61 | 62 | // .ultraviolet-unit { 63 | // font-size: 0.9em; 64 | // opacity: 0.7; 65 | // } 66 | 67 | .ultraviolet-skin-type-grid { 68 | display: grid; 69 | grid-template-columns: repeat(auto-fit, minmax(48px, 1fr)); 70 | gap: 8px; 71 | margin-top: 8px; 72 | } 73 | 74 | .ultraviolet-skin-type-cell { 75 | flex: 1; 76 | min-width: 48px; 77 | height: 48px; 78 | display: flex; 79 | flex-direction: column; 80 | justify-content: center; 81 | align-items: center; 82 | border-radius: 6px; 83 | font-family: 'Segoe UI', sans-serif; 84 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); 85 | color: black; 86 | } 87 | 88 | .ultraviolet-skin-type-label { 89 | font-weight: bold; 90 | font-size: 0.95em; 91 | line-height: 1em; 92 | } 93 | 94 | .ultraviolet-exposure-time { 95 | font-size: 0.75em; 96 | margin-top: 2px; 97 | color: #222; 98 | opacity: 0.85; 99 | } 100 | 101 | 102 | 103 | 104 | 105 | 106 | `; 107 | 108 | export default ultravioletStyle; 109 | -------------------------------------------------------------------------------- /src/iconmodels/im-buienradar.ts: -------------------------------------------------------------------------------- 1 | // clear=ok, partlycloudy=ok, cloudy=ok, partlycloudy-fog=ok, partlycloudy-light-rain=ok, partlycloudy-rain=ok, 2 | // light-rain=ok, rainy=ok, snowy-rainy=ok, partlycloudy-light-snow=ok, partlycloudy-snow=ok, light-snow=ok, snowy=ok, 3 | // partlycloudy-lightning=ok or lightning 4 | 5 | export const cwcBuienradarDayIcons: { [key: string]: string; } = { 6 | // freezing_rain_heavy: 'rainy-3', 7 | // freezing_rain: 'rainy-2', 8 | // freezing_rain_light: 'rainy-1', 9 | // freezing_drizzle: 'rain-and-sleet-mix', 10 | // ice_pellets_heavy: 'rain-and-snow-mix', 11 | // ice_pellets: 'rain-and-snow-mix', 12 | // ice_pellets_light: 'rain-and-snow-mix', 13 | snowy: 'snowy-3', 14 | 'light-snow': 'snowy-2', 15 | 'snowy-rainy': 'snowy-1', 16 | 'partlycloudy-light-snow': 'snowy-1', 17 | 'partlycloudy-snow': 'snowy-1', 18 | // flurries: 'wind', 19 | // tstorm: 'tropical-storm', 20 | // rain_heavy: 'rainy-3', 21 | 'partlycloudy-light-rain': 'rainy-1', 22 | 'light-rain': 'rainy-1', 23 | rainy: 'rainy-2', 24 | 'partlycloudy-rain': 'rainy-1', 25 | // fog_light: 'haze', 26 | 'partlycloudy-fog': 'fog', 27 | cloudy: 'cloudy-original', 28 | // mostly_cloudy: 'cloudy-day-3', 29 | partlycloudy: 'cloudy-day-2', 30 | 'partlycloudy-lightning': 'cloudy-day-1', 31 | lightning: 'cloudy-day-1', 32 | // mostly_clear: 'cloudy-day-1', 33 | clear: 'day', 34 | }; 35 | 36 | export const cwcBuienradarNightIcons: { [key: string]: string; } = { 37 | ...cwcBuienradarDayIcons, 38 | // freezing_rain_heavy: 'rainy-6', 39 | // freezing_rain: 'rainy-5', 40 | // freezing_rain_light: 'rainy-4', 41 | // freezing_drizzle: 'rain-and-sleet-mix', 42 | // ice_pellets_heavy: 'rain-and-snow-mix', 43 | // ice_pellets: 'rain-and-snow-mix', 44 | // ice_pellets_light: 'rain-and-snow-mix', 45 | // snow_heavy: 'snowy-6', 46 | // snow: 'nowy-5', 47 | // snow_light: 'nowy-4', 48 | // flurries: 'wind', 49 | // tstorm: 'tropical-storm', 50 | // rain_heavy: 'rainy-6', 51 | // rain_light: 'rainy-4', 52 | // rain: 'rainy-5', 53 | // drizzle: 'rainy-4', 54 | // fog_light: 'haze', 55 | // fog: 'fog', 56 | // cloudy: 'cloudy', 57 | // mostly_cloudy: 'cloudy-night-3', 58 | // partly_cloudy: 'cloudy-night-2', 59 | // mostly_clear: 'cloudy-night-1', 60 | // clear: 'night' 61 | }; 62 | -------------------------------------------------------------------------------- /src/utils/colors.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | import * as Color from 'color'; 3 | 4 | export const COLORS = [ 5 | 'primary', 6 | 'accent', 7 | 'red', 8 | 'pink', 9 | 'purple', 10 | 'deep-purple', 11 | 'indigo', 12 | 'blue', 13 | 'light-blue', 14 | 'cyan', 15 | 'teal', 16 | 'green', 17 | 'light-green', 18 | 'lime', 19 | 'yellow', 20 | 'amber', 21 | 'orange', 22 | 'deep-orange', 23 | 'brown', 24 | 'light-grey', 25 | 'grey', 26 | 'dark-grey', 27 | 'blue-grey', 28 | 'black', 29 | 'white', 30 | 'disabled', 31 | ]; 32 | 33 | export function computeRgbColor(color: string): string { 34 | if (color === 'primary' || color === 'accent') { 35 | return `var(--rgb-${color}-color)`; 36 | } 37 | if (COLORS.includes(color)) { 38 | return `var(--rgb-${color})`; 39 | // eslint-disable-next-line no-else-return 40 | } else if (color.startsWith('#')) { 41 | try { 42 | return Color.rgb(color).rgb().array().join(', '); 43 | } catch (err) { 44 | return ''; 45 | } 46 | } 47 | return color; 48 | } 49 | 50 | function capitalizeFirstLetter(string) { 51 | return string.charAt(0).toUpperCase() + string.slice(1); 52 | } 53 | 54 | export function computeColorName(color: string): string { 55 | return color 56 | .split('-') 57 | .map((s) => capitalizeFirstLetter(s)) 58 | .join(' '); 59 | } 60 | 61 | export const defaultColorCss = css` 62 | --default-red: 244, 67, 54; 63 | --default-pink: 233, 30, 99; 64 | --default-purple: 146, 107, 199; 65 | --default-deep-purple: 110, 65, 171; 66 | --default-indigo: 63, 81, 181; 67 | --default-blue: 33, 150, 243; 68 | --default-light-blue: 3, 169, 244; 69 | --default-cyan: 0, 188, 212; 70 | --default-teal: 0, 150, 136; 71 | --default-green: 76, 175, 80; 72 | --default-light-green: 139, 195, 74; 73 | --default-lime: 205, 220, 57; 74 | --default-yellow: 255, 235, 59; 75 | --default-amber: 255, 193, 7; 76 | --default-orange: 255, 152, 0; 77 | --default-deep-orange: 255, 111, 34; 78 | --default-brown: 121, 85, 72; 79 | --default-light-grey: 189, 189, 189; 80 | --default-grey: 158, 158, 158; 81 | --default-dark-grey: 96, 96, 96; 82 | --default-blue-grey: 96, 125, 139; 83 | --default-black: 0, 0, 0; 84 | --default-white: 255, 255, 255; 85 | --default-disabled: 189, 189, 189; 86 | `; 87 | 88 | export const defaultDarkColorCss = css` 89 | --default-disabled: 111, 111, 111; 90 | `; 91 | -------------------------------------------------------------------------------- /src/utils/helper-render.ts: -------------------------------------------------------------------------------- 1 | import { css } from 'lit'; 2 | // import { HomeAssistant } from 'custom-card-helpers/dist'; 3 | 4 | import { cwcMoonPhaseIcons } from '../../backup/ha-cwc-consts'; 5 | 6 | import cardStyle from '../css/css-base-card'; 7 | import summaryStyles from '../css/css-summary'; 8 | import presentStyle from '../css/css-present'; 9 | import ultravioletStyle from '../css/css-ultraviolet'; 10 | import pollenStyle from '../css/css-pollen'; 11 | import cameraStyle from '../css/css-camera'; 12 | import { iIconsConfig } from '../base/lovelace-base'; 13 | import weatherForecastStyle from '../css/css-weather-forecast'; 14 | import meteodcpalarmStyle from '../css/css-meteoalarm'; 15 | 16 | export const getMoonIcon = (phase: string): string => cwcMoonPhaseIcons[phase.toLowerCase()]; 17 | 18 | export const getWeatherIcon = ( 19 | condition: string, 20 | iconsConfig: iIconsConfig, 21 | sunState: string, 22 | ): string => { 23 | const isNight = sunState === 'below_horizon'; 24 | const iconMap = isNight ? iconsConfig.iconsNight : iconsConfig.iconsDay; 25 | const iconName = iconMap[condition]; 26 | 27 | if (!iconsConfig.path) { 28 | console.info('Image path not found.'); 29 | } 30 | 31 | if (!iconName) { 32 | console.info( 33 | `Icons issue. Model=${iconsConfig.icons_model}, Time=${isNight ? 'night' : 'day'}, Condition=${condition}`, 34 | ); 35 | return ''; 36 | } 37 | 38 | return `${iconsConfig.path}/${iconsConfig.iconType}/${iconName}.svg`; 39 | }; 40 | 41 | // export const getSensorUnit = (hass: HomeAssistant, measure: string): string => { 42 | // const lengthUnit = hass.config.unit_system.length; 43 | 44 | // const unitOverrides: Record = { 45 | // air_pressure: lengthUnit === 'km' ? 'hPa' : 'inHg', 46 | // precipitation: lengthUnit === 'km' ? 'mm' : 'in', 47 | // length: lengthUnit, 48 | // }; 49 | 50 | // if (measure in unitOverrides) { 51 | // return unitOverrides[measure]; 52 | // } 53 | 54 | // const unit = (hass.config.unit_system as Record)[measure]; 55 | 56 | // if (unit !== undefined) { 57 | // return unit; 58 | // } 59 | 60 | // console.warn(`Unit for '${measure}' not found in hass.config.unit_system.`); 61 | // return ''; 62 | // }; 63 | 64 | export const getCardStyles = () => css` 65 | ${cardStyle} 66 | ${summaryStyles} 67 | ${presentStyle} 68 | ${weatherForecastStyle} 69 | ${ultravioletStyle} 70 | ${pollenStyle} 71 | ${cameraStyle} 72 | ${meteodcpalarmStyle} 73 | `; 74 | -------------------------------------------------------------------------------- /dist/icons/static/rain-and-sleet-mix.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /dist/icons/animated/rainy-4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /dist/icons/static/rain-and-snow-mix.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /dist/icons/animated/rain.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /dist/icons/static/rain.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /dist/icons/static/day.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /dist/icons/static/snowy-5.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /dist/icons/animated/wind.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/builder/b-ultraviolet.ts: -------------------------------------------------------------------------------- 1 | import { HomeAssistant } from 'custom-card-helpers/dist'; 2 | 3 | import { getEntityNumericValue, getEntityRawValue, pad } from '../utils/helper'; 4 | import renderUltraviolet from '../templates/t-ultraviolet'; 5 | import { iUltraviolet } from '../utils/config-schema'; 6 | 7 | // const getRawValue = (hass: HomeAssistant, entityId?: string): string | undefined => entityId && hass.states[entityId]?.state; 8 | // const getValue = (hass: HomeAssistant, entityId?: string, lang: string = 'en', decimals = 0): string | undefined => { 9 | // const state = entityId && hass.states[entityId]?.state; 10 | // return state !== undefined ? formatNumber(state, lang, decimals) : undefined; 11 | // }; 12 | 13 | const getTime = (state?: string | number): string => { 14 | const value = typeof state === 'string' && state.toLowerCase() === 'unknown' 15 | ? NaN 16 | : Number(state); 17 | // console.debug(state); 18 | if (!Number.isFinite(value) || value < 0) return '--'; 19 | 20 | const hours = Math.floor(value / 60); 21 | const minutes = value % 60; 22 | 23 | return hours > 0 24 | ? `${hours}:${pad(minutes, 2)} h` 25 | : `${minutes} m`; 26 | }; 27 | 28 | const summaryData = (hass: HomeAssistant, lang: string, uv: iUltraviolet) => ({ 29 | protectionWindow: { 30 | value: (!getEntityRawValue(hass, uv.protection_window) || getEntityRawValue(hass, uv.protection_window) === 'unknown' ? 'off' : 31 | getEntityRawValue(hass, uv.protection_window) 32 | ), 33 | icon: 'mdi:sunglasses', 34 | }, 35 | currentUVLevel: { value: getEntityRawValue(hass, uv.uv_level), icon: 'mdi:weather-sunny' }, 36 | currentUVIndex: { value: getEntityNumericValue({ entityId: uv.uv_index, hass, lang }), unit: 'UV Idx', icon: 'mdi:weather-sunny' }, 37 | maxUVIndex: { value: getEntityNumericValue({ entityId: uv.max_uv_index, hass, lang }), unit: 'UV Idx', icon: 'mdi:weather-sunny' }, 38 | currentOzoneLevel: { value: getEntityNumericValue({ entityId: uv.ozone_level, hass, lang }), unit: 'DU', icon: 'mdi:vector-triangle' }, 39 | }); 40 | 41 | const skinData = (hass: HomeAssistant, lang: string, uv: iUltraviolet) => ({ 42 | skinType1: { value: getTime(getEntityNumericValue({ entityId: uv.set_skin_type_1, hass, lang })) }, 43 | skinType2: { value: getTime(getEntityNumericValue({ entityId: uv.set_skin_type_2, hass, lang })) }, 44 | skinType3: { value: getTime(getEntityNumericValue({ entityId: uv.set_skin_type_3, hass, lang })) }, 45 | skinType4: { value: getTime(getEntityNumericValue({ entityId: uv.set_skin_type_4, hass, lang })) }, 46 | skinType5: { value: getTime(getEntityNumericValue({ entityId: uv.set_skin_type_5, hass, lang })) }, 47 | skinType6: { value: getTime(getEntityNumericValue({ entityId: uv.set_skin_type_6, hass, lang })) }, 48 | }); 49 | 50 | const buildUltraviolet = (hass: HomeAssistant, lang: string, uv: iUltraviolet) => 51 | // eslint-disable-next-line implicit-arrow-linebreak 52 | renderUltraviolet({ ...summaryData(hass, lang, uv) }, { ...skinData(hass, lang, uv) }); 53 | 54 | export default buildUltraviolet; 55 | -------------------------------------------------------------------------------- /dist/icons/static/severe-thunderstorm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # HA (Lovelace) Card Weather Conditions 2 | 3 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 4 | and this project adheres to [Semantic Versioning](http://semver.org/). 5 | 6 | ## [2.0.1] 2025-06-08 7 | ### Fixed 8 | 9 | ### Added 10 | - ru locale 11 | 12 | ### Changed 13 | - nl locale 14 | 15 | ## [2.0.0] 2025-06-08 16 | ### Changed 17 | - Readme and PNG image 18 | - Fully reengineered the card 19 | - Czech locale 20 | 21 | ### Changed 22 | - Update Spanish locale 23 | 24 | ## [1.9.12] 2021-01-29 25 | ### Fixed 26 | - Minor bug fixing 27 | 28 | ## [1.9.11] 2021-01-29 29 | ### Fixed 30 | - Minor bug fixing 31 | 32 | ## [1.9.10] 2021-01-24 33 | ### Changed 34 | Update ClimaCel icons map 35 | 36 | ## [1.9.9] 2021-01-11 37 | ### Added 38 | - Norwegian locale 39 | 40 | ## [1.9.8] 2021-01-07 41 | ### Added 42 | - Danish locale 43 | 44 | ## [1.9.7] 2020-12-06 45 | ### Fixed 46 | - Fixed the snow icon name for the night time (climacell, darksky, openweathermap) 47 | 48 | ## [1.9.6] 2020-08-17 49 | ### Fixed 50 | - German locale, fix for "Feels Like" word 51 | 52 | ## [1.9.6] 2020-08-08 53 | ### Added 54 | - Icon model for: buienradar, defaulthass 55 | 56 | ## [1.9.5] 2020-08-08 57 | ### Fixed 58 | - Documentation 59 | 60 | ## [1.9.5] 2020-07-21 61 | ### Added 62 | - Errors catch and display while loading translations files 63 | 64 | ## [1.9.4] 2020-07-19 65 | ### Fixed 66 | - Minor bug fixing 67 | 68 | ## [1.9.3] 2020-07-18 69 | ### Changed 70 | - Exposition time change from hours to minutes 71 | 72 | ## [1.9.2] 2020-07-10 73 | ### Fixed 74 | - Minor bug fixing 75 | 76 | ## [1.9.1] 2020-06-22 77 | ### Added 78 | - Added icon override mode for the pollen layer 79 | 80 | ## [1.9.0] 2020-06-21 81 | ### Fixed 82 | - Minor bug fixing 83 | 84 | ### Added 85 | - Add `sea` Weather Forecast session 86 | 87 | ## [1.8.1] 2020-06-15 88 | ### Fixed 89 | - Minor bug fixing 90 | 91 | ## [1.8.0] 2020-06-15 92 | ### Fixed 93 | - Minor bug fixing 94 | 95 | ### Changed 96 | - Internationalization model 97 | 98 | ### Added 99 | - Add `pt` language 100 | - Add Alert Layer 101 | 102 | ### Changed 103 | ## [1.7.1] 2020-05-24 104 | ### Fixed 105 | - Minor bug fixing 106 | 107 | ## [1.7.0] 2020-05-23 108 | ### Fixed 109 | - Minor bug fixing 110 | 111 | ### Added 112 | - Add `sr-latn` language 113 | 114 | ## [1.6.0] 2020-05-22 115 | ### Added 116 | - Add `fr` language 117 | 118 | ## [1.5.1] 2020-05-21 119 | ### Fixed 120 | - Minor bug fixing 121 | 122 | ## [1.5.0] 2020-05-14 123 | ### Fixed 124 | - Minor bug fixing 125 | ### Added 126 | - Add `uv` (ultraviolet) session 127 | 128 | ## [1.4.0] 2020-05-13 129 | ### Added 130 | - Add `es` language 131 | 132 | ## [1.3.1] 2020-05-13 133 | ### Fixed 134 | - Minor bug fixing 135 | 136 | ## [1.3.0] 2020-05-10 137 | ### Added 138 | - Add moon phase 139 | 140 | ## [1.2.0] 2020-05-08 141 | ### Added 142 | - Add NL (Dutch) language 143 | 144 | ## [1.1.0] 2020-05-07 145 | ### Added 146 | - Add feels_like sensor 147 | 148 | ## [1.0.1] 2020-05-07 149 | ### Fixed 150 | - Minor bug fixing 151 | 152 | ## [1.0.0] 2020-05-03 153 | - Initial stable version -------------------------------------------------------------------------------- /dist/icons/animated/snow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | Layer 1 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /dist/icons/static/cloudy-day-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /dist/icons/static/cloudy-day-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /dist/icons/static/cloudy-day-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /dist/icons/static/fair-day.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/iconmodels/im-climacell.ts: -------------------------------------------------------------------------------- 1 | export const cwcClimacellDayIcons: { [key: string]: string; } = { 2 | freezing_rain_heavy: 'rainy-3', 3 | 'heavy freezing rain': 'rainy-3', 4 | freezing_rain: 'rainy-2', 5 | 'freezing rain': 'rainy-2', 6 | freezing_rain_light: 'rainy-1', 7 | 'light freezing rain': 'rainy-1', 8 | freezing_drizzle: 'rain-and-sleet-mix', 9 | 'freezing drizzle': 'rain-and-sleet-mix', 10 | ice_pellets_heavy: 'rain-and-snow-mix', 11 | 'heavy ice pellets': 'rain-and-snow-mix', 12 | ice_pellets: 'rain-and-snow-mix', 13 | 'ice pellets': 'rain-and-snow-mix', 14 | ice_pellets_light: 'rain-and-snow-mix', 15 | 'light ice pellets': 'rain-and-snow-mix', 16 | snow_heavy: 'snowy-3', 17 | 'heavy snow': 'snowy-3', 18 | snow: 'snowy-2', 19 | snow_light: 'snowy-1', 20 | 'light snow': 'snowy-1', 21 | flurries: 'wind', 22 | tstorm: 'tropical-storm', 23 | rain_heavy: 'rainy-3', 24 | 'heavy rain': 'rainy-3', 25 | rain_light: 'rainy-1', 26 | 'light rain': 'rainy-1', 27 | rain: 'rainy-2', 28 | drizzle: 'rainy-1', 29 | fog_light: 'haze', 30 | 'light fog': 'haze', 31 | fog: 'fog', 32 | cloudy: 'cloudy-original', 33 | mostly_cloudy: 'cloudy-day-3', 34 | 'mostly cloudy': 'cloudy-day-3', 35 | partly_cloudy: 'cloudy-day-2', 36 | 'partly cloudy': 'cloudy-day-2', 37 | mostly_clear: 'cloudy-day-1', 38 | 'mostly clear': 'cloudy-day-1', 39 | clear: 'day', 40 | }; 41 | 42 | export const cwcClimacellNightIcons: { [key: string]: string; } = { 43 | ...cwcClimacellDayIcons, 44 | freezing_rain_heavy: 'rainy-6', 45 | 'heavy freezing rain': 'rainy-6', 46 | freezing_rain: 'rainy-5', 47 | 'freezing rain': 'rainy-5', 48 | freezing_rain_light: 'rainy-4', 49 | 'light freezing rain': 'rainy-4', 50 | // freezing_drizzle: 'rain-and-sleet-mix', 51 | // ice_pellets_heavy: 'rain-and-snow-mix', 52 | // ice_pellets: 'rain-and-snow-mix', 53 | // ice_pellets_light: 'rain-and-snow-mix', 54 | snow_heavy: 'snowy-6', 55 | 'heavy snow': 'snowy-6', 56 | snow: 'snowy-5', 57 | snow_light: 'snowy-4', 58 | 'light snow': 'snowy-4', 59 | // flurries: 'wind', 60 | // tstorm: 'tropical-storm', 61 | rain_heavy: 'rainy-6', 62 | 'heavy rain': 'rainy-6', 63 | rain_light: 'rainy-4', 64 | 'light rain': 'rainy-4', 65 | rain: 'rainy-5', 66 | drizzle: 'rainy-4', 67 | // fog_light: 'haze', 68 | // fog: 'fog', 69 | // cloudy: 'cloudy', 70 | mostly_cloudy: 'cloudy-night-3', 71 | 'mostly cloudy': 'cloudy-night-3', 72 | partly_cloudy: 'cloudy-night-2', 73 | 'partly cloudy': 'cloudy-night-2', 74 | mostly_clear: 'cloudy-night-1', 75 | 'mostly clear': 'cloudy-night-1', 76 | clear: 'night', 77 | sunny: 'night', 78 | }; 79 | 80 | export const cwcClimacellDayBg: { [key: string]: string; } = { 81 | freezing_rain_heavy: 'rainy-3', 82 | freezing_rain: 'rainy-2', 83 | freezing_rain_light: 'rainy-1', 84 | freezing_drizzle: 'rain-and-sleet-mix', 85 | ice_pellets_heavy: 'rain-and-snow-mix', 86 | ice_pellets: 'rain-and-snow-mix', 87 | ice_pellets_light: 'rain-and-snow-mix', 88 | snow_heavy: 'snowy-3', 89 | snow: 'snowy-2', 90 | snow_light: 'snowy-1', 91 | flurries: 'wind', 92 | tstorm: 'tropical-storm', 93 | rain_heavy: 'rainy-3', 94 | rain_light: 'rainy-1', 95 | rain: 'rainy-2', 96 | drizzle: 'rainy-1', 97 | fog_light: 'haze', 98 | fog: 'fog', 99 | cloudy: 'cloudy-original', 100 | mostly_cloudy: 'day-cloud-3.jpg', 101 | partly_cloudy: 'day-cloud-2.jpg', 102 | mostly_clear: 'day-cloud-1.jpg', 103 | clear: 'day-clear.jpg', 104 | }; 105 | -------------------------------------------------------------------------------- /src/iconmodels/im-pirateweather.ts: -------------------------------------------------------------------------------- 1 | // Pirate Weather Icons 2 | // clear-day, clear-night, rain, snow, sleet, wind, fog, cloudy, partly-cloudy-day and partly-cloudy-night 3 | // mostly-clear-day, mostly-clear-night, mostly-cloudy-day, mostly-cloudy-night, possible-rain-day, possible-rain-night 4 | // possible-snow-day, possible-snow-night, possible-sleet-day, possible-sleet-night, possible-precipitation-day 5 | // possible-precipitation-night, precipitation, drizzle, light-rain, heavy-rain, flurries, light-snow, heavy-snow 6 | // very-light-sleet, light-sleet, heavy-sleet, breezy, dangerous-wind 7 | 8 | export const cwcDaytimePirateWeatherIcons: { [key: string]: string; } = { 9 | freezing_rain_heavy: 'rainy-3', 10 | 'heavy freezing rain': 'rainy-3', 11 | freezing_rain: 'rainy-2', 12 | 'freezing rain': 'rainy-2', 13 | freezing_rain_light: 'rainy-1', 14 | 'light freezing rain': 'rainy-1', 15 | freezing_drizzle: 'rain-and-sleet-mix', 16 | sleet: 'rain-and-sleet-mix', 17 | 'freezing drizzle': 'rain-and-sleet-mix', 18 | ice_pellets_heavy: 'rain-and-snow-mix', 19 | 'heavy ice pellets': 'rain-and-snow-mix', 20 | ice_pellets: 'rain-and-snow-mix', 21 | 'ice pellets': 'rain-and-snow-mix', 22 | ice_pellets_light: 'rain-and-snow-mix', 23 | 'light ice pellets': 'rain-and-snow-mix', 24 | snow_heavy: 'snowy-3', 25 | 'heavy snow': 'snowy-3', 26 | snow: 'snowy-2', 27 | snow_light: 'snowy-1', 28 | 'light snow': 'snowy-1', 29 | flurries: 'wind', 30 | tstorm: 'tropical-storm', 31 | rain_heavy: 'rainy-3', 32 | 'heavy rain': 'rainy-3', 33 | rain_light: 'rainy-1', 34 | rainy: 'rainy-1', 35 | 'light rain': 'rainy-1', 36 | rain: 'rainy-2', 37 | drizzle: 'rainy-1', 38 | fog_light: 'haze', 39 | 'light fog': 'haze', 40 | fog: 'fog', 41 | cloudy: 'cloudy-original', 42 | mostly_cloudy: 'cloudy-day-3', 43 | 'mostly cloudy': 'cloudy-day-3', 44 | partly_cloudy: 'cloudy-day-2', 45 | partlycloudy: 'cloudy-day-2', 46 | 'partly-cloudy-day': 'cloudy-day-2', 47 | 'partly cloudy': 'cloudy-day-2', 48 | mostly_clear: 'cloudy-day-1', 49 | 'mostly clear': 'cloudy-day-1', 50 | clear: 'day', 51 | 'clear-day': 'day', 52 | wind: 'wind', 53 | windy: 'wind', 54 | sunny: 'day', 55 | 'clear-night': 'day', 56 | }; 57 | 58 | export const cwcNightlyPirateWeaterIcons: { [key: string]: string; } = { 59 | ...cwcDaytimePirateWeatherIcons, 60 | freezing_rain_heavy: 'rainy-6', 61 | 'heavy freezing rain': 'rainy-6', 62 | freezing_rain: 'rainy-5', 63 | 'freezing rain': 'rainy-5', 64 | freezing_rain_light: 'rainy-4', 65 | 'light freezing rain': 'rainy-4', 66 | // freezing_drizzle: 'rain-and-sleet-mix', 67 | // ice_pellets_heavy: 'rain-and-snow-mix', 68 | // ice_pellets: 'rain-and-snow-mix', 69 | // ice_pellets_light: 'rain-and-snow-mix', 70 | snow_heavy: 'snowy-6', 71 | 'heavy snow': 'snowy-6', 72 | snow: 'snowy-5', 73 | snow_light: 'snowy-4', 74 | 'light snow': 'snowy-4', 75 | // flurries: 'wind', 76 | // tstorm: 'tropical-storm', 77 | rain_heavy: 'rainy-6', 78 | 'heavy rain': 'rainy-6', 79 | rain_light: 'rainy-4', 80 | 'light rain': 'rainy-4', 81 | rain: 'rainy-5', 82 | drizzle: 'rainy-4', 83 | // fog_light: 'haze', 84 | // fog: 'fog', 85 | // cloudy: 'cloudy', 86 | mostly_cloudy: 'cloudy-night-3', 87 | 'mostly cloudy': 'cloudy-night-3', 88 | partly_cloudy: 'cloudy-night-2', 89 | partlycloudy: 'cloudy-night-2', 90 | 'partly-cloudy-night': 'cloudy-night-2', 91 | 'partly cloudy': 'cloudy-night-2', 92 | mostly_clear: 'cloudy-night-1', 93 | 'mostly clear': 'cloudy-night-1', 94 | clear: 'night', 95 | 'clear-night': 'night', 96 | sunny: 'night', 97 | }; 98 | -------------------------------------------------------------------------------- /dist/icons/static/rainy-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /dist/icons/animated/rainy-5.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /dist/icons/static/snow-and-sleet-mix.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /dist/icons/static/isolated-thunderstorms.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /dist/icons/static/scattered-thunderstorms.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /dist/icons/static/snowy-6.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /dist/icons/static/tropical-storm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /dist/icons/static/rainy-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /dist/icons/static/rainy-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/builder/b-airquality.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | /* eslint-disable no-else-return */ 3 | /* eslint-disable object-curly-newline */ 4 | import { HomeAssistant } from 'custom-card-helpers/dist'; 5 | import { iAirQuality } from '../utils/config-schema'; 6 | import { getEntityNumericValue, getEntityRawValue, getEntityUnit } from '../utils/helper'; 7 | import { renderWeatherPresent } from '../templates/t-present'; 8 | 9 | /** 10 | * Restituisce un colore (in formato hex) in base al valore dell'indice EPA AQI. 11 | * @param {number} aqi - Valore AQI compreso tra 0 e 500 12 | * @returns {string} - Colore esadecimale associato alla fascia AQI 13 | */ 14 | function getAQIColor(aqi: number): string { 15 | if (aqi <= 50) { 16 | return '#009966'; // Verde (Buona) 17 | } else if (aqi <= 100) { 18 | return '#ffde33'; // Giallo (Moderata) 19 | } else if (aqi <= 150) { 20 | return '#ff9933'; // Arancione (Sensibili) 21 | } else if (aqi <= 200) { 22 | return '#cc0033'; // Rosso (Non salutare) 23 | } else if (aqi <= 300) { 24 | return '#660099'; // Viola (Molto non salutare) 25 | } else { 26 | return '#7e0023'; // Marrone scuro (Pericolosa) 27 | } 28 | } 29 | 30 | const buildAirQuality = ( 31 | hass: HomeAssistant, 32 | language: string, 33 | airquality: iAirQuality, 34 | ) => { 35 | const lang = language || hass.selectedLanguage || hass.language; 36 | 37 | const pm25 = getEntityNumericValue({ entityId: airquality.pm25, hass, lang: language, decimals: 0 }); 38 | const pm10 = getEntityNumericValue({ entityId: airquality.pm10, hass, lang: language, decimals: 0 }); 39 | const o3 = getEntityNumericValue({ entityId: airquality.o3, hass, lang: language, decimals: 1 }); 40 | const no2 = getEntityNumericValue({ entityId: airquality.no2, hass, lang: language, decimals: 0 }); 41 | const co = getEntityNumericValue({ entityId: airquality.co, hass, lang: language, decimals: 1 }); 42 | const so2 = getEntityNumericValue({ entityId: airquality.so2, hass, lang: language, decimals: 0 }); 43 | const epa_aqi = getEntityNumericValue({ entityId: airquality.epa_aqi, hass, lang: language, decimals: 0 }); 44 | const epa_primary_pollutant = getEntityRawValue(hass, airquality.epa_primary_pollutant); 45 | 46 | const airQualityData = { 47 | pm25: { 48 | value: (pm25 ? `pm2.5 ${pm25}` : pm25), 49 | unit: getEntityUnit(hass, airquality.pm25) || 'µg/m³', 50 | icon: 'mdi:weather-hazy', 51 | }, 52 | pm10: { 53 | value: (pm10 ? `pm10 ${pm10}` : pm10), 54 | unit: getEntityUnit(hass, airquality.pm10) || 'µg/m³', 55 | icon: 'mdi:weather-hazy', 56 | }, 57 | o3: { 58 | value: (o3 ? `o3 ${o3}` : o3), 59 | unit: getEntityUnit(hass, airquality.o3) || 'µg/m³', 60 | icon: 'mdi:molecule', 61 | }, 62 | no2: { 63 | value: (no2 ? `no2 ${no2}` : no2), 64 | unit: getEntityUnit(hass, airquality.no2) || 'µg/m³', 65 | icon: 'mdi:molecule', 66 | }, 67 | co: { 68 | value: (co ? `co ${co}` : co), 69 | unit: getEntityUnit(hass, airquality.co) || 'µg/m³', 70 | icon: 'mdi:molecule', 71 | }, 72 | so2: { 73 | value: (so2 ? `so2 ${so2}` : so2), 74 | unit: getEntityUnit(hass, airquality.so2) || 'µg/m³', 75 | icon: 'mdi:molecule', 76 | }, 77 | epa_aqi: { 78 | value: (epa_aqi ? `Air Quality Index ${epa_aqi}` : epa_aqi), 79 | // unit: getEntityUnit(hass, airquality.epa_aqi) || 'µg/m³', 80 | icon: 'mdi:weather-hazy', 81 | icon_color: getAQIColor(Number(getEntityRawValue(hass, airquality.epa_aqi))), 82 | }, 83 | epa_primary_pollutant: { 84 | value: (epa_primary_pollutant ? `Primary ${epa_primary_pollutant}` : epa_primary_pollutant), 85 | // unit: getEntityUnit(hass, airquality.epa_aqi) || 'µg/m³', 86 | icon: 'mdi:weather-hazy', 87 | }, 88 | }; 89 | 90 | return renderWeatherPresent(airQualityData, lang); 91 | }; 92 | 93 | export default buildAirQuality; 94 | -------------------------------------------------------------------------------- /dist/icons/animated/rainy-6.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /dist/icons/animated/rainy-7.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /dist/icons/animated/snowy-4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /dist/icons/static/hurricane.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /dist/icons/static/snowy-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/utils/config-schema.ts: -------------------------------------------------------------------------------- 1 | export interface iLovelaceCardConfig { 2 | index?: number; // Indice della card all'interno della vista (opzionale). 3 | view_index?: number; // Indice della vista in cui si trova la card (opzionale). 4 | view_layout?: unknown; // Informazioni di layout (griglia, posizione, ecc.) per l'editor UI. 5 | type: string; // Obbligatorio. Indica il tipo di card 6 | [key: string]: unknown; // Permette di aggiungere parametri arbitrari, cioè supporta proprietà dinamiche definite dall’utente. 7 | } 8 | 9 | export interface iPresentData { 10 | // sun?: string; 11 | // moonphase?: string; 12 | condition?: string; 13 | temperature?: string; 14 | temperature_feelslike?: string; 15 | 16 | temperature_min?: string; 17 | temperature_max?: string; 18 | 19 | humidity?: string; 20 | pressure?: string; 21 | visibility?: string; 22 | wind_bearing?: string; 23 | wind_speed?: string; 24 | precipitation_intensity?: string; 25 | precipitation_probability?: string; 26 | } 27 | 28 | export interface iTimeSlots { 29 | slot1: string; 30 | slot2: string; 31 | slot3: string; 32 | slot4: string; 33 | slot5: string; 34 | slot6: string; 35 | } 36 | 37 | export interface iDailyForecast { 38 | condition?: iTimeSlots; 39 | temperature_high?: iTimeSlots; 40 | temperature_low?: iTimeSlots; 41 | precipitation_intensity?: iTimeSlots; 42 | precipitation_probability?: iTimeSlots; 43 | 44 | meteogram?: string ; 45 | } 46 | 47 | export interface iHourlyForecast { 48 | condition?: iTimeSlots; 49 | temperature?: iTimeSlots; 50 | temperature_feelslike?: iTimeSlots; 51 | precipitation_intensity?: iTimeSlots; 52 | precipitation_probability?: iTimeSlots; 53 | wind_bearing?: iTimeSlots; 54 | wind_speed?: iTimeSlots; 55 | } 56 | 57 | export interface iMarineHourlyForecast { 58 | swell_direction?: iTimeSlots ; 59 | swell_height?: iTimeSlots ; 60 | swell_period?: iTimeSlots ; 61 | wind_direction: iTimeSlots ; 62 | wind_speed: iTimeSlots ; 63 | air_temperature: iTimeSlots ; 64 | water_temperature: iTimeSlots ; 65 | } 66 | 67 | export interface iMarineDailyForecast { 68 | wave_height_max?: iTimeSlots ; 69 | wave_direction?: iTimeSlots ; 70 | swell_wave_height_max?: iTimeSlots ; 71 | wind_wave_height_max?: iTimeSlots ; 72 | } 73 | 74 | export interface iDPCAlert { 75 | thunderstorms?: string; 76 | hydraulic?: string; 77 | hydrogeological?: string; 78 | } 79 | 80 | export interface iWeather { 81 | name?: string; // location name, in summary 82 | sun?: string; 83 | moonphase?: string; 84 | icons_model: string; 85 | animation?: boolean; 86 | present?: iPresentData ; 87 | daily_forecasts?: iDailyForecast; 88 | hourly_forecasts?: iHourlyForecast; 89 | marine_daily_forecasts?: iMarineDailyForecast; 90 | marine_hourly_forecasts?: iMarineHourlyForecast; 91 | meteoalarm?: string; // Meteoalarm alert 92 | dpcalarm?: iDPCAlert; // DPC alert 93 | } 94 | 95 | export interface iUltraviolet { 96 | protection_window?: string ; 97 | ozone_level?: string ; 98 | uv_index?: string ; 99 | uv_level?: string ; 100 | max_uv_index?: string ; 101 | set_skin_type_1?: string ; 102 | set_skin_type_2?: string ; 103 | set_skin_type_3?: string ; 104 | set_skin_type_4?: string ; 105 | set_skin_type_5?: string ; 106 | set_skin_type_6?: string ; 107 | } 108 | 109 | export interface iPollenItem { 110 | name: string; 111 | entity: string; 112 | } 113 | 114 | export interface iPollen { 115 | entities: iPollenItem[]; 116 | min: number; 117 | max: number; 118 | } 119 | 120 | export interface iAirQuality { 121 | pm25?: string ; 122 | pm10?: string ; 123 | o3?: string ; 124 | no2?: string ; 125 | co?: string ; 126 | so2?: string ; 127 | epa_aqi?: string ; 128 | epa_primary_pollutant?: string ; 129 | epa_health_concern?: string ; 130 | } 131 | 132 | export interface iCardConfig { 133 | type: string; // ha-card-weather-conditions 134 | language?: string ; // Card language 135 | 136 | weather: iWeather; 137 | ultraviolet?: iUltraviolet; 138 | 139 | pollen?: iPollen; 140 | airquality?: iAirQuality ; 141 | 142 | camera?: string; 143 | 144 | // display: string[] 145 | 146 | // alert: Alert ; 147 | // sea: Sea ; 148 | } 149 | --------------------------------------------------------------------------------