2012 | 忘れたらググればいい

2012年12月29日土曜日

GR-SAKURA でフルカラーLEDを制御する

GR-SAKURA

ルネサスのArduino互換ボード.半年前に購入したのにほったらかしていた.

がじぇっとるねさすは、マイコンを搭載した小型のガジェット(電子工作ボード)「GRリファレンスボード」と、マイコン用のプログラムを専門知識がなくても容易に作成できるクラウド環境をWebブラウザ上で提供することで、電子工作を身近なものとして楽しんで頂くことを目的にルネサスで発足した新プロジェクトです。

がじぇっとるねさす | ルネサス エレクトロニクス

プログラムをWebブラウザ上で書いて,コンパイルはサーバ上で行うのが特徴. コンパイルしたバイナリはダウンロードして,USBストレージ (として見えている本体) にコピーするだけでOK.

Webブラウザ上でプログラムをエディットし、コンパイルできるクラウド環境を無償でご提供します。クラウド環境で作成したプログラムおよびコンパイルして生成されたオブジェクトは、 ローカルPCに ダウンロードすることができます。

がじぇっとるねさす | ルネサス エレクトロニクス

がじぇっとるねさす | ルネサス エレクトロニクス

フルカラーLEDを制御したい

最近になって,フルカラーLEDのコンサートライトを作ってみたいと思うようになった.

フルカラーLEDコンサートライトを作ってみた - 日々

ほったらかしていたGR-SAKURAで遊ぶのと,LEDの制御を理解するのにはちょうどいいと思ったので, 秋葉原で部品を集めて実装してみた. (ただ,GR-SAKURAでは機能が豊富すぎるし,そもそも大きすぎて全然筒におさまらないので,いずれマイコンとかに移植しなければならない)

部品

LEDは秋月電子で買った EP204K-35G1R1B1-CA にした.

大型フルカラーLED(35mA)EP204K-35G1R1B1-CA: LED(発光ダイオード) 秋月電子通商 電子部品 ネット通販

回路

なぜか+5Vから5V供給されないようなので,IO7をHIGHにしっぱなしにして5V供給する (が,測ってみると3V前後しか出ていない.よくわからん.とりあえず点灯するのでいいや). 5V供給されたとして,R, G, Bにそれぞれ20mA流れるように適当に抵抗をつなげる. IO0をLOWにすると赤,IO1とLOWにすると青,IO2をLOWにすると緑が点灯する.

プログラムソース

ピンの定義は以下を参考 (公式に情報ないんかな?).

RXduino: GR-SAKURAのピン定義

1秒ごとに赤,黄,ピンク,緑,紫,白が表示されるようにした. 赤,緑はRやGをONにして,他を消せばよいけど,黄色,ピンク,紫はR, G, Bをコントロールしないといけない. analogWriteを使ってPWM制御をする. 黄色は R:100%, G:100%, B:0%, ピンクは R:100%, G:0%, B:14%, 紫は R:61%, G:0%, B:100% とした.

