LoginSignup
2
1

M5stackシリーズとUIFlowでLineNotify 2023年度版

Last updated at Posted at 2023-09-02

1. はじめに

M5stackシリーズとUIFlowで直接Line NotifyにPOSTする方法について、参考になる記事と簡単なサンプルを挙げました。
(2023.12/29追記:UIFlowが用いているmicroPythonのurequestsはリダイレクトに対応してないため、お使いの回線によっては、この方法は利用できない場合があります)

2. 準備

2.1. Line Notifyの準備

多くの資料がwebにあります。「Line notify 準備」などで検索しましょう。次が判り易いと思います。

「LINE Notifyを使いたい」nattyan_tv氏
https://qiita.com/nattyan_tv/items/33ac7a7269fe12e49198

注意点を追加するとしたら次があります。

  • Lineのアカウントが必要です(自分のものや職場の電話で登録するなど)
  • Line Notifyの登録はPCで行う方が良いです(Lineはスマホで使いますがLine Notify登録はPCで)

2.2. M5stackシリーズでUIFlowと連携

多くの資料がwebにあります。「M5stack UIFlow」などで検索しましょう。次が判り易いと思います。

「M5Stack UIFlowのはじめかた」 田中正幸 氏
https://lang-ship.com/blog/work/m5stack-uiflow/

注意点を追加するとしたら次があります。

  • UIFlowにバージョン1 と 2 があり、ここではバージョン1を使うことを前提にしています

3. UIFlowでプログラム

今回利用したのはM5stick c で、真ん中のボタンを押すとLineに通知が行くようにします。LineNotifyとの通信が成功すると画面が水色に、失敗するとオレンジになるようにします。

作成したブロックは以下です。少し冗長ですので、判る方はもっとシンプルにしても良いと思います。

m5ui12_.png

こちらがそのファイルです。三角のマークをクリックして、表示されたテキストをコピーしてメモ帳などにペーストしm5line.m5fなどのファイル名で保存し、UIFlowに読み込ませます。(2023.11/27 修正)

