pco2699’s blog

学んだコード・技術について、保存しておく場所

flutter meetup tokyo #5 に参加してきた

flutter meetup tokyo #5に「ブログ参加枠」で参加してきました!
勉強会をブログにまとめるの初めてなので、拙いところがあってもご容赦ください...

LT① flutterで個人リリースしてみた / shogo.yamada

speakerdeck.com

内容ざっくりまとめ

  • Group Albumというアプリをflutterでリリースしました!
    • こういった勉強会で写真を共有できるようなアプリがほしかったので、flutterでつくった
  • よかったこと
    • とりあえずマテリアルデザインなので、デザイナー不要
    • 開発スピードが早かった!(3ヶ月ぐらいでリリースできた)
  • つらかったこと
    1. flutterだけでは実装できなかった処理があった、結構 SwiftとKotlinも書いた!
      • 画像の一覧表示などの画像表示周り
    2. 基本的に英語の記事しかない

感想

LT② Redux in action

内容ざっくりまとめ

  • flutterはプロトタイピングで使われるけど、要求は代わるので、スコープはしばしば大きくなるしコードのメンテナビリティも下がっちまうよねー。
  • シンプルなカウンターアプリでExample
  • incrementCounterという処理を複数のページで共有するには?
    • MyHomePage -> MySecondPageで渡すという形であれば問題なさそう、ただそれが並列になると?
  • flutter_reduxがよい github.com

  • 実際の実装の説明をコードベースでしてました

感想

LT③ flutter engineことはじめ

scrapbox.io

内容ざっくりまとめ

  • flutter engineとは?
    • flutterはDartから各ネイティブアプリへのつなぎ込みを行っている!
    • Skiaがコアエンジン
    • Skia自体はC++で書かれているので、C++が書ける人はぜひコミットを!
  • Embedder
    • 各ネイティブのハードウェアAPIのラップを行っている?
  • flutterにおけるスレッド管理
  • 各タスクランナーの処理の内容
  • flutter engineへのコントリビューション方法 -> ただ、テストでフェイルしちゃう...

LT④ 画像取得とpermission

speakerdeck.com

内容ざっくりまとめ

  • flutterで画像を取得する機能を作りたい
  • それ自体は、flutterのimage_pickerプラグイン自体でできるよねー
  • ただ、 iOSだとPermissionを考慮する必要がある。
  • Permission自体を確認するOSSはすでにある。

github.com

LT⑤ flutterのライフサイクル

speakerdeck.com

内容のざっくりまとめ

  • flutterのライフサイクル
  • iOSとかAndroidにもあるライフサイクルをまとめてみたよ
  • ざっくりライフサイクル
    • resume
    • suspending
  • AndroidiOSとflutterでライフサイクルの比較 (スライド参照)

LT⑥ flutterを広めるために技術同人誌を出した話

speakerdeck.com

内容

  • flutterめっちゃいいから、社内で広めたいよね
  • でも、社内で広めるには目標ほしいけど、プロダクションは遠いよね...
  • じゃあ技術同人誌を作ってしまおう
  • 結果完売!(パチパチ)
  • ここがよかった
    • 深い理解
    • 絶対的な締切
  • ここが課題
    • 締切をすぎると燃え尽きる...
    • 良くも悪くも限られた範囲

LT⑦ Flutter + Flutter + Bitrise + DeployGateでAndroid/iOS用テストアプリを配信してみた話

speakerdeck.com

ざっくり内容まとめ

  • スタディプラスでWebView使うようなアプリをさっくり作るサーバサイドで業務用件がでてきた -> それならflutterでやっちゃおう!!
  • flutterでiOSアプリでやるんだったらBitriseおすすめ!
  • Bitriseで無料のiOSのビルドできるよ
  • GithubでPushしたらBitriseでビルド、DeployGateで捗る!!

感想

LT⑧ FlutterでWebviewをいい感じにする

speakerdeck.com

ざっくり内容まとめ

  • flutter web viewで flutter_webview_pluginが一番ひっかかる
  • ただもうちょっといい感じにしたい -> もどれるようにしたいとか
  • やったこと
    • 戻れるように
    • 読み込めるように
  • 苦労点
    • レイアウトを右によせるだけで苦労した...

github.com

感想

LT⑨ FlutterでiOSでin-house配信した話