/*
* gr_sketch.ino
*
* Created by FUKUBAYASHI Yuichiro on 2012/12/19
* Copyright (c) 2012, FUKUBAYASHI Yuichiro
*
* last update: <2012/12/23 21:00:36>
*/
#include <rxduino.h>
#define INTERVAL 1000
#define PIN_5V PIN_P33
#define PIN_R PIN_P21
#define PIN_G PIN_P22
#define PIN_B PIN_P20
unsigned int PINS[] = {PIN_R, PIN_G, PIN_B};
void LED_OFF (){
for(int i=0; i<3; i++){
digitalWrite(PINS[i], HIGH);
}
}
void RED_ON(){
digitalWrite(PIN_R, LOW);
digitalWrite(PIN_G, HIGH);
digitalWrite(PIN_B, HIGH);
}
void YELLOW_ON(){
digitalWrite(PIN_R, LOW);
digitalWrite(PIN_G, LOW);
digitalWrite(PIN_B, HIGH);
}
void PINK_ON(){
digitalWrite(PIN_R, LOW);
digitalWrite(PIN_G, HIGH);
analogWrite(PIN_B, (int) 255*(100-14)/100);
}
void GREEN_ON(){
digitalWrite(PIN_R, HIGH);
digitalWrite(PIN_G, LOW);
digitalWrite(PIN_B, HIGH);
}
void PURPLE_ON(){
analogWrite(PIN_R, (int) 255*(100-61)/100);
digitalWrite(PIN_G, HIGH);
digitalWrite(PIN_B, LOW);
}
void WHITE_ON(){
digitalWrite(PIN_R, LOW);
digitalWrite(PIN_G, LOW);
digitalWrite(PIN_B, LOW);
}
void setup()
{
pinMode(PIN_R, OUTPUT);
pinMode(PIN_G, OUTPUT);
pinMode(PIN_B, OUTPUT);
pinMode(PIN_5V, OUTPUT);
digitalWrite(PIN_5V, HIGH);
}
void loop()
{
RED_ON();
delay(INTERVAL);
LED_OFF();
YELLOW_ON();
delay(INTERVAL);
LED_OFF();
PINK_ON();
delay(INTERVAL);
LED_OFF();
GREEN_ON();
delay(INTERVAL);
LED_OFF();
PURPLE_ON();
delay(INTERVAL);
LED_OFF();
WHITE_ON();
delay(INTERVAL);
LED_OFF();
}
view raw gr_sketch.ino hosted with ❤ by GitHub

動作例

黄色

ピンク

白.本当はもうちょっと白いけど,カメラで撮ると赤っぽい. RGBの明るさが完全には同じじゃないからきれいな白にするのは難しいかも.

2012年11月7日水曜日

Time Machine のバックアップ容量を制限する

Time Capsuleの保存領域を確保したい

Time Machineは普通の設定では,バックアップのためのサイズを指定できない. でも,iMac, MBAのバックアップだけでなく, 増大し続ける写真の保存先にもしたいので,バックアップ以外の容量を確保したい.

ちょっと検索してみると,同じように思う人はいっぱいいるようで,簡単に見つかる.

[Mac]Time Machineによるバックアップに容量制限を付ける方法! | こんちくわのぶろぐ

ほとんど同じ内容になるが,自分向けの説明として,手順を記録しておく.

手順

バックアップの作成を指示した後「開始」したら止める

メニューバーから開始を指示する.

開始を指示すると,システム環境設定のTime Machineには「バックアップを準備中」と表示される.

これが「バックアップ作成中」になったら止める.

これが「作成中」になる前に止めると失敗するので注意.

「作成中」に入れば "マシン名.sparsebundle" ができているはずだが, 「準備中」の段階では "マシン名.tmp.sparsebundle" ができている. (ファイルが2つあるのは iMac用とMBA用 の2台分バックアップするつもりのため)

空のディスクイメージを作る

アプリケーション/ユーティリティ内のディスクユーティリティで空のディスクイメージを作る.

ファイル名は,上の手順でTime Machineが作った "マシン名.sparsebundle" とする. また,名前はマウントされた時に表示される名前を適当に設定する. 作ったらすぐ移動させるので,作成先はどこでもいい.とりあえずデスクトップに作った.

  • パーティションはハードディスク
  • イメージフォーマットはスパースバンドル・ディスクイメージ
  • サイズは上記2項目を設定した後に設定する.とりあえず元ディスクの2倍くらいにしておいた.

Time Machineの設定情報だけ抜き出して,作成した空のディスクイメージ内にコピー

最初にTime Machineが作った "マシン名.sparsebundle" 内から com.apple.Timemachine.MachineID.plist を (デスクトップなど適当なところに) コピー.

コピーした com.apple.Timemachine.MachineID.plist を空のディスクの方の "マシン名.sparsebundle" の中にコピー.その後,Info.plistをロック.

空のディスクイメージで元々のディスクイメージを上書き

Time Machineが作成したディスクイメージをデスクトップにある空のディスクイメージで上書き. これでバックアップ用のディスクの容量の上限がさきほど設定したサイズに変わる.

バックアップを再開

止めていたバックアップを再開させる.

止める前に作ったディスクと変わっているので確認が入る. 「このディスクを使用」を選択.

