M5Stack の Proto Module に収まる Real Time Clock を制作する

M5Stack は多機能なマイコンモジュールである。スピーカーとか microSD スロットとかがはじめからついているが、リアルタイムクロック (RTC) がついておらず、時計として使うには 毎回 Wi-Fi 経由で NTP を用いて時刻情報を取得する とか、iPhone などと BLE で接続し Current Time Service を用いて時刻情報を取得する とかのテクニックが必要である。これでは不便なので Proto モジュール 上に DS1302 という IC を使用して RTC を構築した。

ポイントは数点ある。

  1. GPIO のうちどのポートを使うか。
  2. ボタン電池をどうやって Proto モジュールに収めるか。

1つ目については M5 Stack ハマりどころ に詳しい。要は:

  • 使うべきではないポート
    • GPIO 25, Audioと共有
    • GPIO 23, LCDと共有
    • GPIO 19, SDと共有
    • GPIO 18, LCDと共有
    • GPIO 3, TXDと共有
    • GPIO 1, RXDと共有
    • GPIO 0, PULLUP BOOTと共有
  • 注意して使うポート
    • GPIO 34-39, 入力オンリー
    • GPIO 2, [GPIO 0]が0の時、これも0でリセットされるとダウンロードモードになる。
    • GPIO 12, 起動時に1だと LDOが1.8V, 0だと3.3Vになる。
    • GPIO 15 , GPIO 5 標準でPULLUP 起動時に設定すると SDIOスレーブタイミングの設定。

ひとまず今回は SCLK = 13, IO = 5, CE = 17 とすることに決めた。

2つ目についてはコイン電池ホルダーをいくつか試し、タカチ電機工業 表面実装型 コイン電池ホルダー SMTUシリーズ の CR2032 用 ならば入ったのでそれを利用した。 Proto モジュール内部で許容される高さはだいたい 5.5 mm ぐらいっぽい(上のホルダーは 5.4 mm)。

下に配線図と実際の写真を載せる。めちゃめちゃ汚い配線だが許容した。

f:id:KainokiKaede:20200828150239p:plain
M5Stack Proto Module RTC 配線図

f:id:KainokiKaede:20200827230116j:plain
M5Stack Proto Module RTC 写真

いろいろなところからコードをお借りしてガッチャンしてとりあえず動くコードを書いた。

#include <M5Stack.h>
#include <DS1302.h>
// DS1302 用のモジュールを https://github.com/msparks/arduino-ds1302 からダウンロードして使用可能にしておく。

#define incPin 39                   // (+) Inc. button
#define decPin 38                   // (−) Dec. button
#define entPin 37                   // Enter button


// Timer function: https://lang-ship.com/blog/work/esp32-timer/
hw_timer_t * timer = NULL;
void IRAM_ATTR onTimer() {
  // M5 LCD の左上のカーソル位置は (0, 0) で、右下のカーソル位置は (312, 232) である。
  // 1文字の大きさが (6,8) であることと液晶サイズが (320,240) であることとに依拠していると思われる。
  // これをはみ出していたら clear する。
  if (M5.Lcd.getCursorX() >= 320 || M5.Lcd.getCursorY() >= 240) {
    M5.Lcd.clear();
    M5.Lcd.setCursor(0,0);  // https://lang-ship.com/reference/unofficial/M5StickC/Tips/M5Display/
  }
}



// DS1302
// https://github.com/msparks/arduino-ds1302/blob/master/examples/set_clock/set_clock.ino を改変。

