Как передать сообщение азбукой Морзе по Wi-Fi с Raspberry Pi на NodeMCU (ESP8266) — HmHm.WTF

Как передать сообщение азбукой Морзе по Wi-Fi с Raspberry Pi на NodeMCU (ESP8266)

Руководство по настройке Raspberry Pi и NodeMCU для передачи сообщений в коде Морзе через Wi-Fi и отображения их с помощью светодиода.Основные шаги:
1. Создаем Wi-Fi точку доступа на малине.
1. Заливаем прошивку Micropython на NodeMcu.
1. Скрипт morse8266.py автоматически подключается к Wi-Fi точке доступа малины и ждет сообщения.
1. С помощью скрипта morse_rpi.py отправляем с малины сообщение на NodeMcu.

Как настроить Wi-Fi точку доступа с автозапуском на Raspberry Pi?

Подробная инструкция в этой статье (дойти до пункта Настроим IP-форвардинг).

Код

Код Raspberry Pi morse_rpi.py

Импорт библиотек

Словарь MORSE_CODE_DICT

Этот словарь содержит соответствия между символами алфавита (как латинского, так и русского) и их кодами в азбуке Морзе. Каждому символу соответствует строка из точек и тире.

MORSE_CODE_DICT = {
    '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': '-----',
    ', ': '--..--', '.': '.-.-.-', '?': '..--..', '/': '-..-.', '-': '-....-',
    '(': '-.--.', ')': '-.--.-', ' ': ' ',
    'А': '.-', 'Б': '-...', 'В': '.--', 'Г': '--.', 'Д': '-..', 'Е': '.',
    'Ё': '.', 'Ж': '...-', 'З': '--..', 'И': '..', 'Й': '.---', 'К': '-.-',
    'Л': '.-..', 'М': '--', 'Н': '-.', 'О': '---', 'П': '.--.', 'Р': '.-.',
    'С': '...', 'Т': '-', 'У': '..-', 'Ф': '..-.', 'Х': '....', 'Ц': '-.-.',
    'Ч': '---.', 'Ш': '----', 'Щ': '--.-', 'Ъ': '.--.-.', 'Ы': '-.--',
    'Ь': '-..-', 'Э': '..-..', 'Ю': '..--', 'Я': '.-.-'
}

Функция text_to_morse(text)

def text_to_morse(text):
    morse_code = []
    for word in text.upper().split(' '):
        morse_letters = []
        for char in word:
            morse_char = MORSE_CODE_DICT.get(char, '')
            if morse_char:
                morse_letters.append(morse_char)
        morse_word = ' '.join(morse_letters)
        morse_code.append(morse_word)
    return '   '.join(morse_code)  # Три пробела между словами

Функция send_morse_code(message, ip, port)

def send_morse_code(message, ip, port):
    morse_code = text_to_morse(message)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        sock.sendto(morse_code.encode(), (ip, port))
        print(f'Отправлено сообщение: "{message}" как Морзе: "{morse_code}"')
    except Exception as e:
        print(f'Ошибка при отправке сообщения: {e}')
    finally:
        sock.close()

Функция main()

def main():
    parser = argparse.ArgumentParser(description='Отправка сообщений в виде Морзе кодом на ESP.')
    parser.add_argument('message', type=str, nargs='+', help='Сообщение для отправки')
    parser.add_argument('--ip', type=str, default='192.168.4.11', help='IP адрес ESP устройства')
    parser.add_argument('--port', type=int, default=12345, help='UDP порт ESP устройства')

    args = parser.parse_args()
    message = ' '.join(args.message)
    target_ip = args.ip
    target_port = args.port

    send_morse_code(message, target_ip, target_port)

Код NodeMcu morse8266.py

Импорт библиотек

Конфигурация Wi-Fi

Определения временных интервалов для азбуки Морзе

# Morse Code Timing Definitions (in seconds)
UNIT = 0.2  # Duration of one unit
DOT_DURATION = UNIT
DASH_DURATION = 3 * UNIT
INTRA_CHAR_GAP = UNIT  # Gap between dots and dashes within a character
INTER_CHAR_GAP = 3 * UNIT  # Gap between characters
INTER_WORD_GAP = 7 * UNIT  # Gap between words

Инициализация Wi-Fi

# Initialize WiFi
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(SSID, PASSWORD)

Инициализация светодиода

