"""Step 7 - The whole program.

It finds the car. It plays a song with lights.
Then it drives a circle. Then it stops.

WARNING: the car MOVES. Put it on the floor first.

Run it:
    Windows:  python robot.py
    Mac:      python3 robot.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"

SONG = "1155665443322 1"
COLOUR = {"1": "G", "2": "J", "3": "H", "4": "K",
          "5": "I", "6": "L", "7": "G", "8": "J"}


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 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:
        try:
            print("Playing a song.")
            for note in SONG:
                if note == " ":
                    await asyncio.sleep(0.4)
                    continue
                await say(car, note)
                await say(car, COLOUR[note])
                await asyncio.sleep(0.3)
                await say(car, "M")
                await asyncio.sleep(0.1)

            print("Driving in a circle.")
            for i in range(8):
                await say(car, "A")          # forward
                await asyncio.sleep(0.25)
                await say(car, "C")          # turn left
                await asyncio.sleep(0.40)
        finally:
            # This always runs, even if something breaks.
            # So the car always stops.
            for i in range(3):
                await say(car, "0")
                await asyncio.sleep(0.15)
            await say(car, "M")
            print("Stopped.")

    print("Done.")


asyncio.run(main())
