Hi Justus,
that would be it, just a very crude piece of python. Run on a Linux terminal with e.g.
$ nohup local.py > log.txt &
and it should stay running until the machine is shut down. All you need then is a mqtt broker. I added the “tomorrow” computation without running it, so please make sure I did not make a typo or so. As I said before the difference between today and tomorrow is typically only a few minutes away from 24hrs.
The script local.py:
#!/usr/bin/python3
import ephem
import datetime, time
import paho.mqtt.client as mqtt
mqtt_broker="127.0.0.1"
mqttc = mqtt.Client()
mqttc.connect(mqtt_broker, 1883, 60)
# define location Local and start of today
local = ephem.Observer()
local.lat = '<lat>'
local.lon = '<lon>'
local.elevation = 500
tomorrow = local
sun = ephem.Sun()
old = 0
sun_alt_old = 0
sun_az_old = 0
moon_alt_old = 0
moon_az_old = 0
moon_fli_old = 0
mqttc.loop_start()
while True:
now = ephem.Date(datetime.datetime.utcnow())
# Make sure we have today's date and times:
if (now - old) > 1.0:
# IMPORTANT: This is in UTC. If you live significantly away from lon=0, adjust for your timezone by subtracting TZ-offset
# This is to make sure the computation is done after dusk and before dawn. Otherwise no effect, so needs not be precise.
# E.g. subtracting "lon/360" will do just fine, unless you live in arctic regions.
local.date = ephem.Date(datetime.datetime.utcnow().date())
old = local.date
# Compute the relevant time points:
sunrise = local.next_rising(sun)
sunset = local.next_setting(sun)
transit = local.next_transit(sun)
# Modify "horizon" altitude for dusk and dawn. Common values are 6,12,18 (civil, nautical, astro)
local.horizon = '-12'
dawn = local.next_rising(sun)
dusk = local.next_setting(sun)
local.horizon = '0'
#
mqttc.publish('local/sun/dawn', payload=int(dawn.datetime().replace(tzinfo=datetime.timezone.utc).timestamp()), qos=0, retain=True)
mqttc.publish('local/sun/rise', payload=int(sunrise.datetime().replace(tzinfo=datetime.timezone.utc).timestamp()), qos=0, retain=True)
mqttc.publish('local/sun/transit', payload=int(transit.datetime().replace(tzinfo=datetime.timezone.utc).timestamp()), qos=0, retain=True)
mqttc.publish('local/sun/set', payload=int(sunset.datetime().replace(tzinfo=datetime.timezone.utc).timestamp()), qos=0, retain=True)
mqttc.publish('local/sun/dusk', payload=int(dusk.datetime().replace(tzinfo=datetime.timezone.utc).timestamp()), qos=0, retain=True)
tomorrow.date = local.date + 1
# Compute the relevant time points tomorrow:
sunrise_t = tomorrow.next_rising(sun)
sunset_t = tomorrow.next_setting(sun)
transit_t = tomorrow.next_transit(sun)
# Modify "horizon" altitude for dusk and dawn.
tomorrow.horizon = '-12'
dawn_t = tomorrow.next_rising(sun)
dusk_t = tomorrow.next_setting(sun)
tomorrow.horizon = '0'
mqttc.publish('tomorrow/sun/dawn', payload=int(dawn_t.datetime().replace(tzinfo=datetime.timezone.utc).timestamp()), qos=0, retain=True)
mqttc.publish('tomorrow/sun/rise', payload=int(sunrise_t.datetime().replace(tzinfo=datetime.timezone.utc).timestamp()), qos=0, retain=True)
mqttc.publish('tomorrow/sun/transit', payload=int(transit_t.datetime().replace(tzinfo=datetime.timezone.utc).timestamp()), qos=0, retain=True)
mqttc.publish('tomorrow/sun/set', payload=int(sunset_t.datetime().replace(tzinfo=datetime.timezone.utc).timestamp()), qos=0, retain=True)
mqttc.publish('tomorrow/sun/dusk', payload=int(dusk_t.datetime().replace(tzinfo=datetime.timezone.utc).timestamp()), qos=0, retain=True)
# Compute Sun and Moon for now and publish if changed
local.date = now
sol = ephem.Sun(local)
luna = ephem.Moon(local)
sun_alt = int(sol.alt*180/ephem.pi)
if sun_alt != sun_alt_old:
mqttc.publish('local/sun/alt', payload=sun_alt, qos=0, retain=True)
sun_alt_old = sun_alt
sun_az = int(sol.az*180/ephem.pi)
if sun_az != sun_az_old:
mqttc.publish('local/sun/az', payload=sun_az, qos=0, retain=True)
sun_az_old = sun_az
moon_alt = int(luna.alt*180/ephem.pi)
if moon_alt != moon_alt_old:
mqttc.publish('local/moon/alt', payload=moon_alt, qos=0, retain=True)
moon_alt_old = moon_alt
moon_az = int(luna.az*180/ephem.pi)
if moon_az != moon_az_old:
mqttc.publish('local/moon/az', payload=moon_az, qos=0, retain=True)
moon_az_old = moon_az
moon_fli = int(luna.phase)
if moon_fli != moon_fli_old:
mqttc.publish('local/moon/fli', payload=moon_fli, qos=0, retain=True)
moon_fli_old = moon_fli
time.sleep(10)
In openhab then have the items from mqtt defined like this (vers 2.3 or lower, I’ve heard 2.4 may look different, but I don’t run it):
//
// Solar and lunar data f. Local
DateTime Local_Dawn {mqtt="<[raspi-serverMQTT:local/sun/dawn:state:JS(timestamp.js)]"}
DateTime Local_Rise {mqtt="<[raspi-serverMQTT:local/sun/rise:state:JS(timestamp.js)]"}
DateTime Local_Transit {mqtt="<[raspi-serverMQTT:local/sun/transit:state:JS(timestamp.js)]"}
DateTime Local_Set {mqtt="<[raspi-serverMQTT:local/sun/set:state:JS(timestamp.js)]"}
DateTime Local_Dusk {mqtt="<[raspi-serverMQTT:local/sun/dusk:state:JS(timestamp.js)]"}
DateTime Tomorrow_Dawn {mqtt="<[raspi-serverMQTT:tomorrow/sun/dawn:state:JS(timestamp.js)]"}
DateTime Tomorrow_Rise {mqtt="<[raspi-serverMQTT:tomorrow/sun/rise:state:JS(timestamp.js)]"}
DateTime Tomorrow_Transit {mqtt="<[raspi-serverMQTT:tomorrow/sun/transit:state:JS(timestamp.js)]"}
DateTime Tomorrow_Set {mqtt="<[raspi-serverMQTT:tomorrow/sun/set:state:JS(timestamp.js)]"}
DateTime Tomorrow_Dusk {mqtt="<[raspi-serverMQTT:tomorrow/sun/dusk:state:JS(timestamp.js)]"}
Number Local_SunAlt {mqtt="<[raspi-serverMQTT:local/sun/alt:state:default]"}
Number Local_SunAz {mqtt="<[raspi-serverMQTT:local/sun/az:state:default]"}
Number Local_MoonAlt {mqtt="<[raspi-serverMQTT:local/moon/alt:state:default]"}
Number Local_MoonAz {mqtt="<[raspi-serverMQTT:local/moon/az:state:default]"}
Number Local_MoonFLI {mqtt="<[raspi-serverMQTT:local/moon/fli:state:default]"}
and the timestamp.js transformation is just:
(function(i) {
var date = new Date(i * 1000.);
return date.toISOString();
})(input)