キット販売する際の手順
このたび自作キーボードSatsuma JP SMDを遊舎工房で販売させていただきましたが, いくつもの失敗があったので, 今後レンタルボックスを利用される方が同様の失敗をすることがなければいいと思い, ドキュメントにします。
作業手順書を作る
中途半端な組立品として販売したので,
- ゴム足を貼り忘れた
- ネジ・スペーサーを付け忘れた
- スタビライザーを付け忘れた
- ファームウェアを通電確認用から書き換え忘れた
などの失敗しました。(もしくは作業をしたか不安になりました。)不安を解消するためにあったほうがいいと思います。
通常のキット販売なら内容品のチェックリストですかね。
レンタルボックスを予約したら在庫をつくる
レンタルボックスが利用可能になる頃から急に忙しくなって商品を用意することができなくなることもあるため, レンタルボックス利用期間開始前に一定量の在庫を用意しておきましょう。また, 「実際に組み立て済み品を作ってみると想像以上に動作確認が大変だったのでキット販売に切り替える」なんてこともできます。販売する商品の種類は少ないほうがPOPなどの用意も簡単なのでおすすめです。
利用期間になっても商品を用意できないと場所代だけがかかるし, 舎にも売上比例分の収入が入らなくなるのでできれば避けましょう。
キットに入れるもの
ぼくがキーマップ表を作り忘れたのでこの項目があります。
Satsuma JP SMD ソケット通電未確認版に入れたのは次のものです。
- 組み立て・ファームウェア書き換え手順書
- 本体
- キーマップ表
- ねじ・スペーサーの予備
設計・利用している当人は使い方がわかりますが, 購入者にはわからないので, 組み立て・ファームウェア書き換え手順書とキーマップ表はWebでもいいので用意する必要があります。特に今回はファームウェア書き込み済み品を販売したので特にキーマップ表が必要でした。ファームウェアを自分で書き込んでもらうタイプでC言語を読める人を購入者として想定するならキーマップ表は無くてもいいと思います。
ねじ・スペーサーは小単位での購入が面倒なので予備を入れておきました。
販売形態が複数あるなどの理由でPOPに「別途買う必要のあるもの」を書いてない場合, 値札と同じ側に「別途買う必要のあるもの」の表を付けておきましょう。
POPを作る
台はダイソーやセリアで売っています。手書きの紙を折って置くのはおすすめしません。
最低限商品名・値段・別途買う必要のあるものを書くといいと思います。
しないほうがいいこと
販売しない商品は置かないほうがいいです。今回テンキーも基板はありましたが販売が確定していないため・SatsumaJPキットに含まれるとの誤解を防ぐために撤去しました。
まとめ
この記事を読んで販売を面倒に感じたかもしれませんが, キットに不良があったとしても交換すればいいだけなので気軽にやっていきましょう!!
日本語配列60%分割キーボード Satsuma JP SMD について
名称について
"Satsuma"プロジェクトの"JP"配列の"SMD"部品を使ったキーボードです。 元々はJP/ANSI両対応でスルーホール部品を使ったキーボードを作るつもりだった
Satsumaとは英語で温州みかんのことです。
動機
- 最近まで日本語配列分割キーボードが存在しなかった
- 今はOtaku SplitやNin76があります
- 真ん中にキーを追加していないのはこれが唯一かな
- メディアに「組み立てにははんだづけが必要」と書かれるのが癪だった
特徴
- キーキャップを行を違わずに設置できる
- スタビライザー対応
- ベゼルレス
- トップ・ボトムプレートがアルミ製
- 薄い
- ボトムプレートをM2ナットで固定していて外すのに珍しい工具が必要になるため, 販売時は2mm厚くなるかもしれません
- 3mmのネジを使うことで珍しい工具を必要とすることなくそのままの厚さにしました
- ボトムプレートをM2ナットで固定していて外すのに珍しい工具が必要になるため, 販売時は2mm厚くなるかもしれません
- くっつけるとほぼ一体型60%キーボードとして使える
- スペースキーの位置に0.5Uの間が空きます
- ブートローダーをQMK-DFUにしているため, ModemManagerのせいでファームウェアの書き換えに失敗することがない
LUFA MassStorageBootloader版も作るかもしれないWSLでもDFUの書き込みができるため作りません
販売する際ははんだづけ不要でキースイッチとキーキャップを付けるだけで使えるようにする- キーソケットを付けた後の動作確認が大変なのでソケット未取付での販売が主となります
- テンキーを接続できる
- テンキーは未発売です……
Space+A
を押した状態でパソコンに接続することでファームウェアの書き換えなしに右下のキーを矢印キーに変更できる
不良点
改良するかもしれない
改良予定なし
- QMK Firmwareにプルリクを出していないため, QMK Configurater等に対応しない
- コードが雑なのでしません
PendantのUSB端子が薄くて接触が甘いため, テープで嵩増ししている- 嵩増しはやめました
- 左手の電源LEDがスタビライザーと干渉するため設置できない
- 右手の電源LEDで十分なので次期作からは削除されます。
- スペースキーの部分に0.5Uの間が空く
販売について
遊舎工房レンタルボックスでソケット未取付品1万5千円, 完組品2万円で販売中です!! 限定合計6個です!!
レンタルボックスでの販売は終了しました。在庫についてはお問い合わせください。
遊舎工房での委託販売は検討中です。
次期作について
色に統一感を出すために基板の色が白色になります。
moduloにするかもしれない
添付文書
連絡先
QMKファームウェアでステータスLEDを扱う
{{キーボード名}}.c
の led_set_kb(uint8_t usb_led)
で設定する
usb_led
と(1 << USB_LED_NUM_LOCK)
, (1 << USB_LED_CAPS_LOCK)
, (1 << USB_LED_SCROLL_LOCK)
の論理積を取るとそれぞれのLEDを点灯させるべき状態かどうかを取得できる。あとはそれぞれのキーボードに合わせてLED点灯・消灯のコードを書くだけ。
キーボードを設計しています
またか, という感じですが
わかりやすい説明
- 左手用と右手用が分かれたキーボードです
- 左右間は特殊なオーディオケーブルで繋ぎます
- ノートパソコンのキーボードのうちテンキーとファンクションキーと矢印キー以外のキーが揃っています。
- 文章の入力に使う部分がほとんど揃っています
- 普通のキーボードと同じように行ごとにキーがずれています
- 日本語配列にも英字配列にもできます
- キーキャップセットのキーがうまくはまります
- スイッチを簡単に交換できます
- キーボードからテンキーを生やせます
- 親指の位置にたくさんキーがあります
- 穴に端子を差し込むタイプのパーツを使うのではんだづけが簡単です
コンセプト
「そういえば60%を分割した形でスイッチを簡単に交換ができるキーボードってないよね」という気づきがきっかけです。
自分は panda_split が最も良いと感じているので, 新しいキーボードは布教用・一般の環境の練習用に使いたいです。
仕様
- MX互換スイッチ専用
- 組み立てやすいようにスイッチソケット以外はスルーホール部品
- modulo互換(INT用のTRRSジャックはなし)
- 一般のキーキャップセットで全キーを埋められる
- US/JIS両対応
- くっつけると分割式でないキーボードの形になる
妥協点
- Kailh Low Profileスイッチ非対応
- スイッチの選択肢が少ないからスイッチを交換する需要がないと思った
- 正しいサイズのISOエンターキーのキーキャップがないらしい
- 高さのあるスルーホール部品を使いつつ薄くするため, 左右に大きなベゼルができる
- Enterキー周辺の配列がJISとUSで大きく変わるため, 5ピンスイッチ指定になるかもしれない
- 需要があるならプレートを作り分ける??
- 電源ランプ以外光らない
- くっつけるとスペースキーの部分に0.25uの隙間ができる
設計中に気付いたこと
- トラブルシュートのために電源ランプを付けるべき
現状
左手の配線がひと通り完了した
配線成功した pic.twitter.com/Cbih3AiVbj
— すに (@ysni_pub) 2019年6月2日
右手の配線は次のキーボードニュースを見ながらするつもり
進捗 2019/06/04
がんばった pic.twitter.com/wuT70Ab6yn
— すに (@ysni_pub) June 4, 2019
諸々のコストについての議論を見て完組品として販売するのが良さそうだと思いました。
不良が出ないようにTRRSケーブルもModulo Pendant(互換品)も接続した状態で販売したいと思います。
まとめ
いかがでしたか?
ほしい人は「ホギィ」と言っていただけると開発のモチベーションに繋がります。
GoogleHomeにFelicaカードの残高を教えてもらおう
libpafe
をインストール
sudo apt install libavahi-compat-libdnssd-dev mkdir tmp cd tmp # libpafeをインストール sudo apt install libusb-dev wget http://hito.music.coocan.jp/pasori/libpafe-0.0.8.tar.gz tar zxvf libpafe-0.0.8.tar.gz cd libpafe-0.0.8/ ## 以下3行は不要かもしれない ./configure make sudo make install sudo apt install debhelper autotools-dev dpkg-buildpackage -us -uc sudo dpkg -i ../libpafe_0.0.8-1_armhf.deb ls /lib/udev/rules.d/ | grep libpafe # udevの設定ができているか確認 # libpafe-devをインストール wget http://hito.music.coocan.jp/pasori/libpafe-dev_0.0.8-1_all.deb sudo dpkg -i libpafe-dev_0.0.8-1_all.deb # libpafe-rubyをインストール wget http://hito.music.coocan.jp/pasori/libpafe-ruby-0.0.8.tar.gz tar xvzf libpafe-ruby-0.0.8.tar.gz cd libpafe-ruby/ sudo apt install autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev sudo apt install ruby ruby2.3-dev ruby extconf.rb make make install
google-home-voicetext
のインストール
cd ~/prog git clone https://github.com/sikkimtemi/google-home-voicetext.git cd google-home-voicetext npm install patch -u -R node_modules/mdns/lib/browser.js < mdns_patch/browser.js.patch
onServiceUp
が1度しか動作しないようにする
diff --git a/google-home-voicetext.js b/google-home-voicetext.js index a856df4..435fe46 100644 --- a/google-home-voicetext.js +++ b/google-home-voicetext.js @@ -22,7 +22,13 @@ const ip = function(ip) { const notify = function(message, callback) { if (!deviceAddress) { browser.start(); + serviceUpCalled = false; browser.on("serviceUp", function(service) { + if(serviceUpCalled) + return; + else + serviceUpCalled = true;
ポート番号の変更
既にスマートリモコンプログラムが動いているからか8080番, 8888番では動かなかったのでそれぞれ8079番,8887番で動かすことにし, 適切に書き換える
Rubyスクリプトを書く
ICカード読み込み部分はあっきいさんのそのままです。
# coding: utf-8 # IC balance checker / 2019 @y_sni # Licence: # MIT License # references: # http://homepage3.nifty.com/slokar/pasori/libpafe-ruby.html # http://iccard.jennychan.at-ninja.jp/format #require 'wiringpi' require "pasori" require "net/http" require 'uri' def send_message(message) url = "http://localhost:8079/google-home-voicetext" puts message res = Net::HTTP.post_form( URI.parse(url), {'text'=>message} ) puts res.body end pasori = Pasori.open begin begin felica = pasori.felica_polling system = felica.request_system() card = {} system.each {|s| puts "system called" if (s == Felica::POLLING_SUICA || s == -31065 || s == -32546 || s == -31138 || s == -30261) # Suica (Generic traffic IC card) balance felica.foreach(Felica::SERVICE_SUICA_HISTORY) {|l| data = l.unpack('CCnnCCCCvN') card["name"] = "Suica" if (s == -32546) card["name"] = "Iruca" end if (s == -31138) card["name"] = "SAPICA" end if (s == -30261) # PASMO(TOKYU noruleage honorary station master card) card["name"] = "PASMO" end card["balance"] = data[8] break } # SAPICA point felica.foreach(0xBA4B) {|l| data = l.unpack('CCCNNNC') card["point"] = data[2] | data[1] | data[0] } elsif (s == -512) pasori.felica_polling(Felica::POLLING_EDY) {|felica2| # Edy balance felica2.foreach(0x1317) {|l| data = l.unpack('VVNnv') card["name"] = "Edy" card["balance"] = data[0] break } # nanaco balance felica2.foreach(0x5597) {|l| data = l.unpack('VVVV') card["name"] = "nanaco" card["balance"] = data[0] break } # nanaco point cnt = 0 felica2.foreach(0x560B) {|l| if (cnt == 0) cnt += 1 next end data = l.unpack('CCC') card["point"] = data[0] << 16 | data[1] << 8 | data[2] break } # waon balance felica2.foreach(0x6817) {|l| data = l.unpack('vNNNn') card["name"] = "WAON" card["balance"] = data[0] break } # waon point felica2.foreach(0x684B) {|l| data = l.unpack('CCC') card["point"] = data[0] << 16 | data[1] << 8 | data[2] break } } elsif (s == 0xA604) felica2.foreach(0x00CF) {|l| data = l.unpack('NNNCCCC') card["balance"] = data[4] << 16 | data[5] << 8 | data[6] card["name"] = "LuLuCa" break } elsif (s == 0x0F04) felica2.foreach(0x030F) {|l| data = l.unpack('NNNCSC') card["balance"] = data[4] card["name"] = "ナイスパス" break } else if (s != 1223 && s != -32638 && s != -31445) card["name"] = "Unknown" card["balance"] = sprintf("%d(%X)", s, s) end end } send_message "#{card["name"]}の残高は#{card["balance"]}円です。" #sleep 5 rescue => ee puts 'error' send_message "ICカードがありません" #sleep 1 end #while true rescue Interrupt felica.close pasori.close print "\n\n" exit 0 end
サーバーが自動で起動するようにする
~/bin/googlehomeserver.sh
#! /bin/bash cd /home/pi/prog/google-home-voicetext export VOICETEXT_API_KEY=YOUR_API_KEY export WIRELESS_IP=RASPBERRY_PI_ADDRESS node file-server.js & sleep 5 node api-server.js
/etc/systemd/system/googlehomevoice.service
[Unit] Description = google home server [Service] ExecStart=/home/pi/bin/googlehomeserver.sh Restart=always Type=simple [Install] WantedBy=multi-user.target
sudo systemctl enable googlehomevoice.service
苦労した話
- 間にsleepを入れないとエラーになった
- 最後のコマンドの末尾に&を付けると実行が終了したと判断されて殺されるらしい
Slackから起動するようにする
~/homebot/bin/iccard-check.sh
#! /bin/sh ruby /home/pi/prog/iccard-check.rb
既になにかしらのコマンドをSlackから実行できているとして,
$ cd ~/homebot $ bin/hubot homebot> homebot command readic bin/iccard-check.sh
Slackでhomebotにsend readic()
と話しかけると~/homebot/bin/iccard-check.sh
が実行されるようになる。
苦労した話
- hubotのコマンド名には英字大文字は使えない
GoogleHomeへの呼びかけで起動するようにする
IFTTTで適切に設定する
参考
初心者歓迎詐欺被害者の会: Rubyでrequire 'pasori' したい話
Rasberry Piの起動時にhubotも自動的に起動させる - Smart Home
ストロベリー・リナックスのSB1602BWかスイッチサイエンスのI2C LCDを使って、Felica系カードの残高を表示するスクリプト。OSCのデモとかで使用中。 · GitHub
QMKファームウェア書き込み時にリセットボタン2連打が必要なProMicroの挙動
Detecting USB port, reset your controller now.........
と表示されたときにリセットボタンを1回押すと
Device /dev/ttyACM0 has appeared; assuming it is the controller. Waiting for /dev/ttyACM0 to become writable.
と表示される。リセットボタンを2連打すると通常通り書き込みが走る。
一度書き込んだあとはリセットボタンは1回押しで書き込めるようになる。
aptでインストールしたPythonでvirtualenvwrapperを使う
virtualenvwrapper.sh
がない
$HOME/.local/bin/virtualenvwrapper.sh
にある
source $HOME/.local/bin/virtualenvwrapper.sh
するとエラーメッセージが出る
source
する前に以下を実行
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 export WORKON_HOME=$HOME/.virtualenvs export PROJECT_HOME=$HOME/Devel