Skip to content
This repository has been archived by the owner on Dec 23, 2021. It is now read-only.

Commit

Permalink
first commit for sensors
Browse files Browse the repository at this point in the history
  • Loading branch information
Vandy Liu committed Feb 10, 2020
1 parent 6b38fcc commit 8dc2aee
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 6 deletions.
10 changes: 9 additions & 1 deletion src/microbit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
button_a = __mb.button_a
button_b = __mb.button_b
display = __mb.display
accelerometer = __mb.accelerometer


def sleep(n):
Expand All @@ -21,4 +22,11 @@ def running_time():
Return the number of milliseconds since the board was switched on or
restarted.
"""
__mb.running_time()
return __mb.running_time()


def temperature():
"""
Return the temperature of the micro:bit in degrees Celcius.
"""
return __mb.temperature()
120 changes: 120 additions & 0 deletions src/microbit/__model/accelerometer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import enum

from . import constants as CONSTANTS


class Accelerometer:
def __init__(self):
self.__x = 0
self.__y = 0
self.__z = 0
self.__current_gesture = ""
self.__prev_gestures = set()
self.__gestures = []

def get_x(self):
"""
Get the acceleration measurement in the ``x`` axis, as a positive or
negative integer, depending on the direction. The measurement is given in
milli-g.
"""
return self.__x

def get_y(self):
"""
Get the acceleration measurement in the ``y`` axis, as a positive or
negative integer, depending on the direction. The measurement is given in
milli-g.
"""
return self.__y

def get_z(self):
"""
Get the acceleration measurement in the ``z`` axis, as a positive or
negative integer, depending on the direction. The measurement is given in
milli-g.
"""
return self.__z

def get_values(self):
"""
Get the acceleration measurements in all axes at once, as a three-element
tuple of integers ordered as X, Y, Z.
"""
return (self.__x, self.__y, self.__z)

def current_gesture(self):
"""
Return the name of the current gesture.
"""
self.__add_current_gesture_to_gesture_lists()
return self.__current_gesture

def is_gesture(self, name):
"""
Return True or False to indicate if the named gesture is currently active.
"""
self.__add_current_gesture_to_gesture_lists()
if name not in CONSTANTS.GESTURES:
raise ValueError(CONSTANTS.INVALID_GESTURE_ERR)
return name == self.__current_gesture

def was_gesture(self, name):
"""
Return True or False to indicate if the named gesture was active since the
last call.
"""
self.__add_current_gesture_to_gesture_lists()
if name not in CONSTANTS.GESTURES:
raise ValueError(CONSTANTS.INVALID_GESTURE_ERR)
was_gesture = name in self.__prev_gestures
self.__prev_gestures.clear()
return was_gesture

def get_gestures(self):
"""
Return a tuple of the gesture history. The most recent is listed last.
Also clears the gesture history before returning.
"""
self.__add_current_gesture_to_gesture_lists()
gestures = tuple(self.__gestures)
self.__gestures.clear()
return gestures

# Helpers and Hidden Functions

def __set_x(self, x):
self.__x = self.__get_valid_acceleration(x)

def __set_y(self, y):
self.__y = self.__get_valid_acceleration(y)

def __set_z(self, z):
self.__z = self.__get_valid_acceleration(z)

def __get_valid_acceleration(self, acceleration):
if acceleration < CONSTANTS.MIN_ACCELERATION:
return CONSTANTS.MIN_ACCELERATION
elif acceleration > CONSTANTS.MAX_ACCELERATION:
return CONSTANTS.MAX_ACCELERATION
else:
return acceleration

def __get_accel(self, axis):
if axis == "x":
return self.get_x()
elif axis == "y":
return self.get_y()
elif axis == "z":
return self.get_z()

def __set_gesture(self, gesture):
if gesture in CONSTANTS.GESTURES:
self.__current_gesture = gesture
else:
self.__current_gesture = ""

def __add_current_gesture_to_gesture_lists(self):
if self.__current_gesture in CONSTANTS.GESTURES:
self.__gestures.append(self.__current_gesture)
self.__prev_gestures.add(self.__current_gesture)
25 changes: 25 additions & 0 deletions src/microbit/__model/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,30 @@
BRIGHTNESS_MIN = 0
BRIGHTNESS_MAX = 9

# sensor max/min values
MAX_TEMPERATURE = 125
MIN_TEMPERATURE = -55
MAX_LIGHT_LEVEL = 255
MIN_LIGHT_LEVEL = 0
MAX_ACCELERATION = 1023
MIN_ACCELERATION = -1023

GESTURES = set(
[
"up",
"down",
"left",
"right",
"face up",
"face down",
"freefall",
"3g",
"6g",
"8g",
"shake",
]
)

# error messages
BRIGHTNESS_ERR = "brightness out of bounds"
COPY_ERR_MESSAGE = "please call copy function first"
Expand All @@ -120,5 +144,6 @@
NOT_IMPLEMENTED_ERROR = "This method is not implemented by the simulator"
UNSUPPORTED_ADD_TYPE = "unsupported types for __add__:"
SAME_SIZE_ERR = "images must be the same size"
INVALID_GESTURE_ERR = "invalid gesture"

TIME_DELAY = 0.03
15 changes: 11 additions & 4 deletions src/microbit/__model/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ class Display:
def __init__(self):
self.__image = Image()
self.__on = True
self.__current_pid = None
self.__light_level = 0
self.__blank_image = Image()

self.__current_pid = None
self.__lock = threading.Lock()

def scroll(self, value, delay=150, wait=True, loop=False, monospace=False):
Expand Down Expand Up @@ -226,13 +227,19 @@ def is_on(self):

def read_light_level(self):
"""
Not implemented yet.
Use the display's LEDs in reverse-bias mode to sense the amount of light
falling on the display. Returns an integer between 0 and 255 representing
the light level, with larger meaning more light.
"""
raise NotImplementedError(CONSTANTS.NOT_IMPLEMENTED_ERROR)
return self.__light_level

def __set_light_level(self, level):
if level < CONSTANTS.MIN_LIGHT_LEVEL:
self.__light_level = CONSTANTS.MIN_LIGHT_LEVEL
elif level > CONSTANTS.MAX_LIGHT_LEVEL:
self.__light_level = CONSTANTS.MAX_LIGHT_LEVEL
else:
self.__light_level = level

# Helpers

Expand Down
18 changes: 17 additions & 1 deletion src/microbit/__model/microbit_model.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
import time

from .accelerometer import Accelerometer
from .button import Button
from .display import Display
from . import constants as CONSTANTS


class MicrobitModel:
def __init__(self):
# State in the Python process
self.accelerometer = Accelerometer()
self.button_a = Button()
self.button_b = Button()
self.__start_time = time.time()
self.display = Display()

self.__start_time = time.time()
self.__temperature = 0

def sleep(self, n):
time.sleep(n / 1000)

def running_time(self):
print(f"time. time: {time.time()}")
return time.time() - self.__start_time

def temperature(self):
return self.__temperature

def __set_temperature(self, temperature):
if temperature < CONSTANTS.MIN_TEMPERATURE:
self.__temperature = CONSTANTS.MIN_TEMPERATURE
elif temperature > CONSTANTS.MAX_TEMPERATURE:
self.__temperature = CONSTANTS.MAX_TEMPERATURE
else:
self.__temperature = temperature


__mb = MicrobitModel()
95 changes: 95 additions & 0 deletions src/microbit/test/test_accelerometer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import pytest
from unittest import mock

from ..__model import constants as CONSTANTS
from ..__model.accelerometer import Accelerometer


class TestAccelerometer(object):
def setup_method(self):
self.accelerometer = Accelerometer()

@pytest.mark.parametrize(
"accel, expected",
[
(CONSTANTS.MIN_ACCELERATION - 10, CONSTANTS.MIN_ACCELERATION),
(CONSTANTS.MIN_ACCELERATION, CONSTANTS.MIN_ACCELERATION),
(100, 100),
(CONSTANTS.MAX_ACCELERATION, CONSTANTS.MAX_ACCELERATION),
(CONSTANTS.MAX_ACCELERATION + 1, CONSTANTS.MAX_ACCELERATION),
],
)
def test_x_y_z(self, accel, expected):
self.accelerometer._Accelerometer__set_x(accel)
assert expected == self.accelerometer.get_x()
self.accelerometer._Accelerometer__set_y(accel)
assert expected == self.accelerometer.get_y()
self.accelerometer._Accelerometer__set_z(accel)
assert expected == self.accelerometer.get_z()

@pytest.mark.parametrize(
"accels, expected",
[
((23, 25, 26), (23, 25, 26)),
((204, 234, -534), (204, 234, -534)),
(
(CONSTANTS.MIN_ACCELERATION - 10, 234, CONSTANTS.MAX_ACCELERATION),
(CONSTANTS.MIN_ACCELERATION, 234, CONSTANTS.MAX_ACCELERATION),
),
],
)
def test_get_values(self, accels, expected):
self.accelerometer._Accelerometer__set_x(accels[0])
self.accelerometer._Accelerometer__set_y(accels[1])
self.accelerometer._Accelerometer__set_z(accels[2])
assert expected == self.accelerometer.get_values()

@pytest.mark.parametrize("gesture", ["up", "face down", "freefall", "8g"])
def test_current_gesture(self, gesture):
self.accelerometer._Accelerometer__set_gesture(gesture)
assert gesture == self.accelerometer.current_gesture()

@pytest.mark.parametrize("gesture", ["up", "face down", "freefall", "8g"])
def test_is_gesture(self, gesture):
self.accelerometer._Accelerometer__set_gesture(gesture)
assert self.accelerometer.is_gesture(gesture)
for g in CONSTANTS.GESTURES:
if g != gesture:
assert not self.accelerometer.is_gesture(g)

def test_is_gesture_error(self):
with pytest.raises(ValueError):
self.accelerometer.is_gesture("sideways")

def test_was_gesture(self):
mock_gesture_up = "up"
mock_gesture_down = "down"

assert not self.accelerometer.was_gesture(mock_gesture_up)
self.accelerometer._Accelerometer__set_gesture(mock_gesture_up)
self.accelerometer.current_gesture() # Call is needed for gesture detection so it can be added to the lists.
self.accelerometer._Accelerometer__set_gesture("")
assert self.accelerometer.was_gesture(mock_gesture_up)
assert not self.accelerometer.was_gesture(mock_gesture_up)

def test_was_gesture_error(self):
with pytest.raises(ValueError):
self.accelerometer.was_gesture("sideways")

def test_get_gestures(self):
mock_gesture_up = "up"
mock_gesture_down = "down"
mock_gesture_freefall = "freefall"
self.accelerometer._Accelerometer__set_gesture(mock_gesture_up)
self.accelerometer.current_gesture() # Call is needed for gesture detection so it can be added to the lists.
self.accelerometer._Accelerometer__set_gesture(mock_gesture_down)
self.accelerometer.current_gesture()
self.accelerometer._Accelerometer__set_gesture(mock_gesture_freefall)
self.accelerometer.current_gesture()
self.accelerometer._Accelerometer__set_gesture("")
assert (
mock_gesture_up,
mock_gesture_down,
mock_gesture_freefall,
) == self.accelerometer.get_gestures()
assert () == self.accelerometer.get_gestures()
14 changes: 14 additions & 0 deletions src/microbit/test/test_display.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,20 @@ def test_async_tests(self):
self.display.show("6", delay=0)
assert Image._Image__same_image(Image(STR_SIX), self.display._Display__image)

@pytest.mark.parametrize(
"light_level, expected",
[
(CONSTANTS.MIN_LIGHT_LEVEL - 10, CONSTANTS.MIN_LIGHT_LEVEL),
(CONSTANTS.MIN_LIGHT_LEVEL, CONSTANTS.MIN_LIGHT_LEVEL),
(100, 100),
(CONSTANTS.MAX_LIGHT_LEVEL, CONSTANTS.MAX_LIGHT_LEVEL),
(CONSTANTS.MAX_LIGHT_LEVEL + 10, CONSTANTS.MAX_LIGHT_LEVEL),
],
)
def test_temperature(self, light_level, expected):
self.display._Display__set_light_level(light_level)
assert expected == self.display.read_light_level()

# Helpers
def __is_clear(self):
i = Image(CONSTANTS.BLANK_5X5)
Expand Down
15 changes: 15 additions & 0 deletions src/microbit/test/test_microbit_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
from unittest import mock
from ..__model.microbit_model import MicrobitModel
from ..__model import constants as CONSTANTS


class TestMicrobitModel(object):
Expand All @@ -24,3 +25,17 @@ def test_running_time(self):
assert mock_end_time - mock_start_time == pytest.approx(
self.__mb.running_time()
)

@pytest.mark.parametrize(
"temperature, expected",
[
(CONSTANTS.MIN_TEMPERATURE - 10, CONSTANTS.MIN_TEMPERATURE),
(CONSTANTS.MIN_TEMPERATURE, CONSTANTS.MIN_TEMPERATURE),
(0, 0),
(CONSTANTS.MAX_TEMPERATURE, CONSTANTS.MAX_TEMPERATURE),
(CONSTANTS.MAX_TEMPERATURE + 5, CONSTANTS.MAX_TEMPERATURE),
],
)
def test_temperature(self, temperature, expected):
self.__mb._MicrobitModel__set_temperature(temperature)
assert expected == self.__mb.temperature()
Loading

0 comments on commit 8dc2aee

Please sign in to comment.