Last active
January 2, 2025 10:39
-
-
Save theodric/a9504560f462244fa386ae4f4e42b060 to your computer and use it in GitHub Desktop.
ThinkPad lid dot Morse code transmitter - python3 & Linux + thinkpad_acpi required
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
#!/usr/bin/env python3 | |
# theodric 2025-01-01 | |
# ThinkPads have a red dot on the lid that lights up when the system is powered on. | |
# Use it to send messages in Morse code! | |
import sys | |
import time | |
# path to the led brightness file | |
LED_BRIGHTNESS_PATH = "/sys/devices/platform/thinkpad_acpi/leds/tpacpi::lid_logo_dot/brightness" | |
# morse code dictionary | |
MORSE_CODE = { | |
'a': ".-", 'b': "-...", 'c': "-.-.", 'd': "-..", 'e': ".", 'f': "..-.", | |
'g': "--.", 'h': "....", 'i': "..", 'j': ".---", 'k': "-.-", 'l': ".-..", | |
'm': "--", 'n': "-.", 'o': "---", 'p': ".--.", 'q': "--.-", 'r': ".-.", | |
's': "...", 't': "-", 'u': "..-", 'v': "...-", 'w': ".--", 'x': "-..-", | |
'y': "-.--", 'z': "--..", '1': ".----", '2': "..---", '3': "...--", | |
'4': "....-", '5': ".....", '6': "-....", '7': "--...", '8': "---..", | |
'9': "----.", '0': "-----", ' ': " " | |
} | |
def get_led_state(): | |
# Retrieve the current LED state so we can tidy it up after the program exits, and bark at the user if our power level is too low | |
try: | |
with open(LED_BRIGHTNESS_PATH, 'r') as led: | |
return led.read().strip() | |
except PermissionError: | |
print("\n\nA C C E S S D E N I E D\n\n\nEither run the program as root, or set perms to like 666 on /sys/devices/platform/thinkpad_acpi/leds/tpacpi::lid_logo_dot/brightness\n\n") | |
sys.exit(1) | |
except Exception as e: | |
print(f"Error: {e}") | |
sys.exit(1) | |
def set_led(state): | |
# Check and see if we can even control the LED, and bark at the user if our power level is too low | |
try: | |
with open(LED_BRIGHTNESS_PATH, 'w') as led: | |
led.write("1" if state else "0") | |
except PermissionError: | |
print("\n\nA C C E S S D E N I E D\n\n\nEither run the program as root, or set perms to +w on /sys/devices/platform/thinkpad_acpi/leds/tpacpi::lid_logo_dot/brightness\n\n") | |
sys.exit(1) | |
except Exception as e: | |
print(f"Error: {e}") | |
sys.exit(1) | |
def blink_morse(message): | |
# Commence Morsification | |
print('\nTransmitting message: "' + message.lower() + '"') | |
# Define a fixed cell width for each letter pair printed, enough to accommodate the widest Morse letter 0 == '-----' | |
CELL_WIDTH = 5 | |
latin_row = [] | |
morse_row = [] | |
for char in message.lower(): | |
if char not in MORSE_CODE: | |
continue | |
code = MORSE_CODE[char] | |
latin_row.append(f"{char.upper():<{CELL_WIDTH}}") | |
morse_row.append(f"{code:<{CELL_WIDTH}}") | |
print("".join(latin_row)) | |
print("".join(morse_row)) | |
for symbol in code: | |
if symbol == ".": | |
set_led(1) | |
time.sleep(0.3) | |
set_led(0) | |
elif symbol == "-": | |
set_led(1) | |
time.sleep(0.7) | |
set_led(0) | |
time.sleep(0.2) # intra-character gap | |
time.sleep(0.3) # inter-character gap | |
# clear the last two rows for the next update, but leave the final message onscreen at exit. | |
# if char != message.lower().strip()[-1]: | |
print("\033[F\033[K", end="") # move cursor up and clear line | |
print("\033[F\033[K", end="") # move cursor up and clear line | |
if __name__ == "__main__": | |
# Save the current state of the LED for later use | |
initial_state = get_led_state() | |
set_led(0) # switch LED off for second before starting, just in case | |
time.sleep(1) | |
if len(sys.argv) < 2: | |
print("Usage: tpmorse.py <message>") | |
sys.exit(1) | |
message = " ".join(sys.argv[1:]) | |
blink_morse(message) | |
print("Over.\nResetting LED to previous state after 2 seconds so as not to confuse the operator on the receiving end.") | |
time.sleep(2) | |
set_led(int(initial_state)) | |
print("Done, 73\n") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment