Package: misty2py
Misty2pyMisty2py is a Python 3 package for Misty II development usingMisty's REST API.Read the full documentationhere!InstallationPoetryTo install misty2py, runpip install misty2py.From sourceIf this is your first time usingmisty2pyfrom source, do following:Get Poetry (python -m pip install poetry) if you do not have it yet.Copy.env.exampleto.env.Replace the placeholder values in the new.envfile.Runpoetry installto obtain all dependencies.Run the desired script viapoetry 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 forMISTY_IP_ADDRESSin.env.Pytests can be run viapoetry run pytest ..The coverage report can be obtained viapoetry run pytest --cov-report html --cov=misty2py testsfor HTML output or viapoetry run pytest --cov=misty2py testsfor terminal output.FeaturesMisty2py can be used to develop complex skills (behaviours) for the Misty II robot utilising:actionsvia sending aPOSTorDELETErequests to Misty's API;informationsvia sending aGETrequest to Misty's API;continuous streams of datavia 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 aPOSTrequest.UsageGetting startedThe main object of this package isMisty, which is an abstract representation of Misty the robot. To initialise this object, it is required to know the IP address of the Misty robot that should be used.The most direct way to initialise aMistyobject is to use the IP address directly, which allows the user to get the object in one step via:frommisty2py.robotimportMistymy_misty=Misty("192.168.0.1")#example IP addressThis may be impractical and potentially even unsafe, so it is recommended to create a .env file in the project's directory, specify the IP address there viaMISTY_IP_ADDRESS="[ip_address_here]"and use Misty2py'sEnvLoaderto load the IP address via:frommisty2py.robotimportMistyfrommisty2py.utils.env_loaderimportEnvLoaderenv_loader=EnvLoader()my_misty=Misty(env_loader.get_ip())Assuming aMistyobject calledmy_mistywas obtained, all required actions can be performed via the following three methods:# Performing an action (a POST or DELETE request):my_misty.perform_action("<action_keyword>")# Obtaining information (a GET request):my_misty.get_info("<information_keyword>")# Event related methods# (subscribing to an event, getting event data# or event log and unsubscribing from an event):my_misty.event("<parameter>")ResponsesAny action performed via Misty2py which contains communication with Misty's APIs returns theMisty2pyResponseobject.Misty2pyResponseis a uniform representation of two sub-responses that are present in any HTTP or WebSocket communication with Misty's APIs using Misty2py. The first sub-response is always from Misty2py and is represented by the attributesMisty2pyResponse.misty2py_status(Trueif no Misty2py-related errors were encountered) and potentially emptyMisty2pyResponse.error_msgandMisty2pyResponse.error_typethat contain error information if a Misty2py-related error was encountered. The other sub-response is either from Misty's REST API or Misty's WebSocket API. In the first case, it is represented by the attributeMisty2pyResponse.rest_response(Dict), and in the second case, it is represented by the attributeMisty2pyResponse.ws_response. One of these is always empty, because no action in Misty2py includes simultaneous communication with both APIs. For convenience, aMisty2pyResponseobject can be easily parsed to a dictionary via the methodMisty2pyResponse.parse_to_dict.Obtaining informationObtaining digital information is handled bymisty2py.robot::get_infomethod which has two arguments. The argumentinfo_nameis required and it specifies the string information keyword corresponding to an endpoint in Misty's REST API. The argumentparamsis optional and it supplies a dictionary of parameter name and parameter value pairs. This argument defaults to{}(an empty dictionary).Performing actionsPerforming physical and digital actions including removal of non-system files is handled bymisty2py.robot::perform_action()method which takes two arguments. The argumentaction_nameis required and it specifies the string action keyword corresponding to an endpoint in Misty’s REST API. The second argument,data, is optional and it specifies the data to pass to the request as a dictionary or a data shortcut (string). Thedataargument defaults to{}(an empty dictionary).Event typesMisty's WebSocket API follows PUB-SUB architecture, which means that in order to obtain event data in Misty's framework, it is required tosubscribeto an event type on Misty's WebSocket API. The WebSocket server then streams data to the WebSocket client, which receives it a separate thread. Toaccess the data,misty2py.robot::eventmethod must be called with"get_data"parameter from the main thread. When the data are no longer required to be streamed to the client, an event type can beunsubscribedwhich both kills the event thread and stops the API from sending more data.Subscribingto an event is done viamisty2py.robot::eventwith the parameter"subscribe"and following keyword arguments:type-required;event type string as documented inEvent Types Docs.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 to250.len_data_entries-optional;the maximum number of data entries to keep (discards in fifo style); defaults to10.event_emitter-optional;an event emitter function which emits an event upon message recieval. Supplies the message content as an argument.Accessing the dataof an event or its log is done viamisty2py.robot::eventwith the parameter"get_data"or"get_log"and a keyword argumentname(the name of the event).Unsubscribingfrom an event is done viamisty2py.robot::eventwith the parameter"unsubscribe"and a keyword argumentname(the name of the event).A bare-bones implementation of event subscription can be seen below.importtimefrommisty2py.robotimportMistyfrommisty2py.utils.env_loaderimportEnvLoaderenv_loader=EnvLoaderm=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)The following example shows a more realistic scenario which includes an event emitter and an event listener.importtimefrompymitterimportEventEmitterfrommisty2py.robotimportMistyfrommisty2py.utils.env_loaderimportEnvLoaderenv_loader=EnvLoaderm=Misty(env_loader.get_ip())ee=EventEmitter()event_name="myevent_001"@ee.on(event_name)deflistener(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 shortcutsCustom keywords and shortcuts can be passed to a Misty object while declaring a new instance by using the optional argumentscustom_info,custom_actionsandcustom_data.The argumentcustom_infocan be used to pass custom information keywords as a dictionary with keys being the information keywords and values being the endpoints. An information keyword can only be used for aGETmethod supporting endpoint.The argumentcustom_actionscan be used to pass custom action keywords as a dictionary with keys being the action keywords and values being a dictionary of an"endpoint"key (str) and a"method"key (str). The"method"values must be one ofpost,delete,put,head,optionsandpatch. However, it should be noted that Misty's REST API currently only hasGET,POSTandDELETEmethods. The rest of the methods was implement in Misty2py for forwards-compatibility.The argumentcustom_datacan be used to pass custom data shortcuts as a dictionary with keys being the data shortcuts and values being the dictionary of data values.For futher illustration, an example of passing custom keywords and shortcuts can be seen below.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)