システム環境設定の方ではサイズの変更は分からないが,マウントされたディスクの情報を見ればサイズが設定した値になっていることが分かる.

Time Capsule を既存の無線LANネットワークにぶら下げる

Time Capsuleを買った

バックアップだけじゃなく,写真の保存先としても使おうと思うので,大きめの3TBにした.

アップル - Time Capsule - Macを自動でバックアップする802.11n Wi-Fiベースステーション。

無線LAN基地局としては使わない

すでにAtermで無線LANネットワークを作っているので,Time Capsuleはクライアントとして動けばいい. Wi-Fiベースステーション機能なし版のTime Capsuleって需要ないんかな? 少しは安くなるはずだろうに.

手順

アプリケーション/ユーティリティ内のAirMacユーティリティを起動. 「その他の AirMac ベースステーション (1)」からそれっぽいTime Capsuleを選択する.

このTime Capsuleでネットワークは作成しないので,「その他のオプション」を選択.

「既存のネットワークに追加」を選択.

接続するSSIDを選択.

Time Capsuleの設定をする. ベースステーション名はマシン名(?)にもなるので,英数字にした方がいいかもしれない. また,ここで設定するパスワードは,Time Capsuleに接続するためのパスワードで, 無線ネットワークへ接続するためのパスワードではないっぽい. (この後でも無線ネットワークへ接続するためのパスワードを入力することはなかったので,操作しているMacの設定から自動で設定してる?)

設定完了.

AirMac ユーティリティで確認すると接続されていることが分かる.

2012年10月26日金曜日

radikoの仕様変更で録音ができなくなる問題を修正

radikoの録音に失敗してた

不毛な議論が録音できてなかった.寝ちゃってたからMacの不具合かと思い,放っておいたら今日の99のANNも失敗してる.

radikoでラジオを録音→iTunesに登録→iPodに同期を自動実行 | 忘れたらググればいい

仕様変更があったみたい

twitterで検索してみたら情報が出てた

237 :まちがって名前消しちゃいました。:2012/10/24(水) 16:49:48.22 ID:???
player_2.0.1.00.swf 
↓ 
player_3.0.0.01.swf 

swfextract -b 5 
↓ 
swfextract -b 14 

radiko.smartstream.ne.jp 
↓ 
w-radiko.smartstream.ne.jp 

simul-stream 
↓ 
simul-stream.stream 

_defInst_ 
↓ 
_definst_ 

これでイケた。 

RTMPDump 2

スクリプトを修正

これに従って修正.これで動いた.

get_auth.sh

3c3
< playerurl=http://radiko.jp/player/swf/player_2.0.1.00.swf
---
> playerurl=http://radiko.jp/player/swf/player_3.0.0.01.swf
33c33
<             /opt/local/bin/swfextract -b 5 /dev/stdin -o /dev/stdout | \
---
>             /opt/local/bin/swfextract -b 14 /dev/stdin -o /dev/stdout | \

radiko.ksh

91c91
<     rtmpe://radiko.smartstream.ne.jp/${ID}/_defInst_/simul-stream \
---
>     rtmpe://w-radiko.smartstream.ne.jp/${ID}/_definst_/simul-stream.stream \

せっかくだからgistに置く.

