僕のYak Shavingは終わらない

車輪の再発明をやめたらそこには壮大なYakの群れが

コロナ禍でも問題なし!フルリモートIoT案件(副業)をbalenaを使って完遂しました。

f:id:kazuph1986:20200920103836p:plain
開発環境

<2020/09/21 9:24 追記>

ありがとうコロナ渦警察

<追記終わり>

はてブロではお久しぶりです。

この度「フルリモートIoT案件」をbalenaを使って完遂したので、その内容を共有したいと思います。 先に書いておきますが、「技術書典9でbalena本書いたから買ってほしい」という願望により書かれた記事ですw (セルフPR)

案件内容

詳しくは書けませんが、友達のベンチャーのIoTデバイス(抽象的表現)用のゲートウェイスマホアプリとそれをつなぐクラウド部分を担当しました。 その会社には組み込みより下のレイヤーのメンバーしかいない状態だったので、今回は組み込みより上を担当した感じです。

本来であれば、IoT案件となると、開発中の試作品の目の前でうんうんうなりながら開発すると思うのですが、 今回はコロナ禍ということもあり、完全にフルリモートで開発することにしました。

balenaを使った結果、実際に完全にフルリモートで開発することが可能で、 相手はArduinoを利用していたのですが、Arduinoとの通信部分のデバッグも 問題なく可能でした。

今回の副業は、作り込みで言うと完全にPoCレベルですが、本業の方では本番導入が進んでいます。

balenaってなに?

f:id:kazuph1986:20200920101258p:plain
balenaの概略

www.balena.io

一言でいうと「IoT用途のエッジデバイス管理プラットフォーム」です。

以下の事が可能です。

  • Dockerコンテナを使ったアプリケーション開発
  • コンテナのビルドからエッジデバイスへ配布の実行(手元マシンにDockerのインストール不要)
  • エッジデバイスごとにユニークな公開URLを付与
  • 登録したエッジデバイスに対していつでも遠隔ターミナル接続
  • コンテナが参照する環境変数をWebコンソールから設定
  • リリースリビジョンの管理(リリースロックや巻き戻しが容易)
  • 死活監視、ログ監視、リソース監視

その他、死活監視、ログ監視、起動制御、OSアップデートなどエッジデバイス運用でほしい事をすべて遠隔で実施可能です。

無料で10台のエッジデバイスが利用できるので、家庭向けに検討されている方は無料枠だけで一生分遊べるのではないでしょうか?

balenaを使ってできること

基本的になんでもできます。コンテナを利用するからできなくなってしまうこともほぼないと思います(今のところ遭遇してないだけかも?)。

自分が試したことを列挙します(ここに書いてないことができないというわけではないです)。

  • GPIO(High/Low, PWM)を使ったLEDやサーボモーターの制御
  • ArduinoとのSerial通信(USB)
  • カメラモジュールによる撮影(静止画、動画ストリーミング)
  • Bluetooth Low EnergyによるBLEデバイス操作(Switchbotの温湿度計の制御)
  • 公開URLを使ってハードウェア制御用のWeb APIを構築
  • Google Home Notifierの構築(しゃべらせるやつ)
  • Prometheus+Grafanaを使ったリソース等のメトリクスの可視化
  • cronによる何かしらのスクリプトの定期実行

基本的にコンテナに権限を何でも付与できるので、root権限が必要なものも実行可能ですし、 ネットワークについてもホストOSと同等のものも付与できます(セキュリティの話は別にありますが)。

実際に子どもが生まれて、妻と子どもだけ地方に里帰りしていた期間があるのですが、 balenaを入れたラズパイにカメラをつなげて、 自分は東京でそのカメラアプリを開発するということが可能でした。

これによって生まれたばかりの赤ちゃんがベッドで寝ている画像をいつでも見れる環境を構築することができました。 (撮影タイミングを変更したり、撮影した画像をGoogle Driveにバックアップしたりなどは後からどんどん追加開発していました)。

これは完全にbalenaのおかげです。

なぜbalenaを使うのか

f:id:kazuph1986:20200920105726p:plain
バイスの管理画面

balenaを使うと、遠隔にあるエッジデバイスを使った開発が容易に可能になるというのもありますが、 開発した後の運用がめちゃくちゃ楽になるという効果もあります。

この理由の1つ目は、Dockerを利用するのが強制されるおかげで、環境構築がコード化されたり、 デバイス内のアプリケーションを分割しようとする力学が働くからだと思います。

balenaでは、Dockerfileを使うのに加えて、docker-composeも利用が可能です。 これによって、コンテナの分割が容易になったり、 コンテナごとに付与する権限を制御しやすくなったり、 いつでも不要なコンテナを削除したりが簡潔にできるようになります。

github上にはたくさんのbalenaのサンプルが上がっているのですが、 これらも原則に従い、一つのコンテナにすべてを詰め込むようなことはせず、 いくつかのコンテナに分割し、それらが協調するように構成になっているのが伺えます。

それに伴って、コードもシンプルになり、メンテナンス性が向上します。

また2つ目の理由としては、やはり遠隔にあるエッジデバイスの状態がいつでもわかり、アクセスが可能なことです。 これによって、何かの影響でバグが発生したとしても、いつでも確認し修正することが可能です。

開発のしやすさ

balenaが用意しているコマンドラインツールによって、ローカルネットワーク内にあるbalena対応のデバイスを検知して、 クラウドを介さずに開発することも可能です。これによってMac等の開発マシンでソースコードをいじって、 そのコードの変更を検知して自動でコンテナをリビルドし、目的のエッジデバイス上でコンテナの再起動が可能です。

また、VSCodeのRemote Containerも使うことができるので、インクリメンタルにブレイクポイントを使った開発も可能です。

vscodeが64bit向けにしかRemote Containerのagentを提供していないことに注意)

書籍の紹介

ということで、最後に書籍の紹介ですw

現在開催中の技術書典9にて、『実践balena』という書籍を執筆し販売しています。 balenaのアカウントの作成から、実際のアプリの開発例をソースコードを交えて解説しています。

執筆のモチベーションは、balenaの日本語の記事や資料がまだまだ全然ないがために、日本人がbalenaを試せてないということを感じたからです。 IoTに従事して5年以上経ってしまいましたが、エッジデバイスの管理は独自に作り込むのがとても大変で、実際に運用面でとても苦労してきました。

そのためbalenaに出会ってからの感動といったらありませんでした。「これ、ほしかった!」という機能は大体実装されているので、 開発期間もかなり短縮できますし、運用に入ってからのソフトウェア更新もとても簡単になりました。

正直この辺を自前でやるのはつらすぎるので、おそらく自分は今後balenaを利用しないことはないと思います(ネットワークやセキュリティの要件がガチガチの大手向けIoT案件だとまた別かもですが)。

ということで、気になった方はぜひご購入ください。

techbookfest.org

また姉妹本で、技術書典7にて販売していた、ラズパイとDockerの本も半額の500円で販売しているので、 合わせてご利用くださいm( )m

techbookfest.org

(安いせいかこっちの方が3倍くらい売れてるんですよね…人類のためになるのはbalena本の方だと確信していますが…)

macのvscodeでSSH鍵で認証しているサーバーに対してsftp sync

僕の用途的にはクラウドのサーバーではなく、手元のラズパイですね。

まずsftpという拡張をインストール。

⌘+Shift+Pで「sftp config」と検索して実行し、プロジェクトに対応した設定ファイルを記述する。

f:id:kazuph1986:20181113200355p:plain

{
    "protocol": "sftp",
    "username": "<YOUR_USER_NAME>",
    "remotePath": "/path/to/your/remote/project",
    "agent": "$SSH_AUTH_SOCK",
    "watcher": {
      "files": "*.js",
      "autoUpload": false,
      "autoDelete": false
    },
    "profiles": {
      "dev": {
        "host": "<YOUR_DEV_HOST>",
        "uploadOnSave": true
      },
      "prod": {
        "host": "<YOUR_PROD_HOST>",
      }
    },
    "defaultProfile": "dev"
  }