m5linenotify.m5f
{"components":[{"id":"_stickscreen","createTime":1692080457941,"name":"screen","x":0,"y":0,"width":120,"height":240,"backgroundColor":"#111111","backgroundImage":"","size":0,"screenType":"default","type":"screen"}],"type":"stick-C","versions":"Beta","units":[],"hats":[],"stamps":[],"blockly":"<variables><variable id=\".~GQ?Sx@?wW}Z1Hh`6#$\">hostAddress</variable><variable id=\"|V)9^ezI1cP3830Q~_6e\">token</variable><variable id=\"Y7Vhv4hjyxGfbJ2-axn-\">tokenBear</variable><variable id=\"wK[o)2By.X``bl^~p}3d\">mess</variable><variable id=\"-fcaWw)=19l}M83*xg?)\">messSend</variable></variables><block type=\"basic_on_setup\" id=\"setup_block\" deletable=\"false\" x=\"-330\" y=\"-310\"><next><block type=\"wifi_doConnect\" id=\"S,6[Y)x#4?`$Ht-,hZmo\"><value name=\"apiKey\"><shadow type=\"text\" id=\"o6WDwp~tpMRE({r5nA8s\"><field name=\"TEXT\">SSID</field></shadow></value><value name=\"Msg\"><shadow type=\"text_password\" id=\"HfkxMI(17rUh+`|Y%VfJ\"><field name=\"TEXT\">password</field></shadow></value><next><block type=\"screen_set_brightness\" id=\"Qe-8+1x(f0n^KA0IzosV\"><value name=\"BRIGHTNESS\"><shadow type=\"math_slider\" id=\"f-%,O#:4{[m!kc3dGYuV\"><field name=\"NUM\" max=\"100\" step=\"1\">30</field></shadow></value></block></next></block></next></block><block type=\"button_callback\" id=\"72fb=5D2*I322CM})q12\" x=\"-330\" y=\"-190\"><field name=\"BUTTON\">A</field><field name=\"EVENT\">wasPressed</field><statement name=\"FUNC\"><block type=\"variables_set\" id=\"2qR~,GTqJ^@RsKlxX{q@\"><field name=\"VAR\" id=\".~GQ?Sx@?wW}Z1Hh`6#$\">hostAddress</field><value name=\"VALUE\"><block type=\"text\" id=\"SR;rE9R`KUkVl-F-u.dq\"><field name=\"TEXT\">https://notify-api.line.me/api/notify</field></block></value><next><block type=\"variables_set\" id=\"Y#Q|vLbIVufEY9$|V_y~\"><field name=\"VAR\" id=\"|V)9^ezI1cP3830Q~_6e\">token</field><value name=\"VALUE\"><block type=\"text\" id=\"N@4/G2zp_z+E-XqY;w0h\"><field name=\"TEXT\">abcdefghijklmnopqrstuvwxyz01234567890123456</field></block></value><next><block type=\"variables_set\" id=\"AH9Z+9*pbc8?9sk_L}DZ\"><field name=\"VAR\" id=\"Y7Vhv4hjyxGfbJ2-axn-\">tokenBear</field><value name=\"VALUE\"><block type=\"text\" id=\"SUv`L$1,^,1^psq/Lkz{\"><field name=\"TEXT\">Bearer </field></block></value><next><block type=\"variables_set\" id=\"pd%K0sgQHBtW?vH,J;mB\"><field name=\"VAR\" id=\"Y7Vhv4hjyxGfbJ2-axn-\">tokenBear</field><value name=\"VALUE\"><block type=\"text_add\" id=\"J;prv[l]EBC2#+-dNn9K\"><value name=\"arg0\"><shadow type=\"text\" disabled=\"true\"><field name=\"TEXT\"></field></shadow><block type=\"variables_get\" id=\"aOJMp/gCm,`unnu`cvUe\"><field name=\"VAR\" id=\"Y7Vhv4hjyxGfbJ2-axn-\">tokenBear</field></block></value><value name=\"arg1\"><block type=\"variables_get\" id=\"SY#UFUFMEw6)ov+m4ktw\"><field name=\"VAR\" id=\"|V)9^ezI1cP3830Q~_6e\">token</field></block></value></block></value><next><block type=\"variables_set\" id=\"~u;H9J}[$!m9Cl}!6|/H\"><field name=\"VAR\" id=\"wK[o)2By.X``bl^~p}3d\">mess</field><value name=\"VALUE\"><block type=\"text\" id=\"S1`-dnJ26(xwdb)Pzv.Z\"><field name=\"TEXT\">\"hello from m5stick\"</field></block></value><next><block type=\"variables_set\" id=\"@H(qeYeQXoRiO9W|rvwL\"><field name=\"VAR\" id=\"-fcaWw)=19l}M83*xg?)\">messSend</field><value name=\"VALUE\"><block type=\"text_add\" id=\"-r`lWt~0r;*;+52808X*\"><value name=\"arg0\"><shadow type=\"text\" id=\":,Z,Q-`yukjCw,A^}JnX\"><field name=\"TEXT\">message= </field></shadow></value><value name=\"arg1\"><block type=\"variables_get\" id=\"IZTf#uGuuwi8-:|7k`{p\"><field name=\"VAR\" id=\"wK[o)2By.X``bl^~p}3d\">mess</field></block></value></block></value><next><block type=\"screen_set_bgcolor\" id=\"zpeW4O,=w5cLQy+}H$T1\"><field name=\"COLOR\">#cc66cc</field><next><block type=\"http_request\" id=\"Y,k{)[Woj4mRRRInczmJ\"><field name=\"method\">POST</field><value name=\"url\"><shadow type=\"text\" id=\"p#s[#{W.UYsXJ|jy_L{~\"><field name=\"TEXT\"></field></shadow><block type=\"variables_get\" id=\"tHW8~nATJbDaBcLQT/h-\"><field name=\"VAR\" id=\".~GQ?Sx@?wW}Z1Hh`6#$\">hostAddress</field></block></value><value name=\"headers\"><block type=\"map_on_loop\" id=\"O8#+ea|+7VA8-*-T?d|S\"><statement name=\"LOOP\"><block type=\"create_json_key\" id=\"N}r[r]|FLWtjls?X{uVY\"><value name=\"key\"><shadow type=\"text\" id=\"A9[!RFjxzvGo$IEl4+;=\"><field name=\"TEXT\">Authorization</field></shadow></value><value name=\"value\"><shadow type=\"text\" disabled=\"true\"><field name=\"TEXT\"></field></shadow><block type=\"variables_get\" id=\"se;+H_.!e.s:Ky}r9/T3\"><field name=\"VAR\" id=\"Y7Vhv4hjyxGfbJ2-axn-\">tokenBear</field></block></value><next><block type=\"create_json_key\" id=\"jcKP#5pHj03hW]zrbPW8\"><value name=\"key\"><shadow type=\"text\" id=\"!|?D2%.P?(X|`7z_|+D8\"><field name=\"TEXT\">Content-Type</field></shadow></value><value name=\"value\"><shadow type=\"text\" id=\"yGPBJxBs%*7F#z7yh%vI\"><field name=\"TEXT\">application/x-www-form-urlencoded</field></shadow></value></block></next></block></statement></block></value><value name=\"data\"><block type=\"variables_get\" id=\")a/CCvLeTHKdQA@WVm%~\"><field name=\"VAR\" id=\"-fcaWw)=19l}M83*xg?)\">messSend</field></block></value><statement name=\"success\"><block type=\"screen_set_bgcolor\" id=\"5M9SFhCwH!GqKIu@Kn#0\"><field name=\"COLOR\">#33ccff</field></block></statement><statement name=\"fail\"><block type=\"screen_set_bgcolor\" id=\"M21A}157J2!U;dqq{I]{\"><field name=\"COLOR\">#ff0000</field></block></statement></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></statement></block>","Blockly.Remotes":[],"Blockly.RemotePlus":[{"id":"__title","blockId":"","createTime":1693542612886,"name":"M5RemoteTitle","dragAndDrop":false,"resizable":false,"options":{"minWidth":1,"minHeight":1,"maxWidth":6,"maxHeight":10,"defaultWidth":2,"defaultHeight":1},"w":2,"h":1,"bgColor":"#0080FF","color":"#fff","fontsize":"M","label":"M5Remote","interval":3000,"code":"","event":"","dataSource":"none","ezdataToken":"","topic":"","needShadow":false,"type":"title","x":0,"y":0}],"modules":[],"cbIdList_":[],"eventCBIdList_":[],"apikey":"AAAAAAAA","uuid":"6666666a-2225-444f-aaaa-fffffffffff4"}

