気象庁天気予報JSONを取得して天気予報を表示させてみた

気象庁ホームページからJSON取得してESP32で天気予報表示させる ESP32 ( ESP-WROOM-32 )

ESP32開発ボードでArduinoプログラミングしてみる

では、上記を踏まえて、Arduino core for the ESP32 でプログラミングしてみます。

使用したもの

ESP32 開発ボード

ESPr Developer 32

スイッチサイエンスさんのおすすめ開発ボードです。
このUSB端子は Micro USB Type-B なので注意です。ピンヘッダは別売りでハンダ付け必要です。
スイッチサイエンスさんのリンクは以下です。
https://www.switch-science.com/catalog/3210/

過去にこのブログで紹介した記事も参照してみてください。
ESPr Developer 32 ( スイッチサイエンス製 ) を使ってみました

Amazonでも販売しています。

ESPr Developer 32
スイッチサイエンス(Switch Science)
¥2,200(2022/09/05 01:05時点)

USB Type-C タイプもあります。

スイッチサイエンス ESPr Developer 32 Type-C SSCI-063647
スイッチサイエンス
¥2,420(2022/06/04 11:53時点)

ESP32 DevKitC

Espressif Systems 純正ボードです。

その他、パソコン、USBケーブル、WiFiルータ等

WiFiルータ(アクセスポイント)は、事前にファイアウォール設定やMACアドレスフィルタリングの設定を済ませておき、ESP32がインターネットに接続できるようにしておきます。

予め、Arduino core for the ESP32 をインストールしておく

Arduino coer for the ESP32 のインストール方法は以下の記事を参照してください。

https://www.mgo-tec.com/arduino-core-esp32-install

今回使用したバージョンは 2.0.1 です。
(他のバージョンでは動かない場合があります。)

気象庁ホームページのルートCA証明書の公開鍵を取得しておく

気象庁ホームページから天気予報JSONを取得する場合、ルートCA証明書の公開鍵が無くても取得できますが、今後のセキュリティ面も考えると、公開鍵でアクセスした方が良いかと思います。

以下の気象庁の天気予報ホームページにアクセスします。

https://www.jma.go.jp/bosai/#pattern=forecast

ルートCA証明書の公開鍵の取得方法は以下の記事を参照してください。

Arduino – ESP32 WiFiClientSecure ライブラリで、安定して https ( SSL )記事をGETする方法

スケッチ(サンプルプログラム)

前節のweatherCodesを利用した、Arduino IDE のスケッチ例です。
ESP32開発ボードを使って、Arduino IDEのシリアルモニタに表示させるプログラムですから、天気アイコンは表示できません。
ですが、switch文でweatherCodeを分類して、天気予報文章と紐づけているので、これを改良すれば容易に天気予報アイコン表示はできると思います。

今回のスケッチで少々手間取ったところは、Arduino core ESP32プログラミングでお馴染みの client.available() を使っていたら、全然取得できずにタイムアウトしてしまったことです。
よって、それを使わずに、単純にwhile(true)ループを使いました。

WiFiルータのSSIDやパスワードは書き換えてください。ただ、ここに入力してコンパイルしたパスワードはESP32が第三者に渡ると、専用ツールで簡単に読み取られてしまうので注意してください。

また、officeコードやareaコードは、前節を参照して、自分の地域のコードに書き換えてください。

また、jp_weather_root_ca は、気象庁ホームページのルートCA証明書公開鍵です。
xxxxxx の所を書き換えてください。

なお、何度も言っておりますが、私はプログラミングに関しては素人です。
誤り等ありましたら、コメント投稿でご連絡いただけると助かります。

