[TH] การเขียนโปรแกรมไคลเอนต์/เซิร์ฟเวอร์สำหรับสถานีอากาศผ่านระบบเครือข่ายไร้สาย

บทความนี้เป็นตัวอย่างการเขียนโปรแกรมไคลเอนต์/เซิร์ฟเวอร์สำหรับสถานีอากาศผ่านระบบเครือข่ายไร้สาย (Client/Server Programming for Weather Stations via Wireless Networking) โดยใช้ไมโครคอนโทรลเลอร์ esp32 จำนวน 2 ตัวสื่อสารกันผ่านเครือข่ายไร้สาย โดยกำหนดให้ตัวที่ติดตั้งเซ็นเซอร์ DHT22 และ LDR เป็นเครื่องให้บริการ (Server) ทำงานในโหมด AP และบอร์ดไมโครคอนโทรลเลอร์ esp32 อีกบอร์ดหนึ่งทำงานเป็นลูกข่าย และสื่อผ่านทางพอร์ตที่กำหนดขึ้นมาเอง เพื่ออ่านค่าอุณหภูมิ ความชื้นและค่าดิจิทัลที่ได้จากเซ็นเซอร์ LDR ดังภาพที่ 1

ภาพที่ 1 บอร์ดและอุปกรณ์สำหรับการทดลองครั้งนี้

อุปกรณ์การทดลอง

ในบทความใช้บอร์ดไมโครคอนโทรลเลอร์และเซ็นเซอร์ดังรายการต่อไปนี้

  1. บอร์ดไมโครคอนโทรลเลอร์ ESP32 จำนวน 2 บอร์ด
  2. โมดูลเซ็นเซอร์ DHT22
  3. โมดูลเซ็นเซอร์ LDR

การเชื่อมต่อเซ็นเซอร์กับบอร์ดไมโครคอนโทรลเลอร์ esp32 เป็นดังภาพที่ 2

ภาพที่ 2 ผังการเชื่อมต่อเซ็นเซอร์กับบอร์ด ESP32

จากภาพที่ 2 จะพบว่ามีการต่อสายเชื่อมต่อดังนี้

ESP32DHT22LDR
GPIO39I/O
GPIO15I/O
3V3VccVcc
GNDGNDGND

ตัวอย่างโปรแกรม

ตัวอย่างโปรแกรมประกอบด้วย 2 ส่วน คือ ส่วนของบอร์ดที่เชื่อมต่อกับโมดูลเซ็นเซอร์ โดยกำหนดให้เป็นการทำงานแบบ AP และเป็นเครื่องให้บริการ ดังการสื่อสารที่พอร์ต 3002 และโปรแกรมสำหรับตัวลูกข่ายสำหรับร้องขอค่าอุณหภูมิ ความชื้น และค่าที่อ่านได้จากเซ็นเซอร์ LDR

โปรแกรมฝั่งเครื่องให้บริการ

#############################################################
# WeatherStationS.py
# สำหรับเครื่องให้บริการ
# (C) 2021, JarutEx
#############################################################
from machine import Pin,I2C,ADC
import dht
import machine
import gc
import time
import os
import sys
import machine as mc
import network as nw
import ubinascii as ua
import socket
import ssd1306
#############################################################
# system
gc.enable()
gc.collect()
machine.freq(240000000)

i2c = I2C(0,scl=Pin(4), sda=Pin(5), freq=100000)
display = ssd1306.SSD1306_I2C(128, 32, i2c)

###########################################################
# Sensor
dht22 = dht.DHT22(Pin(15))
ldr = ADC(Pin(39))
ldr.width( ADC.WIDTH_12BIT ) # 12bit
ldr.atten( ADC.ATTN_11DB ) # 3.3V

###########################################################
# Main program
APif = nw.WLAN(nw.AP_IF)
# Set WiFi access point name (formally known as ESSID) and WiFi channel
APif.config(essid='JarutEx_WS',
            password='123456789',
            authmode=nw.AUTH_WPA2_PSK,
            channel=1, hidden=True)
APif.active(True)

def showInfo():
    # shiw IPAddress
    display.fill(0)
    display.text("--AP Config.--",0,0,1)
    display.text("{}".format(APif.ifconfig()[0]), 0, 8, 1)
    display.text("{}".format(APif.config('essid')), 0, 16, 1)
    display.show()