#!/bin/sh
playerurl=http://radiko.jp/player/swf/player_3.0.0.01.swf
#
# access auth1_fms
#
auth1_fms=`/usr/local/bin/wget -q \
--header="pragma: no-cache" \
--header="X-Radiko-App: pc_1" \
--header="X-Radiko-App-Version: 2.0.1" \
--header="X-Radiko-User: test-stream" \
--header="X-Radiko-Device: pc" \
--post-data='\r\n' \
--no-check-certificate \
--save-headers \
https://radiko.jp/v2/api/auth1_fms \
-O -`
if [ $? -ne 0 -o ! "${auth1_fms}" ]; then
echo "failed auth1 process" 1>&2
exit 1
fi
# get keydata
# get partial key
#
authtoken=`echo ${auth1_fms} | perl -ne 'print $1 if(/x-radiko-authtoken: ([\w-]+)/i)'`
offset=`echo ${auth1_fms} | perl -ne 'print $1 if(/x-radiko-keyoffset: (\d+)/i)'`
length=`echo ${auth1_fms} | perl -ne 'print $1 if(/x-radiko-keylength: (\d+)/i)'`
partialkey=`/usr/local/bin/wget -q -O - ${playerurl} 2>/dev/null | \
/opt/local/bin/swfextract -b 14 /dev/stdin -o /dev/stdout | \
dd bs=1 skip=${offset} count=${length} 2> /dev/null | \
/opt/local/bin/base64`
if [ $? -ne 0 -o ! "${partialkey}" ]; then
echo "failed auth1 process" 1>&2
exit 1
fi
#
# access auth2_fms
#
auth2_fms=`/usr/local/bin/wget -q \
--header="pragma: no-cache" \
--header="X-Radiko-App: pc_1" \
--header="X-Radiko-App-Version: 2.0.1" \
--header="X-Radiko-User: test-stream" \
--header="X-Radiko-Device: pc" \
--header="X-Radiko-Authtoken: ${authtoken}" \
--header="X-Radiko-Partialkey: ${partialkey}" \
--post-data='\r\n' \
--no-check-certificate \
https://radiko.jp/v2/api/auth2_fms \
-O -`
if [ $? -ne 0 -o ! "${auth2_fms}" ]; then
echo "failed auth2 process" 1>&2
exit 1
fi
### echo "authentication success" 1>&2
areaid=`echo ${auth2_fms} | perl -ne 'print $1 if(/^([^,]+),/i)'`
### echo "areaid: ${areaid}" 1>&2
echo "${playerurl}" "${authtoken}"
view raw get_auth.sh hosted with ❤ by GitHub
#!/bin/ksh
#-----------------------------------------------------------------
# $1:ID (必須)
# TBS TBSラジオ
# QRR 文化放送
# LFR ニッポン放送
# NSB ラジオNIKKEI
# INT INTERFM
# FMT TOKYO FM
# BAYFM78 BayFm
# NACK5 NACK5
# JORF ラジオ日本
# YFM FM yokohama
# ---------------------
# ABC ABCラジオ
# MBS MBSラジオ
# OBC ラジオ大阪
# CCL FM COCOLO
# 802 FM802
# FMO FM大阪
#
# $2:OFILE (必須)
# 任意のファイル名(UTF-8可)
# $3:TIME (必須)
# 録音時間(分)
#
# -t "VALUE" (省略可)
# タイトル
# -a "VALUE" (省略可)
# アーティスト
# -A "VALUE" (省略可)
# アルバム
# -g "VALUE" (省略可)
# ジャンル
#-----------------------------------------------------------------
export LANG="ja_JP.UTF-8" LC_ALL="ja_JP.UTF-8"
USAGE=\
"Usage:$0 ID OFILE TIME [-t \"TITLE\"] [-a \"ARTIST\"] [-A \"ALBUM\"] [-g \"GENRE\"]"
if [ $# -lt 3 ];then
print "${USAGE}\n`head -n36 $0 | grep -v ksh | sed 's/^#//g' `" 1>&2
exit 1
fi
ID="$1"
OFILE="$2"
TIME=$3
#------------------------------------------#
GetAuth_SRC="${HOME}/bin/get_auth.sh"
#------------------------------------------#
TOUT=1800 # sec
DELAY=20 # sec
RDIR=/tmp
CODEC=libmp3lame
####CODEC=libfaac
((TIME=TIME*60+DELAY))
BITRATE=65536
DATE1=$(date +%Y-%m-%d_%H.%M.%S)
DATE2=$(echo ${DATE1} | cut -c1-10)
YEAR=$(echo ${DATE1} | cut -c1-4)
shift 3
while getopts a:g:t:A: opt
do
case ${opt} in
t) TITLE="${OPTARG}";;
a) AUTHOR="${OPTARG}";;
g) GENRE="${OPTARG}";;
A) ALBUM="${OPTARG}";;
*) echo ${USAGE} 1>&2
exit 1;;
esac
done
if [ "${CODEC}" = "libmp3lame" ];then
RFILE="${RDIR}/${ID}_${OFILE}_${DATE1}.mp3"
else
RFILE="${RDIR}/${ID}_${OFILE}_${DATE1}.m4a"
fi
### authentication
RAuth=`${GetAuth_SRC}`
set -- ${RAuth}
playerurl=$1
authtoken=$2
/usr/local/bin/rtmpdump -B ${TIME} -m ${TOUT} -qvr \
rtmpe://w-radiko.smartstream.ne.jp/${ID}/_definst_/simul-stream.stream \
-W ${playerurl} -C S:"" -C S:"" -C S:"" -C S:${authtoken} \
-o - 2>/dev/null | \
/opt/local/bin/ffmpeg \
-metadata author="${AUTHOR}" \
-metadata artist="${AUTHOR}" \
-metadata title="${TITLE}" \
-metadata album="${ALBUM}" \
-metadata genre="${GENRE}" \
-metadata year="${YEAR}" \
-y -i - -vn -acodec ${CODEC} -ar 44100 -ab ${BITRATE} -ac 2 "${RFILE}" > /dev/null 2>&1
iTunes_DIR=`find "${HOME}" -name "iTunes に自動的に追加" -type d | grep -vi trash`
if [ "${iTunes_DIR}" ]; then
cp "${RFILE}" "${iTunes_DIR}"
if [ "$?" = "0" ]; then
rm -f "${RFILE}"
fi
fi
view raw radiko.ksh hosted with ❤ by GitHub
#!/bin/sh
ID="LFR"
OFILE="99ann"
TIME="125"
date=`date -v-1d +%Y年%m月%d日`
TITLE="${date} ナインティナインのオールナイトニッポン"
ARTIST="ニッポン放送"
ALBUM="ナインティナインのオールナイトニッポン"
GENRE="ラジオ"
~/bin/radiko.ksh ${ID} ${OFILE} ${TIME} -t "${TITLE}" -a "${ARTIST}" -A "${ALBUM}" -g "${GENRE}"
open ~/bin/sync_ipod.app/
view raw rec_99ann.sh hosted with ❤ by GitHub

