MotionEyeOS Day and Night Python script: Difference between revisions
From WickyWiki
mNo edit summary |
mNo edit summary |
||
| Line 38: | Line 38: | ||
import os.path | import os.path | ||
import shutil | import shutil | ||
import | import time as time2 | ||
# | # Variant of time zone available on MotionEyeOS | ||
localTimezone = timezone('Europe/Amsterdam') | localTimezone = timezone('Europe/Amsterdam') | ||
# Location of here in lat / long | # Location of here in lat / long | ||
localLat = 51. | localLat = 51.49 | ||
localLong = 5. | localLong = 5.48 | ||
# Sunrise and sunset | # Sunrise and sunset delay (in minutes) | ||
# | # + is later, - is earlier. | ||
sunriseDelayMins = -10 | |||
sunsetDelayMins = +10 | |||
# Current state of day / night is stored in this file. | # Current state of day / night is stored in this file. | ||
dayNightStateFile = '/data/etc/daynight/daynight.dat' | |||
# sun module | |||
class sun: | class sun: | ||
""" | """ | ||
| Line 61: | Line 61: | ||
http://www.srrb.noaa.gov/highlights/sunrise/calcdetails.html | http://www.srrb.noaa.gov/highlights/sunrise/calcdetails.html | ||
""" | """ | ||
def __init__(self,lat=52.37,long=4.90): | def __init__(self,lat=52.37,long=4.90,when=None): | ||
""" | |||
default Amsterdam + local time zone | |||
(including daylight saving if present) | |||
""" | |||
self.lat=lat | self.lat=lat | ||
self.long=long | self.long=long | ||
if when is None : when = datetime.now(tz=localTimezone) | if when is None : when = datetime.now(tz=localTimezone) | ||
self.__preptime(when) | self.__preptime(when) | ||
self.__calc() | self.__calc() | ||
""" | """ | ||
The two fudge factors are in minutes. Negative is earlier. | The two fudge factors are in minutes. Negative is earlier. | ||
| Line 122: | Line 105: | ||
a datetime.datetime object. | a datetime.datetime object. | ||
""" | """ | ||
self.day = when.toordinal()-(734124-40529) | self.day = when.toordinal()-(734124-40529) | ||
t=when.time() | t=when.time() | ||
| Line 139: | Line 117: | ||
""" | """ | ||
Perform the actual calculations for sunrise, sunset and | Perform the actual calculations for sunrise, sunset and | ||
a number of related quantities. | a number of related quantities. | ||
The results are stored in the instance variables | The results are stored in the instance variables | ||
sunrise_t, sunset_t and solarnoon_t | sunrise_t, sunset_t and solarnoon_t | ||
| Line 184: | Line 161: | ||
f.write(data) | f.write(data) | ||
f.close() | f.close() | ||
# The main program | |||
if __name__ == "__main__": | |||
# Calculate | |||
s=sun(lat=localLat,long=localLong) | s=sun(lat=localLat,long=localLong) | ||
# | # Previous day/night -state from file. | ||
fileDayOrNight = readLineOfFile( | fileDayOrNight = readLineOfFile(dayNightStateFile) | ||
# | # Log | ||
print(datetime.now().strftime('%Y-%m-%d_%H.%M.%S ') | print(datetime.now().strftime('%Y-%m-%d_%H.%M.%S ') | ||
+ 'Day ' + sun.timefromdecimalday(s.sunrise_t).strftime('%H.%M') + ['', '+'][ | + 'Day from ' + sun.timefromdecimalday(s.sunrise_t).strftime('%H.%M') + ['(', '(+'][sunriseDelayMins > 0] + str(sunriseDelayMins)+')' | ||
+ ' | + ' to ' + sun.timefromdecimalday(s.sunset_t).strftime('%H.%M') + ['(', '(+'][sunsetDelayMins > 0] + str(sunsetDelayMins)+')' | ||
+ ', state: ' + fileDayOrNight | + ', current state: ' + fileDayOrNight | ||
) | ) | ||
# Current day/night -state based on time-of-day. | |||
currentDayOrNight = s.dayornight(sunriseFudge=sunriseDelayMins,sunsetFudge=sunsetDelayMins) | |||
# New day/night -state? | |||
if fileDayOrNight != currentDayOrNight: | if fileDayOrNight != currentDayOrNight: | ||
print(datetime.now().strftime('%Y-%m-%d_%H:%M:%S ') + 'Changing state to: ' + currentDayOrNight) | print(datetime.now().strftime('%Y-%m-%d_%H:%M:%S ') + 'Changing state to: ' + currentDayOrNight) | ||
# | # Backup the old settings if the selected config is newer | ||
if | if os.stat("/data/etc/thread-1.conf").st_mtime > os.stat("/data/etc/thread-1.conf." + fileDayOrNight).st_mtime: | ||
# | # Backup old day/night settings file | ||
shutil. | shutil.copy2("/data/etc/thread-1.conf." + fileDayOrNight | ||
, | , "/data/etc/thread-1.conf." + fileDayOrNight + "." + datetime.now().strftime('%Y-%m-%d_%H.%M')) | ||
# | # Store new day/night settings file | ||
shutil. | shutil.copy2("/data/etc/thread-1.conf", "/data/etc/thread-1.conf." + fileDayOrNight) | ||
# | # Select the other day/night settings file | ||
shutil. | shutil.copy2("/data/etc/thread-1.conf." + currentDayOrNight, "/data/etc/thread-1.conf") | ||
print(datetime.now().strftime('%Y-%m-%d_%H:%M:%S ') + ' | # Restart MotionEye | ||
os.system("/etc/init.d/S85motioneye | print(datetime.now().strftime('%Y-%m-%d_%H:%M:%S ') + 'Stop MotionEye...') | ||
print(datetime.now().strftime('%Y-%m-%d_%H:%M:%S ') + 'MotionEye | os.system("/etc/init.d/S85motioneye stop") | ||
time2.sleep(10) | |||
print(datetime.now().strftime('%Y-%m-%d_%H:%M:%S ') + 'Start MotionEye...') | |||
os.system("/etc/init.d/S85motioneye start") | |||
print(datetime.now().strftime('%Y-%m-%d_%H:%M:%S ') + 'MotionEye Started.') | |||
# Update | # Update day/night -state file | ||
updateContentsOfFile( | updateContentsOfFile(dayNightStateFile, currentDayOrNight) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Revision as of 19:22, 7 March 2019
See also:
Source:
Setup crontab to execute the script (here every 10 minutes)
crontab -e
02,12,22,32,42,52 * * * * /usr/bin/python /data/etc/daynight/daynight.py >> /data/log/daynight.log
Setup logrotate to limit the size of the logfile.
Script
nano /data/etc/daynight/daynight.py
from math import cos,sin,acos,asin,tan
from math import degrees as deg, radians as rad
from datetime import date,datetime,time
from pytz import timezone
import os
import os.path
import shutil
import time as time2
# Variant of time zone available on MotionEyeOS
localTimezone = timezone('Europe/Amsterdam')
# Location of here in lat / long
localLat = 51.49
localLong = 5.48
# Sunrise and sunset delay (in minutes)
# + is later, - is earlier.
sunriseDelayMins = -10
sunsetDelayMins = +10
# Current state of day / night is stored in this file.
dayNightStateFile = '/data/etc/daynight/daynight.dat'
# sun module
class sun:
"""
Calculate sunrise and sunset based on equations from NOAA
http://www.srrb.noaa.gov/highlights/sunrise/calcdetails.html
"""
def __init__(self,lat=52.37,long=4.90,when=None):
"""
default Amsterdam + local time zone
(including daylight saving if present)
"""
self.lat=lat
self.long=long
if when is None : when = datetime.now(tz=localTimezone)
self.__preptime(when)
self.__calc()
"""
The two fudge factors are in minutes. Negative is earlier.
"""
def dayornight(self,now=None,sunriseFudge=0,sunsetFudge=0):
if now is None : now = datetime.now(tz=localTimezone)
self.__preptime(when=now)
self.__calc()
sunriseFudge = sunriseFudge/60.0/24.0
sunsetFudge = sunsetFudge/60.0/24.0
if (self.time >= (self.sunrise_t + sunriseFudge) and self.time <= (self.sunset_t + sunsetFudge)):
return 'day'
else:
return 'night'
@staticmethod
def timefromdecimalday(day):
"""
returns a datetime.time object.
day is a decimal day between 0.0 and 1.0, e.g. noon = 0.5
"""
hours = 24.0*day
h = int(hours)
minutes= (hours-h)*60
m = int(minutes)
seconds= (minutes-m)*60
s = int(seconds)
return time(hour=h,minute=m,second=s)
def __preptime(self,when):
"""
Extract information in a suitable format from when,
a datetime.datetime object.
"""
self.day = when.toordinal()-(734124-40529)
t=when.time()
self.time= (t.hour + t.minute/60.0 + t.second/3600.0)/24.0
self.timezone=0
offset=when.utcoffset()
if not offset is None:
self.timezone=offset.seconds/3600.0
def __calc(self):
"""
Perform the actual calculations for sunrise, sunset and
a number of related quantities.
The results are stored in the instance variables
sunrise_t, sunset_t and solarnoon_t
"""
timezone = self.timezone # in hours, east is positive
longitude= self.long # in decimal degrees, east is positive
latitude = self.lat # in decimal degrees, north is positive
time = self.time # percentage past midnight, i.e. noon is 0.5
day = self.day # daynumber 1=1/1/1900
Jday = day+2415018.5+time-timezone/24 # Julian day
Jcent = (Jday-2451545)/36525 # Julian century
Manom = 357.52911+Jcent*(35999.05029-0.0001537*Jcent)
Mlong = 280.46646+Jcent*(36000.76983+Jcent*0.0003032)%360
Eccent = 0.016708634-Jcent*(0.000042037+0.0001537*Jcent)
Mobliq = 23+(26+((21.448-Jcent*(46.815+Jcent*(0.00059-Jcent*0.001813))))/60)/60
obliq = Mobliq+0.00256*cos(rad(125.04-1934.136*Jcent))
vary = tan(rad(obliq/2))*tan(rad(obliq/2))
Seqcent = sin(rad(Manom))*(1.914602-Jcent*(0.004817+0.000014*Jcent))+sin(rad(2*Manom))*(0.019993-0.000101*Jcent)+sin(rad(3*Manom))*0.000289
Struelong= Mlong+Seqcent
Sapplong = Struelong-0.00569-0.00478*sin(rad(125.04-1934.136*Jcent))
declination = deg(asin(sin(rad(obliq))*sin(rad(Sapplong))))
eqtime = 4*deg(vary*sin(2*rad(Mlong))-2*Eccent*sin(rad(Manom))+4*Eccent*vary*sin(rad(Manom))*cos(2*rad(Mlong))-0.5*vary*vary*sin(4*rad(Mlong))-1.25*Eccent*Eccent*sin(2*rad(Manom)))
hourangle= deg(acos(cos(rad(90.833))/(cos(rad(latitude))*cos(rad(declination)))-tan(rad(latitude))*tan(rad(declination))))
self.solarnoon_t=(720-4*longitude-eqtime+timezone*60)/1440
self.sunrise_t =self.solarnoon_t-hourangle*4/1440
self.sunset_t =self.solarnoon_t+hourangle*4/1440
def readLineOfFile(path):
if not os.path.isfile(path): return ""
f = open(path, "r")
result = f.readline()
f.close()
return result.rstrip()
def updateContentsOfFile(path, data):
f = open(path, "w")
f.write(data)
f.close()
# The main program
if __name__ == "__main__":
# Calculate
s=sun(lat=localLat,long=localLong)
# Previous day/night -state from file.
fileDayOrNight = readLineOfFile(dayNightStateFile)
# Log
print(datetime.now().strftime('%Y-%m-%d_%H.%M.%S ')
+ 'Day from ' + sun.timefromdecimalday(s.sunrise_t).strftime('%H.%M') + ['(', '(+'][sunriseDelayMins > 0] + str(sunriseDelayMins)+')'
+ ' to ' + sun.timefromdecimalday(s.sunset_t).strftime('%H.%M') + ['(', '(+'][sunsetDelayMins > 0] + str(sunsetDelayMins)+')'
+ ', current state: ' + fileDayOrNight
)
# Current day/night -state based on time-of-day.
currentDayOrNight = s.dayornight(sunriseFudge=sunriseDelayMins,sunsetFudge=sunsetDelayMins)
# New day/night -state?
if fileDayOrNight != currentDayOrNight:
print(datetime.now().strftime('%Y-%m-%d_%H:%M:%S ') + 'Changing state to: ' + currentDayOrNight)
# Backup the old settings if the selected config is newer
if os.stat("/data/etc/thread-1.conf").st_mtime > os.stat("/data/etc/thread-1.conf." + fileDayOrNight).st_mtime:
# Backup old day/night settings file
shutil.copy2("/data/etc/thread-1.conf." + fileDayOrNight
, "/data/etc/thread-1.conf." + fileDayOrNight + "." + datetime.now().strftime('%Y-%m-%d_%H.%M'))
# Store new day/night settings file
shutil.copy2("/data/etc/thread-1.conf", "/data/etc/thread-1.conf." + fileDayOrNight)
# Select the other day/night settings file
shutil.copy2("/data/etc/thread-1.conf." + currentDayOrNight, "/data/etc/thread-1.conf")
# Restart MotionEye
print(datetime.now().strftime('%Y-%m-%d_%H:%M:%S ') + 'Stop MotionEye...')
os.system("/etc/init.d/S85motioneye stop")
time2.sleep(10)
print(datetime.now().strftime('%Y-%m-%d_%H:%M:%S ') + 'Start MotionEye...')
os.system("/etc/init.d/S85motioneye start")
print(datetime.now().strftime('%Y-%m-%d_%H:%M:%S ') + 'MotionEye Started.')
# Update day/night -state file
updateContentsOfFile(dayNightStateFile, currentDayOrNight)