# การใช้โปรโตคอล ESP-NOW

## 1. การแนะนำฟังก์ชัน

ESP-NOW เป็นโปรโตคอลการสื่อสารไร้สายอีกอย่างหนึ่งที่ถูกพัฒนาโดย Espressif ซึ่งทำให้อุปกรณ์หลายตัวสามารถสื่อสารกันได้โดยไม่ต้องใช้ Wi-Fi หรือใช้ Wi-Fi ได้ตามต้องการ โปรโตคอลนี้คล้ายกับการเชื่อมต่อไร้สาย 2.4GHz แบบพลังงานต่ำที่พบได้บ่อยในเม้าส์ไร้สาย โดยอุปกรณ์จะถูกเชื่อมต่อกันก่อนที่จะสื่อสารกันได้ หลังจากการเชื่อมต่อแล้ว การเชื่อมต่อระหว่างอุปกรณ์จะเป็นต่อเนื่องแบบ peer-to-peer และไม่ต้องมีการสร้าง handshake protocol โดยเป็นเทคโนโลยีการสื่อสารที่เร็วและมีการส่งข้อมูลแบบสั้นๆ โดยไม่ต้องมีการเชื่อมต่อ ซึ่งช่วยให้คอนโทรลเลอร์พลังงานต่ำสามารถควบคุมอุปกรณ์อัจฉริยะได้โดยตรงโดยไม่ต้องเชื่อมต่อกับเราเตอร์ นี่เหมาะสำหรับสถานการณ์เช่นไฟอัจฉริยะ การควบคุมระยะไกล และการส่งข้อมูลเซ็นเซอร์กลับมา

หลังจากใช้การสื่อสาร ESP-NOW ถ้ามีอุปกรณ์บางตัวสูญเสียพลังงานโดยไม่ได้ปิดเสียงเชื่อมต่อกับอุปกรณ์ที่เหลือไว้ ให้เริ่มต้นอุปกรณ์นั้นใหม่ ก็จะเชื่อมต่อกับโหนดที่เหลืออยู่โดยอัตโนมัติเพื่อดำเนินการสื่อสารต่อไป

โหมดการสื่อสารที่รองรับโดย ESP-NOW มีดังนี้:

* one-to-one communication
* one-to-many communication
* many-to-one communication
* many-to-many communication

ESP-NOW รองรับคุณสมบัติดังนี้:

* การเข้ารหัสแพคเก็ตแบบยูนิแคสต์หรือการสื่อสารแบบยูนิแคสต์โดยไม่มีการเข้ารหัสแพคเก็ต
* การใช้งานผสมระหว่างอุปกรณ์ที่มีการเข้ารหัสจับคู่และอุปกรณ์ที่ไม่มีการเข้ารหัสจับคู่
* สามารถบรรทุกข้อมูล payload ได้สูงสุดถึง 250 ไบต์
* รองรับการตั้งค่าฟังก์ชันการส่งแบบ callback เพื่อแจ้งให้ชั้นแอปพลิเคชันทราบเมื่อการส่งแฟรมไม่สำเร็จหรือสำเร็จ

ต่อไปนี้เป็นข้อ จำกัด ของ ESP-NOW:

* ไม่รองรับการส่ง Broadcast packet ชั่วคราว;
* มีข้อจำกัดในการใช้กับอุปกรณ์ที่เป็นคู่ระหว่างการเข้ารหัส
  * ในโหมด Station รองรับคู่ระหว่างการเข้ารหัสได้สูงสุด 10 อุปกรณ์;
  * ในโหมด SoftAP หรือ SoftAP + Station mixed mode รองรับคู่ระหว่างการเข้ารหัสได้สูงสุด 6 อุปกรณ์;
  * จำนวนอุปกรณ์ที่เป็นคู่ระหว่างการเข้ารหัสไม่เกิน 20 อุปกรณ์ทั้งหมด;
* ขนาดของข้อมูล payload สามารถรับได้สูงสุด 250 ไบต์.

การควบคุมกลุ่ม Petoi สามารถใช้ฟังก์ชันการสื่อสาร ESP-NOW ของ ESP8266 ได้

## 2. Setup for ESP-NOW

### 2.1 Hardware setup

ในกรณีนี้ เตรียมอุปกรณ์ 2 ตัวของ Bittle (ที่มี ESP8266 ติดตั้งอยู่) และคอมพิวเตอร์ที่เชื่อมต่อกับ ESP8266 1 ตัว

<figure><img src="https://3127300255-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBR9bYMZnmeFFa1GJLvjM%2Fuploads%2FLOCCDHPTGiSmkpAdyRSc%2Fstructure.png?alt=media&#x26;token=2ddd7046-900b-414f-bdb0-d2bcace4699a" alt=""><figcaption></figcaption></figure>

