MotionEyeOS Day and Night Python script: Difference between revisions
From WickyWiki
mNo edit summary |
mNo edit summary |
||
| Line 9: | Line 9: | ||
Source: | Source: | ||
* https://blog.ligos.net/2016-04-18/Day-Night-Cycle-For-MotionEye.html | * https://blog.ligos.net/2016-04-18/Day-Night-Cycle-For-MotionEye.html | ||
Setup crontab to execute the script (here every 10 minutes) | |||
<syntaxhighlight lang=bash> | |||
crontab -e | |||
</syntaxhighlight> | |||
<blockquote> | |||
<syntaxhighlight lang=bash> | |||
02,12,22,32,42,52 * * * * /usr/bin/python /data/script_daynight/daynight.py >> /data/script_daynight/daynight.log | |||
</syntaxhighlight> | |||
</blockquote> | |||
Setup [[How To Manage Logfiles with Logrotate|logrotate]] to limit the size of the logfile. | |||
= Script = | |||
<syntaxhighlight lang=python> | <syntaxhighlight lang=python> | ||
| Line 170: | Line 186: | ||
# Calculate | # Calculate | ||
s.solarnoon() | s.solarnoon() | ||
# Track day / night state in file. | # Track day / night state in file. | ||
fileDayOrNight = readLineOfFile(dayAndNightStateFile) | fileDayOrNight = readLineOfFile(dayAndNightStateFile) | ||
#log | # log | ||
print(datetime.now().strftime('%Y-%m-%d_%H.%M.%S ') | print(datetime.now().strftime('%Y-%m-%d_%H.%M.%S ') | ||
+ ' | + 'Day ' + str(sun.timefromdecimalday(s.sunrise_t)) + [' ', '+'][sunriseFudgeMinutes > 0] + str(sunriseFudgeMinutes) | ||
+ ' | + ' - ' + str(sun.timefromdecimalday(s.sunset_t )) + [' ', '+'][sunsetFudgeMinutes > 0] + str(sunsetFudgeMinutes) | ||
+ ', state: ' + fileDayOrNight | + ', state: ' + fileDayOrNight | ||
) | ) | ||
| Line 209: | Line 221: | ||
updateContentsOfFile(dayAndNightStateFile, currentDayOrNight) | updateContentsOfFile(dayAndNightStateFile, currentDayOrNight) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Revision as of 17:39, 5 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/script_daynight/daynight.py >> /data/script_daynight/daynight.log
Setup logrotate to limit the size of the logfile.
Script
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 filecmp
# variant of time zone available on MotionEyeOS
localTimezone = timezone('Europe/Amsterdam')
# Location of here in lat / long (consult your favourite maps app to determine this)
localLat = 51.5
localLong = 5.5
# Sunrise and sunset fudge factor (in minutes)
# Positive minutes is later, negative minutes is earlier.
sunriseFudgeMinutes = -20
sunsetFudgeMinutes = 20
# Current state of day / night is stored in this file.
scriptDir = '/data/script_daynight/'
dayAndNightStateFile = scriptDir + 'daynight.dat'
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): # default Amsterdam
self.lat=lat
self.long=long
def sunrise(self,when=None):
"""
return the time of sunrise as a datetime.time object
when is a datetime.datetime object. If none is given
a local time zone is assumed (including daylight saving
if present)
"""
if when is None : when = datetime.now(tz=localTimezone)
self.__preptime(when)
self.__calc()
return sun.timefromdecimalday(self.sunrise_t)
def sunset(self,when=None):
if when is None : when = datetime.now(tz=localTimezone)
self.__preptime(when)
self.__calc()
return sun.timefromdecimalday(self.sunset_t)
def solarnoon(self,when=None):
if when is None : when = datetime.now(tz=localTimezone)
self.__preptime(when)
self.__calc()
return sun.timefromdecimalday(self.solarnoon_t)
"""
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.
"""
# datetime days are numbered in the Gregorian calendar
# while the calculations from NOAA are distibuted as
# OpenOffice spreadsheets with days numbered from
# 1/1/1900. The difference are those numbers taken for
# 18/12/2010
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()
if __name__ == "__main__":
s=sun(lat=localLat,long=localLong)
# Calculate
s.solarnoon()
# Track day / night state in file.
fileDayOrNight = readLineOfFile(dayAndNightStateFile)
# log
print(datetime.now().strftime('%Y-%m-%d_%H.%M.%S ')
+ 'Day ' + str(sun.timefromdecimalday(s.sunrise_t)) + [' ', '+'][sunriseFudgeMinutes > 0] + str(sunriseFudgeMinutes)
+ ' - ' + str(sun.timefromdecimalday(s.sunset_t )) + [' ', '+'][sunsetFudgeMinutes > 0] + str(sunsetFudgeMinutes)
+ ', state: ' + fileDayOrNight
)
# Determine current day / night state based on current time of day.
currentDayOrNight = s.dayornight(sunriseFudge=sunriseFudgeMinutes,sunsetFudge=sunsetFudgeMinutes)
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 was updated
if not filecmp.cmp("/data/etc/thread-1.conf", scriptDir + "thread-1.conf." + fileDayOrNight):
# backup old day/night file
shutil.move(scriptDir + "thread-1.conf." + fileDayOrNight
, scriptDir + "thread-1.conf." + fileDayOrNight + "." + datetime.now().strftime('%Y-%m-%d_%H.%M'))
# select other day/night file
shutil.copyfile("/data/etc/thread-1.conf", scriptDir + "thread-1.conf." + fileDayOrNight)
# select the other day/night file
shutil.copyfile(scriptDir + "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 restart")
print(datetime.now().strftime('%Y-%m-%d_%H:%M:%S ') + 'MotionEye restarted.')
# Update the file day / night state.
updateContentsOfFile(dayAndNightStateFile, currentDayOrNight)