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