Merge pull request #847 from newkit/feature_luci-app-wifischedule

Added luci-app-wifischeduler
This commit is contained in:
Hannu Nyman 2016-11-25 17:30:44 +02:00 committed by GitHub
commit ebb5a90f76
5 changed files with 421 additions and 0 deletions

View file

@ -0,0 +1,22 @@
# Copyright (c) 2016, prpl Foundation
#
# Permission to use, copy, modify, and/or distribute this software for any purpose with or without
# fee is hereby granted, provided that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
# FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# Author: Nils Koenig <openwrt@newk.it>
include $(TOPDIR)/rules.mk
LUCI_TITLE:=Turns WiFi on and off according to a schedule
LUCI_DEPENDS:=+wifischedule
include ../../luci.mk
# call BuildPackage - OpenWrt buildroot signature

View file

@ -0,0 +1,86 @@
# wifischedule
Turns WiFi on and off according to a schedule on an openwrt router
## Components
* wifischedule: Shell script that creates cron jobs based on configuration provided in UCI and does all the other logic of enabling and disabling wifi with the use of `/sbin/wifi` and `/usr/bin/iwinfo`. Can be used standalone.
* luci-app-wifischedule: LUCI frontend for creating the UCI configuration and triggering the actions. Depends on wifischedule.
## Use cases
You can create user-defined events when to enable or disable WiFi.
There are various use cases why you would like to do so:
1. Reduce power consumption and therefore reduce CO2 emissions.
2. Reduce emitted electromagnatic radiation.
3. Force busincess hours when WiFi is available.
Regarding 1: Please note, that you need to unload the wireless driver modules in order to get the most effect of saving power.
In my test scenario only disabling WiFi saves about ~0.4 Watt, unloading the modules removes another ~0.4 Watt.
Regarding 2: Think of a wireless accesspoint e.g. in your bedrom, kids room where you want to remove the ammount of radiation emitted.
Regarding 3: E.g. in a company, why would wireless need to be enabled weekends if no one is there working?
Or think of an accesspoint in your kids room when you want the youngsters to sleep after 10 pm instead of facebooking...
## Configuration
You can create an arbitrary number of schedule events. Please note that there is on sanity check done wheather the start / stop times overlap or make sense.
If start and stop time are equal, this leads to disabling the WiFi at the given time.
Logging if enabled is done to the file `/var/log/wifi_schedule.log` and can be reviewed through the "View Logfile" tab.
The cron jobs created can be reviewed through the "View Cron Jobs" tab.
Please note that the "Unload Modules" function is currently considered as experimental. You can manually add / remove modules in the text field.
The button "Determine Modules Automatically" tries to make a best guess determining regarding the driver module and its dependencies.
When un-/loading the modules, there is a certain number of retries (`module_load`) performed.
The option "Force disabling wifi even if stations associated" does what it says - when activated it simply shuts down WiFi.
When unchecked, its checked every `recheck_interval` minutes if there are still stations associated. Once the stations disconnect, WiFi is disabled.
Please note, that the parameters `module_load` and `recheck_interval` are only accessible through uci.
## UCI Configuration `wifi_schedule`
UCI configuration file: `/etc/config/wifi_schedule`:
```
config global
option logging '0'
option enabled '0'
option recheck_interval '10'
option modules_retries '10'
config entry 'Businesshours'
option enabled '0'
option daysofweek 'Monday Tuesday Wednesday Thursday Friday'
option starttime '06:00'
option stoptime '22:00'
option forcewifidown '0'
config entry 'Weekend'
option enabled '0'
option daysofweek 'Saturday Sunday'
option starttime '00:00'
option stoptime '00:00'
option forcewifidown '1'
```
## Script: `wifi_schedule.sh`
This is the script that does the work. Make your changes to the UCI config file: `/etc/config/wifi_schedule`
Then call the script as follows in order to get the necessary cron jobs created:
`wifi_schedule.sh cron`
All commands:
```
wifi_schedule.sh cron|start|stop|forcestop|recheck|getmodules|savemodules|help
cron: Create cronjob entries.
start: Start wifi.
stop: Stop wifi gracefully, i.e. check if there are stations associated and if so keep retrying.
forcestop: Stop wifi immediately.
recheck: Recheck if wifi can be disabled now.
getmodules: Returns a list of modules used by the wireless driver(s)
savemodules: Saves a list of automatic determined modules to UCI
help: This description.
```

View file

