"""Step 9 - the car follows a black line by itself.

WARNING: the car DRIVES ITSELF. Put it on the floor first.

PUT THE CAR ON THE BLACK LINE BEFORE YOU START.
If it does not start on the line, it just drives in circles
looking for one.

    python track.py

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

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

This script only uses line mode (S#). Yahboom's sheet lists two more
modes, T# and U#. Do NOT use them. They drive the car and 0# does not
stop them - only the power switch does. Tested on a real car.
"""
import asyncio
import sys

from bleak import BleakClient, BleakScanner

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

SECONDS = 15


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(seconds):
    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()
        print("Put the car ON the black line now.")
        print("It will follow the line by itself.")
        for n in [5, 4, 3, 2, 1]:
            print("  starting in", n)
            await asyncio.sleep(1)

        try:
            await say(car, "S")            # line mode on
            print("  following the line for", seconds, "seconds...")
            await asyncio.sleep(seconds)
        finally:
            # Send the stop more than once. One lost message would
            # leave the car driving.
            for i in range(3):
                await say(car, "0")
                await asyncio.sleep(0.15)
            print("Stopped.")

    print("Done.")


asyncio.run(main(float(sys.argv[1]) if len(sys.argv) > 1 else SECONDS))
