今日も秋田で IoT

旧 Trema 日記

ATOM Lite から Line へ通知 (MicroPython)

ATOM Lite 本体についているボタンを押したら,Line に通知が飛ぶプログラムを MicroPython で作ってみました.

ATOM Lite とは M5Stack 社が開発した小型マイコンモジュールです.ESP32 という Wi-Fi 機能を持ったマイコンを搭載しています.

ATOM Lite ESP32 IoT Development Kit | m5stack-store

firmware のインストール

以下のサイトに記載の手順をもとに,MicroPython の v1.21.0 をインストールしました.

MicroPython - Python for microcontrollers

はじめ ESP32 に対応したファームウェアを使用したのですが,そちらでは ATOM Lite のボタンなどを制御するためのモジュール (atom) が使えませんでした.

Line Notify のトークン発行

Line に通知を飛ばすためには,Line Notify というサービスを使います.Line Notify のサービスからアクセストークンを取得する必要があります.

PythonでLINE Notifyへ通知を送る #Python - Qiita

MicroPython のプログラム

プログラム (notify.py) は以下のとおりです.Wi-Fi 接続あたりの処理がいい加減ですが,Wi-Fi 接続が失敗しなければ,これでちゃんと動作すると思います.
essid, password, line_notify_token にはそれぞれの環境に合わせた値を設定してください.

from atom import Lite
from network import WLAN, STA_IF
from time import sleep
import requests

essid = 'Wi-Fi接続のESSID'
password = 'Wi-Fi接続のパスワード'

line_notify_api = 'https://notify-api.line.me/api/notify'
line_notify_token = '発行されたトークン'
notification_message = '送りたいメッセージ'

def line_notify( _ ):
    try:
        # Wi-Fi に接続
        wlan = WLAN( STA_IF )
        wlan.active( True )
        if not wlan.isconnected():
            wlan.connect(essid, password) 
            while not wlan.isconnected():
                sleep(1)
        
        # Line への結果通知
        headers = { 
            'Authorization' : 'Bearer {}'.format( line_notify_token ), 
            'Content-Type' : 'application/x-www-form-urlencoded'
        }
        data = 'message="{}"'.format( notification_message )
        response = requests.post( 
            line_notify_api, 
            headers = headers, 
            data = data )
        print(response.status_code)

        # Wi-Fi 切断
        wlan.disconnect()
    except Exception as e:
        print(e)

atom_lite = Lite()
atom_lite.set_button_callback( line_notify )

ATOM Line へのプログラム送信と実行

作ったプログラム (notify.py) は ampy を使って,ATOM Lite に送り,実行します.

$ ampy -p シリアルポート put notify.py
$ ampy -p シリアルポート run nofify.py 

シリアルポートの部分には,ATOM Lite が接続しているシリアルポートのデバイス名を指定してください.Windows であれば COM3 や COM4, MacOS であれば /dev/tty.usbserial-XXXXXXXXXX といったデバイス名になっていると思います.

ampy でプログラムを送り込んだら,ATOM Lite のボタンを押してみてください.Line に通知が行くはずです.

Trema を Docker コンテナ上で動かす

いまさらですが,とある事情で Trema を動かす必要があったため,docker コンテナ上で動かしてみましたので,ここに手順を書き残しておきます.docker 関連の必要なソフトウェアは事前にインストール済みであることを前提に話を進めます.

準備

まず,作業用のディレクトリを用意します.ディレクトリ名は trema-docker としましたが,何でも良いでしょう.

$ mkdir trema-docker
$ cd trema-docker

次に docker-compose.yml を作ります.内容は以下の通り.

version: '3'

services:
  trema:
    container_name: trema
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - type: bind
        source: ./root
        target: /root

Trema を含むコンテナイメージを自前で作る必要があるため,以下の内容で Dockerfile を作成します.Ruby 2.0 が動作するコンテナをベースに,必要な gems を bundle を使ってインストールします.

FROM ruby:2.0
WORKDIR /tmp
COPY ./Gemfile /tmp
RUN bundle install --gemfile=/tmp/Gemfile && bundle clean
WORKDIR /root

Gemfile の中身は以下のとおりです.

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'minitest', '5.8.4'
gem 'concurrent-ruby', '1.0.0'
gem 'trema', '0.10.1'

コンテナ内部の /root にマウントするためのディレクトリを作っておきます.

$ mkdir root

以下のような状態になっていることを確認して次に進みます.

$ ls
docker-compose.yml  Dockerfile  Gemfile  root

コンテナ作成

以下のコマンドでコンテナのイメージを作成します.(少し時間がかかります.)

$ sudo docker-compose build

trema を起動

コンテナ内で trema を起動し,バージョンを表示させるプログラムを動作させてみます.--rm オプションがついているため,trema の終了後,コンテナも消去されます.

$ sudo docker-compose run --rm trema trema --version
trema version 0.10.1

trema アプリを動かす

./root の下に,以下の内容で hello_trema.rb というファイルを作ります.'Trema started.' と表示するだけの OpenFlow コントローラになります.

class HelloTrema < Trema::Controller
  def start(_args)
    logger.info 'Trema started.'
  end
end

このコントローラを起動させるには,以下のようにします.終了させたいときには,Ctrl+C を押してください.

$ sudo docker-compose run --rm trema trema run ./hello_trema.rb
Trema started.

セキュアチャネルを開いて trema アプリを起動

docker-compose run を行う時,docker-compose.yml の ports にセキュアチャネルのポート番号を書いておいても反映されないらしいので,docker-compose のコマンドラインオプションでポート番号を指定します.セキュアチャネルのデフォルトのポート番号は 6653 です.

$ sudo docker-compose run -p 6653:6653 --rm trema trema run ./hello_trema.rb
Trema started.