このBlocklyコードをpythonで表示したものが次になります。何かうまくいかない時などに、このコードと比較すると良いでしょう。

m5linenotify.py
from m5stack import *
from m5ui import *
from uiflow import *
import wifiCfg
import urequests


setScreenColor(0x111111)


hostAddress = None
token = None
tokenBear = None
mess = None
messSend = None






def buttonA_wasPressed():
  global hostAddress, token, tokenBear, mess, messSend
  hostAddress = 'https://notify-api.line.me/api/notify'
  token = 'abcdefghijklmnopqrstuvwxyz01234567890123456'
  tokenBear = 'Bearer '
  tokenBear = (str(tokenBear) + str(token))
  mess = '"hello from m5stick"'
  messSend = (str('message= ') + str(mess))
  setScreenColor(0xcc66cc)
  try:
    req = urequests.request(method='POST', url=hostAddress,json=messSend, headers={'Authorization':tokenBear,'Content-Type':'application/x-www-form-urlencoded'})
    setScreenColor(0x33ccff)
    gc.collect()
    req.close()
  except:
    setScreenColor(0xff0000)
  pass
btnA.wasPressed(buttonA_wasPressed)


wifiCfg.doConnect('SSID', 'password')
axp.setLcdBrightness(30)

別のM5stackシリーズに置き換える場合は、まずはm5fを読み込んだ後に、右上の三本線のアイコンをクリックし、「設定」(Setting)をクリックすると、デバイス選択する画面になります。

selectDevice36.png

なお、スクリーンが無い機種は、画面設定のブロックをLED点灯のブロックに置き換えるなど、お使いのM5シリーズに合わせて編集してお使いください。

実は、UIFlowでプログラムも、webに沢山あります。が、「M5stack Line Notify」と検索しても、IFTTT経由のものが上位にきます。Qiitaでもその傾向があります。

今回の例にマッチした情報が載っている記事が次でした。

「LINE Notify を利用して UIFlow のプログラムで LINE に通知を送る(日本語テキストも送信) #M5Stack」 youtoy 氏
https://qiita.com/youtoy/items/76586479c2d4c5893c5b

4. トラブルシューティング

うまくいかない時は、常に正しく動作するプログラムに戻り、変更点を確認するようにしましょう。
それでも変更するとうまく行かない場合は、次を重点的に確認すると問題が見つかることがあります。

  • Wi-Fiが正しく設定され、繋がっているか?
  • メッセージはダブルクォーテーションでくくってあるか?
  • トークンは正しく記載できているか?

4.1. ボタン押下すると失敗する

2通り考えられます。

  • Wi-Fiが接続できてないので、ボタン押下後に失敗側の色になる
  • Wi-Fiは接続しているけど、ボタン押下後に失敗側の色になる

