"""Step 6 - Play a song with flashing lights.

This script is safe. The car does not move.

The numbers are notes.
1=do 2=re 3=mi 4=fa 5=sol 6=la 7=si 8=high do.
A space is a rest.

Run it:
    Windows:  python song.py
    Mac:      python3 song.py

Install bleak first:
    Windows:  python -m pip install bleak
    Mac:      python3 -m pip install bleak

On a Mac, say yes when it asks for Bluetooth.
If you miss it: System Settings > Privacy and Security >
Bluetooth > turn on your Terminal app.
"""
import asyncio

from bleak import BleakClient, BleakScanner

BOX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"

# Twinkle Twinkle Little Star. Change this and make your own song.
SONG = "1155665443322 1"

# Each note gets a colour. So the lights follow the music.
COLOUR = {"1": "G", "2": "J", "3": "H", "4": "K",
          "5": "I", "6": "L", "7": "G", "8": "J"}

BEAT = 0.4          # how long one note lasts
ON = 0.7            # how much of the beat the light stays on


async def say(car, command):
    """Send one command to the robot."""
    await car.write_gatt_char(BOX, command.encode() + b"#", response=False)
    await asyncio.sleep(0.05)


async def find_robot():
    return await BleakScanner.find_device_by_filter(
        lambda d, a: d.name and "micro:bit" in d.name)


async def play(car, song):
    for note in song:
        if note == " ":
            await asyncio.sleep(BEAT)
            continue
        await say(car, note)              # the sound
        await say(car, COLOUR[note])      # the light
        await asyncio.sleep(BEAT * ON)
        await say(car, "M")               # light off
        await asyncio.sleep(BEAT * (1 - ON))


async def main():
    print("Looking for the robot...")
    robot = await find_robot()
    if robot is None:
        print("No robot. Is it on? Is the phone app closed?")
        return
    print("Found it:", robot.name)

    async with BleakClient(robot) as car:
        print("Playing a song.")
        try:
            await play(car, SONG)
        finally:
            await say(car, "M")
            print("Lights off.")

    print("Done.")


asyncio.run(main())
