User Tools

Site Tools


doc:howto:hardware.button

Attach functions to a push button

There several ways for controlling buttons in OpenWrt.

  • buttons using procd
  • Hotplug buttons, using the hotplug daemon (phased out with r36003).
  • HID buttons, using /dev/input/event with an application like triggerhappy.
Kernel configuration
If a target platform is known to support buttons, appropriate kernel modules are selected by default.
If a platform is not known to support buttons, you are required to install various kernel modules yourself such as diag, input-gpio-buttons, gpio-button-hotplug, and others.
However, installing various modules will not necessarily yield a successful result.

Hotplug Buttons

Please note the introduction of procd into OpenWrt; In r37132 the package hotplug2 was removed from the default packages; this howto may need to be updated.
r37336: procd: make old button hotplug rules work until all packages are migrated
FIXME Please read the articles wifitoggle, buttons and nslu2.hardware.button and eventually merge them into this one article

Preliminary steps

The first step is to make Hotplug execute scripts in /etc/hotplug.d/button when a button is clicked. Modify /etc/hotplug2.rules — remove '^' before 'button' as follow:

$include /etc/hotplug2-common.rules
 
SUBSYSTEM ~~ (^net$|^input$|button$|^usb$|^ieee1394$|^block$|^atm$|^zaptel$|^tty$) {
	exec /sbin/hotplug-call %SUBSYSTEM%
}
 
DEVICENAME == watchdog {
	exec /sbin/watchdog -t 5 /dev/watchdog
	next-event
}

The second step is to find out the internal name of the button you want to use: some images use generic names such as BTN_1, BTN_2, others have more specific ones like reset, wps, etc. Run the following:

# mkdir -p /etc/hotplug.d/button

Create the file /etc/hotplug.d/button/buttons with your favorite text editor, paste the following:

#!/bin/sh
logger $BUTTON
logger $ACTION 

Save and exit. Now press the button you want to use, then run logread.

Jan 1 00:01:15 OpenWrt user.notice root: BTN_1   
Jan 1 00:01:15 OpenWrt user.notice root: pressed   
Jan 1 00:01:16 OpenWrt user.notice root: BTN_1    
Jan 1 00:01:16 OpenWrt user.notice root: released 

BTN_1 is the name of the button you want to use. If you want or need to use another button, replace every instance of BTN_1 in the rest of this document with the correct text. From now on, there are several possible approaches: the first uses the 00-button script from the atheros target, the other a simpler shell script.

notice

If you want to run programs from hotplug's scripts you need to be sure PATH and the like are initialized properly, scripts invoked by hotplug only have a default env. Especially if you install stuff into nonstandard locations like /opt/usr/bin. It's possible by adding . /etc/profile after #!/bin/sh

#!/bin/sh
. /etc/profile

Using Atheros' 00-button + UCI

If you've installed the full version of wget, run the following:

# wget -O /etc/hotplug.d/button/00-button https://dev.openwrt.org/export/36332/trunk/target/linux/atheros/base-files/etc/hotplug.d/button/00-button

If you only have wget-nossl and don't want to or can't upgrade, create /etc/hotplug.d/button/00-button with your favorite editor, then paste the following:

#!/bin/sh
. /lib/functions.sh
do_button () {
        local button
        local action
        local handler
        local min
        local max
 
        config_get button $1 button
        config_get action $1 action
        config_get handler $1 handler
        config_get min $1 min
        config_get max $1 max
 
        [ "$ACTION" = "$action" -a "$BUTTON" = "$button" -a -n "$handler" ] && {
                [ -z "$min" -o -z "$max" ] && eval $handler
                [ -n "$min" -a -n "$max" ] && {
                        [ $min -le $SEEN -a $max -ge $SEEN ] && eval $handler
                }
        }
}
 
config_load system
config_foreach do_button button

Please note that after r34793 /etc/functions.sh → /lib/functions.sh so if you are using an old version change it!

Save and exit, then issue these commands:

uci add system button    
uci set system.@button[-1].button=BTN_1
uci set system.@button[-1].action=pressed
uci set system.@button[-1].handler='logger BTN_1 pressed'
uci commit system 

button is the name as the button, action is the event (two values: pressed and released), handler contains the command line to be run when the event is detected (can be a script as well).