namespace {

// Set the appropriate digital I/O pin connections. These are the pin
// assignments for the Arduino as well for as the DS1302 chip. See the DS1302
// datasheet:
//
//   http://datasheets.maximintegrated.com/en/ds/DS1302.pdf
const int kCePin   = 17;  // Chip Enable
const int kIoPin   = 5;  // Input/Output
const int kSclkPin = 13;  // Serial Clock

// Create a DS1302 object.
DS1302 rtc(kCePin, kIoPin, kSclkPin);

String dayAsString(const Time::Day day) {
  switch (day) {
    case Time::kSunday: return "Sunday";
    case Time::kMonday: return "Monday";
    case Time::kTuesday: return "Tuesday";
    case Time::kWednesday: return "Wednesday";
    case Time::kThursday: return "Thursday";
    case Time::kFriday: return "Friday";
    case Time::kSaturday: return "Saturday";
  }
  return "(unknown day)";
}

void printTime() {
  // Get the current time and date from the chip.
  Time t = rtc.time();

  // Name the day of the week.
  const String day = dayAsString(t.day);

  // Format the time and date and insert into the temporary buffer.
  char buf[50];
  snprintf(buf, sizeof(buf), "%s %04d-%02d-%02d %02d:%02d:%02d",
           day.c_str(),
           t.yr, t.mon, t.date,
           t.hr, t.min, t.sec);

  // Print the formatted string to serial so we can see the time.
  M5.Lcd.println(buf);
}

}  // namespace



//曜日を求める。 https://edu.clipper.co.jp/pg-2-47.html
// 0 = 日曜日
int subZeller( int y, int m, int d )
{
    if( m < 3 ) {
        y--; m += 12;
    }
    return ( y + y/4 - y/100 + y/400 + ( 13*m + 8 )/5 + d )%7;
}

Time::Day subZellerForDS1302Library( int y, int m, int d)
{
    switch (subZeller(y, m, d)) {
      case 0:
        return Time::kSunday;
      case 1:
        return Time::kMonday;
      case 2:
        return Time::kTuesday;
      case 3:
        return Time::kWednesday;
      case 4:
        return Time::kThursday;
      case 5:
        return Time::kFriday;
      case 6:
        return Time::kSaturday;
    }
}



// 時計の設定。 http://radiopench.blog96.fc2.com/blog-entry-923.html を改変。

char buff[10];                     // 文字列操作バッファ
String yymmdd = "yyyy/mm/dd";      // 年月日文字列
String hhmmss = "hh:mm/ss";        // 時分秒文字列
int yy, mo, dd, hh, mi, ss;        // 時刻の要素

void getDateTime(){                // RTCに値を読む、日時の文字列を作成する
  int x;
  yymmdd = "";
  hhmmss = "";
  Time t = rtc.time();

  x =  t.yr%100;           // 年
  yy = x;
  sprintf(buff, "20%02d", x);      // 20に続いて右詰め2桁、1桁なら先頭にゼロ
  yymmdd += buff;

  x = t.mon;            // 月
  mo = x;
  sprintf(buff, "/%02d", x);       // / に続けて右詰め2桁
  yymmdd += buff;
  x = t.date;            // 日
  dd = x;
  sprintf(buff, "/%02d", x);       // / に続けて右詰め2桁
  yymmdd += buff;                  // 年月日の文字列完成(ex:2019/02/28)

  x =  t.hr;           // 時
  hh = x;
  sprintf(buff, "%02d", x);        // 右詰め2桁
  hhmmss += buff;
  x = t.min;            // 分
  mi = x;
  sprintf(buff, ":%02d", x);       // : に続けて右詰め2桁、
  hhmmss += buff;
  x = t.sec;            // 秒
  sprintf(buff, ":%02d", x);       // :に続けて右詰め2桁
  hhmmss += buff;                  // 時分秒の文字列完成(ex:01:02:03)
}

void oledDisp2Chr(int x, int y, int val) {  // OLEDの指定場所に2桁の値を表示
  sprintf(buff, "%02d", val);               // データーを10進2桁0フィル文字列に変換
  M5.Lcd.setCursor(x, y);                     // カーソルを指定位置に合わせて
  M5.Lcd.print(buff);                         // 数値を書き込み
}

