mirror of https://github.com/koreader/koreader
Plugin: Auto warmth and night mode (#8129)
("Auto nightmode" only on devices without warmth.)pull/8261/head
parent
8a750d4692
commit
20f7d14495
@ -0,0 +1,6 @@
|
||||
local _ = require("gettext")
|
||||
return {
|
||||
name = "autowarmth",
|
||||
fullname = require("device"):hasNaturalLight() and _("Auto warmth and night mode") or _("Auto night mode"),
|
||||
description = _([[This plugin allows set the frontlight warmth automagically.]]),
|
||||
}
|
@ -0,0 +1,843 @@
|
||||
--[[--
|
||||
@module koplugin.autowarmth
|
||||
|
||||
Plugin for setting screen warmth based on the sun position and/or a time schedule
|
||||
]]
|
||||
|
||||
local Device = require("device")
|
||||
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local DoubleSpinWidget = require("/ui/widget/doublespinwidget")
|
||||
local DeviceListener = require("device/devicelistener")
|
||||
local Dispatcher = require("dispatcher")
|
||||
local FFIUtil = require("ffi/util")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
local Font = require("ui/font")
|
||||
local Notification = require("ui/widget/notification")
|
||||
local SpinWidget = require("ui/widget/spinwidget")
|
||||
local SunTime = require("suntime")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local _ = require("gettext")
|
||||
local T = FFIUtil.template
|
||||
local Screen = require("device").screen
|
||||
local util = require("util")
|
||||
|
||||
local activate_sun = 1
|
||||
local activate_schedule = 2
|
||||
local activate_closer_noon = 3
|
||||
local activate_closer_midnight =4
|
||||
|
||||
local midnight_index = 11
|
||||
|
||||
local device_max_warmth = Device:hasNaturalLight() and Device.powerd.fl_warmth_max or 100
|
||||
local device_warmth_fit_scale = device_max_warmth / 100
|
||||
|
||||
local function frac(x)
|
||||
return x - math.floor(x)
|
||||
end
|
||||
|
||||
local AutoWarmth = WidgetContainer:new{
|
||||
name = "autowarmth",
|
||||
easy_mode = G_reader_settings:nilOrTrue("autowarmth_easy_mode"),
|
||||
activate = G_reader_settings:readSetting("autowarmth_activate") or 0,
|
||||
location = G_reader_settings:readSetting("autowarmth_location") or "Geysir",
|
||||
latitude = G_reader_settings:readSetting("autowarmth_latitude") or 64.31, --great Geysir in Iceland
|
||||
longitude = G_reader_settings:readSetting("autowarmth_longitude") or -20.30,
|
||||
altitude = G_reader_settings:readSetting("autowarmth_altitude") or 200,
|
||||
timezone = G_reader_settings:readSetting("autowarmth_timezone") or 0,
|
||||
scheduler_times = G_reader_settings:readSetting("autowarmth_scheduler_times") or
|
||||
{0.0, 5.5, 6.0, 6.5, 7.0, 13.0, 21.5, 22.0, 22.5, 23.0, 24.0},
|
||||
warmth = G_reader_settings:readSetting("autowarmth_warmth")
|
||||
or { 90, 90, 80, 60, 20, 20, 20, 60, 80, 90, 90},
|
||||
sched_times = {},
|
||||
sched_funcs = {}, -- necessary for unschedule, function, warmth
|
||||
}
|
||||
|
||||
-- get timezone offset in hours (including dst)
|
||||
function AutoWarmth:getTimezoneOffset()
|
||||
local utcdate = os.date("!*t")
|
||||
local localdate = os.date("*t")
|
||||
return os.difftime(os.time(localdate), os.time(utcdate))/3600
|
||||
end
|
||||
|
||||
function AutoWarmth:init()
|
||||
self:onDispatcherRegisterActions()
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
|
||||
G_reader_settings:saveSetting("autowarmth_easy_mode", self.easy_mode)
|
||||
-- schedule recalculation shortly afer midnight
|
||||
self:scheduleMidnightUpdate()
|
||||
end
|
||||
|
||||
function AutoWarmth:onDispatcherRegisterActions()
|
||||
Dispatcher:registerAction("show_ephemeris",
|
||||
{category="none", event="ShowEphemeris", title=_("Show ephemeris"), general=true})
|
||||
Dispatcher:registerAction("auto_warmth_off",
|
||||
{category="none", event="AutoWarmthOff", title=_("Auto warmth off"), screen=true})
|
||||
Dispatcher:registerAction("auto_warmth_cycle_trough",
|
||||
{category="none", event="AutoWarmthMode", title=_("Auto warmth cycle through modes"), screen=true})
|
||||
end
|
||||
|
||||
function AutoWarmth:onShowEphemeris()
|
||||
self:showTimesInfo(_("Information about the sun in"), true, activate_sun, false)
|
||||
end
|
||||
|
||||
function AutoWarmth:onAutoWarmthOff()
|
||||
self.activate = 0
|
||||
G_reader_settings:saveSetting("autowarmth_activate", self.activate)
|
||||
Notification:notify(_("Auto warmth turned off"))
|
||||
self:scheduleMidnightUpdate()
|
||||
end
|
||||
|
||||
function AutoWarmth:onAutoWarmthMode()
|
||||
if self.activate > 0 then
|
||||
self.activate = self.activate - 1
|
||||
else
|
||||
self.activate = activate_closer_midnight
|
||||
end
|
||||
local notify_text
|
||||
if self.activate == 0 then
|
||||
notify_text = _("Auto warmth turned off")
|
||||
elseif self.activate == activate_sun then
|
||||
notify_text = _("Auto warmth use sun position")
|
||||
elseif self.activate == activate_schedule then
|
||||
notify_text = _("Auto warmth use schedule")
|
||||
elseif self.activate == activate_closer_midnight then
|
||||
notify_text = _("Auto warmth use whatever is closer to midnight")
|
||||
elseif self.activate == activate_closer_noon then
|
||||
notify_text = _("Auto warmth use whatever is closer to noon")
|
||||
end
|
||||
G_reader_settings:saveSetting("autowarmth_activate", self.activate)
|
||||
Notification:notify(notify_text)
|
||||
self:scheduleMidnightUpdate()
|
||||
end
|
||||
|
||||
function AutoWarmth:onResume()
|
||||
if self.activate == 0 then return end
|
||||
|
||||
local resume_date = os.date("*t")
|
||||
|
||||
-- check if resume and suspend are done on the same day
|
||||
if resume_date.day == SunTime.date.day and resume_date.month == SunTime.date.month
|
||||
and resume_date.year == SunTime.date.year then
|
||||
local now = SunTime:getTimeInSec(resume_date)
|
||||
self:scheduleWarmthChanges(now)
|
||||
else
|
||||
self:scheduleMidnightUpdate() -- resume is on the other day, do all calcs again
|
||||
end
|
||||
end
|
||||
|
||||
-- wrapper for unscheduling, so that only our setWarmth gets unscheduled
|
||||
function AutoWarmth.setWarmth(val)
|
||||
if val then
|
||||
if val > 100 then
|
||||
DeviceListener:onSetNightMode(true)
|
||||
else
|
||||
DeviceListener:onSetNightMode(false)
|
||||
end
|
||||
if Device:hasNaturalLight() then
|
||||
val = math.min(val, 100)
|
||||
Device.powerd:setWarmth(val)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AutoWarmth:scheduleMidnightUpdate()
|
||||
-- first unschedule all old functions
|
||||
UIManager:unschedule(self.scheduleMidnightUpdate) -- when called from menu or resume
|
||||
|
||||
local toRad = math.pi / 180
|
||||
SunTime:setPosition(self.location, self.latitude * toRad, self.longitude * toRad,
|
||||
self.timezone, self.altitude)
|
||||
SunTime:setAdvanced()
|
||||
SunTime:setDate() -- today
|
||||
SunTime:calculateTimes()
|
||||
|
||||
self.sched_times = {}
|
||||
self.sched_funcs = {}
|
||||
|
||||
local function prepareSchedule(times, index1, index2)
|
||||
local time1 = times[index1]
|
||||
if not time1 then return end
|
||||
|
||||
local time = SunTime:getTimeInSec(time1)
|
||||
table.insert(self.sched_times, time)
|
||||
table.insert(self.sched_funcs, {AutoWarmth.setWarmth, self.warmth[index1]})
|
||||
|
||||
local time2 = times[index2]
|
||||
if not time2 then return end -- to near to the pole
|
||||
local warmth_diff = math.min(self.warmth[index2], 100) - math.min(self.warmth[index1], 100)
|
||||
if warmth_diff ~= 0 then
|
||||
local time_diff = SunTime:getTimeInSec(time2) - time
|
||||
local delta_t = time_diff / math.abs(warmth_diff) -- can be inf, no problem
|
||||
local delta_w = warmth_diff > 0 and 1 or -1
|
||||
for i = 1, math.abs(warmth_diff)-1 do
|
||||
local next_warmth = math.min(self.warmth[index1], 100) + delta_w * i
|
||||
-- only apply warmth for steps the hardware has (e.g. Tolino has 0-10 hw steps
|
||||
-- which map to warmth 0, 10, 20, 30 ... 100)
|
||||
if frac(next_warmth * device_warmth_fit_scale) == 0 then
|
||||
table.insert(self.sched_times, time + delta_t * i)
|
||||
table.insert(self.sched_funcs, {self.setWarmth,
|
||||
math.floor(math.min(self.warmth[index1], 100) + delta_w * i)})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.activate == activate_sun then
|
||||
self.current_times = {unpack(SunTime.times, 1, midnight_index)}
|
||||
elseif self.activate == activate_schedule then
|
||||
self.current_times = {unpack(self.scheduler_times, 1, midnight_index)}
|
||||
else
|
||||
self.current_times = {unpack(SunTime.times, 1, midnight_index)}
|
||||
if self.activate == activate_closer_noon then
|
||||
for i = 1, midnight_index do
|
||||
if not self.current_times[i] then
|
||||
self.current_times[i] = self.scheduler_times[i]
|
||||
elseif self.scheduler_times[i] and
|
||||
math.abs(self.current_times[i]%24 - 12) > math.abs(self.scheduler_times[i]%24 - 12) then
|
||||
self.current_times[i] = self.scheduler_times[i]
|
||||
end
|
||||
end
|
||||
else -- activate_closer_midnight
|
||||
for i = 1, midnight_index do
|
||||
if not self.current_times[i] then
|
||||
self.current_times[i] = self.scheduler_times[i]
|
||||
elseif self.scheduler_times[i] and
|
||||
math.abs(self.current_times[i]%24 - 12) < math.abs(self.scheduler_times[i]%24 - 12) then
|
||||
self.current_times[i] = self.scheduler_times[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.easy_mode then
|
||||
self.current_times[1] = nil
|
||||
self.current_times[2] = nil
|
||||
self.current_times[3] = nil
|
||||
self.current_times[6] = nil
|
||||
self.current_times[9] = nil
|
||||
self.current_times[10] = nil
|
||||
self.current_times[11] = nil
|
||||
end
|
||||
|
||||
-- here are dragons
|
||||
local i = 1
|
||||
-- find first valid entry
|
||||
while not self.current_times[i] and i <= midnight_index do
|
||||
i = i + 1
|
||||
end
|
||||
local next
|
||||
while i <= midnight_index do
|
||||
next = i + 1
|
||||
-- find next valid entry
|
||||
while not self.current_times[next] and next <= midnight_index do
|
||||
next = next + 1
|
||||
end
|
||||
prepareSchedule(self.current_times, i, next)
|
||||
i = next
|
||||
end
|
||||
|
||||
local now = SunTime:getTimeInSec()
|
||||
|
||||
-- reschedule 5sec after midnight
|
||||
UIManager:scheduleIn(24*3600 + 5 - now, self.scheduleMidnightUpdate, self )
|
||||
|
||||
self:scheduleWarmthChanges(now)
|
||||
end
|
||||
|
||||
function AutoWarmth:scheduleWarmthChanges(time)
|
||||
for i = 1, #self.sched_funcs do -- loop not essential, as unschedule unschedules all functions at once
|
||||
if not UIManager:unschedule(self.sched_funcs[i][1]) then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local actual_warmth
|
||||
for i = 1, #self.sched_funcs do
|
||||
if self.sched_times[i] > time then
|
||||
UIManager:scheduleIn( self.sched_times[i] - time,
|
||||
self.sched_funcs[i][1], self.sched_funcs[i][2])
|
||||
else
|
||||
actual_warmth = self.sched_funcs[i][2] or actual_warmth
|
||||
end
|
||||
end
|
||||
-- update current warmth directly
|
||||
self.setWarmth(actual_warmth)
|
||||
end
|
||||
|
||||
function AutoWarmth:hoursToClock(hours)
|
||||
if hours then
|
||||
hours = hours % 24 * 3600 + 0.01 -- round up, due to reduced precision in settings.reader.lua
|
||||
end
|
||||
return util.secondsToClock(hours, self.easy_mode)
|
||||
end
|
||||
|
||||
function AutoWarmth:addToMainMenu(menu_items)
|
||||
menu_items.autowarmth = {
|
||||
text = Device:hasNaturalLight() and _("Auto warmth and night mode")
|
||||
or _("Auto night mode"),
|
||||
checked_func = function() return self.activate ~= 0 end,
|
||||
sub_item_table_func = function()
|
||||
return self:getSubMenuItems()
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
local function tidy_menu(menu, request)
|
||||
for i = #menu, 1, -1 do
|
||||
if menu[i].mode ~=nil then
|
||||
if menu[i].mode ~= request then
|
||||
table.remove(menu,i)
|
||||
else
|
||||
menu[i].mode = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
return menu
|
||||
end
|
||||
|
||||
local about_text = _([[Set the frontlight warmth (if available) and night mode based on a time schedule or the sun's position.
|
||||
|
||||
There are three types of twilight:
|
||||
|
||||
• Civil: You can read a newspaper
|
||||
• Nautical: You can see the first stars
|
||||
• Astronomical: It is really dark
|
||||
|
||||
Custom warmth values can be set for every kind of twilight and sunrise, noon, sunset and midnight.
|
||||
The screen warmth is continuously adjusted to the current time.
|
||||
|
||||
To use the sun's position, a geographical location must be entered. The calculations are very precise, with a deviation less than minute and a half.]])
|
||||
function AutoWarmth:getSubMenuItems()
|
||||
return {
|
||||
{
|
||||
text = Device:hasNaturalLight() and _("About auto warmth and night mode")
|
||||
or _("About auto night mode"),
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = about_text,
|
||||
width = math.floor(Screen:getWidth() * 0.9),
|
||||
})
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
separator = true,
|
||||
},
|
||||
{
|
||||
text = _("Expert mode"),
|
||||
checked_func = function()
|
||||
return not self.easy_mode
|
||||
end,
|
||||
help_text = _("In the expert mode, different types of twilight can be used in addition to civil twilight."),
|
||||
callback = function(touchmenu_instance)
|
||||
self.easy_mode = not self.easy_mode
|
||||
G_reader_settings:saveSetting("autowarmth_easy_mode", self.easy_mode)
|
||||
self:scheduleMidnightUpdate()
|
||||
touchmenu_instance.item_table = self:getSubMenuItems()
|
||||
touchmenu_instance:updateItems()
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
},
|
||||
{
|
||||
text = _("Activate"),
|
||||
checked_func = function()
|
||||
return self.activate ~= 0
|
||||
end,
|
||||
sub_item_table = self:getActivateMenu(),
|
||||
},
|
||||
{
|
||||
text = _("Location settings"),
|
||||
enabled_func = function() return self.activate ~= activate_schedule end,
|
||||
sub_item_table = self:getLocationMenu(),
|
||||
},
|
||||
{
|
||||
text = _("Schedule settings"),
|
||||
enabled_func = function() return self.activate ~= activate_sun end,
|
||||
sub_item_table = self:getScheduleMenu(),
|
||||
},
|
||||
{
|
||||
text = Device:hasNaturalLight() and _("Warmth and night mode settings")
|
||||
or _("Night mode settings"),
|
||||
sub_item_table = self:getWarmthMenu(),
|
||||
separator = true,
|
||||
},
|
||||
self:getTimesMenu(_("Active parameters")),
|
||||
self:getTimesMenu(_("Information about the sun in"), true, activate_sun),
|
||||
self:getTimesMenu(_("Information about the schedule"), false, activate_schedule),
|
||||
}
|
||||
end
|
||||
|
||||
function AutoWarmth:getActivateMenu()
|
||||
local function getActivateMenuEntry(text, activator)
|
||||
return {
|
||||
text = text,
|
||||
checked_func = function() return self.activate == activator end,
|
||||
callback = function()
|
||||
if self.activate ~= activator then
|
||||
self.activate = activator
|
||||
else
|
||||
self.activate = 0
|
||||
end
|
||||
G_reader_settings:saveSetting("autowarmth_activate", self.activate)
|
||||
self:scheduleMidnightUpdate()
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
getActivateMenuEntry( _("Sun position"), activate_sun),
|
||||
getActivateMenuEntry( _("Time schedule"), activate_schedule),
|
||||
getActivateMenuEntry( _("Whatever is closer to noon"), activate_closer_noon),
|
||||
getActivateMenuEntry( _("Whatever is closer to midnight"), activate_closer_midnight),
|
||||
}
|
||||
end
|
||||
|
||||
function AutoWarmth:getLocationMenu()
|
||||
return {{
|
||||
text_func = function()
|
||||
if self.location ~= "" then
|
||||
return T(_("Location: %1"), self.location)
|
||||
else
|
||||
return _("Location")
|
||||
end
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
local location_name_dialog
|
||||
location_name_dialog = InputDialog:new{
|
||||
title = _("Location name"),
|
||||
input = self.location,
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Cancel"),
|
||||
callback = function()
|
||||
UIManager:close(location_name_dialog)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("OK"),
|
||||
callback = function()
|
||||
self.location = location_name_dialog:getInputText()
|
||||
G_reader_settings:saveSetting("autowarmth_location",
|
||||
self.location)
|
||||
UIManager:close(location_name_dialog)
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end,
|
||||
},
|
||||
}}
|
||||
}
|
||||
UIManager:show(location_name_dialog)
|
||||
location_name_dialog:onShowKeyboard()
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
},
|
||||
{
|
||||
text_func = function()
|
||||
return T(_("Coordinates: (%1, %2)"), self.latitude, self.longitude)
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
local location_widget = DoubleSpinWidget:new{
|
||||
title_text = _("Set location"),
|
||||
info_text = _("Enter decimal degrees, northern hemisphere and eastern length are '+'."),
|
||||
left_text = _("Latitude"),
|
||||
left_value = self.latitude,
|
||||
left_default = 0,
|
||||
left_min = -90,
|
||||
left_max = 90,
|
||||
left_step = 0.1,
|
||||
precision = "%0.2f",
|
||||
left_hold_step = 5,
|
||||
right_text = _("Longitude"),
|
||||
right_value = self.longitude,
|
||||
right_default = 0,
|
||||
right_min = -180,
|
||||
right_max = 180,
|
||||
right_step = 0.1,
|
||||
right_hold_step = 5,
|
||||
callback = function(lat, long)
|
||||
self.latitude = lat
|
||||
self.longitude = long
|
||||
self.timezone = self:getTimezoneOffset() -- use timezone of device
|
||||
G_reader_settings:saveSetting("autowarmth_latitude", self.latitude)
|
||||
G_reader_settings:saveSetting("autowarmth_longitude", self.longitude)
|
||||
G_reader_settings:saveSetting("autowarmth_timezone", self.timezone)
|
||||
self:scheduleMidnightUpdate()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end,
|
||||
}
|
||||
UIManager:show(location_widget)
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
},
|
||||
{
|
||||
text_func = function()
|
||||
return T(_("Altitude: %1m"), self.altitude)
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
UIManager:show(SpinWidget:new{
|
||||
title_text = _("Altitude"),
|
||||
value = self.altitude,
|
||||
value_min = -100,
|
||||
value_max = 15000, -- intercontinental flight
|
||||
wrap = false,
|
||||
value_step = 10,
|
||||
value_hold_step = 100,
|
||||
ok_text = _("Set"),
|
||||
callback = function(spin)
|
||||
self.altitude = spin.value
|
||||
G_reader_settings:saveSetting("autowarmth_altitude", self.altitude)
|
||||
self:scheduleMidnightUpdate()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end,
|
||||
extra_text = _("Default"),
|
||||
extra_callback = function()
|
||||
self.altitude = 200
|
||||
G_reader_settings:saveSetting("autowarmth_altitude", self.altitude)
|
||||
self:scheduleMidnightUpdate()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end,
|
||||
})
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
}}
|
||||
end
|
||||
|
||||
function AutoWarmth:getScheduleMenu()
|
||||
local function store_times(touchmenu_instance, new_time, num)
|
||||
self.scheduler_times[num] = new_time
|
||||
if num == 1 then
|
||||
if new_time then
|
||||
self.scheduler_times[midnight_index]
|
||||
= new_time + 24 -- next day
|
||||
else
|
||||
self.scheduler_times[midnight_index] = nil
|
||||
end
|
||||
end
|
||||
G_reader_settings:saveSetting("autowarmth_scheduler_times",
|
||||
self.scheduler_times)
|
||||
self:scheduleMidnightUpdate()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end
|
||||
-- mode == nil ... show alway
|
||||
-- == true ... easy mode
|
||||
-- == false ... expert mode
|
||||
local function getScheduleMenuEntry(text, num, mode)
|
||||
return {
|
||||
mode = mode,
|
||||
text_func = function()
|
||||
return T(_"%1: %2", text,
|
||||
self:hoursToClock(self.scheduler_times[num]))
|
||||
end,
|
||||
checked_func = function()
|
||||
return self.scheduler_times[num] ~= nil
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
local hh = 12
|
||||
local mm = 0
|
||||
if self.scheduler_times[num] then
|
||||
hh = math.floor(self.scheduler_times[num])
|
||||
mm = math.floor(frac(self.scheduler_times[num]) * 60 + 0.5)
|
||||
end
|
||||
UIManager:show(DoubleSpinWidget:new{
|
||||
title_text = _("Set time"),
|
||||
left_text = _("HH"),
|
||||
left_value = hh,
|
||||
left_default = 0,
|
||||
left_min = 0,
|
||||
left_max = 23,
|
||||
left_step = 1,
|
||||
left_hold_step = 3,
|
||||
left_wrap = true,
|
||||
right_text = _("MM"),
|
||||
right_value = mm,
|
||||
right_default = 0,
|
||||
right_min = 0,
|
||||
right_max = 59,
|
||||
right_step = 1,
|
||||
right_hold_step = 5,
|
||||
right_wrap = true,
|
||||
callback = function(left, right)
|
||||
local new_time = left + right / 60
|
||||
local function get_valid_time(n, dir)
|
||||
for i = n+dir, dir > 0 and midnight_index or 1, dir do
|
||||
if self.scheduler_times[i] then
|
||||
return self.scheduler_times[i]
|
||||
end
|
||||
end
|
||||
return dir > 0 and 0 or 26
|
||||
end
|
||||
if num > 1 and new_time < get_valid_time(num, -1) then
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = _("This time is before the previous time.\nAdjust the previous time?"),
|
||||
ok_callback = function()
|
||||
for i = num-1, 1, -1 do
|
||||
if self.scheduler_times[i] then
|
||||
if new_time < self.scheduler_times[i] then
|
||||
self.scheduler_times[i] = new_time
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
store_times(touchmenu_instance, new_time, num)
|
||||
end,
|
||||
})
|
||||
elseif num < 10 and new_time > get_valid_time(num, 1) then
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = _("This time is after the subsequent time.\nAdjust the subsequent time?"),
|
||||
ok_callback = function()
|
||||
for i = num + 1, midnight_index - 1 do
|
||||
if self.scheduler_times[i] then
|
||||
if new_time > self.scheduler_times[i] then
|
||||
self.scheduler_times[i] = new_time
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
store_times(touchmenu_instance, new_time, num)
|
||||
end,
|
||||
})
|
||||
else
|
||||
store_times(touchmenu_instance, new_time, num)
|
||||
end
|
||||
end,
|
||||
extra_text = _("Invalidate"),
|
||||
extra_callback = function()
|
||||
store_times(touchmenu_instance, nil, num)
|
||||
end,
|
||||
})
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
}
|
||||
end
|
||||
|
||||
local retval = {
|
||||
getScheduleMenuEntry(_("Solar midnight"), 1, false ),
|
||||
getScheduleMenuEntry(_("Astronomical dawn"), 2, false),
|
||||
getScheduleMenuEntry(_("Nautical dawn"), 3, false),
|
||||
getScheduleMenuEntry(_("Civil dawn"), 4),
|
||||
getScheduleMenuEntry(_("Sunrise"), 5),
|
||||
getScheduleMenuEntry(_("Solar noon"), 6, false),
|
||||
getScheduleMenuEntry(_("Sunset"), 7),
|
||||
getScheduleMenuEntry(_("Civil dusk"), 8),
|
||||
getScheduleMenuEntry(_("Nautical dusk"), 9, false),
|
||||
getScheduleMenuEntry(_("Astronomical dusk"), 10, false),
|
||||
}
|
||||
|
||||
return tidy_menu(retval, self.easy_mode)
|
||||
end
|
||||
|
||||
function AutoWarmth:getWarmthMenu()
|
||||
-- mode == nil ... show alway
|
||||
-- == true ... easy mode
|
||||
-- == false ... expert mode
|
||||
local function getWarmthMenuEntry(text, num, mode)
|
||||
return {
|
||||
mode = mode,
|
||||
text_func = function()
|
||||
if Device:hasNaturalLight() then
|
||||
if self.warmth[num] <= 100 then
|
||||
return T(_("%1: %2%"), text, self.warmth[num])
|
||||
else
|
||||
return T(_("%1: 100% + ☾"), text)
|
||||
end
|
||||
else
|
||||
if self.warmth[num] <= 100 then
|
||||
return T(_("%1: ☼"), text)
|
||||
else
|
||||
return T(_("%1: ☾"), text)
|
||||
end
|
||||
end
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
if Device:hasNaturalLight() then
|
||||
UIManager:show(SpinWidget:new{
|
||||
title_text = text,
|
||||
value = self.warmth[num],
|
||||
value_min = 0,
|
||||
value_max = 100,
|
||||
wrap = false,
|
||||
value_step = math.floor(100 / device_max_warmth),
|
||||
value_hold_step = 10,
|
||||
ok_text = _("Set"),
|
||||
callback = function(spin)
|
||||
self.warmth[num] = spin.value
|
||||
self.warmth[#self.warmth - num + 1] = spin.value
|
||||
G_reader_settings:saveSetting("autowarmth_warmth", self.warmth)
|
||||
self:scheduleMidnightUpdate()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end,
|
||||
extra_text = _("Use night mode"),
|
||||
extra_callback = function()
|
||||
self.warmth[num] = 110
|
||||
self.warmth[#self.warmth - num + 1] = 110
|
||||
G_reader_settings:saveSetting("autowarmth_warmth", self.warmth)
|
||||
self:scheduleMidnightUpdate()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end,
|
||||
})
|
||||
else
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = _("Nightmode"),
|
||||
ok_text = _("Set"),
|
||||
ok_callback = function()
|
||||
self.warmth[num] = 110
|
||||
self.warmth[#self.warmth - num + 1] = 110
|
||||
G_reader_settings:saveSetting("autowarmth_warmth", self.warmth)
|
||||
self:scheduleMidnightUpdate()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end,
|
||||
cancel_text = _("Unset"),
|
||||
cancel_callback = function()
|
||||
self.warmth[num] = 0
|
||||
self.warmth[#self.warmth - num + 1] = 0
|
||||
G_reader_settings:saveSetting("autowarmth_warmth", self.warmth)
|
||||
self:scheduleMidnightUpdate()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end,
|
||||
other_buttons = {{
|
||||
{
|
||||
text = _("Cancel"),
|
||||
}
|
||||
}},
|
||||
|
||||
})
|
||||
end
|
||||
end,
|
||||
|
||||
keep_menu_open = true,
|
||||
}
|
||||
end
|
||||
|
||||
local retval = {
|
||||
{
|
||||
text = Device:hasNaturalLight() and _("Set warmth and night mode for:")
|
||||
or _("Set night mode for:"),
|
||||
enabled_func = function() return false end,
|
||||
},
|
||||
getWarmthMenuEntry(_("Solar noon"), 6, false),
|
||||
getWarmthMenuEntry(_("Daytime"), 5),
|
||||
getWarmthMenuEntry(_("Darkest time of civil dawn"), 4, false),
|
||||
getWarmthMenuEntry(_("Darkest time of civil twilight"), 4, true),
|
||||
getWarmthMenuEntry(_("Darkest time of nautical dawn"), 3, false),
|
||||
getWarmthMenuEntry(_("Darkest time of astronomical dawn"), 2, false),
|
||||
getWarmthMenuEntry(_("Midnight"), 1, false),
|
||||
}
|
||||
|
||||
return tidy_menu(retval, self.easy_mode)
|
||||
end
|
||||
|
||||
-- title
|
||||
-- location: add a location string
|
||||
-- activator: nil .. current_times,
|
||||
-- activate_sun .. sun times
|
||||
-- activate_schedule .. scheduler times
|
||||
-- request_easy: true if easy_mode should be used
|
||||
function AutoWarmth:showTimesInfo(title, location, activator, request_easy)
|
||||
local times
|
||||
if not activator then
|
||||
times = self.current_times
|
||||
elseif activator == activate_sun then
|
||||
times = SunTime.times
|
||||
elseif activator == activate_schedule then
|
||||
times = self.scheduler_times
|
||||
end
|
||||
|
||||
-- text to show
|
||||
-- t .. times
|
||||
-- num .. index in times
|
||||
local function info_line(text, t, num, easy)
|
||||
local retval = text .. self:hoursToClock(t[num])
|
||||
if easy then
|
||||
if t[num] and self.current_times[num] and self.current_times[num] ~= t[num] then
|
||||
return text .. "\n"
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
if not t[num] then -- entry deactivated
|
||||
return retval .. "\n"
|
||||
elseif Device:hasNaturalLight() then
|
||||
if self.current_times[num] == t[num] then
|
||||
if self.warmth[num] <= 100 then
|
||||
return retval .. " (💡" .. self.warmth[num] .."%)\n"
|
||||
else
|
||||
return retval .. " (💡100% + ☾)\n"
|
||||
end
|
||||
else
|
||||
return retval .. "\n"
|
||||
end
|
||||
else
|
||||
if self.current_times[num] == t[num] then
|
||||
if self.warmth[num] <= 100 then
|
||||
return retval .. " (☼)\n"
|
||||
else
|
||||
return retval .. " (☾)\n"
|
||||
end
|
||||
else
|
||||
return retval .. "\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local location_string = ""
|
||||
if location then
|
||||
location_string = " " .. self:getLocationString()
|
||||
end
|
||||
|
||||
UIManager:show(InfoMessage:new{
|
||||
face = Font:getFace("scfont"),
|
||||
width = math.floor(Screen:getWidth() * (self.easy_mode and 0.75 or 0.90)),
|
||||
text = title .. location_string .. ":\n\n" ..
|
||||
info_line(_("Solar midnight: "), times, 1, request_easy) ..
|
||||
_(" Dawn\n") ..
|
||||
info_line(_(" Astronomic: "), times, 2, request_easy) ..
|
||||
info_line(_(" Nautical: "), times, 3, request_easy)..
|
||||
info_line(_(" Civil: "), times, 4) ..
|
||||
_(" Dawn\n") ..
|
||||
info_line(_("Sunrise: "), times, 5) ..
|
||||
info_line(_("\nSolar noon: "), times, 6, request_easy) ..
|
||||
|
||||
info_line(_("\nSunset: "), times, 7) ..
|
||||
_(" Dusk\n") ..
|
||||
info_line(_(" Civil: "), times, 8) ..
|
||||
info_line(_(" Nautical: "), times, 9, request_easy) ..
|
||||
info_line(_(" Astronomic: "), times, 10, request_easy) ..
|
||||
_(" Dusk\n") ..
|
||||
info_line(_("Solar midnight: "), times, midnight_index, request_easy)
|
||||
})
|
||||
end
|
||||
|
||||
-- title
|
||||
-- location: add a location string
|
||||
-- activator: nil .. current_times,
|
||||
-- activate_sun .. sun times
|
||||
-- activate_schedule .. scheduler times
|
||||
function AutoWarmth:getTimesMenu(title, location, activator)
|
||||
return {
|
||||
text_func = function()
|
||||
if location then
|
||||
return title .. " " .. self:getLocationString()
|
||||
end
|
||||
return title
|
||||
end,
|
||||
callback = function()
|
||||
self:showTimesInfo(title, location, activator, self.easy_mode)
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
}
|
||||
end
|
||||
|
||||
function AutoWarmth:getLocationString()
|
||||
if self.location ~= "" then
|
||||
return self.location
|
||||
else
|
||||
return "(" .. self.latitude .. "," .. self.longitude .. ")"
|
||||
end
|
||||
end
|
||||
|
||||
return AutoWarmth
|
@ -0,0 +1,310 @@
|
||||
|
||||
-- usage
|
||||
-- SunTime:setPosition()
|
||||
-- SunTime:setSimple() or SunTime:setAdvanced()
|
||||
-- SunTime:setDate()
|
||||
-- SunTime:calculate(height, hour) height==Rad(0°)-> Midday; hour=6 or 18 for rise or set
|
||||
-- SunTime:calculateTimes()
|
||||
-- use values
|
||||
|
||||
-- math abbrevations
|
||||
local toRad = math.pi/180
|
||||
local toDeg = 1/toRad
|
||||
|
||||
local floor = math.floor
|
||||
local sin = math.sin
|
||||
local cos = math.cos
|
||||
local tan = math.tan
|
||||
local asin = math.asin
|
||||
local acos = math.acos
|
||||
local atan = math.atan
|
||||
|
||||
local function Rad(x)
|
||||
return x*toRad
|
||||
end
|
||||
|
||||
--------------------------------------------
|
||||
|
||||
local SunTime = {}
|
||||
|
||||
SunTime.astronomic = Rad(-18)
|
||||
SunTime.nautic = Rad(-12)
|
||||
SunTime.civil = Rad(-6)
|
||||
-- SunTime.eod = Rad(-49/60) -- approx. end of day
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
-- simple 'Equation of time' good for dates between 2008-2027
|
||||
-- errors for latitude 20° are within 1min
|
||||
-- 47° are within 1min 30sec
|
||||
-- 65° are within 5min
|
||||
-- https://www.astronomie.info/zeitgleichung/#Auf-_und_Untergang (German)
|
||||
function SunTime:getZglSimple()
|
||||
local T = self.date.yday
|
||||
return -0.171 * sin(0.0337 * T + 0.465) - 0.1299 * sin(0.01787 * T - 0.168)
|
||||
end
|
||||
|
||||
-- more advanced 'Equation of time' goot for dates between 1800-2200
|
||||
-- errors are better than with the simple method
|
||||
-- https://de.wikipedia.org/wiki/Zeitgleichung (German) and
|
||||
-- more infos on http://www.hlmths.de/Scilab/Zeitgleichung.pdf (German)
|
||||
function SunTime:getZglAdvanced()
|
||||
local e = self.num_ex
|
||||
local e2 = e*e
|
||||
local e3 = e2*e
|
||||
local e4 = e3*e
|
||||
local e5 = e4*e
|
||||
|
||||
local M = self.M
|
||||
-- https://de.wikibooks.org/wiki/Astronomische_Berechnungen_f%C3%BCr_Amateure/_Himmelsmechanik/_Sonne
|
||||
local C = (2*e - e3/4 + 5/96*e5) * sin(M)
|
||||
+ (5/4*e2 + 11/24*e4) * sin(2*M)
|
||||
+ (13/12*e3 - 43/64*e5) * sin(3*M)
|
||||
+ 103/96*e4 * sin(4*M)
|
||||
+ 1097/960*e5 * sin(5*M) -- rad
|
||||
|
||||
local lamb = self.L + C
|
||||
local tanL = tan(self.L)
|
||||
local tanLamb = tan(lamb)
|
||||
local cosEps = cos(self.epsilon)
|
||||
|
||||
local zgl = atan( (tanL - tanLamb*cosEps) / (1 + tanL*tanLamb*cosEps) ) --rad
|
||||
return zgl*toDeg/15 -- to hours *4'/60
|
||||
end
|
||||
|
||||
-- set current date or year/month/day daylightsaving hh/mm/ss
|
||||
-- if dst == nil use curent daylight saving of the system
|
||||
function SunTime:setDate(year, month, day, dst, hour, min, sec)
|
||||
self.oldDate = self.date
|
||||
|
||||
self.date = os.date("*t")
|
||||
|
||||
if year and month and day and hour and min and sec then
|
||||
self.date.year = year
|
||||
self.date.month = month
|
||||
self.date.day = day
|
||||
local feb = 28
|
||||
if year % 4 == 0 and (year % 100 ~= 0 or year % 400 == 0) then
|
||||
feb = 29
|
||||
end
|
||||
local days_in_month = {31, feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||||
self.date.yday = day
|
||||
for i = 1, month-1 do
|
||||
self.date.yday = self.date.yday + days_in_month[i]
|
||||
end
|
||||
self.date.hour = hour or 12
|
||||
self.date.min = min or 0
|
||||
self.date.sec = sec or 0
|
||||
if dst ~= nil then
|
||||
self.date.isdst = dst
|
||||
end
|
||||
end
|
||||
|
||||
-- use cached results
|
||||
if self.olddate and self.oldDate.day == self.date.day and
|
||||
self.oldDate.month == self.date.month and
|
||||
self.oldDate.year == self.date.year and
|
||||
self.oldDate.isdst == self.date.isdst then
|
||||
return
|
||||
end
|
||||
|
||||
self:initVars()
|
||||
|
||||
if not self.getZgl then
|
||||
self.getZgl = self.getZglAdvanced
|
||||
end
|
||||
|
||||
self.zgl = self:getZgl()
|
||||
end
|
||||
|
||||
function SunTime:setPosition(name, latitude, longitude, time_zone, altitude)
|
||||
altitude = altitude or 200
|
||||
|
||||
self.oldDate = nil --invalidate cache
|
||||
self.pos = {name, latitude = latitude, longitude = longitude, altitude = altitude}
|
||||
self.time_zone = time_zone
|
||||
self.refract = Rad(33/60 * .5 ^ (altitude / 5500))
|
||||
end
|
||||
|
||||
function SunTime:setSimple()
|
||||
self.getZgl = self.getZglSimple
|
||||
end
|
||||
function SunTime:setAdvanced()
|
||||
self.getZgl = self.getZglAdvanced
|
||||
end
|
||||
|
||||
function SunTime:daysSince2000()
|
||||
local delta = self.date.year - 2000
|
||||
local leap = floor(delta/4)
|
||||
local days_since_2000 = delta * 365 + leap + self.date.yday -- WMO No.8
|
||||
return days_since_2000
|
||||
end
|
||||
|
||||
-- more accurate parameters of earth orbit from
|
||||
-- Title: Numerical expressions for precession formulae and mean elements for the Moon and the planets
|
||||
-- Authors: Simon, J. L., Bretagnon, P., Chapront, J., Chapront-Touze, M., Francou, G., & Laskar, J., ,
|
||||
-- Journal: Astronomy and Astrophysics (ISSN 0004-6361), vol. 282, no. 2, p. 663-683
|
||||
-- Bibliographic Code: 1994A&A...282..663S
|
||||
function SunTime:initVars()
|
||||
self.days_since_2000 = self:daysSince2000()
|
||||
local T = self.days_since_2000/36525
|
||||
-- self.num_ex = 0.016709 - 0.000042 * T
|
||||
-- self.num_ex = 0.0167086342 - 0.000042 * T
|
||||
-- see wikipedia: https://de.wikipedia.org/wiki/Erdbahn-> Meeus
|
||||
self.num_ex = 0.0167086342 + T*(-0.0004203654e-1
|
||||
+ T*(-0.0000126734e-2 + T*( 0.0000001444e-3
|
||||
+ T*(-0.0000000002e-4 + T* 0.0000000003e-5))))
|
||||
|
||||
-- self.epsilon = (23 + 26/60 + 21/3600 - 46.82/3600 * T) * toRad
|
||||
-- see wikipedia: https://de.wikipedia.org/wiki/Erdbahn-> Meeus
|
||||
local epsilon = 23 + 26/60 + (21.412 + T*(-46.80927
|
||||
+ T*(-0.000152 + T*(0.00019989
|
||||
+ T*(-0.00000051 - T*0.00000025)))))/3600 --°
|
||||
self.epsilon = epsilon * toRad
|
||||
|
||||
-- local L = (280.4656 + 36000.7690 * T ) --°
|
||||
-- see Numerical expressions for precession formulae ...
|
||||
-- shift from time to Equinox as data is given for JD2000.0, but date is in days from 20000101
|
||||
local nT = T * 1.0000388062
|
||||
--mean longitude
|
||||
local L = 100.46645683 + (nT*(1295977422.83429E-1
|
||||
+ nT*(-2.04411E-2 - nT* 0.00523E-3)))/3600--°
|
||||
self.L = (L - floor(L/360)*360) * toRad
|
||||
|
||||
-- wikipedia: https://de.wikipedia.org/wiki/Erdbahn-> Meeus
|
||||
local omega = 102.93734808 + nT*(17.194598028e-1
|
||||
+ nT*( 0.045688325e-2 + nT*(-0.000017680e-3
|
||||
+ nT*(-0.000033583e-4 + nT*( 0.000000828e-5
|
||||
+ nT* 0.000000056e-6))))) --°
|
||||
|
||||
-- Mittlere Länage
|
||||
local M = L - omega
|
||||
self.M = (M - floor(M/360)*360) * toRad
|
||||
|
||||
-- Deklination nach astronomie.info
|
||||
-- local decl = 0.4095 * sin(0.016906 * (self.date.yday - 80.086))
|
||||
--Deklination nach Brodbeck (2001)
|
||||
-- local decl = 0.40954 * sin(0.0172 * (self.date.yday - 79.349740))
|
||||
|
||||
--Deklination nach John Kalisch (derived from WMO-No.8)
|
||||
--local x = (36000/36525 * (self.date.yday+hour/24) - 2.72)*toRad
|
||||
--local decl = asin(0.397748 * sin(x + (1.915*sin(x) - 77.51)*toRad))
|
||||
|
||||
-- Deklination WMO-No.8 page I-7-37
|
||||
--local T = self.days_since_2000 + hour/24
|
||||
--local L = 280.460 + 0.9856474 * T -- self.M
|
||||
--L = (L - floor(L/360)*360) * toRad
|
||||
--local g = 357.528 + 0.9856003 * T
|
||||
--g = (g - floor(g/360)*360) * toRad
|
||||
--local l = L + (1.915 * sin (g) + 0.020 * sin (2*g))*toRad
|
||||
--local ep = self.epsilon
|
||||
-- -- sin(decl) = sin(ep)*sin(l)
|
||||
--self.decl = asin(sin(ep)*sin(l))
|
||||
|
||||
-- Deklination WMO-No.8 page I-7-37
|
||||
local l = self.L + math.pi + (1.915 * sin (self.M) + 0.020 * sin (2*self.M))*toRad
|
||||
self.decl = asin(sin(self.epsilon)*sin(l))
|
||||
|
||||
-- Nutation see https://de.wikipedia.org/wiki/Nutation_(Astronomie)
|
||||
local A = { 2.18243920 - 33.7570460 * T,
|
||||
-2.77624462 + 1256.66393 * T,
|
||||
7.62068856 + 16799.4182 * T,
|
||||
4.36487839 - 67.140919 * T}
|
||||
local B = {92025e-4 + 8.9e-4 * T,
|
||||
5736e-4 - 3.1e-4 * T,
|
||||
977e-4 - 0.5e-4 * T,
|
||||
-895e-4 + 0.5e-4 * T}
|
||||
local delta_epsilon = 0
|
||||
for i = 1, #A do
|
||||
delta_epsilon = delta_epsilon + B[i]*cos(A[i])
|
||||
end
|
||||
|
||||
-- add nutation to declination
|
||||
self.decl = self.decl + delta_epsilon/3600
|
||||
|
||||
-- https://de.wikipedia.org/wiki/Kepler-Gleichung#Wahre_Anomalie
|
||||
self.E = self.M + self.num_ex * sin(self.M) + self.num_ex^2 / 2 * sin(2*self.M)
|
||||
self.a = 149598022.96E3 -- große Halbaches in m
|
||||
self.r = self.a * (1 - self.num_ex * cos(self.E))
|
||||
-- self.eod = -atan(6.96342e8/self.r) - Rad(33.3/60) -- without nutation
|
||||
self.eod = -atan(6.96342e8/self.r) - self.refract -- with nutation
|
||||
-- ^--sun radius ^- astronomical refraction (500m altitude)
|
||||
end
|
||||
--------------------------
|
||||
|
||||
function SunTime:getTimeDiff(height)
|
||||
local val = (sin(height) - sin(self.pos.latitude)*sin(self.decl))
|
||||
/ (cos(self.pos.latitude)*cos(self.decl))
|
||||
|
||||
if math.abs(val) > 1 then
|
||||
return
|
||||
end
|
||||
return 12/math.pi * acos(val)
|
||||
end
|
||||
|
||||
-- get time for a certain height
|
||||
-- set hour to 6 for rise or 18 for set
|
||||
-- result rise or set time
|
||||
-- nil sun does not reach the height
|
||||
function SunTime:calculateTime(height, hour)
|
||||
hour = hour or 12
|
||||
local dst = self.date.isdst and 1 or 0
|
||||
local timeDiff = self:getTimeDiff(height, hour)
|
||||
if not timeDiff then
|
||||
return
|
||||
end
|
||||
|
||||
local local_correction = self.time_zone - self.pos.longitude*12/math.pi + dst - self.zgl
|
||||
if hour < 12 then
|
||||
return 12 - timeDiff + local_correction
|
||||
else
|
||||
return 12 + timeDiff + local_correction
|
||||
end
|
||||
end
|
||||
|
||||
function SunTime:calculateTimeIter(height, hour)
|
||||
return self:calculateTime(height, hour)
|
||||
end
|
||||
|
||||
function SunTime:calculateTimes()
|
||||
self.rise = self:calculateTimeIter(self.eod, 6)
|
||||
self.set = self:calculateTimeIter(self.eod, 18)
|
||||
|
||||
self.rise_civil = self:calculateTimeIter(self.civil, 6)
|
||||
self.set_civil = self:calculateTimeIter(self.civil, 18)
|
||||
self.rise_nautic = self:calculateTimeIter(self.nautic, 6)
|
||||
self.set_nautic = self:calculateTimeIter(self.nautic, 18)
|
||||
self.rise_astronomic = self:calculateTimeIter(self.astronomic, 6)
|
||||
self.set_astronomic = self:calculateTimeIter(self.astronomic, 18)
|
||||
|
||||
self.noon = (self.rise + self.set) / 2
|
||||
self.midnight = self.noon + 12
|
||||
|
||||
self.times = {}
|
||||
self.times[1] = self.noon - 12
|
||||
self.times[2] = self.rise_astronomic
|
||||
self.times[3] = self.rise_nautic
|
||||
self.times[4] = self.rise_civil
|
||||
self.times[5] = self.rise
|
||||
self.times[6] = self.noon
|
||||
self.times[7] = self.set
|
||||
self.times[8] = self.set_civil
|
||||
self.times[9] = self.set_nautic
|
||||
self.times[10] = self.set_astronomic
|
||||
self.times[11] = self.noon + 12
|
||||
end
|
||||
|
||||
-- get time in seconds (either actual time in hours or date struct)
|
||||
function SunTime:getTimeInSec(val)
|
||||
if not val then
|
||||
val = os.date("*t")
|
||||
end
|
||||
|
||||
if type(val) == "table" then
|
||||
return val.hour*3600 + val.min*60 + val.sec
|
||||
end
|
||||
|
||||
return val*3600
|
||||
end
|
||||
|
||||
return SunTime
|
Loading…
Reference in New Issue