Recipes
weewx-skyfield manual · weewx-skyfield on GitHub · Report an issue
Working snippets for your own skin’s Cheetah templates. Each one uses only public $almanac tags, so it works in any skin with this extension installed — no search list, no configuration. For the drawn panels rather than the numbers, see Panels in your own skin.
The test suite evaluates every chain on this page that starts at $almanac against a real almanac, and compiles every snippet as a Cheetah template, so these read correctly as written. What the suite cannot check is your skin’s own HTML around them.
A twilight block
The four moments that bracket a day, using the USNO’s geometric definitions:
<table>
<tr><td>Astronomical dawn</td><td>$almanac(horizon=-18).sun(use_center=1).rise</td></tr>
<tr><td>Nautical dawn</td> <td>$almanac(horizon=-12).sun(use_center=1).rise</td></tr>
<tr><td>Civil dawn</td> <td>$almanac(horizon=-6).sun(use_center=1).rise</td></tr>
<tr><td>Sunrise</td> <td>$almanac.sun.rise</td></tr>
<tr><td>Sunset</td> <td>$almanac.sun.set</td></tr>
<tr><td>Civil dusk</td> <td>$almanac(horizon=-6).sun(use_center=1).set</td></tr>
<tr><td>Nautical dusk</td> <td>$almanac(horizon=-12).sun(use_center=1).set</td></tr>
<tr><td>Astronomical dark</td> <td>$almanac(horizon=-18).sun(use_center=1).set</td></tr>
</table>
use_center=1 measures to the sun’s center rather than its upper limb, which is what the twilight definitions specify. See Accuracy for why no refraction is applied to a custom horizon.
Day length, and whether it is growing
Daylight today: $almanac.sun.visible.long_form
That is $almanac.sun.visible_change() #if $almanac.sun.visible_change().raw > 0 then "longer" else "shorter"# than yesterday.
visible_change() is a method — the parentheses are required. It takes an optional argument: visible_change(7) compares against a week ago.
The moon, with its apsides
$almanac.moon.label is $almanac.moon.phase% illuminated ($almanac.moon_phase).
It rises $almanac.moon.rise and sets $almanac.moon.set,
standing in $almanac.moon.constellation.label.
Next perigee: $almanac.moon.next_perigee
Next apogee: $almanac.moon.next_apogee
$almanac.moon_phase — the top-level tag — is the phase’s name, translated by your report. $almanac.moon.phase is the percentage, and $almanac.moon.moon_phase is PyEphem’s 0–1 fraction. All three are different things; the tag index keeps them apart.
Tonight’s ISS pass
#set $iss_pass = $almanac.iss.next_visible_pass
#if $iss_pass.visible
The ISS appears $iss_pass.rise ($iss_pass.rise_azimuth.ordinal_compass),
peaks at $iss_pass.max_altitude ($iss_pass.culmination_azimuth.ordinal_compass),
and disappears $iss_pass.set ($iss_pass.set_azimuth.ordinal_compass).
Visible for $iss_pass.duration.
#else
No visible ISS pass in the coming week.
#end if
Guard on .visible rather than on a time: with no qualifying pass every attribute is an empty ValueHelper that renders N/A, and .visible is the flag that says so. next_visible_pass is deliberately strict — sunlit, sky dark, peaking at least 10° up — so use next_pass when you want every pass regardless of whether you could see it.
The three times print with their date — 06/22/2025 03:11:25 AM — because the pass being reported is anywhere in the coming week, which is what the #else branch above admits. To print a bare clock time instead, format the tag in place: $iss_pass.rise.format(format_string="%X"). Avoid overriding ephem_year in [Units] [[TimeFormats]] for this: that also restyles the equinoxes, the moon-phase and apsis finders, meteor-shower peaks and a comet’s perihelion (see how far away a time can be).
If a satellite’s elements have gone stale, everything reads N/A and these two say why:
Elements issued $almanac.iss.elements_epoch ($almanac.iss.elements_age old)
A comet, when there is one worth showing
#set $comet = $almanac.halley
#if $comet.mag
$comet.label is magnitude $comet.mag, $comet.distance from Earth,
in $comet.constellation.label. Perihelion: $comet.perihelion
#end if
A configured comet the Minor Planet Center has dropped reports N/A across the board rather than stale numbers, so guarding on mag keeps the block quiet until there is something to say. Remember the magnitude is the MPC’s formula — expectation, not measurement.
The next eclipse visible from here
The next eclipse visible from this station is a
$almanac.next_eclipse_type $almanac.next_eclipse_kind eclipse
on $almanac.next_eclipse.format("%B %e, %Y").
These three tags are designed to be used together: next_eclipse picks the sooner of the lunar and solar candidates, _kind says which it found, and _type gives the type as seen from your location — a station catching only the penumbra of a total solar eclipse honestly reports partial. Include the year: the next visible eclipse can be years out.
The next meteor shower, and whether the moon will ruin it
#set $shower = $almanac.next_meteor_shower
The $shower.label peak $shower.peak.format("%B %e") — up to $shower.zhr per hour,
radiating from $shower.parent's debris.
#set $moon_at_peak = $almanac(almanac_time=$shower.peak.raw).moon.phase
#if $moon_at_peak > 60
A $moon_at_peak% moon will wash out the fainter meteors.
#end if
That almanac_time= line is the time-travel idiom: it builds a new almanac at another instant and asks it an ordinary question. It is how the Sky page reports the moon’s interference honestly rather than quoting tonight’s moon for a shower three weeks away.
Time travel: the coming supermoon’s distance
#set $sm = $almanac.next_supermoon
#if $sm.raw
Next supermoon: $sm.format("%B %e, %Y"),
when the moon will be $almanac(almanac_time=$sm.raw).moon.distance.km from Earth.
#end if
The same idiom, and the reason next_supermoon exists as a tag at all: the rule (a full moon within a day of perigee) lives in the engine, so your page and every live page agree rather than each re-deriving it.
A planet roster
#for $body in ['mercury', 'venus', 'mars', 'jupiter', 'saturn']
#set $p = getattr($almanac, $body)
$p.label: rises $p.rise, magnitude $p.mag, in $p.constellation.label
#end for
getattr is how a template loops over bodies by name — the almanac binds each one as an attribute.
Guarding for “no answer”
Every recipe above assumes the honest-N/A contract: a tag with no answer renders N/A rather than breaking your page. When you want to hide a block instead of printing N/A, test .raw:
#if $almanac.mars.rise.raw
Mars rises $almanac.mars.rise
#end if
When you do arithmetic on a .raw value, pin the unit — $almanac.sun.visible.second.raw, $almanac.sunrise.unix_epoch.raw. An unpinned .raw follows the report’s own unit settings, which is how a page can silently start reporting hours where it means seconds. Values, units and types has the full story.
Where to go next
- Drawn panels — the dome, ribbons, orrery — are
$sky_pagemethods. - The same tags on a page that updates every few seconds: Live-updating pages.
- Everything available: the tag index.