Micro::Bit Fitness Tracker Activity
Description
You will have the opportunity to mimic data interception from a fitness tracker using radio signals. After gathering data from your partner, you will be able to interpret and graph the results using simple techniques. From the interpreted data, you will be able to tell what kind of activities your partner is doing.
Features
-
Estimated Time: 1 Hour (base lab) - 4 Hours (Further Exploration)
-
Appropriate Grades: 9-12
-
Topic Alignment: ( Limited, Medium, High )
- GenCyber Cybersecurity First Principles:
GenCyber CFPs Alignment Data Hiding L Least Privilege L Abstraction M Domain Separation L Resource Encapsulation M Simplicity M Modularity H Process Isolation H Layering H Minimization L - GenCyber Cybersecurity Concepts:
GenCyber CCs Alignment Defense in Depth H Confidentiality M Integrity M Availability H Think Like an Adversary H Keep It Simple L
Step 0: The Basics
- Micro::Bit Coding Options
- [Click here to code with JavaScript/Blocks] (https://makecode.microbit.org)
- Click here to code with MicroPython
- Radio Signal Basics
- Serial Basics
- Basic Math Skills
- We will be finding the acceleration in 3 different directions: x, y, and z.
- To find the total acceleration, you need the following equation:
Acceleration = \sqrt{x^2+y^2+z^2}
Step 1: Gather Materials
- Micro::Bit (1 per person / 2 per team)
- Micro-USB Cable
- Battery Pack (Equivalent to two AA batteries)
Step 2: Get Familiar With Fitness Trackers
-
A Fitness tracker will gather data about its surroundings and send it somewhere else to be synthesized. For example, Fitness watches will measure things like heart rate and steps. They will then send that information to your smart phone to be shown to you. We will be making a fitness tracker, that tracks your acceleration. It will send this data to another Micro::Bit that will graph it on the computer using Python. You will be able to see how much someone is moving, based on the graph.
-
Below is code snippet that gets the acceleration and sends it over the radio to the fitTracker receiver
def capture_data():
x_Accel = accelerometer.get_x()
y_Accel = accelerometer.get_y()
z_Accel = accelerometer.get_z()
radio.send(str(x_Accel) + ',' + str(y_Accel) + ',' + str(z_Accel))
Step 3: Download The Files
-
Download (click on) the following file to get started: 05_FitTrack.zip
-
Unzip BeaconLab.zip to your desired folder. For instructions on how to unzip click here
Step 4: Open your editor
-
This base code is also available in the directory that you downloaded as well as this repository. If you don't remember how to open code in your editor, see the instructions here.
-
NOTE: Python must be downloaded on your computer to run serial_reader.py. You can still complete this lab without serial_reader.py with a chrome extension here.
Step 5: Flash the base code
If you don't remember how to flash code to your Micro::Bit, see the instructions here. The base code is also given below. Note that comments are given in the base code to help complete the code.
JavaScript Base Code (Click to Expand)
let X_Accel = 0 let Y_Accel = 0 let Z_Accel = 0 let measuring = false radio.onDataPacketReceived(({ receivedString: name, receivedNumber: value }) => { if (name == "x") { X_Accel = value } else if (name == "y") { // Set the y acceleration to value} else if (name == "z") { // set the z acceleration to value write_data() } else if (name == "done") { serial.writeLine("done") }
}) input.onButtonPressed(Button.AB, () => { radio.sendValue("done", 0) // Set measuring to false
// Show a happy face on the display
}) input.onButtonPressed(Button.A, () => { // Set measuring to true
// Show a heart on the display
}) input.onButtonPressed(Button.B, () => { // Set measuring to false
// Show check mark (yes icon) on the display
}) function capture_data() { X_Accel = input.acceleration(Dimension.X) // Set the y and z accelerations to the y and z dimensions
radio.sendValue("x", X_Accel) // Send y and z values over radio
} function write_data() { serial.writeLine("" + X_Accel + "," + Y_Accel + "," + Z_Accel) } radio.setGroup(1) radio.setTransmitPower(7) basic.showIcon(IconNames.Yes) basic.forever(() => { if (measuring) { capture_data() basic.pause(200) } })
Python Base Code (Click to Expand)
from microbit import * import radioradio.on() radio.config(channel=1) radio.config(power=7) x_Accel = 0
Initialize y and z acceleration
measuring = False display.show(Image.YES)
def capture_data(): x_Accel = accelerometer.get_x() # Get y and z acceleration
radio.send(str(x_Accel) + ',' + str(y_Accel) + ',' + str(z_Accel))
def write_data(): print(x_Accel, y_Accel, z_Accel, sep=',', end='\n')
while True: if button_a.is_pressed() and button_b.is_pressed(): # Set measuring to False
# Send "done" over radio # Show a Happy face on the display (display.show(Image.HAPPY)) elif button_a.is_pressed(): # Set measuring to True # Show a heart on the display (Image.HEART) elif button_b.is_pressed(): # Set measuring to False # Show a checkmark on the display (Image.YES) incoming = radio.receive() if incoming is not None: if incoming.startswith('done'): display.show(Image.HAPPY) print("done") else: x_Accel, y_Accel, z_Accel = incoming.split(",") write_data() if measuring: capture_data() sleep(200) </pre> </details>
Step 6: Programming!
Read through the links under the prerequisite skills section. This will enable you to understand the basics of the lab. You want to be able to answer the following questions:
- If someone sends a message over radio waves, who can access that message?
- What method do you use to send data over radio on a Micro::Bit?
- What method do you use to run a block of code every time data is received?
- How do you find the total acceleration from the x-acceleration, y-acceleration, and z-acceleration?
Complete the code. Specifically:
- In the capture_data function, get the Micro::Bit's x, y, and z acceleration values. One potential solution to this code section can be seen below.
JavaScript Potential Solution (Click to Expand)
function capture_data() { X_Accel = input.acceleration(Dimension.X) Y_Accel = input.acceleration(Dimension.Y) Z_Accel = input.acceleration(Dimension.Z) radio.sendValue("x", X_Accel) radio.sendValue("y", Y_Accel) radio.sendValue("z", Z_Accel) }Python Potential Solution (Click to Expand)
def capture_data(): vals = {'x':0, 'y':0, 'z':0} vals['x'] = accelerometer.get_x() vals['y'] = accelerometer.get_y() vals['z'] = accelerometer.get_z() radio.send("x"+str(x_Accel)) radio.send("y"+str(y_Accel)) radio.send("z"+str(z_Accel))
- When the A button is pressed, add code to set measuring to true and show a heart on the display. One potential solution to this code section can be seen below.
JavaScript Potential Solution (Click to Expand)
input.onButtonPressed(Button.A, () => { measuring = true basic.showIcon(IconNames.Heart) })
Python Potential Solution (Click to Expand)
elif button_a.is_pressed(): measuring = True display.show(Image.HEART)
- When the B button is pressed, add code to set measuring to false and show a check mark on the display. One potential solution to this code section can be seen below.
JavaScript Potential Solution (Click to Expand)
input.onButtonPressed(Button.B, () => { measuring = false basic.showIcon(IconNames.Yes) })
Python Potential Solution (Click to Expand)
elif button_b.is_pressed(): measuring = False display.show(Image.YES)
- When A and B are pressed together, add code to set measuring to false and display a happy face. One potential solution to this code section can be seen below.
JavaScript Potential Solution (Click to Expand)
input.onButtonPressed(Button.AB, () => { measuring = false radio.sendValue("done", 0) basic.showIcon(IconNames.Happy) })
Python Potential Solution (Click to Expand)
if button_a.is_pressed() and button_b.is_pressed(): measuring = False radio.send("done") display.show(Image.HAPPY)
- Finally, send the values over the radio. The final completed code can be seen below.
JavaScript Potential Solution (Click to Expand)
let Z_Accel = 0 let Y_Accel = 0 let X_Accel = 0 let measuring = false radio.onDataPacketReceived( ({ receivedString: name, receivedNumber: value }) => { if (name == "x") { X_Accel = value } else if (name == "y") { Y_Accel = value } else if (name == "z") { Z_Accel = value write_data() } else if (name == "done") { serial.writeLine("done") basic.showIcon(IconNames.Happy) } }) input.onButtonPressed(Button.AB, () => { measuring = false radio.sendValue("done", 0) basic.showIcon(IconNames.Happy) }) input.onButtonPressed(Button.A, () => { measuring = true basic.showIcon(IconNames.Heart) }) input.onButtonPressed(Button.B, () => { measuring = false basic.showIcon(IconNames.Yes) }) function capture_data() { X_Accel = input.acceleration(Dimension.X) Y_Accel = input.acceleration(Dimension.Y) Z_Accel = input.acceleration(Dimension.Z) radio.sendValue("x", X_Accel) radio.sendValue("y", Y_Accel) radio.sendValue("z", Z_Accel) } function write_data() { serial.writeLine("" + X_Accel + "," + Y_Accel + "," + Z_Accel) } radio.setGroup(1) radio.setTransmitPower(7) basic.showIcon(IconNames.Yes) basic.forever(() => { if (measuring) { capture_data() basic.pause(200) } })
Python Potential Solution (Click to Expand)
from microbit import * import radio radio.on() radio.config(group=1) radio.config(power=7) z_Accel = 0 y_Accel = 0 x_Accel = 0 measuring = False display.show(Image.YES) def capture_data(): vals = {'x':0, 'y':0, 'z':0} vals['x'] = accelerometer.get_x() vals['y'] = accelerometer.get_y() vals['z'] = accelerometer.get_z() radio.send("x"+str(x_Accel)) radio.send("y"+str(y_Accel)) radio.send("z"+str(z_Accel)) def write_data(): print(x_Accel, y_Accel, z_Accel, sep=',', end='\n') while True: if button_a.is_pressed() and button_b.is_pressed(): measuring = False radio.send("done") display.show(Image.HAPPY) elif button_a.is_pressed(): measuring = True display.show(Image.HEART) elif button_b.is_pressed(): measuring = False display.show(Image.YES) incoming = radio.receive() if incoming is not None: if incoming.startswith('done'): display.show(Image.HAPPY) print("done") elif incoming.startswith('x'): elif incoming.startswith('y'): elif incoming.startswith('z'): write_data() else: #x_Accel, y_Accel, z_Accel = incoming.split(",") #write_data() if measuring: capture_data() sleep(200)
-
Find a partner that programmed their Micro::Bit in the same language as you (so if you used JavaScript, find someone who also used JavaScript).
-
Begin by choosing who will be the tracker and who will be the hacker. The tracker will be the user of a fitness tracker. They will use their Micro::Bit to collect data about their movements. The other partner, the hacker, will obtain their data.
-
Flash your completed code onto your Micro::Bits.
-
Test your program by analyzing data from your partner. The instructions below will explain how to graph the data. From the graph, the hacker should make a guess about the activities that the tracker was doing (walking, running, jumping, and so on).
-
Double click on serial_reader.py in the code directory (recommended) or use the chrome extension: here. If you are using the chrome extension, launch the application and select the appropriate COM port (if you only have one device plugged in there will only be one option). Select a Baud Rate of 115200 and click on connect.
-
To start gathering data, hit the A button on the fitness tracker and a heart will appear.
-
To stop gathering data, hit the B button on the fitness tracker and the check mark will reappear.
-
When you are done sending data, hit the A and B buttons at the same time to finish and a happy face will appear.
-
If you used serial_reader.py, a graph of the data will automatically plot. If you used the chrome extension, continue to the following steps.
-
Copy and paste the data from chrome to Excel or Google Spreadsheets (select comma-separated when you paste the numbers).
-
Obtain the total acceleration for each row. This is calculated by squaring each value and taking the square root of the sum. In other words, in cell D1, paste this:
=SQRT((A1)^2+(B1)^2+(C1)^2)
-
Click on the bottom right corner of D1 and drag down to the bottom of your data. This will make the same calculation for each row.
-
To graph the data, highlight the D column and click on the graph button. Some adjustments can be made to make the data easier to read, but the default is simply the total acceleration, ideal for showing different activities.
-
Switch hacker and tracker roles and run again. After analyzing the data, have the new hacker make a guess about the activities of the new tracker.
-
Chat with your partner about the issues with wireless data transmission. What are some potential solutions to these problems? Can you think of a simple encryption solution that allows you to mask the data being sent? Can you reverse the encryption to use the data?
-
With your partner, employ a solution in your code. Run the experiment one last time and to see if your solution worked. What worked well in your solution? How could your solution be improved?
Step 7: Further Exploration
-
Can you think of a way to track steps instead of acceleration? Maybe the fitness Tracker could also detect temperature? What else can be deduced from knowing someone's acceleration throughout the day? Spend some time exploring with your Micro::Bit and see what kind of improvements you can make. Try to steal data from other group's fitness Trackers.
-
Are you able to steal fitness data from another group's tracker?
-
What's the problem with sending unencrypted data over radio?
-
What can you do to make it harder to steal your fitness Tracker data
The GenCyber Wyoming COWPOKES program is supported by the National Security Agency and the National Science Foundation through Award #H98230-18-1-0095. Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Science Foundation, the National Security Agency, or the U.S. government.