# Initialize LED
LED_PIN = 2  # Change this if your LED is connected to a different pin
led = Pin(LED_PIN, Pin.OUT)

Функция blink(duration)

def blink(duration):
    """Blink the LED for the specified duration."""
    led.on()
    time.sleep(duration)
    led.off()

Функция parse_and_blink(morse_code)

"""
    Parse the received Morse code string and blink the LED accordingly.
    Supports dots (.), dashes (-), and spaces for gaps.
    """
    print(f'Parsing Morse code: "{morse_code}"')
    for symbol in morse_code:
        if symbol == '.':
            blink(DOT_DURATION)
            time.sleep(INTRA_CHAR_GAP)
        elif symbol == '-':
            blink(DASH_DURATION)
            time.sleep(INTRA_CHAR_GAP)
        elif symbol == ' ':
            time.sleep(INTER_CHAR_GAP - INTRA_CHAR_GAP)  # Already waited INTRA_CHAR_GAP after symbol
        else:
            pass
    print('Finished parsing Morse code.')

Функция receive_and_process(sock)

def receive_and_process(sock):
    """Receive and process incoming Morse code messages."""
    try:
        while True:
            sock.settimeout(10.0)  # Timeout set to 10 seconds
            try:
                data, addr = sock.recvfrom(1024)  # Buffer size is 1024 bytes
                morse_message = data.decode('utf-8').strip()
                print(f'Received message from {addr}: "{morse_message}"')

                if morse_message:
                    parse_and_blink(morse_message)

            except OSError as e:
                print("Socket timeout, no message received.")
    except KeyboardInterrupt:
        print("Script execution interrupted")
    finally:
        sock.close()
        print("Socket closed")

    # Initialize UDP Server

Инициализация UDP-сервера

UDP_IP = '0.0.0.0'
UDP_PORT = 12345

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))

print('UDP server started and waiting for messages...')

receive_and_process(sock)

Основной цикл

Подготовка Raspberry Pi

Установим библиотеку esptool, чтобы прошивать ESP32:

pip install esptool

Подготовка NodeMcu

Прошивка MicroPython на NodeMcu

Скачаем прошивку MicroPython для NodeMcu, например v1.23.0 (2024-06-02) .binСотрем содержимое флеш-памяти NodeMcu (команда для Windows):

-m esptool \
  --port COM5 \
  erase_flash

Как найти порт, к которому подключен NodeMcu?

На винде введем в CMD

mode

либо в powershell

[System.IO.Ports.SerialPort]::getportnames()

В данном случае порт COM5

Запишем прошивку на NodeMcu

-m esptool \
  --port COM5 \
  --baud 460800 \
  write_flash \
  --flash_size=detect \
  0 ESP8266_GENERIC-20240602-v1.23.0.bin

Получим

Установим mpremote

Установим библиотеку mpremote, которая используется для работы с MicroPython-устройствами (запись и запуск python-файлов на NodeMcu).

pip install mpremote

Загрузим morse8266.py на NodeMcu

mpremote connect COM5 fs cp morse8266.py :

Двоеточие обязательно.

Запустим morse8266.py на NodeMcu

mpremote run morse8266.py

ESP8266 подключится к Wi-FI Raspberry Pi и перейдет в режим «Ожидание передачи».

Узнаем IP-адрес NodeMcu

cat /var/lib/misc/dnsmasq.leases

Получим


IP-адрес NodeMcu, подключенного по Wi-Fi к Raspberry Pi — 192.168.4.11

Запустим morse_rpi.py на Raspberry Pi

morse_rpi.py "Привет. Как дела?" \
    --ip 192.168.4.11 \
    --port 12345

Получим

Если в функции main() указан правильный IP-адрес и порт NodeMcu, то в команде можно обойтись без IP-адреса и порта


Работают обе команды. Пригодится, когда подключено несколько устройств.

Настройка атозапуска morse8266.py

Два варианта автозапуска скрипта.
1. Переименуем скрипт:
- Переименуем скрипт morse8266.py в main.py. MicroPython автоматически выполняет main.py после boot.py при загрузке устройства.
1. Использовать boot.py для вызова скрипта:
- Просто импортируем morse8266 в файле boot.py в NodeMcu.

# boot.py
import morse8266

Результат работы

Передача сообщения Привет. Как дела?

Полный код

Полный код доступен в репозитории на Гитхабе.