Kindle weather displayとKindle news feed displayをダークモード対応にしたのでtimelitも対応させることにしました。自動的に切り替えは意外と落とし穴があって難しい。Kindle weatherは取り寄せるデータに日の出、日の入りがあるのでそのまま使えます。タイムゾーンに合わせてあるので問題は起こりません。ところがPythonモジュールで計算するとUTCを基準にしているので日付がずれます。これはなかなか厄介ですが、日付部分を取り除いて比較すればできます。当然、1日分違うため数分のずれが生じるので正確ではありませんがアプリケーションの精度からみて問題ありません。
timelitはもう少し複雑です。シェルでPythonを動かすのであまり複雑なスクリプトは組めません。さらにPython2なのでPython3より複雑になります。さらにpip等でモジュールをインストールできないので自前で用意しなければなりません。
色々調べると解決策がいくつかあり、特にモジュールをインストールしなくても比較的簡単に算出できる方法がありました。このスクリプトの問題は、日付を無視するので時間だけの情報になります。
import math
import datetime
import time
class Sun:
def getSunriseTime( self, coords ):
return self.calcSunTime( coords, True )
def getSunsetTime( self, coords ):
return self.calcSunTime( coords, False )
def getCurrentUTC( self ):
now = datetime.datetime.now()
return [ now.day, now.month, now.year ]
def calcSunTime( self, coords, isRiseTime, zenith = 90.8 ):
# isRiseTime == False, returns sunsetTime
day, month, year = self.getCurrentUTC()
longitude = coords['longitude']
latitude = coords['latitude']
TO_RAD = math.pi/180
#1. first calculate the day of the year
N1 = math.floor(275 * month / 9)
N2 = math.floor((month + 9) / 12)
N3 = (1 + math.floor((year - 4 * math.floor(year / 4) + 2) / 3))
N = N1 - (N2 * N3) + day - 30
#2. convert the longitude to hour value and calculate an approximate time
lngHour = longitude / 15
if isRiseTime:
t = N + ((6 - lngHour) / 24)
else: #sunset
t = N + ((18 - lngHour) / 24)
#3. calculate the Sun's mean anomaly
M = (0.9856 * t) - 3.289
#4. calculate the Sun's true longitude
L = M + (1.916 * math.sin(TO_RAD*M)) + (0.020 * math.sin(TO_RAD * 2 * M)) + 282.634
L = self.forceRange( L, 360 ) #NOTE: L adjusted into the range [0,360)
#5a. calculate the Sun's right ascension
RA = (1/TO_RAD) * math.atan(0.91764 * math.tan(TO_RAD*L))
RA = self.forceRange( RA, 360 ) #NOTE: RA adjusted into the range [0,360)
#5b. right ascension value needs to be in the same quadrant as L
Lquadrant = (math.floor( L/90)) * 90
RAquadrant = (math.floor(RA/90)) * 90
RA = RA + (Lquadrant - RAquadrant)
#5c. right ascension value needs to be converted into hours
RA = RA / 15
#6. calculate the Sun's declination
sinDec = 0.39782 * math.sin(TO_RAD*L)
cosDec = math.cos(math.asin(sinDec))
#7a. calculate the Sun's local hour angle
cosH = (math.cos(TO_RAD*zenith) - (sinDec * math.sin(TO_RAD*latitude))) / (cosDec * math.cos(TO_RAD*latitude))
if cosH > 1:
return {'status': False, 'msg': 'the sun never rises on this location (on the specified date)'}
if cosH < -1:
return {'status': False, 'msg': 'the sun never sets on this location (on the specified date)'}
#7b. finish calculating H and convert into hours
if isRiseTime:
H = 360 - (1/TO_RAD) * math.acos(cosH)
else: #setting
H = (1/TO_RAD) * math.acos(cosH)
H = H / 15
#8. calculate local mean time of rising/setting
T = H + RA - (0.06571 * t) - 6.622
#9. adjust back to UTC
UT = T - lngHour
UT = self.forceRange( UT, 24) # UTC time in decimal format (e.g. 23.23)
#10. Return
hr = self.forceRange(int(UT), 24)
min = round((UT - int(UT))*60,0)
def convert_unix_time(datetime_obj):
return int(time.mktime(datetime_obj.timetuple()))
unixtime = convert_unix_time(datetime.datetime(int(year), int(month), int(day), int(hr), int(min), int(0)))
return {
'status': True,
'decimal': UT,
'hr': hr,
'min': min,
'unixtime': unixtime
}
def forceRange( self, v, max ):
# force v to be >= 0 and < max
if v < 0:
return v + max
elif v >= max:
return v - max
return v
--- timelit.sh.orig 2020-09-17 22:45:55.414873702 +0000
+++ timelit.sh 2020-09-17 22:45:37.886601266 +0000
@@ -1,11 +1,19 @@
#!/bin/bash
+cd "$(dirname "$0")"
+
# if the Kindle is not being used as clock, then just quit
test -f /mnt/us/timelit/clockisticking || exit
+# my latitude and longitude
+lat=35.8034315
+lng=139.4275599
+offset=+9
+dark_mode='Auto'
# find the current minute of the day
-MinuteOTheDay="$(env TZ=CEST date -R +"%H%M")";
+#MinuteOTheDay="$(env TZ=CEST date -R +"%H%M")";
+MinuteOTheDay="$(env TZ=GMT-9 date -R +"%H%M")";
# check if there is at least one image for this minute
lines="$(find /mnt/us/timelit/images/quote_$MinuteOTheDay* 2>/dev/null | wc -l)"
@@ -16,9 +24,40 @@
echo $lines' files found for '$MinuteOTheDay
fi
+exec_dark_mode() {
+ t_sunrise=$(python -c "from Sun import Sun; coords = {'longitude' : $lng, 'latitude' : $lat }; sun = Sun(); print sun.getSunriseTime( coords )['unixtime']")
+ t_sunset=$(python -c "from Sun import Sun; coords = {'longitude' : $lng, 'latitude' : $lat }; sun = Sun(); print sun.getSunsetTime( coords )['unixtime']")
+ t_now=$(date '+%s')
+
+ [ "$t_sunrise" -gt "$t_sunset" ] && t_sunrise=$(( $t_sunrise - 86400 ))
+
+ t_sunrise=$(( ($t_sunrise + $offset * 3600) % 86400 ))
+ t_sunset=$(( ($t_sunset + $offset * 3600) % 86400 ))
+ t_now=$(( ($t_now + $offset * 3600) % 86400 ))
+
+ if [ "$t_now" -lt "$t_sunrise" ] || [ "$t_now" -gt "$t_sunset" ]; then
+ mode='dark_mode/'
+ else
+ mode=''
+ fi
+}
+
+case "$dark_mode" in
+ "Auto")
+ exec_dark_mode
+ ;;
+ "True")
+ mode='dark_mode/'
+ ;;
+ *)
+ mode=''
+ ;;
+esac
+
# randomly pick a png file for that minute (since we have multiple for some minutes)
-ThisMinuteImage=$( find /mnt/us/timelit/images/quote_$MinuteOTheDay* 2>/dev/null | python -c "import sys; import random; print(''.join(random.sample(sys.stdin.readlines(), int(sys.argv[1]))).rstrip())" 1)
+#ThisMinuteImage=$( find /mnt/us/timelit/images/quote_$MinuteOTheDay* 2>/dev/null | python -c "import sys; import random; print(''.join(random.sample(sys.stdin.readlines(), int(sys.argv[1]))).rstrip())" 1)
+ThisMinuteImage=$( find /mnt/us/timelit/images/${mode}quote_$MinuteOTheDay* 2>/dev/null | python -c "import sys; import random; print ''.join(random.sample(sys.stdin.readlines(), int(sys.argv[1]))).rstrip()" 1)
echo $ThisMinuteImage > /mnt/us/timelit/clockisticking