- 
                Notifications
    You must be signed in to change notification settings 
- Fork 2
Creating a Python Plugin Tutorial
- 
Python >= 3.6 (requires asyncio) 
- 
Nodejs >= 8 (requires async) 
Optional
npm i --global microdrop
microdrop-3
#launching microdrop { HTTP_PORT: 3000, MQTT_PORT: 1883 }
#Launch Jupyterlab (complete)
#  or visit localhost:3000 (no filebrowser, terminal, or notebooks)pip install microdrop_client# if you use conda:
conda install jupyterlab
# if you use pip:
pip install jupyterlab
jupyter serverextension enable --py jupyterlab --sys-prefixmkdir my_python_plugin
cd my_python_plugin
jupyter lab
# A jupyterlab environment should open in your web browserYou might have been hearing more and more about asynchronous programming as of late thanks to Python 3.5, and NodeJS 8 . Python's asyncio library helps with the handling of waiting on requests from communication protocols like http or mqtt. Normally, this would be done either through callbacks (passing functions as parameters called upon a message being received), or by blocking execution of your code through a while loop. Instead Python 3 introduces Futures: an object that is resolved later on, and who's value can be awaited upon when necessary.
For more information, I recommend checking out https://www.blog.pythonlibrary.org/2016/07/26/python-3-an-intro-to-asyncio/.
Your recipe/protocol needs to be written using python 3's new helper syntax for asynchronous methods. If you want to write your recipes without callbacks, you can use microdrops 'execute' method, that expects an asynchronous function (which uses the 'async' decoration keyword), with each asynchronous operation (such as those from microdrop_client) prefixed with the 'await' keyword.
async def my_recipe(microdrop, args):
    plugin = 'some-microdrop-plugin'
    action = 'some-action'
    data = await microdrop.trigger_plugin(plugin, action, {})
    return data
microdrop.execute(my_recipe, args)Open a new Python 3 Jupyter Notebook and enter the following into a new cell
from microdrop_client import MicroDrop
microdrop = MicroDrop()
wait_for = microdrop.loop.run_until_completeNavigate to localhost:3000/plugin-manager, and enable all the plugins. Navigate to localhost:3000/display (should now see a view for the fluxel device)
Awesome! Now we can both see the state of our fluxel device, and control it through a jupyter notebook. Lets toggle on a few electrodes.
- First lets get a list of subscriptions we can publish to for electrodes-model:
subs = wait_for(microdrop.get_subscriptions('electrodes-model'))
print(subs)
#['microdrop/put/electrodes-model/active-electrodes', 'microdrop/trigger/electrodes-model/toggle-electrode', #'microdrop/web-server/signal/running-state-requested', 'microdrop/trigger/electrodes-model/get-subscriptions']- It looks like we want to publish to 'electrodes-model/active-electrodes'. The microdrop_client contains helper functions to make this more simple. Although you will need to be a bit familiar with Python 3's asyncio library. Enter the following into another cell:
electrodes = ['electrode053', 'electrode087','electrode052','electrode049','electrode051','electrode084','electrode048','electrode004','electrode005']
async def toggle_electrode(microdrop, id):
    plugin = 'electrodes-model'
    action = 'toggle-electrode'
    await microdrop.trigger_plugin(plugin, action, {'electrodeId': id, 'state': True} )
for electrode in electrodes:
    microdrop.execute(toggle_electrode, electrode)You can validate this either through seeing a smiley face on the fluxel device view, or by running:
wait_for(microdrop.get_state('electrodes-model', 'active-electrodes'))
#['electrode053',
# 'electrode087',
# 'electrode052',
# 'electrode049',
# 'electrode051',
# 'electrode084',
# 'electrode048',
# 'electrode004',
# 'electrode005']Next lets draw routes programmatically and execute them.
- Turn off all the electrodes
wait_for(microdrop.put_plugin('electrodes-model', 'active-electrodes', []))- Add route to the fluxel device
path = ['down', 'down', 'right', 'right', 'up', 'up']
start = 'electrode065'
r = {'start': start, 'path': path }
wait_for(microdrop.put_plugin('routes-model', 'route', r))- Execute all the routes on the fluxel device
routes = wait_for(microdrop.get_state('routes-model', 'routes'))
wait_for(microdrop.trigger_plugin('routes-model', 'execute', {'routes': routes}))