diff --git a/chandelier/bt_device.py b/chandelier/bt_device.py index d1bb1e4..14dde46 100644 --- a/chandelier/bt_device.py +++ b/chandelier/bt_device.py @@ -4,10 +4,23 @@ from time import sleep import sys +import re import pexpect from retry import retry from .utilities import errprint, stdprint +def reset_config(): + try: + hci_name = re.search('hc..', pexpect.spawn('hcitool dev').read().decode("utf-8")).group(0) + hci = pexpect.spawn("sudo hciconfig "+ hci_name +" reset") + if hci.expect(pexpect.EOF) == 0: + return True + else: + return False + except pexpect.ExceptionPexpect as exception: + errprint(exception) + return False + class BluetoothDevice: """ Class for generic bluetooth. Can be connected, checked if connected and is disconnecting when object remove.""" @@ -17,7 +30,7 @@ class BluetoothError(Exception): class DeviceNotFound(Exception): """Raised when given device can't be found""" - def check_if_connected(self): + def is_connected(self): try: hci = pexpect.spawn("hcitool con") if hci.expect([self.addr, pexpect.EOF]) == 0: @@ -29,24 +42,30 @@ def check_if_connected(self): return False def __end_connection__(self): - self.__interface__.sendline("\ndisconnect") - self.__interface__.expect("diconnected", timeout=5) + print("Disconnecting!") + self.__interface__.sendline("\nremove " + self.addr) + self.__interface__.expect("Device has been removed", timeout=5) + sleep(5) - @retry(pexpect.exceptions.TIMEOUT, tries=20) - def __check_if_device_is_visible__(self): + @retry(pexpect.exceptions.TIMEOUT, tries=5, delay=3) + def __is_device_visible__(self): try: self.__interface__.sendline("\ndevices") self.__interface__.expect(self.addr) except self.DeviceNotFound as exception: raise exception - @retry(pexpect.exceptions.TIMEOUT, tries=120) + @retry(pexpect.exceptions.TIMEOUT, tries=3, delay=5) def __connect_to_device__(self): - if not self.check_if_connected: - self.__end_connection__() - sleep(3) self.__interface__.sendline("\nconnect "+self.addr) self.__interface__.expect("Connection successful", timeout=5) + sleep(2) + if not self.is_connected(): + raise pexpect.exceptions.TIMEOUT + + def __trust__(self): + self.__interface__.sendline("\ntrust " + self.addr) + self.__interface__.expect("trust succeeded") def __pair__(self): try: @@ -66,6 +85,7 @@ def __open_interface__(self): # enable debuging to stdout if self.__debug_on__: bluetoothctl.logfile = sys.stdout.buffer + sleep(3) return bluetoothctl except Exception as exception: errprint(exception) @@ -91,12 +111,16 @@ def __prepare_bluetooth__(self, __agent__): def __connect__(self): try: - self.__check_if_device_is_visible__() + self.__is_device_visible__() stdprint("Device " + self.addr + " is visible") + sleep(1) + self.__trust__() self.__pair__() + sleep(1) stdprint("Device " + self.addr + " is paired") self.__connect_to_device__() - stdprint("Connection to " + self.addr + " are estabilished") + sleep(1) + stdprint("Connection to " + self.addr + " is estabilished") except self.DeviceNotFound as exception: errprint(exception) errprint("Rasberry couldn't find device or connect.") @@ -111,23 +135,29 @@ def __init__(self, addr, debug=False, agent="NoInputNoOutput"): self.addr = addr self.__debug_on__ = debug self.__agent__ = agent - if self.check_if_connected(): + if self.is_connected(): stdprint("Device already connected.") return None self.__interface__ = self.__open_interface__() self.__prepare_bluetooth__(self.__agent__) self.__connect__() - self.__interface__.kill(15) + self.__interface__.close(force=True) + print("Interface is killed") except Exception as exception: print(exception) + reset_config() self.__interface__ = self.__open_interface__() - #self.__end_connection__() + self.__end_connection__() + self.__interface__.close(force=True) + print("Interface is killed") raise exception #def __del__(self): - # self.__interface__ = self.__open_interface__() - # try: - # #self.__end_connection__() - # except: - # pass - # stdprint("Device " + self.addr + " is disconnected!") + # if self.__debug_on__: + # print("disconnect") + # self.__interface__ = self.__open_interface__() + # try: + # self.__end_connection__() + # except: + # pass + # stdprint("Device " + self.addr + " is disconnected!") diff --git a/chandelier/bt_devices.py b/chandelier/bt_devices.py index fe8fece..65b57e6 100644 --- a/chandelier/bt_devices.py +++ b/chandelier/bt_devices.py @@ -7,14 +7,14 @@ class BluetoothSpeaker(bt_device.BluetoothDevice): - @retry(Exception, tries=5, delay=3) + @retry(Exception, tries=3, delay=3) def __get_pulse_audio_sink__(self): with pulsectl.Pulse('list-sinks') as pulse: for sink in pulse.sink_list(): if sink.proplist.get('device.string') == self.addr: return sink.index, sink.name - def __init__(self, addr, debug=False, agent="NoInputNoOutput"): + def __init__(self, addr, debug=False, agent="NoInputNoOutput"): super().__init__(addr, debug, agent) sleep(3) try: @@ -26,17 +26,23 @@ def __init__(self, addr, debug=False, agent="NoInputNoOutput"): class BluetoothRemote(bt_device.BluetoothDevice): + __loop = "" remote_inputs = [] output = "" - @retry(Exception, tries=5, delay=3) + + @retry(Exception, tries=3, delay=3) def __remote_devices__(self, addr): - remote_address = addr devices = [evdev.InputDevice(path) for path in evdev.list_devices()] for device in devices: - if device.phys not in remote_address: + if device.phys == '': devices.remove(device) + if len(devices) < 2: + raise Exception return devices + def stop_waiting_on_output(self): + self.__loop.stop() + def wait_and_get_output(self): @asyncio.coroutine async def print_events(device): @@ -46,27 +52,27 @@ async def print_events(device): asyncio.get_running_loop().stop() return cat_event - loop = asyncio.new_event_loop() + self.__loop = asyncio.new_event_loop() tasks = [] for device in self.remote_inputs: - tasks.append(loop.create_task(print_events(device))) + tasks.append(self.__loop.create_task(print_events(device))) - loop.run_forever() + self.__loop.run_forever() for task in tasks: - if task.done(): - return task.result() - - #devs_tasks = [] - #for device in inputs: - # task = asyncio.ensure_future(print_events(device)) - # devs_tasks.append(task) + try: + if task.done(): + return task.result() + except: + return None def __init__(self, addr, debug=False, agent="NoInputNoOutput"): try: super().__init__(addr, debug, agent) self.remote_inputs = self.__remote_devices__(addr) except Exception as exception: + bt_device.reset_config() utilities.errprint(exception) + self.__end_connection__() raise exception diff --git a/chandelier/chandelier.py b/chandelier/chandelier.py index 9cef163..e1ff38f 100644 --- a/chandelier/chandelier.py +++ b/chandelier/chandelier.py @@ -1,15 +1,21 @@ -import sys from time import sleep -from chandelier import bt_devices, led, movement_sensor, pulseaudio -from .utilities import errprint import threading - +from retry import retry +from chandelier import bt_devices, led, movement_sensor, pulseaudio class Chandelier: standby_on = True + playing_voices = False + press_duration = "" + + @retry(Exception, tries=10, delay=2) + def connect_to_remote(self, addr): + remote = bt_devices.BluetoothRemote(addr) + return remote + def __init__(self, sensors_pins, led_pins, speaker_addr, remote_addr): - self.blt_speaker = bt_devices.BluetoothSpeaker(speaker_addr, debug=False) - self.remote = bt_devices.BluetoothRemote(remote_addr) + self.blt_speaker = bt_devices.BluetoothSpeaker(speaker_addr) + #self.remote = self.connect_to_remote(remote_addr) self.sensors = movement_sensor.MovementSensors(sensors_pins) self.led = led.Led(led_pins[0], led_pins[1], led_pins[2]) @@ -19,95 +25,154 @@ def play_ringtone(self, volume): def stop_playing_ringtone(self): self.ringtone.stop_playing() + self.ringtone = None - def play_voices(self, volume): - self.svoices = pulseaudio.Play([(self.blt_speaker.pa_index, volume)], "../ambient1.wav") + def play_voices(self, volume=1): + self.voices_player = pulseaudio.Play( + [(self.blt_speaker.pa_index, volume)], "../ringtone.mp3", repeat=False) + + def play_failed(self, volume=1): + self.fail_player = pulseaudio.Play( + [(self.blt_speaker.pa_index, volume)], "../ringtone.mp3", repeat=False) + + def play_successed(self, volume=1): + self.success_player = pulseaudio.Play( + [(self.blt_speaker.pa_index, volume)], "./axel.mp3", repeat=False) def stop_playing_voices(self): - self.svoices.stop_playing() + self.voices_player.stop_playing() + self.voices_player = None + + def stop_led(self): + self.led.set_r_intensity(0) + self.led.set_g_intensity(0) def led_white(self): + self.stop_led() self.led.set_r_intensity(100) self.led.set_g_intensity(100) def led_red(self): + self.stop_led() self.led.set_r_intensity(100) self.led.set_g_intensity(0) def __led_pulsing_white(self): - while self.standby_on == True: + self.stop_led() + while self.standby_on: for i in range(1, 155, 1): self.led.set_r_intensity(pow(1.03, i)) self.led.set_g_intensity(pow(1.03, i)) - if self.standby_on == False: + if not self.standby_on: return True sleep(0.03) + sleep(0.03) + for i in range(155, 1, -1): - self.led.set_r_intensity(pow(1.03, i)) - self.led.set_g_intensity(pow(1.03, i)) - if self.standby_on == False: + self.led.set_r_intensity(pow(1.02, i)) + self.led.set_g_intensity(pow(1.02, i)) + if not self.standby_on: return True sleep(0.03) - def __led_pulsing_red(self): - self.led.set_g_intensity(0) - while self.standby_on == True: + def led_pulsing_red(self): + self.stop_led() + while self.standby_on: for i in range(1, 155, 1): self.led.set_r_intensity(pow(1.03, i)) - if self.standby_on == False: + if not self.playing_voices: + print("kup") return True sleep(0.03) + sleep(0.03) + for i in range(155, 1, -1): - self.led.set_r_intensity(pow(1.03, i)) - if self.standby_on == False: + self.led.set_r_intensity(pow(1.02, i)) + if not self.playing_voices: + print("kup") return True sleep(0.03) + def wait_between_seq(self): + ambient = pulseaudio.Play([(self.blt_speaker.pa_index, 1)], "../ringtone.mp3") + button_thread = threading.Thread(target=self.wait_for_pick_up) + button_thread.join(175) + ambient.stop_playing() + ambient = None def wait_for_beggining(self): + ambient = pulseaudio.Play([(self.blt_speaker.pa_index, 1)], "./axel.mp3") led_thread = threading.Thread(target=self.__led_pulsing_white) - sensors_thread = threading.Thread(target=self.sensors.wait_for_movement) + sensors_thread = threading.Thread( + target=self.sensors.wait_for_movement) sensors_thread.start() led_thread.start() sensors_thread.join() self.standby_on = False - + ambient.stop_playing() + ambient = None + def voices(self): - led_thread = threading.Thread(target=self.__led_pulsing_red) - self.play_voices(5) + self.playing_voices = True + led_thread = threading.Thread(target=self.led_pulsing_red) + button_thread = threading.Thread(target=self.wait_for_pick_up) + #self.play_voices() led_thread.start() - result = self.wait_for_pick_up() - self.stop_playing_voices() - return result + button_thread.start() + while button_thread.is_alive():# and self.voices_player.is_playing(): + sleep(0.5) + #while self.voices_player.is_playing(): + # sleep(0.5) + #self.stop_playing_voices() + self.remote.stop_waiting_on_output() + self.playing_voices = False + return self.press_duration + + def fail(self): + self.led_red() + self.play_failed() + + def success(self): + self.led_white() + self.play_successed() def wait_for_pick_up(self): butt_down = self.remote.wait_and_get_output() - print(butt_down) - while True: - if butt_down.keystate == 1: - while True: - butt_up = self.remote.wait_and_get_output() - if butt_up.keystate == 0: - if butt_up.event.sec - butt_down.event.sec >= 3: - return "long" - else: - return "short" - - + if type(butt_down) is None: + self.press_duration = False + return False + elif butt_down.keystate == 1: + butt_up = self.remote.wait_and_get_output() + if butt_up.keystate == 0: + if butt_up.event.sec - butt_down.event.sec >= 3: + self.press_duration = "long" + return self.press_duration + else: + self.press_duration = "short" + return self.press_duration + + +#2A:07:98:10:34:2C ribbon remote +#2A:07:98:10:32:05 with sticker remote def main(): - - chandelier = Chandelier([16, 26], [20, 21, 21], - "30:21:A0:29:85:28", "2A:07:98:10:34:2C") #sensors, leds, speaker, remote + chandelier = Chandelier([16, 19, 26], [20, 21, 21], + "0C:A6:94:62:67:40", "2A:07:98:10:32:05") # sensors, leds, speaker, remote chandelier.wait_for_beggining() + sleep(100) chandelier.led_white() - sleep(3) + sleep(2) chandelier.play_ringtone(1) - print("dupa") chandelier.wait_for_pick_up() + print(1) chandelier.stop_playing_ringtone() - if chandelier.voices() == "short": - print("you did it <3") - \ No newline at end of file + print(2) + press_duration = chandelier.voices() + print(press_duration) + #if press_duration == "long": + # chandelier.fail() + #else: + # chandelier.success() + #chandelier.wait_between_seq() \ No newline at end of file diff --git a/chandelier/pulseaudio.py b/chandelier/pulseaudio.py index 1f653db..f92dd2c 100644 --- a/chandelier/pulseaudio.py +++ b/chandelier/pulseaudio.py @@ -47,13 +47,20 @@ def play(self): def stop_playing(self): self.player.stop() + + def is_playing(self): + self.player.is_playing() def __del__(self): self.player.stop() self.player.release() - def __init__(self, sinks, file): + def __init__(self, sinks, file, repeat=True): self.file = file - self.player = vlc.MediaPlayer(vlc.Instance('--input-repeat=999999'), file) + if repeat: + self.player = vlc.MediaPlayer(vlc.Instance('--input-repeat=999999'), file) + else: + self.player = vlc.MediaPlayer(vlc.Instance(), file) super().__init__(sinks) self.play() +