-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
ESP-NOW error 0x306a if channel is not 1 #7903
Comments
Hello, I was recently playing around with the However, I found some workarounds and made some examples that are might be worth sharing for anyone who will need to work on these issues or want to use the module thoroughly. Broadcast messagesWhile the
Here is an example for these conditions: Demo sender's codeimport espidf
import espnow
import time
import wifi
MAC_SOURCE = b'\xf4\x12\xfa\xcb\xe8\x94' # Somewhat irrelevant
MAC_BROADCAST = b'\xFF\xFF\xFF\xFF\xFF\xFF'
MAC_TARGET = b'\xdcTueX\xb8' # You need to have a listener with this MAC (Can be changed)
MAC_NOBODY = b'\x01\x02\x03\x04\x05\x06'
# Preparing the Wi-Fi radio
wifi.radio.enabled = True
wifi.radio.mac_address = MAC_SOURCE
# Preparing ESP-NOW
e = espnow.ESPNow()
peer_broadcast = espnow.Peer(mac=MAC_BROADCAST)
e.peers.append(peer_broadcast)
# Sending messages with only 1 registered peer
print("Sending message without specific target...")
try:
e.send("Hello world :)")
print("> Success")
except espidf.IDFError: # Should be "ESP-NOW error 0x3069"
print("> Failure")
print("Sending message with specific target...")
try:
e.send("Hello world :)", peer_broadcast)
print("> Success")
except espidf.IDFError: # Should not trigger
print("> Failure")
# Adding peer whose MAC isn't used by anyone.
peer_nobody = espnow.Peer(mac=MAC_NOBODY)
e.peers.append(peer_nobody)
# Sending messages with 2 registered peers
print("Sending message without specific target...")
try:
e.send("Hello world :)")
print("> Success")
except espidf.IDFError: # Should be triggerred
print("> Failure")
# Adding peer whose MAC is used and should receive messages.
peer_valid = espnow.Peer(mac=MAC_TARGET)
e.peers.append(peer_valid)
# Sending messages with 3 registered peers
print("Sending message without specific target...")
try:
e.send("Hello world :)")
print("> Success")
except espidf.IDFError: # Should not trigger
print("> Failure")
# Finishing
print("Done !")
e.deinit() For the receiver, use the one below. Channel switchingIt appears that you can change the interface's channel by quickly creating an AP with the desired channel number and stopping it directly after. The only issue with this approach is that you have to wait for any messages sent to be acknowledged or marked as a failed delivery in the internal callback. See Timing issue examplesAll these examples have two devices:
No waiting
Waiting for 100ms
Sender's codeimport espnow
import time
import wifi
MAC_SOURCE = b'\xf4\x12\xfa\xcb\xe8\x94'
MAC_TARGET = b'\xdcTueX\xb8'
# Preparing the Wi-Fi radio
wifi.radio.enabled = True
wifi.radio.mac_address = MAC_SOURCE
# Preparing ESP-NOW
e = espnow.ESPNow()
# Iterating over the desired channels
message_count = 0
for channel in [1, 9, 1, 9, 1, 9, 1]:
print("Sending a message on channel " + str(channel))
# Moving to the correct channel.
wifi.radio.start_ap(ssid="Moving channels...", channel=channel)
wifi.radio.stop_ap()
# Re-creating the peer to share the target MAC.
peer = espnow.Peer(mac=MAC_TARGET, channel=channel, interface=0)
e.peers.append(peer)
message = "Hello channel {}, this is message {} !".format(channel, message_count).encode("utf-8")
# Sending data directly (Not working)
#e.send(message, peer)
# Sending data in a loop (Works just fine)
for i in range(5):
e.send(message, peer)
time.sleep(0.1)
# Freeing the peer and ESP-NOW
e.peers.remove(peer)
message_count = message_count + 1
# Finishing
print("Done !")
e.deinit() Receiver's codeThe receiver's code is pretty much lifted as-is from the documentation and only has a bit to change the channel import espnow
import wifi
TARGET_CHANNEL = 9
wifi.radio.enabled = True
wifi.radio.start_ap(ssid="NO_SSID", channel=TARGET_CHANNEL)
wifi.radio.stop_ap()
e = espnow.ESPNow()
packets = []
print("Waiting for packets...")
while True:
if e:
packet = e.read()
print(packet)
if packet.msg == b'end':
break |
I was also getting issues when using ESPNow to communicate between a ESP32-S2 and a S3. In all this, I found that the initialization need to be a bit different between them. For ESP32-S2, the initialization need to be this (see that I am communicating with 2 different ESP32 boards, one with ESP32-S3 and other with ESP32-S2): # MAC Address value needed for the wireless communication
my_mac_address = [0x68, 0xb6, 0xb3, 0x01, 0xf7, 0xf3]
mac_address_power_switch_board = [0x68, 0xb6, 0xb3, 0x01, 0xf7, 0xf1]
mac_address_motor_board = [0x68, 0xb6, 0xb3, 0x01, 0xf7, 0xf2]
wifi.radio.enabled = True
wifi.radio.mac_address = bytearray(my_mac_address)
wifi.radio.start_ap(ssid="NO_SSID", channel=1)
wifi.radio.stop_ap()
_espnow = ESPNow.ESPNow()
motor = motor_board_espnow.MotorBoard(_espnow, mac_address_motor_board, system_data) # System data object to hold the EBike data
power_switch = power_switch_espnow.PowerSwitch(_espnow, mac_address_power_switch_board, system_data) # System data object to hold the EBike data The code to send and receiveclass MotorBoard(object):
def __init__(self, _espnow, mac_address, system_data):
self._motor_board_espnow = _espnow
peer = ESPNow.Peer(mac=bytes(mac_address), channel=1)
self._motor_board_espnow.peers.append(peer)
self._packets = []
self._system_data = system_data
self.motor_board_espnow_id = 1
def process_data(self):
try:
data = self._motor_board_espnow.read()
if data is not None:
data = [n for n in data.msg.split()]
self._system_data.battery_voltage_x10 = int(data[0])
self._system_data.battery_current_x100 = int(data[1]) * -1.0
self._system_data.motor_current_x100 = int(data[2]) * -1.0
self._system_data.motor_speed_erpm = int(data[3])
self._system_data.brakes_are_active = True if int(data[4]) == 1 else False
except:
supervisor.reload()
def send_data(self):
try:
system_power_state = 1 if self._system_data.system_power_state else 0
self._motor_board_espnow.send(f"{int(self.motor_board_espnow_id)} {system_power_state}")
except:
supervisor.reload() class PowerSwitch(object):
def __init__(self, _espnow, mac_address, system_data):
self._system_data = system_data
self.power_switch_id = 4 # power switch ESPNow messages ID
self._espnow = _espnow
self._peer = ESPNow.Peer(mac=bytes(mac_address), channel=1)
self._espnow.peers.append(self._peer)
def update(self):
try:
self._espnow.send(f"{self.power_switch_id} {int(self._system_data.display_communication_counter)} {int(self._system_data.turn_off_relay)}")
except:
supervisor.reload() For ESP32-S3, the initialization need to be this (see that I am communicating only with a ESP32-S2): wifi.radio.enabled = True
my_mac_address = [0x68, 0xb6, 0xb3, 0x01, 0xf7, 0xf2]
wifi.radio.mac_address = bytearray(my_mac_address)
# MAC Address value needed for the wireless communication with the display
display_mac_address = [0x68, 0xb6, 0xb3, 0x01, 0xf7, 0xf3]
display = display_espnow.Display(display_mac_address, system_data) The code to send and receiveclass Display(object):
"""Display"""
def __init__(self, display_mac_address, system_data):
self._system_data = system_data
self.my_espnow_id = 1
self._espnow = ESPNow.ESPNow()
peer = ESPNow.Peer(mac=bytes(display_mac_address), channel=1)
self._espnow.peers.append(peer)
def process_data(self):
try:
data = self._espnow.read()
if data is not None:
data = [n for n in data.msg.split()]
# only process packages for us
if int(data[0]) == self.my_espnow_id:
self._system_data.motor_enable_state = True if int(data[1]) != 0 else False
except:
supervisor.reload()
def update(self):
try:
brakes_are_active = 1 if self._system_data.brakes_are_active else 0
self._espnow.send(f"{int(self._system_data.battery_voltage_x10)} {int(self._system_data.battery_current_x100)} {int(self._system_data.motor_current_x100)} {self._system_data.motor_speed_erpm} {brakes_are_active}")
except:
supervisor.reload() |
I'm not entirely clear on the distinction, other than the shared Everything is |
The only difference is that this code is needed on S2: wifi.radio.start_ap(ssid="NO_SSID", channel=1)
wifi.radio.stop_ap() |
CircuitPython version
Code/REPL
Code and initial testing commentary here (also some on Discord):
https://gist.github.com/anecdata/f46a1d07add5fc60cfbcf42dc7be6528
Behavior
The most limiting issue right now I think is that if peer channel is set to anything except
0
(default; becomes channel 1) or1
, send will result inespidf.IDFError: ESP-NOW error 0x306a
. ESP-NOW should operate on any channel. This also prevents running wifi and ESP-NOW simultaneously unless the AP is on channel 1.A couple of other initial questions or issues after testing ESP-NOW... we can put them into separate issues if warranted:
when encryption is used, RSSI is always returned as 0
ValueError: phy_rate must be 0-42
but should allow up to 54Mbps? 36 is allowed to be set, but 24 is the highest that seems to work between sender and receiver.using broadcast peer address results in
ESP-NOW error 0x3066
on send, not sure if this is intended to be supported right nowESP-NOW error 0x306b
if a peer is added more than oncepackets are limited to 250 bytes, trying to send 251 results in
espidf.IDFError: ESP-NOW error 0x306a
but perhaps there's a friendlier input validation error that can be raised?e = espnow.ESPNow()
results inRuntimeError: Already running
if done more than once, but RTD says it's a Singleton:...also unexpected:
Addendum: Two additional nice-to-have features:
Give user code a way to get the number of messages in the buffer. On PSRAM boards, large buffers can be allocated to accommodate high ESP-NOW traffic. Would be nice for user code to see how well it's keeping up. And how many messages have been lost.
Monitor
might be a good example for these.allow configuring more than the default 7 encrypted pairs (can be up to 17, but trades off with SoftAP). Update: An issue has been filed with Espressif to allow runtime configuration of max encrypted pairs.
Addendum 2: Another issue:
microcontroller.ResetReason.WATCHDOG
numerous times per day.Description
No response
Additional information
No response
The text was updated successfully, but these errors were encountered: