はじめに ESP32からウェブサーバーへHTTPリクエストを送るときは、HTTPClient というライブラリを使うと拍子抜けするほど簡単に書けます。ポイントは、GETでもPOSTでも通信の手順(型)がほとんど同じだということです。まずその型を頭に入れてしまえば、あとは送る中身を変えるだけで応用が効きます。
やることは、接続を開いて(http.begin)、リクエストを送り(http.GET() か http.POST())、返ってきた本文を受け取り(http.getString())、接続を閉じる(http.end())——この4手です。GETとPOSTの違いは、真ん中で呼ぶメソッドと、POSTのときだけ送信する本文を渡すかどうかだけ。この記事では、テスト用のダミーサーバーを用意したうえで、GET・POST・HTTPSの順に見ていきます。
開発環境 この記事は、次の環境で動作を確認しています。
項目 値 ボード ESP32-DevKitC IDE PlatformIO ファームウェア arduino-esp32 #2.0.2 HTTPClient ver 2.0.0 テスト用のダミーサーバーを用意する いきなり本番のサーバーに投げる前に、手元でリクエストを受け止めてくれる小さなサーバーがあると開発がぐっと楽になります。Pythonの標準ライブラリだけで書けるので、次の構成でファイルを2つ用意します。
. ├── dummy_root │ └── status.json └── dummy_server.py dummy_server.py は、/status へのGETにJSONを返し、/data へのPOSTを受け取って中身をログに出すだけの内容です。
from http.server import HTTPServer, BaseHTTPRequestHandler import os import re import logging import socket host_list = socket.gethostbyname_ex(socket.gethostname()) lan_address = host_list[2][1] dirname = os.path.dirname(__file__) server_ip = "0.0.0.0" server_port = 9998 lan_url = "http://{}:{:d}".format(lan_address, server_port) url = "http://{}:{:d}".format(server_ip, server_port) os.chdir(dirname + "/dummy_root/") def load_file(path): with open(path, mode='r') as f: s = f.read() return s.encode('utf-8') class S(BaseHTTPRequestHandler): def do_GET(self): m = re.match(r'^/status$', self.path) if m != None: self.send_response(200) self.send_header('Content-type', 'application/json') self.end_headers() self.wfile.write(load_file("status.json")) def do_POST(self): print('======================= POST ======================='); print(self.path) m = re.match(r'^/data$', self.path) if m != None: content_length = int(self.headers['Content-Length']) post_data = self.rfile.read(content_length) print('======================= HTTP Request ======================='); logging.info("POST request,\nPath: %s\nHeaders:\n%s\n\nBody:\n%s\n", str(self.path), str(self.headers), post_data.decode('utf-8')) self.send_response(200) self.send_header('Content-Type', 'application/json') self.end_headers() self.wfile.write('{"status":"ok"}'.encode('utf-8')) def web_server(): logging.basicConfig(level=logging.INFO) httpd = HTTPServer(('', server_port), S) logging.info('Starting httpd...\n') httpd.serve_forever() if __name__ == "__main__": print(lan_url) print(url) web_server() 冒頭の gethostbyname_ex は、起動時にLAN側のURLを表示するための便宜的な処理です。環境によってはLANのIPアドレスをうまく拾えず別の値が出ることがあるので、ESP32側から接続するアドレスは、後述のコードのようにPCの実際のIPアドレス(ipconfig や ifconfig で確認できます)を直接指定するのが確実です。status.json の中身はごく簡単なもので構いません。
...