遠隔メール

IPアドレスの通知でRaspberry PiからGMailへメールを送信するのは既に試したが、受信はまだだったのでPythonで簡単なスクリプトを組んで試してみた。
送信は非常に単純に行えたのだが、受信はメールの構造やエンコードの仕組みについて知らないと正しく処理できないので、ちょっとばかり面倒。エンコードをとりあえず考えなければ、どうにか十数行でGMailから受信テキストを取得する所まではできた。

せっかくなのでそれを使って、メールでRaspberry Piに接続されたI2Cデバイスに対し、汎用的に出力を行えるような仕組みも考えてみた。やっている事は単純で、メールの本文に記載されたコマンドに従い、I2Cデバイスに対して順次出力を行うだけ。

I2Cデバイスのアドレスやコマンド、コマンド送信間のディレイもメールで指定できるので、どんなデバイスが接続されていても汎用的に使えるはずだ。プログラムは以下の通り。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import imaplib
import email
import smbus
import time

login_user = 'xxxxxxxx@gmail.com'
login_pass = 'xxxxxxxx'
remote_subject = '[RaspRemote]'
i2c = smbus.SMBus(1)
interval = 5

def cmd_i2c(param):
    try:
        addr = int(param[1].strip(), 0)
        rw = param[2].strip().upper()
        cmd  = int(param[3].strip(), 0)
        if rw[0] == 'W':
            val = int(param[4].strip(), 0)
            i2c.write_byte_data(addr, cmd, val)
        elif rw[0] == 'P':
            put = param[4].strip()
            [i2c.write_byte_data(addr, cmd, ord(c)) for c in put]
        elif rw[0] == 'R':
            pass
        elif rw[0] == 'G':
            pass
    except ValueError:
        pass

def cmd_wait(param):
    try:
        val = float(param[1].strip())
        time.sleep(val)
    except ValueError:
        pass

def cmd_gpio(param):
    pass

def execute(lines):
    for line in lines:
        param = line.split(',')
        print param
        cmd = param[0].strip()
        if cmd[0] != '$':
            continue
        if cmd == '$I2C':
            cmd_i2c(param)
        elif cmd == '$WAIT':
            cmd_wait(param)
        elif cmd == '$GPIO':
            cmd_gpio(param)

def check():
    mail = imaplib.IMAP4_SSL('imap.gmail.com', 993)
    mail.login(login_user, login_pass)
    mail.list()
    mail.select('inbox')
    # New Mail?
    stat, mlist = mail.search(None, '(UNSEEN)')
    if mlist[0] is not '':
        for num in mlist[0].split():
            res, data = mail.fetch(num, '(RFC822)')
            msg = email.message_from_string(data[0][1])
            # Get Subject
            subject = email.Header.decode_header(msg.get('Subject'))
            text, charset = subject[0]
            if text[0:len(remote_subject)] == remote_subject:
                # Get Body
                for part in msg.walk():
                    if part.get_content_type() == 'text/plain':
                        lines = part.get_payload().splitlines()
                        execute(lines)
                        break
    mail.logout()

if __name__ == '__main__':
    try:
        while True:
            check()
            time.sleep(interval)
    except KeyboardInterrupt:
        print '\nbreak'

使用できるコマンドは今のところI2Cデバイスに対する1バイトの出力と複数バイトの連続出力、それとディレイだけだが、GPIOへの出力やデバイスから取得したデータをメールで送り返すような拡張も容易だろう。

このプログラムをRaspberry Piのターミナルから起動すると、5秒おきにメールサーバへ未読チェックを行い、特定のサブジェクト([RaspRemote])が付いたメールが届いていたらそれを受信して本文を解釈実行する。テストデバイスとして今回もストロベリーリナックスI2C液晶を使用した。

送信するメールの内容は、以下のような感じになる

// I2C液晶初期化
$I2C,0x3e,W,0,0×38
$I2C,0x3e,W,0,0×39
$I2C,0x3e,W,0,0×14
$I2C,0x3e,W,0,0x7A
$I2C,0x3e,W,0,0x7F
$I2C,0x3e,W,0,0×56
$I2C,0x3e,W,0,0x5E
$I2C,0x3e,W,0,0x6C
$WAIT,0.2
// クリア
$I2C,0x3e,W,0,0×38
$I2C,0x3e,W,0,0x0C
$I2C,0x3e,W,0,0×01
$I2C,0x3e,W,0,0×06
$WAIT,0.2
// 出力
$I2C,0x3e,W,0,0×38
$I2C,0x3e,W,0,0×80
$I2C,0x3e,W,0,0×38
$I2C,0x3e,P,0x40,MailRemote Ready

先頭が’$’以外の行は読み飛ばすので、何を書いてもかまわない。送信するときは表題の先頭に’[RaspRemote]’と書いておく。

remotemail01

プログラムが正しく動いていれば、I2C液晶にメールで指定した文字列が表示されるはず。

もちろん接続されるデバイスが決まっているなら、わざわざこんな面倒なことをしなくても専用のプログラムを書けば済む話なので、実用的にはあまり意味のないプログラムかも知れないが、メールを受信したときにRaspberry Piに何かさせたいという時には応用できるだろう。

広告