@ -0,0 +1,32 @@
-- Copyright (c) 2016, prpl Foundation
--
-- Permission to use, copy, modify, and/or distribute this software for any purpose with or without
-- fee is hereby granted, provided that the above copyright notice and this permission notice appear
-- in all copies.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
-- INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
-- FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- Author: Nils Koenig <openwrt@newk.it>
module("luci.controller.wifischedule.wifi_schedule", package.seeall)
function index()
entry({"admin", "wifi_schedule"}, firstchild(), "Wifi Schedule", 60).dependent=false
entry({"admin", "wifi_schedule", "tab_from_cbi"}, cbi("wifischedule/wifi_schedule"), "Schedule", 1)
entry({"admin", "wifi_schedule", "wifi_schedule"}, call("wifi_schedule_log"), "View Logfile", 2)
entry({"admin", "wifi_schedule", "cronjob"}, call("view_crontab"), "View Cron Jobs", 3)
end
function wifi_schedule_log()
local logfile = luci.sys.exec("cat /tmp/log/wifi_schedule.log")
luci.template.render("wifischedule/file_viewer", {title="Wifi Schedule Logfile", content=logfile})
end
function view_crontab()
local crontab = luci.sys.exec("cat /etc/crontabs/root")
luci.template.render("wifischedule/file_viewer", {title="Cron Jobs", content=crontab})
end

View file

