PragmaticPhil
Published © GPL3+

Data Capturing with micro:bit, XinaBox and IoT

Capture accelerometer data remotely on a BBC micro:bit, then use the XinaBox Wi-Fi gateway to transfer the data to an IoT platform.

EasyFull instructions provided30 minutes311
Data Capturing with micro:bit, XinaBox and IoT

Things used in this project

Hardware components

IP01
XinaBox IP01
An interface module equipped to power and program other modules via a USB A connector.
×1
CW01
XinaBox CW01
Wi-Fi Core (ESP8266/ESP-12F)
×1
BM01
XinaBox BM01
A bridge to connect your XinaBox xChips to a micro:bit
×1
XC10
XinaBox XC10
This SKU is a 10 pack - we only need 2 for this project, although I use 3. These are standard uBus connectors.
×1
BBC micro:bit board
BBC micro:bit board
You need 1 to act as a gateway then 1 or more others to send data to the gateway
×1

Software apps and online services

Ubidots
Ubidots
You will need an IoT platform - I use UbiDots with a free 30 day trial account in this blog

Story

Read more

Code

Catch_Collector_Simple

MicroPython
This code collects 120 accelerometer readings (using the 'Simple' method) and transmits them to our gateway
from microbit import *
import radio
radio.on()
radio.config(length=16, queue=64, channel=11, power=6)

accReadingList = []             #   This is a list - we will add each accelerometer reading we take to this list.
totalNumberOfReadings = 120     #   The code is limited to 150 data points - a few more is possible but there is an upper limit
numberOfReadings = 0            #   I don't use a loop to do the 150 readings, so I count how many we've done and stop at 150

readingFrequencyInMS = 25

startingTime = 0                #   We time how long it takes (although this is a factor of totalNumberOfReadings and our sampling period)
duration = 0

recordData = False             #   This is a switch we set to True when we are reading accelerometer data


def countDownValue(currentCount):       #   Just a little countdown to prepare the user for when the micro:bit begins measuring data.
    display.show(str(currentCount))
    sleep(1000)


def getAccelerometerReading(readingFrequencyInMS):
    sleep(readingFrequencyInMS)
    return accelerometer.get_y()


while True:
    if(button_a.was_pressed()):         #   Initiate the process of reading data
        countDownValue(3)
        countDownValue(2)
        countDownValue(1)
        display.show(".")
        recordData  = True
        startingTime = running_time()

    if(recordData):                                         #   True until we collect totalNumberOfReadings data points
        accReadingList.append(str(getAccelerometerReading(readingFrequencyInMS)))
        numberOfReadings += 1

    if((numberOfReadings >= totalNumberOfReadings) and recordData):    #   for 1 cycle after totalNumberOfReadings readings have been taken this switch is True
        recordData = False
        duration = running_time() - startingTime
        display.show(Image.DIAMOND)

    if(button_b.was_pressed()):
        display.show(Image.YES)
        radio.send("0_a" + str(duration))

        for i in range(0, totalNumberOfReadings - 1):
            if( (i >0) and (i % 50) == 0):
                display.show(Image.SQUARE_SMALL)
                sleep(7500)

            radio.send("0_c" + str(accReadingList[i]))
            display.show(Image.YES)
            sleep(100)

Catch_Collector_Advanced

MicroPython
This code collects 120 accelerometer readings (using the 'Advanced' method) and transmits them to our gateway
from microbit import *
import radio
radio.on()
radio.config(length=16, queue=64, channel=11, power=6)

accReadingList = []             #   This is a list - we will add each accelerometer reading we take to this list.
totalNumberOfReadings = 120     #   The code is limited to 150 data points - a few more is possible but there is an upper limit
numberOfReadings = 0            #   I don't use a loop to do the 150 readings, so I count how many we've done and stop at 150

readingFrequencyInMS = 25

startingTime = 0                #   We time how long it takes (although this is a factor of totalNumberOfReadings and our sampling period)
duration = 0

recordData = False             #   This is a switch we set to True when we are reading accelerometer data


def countDownValue(currentCount):       #   Just a little countdown to prepare the user for when the micro:bit begins measuring data.
    display.show(str(currentCount))
    sleep(1000)


def getAccelerometerReading(readingFrequencyInMS):
    loopStart = running_time()  #   record the time now, so we can stop the loop below after 25ms
    accSmoothReading = 0        #   we'll use this to find the sum of all readings during our 25ms
    accSmoothReadings = 0       #   and we count how many readings we are able to make.

    while(  (loopStart + readingFrequencyInMS -1) > running_time() ):   #   we stay in this loop for readingFrequencyInMS ms
        accSmoothReading += accelerometer.get_y()                       #   we add the accelerometer readings during this period
        accSmoothReadings += 1                                          #   and we record the number of readings we are able to make.

    if(accSmoothReadings > 0):                                      #   Unlikely we need this, but it means no risk of dividing by zero below.
        return (accSmoothReading / accSmoothReadings)

    return 0


