Skip to content

Commit 2beac09

Browse files
committed
WIP.
0 parents  commit 2beac09

File tree

1 file changed

+368
-0
lines changed

1 file changed

+368
-0
lines changed

clue.py

Lines changed: 368 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,368 @@
1+
import time
2+
import array
3+
import math
4+
import board
5+
import busio
6+
import digitalio
7+
import audiobusio # possibly audiocore or whatever
8+
import neopixel
9+
import adafruit_bmp280
10+
import adafruit_sht31d
11+
import adafruit_apds9960.apds9960
12+
import adafruit_lis3mdl
13+
import adafruit_lsm6ds
14+
import gamepad
15+
16+
class Clue:
17+
def __init__(self):
18+
# Define I2C:
19+
self._i2c = board.I2C()
20+
21+
# Define buttons:
22+
self._a = digitalio.DigitalInOut(board.BUTTON_A)
23+
self._a.switch_to_input(pull=digitalio.Pull.DOWN)
24+
self._b = digitalio.DigitalInOut(board.BUTTON_B)
25+
self._b.switch_to_input(pull=digitalio.Pull.DOWN)
26+
27+
# Define LEDs:
28+
self._white_leds = digitalio.DigitalInOut(board.WHITE_LEDS)
29+
self._white_leds.switch_to_output()
30+
self._pixel = neopixel.NeoPixel(board.NEOPIXEL, 1)
31+
self._red_led = digitalio.DigitalInOut(board.L)
32+
self._red_led.switch_to_output()
33+
34+
# Define audio:
35+
self._mic = audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA,
36+
sample_rate=16000, bit_depth=16)
37+
self._speaker = digitalio.DigitalInOut(board.SPEAKER)
38+
self._speaker.switch_to_output()
39+
self._sample = None
40+
self._samples = None
41+
self._sine_wave = None
42+
self._sine_wave_sample = None
43+
44+
# Define sensors:
45+
# Accelerometer/gyroscope:
46+
self._accelerometer = adafruit_lsm6ds.LSM6DS33(self._i2c)
47+
48+
# Magnetometer:
49+
self._magnetometer = adafruit_lis3mdl.LIS3MDL(self._i2c)
50+
51+
# DGesture/proximity/color/light sensor:
52+
self._sensor = adafruit_apds9960.apds9960.APDS9960(self._i2c)
53+
54+
# Humidity sensor:
55+
self._humidity = adafruit_sht31d.SHT31D(self._i2c)
56+
57+
# Barometric pressure sensor:
58+
self._pressure = adafruit_bmp280.Adafruit_BMP280_I2C(self._i2c)
59+
60+
@property
61+
def button_a(self):
62+
"""``True`` when Button A is pressed. ``False`` if not.
63+
64+
To use with the CLUE:
65+
"""
66+
return self._a.value
67+
68+
@property
69+
def button_b(self):
70+
"""``True`` when Button B is pressed. ``False`` if not.
71+
72+
To use with the CLUE:
73+
"""
74+
return self._b.value
75+
76+
@property
77+
def were_pressed(self):
78+
"""Returns a set of the buttons that have been pressed.
79+
80+
.. image :: ../docs/_static/button_b.jpg
81+
:alt: Button B
82+
83+
To use with the CLUE:
84+
85+
.. code-block:: python
86+
87+
import
88+
89+
while True:
90+
print(.were_pressed)
91+
"""
92+
ret = set()
93+
pressed = self.gamepad.get_pressed()
94+
for button, mask in (('A', 0x01), ('B', 0x02)):
95+
if mask & pressed:
96+
ret.add(button)
97+
return ret
98+
99+
@property
100+
def acceleration(self):
101+
"""Obtain acceleration data from the x, y and z axes.
102+
103+
This example prints the values. Try moving the board to see how the printed values change.
104+
105+
To use with the CLUE:
106+
107+
108+
"""
109+
return self._accelerometer.acceleration
110+
111+
@property
112+
def gyro(self):
113+
"""Obtain x, y, z angular velocity values in degrees/second.
114+
115+
This example prints the values. Try moving the board to see how the printed values change.
116+
117+
To use with the CLUE:
118+
119+
"""
120+
return self._accelerometer.gyro
121+
122+
@property
123+
def magnetic(self):
124+
"""Obtain x, y, z magnetic values in microteslas.
125+
126+
This example prints the values. Try moving the board to see how the printed values change.
127+
128+
To use with the CLUE:
129+
130+
"""
131+
return self._magnetometer.magnetic
132+
133+
@property
134+
def proximity(self):
135+
"""A relative proximity to the sensor in values from 0 - 255.
136+
137+
This example prints the value. Try moving your hand towards and away from the front of the
138+
board to see how the printed values change.
139+
140+
To use with the CLUE:
141+
142+
"""
143+
self._sensor.enable_proximity = True
144+
return self._sensor.proximity()
145+
146+
@property
147+
def color(self):
148+
"""The red, green blue and clear light values. (r, g, b, c)"""
149+
self._sensor.enable_color = True
150+
return self._sensor.color_data
151+
152+
@property
153+
def gesture(self):
154+
"""gesture code if detected. =0 if no gesture detected
155+
=1 if an UP, =2 if a DOWN, =3 if an LEFT, =4 if a RIGHT"""
156+
self._sensor.enable_gesture = True
157+
return self._sensor.gesture()
158+
159+
@property
160+
def humidity(self):
161+
"""The measured relative humidity in percent."""
162+
return self._humidity.relative_humidity
163+
164+
@property
165+
def pressure(self):
166+
"""The barometric pressure in hectoPascals."""
167+
return self._pressure.pressure
168+
169+
@property
170+
def temperature(self):
171+
"""The temperature in degrees Celsius."""
172+
return self._pressure.temperature
173+
174+
@property
175+
def altitude(self):
176+
"""The altitude in meters based on the sea level pressure at your location. You must set
177+
``sea_level_pressure`` to receive an accurate reading."""
178+
return self._pressure.altitude
179+
180+
@property
181+
def sea_level_pressure(self):
182+
"""Set to the pressure at sea level at your location, before reading altitude for
183+
the most accurate altitude measurement.
184+
"""
185+
return self._pressure.sea_level_pressure
186+
187+
@sea_level_pressure.setter
188+
def sea_level_pressure(self, value):
189+
self._pressure.sea_level_pressure = value
190+
191+
@property
192+
def red_led(self):
193+
"""The red led next to the USB plug labeled LED.
194+
"""
195+
return self._red_led.value
196+
197+
@red_led.setter
198+
def red_led(self, value):
199+
self._red_led.value = value
200+
201+
@property
202+
def pixel(self):
203+
return self._pixel
204+
205+
@staticmethod
206+
def _sine_sample(length):
207+
tone_volume = (2 ** 15) - 1
208+
shift = 2 ** 15
209+
for i in range(length):
210+
yield int(tone_volume * math.sin(2*math.pi*(i / length)) + shift)
211+
212+
def _generate_sample(self, length=100):
213+
if self._sample is not None:
214+
return
215+
self._sine_wave = array.array("H", self._sine_sample(length))
216+
self._sample = self.audiopwmio.PWMAudioOut(board.SPEAKER)
217+
self._sine_wave_sample = audiocore.RawSample(self._sine_wave)
218+
219+
def play_tone(self, frequency, duration):
220+
""" Produce a tone using the speaker. Try changing frequency to change
221+
the pitch of the tone.
222+
223+
:param int frequency: The frequency of the tone in Hz
224+
:param float duration: The duration of the tone in seconds
225+
226+
To use with the CLUE:
227+
228+
.. code-block:: python
229+
230+
import
231+
232+
.play_tone(440, 1)
233+
"""
234+
# Play a tone of the specified frequency (hz).
235+
self.start_tone(frequency)
236+
time.sleep(duration)
237+
self.stop_tone()
238+
239+
def start_tone(self, frequency):
240+
""" Produce a tone using the speaker. Try changing frequency to change
241+
the pitch of the tone.
242+
243+
:param int frequency: The frequency of the tone in Hz
244+
245+
To use with the CLUE:
246+
247+
.. code-block:: python
248+
249+
import
250+
251+
while True:
252+
if .button_a:
253+
.start_tone(262)
254+
elif .button_b:
255+
.start_tone(294)
256+
else:
257+
.stop_tone()
258+
"""
259+
self._speaker_enable.value = True
260+
length = 100
261+
if length * frequency > 350000:
262+
length = 350000 // frequency
263+
self._generate_sample(length)
264+
# Start playing a tone of the specified frequency (hz).
265+
self._sine_wave_sample.sample_rate = int(len(self._sine_wave) * frequency)
266+
if not self._sample.playing:
267+
self._sample.play(self._sine_wave_sample, loop=True)
268+
269+
def stop_tone(self):
270+
""" Use with start_tone to stop the tone produced.
271+
272+
To use with the CLUE:
273+
274+
.. code-block:: python
275+
276+
import
277+
278+
while True:
279+
if .button_a:
280+
.start_tone(262)
281+
elif .button_b:
282+
.start_tone(294)
283+
else:
284+
.stop_tone()
285+
"""
286+
# Stop playing any tones.
287+
if self._sample is not None and self._sample.playing:
288+
self._sample.stop()
289+
self._sample.deinit()
290+
self._sample = None
291+
self._speaker_enable.value = False
292+
293+
@staticmethod
294+
def _normalized_rms(values):
295+
mean_values = int(sum(values) / len(values))
296+
return math.sqrt(sum(float(sample - mean_values) * (sample - mean_values)
297+
for sample in values) / len(values))
298+
299+
@property
300+
def sound_level(self):
301+
"""Obtain the sound level from the microphone (sound sensor).
302+
303+
This example prints the sound levels. Try clapping or blowing on
304+
the microphone to see the levels change.
305+
306+
.. code-block:: python
307+
308+
import
309+
310+
while True:
311+
print(.sound_level)
312+
"""
313+
if self._sample is None:
314+
self._samples = array.array('H', [0] * 160)
315+
self._mic.record(self._samples, len(self._samples))
316+
return self._normalized_rms(self._samples)
317+
318+
def loud_sound(self, sound_threshold=200):
319+
"""Utilise a loud sound as an input.
320+
321+
:param int sound_threshold: Threshold sound level must exceed to return true (Default: 200)
322+
323+
.. image :: ../docs/_static/microphone.jpg
324+
:alt: Microphone (sound sensor)
325+
326+
This example turns the NeoPixel LED blue each time you make a loud sound.
327+
Try clapping or blowing onto the microphone to trigger it.
328+
329+
.. code-block:: python
330+
331+
import
332+
333+
while True:
334+
if .loud_sound():
335+
.pixel.fill((0, 50, 0))
336+
else:
337+
.pixel.fill(0)
338+
339+
You may find that the code is not responding how you would like.
340+
If this is the case, you can change the loud sound threshold to
341+
make it more or less responsive. Setting it to a higher number
342+
means it will take a louder sound to trigger. Setting it to a
343+
lower number will take a quieter sound to trigger. The following
344+
example shows the threshold being set to a higher number than
345+
the default.
346+
347+
.. code-block:: python
348+
349+
import
350+
351+
while True:
352+
if .loud_sound(sound_threshold=300):
353+
.pixel.fill((0, 50, 0))
354+
else:
355+
.pixel.fill(0)
356+
"""
357+
358+
return self.sound_level > sound_threshold
359+
360+
clue = Clue()
361+
"""Object that is automatically created on import.
362+
363+
To use, simply import it from the module:
364+
365+
.. code-block:: python
366+
367+
from adafruit_clue.Clue import clue
368+
"""

0 commit comments

Comments
 (0)