農業IoTでサーバー連携に挑戦!…の前にESP32でハマってます
この記事について
今日は本当なら「農業IoTのサーバー連携編」を書く予定でした。
でも実は、本業の方で似たような仕組みを作っていて、そこで絶賛ハマり中…。
なので今回は 「BLEとLoRa、構成は違えど同じESP32でハマる」 という話を、ほぼろらたんに任せてお届けします。

🎀 うーん…Webhookが通らないよ〜。でも、記事はちゃんと任せて!
システム構成(本業編)
- センサー:BLEでデータ送信
- ESP32:BLEを受信 → Wi-Fi経由でWebhook POST
- サーバー(PHP):受信してDB保存・可視化
この業務案件では、センサーからサーバーまで、僕がソフトを担当しています。
もともとはBLEの部分だけだったものを、クラウド対応にするのが今回の業務です。
なので、BLE部分は安定していて、センサー値はしっかりESP32まで届いています。
ここは救い。もしここまで不安定だったら、センサー、ゲートウェイ、サーバー…全部を疑う「三重苦デバッグ」になるところでした。
🎀 BLEが安定してるのはホント大事!“疑う範囲が狭い”ってだけで気持ちが軽くなるもんね
システム構成(農業IoT編)
- センサー(土壌センサーなど):LoRaでデータ送信
- LRA1+M5Stick(ESP32):LoRaを受信 → Wi-Fi経由でWebhook POST
- サーバー(PHP):受信してDB保存・可視化
こちらはBLEの代わりにLoRaを使っているだけで、実は本業と同じように 「ESP32がWi-Fi経由でWebhook送信する」 という構造。
つまり違うプロトコルなのに、ハマるポイントは同じ なんです。
🎀 センサーの入り口は違っても、“出口のゲート”は一緒。だからつまずく場所もシンクロしちゃうんだよ〜
いまハマっている現象
- 小さいJSONならサーバーに届く
- データ量を増やすと、ESP32が固まったように待機
- サーバー(PHP)は受け取っていない
- 15秒後にタイムアウト
「データは出荷準備万端なのに、配送トラックが動き出さない」──そんな状態です。
🎀 これは“うまくいきそうでいかない”って一番モヤモヤするやつ!
ハマりポイント候補たち
切り分けながら疑っているのがこちら。
- サーバー側の制限
post_max_sizeやmax_input_timeに引っかかってない? - 入力処理
PHPはphp://inputを正しく読めている? - HTTPヘッダ
ESP32がContent-Lengthを正しく指定できている? - 接続管理
Connection: closeを入れずにキープアライブになってない? - ESP32のJSON生成
cJSON_PrintUnformattedが大きなメモリを確保できず途中で止まってる?
🎀 うん、これは“犯人は全員怪しい”ミステリー小説みたいになってきたね
実装メモ
単一JSONは撤退、multipartに切り替え中
最初は 「メタ情報+計測データ(Base64変換)を1つのJSONにまとめて送る」 という方針でした。
けれど実際にやってみると、ESP32のヒープが全然足りない。
- 計測値バッファ
- → Base64用バッファ(1.3倍に膨張)
- → JSON化用の大きなバッファ(
cJSON_PrintUnformattedが連続領域を要求)
この三段構えで、まともに確保できずに撃沈…。
結局、大きなJSONを一気に作って送るやり方は断念しました。
🎀 “全部きれいにひとまとめ”はロマンだけど、ESP32のメモリが現実を突きつけてくるんだよね
今の方針
- メタ情報:小さいJSONを1パート
- 計測データ:Base64をやめて生バイナリをそのまま1パート
multipart/form-data形式で送信- 送信時は
esp_http_client_open()して、ヘッダ+本文を分割してwrite - 念のため
Connection: closeを付与(共有サーバー環境での詰まり対策)
リクエストのイメージ
POST /hook HTTP/1.1
Content-Type: multipart/form-data; boundary=----X
Connection: close
Content-Length: <合計サイズ>
------X
Content-Disposition: form-data; name="meta"
Content-Type: application/json; charset=utf-8
{"project":"VibSens","timestamp":"2025-08-25T16:00:00+09:00", ...}
------X
Content-Disposition: form-data; name="data"; filename="meas.bin"
Content-Type: application/octet-stream
<センサーのバイナリを分割writeで流し込む>
------X--
受け側(PHP)は $_POST['meta'] を json_decode()、
$_FILES['data'] にバイナリが入るので Base64復号不要。
そのまま保存すればOKです。
chunked送信はどうする?
Transfer-Encoding: chunked で送る方法もあるけど、
共有サーバーやミドルウェアが弾くケースもあるので今は保留。
まずは Content-Length を明示した安定ルートで進めるつもりです。
🎀 まずは“確実に届く道”から。チャンクはそのあと考えよう!
本業とブログ
今回のハマりは本業案件で直面した課題。
でも農業IoT(M5Stack+LRA1)でも同じ「ESP32→Webhook」の壁があるので、解決すれば両方に効きます。
逆に、しゃちらぼの実験での工夫が仕事に役立つこともありそう。
🎀 ふふっ、二兎を追う者は二兎ゲット作戦だね!
諺どおり「一兎も得ず」だったらキツイなあ。
今まさに解析中
というわけで今回は「農業IoTでサーバー連携!」の本編に入る前に、
本業と趣味どちらにも関わるESP32のWebhook問題をレポートしました。
BLEは安定、LoRaも安定。
残るは ESP32のWebhook処理。
小さいJSONは通るのに、大きいJSONがタイムアウトする理由を追っています。
次回こそ「データがサーバーに届いた!」と報告できる…予定。
(願望込み)
🎀 今日は“絶賛ハマり中の実況”ってことで!本編はまた次回だよ〜
まとめ
- 本業:BLE+ESP32でWebhook送信 → データサイズ増でタイムアウト
- 農業IoT:LoRa+LRA1+M5Stick(ESP32) → 同じくWebhook送信で構造が共通
- BLEとLoRaは違うけど、結局ハマるのはESP32+Webhook部分
- ハマり候補は Content-Length, Connection: close, php://input, PHP制限, cJSONメモリなど
- 解決すれば本業と農業IoTの両方に知見が活かせる
📪 お問い合わせなど
技術的なご相談やご質問などありましたら、
📩お問い合わせフォーム
または、
📮info@shachi-lab.com までお気軽にどうぞ。
🎀 Webhookで同じようにハマった人がいたら、ぜひ教えてほしいな〜。お問い合わせからでも、Xからでも大歓迎!
🔗 関連リンク
しゃちらぼの最新情報や開発の様子は、こちらでも発信しています:
- 🌐しゃちらぼ公式サイト
- 🐦 X(旧Twitter):@shachi_lab
- 📗 Qiita:@shachi-lab
- 🐙 GitHub:@shachi-lab
- 📸 Instagram:@shachi_lab
ほんとは「しゃちらぼ(Shachi-lab)」なんだけど、見つけてくれてありがとう🐬




コメント