Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

espnow cannot send to a broadcast address #9380

Open
gitcnd opened this issue Jun 28, 2024 · 8 comments
Open

espnow cannot send to a broadcast address #9380

gitcnd opened this issue Jun 28, 2024 · 8 comments
Labels
bug espressif applies to multiple Espressif chips network
Milestone

Comments

@gitcnd
Copy link

gitcnd commented Jun 28, 2024

CircuitPython version

Adafruit CircuitPython 9.1.0-beta.1-18-g781c577745 on 2024-05-11; sunton_esp32_2432S028 with ESP32

Code/REPL

import wifi
import espnow
import time

# Disable WiFi
wifi.radio.enabled = False

# Initialize ESPNOW
esp = espnow.ESPNow()
esp.phy_rate = 0  # Default physical layer rate

if 0: # enabling this line makes the problem go away
    peer = espnow.Peer(b'\x24\xdc\xc3\x8b\xe1\xc8')
    esp.peers.append(peer)

# Add a broadcast peer 
peer = espnow.Peer(b'\xff\xff\xff\xff\xff\xff')
esp.peers.append(peer)

print("Broadcasting message...")

while True:
    try:
        esp.send(b'hello world')
        print("Sent.")
    except Exception as e:
        print(f"esp.read() error: {e}")
    time.sleep(5)  # Send the message every 5 seconds

# exec(open("espnowsender.py").read())

Behavior

Adafruit CircuitPython 9.1.0-beta.1-18-g781c577745 on 2024-05-11; sunton_esp32_2432S028 with ESP32
>>> 
>>> exec(open("estnowtst1.py").read())
Broadcasting message...
esp.read() error: ESP-NOW error 0x3069
esp.read() error: ESP-NOW error 0x3069
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 28, in <module>
KeyboardInterrupt: 
>>> 

Description

Change the "if 0:" to "if 1:" and this is what we see:-

>>> exec(open("estnowtst2.py").read())
Broadcasting message...
Sent.
Sent.
Sent.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 28, in <module>
KeyboardInterrupt: 
>>> 

The logically identical code in micropython works fine

MicroPython version:

import network
import espnow

sta = network.WLAN(network.STA_IF)
sta.active(True)
sta.disconnect()
e = espnow.ESPNow()
e.active(True)
peer = b'\xff\xff\xff\xff\xff\xff' # broadcast mac address to all esp32's (not esp8266)
e.add_peer(peer)      # Must add_peer() before send()

e.send(peer, "Starting...")
for i in range(100):
    e.send(peer, str(i)*20, True) # Supposedly capable of 89250bytes/sec
e.send(peer, b'end')

Additional information

It also does not allow channel numbers - the below errors out:-
peer = espnow.Peer(b'\x24\xdc\xc3\x8b\xe1\xc8', channel=9)
as mentioned in #7903

The "receiver" side of the code does seem to semi-work (gets packets from my micro-python version) but experiences a very high number of read error exceptions

espnowclient.py

import wifi
import espnow
import binascii

# Disable WiFi
#wifi.radio.enabled = False

# Initialize ESPNOW
esp = espnow.ESPNow()
esp.phy_rate = 0  # Default physical layer rate

# Add a broadcast peer
#peer = espnow.Peer(b'\xff\xff\xff\xff\xff\xff', channel=9) # bug - crashes it
peer = espnow.Peer(b'\xff\xff\xff\xff\xff\xff') 
esp.peers.append(peer)

def packet_to_hex_and_ascii(packet):
    hex_data = binascii.hexlify(packet.msg)
    ascii_data = ''.join(chr(b) if 32 <= b <= 126 else '.' for b in packet.msg)
    return hex_data, ascii_data

#print("\033[2J\033[HListening for ESPNOW packets on channel 9...")
print("\033[2J\033[HListening for ESPNOW packets on wifi channel...")

while True:
    try:
        packet = esp.read()
    except Exception as e:
        print(f"esp.read() error: {e}")
    if packet:
        hex_data, ascii_data = packet_to_hex_and_ascii(packet)
        print("Received packet:")
        print("Hex: ", hex_data)
        print("ASCII: ", ascii_data)
        print("sender mac: ",  binascii.hexlify(packet.mac)  )
        print("rssi: ", packet.rssi )
        print("time: ", packet.time )


