Skip to content
These pages describe Stewart 1.x. Read the docs for the latest release, and how to upgrade.

Sun

Stewart computes the sun’s times and position from the location set in Home Assistant (Settings → System → General). The results agree with Home Assistant’s own sun integration within seconds, and keep coming while Home Assistant is unreachable. This app closes the south-facing blinds while the sun shines on them:

apps/SouthBlinds.php
<?php
declare(strict_types=1);
namespace App;
use Stewart\Contracts\App;
use Stewart\Contracts\Automation;
use Stewart\Contracts\HaContext;
use Stewart\Contracts\Schedule\Scheduler;
use Stewart\Contracts\Service\ServiceTarget;
use Stewart\Contracts\Sun\SunCalendar;
use Stewart\Contracts\Time\Duration;
#[Automation(id: 'south-blinds')]
final readonly class SouthBlinds implements App
{
public function __construct(
private HaContext $ha,
private Scheduler $scheduler,
private SunCalendar $sun,
private string $blinds = 'cover.south_blinds',
) {}
public function initialize(): void
{
$this->scheduler->runEvery(Duration::minutes(10), function (): void {
$position = $this->sun->getCurrentPosition();
$sunOnTheFacade = $position->isWithinAzimuth(135.0, 225.0) && $position->isHigherThan(15.0);
if ($sunOnTheFacade && $this->ha->getState($this->blinds)?->state === 'open') {
$this->ha->callAction('cover.close_cover', target: ServiceTarget::forEntities($this->blinds));
}
});
}
}
$this->scheduler->runAtSunEvent(SunEvent::Sunrise, $this->openBlinds(...));
$this->scheduler->runAtSunEvent(SunEvent::Sunset, $this->lightsOn(...), SunOffset::before(Duration::minutes(30)));
$this->scheduler->runAtSunEvent(SunEvent::GoldenHourEveningStart, $this->warmLights(...));

These are ordinary schedules; see Scheduling and waiting. On a day an event does not happen, such as sunset during the midnight sun, the schedule waits for the next day it does.

SunEvent The sun’s height
AstronomicalDawn / AstronomicalDusk −18°
NauticalDawn / NauticalDusk −12°
CivilDawn / CivilDusk −6°
BlueHourMorningStart / BlueHourEveningEnd −6°
BlueHourMorningEnd / BlueHourEveningStart −4°
Sunrise / Sunset Top edge on the horizon
GoldenHourMorningEnd / GoldenHourEveningStart +6°
SolarNoon Highest point of the day

Golden hour runs from −4° to +6°, blue hour from −6° to −4°.

Ask for SunCalendar in the constructor:

Method Returns
isSunUp() Whether the sun is up now
findNextEvent(SunEvent::CivilDusk) When the event next happens, as an Instant
findNextEvent(SunEvent::Sunrise, SunOffset::after(Duration::minutes(20))) The same, shifted
getDayOn(new DateTimeImmutable('tomorrow'))->findEventTime(SunEvent::Sunset) An event on a given day
getCurrentPosition() Where the sun stands now
getPositionAt($instant) Where it stands at another moment

A SunPosition has azimuthDegrees (0° is north, 90° east) and elevationDegrees (above the horizon, including refraction, like the elevation attribute of sun.sun). isWithinAzimuth(135.0, 225.0) checks a compass sector, also one that wraps past north, and isHigherThan(15.0) the height.

The test harness’s sun rises at 06:00, stands in the south at 45° all day, and sets at 18:00. $harness->sunCalendar->stubEventTime(SunEvent::Sunset, '16:30') moves an event.

A sunset schedule needs a location, or a SunException. Home Assistant has no location. Set it under Settings → System → General and restart Stewart. Stewart also picks up a changed location only at restart.