@ -0,0 +1,259 @@
-- Copyright (c) 2016, prpl Foundation
--
-- Permission to use, copy, modify, and/or distribute this software for any purpose with or without
-- fee is hereby granted, provided that the above copyright notice and this permission notice appear
-- in all copies.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
-- INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
-- FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- Author: Nils Koenig <openwrt@newk.it>
function file_exists(name)
local f=io.open(name,"r")
if f~=nil then io.close(f) return true else return false end
end
function time_validator(self, value, desc)
if value ~= nil then
h_str, m_str = string.match(value, "^(%d%d?):(%d%d?)$")
h = tonumber(h_str)
m = tonumber(m_str)
if ( h ~= nil and
h >= 0 and
h <= 23 and
m ~= nil and
m >= 0 and
m <= 59) then
return value
end
end
return nil, translate("The value '" .. desc .. "' is invalid")
end
-- -------------------------------------------------------------------------------------------------
-- BEGIN Map
m = Map("wifi_schedule", translate("Wifi Schedule"), translate("Defines a schedule when to turn on and off wifi."))
function m.on_commit(self)
luci.sys.exec("/usr/bin/wifi_schedule.sh cron")
end
-- END Map
-- BEGIN Global Section
global_section = m:section(TypedSection, "global", "Global Settings")
global_section.optional = false
global_section.rmempty = false
global_section.anonymous = true
-- END Section
-- BEGIN Global Enable Checkbox
global_enable = global_section:option(Flag, "enabled", translate("Enable Wifi Schedule"))
global_enable.optional=false;
global_enable.rmempty = false;
function global_enable.validate(self, value, global_section)
if value == "1" then
if ( file_exists("/sbin/wifi") and
file_exists("/usr/bin/wifi_schedule.sh") )then
return value
else
return nil, translate("Could not find required /usr/bin/wifi_schedule.sh or /sbin/wifi")
end
else
return "0"
end
end
-- END Global Enable Checkbox
-- BEGIN Global Logging Checkbox
global_logging = global_section:option(Flag, "logging", translate("Enable logging"))
global_logging.optional=false;
global_logging.rmempty = false;
global_logging.default = 0
-- END Global Enable Checkbox
-- BEGIN Global Activate WiFi Button
enable_wifi = global_section:option(Button, "enable_wifi", translate("Activate wifi"))
function enable_wifi.write()
luci.sys.exec("/usr/bin/wifi_schedule.sh start manual")
end
-- END Global Activate Wifi Button
-- BEGIN Global Disable WiFi Gracefully Button
disable_wifi_gracefully = global_section:option(Button, "disable_wifi_gracefully", translate("Disable wifi gracefully"))
function disable_wifi_gracefully.write()
luci.sys.exec("/usr/bin/wifi_schedule.sh stop manual")
end
-- END Global Disable Wifi Gracefully Button
-- BEGIN Disable WiFi Forced Button
disable_wifi_forced = global_section:option(Button, "disable_wifi_forced", translate("Disabled wifi forced"))
function disable_wifi_forced.write()
luci.sys.exec("/usr/bin/wifi_schedule.sh forcestop manual")
end
-- END Global Disable WiFi Forced Button
-- BEGIN Global Unload Modules Checkbox
global_unload_modules = global_section:option(Flag, "unload_modules", translate("Unload Modules (experimental; saves more power)"))
global_unload_modules.optional = false;
global_unload_modules.rmempty = false;
global_unload_modules.default = 0
-- END Global Unload Modules Checkbox
-- BEGIN Modules
modules = global_section:option(TextValue, "modules", "")
modules:depends("unload_modules", global_unload_modules.enabled);
modules.wrap = "off"
modules.rows = 10
function modules.cfgvalue(self, section)
mod=uci.get("wifi_schedule", section, "modules")
if mod == nil then
mod=""
end
return mod:gsub(" ", "\r\n")
end
function modules.write(self, section, value)
if value then
value_list = value:gsub("\r\n", " ")
ListValue.write(self, section, value_list)
uci.set("wifi_schedule", section, "modules", value_list)
end
end
-- END Modules
-- BEGIN Determine Modules
determine_modules = global_section:option(Button, "determine_modules", translate("Determine Modules Automatically"))
determine_modules:depends("unload_modules", global_unload_modules.enabled);
function determine_modules.write(self, section)
output = luci.sys.exec("/usr/bin/wifi_schedule.sh getmodules")
modules:write(section, output)
end
-- END Determine Modules
-- BEGIN Section
d = m:section(TypedSection, "entry", "Schedule events")
d.addremove = true
--d.anonymous = true
-- END Section
-- BEGIN Enable Checkbox
c = d:option(Flag, "enabled", translate("Enable"))
c.optional=false; c.rmempty = false;
-- END Enable Checkbox
-- BEGIN Day(s) of Week
dow = d:option(MultiValue, "daysofweek", translate("Day(s) of Week"))
dow.optional = false
dow.rmempty = false
dow:value("Monday")
dow:value("Tuesday")
dow:value("Wednesday")
dow:value("Thursday")
dow:value("Friday")
dow:value("Saturday")
dow:value("Sunday")
-- END Day(s) of Weel
-- BEGIN Start Wifi Dropdown
starttime = d:option(Value, "starttime", translate("Start WiFi"))
starttime.optional=false;
starttime.rmempty = false;
starttime:value("00:00")
starttime:value("01:00")
starttime:value("02:00")
starttime:value("03:00")
starttime:value("04:00")
starttime:value("05:00")
starttime:value("06:00")
starttime:value("07:00")
starttime:value("08:00")
starttime:value("09:00")
starttime:value("10:00")
starttime:value("11:00")
starttime:value("12:00")
starttime:value("13:00")
starttime:value("14:00")
starttime:value("15:00")
starttime:value("16:00")
starttime:value("17:00")
starttime:value("18:00")
starttime:value("19:00")
starttime:value("20:00")
starttime:value("21:00")
starttime:value("22:00")
starttime:value("23:00")
function starttime.validate(self, value, d)
return time_validator(self, value, translate("Start Time"))
end
-- END Start Wifi Dropdown
-- BEGIN Stop Wifi Dropdown
stoptime = d:option(Value, "stoptime", translate("Stop WiFi"))
stoptime.optional=false;
stoptime.rmempty = false;
stoptime:value("00:00")
stoptime:value("01:00")
stoptime:value("02:00")
stoptime:value("03:00")
stoptime:value("04:00")
stoptime:value("05:00")
stoptime:value("06:00")
stoptime:value("07:00")
stoptime:value("08:00")
stoptime:value("09:00")
stoptime:value("10:00")
stoptime:value("11:00")
stoptime:value("12:00")
stoptime:value("13:00")
stoptime:value("14:00")
stoptime:value("15:00")
stoptime:value("16:00")
stoptime:value("17:00")
stoptime:value("18:00")
stoptime:value("19:00")
stoptime:value("20:00")
stoptime:value("21:00")
stoptime:value("22:00")
stoptime:value("23:00")
function stoptime.validate(self, value, d)
return time_validator(self, value, translate("Stop Time"))
end
-- END Stop Wifi Dropdown
-- BEGIN Force Wifi Stop Checkbox
force_wifi = d:option(Flag, "forcewifidown", translate("Force disabling wifi even if stations associated"))
force_wifi.default = false
force_wifi.rmempty = false;
function force_wifi.validate(self, value, d)
if value == "0" then
if file_exists("/usr/bin/iwinfo") then
return value
else
return nil, translate("Could not find required programm /usr/bin/iwinfo")
end
else
return "1"
end
end
-- END Force Wifi Checkbox
return m

View file

@ -0,0 +1,22 @@
<%#
Copyright (c) 2016, prpl Foundation
Permission to use, copy, modify, and/or distribute this software for any purpose with or without
fee is hereby granted, provided that the above copyright notice and this permission notice appear
in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Author: Nils Koenig <openwrt@newk.it>
-%>
<%+header%>
<h2 name="title"><%=title%></h2>
<div id="content_fileviewer">
<textarea style="width: 100%" readonly="readonly" wrap="off" rows="<%=content:cmatch("\n")+1%>" id="content_id"><%=content:pcdata()%></textarea>
</div>
<%+footer%>