I've recently come across PyEphem
https://rhodesmill.org/pyephem/index.html, which is a Python library which enables you to calculate the position of the sun and moon - and other celestial bodies, if you're into astronomy.
This is a very comprehensive library, which enables you to write some very compact code. Install as follows:
For example, the following will display the current sun altitude and azimuth at your location:
Code: Select all
import ephem
import datetime
home = ephem.Observer()
home.lat, home.lon = <your latitude in decimal degrees>, <your longitude in decimal degrees>
home.date = datetime.datetime.utcnow()
sun = ephem.Sun()
sun.compute(home)
print sun.alt, sun.az
I've created the following Python script, which will send the following to Domoticz:
- sun azimuth (°)
- sun altitude (°)
- moon azimuth (°)
- moon altitude (°)
- moon illumination (%)
- moon phase
- date & time of next moonrise
- date & time of next full moon
The first 5 are custom sensors, the last 3 are text sensors.
- Spoiler: show
Code: Select all
#!/usr/bin/python
import datetime
import ephem
from math import degrees as deg
import requests
format = "%Y-%m-%d %H:%M"
# Local latitude, longitude coordinates - decimal degrees
# latitude is +ve in Northern hemisphere, longitude is +ve east of Greenwich
home_lat, home_lon = 'xx.xxxx','xx.xxxx'
# Domoticz command stub and Idx's
baseURL = 'http://<domoticz url:port>/json.htm?type=command¶m=udevice&nvalue=0'
sun_azIdx, sun_altIdx = <xxx>, <xxx> # custom sensors, label: °
moon_azIdx, moon_altIdx = <xxx>, <xxx> # custom sensors, label: °
moon_illumIdx = <xxx> # custom sensors, label: %
moon_riseIdx, moon_fullIdx = <xxx>, <xxx> # text sensors
moon_phaseIdx = <xxx> # text sensor
def human_moon(home):
# Human-readable names for phases of the moon, taken from:
# https://stackoverflow.com/questions/26702144/human-readable-names-for-phases-of-the-moon-with-pyephem/26707918
target_date_utc = home.date
target_date_local = ephem.localtime(target_date_utc).date()
next_full = ephem.localtime(ephem.next_full_moon(target_date_utc)).date()
next_new = ephem.localtime(ephem.next_new_moon(target_date_utc)).date()
next_last_quarter = ephem.localtime(ephem.next_last_quarter_moon(target_date_utc)).date()
next_first_quarter = ephem.localtime(ephem.next_first_quarter_moon(target_date_utc)).date()
previous_full = ephem.localtime(ephem.previous_full_moon(target_date_utc)).date()
previous_new = ephem.localtime(ephem.previous_new_moon(target_date_utc)).date()
previous_last_quarter = ephem.localtime(ephem.previous_last_quarter_moon(target_date_utc)).date()
previous_first_quarter = ephem.localtime(ephem.previous_first_quarter_moon(target_date_utc)).date()
if target_date_local in (next_full, previous_full):
return 'Full'
elif target_date_local in (next_new, previous_new):
return 'New'
elif target_date_local in (next_first_quarter, previous_first_quarter):
return 'First quarter'
elif target_date_local in (next_last_quarter, previous_last_quarter):
return 'Last quarter'
elif previous_new < next_first_quarter < next_full < next_last_quarter < next_new:
return 'Waxing crescent'
elif previous_first_quarter < next_full < next_last_quarter < next_new < next_first_quarter:
return 'Waxing gibbous'
elif previous_full < next_last_quarter < next_new < next_first_quarter < next_full:
return 'Waning gibbous'
elif previous_last_quarter < next_new < next_first_quarter < next_full < next_last_quarter:
return 'Waning crescent'
home = ephem.Observer()
home.lat, home.lon = home_lat, home_lon
home.date = datetime.datetime.utcnow()
sun, moon = ephem.Sun(), ephem.Moon()
sun.compute(home)
sun_azimuth = round(deg(float(sun.az)),1)
sun_altitude = round(deg(float(sun.alt)),1)
sunrise = home.previous_rising(sun)
sunset = home.next_setting(sun)
moon.compute(home)
moon_azimuth = round(deg(float(moon.az)),1)
moon_altitude = round(deg(float(moon.alt)),1)
moon_illum = round(moon.phase,1)
moonrise = ephem.localtime(home.next_rising(moon)).strftime(format)
moonset = ephem.localtime(home.next_setting(moon)).strftime(format)
full_moon = ephem.localtime(ephem.next_full_moon(home.date)).strftime(format)
moon_phase = human_moon(home)
'''
print "date / time", home.date
#print sunrise, sunset
print "sun azimuth / altitude", sun_azimuth, sun_altitude
print "moon azimuth / altitude", moon_azimuth, moon_altitude
print "moon illumination", moon_illum
print "next moon rise / full moon", moonrise, full_moon
print "phase: ", moon_phase
'''
# Send data to Domoticz
url = baseURL + "&idx=%s&svalue=%s" % (sun_azIdx, sun_azimuth)
r = requests.get(url)
url = baseURL + "&idx=%s&svalue=%s" % (sun_altIdx, sun_altitude)
r = requests.get(url)
url = baseURL + "&idx=%s&svalue=%s" % (moon_azIdx, moon_azimuth)
r = requests.get(url)
url = baseURL + "&idx=%s&svalue=%s" % (moon_altIdx, moon_altitude)
r = requests.get(url)
url = baseURL + "&idx=%s&svalue=%s" % (moon_illumIdx, moon_illum)
r = requests.get(url)
url = baseURL + "&idx=%s&svalue=%s" % (moon_riseIdx, moonrise)
r = requests.get(url)
url = baseURL + "&idx=%s&svalue=%s" % (moon_fullIdx, full_moon)
r = requests.get(url)
url = baseURL + "&idx=%s&svalue=%s" % (moon_phaseIdx, moon_phase)
r = requests.get(url)
Edit latitude, longitude and Domoticz values as appropriate.
Run this with cron, every 5 minutes (or whatever - the text devices don't need to be updated that frequently).
