T'was the night before Sixmas, when all through the Net, Not a download was stirring - it hadn't launched yet. The browsers were pointed at Yahoo with care, In hopes that Community soon would be there.
I've always been a bit of a sucker for the idea of home automation, but have never got around to investing in any of the hardware necessary to make it a reality. This evening, though, I thought it would be rather near to set a process running on my Pi that would be aware of my presence, as a "hook" on which to hang future actions should I invest in such everyday essentials as, say, Internet-connected lightbulbs.
The obvious "input" would be to switch behaviour based on whether my phone was connected to Home WiFi or not. Handily, I can set a static IP for my phone, so this can be easily ping'd.
As a first stab, I tried the following (as jarvis.py, naturally):
#!/usr/bin/env python import subprocess PHONE_IP = '192.168.0.6' def isHome(): with open(subprocess.os.devnull,'w') as DEVNULL: output = subprocess.Popen(["fping","-c","1",PHONE_IP],stdout=DEVNULL,stderr=DEVNULL,shell=False) output.communicate() return output.returncode == 0 def main(): wasHome = True while True: homeness = isHome() if wasHome != homeness: print 'state changed to ' + str(homeness) wasHome = homeness if __name__ == '__main__': main() This ran into a problem, though - ping, though pretty reliable, isn't guaranteed to succeed. I was getting false positives all over the place. I introduced a "buffering" system in the next iteration, as well as an actual action to be taken (emailing myself a "Welcome Home!" note, via mutt)
#!/usr/bin/env python import subprocess PHONE_IP = '192.168.0.6' CACHING_LEVEL = 3 def isHome(): with open(subprocess.os.devnull,'w') as DEVNULL: output = subprocess.Popen(["fping","-c","1",PHONE_IP],stdout=DEVNULL,stderr=DEVNULL,shell=False) output.communicate() return output.returncode == 0 def onHomenessChange(homeness): if homeness: p1 = subprocess.Popen(['echo'],stdout=subprocess.PIPE) p2 = subprocess.Popen(['mutt','-s','Welcome home!','scubbojj@gmail.com'],stdin=p1.stdout, stdout=subprocess.PIPE) p2.communicate() def main(): previousHomenessState = True cachedHomenessStates = [True]*CACHING_LEVEL while True: homeness = isHome() cachedHomenessStates = cachedHomenessStates[1:] + [homeness] if previousHomenessState != homeness and (not any(cachedHomenessStates) if previousHomenessState else all(cachedHomenessStates)): onHomenessChange(homeness) previousHomenessState = homeness if __name__ == '__main__': main() This way, the "change" has to last for CACHING_LEVEL number of pings before it registers. If your ping is regularly blipping out for more than three consecutive attempts, well, you've probably got bigger problems on your hands. I'm pretty proud of the if clause in main(), which checks that:
the latest "homeness" value is different from the oldest recorded one, and that
all the recorded "homeness" values (except the oldest one) are the same - I could have achieved the same with something like reduce(lambda x, y: x and y, [cachedHomenessStates[i] == cachedHomenessStates[i+1] for i in range(len(cachedHomenessStates) - 1)]), which would arguably have been more readable and less clever, but I couldn't not use this once I'd thought of it!
But wait! When you close the ssh connection, this process will end! Never fear, nohup is here. Simply run nohup ./jarvis.py & and your process will merrily run until the end of time - the appended & sends the process into the background, and nohup means the process keeps running even after receiving the "hang-up" signal (sent by a disconnected ssh session).
For my next trick, I'll re-establish my torrent server, and set it to only be downloading when I'm not around and wanting my precious bandwidth. Anything else I should implement?