
The phase above is shown as seen in the Southern Hemisphere. That choice, along with several other things are configurable.
The phase is approximate, based on the date and time, a configured reference New Moon and a fixed nominal lunar period.
The code keeps track of the approximate time and date using the Atmega32U4's built-in oscillator. This will cause unbounded drift.
To keep the drift constrained, the code monitors the LDR. Every minute the LDR reading (i.e. ambient light) is classified as Dark or Light (Night or Day). These values are averaged into 10-minute intervals also classified as Dark or Light.
When this monitoring code detects a Light interval that was preceded by sufficiently long period of Dark intervals it concludes that dawn has occurred. It assumes the Dark period was night and that midnight was the midpoint. It adjusts the approximate time accordingly. The date will have already advanced. Note that there are sanity checks applied to the adjustment and shift factors.
The time will always be a little off, but for our purposes that doesn't matter -- the date is the important thing and it should never deviate.

There's a small 128x32 OLED display and two push-buttons for configuration etc (the ePaper is too slow for interaction). Two other faces are available: a calendar and just the current date.
For many many more details see the bulk comment in QuotidianMoon.ino on GitHub..
Mark Wilson
PTIdea
Stephen Holdaway
Using the LDR to find midnight is a great hack. The case that'll bite is a lamp left on all night, or the thing sitting in a drawer for a day, so I'm curious what the sanity checks do when a night looks too short or never ends. If it ever gets annoying, a DS3231 is a few dollars and two I2C pins, but the LDR version is way more fun.