Micropythonを使ってお手軽簡単IoT生活！

# 本投稿は
[Python Advent Calendar 2019](https://qiita.com/advent-calendar/2019/python)　3日目の投稿となります。

# Micropython はいいぞー

Raspberry Piはともかくとして
いわゆるESP32系といわれるものは、Wifiがつかえるけど、Arduinoと同じように、プログラムをROM焼きして実行させるような代物で、基本的にはArduinoのIDEを使ったC言語ライクな感じでプログラムを書くわけです。

・・・が

HTTPリクエストがだるいｗｗｗｗ
エッジポイントのデータをSaaSに連携してこそのIoTというのに
HTTPリクエストがだるいと正直やる気なくしますよね・・・。

## Arduinoだとこのように書く

Arduino Http Client のサンプルスケッチ

``` C:HTTPPost
#include <ArduinoHttpClient.h>
#include <WiFi101.h>

#include "arduino_secrets.h"

///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;


char serverAddress[] = "192.168.0.3";  // server address
int port = 8080;

WiFiClient wifi;
HttpClient client = HttpClient(wifi, serverAddress, port);
int status = WL_IDLE_STATUS;

void setup() {
  Serial.begin(9600);
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to Network named: ");
    Serial.println(ssid);                   // print the network name (SSID);

    // Connect to WPA/WPA2 network:
    status = WiFi.begin(ssid, pass);
  }

  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
}

void loop() {
  Serial.println("making POST request");
  String postData = "name=Alice&age=12";

  client.beginRequest();
  client.post("/");
  client.sendHeader("Content-Type", "application/x-www-form-urlencoded");
  client.sendHeader("Content-Length", postData.length());
  client.sendHeader("X-Custom-Header", "custom-header-value");
  client.beginBody();
  client.print(postData);
  client.endRequest();

  // read the status code and body of the response
  int statusCode = client.responseStatusCode();
  String response = client.responseBody();

  Serial.print("Status code: ");
  Serial.println(statusCode);
  Serial.print("Response: ");
  Serial.println(response);

  Serial.println("Wait five seconds");
  delay(5000);
}

```

ただPOSTするだけなのに、まぁだるいｗｗｗ
まぁ慣れればいいんですけど、本当にヤダ・・・

# MicroPython を使うためには・・・

とりあえず、基盤が必要です。

## 基盤

この辺がよいかと思います。

https://www.switch-science.com/catalog/5448/
https://www.switch-science.com/catalog/3210/

Amazonで売っている格安のESP32系でもいいっちゃいいんですけどね
正直技適の問題がありますし、マークがついてたとしても、それが本当に本物の技適かどうかという問題もありますから、この辺はしっかりとしたところから買いましょう。

インストールのやり方はこちらのマニュアルを見ながら実施。

[ESP32 での MicroPython の始め方](https://micropython-docs-ja.readthedocs.io/ja/latest/esp32/tutorial/intro.html)

# 書き方

MicroPythonは、電源が入ると、まずboot.pyを実行した後に、main.pyが実行されるようになっています。

## boot.py

電源が起動されると呼び出される最初のPythonファイルになります。
基本的にはWifiの接続を行うような処理を組み込むとよいですね。

``` Python:boot.py

import utime
import network
# ==== connecti to wifi access point ============================================
SSID_NAME = <SSID>
SSID_PASS = <WifiPassword>

def connect_wifi(ssid, passkey, timeout=10):
    wifi= network.WLAN(network.STA_IF)
    if wifi.isconnected() :
        print('already Connected.    connect skip')
        return wifi
    else :
        wifi.active(True)
        wifi.connect(ssid, passkey)
        while not wifi.isconnected() and timeout > 0:
            print('.')
            utime.sleep(1)
            timeout -= 1
    
    if wifi.isconnected():
        print('Connected')
        return wifi
    else:
        print('Connection failed!')
        return null

wifi = connect_wifi(SSID_NAME, SSID_PASS)
if not wifi :
    sys.exit(0)

```

## main.py

boot.pyの実行が正常終了すると実行されるPythonファイルとなります。
Arduinoなどを作ったことがある方はご理解いただけると思いますが
基本的に、本Pythonファイルは **無限ループが前提** となります。

``` Python:main.py

from m5stack import lcd # m5stack Library
import machine
import time

lcd.setCursor(0, 0)
lcd.setColor(lcd.WHITE)
lcd.font(lcd.FONT_DejaVu24)
rtctime = machine.RTC()

def aaaaaa():
    global rtctime
    prm_year = '{:0=4}'.format(timedata[0])
    prm_month = '{:0=2}'.format(timedata[1])
    prm_day = '{:0=2}'.format(timedata[2])
    prm_hour = '{:0=2}'.format(timedata[3])
    prm_minute = '{:0=2}'.format(timedata[4])
    prm_second = '{:0=2}'.format(timedata[5])
    
    prm_datetime =  prm_year + "-" \
                +   prm_month + "-" \
                +   prm_day + "T" \
                +   prm_hour + ":" \
                +   prm_minute + ":" \
                +   prm_second + "Z"


    lcd.print(prm_datetime,10,10)

while True: # 無限ループ
    aaaaaa()
    time.sleep(1)

```

## 注意点

パソコンやRaspberry Piほど、潤沢な記憶領域、実行メモリ領域（ヒープ領域）があるわけではありません。
こちらの記事を見てもらうとわかりますが、ぶっちゃけかなり少ないです。

[mgo-tec電子工作:ESP32-WROOM-32 チップ・メモリ・MACアドレス情報取得方法](https://www.mgo-tec.com/blog-entry-chip-info-esp-wroom-32-esp32.html)

ガリガリなコーディングすると、あっという間にヒープ領域を使いこなして、GCが頻発したり、そもそも作ったPythonファイルが入らないってことが起きたりもしますのでご注意を。

# httpリクエストはどうやるの？

Pythonだと、requestsライブラリを使用すると思いますが
MicroPythonの場合は urequests ライブラリを用います。
機能はrequestsライブラリとほぼ変わりません。

``` Python:urequests

import ujson
import urequests

    def postpowerbi(self):
        pbheaders = {
            'Content-Type' :'application/json'
        }
        body = [
                {
                    "datetime" : self.datetime,
                    "temp" : float(self.temp),
                    "humi" : float(self.humi),
                    "pres" : float(self.pres)
                }
            ]
        body_json = ujson.dumps(body).encode("utf-8")
        res = urequests.post(
            self.posturl,
            data=body_json,
            headers=pbheaders
        )
        res.close()

```

# ほかのライブラリは？？

基本的にこちらを見てもらえればよろしいかと・・・

[github MicroPython Lib](https://github.com/micropython/micropython-lib)

# IoTデバイスのライブラリはどうしているの？

気温センサーなどを多く作っているAdafruitさんなどは、Python向けのライブラリも用意しています。

[github Adafruit](https://github.com/adafruit)

こちらを用いることで簡単にIoTデバイスを制御することが可能になります。

## Adafruitさんの高いけど、Amazonで売ってる中華製のやつはダメなの？

非推奨ではありますが、使っているセンサーなどの基盤が一致していれば使うことは可能なものもあります。
ただし、トラップもありますので自己責任で。
ライブラリを一部改造する必要があったりもします。
くれぐれも、自社のプロダクトなんかに使うのはやめて、趣味の範囲内でやりましょう。


# まとめ

だらだらと書いてしまいましたが、Pythonでも十分安価にオリジナルなIoTデバイスを簡単に作ることができます！
皆さんもぜひ一度試してみてください！