diff --git a/.gitignore b/.gitignore index 45112f8..91649bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -temipy/__pycache__/ -temipy.egg-info/ +pytemi/__pycache__/ +pytemi.egg-info/ venv/ test.py \ No newline at end of file diff --git a/README.md b/README.md index b995b71..0b45030 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,30 @@ -# temi Connect Python Package +# pytemi Control temi using Python scripts over MQTT. ## Prerequisites * [Python 3](https://www.python.org/downloads/) -* Python [virtualenv](https://virtualenv.pypa.io/en/stable/installation.html) -* Connect APK installed on temi, see [here](https://github.com/hapi-robo/connect/tree/devel/android) +* [Connect app](https://github.com/hapi-robo/connect/releases) installed on temi * MQTT broker. Free brokers for testing: * [Eclipse](http://test.mosquitto.org/) * [Mosquitto](http://mqtt.eclipse.org) * [HiveMQ](http://broker.hivemq.com) -## Ubuntu / MacOS Setup -Clone this repository: +## Setup +Clone this repository and install all dependencies with pip: ``` -git clone ... +pip install -r requirements.txt ``` -Create a Python virtual environment (`venv`) and install all dependencies: +For Linux users, there's a script that will create a Python virtual environment (assuming it's installed) and install all dependencies: ``` -cd temipy/ ./setup.sh ``` -Activate the virtual environment: -``` -source venv/bin/activate -``` - ## Usage -Make sure temi is connected to an MQTT broker via the Connect app. +Make sure the robot is connected to an MQTT broker via the [Connect app](https://github.com/hapi-robo/connect/releases). Edit the `sample.py` script and adjust the `parameters` appropriately, then run: ``` @@ -41,12 +34,14 @@ python sample.py ## Sample Script ``` -import temipy as temi +import pytemi as temi +MQTT_HOST = "test.mosquitto.org" +MQTT_PORT = 1883 TEMI_SERIAL = "01234567890" -# connect to the MQTT server -mqtt_client = temi.connect("test.mosquitto.org", 1883) +# connect to the MQTT broker +mqtt_client = temi.connect(MQTT_HOST, MQTT_PORT) # create robot object robot = temi.Robot(mqtt_client, TEMI_SERIAL) diff --git a/temipy/__init__.py b/pytemi/__init__.py similarity index 100% rename from temipy/__init__.py rename to pytemi/__init__.py diff --git a/temipy/connect.py b/pytemi/connect.py similarity index 100% rename from temipy/connect.py rename to pytemi/connect.py diff --git a/temipy/robot.py b/pytemi/robot.py similarity index 59% rename from temipy/robot.py rename to pytemi/robot.py index 8b66c66..77eb2ef 100644 --- a/temipy/robot.py +++ b/pytemi/robot.py @@ -18,73 +18,85 @@ def __init__(self, mqtt_client, temi_serial): """ self.client = mqtt_client - self.serial = temi_serial + self.id = temi_serial def rotate(self, angle): - """Rotate robot + """Rotate """ print("[CMD] Rotate: {} [deg]".format(angle)) - topic = "temi/" + self.serial + "/command/move/turn_by" - payload = json.dumps({"angle": angle}) + if (angle != 0): + topic = "temi/" + self.id + "/command/move/turn_by" + payload = json.dumps({"angle": angle}) - self.client.publish(topic, payload, qos=0) + self.client.publish(topic, payload, qos=0) def translate(self, value): - """Translate robot + """Translate """ print("[CMD] Translate: {} [unitless]".format(value)) - if math.copysign(1, value): - topic = "temi/" + self.serial + "/command/move/forward" - elif math.copysign(1, value): - topic = "temi/" + self.serial + "/command/move/backward" + if math.copysign(1, value) > 0: + topic = "temi/" + self.id + "/command/move/forward" + self.client.publish(topic, "{}", qos=0) + elif math.copysign(1, value) < 0: + topic = "temi/" + self.id + "/command/move/backward" + self.client.publish(topic, "{}", qos=0) else: pass # do nothing - self.client.publish(topic, "{}", qos=0) def tilt(self, angle): - """Tilt robot's head (absolute angle) + """Tilt head (absolute angle) """ print("[CMD] Tilt: {} [deg]".format(angle)) - topic = "temi/" + self.serial + "/command/move/tilt" + topic = "temi/" + self.id + "/command/move/tilt" payload = json.dumps({"angle": angle}) self.client.publish(topic, payload, qos=0) def tilt_by(self, angle): - """Tilt robot's head (relative angle) + """Tilt head (relative angle) """ print("[CMD] Tilt By: {} [deg]".format(angle)) - topic = "temi/" + self.serial + "/command/move/tilt_by" + topic = "temi/" + self.id + "/command/move/tilt_by" payload = json.dumps({"angle": angle}) self.client.publish(topic, payload, qos=0) def stop(self): - """Follow + """Stop """ print("[CMD] Stop") - topic = "temi/" + self.serial + "/command/move/stop" + topic = "temi/" + self.id + "/command/move/stop" + + self.client.publish(topic, "{}", qos=1) + + def follow(self): + """Follow + + """ + print("[CMD] Follow") + + topic = "temi/" + self.id + "/command/follow/unconstrained" self.client.publish(topic, "{}", qos=1) def goto(self, location_name): - """Go to a specified location + """Go to a saved location """ print("[CMD] Go-To: {}".format(location_name)) - topic = "temi/" + self.serial + "/command/waypoint/goto" + topic = "temi/" + self.id + "/command/waypoint/goto" payload = json.dumps({"location": location_name}) self.client.publish(topic, payload, qos=1) @@ -95,7 +107,7 @@ def tts(self, text): """ print("[CMD] TTS: {}".format(text)) - topic = "temi/" + self.serial + "/command/tts" + topic = "temi/" + self.id + "/command/tts" payload = json.dumps({"utterance": text}) self.client.publish(topic, payload, qos=1) @@ -106,7 +118,7 @@ def tts(self, text): # """ # print("[CMD] Play Audio: {}".format(url)) - # topic = "temi/" + self.serial + "/command/media/audio" + # topic = "temi/" + self.id + "/command/media/audio" # payload = json.dumps({"url": url}) # self.client.publish(topic, payload, qos=1) @@ -117,7 +129,7 @@ def video(self, url): """ print("[CMD] Play Video: {}".format(url)) - topic = "temi/" + self.serial + "/command/media/video" + topic = "temi/" + self.id + "/command/media/video" payload = json.dumps({"url": url}) self.client.publish(topic, payload, qos=1) @@ -128,7 +140,7 @@ def youtube(self, video_id): """ print("[CMD] Play YouTube: {}".format(video_id)) - topic = "temi/" + self.serial + "/command/media/youtube" + topic = "temi/" + self.id + "/command/media/youtube" payload = json.dumps({"video_id": video_id}) self.client.publish(topic, payload, qos=1) @@ -139,18 +151,29 @@ def webview(self, url): """ print("[CMD] Show Webview: {}".format(url)) - topic = "temi/" + self.serial + "/command/media/webview" + topic = "temi/" + self.id + "/command/media/webview" payload = json.dumps({"url": url}) self.client.publish(topic, payload, qos=1) + def app(self, package_name): + """Start Android app + + """ + print("[CMD] Start App: {}".format(package_name)) + + topic = "temi/" + self.id + "/command/app" + payload = json.dumps({"package_name": package_name}) + + self.client.publish(topic, payload, qos=1) + def call(self, room_name): """Start a call """ print("[CMD] Call: {}".format(room_name)) - topic = "temi/" + self.serial + "/command/call/start" + topic = "temi/" + self.id + "/command/call/start" payload = json.dumps({"room_name": room_name}) self.client.publish(topic, payload, qos=1) @@ -161,6 +184,6 @@ def hangup(self): """ print("[CMD] Hangup") - topic = "temi/" + self.serial + "/command/call/end" + topic = "temi/" + self.id + "/command/call/end" self.client.publish(topic, "{}", qos=1) diff --git a/sample.py b/sample.py index 97673b5..671d92b 100644 --- a/sample.py +++ b/sample.py @@ -3,7 +3,7 @@ """Sample script """ -import temipy as temi +import pytemi as temi import time @@ -12,7 +12,7 @@ MQTT_PORT = 1883 TEMI_SERIAL = "01234567890" -# connect to the MQTT server +# connect to the MQTT broker mqtt_client = temi.connect(MQTT_HOST, MQTT_PORT) # create robot object @@ -22,62 +22,54 @@ # -------------------------------------------------------------- # TEXT-TO-SPEECH COMMANDS # -------------------------------------------------------------- -# command the robot to speak -robot.tts("Going to the Entrance") +robot.tts("Going to the Entrance") # command the robot to speak +time.sleep(1) # wait some time for action to complete # -------------------------------------------------------------- # WAYPOINT COMMANDS # -------------------------------------------------------------- -# command the robot to go to a saved location -robot.goto("entrance") +robot.goto("entrance") # command the robot to go to a saved location +time.sleep(1) # wait some time for action to complete # -------------------------------------------------------------- # MOVE COMMANDS # -------------------------------------------------------------- -# tilt the robot's head to +55 degrees (absolute angle) -robot.tilt(+45) -time.sleep(3) # wait 3 seconds for action to complete +robot.tilt(+45) # tilt the robot's head (absolute angle) +time.sleep(3) # wait some time for action to complete -# tilt the robot's head to -15 degrees (absolute angle) -robot.tilt(-15) -time.sleep(3) # wait 3 seconds for action to complete +robot.tilt(-15) # tilt the robot's head (absolute angle) +time.sleep(3) # wait some time for action to complete -# tilt the robot's head to +30 degrees (relative angle) -robot.tilt_by(+30) -time.sleep(3) # wait 3 seconds for action to complete +robot.tilt_by(+30) # tilt the robot's head (relative angle) +time.sleep(3) # wait some time for action to complete -# tilt the robot's head to -10 degrees (relative angle) -robot.tilt_by(-10) -time.sleep(3) # wait 3 seconds for action to complete +robot.tilt_by(-10) # tilt the robot's head (relative angle) +time.sleep(3) # wait some time for action to complete -# rotate the robot by 90 degrees (relative angle) -robot.rotate(90) -time.sleep(5) # wait 5 seconds for action to complete +robot.rotate(90) # rotate the robot (relative angle) +time.sleep(5) # wait some time for action to complete -# rotate the robot by -30 degrees (relative angle) -robot.rotate(-30) -time.sleep(5) # wait 5 seconds for action to complete +robot.rotate(-30) # rotate the robot (relative angle) +time.sleep(5) # wait some time for action to complete # -------------------------------------------------------------- # MEDIA COMMANDS # -------------------------------------------------------------- -# play YouTube video by passing in a video ID -robot.youtube("ZsEano0qwcg") -time.sleep(30) # wait 30 seconds before performing next action +robot.youtube("ZsEano0qwcg") # play YouTube video by passing in a YouTube video ID +time.sleep(30) # wait some time for action to complete -# play online video by passing a URL robot.video( "https://roboteam-assets.s3.eu-central-1.amazonaws.com/ui/skills/tutorials/videos/intorducing+temi.mp4" -) -time.sleep(30) # wait 30 seconds before performing next action +) # play online video by passing a URL +time.sleep(30) # wait some time for action to complete # show webview by passing a URL robot.webview("https://www.robotemi.com/") -time.sleep(5) # wait 5 seconds before performing next action -robot.webview("https://www.his.co.jp/en/") -time.sleep(5) # wait 5 seconds before performing next action +time.sleep(5) robot.webview("https://hapi-robo.com/") -time.sleep(5) # wait 5 seconds before performing next action +time.sleep(5) +robot.webview("https://www.his.co.jp/en/") +time.sleep(5) diff --git a/setup.py b/setup.py index d148389..82342fc 100644 --- a/setup.py +++ b/setup.py @@ -5,18 +5,21 @@ def readme(): with open("README.md", "r") as f: return f.read() +def requirements(): + with open("requirements.txt", "r") as f: + return f.read().splitlines() setuptools.setup( - name="temipy", + name="pytemi", version="1.0.0", - description="MQTT bridge for temi", + description="A Python client that can be used with Connect MQTT bridge for temi.", long_description=readme(), long_description_content_type="text/markdown", author="R. Oung", author_email="r.oung@hapi-robo.com", url="https://github.com/", packages=setuptools.find_packages(), - install_requires=["paho-mqtt",], + install_requires=requirements(), classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License",