これで、SSH鍵で認証しているホストに対してパスフレーズなどいちいち入力しなくても保存時にアップデートされるようになる。agent部分が肝。

参考

stackoverflow.com

github.com

builderscon tokyo 2018 で前夜祭とDay1のダブルで発表してきました

いやー、こんなに発表させてもらっていいんでしょうか?ってくらい今年のビルコンでは枠をいただき、話をさせていただくことができました。

前夜祭 『IoTの闇』30分枠

きっかけはこんな牧さんからのメッセージ。

f:id:kazuph1986:20180907173650p:plain

正直すぐに光栄だなぁって思って、僕の会社ももう4周年を迎えていたのですが、光があれば闇があるということなので、そういう認識をして快諾させていただきました。

発表内容は残念ながら会場にいた人限定での共有で、SNSへの投稿も禁止とさせていただきました。 発表時の様子は以下のTLから伺えますw

twitter.com

Twitterの検索機能便利!)

Day 1 『産業でガチ利用されるRaspberry Piの話』

speakerdeck.com

builderscon.io

こちらが本編です。

なんと前夜祭に来ていただいた方々がほとんどで、闇での宣伝効果がすごいなと思いました。

やはり皆様、闇も光も両方コンプリートしたかったという感じでしょうか。

twitter.com

おわりに

実は僕はDay2は帰郷する用事があったので、参加できませんでした。悲しい。

でも、前夜祭も発表させていただくという貴重な体験ができたことが救いです(指名制なので)。

ただ懇親会は出ることができたので、旧友や発表を聴いてくださった方々とお話をすることができてとても楽しかったです。

また来年も参加します。発表者ならびに運営・スポンサーの皆様、素敵なイベントをありがとうございました。

『iOSアプリ開発者のためのFirebase入門』を読んだ。

booth.pm

本の感想としては、ざっくりドキュメントから読むのがしんどい人用に掻い摘んで要点をまとめてくれているので、実装部分を読まなくても全体を把握するのに適してるなってのと、筆者の個人的なまとめ(Realtime DatabaseとFirestoreどっちがいいの?みたいな)があるので、第三者のコメントを見て思考をショートカットできたのが良かったです。

Firebaseについては、

  • Google傘下に入ったのでClashlyticsやFabricを個別に導入して移行を繰り返してきた身としては、「やっと決着(終着)したか?」とアプリの解析ツールとして最後の希望みたいな印象を持っている
  • AWSのS3やLambda、DynamoDB、Cognito等のいいとこ取りをして一つのパッケージ(サービス)にしているのが、「もうFirebaseのことを考えていればいいんだ」って心の平穏を保てそう

という感じで良い(疲れているのか??)。

Firebaseざっくり

  • 解析ツール全部のせ(クラッシュ分析、コホート分析、アクティブ分析等諸々GAにあるようなやつも)
  • アプリのプッシュ通知部分を肩代わり
  • 認証系実装の肩代わり(TwitterFacebookGoogle,SMS認証、普通のID認証、匿名認証など、開発初期でめんどいけど入れておきたい系)
  • リアルタイムデータベース(いわゆるKVSだけど、データをアプリローカルでキャッシュしつつ、ネット上で変更があったらリアルタイムに反映などの基盤も提供)
  • 更に上記の進化版でよりRDB的にSQLも書けるデータベース(ベータ)
  • S3的なストレージ、ホスティングもできる(Reactとか静的サイトをぽんと置ける、認証ユーザーのみのアクセス許可等も可能なはず)
  • デプロイなしでのアプリ設定変更(configファイルをWebコーンソールから編集して条件フィルタして反映、A/Bテストなどを考慮)
  • AWS Lambda的な感じでイベント拾って任意のソースコードを実行
  • etc…

AWSでもほぼ同系統のことができるけど、Firebaseは一気通貫でできるので、色々コストは減りそう。 ただ、すでにAWSを導入している場合には併用することの弊害があると思うので、その辺は責務を競合しないように決めをつくっておく必要あり。