ข้อมูลต่อไปนี้เกี่ยวกับการอัปโหลดโปรแกรมและการเรียกรูปแบบ MAC ของโมดูลในรูปภาพ

### 2.2 Software setup

ติดตั้งโปรแกรม Thonny บนคอมพิวเตอร์เพื่อให้สะดวกในการดีบั๊ก MicroPython ของโมดูล ESP8266 โดยใช้โปรโตคอล ESP-NOW ต้องใช้เฟิร์มแวร์ MicroPython เฉพาะ (ดูที่ [Github](https://github.com/glenn20/micropython-espnow-images)). เนื่องจากเวอร์ชันธรรมดาของฟิวเจอร์เซ็ต MicroPython สำหรับ 8266 จะแจ้งเตือนว่าไม่พบไลบรารี

เปิดโปรแกรม Thonny และใช้ USB uploader เพื่อเชื่อมต่อโมดูล ESP8266 แล้วป้อนคำสั่งต่อไปนี้ใน shell interface:

```python
import espnow
```

หากมีการแจ้งเตือนข้อผิดพลาดเช่น "ไม่พบโมดูล espnow" แปลว่ามีปัญหาในการอัพโหลดเฟิร์มแวร์ ในขณะที่หากไม่มีการแจ้งเตือน แปลว่าการอัพโหลดเฟิร์มแวร์เสร็จสมบูรณ์

{% hint style="info" %}
ถ้าหลังจากเขียนเฟิร์มแวร์ ESP-NOW แล้วไม่มีสัญลักษณ์ >>> ของ Python ปรากฏในอินเทอร์เฟซเชลล์ หมายความว่าการเขียนเฟิร์มแวร์ล้มเหลว คุณสามารถลองใช้เครื่องมือเผาไฟแบบ Flash ชื่อ NodeMCU-PyFlasher.exe และการตั้งค่าการเผาไฟแสดงในภาพด้านล่าง:

<img src="https://3127300255-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBR9bYMZnmeFFa1GJLvjM%2Fuploads%2FtHp5u5T4EFi6AuaaBjfL%2FNodeMCU_config_espnow.png?alt=media&#x26;token=a27de55b-442d-4d2c-af2c-fe92dae4cdc1" alt="" data-size="original">
{% endhint %}

## 3. Code introduction

โค้ดควบคุมกลุ่มถูกแบ่งเป็น 3 ส่วน:

* Query the MAC address of the module
* Transmitter program
* receiver program

### 3.1 Query the MAC address of the module

หมายเลข MAC คือหมายเลขที่ใช้ในการยืนยันตำแหน่งของอุปกรณ์เครือข่าย และรับผิดชอบในชั้นที่สอง (data link layer) ของโมเดลเครือข่าย OSI หมายเลข MAC ยังเรียกว่าที่อยู่ฟิสิกส์ (physical address) และที่อยู่ฮาร์ดแวร์ (hardware address) มันถูกเขียนลงบนหน่วยความจำที่ไม่สูญเสีย (เช่น EEPROM) ของการ์ดเครือข่ายเมื่อผู้ผลิตอุปกรณ์เครือข่ายผลิตอุปกรณ์นั้นๆ ขึ้นมา

ที่อยู่ MAC เป็นที่อยู่ที่ใช้สำหรับยืนยันตำแหน่งของอุปกรณ์เครือข่าย และรับผิดชอบด้านชั้นที่สอง (data link layer) ของโมเดลเครือข่าย OSI ที่อยู่ MAC ยังเรียกว่าที่อยู่ฟิสิกส์และที่อยู่ฮาร์ดแวร์ จะถูกเขียนลงในหน่วยความจำที่ไม่สูญเสีย (เช่น EEPROM) ของการ์ดเครือข่ายเมื่อมันถูกผลิตโดยผู้ผลิตอุปกรณ์เครือข่าย

ความยาวของที่อยู่ MAC คือ 48 บิต (6 ไบต์) ซึ่งมักแสดงเป็น 12 ตัวเลขฐานสิบหก 3 ไบต์แรกแทนหมายเลขอุปกรณ์ซีเรียลของผู้ผลิตฮาร์ดแวร์เครือข่ายที่ได้รับมอบหมายโดย IEEE (สถาบันวิทยาการและอิเล็กทรอนิกส์) และ 3 ไบต์สุดท้ายแทนหมายเลขอุปกรณ์เครือข่ายบางอย่าง (เช่นการ์ดเครือข่าย) ที่ผลิตโดยผู้ผลิต

เพียงแค่คุณไม่เปลี่ยนที่อยู่ MAC ของคุณ ที่อยู่ MAC จะเป็นเอกลักษณ์ในโลก ด้วยภาพการมองเห็น ที่อยู่ MAC เหมือนหมายเลขบัตรประชาชนบนบัตรประชาชน เป็นเอกลักษณ์

วิธีที่ง่ายที่สุดในการใช้ ESPNOW คือการส่งข้อมูลด้วย MAC address โดยเราจะใช้โปรแกรมเล็ก ๆ เพื่อสอบถาม MAC address ของโมดูล

```python
import ubinascii
import network

wlan_sta = network.WLAN(network.STA_IF)
wlan_sta.active(True)
wlan_mac = wlan_sta.config('mac')
print(ubinascii.hexlify(wlan_mac).decode())Pythonp
```

หลังจากการรันโปรแกรมใน Thonny เสร็จสิ้น โปรแกรมจะแสดง MAC address บน terminal ออกมา ในขณะนี้ คุณสามารถใช้สติ๊กเกอร์สำหรับเขียน MAC address ของโมดูลแล้ววางไว้บนโมดูลได้เลย

### 3.2 Transmitter program

โปรแกรมส่งประกอบด้วยส่วนต่อไปนี้:

* Enable the WiFi function of the module
* Configure the ESP-NOW protocol and enable it
* Add a node (peer) that needs to communicate
* Send a message

โค้ดที่เป็นตัวอย่างเฉพาะ:

```python
import network
import espnow
import time

sta = network.WLAN(network.STA_IF)    # Enable station mode for ESP
sta.active(True)
sta.disconnect()        # Disconnect from last connected WiFi SSID

e = espnow.ESPNow()     # Enable ESP-NOW
e.active(True)

peer1 = b'\xe8\x68\xe7\x4e\xbb\x19'   # MAC address of peer1's wifi interface
e.add_peer(peer1)                     # add peer1 (receiver1)

peer2 = b'\x60\x01\x94\x5a\x9c\xf0'   # MAC address of peer2's wifi interface
e.add_peer(peer2)                     # add peer2 (receiver2)

print("Starting...")            # Send to all peers

e.send(peer1, "walk", True)     # send commands to pear 1
e.send(peer2, "walk", True)     # send commands to pear 2
time.sleep_ms(2000)
e.send(peer1, "walk", True)
e.send(peer2, "back", True)
time.sleep_ms(2000)
```

### 3.3 Receiver program

โปรแกรมตัวรับประกอบด้วยส่วนต่อไปนี้:

* Enable the WiFi function of the module
* Configure the ESP-NOW protocol and enable it
* Add a node (peer) that needs to communicate
* Receive and decode the message, and send commands to NyBoard through the serial port

โค้ดที่เป็นตัวอย่างเฉพาะ:

```python
import network
import espnow
from machine import UART

def espnow_rx():
    #config UART
    uart = UART(0, baudrate=115200)

    # A WLAN interface must be active to send()/recv()
    sta = network.WLAN(network.STA_IF)
    sta.active(True)
    sta.disconnect()                # Disconnect from last connected WiFi SSID

    e = espnow.ESPNow()                  # Enable ESP-NOW
    e.active(True)

    peer = b'\x5c\xcf\x7f\xf0\x06\xda'   # MAC address of peer's wifi interface
    e.add_peer(peer)                     # Sender's MAC registration

    while True:
        host, msg = e.recv()
        if msg:                          # wait for message
            if msg == b'walk':           # decode message and translate
                uart.write("kwkF")       # to the NyBoard's command
            elif msg == b'back':
                uart.write('kbk')
            elif msg == b'stop':
                uart.write('d')

if __name__ == "__main__":
    espnow_rx()
    
```

โค้ดนี้ถูกแพ็กเก็ตไว้ในฟังก์ชันที่ชื่อว่า `espnow_rx()` เพื่อความสะดวกในการเริ่มโปรแกรมโดยอัตโนมัติหลังจากเปิดเครื่องขึ้นมา

มีวิธีสองวิธีในการเรียกใช้โปรแกรมโดยอัตโนมัติหลังจากเปิดเครื่อง:

* Rename the code file to `main.py`;
* Modify the `boot.py` ;

สำหรับผู้เริ่มต้นเราแนะนำอันแรก

### 3.4 Communication-Command Converter

การเขียนการแปลงคำสั่งผ่านทางซีเรียลที่ส่งมาจะทำให้โปรแกรมซับซ้อนและยากต่อการบำรุงรักษา ดังนั้นเราสามารถสร้างฟังก์ชันใหม่เพื่อทำการแปลงคำสั่งและส่งออกคำสั่งได้ โดยจะทำการเก็บคำสั่งที่รับเข้ามาเป็นตัวเลขเดียวกันกับคำสั่งที่ส่งออกไปยังฝั่งอีกข้าง ที่เขียนเป็นฟังก์ชันใหม่ ตั้งชื่อว่า“instruction\_handle()” เพื่อแปลงข้อความที่ได้รับเป็นตัวเลขและส่งออกข้อความตามรูปแบบของคำสั่งที่ต้องการ