ざっくり内容

  • iPadワコムタブレットとBLE通信するアプリをflutterで作った
  • タブレットの通信部はSDKを使わず自分でBluetoothのパケットを解析して自作
  • FlutterBlueというBLEライブラリがある(驚き)
  • バグが多いがユーザコードで回避できる
  • async/awaitが書けるのはSwiftより全然らく!
  • PDFを開くライブラリもなかったので自作した(驚愕)
  • せっかくなのでflutterのplugin化した
  • よいところ
    • ListView.builder
    • async/await
    • Hot Reload
  • 悲しいところ
    • いっぱい

感想

Vue.js + Firebaseだけでアプリを作るときにクライアント側にFirebase API Keyをおいてしまって問題ないのか?

背景

Vue.js + Firebase だけWebサービス作れるやーん!っていう言説が非常に多い気がする昨今(私も同意です)
ちょっと前までは、「APIキーはサーバサイドにおいておくのがセキュリティの鉄則!」だった気がします。

で、Vue.js + Firebaseでサーバレスでアプリをつくるとなると、APIキーはクライアントに置かれることになります。
そこらへんって本当に大丈夫なの、って疑問に思ってたので調べてみました。

結論

結論から先に述べると、「問題なし」
Realtime Databaseとかの権限設定が適切に設定されている前提ならば 特に問題ない

調べたもの

やはりあるよねStackOverFlow

stackoverflow.com

内容

質問(意訳)

Firebaseのキーって見てる人全員にさらされちゃってるけど、それでいいんかい?  
このキーの目的ってなんなんだよ?公開されちゃってていいんかいー!

回答(意訳)

APIキーはただ、Firebaseプロジェクトの居場所を特定するだけのもので、知ったところで
別にリスクは無いよ。
データベースのURLみたいなもんさ...?

↓のディスカッションも見てみるとよいとのことです。
(Realtime Databaseの権限設定などのディスカッションがされてます。) stackoverflow.com

Vue.js + Vue-Material + Firebase でハッカブルな結婚式二次会フォームを爆速で実装する


こんにちは、実はこの度、結婚することになりまして、結婚式をあげる運びとなりました。(パチパチ)
せっかくなので、なにかエンジニアリング的なことを結婚式でやってみようと思いまして
とりあえず 結婚式の二次会受付フォーム を自作することにしました!
Vue.jsとFirebaseで自分でも思ったより爆速に仕上がったので、やりかたをまとめておきます。

つくったもの

f:id:pco2699:20180819192802g:plain

利用技術

  • Vue.js (2.5.2)
  • Vue Material (1.0.0 beta-10.2)
  • Firebase Cloud Firestore
  • Firebase Hosting
  • Firebase Cloud Functions(フォームの結果出力で利用、今回は説明は省略)

Typescriptも利用しようと思ったんですが
Vue.jsとTypescriptはいまのところ相性が良くなさそうで、普通のjsでやることにしました。 (今後のVerUpで良くなりそう。)

つくりかた

vue-cliの導入

なにわともあれ、Vue.jsを使う場合は、vue-cliから作るのが一番、爆速です。 vue-cliはNodeやnpm、yarnなどを利用しますがそこらへんの導入の仕方は、他のページなどを参照してください。
今回、私はyarnを利用して必要なパッケージを導入していきます。

$ yarn global add vue-cli

Vue プロジェクトの作成

先程の vue-cliでVueのProjectを作成しましょう

$ vue init webpack WeddingForm

色々聞かれると思うので、答えてプロジェクトを作りましょう。
ちなみに、Project Nameは大文字×らしいので、wedding_formとかにしておきます。
ESLintとかテストとかは、適当に選んでおきます。 (自分は、全部ONにしましたが、テストとか全く書かなかったので、不要だと思いました。)
最初のパッケージインストールはvue-cli側で勝手にやってくれます。

必要なパッケージ類の導入

できたページに必要なパッケージを導入していきましょう

# firebase, vue-materialなどの導入
$ cd WeddingForm
$ yarn add firebase vue-material
# バリデーション用パッケージ類の導入
$ yarn add vuelidate
# かな自動入力の際に使うパッケージの導入
$ yarn add historykana

とりあえずプロジェクトを立ち上げてみる

