Skip to content

Commit bd25747

Browse files
authored
Calculation and graph overhaul + Moon support (#56)
- 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
1 parent 3327d5a commit bd25747

File tree

90 files changed

+7057
-4094
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+7057
-4094
lines changed

.eslintrc

-31
This file was deleted.

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,6 @@ dist
102102

103103
# TernJS port file
104104
.tern-port
105+
106+
# IDEs
107+
.idea

README.md

+98-21
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,28 @@ Consider joining us!
1010

1111
## Introduction
1212

13-
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.
13+
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.
1414

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

20+
### How it works
21+
22+
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.
23+
24+
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.
25+
26+
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.
27+
28+
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`.
29+
30+
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).
31+
32+
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.
33+
34+
2035
## Installation
2136

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

8095
## Configuration
8196

82-
| Name | Accepted values | Description | Default |
83-
| -------------- | -------------------- | -------------------------------------- | --------------------------------------------------- |
84-
| component | `string` | Changes which sun component to use | Home Assistant `sun.sun` |
85-
| darkMode | `boolean` | Changes card colors to dark or light | Home Assistant dark mode state |
86-
| fields | See below | Fine-tuned control over visible fields | |
87-
| language | See below | Changes card language | Home Assistant language or english if not supported |
88-
| use12hourClock | `boolean` | Use 12/24 hour clock | Uses locale of configured language to decide |
89-
| title | `string` | Card title | Doesn't display a title by default |
97+
### General options
98+
99+
| Name | Accepted values | Description | Default |
100+
|---------------------|-----------------|---------------------------------------------------|----------------------------------------------------------------|
101+
| title | *string* | Card title | Doesn't display a title by default |
102+
| moon | *boolean* | Shows the Moon together with the Sun | `true` |
103+
| refresh_period | *number* | Refresh period between updates, in seconds | 60 |
104+
| fields | See below | Fine-tuned control over visible fields | |
105+
| southern_flip | *boolean* | Draws the graph in the opposite direction | `true` in the Southern hemisphere, `false` in the Northern one |
106+
| moon_phase_rotation | *number* | Angle in degrees for rotating the moon phase icon | Determined from the latitude |
107+
108+
### Advanced options
109+
110+
In general, you should not need to set any of these as they override Home Assistant's settings or set debug options.
111+
112+
| Name | Accepted values | Description | Default |
113+
|-----------|----------------------------------------------|--------------------------------------------------------------------------------|-----------------------------------------------------|
114+
| language | See below | Changes card language | Home Assistant language or English if not supported |
115+
| time_format | `language`, `12`, `24` | Set to `12` or `24` to force 12/24 hour clock | `language` - uses default for configured language |
116+
| 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 |
117+
| latitude | *number* | Latitude used for calculations | Home Assistant's latitude |
118+
| longitude | *number* | Longitude used for calculations | Home Assistant's longitude |
119+
| elevation | *number* | Elevation (above sea) used for calculations | Home Assistant's elevation |
120+
| time_zone | *string* | Time zone (IANA) used for calculations and time presentation | Home Assistant's time zone |
121+
| now | *Date* | Overrides the current moment shown on the card | None, i.e., always show the current moment |
122+
| debug_level | *number* | Sets debug level, 0 and up | 0, i.e., no debug |
90123

91124
### Visibility Fields
92125

93126
Supported settings inside the `fields` setting:
94127

95-
| Name | Accepted values | Description | Default |
96-
|----------------|-----------------|----------------|---------|
97-
| sunrise | `boolean` | Show sunrise | `true` |
98-
| sunset | `boolean` | Show sunset | `true` |
99-
| dawn | `boolean` | Show dawn | `true` |
100-
| noon | `boolean` | Show noon | `true` |
101-
| dusk | `boolean` | Show dusk | `true` |
102-
| azimuth | `boolean` | Show azimuth | `false` |
103-
| elevation | `boolean` | Show elevation | `false` |
128+
| Name | Accepted values | Description | Default |
129+
|----------------|-----------------|-----------------------------|--------------------------|
130+
| sunrise | *boolean* | Show sunrise time | `true` |
131+
| sunset | *boolean* | Show sunset time | `true` |
132+
| dawn | *boolean* | Show dawn time | `true` |
133+
| noon | *boolean* | Show solar noon time | `true` |
134+
| dusk | *boolean* | Show dusk time | `true` |
135+
| azimuth | *boolean* | Show Sun and Moon azimuth | `false` |
136+
| sun_azimuth | *boolean* | Show Sun azimuth | the value of `azimuth` |
137+
| moon_azimuth | *boolean* | Show Moon azimuth | the value of `azimuth` |
138+
| elevation | *boolean* | Show Sun and Moon elevation | `false` |
139+
| sun_elevation | *boolean* | Show Sun elevation | the value of `elevation` |
140+
| moon_elevation | *boolean* | Show Moon elevation | the value of `elevation` |
141+
| moonrise | *boolean* | Show moonrise time | `false` |
142+
| moonset | *boolean* | Show moonset time | `false` |
143+
| moon_phase | *boolean* | Show the Moon phase | `false` |
104144

105145
### Languages
106146

@@ -140,6 +180,43 @@ Supported options for the `language` setting:
140180
- `zh-Hans` Chinese, simplified
141181
- `zh-Hant` Chinese, traditional
142182

143-
## Known Issues
144-
145-
- 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.
183+
### Caveats
184+
185+
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.
186+
187+
### Example config
188+
189+
The following YAML configuration illustrates the use of all options.
190+
191+
```yaml
192+
type: custom:horizon-card
193+
title: Example Horizon Card
194+
moon: true
195+
refresh_period: 60
196+
fields:
197+
sunrise: true
198+
sunset: true
199+
dawn: true
200+
noon: true
201+
dusk: true
202+
azimuth: true
203+
sun_azimuth: true
204+
moon_azimuth: true
205+
elevation: true
206+
sun_elevation: true
207+
moon_elevation: true
208+
moonrise: true
209+
moonset: true
210+
moon_phase: true
211+
southern_flip: false
212+
moon_phase_rotation: -10
213+
language: en
214+
time_format: language
215+
number_format: language
216+
latitude: 42.55
217+
longitude: 23.25
218+
elevation: 1500
219+
time_zone: Europe/Sofia
220+
now: 2023-07-06T00:30:05+0300
221+
debug_level: 0
222+
```

dev/curve_scale.py

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import re
2+
3+
4+
def scale(group, x_offset, x_length, y_offset, y_length):
5+
x = float(group[2])
6+
y = float(group[3])
7+
8+
x *= x_length/400
9+
x += x_offset
10+
x = round(x, 3)
11+
12+
y *= y_length/100
13+
y += y_offset
14+
y = round(y, 3)
15+
16+
return f"{group[1]}{x},{y}"
17+
18+
19+
# Base curve composed of two segments
20+
# Full
21+
# base_curve = "M0,100 C72.84,100 127.16,0 200,0 C272.84,0 327.16,100 400,100"
22+
# Simplified
23+
base_curve = "M0,100 C72.84,100 127.16,0 200,0 S327.16,100 400,100"
24+
25+
groups = re.findall(r"(([A-Z ]+)([0-9.]+)[, ]+([0-9.]+))", base_curve)
26+
scaled = []
27+
for g in groups:
28+
scaled.append(scale(g, 5, 540, 20, 126))
29+
30+
# Prints scaled curve
31+
print("".join(scaled))

dev/dev.css

+21-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@100;200;300;400;500;700;900&display=swap');
22

3+
horizon-card {
4+
--primary-text-color: #e1e1e1;
5+
--secondary-text-color: #9b9b9b;
6+
--primary-color: rgb(3, 169, 244);
7+
font-size: 18px;
8+
}
9+
10+
body.light horizon-card {
11+
--primary-text-color: #212121;
12+
--secondary-text-color: #727272;
13+
--primary-color: rgb(3, 169, 244);
14+
}
15+
316
body {
417
font-family: 'Roboto', sans-serif;
518
background: #111111;
@@ -14,8 +27,9 @@ body.light {
1427
border-radius: 4px;
1528
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);
1629
padding: 1rem;
17-
max-width: 1000px;
30+
max-width: 700px;
1831
margin: auto;
32+
box-sizing: border-box;
1933
}
2034

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

2943
#dev-panel > div {
30-
max-width: 1000px;
44+
max-width: 1200px;
3145
margin: auto;
3246
}
3347

3448
#time {
3549
text-align: center;
3650
padding-top: 1em;
51+
padding-bottom: 1em;
3752
font-size: 120%;
3853
}
3954

4055
#buttons {
4156
display: flex;
57+
flex-wrap: wrap;
58+
gap: 20px;
4259
}
4360

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

5067
#buttons > div {
51-
flex-grow: 1;
68+
/*flex-grow: 1;*/
5269
}
5370

5471
.radio {
5572
display: flex;
5673
flex-flow: column wrap;
57-
max-height: 150px;
74+
max-height: 180px;
5875
}
5976

6077
#buttons div {

0 commit comments

Comments
 (0)