from signal import SIGTERM, signal from subprocess import CalledProcessError, check_output from sys import exit from time import sleep INITIAL_DELAY_IN_SECONDS = 40 PING_INTERVAL_IN_SECONDS = 80 class WifiKeepalive: def __init__(self): self.defaultRoute = None self.initialDelay = INITIAL_DELAY_IN_SECONDS self.pingInterval = PING_INTERVAL_IN_SECONDS self.isConnected = False self.pingCommand = 'ping -4 -c 1 -W 2 -n' self.connectedMessage = 'Connected to Wifi' self.disconnectedMessage = 'No Wifi Connection' def run(self): self.prepare() while True: self.keepalive() sleep(self.pingInterval) def prepare(self): sleep(self.initialDelay) self.updateDefaultWifiRoute() if self.defaultRoute: self.connect(preparing=True) else: self.disconnect(preparing=True) def keepalive(self): if self.defaultRoute: self.connect() self.ping() or self.updateDefaultWifiRoute() else: self.disconnect() self.updateDefaultWifiRoute() def connect(self, preparing=False): if not self.isConnected or preparing: print(self.connectedMessage, flush=True) self.isConnected = True def disconnect(self, preparing=False): if self.isConnected or preparing: print(self.disconnectedMessage, flush=True) self.isConnected = False def ping(self): try: check_output([*self.pingCommand.split(), self.defaultRoute]) except CalledProcessError as e: return False return True def updateDefaultWifiRoute(self): defaults = [ r['gateway'] for r in self.getRoutes() if self.isDefaultWifiRoute(r) ] self.defaultRoute = defaults[0] if defaults else None def getRoutes(self): outputLines = check_output( ['route', '-n'] ).decode('utf-8').splitlines()[2:] routes = map(lambda r: self.parseRoute(r), outputLines) return routes def parseRoute(self, routeLine): destination, gateway, _, _, _, _, _, interface = routeLine.split() return {'destination': destination, 'gateway': gateway, 'interface': interface} def isDefaultWifiRoute(self, route): return route['destination'] == '0.0.0.0' and route['interface'].startswith('w') def main(): signal(SIGTERM, lambda s, f: exit(0)) WifiKeepalive().run() if __name__ == '__main__': main()