Skip to content

Commit

Permalink
Calculation and graph overhaul + Moon support (#56)
Browse files Browse the repository at this point in the history
- Completely revamped calculations and Sun graph, now way more realistic
- Moon support: Moon on the graph, moonrise, moonset, Moon phase, Moon elevation and Moon azimuth
- Obeys Home Assistant's settings for time and number formatting
- Cleaned up config options
- Font size adjustments, including the smaller AM/PM text from the original card
- Lots of tests
- All lint warnings gone

Resolves the following issues:
- #11 - Moon support
- #30 - Horizon-card customize with card-mod
- #40 - More realistic visualization and own source of Sun data
- #54 - 24h format not working by default
- #58 - Support HA 2023.7's local/server time zone setting
  • Loading branch information
avataar authored Jul 13, 2023
1 parent 3327d5a commit bd25747
Show file tree
Hide file tree
Showing 90 changed files with 7,057 additions and 4,094 deletions.
31 changes: 0 additions & 31 deletions .eslintrc

This file was deleted.

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,6 @@ dist

# TernJS port file
.tern-port

# IDEs
.idea
119 changes: 98 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,28 @@ Consider joining us!

## Introduction

The Horizon Card tracks the position of the Sun over the horizon and shows the times of various Sun events, as well as the current azimuth and elevation, in a visually appealing and easy-to-read format.
The Horizon Card tracks the position of the Sun and the Moon over the horizon and shows the times of various Sun and Moon events, as well as their current azimuth and elevation, in a visually appealing and easy-to-read format.

<p align="center">
<img width="400" alt="Light mode preview" src="https://user-images.githubusercontent.com/6829526/118412152-54d93900-b690-11eb-8b2b-e87b4cbcca7f.png"/>
<img width="400" alt="Dark mode preview" src="https://user-images.githubusercontent.com/6829526/118412162-64f11880-b690-11eb-9bd7-b8c6c7d8efd8.png"/>
</p>

### How it works

The card will show the Sun and the Moon as they travel across the horizon from East to West. Both celestial bodies will be shown when above or below the horizon.

The current view shows a period of 24 hours centered around the local solar noon. This means that the Sun will continue to travel to the far end of the graph until it reaches solar midnight, which may be some time before or after midnight in your local time zone. Once solar midnight is reached, the view will reset and start showing the data for the next day.

In the Northern hemisphere, East is on the left, South is in the middle (when the Sun is in its highest position), and West is on the right. You are facing South and the Sun travels left-to-right.

In the Southern hemisphere, West is on the left, North is in the middle (when the Sun is in its highest position), and East is on the right. You are facing North and the Sun travels right-to-left. You can disable the direction flip by setting `southern_flip: false`.

The elevation of the Sun follows a predetermined curve that approximates the actual elevation, while the elevation of the Moon affects its vertical position in the graph. The scale for the Moon elevation is logarithmic, so lower elevations will appear higher (above horizon) or lower (below horizon).

If showing the moon phase is enabled, the icon will be rotated to match the approximate view for your latitude. You can disable this by setting `moon_phase_rotation: 0` or set a different angle to match your location or preferences.


## Installation

Please ensure you have the [Sun integration](https://www.home-assistant.io/integrations/sun/) enabled in your Home Assistant setup.
Expand Down Expand Up @@ -79,28 +94,53 @@ Installation via HACS is recommended, but a manual setup is supported.

## Configuration

| Name | Accepted values | Description | Default |
| -------------- | -------------------- | -------------------------------------- | --------------------------------------------------- |
| component | `string` | Changes which sun component to use | Home Assistant `sun.sun` |
| darkMode | `boolean` | Changes card colors to dark or light | Home Assistant dark mode state |
| fields | See below | Fine-tuned control over visible fields | |
| language | See below | Changes card language | Home Assistant language or english if not supported |
| use12hourClock | `boolean` | Use 12/24 hour clock | Uses locale of configured language to decide |
| title | `string` | Card title | Doesn't display a title by default |
### General options

| Name | Accepted values | Description | Default |
|---------------------|-----------------|---------------------------------------------------|----------------------------------------------------------------|
| title | *string* | Card title | Doesn't display a title by default |
| moon | *boolean* | Shows the Moon together with the Sun | `true` |
| refresh_period | *number* | Refresh period between updates, in seconds | 60 |
| fields | See below | Fine-tuned control over visible fields | |
| southern_flip | *boolean* | Draws the graph in the opposite direction | `true` in the Southern hemisphere, `false` in the Northern one |
| moon_phase_rotation | *number* | Angle in degrees for rotating the moon phase icon | Determined from the latitude |

### Advanced options

In general, you should not need to set any of these as they override Home Assistant's settings or set debug options.

| Name | Accepted values | Description | Default |
|-----------|----------------------------------------------|--------------------------------------------------------------------------------|-----------------------------------------------------|
| language | See below | Changes card language | Home Assistant language or English if not supported |
| time_format | `language`, `12`, `24` | Set to `12` or `24` to force 12/24 hour clock | `language` - uses default for configured language |
| number_format | `language`, `comma_decimal`, `decimal_comma` | Set to `comma_decimal` or `decimal_comma` to force 123.45/123,45 number format | `language` - uses default for configured language |
| latitude | *number* | Latitude used for calculations | Home Assistant's latitude |
| longitude | *number* | Longitude used for calculations | Home Assistant's longitude |
| elevation | *number* | Elevation (above sea) used for calculations | Home Assistant's elevation |
| time_zone | *string* | Time zone (IANA) used for calculations and time presentation | Home Assistant's time zone |
| now | *Date* | Overrides the current moment shown on the card | None, i.e., always show the current moment |
| debug_level | *number* | Sets debug level, 0 and up | 0, i.e., no debug |

### Visibility Fields

Supported settings inside the `fields` setting:

| Name | Accepted values | Description | Default |
|----------------|-----------------|----------------|---------|
| sunrise | `boolean` | Show sunrise | `true` |
| sunset | `boolean` | Show sunset | `true` |
| dawn | `boolean` | Show dawn | `true` |
| noon | `boolean` | Show noon | `true` |
| dusk | `boolean` | Show dusk | `true` |
| azimuth | `boolean` | Show azimuth | `false` |
| elevation | `boolean` | Show elevation | `false` |
| Name | Accepted values | Description | Default |
|----------------|-----------------|-----------------------------|--------------------------|
| sunrise | *boolean* | Show sunrise time | `true` |
| sunset | *boolean* | Show sunset time | `true` |
| dawn | *boolean* | Show dawn time | `true` |
| noon | *boolean* | Show solar noon time | `true` |
| dusk | *boolean* | Show dusk time | `true` |
| azimuth | *boolean* | Show Sun and Moon azimuth | `false` |
| sun_azimuth | *boolean* | Show Sun azimuth | the value of `azimuth` |
| moon_azimuth | *boolean* | Show Moon azimuth | the value of `azimuth` |
| elevation | *boolean* | Show Sun and Moon elevation | `false` |
| sun_elevation | *boolean* | Show Sun elevation | the value of `elevation` |
| moon_elevation | *boolean* | Show Moon elevation | the value of `elevation` |
| moonrise | *boolean* | Show moonrise time | `false` |
| moonset | *boolean* | Show moonset time | `false` |
| moon_phase | *boolean* | Show the Moon phase | `false` |

### Languages

Expand Down Expand Up @@ -140,6 +180,43 @@ Supported options for the `language` setting:
- `zh-Hans` Chinese, simplified
- `zh-Hant` Chinese, traditional

## Known Issues

- Home Assistant reports the time of the next occurring Sun event. For example, if you look at the card during the day, the time for sunrise will reflect tomorrow's sunrise and not the one that occurred on the same day.
### Caveats

The Moon phase name (if the field `moon_phase` is enabled) is obtained via the [Moon integration](https://www.home-assistant.io/integrations/moon/). If the integration is not installed, the card will still show the Moon phase as a human-readable constant followed by `(!)`, e.g., `waning_gibbuous (!)`. Due to the way Home Assistant works, the localized Moon phase name will always be in Home Assistant's language and not in the language set for the card via the `language` option.

### Example config

The following YAML configuration illustrates the use of all options.

```yaml
type: custom:horizon-card
title: Example Horizon Card
moon: true
refresh_period: 60
fields:
sunrise: true
sunset: true
dawn: true
noon: true
dusk: true
azimuth: true
sun_azimuth: true
moon_azimuth: true
elevation: true
sun_elevation: true
moon_elevation: true
moonrise: true
moonset: true
moon_phase: true
southern_flip: false
moon_phase_rotation: -10
language: en
time_format: language
number_format: language
latitude: 42.55
longitude: 23.25
elevation: 1500
time_zone: Europe/Sofia
now: 2023-07-06T00:30:05+0300
debug_level: 0
```
31 changes: 31 additions & 0 deletions dev/curve_scale.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import re


def scale(group, x_offset, x_length, y_offset, y_length):
x = float(group[2])
y = float(group[3])

x *= x_length/400
x += x_offset
x = round(x, 3)

y *= y_length/100
y += y_offset
y = round(y, 3)

return f"{group[1]}{x},{y}"


# Base curve composed of two segments
# Full
# base_curve = "M0,100 C72.84,100 127.16,0 200,0 C272.84,0 327.16,100 400,100"
# Simplified
base_curve = "M0,100 C72.84,100 127.16,0 200,0 S327.16,100 400,100"

groups = re.findall(r"(([A-Z ]+)([0-9.]+)[, ]+([0-9.]+))", base_curve)
scaled = []
for g in groups:
scaled.append(scale(g, 5, 540, 20, 126))

# Prints scaled curve
print("".join(scaled))
25 changes: 21 additions & 4 deletions dev/dev.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@100;200;300;400;500;700;900&display=swap');

horizon-card {
--primary-text-color: #e1e1e1;
--secondary-text-color: #9b9b9b;
--primary-color: rgb(3, 169, 244);
font-size: 18px;
}

body.light horizon-card {
--primary-text-color: #212121;
--secondary-text-color: #727272;
--primary-color: rgb(3, 169, 244);
}

body {
font-family: 'Roboto', sans-serif;
background: #111111;
Expand All @@ -14,8 +27,9 @@ body.light {
border-radius: 4px;
box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12);
padding: 1rem;
max-width: 1000px;
max-width: 700px;
margin: auto;
box-sizing: border-box;
}

body.light .card {
Expand All @@ -27,18 +41,21 @@ body:not(.light) #dev-panel {
}

#dev-panel > div {
max-width: 1000px;
max-width: 1200px;
margin: auto;
}

#time {
text-align: center;
padding-top: 1em;
padding-bottom: 1em;
font-size: 120%;
}

#buttons {
display: flex;
flex-wrap: wrap;
gap: 20px;
}

#langs {
Expand All @@ -48,13 +65,13 @@ body:not(.light) #dev-panel {
}

#buttons > div {
flex-grow: 1;
/*flex-grow: 1;*/
}

.radio {
display: flex;
flex-flow: column wrap;
max-height: 150px;
max-height: 180px;
}

#buttons div {
Expand Down
Loading

0 comments on commit bd25747

Please sign in to comment.