あんパン

こしあん派

久々にRaspberry Piセットアップして躓いたところメモ

ちまたに情報は満ち溢れているのでいまさらだけど自分用にまとめておく。ちなみに前回Raspberry Piを触ったのは一昨年でRaspberry Pi Zero WHで勤怠ツールを作ったとき。その前は多分5年くらい前で、 Raspberry Pi 2 Model Bで勤怠ツールを作ったとき。

OSのインストール

以前はRaspbianとかArchとか選んで直接書き込んだりファイルをSDカード上に置く形式だったけれど、いまは基本的にRaspberry Pi OSがオススメということになっている。Raspberry Pi OSは Raspbianの名前が変わったやつという認識。SDカードへの焼き込みは専用のRaspberry Pi ImagerというGUIツールがあるので、これを選ぶ。

Arch Linuxの場合はAURにあるので yay --Sy rpi-imager でインストールできる。microSDカードを適当なSDカードリーダーに挿してUSBポートに接続すれば、mountなどはせずにrpi-imagerが認識してくれる。実行する際は管理者権限がないとSDカードに書き込めずエラーになるので、 sudo rpi-imager で起動する必要がある。

f:id:masawada:20210117101322p:plain
Raspberry Pi Imager

Raspberry Pi OSには以下のバージョンがある。

  • Raspberry Pi OS with desktop and recommended software
  • Raspberry Pi OS with desktop
  • Raspberry Pi OS Lite

だいたい書いてあるとおりで、Liteはデスクトップ環境がない。Raspberry Pi Imagerはデフォルトではwith desktopを推してくるけど、デスクトップが不要であればLiteを選択する。with desktop and recommended softwareの方はFull版として表示される。

画面を表示する

通常のRaspberry PiシリーズはHDMIケーブルが利用できる。Raspberry Pi Zeroシリーズはmini HDMIケーブルが必要になる。直接画面に繋いでも良いが、 どうせすぐにSSH経由でしか利用しなくなるので、激安HDMIキャプチャを噛ませて一瞬だけ見るのでも良い。だいたい入力から1秒くらいギャップがある。常用しないしわざわざ画面の裏に手を入れるのが面倒な人向けと言える。激安HDMIキャプチャはAliExpressやAmazonなどで買える。

こういうやつ。だいたい1000円くらいで買えて便利。ただ、表記上のスペックを満たしていないケースが多いのでその点は注意。詳しくはMS2109で検索すると良さそう。

f:id:masawada:20210117102638p:plain
OBSで画面出力をキャプチャする

事前にSDカードにWiFiのcredentialとSSHを起動するフラグを立てるファイルを置いておくだけで画面を見ずに接続する方法もあるけど、なんだかんだ画面を見ながらデバッグしたいということはあるのでこういうことができると良い。

キーボードを繋ぐ

通常のRaspberry PiであればUSB Type-Aが刺さるので特に問題はないがRaspberry Pi Zeroの場合はMicro USBポートしかないので、Micro USB(オス)からUSB Type-A(メス)に変換するUSB OTGケーブル/アダプタが必要になる。

こういうやつ。

piユーザのパスワードを変更しておく

sudo raspi-config から変更できる。普通に passwd コマンドでもOK。

キーボードのレイアウトを変更する

デフォルトだとUK配列になってるぽい? のでUS配列にする。 sudo raspi-config から変更できる。何気にHappy Hacking Keyboardのレイアウトが登録されていた。そのまま登録を進めていくとEnglishだけどUK配列になってしまうので、ここでUS配列にする。

IPを固定してネットワークに繋ぐ

/etc/wpa_supplicant/wpa_supplicant.conf に無線LANのcredentialを置く。無線LANのパスワードは事前に暗号化しておく。sudo su && wpa_passphrase ESSID passphrase >> /etc/wpa_supplicant/wpa_supplicant.conf しておいて、後で整形する。Raspberry Pi Zero Wは2.4GHz帯の規格にしか対応していないので5GHz帯のESSIDで繋ぎにいかないこと。最初忘れてて15分くらい潰した。