int oledRW(int x, int y, int d, int stepD, int minD, int maxD) { // OLEから値を入力
  // OLEDの指定位置に2桁右詰めで変数の値を表示。ボタン操作で値を増減し、
  // Ent入力で値を確定し戻り値として返す。表示位置の左上をx, y 座標で指定
  // 操作位置は下線で表示。値は上下限の範囲でサーキュレート。文字サイズは2倍角(12x16画素)
  // 引数:x座標、y座標、変更したい変数、変更ステップ量、下限値、上限値

  oledDisp2Chr(x, y, d);                    // 画面の指定位置に数値を2桁表示(下線付き)
  while (digitalRead(entPin) == LOW) {      // enterボタンが押されていたら離されるまで待つ
  }
  delay(30);
  while (digitalRead(entPin) == HIGH) {     // enterボタンが押されるまで以下を実行

    if (digitalRead(incPin) == 0) {         // + ボタンが押されていたら
      d = d + stepD;                        // x を指定ステップ増加
      if (d > maxD) {                       // 上限超えたら下限へサキュレート
        d = minD;
      }
      oledDisp2Chr(x, y, d);                // 画面の指定位置に数値を2桁表示(下線付き)
      while (digitalRead(incPin) == 0) {    // + ボタンが離されるまで待つ
      }
      delay(30);
    }

    if (digitalRead(decPin) == 0) {         // - ボタンが押されていたら
      d = d - stepD;                        // x を指定ステップ減らす
      if (d < minD) {                       // 下限以下なら上限へサーキュレート
        d = maxD;
      }
      oledDisp2Chr(x, y, d);                // 画面の指定位置に数値を2桁表示(下線付き)
      while (digitalRead(decPin) == 0) {    // - ボタンが離されるまで待つ
      }
      delay(30);
    }
  }
  delay(30);
  return d;                                 // 戻り値
}

void clockAdjust() {                        // OLEDとボタンスイッチで時刻を合わせる
  M5.Lcd.println("Clock adj.");               // 時刻合わせ開始表示

  while (digitalRead(entPin) == LOW) {      // entボタンが離されるまで待つ
  }
  getDateTime();                            // 現在時刻を取得

  M5.Lcd.clear();                           // 画面を消して
  M5.Lcd.setCursor(0, 0);
  M5.Lcd.println(yymmdd);                     // 現在の年月日を表示

  hhmmss[6] = '-';                          // 秒の桁に--を表示
  hhmmss[7] = '-';
  M5.Lcd.setCursor(13, 16);                   //  (表示位置要調整)
  M5.Lcd.println(hhmmss);                     // 時刻表示

  // x, y座標, 値, ステップ, 下限, 上限を指定して時計の設定値を入力
  yy = oledRW(12,  0, yy, 1, 0, 40);        // 年の値を入力
  mo = oledRW(30,  0, mo, 1, 1, 12);        // 月の入力
  dd = oledRW(48,  0, dd, 1, 1, 31);        // 日の入力。存在しない日(ex:2/31)も入力可能だが動作は不定
  hh = oledRW(13, 16, hh, 1, 0, 23);        // 時 (表示位置要調整)
  mi = oledRW(31, 16, mi, 1, 0, 59);        // 分 (表示位置要調整)

  // Initialize a new chip by turning off write protection and clearing the
  // clock halt flag. These methods needn't always be called. See the DS1302
  // datasheet for details.
  rtc.writeProtect(false);
  rtc.halt(false);

  // Make a new time object to set the date and time.
  // Sunday, September 22, 2013 at 01:38:50.
  Time t(2000+yy, int(mo), int(dd), int(hh), int(mi), 0, subZellerForDS1302Library(2000+yy, mo, dd));

  // Set the time and date on the chip.
  rtc.time(t);
}







void setup() {
  // put your setup code here, to run once:
  M5.begin();

  // Mute Speaker Noise: https://asukiaaa.blogspot.com/2020/03/m5stack-disable-speaker.html
  M5.Speaker.begin();
  M5.Speaker.mute();

  // Set ESP32 Timer: https://lang-ship.com/blog/work/esp32-timer/
  timer = timerBegin(0, 80, true);
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmWrite(timer, 1000000, true);  // us
  timerAlarmEnable(timer);



  if (digitalRead(entPin) == LOW){ // 起動時にEnt.ボタンが押されていたら
    clockAdjust();                 // OLED画面と押しボタンを使って時刻合わせ。
  }
  
}

void loop() {
  // put your main code here, to run repeatedly:
  printTime();
  delay(1000);
}

ふつうに起動するとずっと現在時刻を表示しつづける。ボタンC(一番右のボタン)を押しながら電源を入れると時計設定モードに入ることができる。

Misc

Proto モジュール、GND を引き出すことが想定されてないとしか思えない配置でつらい。

はじめは PCF8523 という IC を使用しようと思ったが、この IC の i2c address 0x68 と M5Stack Gray に標準搭載されている MPU9250 の i2c address 0x68 がぶつかってしまい使用不可であった。

ちなみに M5Stick-C ならば RTC がビルトインされているようだ。M5Stack にも載せてくれればよかったのに。

2021-08-16 追記

M5Stack 用 RTC モジュール基盤が Switch Science で販売されている。IC は PCF8563 で、I2C アドレスは 0x51 のようであり MPU9250 とのアドレス衝突もなさそう。

MacVim で日本語入力中に Shift+Space が効かない問題を修正する

問題

  • 私は日本語入力中でも Shift+Spaceで常に半角スペースを入力できるようにしている。
  • この機能はほぼすべてのアプリケーションで問題なく利用可能だが、唯一 MacVim のみで利用不可能であった。MacVim は私のメインエディタなので非常に困っていた。
  • MacVim-Kaoriya ではこの問題が修正されているが、更新が途絶えており可能であれば最新版の MacVim を使用したい。
  • macOS 標準の日本語入力ではなく Google 日本語入力に変更すればこの問題は解決するとする記事もあるが、私の環境では Google 日本語入力でも Shift+Space で半角スペース入力不可であった。

既存の報告

既存の報告もいくつかある。

MacVim-Kaoriya には下のパッチが取り込まれている。このパッチを取り込む形で最新版の MacVim をビルドすればよいと考えた。

commit 6b36374325cbcfe58172edfe95b6bbeff42b3bae
Author: Masayuki Yamaya <yamaya@cyberdom.co.jp>
Date:   Wed Oct 22 23:59:30 2014 +0900

    Fix dont input space with shift on yosemite

diff --git a/src/MacVim/MMTextViewHelper.m b/src/MacVim/MMTextViewHelper.m
index fdc7aaf..3da0c29 100644
--- a/src/MacVim/MMTextViewHelper.m
+++ b/src/MacVim/MMTextViewHelper.m
@@ -187,6 +187,11 @@ KeyboardInputSourcesEqual(TISInputSourceRef a, TISInputSourceRef b)
         // with Ctrl-6 or Ctrl-^ when IM is active.
         [self doKeyDown:@"\x1e"];
         string = nil;
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10)
+    } else if ((flags & NSShiftKeyMask) && [string isEqualToString:@" "]) {
+        // HACK! for Yosemite - Fix for Shift+Space inputing
+        // do nothing
+#endif
     } else {
         // HACK!  interpretKeyEvents: may call insertText: or
         // doCommandBySelector:, or it may swallow the key (most likely the

挿入ファイルと位置: https://github.com/macvim-dev/macvim/blob/35dc1a84c170d9945cd4cda69cafe60999f86824/src/MacVim/MMTextViewHelper.m#L176

ビルド

./configure

ビルドオプションは MacVim の Release 版をビルドしていると思われる Travis CI で指定されているものを利用した。 https://travis-ci.com/github/macvim-dev/macvim/jobs/372444524/config

$ ./configure LANGOPT="--enable-perlinterp=dynamic --enable-pythoninterp=dynamic --enable-python3interp=dynamic --enable-rubyinterp=dynamic --enable-luainterp=dynamic --with-lua-prefix=/usr/local" HAS_GETTEXT=1

2022-12-28 追記: ビルドは GitHub CI に移行したようだ。MacVim GitHub CI における MacVim Release 174 のビルド方法ワークフロー)を参考にビルドオプションを見直した。

