LoginSignup
1
0

More than 1 year has passed since last update.

ESP32をJavascriptでLチカする:HTTP でJsonをPostする

Last updated at Posted at 2021-11-23

前回の投稿「ESP32をJavascriptでLチカする」に引き続き、ESP32でJavascriptを動かします。
今回は、HTTPでJsonをPOSTします。

ESP32に以下の人感センサ PIR Hatを接続して、検出したらBeebotteにアップします。

PIR Hat

Beebotte

※Beebotteは、HTTPやMQTTでデータを集約して、グラフ化してくれるサービスです。

ソースコードもろもろは、前回同様以下に上げてあります。
随時、修正、拡張しています。

poruruba/QuickJS_ESP32

HTTP通信

2つの通信方法を用意しました。

①HTTPSで中継サーバを介してPost/Get接続

ESP32でHTTPS通信するためには少々骨が折れるため、Node.jsを使った中継サーバをイントラネットに配置し、中継サーバまではHTTP、中継サーバから先をHTTPS通信するようにします。

httpモジュールとして用意しています。

import * as http from "http";

中継サーバは、GitHubからダウンロードしたファイルのnode.jsフォルダを立ち上げます。

また、main.cppの以下の部分を、立ち上げた中継サーバのURLに変更します。

const char *HTTPPROXY_URL = "http://【中継サーバのURL】/httpproxy-call";

ちなみに、中継サーバは以下のような実装になってます。

node.js/api/controllers/http-proxy/index.js
'use strict';

const HELPER_BASE = process.env.HELPER_BASE || '../../helpers/';
const Response = require(HELPER_BASE + 'response');
const TextResponse = require(HELPER_BASE + 'textresponse');
const BinResponse = require(HELPER_BASE + 'binresponse');

const { URLSearchParams } = require('url');
const fetch = require('node-fetch');
const Headers = fetch.Headers;

exports.handler = async (event, context, callback) => {
    switch(event.path){
        case '/httpproxy-call':{
            var body = JSON.parse(event.body);
            console.log(body.method, body.url, body.params, body.headers, body.response_type, body.method);
            var result;
            switch(body.method){
                case 'POST':{
                    result = await do_post(body.url, body.params, body.headers, body.response_type);
                    break;
                }
                case 'GET':{
                    result = await do_get(body.url, body.params, body.headers, body.response_type);
                    break;
                }
                default:
                    throw "unknown method";
            }

            if (body.response_type == 'TEXT')
                return new TextResponse("text/plain", result);
            else if (body.response_type == 'BINARY')
                return new BinResponse("application/octet-stream", Buffer.from(result));
            else
                return new Response(result);
        }
    }
};

function do_post(url, body, header, response_type = 'JSON') {
    const headers = new Headers(header);
    headers.append("Content-Type", "application/json");
    console.log(headers);
    console.log(body);
    console.log(url);

    return fetch(url, {
        method: 'POST',
        body: JSON.stringify(body),
        headers: headers
    })
        .then((response) => {
            if (!response.ok)
                throw 'status is not 200';

            if (response_type == 'TEXT')
                return response.text();
            else if (response_type == 'BINARY')
                return response.arrayBuffer();
            else
                return response.json();
        });
}

function do_get(url, qs, header, response_type = 'JSON') {
    const params = new URLSearchParams(qs);
    const headers = new Headers(header);

    var append_params = params.toString();
    if (append_params ){
        url += (url.indexOf('?') >= 0) ? "&" : "?";
        url += append_params;
    }
    console.log(url);
    return fetch(url, {
        method: 'GET',
        headers: headers
    })
        .then((response) => {
            if (!response.ok)
                throw 'status is not 200';

            if (response_type == 'TEXT')
                return response.text();
            else if (response_type == 'BINARY')
                return response.arrayBuffer();
            else
                return response.json();
        });
}

②HTTPで直接Post/Get接続

接続先サーバが、HTTPであれば、直接接続できるようにしています。

utilsモジュールに用意しています。

import * as utils from "utils";

①、②いずれも、パラメータの指定方法は同じです。

Post接続、JSON戻り

http.postJson(url, params, headers);
utils.httpPostJson(url, params, headers);

・url:接続先URL
・params(option):bodyにJSONとして渡す引数
・headers(options):headerに指定する引数

var response = http.postJson("http://api.beebotte.com/v1/data/write/pir", { records: [{ "resource": "pir", data: (pir != 0) }]}, { "X-Auth-Token": X_AUTH_TOKEN } )

Post接続、TEXT戻り

http.postText(url, params, headers);
utils.httpPostText(url, params, headers);

Get接続、JSON戻り

http.getJson(url, params, headers);

・url:接続先URL
・params(option):queryStringに指定する引数
・headers(options):headerに指定する引数

Get接続、TEXT戻り

http.getText(url, params, headers);
utils.httpGetText(url, params, headers);

ほかに有用なAPIとして以下があります。

・utils.urlencode(str)
・utils.base64Encode(str)
・utils.base64Decode(b64)

また、当然以下もあります。
・JSON.parse(str)
・JSON.stringify(obj)

Javascriptソース

PIR Hatは、GPIO_36につながれています。

import * as http from "http";
import * as input from "input";
import * as utils from "utils";
import * as gpio from "gpio";

const X_AUTH_TOKEN = "【Beabotteチャネルトークン】 ";

async function setup()
{
    var ipaddress = esp32.getIpAddress();
    console.log("ipaddress=" + ((ipaddress >> 24) & 0xff) + "." + ((ipaddress >> 16) & 0xff) + "." + ((ipaddress >> 8) & 0xff) + "." + (ipaddress & 0xff));

    gpio.pinMode(36, gpio.INPUT);
}

var pir = -1;
async function loop()
{
    esp32.update();
    if( input.isPressed(input.BUTTON_B) ){
        esp32.restart();
    }

    var t = gpio.digitalRead(36);
    if( t != pir ){
        pir = t;
        console.log("PIR=" + pir);
//      var result2 = http.postJson("http://api.beebotte.com/v1/data/write/pir", { records: [{ "resource": "pir", data: (pir != 0) }]}, { "X-Auth-Token": X_AUTH_TOKEN } );
        var result2 = utils.httpPostJson("http://api.beebotte.com/v1/data/write/pir", { records: [{ "resource": "pir", data: (pir != 0) }]}, { "X-Auth-Token": X_AUTH_TOKEN } );
        console.log(JSON.stringify(result2));
    }
}

終わりに

かなり形になってきました。
異常系を整備しようかな。。。

以上

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0