MicroPythonでWebにアクセス

#免責
この記事に従って発生した如何なる損害も筆者は負うことができません。ご免なさい。

#はじめに
使い勝手が良いのでMicroPythonがお気に入りです。
電子工作をしていたら、デバイスをネットにアクセスさせたくなりました。センサーのデータをアップしたり、デバイスから[WebHook](https://en.wikipedia.org/wiki/Webhook)を呼びたいのです。

#目的
[urequestsパッケージ](https://github.com/micropython/micropython-lib/tree/master/urequests)を使ってMicroPythonからGAPPSなどのWebへアクセスできるようにします。

#urequestsはリダイレクトに対応していない
urequestsパッケージがあり、HTTP/HTTPSアクセスはできますが、リダイレクトが必要な場合は例外が起きてエラーになります。
[kk2170さん](https://qiita.com/kk2170)の[解説](https://qiita.com/kk2170/items/23d02ab7258139bac914)に、解決策など全ての答えがありますので、そちらをお勧めします。

```shell-session:urequestsはリダイレクトに未対応
$ micropython
MicroPython v1.11-37-g62f004b on 2019-06-05; linux version
Use Ctrl-D to exit, Ctrl-E for paste mode
>>>
>>> import upip
>>> upip.install("urequests")
>>>
>>> import urequests
>>> data = urequests.get("https://time.google.com/")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "~/.micropython/lib/urequests.py", line 112, in get
  File "~/.micropython/lib/urequests.py", line 100, in request
  File "~/.micropython/lib/urequests.py", line 97, in request
NotImplementedError: Redirects not yet supported
>>>
````

#urequestsを改造してリダイレクトに対応させてみる
ただ、「[解決策 その１](https://qiita.com/kk2170/items/23d02ab7258139bac914#解決策その1)」をやってみたくなりました。
ということで、urequests.pyのソースコードを改造して無理やりリダイレクトに対応させます。
リダイレクト要求でエラーにせずにurequestsを再帰的に呼び出すように無理やり改造します。危険な感じですけど。
メモリが足らなくなるといけないので、gcパッケージの力を借りることにしました。gcパッケージはMicroPythonにデフォルトで入っているようです。

###urequestsをインストールする
何はともあれインストールしてみます。

```shell-session:urequestsをインストールする
$ micropython
MicroPython v1.11-37-g62f004b on 2019-06-05; linux version
Use Ctrl-D to exit, Ctrl-E for paste mode
>>> import upip
>>> upip.install("urequests")
Installing to: ~/.micropython/lib/
Warning: micropython.org SSL certificate is not validated
Installing urequests 0.6 from https://micropython.org/pi/urequests/urequests-0.6.tar.gz
>>>
```

###urequestsを改造してみる
早速、改造してみます。
できれば、パッチの内容をこのようなログではなくファイル形式で公開したいと思っています。

```shell-session:urequestsを改造する
$ cat urequests.py.patch
--- ~/.micropython/lib/urequests.py     2019-06-07 14:55:55.200352343 +0900
+++ ~/.micropython/lib/urequests.py     2019-06-07 15:03:42.659537996 +0900
@@ -1,4 +1,5 @@
 import usocket
+import gc

 class Response:

@@ -93,8 +94,11 @@
             if l.startswith(b"Transfer-Encoding:"):
                 if b"chunked" in l:
                     raise ValueError("Unsupported " + l)
-            elif l.startswith(b"Location:") and not 200 <= status <= 299:
-                raise NotImplementedError("Redirects not yet supported")
+            elif l.startswith(b"Location:") and 300 <= status <= 399:
+                url = l[9:].decode().strip() # delete "Location:" from Redirect text.
+                s.close() # close the s handle to request the url recursively.
+                gc.collect() # gc.collect() for work memory.
+                return request(method, url)
     except OSError:
         s.close()
         raise
@@ -102,6 +106,7 @@
     resp = Response(s)
     resp.status_code = status
     resp.reason = reason
+    gc.collect() # don't close the s handle, but gc.collect() for work memory.
     return resp


$
$ patch --dry-run どこか/urequests.py < urequests.py.patch
checking file どこか/urequests.py
$
$ # 問題ないなら --dry-run をはずしてパッチを当てる
$ patch どこか/urequests.py < urequests.py.patch
```

#改造したurequestsを使ってみる
urequestsを使って https://time.google.com/ にアクセスしてみます。
なお、[mpy-cross](https://qiita.com/tab4moji/items/8c1f9fdbb170738b3630#デバイスならバイトコードがお勧め)を使うと、リソースの消費量を抑えられそうです。

```shell-session:改造したurequestsでHTTP/HTTPSアクセス
$ micropython 
MicroPython v1.11-37-g62f004ba4 on 2019-06-07; linux version
Use Ctrl-D to exit, Ctrl-E for paste mode
>>> 
>>> import urequests
>>> data = urequests.get("https://time.google.com/")
>>> print(data)
<Response object at b6c4bdd0>
>>> 
````

#参考
* [UNIX版MicroPython](https://qiita.com/tab4moji/items/c22279ff397c7f2782cc)
* [MicroPythonのurequestsとActiveStorageの相性が悪い話](https://qiita.com/kk2170/items/23d02ab7258139bac914)