いっぺーちゃんの いろいろやってみよ~

micropython on ESP32 でモジュールをインストールする

micropythonにはPyPiサイトに用意されたモジュールをインストールするためのモジュール upip が用意されています。

import upip
upip.install("パッケージ名")

でインストールできます。
ちなみに、upipのソースはmicropython-esp32/esp32/modules/upip.pyにあり、micropython本体に組み込まれています。

しかし、サーバアドレスが固定されているため、自分で作ったモジュールをインストールするには使用できません。
また、PyPiサイトのモジュール管理形式を使用しているため、URLを自分のサーバに変えるだけではうまくいきません。

 

そこで、upipもどきなモジュール upipm (例によって「もどき」の「m」を追加)を作ってみました。
BaseURL で指定されたURLからget_file()の第1パラメータで指定したファイルを第2パラメータで指定したディレクトリに保存します。
ダウンロード元はHTTPサーバでなければなりません(Espruinoで作ったmnpmと同じです)。

import sys
import gc
import uos as os

gc.collect()

debug = False

# Base URL
BaseURL = "http://192.168.78.80/py_modules/"# 自分の環境に合わせて修正してくさだい

class NotFoundError(Exception):
    pass

import ussl
import usocket
warn_ussl = True
def url_open(url):
    global warn_ussl

    if debug:
        print(url)

    proto, _, host, urlpath = url.split('/', 3)
    if debug:
        print("proto:%s, host:%s, urlpath:%s" % (proto, host, urlpath))

    if proto == "https:":
        port = 443
    else:
        port = 80

    try:
        ai = usocket.getaddrinfo(host, port)
    except OSError as e:
        fatal("Unable to resolve %s (no Internet?)" % host, e)

    if debug:
        print("Address infos:", ai)
    addr = ai[0][4]

    s = usocket.socket(ai[0][0])
    try:
        if debug:
            print("Connect address:", addr)
        s.connect(addr)

        if proto == "https:":
            s = ussl.wrap_socket(s)
            if warn_ussl:
                print("Warning: %s SSL certificate is not validated" % host)
                warn_ussl = False

        # MicroPython rawsocket module supports file interface directly
        s.write("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n" % (urlpath, host))
        l = s.readline()
        if debug:
            print(l)
        protover, status, msg = l.split(None, 2)
        if status != b"200":
            if status == b"404" or status == b"301":
                raise NotFoundError("File not found")
            raise ValueError(status)
        while 1:
            l = s.readline()
            if debug:
                print(l)
            if not l:
                raise ValueError("Unexpected EOF in HTTP headers")
            if l == b'\r\n':
                break
    except Exception as e:
        s.close()
        raise e

    return s


def fatal(msg, exc=None):
    print("Error:", msg)
    if exc and debug:
        raise exc
    sys.exit(1)


def get_file(name, distdir=None):
    if distdir is None:
        distdir = sys.path[1]
    if distdir[-1] != "/":
        distdir += "/"

    f = url_open(BaseURL + name)
    print("==== START ====")
    with open(distdir + name, "wb") as outf:
        while True:
            l = f.readline()
            if not l:
                break
            outf.write(l, len(l))
            # print(len(l))
            print(l)
    print("==== DONE ====")

def help():
    print("""\
upipm - Simple PyPI package manager **MODOKI** for MicroPython
Usage: 
import upipm; upipm.get_file(name, [<path>])

If <path> is not given, packages will be installed into sys.path[1].
""")
    print("Current value of sys.path[1]:", sys.path[1])

if __name__ == "__main__":
    def main():
        get_file("upipm.py")

if __name__ == "__main__":
    main()

 

BaseURLは自分の環境に合わせて変更しておいてください。
また、オンボードストレージに/libディレクトリが存在しない場合は、以下のように実行してディレクトリを作成しておいてください。

import uos
uos.chdir("/")
uos.listdir()
     ==> ['boot.py']
uos.mkdir("/lib")
uos.listdir()
     ==> ['boot.py', 'lib']

 

このプログラムのファイルをupipm.pyという名前でBaseURLの場所に格納しておき、プログラム自体をコンソールからコピペして実行すると、upipm.pyがインストールされます。

以下のように実行すると正常にインストールできたか確認できます。

import uos
uos.listdir("/lib")
     ==> ['upipm.py']

 

インストール後は、以下のように実行すると任意のファイルをインストールできます。
モジュール単位でのインストールではなく、ファイル単位なので、ファイル拡張子(.py)も忘れずに指定してください。
デフォルトのインストール先はsys.path[1](ESP32の場合は/lib)です。

import upipm
upipm.get_file("ファイル名")

 

また、第2パラメータにはインストール先を指定することも可能です。
たとえば、こんな感じ。

upipm.get_file("boot.py", "/")

 

micropython on ESP32 でWi-Fiルータ(or AP)に接続する

ESP32をWi-Fiルータ または アクセスポイントに接続します。
以下のプログラムを実行すると、Wi-Fiルータに接続できます。

SSID_NAME = "SSID名"
SSID_PASS = "パスワード"

import utime
import network
# ==== connecti to wifi access point ============================================
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)

 

Espruinoのときとは違い、micropythonでは次回起動時に自動的に再接続はしてくれません。
Wi-Fiに接続するには、このプログラムを起動の度に実行しなければなりません。
micropythonは起動時にオンボードストレージの /boot.py を自動的に実行してくれますので、このプログラムを /boot.py として保存しておけば起動のたびにWi-Fiに接続できます。
ただし、設定したSSIDが通信範囲内にない場合はタイムアウトするまで(10秒)起動が遅れます。

