I would use a parser and a specific format that describes the entire action.
The following is a sketch, but is almost completed, and probably will be helpful for you.
and almost working...
====
UPD: I updated the code. It is not tested, however. The main idea is to use human understandable commands
that describe the theatrical performance. If you look at
Each new line is a new command. Awesome invention, I think. Hope that helps.
The following is a sketch, but is almost completed, and probably will be helpful for you.
import RPi.GPIO as GPIO import time import random import pygame pygame.mixer.init() pygame.mixer.music.load("/home/pi/Music/Romance para teatro.mp3") class Theater: freq = 100 actors = { 'defunto': 1, # put comments here directional central etc... 'caveira': 2, # ... define the same way all 12 items/switches?! 'int_caveira': 11 'geral': 12 } takt_executors = { 'mplay': '_mplay_exec', 'mstop': '_mstop_exec', 'o': '_o_exec', 's': '_s_exec' } def __init__(self): self.iface = GPIO self.iface.setmode(self.iface.BCM) # do setup for actor, num in Theater.actors.items(): self.iface.setup(num) def output(self): """ Docstring needs be here. I didn't see that you use this function?! It seems to be never called in your code. """ # is this allowed, or you need to split # it into 2 separated for-loops? for actor, num in Theater.actors.items(): self.iface.output(num, False) self.iface.PWM(num, Theater.freq).start(0) def load_episode(self, episode): """ Docstring needs be here. """ self.episode = episode def play(self, mode=None): """ Docstring needs be here. """ if self.episode is None: # I don't know, where it will be printed in case of GPIO?! print("No episode was loaded. Load an episode first") try: if mode == 'always': while True: self._play() else: # you can define more modes using elif statement... self._play() # play only once except KeyboardInterrupt: pass finally: pygame.mixer.music.stop() #Stop music. GPIO.cleanup() def _parse(self): if self.episode is None: return [] result = [] for token in map(str.strip, self.episode.split('\n')): if token == 'mplay': result.append(("mplay", None, None)) elif token == 'mstop': result.append(("mstop", None, None)) elif token.startswith('s'): try: result.append(('s', float(token[1:]), None)) except (ValueError, IndexError): pass elif token.startswith('o'): try: result.append(('o', token[2:-2], True if token[-1] == 't' else False)) except (ValueError, IndexError): pass return result def _mplay_exec(self, *args): pygame.mixer.music.play() def _mstop_exec(self, *args): pygame.mixer.music.stop() def _o_exec(self, *args): channel = Theater.actors.get(args[1]) if ch is not None: self.iface.output(channel, args[-1]) def _s_exec(self, *args): time.sleep(args[1]) def _nothing_exec(self, *args): pass def _play(self): for takt in self._parse(): exec_name = self.takt_executors.get(takt[0], '_nothing_exec') getattr(self, exec_name)(*takt) # --------------------- Structure of episode description --------------- # This is your action, it is written as a string, so it can be saved # to a file, read and played again. episode = """ mplay s2.5 o_caveira_t s1.2 o_caveira_f s0 # complete full action; syntax is self-explanatory, i hope o_int_caveira_f s1.9 mstop """ # mstop, mplay -- stop and play music respectively theater = Theater() theater.load_episode(episode) theater.play(mode='always')I am sorry about too few comments ( I am tired), but I hope the code is self-explanatory
and almost working...
====
UPD: I updated the code. It is not tested, however. The main idea is to use human understandable commands
that describe the theatrical performance. If you look at
episode
variable, it is just a string. Each new line is a new command. Awesome invention, I think. Hope that helps.