Ich probiere gerade mit der UIFlow-IDE ein kleines Programm zu erstellen, das mittels ESP-Now eine Verbindung herstellt und Daten austauscht.

Mein erster Versuch (Master):

  • Zuerst wird ESP-Now initialisiert.
  • Dann wird ein Name (SSID) für die Arbeitsgruppe festgelegt.
  • Und schließlich die eigene MAC-Adresse geholt und angezeigt.
  • In der folgenden Schleife wird nach einem Mitglied der Arbeitsgruppe gesucht und dessen MAC angezeigt.
  • Das Mitglied wird dann in eine Liste eingetragen.
  • Die MainLoop ist noch nicht getestet.

Das Programm auf dem Slave:

  • Auch hier wird zuerst ESP-Now initialisiert.
  • Dann wird der Arbeitsgruppennamen (SSID) festgelegt und bekanntgemacht.
  • Schließlich wird die eigene MAC-Adresse geholt und angezeigt.

Mehr macht dieses Programm nicht. Das genügt aber, um vom Master erkannt zu werden!

Eine zuverlässige Datenübertragung hat aber nicht funktioniert.

Ein zweiter Anlauf

Also das Beispiel von MStack hat nicht funktioniert. Ich habe heute einen neuen Anlauf gemacht. Es funktionierte wieder nichts. Also habe ich einen ESP32 genommen und die Micropython Demo als Grundlage genommen. Das funktionierte in Thonny:

# ESPNow_test_001.py
#


import network
import espnow

sta = network.WLAN(network.STA_IF)  # Or network.AP_IF
sta.active(True)

e = espnow.ESPNow()
e.active(True)

peer = b'\x94\xb9\x7e\x8d\x41\xdc'
e.add_peer(peer)

Dieses kleine Programm hat einen ESP-Now Sender erzeugt. Mit

>>> e.send(peer, "Starting...")
True

habe ich senden können. Das Programm RX_001.m5f hat diese Aussendungen empfangen. Es waren noch kleine Fehler drinn, deshalb hier die endgültige Fassung:

Wenn eine Message empfangen wird, so wird die MAC des Senders und die Nachricht für 1 Sekunde angezeigt, dann erscheinen wieder —.

Dann habe ich am Senderprogramm gearbeitet. Das automatische Suchen von Peers habe ich rausgeschmissen und die MAC des Peers (Empfänger) ins Programm geschrieben. Damit funktionierte dann auch der Sender. Hier das Programm TX_003.m5f:

Damit ist die Grundlage für eine einseitige Verbindung mittels ESP-Now geschaffen.

Das automatische finden des Peer hat prinzipiell funktioniert. Allerdings wurde eine Slave-MAC angezeigt, die um 1 höher war, als die vom Slave selbst angezeigte.

Nachgedanken

Es ist möglich, dass der Erste Versuch unbefriedigend verlief, weil ich den Kanal auf 0 eingestellt hatte. Kanal 0 bedeutet, das der eingestellte Kanal verwendet wird. Wenn sich aus irgendwelchen Gründen bei Sender und Empfänger unterschiedliche Kanäle einstellen finden sie sich nicht.

Das werde ich vielleicht später mal testen. Für eine vorgesehenen Reichweitentest ist das jetzt ausreichend.

Kürzlich bin ich auf ein Projekt gestoßen, das mittels Adafruit_TinyUSB-Library mit einem Raspberry Pi Pico Tastatureingaben simuliert hat. Hier werde ich mir die Technik dafür erarbeiten. Deshalb befindet sich diese Seite z.Z. noch im Entstehungsmodus.

Die Entwicklungsbasis ist das Pico Restouch LCD 3,5″ Display von Waveshare. Bestückt mit einen Pico, der im Lieferumfang von azdelivery.de enthalten war. Außerdem gibt dazu einen Projektvorschlag für einen Tastatursimulator. Als IDE kommt die Arduino-IDE zum Einsatz.

Die Adafruit_TinyUSB Library stellt verschiedene HID’s (Human Interface Device) zur Verfügung. Mich interessiert hier nur die Keyboard HID. Ein Beispiel für deren Anwendung befindet sich hier. Ich habe aus diesem Beispiel nur die Teile heraus gesucht, die für das Keyboard-HID erforderlich sind:

Zuerst muss die Headerdatei eingebunden werden.

#include "Adafruit_TinyUSB.h"

Dann wird das Keyboard eingerichtet:

// -------- USB HID KEYBOARD -----------
enum { RID_KEYBOARD = 1 };
uint8_t const desc_hid_report[] = { TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(RID_KEYBOARD)) };
uint8_t keycode[6] = { HID_KEY_NONE, HID_KEY_NONE, HID_KEY_NONE, HID_KEY_NONE, HID_KEY_NONE, HID_KEY_NONE };
Adafruit_USBD_HID usb_hid;

keycode[] ist ein Array in dem der zu übertragende Text aufbereitet und an usb_hid übergeben wird. Dafür stehen Konstanten in hid.h zur Verfügung.

Ob keycode[] nur 6 Elemente enthalten darf werde ich später noch klären.

Die Anwendung ist dann ganz einfach:

keycode[0] = HID_KEY_C;
usb_hid.keyboardReport(RID_KEYBOARD, KEYBOARD_MODIFIER_LEFTCTRL, keycode);
delay(10);
usb_hid.keyboardRelease(RID_KEYBOARD);
  • In keycode[] werden die Werte eingetragen.
  • Der KEYBOARD_MODIFIER ist normalerweise 0.
  • Mit usb_hid.keyboardReport() werden die Daten zum PC geschickt.
  • Dann wird kurz gewartet (wahrscheinlich hier 10mS).
  • Und schließlich mit usb_hid.keyboardRelease() dem PC mitgeteilt, dass die Übertragung beendet ist.

Die Übertragung ist sehr zeitkritisch! Zwei gleiche Zeichen direkt hintereinander (Hallo) funktioniert meistens nicht. Hier das Ergebnis zur zuverlässigen Übertragung von „Hallo\n“:

// ----- btn_12 action
void btn_12_pressAction(void) {
  if (btn_12.justPressed()) {
    keycode[0] = HID_KEY_H;
    keycode[1] = HID_KEY_NONE;
    keycode[2] = HID_KEY_NONE;
    keycode[3] = HID_KEY_NONE;
    keycode[4] = HID_KEY_NONE;
    keycode[5] = HID_KEY_NONE;
    usb_hid.keyboardReport(RID_KEYBOARD, KEYBOARD_MODIFIER_LEFTSHIFT, keycode);
    delay(10);
    usb_hid.keyboardRelease(RID_KEYBOARD);
    delay(25);
    keycode[0] = HID_KEY_A;
    keycode[1] = HID_KEY_L;
    keycode[2] = HID_KEY_NONE;
    keycode[3] = HID_KEY_NONE;
    keycode[4] = HID_KEY_NONE;
    keycode[5] = HID_KEY_NONE;
    usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
    delay(10);
    usb_hid.keyboardRelease(RID_KEYBOARD);
    delay(25);
    keycode[0] = HID_KEY_L;
    keycode[1] = HID_KEY_O;
    keycode[2] = HID_KEY_NONE;
    keycode[3] = HID_KEY_NONE;
    keycode[4] = HID_KEY_NONE;
    keycode[5] = HID_KEY_NONE;
    usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
    delay(10);
    usb_hid.keyboardRelease(RID_KEYBOARD);
    delay(25);
    keycode[0] = HID_KEY_ENTER;
    keycode[1] = HID_KEY_ENTER;
    keycode[2] = HID_KEY_NONE;
    keycode[3] = HID_KEY_NONE;
    keycode[4] = HID_KEY_NONE;
    keycode[5] = HID_KEY_NONE;
    usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
    delay(10);
    usb_hid.keyboardRelease(RID_KEYBOARD);
    btn_12.drawSmoothButton(true);
  }
}
void btn_12_releaseAction(void) {
  if (btn_12.justReleased()) {
    usb_hid.keyboardRelease(RID_KEYBOARD);
    btn_12.drawSmoothButton(false);
  }
}

Sonderbarer Weise wird Enter nur zuverlässig übergeben, wenn es zweimal gesendet wird! Es kommt zu keiner doppelten Erkennung! Es funktioniert auch, wenn Enter im ersten und im letzten Element übergeben werden.

Mysterium

Wenn schon vorher Text eingegeben wurde wird meistens 2x \n ausgegeben?!