Misty2py
Misty2py is a Python 3 package for Misty II development using Misty's REST API.
Installation
Poetry
To install misty2py, run pip install misty2py
.
From source
- If this is your first time using
misty2py
from source, do following:- Get Poetry (
python -m pip install poetry
) if you do not have it yet. - Copy
.env.example
to.env
. - Replace the placeholder values in the new
.env
file. - Run
poetry install
to obtain all dependencies.
- Get Poetry (
- Run the desired script via
poetry run python -m [name]
where[name]
is the placeholder for the module location (in Python notation). - If the scripts run but your Misty does not seem to respond, you have most likely provided an incorrect IP address for
MISTY_IP_ADDRESS
in.env
. - Pytests can be run via
poetry run pytest .
. - The coverage report can be obtained via
poetry run pytest --cov-report html --cov=misty2py tests
for HTML output or viapoetry run pytest --cov=misty2py tests
for terminal output.
Features
Misty2py can be used to develop complex skills (behaviours) for the Misty II robot utilising:
- actions via sending a
POST
orDELETE
requests to Misty's API; - informations via sending a
GET
request to Misty's API; - continuous streams of data via subscribing to event types on Misty's websockets.
Misty2py uses following concepts for easy of usage:
- action keywords - customisable python-styled keywords for endpoints of Misty's API that correspond to performing actions;
- information keywords - customisable python-styled keywords for endpoints of Misty's API that correspond to retrieving information;
- data shortcuts - customisable python-styled keywords for commonly used data that are supplied to Misty's API as the body of a
POST
request.
Usage
Getting started
- Start by making a new instance of
misty2py.robot
'sMisty
bymisty_robot = Misty("ip_address_here")
- Substitute
ip_address_here
with the IP address of your Misty. misty2py.utils.env_loader
module containsEnvLoader
class that can be used to load Misty's IP from the .env file in your project's home directory:- Create the
.env
file and writeMISTY_IP_ADDRESS="[ip_address_here]"
in it. - Initialise an
EnvLoader
object viaenv_loader = EnvLoader()
; this loads the environment variables. - Use
env_loader.get_ip()
to obtain the IP address.
- Create the
- Substitute
- Use the method
misty_robot.perform_action()
to tell Misty to perform an action. - Use the method
misty_robot.get_info()
to tell Misty to return information. - Use the method
misty_robot.event()
to initialise, obtain and stop continuous streams of data from Misty's event types.
Obtaining information
Obtaining digital information is handled by misty2py.robot::get_info
method.
misty2py.robot::get_info
has following arguments:
info_name
- required; the string information keyword corresponding to an endpoint in Misty's API;params
- optional; a dictionary of parameter name and parameter value pairs, defaults to{}
.
Performing actions
Performing physical and digital actions including removal of non-system files is handled by misty2py.robot::perform_action()
method.
misty2py.robot::perform_action()
has following arguments:
action_name
- required; the string action keyword corresponding to an endpoint in Misty's API;data
- optional; the data to pass to the request as a dictionary or a data shortcut (string), defaults to{}
.
Event types
To obtain event data in Misty's framework, it is required to subscribe to an event type on Misty's websocket server. Misty's websocket server then streams data to the websocket client, in this implementation via a separate thread. To access this data, misty2py.robot::event
method must be called with "get_data"
parameter from the main thread. When data are no longer required to be streamed to the client, an event type can be unsubscribed to kill the event thread.
Subscription
Subscribe to an event via misty2py.robot::event
with the parameter "subscribe"
and following keyword arguments:
- `type` - *required;* event type string as documented in [Event Types Docs](https://docs.mistyrobotics.com/misty-ii/robot/sensor-data/ "Misty Robotics Event Types").
- `name` - *optional;* a custom event name string; must be unique.
- `return_property` - *optional;* the property to return from Misty's websockets; all properties are returned if return_property is not supplied.
- `debounce` - *optional;* the interval in ms at which new information is sent; defaults to 250.
- `len_data_entries` - *optional;* the maximum number of data entries to keep (discards in fifo style); defaults to 10.
- `event_emitter` - *optional;* an event emitter function which emits an event upon message recieval. Supplies the message content as an argument.
Accessing the data and the log
Access the data of an event or its log via misty2py.robot::event
with the parameter "get_data"
or "get_log"
and a keyword argument name
(the name of the event).
Unsubscribing
Unsubscribe from an event via misty2py.robot::event
with the parameter "unsubscribe"
and a keyword argument name
(the name of the event).
Basic example
import time
from misty2py.robot import Misty
from misty2py.utils.env_loader import EnvLoader
env_loader = EnvLoader
m = Misty(env_loader.get_ip())
d = m.event("subscribe", type = "BatteryCharge")
e_name = d.get("event_name")
time.sleep(1)
d = m.event("get_data", name = e_name)
d = m.event("unsubscribe", name = e_name)
Event emitter usage - example
import time
from pymitter import EventEmitter
from misty2py.robot import Misty
from misty2py.utils.env_loader import EnvLoader
env_loader = EnvLoader
m = Misty(env_loader.get_ip())
ee = EventEmitter()
event_name = "myevent_001"
@ee.on(event_name)
def listener(data):
print(data)
d = m.event("subscribe", type = "BatteryCharge", name = event_name, event_emitter = ee)
time.sleep(2)
d = m.event("unsubscribe", name = event_name)
Adding custom keywords and shortcuts
Custom keywords and shortcuts can be passed to a Misty object while declaring a new instance by using the optional arguments:
custom_info
for custom information keywords (a dictionary with keys being the information keywords and values being the endpoints),custom_actions
for custom action keywords (a dictionary with keys being the action keywords and values being a dictionary{"endpoint" : "edpoint_value", "method" : "method_value"}
wheremethod_value
is eitherpost
ordelete
),custom_data
for custom data shortcuts (a dictionary with keys being the data shortcuts and values being the dictionary of data values).
An example:
custom_allowed_infos = {
"hazards_settings": "api/hazards/settings"
}
custom_allowed_data = {
"amazement": {
"FileName": "s_Amazement.wav"
},
"red": {
"red": "255",
"green": "0",
"blue": "0"
}
}
custom_allowed_actions = {
"audio_play" : {
"endpoint" : "api/audio/play",
"method" : "post"
},
"delete_audio" : {
"endpoint" : "api/audio",
"method" : "delete"
}
}
misty_robot = Misty("0.0.0.0",
custom_info=custom_allowed_infos,
custom_actions=custom_allowed_actions,
custom_data=custom_allowed_data)