$ sudo vi /etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP

network={
        ssid="ESSID"
        psk=***
}

みたいな形にしておく。次に、IPを固定するためにdhcpcd.confを編集する。最後の以下の4行を追加する。IPとかは環境による。

$ sudo vi /etc/dhcpcd.conf
...
interface wlan0
static ip_address=192.168.0.2/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1

SSHする

あとはいつもどおり。

  • sudo systemctl enable ssh.service && sudo systemctl start ssh.service
  • ssh-copy-id で接続元の端末のpubkeyを転送しておく
  • sudo vi /etc/ssh/sshd_configして以下の箇所を変更
    • PubkeyAuthentication yes にする
    • PasswordAuthentication no にする
  • sudo systemctl restart ssh.service

だいたいこれでまともにつかえるはず。

X270環境構築時のつまずきメモ

画面がチラつく

lspci -vv すると Intel Corporation HD Graphics 620kernel driveri915 ということが分かる。i915ではPanel Self Refreshにより画面がチラつくことがある。/etc/default/grub を編集して GRUB_CMDLINE_LINUX_DEFAULT の値の末尾に i915.enable_psr=0 を追加すればチラつかなくなる。

参考: https://wiki.archlinux.org/index.php/intel_graphics#Screen_flickering

無線LANが繋がらない

wifi-menu で設定しても CONNECTING FAILED と出てしまう。 これは単純に netctl-auto が有効になっていないからだった。ip a で対象のNICを特定して

$ sudo systemctl enable netctl-auto@wlp3s0.service
$ reboot

すれば wifi-menu で繋げられるようになる

バックライトの照度を変更できない

light コマンドがうまく動かない。 light -v3 -A 10 とかするとエラーメッセージが出てくるのでそれを確認する。みたところPermission Deniedのようだった。ユーザがvideoグループに入っていれば良いとのことなので

$ sudo usermod -aG video $USER

で解決。

参考: https://github.com/haikarainen/light#debianubuntu ここの Note に書いてあった。

引数に取ったPerlのコードを実行して結果を表示しつつクリップボードに投入するシェルスクリプト

#!/bin/bash

EXPR="$@"; perl -e "print $EXPR" | tee >(xsel -ib); echo;

これを p という名前でPATHの通った場所に置いています。使い方は

$ p '1+2'
3
$ xsel -ob
3

みたいな感じ。xsel -ib はLinuxにおける標準入力をクリップボードに投入するコマンド、xsel -ob はクリップボードからstdoutに出力するコマンド。macOSであればそれぞれ pbcopy pbpaste に相当します。

普段は上記のように便利計算機として使うことが多いですが、Perlのコードを評価できるのでもうすこし面白い使い方ができそうな気もします。

$ p 'join ", ", (1, 2, 3)'
1, 2, 3

みたいなことができたりとか。まあ、いまのところ良い使い道は思い付かないですが。

蔵書管理を支える技術

これは Spreadsheets/Excel Advent Calendar 2020 4日目の記事です。
昨日は id:yunico_jp さんの スプレッドシートを使った超単純な進捗管理、過去最高に捗る説 - Yunicode でした。

こんにちは、 id:masawada です。突然ですが、みなさんが所属されている組織ではどのように蔵書を管理していますか?

組織において書籍や検証機など何らかの物品を貸し出すケースはごく日常的なものだと思います。貸し出す物品の数や人数が少なければホワイトボードなどに書いて管理することもできそうですが、膨大になってくるとそれでは立ち行かないこともあるでしょう。わざわざ物理的なカンバンを見に行かずにどこにどの物品があるのかを検索したいというニーズもありそうです。

この記事では、このような問題を解決するために自分が作った蔵書管理用のスプレッドシートをご紹介します。実際に自分が所属している会社ではこのスプレッドシートを利用して蔵書を管理しています。

https://docs.google.com/spreadsheets/d/1XshcYZmNPpKHAJjFEY-KdFJkYzjwj3lHtreRqfEvxXk/edit?usp=sharing

