Automatic wifi router resetter control scripts. Install `thunker` into your `/usr/local/bin` on the RPi and `thunker_daemon` into your *init.d*. You will need Ruby and the `net-ping` and 'wiringpi' gems. See it in action at https://vimeo.com/66365606
#! /usr/bin/ruby | |
require 'wiringpi' | |
require 'net/ping' | |
require 'syslog' | |
# Constants | |
OUTPUT_PINA = 0 # RPi Pin 11 | |
OUTPUT_PINB = 1 # RPi Pin 12 | |
ARM_ON_TIME = 0.1 | |
ARM_RESET_TIME = 0.05 | |
ARM_PAUSE_TIME = 1 | |
# Configs | |
@logfile_name = "/var/log/syslog" | |
@router_ip = '192.168.5.2' | |
# Globals | |
@resetting = false | |
# Singletons | |
@gpio = WiringPi::GPIO.new | |
@pinger = Net::Ping::ICMP.new | |
## | |
# Controls the 'organic rotory button actuator' | |
# | |
# This should never be calld with HIGH, HIGH or the battery will short out. Both | |
# pins should be connected to the inputs of a two output H bridge. | |
def write_bits(a, b) | |
if a == HIGH | |
raise "Can't have two high bits" if b == HIGH | |
# ensure we never have two high bits by always writing LOW first | |
@gpio.write OUTPUT_PINB, LOW | |
@gpio.write OUTPUT_PINA, HIGH | |
else | |
# Write out pin values | |
@gpio.write OUTPUT_PINA, LOW | |
@gpio.write OUTPUT_PINB, b | |
end | |
end | |
def motor_right | |
write_bits(HIGH, LOW) | |
end | |
def motor_left | |
write_bits(LOW, HIGH) | |
end | |
def motor_stop | |
write_bits(LOW, LOW) | |
end | |
## | |
# Log a message in the system log so we can keep track of the daemon's actions | |
def write_to_syslog msg | |
Syslog.open 'thunker', Syslog::LOG_PID, Syslog::LOG_DAEMON do |log| | |
log.log Syslog::LOG_NOTICE, "%s", msg | |
end | |
end | |
## | |
# Check the current status of the wireless network | |
def wireless_down? | |
# Try to ping the router, if we can't after five the wireless is down | |
5.times do | |
return false if @pinger.ping @router_ip | |
end | |
true | |
rescue | |
# When the network is unreachable there be errors... | |
true | |
end | |
## | |
# Does the router need a slap? | |
def reset_necessary? | |
down = wireless_down? | |
# We need to reset if the wireless is down but we aren't yet resetting | |
ret = down && !@resetting | |
# Log the network comming back up | |
write_to_syslog("Network back up") if !down && @resetting | |
# Store the state for next time | |
@resetting = down | |
ret | |
end | |
## | |
# Get the router back up and running | |
def reset_router | |
write_to_syslog("Outage detected.") | |
reset_arm | |
sleep ARM_PAUSE_TIME | |
motor_left | |
sleep ARM_ON_TIME | |
motor_stop | |
sleep ARM_PAUSE_TIME | |
reset_arm | |
write_to_syslog("Reset complete.") | |
end | |
def reset_arm | |
motor_right | |
sleep ARM_RESET_TIME | |
motor_stop | |
sleep ARM_RESET_TIME | |
motor_right | |
sleep ARM_RESET_TIME | |
motor_stop | |
end | |
## | |
# It all starts here... | |
def listener_main | |
# Set up the pins to use as an output pin | |
@gpio.mode OUTPUT_PINA, OUTPUT | |
@gpio.mode OUTPUT_PINB, OUTPUT | |
motor_stop | |
Signal.trap("TERM") do | |
motor_stop | |
exit | |
end | |
Signal.trap("USR1") do | |
reset_router | |
end | |
# Listen to the network for failures, with 5 seconds between polls | |
loop do | |
reset_router if reset_necessary? | |
sleep 5 | |
end | |
end | |
# Go! | |
listener_main |
#! /usr/bin/env bash | |
# This is intended for Debain consuption | |
### BEGIN INIT INFO | |
# Provides: thunker_daemon | |
# Required-Start: $all | |
# Required-Stop: | |
# Should-Start: $all | |
# Should-Stop: | |
# Default-Start: 2 3 4 5 | |
# Default-Stop: 0 1 6 | |
# Short-Description: Thunker | |
# Description: Thunker hits things when wireless drops. | |
### END INIT INFO | |
. /lib/lsb/init-functions | |
exec_name=thunker | |
exec_path=/usr/local/bin/$exec_name | |
display_name="Thunker Daemon" | |
start() { | |
pgrep ${exec_name} > /dev/null | |
if [ $? -eq 0 ]; then | |
log_success_msg "${display_name} is already running" | |
return | |
fi | |
if ${exec_path}& | |
then | |
disown | |
log_success_msg "${display_name} started" | |
else | |
log_failure_msg "Failed to start ${display_name}" | |
fi | |
} | |
stop() { | |
pkill ${exec_name} | |
pgrep ${exec_name} > /dev/null | |
if [ $? -ne 0 ] | |
then | |
log_success_msg "${display_name} stopped" | |
else | |
log_failure_msg "Failed to stop ${display_name}" | |
fi | |
} | |
case "$1" in | |
start) | |
start | |
;; | |
stop) | |
stop | |
;; | |
restart) | |
stop | |
start | |
;; | |
status) | |
pid=`pgrep ${exec_name}` | |
if [ $? -eq 0 ] | |
then | |
# All OK | |
echo "${display_name} running as PID:$pid." | |
exit 0 | |
else | |
# We are not running | |
echo "${display_name} is not running." | |
exit 3 | |
fi | |
;; | |
*) | |
echo "Usage: /etc/init.d/thunker_daemon {start|stop|restart|status}" | |
exit 1 | |
;; | |
esac | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
With thanks to @jstephenson and @tommylommykins