aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Powers <mark@marks.kitchen>2021-08-15 04:52:18 +0100
committerMark Powers <mark@marks.kitchen>2021-08-15 04:52:18 +0100
commitdb747d54bece564ff881cda3e21e38b45c91f35e (patch)
tree55582958a39c48222d76022cc714d4aaf7875ab6
parentdc62736d843949a4f6a01cbd1af09c25a38673a9 (diff)
Refactor some things
-rw-r--r--dial.py23
-rw-r--r--events.py45
-rw-r--r--hangup.py16
-rwxr-xr-xmain.py41
-rw-r--r--phone.py68
5 files changed, 111 insertions, 82 deletions
diff --git a/dial.py b/dial.py
index d5117ff..fa5ca9e 100644
--- a/dial.py
+++ b/dial.py
@@ -10,12 +10,10 @@ REST_TIME = 0.3 # seconds
DIAL_RESET_TIME = 5 # seconds
class DialThread(threading.Thread):
- def __init__(self, queue, phone_held, processing_event):
+ def __init__(self, phone):
threading.Thread.__init__(self, args=(), kwargs=None)
- self.queue = queue
self.daemon = True
- self.phone_held = phone_held
- self.processing_event = processing_event
+ self.phone = phone
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
@@ -40,8 +38,8 @@ class DialThread(threading.Thread):
pressed = False
if self.dial_over(rest_start) and not printed:
# Only add this dial to queue if we should accept numbers at this time
- if self.phone_held.is_set() and not self.processing_event.is_set():
- self.queue.put(count % 10) # wrap 10 to 0
+ if self.phone.phone_held.is_set() and not self.phone.processing_event.is_set():
+ self.phone.queue.put(count % 10) # wrap 10 to 0
count = 0
printed = True
time.sleep(0.01)
@@ -52,23 +50,24 @@ class DialThread(threading.Thread):
class DialManager:
- def __init__(self, phone_held, phone_hung_up):
+ def __init__(self, phone):
self.sequence = []
+ self.phone = phone
self.update = datetime.now()
- self._load_sequences(phone_held, phone_hung_up)
+ self._load_sequences()
+ print(self.sequences)
- def _load_sequences(self, phone_held, phone_hung_up):
+ def _load_sequences(self):
def recursive_add(classname, sequence_list, sequences, args):
key = int(sequence_list[0])
if not sequence_list[1:]:
- sequences[key] = eval(classname)(self, phone_held, phone_hung_up, args)
+ sequences[key] = eval(classname)(self.phone, args)
else:
- sequences[key] = {}
+ sequences[key] = sequences[key] if key in sequences and isinstance(sequences[key], dict) else {}
recursive_add(classname, sequence_list[1:], sequences[key], args)
self.sequences = {}
for sequence in config["sequences"]:
- print(sequence, config["sequences"][sequence], sep="\t")
parts = config["sequences"][sequence].split(" ", 1)
classname = parts[0]
args = parts[1:]
diff --git a/events.py b/events.py
index fa702c0..36ca972 100644
--- a/events.py
+++ b/events.py
@@ -4,24 +4,19 @@ from config import config
import requests
from multiprocessing import Process
-def run_until_hangup(command, phone_hung_up):
- '''
- returns true if process was finished
- '''
- process = subprocess.Popen(command)
- while process.poll() is None:
- if phone_hung_up.wait(timeout=0.1):
- process.terminate()
- return False
- return True
-
+def tts_command(text):
+ if config["engine"]["tts"] == "espeak":
+ return ["espeak", text]
+ elif config["engine"]["tts"] == "festival":
+ filename = "/tmp/phone_input.txt"
+ with open(filename, "w") as f:
+ f.write(text)
+ return ["festival", "--tts", filename]
class Event():
- def __init__(self, dial_manager, phone_held, phone_hung_up, args):
- self.dial_manager = dial_manager
- self.phone_held = phone_held
- self.phone_hung_up = phone_hung_up
+ def __init__(self, phone, args):
self.args = args
+ self.phone = phone
def get_name(self):
return "generic event"
@@ -30,7 +25,7 @@ class Event():
return "event"
def run(self):
- run_until_hangup(["espeak", self.get_text()], self.phone_hung_up)
+ self.phone.run_until_hangup(tts_command(self.get_text()))
class FortuneEvent(Event):
@@ -56,7 +51,7 @@ class DirectoryEvent(Event):
else:
sequence_list.append((sequence, sequences[key]))
return sequence_list
- sequences = self.dial_manager.sequences
+ sequences = self.phone.dial_manager.sequences
text = ""
for sequence, event in recursive_build("", sequences):
text += f"For {event.get_name()} dial {sequence}. "
@@ -75,9 +70,8 @@ class OperatorEvent(Event):
next_hour = now.hour % 12 if nearest_quarter != 0 else (now.hour + 1) % 12
next_hour = next_hour if next_hour != 0 else 12
text = f"In {nearest_quarter - now.minute} minutes it will be {next_hour} {nearest_quarter}"
- loop = run_until_hangup(["espeak", text], self.phone_hung_up)
- if loop:
- loop = run_until_hangup(["aplay", "/etc/phone/sound/hold.wav"], self.phone_hung_up)
+ commands = [tts_command(text), ["aplay", "/etc/phone/sound/hold.wav"]]
+ self.phone.run_many_until_hangup(commands)
class WeatherEvent(Event):
@@ -106,9 +100,10 @@ class RecordEvent(Event):
return "recorder"
def run(self):
- run_until_hangup(["espeak", "Please record a message."], self.phone_hung_up)
+ self.phone.run_until_hangup(tts_command("Please record a message."))
+
process = subprocess.Popen(["arecord", "/tmp/out.wav"])
- self.phone_hung_up.wait()
+ self.phone.wait_until_hung_up()
process.terminate()
return "recording done"
@@ -118,13 +113,11 @@ class PlayEvent(Event):
return "play"
def run(self):
- run_until_hangup(["aplay", "/tmp/out.wav"], self.phone_hung_up)
+ self.phone.run_until_hangup(["aplay", "/tmp/out.wav"])
class WavEvent(Event):
def get_name(self):
return self.args[0]
def run(self):
- run_until_hangup(["aplay", self.args[0]], self.phone_hung_up)
-
-
+ self.phone.run_until_hangup(["aplay", self.args[0]])
diff --git a/hangup.py b/hangup.py
index cfe6bdf..152118f 100644
--- a/hangup.py
+++ b/hangup.py
@@ -5,11 +5,9 @@ import time
BUTTON_GPIO = 24
class HangUpThread(threading.Thread):
- def __init__(self, phone_held, phone_hung_up, dial_manager):
+ def __init__(self, phone):
threading.Thread.__init__(self, args=(), kwargs=None)
- self.phone_held = phone_held
- self.phone_hung_up = phone_hung_up
- self.dial_manager = dial_manager
+ self.phone = phone
self.daemon = True
GPIO.setmode(GPIO.BCM)
@@ -18,11 +16,11 @@ class HangUpThread(threading.Thread):
def run(self):
while True:
if not GPIO.input(BUTTON_GPIO):
- self.phone_held.clear()
- self.phone_hung_up.set()
- self.dial_manager.clear_sequence()
+ self.phone.phone_held.clear()
+ self.phone.phone_hung_up.set()
+ self.phone.dial_manager.clear_sequence()
else:
- self.phone_held.set()
- self.phone_hung_up.clear()
+ self.phone.phone_held.set()
+ self.phone.phone_hung_up.clear()
time.sleep(0.1)
diff --git a/main.py b/main.py
index c72147c..7c41d7b 100755
--- a/main.py
+++ b/main.py
@@ -1,47 +1,18 @@
#!/usr/bin/env python3
-from dial import DialManager, DialThread
-from hangup import HangUpThread
-
-from time import sleep
-from queue import Queue
-from threading import Event
+from phone import Phone
if __name__ == "__main__":
- queue = Queue()
- phone_held = Event()
- phone_hung_up = Event()
- processing_event = Event()
-
- # start phone as on hook
- phone_held.clear()
- phone_hung_up.set()
- processing_event.clear()
-
- dial_thread = DialThread(queue, phone_held, processing_event)
- dial_thread.start()
- dial_manager = DialManager(phone_held, phone_hung_up)
-
- hang_up_thread = HangUpThread(phone_held, phone_hung_up, dial_manager)
- hang_up_thread.start()
-
+ phone = Phone.get_instance()
print("Ready")
while True:
try:
# Wait for phone to be picked up
- phone_held.wait()
+ phone.wait_until_answered()
# Dial a number
- try:
- dialed = queue.get(block=True, timeout=0.1)
- except:
- continue
- response = dial_manager.dial(dialed)
- # If we matched a sequence, play out event
- if response is not None:
- processing_event.set()
- response.run()
+ phone.process_dial()
except Exception as e:
print(e)
+ raise e
finally:
- processing_event.clear()
-
+ phone.clear_event()
diff --git a/phone.py b/phone.py
new file mode 100644
index 0000000..b47ea41
--- /dev/null
+++ b/phone.py
@@ -0,0 +1,68 @@
+from dial import DialManager, DialThread
+from hangup import HangUpThread
+from threading import Event
+
+import subprocess
+from queue import Queue
+
+class Phone:
+ __instance = None
+ @staticmethod
+ def get_instance():
+ if Phone.__instance is None:
+ Phone()
+ return Phone.__instance
+
+ def __init__(self):
+ Phone.__instance = self
+ self.queue = Queue()
+ self.phone_held = Event()
+ self.phone_hung_up = Event()
+ self.processing_event = Event()
+
+ # start phone as on hook
+ self.phone_held.clear()
+ self.phone_hung_up.set()
+ self.processing_event.clear()
+
+ self.dial_thread = DialThread(self)
+ self.dial_thread.start()
+ self.dial_manager = DialManager(self)
+
+ self.hang_up_thread = HangUpThread(self)
+ self.hang_up_thread.start()
+
+ def wait_until_answered(self, timeout=None):
+ return self.phone_held.wait(timeout)
+
+ def wait_until_hung_up(self, timeout=None):
+ return self.phone_hung_up.wait(timeout)
+
+ def process_dial(self):
+ try:
+ dialed = self.queue.get(block=True, timeout=0.1)
+ except:
+ return
+ response = self.dial_manager.dial(dialed)
+ # If we matched a sequence, play out event
+ if response is not None:
+ self.processing_event.set()
+ response.run()
+
+ def clear_event(self):
+ self.processing_event.clear()
+
+ def run_until_hangup(self, command):
+ process = subprocess.Popen(command)
+ while process.poll() is None:
+ if self.wait_until_hung_up(0.1):
+ print("terminating process")
+ process.terminate()
+ process.kill()
+ return False
+ return True
+
+ def run_many_until_hangup(self, commands):
+ for command in commands:
+ if not self.run_until_hangup(command):
+ break