/*
  Use Arduino core for the ESP32 ver 2.0.1 or 2.0.3-RC1
  Wifi secure connection example for ESP32
  Running on TLS 1.2 using mbedTLS
  Suporting the following chipersuites:
  "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_DHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_ECDSA_WITH_AES_256_CCM","TLS_DHE_RSA_WITH_AES_256_CCM","TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384","TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384","TLS_DHE_RSA_WITH_AES_256_CBC_SHA256","TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA","TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA","TLS_DHE_RSA_WITH_AES_256_CBC_SHA","TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8","TLS_DHE_RSA_WITH_AES_256_CCM_8","TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384","TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384","TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384","TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384","TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384","TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256","TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA","TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256","TLS_DHE_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_CCM","TLS_DHE_RSA_WITH_AES_128_CCM","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256","TLS_DHE_RSA_WITH_AES_128_CBC_SHA256","TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA","TLS_DHE_RSA_WITH_AES_128_CBC_SHA","TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8","TLS_DHE_RSA_WITH_AES_128_CCM_8","TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256","TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256","TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256","TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256","TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256","TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA","TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA","TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA","TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA","TLS_DHE_PSK_WITH_AES_256_GCM_SHA384","TLS_DHE_PSK_WITH_AES_256_CCM","TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384","TLS_DHE_PSK_WITH_AES_256_CBC_SHA384","TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA","TLS_DHE_PSK_WITH_AES_256_CBC_SHA","TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384","TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384","TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384","TLS_PSK_DHE_WITH_AES_256_CCM_8","TLS_DHE_PSK_WITH_AES_128_GCM_SHA256","TLS_DHE_PSK_WITH_AES_128_CCM","TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256","TLS_DHE_PSK_WITH_AES_128_CBC_SHA256","TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA","TLS_DHE_PSK_WITH_AES_128_CBC_SHA","TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256","TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256","TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256","TLS_PSK_DHE_WITH_AES_128_CCM_8","TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA","TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA","TLS_RSA_WITH_AES_256_GCM_SHA384","TLS_RSA_WITH_AES_256_CCM","TLS_RSA_WITH_AES_256_CBC_SHA256","TLS_RSA_WITH_AES_256_CBC_SHA","TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384","TLS_ECDH_RSA_WITH_AES_256_CBC_SHA","TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384","TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384","TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA","TLS_RSA_WITH_AES_256_CCM_8","TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384","TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256","TLS_RSA_WITH_CAMELLIA_256_CBC_SHA","TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384","TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384","TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384","TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384","TLS_RSA_WITH_AES_128_GCM_SHA256","TLS_RSA_WITH_AES_128_CCM","TLS_RSA_WITH_AES_128_CBC_SHA256","TLS_RSA_WITH_AES_128_CBC_SHA","TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256","TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256","TLS_ECDH_RSA_WITH_AES_128_CBC_SHA","TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256","TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256","TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA","TLS_RSA_WITH_AES_128_CCM_8","TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256","TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256","TLS_RSA_WITH_CAMELLIA_128_CBC_SHA","TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256","TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256","TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256","TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256","TLS_RSA_WITH_3DES_EDE_CBC_SHA","TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA","TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA","TLS_RSA_PSK_WITH_AES_256_GCM_SHA384","TLS_RSA_PSK_WITH_AES_256_CBC_SHA384","TLS_RSA_PSK_WITH_AES_256_CBC_SHA","TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384","TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384","TLS_RSA_PSK_WITH_AES_128_GCM_SHA256","TLS_RSA_PSK_WITH_AES_128_CBC_SHA256","TLS_RSA_PSK_WITH_AES_128_CBC_SHA","TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256","TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256","TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA","TLS_PSK_WITH_AES_256_GCM_SHA384","TLS_PSK_WITH_AES_256_CCM","TLS_PSK_WITH_AES_256_CBC_SHA384","TLS_PSK_WITH_AES_256_CBC_SHA","TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384","TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384","TLS_PSK_WITH_AES_256_CCM_8","TLS_PSK_WITH_AES_128_GCM_SHA256","TLS_PSK_WITH_AES_128_CCM","TLS_PSK_WITH_AES_128_CBC_SHA256","TLS_PSK_WITH_AES_128_CBC_SHA","TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256","TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256","TLS_PSK_WITH_AES_128_CCM_8","TLS_PSK_WITH_3DES_EDE_CBC_SHA","TLS_EMPTY_RENEGOTIATION_INFO_SCSV"]
  2017 - Evandro Copercini - Apache 2.0 License.
*/

