Skip to content

Commit

Permalink
[#662] Use sun position calculations to show partly cloudy night labe…
Browse files Browse the repository at this point in the history
…l/icons
  • Loading branch information
decompil3d committed Jun 12, 2024
1 parent eb5c791 commit aa48e24
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 31 deletions.
35 changes: 18 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,23 +151,24 @@ color in your Home Assistant theme.
Some conditions will default to whatever the value is of some other condition. For example, `fog` will default to
whatever `cloudy` is.

| Key | Default |
|-------------------|------------------------|
| `clear-night` | `#000` |
| `cloudy` | `#777` |
| `fog` | same as `cloudy` |
| `hail` | `#2b5174` |
| `lightning` | same as `rainy` |
| `lightning-rainy` | same as `rainy` |
| `partlycloudy` | `#b3dbff` |
| `pouring` | same as `rainy` |
| `rainy` | `#44739d` |
| `snowy` | `#fff` |
| `snowy-rainy` | same as `partlycloudy` |
| `sunny` | `#90cbff` |
| `windy` | same as `sunny` |
| `windy-variant` | same as `sunny` |
| `exceptional` | `#ff9d00` |
| Key | Default |
|-----------------------|------------------------|
| `clear-night` | `#111` |
| `cloudy` | `#777` |
| `fog` | same as `cloudy` |
| `hail` | `#2b5174` |
| `lightning` | same as `rainy` |
| `lightning-rainy` | same as `rainy` |
| `partlycloudy` | `#b3dbff` |
| `night-partly-cloudy` | `#333` |
| `pouring` | same as `rainy` |
| `rainy` | `#44739d` |
| `snowy` | `#fff` |
| `snowy-rainy` | same as `partlycloudy` |
| `sunny` | `#90cbff` |
| `windy` | same as `sunny` |
| `windy-variant` | same as `sunny` |
| `exceptional` | `#ff9d00` |

### Sample colors configuration

Expand Down
33 changes: 22 additions & 11 deletions cypress/e2e/weather-bar.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@ describe('Weather bar', () => {
.find('div.axes')
.should('exist');
});
it('has the current number of condition blocks', () => {
it('has the correct number of condition blocks', () => {
cy.get('weather-bar')
.shadow()
.find('div.bar > div')
.should('have.length', 4);
.should('have.length', 5);
});
const expectedConditions = [
'Cloudy',
'Partly cloudy',
'Partly cloudy (night)',
'Sunny',
'Clear'
];
Expand All @@ -48,13 +49,15 @@ describe('Weather bar', () => {

const expectedWidths = [
6,
6,
2,
4,
10,
2
];
const expectedColors = [
'rgb(119, 119, 119)',
'rgb(179, 219, 255)',
'rgb(51, 51, 51)',
'rgb(144, 203, 255)',
'rgb(17, 17, 17)'
];
Expand All @@ -77,8 +80,9 @@ describe('Weather bar', () => {
const expectedCustomColors = [
'rgb(255, 0, 0)',
'rgb(0, 255, 0)',
'rgb(0, 255, 255)',
'rgb(0, 0, 255)',
'rgb(0, 255, 255)'
'rgb(34, 34, 34)'
];

it('uses custom colors when specified', () => {
Expand All @@ -87,7 +91,8 @@ describe('Weather bar', () => {
cloudy: '#FF0000',
partlycloudy: 'rgb(0, 255, 0)',
sunny: 'hsl(240, 100%, 50%)',
"clear-night": 'cyan'
"night-partly-cloudy": 'cyan',
"clear-night": '#222',
}
});
cy.get('weather-bar')
Expand All @@ -102,8 +107,9 @@ describe('Weather bar', () => {
const expectedCustomObjectColors = [
{ bg: 'rgb(18, 52, 86)', fg: 'rgb(0, 0, 0)' },
{ bg: 'rgb(179, 219, 255)', fg: 'rgb(123, 45, 6)' },
{ bg: 'rgb(50, 205, 50)', fg: 'rgb(0, 0, 0)' },
{ bg: 'rgb(0, 255, 0)', fg: 'rgb(255, 0, 255)' },
{ bg: 'rgb(50, 205, 50)', fg: 'rgb(0, 0, 0)' }
{ bg: 'rgb(34, 34, 34)', fg: 'rgb(255, 255, 255)' }
];

it('uses custom colors when specified as color objects', () => {
Expand All @@ -119,7 +125,11 @@ describe('Weather bar', () => {
background: 'hsl(120, 100%, 50%)',
foreground: 'magenta'
},
"clear-night": 'limegreen'
"night-partly-cloudy": 'limegreen',
"clear-night": {
background: '#222',
foreground: 'white'
}
}
});
cy.get('weather-bar')
Expand All @@ -136,7 +146,7 @@ describe('Weather bar', () => {
cy.get('weather-bar')
.shadow()
.find('div.bar > div > span.condition-label')
.should('have.length', 4)
.should('have.length', 5)
.each((el, i) => {
cy.wrap(el).should('have.text', expectedConditions[i]);
});
Expand All @@ -156,7 +166,7 @@ describe('Weather bar', () => {
cy.get('weather-bar')
.shadow()
.find('div.bar > div')
.its(2)
.its(3)
.find('span.condition-label')
.should(label => {
const cs = window.getComputedStyle(label.get(0));
Expand All @@ -174,6 +184,7 @@ describe('Weather bar', () => {
const expectedIcons = [
'mdi:weather-cloudy',
'mdi:weather-partly-cloudy',
'mdi:weather-night-partly-cloudy',
'mdi:weather-sunny',
'mdi:weather-night'
];
Expand All @@ -182,7 +193,7 @@ describe('Weather bar', () => {
cy.get('weather-bar')
.shadow()
.find('div.bar > div > span.condition-icon')
.should('have.length', 4)
.should('have.length', 5)
.find('ha-icon')
.each((el, i) => {
cy.wrap(el).invoke('attr', 'icon')
Expand All @@ -194,7 +205,7 @@ describe('Weather bar', () => {
cy.get('weather-bar')
.shadow()
.find('div.bar > div')
.its(3)
.its(1)
.find('span.condition-icon')
.should(icon => {
const cs = window.getComputedStyle(icon.get(0));
Expand Down
4 changes: 4 additions & 0 deletions cypress/fixtures/harness.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@
}
},
},
config: {
latitude: 51.48346270,
longitude: 0.05862020,
},
states: {
'weather.mock': {
attributes: {
Expand Down
6 changes: 6 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"home-assistant-js-websocket": "^9.3.0",
"is-valid-css-color": "^2.0.3",
"lit": "^2.8.0",
"solar-calculator": "^0.3.0",
"tippy.js": "^6.3.7"
},
"devDependencies": {
Expand Down
2 changes: 2 additions & 0 deletions src/conditions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const LABELS = {
'lightning': 'conditions.thunderstorm',
'lightning-rainy': 'conditions.thunderstorm',
'partlycloudy': 'conditions.partlyCloudy',
'night-partly-cloudy': 'conditions.partlyCloudyNight',
'pouring': 'conditions.heavyRain',
'rainy': 'conditions.rain',
'snowy': 'conditions.snow',
Expand All @@ -22,6 +23,7 @@ export const ICONS = {
'hail': 'hail',
'lightning': 'lightning',
'lightning-rainy': 'lightning-rainy',
'night-partly-cloudy': 'weather-night-partly-cloudy',
'partlycloudy': 'weather-partly-cloudy',
'pouring': 'pouring',
'rainy': 'rainy',
Expand Down
17 changes: 15 additions & 2 deletions src/hourly-weather.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
formatDateShort,
} from 'custom-card-helpers'; // This is a community maintained npm module with common helper functions/types. https://github.com/custom-cards/custom-card-helpers
import { isValidColorName, isValidHSL, isValidRGB } from 'is-valid-css-color';
import { rise as sunrise, set as sunset } from 'solar-calculator';

import type {
ColorConfig,
Expand Down Expand Up @@ -413,11 +414,11 @@ export class HourlyWeatherCard extends LitElement {
}

private getConditionListFromForecast(forecast: ForecastSegment[], numSegments: number, offset: number): ConditionSpan[] {
let lastCond: string = forecast[offset].condition;
let lastCond: string = this.getAdjustedConditionForForecastSegment(forecast[offset]);
let j = 0;
const res: ConditionSpan[] = [[lastCond, 1]];
for (let i = offset + 1; i < numSegments + offset; i++) {
const cond: string = forecast[i].condition;
const cond: string = this.getAdjustedConditionForForecastSegment(forecast[i]);
if (cond === lastCond) {
res[j][1]++;
} else {
Expand All @@ -429,6 +430,18 @@ export class HourlyWeatherCard extends LitElement {
return res;
}

private getAdjustedConditionForForecastSegment(fs: ForecastSegment): string {
const when = new Date(fs.datetime);
const { latitude, longitude } = this.hass.config;
const rise = sunrise(when, latitude, longitude);
const set = sunset(when, latitude, longitude);
const isDay = when >= rise && when <= set;
if (!isDay && fs.condition === 'partlycloudy') {
return 'night-partly-cloudy';
}
return fs.condition;
}

private getTemperatures(forecast: ForecastSegment[], numSegments: number, offset: number): SegmentTemperature[] {
const temperatures: SegmentTemperature[] = [];
for (let i = offset; i < numSegments + offset; i++) {
Expand Down
1 change: 1 addition & 0 deletions src/localize/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"hail": "Hail",
"thunderstorm": "Thunderstorm",
"partlyCloudy": "Partly cloudy",
"partlyCloudyNight": "Partly cloudy (night)",
"heavyRain": "Heavy rain",
"rain": "Rain",
"snow": "Snow",
Expand Down
4 changes: 4 additions & 0 deletions src/solar-calculator.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module 'solar-calculator' {
export function rise(date: Date, latitude: number, longitude: number): Date;
export function set(date: Date, latitude: number, longitude: number): Date;
}
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export interface ColorConfig {
'lightning'?: ColorDefinition;
'lightning-rainy'?: ColorDefinition;
'partlycloudy'?: ColorDefinition;
'night-partly-cloudy'?: ColorDefinition;
'pouring'?: ColorDefinition;
'rainy'?: ColorDefinition;
'snowy'?: ColorDefinition;
Expand Down
7 changes: 6 additions & 1 deletion src/weather-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,13 @@ export class WeatherBar extends LitElement {
static styles = [unsafeCSS(tippyStyles), css`
.main {
--color-clear-night: #111;
--color-cloudy: #777777;
--color-cloudy: #777;
--color-fog: var(--color-cloudy);
--color-hail: #2b5174;
--color-lightning: var(--color-rainy);
--color-lightning-rainy: var(--color-rainy);
--color-partlycloudy: #b3dbff;
--color-night-partly-cloudy: #333;
--color-pouring: var(--color-rainy);
--color-rainy: #44739d;
--color-snowy: white;
Expand Down Expand Up @@ -276,6 +277,10 @@ export class WeatherBar extends LitElement {
background-color: var(--color-partlycloudy);
color: var(--color-partlycloudy-foreground, var(--primary-text-color));
}
.night-partly-cloudy {
background-color: var(--color-night-partly-cloudy);
color: var(--color-night-partly-cloudy-foreground, var(--primary-text-color));
}
.pouring {
background-color: var(--color-pouring);
color: var(--color-pouring-foreground, var(--primary-text-color));
Expand Down

0 comments on commit aa48e24

Please sign in to comment.