これだけで、とりあえずVueのサンプルプロジェクトができたので
早速立ち上げてみましょう。 かっこいいVueのロゴが現れます!

$ yarn run dev

f:id:pco2699:20180818002047p:plain

Vue-materialとかfirebaseを使えるようにする

パッケージを導入しただけだとVue-matrialとかfirebaseが使えないので セットアップしていきましょう。
基本的には[プロジェクトルート]/src/main.jsに設定は記入していきます。

# Vue-materialについて、必要な部品をインポート
import { MdButton, MdToolbar, MdField, MdRadio MdSnackbar, MdProgress } from 'vue-material/dist/components'

# firebase
import firebase from 'firebase/app'
import 'firebase/firestore'

# cssをインポート
import 'vue-material/dist/vue-material.min.css'

# importしたvue-materialの部品を読み込み
Vue.use(MdButton)
Vue.use(MdToolbar)
Vue.use(MdField)
Vue.use(MdRadio)
Vue.use(MdSnackbar)
Vue.use(MdProgress)

今回は、必要な部品のみ読み込むようにしてます。
ここで読み込むことで、全ての.vueファイルのテンプレート部でHTMLのコンポーネントとして上記の部品が使えるようになります。
ただJs上とHTML上だとMdButton -> <md-button></md-button> といった形で、記法が少々、違うので注意。

全部の部品を読み込む方法は↓です。(パフォーマンスが悪くなるのでおすすめしません。)

import Vue from 'vue'
import VueMaterial from 'vue-material'
import 'vue-material/dist/vue-material.min.css'

Vue.use(VueMaterial)

上記の読み込んだMdButtonなどのコンポーネント類の使い方の詳細は↓に載ってます。
App - Vue Material

フォーム部の設定

navbarとか基本的なvue-materialの使い方は、他のページに譲るとして
今回は、一番苦労したフォーム部のを重点的に説明していきます。

基本的な使い方編

src/componentsにWForm.vueのようなvueファイルを作成して、 そこにフォームの基本的なデザインとVueで使うモデルを定義していきましょう。


HTML部(抜粋)

<template>
  <form class="Wform" @submit.prevent="validate">
    <div class="md-layout md-gutter">
      <div class="md-layout-item md-medium-size-50">
        <md-field>
          <label for="first_name"></label>
          <md-input id="first_name" name="first_name" v-model="form.firstName" @input="first_phonetic" @keyup="first_phonetic" required :disabled="sending">
          </md-input>
          <span class="md-error" v-if="!$v.form.firstName.required">必須項目です</span>
        </md-field>
      </div>
       <div class="md-layout-item md-medium-size-50">
        <md-field>
          <label for="first_name"></label>
          <md-input id="last_name" name="last_name" v-model="form.lastName" @input="last_phonetic" @keyup="last_phonetic" required :disabled="sending">
          </md-input>
          <span class="md-error" v-if="!$v.form.lastName.required">必須項目です</span>
       </md-field>
      </div>
    </div>
    <md-button class="md-raised md-primary" type="submit" :disabled="sending">送信</md-button>
    <md-progress-bar md-mode="indeterminate" v-if="sending" />
    <md-snackbar :md-active.sync="userSaved">登録ありがとうございました!</md-snackbar>
  </form>
</template>

以下、コードの詳細です。

横並びレイアウト

<div class="md-layout md-gutter">

今回は姓と名で横並びのレイアウトにしたいので、md-layoutというclassを付与します。
ここらへんはvue-materialのcss内に定義されてるのでBootstrapっぽい要領でレイアウトしてくれます。
md-layoutで横並びのレイアウトのコンテナ的なものを作ります。
md-gutterは横並びのレイアウトのパターンで、横並びに一定の溝(gutter)をつけてレイアウトします。

ここらへんのレイアウトもvue-materialのレイアウトを参考にしてます。

インプット部品

          <md-input id="last_name" name="last_name" v-model="form.lastName" @input="last_phonetic" @keyup="last_phonetic" required :disabled="sending">
          </md-input>

md-inputでテキストを入力する部品を定義出来ます。v-modelで後で定義するモデルと紐付けるようにしましょう。 @input@keyupで姓を入力したときに同時にふりがなを入力する関数と紐付けています。 また、送信中に、フォームの入力等を避けるため、sendingという状態を持っており、sendingがtrueのときはdisabledになるようにします。

