2. Python

Welcome to the Python on Windows tutorial. Below you will be able to run some basic examples, in Windows and Python, to interface with your MetaSensor.

You are expected to have at least a basic understanding of Python as a language. There are many amazing websites such as https://www.learnpython.org/ to teach you if you are new to Python.

The Python SDK itself is a wrapper around the C++ SDK, calling into the C++ code using the ctypes library. You will want to keep a reference to the ctype documentation and C++ SDK documentation handy.

2.1. Prerequsites

You should have completed the instructions in the previous section related to the Windows Installation.

We will be using the Git Bash terminal to run the Python examples below.

First, let’s check that you have Python 2.7 installed:

  1. Open Git Bash
  2. Run the command
>>> which python
_images/python-1.jpg
  1. You can use Python 3.4 if you would like to. This tutorial will not cover Python 2.7.

2.1.1. Install Pip

We use pip to install dependencies and the matlab libraries. pip is a package management system used to install and manage software packages written in Python.

  1. Download get-pip.py to a folder on your computer.
  2. Open a command prompt window and navigate to the folder containing get-pip.py.
  3. Then run python get-pip.py. This will install pip.
>>> python get-pip.py
_images/python-2.jpg
  1. Verify a successful installation by opening a command prompt window and navigating to your Python installation’s script directory (default is C:Python27Scripts). Type pip freeze from this location to launch the Python interpreter.
>>> pip freeze
_images/python-3.jpg

pip freeze displays the version number of all modules installed in your Python non-standard library; On a fresh install, pip freeze will display little content.

  1. Don’t forget to make sure your PATH ENVIRONMENT VARIABLE is up to date with your Python path. You can consult the Windows Installation section for more details.

2.1.2. Upgrade Pip

It is essential that your pip be up to date. For good measure, run the commands below:

>>>  pip install pip --upgrade
>>>  pip install --upgrade pip setuptools
_images/python-4.jpg

2.1.3. Install MetaWear

MetaWear is available on Pip. This means you can run the command below to install the MetaWear Python library directly:

>>>  pip install metawear
_images/python-5.jpg

Please take a look at the official website for PyPi to learn more about the MetaWear package: https://pypi.org/project/metawear/

_images/python-12.jpg

2.1.4. Download Examples

Head over to our Python github page: https://github.com/mbientlab/MetaWear-SDK-Python

_images/python-6.jpg

You can clone the repository or simply download as a ZIP file:

>>>  git clone https://github.com/mbientlab/MetaWear-SDK-Python.git
_images/python-7.jpg

2.2. Scan and Connect

This tutorial will take you through your first MetaWear Python App.

Note

Make sure you have a MetaWear device with you, fully-charged, and that you are aware of that device’s MAC address.

We will ignore most of the items in the Github repository and instead we will focus on the examples folder:

_images/python-8.jpg

Using your favorite editor, take a look at the scan_connect.py example.

This python code will scan for nearby Bluetooth devices and print out a list of available devices. You can then choose a device you want to connect to.

print("scanning for devices...")
devices = {}
def handler(result):
    devices[result.mac] = result.name

BleScanner.set_handler(handler)
BleScanner.start()

sleep(10.0)
BleScanner.stop()

i = 0
for address, name in six.iteritems(devices):
    print("[%d] %s (%s)" % (i, address, name))
    i+= 1

msg = "Select your device (-1 to rescan): "
selection = int(raw_input(msg) if platform.python_version_tuple()[0] == '2' else input(msg))

Run the code

>>>  # usage: python scan_connect.py
>>>  python scan_connect.py
_images/python-9.jpg

Select the device you want to connect to. The MAC address for my favorite MetaSensor is D8:B5:11:21:96:06.

>>>  Select your device (-1 to rescan): 1

The code will then connect to this device for 5 seconds, retrieve device information, and disconnect.

_images/python-10.jpg

As you can see, your Windows machine connected to the MetaSensor using Bluetooth and retrieved some infromation about the devices such as the firmware version and the manufacturer name.

Congratulations, you ran your first Python script!

2.3. LED

Now you can try our led.py example by running:

>>>  python led.py D8:B5:11:21:96:06

This example connects to a specific MetaSensor by specifing the MAC address on the cmd line.

device = MetaWear(sys.argv[1])
device.connect()
print("Connected")

pattern= LedPattern(repeat_count= Const.LED_REPEAT_INDEFINITELY)
libmetawear.mbl_mw_led_load_preset_pattern(byref(pattern), LedPreset.SOLID)
libmetawear.mbl_mw_led_write_pattern(device.board, byref(pattern), LedColor.GREEN)
libmetawear.mbl_mw_led_play(device.board)

In this example we make use of the fundamental C libraries used by Python by referencing API calls for LED animations.

First, you will notice the import of the C bindings at the top of the file:

from mbientlab.metawear import MetaWear, libmetawear
from mbientlab.metawear.cbindings import *

