diff --git a/collect_data.py b/collect_data.py index 94d976d..cd751f7 100644 --- a/collect_data.py +++ b/collect_data.py @@ -2,6 +2,7 @@ import asyncio import json import platform +from kano_wand.ble_client import KanoBLEClient """ This is used for reading and decoding values from t he Kano Harry Potter Coding Wand @@ -10,7 +11,7 @@ This is used for reading and decoding values from t he Kano Harry Potter Coding - Wand seems to send smaller single dimensional data in 16bit unsigned integers """ -SPELLS = json.load("spells.json") +# SPELLS = json.load("spells.json") CURR_SPELL = 0 # TODO: RUMBLE @@ -29,5 +30,11 @@ if __name__ == "__main__": if platform.system() != "Darwin" else "243E23AE-4A99-406C-B317-18F1BD7B4CBE" # <--- Change to your device's address here if you are using macOS ) + loop = asyncio.get_event_loop() - loop.run_until_complete(run(address, loop, True)) + + kble = KanoBLEClient(address, loop) + + loop.run_until_complete(kble.connect_and_read(True)) + + diff --git a/kano_wand/ble_client.py b/kano_wand/ble_client.py index 1b4ee8d..6ad67ae 100644 --- a/kano_wand/ble_client.py +++ b/kano_wand/ble_client.py @@ -1,21 +1,24 @@ import logging -import struct from converters import BinToInt, BinToFloat -from .sensor_tracker import * +from .wand_sensors import * from bleak import BleakClient from bleak import _logger as logger -from .utils import * +from .wand_utils import * +from .sensor_decoders import wand_decoder + class KanoBLEClient(object): - def __init__(self, wand_address, spells=None): + def __init__(self, wand_address, loop, spells=None): self.wand_address = wand_address self.int_decoder = BinToInt(48) self.float_decoder = BinToFloat(16, 31) self.client = None + self.decoder = wand_decoder() + self.wand_sensors = WandSensors(self.sensor_update_handler) + self.loop = loop - - async def connect(self, loop, debug=False): + async def connect_and_read(self, debug=False): if debug: import sys l = logging.getLogger("asyncio") @@ -25,40 +28,32 @@ class KanoBLEClient(object): l.addHandler(h) logger.addHandler(h) - async with BleakClient(self.wand_address, loop=loop) as client: + async with BleakClient(self.wand_address, loop=self.loop) as client: self.client = client x = await client.is_connected() logger.info("Connected: {0}".format(x)) - - async def start_recieving_data(self): - await start_notify(self.client) + await start_notify(self.client, self.sensor_handling) async def stop_recieving_data(self): await stop_notify(self.client) + def sensor_update_handler(self, sensors): + print(sensors) + def sensor_handling(self, sender, data): """Simple notification handler which prints the data received.""" - # TODO: Convert to a dictionary and a single decode command sender = CHARACTERISTIC_UUIDS[sender] if sender == BUTTON: - self.decode_button(data) + self.wand_sensors.set_button(self.decoder.decode_button(data)) elif sender == NINE_AXIS: - #TODO: refactor the gyro to be local to the sensors file only - gyro = Gyro() - gyro.x, gyro.y, gyro.z = self.decode_nine_axis(data) - sensors.set_gyro(gyro) - sensors.append_to_dataframe() + self.wand_sensors.set_gyro(*self.decoder.decode_nine_axis(data)) elif sender == ACCELEROMETER: - accel = Accel() - accel.x, accel.y, accel.z = self.decode_nine_axis(data) - sensors.set_accel(accel) - sensors.append_to_dataframe() + self.wand_sensors.set_accel(*self.decoder.decode_nine_axis(data)) elif sender == BATTERY: - self.decode_battery(data) + self.decoder.decode_battery(data) elif sender == TEMPERATURE: - self.decode_temp(data) + self.wand_sensors.set_temp(self.decoder.decode_temp(data)) elif sender == MAGNETOMETER: - self.decode_magnet(data) - + self.wand_sensors.set_magneto(self.decoder.decode_magnet(data)) diff --git a/kano_wand/constants.py b/kano_wand/constants.py index 027ce3f..75e06e2 100644 --- a/kano_wand/constants.py +++ b/kano_wand/constants.py @@ -11,5 +11,5 @@ CHARACTERISTIC_UUIDS = { ("64a7000c-f691-4b93-a6f4-0968f5b648f8"): ACCELEROMETER, # Accel ("64a70007-f691-4b93-a6f4-0968f5b648f8"): BATTERY, ("64a70014-f691-4b93-a6f4-0968f5b648f8"): TEMPERATURE, - ("64a70021-f691-4b93-a6f4-0968f5b648f8"):MAGNETOMETER + ("64a70021-f691-4b93-a6f4-0968f5b648f8"): MAGNETOMETER } # <--- Change to the characteristic you want to enable notifications from. diff --git a/kano_wand/sensor_decoders.py b/kano_wand/sensor_decoders.py index 9d1c379..01ab9d0 100644 --- a/kano_wand/sensor_decoders.py +++ b/kano_wand/sensor_decoders.py @@ -1,16 +1,14 @@ import struct +from .wand_utils import chunker from converters import BinToInt, BinToFloat -class decoder(object): +class wand_decoder(object): def __init__(self, int_decoder=BinToInt(48), float_decoder= BinToFloat(16, 31)): self.int_decoder = int_decoder self.float_decoder = float_decoder def decode_button(self, data): - if int.from_bytes(data, byteorder='big'): - print("Button Pressed") - else: - print("Button Released") + return int.from_bytes(data, byteorder='big') def decode_nine_axis(self, data): converted = [self.int_decoder.process(x, True) / 10 ** 14 for x in chunker(data, 6)] @@ -21,13 +19,12 @@ class decoder(object): return converted def decode_battery(self, data): - int.from_bytes(data, byteorder='big') + return int.from_bytes(data, byteorder='big') def decode_temp(self, data): - print(len(data)) - print(data) - print(struct.unpack("h", data)) + return struct.unpack("h", data) def decode_magnet(self, data): print(data) print(len(data)) + return 0 diff --git a/kano_wand/sensor_tracker.py b/kano_wand/sensor_tracker.py deleted file mode 100644 index b3cffb1..0000000 --- a/kano_wand/sensor_tracker.py +++ /dev/null @@ -1,54 +0,0 @@ -import pandas as pd - -class Gyro(object): - def __init__(self): - self.x = 0 - self.y = 0 - self.z = 0 - - def __str__(self): - print(self.x, self.y, self.z) - - -class Accel(object): - def __init__(self): - self.x = 0 - self.y = 0 - self.z = 0 - - def __str__(self): - print(self.x, self.y, self.z) - - -class SensorTracker(object): - def __init__(self): - self.gyro = None - self.gyro_updates = 0 - - self.accel = None - self.accel_updates = 0 - self.dataframe = pd.DataFrame(columns=["gyro_x", "gyro_y", "gyro_z", "accel_x", "accel_y", "accel_z"]) - - def append_to_dataframe(self): - if self.gyro_updates == self.accel_updates: - self.dataframe = self.dataframe.append( - pd.DataFrame({ - "gyro_x": self.gyro.x, - "gyro_y": self.gyro.y, - "gyro_z": self.gyro.z, - "accel_x": self.accel.x, - "accel_y": self.accel.y, - "accel_z": self.accel.z, - }, index=[0]) - ) - - def save_df_to_file(self, filename): - self.dataframe.to_csv(filename, index=False) - - def set_gyro(self, gyro): - self.gyro = gyro - self.gyro_updates += 1 - - def set_accel(self, accel): - self.accel = accel - self.accel_updates += 1 diff --git a/kano_wand/wand_sensors.py b/kano_wand/wand_sensors.py new file mode 100644 index 0000000..92da60b --- /dev/null +++ b/kano_wand/wand_sensors.py @@ -0,0 +1,72 @@ +import pandas as pd + + +class ThreeAxisSensor(object): + def __init__(self, x, y, z): + self.x = x + self.y = y + self.z = z + + def __str__(self): + print(self.x, self.y, self.z) + + +class WandSensors(object): + def __init__(self, wand_update_callback): + self.gyro = None + self.gyro_updates = 0 + + self.accel = None + self.accel_updates = 0 + + self.magneto = 0 + self.button = 0 + self.temperature = 0 + + self.dataframe = pd.DataFrame(columns=["gyro_x", "gyro_y", "gyro_z", "accel_x", "accel_y", "accel_z"]) + + self.wand_update_callback = wand_update_callback + + def __str__(self): + return super().__str__() + + def append_to_dataframe(self): + if self.gyro_updates == self.accel_updates: + self.dataframe = self.dataframe.append( + pd.DataFrame({ + "gyro_x": self.gyro.x, + "gyro_y": self.gyro.y, + "gyro_z": self.gyro.z, + "accel_x": self.accel.x, + "accel_y": self.accel.y, + "accel_z": self.accel.z, + "magneto": self.magneto, + "button": self.button + }, index=[0]) + ) + self.wand_update_callback(self.dataframe) + + def save_df_to_file(self, filename): + self.dataframe.to_csv(filename, index=False) + + def set_gyro(self, x, y, z): + self.gyro = ThreeAxisSensor(x, y, z) + self.gyro_updates += 1 + self.append_to_dataframe() + + def set_accel(self, x, y, z): + self.accel = ThreeAxisSensor(x, y, z) + self.accel_updates += 1 + self.append_to_dataframe() + + def set_temp(self, temp): + self.temp = temp + + def set_button(self, button): + self.button = button + + def set_magneto(self, magneto): + self.magneto = magneto + + def get_dataframe(self): + return self.dataframe diff --git a/kano_wand/utils.py b/kano_wand/wand_utils.py similarity index 100% rename from kano_wand/utils.py rename to kano_wand/wand_utils.py diff --git a/spells.json b/spells.json index 1812c6e..3c4c9fb 100644 --- a/spells.json +++ b/spells.json @@ -2,5 +2,8 @@ "0": "unknown", "1": "lumos", "2": "nox", - "3": "accio" + "3": "accio", + "4": "expelliarmus", + "5": "engorgio", + "6": "reducio" } \ No newline at end of file