Python script for thinkingcleaner roomba interface
Python script for thinkingcleaner roomba interface
Since this topic not so related to the rP I created a separate topic for this.
Håvard
Re: Python script for thinkingcleaner roomba interface
Hi Karl.
I made som minor changes just ro reflect the variable name and python scirpt name that makes sense for me.
It works perfectly and the timestamp is updated every time the state of the roomba changes.
When an update is detected and the variabel above is updated I am running a script that sends a request to the roomba for status update. This is handled in a new script. Could this script be implemented in your script and be the result of incoming web hook?
I made som minor changes just ro reflect the variable name and python scirpt name that makes sense for me.
It works perfectly and the timestamp is updated every time the state of the roomba changes.
Code: Select all
# by Karl Wachs
# feb 5
# try to get roomba command
##
import SocketServer
import datetime, subprocess, os, time
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
#indigo.server.log( unicode(self.client_address))
#indigo.server.log( unicode(self.data))
if unicode(self.data).find("webhook.html")>-1:
indigo.server.log( "roomba send command")
indigo.variable.updateValue("RoombaUpdate",datetime.datetime.now().strftime("%Y%m%d-%H:%M:%S"))
return
def killOldPgm(myPID,pgmToKill):
cmd= "ps -ef | grep "+pgmToKill+" | grep -v grep"
ret = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()[0]
lines=ret.split("\n")
for line in lines:
if len(line) < 10: continue
line=line.split()
pid=int(line[1])
if pid == int(myPID): continue
os.system("kill -9 "+str(pid))
indigo.server.log( "killed program: "+pgmToKill+" pid="+str(pid))
time.sleep(5)
if __name__ == "__main__":
PORT = 6193 ## port number used by roomba
ipAddress="192.168.1.100" ## ip number of your indigo MAC
try:
indigo.variable.create("RoombaUpdate","")
except:
pass
myPID = str(os.getpid())
indigo.server.log(" PID of roomba server is:" +myPID )
killOldPgm(myPID,"RoombaUpdate.py")
# Create the server, binding on port xxx
server = SocketServer.TCPServer((ipAddress, PORT), MyTCPHandler)
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
Code: Select all
import simplejson as json
import urllib2
urlReturned = urllib2.urlopen('http://192.168.1.114/status.json')
#format api returned data
data_getStatus = urlReturned.read()
#interpret json
dict = json.loads(data_getStatus)
action = str(dict['action'])
indigo.variable.updateValue(12824087, action)
result = str(dict['result'])
indigo.variable.updateValue(1042192793, result)
name = str(dict['status']['name'])
indigo.variable.updateValue(1267855651, name)
battery_charge = str(dict['status']['battery_charge'])
indigo.variable.updateValue(1262851281, battery_charge)
capacity = str(dict['status']['capacity'])
indigo.variable.updateValue(720495017, capacity)
cleaner_state = str(dict['status']['cleaner_state'])
indigo.variable.updateValue(1925578960, cleaner_state)
cleaning = str(dict['status']['cleaning'])
indigo.variable.updateValue(1995969993, cleaning)
schedule_serial_number = str(dict['status']['schedule_serial_number'])
indigo.variable.updateValue(1720655499, schedule_serial_number)
near_homebase = str(dict['status']['near_homebase'])
indigo.variable.updateValue(321117213, near_homebase)
translateDict = {'st_base': 'On homebase: Not Charging', 'st_base_recon': 'On homebase: Reconditioning Charging', 'st_base_full': 'On homebase: Full Charging', 'st_base_trickle': 'On homebase: Trickle Charging', 'st_base_wait': 'On homebase: Waiting', 'st_plug': 'Plugged in: Not Charging', 'st_plug_recon': 'Plugged in: Reconditioning Charging', 'st_plug_full': 'Plugged in: Full Charging', 'st_plug_trickle': 'Plugged in: Trickle Charging', 'st_plug_wait': 'Plugged in: Waiting', 'st_stopped': 'Stopped', 'st_clean': 'Cleaning', 'st_cleanstop': 'Stopped with cleaning', 'st_clean_spot': 'Spot cleaning', 'st_clean_max': 'Max cleaning', 'st_delayed': 'Delayed cleaning will start soon ..', 'st_dock': 'Searching Homebase', 'st_pickup': 'Roomba picked up', 'st_remote': 'Remote control driving', 'st_wait': 'Waiting for command', 'st_off': 'Off', 'st_error': 'Error', 'st_locate': 'Find me!', 'st_unknown': 'Unknown state'}
translateFrom = indigo.variables[1925578960].value
translateTo = translateDict.get(translateFrom, 'error translation')
indigo.variable.updateValue(1017727089, value=translateTo)Håvard
Re: Python script for thinkingcleaner roomba interface
As for resources consumed: open activity monitor and look at the process with the pid in the logfile
It should be very small as it just sits there and waits
As for stopping:
Copy the part that kills the old process and put it into another action. This can be an internal script.
To handle the send part: we could add a curl statement that sends the commands to the roomba. I am on my iPhone and can't look at your code. Will check it later.
Sent from my iPhone using Tapatalk
It should be very small as it just sits there and waits
As for stopping:
Copy the part that kills the old process and put it into another action. This can be an internal script.
To handle the send part: we could add a curl statement that sends the commands to the roomba. I am on my iPhone and can't look at your code. Will check it later.
Sent from my iPhone using Tapatalk
Re: Python script for thinkingcleaner roomba interface
This should do the whole thing:
and put this into an action "killRomba" execute script, should not need to be external script, it executes FAST
Karl
Code: Select all
# by Karl Wachs
# feb 5
# try to get roomba command
##
import SocketServer
import datetime, subprocess, os, time
import simplejson as json
import urllib2
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
#indigo.server.log( unicode(self.client_address))
#indigo.server.log( unicode(self.data))
if unicode(self.data).find("webhook.html")>-1:
indigo.server.log( "roomba send command")
indigo.variable.updateValue("RoombaUpdate",datetime.datetime.now().strftime("%Y%m%d-%H:%M:%S"))
urlReturned = urllib2.urlopen('http://192.168.1.114/status.json')
#format api returned data
data_getStatus = urlReturned.read()
#interpret json
dict = json.loads(data_getStatus)
action = str(dict['action'])
indigo.variable.updateValue(12824087, action)
result = str(dict['result'])
indigo.variable.updateValue(1042192793, result)
name = str(dict['status']['name'])
indigo.variable.updateValue(1267855651, name)
battery_charge = str(dict['status']['battery_charge'])
indigo.variable.updateValue(1262851281, battery_charge)
capacity = str(dict['status']['capacity'])
indigo.variable.updateValue(720495017, capacity)
cleaner_state = str(dict['status']['cleaner_state'])
indigo.variable.updateValue(1925578960, cleaner_state)
cleaning = str(dict['status']['cleaning'])
indigo.variable.updateValue(1995969993, cleaning)
schedule_serial_number = str(dict['status']['schedule_serial_number'])
indigo.variable.updateValue(1720655499, schedule_serial_number)
near_homebase = str(dict['status']['near_homebase'])
indigo.variable.updateValue(321117213, near_homebase)
translateDict = {'st_base': 'On homebase: Not Charging', 'st_base_recon': 'On homebase: Reconditioning Charging', 'st_base_full': 'On homebase: Full Charging', 'st_base_trickle': 'On homebase: Trickle Charging', 'st_base_wait': 'On homebase: Waiting', 'st_plug': 'Plugged in: Not Charging', 'st_plug_recon': 'Plugged in: Reconditioning Charging', 'st_plug_full': 'Plugged in: Full Charging', 'st_plug_trickle': 'Plugged in: Trickle Charging', 'st_plug_wait': 'Plugged in: Waiting', 'st_stopped': 'Stopped', 'st_clean': 'Cleaning', 'st_cleanstop': 'Stopped with cleaning', 'st_clean_spot': 'Spot cleaning', 'st_clean_max': 'Max cleaning', 'st_delayed': 'Delayed cleaning will start soon ..', 'st_dock': 'Searching Homebase', 'st_pickup': 'Roomba picked up', 'st_remote': 'Remote control driving', 'st_wait': 'Waiting for command', 'st_off': 'Off', 'st_error': 'Error', 'st_locate': 'Find me!', 'st_unknown': 'Unknown state'}
translateFrom = indigo.variables[1925578960].value
translateTo = translateDict.get(translateFrom, 'error translation')
indigo.variable.updateValue(1017727089, value=translateTo)
return
def killOldPgm(myPID,pgmToKill):
cmd= "ps -ef | grep "+pgmToKill+" | grep -v grep"
ret = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()[0]
lines=ret.split("\n")
for line in lines:
if len(line) < 10: continue
line=line.split()
pid=int(line[1])
if pid == int(myPID): continue
os.system("kill -9 "+str(pid))
indigo.server.log( "killed program: "+pgmToKill+" pid="+str(pid))
time.sleep(5)
if __name__ == "__main__":
PORT = 6193 ## port number used by roomba
ipAddress="192.168.1.100" ## ip number of your indigo MAC
try:
indigo.variable.create("RoombaUpdate","")
except:
pass
myPID = str(os.getpid())
indigo.server.log(" PID of roomba server is:" +myPID )
killOldPgm(myPID,"RoombaUpdate.py")
# Create the server, binding on port xxx
server = SocketServer.TCPServer((ipAddress, PORT), MyTCPHandler)
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()Code: Select all
import subprocess
pgmToKill="roomba.py"
cmd= "ps -ef | grep "+pgmToKill+" | grep -v grep"
ret = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()[0]
lines=ret.split("\n")
for line in lines:
if len(line) < 10: continue
line=line.split()
pid=int(line[1])
os.system("kill -9 "+str(pid))
indigo.server.log( "killed program: "+pgmToKill+" pid="+str(pid))
Re: Python script for thinkingcleaner roomba interface
That is also working Karl. Thank you so much for your support. This roomba project is really starting to be fun now! 
Håvard
Re: Python script for thinkingcleaner roomba interface
good to hear.. I am just getting into socket communication.. struggling with threading and callbacks.. but that would open a host of options do do things much faster , more stable ..
karl
ps do you see any load from the program in activity log? should be minimal.
karl
ps do you see any load from the program in activity log? should be minimal.
Re: Python script for thinkingcleaner roomba interface
Yepp that is indeed minimal... See the pictures below:
- Attachments
-
- Screen Shot 2016-02-06 at 18.24.57.png (65.93 KiB) Viewed 6460 times
-
- Screen Shot 2016-02-06 at 18.24.38.png (58.96 KiB) Viewed 6460 times
Håvard
Re: Python script for thinkingcleaner roomba interface
Hi Karl.
I have been running this for some time now and I seams very stable. Is it difficult to collect this as a plugin, and start stop the server when the plugin is enabled/disabled? And in addition store the response as states in the plugin? I guess that if this would be a plugin then the IP address and listening port should be configurable also?
I have been running this for some time now and I seams very stable. Is it difficult to collect this as a plugin, and start stop the server when the plugin is enabled/disabled? And in addition store the response as states in the plugin? I guess that if this would be a plugin then the IP address and listening port should be configurable also?
Håvard
Re: Python script for thinkingcleaner roomba interface
Harvard,
sure its possible
but what can you NOT do with the 2 scripts:
1. start: yes= run the script
2. stop: yes= run the kill script
3. set IP# and PORT number dynamically: yes (read 2 variables from indigo )
3. set variables to values of roomba responses : yes
4. the only thing you can not do is change a state of a device.
what else is missing?
Writing a plugin would probably take a day with debugging. Happy to do that if there is a real "payback"(*) for it.
Karl
(*) functionality
sure its possible
but what can you NOT do with the 2 scripts:
1. start: yes= run the script
2. stop: yes= run the kill script
3. set IP# and PORT number dynamically: yes (read 2 variables from indigo )
3. set variables to values of roomba responses : yes
4. the only thing you can not do is change a state of a device.
what else is missing?
Writing a plugin would probably take a day with debugging. Happy to do that if there is a real "payback"(*) for it.
Karl
(*) functionality
Re: Python script for thinkingcleaner roomba interface
Hi Karl. I see your point. There is practically now gain from assembling this to a plugin.
Is there an elegant way to handle a state dependent timer. I want to pull the device every 30 minutes when in docking, and once a minute when leaving the base station.
I know I could do this with triggers and timers, but is it more effective to handle this in the script?
Is there an elegant way to handle a state dependent timer. I want to pull the device every 30 minutes when in docking, and once a minute when leaving the base station.
I know I could do this with triggers and timers, but is it more effective to handle this in the script?
Håvard
Re: Python script for thinkingcleaner roomba interface
there is no trivial way to do this in the script. the beauty of the script is that it is fast and ends once it receives/sends the roomba messages. If we want to add an asynchronous action it can not be in the same method, as it waits for the next call from roomba. so we would need to launch another script that waits for x / y seconds before it queries it again. and then you would need to handle already called scripts if you get the same message twice from roomba.
better to do this in an independent (external script) something like this:
import time
option="B"
while True:
read indigo variable x,y, and check if any change:
- if option A: nextCall=time.time()+30*60; option="A"
- if option B: nextCall=time.time() + 60. ; option ="B"
if time.time() > nextCall:
send msg to roomba
if option=="A": nextCall=time.time() + 30*60
else: nextCall=time.time()+60
time.sleep(5)
if you need help let me know
Karl
better to do this in an independent (external script) something like this:
import time
option="B"
while True:
read indigo variable x,y, and check if any change:
- if option A: nextCall=time.time()+30*60; option="A"
- if option B: nextCall=time.time() + 60. ; option ="B"
if time.time() > nextCall:
send msg to roomba
if option=="A": nextCall=time.time() + 30*60
else: nextCall=time.time()+60
time.sleep(5)
if you need help let me know
Karl
Re: Python script for thinkingcleaner roomba interface
in python (compiles w/o error):
Code: Select all
import time
nextCall=0.
lastState=""
while True:
theState= indigo.variables[1925578960].value # this is the state of roomba
if theState != lastState:
if theState == 'cleaner_state': ## you need to put the proper string here
nextCall=time.time()+30*60
lastState="cleaning"
else:
nextCall=time.time()+60
lastState="home"
if time.time() > nextCall:
continue # put your send msg to roomba here
if lastState !="home": # put the next msg time into nextCall: 1 minute or 30 minutes
nextCall=time.time() + 30*60
else:
nextCall=time.time()+60
time.sleep(5)