showInfo()
# main loop
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP
s.bind(('',3002))
s.listen(5)
try:
    while True:
        conn, addr = s.accept()
        request = conn.recv(1024)
        if (request == b'tem'):
            dht22.measure()
            conn.send("{}".format(dht22.temperature()))
        elif (request == b'hum'):
            dht22.measure()
            conn.send("{}".format(dht22.humidity()))
        elif (request == b'ldr'):
            conn.send("{}".format(ldr.read()))
        else:
            conn.send("na")
        conn.close()
except KeyboardInterrupt:
    pass
s.close()
# end of program
APif.active(False)

โปรแกรมฝั่งเครื่องลูกข่าย

ตัวอย่างโปรแกรมฝั่งลูกข่ายทำหน้าที่เชื่อต่อเข้า AP ของเครื่องให้บริการ และร้องขอข้อมูล tem, hum และ ldr ไปที่พอร์ต 3002 ตามลำดับ และได้ตัวอย่างผลลัพธ์ดังภาพที่ 3

#############################################################
# WeatherStationC.py
# สำหรับเครื่องให้บริการ
# (C) 2021, JarutEx
#############################################################
import machine
import gc
import time
import os
import sys
import network as nw
import ubinascii as ua
import socket

#############################################################
# system
gc.enable()
gc.collect()
machine.freq(240000000)

###########################################################
# Main program
sta = nw.WLAN( nw.STA_IF )
sta.active(True)
# เชื่อมต่อ
sta.connect('JarutEx_WS','123456789')
while not sta.isconnected():
    time.sleep_ms(200)
print(sta.ifconfig())
serverInfo = socket.getaddrinfo( '192.168.4.1', 3002, 0, socket.SOCK_STREAM )[0]
print("Server info : {}".format(serverInfo))
# ร้องขอค่าอุณหภูมิ
s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
s.connect(serverInfo[-1])
s.write(b'tem')
result = s.readline()
s.close()
print("Temperature : {}C".format(result))
# ร้องขอค่าความชื้น
s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
s.connect(serverInfo[-1])
s.write(b'hum')
result = s.readline()
s.close()
print("Humidity : {}%".format(result))
# ร้องขอค่าจาก LDR
s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
s.connect(serverInfo[-1])
s.write(b'ldr')
result = s.readline()
print("LDR Value : {}".format(result))
s.close()


###########################################################
# End of Program
sta.active(False)
ภาพที่ 3 ตัวอย่างการแสดงผลของตัวอย่างโปรแกรมฝั่งลูกข่าย

สรุป

จากตัวอย่างนี้จะพบว่าเป็นการประยุกต์ใช้จากบทความ WiFi ที่ได้กล่าวไปก่อนหน้านี้ โดยเพิ่มเกี่ยวกับการให้บอร์ดหนึ่งทำหน้าที่เป็น AP และเครื่องให้บริการข้อมูลอุณหภูมิ ความชื้นและค่าของ LDR และมีลูกข่ายเชื่อมเข้ากับ AP เดียวกัน ทำให้ทั้ง 2 โหนดนั้นอยู่ภายใต้เครือข่ายเดียวกัน หลังจากนั้นเครื่องลูกข่ายทำการร้องขอข้อมูลไปยังพอร์ต ส่วนฝั่งเครื่องให้บริการเมื่อได้รับคำร้องขอจึงทำการตรวจสอบประเภทของการร้องขอและดำเนินการตามคำร้องขอนั้นพร้อมส่งผลลัพธ์ของการทำงานกลับไป

ถ้าผู้อ่านเข้าใจหลักการเขียนโปรแกรมแบบ Client/Server ของบทความนี้จะสามารถนำไปประยุกต์ใช้สั่งงานในเครือข่ายได้อีกมากมาย และสุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ

ท่านใดต้องการพูดคุยสามารถคอมเมนท์ไว้ได้เลยครับ

แหล่งอ้างอิง

  1. xxx, ESP32 Networking
  2. micropython.org : Network basics
  3. micropython.org : network — network configuration
  4. micropython.org : Network – TCP Sockets
  5. micropython.org : socket — socket module

(C) 2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-09-14, 2021-12-01