configure 前に brew install lua などで lua などをインストールしておく。--enable-pythoninterp=dynamic はうまくいかなかったので除外した。arm64 の設定は ld: symbol(s) not found for architecture arm64 のエラーが出たため除外した。

$ ./configure --with-features=huge --enable-netbeans --with-tlib=ncurses --enable-cscope --enable-gui=macvim --enable-perlinterp=dynamic --enable-python3interp=dynamic --enable-rubyinterp=dynamic --enable-luainterp=dynamic --with-lua-prefix=/usr/local --with-macarchs=x86_64 --enable-fail-if-missing

make

Anaconda を使っている場合は make 前に conda deactivate しておく。 また Xcode をアップデートしてある場合は xcode-select --install しておく。

$ make -C src Vim
$ make

make 中にいくつかのエラーに遭遇したので対処した。

msgfmt: "ISO-8859-1" から "UTF-8" に変換できません. msgfmt は iconv() に依存しています.このバージョンは iconv() なしで作られています.

which gettext したところ Anaconda でインストールしたものが参照されていた。Deactivate して再度 make した。

$ conda deactivate

試行錯誤中に brew install gettext もしたが、おそらく conda deactivate だけでOKで、brew install gettext は不要だったと考える(∵ 公式のビルド説明書に Xcode Tools 以外には依存していないと書かれているので)。

tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance

Command Line Tools を使用可能にしていなかったために起きたと思われる。 下のURLを参考に使用可能とした。 https://qiita.com/eytyet/items/59c5bad1c167d5addc68

Xcode を起動→Preferences→Locations→Command Line Tools のリストボックスから Xcode 10.x(現在のバージョンと同一の名称)を選択した。

ちなみにXcodeをアップデートした際は毎回 $ xcode-select --install すべきとのこと。

結果

Shift+Space で半角入力ができる MacVim をビルドすることができた。

2014年頃から存在する問題のようで、Pull Request を送ってもよさそうだが……。

追記

MacVim r179 をインストールしてみたらこの問題が修正されているように見える。しかしどのコミットで修正されたのかは不明。

オフラインの状態で iOS に APN プロファイル設定ファイルを適用する

格安 SIM の使用には APN プロファイルの適用が必要であるものがある。 この設定ファイルはウェブサイトからダウンロード可能となっていることが多いが、たとえば海外に行って海外の SIM を使用したのちに日本に帰ってきた場合、着陸から空港の Wi-Fi が使えるようになるまでの間は日本の SIM が使えないということになる。 特に成田空港ではタキシングに15分程度かかることがあるため、オフラインの状態で APN プロファイルの再設定をすることができるようにしておけば15分早く家族に無事を伝えることができて親孝行である。

ウェブを検索すると、設定ファイルをメールで自分自身に送っておく手法が複数ヒットするが(下に参考URLを掲載する)、メールアプリのキャッシュからいつ消えるかわからないので不安が残る。 https://iwatomo3.blogspot.com/2017/09/iphoneapnsim.html https://www.iphone-kakuyasu-sim.jp/news/no-wifi-iphone-apn/

Pythonista を使えば iOS 内で HTML サーバーを立ち上げることができるので、Safari を開いてそこから設定ファイルをダウンロード可能である。 下のスクリプトと同じディレクトリ内に、事前にダウンロードしておいた設定ファイル(拡張子 .mobileconfig)を配置しておく。実行すると localhost:8080 でディレクトリ内のファイル一覧が見られるので、設定ファイルをタップするといつもの設定適用画面になる。複数の SIM を使い分けている場合は複数の mobileconfig ファイルを置いておけば場合によって使い分けられるだろう。

Spotify API を利用して、ライブラリ内の曲の情報などを保存する

