Wi-Fiを検知しよう

Ruby

こんにちは、kazutoです。今回は、Wi-Fiの接続を検知をして、接続を確認ができたら、自分宛てにメールを送信していきます。また、使用するメールの種類は、webメールであるgmailを使用していきます。

事前準備

まずは事前準備をしていきましょう。

  • ファイルを作成しよう
  • gemをインストールをしよう
  • 環境変数の準備をしよう

ファイルを作成しよう

まずは必要なファイルを作成していきましょう。

touch wify_detect.rb             

ファイルを作成ができたら次のステップに進みましょう。

gemをインストールをしよう

次にgmailでメールを送るのに必要な「ruby gmail」というgemをインストールをしましょう。

gem install ruby-gmail

次にGemがインストールできたか確認をするためにsearchコマンドを実行しましょう。

gem search -r ruby-gmail
laco-ruby-gmail (0.2.0)
pauldix-ruby-gmail (0.2.0)
purp-ruby-gmail (0.2.2)
ruby-gmail (0.3.1)
ruby-gmail-nritholtz (0.3.4)

上記の様にruby-gmailと色々、表示されていれば、無事、インストールができた事になりますので、次のステップに進みましょう。

環境変数にスマホのmacアドレスを格納しよう

次に環境変数にご自身のスマホのエントリ情報を格納をしていきます。今回は、arpコマンドというIPアドレスとMACアドレスの対応を確認や設定ができるコマンドを用います。

まずは、スマホをWi-Fiに接続をした状態で、arpコマンドを実行してみてください。

arp -a 
takeuchnoiphone (IPアドレス) at maxアドレス on en0 ifscope [ethernet]

-aコマンドでarpキャッシュを調べ、エントリを表示しています。つまり、Wi-Fiへの接続状況を確認をしています。ご自身のスマホ情報を探し出し、macアドレスをコピペして、メモ帳などに貼り付けておいてください。macアドレスとは、ネットワーク機器やネットワークアダプターに付いている固有の識別番号の事を指します。

今回は、 rubyファイル内でarpコマンドを実行をして、リアルタイムのエントリ状況を取得、出力結果を変数arp_statusに格納をします。その後、スマホのmacアドレスを環境変数から取得をして、出力結果(arp_status)にスマホのmacアドレスが含まれていたら、自分宛てに「Wi-Fiが接続しました」という件名のメールを送信します。

※-aオプション
arpキャッシュを調べ、エントリを表示。IPアドレスを指定した時には
そのIPアドレスとMACアドレスの対照表を表示する。
IPアドレスを指定しなければ、全てのarpエントリを表示

次に先ほど取得した、macアドレスを.zshrcファイルの環境変数に格納をしていきましょう。

vim ~/.zshrc
export IPHONE_MAC_ADDRESS=macアドレス

環境変数IPHONE_MAC_ADDRESSが定義できたら、:wqコマンドを入力をしてファイルを保存をしましょう。(環境変数名はご自身の端末名(スマホ))

source ~/.zshrc
echo $IPHONE_MAC_ADDRESS
...
macアドレス

sourceコマンドを実行をして、zshrcファイルを読み込み、更新をします。その後、echoコマンドを実行して、環境変数IPHONE_MAC_ADDRESSの中身を出力をして、macアドレスが設定されているか、確認をしましょう。

macアドレスが確認ができたら次のステップに進みましょう。

Wi-Fiを検知をしよう[実装編]

次にWi-Fiを検知をする機能を実装をしていきます。

  • gmailで送信をしよう
  • Wi-Fiを検知するメソッドを実装
  • WifiDetectクラスを実装
  • 実際にWi-Fiを接続をして検知ができるか確認をしてみよう
require"/Users/kazuto/projects/environment/wther/line_notify.rb"
require"/Users/kazuto/projects/environment/wther/config.rb"
require "gmail"
require "date"
require "mail"

class WifiDetect
  def self.search
    first_time = Time.now.to_i
    while true
      elsped_time =  Time.now.to_i - first_time
      case
        when elsped_time <= 300
          return send_gmail(
            "ログインするgmailアドレス",
            "パスワード",
            "送信先のmailアドレス",
            "Wi-Fiへの接続を検知しました!!",
            "お帰りなさいkazutoさん") if self.detect?()
        when elsped_time <= 600
         return send_gmail(
          "ログインするgmailアドレス",
          "パスワード",
          "送信先のmailアドレス",
          "Wi-Fiへの接続を検知しました!!",
          "予定時刻から#{elsped_time/60}分経過しました。\nお帰りなさいkazutoさん") if self.detect?()
        when elsped_time <= 1800
           return send_gmail(
            "ログインするgmailアドレス",
            "パスワード",
            "送信先のmailアドレス",
            "Wi-Fiへの接続を検知しました!!",
            "予定時刻から#{elsped_time/60}分経過しました。\n何かありましたか?\nkazutoさん") if self.detect?()
        when elsped_time > 1800
          return  self.detect?()?
            send_gmail(
             "ログインするgmailアドレス",
             "パスワード",
             "送信先のmailアドレス",
             "Wi-Fiへの接続を検知しました!!",
             "予定時刻から#{elsped_time/60}分経過しました。\n時間を守ってください!!")
            :
            send_gmail(
             "ログインするgmailアドレス",
             "パスワード",
             "送信先のmailアドレス",
             "Wi-Fiへの接続が確認できません",
             "予定時刻から#{elsped_time/60}分経過しました。
             \nWi-Fiへの接続が確認ができません。何かトラブルに巻き込まれましたか?")
       end
    end
 end

  def self.detect?()
    arp_status = %x(arp -a)
      detect=arp_status.include?(ENV['IPHONE_MAC_ADDRESS'])? true : false
      %x(say "お帰りなさい、kazutoさん") if detect
      detect
  end
end

def send_gmail(user_name,password,destinationm,title,msg)
  gmail=Gmail.new(user_name,password)
  mail = gmail.generate_message do
    to destinationm
    subject title
    body msg
  end
  gmail.deliver(mail)
end
WifiDetect.search()

gmailで送信をしよう

まずは、gmailで送信ができる様にsend_gmailメソッドを作成をしていきます。まあ、実装すると言っても、gemを用いるので簡単です。

公式ドキュメント
 https://github.com/dcparker/ruby-gmail

def send_gmail(user_name,password,destinationm,title,msg)
  gmail=Gmail.new(user_name,password)
  mail = gmail.generate_message do
    to destinationm
     subject title
    body msg
  end
  gmail.deliver(mail)
end

それでは、解説をしていきます。

 gmail=Gmail.new(user_name,password)

まずは、Gmailクラスのインスタンスを生成をして、ログインをします。なお、引数には、左から順に、gmailアドレス、パスワードを渡しています。

 mail = gmail.generate_message do
    to destinationm
    subject title
    body msg
  end

次にgenerate_messageメソッドを用いて、メールを作成をします。

  • to(宛先)
  • subject(件名)
  • body(本文)

を設定をしています。

generate_messageメソッドの返り値、つまり、メール情報を変数mailに格納をしています。

 gmail.deliver(mail)

次に変数mail(メール情報)をdeliverメソッドの引数に渡して 、メールを送信をします。

この一連の流れを行う事により、メールを送信する事ができます。

以上で、「gmailを送信をしよう」の解説を終了します。

WifiDetectクラスを実装

次にWi-Fiの接続を検知するWifiDetectクラスを実装をしていきます。

require"/Users/kazuto/projects/environment/wther/line_notify.rb"
require"/Users/kazuto/projects/environment/wther/config.rb"
require "gmail"
require "date"
require "mail"

class WifiDetect
  def self.search
    first_time = Time.now.to_i
    while true
      elsped_time =  Time.now.to_i - first_time
      case
        when elsped_time <= 300
          return send_gmail(
            "ログインするgmailアドレス",
            "パスワード",
            "送信先のmailアドレス",
            "Wi-Fiへの接続を検知しました!!",
            "お帰りなさいkazutoさん") if self.detect?()
        when elsped_time <= 600
         return send_gmail(
          "ログインするgmailアドレス",
          "パスワード",
          "送信先のmailアドレス",
          "Wi-Fiへの接続を検知しました!!",
          "予定時刻から#{elsped_time/60}分経過しました。\nお帰りなさいkazutoさん") if self.detect?()
        when elsped_time <= 1800
           return send_gmail(
            "ログインするgmailアドレス",
            "パスワード",
            "送信先のmailアドレス",
            "Wi-Fiへの接続を検知しました!!",
            "予定時刻から#{elsped_time/60}分経過しました。\n何かありましたか?\nkazutoさん") if self.detect?()
        when elsped_time > 1800
          return  self.detect?()?
            send_gmail(
             "ログインするgmailアドレス",
             "パスワード",
             "送信先のmailアドレス",
             "Wi-Fiへの接続を検知しました!!",
             "予定時刻から#{elsped_time/60}分経過しました。\n時間を守ってください!!")
            :
            send_gmail(
             "ログインするgmailアドレス",
             "パスワード",
             "送信先のmailアドレス",
             "Wi-Fiへの接続が確認できません",
             "予定時刻から#{elsped_time/60}分経過しました。
             \nWi-Fiへの接続が確認ができません。何かトラブルに巻き込まれましたか?")
       end
   end
 end
  def self.detect?()
    arp_status = %x(arp -a)
      detect=arp_status.include?(ENV['IPHONE_MAC_ADDRESS'])? true : false
      %x(say "お帰りなさい、kazutoさん") if detect
      detect
  end
end

def send_gmail(user_name,password,destinationm,title,msg)
  gmail=Gmail.new(user_name,password)
  mail = gmail.generate_message do
    to destinationm
    subject title
    body msg
  end
  gmail.deliver(mail)
end
WifiDetect.search()

それでは、解説をしていきます。

class WifiDetect
  def self.search()
  end
  def self.detect?()
  end
end

今回は、インスタンスを生成をしないので、クラスメソッドでメソッドを定義をして、実装をしていきます。

def self.search
    first_time = Time.now.to_i
    while true
      elsped_time =  Time.now.to_i - first_time
      case
        when elsped_time <= 300
          return send_gmail(
            "ログインするgmailアドレス",
            "パスワード",
            "送信先のmailアドレス",
            "Wi-Fiへの接続を検知しました!!",
            "お帰りなさいkazutoさん") if self.detect?()
        when elsped_time <= 600
         return send_gmail(
          "ログインするgmailアドレス",
          "パスワード",
          "送信先のmailアドレス",
          "Wi-Fiへの接続を検知しました!!",
          "予定時刻から#{elsped_time/60}分経過しました。\nお帰りなさいkazutoさん") if self.detect?()
        when elsped_time <= 1800
           return send_gmail(
            "ログインするgmailアドレス",
            "パスワード",
            "送信先のmailアドレス",
            "Wi-Fiへの接続を検知しました!!",
            "予定時刻から#{elsped_time/60}分経過しました。\n何かありましたか?\nkazutoさん") if self.detect?()
        when elsped_time > 1800
          return  self.detect?()?
            send_gmail(
             "ログインするgmailアドレス",
             "パスワード",
             "送信先のmailアドレス",
             "Wi-Fiへの接続を検知しました!!",
             "予定時刻から#{elsped_time/60}分経過しました。\n時間を守ってください!!")
            :
            send_gmail(
             "ログインするgmailアドレス",
             "パスワード",
             "送信先のmailアドレス",
             "Wi-Fiへの接続が確認できません",
             "予定時刻から#{elsped_time/60}分経過しました。
             \nWi-Fiへの接続が確認ができません。何かトラブルに巻き込まれましたか?")
      end
   end
end

まずは、searchメソッドについて解説をしていきます。

 first_time = Time.now.to_i

現在時間を取得をします。今回は、経過時間ごとに送るメールの内容を変更していきたいので、ループを回す前に現在時間を取得します。

while true
 
end

while文で無限ループを組みます。スマホがWi-Fiに接続をしたらループを抜けます。30分以上、経過してもWi-Fiの接続が確認できない場合は、生存確認メールを送ります。

 elsped_time =  Time.now.to_i - first_time

こちらは、経過時間を求めて、変数elsped_timeに格納をしています。while文のスコープ外でWi-Fi検知の開始時間を取得をして、変数first_timeに格納をしました。なので、1ループごとに現在時間を取得をして、開始時間(first_time)で引いていく事で、経過時間を求める事ができます。

次にcase文の中身をみていきましょう。

case
        when elsped_time <= 300
          return send_gmail(
            "ログインするgmailアドレス",
            "パスワード",
            "送信先のmailアドレス",
            "Wi-Fiへの接続を検知しました!!",
            "お帰りなさいkazutoさん") if self.detect?()
        when elsped_time <= 600
         return send_gmail(
          "ログインするgmailアドレス",
          "パスワード",
          "送信先のmailアドレス",
          "Wi-Fiへの接続を検知しました!!",
          "予定時刻から#{elsped_time/60}分経過しました。\nお帰りなさいkazutoさん") if self.detect?()
        when elsped_time <= 1800
           return send_gmail(
            "ログインするgmailアドレス",
            "パスワード",
            "送信先のmailアドレス",
            "Wi-Fiへの接続を検知しました!!",
            "予定時刻から#{elsped_time/60}分経過しました。\n何かありましたか?\nkazutoさん") if self.detect?()
        when elsped_time > 1800
          return  self.detect?()?
            send_gmail(
             "ログインするgmailアドレス",
             "パスワード",
             "送信先のmailアドレス",
             "Wi-Fiへの接続を検知しました!!",
             "予定時刻から#{elsped_time/60}分経過しました。\n時間を守ってください!!")
            :
            send_gmail(
             "ログインするgmailアドレス",
             "パスワード",
             "送信先のmailアドレス",
             "Wi-Fiへの接続が確認できません",
             "予定時刻から#{elsped_time/60}分経過しました。
              \nWi-Fiへの接続が確認ができません。何かトラブルに巻き込まれましたか?")
         end
   end
           

case文では、経過時間(elsped_time)によって、送信するメール内容を変えるための条件分岐を行っています。

when elsped_time <= 300
          return send_gmail(
            "ログインするgmailアドレス",
            "パスワード",
            "送信先のmailアドレス",
            "Wi-Fiへの接続を検知しました!!",
            "お帰りなさいkazutoさん") if self.detect?()

まず初めに、elsped_timeが300以内の場合と条件分岐をしています。つまり、監視を始めて、5分以内です。こちらの条件が該当する場合は、予定時刻から5分以内なので、ノーマルな「Wi-Fiへの接続を検知しました!!」という件名のメールをsend_gmailメソッドを用いて送ります。

def self.detect?()
    arp_status = %x(arp -a)
    detect = arp_status.include?(ENV['IPHONE_MAC_ADDRESS'])? true : false
    %x(say "お帰りなさい、kazutoさん") if detect
    detect
end
 if self.detect?()

detect?メソッドは、Wi-Fiの接続を検知するメソッドで、返り値は、真偽値を返します。処理内容を確認しておきましょう。

arp_status = %x(arp -a)

%xとする事で、コマンド出力を行う事ができます。

arpコマンドを実行して、arpキャッシュを調べ、エントリ状況をarp_status に格納をしています。

 detect = arp_status.include?(ENV['IPHONE_MAC_ADDRESS'])? true : false

次に変数arp_statusに対して、include?メソッドを用いて、iPhoneのmacアドレスがarpキャッシュに含まれているかを確認しています。含まれていれば、trueを変数detectに格納をします。

%x(say "お帰りなさい、kazutoさん") if detect

detectがtrueな場合、つまり、スマホがWiFiに接続している場合に%記法を用いて、sayコマンドを実行をします。sayコマンドは音声読み上げコマンドです。引数に渡した、文字列を読み上げます。

  detect

最後に変数detectを返り値として返します。

when elsped_time <= 600
         return send_gmail(
          "ログインするgmailアドレス",
          "パスワード",
          "送信先のmailアドレス",
          "Wi-Fiへの接続を検知しました!!",
          "予定時刻から#{elsped_time/60}分経過しました。\nお帰りなさいkazutoさん") if self.detect?()

本題に戻りましょう。経過時間が10分以内であれば、緊急性は無いと思いますので、Wi-Fiの接続が確認できた場合、予定時刻から何分経過をしたのかを本文に付け加えたメールを送信します。

when elsped_time <= 1800
           return send_gmail(
            "ログインするgmailアドレス",
            "パスワード",
            "送信先のmailアドレス",
            "Wi-Fiへの接続を検知しました!!",
            "予定時刻から#{elsped_time/60}分経過しました。\n何かありましたか?\nkazutoさん") if self.detect?()

経過時間が30分以内の場合は、何かトラブルが起きた事を察し、「何かありましたか?」というフレーズを本文に追加します。

 when elsped_time > 1800
          return  self.detect?()?
            send_gmail(
             "ログインするgmailアドレス",
             "パスワード",
             "送信先のmailアドレス",
             "Wi-Fiへの接続を検知しました!!",
             "予定時刻から#{elsped_time/60}分経過しました。\n時間を守ってください!!")
            :
            send_gmail(
             "ログインするgmailアドレス",
             "パスワード",
             "送信先のmailアドレス",
             "Wi-Fiへの接続が確認できません",
             "予定時刻から#{elsped_time/60}分経過しました。
              \nWi-Fiへの接続が確認ができません。何かトラブルに巻き込まれましたか?")
         end

経過時間が30分を過ぎた場合にWi-Fiの接続が確認ができる場合は、「時間を守ってください!!」というフレーズを追加をして、時間に遅れた事を注意をします。30分を過ぎてもWi-Fiの接続が確認ができない場合は、トラブルなどに巻き込まれた可能性があるので、「Wi-Fiへの接続が確認できません」という件名のメールを送信をして、生存確認をします。

以上で、「WifiDetectクラスを実装」の解説を終了します。経過時間ごとに送るメールの内容を変更する事でリアル感が増しますね。

実際にWi-Fiを接続をして検知ができるか確認をしてみよう

最後に一度、スマホのWi-Fiの接続を解除して、Wi-Fiの接続が検知できるか確認しましょう。rubyコマンドを実行しましょう。

ruby wify_detect.rb

上記の画像の通り、自分宛てにメールが送られて来れば、今回の実装は、完了になります。

まとめ:Wi-Fiを検知をしよう

今回は、Wi-Fiの接続を検知する機能を実装しました。この機能は、とても実用性が高いと個人的には思います。例えば、低学年くらいのお子様の門限管理などに相性が良いと思います。午後17:00時にcronコマンドを用いて、ジョブをセットをしてロスがある場合は、お小遣いを減らすなど色々、家庭独自のオプションなどの追加をするのも面白いですね。

以上、kazutoでした。