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でも販売しています。
USB Type-C タイプもあります。
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 の所を書き換えてください。
なお、何度も言っておりますが、私はプログラミングに関しては素人です。
誤り等ありましたら、コメント投稿でご連絡いただけると助かります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | /* 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)
ここまでできれば、天気アイコンと紐づけるだけで液晶表示できると思います。
いろいろ応用できそうですね。
(おまけ)降水確率について
今回は降水確率のプログラミングはやりませんが、一応、気付いたことを説明します。
降水確率は、JSONデータ中の “pops” というキーワードの中にあります。
(図20)
これは、現在の時間帯によって、JSONデータ中の降水確率数値の場所が異なります。
そのヒントになるのは、気象庁の天気予報ホームページを見れば分かると思います。
例えば、現在時刻が21:00で東京都の天気予報ページを見てみると、下図の様になっています。
(図21)【気象庁ホームページの画像を加工】
これを見て分かる通り、1日を6時間毎に区切って、過ぎ去った時間帯の降水確率は表示されていません。
となると、JSONデータにある降水確率は、最新の6時間区切りの降水確率が1番目になっているということです。ですから、時間によって降水確率の表示場所がスライドしていくということです。こんな感じです。
(図22)
ですから、今の時間が朝の5:00になれば、1番目の数値が0:00~6:00の降水確率にスライドしていくということです。
これがわかれば、プログラミングできそうですね。
以上、おまけでした。
コメント
こんにちは。私も以前はESP32を使っていましたが、消費電流をほぼ0にできるくらいで、
あまり使い勝手よいとは思いませんでした。現在はLinuxで遊んでいます。RPIを使っているそうですが、これは価格が安く、実行速度もそこそこでとても良いM/Cです。さらに開発言語にGO言語をサポートしているので、プログラムがとても組みやすいです。もうC/C++には戻れません。
sbtnsさん
記事をご覧いただき、ありがとうございます。
自分も最近はESP32を殆ど触っていません。ブログのコメント質問に答える時に触るくらいです。
ラズパイも最近は放置状態ですが、WEBアプリをPythonで作るにはとても重宝しています。
GO言語はまったく触ったこと無いです。
C/C++はM5Stackみたいな組み込みマイコンには良いですが、汎用性はやっぱりラズパイですね~。
(^^)