ファイル > コピーを作成 から自分のGoogle Driveにコピーを作成してご利用ください。

スプレッドシートは

  • 貸出記録
  • 蔵書一覧
  • 所蔵場所
  • 蔵書分類

の4つに分かれています。具体的にどこでどのようなテクニックを使っているのかを交えながら紹介します。

貸出記録

貸出記録シートには、以下のような機能があります

  • 書籍IDを記入すると書名を自動でフィルインする
  • 貸出日を記入すると返却日(貸出日の2週間後)を自動でフィルインする

f:id:masawada:20201204001639p:plain

書籍IDは、蔵書一覧シート(後述)において書籍ひとつひとつに対して割り振るIDです。蔵書一覧シートのA列が蔵書IDになっています。例えば貸出記録のC2セルは

=IF(ISBLANK(B2),,VLOOKUP(B2, '蔵書一覧'!$A$2:B, 2))

のようになっており、 B2(B列の同じ行)に何か値があったら、蔵書一覧の$A$2:Bの範囲からB2の値に合致するものを探し出してきて、その行の2番目のセルを表示 しています。

この例ではB2は 1 なので、蔵書一覧の $A$2:B から 1 に合致するものを探してきてその行の2番目のセルを表示します。

f:id:masawada:20201204002623p:plain

蔵書一覧の $A$2:B はこの範囲なので、書籍IDが1にマッチする 転生したらスプレッドシートだった件 が表示されます。


返却日のフィルインは

=IF(ISBLANK(E2),,E2+14)

のようになっており、貸出日(ここではE2)が入力されていたら E2+14 を返すとしています。日付の値が入っている場合は、単純に +14 とするだけで2週間後の値を計算できます。

蔵書一覧

蔵書一覧シートには、以下のような機能があります

  • 貸出中かどうかを判定する機能
  • 所蔵場所の選択肢を所蔵場所シートから引っ張ってくる機能
  • 分類の選択肢を蔵書分類シートから引っ張ってくる機能

f:id:masawada:20201204003708p:plain

貸出中かどうかを判定する機能は、以下のように実現しています。

=IF(ISBLANK(B2), , IF(COUNTBLANK(QUERY('貸出記録'!$A$2:G, "select G where B = " & A2, -1)) > 0, "貸出中", "貸出可能"))

なかなか複雑ですね。分解してみましょう。まず一番外の IF は、蔵書名がなかった場合は何も表示しないための条件分岐です。この外側のIFがないと以下のようになります。

f:id:masawada:20201204003844p:plain

書籍がなければ貸し出し可能もなにもないのでこのIF文でガードしています。

次に COUNTBLANK(QUERY('貸出記録'!$A$2:G, "select G where B = " & A2, -1)) > 0 の部分を見てみましょう。まず QUERY で貸出記録シートの $A$2:G の範囲から "select G where B = " & A2 しています。& は単なる文字列結合で、A2はここでは 1 なので select G where B = 1 と等価です。貸出記録シートにおいてG列は返却日、B列は書籍IDなので、 書籍IDが1の行の返却日 を検索しています。これを包んでいるのが COUNTBLANK で、これは文字通り空セルを数えるものです。QUERYで引いた返却日リストに空セルがある場合、つまり貸出記録で書籍IDが埋まっているが返却日が記入されていない場合はそのセルの数を計算できます。これが1以上であれば貸出中という寸法です。

最後にIFで 貸出中 を表示するか 貸出可能 を表示するかを判定しています。


所蔵場所や分類の選択肢をそれぞれのシートから引っ張ってくる機能は、 データの入力規則 から設定できます。条件として リストを範囲で指定 して、シート名!範囲 を指定すれば良いだけです。例えば、所蔵場所シートのA2以降を指定したいときは 所蔵場所!A2:A1000 のような値を指定します。所蔵場所が1000を超えることはないので、適当に1000としています。

その他の機能