送信部分

    <md-button class="md-raised md-primary" type="submit" :disabled="sending">送信</md-button>
    <md-progress-bar md-mode="indeterminate" v-if="sending" />
    <md-snackbar :md-active.sync="userSaved">登録ありがとうございました!</md-snackbar>

ボタンはmd-raisedという属性をつけておくことで、画面から浮いた (raised)のようなデザインにすることができます。
md-progress-barはボタン押下後に、表示されるローディングバーなので、sending状態のみ出るようにします。
md-snackbarは、登録成功時に画面下に「登録されました」と表示されるバーです。
これは:md-actice.sync="userSaved"とつけておき、データが登録されたタイミングでuserSavedをtrueにすることで 本スナックバーが表示されるようにします。


スクリプト部(抜粋)

<script>
import { db } from '../main'

export default {
  name: 'WForm',
  data () {
     return {
       form: {
        lastName: '',
        firstName: '',
        lastNamePhonetic: '',
        firstNamePhonetic: '',
        presence: true,
        message: '',
        contact: ''
       },
       first_history: [],
       last_history: [],
       userSaved: false,
       sending: false
     }
   },
   methods: {
    validate () {
      this.$v.$touch()
      if (!this.$v.$invalid) {
        this.sending = true
        db.collection('presences').add(this.form).then(() => {
          this.userSaved = true
          this.sending = false
          this.clearForm()
        }).catch(() => {
          this.sending = false
        })
      }
    },
    clearForm () {
      this.$v.$reset()
      for (let field in this.form) {
        if (this.form.hasOwnProperty(field)) {
          this.form[field] = ''
        }
      }
    }
   }
}
</script>