# exec(open("espnowclient.py").read())
@gitcnd gitcnd added the bug label Jun 28, 2024
@gitcnd
Copy link
Author

gitcnd commented Jun 28, 2024

Update;
while adding b'\xff\xff\xff\xff\xff\xff' as a peer seems to stop the error - the corresponding receiver listening to broadcast traffic does not receive anything.

@gitcnd
Copy link
Author

gitcnd commented Jul 1, 2024

I'm planning to take a look at this and #7903. For reference: ( https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/error-codes.html )

ESP_ERR_ESPNOW_INTERNAL (0x306a): Internal error

ESP_ERR_ESPNOW_NOT_FOUND (0x3069): ESPNOW peer is not found

leave a note here if you've done (or are doing) any work on it, so no effort gets duplicated.

@dhalbert dhalbert added this to the Long term milestone Jul 3, 2024
@dhalbert dhalbert added network espressif applies to multiple Espressif chips labels Jul 3, 2024
@gitcnd
Copy link
Author

gitcnd commented Jul 7, 2024

I was unable to get circuitpython to reliably (or in most cases - at all) communicate with micropython over espnow (packet corruption and loss mostly when it semi-worked, or nothing at all most of the time probably due to code issue in the peer address setup/handling).
I was unable to work out where/how in the code to fix this, or where the issue might be (I used "printf()" in the C to emit debug info - couldn't work it out still).
For now - I'm giving up on this.

@stanelie
Copy link

stanelie commented Nov 7, 2024

Adding b'\xff\xff\xff\xff\xff\xff' as a peer does not work for me :
peer = espnow.Peer(b'\xff\xff\xff\xff\xff\xff')
I get error message espidf.IDFError: ESP-NOW error 0x3069 ((0x3069): ESPNOW peer is not found)

Without the possibility of sending gratuitous broadcast packets and receiving them, it is not possible to pair ESPNow devices.

Is there any update on this?

@Sola85
Copy link

Sola85 commented Nov 7, 2024

I am using circuitpython + ESPNow for a custom sensor and this has been working reliably for the past few months - also using the broadcast adress.

My receiver is additionally using wifi, so I had to fix the Wifi channel in my router settings (in this case to channel 6).
One then has to force the transmitter to also use this channel. As far as I know, this can only be done using the wifi api and not using the ESPNow api.

Here are snippets of my code:
Receiver:

async def handle_esp_now():
    e = espnow.ESPNow()
    while True:
        await asyncio.sleep(0.1)
        if not e: continue

        packet = e.read()
        last_received_data = json.loads(packet.msg.decode())
        if "topic" in last_received_data:
            mqtt_client.publish(last_received_data["topic"], json.dumps(last_received_data))

Transmitter:

# hack to switch channel that is used for ESPNow
# this takes just a few milliseconds, so doesn't waste a lot of power
wifi.radio.start_ap(" ", "", channel=6, max_connections=0)
wifi.radio.stop_ap()

e = espnow.ESPNow()
peer = espnow.Peer(mac=b'\xff\xff\xff\xff\xff\xff', channel=6)
e.peers.append(peer)

...

data = {
    "voltage": voltage,
    "topic": "state/circuitpy-sensor3"
}
message = json.dumps(data)
e.send(message, peer)

If I remember correctly, the seeming redundancy (specifying the channel twice, i.e. once in the wifi settings as well as in the Peer) and the redundancy of specifying the peer both in e.peers as well as in e.send was both necessary. I had briefly looked into CircuitPython's source but came to the conclusion that its not CircuitPython that is causing the friction here, but that we are instead seeing quirks of the underlying esp-idf.

@stanelie
Copy link

stanelie commented Nov 7, 2024

Well, this is precious information!
I wish this were documented in the circuitpython documentation.
Thanks @Sola85 !

@gitcnd
Copy link
Author

gitcnd commented Nov 7, 2024

Switch to MicroPython - it properly supports channel selection and broadcast addresses.

@stanelie
Copy link

stanelie commented Nov 7, 2024

Sadly, MicroPython has other issues that make it even less desirable for me. For example, the default hardware transmission mode of Circuitpython gives me twice the range of MicroPython's default mode (neither can be switched, it's another bug see #9790 and micropython#16179).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug espressif applies to multiple Espressif chips network
Projects
None yet
Development

No branches or pull requests

4 participants