オンボードストレージには下記のプログラムで書き込めます。
プログラムが小さいので、プログラム全体を文字列として保存し、それを書き込んでいます。
プログラムの中に「'''」「\n」「\r」などがないことを確認し、あれば別の文字に置き換えてください。

script = '''
# <<ここにパラメータを設定した上のプログラムをコピペしてください>>
'''
f=open("boot.py","wt")
f.write(script)
f.close()

 

書き込んだ内容を確認するには以下のように実行すればOKです。

open("/boot.py","rt").read()

 

一時的にboot.pyを無効にしたい場合はリネームしておくと良いでしょう。
以下のように実行するとリネームできます。

import uos
uos.chdir("/")
uos.listdir()
     ==> ['boot.py']
uos.rename("boot.py", "boot.temp")
uos.listdir()
     ==> ['boot.temp']

 

元に戻す場合は、uos.renameのパラメータを入れ替えて元に戻してください。

 

/boot.pyでなく、/lib/MyWifi.pyとして保存しておき、必要なときに

import MyWifi

とすることもできます。
/lib に保存するときはあらかじめ/libディレクトリを作成しておいてください。

import uos
uos.chdir("/")
uos.listdir()
     ==> ['boot.py']
uos.mkdir("/lib")
uos.listdir()
     ==> ['boot.py', 'lib']

 

 

 

micropython on ESP32 でダウンローダを使う

プログラムを作成して、逐一コピペするのは面倒だなぁ、と思うでしょ?
micropythonにはダウンローダが用意されています。tools/pyboard.py がそれです。

/work2/esp/micropython-esp32/tools/pyboard.py --device /dev/ttyUSB0 file名

で実行できるはずなんですが、ちょっとうまく動きません(PATHが通ってないのでフルパスで指定)。
どうも、ESP32をリセットした後からシリアルを接続するとうまく接続できない現象が影響しているようです。
そこで、pyboard.pyが動作開始時にソフトリセットを行っている部分をハードリセットに変更する変更を行います。
ついでに、--device オプションのデフォルト値を /dev/ttyUSB0 に変更しておきます。
以下がそのパッチです。
あ、手動でリセットボタン押す修正をしたときの残骸がコメントアウトされて残ってる。。。(^^ゞ

diff --git a/tools/pyboard.py b/tools/pyboard.py
index d15f520..992b1ac 100755
--- a/tools/pyboard.py
+++ b/tools/pyboard.py
@@ -220,6 +220,12 @@ class ProcessPtyToTerminal:
     def inWaiting(self):
         return self.ser.inWaiting()
 
+    def setRTS(self, data):
+        return self.ser.setRTS(data)
+
+    def setDTR(self, data):
+        return self.ser.setDTR(data)
+
 
 class Pyboard:
     def __init__(self, device, baudrate=115200, user='micro', password='python', wait=0):
@@ -278,13 +284,47 @@ class Pyboard:
         return data
 
     def enter_raw_repl(self):
-        self.serial.write(b'\r\x03\x03') # ctrl-C twice: interrupt any running program
+        ## self.serial.write(b'\r\x03\x03') # ctrl-C twice: interrupt any running program
+        # print("Reset Target and Hit CR key!!")
+        # sys.stdin.readline()
+        # print("continue...")
+        # time.sleep(1)
+        # ====== haedware reset ! =======
+        """
+            == truth table ==
+            RTS DTR |RESET BOOT
+            --------+----------
+             0   0  | 1     1
+             0   1  | 0     1
+             1   0  | 1     0
+             1   1  | 1     1
+
+        """
+        print("Reseting Target ....")
+        self.serial.setDTR(False)  # DTR = HIGH  
+        self.serial.setRTS(True)   # RTS = LOW   IO0=HIGH, EN=LOW  reset assert
+        time.sleep(0.3)
+        self.serial.setRTS(False)  # RTS = HIGH  IO0=HIGH, EN=HIGH  reset deassert
+        time.sleep(0.8)
+        print("Done")
 
         # flush input (without relying on serial.flushInput())
         n = self.serial.inWaiting()
+        if n == 0 :
+            print("probably reset failure...")
+        """
         while n > 0:
-            self.serial.read(n)
+            a = self.serial.read(n)
+            print(a)
             n = self.serial.inWaiting()
+        print("^^^^^^^^ boot message end ^^^^^^^^")
+        """
+        # waiting prompt...
+        print("waiting prompt")
+        data = self.read_until(1, b'>>>')
+        if not data.endswith(b'>>>'):
+            print(data)
+            raise PyboardError('could not get prompt')
 
         self.serial.write(b'\r\x01') # ctrl-A: enter raw REPL
         data = self.read_until(1, b'raw REPL; CTRL-B to exit\r\n>')
@@ -295,7 +335,6 @@ class Pyboard:
         self.serial.write(b'\x04') # ctrl-D: soft reset
         data = self.read_until(1, b'soft reboot\r\n')
         if not data.endswith(b'soft reboot\r\n'):
-            print(data)
             raise PyboardError('could not enter raw repl')
         # By splitting this into 2 reads, it allows boot.py to print stuff,
         # which will show up after the soft reboot and before the raw REPL.
@@ -384,7 +423,7 @@ def execfile(filename, device='/dev/ttyACM0', baudrate=115200, user='micro', pas
 def main():
     import argparse
     cmd_parser = argparse.ArgumentParser(description='Run scripts on the pyboard.')
-    cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device or the IP address of the pyboard')
+    cmd_parser.add_argument('--device', default='/dev/ttyUSB0', help='the serial device or the IP address of the pyboard')
     cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device')
     cmd_parser.add_argument('-u', '--user', default='micro', help='the telnet login username')
     cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password')

 

このパッチをあてて

/work2/esp/micropython-esp32/tools/pyboard.py file名

と実行するとfile名で指定したプログラムがダウンロードされ、実行されます。
プログラムの実行が完了し、プロンプトが返ってきたらダウンローダは終了します。
ただし、前回のプログラムのように、プロンプトが返ってきた後も割り込みが発生するようなプログラムではダウンローダが終了すると割り込み処理結果を得ることができません。
その場合は、--follow オプションを指定して実行してください。プロンプトが返ってきたあともダウンローダは終了せず、ESP32からのデータを表示し続けます。
終了するにはCTRL-Cを入力します。
--followオプション指定時、プロンプトが表示されてもキー入力はできませんので注意してください。

 

micropython on ESP32 でぽちっとな

またまた定番のボタンをぽちっと押してみます。

GPIO端子(下の例ではIO21)にpull-up抵抗とスイッチを接続し、Active Lowな入力にします。
以下のプログラムを実行すると、スイッチを押したり放したりすると「ぽちっとな~」とか「はなしたでー」とか表示されます。

。。。ん?そうです、micropythonは日本語が使えるんです。

ということで、シリアルコンソールの日本語モードは「UTF-8」に設定しておいてください。gtktermはUTF-8のみ対応のようなので、これを使う場合は特に設定不要です。

また、コンソール上で通常モード時は日本語入力ができないので、CTRL+Eでペーストモードにしてからコピペし、CTRL-Dで通常モードに戻してください。

 

import sys
platform = sys.platform
# platform :    ESP32 => 'esp32'
#               Linux => 'linux'

if platform == 'linux':
    raise ValueError("Linux not support GPIO")

import machine
import utime

# 前回の割り込み受付時刻
pin21_prev_time = utime.ticks_ms()

# PIN21の割り込みハンドラ
def int_handler_gpio21(p):
    global pin21_prev_time
    cur_time = utime.ticks_ms()
    if cur_time < pin21_prev_time + 100 :
        # 前回受付から100msec未満だったらチャタリングと判断してスキップ
        return

    # 前回の割り込み受付時刻を更新
    pin21_prev_time = cur_time

    # 現在のpinレベル
    cur_data = p.value()
    # 現在のpinレベルをスイッチ状態の文字列に変換(active LOWなのでTrueのとき"OFF")
    message = 'はなしたでー' if cur_data else 'ぽちっとな~'     # active LOW
    print(message)

# PIN21を入力モードに設定
pin21=machine.Pin(21, machine.Pin.IN)
# int_handler_gpio21 を PIN21の割り込みハンドラに設定(両エッジ)
pin21.irq(trigger=machine.Pin.IRQ_RISING | machine.Pin.IRQ_FALLING, handler=int_handler_gpio21)

 

 以下解説。

最初の方は前回と同じです。

時刻関連の処理を行うため、utimeモジュールをインポートします。今回は相対時間だけ欲しいので、時刻合わせは不要です。

import utime

# 前回の割り込み受付時刻
pin21_prev_time = utime.ticks_ms()

割り込み発生間隔を測るための時刻ですが、最初に1回読み込んでおきます。

 

端子の入力レベルが変化したときに実行されるcallback関数です。関数のパラメータpには対象の端子のインスタンスが入っています。これを使えば複数の端子に同じcallback関数を割り当てる、という使い方も可能です。

# PIN21の割り込みハンドラ
def int_handler_gpio21(p):
    ....

 

Espruinoではチャタリング除去時間を設定できましたが、micropythonではそのような機能がありません。そこで、現在の時刻とcallback関数が前回実行された時刻の差が100msec以下だったらチャタリングとみなして何も処理せずに終了します。100msecが妥当かどうかは検証する必要があるでしょう。

    global pin21_prev_time
    cur_time = utime.ticks_ms()
    if cur_time < pin21_prev_time + 100 :
        # 前回受付から100msec未満だったらチャタリングと判断してスキップ
        return

    # 前回の割り込み受付時刻を更新
    pin21_prev_time = cur_time

 

現在の端子レベルを読み込んで、Lowレベルだったら「ぽちっとな~」、Highレベルだったら「はなしたでー」を表示します。Active Lowのスイッチなので、こうなっています。Active Highのスイッチの場合は文字列を逆にしてください。(このコードだとチャタリングの発生タイミングによっては正常な値が読めるとは限らないんだよなぁーー。細かいことは目をつぶってください。)

    # 現在のpinレベル
    cur_data = p.value()
    # 現在のpinレベルをスイッチ状態の文字列に変換(active LOWなのでTrueのとき"OFF")
    message = 'はなしたでー' if cur_data else 'ぽちっとな~'     # active LOW
    print(message)

 

 messageを設定している部分はCで言う三項演算子です。ちょっとわかりにくいですね。
Cで書くとこんな感じかな。

message = cur_data ? "はなしたでー" : "ぽちっとな~"

 

 使用する端子を入力モードに設定します。

pin21=machine.Pin(21, machine.Pin.IN)

 

 端子の割り込み処理を登録します。
triggerでIRQ_RISING(立ち上がり)とIRQ_FALLING(立ち下り)を指定しているので両エッジでcallback関数が実行されます。

pin21.irq(trigger=machine.Pin.IRQ_RISING | machine.Pin.IRQ_FALLING, handler=int_handler_gpio21)

 

 

micropython on ESP32 でLチカ

ということで、定番のLチカ

GPIO端子(下の例ではIO22とIO23)にLEDと電流制限用抵抗を接続しておきます。
Active HighでもActive LowでもOK(点滅するので、どっちになってても分からない)。

 

以下のプログラムを実行すると、LEDがそれぞれの周期で点滅します。

import sys
platform = sys.platform
# platform :    ESP32 => 'esp32'
#               Linux => 'linux'

if platform == 'linux':
    raise ValueError("Linux not support GPIO")

import machine


# 現在のpinレベルを反転して出力
def pin_toggle(p) :
    cur_data = p.value()
    p.value(not cur_data)

# 端子を初期化(出力モード、Low出力)
pin22=machine.Pin(22, mode=machine.Pin.OUT, value=0)
pin23=machine.Pin(23, mode=machine.Pin.OUT, value=0)

# タイマ0用割り込みハンドラ
def int_handler_timer0(t):      # t はタイマのインスタンスが入っている
    pin_toggle(pin22)

# タイマ1用割り込みハンドラ
def int_handler_timer1(t):      # t はタイマのインスタンスが入っている
    pin_toggle(pin23)

# タイマ0の設定
t0 = machine.Timer(0)           # タイマは0~3が指定可能
t0.init(period=1300, mode=machine.Timer.PERIODIC, callback=int_handler_timer0)

# タイマ1の設定
t1 = machine.Timer(1)
t1.init(period=1000, mode=machine.Timer.PERIODIC, callback=int_handler_timer1)

 

 

プログラムを実行するには、ESP32を接続したシリアルコンソールで1文字ずつ入力するか、CTRL+Eでペーストモードにして(プロンプトが===に変わる)、ソースをコピペし、CTRL+Dで通常モードに戻すとプログラムが実行されます。

通常モードでコピペすると悲しいことになりますので注意してください。

 

 

 以下解説のようなものです。

 

現在の実行環境をチェックします。Linux版ではGPIOを使えないのでエラー終了しています。

import sys
platform = sys.platform
# platform :    ESP32 => 'esp32'
#               Linux => 'linux'

if platform == 'linux':
    raise ValueError("Linux not support GPIO")

 

GPIOやタイマを使用するため、machineモジュールをインポートします。

import machine

 

GPIO端子の出力を反転する関数です。Espruinoのようなtoggleメソッドは用意されていないようです。

valueメソッドはパラメータなしのとき、現在の端子の値を取得します。パラメータにFalseや0を指定するとLowが、Trueや1を指定するとHighが出力されます。

def pin_toggle(p) :
    cur_data = p.value()
    p.value(not cur_data)

 

端子の初期化です。IO22を出力モードで、Lowレベル出力に初期化しています。

以下、説明はIO22端子側だけですが、IO23端子も同様の処理を行っています。

pin22=machine.Pin(22, mode=machine.Pin.OUT, value=0)

 

周期的に実行するため、タイマのcallbackを使用します。そのcallback関数です。端子を反転する処理を行っています。
関数のパラメータtには対象のタイマのインスタンスが入っていますが、特に有用な情報が入っていないので参照していません。でも書いておかないと実行時にエラー(TypeError: function takes 0 positional arguments but 1 were given)になります。

def int_handler_timer0(t):      # t はタイマのインスタンスが入っている
    pin_toggle(pin22)

細かい話ですが、このcallback関数はハードウェアの割り込みハンドラで直接実行されるのではなく、ハードウェアの割り込みハンドラで仮想マシンの例外をアサートし、仮想マシンのコマンドループ内で例外として処理されるようです。

 

タイマの初期化です。
タイマは0~3が指定できます。それ以上を指定した場合は指定値を0x03でマスクした値が使用されます。つまり、4を指定すると0が、5を指定すると1が指定されたものとみなします。
modeにmachine.Timer.PERIODICを指定することでperiodicで指定した時間(msec)間隔でcallbackで指定した関数が実行されます。
modeにmachine.Timer.ONE_SHOTを指定すると、 periodicで指定した時間(msec)後に1回だけcallbackで指定した関数が実行されます。

t0 = machine.Timer(0)           # タイマは0~3が指定可能
t0.init(period=1300, mode=machine.Timer.PERIODIC, callback=int_handler_timer0)

タイマを停止するときは t0.deinit() と実行します。

 

 

 

ESP32でmicropython

天邪鬼ないっぺーちゃんはpythonを避けてEspruinoでごちょごちょやってきましたが、やはりpythonも試しておこうということで、micropythonを試してみることにします。

 

micropythonのビルドは、Windowsで色々ハマるより、Ubuntu仮想マシンで実行するのがオススメです。
私の環境はこんな感じです。
環境:Windows10 Home(64bit) + VirtualBox + Ubuntu(64bit) 16.04 LTS

インストールについては、このあたりでどうぞ。
(バージョンちょっと違うけど、手順は似たようなもんです)

 特に、sambaの設定をしておくと、WindowsからネットワークドライブとしてUbubtuのディスクが見えるので使い慣れたエディタが使えて便利です。

 

以下、ツールのインストールからビルド、書き込みまでの手順です。

使用するツール類をインストールします。

sudo apt-get install -y git wget make libncurses-dev flex bison gperf python python-serial

シリアルターミナルにgtktermを使いたい場合はインストールします

sudo apt-get install -y gtkterm

使わないっぽいけど入れておいてもいいかな?(たぶんesp-idfのサンプルをmakeするときに必要?)

sudo apt-get install -y autoconf  libtool

シリアルポートを使用するための設定をします。これをやらないとシリアルポートを使おうとしたときに「ぱーみっしょんでないど~」と怒られます。

sudo gpasswd -a <<ユーザ名>> dialout 

これを有効にするには一旦ログアウトして再ログインが必要ですが、後でやるのとまとめてもOKです。

 

作業ディレクトリを作成します。以降、この作業ディレクトリとして書いてありますので、自分の環境に合わせて読み替えてください。

mkdir -p /work2/esp
cd /work2/esp

コンパイラをインストールします。下記は64bit版です。32bitOSでは動きません。

wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz
tar xzvf xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz

esp-idf(ESP32のドライバ)を取得します。--recursiveの指定を忘れると悲しいことになるので注意してください。

git clone https://github.com/espressif/esp-idf.git --recursive

micropythonのソースを取得します。こっちも--recursive忘れないように。

git clone https://github.com/micropython/micropython-esp32.git --recursive

micropythonのソースは Sun Jul 30 19:44:58 2017 -0400 にcommitされたもの( ハッシュ値は 79feb95670311eee5ffb61f1dfd8183901d5e441 ) で確認しています。

~/.profile に以下の設定を追加します。

# for ESP32
export PATH=$PATH:/work2/esp/xtensa-esp32-elf/bin
export IDF_PATH=/work2/esp/esp-idf

# for Micropython
export ESPIDF=/work2/esp/esp-idf

.profileの設定を有効にするため、一旦ログアウトして再度ログインしてください。

 

再ログインしたら、micropythonのbuildにかかりましょう。

まず、micropythonクロスコンパイラを生成します。

cd /work2/esp/micropython-esp32/mpy-cross
make

必要なesp-idfのバージョン(HASH値)を確認します。バージョンが異なっているとmakeに失敗したり、うまく動作しなかったりすることがあります。

cd /work2/esp/micropython-esp32/esp32
make idf-version
== 結果 ==
ESP IDF supported hash: 4ec2abbf23084ac060679e4136fa222a2d0ab0e8

このHASHを使ってesp-idfをチェックアウトします。念のため、branch作っておきます。

cd /work2/esp/esp-idf
git checkout 4ec2abbf23084ac060679e4136fa222a2d0ab0e8 -b micropythn

submoduleもupdate します。これ重要!! やらないとsubmoduleと本体のバージョンが合わなくなることがあります。

git submodule update

 

ESP32用 micropython をbuildします。

cd /work2/esp/micropython-esp32/esp32
make

buildが完了したらプログラムを書き込むためESP32を接続します。

ESP32は/dev/ttyUSB0につながっているものとします。それ以外につながっているときは、PORT=/dev/ttyほにゃらら で指定してください。

現在書き込まれているプログラムを消去します。Flash全体を消去しますので、すべてのデータが消去されます。

make erase

buildしたプログラムを書き込みます。

make deploy

Flashの書き込みで失敗する場合は、
VirtualBoxでは 一旦仮想マシンをシャットダウンし、VirtualBoxマネージャで 設定→USB の「USB 3.0(xHCI)コントローラ」を選択してから再起動してみてください。

 

ターミナルソフトを起動します。

gtkterm&

Configuration → Port でポートの設定をします

Port /dev/ttyUSB0
BaudRate 115200
Parity none
Bits 8
Stopbits 1
Flow control Xon/Xoff

 

を選択してOK

Configuration → Save configuration で設定を保存します
Configuration name にdefaultを指定し、OK
overwrite?と聞かれるのでOK

defaultに保存しておけば、次回からは設定不要です。

ターミナルソフトを起動してからESP32をリセットしないと、通信がうまくいかないようです。
ターミナルソフトを起動した後、ESP32のリセットボタンを押してください。

 

gitで最新版のファイルに差し替えるには、git pull するのが普通だけど、
今あるディレクトリを~.oldとかにリネームしておいて、再度新しくgit clone した方が間違いが少ないと思われます。(submodule関連がとくにややこしい)
開発に参加しているわけではないので、それで事足ります。
自分が修正した部分は、あらかじめgit diff を保存しておいて、新しいディレクトリでpatchをあてるのが簡単かな。

 

 

 

Espruino on ESP32 で Twitter にも日本語を

LINEでは日本語の送信をできるようにしたので、Twitterでも日本語の送信ができるようにということで、Espruino on ESP32 で Twitter(その2) - いっぺーちゃんの いろいろやってみよ~ で紹介したtiny_twitterモジュールのtweet処理のメッセージを日本語対応にしてみました。

 

チョイ変だけで済むと思ったら、そうでもなかった。。。
ついでにパーセントエンコード処理がダブっていた部分を整理したり、ちょこちょこと変更しました。

 

以下が日本語対応版 tiny_twitter モジュールです。

tiny_twitter_20170803.zip

zipファイルを解凍してオンボードストレージの /node_modules ディレクトリに格納してください。
日本語対応しているのは送信のみで、受信は対応していません。
受信を日本語対応するには、Espruino本体のString関連処理を大幅に修正する必要がありそうなので、あきらめました。

 

日本語をtweetするには、LINEのときと同様に送信文字列をあらかじめパーセントエンコードしたものを指定し、第3パラメータにエンコード済みを示すtrueを指定します。

var message = "%E3%81%8A%E3%81%AF%E3%82%88%E3%81%86";                 // おはよう
var param   = {"trim_user":true,"include_entities":false};
tw.tweet(message, param, true);                    // パーセントエンコード済み文字列のときは第3パラメータをtrueに

 

これを使って、Espruino on ESP32 で Twitter(その3) - いっぺーちゃんの いろいろやってみよ~ のTweetボタンを日本語化したものが以下です。

 

consumer_key    = '取得した Consumer key';
consumer_secret = '取得した Consumer secret';
access_token    = '取得した Access Token';
access_secret   = '取得した Access Token Secret';

var messages = [
    "%E3%81%8A%E3%81%AF%E3%82%88%E3%81%86",                 // おはよう
    "%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF",        // こんにちは
    "%E3%81%93%E3%82%93%E3%81%B0%E3%82%93%E3%81%AF",        // こんばんは
    "%E3%81%8A%E3%82%84%E3%81%99%E3%81%BF",                 // おやすみ
];

if (typeof(ESP32) ==='function') {
    // platform is espruino on ESP32
    // Wi-Fi アクセスポイントへの接続
    var wifi = require('MyWifi');
    // set time zone  fixed to 'JST'
    E.setTimeZone(9);

    // Initialize for switch
    var sw1  = Pin(21);
    sw1.mode("input" );
} else {
    throw "not ESP32";
}

// モジュール読み込み
var tiny_twitter = require("tiny_twitter");

// 初期化
var tw = new tiny_twitter(consumer_key, consumer_secret, access_token, access_secret, true);

tw.on("connect", function() {
    console.log("%%%% CONNECTED %%%%");
});
tw.on("response_header", function(data, code, msg) {
    if (code != 200) {
        console.log("%%%% RESPONSE ERROR!!!   " + code.toString() + " : " + msg);
    }
    console.log("%%%% RESPONSE_HEADER %%%%\n" + data + "\n%%%%%%%%%%%%%%%%%%%%%%%%%");
});
tw.on("data", function(data) {
    console.log("%%%% DATA %%%%");
    console.log(JSON.stringify(data,  null, '\t'));
    // エラー時はdata.errors.code data.errors.message に情報が入る
    console.log("%%%%%%%%%%%%%%%%%%%%%%%%%");
});
tw.on("end", function() {
    console.log("%%%% END %%%%");
});

function button_down(e) {
    var msg;
    var date = new Date();
    h = date.getHours();
    if (h >=4 && h < 12) {
        msg = messages[0];      // おはよう
    } else if (h >=12 && h < 17){
        msg = messages[1];      // こんにちは
    } else if (h >=17 && h < 21){
        msg = messages[2];      // こんばんは
    } else {
        msg = messages[3];      // おやすみ
    }
    tw.tweet(msg, {"trim_user":true,"include_entities":false}, true);
}

setWatch(button_down, sw1, {repeat:true, edge:"falling", debounce:100});

 

 これで日本語をtweetすることができるようになりました(ひと手間余分に必要ですが)。
ちょっと使い道が広がったかな??