2012年10月20日土曜日

Google App Engine 向け OAuth ライブラリ (ouath.py) を修正

oauth.pyのエラー

Google App EngineでOAuthを使うためのoauth.pyをtwitter botやアプリケーションで使っていたが, 何日か前からアカウント認証に失敗していたようだ.

mikeknapp/AppEngine-OAuth-Library · GitHub

エラーメッセージ

ERROR    2012-10-20 06:06:29,647 _webapp25.py:464] 'id'
Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/_webapp25.py", line 710, in __call__
    handler.get(*groups)
  File "/path/to/src/main.py", line 108, in get
    user_info = client.get_user_info(auth_token,auth_verifier=auth_verifier)
  File "/path/to/src/oauth.py", line 233, in get_user_info
    user_info = self._lookup_user_info(result["token"], result["secret"])
  File "/path/to/src/oauth.py", line 360, in _lookup_user_info
    user_info["id"] = data["id"]
KeyError: 'id'

twitterの古いversionのURLが使えなくなったっぽい

エラーが発生した付近のサーバーからのレスポンスを見ると,{"errors":[{"message":"Sorry, that page does not exist","code":34}]} などが返ってきている. 調べてみると,古いURLが使えなくなったようだ.

メールで Twitter、「Sorry, that page does not exist」対策 (API の URL) - Rubyとか Illustratorとか SFとか折紙とか

というわけで,URLをver.1.1を使うように修正.

chage URL of twitter to use API ver.1.1 · 28b8c7c · fukubaya/AppEngine-OAuth-Library · GitHub

はじめてのpull request

せっかくなので,修正してgithubでpull request出してみた.

changed the URL of API to ver.1.1 by fukubaya · Pull Request #8 · mikeknapp/AppEngine-OAuth-Library · GitHub
commit messageでスペルミスしてるけどもう直せない...

2012.10.23追記

作者さんにmergeしてもらった. たいした修正じゃないけど,取り込んでもらえるとうれしい.