micropython / micropython-esp32

Old port of MicroPython to the ESP32 -- new port is at https://github.com/micropython/micropython
MIT License
673 stars 216 forks source link

ESP-Now Protocol #197

Closed nickzoic closed 4 years ago

nickzoic commented 6 years ago

ESP-Now offers a low-level adhoc network over 802.11 frames ... make this available from a nice MicroPython API.

Refs: http://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf http://esp-idf.readthedocs.io/en/latest/api-reference/wifi/esp_now.html http://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf chapter 3.8

This is related to #176 (mesh networking) and #188 (generalized packet objects)

nickzoic commented 6 years ago

The API is subject to change but I've made a start at https://github.com/nickzoic/micropython-esp32/tree/esp32-espnow

mcauser commented 6 years ago

It seems the protocol can be used on both ESP8266 + ESP32.

I wonder if an Arduino+nrf24l01 could be modified to send esp-now packets

nickzoic commented 6 years ago

Yeah, I'd like to get around to implementing it on MicroPython/ESP8266 as well. Don't tell anyone, but the unencrypted form is pretty easy to send and receive from a Linux "monitor" device as well :-)The encrypted version may take a little more reverse engineering.

ghost commented 6 years ago

Is there somewhere a working example? I got this to work alright if I first connect to a WiFi ap, but I suppose the whole point is that this should not be needed.

Without AP connection, espnow.send throws RuntimeError: ESP-Now Unknown Error 0x306c..

There is an example in the espressif docs (https://github.com/espressif/esp-idf/tree/master/examples/wifi/espnow)... but I thought I'd ask here first.

nickzoic commented 6 years ago

I assume you mean from the micropython espnow branch?

I'll have to rewrite some of this stuff, and provide a better example, but here's an example of broadcast based on http://nick.zoic.org/art/rocket-surgery-airborne-iot-telemetry-buzzconf/

import network
w = network.WLAN(network.STA_IF)
w.active(True)
w.config(protocol=network.MODE_LR)
from esp import espnow
espnow.init()
espnow_bcast = b'\xFF' * 6
espnow.add_peer(w, espnow_bcast) 
seq = 0
while True:
    msg = "Hello World %d" % seq
    espnow.send(espnow_bcast, msg)
    time.sleep(0.004)
    seq += 1

Receiving is even simpler:

import network
w = network.WLAN()
w.active(True)
w.config(protocol=network.MODE_LR)
from esp import espnow
espnow.init()
while True:
    msg = espnow.recv()
    if msg: print(msg[1])

The important bits are:

I'm going to rewrite it so that espnow.recv() is easier to use asynchronously or as a socket ... it is just a proof-of-concept at the moment.

Mbonea-Mjema commented 6 years ago

Hey am new to micropython can you tell me how to get the esp-now working on my esp8266..that is how to install it and some few examples on it.. thanks

deshipu commented 6 years ago

@Mbonea-Mjema it's not yet implemented for the esp8266.

eviscares commented 5 years ago

Any hope of the pr that was closed a couple of days ago being merged soonish? Would love to avoid lora as another complication.

thomasfla commented 5 years ago

Yeah, I'd like to get around to implementing it on MicroPython/ESP8266 as well. Don't tell anyone, but the unencrypted form is pretty easy to send and receive from a Linux "monitor" device as well :-)The encrypted version may take a little more reverse engineering.

@nickzoic This is exactly what I want to do! Do you have a working example? What library do you use to send raw wifi vendor specific action frame?

johncblacker commented 5 years ago

I built MP from the esp-now repository and flashed to a couple of chips. The send program seems to be OK, but the receiver gets an error that espnow.recv() doesn't exist. Indeed if I do: from esp import espnow help(espnow) I do not see a recv function. Something is missing. Perhaps there is a later repository that I should have built from? Help would be greatly appreciated.

johncblacker commented 5 years ago

I believe the receive example leaves a bit of tweaking. First, there is no espnow.recv function, only a espnow.set_recv_cb(callback function); secondly, I don't think the order of the statements is very helpful. I tweaked it a bit to come up with: import network w = network.WLAN() w.active(True) w.config(protocol=network.MODE_LR) from esp import espnow espnow.init() msg = ("", 0)

