#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Magnetometer module
-------------------
Created by jboeer <jonas.boeer@kinemic.de> on 2016-09-07
"""
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import
import re
import logging
from pymetawear import libmetawear
from pymetawear.exceptions import PyMetaWearException
from mbientlab.metawear.cbindings import MagBmm150Odr, MagBmm150Preset
from pymetawear.modules.base import PyMetaWearLoggingModule, Modules, data_handler
log = logging.getLogger(__name__)
def require_bmm150(f):
def wrapper(*args, **kwargs):
if getattr(args[0], 'mag_p_class', None) is None:
raise PyMetaWearException("There is not Magnetometer "
"module on your MetaWear board!")
return f(*args, **kwargs)
return wrapper
[docs]class MagnetometerModule(PyMetaWearLoggingModule):
"""MetaWear accelerometer module implementation.
:param ctypes.c_long board: The MetaWear board pointer value.
:param int module_id: The module id of this accelerometer
component, obtained from ``libmetawear``.
:param bool debug: If ``True``, module prints out debug information.
"""
def __init__(self, board, module_id):
super(MagnetometerModule, self).__init__(board)
self.module_id = module_id
self.power_presets = {}
self.odr = {}
if self.module_id == Modules.MBL_MW_MODULE_NA:
# No magnetometer present!
self.mag_o_class = None
self.mag_p_class = None
else:
self.mag_o_class = MagBmm150Odr
self.mag_p_class = MagBmm150Preset
if self.mag_p_class is not None:
# Parse possible presets for this magnetometer.
for key, value in vars(self.mag_p_class).items():
if re.search('^([A-Z\_]*)', key) and isinstance(value,int):
self.power_presets.update({key.lower(): value})
if self.mag_o_class is not None:
# Parse possible data rates for this magnetometer.
for key, value in vars(self.mag_o_class).items():
if re.search('^_([0-9\_]*Hz)', key) and isinstance(value,int):
self.odr.update({key[1:-2]: value})
def __str__(self):
return "{0} {1}: Power presets: {2}".format(
self.module_name, self.sensor_name,
[float(k) for k in sorted(self.power_presets.keys())])
def __repr__(self):
return str(self)
@property
def module_name(self):
return "Magnetometer"
@property
def sensor_name(self):
if self.mag_p_class is not None:
return self.mag_p_class.__name__.replace(
'Mag', '').replace('Preset', '')
else:
return ''
@property
@require_bmm150
def data_signal(self):
return libmetawear.mbl_mw_mag_bmm150_get_b_field_data_signal(self.board)
def _get_power_preset(self, value):
if value.lower() in self.power_presets:
return self.power_presets.get(value.lower())
else:
raise ValueError("Requested power preset ({0}) was not part of "
"possible values: {1}".format(value.lower(), [self.power_presets.keys()]))
@require_bmm150
def get_current_settings(self):
raise NotImplementedError()
@require_bmm150
def get_possible_settings(self):
return {
'power_preset': [sorted(self.power_presets.keys(), key=lambda x:(x.lower()))],
'odr': [sorted(self.odr.keys(), key=lambda x:(x.lower()))]
}
@require_bmm150
def set_settings(self, power_preset):
"""Set magnetometer settings.
.code-block:: python
mwclient.magnetometer.set_settings(power_preset="LOW_POWER")
Call :meth:`~get_possible_settings` to see which values
that can be set for this sensor.
:param str power_preset: The power preset, influencing the data rate,
accuracy and power consumption
"""
# TODO: Add setting of ODR.
pp = self._get_power_preset(power_preset)
log.debug("Setting Magnetometer power preset to {0}".format(pp))
libmetawear.mbl_mw_mag_bmm150_set_preset(self.board, pp)
@require_bmm150
def notifications(self, callback=None):
"""Subscribe or unsubscribe to magnetometer notifications.
Convenience method for handling magnetometer usage.
Example:
.. code-block:: python
def handle_notification(data):
# Handle dictionary with [epoch, value] keys.
epoch = data["epoch"]
xyz = data["value"]
print(str(data))
mwclient.magnetometer.notifications(handle_notification)
:param callable callback: Magnetometer notification callback function.
If `None`, unsubscription to magnetometer notifications is registered.
"""
if callback is None:
self.stop()
self.toggle_sampling(False)
super(MagnetometerModule, self).notifications(None)
else:
super(MagnetometerModule, self).notifications(data_handler(callback))
self.toggle_sampling(True)
self.start()
@require_bmm150
def start(self):
"""Switches the magnetometer to active mode."""
libmetawear.mbl_mw_mag_bmm150_start(self.board)
@require_bmm150
def stop(self):
"""Switches the magnetometer to standby mode."""
libmetawear.mbl_mw_mag_bmm150_stop(self.board)
@require_bmm150
def toggle_sampling(self, enabled=True):
"""Enables or disables magnetometer sampling.
:param bool enabled: Desired state of the magnetometer.
"""
if enabled:
libmetawear.mbl_mw_mag_bmm150_enable_b_field_sampling(self.board)
else:
libmetawear.mbl_mw_mag_bmm150_disable_b_field_sampling(self.board)