以下、コードの詳細です。 フォームに紐づくモデルの設定

  data () {
     return {
       form: {
        lastName: '',
        firstName: '',
        lastNamePhonetic: '',
        firstNamePhonetic: '',
        presence: true,
        message: '',
        contact: ''
       },

フォームで用いるモデルをdataで定義していきます。
dataは関数で返す必要があるのでdata(): {return ...}といった形で記載してます。
(コンポーネントを同ページで何回も利用したときに、値がコピーされずに同じモデルに紐付いちゃうから関数で返す必要がある、という理解です。↓参照)

コンポーネントの基本 — Vue.js

そして各フォームに紐づく、モデルのデータはすべてformの子に定義しておきます。
こうすることで、firebaseの登録時にthis.formだけで、フォームのデータを送信することが出来て、後から項目が増えても、コードに手を入れる部分が減ります。

その他の機能で用いるモデルの定義

       first_history: [],
       last_history: [],
       userSaved: false,
       sending: false

その他のフォームには紐付かないものの、機能として利用するモデルはformの外に定義します。
それぞれ以下のような使い方をしています。

first_history, last_history: かな入力機能で利用(first:姓, last:名で利用、ホントはもっとスマートにできそう...)
userSaved: 情報が保存されたかどうかを示すフラグ
sending: 情報を送信中かどうかを示すフラグ

関数の定義
フォームで必要な関数を定義していきます。

    validate () {
      this.$v.$touch()
      if (!this.$v.$invalid) {
        this.sending = true
        db.collection('presences').add(this.form).then(() => {
          this.userSaved = true
          this.sending = false
          this.clearForm()
        }).catch(() => {
          this.sending = false
        })
      }
    },

validateと書いてますが、validateしてfirebaseに登録する処理を行っています。
送信開始時にsending=trueとして、値が無事に追加される or エラーとなったらsending=falseで値を元に戻します。
db.collection('presences').add(this.form)でfirestoreに値を追加します。
.thenで正常系の処理、.catchでエラー時の処理を記載します。 今回はエラー時はあまり考慮しないので、sendingフラグを元に戻すだけにしてます。(ここらへんはもっと改善したいですね。)

clearForm () {
      this.$v.$reset()
      for (let field in this.form) {
        if (this.form.hasOwnProperty(field)) {
          this.form[field] = ''
        }
      }
}

clearFormで、モデルの状態をリセットして送信後にフォームがリセットされるようにします。
(でないと連打して登録しまくる人がいそうなので...)

かな自動入力編

今回、名前を入力する際に同時にかな入力されるようにしてあります。 主に以下を参考にしつつ実装しました。

qiita.com

HTML部の定義

<md-input id="last_name" name="last_name" v-model="form.lastName" @input="last_phonetic" @keyup="last_phonetic" required :disabled="sending"></md-input>

@input, @keyup時に後述するmethodを呼び出すようにフォーム側で指定します。
前述の記事だと@inputだけつけてるんですが、かながうまく入らなかったので@keyup時にも指定しています。

モデル・スクリプト部の定義

data() {
   return {
      first_history: [],
      last_history: []
   }
}

姓・名それぞれのかなを管理するためのモデルを定義しています。

methods{
    first_phonetic () {
      const input = document.getElementById('first_name').value
      this.first_history.push(input)
      this.form.firstNamePhonetic = historykana(this.first_history)
    },
    last_phonetic() {
      // 上と同じなので省略
    }
}

前述の記事で、 関数の引数からフォームの入力値をとってきているんですが、それがうまくいかなく
document.getElementById('first_name')で無理やり値を持ってきています。
で、とってきた値を上記で定義したモデルにpushしていって、そのhisotryをhistorykanaにつっこめば、かな自動入力ができます。

バリデーション編

フォームなのでバリデーションは欠かせません。今回はvuelidateというVueのバリデーション用ライブラリを使いました。 monterail.github.io

HTML部の定義

        <md-field :class="getValidationClass('firstName')">
          <label for="first_name"></label>
          <md-input id="first_name" name="first_name" v-model="form.firstName" @input="first_phonetic" @keyup="first_phonetic" required :disabled="sending"></md-input>
          <span class="md-error" v-if="!$v.form.firstName.required">必須項目です</span>
        </md-field>

バリデーションでポイントになるのが、md-inputの下の<span>クラスです。
あとで、説明しますが、モデルの$vの下に、バリデーションの結果が入るので、そこをチェックして
falseの場合、バリデーションがエラーなので、エラーとして表示します。

モデル・スクリプト部の実装

  validations: {
    form: {
      lastName: {
        required
      },
      firstName: {
        required
      },
      firstNamePhonetic: {
        required
      },
      lastNamePhonetic: {
        required
      },
      presence: {
        required
      },
      contact: {
        email,
        required
      }
    }

まず、どのフォームのどの部品をバリデーションするかを定義します。
dataとかmethodsと並列で、validationsというモデルを定義すればOKです。

    validate () {
      this.$v.$touch()
      if (!this.$v.$invalid) {
        this.sending = true
        db.collection('presences').add(this.form).then(() => {
          this.userSaved = true
          this.sending = false
          this.clearForm()
        }).catch(() => {
          this.sending = false
        })
      }
    },

上記では、this.$v.$touch()ですべてのフォーム部品をユーザが触った状態にします。
(デフォルト値のままで、ユーザが触ってない部品があったりすると、その時点でバリデーションエラーになってしまうため)
そして、$v.$invalidでフォーム全体のバリデーションがOKかの値が入っているので、これをチェックすることでデータ送信可能か確認します。

テーマ色の設定

最後に、テーマ色が青色で超Googleっぽくて味気ないので別の色に変えておきましょう。
vue-materialのテーマ色をカスタマイズできるようにするには、まずscssを使えるようにする必要があります。

scssを使えるようにする設定
scssを使えるようにするには、webpackの設定を変更します。 build/webpack.base.conf.jsのmodule.rulesに以下を追加します。

  module: {
    rules: [
      // もともと書かれている設定は省略
      {
        test: /\.scss$/,
        use: [
          'vue-style-loader',
          'css-loader',
          'sass-loader'
       ]
    ]
  }

次にutilsで設定されているcssLoaderの設定を変更してscssをコメントアウトします。 build/utils.jsの以下の部分をコメントアウトします。 (ここに気づくのに結構時間がかかった...)

exports.cssLoaders = function (options) {
  //省略
  return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less'),
    sass: generateLoaders('sass', { indentedSyntax: true }),
    // ↓を省略する!
    // scss: generateLoaders('sass'),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
  }
}

テーマ設定用scssファイルの作成・インポート
こうすることでようやくscssをインポートできるようになります。
では、scssを作成してインポートしましょう。

src/assets/cssというディレクトリを作ってtheme.scssというファイルを以下の内容で作成しましょう

@import "~vue-material/dist/theme/engine"; // Import the theme engine

@include md-register-theme("default", (
  primary: md-get-palette-color(pink, A200), // The primary color of your application
  accent: md-get-palette-color(blue, A200) // The accent or secondary color
));

@import "~vue-material/dist/theme/all"; // Apply the theme

md-register-themeで、primaryやaccentの色を指定してます。
今回は、結婚式らしくメインの色はピンク色、アクセントで青を設定してます。

これをVue.js側で読み込めば完了です。
src/main.jsに以下のimport文を追加します 。

import './assets/css/theme.scss'

Github

github.com

その他

ここまでは実際のものの作り方でしたが、firebase-hostingをつかって実際に本番にデプロイもしたり、functionsを使って、入力された情報をcsvで吐き出したりしています。
このfirebase-hostingが鬼楽で、超絶よかったので、また別記事に纏めたいと思います〜

grep + sedコマンドでlogから華麗に時刻を抜き出す

問い合わせ調査でせっかくなんで、grep + sedでフフフーンと華麗にログ調査をしようとしたら華麗にハマったのでメモ。

やりたかったこと

hoge 2018-08-10 07:31:31 hage

↑単純にこいつから時刻を抜き出したかった。

試したコマンド

$ echo "hoge 2018-08-10 07:31:31 hage" | sed -e 's/^.+\([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\).+$/\1/'

結果

hoge 2018-08-10 07:31:31 hage

なんでや!!!ってずっとなってました。

原因

Linuxコマンドだと{}にも\をつけてエスケープする必要があるんですよねー。
というわけで正解は↓

$ echo "hoge 2018-08-10 07:31:31 hage" | sed -e 's/^.+\([0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\} [0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}\).+$/\1/'

結果

2018-08-10 07:31:31

ちなみに

hoge (2018-08-10 07:31:31) hage

こんな感じで()をマッチングさせたい場合は、\(や\)を利用します。
(一個目のスラッシュがLinuxコマンドとしてのエスケープ、二個目のスラッシュが正規表現としてのエスケープ。ややこしや)

$ echo "hoge 2018-08-10 07:31:31 hage" | sed -e 's/^.+\(\\([0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\} [0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}\\)\).+$/\1/'

参考サイト

qiita.com

Yahoo! Hack Day 10th Aniv. に参加してHack賞 受賞しました!!

12/9(土)-12/10(日)で開催されたYahoo! Hack Day 10th Aniv.に参加してきました!! そしてまさかのHack 賞 受賞!

ハッカソンは今まで何回も出場してきましたが、まともに賞をゲットできたのは
初めてで、ひっじょおううに嬉しいので本ブログに思い出を綴っていきます。

正直、当日も大変だったのですが、一番苦労したのがアイデア出し、 でした。
そこの部分をメインで書かせていただきます。
(気が向いたら技術編も書きます...)

つくったもの

電車でどこで降りるかを超音波通信で知れるWebアプリ、なるものを作りました。
題していすとりSonicです。 f:id:pco2699:20171213002216p:plain

内容は以下のプレゼンを見ていただくとわかりやすいかと思います。
https://youtu.be/1Nlm69tcuak?t=13539

これができた経緯

この作品ができた経緯を、チーム結成から振り返りたいと思います...笑

2ヶ月前 チーム結成

私を含めたメンバ全員、ジーズアカデミーというプログラミングスクールを10月に卒業し
その中のメンバで意気投合し、ハッカソンにでよう!、という話になりました。

ちなみに、ジーズアカデミーは最高なプログラミングスクールなので
みなさん、ぜひ入ってください。
いろんなバックグラウンドの人がいて、めっちゃ面白いです。 gsacademy.tokyo

1ヶ月前 アイデア出し・技術調査

初めてのHack Dayのため、みんなで前回のHack Dayの発表動画を穴が空くほど見ました。
どれも技術力・実装力がめちゃくちゃすごい作品ばっかりで
メンバ間でも「これ、いけんのか笑」的な感じでした。

www.youtube.com

それでも出るからには最優秀賞!ということで技術をベースにしてアイデア出しや技術調査をめっちゃしました。
ただ、まともなアイデアは出てこず、あっというまに1週間前になります...

1週間前 アイデア出し

企画会議で、最初は「ARKit出たからARアプリつくりたいよね〜」って感じで ARアプリを考えていました。
それで電車の降りる人がARでわかったらおもろい、というネタが出てきました。

その時のデザイナさんが書いてくれたイメージはこんな感じ↓ f:id:pco2699:20171213002805p:plain

5日前 技術調査・フィージビリティ調査

ただ、「電車AR」は一つ、問題があることがわかりました。
電車は移動しているからGPSの位置情報が使えない、ということです。
当たり前ですが...

知らない人と端末間通信をするときは

  • 位置情報
  • BLEビーコン

が主流。ですが

  • 位置情報→移動しているので☓
  • BLEビーコン→正確な場所わからない

ということで 、かなり積んだ感じとなってしまいチーム内の空気が重苦しくなりました...

4日前〜1日前 企画会議

ここから、ヤバイということになり仕事終了~終電まで、毎日 企画会議をすることに。

そんな時に自分がふと思い出したのが、このアプリ hacklog.jp

このアプリを見たときから超音波通信!とは思ってましたが
この超音波通信は、電車内の匿名通信に使えるのでは?とふと思いつきました。

ARは無理そうなので、超音波を意識したUIをデザイナに考えてもらい これで当日行くことになりました。

ただ、これって本当に電車をHackできてるわけじゃないよね?と納得できていないメンバもおり
なんとなくもやもやした状態でHack Dayを迎えることになります。

Hack Day 当日 1日目

前日のもやもやが続いており、ネーミングでそれが噴出しました。
自分が思いつきで SuperSonicニコニコ電車(超適当)でよくね!?と言ったら
デザイナの方がそのネーミングだとロゴが書けないとなり、提出期限の夜10時まで、ギリギリまで悩んでました。

ただ、自分はフロント実装担当だったので
途中からネーミング考えるのは放棄して実装に集中しました笑
そしたら「いすとりSonic」という名前で納得したようで、ネーミング決定と相成りました。

Hack Day 当日 2日目

やはりというかなんというか、他のプロダクトが凄すぎて
メンバと、「来年、もっと実装力をつけて頑張ろう」とプチ反省会を開くぐらいでした。

個人的に、凄いと思ったのは、

  • 最優秀賞の「とるだけ!ユーチューバー」
  • アプリだけでモノの重さが測れる「Weight Memo」
  • スマートスピーカーをハックした「スマートスピーカー2.0」などなど...

(ってかモノが出来ませんでした〜、って言ってるところが無いのも普通に凄いよなって思います。)

そんな中で、Hack賞を貰えたのは本当にありがたい話です。
これはひとえに、チームメンバが各々の度量を最大限に発揮した結果だと思ってますし
ホントチームメンバの方には、一生 頭が上がりません。

ただ、この受賞で慢心せず 新人賞をもらったと思って 来年以降のHack Dayは更にレベルアップして頑張っていきたいと思います!

GrovePiの実装を実機テストなしでできてしまうGrovePiエミュレータの使い方

言いたいこと

Groveってはんだ付けなしでセンサがつくれて便利…!
GrovePiってGroveセンサをRasPiに繋げられて更に便利..! でも、GrovePiをつかったプログラムを組むとき、わざわざ実機テストするのはめんどくさい…!
と思っていたら、こんな便利なGrovePiエミュレータがありました。
(GrovePi自体はNodeやJavaでも動きますが、本エミュレータPythonでしか動かないようです…!)

github.com

使い方

基本 Macでの使用を前提しています

GrovePiエミュレータをgitからもってくる

$ git clone https://github.com/joemarshall/grovepi-emulator.git

GrovePiエミュレータを立ち上げる

$ cd grovepi-emulator
$ python grovepiemu.py

そうするっとアッラー素敵なGUIが立ち上がります
f:id:pco2699:20170806195013p:plain

GrovePi用のPythonスクリプトの実行

Pythonスクリプトを以下の「Load…」部から指定すると
GUIで指定したセンサの値が入力されている前提で、エミュレータが動いてくれます。
f:id:pco2699:20170806195124p:plain

動かすスクリプトは以下の通り、GrovePiのライブラリをimportした 前提で実装すれば、エミュレータがよしなにやってくれるみたいです

import grovepi
import time

if __name__ == '__main__':
    while True:
        input = grovepi.analogRead(0)
        print(input)
        time.sleep(1)