GPIO ピンからとれる電源は普通に電源回路直結なので、Raspberry Pi 自体が起動していようがしていまいが、電源ケーブルさえ接続されていれば供給されています。まぁこれはいいんですが、Raspberry Pi 本体が起動していないとき、もっというとそれらを扱うデーモンが起動していないときに電源供給されてもエコじゃないので、なんとかしました。

回路図

ちょっと余計な線がありますが、キモは FET だけです。伸びてる GND と VCC を周辺回路に繋ぐと、GPIO 25 (22pinから出てる) の論理によってオン・オフします。

手元では 2SK2796L を使ってます (3.3V で直接駆動できるので)

コード側

単に GPIO 25 ピンのハイ・ローを切り替えるだけです。Ruby の場合以下のように

#!/usr/bin/env ruby
# coding: utf-8
 
module GPIO
	def self.export(pin)
		File.open("/sys/class/gpio/export", "w") do |f|
			f.write(pin)
		end
	end
 
	def self.unexport(pin)
		File.open("/sys/class/gpio/unexport", "w") do |f|
			f.write(pin)
		end
	end
 
	def self.direction(pin, direction)
		[:in, :out].include?(direction) or raise "direction must be :in or :out"
		File.open("/sys/class/gpio/gpio#{pin}/direction", "w") do |f|
			f.write(direction)
		end
	end
 
	def self.read(pin)
		File.open("/sys/class/gpio/gpio#{pin}/value", "r") do |f|
			f.read.to_i
		end
	end
 
	def self.write(pin, val)
		File.open("/sys/class/gpio/gpio#{pin}/value", "w") do |f|
			f.write(val ? "1" : "0")
		end
	end
end
 
GPIO.export(25)
GPIO.direction(25, :out)
GPIO.write(25, true)
at_exit do
    GPIO.write(25, false)
end
sleep 3 # 周辺機器が安定するまで適当な時間

...

at_exit でローにするようにしてるだけです。

備考

回路図だとわかりにくい感じだけど、これは GND 側のスイッチ (ローサイドスイッチ) で、VCC は繋がりっぱなしなので、Raspberry Pi 以外の他の電源を回路に接続するとよくないかもしれないです。

ぜんぜんよくわからないんですが、こういう回路はハイサイドにしたほうが安全なのかな。応答速度はあまり必要ではないし……

  1. トップ
  2. raspberrypi
  3. Raspberry Pi のローレベル周辺機器の電源を特定プロセスが動いているときだけオンにする
  1. トップ
  2. tech
  3. Raspberry Pi のローレベル周辺機器の電源を特定プロセスが動いているときだけオンにする

AngularJS には ngResource という拡張があって、サーバに対する API 経由の CRUD 的操作を JavaScript のオブジェクトとしてラッピングできる。具体的には例えば

var Entry = $resource('/entry/:id');
var entry = Entry.get({ id : 0 }, function () {
    entry.title = "yuno";
    entry.$save(); // XHR (async)
});

とかできる。ちょっとかっこいいけど、既存APIで使おうとすると、些細なフォーマットの違いで案の定使えなかったりする。どうしても使ってみたいけど、サーバサイドAPIの仕様まで変えたくない場合、若干無理矢理な方法である程度なら対応させることができる。

サーバサイドの仕様

前提として以下のような仕様だとする

エントリリスト取得

GET /api/entries

# Response
{
  "ok" : true,
  "has_more" : true,
  "entries" : [ ... ]
}

データの新規作成

POST /api/entries
Content-Type: application/x-www-form-urlencoded

title=xxx&body=yyy

# Response
{
  "ok": true
  "entry" : { ... }
}

データの編集

PUT /api/entries?id=0
Content-Type: application/x-www-form-urlencoded

title=xxx&body=yyy

# Response
{
  "ok": true
  "entry" : { ... }
}

ngResource での対応

いくつかハマりポイントがある

  • AngularJS は POST 時のデフォルト Content-Type が application/json
  • ngResource は直接配列のJSONが返ってくることを前提にしている
    • そして付属するデータをうまく返す方法がない

いろいろやってみると以下のようになった。

var Entry = $resource('/api/entries', { id : '@id' }, {
	'query':  {
		method:'GET',
		isArray: true,
		transformResponse : function (data, headers) {
			data = angular.fromJson(data);
			if (!data.ok) throw "API failed";
			Entry.hasMore = data.has_more;
			return data.entries;
		}
	},
	'save':  {
		method:'POST',
		transformResponse : function (data, headers) {
			data = angular.fromJson(data);
			if (!data.ok) throw "API failed";
			return data.entry;
		},
		transformRequest: function (data, headers) {
			var ret = '';
			for (var key in data) if (data.hasOwnProperty(key)) {
				var val = data[key];
				ret += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(val);
			}
			return ret;
		},
		headers : {
			'Content-Type' : 'application/x-www-form-urlencoded'
		}
	},

	'update' : {
		method: 'PUT',
		transformResponse : function (data, headers) {
			data = angular.fromJson(data);
			if (!data.ok) throw "API failed";
			return data.entry;
		},
		transformRequest: function (data, headers) {
			var ret = '';
			for (var key in data) if (data.hasOwnProperty(key)) {
				var val = data[key];
				ret += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(val);
			}
			return ret;
		},
		headers : {
			'Content-Type' : 'application/x-www-form-urlencoded'
		}
	}
});
  • 自力で transformResponse, transformRequest で ngResource が要求しているフォーマットに変更してやる
  • リストに付随するデータはスタティックに持たせてしまう (リクエスト直後に読み出すことを想定)
  • 自力で application/x-www-form-urlencoded なリクエストを作ってやる
  • 冗長に書いてるけど PUT と POST はメソッドが違うだけ

これを使う場合、

var entries = Entry.query(function () {
    $scope.hasMore = Entry.hasMore;
});

...

var entry = entries[0];

entry.title = "FooBar";
entry.$update();

みたいになる。だいぶアホっぽいし、この部分のコードがカオスになるけど、一応使えるようにはなる。

もっといい方法があったら教えてください……

  1. トップ
  2. angularjs
  3. AngularJS の ngResource を既存APIの仕様にあわせる
  1. トップ
  2. tech
  3. AngularJS の ngResource を既存APIの仕様にあわせる