Spotify で曲を保存したりしていても、いつか解約したときにすべて消えてしまうような気がしてつらい。 せめてどんな曲を保存していたかの情報があれば、乗り換え先の音楽サービスで同じものを探すことができるかもしれない。 幸い Spotify は善良なサービスなので、API を公開している。これを利用すれば情報を取得できる。

事前に Spotify for Developers に登録してクライアントIDなどを取得する必要がある。 https://developer.spotify.com/dashboard/login

また、Python から Spotify の情報にアクセスするために、Spotipy というライブラリを利用する。 https://github.com/plamere/spotipy

import sys
import spotipy
import spotipy.util as util

scope = 'user-library-read user-follow-read playlist-read-collaborative playlist-read-private'
username = 'your_username'
token = util.prompt_for_user_token(username, scope, client_id='your_client_id',client_secret='your_client_secret',redirect_uri='http://localhost/')

if not token:
    print("Can't get token for", username)
    sys.exit()

sp = spotipy.Spotify(auth=token)
# Get all saved tracks:

# The result is paginated, so use spotipy.Spotify().next() to retrive all items.
results = sp.current_user_saved_tracks(limit=50)
tracks = results['items']
while results['next']:
    results = sp.next(results)
    tracks.extend(results['items'])

for item in tracks:
    track = item['track']
    print(track['name'] + ' - ' + track['artists'][0]['name'])

# Save: tracks
San Diego - South Park
Once Upon a Time - Toby Fox
Start Menu - Toby Fox
...
Ribcage - Kettel
Bootmens - Kettel
Alacasa (Rolando Simmons Remix) - Kettel
# Get all saved albums:

results = sp.current_user_saved_albums(limit=50)
albums = results['items']
while results['next']:
    results = sp.next(results)
    albums.extend(results['items'])

album_tracks = {}
for album in albums:
    album = album['album']
    print(album['name'] + ' - ' + album['artists'][0]['name'])
    results = sp.album_tracks(album['id'])
    this_album_tracks = results['items']
    while results['next']:
        results = sp.next(results)
        this_album_tracks.extend(results['items'])
    album_tracks[album['id']] = this_album_tracks
    for item in this_album_tracks:
        print(item['name'])

# Save: albums, album_tracks
UNDERTALE Soundtrack - Toby Fox
Once Upon a Time
Start Menu
...
Ribcage
Bootmens
Alacasa (Rolando Simmons Remix)
# Get all followed artists:

results = sp.current_user_followed_artists(limit=50)['artists']
artists = results['items']
while results['next']:
    results = sp.next(results)
    artists.extend(results['items'])

for item in artists:
    artist = item
    print(artist['name'])

# Save: artists
Kettel
Domotic
Casey Abrams
...
Aphex Twin
Juana Molina
I Am Robot And Proud
# Get all playlists:

results = sp.current_user_playlists(limit=50)
playlists = results['items']
while results['next']:
    results = sp.next(results)
    playlists.extend(results['items'])

playlist_tracks = {}
for playlist in playlists:
    print(playlist['name'])
    results = sp.user_playlist_tracks(user=sp.me()['id'], playlist_id=playlist['id'])  # playlist の中身を表示
    this_playlist_tracks = results['items']
    while results['next']:
        results = sp.next(results)
        this_playlist_tracks.extend(results['items'])
    playlist_tracks[playlist['id']] = this_playlist_tracks
    for item in this_playlist_tracks:
        print(item['track']['name'])

# Save: playlists, playlist_tracks
Jazz Favorite
Del Sasser
IDM
...
Words (feat. Bri Tolani) [kr1sh Remix]
Angery
Without Your Love (feat. Ralph Larenzo)
data = {'tracks': tracks, 'albums': albums, 'album_tracks': album_tracks, 'artists': artists, 'playlists': playlists, 'playlist_tracks': playlist_tracks}

import pickle
with open('spotify_data.pickle', mode='wb') as f:
    pickle.dump(data, f)

家事の自動化に必要な投資額とオススメ機種紹介