Google App Scriptを利用すると、返却日を過ぎていた場合にSlackに通知することもできます。以下のようなスクリプトを ツール > スクリプトエディタ から起動するエディタに貼り付けてSlackのwebhookのURLなどを設定しておき、時間をトリガーに doPost 関数を実行することで、返却日当日や返却日を過ぎていた場合にSlackで通知することができます。…多分動きます(未検証だけどだいたい同じものを運用しています。)

/// <reference path="typings/bundle.d.ts" />
// Configuration
var WEBHOOK_URL = 'SLACK_WEBHOOK_URL';
var SLACK_USERNAME = '蔵書管理';
var SLACK_ICON_EMOJI = ':books:';
var SHEET_NAME = '貸出記録';

// Slackにメッセージを送信する関数
function sendMessage (userId, message) {
  // send message
  var res = UrlFetchApp.fetch(WEBHOOK_URL, {
    method: 'post',
    payload: JSON.stringify({
      username: SLACK_USERNAME,
      icon_emoji: SLACK_ICON_EMOJI,
      link_names: 1,
      text: '@' + userId + ': ' + message,
    }),
  });
};

// 返却日を確認する本丸
function doPost () {
  // 貸出シートからsheetのインスタンスを得て行数を取得しておく
  var sheet = SHEET_NAME ? SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME) : SpreadsheetApp.getActiveSheet();
  var maxRows = sheet.getMaxRows();

  // 貸出シートを1行ずつ舐めていく
  for (var r = 2; r <= maxRows; r++) {
    var row = sheet.getRange(r, 1, r, 7);

    var bookName   = row.getCell(1, 3).getValue();
    var userId     = row.getCell(1, 4).getValue();
    var startDate  = row.getCell(1, 5).getValue();
    var endDate    = row.getCell(1, 6).getValue();
    var returnDate = row.getCell(1, 7).getValue();

    if (startDate === '') {
      break;
    }

    // 返却日をミリ秒で取得する
    var d = new Date(endDate).getTime();

    // 今日の00:00:00の値をミリ秒で取得する
    // `- 32400000` してるのは時差のためだったはず…(不明)
    var n = (function(d){return d - d % 86400000 - 32400000;})(new Date().getTime());

    if (d === n && returnDate === '') {
      sendMessage(userId, '本日が書籍 "' + bookName + '"の返却日です。');
    } else if (d < n && returnDate === '') {
      sendMessage(userId, '書籍 "' + bookName + '"の返却日を過ぎています。お早めにお返しください。');
    }
  }
};

トリガーは Edit > Current project's triggers のあたりで設定できます。これを押すと以下のような画面に遷移して設定できるようになります。

f:id:masawada:20201204010150p:plain

借りていたことを忘れるのはよくあることなので、実際に返却日にお知らせがあると便利です。

f:id:masawada:20201204011330p:plain

まとめ

蔵書管理システムでも、簡単なものであればスプレッドシートで実現できますよというご紹介でした。欠点としては、あまりにも貸出記録の行数が増えるとVLOOKUPが大量に走って重くなることでしょうか。一定期間ごとにrotateしてあげるのが良いと思います。

このシートを作ってみて、スプレッドシートは意外と表現力が柔軟で、かつ複雑な管理UIを作らなくても利用できて便利だなと感じました。あまりに複雑なものを作ってしまうとメンテナンス性が損なわれるのでユースケースにもよりそうですが、もっと活用していきたいですね。

別ブランチの特定のファイルを直接開くコマンド

欲しいときがありますよね。

masawada.hatenablog.jp

方法は4年前に書いてたんですが、最近欲しくなってちまちま打つのがだるくなってきたのでgitのサブコマンドにしました。Vimを使っているので直接Vimに流し込んでいます。pecoが2回起動するので、ブランチ名とファイル名を指定すると開けます。git-afとして保存して、git afコマンドとして使っています。afはアトラクタフィールドの略です。

doautocmd BufRead $(basename $FILE_PATH) がキモで、シンタックスハイライトを正しく指定しつつ開いてくれます。

dotfiles/git-af at master · masawada/dotfiles · GitHub

どうぞご利用ください。