Передаем сообщения в виде азбуки Морзе по Wi-Fi с использованием Raspberry Pi и NodeMcu (ESP8266)

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

Руководство по настройке Raspberry Pi и NodeMCU для передачи сообщений в коде Морзе через Wi-Fi и отображения их с помощью светодиода.

Основные шаги:

  1. Создаем Wi-Fi точку доступа на малине.
  2. Заливаем прошивку Micropython на NodeMcu.
  3. Скрипт morse8266.py автоматически подключается к Wi-Fi точке доступа малины и ждет сообщения.
  4. С помощью скрипта morse_rpi.py отправляем с малины сообщение на NodeMcu.

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

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

Код

Код Raspberry Pi morse_rpi.py

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

  • import socket: Импортирует библиотеку для работы с сетевыми сокетами. Используется для отправки сообщений по сети.
  • import argparse: Импортирует библиотеку для обработки аргументов командной строки. Это позволяет программе принимать параметры от пользователя при запуске.

Словарь MORSE_CODE_DICT

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

Python
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)

  • Цель: Преобразовать текстовое сообщение в код Морзе.
  • Процесс:
    1. Приводит текст к верхнему регистру и разбивает его на слова.
    2. Для каждого слова и каждого символа в слове ищет соответствующий код Морзе в словаре MORSE_CODE_DICT.
    3. Собирает символы Морзе в слова, разделяя их пробелами.
    4. Возвращает строку, в которой слова в коде Морзе разделены тремя пробелами.
Python
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)

  • Цель: Отправить закодированное в Морзе сообщение на заданный IP-адрес и порт.
  • Процесс:
    1. Преобразует текстовое сообщение в код Морзе с помощью text_to_morse.
    2. Создает UDP-сокет.
    3. Отправляет сообщение на указанный IP-адрес и порт.
    4. Обрабатывает возможные исключения при отправке.
    5. Закрывает сокет после отправки.
Python
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()

  • Цель: Обработать аргументы командной строки и инициировать отправку сообщения.
  • Процесс:
    1. Создает объект ArgumentParser для описания программы и ее аргументов.
    2. Добавляет аргументы: message для текста сообщения, --ip для IP-адреса и --port для порта.
    3. Парсит аргументы командной строки.
    4. Объединяет части сообщения в одну строку.
    5. Вызывает send_morse_code с полученными параметрами.
Python
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

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

  • import network: Библиотека для работы с сетевыми интерфейсами, такими как Wi-Fi.
  • import socket: Библиотека для работы с сетевыми сокетами, используемыми для передачи данных.
  • import time: Библиотека для работы с временем, используется для задержек.
  • from machine import Pin: Библиотека для работы с пинами микроконтроллера, позволяет управлять светодиодом.
  • import sys: Библиотека для работы с системными функциями, используется для выхода из программы.

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

  • SSID и PASSWORD: Задаются имя сети (SSID) и пароль для подключения к Wi-Fi.

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

  • UNIT: Основная единица времени, на основе которой определяются длительности точек, тире и промежутков.
  • DOT_DURATION, DASH_DURATION: Длительности точки и тире.
  • INTRA_CHAR_GAP, INTER_CHAR_GAP, INTER_WORD_GAP: Промежутки между элементами символа, символами и словами соответственно.
Python
# 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

  • Создается объект station для управления Wi-Fi интерфейсом.
  • Активируется интерфейс и производится попытка подключения к заданной сети.
  • Выводится на экран состояние подключения. Если подключение не удалось, программа завершает работу.
Python
# Initialize WiFi
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(SSID, PASSWORD)

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

  • LED_PIN: Номер пина, к которому подключен светодиод.
  • Создается объект led для управления светодиодом.
Python
# Initialize LED
LED_PIN = 2  # Change this if your LED is connected to a different pin
led = Pin(LED_PIN, Pin.OUT)

Функция blink(duration)

  • Включает светодиод на заданное время, затем выключает его.
Python
def blink(duration):
    """Blink the LED for the specified duration."""
    led.on()
    time.sleep(duration)
    led.off()

Функция parse_and_blink(morse_code)

  • Парсит строку, содержащую сообщение в коде Морзе, и мигает светодиодом в соответствии с кодом.
  • Поддерживает точки (.), тире (-) и пробелы для разделения символов.
Python
    """  
    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)

  • Ожидает и обрабатывает входящие сообщения в коде Морзе через UDP-сокет.
  • Устанавливает таймаут на получение данных и обрабатывает исключения.
  • Декодирует полученные данные и вызывает parse_and_blink для отображения сообщения.
Python
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 и UDP_PORT: Задаются IP-адрес и порт для приема UDP-сообщений.
  • Создается и привязывается UDP-сокет.
  • Запускается сервер, который ожидает и обрабатывает сообщения.
Python
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:

Bash
pip install esptool

Подготовка NodeMcu

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

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

Сотрем содержимое флеш-памяти NodeMcu (команда для Windows):

Bash
python -m esptool --port COM5 erase_flash

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

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

PowerShell
mode

либо в powershell

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

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

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

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

Получим

Установим mpremote

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

Bash
pip install mpremote

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

Bash
mpremote connect COM5 fs cp morse8266.py :

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

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

Bash
mpremote run morse8266.py

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

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

Bash
cat /var/lib/misc/dnsmasq.leases

Получим

Bash
1726944373 dc:4f:22:5e:9e:22 192.168.4.11 mpy-esp8266 *

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

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

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

Получим

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

Bash
python morse_rpi.py Привет. Как дела?

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

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

Два варианта автозапуска скрипта.

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

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

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

Передача кода Морзе на NodeMcu

Полный код

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