最近 Twitter で「食洗機買え」「ルンバ買え」の声をよく目にする。たしかにこれらの自動化家電は家事の負担を軽減させ、QoL の向上に寄与する。しかしそれらの声に対して「でもお高いんでしょう」「いろいろあってどれがいいかわからない」と尋ねる声も目にする。そこで、金額やオススメ機種の情報を探しているかた向けに、実際に食洗機・ルンバ・ドラム型洗濯乾燥機を導入してみた自分がそれぞれのオススメを紹介しようと思う。結論から書くと、すべて購入すると工事費をあわせて約 22 万円弱かかるが、それでも購入して損はない。

ロボット掃除機

ロボット掃除機は、1回の掃除で床を完璧に綺麗にするものではない。むしろ毎日動かして綺麗を維持するためのものである。ゆえに、1回の掃除力は高くなくてよく、金額としては安いものでも十分にその役割を果たしてくれる。

そうは言っても、他社製の安いものより Roomba はやはり安定なので、Roomba の最安品がおすすめである。

Roomba 641(2018-07-24 現在、約32000円)

カーペットを使用しない・床に物を置かないなど、生活をロボット掃除機に適したものに変更する必要はある。

食器洗い乾燥機 追記あり

ビルトインでない家庭用食洗機は Panasonic しか製造していないので、選択肢は少ない。 その少ない選択肢の中で、毎日使用する・昼食は外で取る前提を置けば、1-2人で生活するならばプチ食洗で間に合う。 乾燥機能は必須なので、必ず乾燥機能つきのものを選択する必要がある(洗濯機能のみのものは、洗濯完了後に食洗機の蓋を開ける必要があるが、それは自動化としては不十分である。選択完了後に蓋を開けられるような人は家事を自動化しようとは思い立たないはずである)。特殊な洗浄機能は不要である。以上の条件を満たすのは下の1機種のみである。

NP-TCM4(2018-07-24 現在、約40000円)

食洗機購入に際しての注意点としては工事費が別途かかることが挙げられる。本体以外に分岐水栓パーツ代(約1万円強;蛇口の形式によって異なる)+分岐水栓工事代(約1万円弱;業者によって異なる)が別途必要で、本体と合わせて計6万円程度の出費となる。

また、食器についても、この食洗機に入り、かつ食洗機対応の食器を選んで購入・使用する必要がある。

加えて、調理器具(フライパン等)も、T-fal の取っ手が取れるタイプのうち、食洗機対応で、この食洗機に入るものを使用すれば手洗いの手間が省ける。

2019-03-15 追記

2018年9月、水道工事の不要な食洗機が発売された。SKジャパン の SDW-J5L である。

2019年3月現在の価格が約40000円弱と、NP-TCM4と同等かそれ以下の価格であるのに加え、洗浄水の供給がタンク式なので水道工事が不要であるという大きな利点がある。 この利点によって、入居・退去時の水道工事代を削減することができるのに加え、設置自由度が上がるため一人暮らしの狭い台所でも設置場所を見つけることができる(排水はバケツなどを別途購入してそこへすればよい)。

価格・工事不要・設置自由度の点から、前述の NP-TCM4 よりおすすめできる品である。

ドラム型洗濯乾燥機

各社各機種存在するが、基本的な機能はどれも同じである。要は自動で洗濯から乾燥までやってくれればよいので、最安のもので問題ない。

たとえば、BD-SG100BL などで十分用をなすだろう(2018-07-24 現在、約120000円)

これについても食洗機と同様に、ノーアイロンシャツなど、乾燥後に放置してもシワにならない衣服を選ぶ必要はある。

まとめ

上記3機種で、計22万円弱。ロボット掃除機をより低価格なものに抑えれば20万円以内も夢ではない。それでもなかなか高額だが、これらによって家事の時間的・肉体的・精神的負担が激減する。初任給が出たら買って損はないと考える。

グラフィックボードの交換

最近 PUBG というゲームをやっているのだが、グラフィックを最低設定にしても、室内に入ると重くなる・急に振り向くことができない などの問題が生じていてなかなかドン勝を食べることができていなかった。勝てないのは自分の腕のせいではなくグラボのせいにするという PC ゲーマーの旧習に則り、私もグラボのせいにすることにして2011年ごろに購入したグラボを交換することにした。

まずは AMD のドライバを削除する。コントロールパネル の プログラムの変更・削除 から AMD Catalyst Control Center をアンインストール。 また、AMDドライバを完全に削除するユーティリティ を配布している。通常のアンインストールが失敗したら使用せよと書かれているので、コントロールパネルからのアンインストール終了後に1回実行しておこう。

続いて、完全に PC の電源を落として(裏面の電源スイッチまで切る)からグラフィックボードを差し替える。

電源を入れ、新しいドライバを GeForce のサイト からダウンロードしてくる。インストールの際に、標準でインストールしようとしたら失敗した。カスタムから、クリーンインストールする にチェックを入れてインストールしたら正常にインストールされた。

とてもスムーズに交換することができた。ファンが2枚から1枚になったので静音にもなり、足音がよく聞こえるようになった。 PUBG はグラフィック 中 設定で快適に動くようになった。高 でもわりと快適だがところどころひっかかりを感じる。 ちょっとまえに購入して、これまたグラフィック最低設定で遊んでいた Watch_Dogs 2 も高めのグラフィック設定でプレイできるようになったのでサンフランシスコの霧を味わいに行ってこようと思う。

Raspberry Pi 2 を AirPlay サーバーにする

Sharepoint Sync をインストール

本家 の General Build Instructions を参考に必要なライブラリをインストール。 libsoxr は負荷が高いようなので使用しないことにする。

$ sudo apt-get install build-essential git
$ sudo apt-get install autoconf automake libtool libdaemon-dev libasound2-dev libpopt-dev libconfig-dev
$ sudo apt-get install avahi-daemon libavahi-client-dev
$ sudo apt-get install libssl-dev
$ sudo apt-get install libpolarssl-dev

続いて Sharepoint Sync 本体のインストールに移る。

$ git clone https://github.com/mikebrady/shairport-sync.git
$ cd shairport-sync
$ autoreconf -i -f

systemd が走っているシステムなのか System V なのかを次のコマンドで判断。出力に systemd を含むものがあれば前者。

$ ps aux | grep systemd | grep -v grep

コンパイルオプションを指定して make してユーザーを作って make install する。公式の手順に従っているだけ。

$ ./configure --sysconfdir=/etc --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-systemd
$ make
$ getent group shairport-sync &>/dev/null || sudo groupadd -r shairport-sync >/dev/null
$ getent passwd shairport-sync &> /dev/null || sudo useradd -r -M -g shairport-sync -s /usr/bin/nologin -G audio shairport-sync >/dev/null
$ sudo make install
$ sudo systemctl enable shairport-sync

名前の設定を変更する。

$ sudo vi /etc/shairport-sync.conf

general = {
  name = "AirPi";

}

あとは $ sudo reboot すれば使えるようになるはず。同じネットワークにある iOS 機器 もしくは iTunes から、さきほど設定した名前のデバイスが検出できていることを確認する。

USB オーディオ機器を接続

オーディオの音質を上げるため、USB サウンドデバイスを接続した。手順は ここ を参考にした。デバイスとしては、家にあった UA-4FX を利用した。

まずは何も接続していない状態でサウンドデバイスを確認。

$ cat /proc/asound/modules
0 snd_bcm2835

USB に UA-4FX を接続して、再度確認。

$ cat /proc/asound/modules
0 snd_bcm2835
1 snd_usb_audio

この機器番号 (1) をデフォルトとして使うように alsa のコンフィグを変更し、再起動。

$ sudo vi /usr/share/alsa/alsa.conf
...
defaults.ctl.card 1
defaults.pcm.card 1
...
$ sudo reboot