Created
June 13, 2025 13:08
-
-
Save fieldOfView/82d70d94979894e2355bff387090f924 to your computer and use it in GitHub Desktop.
MIDI to Tasmota PWM frequency script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import argparse | |
import time | |
import mido | |
import requests | |
class MidiToTasmota: | |
def __init__(self, midi_filename: str, ip_address: str, http_username: str|None=None, http_password: str|None=None): | |
self.midi_filename = midi_filename | |
if not http_username: | |
self._tasmota_url = f"http://{ip_address}" | |
elif not http_password: | |
self._tasmota_url = f"http://{http_username}@{ip_address}" | |
else: | |
self._tasmota_url = f"http://{http_username}:{http_password}@{ip_address}" | |
self._turned_on: bool = False | |
def _midi_to_frequency(self, midi_note) -> int: | |
"""Convert a MIDI note number to its corresponding frequency in Hz.""" | |
return int(440 * (2 ** ((midi_note - 69) / 12))) | |
def _send_commands(self, commands: list[tuple[str, str]]) -> None: | |
"""Format one command, or append multuple in one Backlog command""" | |
if len(commands) == 1: | |
formatted_command: str = f"{commands[0][0]}+{commands[0][1]}" | |
else: | |
formatted_command: str = f"Backlog%20{'%3b'.join([f'{c[0]}%20{c[1]}' for c in commands])}" | |
requests.get(f'{self._tasmota_url}/cm?cmnd={formatted_command}') | |
def play(self) -> None: | |
"""Load a MIDI file and convert all notes to frequencies.""" | |
midi = mido.MidiFile(self.midi_filename) | |
for track in midi.tracks: | |
for msg in track: | |
time.sleep(msg.time / 4000) | |
if msg.type == 'note_on': | |
freq = self._midi_to_frequency(msg.note) | |
print(f"Time {msg.time:4d}: MIDI {msg.note:3d} → {freq:.2f} Hz") | |
commands: list[tuple[str, str]] = [('PWMFrequency', str(freq))] | |
if not self._turned_on: | |
commands.append(('Power', '1')) | |
self._turned_on = True | |
self._send_commands(commands) | |
def close(self) -> None: | |
"""Turn off the bulb if it was left on""" | |
self._send_commands([('Power', '0')]) | |
self.turned_on = False | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser(description="Process MIDI file and send commands to Tasmota") | |
parser.add_argument("midi_filename", help="MIDI file to play") | |
parser.add_argument("ip_address", help="Tasmota device IP address") | |
parser.add_argument("--username", "--http-username", "-u", dest="http_username", | |
help="HTTP username for authentication (optional)") | |
parser.add_argument("--password", "--http-password", "-p", dest="http_password", | |
help="HTTP password for authentication (optional)") | |
args = parser.parse_args() | |
midi_to_tasmota = MidiToTasmota( | |
midi_filename=args.midi_filename, | |
ip_address=args.ip_address, | |
http_username=args.http_username, | |
http_password=args.http_password | |
) | |
try: | |
midi_to_tasmota.play() | |
except KeyboardInterrupt: | |
pass | |
midi_to_tasmota.close() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mido | |
requests |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment