Friday, January 15, 2010

Reconnect to wireless network when opening laptop lid

When I close my laptop's LID, my installation is configured to put the computer into "standby", a.k.a. sleep mode. This turns off some devices, which includes my network devices, specifically my wireless device.

When it wakes from sleep mode, the "known" wireless networks isn't always up to date, and sometimes doesn't update for up to 10 to 20 seconds, which means NetworkManager only reconnects to the wireless network when it does do such a scan.

I have, however, noticed that forcing a scan by running "iwlist scan" as root causes NetworkManager to immediately pick up the network and initiate the connection.

So I conjured up a script to help with this.

ACPI allows one to plug into some of it's events, one of which is the "lid" event. Though, once my laptop went into sleep mode, opening the lid doesn't automatically wake it up. I have to explicitly press the power button for this. The result is that the lid OPEN event is never triggered, as the machine is in standby when it physically happens.

I had a look at the ACPI docs, and there doesn't seem to be an event for "wake". Using acpi_listen, I did notice some events being triggered with the wake up. These are the ac_adapter, battery and 2 processor events (one for each core). They didn't carry any information which could reliably indicate a wake event, so I was forced to do my own.

So whenever I close my lid, I have an event that creates a file under /tmp. When the processor event is handled, it would check for this file, which if it exists indicates a fairly descent probability of "wake up".

If I were to close the lid and open it up before sleep mode has entered, ACPI does trigger an open event, which is the reason for the check on line 15 of "sleeplid.sh".

So to set this up I edited /etc/acpi/events/lidbtn, and added a 2nd action to trigger my event script. This results in the file reading:
event=button[ /]lid
action=/etc/acpi/lid.sh
action=/etc/acpi/sleeplid.sh lid
I also created a new event configuration, called /etc/acpi/events/processor, which reads:
event=processor
action=/etc/acpi/sleeplid.sh processor
And finally, just to make the actual event handler /etc/acpi/sleeplist.sh:
#!/bin/bash

LOG=/tmp/.sleeplig.log
SLEEPING=/tmp/.sleeplid.sleeping
DEV=wlan0

exec 2>&1 >> "$LOG"

echo "Event triggered: "`date`

DOSCAN=0
if [ "$1" = "lid" ]
then
  if grep -q closed /proc/acpi/button/lid/*/state
  then
    echo "LID closed"
    touch "$SLEEPING"
  else
    echo "LID opened"
  fi
elif [ "$1" = "processor" ]
then
  echo "Processor event"

  if [ -f "$SLEEPING" ]
  then
    rm -f "$SLEEPING"
    DOSCAN=1
  fi
else
  echo "WARN: Unknown event '$1'"
fi

if [ $DOSCAN -eq 1 ]
then
  echo "Initiating scan."
  iwlist $DEV scan
fi
So this basically triggers the script to run with an argument "lid" whenever the lid event occurs, and argument "processor" when the processor event occurs.
If you intend on using this you might need to update the DEV variable to whatever your wireless device is named. Since ACPI events are very device specific, you might also need to customize other aspects. Though the general idea would probably not change much.


And people wonder why I only use Linux...

No comments: