Raspberry PI 起動後 IP アドレスを教えてくれる

Raspberry PI でなにかしたいときに自分のパソコンから SSH して作業することが多いと思います。ですが、Raspberry PI の IPアドレスがわからないので、毎回ディスプレイを接続して確認するとか固定IP設定を行うとか…まぁどちらも面倒ですね。

なので起動したら自動で IP アドレスを Slack に送るようにしよう!ということで Golang でそんなコードを書いてみました。

とりあえず Binary が欲しいあなたに

コードが見たいんじゃねぇ!すぐ使えるものが欲しいという方は続きの記事を読まず下にあるコマンドで Binary を取得してコマンド実行してください。そして最後のセクションへ

$ SLACK_URL=https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxxx
$ curl -L -o raspi-ip-check https://www.dropbox.com/s/tfpi18tcpc2r8si/raspi-ip-check?dl=0; chmod +x raspi-ip-check; mv raspi-ip-check /usr/bin
$ raspi-ip-check

ソースコードが見たい方はこちら

今回は Golang で実装してみました。最初はNode.Js で書いていたのですが、Binary を配布できる形にしたほうがみんな喜ぶかなと思い Golang で書いてみました。ではソースコードを見てみましょう!

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"os"
	"strings"
)

var url = os.Getenv("SLACK_URL")

func slack(message string) error {
	requestBody, err := json.Marshal(map[string]string{"text": message})
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(requestBody)))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	defer resp.Body.Close()

	return err
}

func localAddresses() (string, error) {
	var list []string

	name, err := os.Hostname()
	if err != nil {
		return "", err
	}

	interfaceList, err := net.Interfaces()
	if err != nil {
		return "", err
	}

	list = append(list, name)
	for _, networkInterface := range interfaceList {
		addressList, err := networkInterface.Addrs()
		if err != nil {
			continue
		}

		for _, netInterfaceAddress := range addressList {
			networkIp, ok := netInterfaceAddress.(*net.IPNet)
			if ok && !networkIp.IP.IsLoopback() && networkIp.IP.To4() != nil {
				ip := networkIp.IP.String()

				list = append(list, networkInterface.Name+": "+ip)
			}
		}
	}

	return strings.Join(list, "\n"), nil
}

func main() {
	if len(url) == 0 {
		fmt.Println("環境変数 SLACK_URL を設定してください")
		os.Exit(1)
		return
	}

	for i := 0; i < 30; i += 1 {
		addresses, err := localAddresses()
		if err != nil {
			continue
		}

		if err := slack(addresses); err == nil {
			break
		}

		time.Sleep(time.Second)
	}
}

特に難しい部分もないですね。

ローカルの IP アドレス取得部分を調べるのに少し時間がかかりましたが、それぐらいですね。main 関数で for で 30 回回しているのは Raspberry PI の起動時にネットワークが確立する前にこのプログラムが動作しても30秒もあればなんとかなるだろうという適当な理由です。

起動時にプログラムを起動するように

/etc/rc.local ファイルを編集するのみです

$ sudo vi /etc/rc.local

$ sudo vi /etc/rc.local

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

export SLACK_URL=https://hooks.slack.com/services/*****
raspi-ip-check

exit 0

このファイルの最後に exit 0 と書かれているのでその前に追記するだけです