├── 02-PyBoard └── blink.py ├── 03-BBC_microbit └── blink.py ├── 04-Adafruit_Circuit_Playground └── blink.py ├── 05-ESP8266-32 └── blink.py ├── 07-Visual_Feedback ├── circuit_playground_neopixels_alive.py ├── circuit_playground_pwm_brightness.py ├── microbit_custom_brightness_image.py ├── microbit_happy.py ├── microbit_hello_world.py ├── microbit_image_from_bytearray.py ├── microbit_wopr.py ├── pyboard_lcd_hello_world.py ├── pyboard_lcd_modrian.py ├── pyboard_lcd_snow_crash.py └── pyboard_pwm_brightness.py ├── 08-Input_and_Sensing ├── circuit_playground_audio_record.py ├── circuit_playground_buttons.py ├── circuit_playground_switch.py ├── circuit_playground_touch.py ├── esp8266_button.py ├── microbit_accelerometer_tail.py ├── microbit_compass.py ├── microbit_event_loop.py ├── microbit_gestures.py ├── microbit_touch.py ├── pyboard_switch_callback.py ├── pyboard_switch_loop.py └── pyboard_touch_paint.py ├── 09-GPIO ├── esp8266_interrupt.py └── microbit_uart.py ├── 10-Networking ├── circuit_playground_ir_receive.py ├── circuit_playground_ir_send.py ├── esp8266_mqtt_publish.py ├── esp8266_mqtt_subscribe.py ├── esp8266_star_wars.py ├── esp8266_web_server.py ├── microbit_firefly.py ├── microbit_listener.py ├── microbit_mesh_bathroom.py ├── microbit_mesh_kitchen.py ├── microbit_mesh_lounge.py ├── microbit_radio_hello.py └── pc_listener.py ├── 11-Sound_and_Music ├── circuit_playground_first_bloop.py ├── circuit_playground_frere_jacques.py ├── circuit_playground_metronome.py ├── circuit_playground_play_wav.py ├── circuit_playground_wave_forms.py ├── microbit_beat_box.py ├── microbit_daisy_bell.py ├── microbit_nyan.py ├── microbit_pentatonic_instrument.py ├── microbit_say_hello.py ├── microbit_sing.py ├── microbit_strangled_cat_o_phone.py ├── music.py ├── pyboard_generative_music.py ├── pyboard_whitenoise.py └── sound.wav ├── 12-Robots ├── microbit_racer_controller.py ├── microbit_racer_driver.py └── microbit_trundle_bot.py └── README.rst /02-PyBoard/blink.py: -------------------------------------------------------------------------------- 1 | # Taken from the REPL based example. 2 | import pyb 3 | 4 | 5 | while True: 6 | pyb.LED(1).toggle() 7 | pyb.delay(500) 8 | -------------------------------------------------------------------------------- /03-BBC_microbit/blink.py: -------------------------------------------------------------------------------- 1 | from microbit import display, sleep 2 | 3 | 4 | while True: 5 | display.set_pixel(2, 2, 9) 6 | sleep(500) 7 | display.set_pixel(2, 2, 0) 8 | sleep(500) 9 | -------------------------------------------------------------------------------- /04-Adafruit_Circuit_Playground/blink.py: -------------------------------------------------------------------------------- 1 | # Taken from the REPL based example. 2 | from board import D13 3 | import digitalio 4 | import time 5 | 6 | led = digitalio.DigitalInOut(D13) 7 | led.switch_to_output() 8 | while True: 9 | led.value = not led.value 10 | time.sleep(0.5) 11 | -------------------------------------------------------------------------------- /05-ESP8266-32/blink.py: -------------------------------------------------------------------------------- 1 | # Taken from the REPL based example. 2 | from machine import Pin 3 | import time 4 | 5 | 6 | led = Pin(2, Pin.OUT) 7 | 8 | 9 | while True: 10 | led.value(not led.value()) 11 | time.sleep(0.5) 12 | -------------------------------------------------------------------------------- /07-Visual_Feedback/circuit_playground_neopixels_alive.py: -------------------------------------------------------------------------------- 1 | import neopixel 2 | import random 3 | import time 4 | from board import NEOPIXEL 5 | 6 | 7 | np = neopixel.NeoPixel(NEOPIXEL, 10, auto_write=False) 8 | step = 32 9 | 10 | 11 | while True: 12 | for i in range(10): 13 | for j in range(10): 14 | np[j] = tuple((max(0, val - step) for val in np[j])) 15 | r = random.randint(0, 255) 16 | g = random.randint(0, 255) 17 | b = random.randint(0, 255) 18 | np[i] = (r, g, b) 19 | np.write() 20 | time.sleep(0.05) 21 | -------------------------------------------------------------------------------- /07-Visual_Feedback/circuit_playground_pwm_brightness.py: -------------------------------------------------------------------------------- 1 | # Taken from the REPL based example. 2 | from board import D13 3 | import time 4 | import pulseio 5 | 6 | 7 | pin = pulseio.PWMOut(D13) 8 | 9 | 10 | while True: 11 | for i in range(16): 12 | pin.duty_cycle = 2 ** i 13 | time.sleep(0.1) 14 | -------------------------------------------------------------------------------- /07-Visual_Feedback/microbit_custom_brightness_image.py: -------------------------------------------------------------------------------- 1 | from microbit import display, Image 2 | 3 | 4 | my_picture = Image( 5 | '33333:' 6 | '36663:' 7 | '36963:' 8 | '36663:' 9 | '33333:') 10 | 11 | display.show(my_picture) 12 | -------------------------------------------------------------------------------- /07-Visual_Feedback/microbit_happy.py: -------------------------------------------------------------------------------- 1 | # Taken from the REPL based example. 2 | from microbit import display, Image 3 | 4 | 5 | display.show(Image.HAPPY) 6 | -------------------------------------------------------------------------------- /07-Visual_Feedback/microbit_hello_world.py: -------------------------------------------------------------------------------- 1 | # Taken from the REPL based example 2 | from microbit import display 3 | 4 | 5 | display.scroll("Hello World!", delay=80, wait=False, loop=True, monospace=True) 6 | -------------------------------------------------------------------------------- /07-Visual_Feedback/microbit_image_from_bytearray.py: -------------------------------------------------------------------------------- 1 | from microbit import display, Image 2 | 3 | buf = bytearray(x % 10 for x in range(100)) 4 | i = Image(10, 10, buf) 5 | 6 | display.show(i.crop(3, 4, 5, 5)) 7 | -------------------------------------------------------------------------------- /07-Visual_Feedback/microbit_wopr.py: -------------------------------------------------------------------------------- 1 | from microbit import * 2 | import random 3 | import array 4 | 5 | 6 | def animation(): 7 | blinkenlights = array.array('b', [random.randint(0, 9) for i in range(25)]) 8 | yield Image(5, 5, blinkenlights) 9 | 10 | 11 | while True: 12 | display.show(animation()) 13 | -------------------------------------------------------------------------------- /07-Visual_Feedback/pyboard_lcd_hello_world.py: -------------------------------------------------------------------------------- 1 | import lcd160cr 2 | 3 | 4 | lcd = lcd160cr.LCD160CR('X') 5 | lcd.erase() 6 | lcd.write('Hello, World!') 7 | -------------------------------------------------------------------------------- /07-Visual_Feedback/pyboard_lcd_modrian.py: -------------------------------------------------------------------------------- 1 | import pyb 2 | import lcd160cr 3 | from random import randint, choice, uniform 4 | 5 | 6 | lcd = lcd160cr.LCD160CR('X') 7 | 8 | 9 | MAX_DEPTH = 4 10 | RED = lcd.rgb(255, 0, 0) 11 | YELLOW = lcd.rgb(255, 255, 0) 12 | BLUE = lcd.rgb(0, 0, 255) 13 | WHITE = lcd.rgb(255, 255, 255) 14 | BLACK = lcd.rgb(0, 0, 0) 15 | COLOURS = [RED, YELLOW, BLUE, WHITE, WHITE, WHITE] 16 | 17 | 18 | class Node: 19 | """ 20 | A node in a tree representation of a Mondrian painting. 21 | """ 22 | 23 | def __init__(self, depth=0): 24 | """ 25 | Choose the colour of the rectangle, work out the depth 26 | add child nodes if not too deep. 27 | """ 28 | self.colour = choice(COLOURS) 29 | self.depth = depth + 1 30 | self.children = [] 31 | if self.depth <= MAX_DEPTH: 32 | self.direction = choice(['h', 'v']) 33 | self.divide = uniform(0.1, 0.9) 34 | self.children.append(Node(self.depth)) 35 | self.children.append(Node(self.depth)) 36 | 37 | def draw(self, x, y, w, h): 38 | """ 39 | Recursively draw this node and its children. 40 | """ 41 | lcd.set_pen(BLACK, self.colour) 42 | lcd.rect(x, y, w, h) 43 | if self.children: 44 | if self.direction == 'h': 45 | self.children[0].draw(x, y, int(w * self.divide), h) 46 | self.children[1].draw(x + int(w * self.divide), y, 47 | int(w * (1.0 - self.divide)), h) 48 | else: 49 | self.children[0].draw(x, y, w, int(h * self.divide)) 50 | self.children[1].draw(x, y + int(h * self.divide), w, 51 | int(h * (1.0 - self.divide))) 52 | 53 | 54 | while True: 55 | # Keep re-drawing new Mondrian pictures every few seconds. 56 | tree = Node() 57 | tree.draw(0, 0, lcd.w, lcd.h) 58 | pyb.delay(randint(4000, 8000)) 59 | -------------------------------------------------------------------------------- /07-Visual_Feedback/pyboard_lcd_snow_crash.py: -------------------------------------------------------------------------------- 1 | import lcd160cr 2 | import random 3 | 4 | 5 | lcd = lcd160cr.LCD160CR('X') 6 | lcd.erase() 7 | 8 | 9 | while True: 10 | r = random.randint(0, 255) 11 | g = random.randint(0, 255) 12 | b = random.randint(0, 255) 13 | colour = lcd.rgb(r, g, b) 14 | x = random.randint(0, lcd.w) 15 | y = random.randint(0, lcd.h) 16 | lcd.set_pixel(x, y, colour) 17 | -------------------------------------------------------------------------------- /07-Visual_Feedback/pyboard_pwm_brightness.py: -------------------------------------------------------------------------------- 1 | # Taken from REPL based example. 2 | import pyb 3 | 4 | 5 | blue = pyb.LED(4) 6 | i = 0 7 | while True: 8 | pyb.delay(5) 9 | i += 1 10 | if i > 255: 11 | i = 0 12 | blue.intensity(i) 13 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/circuit_playground_audio_record.py: -------------------------------------------------------------------------------- 1 | import neopixel 2 | import audiobusio 3 | import digitalio 4 | import audioio 5 | import time 6 | from board import * 7 | 8 | 9 | def countdown(np): 10 | """ Uses the NeoPixels to display a countdown.""" 11 | # Start from an "off" state. 12 | np.fill((0, 0, 0)) 13 | np.write() 14 | for i in range(10): 15 | np[i] = (0, 20, 0) 16 | np.write() 17 | time.sleep(0.5) 18 | np.fill((0, 128, 0)) 19 | np.write() 20 | 21 | 22 | def record(): 23 | """ Returns a buffer of recorded sound.""" 24 | buf = bytearray(8000) 25 | with audiobusio.PDMIn(MICROPHONE_CLOCK, MICROPHONE_DATA) as mic: 26 | mic.record(buf, len(buf)) 27 | return buf 28 | 29 | 30 | def play(buf, freq): 31 | """ 32 | Play the referenced buffer of recorded sound at a certain 33 | frequency. 34 | """ 35 | # Set the speaker ready for output. 36 | speaker_enable = digitalio.DigitalInOut(SPEAKER_ENABLE) 37 | speaker_enable.switch_to_output(value = True) 38 | # Play the audio buffer through the speaker. 39 | with audioio.AudioOut(SPEAKER, buf) as speaker: 40 | speaker.frequency = freq 41 | speaker.play() 42 | # Block while the speaker is playing. 43 | while speaker.playing: 44 | pass 45 | 46 | 47 | neopixels = neopixel.NeoPixel(NEOPIXEL, 10, auto_write=False) 48 | button_a = digitalio.DigitalInOut(BUTTON_A) 49 | button_a.pull = digitalio.Pull.DOWN 50 | button_b = digitalio.DigitalInOut(BUTTON_B) 51 | button_b.pull = digitalio.Pull.DOWN 52 | 53 | 54 | countdown(neopixels) 55 | audio_buffer = record() 56 | neopixels.fill((0, 0, 0)) 57 | neopixels.write() 58 | 59 | 60 | freq = 8000 # Default = normal speed. 61 | if button_a.value: 62 | freq = 12000 # Button A = chipmunk. 63 | elif button_b.value: 64 | freq = 6000 # Button B = Barry White. 65 | 66 | 67 | play(audio_buffer, freq) 68 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/circuit_playground_buttons.py: -------------------------------------------------------------------------------- 1 | import neopixel 2 | import time 3 | import digitalio 4 | from board import NEOPIXEL, BUTTON_A, BUTTON_B 5 | 6 | 7 | np = neopixel.NeoPixel(NEOPIXEL, 10, auto_write=False) 8 | button_a = digitalio.DigitalInOut(BUTTON_A) 9 | button_a.pull = digitalio.Pull.DOWN 10 | button_b = digitalio.DigitalInOut(BUTTON_B) 11 | button_b.pull = digitalio.Pull.DOWN 12 | 13 | 14 | clockwise = True 15 | 16 | 17 | while True: 18 | time.sleep(0.05) 19 | if button_a.value: 20 | clockwise = True 21 | elif button_b.value: 22 | clockwise = False 23 | for i in range(10): 24 | if clockwise: 25 | i = 9 - i 26 | for j in range(10): 27 | np[j] = tuple((max(0, val - 64) for val in np[j])) 28 | np[i] = (0, 0, 254) 29 | np.write() 30 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/circuit_playground_switch.py: -------------------------------------------------------------------------------- 1 | import neopixel 2 | import time 3 | import digitalio 4 | from board import NEOPIXEL, SLIDE_SWITCH 5 | 6 | 7 | np = neopixel.NeoPixel(NEOPIXEL, 10, auto_write=False) 8 | switch = digitalio.DigitalInOut(SLIDE_SWITCH) 9 | switch.pull = digitalio.Pull.UP 10 | 11 | 12 | while True: 13 | time.sleep(0.05) 14 | for i in range(10): 15 | if switch.value: 16 | i = 9 - i 17 | for j in range(10): 18 | np[j] = tuple((max(0, val - 64) for val in np[j])) 19 | np[i] = (0, 0, 254) 20 | np.write() 21 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/circuit_playground_touch.py: -------------------------------------------------------------------------------- 1 | import neopixel 2 | import touchio 3 | import digitalio 4 | from board import * 5 | 6 | 7 | # Stops the speaker crackling when touched. 8 | spkr = digitalio.DigitalInOut(SPEAKER_ENABLE) 9 | spkr.switch_to_output() 10 | spkr.value = False 11 | 12 | 13 | np = neopixel.NeoPixel(NEOPIXEL, 10, auto_write=False) 14 | touch_a1 = touchio.TouchIn(A1) 15 | touch_a3 = touchio.TouchIn(A3) 16 | touch_a4 = touchio.TouchIn(A4) 17 | touch_a6 = touchio.TouchIn(A6) 18 | 19 | 20 | while True: 21 | if touch_a4.value: 22 | np[0] = (255, 0, 0) 23 | np[1] = (255, 0, 0) 24 | if touch_a6.value: 25 | np[3] = (0, 255, 0) 26 | np[4] = (0, 255, 0) 27 | if touch_a1.value: 28 | np[5] = (255, 255, 0) 29 | np[6] = (255, 255, 0) 30 | if touch_a3.value: 31 | np[8] = (0, 0, 255) 32 | np[9] = (0, 0, 255) 33 | for j in range(10): 34 | np[j] = tuple((max(0, val - 32) for val in np[j])) 35 | np.write() 36 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/esp8266_button.py: -------------------------------------------------------------------------------- 1 | from machine import Pin 2 | 3 | 4 | led = Pin(2, Pin.OUT) 5 | button = Pin(14, Pin.IN, Pin.PULL_UP) 6 | 7 | 8 | while True: 9 | led.value(button.value()) 10 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/microbit_accelerometer_tail.py: -------------------------------------------------------------------------------- 1 | from microbit import * 2 | 3 | 4 | x = 2 5 | y = 2 6 | sensitivity = 50 7 | pause = 90 8 | fade = 2 9 | 10 | 11 | while True: 12 | roll = accelerometer.get_x() 13 | yaw = accelerometer.get_y() 14 | if roll < -sensitivity: 15 | x = max(0, x - 1) 16 | elif roll > sensitivity: 17 | x = min(4, x + 1) 18 | if yaw < -sensitivity: 19 | y = max(0, y - 1) 20 | elif yaw > sensitivity: 21 | y = min(4, y + 1) 22 | for i in range(5): 23 | for j in range(5): 24 | brightness = max(0, display.get_pixel(i, j) - fade) 25 | display.set_pixel(i, j, brightness) 26 | display.set_pixel(x, y, 9) 27 | sleep(pause) 28 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/microbit_compass.py: -------------------------------------------------------------------------------- 1 | from microbit import * 2 | 3 | 4 | compass.calibrate() 5 | 6 | 7 | while True: 8 | sleep(100) 9 | needle = ((15 - compass.heading()) // 30) % 12 10 | display.show(Image.ALL_CLOCKS[needle]) 11 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/microbit_event_loop.py: -------------------------------------------------------------------------------- 1 | from microbit import * 2 | 3 | 4 | position = 2 5 | 6 | 7 | while True: # event loop 8 | sleep(60) # pause 9 | if button_a.is_pressed(): 10 | display.clear() 11 | position = max(0, position - 1) 12 | elif button_b.is_pressed(): 13 | display.clear() 14 | position = min(4, position + 1) 15 | display.set_pixel(position, 2, 9) 16 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/microbit_gestures.py: -------------------------------------------------------------------------------- 1 | from microbit import * 2 | 3 | 4 | while True: 5 | if accelerometer.was_gesture('shake'): 6 | display.show(Image.ANGRY) 7 | elif accelerometer.was_gesture('face up'): 8 | display.show(Image.ASLEEP) 9 | elif accelerometer.was_gesture('up'): 10 | display.show(Image.HAPPY) 11 | sleep(100) 12 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/microbit_touch.py: -------------------------------------------------------------------------------- 1 | from microbit import display, Image, pin0 2 | 3 | 4 | while True: 5 | display.show(Image.ASLEEP) 6 | if pin0.is_touched(): 7 | display.show(Image.HAPPY) 8 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/pyboard_switch_callback.py: -------------------------------------------------------------------------------- 1 | import pyb 2 | 3 | sw = pyb.Switch() 4 | 5 | 6 | def my_callback(): 7 | pyb.LED(1).toggle() 8 | 9 | 10 | sw.callback(my_callback) 11 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/pyboard_switch_loop.py: -------------------------------------------------------------------------------- 1 | import pyb 2 | 3 | 4 | led = pyb.LED(1) 5 | sw = pyb.Switch() 6 | while True: 7 | pyb.delay(100) 8 | if sw(): 9 | led.toggle() 10 | -------------------------------------------------------------------------------- /08-Input_and_Sensing/pyboard_touch_paint.py: -------------------------------------------------------------------------------- 1 | import lcd160cr 2 | 3 | 4 | lcd = lcd160cr.LCD160CR('X') 5 | lcd.erase() 6 | 7 | 8 | while True: 9 | a, x, y = lcd.get_touch() 10 | if a: 11 | lcd.set_pixel(x, y, lcd.rgb(255, 255, 255)) 12 | -------------------------------------------------------------------------------- /09-GPIO/esp8266_interrupt.py: -------------------------------------------------------------------------------- 1 | from machine import Pin 2 | 3 | 4 | def callback(p): 5 | print('Pin', o) 6 | 7 | 8 | p0 = Pin(0, Pin.IN) 9 | p0.irq(trigger=Pin.IRQ_FALLING, handler=callback) 10 | -------------------------------------------------------------------------------- /09-GPIO/microbit_uart.py: -------------------------------------------------------------------------------- 1 | from microbit import * 2 | 3 | 4 | while True: 5 | msg = uart.read() 6 | if msg: 7 | uart.write(msg) 8 | -------------------------------------------------------------------------------- /10-Networking/circuit_playground_ir_receive.py: -------------------------------------------------------------------------------- 1 | import array 2 | import pulseio 3 | import board 4 | import time 5 | 6 | # A lookup table of morse codes and characters. 7 | MORSE_CODE_LOOKUP = { 8 | ".-": "A", 9 | "-...": "B", 10 | "-.-.": "C", 11 | "-..": "D", 12 | ".": "E", 13 | "..-.": "F", 14 | "--.": "G", 15 | "....": "H", 16 | "..": "I", 17 | ".---": "J", 18 | "-.-": "K", 19 | ".-..": "L", 20 | "--": "M", 21 | "-.": "N", 22 | "---": "O", 23 | ".--.": "P", 24 | "--.-": "Q", 25 | ".-.": "R", 26 | "...": "S", 27 | "-": "T", 28 | "..-": "U", 29 | "...-": "V", 30 | ".--": "W", 31 | "-..-": "X", 32 | "-.--": "Y", 33 | "--..": "Z", 34 | ".----": "1", 35 | "..---": "2", 36 | "...--": "3", 37 | "....-": "4", 38 | ".....": "5", 39 | "-....": "6", 40 | "--...": "7", 41 | "---..": "8", 42 | "----.": "9", 43 | "-----": "0", 44 | } 45 | 46 | 47 | VALID_VALUES = (1000, 2000, 4000, 8000) 48 | 49 | 50 | def normalise(raw): 51 | """ 52 | A generator function that yields normalised items from the raw input. 53 | """ 54 | for val in raw: 55 | rounded_val = round(val/1000) * 1000 56 | if rounded_val in VALID_VALUES: 57 | yield rounded_val 58 | 59 | 60 | def get_character(tokens): 61 | """ 62 | Given a list of tokens (Morse code dahs and dits represented as "-" and 63 | "."), return the related character or "?" if there's no match. 64 | """ 65 | return MORSE_CODE_LOOKUP.get(''.join(tokens), "?") 66 | 67 | 68 | def decode_message(normalised): 69 | """ 70 | Given a source of normalised incoming values, returns a string 71 | representation of the message contained therein. 72 | """ 73 | # Split the incoming normalised values into words, characters and tokens. 74 | words = [] 75 | characters = [] 76 | tokens = [] 77 | for val in normalised: 78 | if val == 8000: 79 | # A new word. 80 | # Store away the old tokens and characters and reset state. 81 | if tokens: 82 | characters.append(get_character(tokens)) 83 | if characters: 84 | words.append(''.join(characters)) 85 | tokens = [] 86 | characters = [] 87 | elif val == 4000: 88 | # A new character. 89 | # Store away and reset the tokens of the previous character. 90 | if tokens: 91 | characters.append(get_character(tokens)) 92 | tokens = [] 93 | elif val == 2000: 94 | # A dah (represented as '-') 95 | tokens.append('-') 96 | elif val == 1000: 97 | # A dit token (represented as '.') 98 | tokens.append('.') 99 | return ' '.join(words).strip() 100 | 101 | 102 | ir_in = pulseio.PulseIn(board.REMOTEIN, maxlen=512, idle_state=False) 103 | 104 | 105 | while True: 106 | while len(ir_in) == 0: 107 | time.sleep(1) 108 | ir_in.pause() 109 | raw = [ir_in[i] for i in range(len(ir_in))] 110 | normalised = normalise(raw) 111 | msg = decode_message(normalised) 112 | if msg: 113 | print(msg) 114 | ir_in.clear() 115 | ir_in.resume() 116 | -------------------------------------------------------------------------------- /10-Networking/circuit_playground_ir_send.py: -------------------------------------------------------------------------------- 1 | import array 2 | import pulseio 3 | import board 4 | 5 | # A lookup table of morse codes and characters. 6 | MORSE_CODE_LOOKUP = { 7 | "A": ".-", 8 | "B": "-...", 9 | "C": "-.-.", 10 | "D": "-..", 11 | "E": ".", 12 | "F": "..-.", 13 | "G": "--.", 14 | "H": "....", 15 | "I": "..", 16 | "J": ".---", 17 | "K": "-.-", 18 | "L": ".-..", 19 | "M": "--", 20 | "N": "-.", 21 | "O": "---", 22 | "P": ".--.", 23 | "Q": "--.-", 24 | "R": ".-.", 25 | "S": "...", 26 | "T": "-", 27 | "U": "..-", 28 | "V": "...-", 29 | "W": ".--", 30 | "X": "-..-", 31 | "Y": "-.--", 32 | "Z": "--..", 33 | "1": ".----", 34 | "2": "..---", 35 | "3": "...--", 36 | "4": "....-", 37 | "5": ".....", 38 | "6": "-....", 39 | "7": "--...", 40 | "8": "---..", 41 | "9": "----.", 42 | "0": "-----", 43 | } 44 | 45 | 46 | def encode_message(msg): 47 | words = msg.split(' ') 48 | message_buffer = [] 49 | for word in words: 50 | message_buffer.extend([8000, 8000, ]) # Indicates a new word. 51 | for character in word: 52 | message_buffer.extend([4000]) # Indicates a new letter. 53 | for val in MORSE_CODE_LOOKUP[character]: 54 | if val == '-': 55 | message_buffer.extend([2000]) # Indicates a dah. 56 | else: 57 | message_buffer.extend([1000]) # Indicates a dit. 58 | if words: 59 | message_buffer.extend([8000, 8000, ]) # Indicates end of message 60 | return array.array('H', message_buffer) 61 | 62 | 63 | ir_led = pulseio.PWMOut(board.REMOTEOUT, frequency=38000, duty_cycle=2**15) 64 | ir_out = pulseio.PulseOut(ir_led) 65 | message = encode_message("HELLO WORLD") 66 | ir_out.send(message) 67 | -------------------------------------------------------------------------------- /10-Networking/esp8266_mqtt_publish.py: -------------------------------------------------------------------------------- 1 | import time 2 | import ubinascii 3 | import machine 4 | from umqtt.simple import MQTTClient 5 | 6 | 7 | button = machine.Pin(0, machine.Pin.IN) 8 | 9 | broker_address = '192.168.1.35' 10 | client_id = 'esp8266_{}'.format(ubinascii.hexlify(machine.unique_id())) 11 | topic = b'button' 12 | 13 | client = MQTTClient(client_id, broker_address) 14 | client.set_last_will(topic, b'dead') 15 | client.connect() 16 | 17 | while True: 18 | while True: 19 | if button.value() == 0: 20 | break 21 | time.sleep_ms(20) 22 | client.publish(topic, b'toggled') 23 | time.sleep_ms(200) 24 | 25 | client.disconnect() 26 | -------------------------------------------------------------------------------- /10-Networking/esp8266_mqtt_subscribe.py: -------------------------------------------------------------------------------- 1 | import time 2 | import ubinascii 3 | import machine 4 | from umqtt.simple import MQTTClient 5 | 6 | 7 | def callback(topic, message): 8 | """ 9 | Received messages are processed by this callback. 10 | """ 11 | print((topic, message)) 12 | 13 | 14 | broker_address = '192.168.1.35' 15 | client_id = 'esp8266_{}'.format(ubinascii.hexlify(machine.unique_id())) 16 | topic = b'button' 17 | 18 | client = MQTTClient(client_id, broker_address) 19 | client.set_callback(callback) 20 | client.connect() 21 | client.subscribe(topic) 22 | 23 | while True: 24 | client.wait_msg() 25 | -------------------------------------------------------------------------------- /10-Networking/esp8266_star_wars.py: -------------------------------------------------------------------------------- 1 | # Taken from the REPL based example. 2 | import socket 3 | 4 | 5 | addr_info = socket.getaddrinfo("towel.blinkenlights.nl", 23) 6 | server_addr = addr_info[0][-1] 7 | s = socket.socket() 8 | s.connect(server_addr) 9 | while True: 10 | data = s.recv(500) 11 | print(str(data, 'utf8'), end='') 12 | -------------------------------------------------------------------------------- /10-Networking/esp8266_web_server.py: -------------------------------------------------------------------------------- 1 | import machine 2 | import socket 3 | import json 4 | 5 | template = """HTTP/1.1 200 OK 6 | Content-Type: application/json 7 | Content-Length: {length} 8 | Server: MicroPython 9 | 10 | {json}""" 11 | 12 | pins = [machine.Pin(i, machine.Pin.IN) for i in (0, 2, 4, 5, 12, 13, 14, 15)] 13 | addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] 14 | 15 | s = socket.socket() 16 | s.bind(addr) 17 | s.listen(1) 18 | 19 | print('listening on', addr) 20 | 21 | while True: 22 | cl, addr = s.accept() 23 | print('client connected from', addr) 24 | cl_file = cl.makefile('rwb', 0) 25 | while True: 26 | line = cl_file.readline() 27 | if not line or line == b'\r\n': 28 | break 29 | status = {str(p): p.value() for p in pins} 30 | data = json.dumps(status) 31 | response = template.format(length=len(data), json=data) 32 | cl.send(response) 33 | cl.close() 34 | -------------------------------------------------------------------------------- /10-Networking/microbit_firefly.py: -------------------------------------------------------------------------------- 1 | import radio 2 | import random 3 | from microbit import display, Image, button_a, sleep 4 | 5 | # Create the "flash" animation frames. Can you work out how it's done? 6 | flash = [Image().invert()*(i/9) for i in range(9, -1, -1)] 7 | 8 | radio.on() 9 | 10 | while True: 11 | # Button A sends a "flash" message. 12 | if button_a.was_pressed(): 13 | radio.send('flash') # a-ha 14 | # Read any incoming messages. 15 | incoming = radio.receive() 16 | if incoming == 'flash': 17 | # If there's an incoming "flash" message display 18 | # the firefly flash animation after a random short 19 | # pause. 20 | sleep(random.randint(50, 350)) 21 | display.show(flash, delay=100, wait=False) 22 | # Randomly re-broadcast the flash message after a 23 | # slight delay. 24 | if random.randint(0, 9) == 0: 25 | sleep(500) 26 | radio.send('flash') # a-ha 27 | -------------------------------------------------------------------------------- /10-Networking/microbit_listener.py: -------------------------------------------------------------------------------- 1 | from microbit import * 2 | import radio 3 | 4 | radio.on() 5 | 6 | while True: 7 | radio_msg = radio.receive_bytes() 8 | if radio_msg: 9 | uart.write(radio_msg) 10 | pc_msg = uart.read() 11 | if pc_msg: 12 | radio.send_bytes(pc_msg) 13 | -------------------------------------------------------------------------------- /10-Networking/microbit_mesh_bathroom.py: -------------------------------------------------------------------------------- 1 | import radio 2 | from microbit import * 3 | 4 | radio.config(length=64) 5 | radio.on() 6 | 7 | device_name = "Bathroom" 8 | 9 | messages = [ 10 | "Need more toilet roll.", 11 | "Run out of soap.", 12 | "Blocked drain.", 13 | "Missing toothbrush.", 14 | "The shower is free.", 15 | "Yes", 16 | "No", 17 | ] 18 | 19 | message_cache = {} 20 | cache_lifetime = 1000 * 5 # 5 seconds 21 | 22 | position = 0 23 | 24 | while True: 25 | sleep(20) 26 | # Sweep and clean the cache of stale messages. 27 | now = running_time() 28 | to_delete = [] 29 | # Sweep. 30 | for key, timestamp in message_cache.items(): 31 | # Check the age of the cached message. 32 | if now > timestamp + cache_lifetime: 33 | to_delete.append(key) 34 | # Clean the cache of out stale messages. 35 | for stale_message in to_delete: 36 | del message_cache[stale_message] 37 | # Cycle through the available messages. 38 | if button_a.was_pressed(): 39 | position += 1 40 | # Skip back to the beginning if we reach the end. 41 | if position == len(messages): 42 | position = 0 43 | # Preview the newly selected message. 44 | display.scroll(messages[position], 50, wait=False) 45 | # Send the currently selected message. 46 | if button_b.was_pressed(): 47 | # Message format is "sender:content". 48 | radio.send('{}:{}'.format(device_name, messages[position])) 49 | # Check for and display incoming message, rebroadcast if required. 50 | msg = radio.receive() 51 | if msg: 52 | if msg not in message_cache: 53 | # This is a new message, so store it in the cache. 54 | message_cache[msg] = running_time() 55 | # Rebroadcast it. 56 | radio.send(msg) 57 | # Display it in a friendly way. 58 | sender, message = msg.split(':') 59 | display.scroll('{} says: {}'.format(sender, message), 50, 60 | wait=False) 61 | -------------------------------------------------------------------------------- /10-Networking/microbit_mesh_kitchen.py: -------------------------------------------------------------------------------- 1 | import radio 2 | from microbit import * 3 | 4 | radio.config(length=64) 5 | radio.on() 6 | 7 | device_name = "Kitchen" 8 | 9 | messages = [ 10 | "Food is ready!", 11 | "Does anyone want a cup of tea?", 12 | "The dishwasher is finished.", 13 | "We need more milk.", 14 | "The table needs setting.", 15 | "Yes", 16 | "No", 17 | ] 18 | 19 | message_cache = {} 20 | cache_lifetime = 1000 * 5 # 5 seconds 21 | 22 | position = 0 23 | 24 | while True: 25 | sleep(20) 26 | # Sweep and clean the cache of stale messages. 27 | now = running_time() 28 | to_delete = [] 29 | # Sweep. 30 | for key, timestamp in message_cache.items(): 31 | # Check the age of the cached message. 32 | if now > timestamp + cache_lifetime: 33 | to_delete.append(key) 34 | # Clean the cache of out stale messages. 35 | for stale_message in to_delete: 36 | del message_cache[stale_message] 37 | # Cycle through the available messages. 38 | if button_a.was_pressed(): 39 | position += 1 40 | # Skip back to the beginning if we reach the end. 41 | if position == len(messages): 42 | position = 0 43 | # Preview the newly selected message. 44 | display.scroll(messages[position], 50, wait=False) 45 | # Send the currently selected message. 46 | if button_b.was_pressed(): 47 | # Message format is "sender:content". 48 | radio.send('{}:{}'.format(device_name, messages[position])) 49 | # Check for and display incoming message, rebroadcast if required. 50 | msg = radio.receive() 51 | if msg: 52 | if msg not in message_cache: 53 | # This is a new message, so store it in the cache. 54 | message_cache[msg] = running_time() 55 | # Rebroadcast it. 56 | radio.send(msg) 57 | # Display it in a friendly way. 58 | sender, message = msg.split(':') 59 | display.scroll('{} says: {}'.format(sender, message), 50, 60 | wait=False) 61 | -------------------------------------------------------------------------------- /10-Networking/microbit_mesh_lounge.py: -------------------------------------------------------------------------------- 1 | import radio 2 | from microbit import * 3 | 4 | radio.config(length=64) 5 | radio.on() 6 | 7 | device_name = "Lounge" 8 | 9 | messages = [ 10 | "TV is free.", 11 | "Need logs for the fireplace.", 12 | "Fireplace needs cleaning.", 13 | "Lovely log fire!", 14 | "Nibbles and snacks available.", 15 | "Yes", 16 | "No", 17 | ] 18 | 19 | message_cache = {} 20 | cache_lifetime = 1000 * 5 # 5 seconds 21 | 22 | position = 0 23 | 24 | while True: 25 | sleep(20) 26 | # Sweep and clean the cache of stale messages. 27 | now = running_time() 28 | to_delete = [] 29 | # Sweep. 30 | for key, timestamp in message_cache.items(): 31 | # Check the age of the cached message. 32 | if now > timestamp + cache_lifetime: 33 | to_delete.append(key) 34 | # Clean the cache of out stale messages. 35 | for stale_message in to_delete: 36 | del message_cache[stale_message] 37 | # Cycle through the available messages. 38 | if button_a.was_pressed(): 39 | position += 1 40 | # Skip back to the beginning if we reach the end. 41 | if position == len(messages): 42 | position = 0 43 | # Preview the newly selected message. 44 | display.scroll(messages[position], 50, wait=False) 45 | # Send the currently selected message. 46 | if button_b.was_pressed(): 47 | # Message format is "sender:content". 48 | radio.send('{}:{}'.format(device_name, messages[position])) 49 | # Check for and display incoming message, rebroadcast if required. 50 | msg = radio.receive() 51 | if msg: 52 | if msg not in message_cache: 53 | # This is a new message, so store it in the cache. 54 | message_cache[msg] = running_time() 55 | # Rebroadcast it. 56 | radio.send(msg) 57 | # Display it in a friendly way. 58 | sender, message = msg.split(':') 59 | display.scroll('{} says: {}'.format(sender, message), 50, 60 | wait=False) 61 | -------------------------------------------------------------------------------- /10-Networking/microbit_radio_hello.py: -------------------------------------------------------------------------------- 1 | from microbit import * 2 | import radio 3 | 4 | 5 | radio.config(channel=42) 6 | radio.on() 7 | 8 | 9 | while True: 10 | sleep(20) 11 | if button_a.was_pressed(): 12 | radio.send("Hello") 13 | msg = radio.receive() 14 | if msg: 15 | display.scroll(msg, 80, wait=False) 16 | -------------------------------------------------------------------------------- /10-Networking/pc_listener.py: -------------------------------------------------------------------------------- 1 | """ 2 | Listen to a connected micro:bit for incoming messages to which you can react 3 | as needs apply. 4 | """ 5 | from serial.tools.list_ports import comports as list_serial_ports 6 | from serial import Serial 7 | 8 | 9 | def find_microbit(): 10 | """ 11 | Finds the port to which the device is connected. 12 | """ 13 | ports = list_serial_ports() 14 | for port in ports: 15 | # Use the vendor and product ID to identify the micro:bit. 16 | if "VID:PID=0D28:0204" in port[2].upper(): 17 | return port[0] 18 | return None 19 | 20 | 21 | def get_serial(): 22 | """ 23 | Detect if a micro:bit is connected and return a serial object to talk to 24 | it. 25 | """ 26 | port = find_microbit() 27 | if port is None: 28 | raise IOError('Could not find micro:bit.') 29 | return Serial(port, 115200, timeout=1, parity='N') 30 | 31 | 32 | serial = get_serial() # create the serial connection to the micro:bit 33 | 34 | 35 | # Keep listening for bytes from the device. If any are received print them. 36 | while True: 37 | msg = serial.read_all() # Remember, msg will be bytes not a string. 38 | if msg: 39 | # At this point you could check the content of msg to react in more 40 | # complicated ways than just printing it. For example, you could use 41 | # serial.write(a_response) to re-broadcast a message from the 42 | # micro:bit. 43 | print(msg) 44 | -------------------------------------------------------------------------------- /11-Sound_and_Music/circuit_playground_first_bloop.py: -------------------------------------------------------------------------------- 1 | import audioio 2 | import array 3 | import time 4 | import digitalio 5 | from board import SPEAKER, SPEAKER_ENABLE 6 | 7 | # Switch on the speaker for output. 8 | speaker_enable = digitalio.DigitalInOut(SPEAKER_ENABLE) 9 | speaker_enable.switch_to_output(value=True) 10 | 11 | duration = 2 12 | length = 8000 // 1760 13 | wave = array.array("H", [0] * length) 14 | wave[0] = int(2 ** 15 - 1) 15 | 16 | with audioio.AudioOut(SPEAKER, wave) as speaker: 17 | speaker.play(loop=True) 18 | time.sleep(duration) 19 | speaker.stop() 20 | -------------------------------------------------------------------------------- /11-Sound_and_Music/circuit_playground_frere_jacques.py: -------------------------------------------------------------------------------- 1 | import audioio 2 | import digitalio 3 | import array 4 | import time 5 | from board import SPEAKER, SPEAKER_ENABLE 6 | 7 | # Switch on the speaker for output. 8 | speaker_enable = digitalio.DigitalInOut(SPEAKER_ENABLE) 9 | speaker_enable.switch_to_output(value=True) 10 | 11 | notes = { 12 | 'b': 493, 13 | 'a#': 466, 14 | 'a': 440, 15 | 'g#': 415, 16 | 'g': 392, 17 | 'f#': 370, 18 | 'f': 347, 19 | 'e': 330, 20 | 'd#': 311, 21 | 'd': 294, 22 | 'c#': 277, 23 | 'c': 262, 24 | } 25 | 26 | 27 | def bloop(pitch, duration): 28 | length = 8000 // pitch 29 | wave = array.array("H", [0] * length) 30 | wave[0] = int(2 ** 16 - 1) 31 | with audioio.AudioOut(SPEAKER, wave) as speaker: 32 | speaker.play(loop=True) 33 | time.sleep(duration - 0.01) 34 | speaker.stop() 35 | time.sleep(0.01) # add articulation silence 36 | 37 | 38 | def play(tune): 39 | for note in tune: 40 | name, duration = note.split(':') 41 | bloop(notes[name], int(duration) / 8) 42 | 43 | line1 = ['c:4', 'd:4', 'e:4', 'c:4'] 44 | line2 = ['e:4', 'f:4', 'g:8'] 45 | line3 = ['g:2', 'a:2', 'g:2', 'f:2', 'e:4', 'c:4'] 46 | line4 = ['c:4', 'g:4', 'c:8'] 47 | frere_jacques = line1 * 2 + line2 * 2 + line3 * 2 + line4 * 2 48 | 49 | play(frere_jacques) 50 | -------------------------------------------------------------------------------- /11-Sound_and_Music/circuit_playground_metronome.py: -------------------------------------------------------------------------------- 1 | import neopixel 2 | import audioio 3 | import digitalio 4 | import array 5 | import time 6 | from board import * 7 | 8 | np = neopixel.NeoPixel(NEOPIXEL, 10) 9 | left = digitalio.DigitalInOut(BUTTON_A) 10 | left.pull = digitalio.Pull.DOWN 11 | right = digitalio.DigitalInOut(BUTTON_B) 12 | right.pull = digitalio.Pull.DOWN 13 | 14 | length = 8000 // 1760 15 | wave = array.array("H", [0] * length) 16 | wave[0] = int(2 ** 16 - 1) 17 | 18 | # Switch on the speaker for output. 19 | speaker_enable = digitalio.DigitalInOut(SPEAKER_ENABLE) 20 | speaker_enable.switch_to_output(value=True) 21 | 22 | speaker = audioio.AudioOut(SPEAKER, wave) 23 | bleep_duration = 0.02 24 | default_tempo = 0.48 25 | tempo = default_tempo 26 | tempo_change = 0.02 27 | 28 | while True: 29 | if left.value and right.value: 30 | tempo = default_tempo 31 | elif left.value: 32 | tempo = min(tempo + tempo_change, 2.98) 33 | elif right.value: 34 | tempo = max(tempo - tempo_change, 0.02) 35 | np.fill((0, 255, 0)) 36 | np.write() 37 | speaker.play(loop=True) 38 | time.sleep(bleep_duration) 39 | speaker.stop() 40 | np.fill((0, 0, 0)) 41 | np.write() 42 | time.sleep(tempo) 43 | -------------------------------------------------------------------------------- /11-Sound_and_Music/circuit_playground_play_wav.py: -------------------------------------------------------------------------------- 1 | import board 2 | import audioio 3 | import digitalio 4 | from board import SPEAKER, SPEAKER_ENABLE 5 | 6 | # Required for CircuitPlayground Express 7 | speaker_enable = digitalio.DigitalInOut(SPEAKER_ENABLE) 8 | speaker_enable.switch_to_output(value=True) 9 | 10 | f = open("sound.wav", "rb") 11 | speaker = audioio.AudioOut(SPEAKER, f) 12 | 13 | speaker.play() 14 | while speaker.playing: 15 | pass # Block 16 | -------------------------------------------------------------------------------- /11-Sound_and_Music/circuit_playground_wave_forms.py: -------------------------------------------------------------------------------- 1 | import audioio 2 | import digitalio 3 | import time 4 | import array 5 | import math 6 | from board import SPEAKER, SPEAKER_ENABLE 7 | 8 | 9 | # Switch on the speaker for output. 10 | speaker_enable = digitalio.DigitalInOut(SPEAKER_ENABLE) 11 | speaker_enable.switch_to_output(value=True) 12 | 13 | length = 8000 // 440 14 | sine = array.array("H", [0] * length) 15 | triangle = array.array("H", [0] * length) 16 | sawtooth = array.array("H", [0] * length) 17 | square = array.array("H", [0] * length) 18 | 19 | 20 | # The waveforms are created here. 21 | for i in range(length): 22 | sine[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15 - 1) + (2 ** 15)) 23 | triangle[i] = abs(int(i * ((2 ** 15 - 1) // length)) - 2 ** 14) 24 | sawtooth[i] = int(i * ((2 ** 15 - 1) // length)) 25 | if i < length // 2: 26 | square[i] = (2 ** 16 -1) 27 | 28 | 29 | # Play each waveform. 30 | print("Sine") 31 | with audioio.AudioOut(SPEAKER, sine) as sample: 32 | sample.play(loop=True) 33 | time.sleep(2) 34 | sample.stop() 35 | 36 | print("Triangle") 37 | with audioio.AudioOut(SPEAKER, triangle) as sample: 38 | sample.play(loop=True) 39 | time.sleep(2) 40 | sample.stop() 41 | 42 | print("Sawtooth") 43 | with audioio.AudioOut(SPEAKER, sawtooth) as sample: 44 | sample.play(loop=True) 45 | time.sleep(2) 46 | sample.stop() 47 | 48 | print("Square") 49 | with audioio.AudioOut(SPEAKER, square) as sample: 50 | sample.play(loop=True) 51 | time.sleep(2) 52 | sample.stop() 53 | -------------------------------------------------------------------------------- /11-Sound_and_Music/microbit_beat_box.py: -------------------------------------------------------------------------------- 1 | import speech 2 | from microbit import sleep, button_a, button_b, display, Image 3 | 4 | gap = 220 # How long a silence should be. 5 | bass_drum = "BUH" # Sound of a beat box bass drum 6 | snare = "CHIXIX" # Sound of a beat box snare 7 | roll = "DGDG" # Sound of a beat box drum roll 8 | rest = "" # Represents a rest of "gap" duration 9 | 10 | # Two sequences (lists) of beats. One beat per line. 11 | beats1 = [ # Mellow 12 | bass_drum, rest, rest, rest, 13 | snare, rest, rest, rest, 14 | bass_drum, bass_drum, bass_drum, rest, 15 | snare, rest, roll, roll, 16 | ] 17 | 18 | beats2 = [ # Hardcore 19 | bass_drum, snare, snare, snare, 20 | bass_drum, snare, roll, roll, 21 | bass_drum, bass_drum, bass_drum, snare, 22 | bass_drum, roll, roll, bass_drum, 23 | ] 24 | 25 | # Play a sound or silence. 26 | def beat_box(sound): 27 | if sound: 28 | display.show(Image.HEART) 29 | sleep(10) 30 | display.clear() 31 | speech.pronounce(sound) 32 | else: 33 | sleep(gap) 34 | 35 | # Play all sounds in "beats" sequence. 36 | def play(beats): 37 | for beat in beats: 38 | beat_box(beat) 39 | 40 | selected = beats1 # Default beat sequence 41 | # Keep on looping over the selected sequence 42 | while True: 43 | # Change sequence with buttons A and B 44 | if button_a.was_pressed(): 45 | selected = beats1 46 | elif button_b.was_pressed(): 47 | selected = beats2 48 | # Finally play the selected sequence 49 | play(selected) 50 | -------------------------------------------------------------------------------- /11-Sound_and_Music/microbit_daisy_bell.py: -------------------------------------------------------------------------------- 1 | import speech 2 | 3 | line1 = [ 4 | '#26DEYYYYYYYYY', 5 | '#31ZIYIYIYIYIYIYIY', 6 | '#39DEYYYYYYYYY', 7 | '#52ZIYIYIYIYIYIYIY', 8 | '#46GIXV', 9 | '#42MIYIY', 10 | '#39YAOW', 11 | '#46AEAEAEN', 12 | '#39SERER', 13 | '#52DUXUXUXUXUXUXUXUXUXUXUXUX'] 14 | 15 | line2 = [ 16 | '#35AYYYYYYMM', 17 | '#26/HAEAEAEAEAEAEF', 18 | '#31KREYYYYYYY', 19 | '#39ZIYIYIYIYIYIYIY', 20 | '#46AXLL', 21 | '#42FAOR', 22 | '#39DHER', 23 | '#35LUHUHUHV', 24 | '#31AXAXV', 25 | '#35YUXUXUXUXUXUXUXUXUXUX'] 26 | 27 | line3 = [ 28 | '#31IHT', 29 | '#29WOWNT', 30 | '#31BIY', 31 | '#35ER', 32 | '#26STAYYYYY', 33 | '#31LIHSH', 34 | '#35MAE', 35 | '#39RIXIXIXIXIXIXIXIXIXIXIXIXIXJ', 36 | '#35AYY', 37 | '#31KAEAEAEAENT', 38 | '#39ER', 39 | '#46FAOAOAORD', 40 | '#39ER', 41 | '#46KAA', 42 | '#52RIXIXIXIXIXIXIXIXIXIXIXIXIXJ'] 43 | 44 | line4 = [ 45 | '#52BUHT', 46 | '#39YUXUXL', 47 | '#31LUXK', 48 | '#35SWIYIYIYIYT', 49 | '#52ER', 50 | '#39PAAAAAAN', 51 | '#31ER', 52 | '#35SIYIYIYT', 53 | '#31UHV', 54 | '#29ER', 55 | '#26BAY', 56 | '#31SIH', 57 | '#39KUXL', 58 | '#35MEYYYYD', 59 | '#52FER', 60 | '#39TUXUXUXUXUXUXUXUXUXUXUX'] 61 | 62 | speech.sing(''.join(line1)) 63 | speech.sing(''.join(line2)) 64 | speech.sing(''.join(line3)) 65 | speech.sing(''.join(line4)) 66 | -------------------------------------------------------------------------------- /11-Sound_and_Music/microbit_nyan.py: -------------------------------------------------------------------------------- 1 | import music 2 | 3 | 4 | music.play(music.NYAN) 5 | -------------------------------------------------------------------------------- /11-Sound_and_Music/microbit_pentatonic_instrument.py: -------------------------------------------------------------------------------- 1 | import music 2 | from microbit import accelerometer 3 | 4 | buckets = [ 5 | 262, # C 6 | 294, # D 7 | 330, # E 8 | 392, # G 9 | 440, # A 10 | ] 11 | 12 | while True: 13 | reading = abs(accelerometer.get_x()) 14 | bucket = min(4, max(0, reading // 200)) # quantize! 15 | music.pitch(buckets[bucket], 20) 16 | -------------------------------------------------------------------------------- /11-Sound_and_Music/microbit_say_hello.py: -------------------------------------------------------------------------------- 1 | import speech 2 | 3 | 4 | speech.say("Hello, World!") 5 | -------------------------------------------------------------------------------- /11-Sound_and_Music/microbit_sing.py: -------------------------------------------------------------------------------- 1 | import speech 2 | 3 | solfa = [ 4 | "#115DOWWWWWW", # Doh 5 | "#103REYYYYYY", # Re 6 | "#94MIYYYYYY", # Mi 7 | "#88FAOAOAOAOR", # Fa 8 | "#78SOHWWWWW", # Soh 9 | "#70LAOAOAOAOR", # La 10 | "#62TIYYYYYY", # Ti 11 | "#58DOWWWWWW", # Doh 12 | ] 13 | song = ''.join(solfa) 14 | speech.sing(song, speed=100) 15 | 16 | -------------------------------------------------------------------------------- /11-Sound_and_Music/microbit_strangled_cat_o_phone.py: -------------------------------------------------------------------------------- 1 | import music 2 | from microbit import accelerometer 3 | 4 | 5 | while True: 6 | music.pitch(accelerometer.get_x(), 20) 7 | -------------------------------------------------------------------------------- /11-Sound_and_Music/music.py: -------------------------------------------------------------------------------- 1 | """ 2 | To be copied as a module onto the Circuit Playground Express board. 3 | """ 4 | import audioio 5 | import digitalio 6 | import array 7 | import time 8 | from board import * 9 | 10 | # Switch on the speaker for output. 11 | speaker_enable = digitalio.DigitalInOut(SPEAKER_ENABLE) 12 | speaker_enable.switch_to_output(value=True) 13 | 14 | def bloop(pitch, duration): 15 | length = 8000 // pitch 16 | wave = array.array("H", [0] * length) 17 | wave[0] = int(2 ** 16 - 1) 18 | with audioio.AudioOut(SPEAKER, wave) as speaker: 19 | speaker.play(loop=True) 20 | time.sleep(duration - 0.01) 21 | speaker.stop() 22 | time.sleep(0.01) # add articulation silence 23 | -------------------------------------------------------------------------------- /11-Sound_and_Music/pyboard_generative_music.py: -------------------------------------------------------------------------------- 1 | import pyb 2 | from pyb import DAC 3 | 4 | 5 | def volume(val): 6 | pyb.I2C(1, pyb.I2C.MASTER).mem_write(val, 46, 0) 7 | 8 | volume(127) 9 | dac = DAC(1) 10 | t = 0 11 | while True: 12 | dac.write(int(t*((t>>9|t>>13)&25&t>>6)) % 256) 13 | #dac.write(int(t*((15&t>>11)%12)&55-(t>>5|t>>12)|t*(t>>10)*32) % 256) 14 | #dac.write(int((t*9&t>>4|t*5&t>>7|t*3&t//1024)-1)) 15 | t += 1 16 | 17 | -------------------------------------------------------------------------------- /11-Sound_and_Music/pyboard_whitenoise.py: -------------------------------------------------------------------------------- 1 | import pyb 2 | import random 3 | from pyb import DAC 4 | 5 | 6 | def volume(val): 7 | pyb.I2C(1, pyb.I2C.MASTER).mem_write(val, 46, 0) 8 | 9 | volume(127) 10 | dac = DAC(1) 11 | while True: 12 | dac.write(random.randint(0, 256)) 13 | -------------------------------------------------------------------------------- /11-Sound_and_Music/sound.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntoll/programming-with-micropython/806a29e90cb999a3c7ccc37a5b08f6d12b2a87a7/11-Sound_and_Music/sound.wav -------------------------------------------------------------------------------- /12-Robots/microbit_racer_controller.py: -------------------------------------------------------------------------------- 1 | from microbit import * 2 | import radio 3 | 4 | 5 | radio.config(channel=44) 6 | radio.on() 7 | 8 | 9 | # Defines the range of valid tilt from accelerometer readings. 10 | max_tilt = 1000 11 | min_tilt = 199 12 | 13 | 14 | while True: 15 | # Grab the inputs. 16 | y = accelerometer.get_y() # Forwards / backwards. 17 | x = accelerometer.get_x() # Left / right. 18 | a = button_a.was_pressed() # Horn. 19 | b = button_b.was_pressed() # Toggle lights. 20 | 21 | # Data from the controller to be sent to the vehicle. 22 | # [speed, steer, buzzer, neopixel] 23 | control_data = [0, 0, 0, 0] 24 | if x < -min_tilt and y < -min_tilt: 25 | # forwards left 26 | display.show(Image.ARROW_NW) 27 | control_data[0] = max(y, -max_tilt) 28 | control_data[1] = max(x, -max_tilt) 29 | elif x < -min_tilt and y > min_tilt: 30 | # backwards left 31 | display.show(Image.ARROW_SW) 32 | control_data[0] = min(y, max_tilt) 33 | control_data[1] = max(x, -max_tilt) 34 | elif x > min_tilt and y < -min_tilt: 35 | # forwards right 36 | display.show(Image.ARROW_NE) 37 | control_data[0] = max(y, -max_tilt) 38 | control_data[1] = min(x, max_tilt) 39 | elif x > min_tilt and y < min_tilt: 40 | # backwards right 41 | display.show(Image.ARROW_SE) 42 | control_data[0] = min(y, max_tilt) 43 | control_data[1] = min(x, max_tilt) 44 | elif y > min_tilt: 45 | # backwards 46 | display.show(Image.ARROW_S) 47 | control_data[0] = min(y, max_tilt) 48 | elif y < -min_tilt: 49 | # forwards 50 | display.show(Image.ARROW_N) 51 | control_data[0] = max(y, -max_tilt) 52 | if a: 53 | # Sound the buzzer 54 | control_data[2] = 1 55 | if b: 56 | # Toggle the NeoPixels 57 | control_data[3] = 1 58 | if any(control_data): 59 | msg = '{}:{}:{}:{}'.format(*control_data) 60 | radio.send(msg) 61 | else: 62 | display.clear() 63 | sleep(20) 64 | -------------------------------------------------------------------------------- /12-Robots/microbit_racer_driver.py: -------------------------------------------------------------------------------- 1 | from microbit import * 2 | import radio 3 | import neopixel 4 | 5 | 6 | display.show(Image.SKULL) # Logo :-) 7 | 8 | colour = (244, 0, 244) # NeoPixel colour to use for lights. 9 | np = neopixel.NeoPixel(pin13, 12) 10 | lights = False 11 | 12 | radio.config(channel=44) 13 | radio.on() 14 | 15 | 16 | def move(speed, steer): 17 | # Sensible defaults that mean "stop". 18 | forward = 0 19 | left = 0 20 | right = 0 21 | if speed > 0: 22 | # Moving forward. 23 | forward = 1 24 | left = 1000 - speed 25 | right = 1000 - speed 26 | elif speed < 0: 27 | # In reverse. 28 | left = 1000 + (-1000 - speed) 29 | right = 1000 + (-1000 - speed) 30 | if steer < 0: 31 | # To the right. 32 | right = min(1000, right + abs(steer)) 33 | left = max(0, left - abs(steer)) 34 | elif steer > 0: 35 | # To the left. 36 | left = min(1000, left + steer) 37 | right = max(0, right - steer) 38 | # Write to the motors. 39 | pin8.write_digital(forward) 40 | pin12.write_digital(forward) 41 | pin0.write_analog(left) 42 | pin1.write_analog(right) 43 | 44 | 45 | while True: 46 | pin14.write_digital(0) # Switch off the horn 47 | try: 48 | msg = radio.receive() 49 | except: 50 | msg = None # Networks are not safe! 51 | if msg is not None: 52 | # Get data from the incoming message. 53 | speed, steer, horn, light = [int(val) for val in msg.split(':')] 54 | move(speed, steer) # Move the robot. 55 | if horn: 56 | # Sound the horn 57 | pin14.write_digital(1) 58 | if light: 59 | # Toggle lights 60 | if lights: 61 | np.clear() 62 | lights = False 63 | else: 64 | lights = True 65 | for i in range(12): 66 | np[i] = colour 67 | np.show() 68 | else: 69 | # No message? Do nothing! 70 | move(0, 0) 71 | sleep(20) 72 | -------------------------------------------------------------------------------- /12-Robots/microbit_trundle_bot.py: -------------------------------------------------------------------------------- 1 | import microbit 2 | 3 | class Servo: 4 | def __init__(self, pin, trim=0): 5 | self.pin = pin 6 | self.trim = trim 7 | self.speed = 0 8 | self.pin.set_analog_period(20) 9 | 10 | def set_speed(self, speed): 11 | self.pin.write_analog(int(25 + 100 * (90 + speed) / 180 + self.trim)) 12 | self.speed = speed 13 | 14 | 15 | class Robot: 16 | def __init__(self): 17 | # Remember to check the trim values. 18 | self.left_servo = Servo(microbit.pin0, 2) 19 | self.right_servo = Servo(microbit.pin1, 1) 20 | 21 | def go(self, distance): 22 | microbit.display.show(microbit.Image.ARROW_S) 23 | self.left_servo.set_speed(-90) 24 | self.right_servo.set_speed(90) 25 | microbit.sleep(int(distance * 2000 / 17)) 26 | self.stop() 27 | 28 | def turn(self, angle): 29 | if angle > 0: 30 | microbit.display.show(microbit.Image.ARROW_E) 31 | self.left_servo.set_speed(-90) 32 | self.right_servo.set_speed(-90) 33 | microbit.sleep(int(angle * 64 / 9)) 34 | else: 35 | microbit.display.show(microbit.Image.ARROW_W) 36 | self.left_servo.set_speed(90) 37 | self.right_servo.set_speed(90) 38 | microbit.sleep(int(-angle * 64 / 9)) 39 | self.stop() 40 | 41 | def stop(self): 42 | microbit.display.show(microbit.Image.DIAMOND) 43 | self.left_servo.set_speed(0) 44 | self.right_servo.set_speed(0) 45 | 46 | def get_distance(self): 47 | return microbit.pin2.read_analog() 48 | 49 | 50 | robot = Robot() 51 | while True: 52 | robot.go(5) 53 | if robot.get_distance() > 700: 54 | robot.turn(20) 55 | left_distance = robot.get_distance() 56 | robot.turn(-40) 57 | right_distance = robot.get_distance() 58 | robot.turn(20) 59 | if left_distance < right_distance: 60 | robot.turn(60) 61 | else: 62 | robot.turn(-60) 63 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Programming With MicroPython 2 | ============================ 3 | 4 | Code samples from the O'Reilly book. 5 | 6 | Each directory contains code examples and scripts from the referenced 7 | chapters. Code samples use the device name and a small description to identify 8 | them. 9 | 10 | These scripts work as of 12th September 2017. MicroPython is a fast moving 11 | target and if you get errors it's probably because the API has moved on since 12 | the book was published. Don't worry! This is a fun challenge for you to 13 | learn something by correcting the script. 14 | 15 | Another reason things may not work is because of hardware failure. 16 | 17 | Most importantly, have fun..! 18 | 19 | Best wishes, 20 | 21 | Nicholas. 22 | --------------------------------------------------------------------------------