ESP8266のmicropythonでLCD Keypad Sheildを使う

# 調べる
arduino IDEだとLiquidCrystalでまったく苦労しなかったのですがmicropythonからLCDを使えるようにするのに大苦戦しました。LCD Keypadシールドを使いたかったので、Wemos D1というArduino Uno互換ボードを使って実験しています。

### arudino IDEのサンプルコード

- Wemos D1から使用する場合の変更点は下記の通りです。

``` display.ino
//const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
const int rs = 0, en = 2, d4 = 4, d5 = 14, d6 = 12, d7 = 13; // Wemos D1 
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
```

# LCD Keypad Sheildを使う

### A0 - GNDに抵抗を入れる

- A0を保護するため3.3KΩの抵抗をA0 - GNDに入れる。<br/>
　（ESP8266のA0は3.3Vなので5Vを3.3Vに分圧します。）

### ライブラリをダウンロードする。

- [python_lcd](https://github.com/dhylands/python_lcd)
（dhylandsさんに感謝！）

### ライブラリをESP8266に転送する

- lcd_api.py
- machine_i2c_lcd.py

### サンプルコードをESP8266に転送する

- machine_i2c_lcd_test.py
- GpioLcdの宣言を環境に合わせて変更します。
- Wemos D1から使用する場合の変更点は下記の通りです。

``` machine_i2c_lcd_test.py
    """
    lcd = GpioLcd(rs_pin=Pin(4),
                  enable_pin=Pin(17),
                  d4_pin=Pin(5),
                  d5_pin=Pin(18),
                  d6_pin=Pin(21),
                  d7_pin=Pin(22),
                  num_lines=2, num_columns=20)
    """
    lcd = GpioLcd(rs_pin=Pin(0),
                  enable_pin=Pin(2),
                  d4_pin=Pin(4),
                  d5_pin=Pin(14),
                  d6_pin=Pin(12),
                  d7_pin=Pin(13),
                  num_lines=2, num_columns=16) # Wemos D1
```

### 無事表示されました！！

# おまけ

### python_lcdのAPI一覧

|no.|API|機能|備考|
|:-- |:-- |:-- |:-- 
|1|lcd.clear()|画面クリア||
|2|lcd.show_cursor()|カーソル表示||
|3|lcd.hide_cursor()|カーソル非表示||
|4|lcd.blink_cursor_on()|カーソル点滅||
|5|lcd.blink_cursor_off()|カーソル点滅停止||
|6|lcd.display_on()|画面表示||
|7|lcd.display_off()|画面非表示||
|8|lcd.backlight_on()|バックライト点灯||
|9|lcd.backlight_off()|バックライト非点灯||
|10|lcd.move_to(x,y)|カーソル位置移動||
|11|lcd.putchar(char)|文字表示||
|12|lcd.putstr(str)|文字列表示||
|13|lcd.custom_char(location, charmap)|カスタム文字登録| location 0 - 7:8 CGRAM locations<br/> charmap = data[8]|

カスタム文字表示のサンプル

``` custom_char_test.py
data  = [0xff, 
         0xff, 
         0xff, 
         0xff, 
         0xff, 
         0xff, 
         0xff,
         0xff]
lcd.custom_char(0, data)
lcd.putchar(chr(0))
```

### LCD Keypadシールドを使った利用例

以前作ったソースコードを流用して天気予報付き時計を作ってみました。
個体差なのか手元のWemos D1は1時間に数分レベルで時間がずれるので１時間毎にNTPで時間を再設定しています。RSSも同じタイミングで更新しています。

実用性は相変わらず微妙です。

``` main.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from machine import Pin
from nodemcu_gpio_lcd import GpioLcd
import urequests
import ntptime
import time

HARE = "\\xc0\\xb2\\xa4\\xec"
KUMORI = "\\xc6\\xde\\xa4\\xea"
AME = "\\xb1\\xab"
TOKIDOKI = "\\xbb\\xfe\\xa1\\xb9"
NOCHI = "\\xa4\\xce\\xa4\\xc1"
ICHIJI = "\\xb0\\xec\\xbb\\xfe"

weather_view_eng = ["and ", "and ", "and ", "Rainy ", "Cloudy ", "Sunny "]
weather_table = [ICHIJI, NOCHI, TOKIDOKI, AME, KUMORI, HARE]
url = "http://weather.goo.ne.jp/area/4410.rdf"

# 時間を表示する
def draw_time(lcd):
    t = time.gmtime()
    h = (t[3] + 9) % 24  # GMT+9
    m = t[4]
    s = t[5]
    lcd.putstr("Time: {0:02}:{1:02}:{2:02}".format(h, m, s))

# 天気予報を表示する
def draw_tenki(lcd):
    # 東京
    r = urequests.get(url)
    lines = str(r.content)
    line = lines.split("\\n")
    description = line[10]
    description = description.replace("<description>", "")
    description = description.replace("</description>", "")
    flg = True
    while flg:
        flg = False
        for i in range(len(weather_table)):
            if description.startswith(weather_table[i]):
                description = description.replace(weather_table[i], "")
                description = description.strip()
                lcd.putstr(weather_view_eng[i])
                flg = True
                break


# メイン処理
if __name__ == '__main__':
    lcd = GpioLcd(rs_pin=Pin(0),
                  enable_pin=Pin(2),
                  d4_pin=Pin(4),
                  d5_pin=Pin(14),
                  d6_pin=Pin(12),
                  d7_pin=Pin(13),
                  num_lines=2, num_columns=16)
    lcd.clear ()
    count = 0
    while True:
        lcd.move_to(0, 0)
        draw_time(lcd)
        if count % 3600 == 0:    # 1h(60s * 60m)
            count = 0
            ntptime.settime() # NTP
            lcd.move_to(0, 1)
            draw_tenki(lcd)
        count += 1
        time.sleep(1.0)
```