Second you will notice a few API calls such as mbl_mw_led_load_preset_pattern, mbl_mw_led_write_pattern and mbl_mw_led_play.

To understand what they are, you should reference two documents:

  1. The C LED documentation: https://mbientlab.com/cppdocs/latest/led.html
  2. The C LED API reference: https://mbientlab.com/documents/metawear/cpp/latest/led_8h.html

So if we take a quick look, this line sets the LED to be a solid color:

libmetawear.mbl_mw_led_load_preset_pattern(byref(pattern), LedPreset.SOLID)

and this line sets the color:

libmetawear.mbl_mw_led_write_pattern(device.board, byref(pattern), LedColor.GREEN)

We could change the line to the following to set the LED color blue:

libmetawear.mbl_mw_led_write_pattern(device.board, byref(pattern), LedColor.BLUE)

When you run the script, the MetaSensor will light up green for a few seconds.

_images/python-11.jpg

Warning

If you are having issues, try running the scan_connect.py first.

2.4. Streaming Accelerometer

The stream_data.py example will illustrate how to stream accelerometer data at 25Hz with 16G range from a single sensor.

>>>  python stream_data.py D8:B5:11:21:96:06
_images/python-13.jpg

In this example, we can take a look at the C commands to set the accelerometer settings:

libmetawear.mbl_mw_acc_set_odr(s.device.board, 25.0)
libmetawear.mbl_mw_acc_set_range(s.device.board, 16.0)
libmetawear.mbl_mw_acc_write_acceleration_config(s.device.board)

We can see that we set the sampling frequency of the accelerometer to 25Hz as well as the range to 16Gs.

Our APIs manage the Bluetooth link for you. All you have to do is make sure you are ready to get the data in the appropriate callback and export it in the right format.

signal = libmetawear.mbl_mw_acc_get_acceleration_data_signal(s.device.board)
libmetawear.mbl_mw_datasignal_subscribe(signal, None, s.callback)

The callback is found in the State class:

self.callback = FnVoid_VoidP_DataP(self.data_handler)

and the data processing for the callback is found in the same class:

def data_handler(self, ctx, data):
    print("%s -> %s" % (self.device.address, parse_value(data)))
    self.samples+= 1

The data coming from the Bluetooth link includes the devices address and a sample of accelerometer data. We print this information to the screen.

libmetawear.mbl_mw_acc_enable_acceleration_sampling(s.device.board)
libmetawear.mbl_mw_acc_start(s.device.board)

Now that our accelerometer is setup and so is our callback, we start the stream.

sleep(10.0)

libmetawear.mbl_mw_acc_stop(s.device.board)
libmetawear.mbl_mw_acc_disable_acceleration_sampling(s.device.board)

signal = libmetawear.mbl_mw_acc_get_acceleration_data_signal(s.device.board)
libmetawear.mbl_mw_datasignal_unsubscribe(signal)
libmetawear.mbl_mw_debug_disconnect(s.device.board)

After 10 seconds have passed, we stop the stream and clean up by unsubscribing the callback and disconnecting from the device.

_images/python-14.jpg

Note

You can refer to the API documentation for data streaming here: https://mbientlab.com/cppdocs/latest/mblmwdatasignal.html#streaming

Note

You can refer to the API references for the accelerometer here: https://mbientlab.com/documents/metawear/cpp/latest/accelerometer_8h.html

2.5. Multiple Devices

The multi_device.py example will illustrate how to work with multiple devices at the same time.

We continue from the previous example and instead we add a for loop that will replicate the same set of commands for every single sensor we want to connect to.

for s in states:
    print("configuring device")
    libmetawear.mbl_mw_acc_set_odr(s.device.board, 25.0)

This time we run it on two devices by adding two MACs to the cmd line:

>>>  # usage: python multi_device [mac1] [mac2] ... [mac(n)]
>>>  python stream_data.py D8:B5:11:21:96:06 F6:99:FD:A4:64:80
_images/python-15.jpg _images/python-16.jpg

Note

You can refer to the API documentation, specifically this section: https://mbientlab.com/cppdocs/latest/mblmwdatasignal.html#streaming

Note

You can refer to the API references for the accelerometer here: https://mbientlab.com/documents/metawear/cpp/latest/accelerometer_8h.html

2.6. Data Processor

The data_processor.py example will illustrate how to stream accelerometer that is averaged using the data processor average function.

Continuing from our previous example, we will now switch out the data fuser for the data processor.

fn_wrapper = cbindings.FnVoid_VoidP_VoidP(processor_created)

acc = libmetawear.mbl_mw_acc_get_acceleration_data_signal(self.device.board)
libmetawear.mbl_mw_dataprocessor_average_create(acc, 4, None, fn_wrapper)

libmetawear.mbl_mw_datasignal_subscribe(self.processor, None, self.callback)

Now we run the example:

>>>  python stream_data.py D8:B5:11:21:96:06 F6:99:FD:A4:64:80

The example was modified to run for less than a second:

_images/python-17.jpg

Note

You can refer to the API documentation for the data processor here: https://mbientlab.com/cppdocs/latest/mblmwdataprocessor.html

Note

You can refer to the API references for the averager here: https://mbientlab.com/documents/metawear/cpp/latest/average_8h.html

2.7. Logging Temperature

The log_temp.py example will illustrate how to log temperature data in the MetaSensor memory and retrieve it later.

The Python script has multiple parts. First, the main portion of the script sets up the logger, then the script goes to sleep for 15 seconds (while the MetaSensor logs temperature data) and finally downloads the data:

try:
    s.setup_logger()

    print("Logging data for 15s")
    sleep(15.0)

    s.download_data()

logger_setup uses the mbl_mw_multi_chnl_temp_get_temperature_data_signal and mbl_mw_datasignal_log API functions to setup the thermistor sensor onboard the MetaSensor:

signal = libmetawear.mbl_mw_multi_chnl_temp_get_temperature_data_signal(self.device.board, \
    MetaWearRProChannel.ON_BOARD_THERMISTOR)
libmetawear.mbl_mw_datasignal_log(signal, None, fn_wrapper)

logger_setup uses the mbl_mw_logging_start and mbl_mw_timer_start API functions to setup the timer and logger:

self.logger = result[0]
self.timer = self._setup_timer()
self._setup_read_event(self.timer, signal)

libmetawear.mbl_mw_logging_start(self.device.board, 0);
libmetawear.mbl_mw_timer_start(self.timer)

Looking at the setup_timer, we see that this creates a timer within the device using the mbl_mw_timer_create_indefinite API function:

fn_wrapper = FnVoid_VoidP_VoidP(timer_handler)
libmetawear.mbl_mw_timer_create_indefinite(self.device.board, 1000, 0, None, fn_wrapper)

And then setup_read_event sends further commands to the MetaSensor using the mbl_mw_event_record_commands, mbl_mw_datasignal_read and mbl_mw_event_end_record API functions.

fn_wrapper = FnVoid_VoidP_VoidP_Int(commands_recorded)
libmetawear.mbl_mw_event_record_commands(timer)
libmetawear.mbl_mw_datasignal_read(signal)
libmetawear.mbl_mw_event_end_record(timer, None, fn_wrapper)

Take a minute to get familiar with the logger_handler function which checks that a MblMwDataLogger pointer has been created successfully.

def logger_handler(ctx, pointer):
    result[0] = RuntimeError("Could not create logger") if pointer == None else pointer

Finally, we look at the download_data function which takes care of stopping the logger and timer and downloading the data in memory via the progress_update_handler:

fn_wrapper = FnVoid_VoidP_UInt_UInt(progress_update_handler)
download_handler= LogDownloadHandler(context = None, \
    received_progress_update = fn_wrapper, \
    received_unknown_entry = cast(None, FnVoid_VoidP_UByte_Long_UByteP_UByte), \
    received_unhandled_entry = cast(None, FnVoid_VoidP_DataP))

callback = FnVoid_VoidP_DataP(lambda ctx, p: print("%f" % (parse_value(p))))
libmetawear.mbl_mw_logger_subscribe(self.logger, None, callback)
libmetawear.mbl_mw_logging_download(self.device.board, 0, byref(download_handler))

Let’s go ahead and run the example:

>>>  python log_temp.py D8:B5:11:21:96:06

Note

You can refer to the API documentation for the data processor here: https://mbientlab.com/cppdocs/latest/logging.html

Note

You can refer to the API references for the logger here: https://mbientlab.com/documents/metawear/cpp/latest/logging_8h.html

Optionally, you can run the simpler accelerometer logger example. Please take a minute and go through the script and run it:

>>>  python log_acc.py D8:B5:11:21:96:06

2.8. Logging Anonymously

The anonymous_datasignal.py example will illustrate how to retrieve data from the sensors memory when the log was started by another device.

First run the MetaBase App on any device such as your iPhone and set the device D8:B5:11:21:96:06 to start logging data (any data, any frequency).

In this example, I used the MetaBase App on an iPhone 8 to log Ambient Light at 0.5Hz.

Then run the command below to download the data on your Windows machine:

>>>  python anonymous_datasignal.py D8:B5:11:21:96:06
_images/python-18.jpg

Note

You can refer to the API documentation for anonymous signals here: https://mbientlab.com/cppdocs/latest/advanced_features.html#anonymous-signals

2.9. Events, Macros, and the Data Processor

The anonymous_datasignal.py example will illustrate how to use macros, events, and even link back to back processor types.

We encourage you to take a look at the script to learn about the advanced features of our APIs.

Then run the command below to download the data on your Windows machine:

>>>  python proc_macro_event.py D8:B5:11:21:96:06

2.10. Next steps

Please read our C docs to learn about all of the capabilities of the MetaSensors: https://mbientlab.com/cppdocs/latest/index.html

Go and build your own Python script!