You may need to reboot the router the make the change effective (mine would work with the simple shell script just fine but wouldn't budge when using the 00-button script — Frex 2011/03/25 22:29). If this works, you can change the handler to something more useful, and add more button handlers.

Examples

Example 1: Toggle Wi-Fi radio with a button press

uci add system button    
uci set system.@button[-1].button=wps    
uci set system.@button[-1].action=pressed
uci set system.@button[-1].handler='uci set wireless.@wifi-device[0].disabled=1 && wifi'
uci commit system 

Example 2: Assign two different functions to the same button: short press VS long press. This relies on tracking the released event rather than the pressed event.

uci add system button
uci set system.@button[-1].button=BTN_1
uci set system.@button[-1].action=released
uci set system.@button[-1].handler='logger timed pressed: 0-3s'
uci set system.@button[-1].min=0
uci set system.@button[-1].max=3
uci add system button
uci set system.@button[-1].button=BTN_1
uci set system.@button[-1].action=released
uci set system.@button[-1].handler='logger timed pressed: 8-10s'
uci set system.@button[-1].min=8
uci set system.@button[-1].max=10
uci commit system 

Example 3: Unmount USB storage using a long-ish press

uci add system button
uci set system.@button[-1].button=BTN_1
uci set system.@button[-1].action=released
uci set system.@button[-1].handler="for i in \$(mount | awk '/dev\/sd[b-z]/ { print \$1}'); do umount \$i; done"
uci set system.@button[-1].min=5
uci set system.@button[-1].max=10
uci commit system 

Example 4: Restore defaults

config button
        option button   reset
        option action   released
        option handler  "firstboot && reboot"
        option min              5
        option max             30

Example 5: Toggle Wi-Fi using a script

config button
        option button   wps
        option action   released
        option handler  "/usr/bin/wifionoff"
        option min      0
        option max      3

You'll have to create the file /usr/bin/wifionoff and paste this:

#!/bin/sh
SW=$(uci -q get wireless.@wifi-device[0].disabled)
[ "$SW" == "1" ] && uci set wireless.@wifi-device[0].disabled=0
[ "$SW" == "1" ] || uci set wireless.@wifi-device[0].disabled=1
wifi

Another option for wifionoff is this script (doesn't store the state in uci, so it remains what is set in the configuration) You can also call this script eg. from cron, to switch off your wifi at night.

#!/bin/sh
STATEFILE="/tmp/wifionoff.state"
 
if [ $# -eq 1 ]; then
  case $1 in
    "up"|"on")
      STATE=off
      ;;
    "down"|"off")
      STATE=on
      ;;
  esac
else
  if [ ! -e ${STATEFILE} ]; then
    STATE=on
  else
    . ${STATEFILE}
  fi
fi
if [ -z ${STATE} ]; then
  STATE=on
fi
 
if [ ${STATE} == "on" ]; then
  /sbin/wifi down
  STATE=off
else
  /sbin/wifi up
  STATE=on
fi
 
echo "STATE=${STATE}" > ${STATEFILE}

Example 6: Set transmission-daemon alt-speed, enable or disable.Short press will activate alt-speed or longer press will deactivate alt-speed and also turns on qss led about speed status on tl-wr1043nd

Edit your alt-speed limits from transmission-daemon , settings.json file.To execute script, you need to install transmission-remote package from opkg.

uci add system button    
uci set system.@button[-1].button=BTN_1
uci set system.@button[-1].action=pressed
uci set system.@button[-1].handler='transmission-remote -as'
uci add system button    
uci set system.@button[-1].button=BTN_1
uci set system.@button[-1].action=pressed
uci set system.@button[-1].handler='echo 1 > /sys/class/leds/tl-wr1043nd:green:qss/brightness'
uci add system button
uci set system.@button[-1].button=BTN_1
uci set system.@button[-1].action=released
uci set system.@button[-1].handler='transmission-remote -AS'
uci set system.@button[-1].min=1
uci set system.@button[-1].max=4
uci add system button
uci set system.@button[-1].button=BTN_1
uci set system.@button[-1].action=released
uci set system.@button[-1].handler='echo 0 > /sys/class/leds/tl-wr1043nd:green:qss/brightness'
uci set system.@button[-1].min=1
uci set system.@button[-1].max=4
uci commit system

Leftovers from a previous version

FIXME

mkdir -p /etc/hotplug.d/button
touch /etc/hotplug.d/button/00-button

if [ "$ACTION" = "pressed" ]; then
    if [ "$BUTTON" = "BTN_0" ]; then BTN_0
    elif [ "$BUTTON" = "BTN_1" ]; then BTN_1
    fi 
fi 

mkdir -p /etc/hotplug.d/button
wget -O /etc/hotplug.d/button/00-button http://dev.openwrt.org/export/21216/trunk/target/linux/atheros/base-files/etc/hotplug.d/button/00-button 
wget -O http://dev.openwrt.org/export/21216/trunk/target/linux/atheros/base-files/etc/hotplug.d/button/00-button

#!/bin/sh
[ "$BUTTON" = "BTN_1" ] && [ "$ACTION" = "pressed" ] && {
SW=$(uci get wireless.@wifi-device[0].disabled)
[ $SW == '0' ] && uci set wireless.@wifi-device[0].disabled=1
[ $SW == '0' ] || uci set wireless.@wifi-device[0].disabled=0
wifi
}

WR1043ND

If you decide to use the wifitoggle package, you will need to change a few things on the default configuration. The following will work and make the QSS led blink "slowly" when wifi is on:

uci show wifitoggle
uci set wifitoggle.@wifitoggle[0]=wifitoggle
uci set wifitoggle.@wifitoggle[0].led_enable_trigger=timer
uci set wifitoggle.@wifitoggle[0].persistent=1
uci set wifitoggle.@wifitoggle[0].button=BTN_1
uci set wifitoggle.@wifitoggle[0].led_sysfs=tl-wr1043nd:green:qss
uci set wifitoggle.@wifitoggle[0].led_enable_delayon=2000
uci set wifitoggle.@wifitoggle[0].led_disable_default=1
uci set wifitoggle.@wifitoggle[0].led_enable_delayoff=3000
uci set wifitoggle.@wifitoggle[0].timer=0

:!: You can probably get similar behaviour with phy0tpt trigger.

HID buttons

triggerhappy

To manage the router buttons and also other HID buttons (i.e pad buttons or keys of an usb device) we can use an application like triggerhappy.

Installation

  1. Install the triggerhappy package and the kmod-hid kernel module
  2. list your available buttons: execute
    thd --dump /dev/input/event*
    press your buttons
    EV_KEY KEY_WPS_BUTTON 1 /dev/input/event0 # KEY_WPS_BUTTON 1 command EV_KEY KEY_WPS_BUTTON 0 /dev/input/event0 # KEY_WPS_BUTTON 0 command EV_KEY KEY_VOLUMEDOWN 1 /dev/input/event1 # KEY_VOLUMEDOWN 1 command EV_KEY KEY_VOLUMEDOWN 0 /dev/input/event1 # KEY_VOLUMEDOWN 0 command
  3. Now associate your buttons to commands or scripts
    path /etc/triggerhappy/triggers.d/example.conf
    KEY_WPS_BUTTON 1 /etc/mywifiscript.sh
    KEY_VOLUMEUP 1 amixer -q set Speaker 3%+
    KEY_VOLUMEDOWN 1 amixer -q set Speaker 3%-
  4. run triggerhappy
    /etc/init.d/triggerhappy start
  5. enable triggerhappy permanently
    /etc/init.d/triggerhappy enable

Notes

  • triggerhappy repeats commands twice: see bug https://dev.openwrt.org/ticket/14995
  • kernel modules: kmod-hid and kmod-hid-generic both should be installed
    The kmod-hid-generic kernel module must be installed for buttons on USB devices such as USB sound cards to work in OpenWrt trunk. Only then the /dev/input/event0 node for the buttons was created on the DIR-505 router with attached USB sound card.
    [   31.720000] input: C-Media USB Headphone Set   as /devices/platform/ehci-platform/usb1/1-1/1-1:1.3/input/input0
    [   31.760000] hid-generic 0003:0D8C:000C.0001: input,hidraw0: USB HID v1.00 Device [C-Media USB Headphone Set  ] on usb-ehci-platform-1/input3
    [   31.800000] usbcore: registered new interface driver usbhid
    [   31.800000] usbhid: USB HID core driver
    This is also noted in https://dev.openwrt.org/ticket/12631

cmdpad

Another simpler application to manage buttons.

doc/howto/hardware.button.txt · Last modified: 2014/07/06 12:49 by theoradicus