前者は、Wi-Fiの設定を確認します。UIFlowを接続する場合は、Wi-Fiに接続していることが前提ですので、このケースはあまり遭遇しないと思います。

後者は、URLを間違っているなどが考えられます。LINE 公式サイトに書かれているURLがきちんと入力されているかを確認しましょう。

(2023.12/29追記): httpsをリダイレクトするような回線では、UIFlowでサーバに接続ができません。テザリングでも回線によっては接続ができませんでした。

4.2. ボタン押下してもLINEに届かない

ボタン押下後に成功側の色になっているのにもかかわらず、LINEに届かない場合についてです。
HTTP Requestの処理が成功していても、サーバからエラーを返答されている場合にこのような現象になります。これは、HTTP Request処理の記述が問題があることが多いです。

後述しますが、Http Requestのブロックでは、サーバからの返答値を取得することができます。

ありがちなのは次の2つですので、それぞれ勘所を述べます。

  • 400 : Bad Request : ヘッダなどの情報が正しくない
  • 401 : Unauthorized : 認証資格が不足

4.2.1. 400 Bad Request

まず、400番 Bad Request エラーについてです。

  • 400 Bad Request
    • message: must not be empty: メッセージが空

メッセージに関して必要なヘッダ情報は次です。

{'content-type':'application/x-www-form-urlencoded'}

UIFlowでは、キーにcontent-type、値にapplication/x-www-form-urlencodedを入れたmapをHeadersに入れることで送信してくれます。

「メッセージが空」の問題については、次のように送りたいメッセージをダブルクォーテーションでくくることで解決しました。
入力するのは文字列だからダブルクォーテーションは不要と思ったのですが、これを付けないと空のメッセージとみなされるようでした。

"hello from M5"

よって、UIFlowで送信するメッセージとして用意する文字列は次の通りです。

'message= "hello from M5"'

上記は、message: ではなくmessage= (コロンではなくイコール)です。これを間違えるとやはり同じく400エラーになります。

このメッセージ本体を Dataの部分に入れることで送信してくれます。

4.2.2. 401 Unauthorized

次に 401番 Unauthorized エラーについてです。これは認証できなかった時に返ってくるエラーです。

例えば、LINEから取得したアクセストークンが次だったとします。

abcdefghijklmnopqrstuvwxyz01234567890123456

認証に関して必要なヘッダ情報は次です。

{'Authorization':'Bearer abcdefghijklmnopqrstuvwxyz01234567890123456'}

UIFlowでは、

  • キーに Authorization
  • 値に Bearer abcdefghijklmnopqrstuvwxyz01234567890123456

を入れたmapをHeadersに入れることで送信してくれます。

(2023.11/27追記)

この値は、Bearerとトークンの間はスペース1個です。2個以上スペースがあると、401エラーになります。
上は正しい例、下は間違った例です。

Bearer abcdefghijklmnopqrstuvwxyz01234567890123456
Bearer  abcdefghijklmnopqrstuvwxyz01234567890123456

(修正前のm5fファイルは2個スペースが入っており、401エラーになっていました)

4.3. UIFlowでのデバッグ

どうしても問題が解消できない場合は、一つずつ確認する処理を入れると良いでしょう。

  • Wi-Fi接続している場合は画面をフラッシュさせる

これは、「Wi-Fi接続と接続している」( Wi-Fi is connected )とifを使い、その後に画面フラッシュを入れることで実装できます。

  • Http Requestsの返答値を表示する

これは、画面表示ができる機種限定になりますが、「ステータスコードを取得」( Get Status Code (return int) )をLabelに表示することで実装できます。

(追記:2023.12/29)

UIFlowに(beta版の)ターミナルモードがあります。これを使うとデバッグが劇的楽になります。

まずは、M5stack等とPCをUSBで接続し、chromeブラウザなどを起動します。(operaは利用可能なようでした。Firefoxは利用できませんでした)

  1. オレンジ色のTerminal (beta) をクリックします
  2. 現れたターミナルウインドウの左上にあるチェーンのようなアイコンをクリックします
  3. M5が繋がっているcom番号を選択します
  4. 接続をクリックします
  5. ターミナルウインドウの三角マークをクリック
  6. 別途用意したpythonのスクリプトを1行ずつペーストしてい、エラーが出るかを確認していきます

terminal_.png

この方法を用いると、Wi-Fi接続せずともM5に指示を与えることができるので、とても便利です。

4.4. micro Pythonでデバッグ

