Skip to content

Commit 09f400b

Browse files
Merge pull request #1 from microbit-carlos/datalog
docs: Update data logging.
2 parents 942bb4a + e8069e4 commit 09f400b

File tree

6 files changed

+115
-75
lines changed

6 files changed

+115
-75
lines changed

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ Projects related to MicroPython on the BBC micro:bit include:
7878
ble.rst
7979
button.rst
8080
compass.rst
81+
log.rst
8182
display.rst
8283
filesystem.rst
8384
i2c.rst

docs/log-html-view.jpeg

26.2 KB
Loading

docs/log-my_data.png

40.2 KB
Loading

docs/log.rst

Lines changed: 82 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,114 @@
1-
Data logging **V2**
1+
Data Logging **V2**
22
*******************
33

44
.. py:module:: log
55
6-
This module lets you log data to a ``MY_DATA`` file saved on a
7-
micro:bit **V2**.
6+
This module lets you log data to a ``MY_DATA`` file saved on a micro:bit
7+
**V2** ``MICROBIT`` USB drive.
88

9-
Further guidance on the feature can be found on the
10-
`data logging page of the microbit.org website <https://microbit.org/get-started/user-guide/data-logging/>`_.
9+
.. image:: log-my_data.png
10+
11+
The data is structured in a table format and it can be viewed and plotted with
12+
a browser.
13+
14+
.. image:: log-html-view.jpeg
15+
16+
Further guidance on this feature can be found on the
17+
`data logging page of the microbit.org website
18+
<https://microbit.org/get-started/user-guide/data-logging/>`_.
1119

1220
Functions
1321
=========
1422

15-
.. py:function:: set_labels(value, timestamp=log.MILLISECONDS)
23+
.. py:function:: set_labels(*labels, timestamp=log.SECONDS)
24+
25+
Set up the log file header.
1626

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

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

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

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

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

37-
Mirrors the datalogging activity to the serial output.
38-
Serial mirroring is off by default.
51+
.. py:function:: set_mirroring(serial)
3952
40-
* **value**: Boolean. ``True`` will enable mirroring data to the serial output.
53+
Configure mirroring of the data logging activity to the serial output.
54+
55+
Serial mirroring is disabled by default. When enabled, it will print to
56+
serial each row logged into the log file.
57+
58+
:param serial: ``True`` enables mirroring data to the serial output.
4159

4260
.. py:function:: delete(full=False)
4361
44-
Deletes the contents of the log, including headers.
45-
To add the log headers the ``set_labels`` function has to be called again
46-
after this.
62+
Delete the contents of the log, including headers.
63+
64+
To add the log headers again the ``set_labels`` function should to be
65+
called after this function.
4766

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

53-
.. py:function:: add({key:value})
54-
add(key=value)
55-
56-
There are two ways to add a data row into the log:
70+
:param full: ``True`` selects a "full" erase and ``False`` selects the
71+
"fast" erase method.
5772

58-
1. From a positional argument dictionary (key == label)
59-
- e.g. log.add({ 'temp': microbit.temperature() })
73+
.. py:function:: add( data_dictionary, /, *, **kwargs)
6074
61-
2. From keyword arguments (argument name == label)
62-
- e.g. log.add(temp=microbit.temperature())
75+
Add a data row to the log.
6376

64-
Each call to this function adds a row to the log.
77+
There are two ways to log data with this function:
6578

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

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

74-
Example
75-
=======
83+
#. Via a dictionary, each dictionary key representing a label.
7684

77-
An example that runs through some of the functions of the log module API::
85+
* e.g. ``log.add({ "X": compass.get_x(), "Y": compass.get_y() })``
86+
87+
The keyword argument option can be easier to use, and the dictionary option
88+
allows the use of spaces (and other special characters), that could not be
89+
used with the keyword arguments.
90+
91+
New labels not previously specified via the ``set_labels`` function, or by
92+
a previous call to this function, will trigger a new header entry to be
93+
added to the log with the extra labels.
94+
95+
Labels previously specified and not present in a call to this function will
96+
be skipped with an empty value in the log row.
97+
98+
Examples
99+
========
100+
101+
A minimal example::
78102

79103
from microbit import *
80104
import log
81105

82-
# Creates a new "log" file with the given "headers", timestamp added by default
83-
log.set_labels('temperature', 'brightness')
84-
85-
# Configuring a different time unit for the timestamp
86-
log.set_labels('temperature', 'brightness', timestamp=log.SECONDS)
87-
88-
# Enables the serial mirroring
89-
log.set_mirroring(True)
90-
91-
# Set the timer to log data every 1h20m30s50ms
92-
run_every(h=1, min=20, s=30, ms=50)
93-
94-
while True:
95-
if button_a.is_pressed() and button_b.is_pressed():
96-
log.delete(full=True)
97-
elif button_a.is_pressed():
98-
# Records the temperature & brightness every 00:01:20:30:50 (dd:hh:mm:ss:ms).
99-
log.add({
100-
"temperature": temperature(),
101-
"brightness": display.read_light_level()
102-
})
103-
display.show(Image.HAPPY)
104-
sleep(500)
105-
else:
106-
display.show(Image.CONFUSED)
106+
# Set the timer to log data every 5 seconds
107+
@run_every(s=5)
108+
def log_temp():
109+
log.add(temp=temperature())
110+
111+
An example that runs through all of the functions of the log module API:
112+
113+
.. include:: ../examples/data-logging.py
114+
:code: python

docs/microbit.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ Modules
8989
compass.rst
9090
display.rst
9191
i2c.rst
92-
log.rst
9392
microphone.rst
9493
speaker.rst
9594
spi.rst

examples/data-logging.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from microbit import *
2+
import log
3+
4+
# Configure the labels and select a time unit for the timestamp
5+
log.set_labels('temp', 'brightness', timestamp=log.SECONDS)
6+
7+
# Send each data row to the serial output
8+
log.set_mirroring(True)
9+
10+
# This decorator schedules this function to run every 10s 50ms
11+
@run_every(s=10, ms=50)
12+
def log_data():
13+
"""Log the temperature and light level, and display an icon."""
14+
log.add(temp=temperature(), brightness=display.read_light_level())
15+
display.show(Image.SURPRISED)
16+
sleep(500)
17+
18+
while True:
19+
if button_a.is_pressed() and button_b.is_pressed():
20+
display.show(Image.MEH)
21+
# Delete the log file using the "full" options, which takes
22+
# longer but ensures the data is wiped from the device
23+
log.delete(full=True)
24+
elif button_a.is_pressed():
25+
display.show(Image.HAPPY)
26+
# Log only the light level, the temp entry will be empty
27+
log.add({
28+
"brightness": display.read_light_level()
29+
})
30+
else:
31+
display.show(Image.CONFUSED)
32+
sleep(500)

0 commit comments

Comments
 (0)