Qiitaの「いいね」メーターを作る

#はじめに
ESP-WROOM-32ってWiFiにつながるんだから、もっと役に立ちそう。
単体で情報取得してLEDでも点灯させようかな。
でも、天気予報に応じて色が変わる傘立てとかあったような。
じゃあ、[QiitaAPI](https://qiita.com/api/v2/docs)を使ってみよう!
そして、「いいね」を取得してみよう!
#やりたいこと
「いいね」メーターによる投稿状況の可視化で、目標達成へのモチベーションを上げる。
#やり方
1.ESP-WROOM-32をWiFiにつなぐ
2.Qiita APIを使って情報を取得
3.いいね状況に応じてメーターに反映する
##完成イメージ
![system.png](https://qiita-image-store.s3.amazonaws.com/0/140055/8480e373-2ced-baf4-fbf9-c5f3ac1379a3.png)
##詳細ルール
1.「いいね」状況をQiita APIを使用して15分ごとに確認する
2.メーターは__100__「いいね」をMAX(これは自分の目標に合わせる)
3.新着LEDで新着「いいね」があった場合に点灯する
4.新着LEDはESP-WROOM-32のタッチセンサへのタッチで消灯する

#用意するもの
- ESP-WROOM-32(ESP32-DevKitC)
- [バーグラフLED](http://akizukidenshi.com/catalog/g/gI-05348/) : いいね目標値への達成度表示用
- LED : 新着いいね用
- 抵抗 : LED抵抗用

タッチセンサはESP-WROOM-32に内蔵されている

#作る
##接続する
回路はあまり得意ではないので、チップの寿命を縮めているかもしれない。
![Evernote Snapshot 20171105 185343.png](https://qiita-image-store.s3.amazonaws.com/0/140055/b20c86ea-02fd-354f-d728-feab6f3b3cb6.png)

完成!
![qmeter.png](https://qiita-image-store.s3.amazonaws.com/0/140055/52f23526-d770-71ed-e9c0-6febc8d60b8f.png)
##プログラムを作る
WebアクセスやJSONなどはC言語で使いにくいため、[MicroPython](http://makezine.jp/blog/2017/10/esp32_with_micropython.html)を使用した。これはいい。
Qiita APIは「いいね」を直接取得することはできない。そのため投稿からその数を取得する。
投稿を取得すると、ESP-WROOM-32ではメモリが不足したため工夫が必要だった。
###ソースコード
ソースコード全体は[github](https://github.com/mitazet/esp/blob/master/micropython/qlikes_meter/main.py)においた。
####WiFiに接続する
SSIDとパスワードを指定してWiFiに接続する。

```py3
def connect_wifi(ssid, passkey, timeout=10):
    wifi = network.WLAN(network.STA_IF)
    if wifi.isconnected():
        print('already Connected. 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
```
####WebAPIを使う
urequestsを使用し、HTTP GETを行なっている。
投稿を一度に取得すると、ESP-WROOM-32上のMicroPythonではメモリが足りなくなった。
そのため、`get_item_count`で投稿数を取得し、`get_likes_count`で1投稿ずつ「いいね」の数を取得している。
1投稿ずつでもメモリが足りなくなるため、`del`、`gc.collect()`で使用しなくなった変数を解放している。

```py3
def get_items_count():
    token = 'set_your_token'
    headers = {
            'content-type'  : 'application/json',
            'charset'       : 'utf-8',
            'Authorization' : 'Bearer ' + token
            }
    url = 'https://qiita.com/api/v2/authenticated_user'
    response = urequests.get(url, headers=headers)
    json = response.json()
    count = int(json["items_count"])
    del token
    del headers
    del url
    del response
    del json
    gc.collect()
    
    return count

def get_likes_count(num):
    token = 'set_your_token'
    headers = {
            'content-type'  : 'application/json',
            'charset'       : 'utf-8',
            'Authorization' : 'Bearer ' + token
            }

    u1 = 'https://qiita.com/api/v2/authenticated_user/items?page='
    u2 = str(num)
    u3 = '&per_page=1'
    url = u1 + u2 + u3

    del token
    del u1
    del u2
    del u3
    gc.collect()

    response = urequests.get(url, headers=headers)
    pattern = r'"likes_count":[0-9]+'
    matchOB = ure.search(pattern, response.text)

    if not matchOB:
        sys.exit(0)

    likes_str = matchOB.group(0)
    likes_str = likes_str.split(':')
    count = int(likes_str[1])

    del headers
    del pattern
    del url
    del response
    del matchOB
    del likes_str
    gc.collect()

    return count 
```

####JSONをParseする
ujsonを使用したかったがメモリが足りず。。。
文字列を解析し、いいね数を取得する方針とした。

```py3
response = urequests.get(url, headers=headers)
    pattern = r'"likes_count":[0-9]+'
    matchOB = ure.search(pattern, response.text)

    if not matchOB:
        sys.exit(0)

    likes_str = matchOB.group(0)
    likes_str = likes_str.split(':')
    count = int(likes_str[1])
```

####バーグラフLEDを制御する
達成度に応じて、つけるLEDを増やしていく。

```py3
def set_led_level(level):
    pin12 = machine.Pin(12) 
    pin14 = machine.Pin(14) 
    pin27 = machine.Pin(27) 
    pin26 = machine.Pin(26) 
    pin25 = machine.Pin(25) 
    pin33 = machine.Pin(33) 
    pin32 = machine.Pin(32) 
    pin5 = machine.Pin(5) 
    pin18 = machine.Pin(18) 
    pin19 = machine.Pin(19) 

    if level >= 10:
        pin12.value(1)
    
    if level >= 20:
        pin14.value(1)

    if level >= 30:
        pin27.value(1)

    if level >= 40:
        pin26.value(1)

    if level >= 50:
        pin25.value(1)

    if level >= 60:
        pin33.value(1)

    if level >= 70:
        pin32.value(1)

    if level >= 80:
        pin5.value(1)

    if level >= 90:
        pin18.value(1)

    if level >= 100:
        pin19.value(1)
```
####新着LEDを点灯/消灯する
GPIO21に新着LEDを接続しており、その制御をする。

```py3
def set_arrivals_led_on():
    pin = machine.Pin(21) 
    pin.value(1)

def set_arrivals_led_off():
    pin = machine.Pin(21) 
    pin.value(0)
```
####「いいね」状況をLEDに反映する
目標値を100として今の達成度合いをバーグラフLEDに反映させる。
また、前回取得時から「いいね」が増加している場合は新着LEDを点灯させる。

```py3
def update_likes_led():
    global prev_likes_count

    items_count = get_items_count()

    likes_count = 0
    for num in range(1, items_count+1):
        likes_count += get_likes_count(num)

    print(likes_count)

    target = 100
    rate = (likes_count/target)*100
    set_led_level(int(rate))   
    
    if (likes_count > prev_likes_count) and (prev_likes_count > 0) :
        set_arrivals_led_on()

    prev_likes_count = likes_count
```
####タッチセンサ入力を取得する
タッチセンサを使用する方法は以下である。
タッチで数値が下がるため閾値(適当)を設けてタッチ判定を行なっている。
割り込み処理のやり方が分からなかったため、ポーリングにしている。

```py3
tp = machine.TouchPad(machine.Pin(13))
while True:
    utime.sleep(0.1)
    value = tp.read()
    if value < 400:
        print('touched')
        set_arrivals_led_off()
```
####15分毎に状況を確認する
タイマー割り込みを使用している。
900000msec(15分)ごとにcallback関数が呼ばれるように設定する。
callback関数はupdate_likes_ledが呼ばれる。

```py3
t0 = machine.Timer(0)
t0.init(period=900000, mode=machine.Timer.PERIODIC, callback=intr_handler_timer0)
```

#テスト
##いいね達成度メーター
いいね状況が分かる!
現在、58いいねだから、取得と表示が成功しているようだ。
![meter_led.png](https://qiita-image-store.s3.amazonaws.com/0/140055/97321189-7004-4900-ffa9-f6825c261c0e.png)
##新着LED
新着LEDの点灯/消灯は新しく「いいね」がつかないので確認できなかった。
__この投稿で確認できたらなぁ__。

#最後に
サイト見れば済む話だけどね。

#参考サイト
[techtutorialsx](https://techtutorialsx.com/2017/06/11/esp32-esp8266-micropython-http-get-requests/)
[micropython on ESP32 でぽちっとな](http://ippei8jp.hatenablog.jp/entry/2017/08/14/113816)
[いっぺーちゃんの いろいろやってみよ～](http://ippei8jp.hatenablog.jp/entry/2017/08/17/113753)