新規のコードをUIFlowでデバッグするのは結構面倒臭いと思います。
UIFlowは、googleのblocklyを利用してmicro Pythonに変換してM5stack類で動かしています。なので、micro Pythonで確認するのが無難なことがあります。ただし、micro python環境は別途構築が必要で、初心者にはお勧めできませんが、私の場合はthonyを使い、次のようなコードで確認しました。

esp32linenotify.py
#from m5stack import *
#from m5ui import *
#from uiflow import *
#import wifiCfg
import urequests
import network
import utime

#setScreenColor(0x111111)


hostAddress = None
token = None
tokenBear = None
reqhead = None
mess = None
mess = 'hello from M5'
messSend = None


MYSSID='SSID'
MYPASS='PASS'
MYHostAddress = 'https://notify-api.line.me/api/notify'
#wifiCfg.doConnect(MYSSID,MYPASS)
#axp.setLcdBrightness(30)
wifi= network.WLAN(network.STA_IF)
if wifi.isconnected() :
    print('connected')
else:
    wifi.active(True)
    wifi.connect(MYSSID, MYPASS)

TIMEOUT=10
timeout=0
while not wifi.isconnected() and TIMEOUT > timeout:
    print('.')
    utime.sleep(1)
    timeout -= 1


def buttonA_wasPressed():
  global hostAddress, token, tokenBear, reqhead, mess, messSend
  hostAddress = MYHostAddress
  #print('send to'+hostAddress)
  token = 'abcdefghijklmnopqrstuwvxyz01234567890123456'
  tokenBear = 'Bearer '
  tokenBear = (str(tokenBear) + str(token))
  mess = 'hello from M5'
  messSend = (str('message:') + str(mess))
  mess2 = 'message="hello from M5"'
#  messSend = (str(messSend) + str('\\r\\n'))
#  messSend = (str(messSend) + str('\\r\\n'))
  #setScreenColor(0xcc66cc)
  #print('tokenBear: '+tokenBear)
  #print('messSend: '+messSend)
  myHead ={'content-type':'application/x-www-form-urlencoded', 'Authorization':tokenBear }
  try:
    #print('try reqest')
    #req = urequests.get(hostAddress)
    #req = urequests.request(method='POST', url=hostAddress,json=messSend, headers={'Authorization':tokenBear, 'Content-Type':'application/x-www-form-urlencoded', 'Content-Length':str(len(mess)) })
    req = urequests.post(url=hostAddress, headers=myHead,data=mess2 ) #{"status":200,"message":"ok"}
    #setScreenColor(0x33ccff)
    print(req.text)
    gc.collect()
    req.close()
    print('http sent')
  except :
    print('http failure  ')
    #setScreenColor(0xff0000)
  #setScreenColor(0x000000)
  #pass


#print('call function')
buttonA_wasPressed()
print('end of script')


これらを対処するために参考にした記事を紹介します。
まずは、悩ましい エラー400 bad request の解決策を判り易く記載されているのが次でした。

「【ESP32・MicroPython】ドアホンが鳴ったらLINEに通知する」 nak435 氏
https://qiita.com/nak435/items/879b647aa3d7343ba0be

また、Arduino-IDEで組む場合については次が判り易かったです。

「【ESP32】ボタンを押したらLINE通知」 コダマ 氏
https://www.ekit-tech.com/?p=3434

5. おわりに

Line NotifyとUIFlowの組み合わせは、話としてよく聞きます。
Line Notifyについては随分長く継続されているサービスのようで、比較的安心感があります。
一方、UIFlowはバージョンアップが重ねられた後アプリ版の更新が止まり、更新されているのはクラウド版のみになりました。
正直なところ私は、IoTなどの入門として無料のサービスを勧めるのはリスキーだと感じています。無料であるが故に、突然の機能制限や停止の可能性がゼロではないためです。
その観点から、IoT入門の王道は、Arduino-IDEにESP32やRP-picoW、ラズパイにnode-redではないかと思います。
そこへのきっかけとして、Line NotifyとUIFlowの組み合わせは悪くはないとは思いますが、Line NotifyはLineが使えなければ利用できないことを理解しておくべきでしょうし、UIFlowは接続先など様々なリスクを考えて利用すべきだろうと、私は考えます。

A. 修正履歴

(2023.11/27):文章を修正。m5fファイルの認証部分の余計な空白を削除。デバイス変更方法を追加。

(2023.12/29):この方法が使えない場合について追記。デバッグ方法を追記。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1