Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
docs: Update data logging content.
  • Loading branch information
microbit-carlos committed Mar 21, 2022
commit c6ee83f7fcb5dc4626dffe4b4e57c9b1523da66b
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.
151 changes: 92 additions & 59 deletions docs/log.rst
Original file line number Diff line number Diff line change
@@ -1,111 +1,144 @@
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
.. 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.

Each call to this function with positional arguments will generate a new
header entry into the log file.
This function accepts any number of positional arguments, each creates
a column header, e.g. ``log.set_labels("X", "Y", "Z")``.

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.

There are two erase modes, "full" completely removes the data from the
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this is more explicit about the two modes?

Suggested change
There are two erase modes, "full" completely removes the data from the
There are two erase modes; "full" completely removes the data from the physical storage and "fast" which invalidates the data without removing it from the storage.

physical storage, and the "fast" method only invalidates the data.

* **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.
:param full: ``True`` selects a "full erase" and ``False`` selects the
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than having quote marks for "full erase", just quote the mode names "full" and "fast" as it will be more consistent in help docs

Suggested change
:param full: ``True`` selects a "full erase" and ``False`` selects the
:param full: ``True`` selects a "full" erase and ``False`` selects the "fast" erase method.

"fast erase" method.

.. py:function:: add({key:value})
add(key=value)
.. py:function:: add( data_dictionary, /, *, **kwargs)

There are two ways to add a data row into the log:
Add a data row to the log.

#. From a positional argument dictionary (key == label)
There are two ways to log data with this function:

* e.g. ``log.add({ 'temp': microbit.temperature() })``
#. Via keyword arguments, each argument name representing a label.

#. From keyword arguments (argument name == label)
* e.g. ``log.add(X=compass.get_x(), Y=compass.get_y())``

* e.g. ``log.add(temp=microbit.temperature())``
#. Via a dictionary, each dictionary key representing a label.

Each call to this function adds a row to the log.
* e.g. ``log.add({ "X": compass.get_x(), "Y": compass.get_y() })``

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.
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.

Labels previously specified and not present in this function call will be
skipped with an empty value in the log row.
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.

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

An example that runs through some of the functions of the log module API::
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')
# 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:

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

# Enables the serial mirroring
# 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)

# Set the timer to log data every 1h20m30s50ms
run_every(h=1, min=20, s=30, ms=50)
# 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():
# Records the temperature & brightness every 00:01:20:30:50 (dd:hh:mm:ss:ms).
display.show(Image.HAPPY)
# Log only the light level, the temp entry will be empty
log.add({
"temperature": temperature(),
"brightness": display.read_light_level()
})
display.show(Image.HAPPY)
sleep(500)
else:
display.show(Image.CONFUSED)
sleep(500)