While looking for accurate algorithms I stumbled upon this tread. I gave skyfield
a try. Installing on openHABian was straightforward:
$ sudo pip install skyfield
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting skyfield
Downloading https://files.pythonhosted.org/packages/98/ab/d2c3efc399e8531eaa1c1e368135fe7a53fd1e29469bc6409f1b32cd90a9/skyfield-1.15.tar.gz (226kB)
100% |████████████████████████████████| 235kB 918kB/s
Collecting jplephem>=2.3 (from skyfield)
Downloading https://files.pythonhosted.org/packages/00/70/d6f31d1e3bdc43d170280426a8a91dcbba1a1698360695424b198e567de5/jplephem-2.11.tar.gz
Requirement already satisfied: numpy in /usr/local/lib/python2.7/dist-packages (from skyfield) (1.16.5)
Collecting sgp4>=1.4 (from skyfield)
Downloading https://files.pythonhosted.org/packages/d2/00/3f3699203176017211a71fe16e3fa71bae946ac92ade77d5a2ffc5da8576/sgp4-1.4.tar.gz
Building wheels for collected packages: skyfield, jplephem, sgp4
Running setup.py bdist_wheel for skyfield ... done
Stored in directory: /root/.cache/pip/wheels/e5/b5/b2/4aaf2c25bb51376bd0ebeb7671f2223c2732101b77c500eaa2
Running setup.py bdist_wheel for jplephem ... done
Stored in directory: /root/.cache/pip/wheels/c1/6f/9e/392c7e798a41b202e6008e8cf711a04c9aafebb7fc684c1d94
Running setup.py bdist_wheel for sgp4 ... done
Stored in directory: /root/.cache/pip/wheels/6d/e2/42/5dc20daf2ba62ae03dc8abe10744ee67d9452df447dac561db
Successfully built skyfield jplephem sgp4
Installing collected packages: jplephem, sgp4, skyfield
Successfully installed jplephem-2.11 sgp4-1.4 skyfield-1.15
And running from the interactive shell:
$ python
Python 2.7.16 (default, Oct 10 2019, 22:02:15)
[GCC 8.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from skyfield import api
>>>
>>> ts = api.load.timescale()
[#################################] 100% deltat.data
[#################################] 100% deltat.preds
[#################################] 100% Leap_Second.dat
>>> e = api.load('de421.bsp')
[#################################] 100% de421.bsp
>>> from skyfield import almanac
>>> t0 = ts.utc(2019,1,1)
>>> t1 = ts.utc(2019,12,31)
>>> t, y = almanac.find_discrete(t0, t1, almanac.moon_phases(e))
>>> print(t.utc_iso())
['2019-01-06T01:28:11Z', '2019-01-14T06:45:31Z', '2019-01-21T05:16:05Z', '2019-01-27T21:10:20Z', '2019-02-04T21:03:35Z', '2019-02-12T22:26:14Z', '2019-02-19T15:53:35Z', '2019-02-26T11:27:43Z', '2019-03-06T16:03:58Z', '2019-03-14T10:27:05Z', '2019-03-21T01:42:52Z', '2019-03-28T04:09:41Z', '2019-04-05T08:50:29Z', '2019-04-12T19:05:53Z', '2019-04-19T11:12:10Z', '2019-04-26T22:18:18Z', '2019-05-04T22:45:30Z', '2019-05-12T01:12:14Z', '2019-05-18T21:11:21Z', '2019-05-26T16:33:35Z', '2019-06-03T10:01:57Z', '2019-06-10T05:59:18Z', '2019-06-17T08:30:40Z', '2019-06-25T09:46:24Z', '2019-07-02T19:16:13Z', '2019-07-09T10:54:51Z', '2019-07-16T21:38:13Z', '2019-07-25T01:18:01Z', '2019-08-01T03:11:55Z', '2019-08-07T17:30:57Z', '2019-08-15T12:29:15Z', '2019-08-23T14:56:06Z', '2019-08-30T10:37:09Z', '2019-09-06T03:10:26Z', '2019-09-14T04:32:46Z', '2019-09-22T02:40:54Z', '2019-09-28T18:26:22Z', '2019-10-05T16:47:06Z', '2019-10-13T21:07:52Z', '2019-10-21T12:39:18Z', '2019-10-28T03:38:28Z', '2019-11-04T10:23:05Z', '2019-11-12T13:34:24Z', '2019-11-19T21:10:56Z', '2019-11-26T15:05:35Z', '2019-12-04T06:58:13Z', '2019-12-12T05:12:16Z', '2019-12-19T04:57:05Z', '2019-12-26T05:13:08Z']
>>> print(y)
[0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0
1 2 3 0 1 2 3 0 1 2 3 0]
>>> print([almanac.MOON_PHASES[yi] for yi in y])
['New Moon', 'First Quarter', 'Full Moon', 'Last Quarter', 'New Moon', 'First Quarter', 'Full Moon', 'Last Quarter', 'New Moon', 'First Quarter', 'Full Moon', 'Last Quarter', 'New Moon', 'First Quarter', 'Full Moon', 'Last Quarter', 'New Moon', 'First Quarter', 'Full Moon', 'Last Quarter', 'New Moon', 'First Quarter', 'Full Moon', 'Last Quarter', 'New Moon', 'First Quarter', 'Full Moon', 'Last Quarter', 'New Moon', 'First Quarter', 'Full Moon', 'Last Quarter', 'New Moon', 'First Quarter', 'Full Moon', 'Last Quarter', 'New Moon', 'First Quarter', 'Full Moon', 'Last Quarter', 'New Moon', 'First Quarter', 'Full Moon', 'Last Quarter', 'New Moon', 'First Quarter', 'Full Moon', 'Last Quarter', 'New Moon']
>>>
So the accurate timestamp of yesterday’s Full Moon is 2019-12-12T05:12:16Z (Dec 12, 2019 @ 05:12:16 AM UTC).
As you see the almanac returns results in UTC. These must be converted back to local time, which may shift the lunar phase by 1 day from time to time.
And here’s a way to quickly display the almanac in UTC and local time (make sure to define the interval as the full year + 31/12 + 01/01 to ensure you capture all lunar phase events in a calendar year in local time:
>>> t0 = ts.utc(2018, 12, 31)
>>> t1 = ts.utc(2020,1, 1)
>>> t, y = almanac.find_discrete(t0, t1, almanac.moon_phases(e))
>>> for ts_utc, phase in zip(t, y):
... print "{}\t{} UTC\t{} local time".format(("%-16s" % almanac.MOON_PHASES[phase]), ts_utc.astimezone(from_zone), ts_utc.astimezone(to_zone))
...
New Moon 2019-01-06 01:28:11.221000+00:00 UTC 2019-01-06 02:28:11.221000+01:00 local time
First Quarter 2019-01-14 06:45:31.132000+00:00 UTC 2019-01-14 07:45:31.132000+01:00 local time
Full Moon 2019-01-21 05:16:04.684000+00:00 UTC 2019-01-21 06:16:04.684000+01:00 local time
Last Quarter 2019-01-27 21:10:20.257000+00:00 UTC 2019-01-27 22:10:20.257000+01:00 local time
New Moon 2019-02-04 21:03:34.875000+00:00 UTC 2019-02-04 22:03:34.875000+01:00 local time
First Quarter 2019-02-12 22:26:13.948000+00:00 UTC 2019-02-12 23:26:13.948000+01:00 local time
Full Moon 2019-02-19 15:53:34.539000+00:00 UTC 2019-02-19 16:53:34.539000+01:00 local time
Last Quarter 2019-02-26 11:27:42.842000+00:00 UTC 2019-02-26 12:27:42.842000+01:00 local time
New Moon 2019-03-06 16:03:58.269000+00:00 UTC 2019-03-06 17:03:58.269000+01:00 local time
First Quarter 2019-03-14 10:27:05.233000+00:00 UTC 2019-03-14 11:27:05.233000+01:00 local time
Full Moon 2019-03-21 01:42:51.567000+00:00 UTC 2019-03-21 02:42:51.567000+01:00 local time
Last Quarter 2019-03-28 04:09:41.192000+00:00 UTC 2019-03-28 05:09:41.192000+01:00 local time
New Moon 2019-04-05 08:50:28.624000+00:00 UTC 2019-04-05 10:50:28.624000+02:00 local time
First Quarter 2019-04-12 19:05:52.970000+00:00 UTC 2019-04-12 21:05:52.970000+02:00 local time
Full Moon 2019-04-19 11:12:10.205000+00:00 UTC 2019-04-19 13:12:10.205000+02:00 local time
Last Quarter 2019-04-26 22:18:17.812000+00:00 UTC 2019-04-27 00:18:17.812000+02:00 local time
New Moon 2019-05-04 22:45:29.812000+00:00 UTC 2019-05-05 00:45:29.812000+02:00 local time
First Quarter 2019-05-12 01:12:14.118000+00:00 UTC 2019-05-12 03:12:14.118000+02:00 local time
Full Moon 2019-05-18 21:11:21.081000+00:00 UTC 2019-05-18 23:11:21.081000+02:00 local time
Last Quarter 2019-05-26 16:33:34.968000+00:00 UTC 2019-05-26 18:33:34.968000+02:00 local time
New Moon 2019-06-03 10:01:56.654000+00:00 UTC 2019-06-03 12:01:56.654000+02:00 local time
First Quarter 2019-06-10 05:59:17.999000+00:00 UTC 2019-06-10 07:59:17.999000+02:00 local time
Full Moon 2019-06-17 08:30:39.681000+00:00 UTC 2019-06-17 10:30:39.681000+02:00 local time
Last Quarter 2019-06-25 09:46:23.763000+00:00 UTC 2019-06-25 11:46:23.763000+02:00 local time
New Moon 2019-07-02 19:16:12.664000+00:00 UTC 2019-07-02 21:16:12.664000+02:00 local time
First Quarter 2019-07-09 10:54:51.155000+00:00 UTC 2019-07-09 12:54:51.155000+02:00 local time
Full Moon 2019-07-16 21:38:13.077000+00:00 UTC 2019-07-16 23:38:13.077000+02:00 local time
Last Quarter 2019-07-25 01:18:01.468000+00:00 UTC 2019-07-25 03:18:01.468000+02:00 local time
New Moon 2019-08-01 03:11:55.249000+00:00 UTC 2019-08-01 05:11:55.249000+02:00 local time
First Quarter 2019-08-07 17:30:57.356000+00:00 UTC 2019-08-07 19:30:57.356000+02:00 local time
Full Moon 2019-08-15 12:29:15.253000+00:00 UTC 2019-08-15 14:29:15.253000+02:00 local time
Last Quarter 2019-08-23 14:56:06.001000+00:00 UTC 2019-08-23 16:56:06.001000+02:00 local time
New Moon 2019-08-30 10:37:08.502000+00:00 UTC 2019-08-30 12:37:08.502000+02:00 local time
First Quarter 2019-09-06 03:10:25.639000+00:00 UTC 2019-09-06 05:10:25.639000+02:00 local time
Full Moon 2019-09-14 04:32:45.902000+00:00 UTC 2019-09-14 06:32:45.902000+02:00 local time
Last Quarter 2019-09-22 02:40:54.116000+00:00 UTC 2019-09-22 04:40:54.116000+02:00 local time
New Moon 2019-09-28 18:26:21.566000+00:00 UTC 2019-09-28 20:26:21.566000+02:00 local time
First Quarter 2019-10-05 16:47:06.199000+00:00 UTC 2019-10-05 18:47:06.199000+02:00 local time
Full Moon 2019-10-13 21:07:52.232000+00:00 UTC 2019-10-13 23:07:52.232000+02:00 local time
Last Quarter 2019-10-21 12:39:18.100000+00:00 UTC 2019-10-21 14:39:18.100000+02:00 local time
New Moon 2019-10-28 03:38:27.754000+00:00 UTC 2019-10-28 04:38:27.754000+01:00 local time
First Quarter 2019-11-04 10:23:04.635000+00:00 UTC 2019-11-04 11:23:04.635000+01:00 local time
Full Moon 2019-11-12 13:34:24.114000+00:00 UTC 2019-11-12 14:34:24.114000+01:00 local time
Last Quarter 2019-11-19 21:10:56.019000+00:00 UTC 2019-11-19 22:10:56.019000+01:00 local time
New Moon 2019-11-26 15:05:35.280000+00:00 UTC 2019-11-26 16:05:35.280000+01:00 local time
First Quarter 2019-12-04 06:58:13.304000+00:00 UTC 2019-12-04 07:58:13.304000+01:00 local time
Full Moon 2019-12-12 05:12:15.923000+00:00 UTC 2019-12-12 06:12:15.923000+01:00 local time
Last Quarter 2019-12-19 04:57:04.968000+00:00 UTC 2019-12-19 05:57:04.968000+01:00 local time
New Moon 2019-12-26 05:13:07.751000+00:00 UTC 2019-12-26 06:13:07.751000+01:00 local time
>>>
It appears that we reach millisecond accuracy with skyfield
.
And you’ll also see that sometimes the UTC date for a given precise lunar phase differs from the local time date, as is the case with:
Last Quarter 2019-04-26 22:18:17.812000+00:00 UTC 2019-04-27 00:18:17.812000+02:00 local time
New Moon 2019-05-04 22:45:29.812000+00:00 UTC 2019-05-05 00:45:29.812000+02:00 local time
An option is to replace the current astro binding with a JSR223 Python implemented rule that uses skyfield
. To do so, ask pip
to install skyfield
(and other dependencies) in /etc/openhab2/automation/lib/python/
so the rules can use skyfield
:
$ pip install --target=/etc/openhab2/automation/lib/python skyfield
A starting point is e.g. Almanac Computation