while True:
    if(button_a.was_pressed()):         #   Initiate the process of reading data
        countDownValue(3)
        countDownValue(2)
        countDownValue(1)
        display.show(".")
        recordData  = True
        startingTime = running_time()

    if(recordData):                                         #   True until we collect totalNumberOfReadings data points
        accReadingList.append(str(getAccelerometerReading(readingFrequencyInMS)))
        numberOfReadings += 1

    if((numberOfReadings >= totalNumberOfReadings) and recordData):    #   for 1 cycle after totalNumberOfReadings readings have been taken this switch is True
        recordData = False
        duration = running_time() - startingTime
        display.show(Image.DIAMOND)

    if(button_b.was_pressed()):
        display.show(Image.YES)
        radio.send("0_a" + str(duration))

        for i in range(0, totalNumberOfReadings - 1):
            if( (i >0) and (i % 50) == 0):
                display.show(Image.SQUARE_SMALL)
                sleep(7500)

            radio.send("0_c" + str(accReadingList[i]))
            display.show(Image.YES)
            sleep(100)

Catch_Gateway

MicroPython
Code for the micro:bit gateway
from microbit import *
import radio
radio.on()
radio.config(length=16, queue=64, channel=11, power=6)
#   NOTE: radio settings are identical to those in the classroomMicrobit.py code.  Long queue is necessary as we process each slowly

uart.init(baudrate=9600, bits=8, parity=None, stop=1, tx=pin20, rx=pin19)
# NOTE: gets the uart (serial / USB) port on the micro:bit ready to communicate with the CW01


def sendMessageToCW01(parm, pauseLength):
    display.clear()
    uart.write(parm)
    sleep(pauseLength)
    data = uart.readline()
    while(data is None):
        data = uart.readline()

    if(len(str(data)) >0):
        uartMessageID = getIntegerFromString(data[:1])
        if(uartMessageID == 1):     display.show(Image.YES)     # NOTE: a tick is displayed when data is being transmitted correctly to the CW01
        else:                       display.show(Image.NO)      # NOTE: this means that a cross is displayed when an attempt to send data fails

    sleep(pauseLength)


def processRadioSignal(radioSignal):
    global testMode

    if(len(str(radioSignal)) < 4):   return False                       #   NOTE: valid radio signals are at least 3 or more characters long

    locationOfUnderscore = getLocationOfUnderscore(radioSignal)
    if(locationOfUnderscore == -1): return False                        #   NOTE: valid radio signals contain an underscore

    currentMicrobitID = getIntegerFromString(radioSignal[0:locationOfUnderscore])
    if(currentMicrobitID < 0):    return False                          #   NOTE: valid radio messages begin with an integer starting at 0.
    if(currentMicrobitID > 9): return False                             #   NOTE: IDs should go from 0 to 9

    #   NOTE: If we've reached this point of the code the radioSignal has passed all our validation checks.  It is 'safe' to process it.
    return sendValidMessageToCW01(radioSignal, locationOfUnderscore)

def sendValidMessageToCW01(radioSignal, locationOfUnderscore):
    messageType = str(radioSignal[locationOfUnderscore +1 : locationOfUnderscore +2])

    if(messageType == "a"):
        sendMessageToCW01("+4@YOURMICROBIT@duration@" + getValueFromRadioSignal(radioSignal, locationOfUnderscore) + "$", 250)
        return True

    if(messageType == "b"):
        sendMessageToCW01("+4@YOURMICROBIT@speed@" + getValueFromRadioSignal(radioSignal, locationOfUnderscore) + "$", 250)
        return True

    if(messageType == "c"):
        sendMessageToCW01("+4@YOURMICROBIT@AccReading@" + getValueFromRadioSignal(radioSignal, locationOfUnderscore) + "$", 250)
        return True

    return False


def getLocationOfUnderscore(radioSignal):
    #   NOTE: The underscore can only be in 1 of 2 places in the string, so KISS:
    radioSignalStr = str(radioSignal)
    if(radioSignalStr[1:2] == "_"):    return 1
    if(radioSignalStr[2:3] == "_"):    return 2
    return -1


def getIntegerFromString(uncheckedString):
    try: return int(uncheckedString)
    except ValueError: return -1


def getValueFromRadioSignal(radioSignal, locationOfUnderscore):
    #display.show(str(radioSignal[locationOfUnderscore +2 : len(radioSignal)]))
    try: return str(radioSignal[locationOfUnderscore +2 : len(radioSignal)])
    except: return "0"

#   INIT:

display.show(Image.SQUARE)          # NOTE: the square is shown on your micro:bit while it is connecting to Ubidots
sleep(2000)
uart.write("$")                     # NOTE: Cleans out the serial buffer
sleep(100)
uart.write("+9@?$")                 # NOTE: Reboots the CW01
sleep(5000)                         # NOTE: long delay is necessary - we need to give Wi-Fi time to sort itself out.
uart.write("$")                     # NOTE: Clean out Serial buffer, again.
sleep(500)


#sendMessageToCW01("+1@WIFINAME@WIFIPASSWORD$")
# EDIT GUIDELINES: you MUST enter the name and password of the Wi-Fi network you are trying to connect to in the line above.

#sendMessageToCW01("+2@DEFAULTTOKEN@?$")
# EDIT GUIDELINES: you MUST enter the DEFAULT TOKEN from Ubidots in the line above.

sendMessageToCW01("+3@things.ubidots.com@1883$", 750)
# NOTE: above line tells the micro;bit where to send the data to - its a Ubidots URL.


while True:
    if(processRadioSignal(radio.receive())):
        display.show(Image.HAPPY)
    else:
        display.show(Image.SAD)

    sleep(50)

Credits

PragmaticPhil

PragmaticPhil

5 projects • 7 followers
Hobbyist + EdTech consultant

Comments