この記事は FORK Advent Calendar 2018 25日目の記事です。

こんにちは、棚澤です。
年末が近づいてきた頃、来年9月に東京テレメッセージのポケベルのサービスが終了するというニュースを見ました。
ポケベルのピークだった1996年当時、高校生だった私もポケベルを使っていました。
20年以上経ち、今のスマホとwebサービスを組み合わせれば似たような仕組みは簡単に作れそうだったので、今回はなるべくプログラムを書かないで作ってみようと思います。

ポケベルのおさらい

ポケベルの仕組みはざっくり言うと以下です。

  • 相手のポケベル番号に電話をかける
  • 音声ガイダンスに従って電話のダイヤルキーを押してメッセージを入力する
  • 相手のポケベル端末にメッセージが届く

ポケベルの番号(通称「ベル番」)は1人1つ持っていて、固定電話と同じ市外局番を含んだ電話番号でした。 メッセージを送る時は相手のベル番に電話をかけるため電話が必要なので、財布には常にテレホンカード(通称「テレカ」)が入っていて、公衆電話はいつも行列が出来ていました。 メッセージの入力は通称「ベル打ち」と呼ばれる方法で入力します。ダイヤルキーの2つで日本語1文字を表現します。「11」は「あ」で、「12」は「い」、「13」は「う」、「21」は「か」、「31」は「さ」といった感じです。変換表は以下になります。

当時の女子高校生は、これを打つのがやたら速かったです。両手でブラインドタッチしてました。と言うのも、メッセージを送る時は電話をかけるので、最低10円かかります。これが20円かかるか10円で済むかは当時の高校生には大きな問題でした。

ポケベル風サービスの仕組み

今回はなるべくプログラムを書かずに(というか12/25が終わってしまいそうで焦ってます)作りたいので、以下でいきたいと思います。

  • ベル番に相当するもの、電話の受け付けには Twilio を利用
  • ポケベル端末に相当するものはスマホを利用
  • メッセージは Twilio → Google Cloud Functions → IFTTT → Twitter を経由してスマホのブラウザで表示

Twilio <https://twilio.kddi-web.com/>
Google Cloud Functions <https://cloud.google.com/functions/>
IFTTT <https://ifttt.com/>
Twitter <https://twitter.com/>

ベル番の取得

ベル番は Twilio で取得します。 今回は、電話の自動音声ガイダンス機能が使えれば十分なので、日本の電話番号で問題ないです。 検索すると 050 や 0800 などの番号が出てくるので、気に入ったものを選びます。

Twilio → Google Cloud Functions → IFTTT のデータ連携

Google Cloud Functions で関数を作成します。 今回は、Node.js で作りました。ソースコードは以下になります。

const axios = require('axios')

exports.convertPocketbell = (req, res) => {

  if (req.method === 'GET') {
      guidance(req, res)
  } else if (req.method === 'POST') {
      sendMessage(req, res)
  }

}

function guidance(req, res) {

    res.status(200)
    res.set('Content-Type', 'application/xml')
    res.send('<?xml version="1.0" encoding="UTF-8"?><Response><Gather action="https://xxxxxxxxxxxx.cloudfunctions.net/pocketbell" method="POST" numDigits="130" timeout="120" finishOnKey="#"><Say voice="alice" language="ja-JP">メッセージを入力してください。終了したらシャープを押してください。</Say></Gather></Response>')

}

async function sendMessage(req, res) {

    let message = req.body.Digits

    const pocketbellTable = {
        "11":"ア", "12":"イ", "13":"ウ", "14":"エ", "15":"オ", "16":"A", "17":"B", "18":"C", "19":"D", "10":"E",
        "21":"カ", "22":"キ", "23":"ク", "24":"ケ", "25":"コ", "26":"F", "27":"G", "28":"H", "29":"I", "20":"J",
        "31":"サ", "32":"シ", "33":"ス", "34":"セ", "35":"ソ", "36":"K", "37":"L", "38":"M", "39":"N", "30":"O",
        "41":"タ", "42":"チ", "43":"ツ", "44":"テ", "45":"ト", "46":"P", "47":"Q", "48":"R", "49":"S", "40":"T",
        "51":"ナ", "52":"ニ", "53":"ヌ", "54":"ネ", "55":"ノ", "56":"U", "57":"V", "58":"W", "59":"X", "50":"Y",
        "61":"ハ", "62":"ヒ", "63":"フ", "64":"ヘ", "65":"ホ", "66":"Z", "67":"?", "68":"!", "69":"ー", "60":"/",
        "71":"マ", "72":"ミ", "73":"ム", "74":"メ", "75":"モ", "76":"¥", "77":"&", "78":"⏰", "79":"☎", "70":"☕",
        "81":"ヤ", "82":"(", "83":"ユ", "84":")", "85":"ヨ", "86":"*", "87":"#", "88":" ", "89":"", "80":"",
        "91":"ラ", "92":"リ", "93":"ル", "94":"レ", "95":"ロ", "96":"1", "97":"2", "98":"3", "99":"4", "90":"5",
        "01":"ワ", "02":"ヲ", "03":"ン", "04":"゛", "05":"゜", "06":"6", "07":"7", "08":"8", "09":"9", "00":"0"
    }

    let messageJp = ''
    for (let i=0; i<message.length; i+=2) {
        let str = message.substr(i, 2)
        if (pocketbellTable[str]) {
            messageJp += pocketbellTable[str]
        }
    }

    await axios.post('https://maker.ifttt.com/trigger/pocketbell/with/key/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', {
        value1: messageJp
    })
    .then(response => {
        res.status(200)
        res.set('Content-Type', 'application/xml')
        res.send('<?xml version="1.0" encoding="UTF-8"?><Response><Say voice="alice" language="ja-JP">メッセージを受け付けました。</Say></Response>')
    })
    .catch(error => {
        res.status(200)
        res.set('Content-Type', 'application/xml')
        res.send('<?xml version="1.0" encoding="UTF-8"?><Response><Say voice="alice" language="ja-JP">エラーが発生しました。</Say></Response>')
    })

}

Twilio では、TwiML と呼ばれる XML を記述することにより、自動音声ガイダンスを再生したり、別の電話番号に転送したりなどの制御を行うことができ、TwiML を電話への着信の webhookに設定することができます。

まず、最初に電話番号に着信があった時は、以下の TwiML を返すようにします。

<?xml version="1.0" encoding="UTF-8"?>
  <Response>
    <Gather action="https://xxxxxxxxxxxx.cloudfunctions.net/pocketbell" method="POST" numDigits="130" timeout="120" finishOnKey="#">
      <Say voice="alice" language="ja-JP">メッセージを入力してください。終了したらシャープを押してください。</Say>
    </Gather>
  </Response>

Gather 要素の action 属性は Google Cloud Functions の関数のURLです。 これを設定することで、自動音声が再生され、ダイヤルキーの入力値が action 先に POST されます。

次に、ダイヤルキーの入力値を受け取り、日本語に変換します。

    let message = req.body.Digits

    const pocketbellTable = {
        "11":"ア", "12":"イ", "13":"ウ", "14":"エ", "15":"オ", "16":"A", "17":"B", "18":"C", "19":"D", "10":"E",
        "21":"カ", "22":"キ", "23":"ク", "24":"ケ", "25":"コ", "26":"F", "27":"G", "28":"H", "29":"I", "20":"J",
        "31":"サ", "32":"シ", "33":"ス", "34":"セ", "35":"ソ", "36":"K", "37":"L", "38":"M", "39":"N", "30":"O",
        "41":"タ", "42":"チ", "43":"ツ", "44":"テ", "45":"ト", "46":"P", "47":"Q", "48":"R", "49":"S", "40":"T",
        "51":"ナ", "52":"ニ", "53":"ヌ", "54":"ネ", "55":"ノ", "56":"U", "57":"V", "58":"W", "59":"X", "50":"Y",
        "61":"ハ", "62":"ヒ", "63":"フ", "64":"ヘ", "65":"ホ", "66":"Z", "67":"?", "68":"!", "69":"ー", "60":"/",
        "71":"マ", "72":"ミ", "73":"ム", "74":"メ", "75":"モ", "76":"¥", "77":"&", "78":"⏰", "79":"☎", "70":"☕",
        "81":"ヤ", "82":"(", "83":"ユ", "84":")", "85":"ヨ", "86":"*", "87":"#", "88":" ", "89":"", "80":"",
        "91":"ラ", "92":"リ", "93":"ル", "94":"レ", "95":"ロ", "96":"1", "97":"2", "98":"3", "99":"4", "90":"5",
        "01":"ワ", "02":"ヲ", "03":"ン", "04":"゛", "05":"゜", "06":"6", "07":"7", "08":"8", "09":"9", "00":"0"
    }

    let messageJp = ''
    for (let i=0; i<message.length; i+=2) {
        let str = message.substr(i, 2)
        if (pocketbellTable[str]) {
            messageJp += pocketbellTable[str]
        }
    }

次に、Google Cloud Functions から IFTTT に日本語に変換したデータを送ります。

    await axios.post('https://maker.ifttt.com/trigger/pocketbell/with/key/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', {
        value1: messageJp
    })

最後に、これらの作成した Google Cloud Functions の関数の URL を Twilio の着信時の webhook に設定します。

IFTTT → Twitter のデータ連携

今回は、なるべくプログラムを書かないで作りたかったので、Twitter へは IFTTT を経由してデータを送るようにします。

と設定すると、 https://maker.ifttt.com/trigger/pocketbell/with/key/自分のキー にリクエストが来た時に、tweet してくれるようになります。

Twitter のデータをスマホで表示する

最後にポケベルのインターフェースを作り、メッセージデータを表示させます。 今回は時間がないので紙で作ります。

Twitterをブラウザで表示して、紙を貼ればおしまいです。 12/25ギリギリ間に合いました。

それでは、ちょっと早いですが、良いお年を。