{ "info": { "author": "", "author_email": "nick.waterton@med.ge.com", "bugtrack_url": null, "classifiers": [], "description": "roombapy\n================\n\nUnofficial iRobot Roomba 980 python library (SDK).\n\nThanks to https://github.com/koalazak/dorita980 where much of the inner workings were derived from.\n\nThis is version 1.0 so it may be buggy!\n**NEW** Now version 1.1.2 - so it may be less buggy (or not)\n\n## roombapy-delay\nFork from repository https://github.com/pschmitt/roombapy\n\nNew version, with custom delay\n\n## Advice\nIf you enjoy python980 and it works well for you, I recommend blocking the internet access to your robot to avoid the OTA firmware updates. New firmware changes can cause python980 to stop working. Blocking firmware updates can be performed using the parental control options on your router.\n\nWhen a new firmware is published, you can come here to verify if python980 is still compatible. Once python980 is compatible you can temporarily enable internet access for your robot to get the firmware upgrade.\n\n## Firmware 2.x.x notes\n**This library is only for firmware 2.x.x.** [Check your robot version!](http://homesupport.irobot.com/app/answers/detail/a_id/529) *NEW* **Now supports Python 2.7 and Python 3.6** (thanks to pschmitt for adding Python 3 compatibility)\n\nOnly local connections are supported, cloud connections are a future project. The project was written to allow Openhab2 control, so if you integrate Roomba into Openhab2, you can control it from anywhere.\n\nAs only **one connection at at time is** allowed to the Roomba local mqtt server, the app will connect via the cloud if you run in continuous mode. In periodic mode, the app can connect locally, but the library will be off line until the app disconnects, when it will automatically reconnect.\n\nTested with firmware version V2.2.5-2/Ubuntu 14.04\n* Now tested and working with F/W 2.2.9-1\n* Now tested on Ubuntu 16.04\n* Now tested with Python 3.5\n* Now Tested with OpenCV 3.2\n* Now Tested with paho-mqtt 1.3 (on python V2.7.12 and above - does **NOT** work on python versions lower than 2.7.9 - see \"Dependencies\")\n\n## Features\n* Get your username/password easily\n* Auto discovery robot IP (optional)\n* Local API control\n* Remote API control (via your MQTT broker)\n* Simplified Cleaning Preferences settings.\n* **NOT Firmware 1.6.x compatible.**\n* Firmware 2.x.x compatible.\n* Multiple Roombas supported (but not tested)\n* Continuous or periodic connection (to allow local app access)\n* Live Maps\n* Maps show locations of errors, bin full, cancelled runs\n* auto map translation and rotation (at cleaning completion/error etc.)\n* designed for openhab2 compatibility\n\n## Live Maps\n![iRobot Roomba 980 cleaning map using python980 lib](/roomba/res/map.png)\n### OpenCV\nIf you have OpenCV installed, the library will use it to render the final map (on completion/error), it uses PIL for Live Maps, so the final map looks nicer. **This uses a lot of processing power/memory**, I don't know what happens if you try this on a RPi or other limited platform!\nAlso, if you enable debugging mode (-D), intermediate maps (edges.png, final_map.png and so on) are drawn every time a new co-ordinate is reported (every second or so when running). This consumes a lot of resources **You have been warned!**.\n### PIL\nPlease use the latest version of pillow (V 4.1.1 at least), there are some nasty memory leaks in text processing in earlier versions that will quickly use up all your RAM and make the program unresponsive.\nThe library will issue a warning if it detects an earlier version of PIL.\n\nIf you do not have PIL installed, the system will not draw maps (even if enabled), even if you have OpenCV. PIL is used for basic image manipulations. If you do not specifically enable maps, no maps will be drawn. `roomba.py` uses maps, but the class default is to disable maps, so in your own scripts, if you want maps, you have to enable them (after creating the object).\n\n## Dependencies\nThe following libraries/modules are used. Some are optional:\n* six **required**\n* paho-mqtt *optional*\n* PIL/pillow *optional*\n* openCV *optional*\n* numpy *optional (used by openCV)*\n\nThis script/library is intended to forward roomba data/commands to/from a local MQTT server (this is optional though). In this case, you need paho-mqtt installed\n```bash\n pip install paho-mqtt\n```\n\n**NOTE:** Our friends at paho-mqtt have just released v1.3 (replaces v1.2.3) *which has breaking changes in it* You need to take note of the following:\nIf you are running python versions lower than 2.7.9 (eg Ubuntu 14.04), you **need to install/stay with the older version of paho-mqtt**. Check your python version using `python -V`.\nTo install the old version of paho-mqtt, use:\n```bash\n pip install paho-mqtt==1.2.3\n```\n\nlater versions of python should work with either version of paho-mqtt now, due to changes made in V1.1.1 and above of roomba.py.\n\nFor map drawing, you need at least PIL installed (preferably the latest version of pillow)\n```bash\n pip install pillow\n```\n\nFor fancy maps, you need openCV installed (V2, or V3). The installation of this can be complex, so I leave that up to you. Maps works without it, but it's nicer with it.\n\nFor Python 3.x compatibility, the six library is used\n```bash\n pip install six\n```\n\nor\n```bash\n pip3 install six\n```\ndepending on your default python environment (in Unbuntu 14.04 and 16.04, python 2.7 is the default, but python 3.x is available).\n\n## Install\nFirst you need python 2.7 *or* python 3.5/3.6 installed (thanks to pschmitt for adding Python 3 compatibility) and then:\n\ninstall via pip (this will take of dependencies as well):\n```bash\npip install https://github.com/NickWaterton/Roomba980-Python.git\n```\n\nAlternatively you may get going by cloning this repository:\n```bash\ngit clone https://github.com/NickWaterton/Roomba980-Python.git\ncd Roomba980-Python\n```\n\nrun `roomba -h` (or `python roomba/roomba.py` if you opted for the git checkout) to get the available options. This is what you will get:\n\n```bash\nusage: roomba [-h] [-f CONFIGFILE] [-n ROOMBANAME] [-t TOPIC]\n [-T BROKERFEEDBACK] [-C BROKERCOMMAND] [-S BROKERSETTING]\n [-b BROKER] [-p PORT] [-U USER] [-P PASSWORD] [-R ROOMBAIP]\n [-u BLID] [-w ROOMBAPASSWORD] [-i INDENT] [-l LOG] [-e] [-D]\n [-r] [-j] [-c] [-d DELAY] [-m] [-M MAPPATH] [-s MAPSIZE]\n [-I ICONPATH] [-o] [-x EXCLUDE] [--cert CERT] [--version]\n\nForward MQTT data from Roomba 980 to local MQTT broker\n\noptional arguments:\n -h, --help show this help message and exit\n -f CONFIGFILE, --configfile CONFIGFILE\n config file name (default: ./config.ini)\n -n ROOMBANAME, --roombaName ROOMBANAME\n optional Roomba name (default: \"\")\n -t TOPIC, --topic TOPIC\n Roomba MQTT Topic to subscribe to (can use wildcards #\n and + default: #)\n -T BROKERFEEDBACK, --brokerFeedback BROKERFEEDBACK\n Topic on broker to publish feedback to (default:\n /roomba/feedback)\n -C BROKERCOMMAND, --brokerCommand BROKERCOMMAND\n Topic on broker to publish commands to (default:\n /roomba/command)\n -S BROKERSETTING, --brokerSetting BROKERSETTING\n Topic on broker to publish settings to (default:\n /roomba/setting)\n -b BROKER, --broker BROKER\n ipaddress of MQTT broker (default: None)\n -p PORT, --port PORT MQTT broker port number (default: 1883)\n -U USER, --user USER MQTT broker user name (default: None)\n -P PASSWORD, --password PASSWORD\n MQTT broker password (default: None)\n -R ROOMBAIP, --roombaIP ROOMBAIP\n ipaddress of Roomba 980 (default: None)\n -u BLID, --blid BLID Roomba 980 blid (default: None)\n -w ROOMBAPASSWORD, --roombaPassword ROOMBAPASSWORD\n Roomba 980 password (default: None)\n -i INDENT, --indent INDENT\n Default indentation=auto\n -l LOG, --log LOG path/name of log file (default: ./Roomba.log)\n -e, --echo Echo to Console (default: True)\n -D, --debug debug mode\n -r, --raw Output raw data to mqtt, no decoding of json data\n -j, --pretty_print pretty print json in logs\n -c, --continuous Continuous connection to Roomba (default: True)\n -d DELAY, --delay DELAY\n Disconnect period for non-continuous connection\n (default: 1000ms)\n -m, --drawmap Draw Roomba cleaning map (default: True)\n -M MAPPATH, --mapPath MAPPATH\n Location to store maps to (default: .)\n -s MAPSIZE, --mapSize MAPSIZE\n Map Size, Dock offset and skew for the map. (800,1500)\n is the size, (0,0) is the dock location, in the center\n of the map, 0 is the rotation of the map, 0 is the\n rotation of the roomba. use single quotes around the\n string. (default: '(800,1500,0,0,0,0)')\n -I ICONPATH, --iconPath ICONPATH\n location of icons. (default: \"./\")\n -o, --roomOutline Draw room outline (default: True)\n -x EXCLUDE, --exclude EXCLUDE\n Exclude topics that have this in them (default: \"\")\n --cert CERT Set the certificate to use for MQTT communication with\n the Roomba\n --version show program's version number and exit\n```\n\n## quick start\nWith the roomba 980 on the dock and charged (and connected to wifi), stand by the roomba and run\n```bash\nroomba\n```\nor\n```bash\npython roomba.py\n```\n\nFollow the instructions, the script will attempt to find the roomba, obtain the IP, blid, and password - then save these to a local configuration file. If this works, the program will then start displaying messages from your Roomba, and printing the master_state every few seconds. the results are logged to a log file (Roomba.log by default).\n\nOn future runs (Once successful), these values will be taken from the configuration file, so you only have to do this once. You can manually specify these on the command line, some example start up bash scripts are supplied.\nI advice you to experiment with the map size (if you are using maps), as that is the one variable that isn't totally automatic. the size, position of the dock etc depend on your house layout.\nthe syntax of the map layout is (map x,map y, dock x, dock y, map rotation, roomba rotation). See the examples.\n\n### Example output\nLogging is supported with the python standard logging module\n```bash\n[I 2017-05-09 08:52:10,792] *******************\n[I 2017-05-09 08:52:10,792] * Program Started *\n[I 2017-05-09 08:52:10,792] *******************\n[I 2017-05-09 08:52:10,792] Paho MQTT Version: 1002003\n[I 2017-05-09 08:52:10,792] to Exit\n[I 2017-05-09 08:52:10,792] Roomba 980 MQTT data Interface\n[I 2017-05-09 08:52:10,792] connecting to broker\n[I 2017-05-09 08:52:10,792] Creating Roomba object 192.168.100.181\n[I 2017-05-09 08:52:10,793] CONTINUOUS connection\n[I 2017-05-09 08:52:10,793] connecting Roomba 192.168.100.181\n[I 2017-05-09 08:52:10,793] Posting DECODED data\n[I 2017-05-09 08:52:10,793] MAP: Maps Enabled\n[I 2017-05-09 08:52:10,793] MAP: openening existing line image\n[I 2017-05-09 08:52:10,814] MAP: openening existing problems image\n[I 2017-05-09 08:52:10,830] MAP: home_pos: (100,775)\n[I 2017-05-09 08:52:10,834] MAP: Initialisation complete\n[I 2017-05-09 08:52:10,835] Connecting\n[I 2017-05-09 08:52:13,243] Roomba Connected\n[I 2017-05-09 08:52:13,262] Received Roomba Data : wifistat, {\"state\":{\"reported\":{\"netinfo\":{\"dhcp\":true,\"addr\":3232261301,\"mask\":4294967040,\"gw\":3232261121,\"dns1\":3232261121,\"dns2\":0,\"bssid\":\"6c:b0:ce:14:2f:cd\",\"sec\":4}}}}\n[I 2017-05-09 08:52:13,307] Received Roomba Data : wifistat, {\"state\":{\"reported\":{\"wifistat\":{\"wifi\":1,\"uap\":false,\"cloud\":1}}}}\n[I 2017-05-09 08:52:13,308] Received Roomba Data : wifistat, {\"state\":{\"reported\":{\"netinfo\":{\"dhcp\":true,\"addr\":3232261301,\"mask\":4294967040,\"gw\":3232261121,\"dns1\":3232261121,\"dns2\":0,\"bssid\":\"6c:b0:ce:14:2f:cd\",\"sec\":4}}}}\n[I 2017-05-09 08:52:13,309] Received Roomba Data : wifistat, {\"state\":{\"reported\":{\"wlcfg\":{\"sec\":7,\"ssid\":\"7761746572746F6E73\"}}}}\n[I 2017-05-09 08:52:13,309] Received Roomba Data : wifistat, {\"state\":{\"reported\":{\"mac\":\"f0:03:8c:13:24:5b\"}}}\n[I 2017-05-09 08:52:13,310] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"country\": \"US\"}}}\n[I 2017-05-09 08:52:13,325] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"cloudEnv\": \"prod\"}}}\n[I 2017-05-09 08:52:13,331] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"svcEndpoints\":{\"svcDeplId\": \"v011\"}}}}\n[I 2017-05-09 08:52:13,429] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"mapUploadAllowed\":true}}}\n[I 2017-05-09 08:52:13,483] Received Roomba Data : wifistat, {\"state\":{\"reported\":{\"localtimeoffset\":-240,\"utctime\":1494334341,\"pose\":{\"theta\":-179,\"point\":{\"x\":181,\"y\":-13}}}}}\n[I 2017-05-09 08:52:13,533] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"batPct\":100,\"dock\":{\"known\":false},\"bin\":{\"present\":true,\"full\":false},\"audio\":{\"active\":false}}}}\n[I 2017-05-09 08:52:13,689] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"cleanMissionStatus\":{\"cycle\":\"none\",\"phase\":\"charge\",\"expireM\":0,\"rechrgM\":0,\"error\":0,\"notReady\":0,\"mssnM\":0,\"sqft\":0,\"initiator\":\"localApp\",\"nMssn\":109},\"language\":0,\"noAutoPasses\":false,\"noPP\":false,\"ecoCharge\":false}}}\n[I 2017-05-09 08:52:13,693] updated state to: Charging\n[I 2017-05-09 08:52:13,693] MAP: received: new_co_ords: {'y': 181, 'x': -13, 'theta': -179} old_co_ords: {'y': 181, 'x': -13, 'theta': -179} phase: charge, state: Charging\n[I 2017-05-09 08:52:13,693] MAP: ignoring new co-ords in charge phase\n[I 2017-05-09 08:52:13,756] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"vacHigh\":false,\"binPause\":true,\"carpetBoost\":true,\"openOnly\":false,\"twoPass\":false,\"schedHold\":false,\"lastCommand\":{\"command\":\"dock\",\"time\":1494260716,\"initiator\":\"localApp\"}}}}\n[I 2017-05-09 08:52:13,821] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"langs\":[{\"en-US\":0},{\"fr-FR\":1},{\"es-ES\":2},{\"de-DE\":3},{\"it-IT\":4}],\"bbnav\":{\"aMtrack\":98,\"nGoodLmrks\":5,\"aGain\":7,\"aExpo\":56},\"bbpanic\":{\"panics\":[11,8,6,8,6]},\"bbpause\":{\"pauses\":[0,14,0,0,0,0,17,0,4,0]}}}}\n[I 2017-05-09 08:52:14,231] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"bbmssn\":{\"nMssn\":109,\"nMssnOk\":30,\"nMssnC\":78,\"nMssnF\":0,\"aMssnM\":14,\"aCycleM\":15},\"bbrstinfo\":{\"nNavRst\":3,\"nMobRst\":0,\"causes\":\"0000\"}}}}\n[I 2017-05-09 08:52:14,242] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"cap\":{\"pose\":1,\"ota\":2,\"multiPass\":2,\"carpetBoost\":1,\"pp\":1,\"binFullDetect\":1,\"langOta\":1,\"maps\":1,\"edge\":1,\"eco\":1},\"sku\":\"R980020\",\"batteryType\":\"lith\",\"soundVer\":\"31\",\"uiSwVer\":\"4582\",\"navSwVer\":\"01.11.02\",\"wifiSwVer\":\"20923\"}}}\n[I 2017-05-09 08:52:14,245] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"mobilityVer\":\"5420\",\"bootloaderVer\":\"4042\",\"umiVer\":\"6\",\"softwareVer\":\"v2.2.5-2\",\"tz\":{\"events\":[{\"dt\":0,\"off\":-300},{\"dt\":0,\"off\":-240},{\"dt\":0,\"off\":-300}],\"ver\":3},\"timezone\":\"America/Toronto\",\"name\":\"Roomba\"}}}\n[I 2017-05-09 08:52:14,263] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"cleanSchedule\":{\"cycle\":[\"none\",\"start\",\"start\",\"start\",\"start\",\"start\",\"none\"],\"h\":[0,9,9,9,9,9,0],\"m\":[0,0,0,0,0,0,0]},\"bbchg3\":{\"avgMin\":81,\"hOnDock\":448,\"nAvail\":163,\"estCap\":12311,\"nLithChrg\":38,\"nNimhChrg\":0,\"nDocks\":45}}}}\n[I 2017-05-09 08:52:14,304] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"bbchg\":{\"nChgOk\":34,\"nLithF\":0,\"aborts\":[0,0,0]},\"bbswitch\":{\"nBumper\":41275,\"nClean\":37,\"nSpot\":12,\"nDock\":45,\"nDrops\":187}}}}\n[I 2017-05-09 08:52:14,310] Received Roomba Data : $aws/things/3117850851637850/shadow/update, {\"state\":{\"reported\":{\"bbrun\":{\"hr\":48,\"min\":18,\"sqft\":190,\"nStuck\":7,\"nScrubs\":75,\"nPicks\":199,\"nPanics\":51,\"nCliffsF\":871,\"nCliffsR\":348,\"nMBStll\":1,\"nWStll\":3,\"nCBump\":0},\"bbsys\":{\"hr\":518,\"min\":55}}}}\n[I 2017-05-09 08:52:15,406] Received Roomba Data : wifistat, {\"state\":{\"reported\":{\"signal\":{\"rssi\":-46,\"snr\":39}}}}\n```\n\n## How to get your username/blid and password\nYou can get it automatically as described in quick start, or you can run:\n```bash\n./getpassword.py\n```\n\neither with or without the IP address of your roomba.\n```bash\n./getpassword.py -R \n```\n\nYou can also specify a config file other than the default (-h for options). Results are displayed and saved to the config file.\n\n## API\nThe API calls are (see getpassword.py for an example of how to use the password class):\n### Classes\n```python\npassword(address='255.255.255.255', file=\".\\config.ini\")\nRoomba(address=None, blid=None, password=None, topic=\"#\", continuous=True, clean=False, cert_name=\"\", roombaName=\"\", file=\"./config.ini\")\n```\n### Roomba methods\n```python\nconnect()\ndisconnect()\nsend_command(command)\nset_preference(preference, setting)\nset_mqtt_client(mqttc=None, brokerFeedback=\"\")\nset_options(raw=False, indent=0, pretty_print=False)\nenable_map( enable=False, mapSize=\"(800,1500,0,0,0,0)\", mapPath=\"./\", iconPath=\"./\",\n home_icon_file=\"home.png\",\n roomba_icon_file=\"roomba.png\",\n roomba_error_file=\"roombaerror.png\",\n roomba_cancelled_file=\"roombacancelled.png\",\n roomba_battery_file=\"roomba-charge.png\",\n bin_full_file=\"binfull.png\",\n roomba_size=(50,50), draw_edges = 15, auto_rotate=True)\nmake_icon(input=\"./roomba.png\", output=\"./roomba_mod.png\")\n```\n### Data Structures\n```python\n#boolean\nroomba_connected\nbin_full\n#string\ncleanMissionStatus_phase\ncurrent_state\nerror_message\n#dictionarys\nco_ords\nmaster_state\n```\n### Notes\nIf you have multiple roomba's, these should be supported *not tested yet - I only have one roomba!*. Each roomba has it's own name, and this will be automatically used to differentiate them. feedback is published to `\\roomba\\feedback\\\\`, commands go to `\\roomba\\command\\` and settings to `\\roomba\\setting\\`. Maps and so on have prepended to them.\nYou can manually specify the roomba name in the object, in your own scripts, in which case the same applies.\n\n## Using the library in your python script\nBoth these scripts are in the examples directory, as simple.py and complicated.py. To use them, copy them from examples to the main roomba.py directory (or copy roomba.py to examples). Edit them to include your own roomba ip address, blid and password, and run `python simple.py`. For \"complicated.py\" you also need to add your mqtt broker adddress, username, and password. Then run `python complicated.py`\n### Simple Version\n```python\nfrom roomba import Roomba\n\n#uncomment the option you want to run, and replace address, blid and roombaPassword with your own values\n\naddress = \"192.168.100.181\"\nblid = \"3835850251647850\"\nroombaPassword = \":1:1493319243:gOizXpQ4lcdSoD1xJ\"\n\nmyroomba = Roomba(address, blid, roombaPassword)\n#or myroomba = Roomba() #if you have a config file - will attempt discovery if you don't\nmyroomba.connect()\n\nmyroomba.set_preference(\"carpetBoost\", \"true\")\n#myroomba.set_preference(\"twoPass\", \"false\")\n\n#myroomba.send_command(\"start\")\n#myroomba.send_command(\"stop\")\n#myroomba.send_command(\"dock\")\n\nimport json, time\nfor i in range(5):\n print json.dumps(myroomba.master_state, indent=2)\n time.sleep(1)\nmyroomba.disconnect()\n```\n### More Complicated Version\n```python\nfrom roomba import Roomba\nimport paho.mqtt.client as mqtt\nimport time\nimport json\n\n#put your own values here\nbroker = 'localhost' #ip of mqtt broker\nuser = 'user' #mqtt username\npassword = 'password' #mqtt password\n#broker = None if not using local mqtt broker\naddress = '192.168.100.181'\nblid = \"3515850261627850\"\nroombaPassword = \":1:1492379243:gOiyXpQ4lbRoD1xJ\"\n\ndef broker_on_connect(client, userdata, flags, rc):\n print(\"Broker Connected with result code \"+str(rc))\n #subscribe to roomba feedback\n if rc == 0:\n mqttc.subscribe(brokerCommand)\n mqttc.subscribe(brokerSetting)\n\ndef broker_on_message(mosq, obj, msg):\n #publish to roomba\n if \"command\" in msg.topic:\n print(\"Received COMMAND: %s\" % str(msg.payload))\n myroomba.send_command(str(msg.payload))\n elif \"setting\" in msg.topic:\n print(\"Received SETTING: %s\" % str(msg.payload))\n cmd = str(msg.payload).split()\n myroomba.set_preference(cmd[0], cmd[1])\n\ndef broker_on_publish(mosq, obj, mid):\n pass\n\ndef broker_on_subscribe(mosq, obj, mid, granted_qos):\n print(\"Broker Subscribed: %s %s\" % (str(mid), str(granted_qos)))\n\ndef broker_on_disconnect(mosq, obj, rc):\n print(\"Broker disconnected\")\n\ndef broker_on_log(mosq, obj, level, string):\n print(string)\n\n\nmqttc = None\nif broker is not None:\n brokerCommand = \"/roomba/command\"\n brokerSetting = \"/roomba/setting\"\n brokerFeedback = \"/roomba/feedback\"\n\n #connect to broker\n mqttc = mqtt.Client()\n #Assign event callbacks\n mqttc.on_message = broker_on_message\n mqttc.on_connect = broker_on_connect\n mqttc.on_disconnect = broker_on_disconnect\n mqttc.on_publish = broker_on_publish\n mqttc.on_subscribe = broker_on_subscribe\n\n try:\n mqttc.username_pw_set(user, password) #put your own mqtt user and password here if you are using them, otherwise comment out\n mqttc.connect(broker, 1883, 60) #Ping MQTT broker every 60 seconds if no data is published from this script.\n\n except Exception as e:\n print(\"Unable to connect to MQTT Broker: %s\" % e)\n mqttc = None\n\nmyroomba = Roomba() #minnimum required to connect on Linux Debian system, will read connection from config file\n#myroomba = Roomba(address, blid, roombaPassword, topic=\"#\", continuous=True, clean=False, cert_name = \"./ca-certificates.crt\") #setting things manually\n\n#all these are optional, if you don't include them, the defaults will work just fine\n#if you are using maps\nmyroomba.enable_map(enable=True, mapSize=\"(800,1650,-300,-50,2,0)\", mapPath=\"./\", iconPath=\"./\") #enable live maps, class default is no maps\nif broker is not None:\n myroomba.set_mqtt_client(mqttc, brokerFeedback) #if you want to publish Roomba data to your own mqtt broker (default is not to) if you have more than one roomba, and assign a roombaName, it is addded to this topic (ie brokerFeedback/roombaName)\n#finally connect to Roomba - (required!)\nmyroomba.connect()\n\nprint(\" to exit\")\nprint(\"Subscribe to /roomba/feedback/# to see published data\")\n\ntry:\n if mqttc is not None:\n mqttc.loop_forever()\n else:\n while True:\n print(\"Roomba Data: %s\" % json.dumps(myroomba.master_state, indent=2))\n time.sleep(5)\n\nexcept (KeyboardInterrupt, SystemExit):\n print(\"System exit Received - Exiting program\")\n myroomba.disconnect()\n if mqttc is not None:\n mqttc.disconnect()\n\n```\n## Data/Feedback\nmaster_state starts empty, and fills with time, it is published in full every 5 minutes by default (but updates to it are published live)\n\nmaster_state should contain:\n```javascript\n{\n \"state\": {\n \"reported\": {\n \"netinfo\": {\n \"dhcp\": true,\n \"addr\": 3232261301,\n \"mask\": 4294967040,\n \"gw\": 3232261121,\n \"dns1\": 3232261121,\n \"dns2\": 0,\n \"bssid\": \"6c:b0:ce:14:2f:cd\",\n \"sec\": 4\n },\n \"wifistat\": {\n \"wifi\": 1,\n \"uap\": false,\n \"cloud\": 1\n },\n \"wlcfg\": {\n \"sec\": 7,\n \"ssid\": \"7761746572746F6E73\"\n },\n \"mac\": \"f0:03:8c:13:24:5b\",\n \"country\": \"US\",\n \"cloudEnv\": \"prod\",\n \"svcEndpoints\": {\n \"svcDeplId\": \"v011\"\n },\n \"mapUploadAllowed\": true,\n \"localtimeoffset\": -240,\n \"utctime\": 1494331734,\n \"pose\": {\n \"theta\": -179,\n \"point\": {\n \"x\": 181,\n \"y\": -13\n }\n },\n \"batPct\": 100,\n \"dock\": {\n \"known\": false\n },\n \"bin\": {\n \"present\": true,\n \"full\": false\n },\n \"audio\": {\n \"active\": true\n },\n \"cleanMissionStatus\": {\n \"cycle\": \"none\",\n \"phase\": \"charge\",\n \"expireM\": 0,\n \"rechrgM\": 0,\n \"error\": 0,\n \"notReady\": 0,\n \"mssnM\": 0,\n \"sqft\": 0,\n \"initiator\": \"localApp\",\n \"nMssn\": 109\n },\n \"language\": 0,\n \"noAutoPasses\": false,\n \"noPP\": false,\n \"ecoCharge\": false,\n \"vacHigh\": false,\n \"binPause\": true,\n \"carpetBoost\": true,\n \"openOnly\": false,\n \"twoPass\": false,\n \"schedHold\": false,\n \"lastCommand\": {\n \"command\": \"dock\",\n \"time\": 1494260716,\n \"initiator\": \"localApp\"\n },\n \"langs\": [\n {\n \"en-US\": 0\n },\n {\n \"fr-FR\": 1\n },\n {\n \"es-ES\": 2\n },\n {\n \"de-DE\": 3\n },\n {\n \"it-IT\": 4\n }\n ],\n \"bbnav\": {\n \"aMtrack\": 98,\n \"nGoodLmrks\": 5,\n \"aGain\": 7,\n \"aExpo\": 56\n },\n \"bbpanic\": {\n \"panics\": [\n 11,\n 8,\n 6,\n 8,\n 6\n ]\n },\n \"bbpause\": {\n \"pauses\": [\n 0,\n 14,\n 0,\n 0,\n 0,\n 0,\n 17,\n 0,\n 4,\n 0\n ]\n },\n \"bbmssn\": {\n \"nMssn\": 109,\n \"nMssnOk\": 30,\n \"nMssnC\": 78,\n \"nMssnF\": 0,\n \"aMssnM\": 14,\n \"aCycleM\": 15\n },\n \"bbrstinfo\": {\n \"nNavRst\": 3,\n \"nMobRst\": 0,\n \"causes\": \"0000\"\n },\n \"cap\": {\n \"pose\": 1,\n \"ota\": 2,\n \"multiPass\": 2,\n \"carpetBoost\": 1,\n \"pp\": 1,\n \"binFullDetect\": 1,\n \"langOta\": 1,\n \"maps\": 1,\n \"edge\": 1,\n \"eco\": 1\n },\n \"sku\": \"R980020\",\n \"batteryType\": \"lith\",\n \"soundVer\": \"31\",\n \"uiSwVer\": \"4582\",\n \"navSwVer\": \"01.11.02\",\n \"wifiSwVer\": \"20923\",\n \"mobilityVer\": \"5420\",\n \"bootloaderVer\": \"4042\",\n \"umiVer\": \"6\",\n \"softwareVer\": \"v2.2.5-2\",\n \"tz\": {\n \"events\": [\n {\n \"dt\": 0,\n \"off\": -300\n },\n {\n \"dt\": 0,\n \"off\": -240\n },\n {\n \"dt\": 0,\n \"off\": -300\n }\n ],\n \"ver\": 3\n },\n \"timezone\": \"America/Toronto\",\n \"name\": \"Roomba\",\n \"cleanSchedule\": {\n \"cycle\": [\n \"none\",\n \"start\",\n \"start\",\n \"start\",\n \"start\",\n \"start\",\n \"none\"\n ],\n \"h\": [\n 0,\n 9,\n 9,\n 9,\n 9,\n 9,\n 0\n ],\n \"m\": [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0\n ]\n },\n \"bbchg3\": {\n \"avgMin\": 81,\n \"hOnDock\": 448,\n \"nAvail\": 163,\n \"estCap\": 12311,\n \"nLithChrg\": 38,\n \"nNimhChrg\": 0,\n \"nDocks\": 45\n },\n \"bbchg\": {\n \"nChgOk\": 34,\n \"nLithF\": 0,\n \"aborts\": [\n 0,\n 0,\n 0\n ]\n },\n \"bbswitch\": {\n \"nBumper\": 41275,\n \"nClean\": 37,\n \"nSpot\": 12,\n \"nDock\": 45,\n \"nDrops\": 187\n },\n \"bbrun\": {\n \"hr\": 48,\n \"min\": 18,\n \"sqft\": 190,\n \"nStuck\": 7,\n \"nScrubs\": 75,\n \"nPicks\": 199,\n \"nPanics\": 51,\n \"nCliffsF\": 871,\n \"nCliffsR\": 348,\n \"nMBStll\": 1,\n \"nWStll\": 3,\n \"nCBump\": 0\n },\n \"bbsys\": {\n \"hr\": 518,\n \"min\": 11\n },\n \"signal\": {\n \"rssi\": -36,\n \"snr\": 53\n }\n }\n }\n}\n```\n\nin raw mode, the json from the Roomba is passed directly to the mqtt topic (usually /roomba/feedback), in normal mode, each json item is decoded and published as a seperate topic. To see the topic published and their values run:\n```bash\nmosquitto_sub -v -t /roomba/feedback/#\n```\n\nOutput should look like this:\n```bash\n/roomba/feedback/netinfo_dhcp True\n/roomba/feedback/netinfo_addr 3232261301\n/roomba/feedback/netinfo_mask 4294967040\n/roomba/feedback/netinfo_gw 3232261121\n/roomba/feedback/netinfo_dns1 3232261121\n/roomba/feedback/netinfo_dns2 0\n/roomba/feedback/netinfo_bssid 6c:b0:ce:14:2f:cd\n/roomba/feedback/netinfo_sec 4\n/roomba/feedback/wifistat_wifi 1\n/roomba/feedback/wifistat_uap False\n/roomba/feedback/wifistat_cloud 1\n/roomba/feedback/netinfo_dhcp True\n/roomba/feedback/netinfo_addr 3232261301\n/roomba/feedback/netinfo_mask 4294967040\n/roomba/feedback/netinfo_gw 3232261121\n/roomba/feedback/netinfo_dns1 3232261121\n/roomba/feedback/netinfo_dns2 0\n/roomba/feedback/netinfo_bssid 6c:b0:ce:14:2f:cd\n/roomba/feedback/netinfo_sec 4\n/roomba/feedback/wlcfg_sec 7\n/roomba/feedback/wlcfg_ssid 7761746572746F6E73\n/roomba/feedback/mac f0:03:8c:13:24:5b\n/roomba/feedback/country US\n/roomba/feedback/cloudEnv prod\n/roomba/feedback/svcEndpoints_svcDeplId v011\n/roomba/feedback/mapUploadAllowed True\n/roomba/feedback/localtimeoffset -240\n/roomba/feedback/utctime 1494330872\n/roomba/feedback/pose_theta -179\n/roomba/feedback/pose_point_x 181\n/roomba/feedback/pose_point_y -13\n/roomba/feedback/batPct 100\n/roomba/feedback/dock_known False\n/roomba/feedback/bin_present True\n/roomba/feedback/bin_full False\n/roomba/feedback/audio_active False\n/roomba/feedback/cleanMissionStatus_cycle none\n/roomba/feedback/cleanMissionStatus_phase charge\n/roomba/feedback/cleanMissionStatus_expireM 0\n/roomba/feedback/cleanMissionStatus_rechrgM 0\n/roomba/feedback/cleanMissionStatus_error 0\n/roomba/feedback/cleanMissionStatus_notReady 0\n/roomba/feedback/cleanMissionStatus_mssnM 0\n/roomba/feedback/cleanMissionStatus_sqft 0\n/roomba/feedback/cleanMissionStatus_initiator localApp\n/roomba/feedback/cleanMissionStatus_nMssn 109\n/roomba/feedback/language 0\n/roomba/feedback/noAutoPasses False\n/roomba/feedback/noPP False\n/roomba/feedback/ecoCharge False\n/roomba/feedback/state Charging\n/roomba/feedback/vacHigh False\n/roomba/feedback/binPause True\n/roomba/feedback/carpetBoost True\n/roomba/feedback/openOnly False\n/roomba/feedback/twoPass False\n/roomba/feedback/schedHold False\n/roomba/feedback/lastCommand_command dock\n/roomba/feedback/lastCommand_time 1494260716\n/roomba/feedback/lastCommand_initiator localApp\n/roomba/feedback/state Charging\n/roomba/feedback/langs [('en-US', 0), ('fr-FR', 1), ('es-ES', 2), ('de-DE', 3), ('it-IT', 4)]\n/roomba/feedback/bbnav_aMtrack 98\n/roomba/feedback/bbnav_nGoodLmrks 5\n/roomba/feedback/bbnav_aGain 7\n/roomba/feedback/bbnav_aExpo 56\n/roomba/feedback/bbpanic_panics [11, 8, 6, 8, 6]\n/roomba/feedback/bbpause_pauses [0, 14, 0, 0, 0, 0, 17, 0, 4, 0]\n/roomba/feedback/state Charging\n/roomba/feedback/bbmssn_nMssn 109\n/roomba/feedback/bbmssn_nMssnOk 30\n/roomba/feedback/bbmssn_nMssnC 78\n/roomba/feedback/bbmssn_nMssnF 0\n/roomba/feedback/bbmssn_aMssnM 14\n/roomba/feedback/bbmssn_aCycleM 15\n/roomba/feedback/bbrstinfo_nNavRst 3\n/roomba/feedback/bbrstinfo_nMobRst 0\n/roomba/feedback/bbrstinfo_causes 0000\n/roomba/feedback/state Charging\n/roomba/feedback/cap_pose 1\n/roomba/feedback/cap_ota 2\n/roomba/feedback/cap_multiPass 2\n/roomba/feedback/cap_carpetBoost 1\n/roomba/feedback/cap_pp 1\n/roomba/feedback/cap_binFullDetect 1\n/roomba/feedback/cap_langOta 1\n/roomba/feedback/cap_maps 1\n/roomba/feedback/cap_edge 1\n/roomba/feedback/cap_eco 1\n/roomba/feedback/sku R980020\n/roomba/feedback/batteryType lith\n/roomba/feedback/soundVer 31\n/roomba/feedback/uiSwVer 4582\n/roomba/feedback/navSwVer 01.11.02\n/roomba/feedback/wifiSwVer 20923\n/roomba/feedback/state Charging\n/roomba/feedback/mobilityVer 5420\n/roomba/feedback/bootloaderVer 4042\n/roomba/feedback/umiVer 6\n/roomba/feedback/softwareVer v2.2.5-2\n/roomba/feedback/tz_events [('dt', 0), ('off', -300), ('dt', 0), ('off', -240), ('dt', 0), ('off', -300)]\n/roomba/feedback/tz_ver 3\n/roomba/feedback/timezone America/Toronto\n/roomba/feedback/name Roomba\n/roomba/feedback/state Charging\n/roomba/feedback/cleanSchedule_cycle ['none', 'start', 'start', 'start', 'start', 'start', 'none']\n/roomba/feedback/cleanSchedule_h [0, 9, 9, 9, 9, 9, 0]\n/roomba/feedback/cleanSchedule_m [0, 0, 0, 0, 0, 0, 0]\n/roomba/feedback/bbchg3_avgMin 81\n/roomba/feedback/bbchg3_hOnDock 448\n/roomba/feedback/bbchg3_nAvail 163\n/roomba/feedback/bbchg3_estCap 12311\n/roomba/feedback/bbchg3_nLithChrg 38\n/roomba/feedback/bbchg3_nNimhChrg 0\n/roomba/feedback/bbchg3_nDocks 45\n/roomba/feedback/state Charging\n/roomba/feedback/bbchg_nChgOk 34\n/roomba/feedback/bbchg_nLithF 0\n/roomba/feedback/bbchg_aborts [0, 0, 0]\n/roomba/feedback/bbswitch_nBumper 41275\n/roomba/feedback/bbswitch_nClean 37\n/roomba/feedback/bbswitch_nSpot 12\n/roomba/feedback/bbswitch_nDock 45\n/roomba/feedback/bbswitch_nDrops 187\n/roomba/feedback/state Charging\n/roomba/feedback/bbrun_hr 48\n/roomba/feedback/bbrun_min 18\n/roomba/feedback/bbrun_sqft 190\n/roomba/feedback/bbrun_nStuck 7\n/roomba/feedback/bbrun_nScrubs 75\n/roomba/feedback/bbrun_nPicks 199\n/roomba/feedback/bbrun_nPanics 51\n/roomba/feedback/bbrun_nCliffsF 871\n/roomba/feedback/bbrun_nCliffsR 348\n/roomba/feedback/bbrun_nMBStll 1\n/roomba/feedback/bbrun_nWStll 3\n/roomba/feedback/bbrun_nCBump 0\n/roomba/feedback/bbsys_hr 517\n/roomba/feedback/bbsys_min 57\n/roomba/feedback/state Charging\n/roomba/feedback/signal_rssi -35\n/roomba/feedback/signal_snr 54\n/roomba/feedback/state Charging\n/roomba/feedback/signal_rssi -36\n/roomba/feedback/signal_snr 53\n/roomba/feedback/state Charging\n```\n\nIn addition `state` and `error_message` are published which are derived by the class.\n\n## Commands/Settings\n### Commands\n* Commands are:\n * \"start\"\n * \"stop\"\n * \"pause\"\n * \"resume\"\n * \"dock\"\n### Settings\n* Settings are:\n * carpetBoost true\n * vacHigh true\n * openOnly true *this is edge clean - set to false to enable edge cleaning*\n * noAutoPasses true\n * twoPass true\n * binPause true\n\nYou publish this as a string to your mqtt broker topic /roomba/command or /roomba/setting (or whatever you have defined if you change these from default)\nUbuntu example (assuming the broker is on your localhost) - should work for any linux system with mosquitto installed\n```bash\nmosquitto_pub -t \"/roomba/command\" -m \"start\"\nmosquitto_pub -t \"/roomba/setting\" -m \"carpetBoost true\"\n```\n\nOr call directly from a python script (see simple example above).\n\n## Openhab/Openhab2 Interface\nHere are my Openhab2 files:\n### Items\n```\n/* Roomba items */\nGroup roomba_items \"Roomba\" (gGF)\n\n/* Roomba Commands */\nString roomba_command \"Roomba\" (roomba_items) {mqtt=\">[proliant:/roomba/command:command:*:${command}]\", autoupdate=false}\n/* Settings */\nSwitch roomba_edgeClean \"Edge Clean [%s]\" (roomba_items) {mqtt=\">[proliant:/roomba/setting:command:ON:openOnly false],>[proliant:/roomba/setting:command:OFF:openOnly true],<[proliant:/roomba/feedback/openOnly:state:MAP(inverse_switch.map)]\", autoupdate=false}\nSwitch roomba_carpetBoost \"Auto carpet Boost [%s]\" (roomba_items) {mqtt=\">[proliant:/roomba/setting:command:ON:carpetBoost true],>[proliant:/roomba/setting:command:OFF:carpetBoost false],<[proliant:/roomba/feedback/carpetBoost:state:MAP(switch.map)]\", autoupdate=false}\nSwitch roomba_vacHigh \"Vacuum Boost [%s]\" (roomba_items) {mqtt=\">[proliant:/roomba/setting:command:ON:vacHigh true],>[proliant:/roomba/setting:command:OFF:vacHigh false],<[proliant:/roomba/feedback/vacHigh:state:MAP(switch.map)]\", autoupdate=false}\nSwitch roomba_noAutoPasses \"Auto Passes [%s]\" (roomba_items) {mqtt=\">[proliant:/roomba/setting:command:ON:noAutoPasses false],>[proliant:/roomba/setting:command:OFF:noAutoPasses true],<[proliant:/roomba/feedback/noAutoPasses:state:MAP(inverse_switch.map)]\", autoupdate=false}\nSwitch roomba_twoPass \"Two Passes [%s]\" (roomba_items) {mqtt=\">[proliant:/roomba/setting:command:ON:twoPass true],>[proliant:/roomba/setting:command:OFF:twoPass false],<[proliant:/roomba/feedback/twoPass:state:MAP(switch.map)]\", autoupdate=false}\nSwitch roomba_binPause \"Always Complete (even if bin is full) [%s]\" (roomba_items) {mqtt=\">[proliant:/roomba/setting:command:ON:binPause false],>[proliant:/roomba/setting:command:OFF:binPause true],<[proliant:/roomba/feedback/binPause:state:MAP(inverse_switch.map)]\", autoupdate=false}\n/* Roomba Feedback */\nString roomba_softwareVer \"Software Version [%s]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/softwareVer:state:default]\"}\nNumber roomba_batPct \"Battery [%d%%]\" (roomba_items, Battery) {mqtt=\"<[proliant:/roomba/feedback/batPct:state:default]\"}\nString roomba_lastcommand \"Last Command [%s]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/lastCommand_command:state:default]\"}\nSwitch roomba_bin_present \"Bin Present [%s]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/bin_present:state:MAP(switch.map)]\"}\nSwitch roomba_full \"Bin Full [%s]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/bin_full:state:MAP(switch.map)]\"}\n/* Mission values */\nString roomba_mission \"Mission [%s]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/cleanMissionStatus_cycle:state:default]\"}\nNumber roomba_nMssn \"Cleaning Mission Number [%d]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/cleanMissionStatus_nMssn:state:default]\"}\nString roomba_phase \"Phase [%s]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/cleanMissionStatus_phase:state:default]\"}\nString roomba_initiator \"Initiator [%s]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/cleanMissionStatus_initiator:state:default]\"}\nSwitch roomba_error \"Error [%]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/cleanMissionStatus_error:state:MAP(switchFromMqtt.map)]\"}\nString roomba_errortext \"Error Message [%s]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/error_message:state:default]\"}\nNumber roomba_mssnM \"Cleaning Elapsed Time [%d m]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/cleanMissionStatus_mssnM:state:default]\"}\nNumber roomba_sqft \"Square Ft Cleaned [%d]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/cleanMissionStatus_sqft:state:default]\"}\nNumber roomba_expireM \"Mission Recharge Time [%d m]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/cleanMissionStatus_expireM:state:default]\"}\nNumber roomba_rechrgM \"Remaining Time To Recharge [%d m]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/cleanMissionStatus_rechrgM:state:default]\"}\nString roomba_status \"Status [%s]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/state:state:default]\"}\nDimmer roomba_percent_complete \"Mission % Completed [%d%%]\" (roomba_items)\nDateTime roomba_lastmissioncompleted \"Last Mission Completed [%1$ta %1$tR]\" \n/* Schedule */\nString roomba_cycle \"Day of Week [%s]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/cleanSchedule_cycle:state:default]\"}\nString roomba_cleanSchedule_h \"Hour of Day [%s]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/cleanSchedule_h:state:default]\"}\nString roomba_cleanSchedule_m \"Minute of Hour [%s]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/cleanSchedule_m:state:default]\"}\nString roomba_cleanSchedule \"Schedule [%s]\" (roomba_items)\n/* General */\nSwitch roomba_control \"Roomba ON/OFF [%s]\" (roomba_items)\nNumber roomba_theta \"Theta [%d]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/pose_theta:state:default]\"}\nNumber roomba_x \"X [%d]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/pose_point_x:state:default]\"}\nNumber roomba_y \"Y [%d]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/pose_point_y:state:default]\"}\nNumber roomba_rssi \"RSSI [%d]\" (roomba_items) {mqtt=\"<[proliant:/roomba/feedback/signal_rssi:state:default]\"}\nDateTime roomba_lastheardfrom \"Last Update [%1$ta %1$tR]\" \n```\n### Sitemap\n```\nGroup item=roomba_items {\n Switch item=roomba_command mappings=[start=\"Start\",stop=\"Stop\",pause=\"Pause\",dock=\"Dock\",resume=\"Resume\"]\n Switch item=roomba_control\n Group label=\"Map\" icon=\"map\" {\n Frame label=\"Map\" {\n //Image icon=\"map\" url=\"http://your_OH_ip_address:port/static/map.png\" label=\"Map\" refresh=1000\n Webview icon=\"map\" url=\"http://your_OH_ip_address:port/static/roomba_map.html\" height=21 label=\"Map\"\n }\n }\n Group label=\"Settings\" icon=\"select\"{\n Text item=roomba_cleanSchedule\n Switch item=roomba_edgeClean\n Switch item=roomba_carpetBoost\n Switch item=roomba_vacHigh visibility=[roomba_carpetBoost==OFF]\n Switch item=roomba_noAutoPasses\n Switch item=roomba_twoPass visibility=[roomba_noAutoPasses==OFF]\n Switch item=roomba_binPause\n }\n Frame label=\"Status\" {\n Text item=roomba_softwareVer\n Text item=roomba_batPct\n Text item=roomba_phase\n Text item=roomba_lastcommand\n Switch item=roomba_full mappings=[ON=\"FULL\", OFF=\"Not Full\"]\n Switch item=roomba_bin_present mappings=[OFF=\"Removed\", ON=\"Installed\"]\n Text item=roomba_rssi\n Text item=roomba_lastheardfrom\n }\n Frame label=\"Mission\" {\n Text item=roomba_status\n Text item=roomba_rechrgM visibility=[roomba_status==\"Recharging\"]\n Text item=roomba_mission\n Text item=roomba_percent_complete\n Switch item=roomba_error mappings=[ON=\"ERROR!\", OFF=\"Normal\"]\n Text item=roomba_errortext\n Text item=roomba_mssnM\n Text item=roomba_sqft\n Text item=roomba_nMssn\n Text item=roomba_lastmissioncompleted\n Text item=roomba_initiator\n }\n Frame label=\"Location\" {\n Text item=roomba_theta\n Text item=roomba_x\n Text item=roomba_y\n }\n }\n```\n### Transforms\n```\n/etc/openhab2/transform/switch.map\nON=ON\nOFF=OFF\n0=OFF\n1=ON\nTrue=ON\nFalse=OFF\ntrue=ON\nfalse=OFF\n-=Unknown\nNULL=Unknown\n\n/etc/openhab2/transform/inverse_switch.map\nON=OFF\nOFF=ON\n0=ON\n1=OFF\nTrue=OFF\nFalse=ON\ntrue=OFF\nfalse=ON\n-=Unknown\nNULL=Unknown\n\n/etc/openhab2/transform/switchFromMqtt.map\n-=Unknonwn\nNULL=Unknown\nOFF=OFF\n0=OFF\n1=ON\n2=ON\n3=ON\n4=ON\n5=ON\n6=ON\n7=ON\n8=ON\n9=ON\n10=ON\n11=ON\n12=ON\n13=ON\n14=ON\n15=ON\n16=ON\n17=ON\n18=ON\n19=ON\n20=ON\n21=ON\n22=ON\n23=ON\n24=ON\n25=ON\n26=ON\n27=ON\n28=ON\n29=ON\n30=ON\n31=ON\n32=ON\n33=ON\n34=ON\n35=ON\n36=ON\n37=ON\n38=ON\n39=ON\n40=ON\n41=ON\n42=ON\n43=ON\n44=ON\n45=ON\n46=ON\n47=ON\n48=ON\n49=ON\n50=ON\n51=ON\n52=ON\n53=ON\n54=ON\n55=ON\n56=ON\n57=ON\n58=ON\n59=ON\n60=ON\n61=ON\n62=ON\n63=ON\n64=ON\n65=ON\n66=ON\n67=ON\n68=ON\n69=ON\n70=ON\n71=ON\n72=ON\n73=ON\n74=ON\n75=ON\n76=ON\n77=ON\n78=ON\n79=ON\n80=ON\n81=ON\n82=ON\n83=ON\n84=ON\n85=ON\n86=ON\n87=ON\n88=ON\n89=ON\n90=ON\n91=ON\n92=ON\n93=ON\n94=ON\n95=ON\n96=ON\n97=ON\n98=ON\n99=ON\n100=ON\n101=ON\n102=ON\n103=ON\n104=ON\n105=ON\n106=ON\n107=ON\n108=ON\n109=ON\n110=ON\n111=ON\n112=ON\n113=ON\n114=ON\n115=ON\n116=ON\n117=ON\n118=ON\n119=ON\n120=ON\n121=ON\n122=ON\n123=ON\n124=ON\n125=ON\n126=ON\n127=ON\n128=ON\n129=ON\n130=ON\n131=ON\n132=ON\n133=ON\n134=ON\n135=ON\n136=ON\n137=ON\n138=ON\n139=ON\n140=ON\n141=ON\n142=ON\n143=ON\n144=ON\n145=ON\n146=ON\n147=ON\n148=ON\n149=ON\n150=ON\n151=ON\n152=ON\n153=ON\n154=ON\n155=ON\n156=ON\n157=ON\n158=ON\n159=ON\n160=ON\n161=ON\n162=ON\n163=ON\n164=ON\n165=ON\n166=ON\n167=ON\n168=ON\n169=ON\n170=ON\n171=ON\n172=ON\n173=ON\n174=ON\n175=ON\n176=ON\n177=ON\n178=ON\n179=ON\n180=ON\n181=ON\n182=ON\n183=ON\n184=ON\n185=ON\n186=ON\n187=ON\n188=ON\n189=ON\n190=ON\n191=ON\n192=ON\n193=ON\n194=ON\n195=ON\n196=ON\n197=ON\n198=ON\n199=ON\n200=ON\n201=ON\n202=ON\n203=ON\n204=ON\n205=ON\n206=ON\n207=ON\n208=ON\n209=ON\n210=ON\n211=ON\n212=ON\n213=ON\n214=ON\n215=ON\n216=ON\n217=ON\n218=ON\n219=ON\n220=ON\n221=ON\n222=ON\n223=ON\n224=ON\n225=ON\n226=ON\n227=ON\n228=ON\n229=ON\n230=ON\n231=ON\n232=ON\n233=ON\n234=ON\n235=ON\n236=ON\n237=ON\n238=ON\n239=ON\n240=ON\n241=ON\n242=ON\n243=ON\n244=ON\n245=ON\n246=ON\n247=ON\n248=ON\n249=ON\n250=ON\n251=ON\n252=ON\n253=ON\n254=ON\n255=ON\n256=ON\nON=ON\n```\n### Rules\nThese use one of my functions getTimestamp, here it is:\n```\nval Functions$Function2 getTimestamp = [ //function (lambda) to get a timestamp. Returns formatted string and optionally updates an item\n item,\n date_format |\n\n var date_time_format = date_format\n if(date_format == \"\" || date_format == null) date_time_format = \"%1$ta %1$tT\" //default format Day Hour:Minute:Seconds\n var String Timestamp = String::format( date_time_format, new Date() )\n if(item != NULL && item != null) {\n var Integer time = now().getMillis() //current time (/1000?)\n var cal = new java.util.GregorianCalendar()\n cal.setTimeInMillis(time) //timestamp in unix format\n var t = new DateTimeType(cal)\n\n if(item instanceof DateTimeItem) {\n postUpdate(item, t)\n logInfo(\"Last Update\", item.name + \" DateTimeItem updated at: \" + Timestamp )\n }\n else if(item instanceof StringItem) {\n postUpdate(item, Timestamp)\n logInfo(\"Last Update\", item.name + \" StringItem updated at: \" + Timestamp )\n }\n else\n logWarn(\"Last Update\", item.name + \" is not DateTime or String - not updating\")\n }\n Timestamp\n ]\n```\nHere are my roomba rules, some of them assume you have e-mail and pushNotification set up:\n```\n/* Roomba Rules */\nrule \"Roomba start and stop\"\nwhen\n Item roomba_control received command\nthen\n logInfo(\"Roomba\", \"Roomba ON/OFF received command: \" + receivedCommand)\n if (receivedCommand == ON)\n sendCommand(roomba_command, \"start\")\n if (receivedCommand == OFF) {\n sendCommand(roomba_command, \"stop\")\n Thread::sleep(1000)\n sendCommand(roomba_command, \"dock\")\n }\nend\n\nrule \"Roomba Auto Boost Control\"\nwhen\n Item roomba_carpetBoost changed\nthen\n logInfo(\"Roomba\", \"Roomba Boost changed to: Auto \" + roomba_carpetBoost.state + \" Manual: \" + roomba_vacHigh.state)\n if (roomba_carpetBoost.state == ON && roomba_vacHigh.state == ON)\n sendCommand(roomba_vacHigh, OFF)\nend\n\nrule \"Roomba Manual Boost Control\"\nwhen\n Item roomba_vacHigh changed\nthen\n logInfo(\"Roomba\", \"Roomba Boost changed to: Auto \" + roomba_carpetBoost.state + \" Manual: \" + roomba_vacHigh.state)\n if (roomba_carpetBoost.state == ON && roomba_vacHigh.state == ON)\n sendCommand(roomba_carpetBoost, OFF)\nend\n\nrule \"Roomba Auto Passes Control\"\nwhen\n Item roomba_noAutoPasses changed or\n Item roomba_twoPass changed\nthen\n logInfo(\"Roomba\", \"Roomba Passes changed to: Auto \" + roomba_noAutoPasses.state + \" Manual: \" + roomba_twoPass.state)\n if (roomba_noAutoPasses.state == ON && roomba_twoPass.state == ON)\n sendCommand(roomba_twoPass, OFF)\nend\n\nrule \"Roomba Last Update Timestamp\"\nwhen\n Item roomba_rssi received update\nthen\n getTimestamp.apply(roomba_lastheardfrom, \"%1$ta %1$tR\")\nend\n\nrule \"Roomba Bin Full\"\nwhen\n Item roomba_full changed from OFF to ON\nthen\n val Timestamp = getTimestamp.apply(roomba_lastheardfrom, \"%1$ta %1$tR\")\n pushNotification(\"Roomba\", \"BIN FULL reported by Roomba at: \" + Timestamp)\nend\n\nrule \"Roomba Error\"\nwhen\n Item roomba_error changed from OFF to ON\nthen\n val Timestamp = getTimestamp.apply(roomba_lastheardfrom, \"%1$ta %1$tR\")\n pushNotification(\"Roomba\", \"ERROR reported by Roomba at: \" + Timestamp)\n sendMail(mailTo, \"Roomba\", \"ERROR reported by Roomba at: \" + Timestamp + \"See attachment for details\", \"http://your_OH_ip:port/static/map.png\")\nend\n\nrule \"Roomba percent completed\"\nwhen\n Item roomba_sqft received update\nthen\n var sqft_completed = roomba_sqft.state as Number\n\n var max_sqft = 470 //insert max square footage here\n var min_sqft = 0\n\n var Number completed_percent = 0\n\n if (sqft_completed < min_sqft) {completed_percent = 0)\n else if (sqft_completed > max_sqft) {completed_percent = 100}\n else {\n completed_percent = (((sqft_completed - min_sqft) * 100) / (max_sqft-min_sqft)).intValue\n }\n logInfo(\"Roomba\", \"Roomba percent complete \"+roomba_sqft.state+\" of \"+max_sqft.toString+\" calculated as \" + completed_percent.toString + \"%\")\n postUpdate(roomba_percent_complete,completed_percent)\nend\n\nrule \"Roomba update command\"\nwhen\n Item roomba_phase received update\nthen\n logInfo(\"Roomba\", \"Roomba phase received update: \" + roomba_phase.state}\n switch(roomba_phase.state) {\n case \"run\" : postUpdate(roomba_command,\"start\")\n case \"hmUsrDock\" : postUpdate(roomba_command,\"pause\")\n case \"hmMidMsn\" : postUpdate(roomba_command,\"pause\")\n case \"hmPostMsn\" : {\n postUpdate(roomba_command,\"dock\")\n getTimestamp.apply(roomba_lastmissioncompleted, \"%1$ta %1$tR\")\n }\n case \"charge\" : postUpdate(roomba_command,\"dock\")\n case \"stop\" : postUpdate(roomba_command,\"stop\")\n case \"pause\" : postUpdate(roomba_command,\"pause\")\n case \"stuck\" : postUpdate(roomba_command,\"stop\")\n }\nend\n\nrule \"Roomba Notifications\"\nwhen\n Item roomba_status changed\nthen\n logInfo(\"Roomba\", \"Roomba status is: \" + roomba_status.state}\n val Timestamp = getTimestamp.apply(roomba_lastheardfrom, \"%1$ta %1$tR\")\n switch(roomba_status.state) {\n case \"Running\" : pushNotification(\"Roomba\", \"Roomba is RUNNING at: \" + Timestamp)\n case \"Docking - End Mission\" : {\n createTimer(now.plusSeconds(2)) [|\n pushNotification(\"Roomba\", \"Roomba has FINISHED cleaning at: \" + Timestamp)\n sendMail(mailTo, \"Roomba\", \"Roomba has FINISHED cleaning at: \" + Timestamp + \"See attachment for details\", \"http://your_OH_ip:port/static/map.png\")\n ]\n }\n case \"Stuck\" : {\n pushNotification(\"Roomba\", \"HELP! Roomba is STUCK at: \" + Timestamp)\n sendMail(mailTo, \"Roomba\", \"HELP! Roomba is STUCK at: \" + Timestamp + \"See attachment for location\", \"http://your_OH_ip:port/static/map.png\")\n }\n }\nend\n\nrule \"Roomba Schedule Display\"\nwhen\n Item roomba_cycle changed or\n Item roomba_cleanSchedule_h changed or\n Item roomba_cleanSchedule_m changed\nthen\n logInfo(\"Roomba\", \"Roomba Schedule: Day \" + roomba_cycle.state + \" Hour: \" + roomba_cleanSchedule_h.state + \" Minute: \" + roomba_cleanSchedule_m.state)\n var String schedule = \"\"\n var String days = (roomba_cycle.state as StringType).toString\n var String hours = (roomba_cleanSchedule_h.state as StringType).toString\n var String minutes = (roomba_cleanSchedule_m.state as StringType).toString\n val ArrayList daysOfWeek = newArrayList(\"Sun\",\"Mon\",\"Tues\",\"Wed\",\"Thur\",\"Fri\",\"Sat\")\n val ArrayList daysList = new ArrayList(days.replace(\"[\",\"\").replace(\"]\",\"\").replace(\"'\",\"\").split(\",\"))\n val ArrayList hoursList = new ArrayList(hours.replace(\"[\",\"\").replace(\"]\",\"\").split(\",\"))\n val ArrayList minutesList = new ArrayList(minutes.replace(\"[\",\"\").replace(\"]\",\"\").split(\",\"))\n daysList.forEach[ item, i |\n if(item.trim() == \"start\") {\n schedule += daysOfWeek.get(i) + \": \" + hoursList.get(i) + \":\" + minutesList.get(i) + \", \"\n }\n ]\n postUpdate(roomba_cleanSchedule, schedule.trim())\nend\n```\n### Icons\nI also have various roomba icons in /etc/openhab2/icons/classic\n\nThese are here in openhab/icons, copy them to /etc/openhab2/icons/classic.\nitems and transforms are there also.\n### General\nstart_openhab_roomba is a bash script that starts roomba with the maps in the right location (on Ubuntu) for openhab2, you may have to change this location for other systems (windows, RPi, etc), depending on how you installed Openhab2. You need the mqtt binding installed as well.\nIn the above rules/sitemap replace `your_OH_ip:port` with your own Openhab2 ip and port - to use this from anywhere, these should be externally available (from outside your own network) addresses, otherwise you can only access then from within your own network (e-mail attachments should work though).\n\n## ToDo's\nI'm just using some roomba icons I found on the web, if you have better roomba icons, please let me know, I know these are not Roomba 980 icons...\nUpdate the example map shown here, it's an older version, the new ones are a little nicer.\nWrite a nice web interface script. Done! (well a web map display anyway). See `roomba_map.html` - for openhab2 copy this to /etc/openhab2/html (same location as map.png will go in), now you can see the live maps via `http://your_OH_ip:port/static/roomba_map.html` in your browser. I use a subdirectory to avoid cluttering the root html directory, just be consistent in the pathnames, and make sure the directory exists (with write permission) before running roomba.py!", "description_content_type": "text/markdown", "docs_url": null, "download_url": "https://github.com/freekode/roombapy-delay/archive/1.4.0.tar.gz", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/freekode/roombapy-delay", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "roombapy-delay", "package_url": "https://pypi.org/project/roombapy-delay/", "platform": "", "project_url": "https://pypi.org/project/roombapy-delay/", "project_urls": { "Download": "https://github.com/freekode/roombapy-delay/archive/1.4.0.tar.gz", "Homepage": "https://github.com/freekode/roombapy-delay" }, "release_url": "https://pypi.org/project/roombapy-delay/1.4.0/", "requires_dist": null, "requires_python": "", "summary": "Python program and library to control Wi-Fi enabled iRobot Roomba vacuum cleaners", "version": "1.4.0" }, "last_serial": 5931556, "releases": { "1.4.0": [ { "comment_text": "", "digests": { "md5": "1a509cf9eb4ac415a531971619975777", "sha256": "a2a8d0cd1fa61f2c0e08cd575263a1f45a9b0d9cc046ee59c7e02f736fa58a59" }, "downloads": -1, "filename": "roombapy-delay-1.4.0.tar.gz", "has_sig": false, "md5_digest": "1a509cf9eb4ac415a531971619975777", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 122984, "upload_time": "2019-10-05T09:52:34", "url": "https://files.pythonhosted.org/packages/2f/d0/31f333da6bb8d934a2a55c8b592b09eb22824c03003c706806942888ab63/roombapy-delay-1.4.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "1a509cf9eb4ac415a531971619975777", "sha256": "a2a8d0cd1fa61f2c0e08cd575263a1f45a9b0d9cc046ee59c7e02f736fa58a59" }, "downloads": -1, "filename": "roombapy-delay-1.4.0.tar.gz", "has_sig": false, "md5_digest": "1a509cf9eb4ac415a531971619975777", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 122984, "upload_time": "2019-10-05T09:52:34", "url": "https://files.pythonhosted.org/packages/2f/d0/31f333da6bb8d934a2a55c8b592b09eb22824c03003c706806942888ab63/roombapy-delay-1.4.0.tar.gz" } ] }