#include <WiFiClientSecure.h>

const char* ssid = "xxxxxxxxx"; //ご自分のルーターのSSIDに書き換えてください
const char* password = "xxxxxxxxx"; //ご自分のルーターのパスワードに書き換えてください

const int port = 443;

const char* jp_weather_host = "www.jma.go.jp";
String office_code= "130000"; //東京都
String jp_weather_area_url = "/bosai/forecast/data/forecast/" + office_code + ".json";
String area_code_str = "130010"; //東京地方

String search_tag =  "code\":\"" + area_code_str + "\"},\"weatherCodes\":[\"";

const char* jp_weather_root_ca= \
"-----BEGIN CERTIFICATE-----\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
//................
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" \
"-----END CERTIFICATE-----\n";

WiFiClientSecure client;

void setup() {
  Serial.begin(115200);
  Serial.println();
  delay(100);

  Serial.print("Attempting to connect to SSID: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }

  Serial.print("Connected to ");
  Serial.println(ssid);

  client.setCACert(jp_weather_root_ca);
  //client.setInsecure(); //ルートCA無しの場合

  uint32_t time_out = millis();
  while(true){
    if (client.connect(jp_weather_host, port)){
      Serial.print(jp_weather_host); Serial.print("-------------");
      Serial.println("connected");
      Serial.println("-------Send HTTPS GET Request");

      String req_header_str = String("GET ");
             req_header_str += String(jp_weather_area_url) + " HTTP/1.1\r\n";
             req_header_str += "Host: ";
             req_header_str += String(jp_weather_host) + "\r\n";
             req_header_str += "User-Agent: BuildFailureDetectorESP32\r\n";
             req_header_str += "Accept: text/html,application/xhtml+xml,application/xml\r\n";
             req_header_str += "Connection: close\r\n\r\n";

      client.print(req_header_str);
      break;
    }

    if((millis() - time_out ) > 20000){
      Serial.println("time out!");
      Serial.println("Host connection failed.");
    }
    delay(1);
  }

  String ret_str;
  time_out = millis();

  if(client){
    String tmp_str;
    Serial.println("-------Receive HTTPS Response");

    if(client.connected()){
      while(true) {
        if((millis() - time_out ) > 60000){
          Serial.println("time out!");
          Serial.println("Host HTTPS response failed.");
          break;
        }

        tmp_str = client.readStringUntil(']');
        //Serial.println(tmp_str);
        if(tmp_str.indexOf(search_tag) >= 0 ){
          ret_str += tmp_str;
          ret_str += "] ";
          break;
        }
        delay(1);
      }

      while(client.available()){
        if((millis() - time_out ) > 60000) break; //60seconds Time Out
        client.read();
        delay(1);
      }

      delay(10);
      client.stop();
      delay(10);
      Serial.println("-------Client Stop");
    }
  }

  if(ret_str.length() < 20) ret_str = "※JSON GETできませんでした";

  if(client){
    delay(10);
    client.stop();
    delay(10);
    Serial.println("-------Client Stop");
  }

  Serial.print("抽出した文字列:");
  Serial.println(ret_str);

  String weather_code_from_key = "weatherCodes\":[\"";
  extractWeatherCodes(ret_str, weather_code_from_key);
}

void loop() {
  // do nothing
}

void extractWeatherCodes(String ret_str, String weather_code_from_key){
  uint8_t from1 = ret_str.indexOf(weather_code_from_key, 0) + weather_code_from_key.length();
  uint8_t to1 = from1 + 3;
  uint8_t from2 = to1 + 3;
  uint8_t to2 = from2 + 3;
  String today_w_code_str = ret_str.substring(from1, to1);
  String tomorrow_w_code_str = ret_str.substring(from2, to2);
  uint16_t today_weather_code = atoi(today_w_code_str.c_str());
  uint16_t tomorrow_weather_code = atoi(tomorrow_w_code_str.c_str());
  Serial.print("Today Weather Coode = ");
  Serial.println(today_weather_code);
  Serial.print("今日の天気:");
  classifyWeatherCode(today_weather_code);
  Serial.print("Tomorrow Weather Code = ");
  Serial.println(tomorrow_weather_code);
  Serial.print("明日の天気:");
  classifyWeatherCode(tomorrow_weather_code);
}

void classifyWeatherCode(uint16_t weather_code){
  switch(weather_code){
    //--------Clear(晴れ)-----------------
    case 100:
    case 123:
    case 124:
    case 130:
    case 131:
      Serial.println("晴れ");
      break;

    //--------晴れ時々(一時)曇り----------------
    case 101:
    case 132:
      Serial.println("晴れ時々曇り");
      break;

    //--------晴れ時々(一時)雨----------------
    case 102:
    case 103:
    case 106:
    case 107:
    case 108:
    case 120:
    case 121:
    case 140:
      Serial.println("晴れ時々雨");
      break;

    //--------晴れ時々(一時)雪----------------
    case 104:
    case 105:
    case 160:
    case 170:
      Serial.println("晴れ時々雪");
      break;

    //--------晴れ後曇り----------------
    case 110:
    case 111:
      Serial.println("晴れ後曇り");
      break;

    //--------晴れ後雨----------------
    case 112:
    case 113:
    case 114:
    case 118:
    case 119:
    case 122:
    case 125:
    case 126:
    case 127:
    case 128:
      Serial.println("晴れ後雨");
      break;

    //--------晴れ後雪----------------
    case 115:
    case 116:
    case 117:
    case 181:
      Serial.println("晴れ後雪");
      break;
    
    //--------曇り-----------------
    case 200:
    case 209:
    case 231:
      Serial.println("曇り");
      break;

    //--------曇り時々晴れ-----------------
    case 201:
    case 223:
      Serial.println("曇り時々晴れ");
      break;
    
    //--------曇り時々雨-----------------
    case 202:
    case 203:
    case 206:
    case 207:
    case 208:
    case 220:
    case 221:
    case 240:
      Serial.println("曇り時々雨");
      break;
    
    //--------曇り一時雪-----------------
    case 204:
    case 205:
    case 250:
    case 260:
    case 270:
      Serial.println("曇り一時雪");
      break;

    //--------曇り後晴れ-----------------
    case 210:
    case 211:
      Serial.println("曇り後晴れ");
      break;

    //--------曇り後雨-----------------
    case 212:
    case 213:
    case 214:
    case 218:
    case 219:
    case 222:
    case 224:
    case 225:
    case 226:
      Serial.println("曇り後雨");
      break;
    
    //--------曇り後雪-----------------
    case 215:
    case 216:
    case 217:
    case 228:
    case 229:
    case 230:
    case 281:
      Serial.println("曇り後雪");
      break;
    
    //--------雨-----------------
    case 300:
    case 304:
    case 306:
    case 328:
    case 329:
    case 350:
      Serial.println("雨");
      break;

    //--------雨時々晴れ-----------------
    case 301:
      Serial.println("雨時々晴れ");
      break;
    
    //--------雨時々曇り-----------------
    case 302:
      Serial.println("雨時々曇り");
      break;
    
    //--------雨時々雪-----------------
    case 303:
    case 309:
    case 322:
      Serial.println("雨時々雪");
      break;
    
    //--------暴風雨-----------------
    case 308:
      Serial.println("暴風雨");
      break;
    
    //--------雨後晴れ-----------------
    case 311:
    case 316:
    case 320:
    case 323:
    case 324:
    case 325:
      Serial.println("雨後晴れ");
      break;

    //--------雨後曇り-----------------
    case 313:
    case 317:
    case 321:
      Serial.println("雨後曇り");
      break;

    //--------雨後雪-----------------
    case 314:
    case 315:
    case 326:
    case 327:
      Serial.println("雨後雪");
      break;
    
    //--------雪-----------------
    case 340:
    case 400:
    case 405:
    case 425:
    case 426:
    case 427:
    case 450:
      Serial.println("雪");
      break;
    
    //--------雪時々晴れ-----------------
    case 401:
      Serial.println("雪時々晴れ");
      break;
    
    //--------雪時々曇り-----------------
    case 402:
      Serial.println("雪時々曇り");
      break;
    
    //--------雪時々雨-----------------
    case 403:
    case 409:
      Serial.println("雪時々雨");
      break;
    
    //--------暴風雪-----------------
    case 406:
    case 407:
      Serial.println("暴風雪");
      break;
    
    //--------雪後晴れ-----------------
    case 361:
    case 411:
    case 420:
      Serial.println("雪後晴れ");
      break;
    
    //--------雪後曇り-----------------
    case 371:
    case 413:
    case 421:
      Serial.println("雪後曇り");
      break;

    //--------雪後雨-----------------
    case 414:
    case 422:
    case 423:
      Serial.println("雪後雨");
      break;

    default:
      break;
  }
}

コンパイル書き込み、実行

では、Arduino IDEのシリアルモニタを115200bpsで起動し、コンパイル書き込み実行してみます。
すると、以下のように表示されると思います。

(図30)

プログラミング結果をシリアルモニタに表示

Arduino IDEスケッチをコンパイル書き込み実行し、シリアルモニタに表示

ここまでできれば、天気アイコンと紐づけるだけで液晶表示できると思います。
いろいろ応用できそうですね。

(おまけ)降水確率について

今回は降水確率のプログラミングはやりませんが、一応、気付いたことを説明します。

降水確率は、JSONデータ中の “pops” というキーワードの中にあります。

(図20)

JSON中の降水確率

JSONデータ中の降水確率

これは、現在の時間帯によって、JSONデータ中の降水確率数値の場所が異なります。
そのヒントになるのは、気象庁の天気予報ホームページを見れば分かると思います。

例えば、現在時刻が21:00で東京都の天気予報ページを見てみると、下図の様になっています。

(図21)【気象庁ホームページの画像を加工】

気象庁ホームページの降水確率表示

気象庁ホームページの降水確率表示

これを見て分かる通り、1日を6時間毎に区切って、過ぎ去った時間帯の降水確率は表示されていません。
となると、JSONデータにある降水確率は、最新の6時間区切りの降水確率が1番目になっているということです。ですから、時間によって降水確率の表示場所がスライドしていくということです。こんな感じです。

(図22)

JSONデータ中の降水確率

JSONデータ中の降水確率

ですから、今の時間が朝の5:00になれば、1番目の数値が0:00~6:00の降水確率にスライドしていくということです。
これがわかれば、プログラミングできそうですね。
以上、おまけでした。

コメント

  1. sbtns より:

    こんにちは。私も以前はESP32を使っていましたが、消費電流をほぼ0にできるくらいで、
    あまり使い勝手よいとは思いませんでした。現在はLinuxで遊んでいます。RPIを使っているそうですが、これは価格が安く、実行速度もそこそこでとても良いM/Cです。さらに開発言語にGO言語をサポートしているので、プログラムがとても組みやすいです。もうC/C++には戻れません。

    • mgo-tec mgo-tec より:

      sbtnsさん

      記事をご覧いただき、ありがとうございます。
      自分も最近はESP32を殆ど触っていません。ブログのコメント質問に答える時に触るくらいです。
      ラズパイも最近は放置状態ですが、WEBアプリをPythonで作るにはとても重宝しています。
      GO言語はまったく触ったこと無いです。
      C/C++はM5Stackみたいな組み込みマイコンには良いですが、汎用性はやっぱりラズパイですね~。
      (^^)

タイトルとURLをコピーしました