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?
Still got a ways to go yet