Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Projects related to MicroPython on the BBC micro:bit include:
ble.rst
button.rst
compass.rst
log.rst
display.rst
filesystem.rst
i2c.rst
Expand Down
Binary file added docs/log-html-view.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/log-my_data.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
156 changes: 82 additions & 74 deletions docs/log.rst
Original file line number Diff line number Diff line change
@@ -1,106 +1,114 @@
Data logging **V2**
Data Logging **V2**
*******************

.. py:module:: log

This module lets you log data to a ``MY_DATA`` file saved on a
micro:bit **V2**.
This module lets you log data to a ``MY_DATA`` file saved on a micro:bit
**V2** ``MICROBIT`` USB drive.

Further guidance on the feature can be found on the
`data logging page of the microbit.org website <https://microbit.org/get-started/user-guide/data-logging/>`_.
.. image:: log-my_data.png

The data is structured in a table format and it can be viewed and plotted with
a browser.

.. image:: log-html-view.jpeg

Further guidance on this feature can be found on the
`data logging page of the microbit.org website
<https://microbit.org/get-started/user-guide/data-logging/>`_.

Functions
=========

.. py:function:: set_labels(value, timestamp=log.MILLISECONDS)
.. py:function:: set_labels(*labels, timestamp=log.SECONDS)

Set up the log file header.

Set up the log file header.
This function accepts any number of positional arguments, each creates
a column header, e.g. ``log.set_labels("X", "Y", "Z")``.

Each call to this function with positional arguments will generate a new
header entry into the log file.
Ideally this function should be called a single time, before any data is
logged, to configure the data table header once.

If the programme starts and a log file already exists it will compare the
labels setup by this function call to the last headers declared in the
file. If the headers are different it will add a new header entry at the
end of the file.
If a log file already exists when the programme starts, or if this function
is called multiple times, it will check the labels already defined in the
log file.
If this function call contains any new labels not already present, it will
generate a new header row with the additional columns.

* **value**: Positional arguments used to generate the log headers,
which go on the first line of the CSV file. For example, ``set_labels("A","B","C")``
will create three column headers titled ``A``, ``B`` and ``C`` in that order.
* **timestamp**: Select the timestamp unit that will be automatically
added as the first column in every row. Timestamp values can be one of
``MILLISECONDS``, ``SECONDS``, ``MINUTES``, ``HOURS``, ``DAYS`` or ``None`` to
disable the timestamp.
By default the first column contains a time stamp for each row. The time
unit can be selected via the ``timestamp`` argument, e.g.
``log.set_labels("temp", timestamp=log.MINUTES)``

.. py:function:: set_mirroring(value)
:param \*labels: Any number of positional arguments, each corresponding to
an entry in the log header.
:param timestamp: Select the timestamp unit that will be automatically
added as the first column in every row. Timestamp values can be one of
``log.MILLISECONDS``, ``log.SECONDS``, ``log.MINUTES``, ``log.HOURS``,
``log.DAYS`` or ``None`` to disable the timestamp. The default value
is ``log.SECONDS``.

Mirrors the datalogging activity to the serial output.
Serial mirroring is off by default.
.. py:function:: set_mirroring(serial)

* **value**: Boolean. ``True`` will enable mirroring data to the serial output.
Configure mirroring of the data logging activity to the serial output.

Serial mirroring is disabled by default. When enabled, it will print to
serial each row logged into the log file.

:param serial: ``True`` enables mirroring data to the serial output.

.. py:function:: delete(full=False)

Deletes the contents of the log, including headers.
To add the log headers the ``set_labels`` function has to be called again
after this.
Delete the contents of the log, including headers.

To add the log headers again the ``set_labels`` function should to be
called after this function.

* **full**: Selects a "full" erase format that removes the data from the
flash storage. If set to ``False`` it uses a "fast" method,
which invalidates the data instead of performing a slower
full erase.
There are two erase modes; "full" completely removes the data from the
physical storage, and "fast" invalidates the data without removing it.

.. py:function:: add({key:value})
add(key=value)

There are two ways to add a data row into the log:
:param full: ``True`` selects a "full" erase and ``False`` selects the
"fast" erase method.

1. From a positional argument dictionary (key == label)
- e.g. log.add({ 'temp': microbit.temperature() })
.. py:function:: add( data_dictionary, /, *, **kwargs)

2. From keyword arguments (argument name == label)
- e.g. log.add(temp=microbit.temperature())
Add a data row to the log.

Each call to this function adds a row to the log.
There are two ways to log data with this function:

New data labels (dictionary keys or keyword arguments) not already
specified via the `set_labels` function, or by a previous call to this
function, will trigger a new header entry to be added to the log with
the extra label.
#. Via keyword arguments, each argument name representing a label.

Labels previously specified and not present in this function call will be
skipped with an empty value in the log row.
* e.g. ``log.add(X=compass.get_x(), Y=compass.get_y())``

Example
=======
#. Via a dictionary, each dictionary key representing a label.

An example that runs through some of the functions of the log module API::
* e.g. ``log.add({ "X": compass.get_x(), "Y": compass.get_y() })``

The keyword argument option can be easier to use, and the dictionary option
allows the use of spaces (and other special characters), that could not be
used with the keyword arguments.

New labels not previously specified via the ``set_labels`` function, or by
a previous call to this function, will trigger a new header entry to be
added to the log with the extra labels.

Labels previously specified and not present in a call to this function will
be skipped with an empty value in the log row.

Examples
========

A minimal example::

from microbit import *
import log

# Creates a new "log" file with the given "headers", timestamp added by default
log.set_labels('temperature', 'brightness')

# Configuring a different time unit for the timestamp
log.set_labels('temperature', 'brightness', timestamp=log.SECONDS)

# Enables the serial mirroring
log.set_mirroring(True)

# Set the timer to log data every 1h20m30s50ms
run_every(h=1, min=20, s=30, ms=50)

while True:
if button_a.is_pressed() and button_b.is_pressed():
log.delete(full=True)
elif button_a.is_pressed():
# Records the temperature & brightness every 00:01:20:30:50 (dd:hh:mm:ss:ms).
log.add({
"temperature": temperature(),
"brightness": display.read_light_level()
})
display.show(Image.HAPPY)
sleep(500)
else:
display.show(Image.CONFUSED)
# Set the timer to log data every 5 seconds
@run_every(s=5)
def log_temp():
log.add(temp=temperature())

An example that runs through all of the functions of the log module API:

.. include:: ../examples/data-logging.py
:code: python
1 change: 0 additions & 1 deletion docs/microbit.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ Modules
compass.rst
display.rst
i2c.rst
log.rst
microphone.rst
speaker.rst
spi.rst
Expand Down
32 changes: 32 additions & 0 deletions examples/data-logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from microbit import *
import log

# Configure the labels and select a time unit for the timestamp
log.set_labels('temp', 'brightness', timestamp=log.SECONDS)

# Send each data row to the serial output
log.set_mirroring(True)

# This decorator schedules this function to run every 10s 50ms
@run_every(s=10, ms=50)
def log_data():
"""Log the temperature and light level, and display an icon."""
log.add(temp=temperature(), brightness=display.read_light_level())
display.show(Image.SURPRISED)
sleep(500)

while True:
if button_a.is_pressed() and button_b.is_pressed():
display.show(Image.MEH)
# Delete the log file using the "full" options, which takes
# longer but ensures the data is wiped from the device
log.delete(full=True)
elif button_a.is_pressed():
display.show(Image.HAPPY)
# Log only the light level, the temp entry will be empty
log.add({
"brightness": display.read_light_level()
})
else:
display.show(Image.CONFUSED)
sleep(500)