def receivecb(msg): print("in recv") if msg: print(msg[1])

espnow.set_recv_cb(receivecb(msg))

while True: pass

msg = espnow.recv()

Problem is: I'm not getting anything printed out! Anyone have any ideas?

johncblacker commented 5 years ago

OK, fixed my received problem; here is the final send code (had an error) and receive code: --------------------------- send code final version ---------------------------- import network import time w = network.WLAN(network.STA_IF) w.active(True) w.config(protocol=network.MODE_LR) from esp import espnow espnow.init() espnow_bcast = b'\xFF' * 6 espnow.add_peer(w, espnow_bcast) seq = 0 while True: msg = ("Hello World %d" % seq) espnow.send(espnow_bcast, msg) time.sleep(0.2) print("sent %d" % seq) seq += 1 --------------------------------- end of send code ------------------------------------------ and the receive code: -------------------------------- start of receive code ---------------------------------------- import network w = network.WLAN() w.active(True) w.config(protocol=network.MODE_LR) from esp import espnow espnow.init() msg = ("", 0)

def receivecb(*dobj): print("in recv") if dobj: print(dobj[0])

print(" len, %d\n" % dobj[1])

espnow.set_recv_cb(receivecb)

while True: pass

msg = espnow.recv()

----------------------------------------- end of receive code ----------------------------- Here is what receive prints out: (b'0\xae\xa4\xfe\x92\x18', b'Hello World 89')

in recv

(b'0\xae\xa4\xfe\x92\x18', b'Hello World 90')

in recv

(b'0\xae\xa4\xfe\x92\x18', b'Hello World 91')

in recv

(b'0\xae\xa4\xfe\x92\x18', b'Hello World 92')

in recv

(b'0\xae\xa4\xfe\x92\x18', b'Hello World 93')

As you can see, the first member of the tuple is the mac address and the next part is the text send by the sender. Since the sender is using a "broadcast" address ( = 6 bytes of 0x'ff') every device on the network would produce the same output. A specific address can be used to send only to a specific machine. But I haven't figured that out yet.

KKawase0104 commented 5 years ago

@johncblacker

Hello.

Your script is very helpful.

When I run a script similar to your script for a long time, "core panic" is occured on the receiving side. Such a phenomenon was not happening?

Thank you.

https://github.com/micropython/micropython/pull/4115#issuecomment-476050962

johncblacker commented 5 years ago

Sorry I can't help you; I didn't write the underlying espnow.c module, I just made changes to the originally posted script (which didn't work for me). How long did it take before it fails? Did you make your own firmware from the esp-now branch of the repository? I only let my program run for a couple of minutes and it continued to work that long. I believe the question would probably be best answered by the original author. Remember, this is not officially released code; therefore, there may be (and probably are) bugs somewhere that will only surface with exhaustive testing.

KKawase0104 commented 5 years ago

Hello,

Thank you for your reply. I was using shawwwn's repository because I thought it was the newest esp now module, but now I see it's not your module, sorry about that.

commit 21e3426f7dec96c46d921fa16bb8e5db06572771

It took some time for the core panic to occur, but I don't remember exactly how long. When I tried after changing the sending side interval to 10msec, the core panic occurred after a couple minutes had passed. I also tried again using gc.mem_free on the receiving side. The timing of the core panic seems to be based on gc's collection timing.

The sending and receiving sides my original script were the same, which made it hard for me to tell where the core panic was occurring, but with your script I could see it was on the receiving side.

Thank you so much for your time.

nickzoic commented 4 years ago

Discussion of this is now over at micropython/micropython#4115 and I'll make a new issue and/or pull request for on-going changes soon.

The problem you've described with panics is quite possibly caused by the memory allocation issue raised here: https://github.com/micropython/micropython/pull/4115#issuecomment-484375819

In the meantime I'm closing this issue as the micropython-esp32 repo is closed now.