参考 : docker-composeのportsの設定が反映されない - Qiita

まとめ

docker コンテナ内で Trema を動作させる方法を説明しました.

USB_E220-900T22S レビュー (その 1)

低価格の LoRa モジュール E220-900T22S を搭載した FLINT LoRa無線USBドングル (USB_E220-900T22S) を触ってみたので,備忘録を兼ねて,簡単にレビューする.

ハードウェア

USB シリアル

私は Mac にて使用したが,以下のサイトにて説明されている通りドライバ追加無しで使用できた.

https://flint.works/p/flint-lora-usb/

設定

E220-900T22S は,LoRa 送受信と設定はそれぞれ異なる動作モードで行う必要がある.USB_E220-900T22S ではモードの切り替えスイッチで行うことになる.

付属のケースに収納した後だと,この切り替えスイッチに触ることができない.また,ケースは一度締めると開けづらいので,注意が必要である.

ファームウェア

アドレスについて

設定項目にアドレスが存在し,16 ビットのアドレスを設定することができる.しかしこのモジュールにおけるアドレスは,IP アドレスなどのようにモジュール毎にユニークに割り当てられるアドレスと言うよりは,どちらかというとマルチキャストのグループアドレスに考え方が近いので注意が必要である.

送受信にアドレスがどう使われるかについては,設定項目中の送信方法によって異なる.

  • 送信方法がトランスペアレント送信モードの場合

送信側は,送信フレームに設定項目で設定されたアドレスを付与する.
受信側は,設定項目で設定されたアドレスと送信フレーム中のアドレスが同じ場合のみフレームを受信する.ただし,送信フレームのアドレスが FFFF だった場合,設定されているアドレスに関わらず受信する.

  • 送信方法が固定送信モードの場合

送信側は,送信フレームにアプリケーションから指定されたアドレスを付与する.
受信側は,トランスペアレント送信モードの場合と同じ動作をする.

チャンネルについて

当然のことながら,送受信側で同じチャネルでないと通信ができない.設定項目で設定されたチャネルにて受信処理が行われる.
送信時にどのチャンネルが使われるかは,送信方式によって異なる.

  • 送信方法がトランスペアレント送信モードの場合,設定項目で設定されたチャネルで送信される.
  • 送信方法が固定送信モードの場合,アプリケーションから設定されたチャネルで送信される.

固定送信モードの場合,受信用に設定されたチャンネルとは独立に,送信時に使用するチャンネルを指定できる.この点は ES920LR と異なる点である.

続きは,また後日.

レビュー「サーバ/インフラエンジニア養成読本 仮想化活用編 第二版」

先月、「サーバ/インフラエンジニア養成読本 仮想化活用編」の改訂版が発売されました。献本頂きましたので、レビューをしたいと思います。

  • 技術説明では、教科書的な説明にとどまらず、一歩踏み込んだ説明をしてくれています。この本は、Software Design 本誌に掲載されていた記事を、再編集してまとめたものなので、違う章で重複した説明があったりします。しかし、一線で活躍している各章の著者がどのように説明しているのか、その違いを比べてみるのも面白いかもしれません。
  • 運用監視やセキュリティなど、実用上重要なポイントも取り扱っています。Hinemos/Zabbix/Nagios の比較記事などは、実際に現場で役立つ知識を得るのに適した記事かと思います。
  • OpenFlow の記事では、Trema でのプラグラミングを取り扱っています。「こんな夜中に」の記事を元にしていますが、Trema 最新版を使用するよう内容が修正されています。これから Trema を始める人の入門として適した内容になっています。

サーバ/インフラエンジニア養成読本には、仮想化活用編以外にも、無印編、管理/監視編がありますが、こちらも改訂版が発売されているようです。興味のある方は、ご覧になってみるとよいでしょう。

rvm を使って trema/trema-edge 共存環境をつくる

今回から OpenFlow 1.3 に対応した trema-edge に挑戦してみます。
streocat さんに先をこされた気もしますが、気にしないこととします。

trema と trema-edge では必要とする ruby のバージョンが異なります。両者を扱える環境では、複数のバージョンの ruby を使い分ける必要があります。今回は、このために rvm を使う方法を紹介します。

ruby パッケージを削除

今回 ruby はすべて rvm 経由で入れることとします。そのため、パッケージを使ってインストール済みの ruby があるとややこしくなるため、ここではこれを削除することとします。

$ sudo apt-get --purge remove ruby rubygems

ただし、この段階でシステム上に ruby が存在しない状態になります。trema 以外にも ruby を使用している場合には、悪影響が及ばないかをご確認の上、削除してください。

rvm のインストール

次に rvm をインストールします。Ubuntu にて apt-get install ruby-rvm すると、問題があるらしいとの記事をちらほら見かけます(例えばここ)。なので、パッケージを使わないでインストールします。

curl -L https://get.rvm.io | bash -s stable --ruby

curl が入っていなければ、apt-get で入れてからインストールしましょう。
インストールが出来たら、別に新しいターミナルを立ちあげて、そこで以下のコマンドを打ってください。

$ rvm list

rvm rubies

=* ruby-2.0.0-p247 [ x86_64 ]

# => - current
# =* - current && default
#  * - default

rvm のインストールと同時に ruby の最新版がインストールされているのがわかります。

rvm 経由で ruby のインストール

trema では 1.8.7-p371 を、trema-edge では 2.0.0-p0 の ruby が必要です (ここや、ここ を参照のこと)。rvm コマンドを使い、それぞれのバージョンの ruby をインストールします。

$ rvm install 2.0.0-p0
...
$ rvm install 1.8.7-p371
...

インストールが完了したら、rvm list で確認してみましょう。