導入の簡単順としては、解析系→通知系→認証系→(必要なら)DB・FaaSでゴニョゴニョという感じですかね。

最後に行くほど、やるときに適切な設計が必要な気がします。

次はこの本を読みます。

booth.pm

Logicool K480 Bluetooth Key Boardを買った

f:id:kazuph1986:20170223202202j:image

 

思っていたよりも大きいけど快適。

びっくりしたのが、iOSがちゃんとBluetoothキーボードのときは、ソフトキーボードを表示しないこと。

でもちゃんと変換候補は出してくれる。

良い点は、
- スマホをキーボード自体にさせる(ので場所を取らない
- Bluetoothの接続切り替えスイッチがあって、簡単にMacスマホの切り替えができる
- iOSの場合、画面が暗い状態からパスコード解除がキーボードだけでできる
- ホームボタンの代替キーがあるので、アプリ切り替えも楽
- スクショ用のボタンもある
- 安い、3000円台
- 久々タイピング音が気になるが、逆に新鮮で好き


気になる点は、

- 日本語の配列キーボードだけど英語配列として認識される→でも英語配列になっても、物理キーボードの方に場所のラベルが書いてあるから全然困らない。
- 自分の変換の方法いつもおかしかったのかもだけど、入力の候補選択時にtab keyを押してしまって変換候補選択が消える→space keyが正解らしいが最初なれる必要がある
- MacBook Airと擦れて黒い塗装が剥がれた
- caps lockが左手小指の位置にない(地味に一番嫌だ

- ちゃんとはめないとiPhoneが抜けて落ちる

 

物書きがはかどりそうだったらまた報告します。

 

 

 

 

 

Webエンジニアとして最低限の体裁を保つための結婚式入門

Wedding Hack

f:id:kazuph1986:20161224125705p:image

今年の9月に結婚式を上げました。

Webエンジニアとして長年生きてきた自分は、結婚式でも絶対面白いことをやろう!と思って、 人生で2, 3番目くらいには重要なイベントである結婚式にすらエンジニアとしての最低限のHackをやって来ました。

もし一生をものづくりをする人間として過ごすのなら、人生を振り返ったときに立ち戻る重要な瞬間が必要です。

僕に取ってはそれが「結婚式でWebエンジニアリングをする」でした。

新婚旅行よりもbuildersconを優先したことで一部で有名な僕ですが、 今回は結婚式でのHackを紹介します。

それではいきましょう!

ウェルカムボードでWebエンジニアリングする

最初は、結婚式中のコンテンツとして何かWebやハードウェアと連携するものをと思ったのですが、 流石に結婚式の本番中に失敗してしまっては、親族などに顔向けできません。

やるなら、そもそも失敗ないような設計をするべきです。

ということで僕はウェルカムボードをHackすることにしました。

ウェルカムボードとは、式場の入り口に置く招待者を最初に迎え入れるボードのことです。

人によってはものすごく簡素なものを用意していることもありますが、 新郎新婦の似顔絵だったり、友人につくってもらったり、二人の趣味のものを飾ったりと人それぞれです。

基本的には素通りされるものなので、そもそも失敗自体しづらいです。 弊社の回路エンジニアもウェルカムボードを回路基板で作成してLEDを点灯させたりしていました。

 完成品

みんなでつくるWelcome Board

f:id:kazuph1986:20161224130155g:plain

これだけだとよくわからないので、解説。

ディスプレイには予め「Welcome to our wedding reception!」と表示させておき、 基本的には新郎新婦の思い出社員をスライドショーさせておきます。

それだけだとつまらないので、横に置いてあるMacのカメラで写真が取れるようにしておきます。

そこで写真を撮影すると、メインのディスプレイに撮影した人たちが投影される仕組みです。

数秒後には元にスライドショーに戻りますが、このときの写真がどんどん追加されていくイメージです。

必要なのはディスプレイとMac一台と結婚式っぽく見せるための造花。

写真共有サイト

f:id:kazuph1986:20161224125736g:plain

こちらは単純にスマホブラウザから写真のアップロードができるサイトです。他の人がアップロードしたものも見れて、「1分前」 「10分前」など時系列で閲覧できます。

 

一応複数枚同時アップロードにも対応。

 

 実際どうだった?

待合室にこんな感じで置かれており、うちの共同創業メンバーや同僚が周りの人に紹介してくれたので、結構使ってもらえたみたいです。

f:id:kazuph1986:20161224125713p:image

※モザイク掛かってない二人はうちの会社の創業メンバー

なんだなんだと眺めていると他の人が撮影した写真が映るので、じゃあ自分もやってみようかという感じで 沢山の人が撮影してくれればいいなと思ってつくりましたが、その結果がこちら。

f:id:kazuph1986:20161224125722p:image

※人物が特定できないようにかなり解像度を下げてます。

全部で50枚くらい撮影してくれました!会場のスタッフの方が、待合室からさらに披露宴会場の入り口にも移動してくれたので、入退場含めさらに多くの人に使ってもらえました。

またこの時撮影した写真は、これまた結婚式のためのつくったお手製の写真共有サイトに リアルタイムに表示されるようになっていたので、花嫁の準備中に1人で見て(・∀・)ニヤニヤしてました。

やはり自分がつくったサービスが人に使われるのを見るのはうれしいことですね。

そして個人的に嬉しかったのが、嫁の両親が使ってくれていたこと。

しかも笑顔で。これを見た時にはなんというか「一つ認めてもらえたかな」と思えるような、そんな大事な瞬間でした。

どうやってつくったの?

ということで、どうやってつくったか見ていきます。

SAKURAのVPSを準備

元々持っていたのでそれをそのまま使いました。

CentOS 6.5でした。

MySQLじゃなくて、SQLiteでサクッと作るつもりだったので、そうします。

$ yum update -y$ yum install -y git vim make glibc-devel gcc gcc-c++ openssl-devel$ yum install -y sqlite-devel$ yum install -y ImageMagick$ useradd app

Install ruby

[root]$ yum install -y readline-devel [app]$ git clone git@github.com:tagomoris/xbuild.git$ xbuild/ruby-install 2.3.1 ~/local/ruby-2.3.1$ export PATH=$HOME/local/ruby-2.3.1/bin:$PATH※↑は.bashrcにも追記

Setup application

$ cd$ git clone git@bitbucket.org:kazuph/wedding-photo.git$ cd wedding-photo$ bundle install --without development test --path vendor/bundle

Nginx

$ yum install -y nginx

設置

server {    listen       80;    server_name  ore-wedding.com     location / {        proxy_pass          http://localhost:3000;        proxy_set_header    Host             $host;        proxy_set_header    X-Real-IP        $remote_addr;        proxy_set_header    X-Forwarded-For  $proxy_add_x_forwarded_for;        proxy_set_header    X-Client-Verify  SUCCESS;        proxy_set_header    X-Client-DN      $ssl_client_s_dn;        proxy_set_header    X-SSL-Subject    $ssl_client_s_dn;        proxy_set_header    X-SSL-Issuer     $ssl_client_i_dn;        proxy_read_timeout 1800;        proxy_connect_timeout 1800;    }}
$ service nginx start$ chkconfig nginx on

起動

productionで起動するための設定

$ echo SECRET_KEY_BASE=`bundle exec rake secret` > .env$ bin/rails db:migrate RAILS_ENV=production$ bin/rails assets:precompile RAILS_ENV=production$ export $(cat .env | xargs) && bundle exec puma -C config/puma.rb -eproduction

exportなんとか〜&&ってやると.envにある値を全部展開してくれて、プログラム中に使えるようになります。 doenvに頼る必要がないので便利です。

pumaをinitで使う

このままだと、pumaが死んだらそのまま死んだままなので、その辺はinitさんにお願いします。

https://gist.github.com/niwo/4526179

自分はこれを使いました。以下のinstallが必要でした。

$ yum provides /lib/lsb/init-functions$ yum install redhat-lsb-core

設定ファイルはgistにあげてます。

https://gist.github.com/kazuph/b0d84d078cc23b8a6eb605bb15e08b2a

nginx basic auth

開発中はBasic認証で見えないようにしてました。

$ yum install -y httpd-tools$ cd /etc/nginx$ htpasswd -c .htpasswd wedding

/etc/nginx/conf.d/virtual.conf

server {    auth_basic "Restricted";    auth_basic_user_file /etc/nginx/.htpasswd;}

wedding photoアプリ

Rails5でつくりました。Versionは5.0.0。

Gemfileにはこれを追加しました。

gem 'carrierwave', '>= 1.0.0.beta', '< 2.0'gem 'mini_magick'gem 'exifr'gem 'materialize-sass'gem 'kaminari'

使ったJSファイルは、

  • webcam.js
  • material-photo-gallery.js
  • lodash.js

だけです。

残念ながらこの時点では僕がReact触ってなかったので、古き良きRailsアプリケーションという形で作成されてます。

ちなみにTurbolinksはONのままやりきりました。やはり画面の遷移がスムーズになるのは気持ちいいですね。

carrierwaveのuploaderは以下のような感じにしました。

app/uploaders/photo_uploader.rb

class PhotoUploader < CarrierWave::Uploader::Base  include CarrierWave::MiniMagick   storage :file   def store_dir    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"  end   # 回転対応   def fix_exif_rotation    manipulate! do |img|      img.tap(&:auto_orient)    end  end  process :fix_exif_rotation   process :resize_to_limit => [2048, 2048]   version :normal do    process resize_to_fit: [1024, 1024]  end   version :thumb, from_version: :normal do    process resize_to_fit: [200, 200]  end   def extension_whitelist    %w(jpg jpeg gif png)  end end

Welcome boardのjsはこんな感じでした。

app/assets/javascripts/welcome.js

$(document).on('turbolinks:load', function(event) {  if (controller !== "welcome") { return; }   // 画像のローテーション   $('#fullscreen').find('img:gt(0)').hide();  var imgAnimation = function() {    $('#fullscreen :first-child')      .fadeOut(1000)      .next('img')      .fadeIn(2000)      .end()      .appendTo('#fullscreen');  }  var imgInterval = setInterval(imgAnimation ,3000);   Webcam.set({    width: 320,    height: 240,    dest_width: 640,    dest_height: 480,    image_format: 'jpeg',    jpeg_quality: 90  });   Webcam.attach('#my-camera');   document.addEventListener("keydown" , function(e) {    var keyCode = e.keyCode;    if ( keyCode === 13 ) {      Webcam.snap(function(dataUri) {        console.log("Data URL: " + dataUri)         // 表示されるようにする         $('#fullscreen :first-child').fadeOut(100);        $('#fullscreen').prepend(''+dataUri+'" />');        clearInterval(imgInterval);        setTimeout(function() {          imgInterval = setInterval(imgAnimation ,3000);        }, 5000);         // Ajaxでサーバーに画像の送信         Webcam.upload( dataUri, '/welcome/create', function(code, text) {        });      });     }  });});

Webcam.jsに予め撮影画像のuploadメソッドが生えているのが便利でした。

webcamのuploadをrailsで使えるようにする

ただしそのままでは、WebCamで撮影した写真をアップロードできなかったので、Railsが発行しているcsrf-tokenを、 アップロード時のパラメーターに含めるようにだけ修正しました。

vendor/assets/javascripts/webcam.js

  var l = new FormData;  l.append(s, h, s + "." + i.replace(/e/, ""));  // 以下を追加   l.append('authenticity_token', $('meta[name="csrf-token"]').attr('content'));  o.send(l)

まとめ

ということで、結婚式にどんなハックをしたのか紹介してみました。

全部で3人日ちょいくらいでしたが、デザインにこだわっていたらもっとかかっていたかもしれません。

マテリアルデザイン便利だなーって思いつつ、当時でいうと久々Rails書けて楽しかったです。

あとpumaも始めてでしたが先人がいいものをたくさん用意してくれていたので、 ほぼ詰まらずにinit化くらいまではいけたかなと思います。あとhot deployも意識せずにできたりと、良いことが色々ありました。

嫁側の両親や親戚や招待した方々に、自分のことを知ってもらうのが目的でつくったので、それは達成できたかなと思います。

あと、自分側については一応僕は大学時代からこんなことをやっていたので「相変わらずだな」って思ってもらえてればいいなぁと。

ということで、当日までは結構ドキドキでしたがうまくいって良かったです。

結婚式がまだな方は是非参考にしてみてください!

Enjoy Wedding Hack!

 

---

ちなみにトップ画の一升瓶は、地元の酒造が出しているもので、通常の一升瓶が1.8Lに対して、2.5倍の4.5Lの大型サイズのものです。当日は二人の画像を貼るとともに、新郎新婦の場所に来てもらった人達に注ぎまくるという演出をやってました。

大変縁起がいいので、もし良ければこちらもどうぞ。

f:id:kazuph1986:20161224133226p:plain

益々繁盛 | 朝日山 | 朝日酒造株式会社

[Note ID: 7c63437b4789f87ffdc239e14e605d93]

2016-12-24 12:52:07

AtomとEvernoteを連携するever-notedownを使う

Vimプラグインであるmemolistで作成した技術メモが大量にDropBoxに入っているのですが、 プレビューが面倒だなぁって思っていて、VimからMarkdownをプレビューできるPreVimを使ってもいるのですが、ワンクッションおくのでうーんと思っていました。

Qiitaのインターフェースは好きなので、じゃあKobitoでも使うかぁって思ったのですが、なんとなく却下。 #ひどい

で、最近回りの人達がAtomを使い始めたので、自分も使ってみようと思って手を出しています。

今はまだ、Atom自体でコーディングをするつもりにはなれませんが、一旦はEvernoteへの連携のために使ってみようと思い。

ということで、今回はAtomEvernote連携パッケージである、ever-nodedownを使ってみます。

ソースコードもハイライトされてものがEvernoteにアップロードされるので、とても便利ですよ。

ever-notedownのインストール

atomにはコマンドラインを用いてパッケージをインストールする方法があることは知っているのですが、いやGUIだからむしろじゃまでしょ??って思って、普通に設定から入れます。

⌘, で設定を開いて +install からインストールします。

一応公式の手順があるので、それに従いましたがgitでの管理が必須化はわかりません。

$ ln -s path/to/your/folder ~/.atom/evnd$ cd ~/.atom/evnd$ echo "{}" > index.json$ cd path/to/your/folder$ git init------ Optional ------$ git add .$ git commit -m "Initial commit"

バグを修正する(日本語環境だけ?)

ということで、いきなりバグを踏みました。 もしかしたら海外のMacでは正常に動作するのかもしれませんが、僕の手元の環境ではだめでした。

cd~/.atom/packages/ever-notedownvim lib/evernote-helper.coffee

以下の様に変更して下さい。

-    cmd += "\tset newDate to date (m & \"/\" & d & \"/\" & y)"+    cmd += "\tset newDate to date (y & \"/\" & m & \"/\" & d)"

AppleScriptのdate関数に食わせる年月日の順番が違いました。

また、どうやらEvertnoteのnotebook対応が微妙だったみたいなので、その部分も修正します。

vim lib/note-prototypes/note-base.coffee
-    if options.notebook and @notebook? then queryString += " notebook:\"#{@notebook.name}\""+    if options.notebook and @notebook? then queryString += " notebook:\"受信箱\""

ever-notedownで作成した記事にNotebookを指定する箇所があるのですが、自分の場合はそこを指定してもお望みのノートブックへは保存できませんでした。悲しい。

僕がたまたまメインのBoxを受信箱にしているのでそうしましえ。 これで問題なく動きます。

使ってみる

ちなみにEvernoteもインストールされてないとだめです。

最初WebAPIを使って同期するのかな?と思ったら、Macに入れたデスクトップ版Evernoteアプリに対してAppleScript経由で操作をしているようでした。

AtomのMenu > Packages > Ever Notedown > New Note > Create Note NoteB

として最初のノートを開きます。

f:id:kazuph1986:20161223152803p:image

あとは、適当に編集して⌘Sで保存し、プレビューのEvernoteアイコンクリックで、Evernote側にも保存されます。

f:id:kazuph1986:20161223152812p:image

画像はどうなる?

最初自分で~/.atom/evnd 以下にインストールしないといけないのかなぁって思ったのですが、なんとFinderで画像を⌘Cした後に、編集エリアで⌘V するだけでした!!

f:id:kazuph1986:20161223152828p:plain

最高か。

Evernote上での見た目

試しにソースコードを貼ってみます。

## TODO: Implement this!##@subscriptions.add atom.config.observe 'ever-notedown.renderDiagrams', (toRender) =>#  if toRender and not window.evnd.chartsLibsLoaded#    chartsHelper ?= require './charts-helper'#    chartsHelper.loadChartsLibraries() @subscriptions.add atom.config.onDidChange 'ever-notedown.gitPath', (event) =>  newGitPath = event.newValue  reloadGitRepo = =>    @loadGitRepo newGitPath, null, (newStorageManager) =>      if newStorageManager?        window.evnd.storageManager = newStorageManager        @loadJSON (newNoteIndex) =>          window.evnd.noteIndex = newNoteIndex          if window.evnd.evndView? then window.evnd.evndView.refresh()          window.evnd.gitPath = newGitPath  dmsg = "Changing git repo path for EVND to #{newGitPath}"  if atom.config.get('ever-notedown.gitPathSymlink') then dmsg += " (symbolic link)"  atom.confirm    message: dmsg + "?"    buttons:      "Confirm": => reloadGitRepo()      "Cancel": => return      "Revert": =>        atom.config.set 'ever-notedown.gitPath', event.oldValue

Atom自体の表示はデフォでもかなりいい感じにハイライトされてますね。右のプレビューもいい感じです。

f:id:kazuph1986:20161223152816p:image

ではEvernote自体ではどうでしょうか?

f:id:kazuph1986:20161223152757p:image

いい感じです!当たり前かもですがプレビューと同じ見た目ですね。

ついでですが、先程の画像もちゃんとアップロードされて思った通りの場所に貼ってあります。

f:id:kazuph1986:20161223152822p:image

Evernote側を修正したらどうなる?

当然気になるやつですよね。

Evernote側を修正してみます。

f:id:kazuph1986:20161223152245p:plain

ありゃ、壊れちゃいました。

ただ、よく見ると単に全体が`<div>`で囲われただけで、エディタ側`<div>`を削除したら直りました、、、と思ったら色々コード部分の改行がおかしくなったりしているので、やらない方がいいかなと思いました。気が向いたら直します。

ご利用は計画的にという感じですが、ever-notedownが結構作り込まれていることがわかります。

Evernoteからはてなに投稿する

最初みたままモードからのコピペしかない?って思ったのですが、そのままやっても画像が反映されず。まあそうですよねーって思ってたのですが、なんと連携が可能みたいです。

f:id:kazuph1986:20161223152837p:plain

まず、はてなの記事編集画面を開き右にある設定から探すとEvernote連携があることがわかります。 ONにするとEvernoteの記事一覧が出てきて、貼り付けってするとべべってコピペされました。

f:id:kazuph1986:20161223152840p:plain

画像も最初は表示されませんが、徐々にアップロードされます。

ちなみにMarkdownモードやると完全に壊れて使い物にならないので、みたままモードでやるといいです。

当然ですが、AtomからEvernoteに保存したあとに、Evernote側でクラウドとの同期が終わっている必要があります。

まとめ

ever-notedown いい感じです。

実際この記事はever-notedownで書きましたが、個人Qiitaを手に入れたような快適さでした。

皆様も是非。

[Note ID: f91a1095ca8ec708f5908722220b6b32]

2016-12-23 15:27:15