#!/usr/bin/env python3
#
# BTZen - library to asynchronously access Bluetooth devices.
#
# Copyright (C) 2015-2021 by Artur Wroblewski <wrobell@riseup.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""
BTZen demo using SensorTag Bluetooth device.

The demo supports reconnection of device.
"""

import argparse
import asyncio
import logging
import uvloop
import typing as tp
from datetime import datetime

import btzen

logger = logging.getLogger()

async def read_sensors(mac: str, interface: str) -> None:
    battery = btzen.battery_level(mac)
    devices = [ctor(mac, make=btzen.Make.SENSOR_TAG) for _, ctor, _ in SENSORS]
    devices.append(battery)

    async with btzen.connect(devices, interface=interface) as session:
        items = zip(SENSORS, devices)
        tasks = [reader(name, dev) for (name, _, reader), dev in items]
        tasks.append(read_battery('battery', battery))
        await asyncio.gather(session, *tasks)

async def read_sensor(name: str, sensor: btzen.DeviceBase) -> None:
    loop = asyncio.get_event_loop()
    async for value in btzen.read_all(sensor):
        print_data(name, '{:.1f}'.format(value))
        await asyncio.sleep(-loop.time() % 1)

async def read_accelerometer(name: str, sensor: btzen.DeviceBase) -> None:
    async for values in btzen.read_all(sensor):
        values = ', '.join('{:.4f}'.format(v) for v in values)
        print_data(name, values)

async def read_button(name: str, button: btzen.DeviceBase) -> None:
    async for value in btzen.read_all(button):
        print_data('button', str(value))

async def read_battery(name: str, battery: btzen.DeviceBase) -> None:
    async for value in btzen.read_all(battery):
        print_data('battery level', value)

def print_data(name: str, value: tp.Union[str, int, float]) -> None:
    print('{} {}: {}'.format(datetime.now(), name, value))

#
# sensor definitions
#
SENSORS = [
    ('pressure', btzen.pressure, read_sensor),
    ('temperature', btzen.temperature, read_sensor),
    ('humidity', btzen.humidity, read_sensor),
    ('light', btzen.light, read_sensor),
    ('button', btzen.button, read_button),
    ('accelerometer', btzen.accelerometer, read_accelerometer),
]

parser = argparse.ArgumentParser()
parser.add_argument(
    '--verbose', default=False, action='store_true',
    help='show debug log'
)
parser.add_argument(
    '-i', '--interface', default='hci0',
    help='Host controller interface (HCI)'
)
parser.add_argument('mac', help='MAC address of device')
args = parser.parse_args()

level = logging.DEBUG if args.verbose else logging.INFO
logging.basicConfig(level=level)

uvloop.install()
asyncio.run(read_sensors(args.mac, args.interface))

# vim: sw=4:et:ai
