Google Home と Akerunで簡単スマートオフィス

CTOの@kazuphです(この記事は前年のアドベントカレンダーの居残りエントリーです(汗))。

Google Home、みなさん買いましたか?

僕という意味では会社で2台、家用に1台購入して遊んでいます。 HomeごとにGoogleのアカウントを分けて管理できるので、プライバシーも守られていていい感じです。

うちの会社では元々数台のChromeCastを使って遊んだり業務用に使っていましたが、 ここにGoogle Homeを加えたときにどうなるかやってみました。

やりたいこと

  • 手っ取り早くAkerunと連携したい
  • 受付に人が来たら音声で教えてほしい

ということでやってみましょう。

Akerun連携する

Akerunで開閉があったらGoogle Homeが教えてくれるようにしてみましょう。

今回は全部ができる一つのプログラムを書くのではなく、 一つのことをする複数のプログラムを掛け合わせてて作成します。

Akerunで投稿があったらSlackに通知する

方法はいくつかあります。

  • YahooさんのmyThingsを使う(プログラミングなし)
  • 公開版のAkerun 履歴 APIを使う
  • (中の人のみ)社内向けのAkerun APIを使う

myThingsさんの方法が簡単です。 ですが、こちらである程度制御したかったので、今回は社内向けのAPIでやってしまいましたのでソースは割愛(え)。

Slackの通知を見てGoogle Homeにテキスト送信

ここでは特定のSlackチャンネルの投稿があったらGoogle HomeAPIを叩くことを考えます。言わば中継役です。

今回はGASで実装してみました。

doPostで

  • Slackからのoutgoingのwebhookのmessageを受け取り
  • ローカルネットワーク内で立ち上がってるサーバーのngrok上でのURLの受け取り

をやっています。

テキストで受け取った場合は、それをそのまま後述するngrokで公開されているURLにポストします。ngrokのURLは起動時に毎回変わるので、今回はそのURLを中継役のGASにpostすることで、プログラムを書き換えなくても自動で連携するようにしています。

function doPost(e) {
  if ("AAAAAA..." === e.parameter.token) { 
    var text = e.parameter.text;
    text = text;
    return request(text);
  }
  if ("BBBBBB..." === e.parameter.token) {
    var url = e.parameter.url; 
     var sheet = getSheet("google home api");
    sheet.getRange(2,1,1,1).setValues([[url]]); // getRange(開始行、開始列、行数、列数)
    return "ok";
  }
} 

function request(text) {
  try {
   var sheet = getSheet("google home api");
   var url = sheet.getRange(2,1,1,1).getValues()[0][0] + '/google-home-notifier';
    var urlFetchOption = { 
        'method' : 'post',     
        'contentType' : 'application/x-www-form-urlencoded', 
        'payload' : { 'text' : text}  
    }; 
 
    var response = UrlFetchApp.fetch(url, urlFetchOption); 
    return response; 
  } catch (e) {
    var sheet = getSheet("gaslog");
    sheet.appendRow([e]);
  }
}

function getSheetApp() {
  return SpreadsheetApp.openById("<NGROKのURLを保存しているシートのID>");
}

function getSheet(name) {
  var sheetApp  = getSheetApp();
  var sheet     = sheetApp.getSheetByName(name);
  return sheet;
}

このGASのスクリプトスクリプトエディタの「公開>ウェブアプリケーションとして導入…」から公開しておきます。AAA...BBB...となっているトークンはそれぞれ、SlackのWebhookとGoogle Home側のネットワークに自前で立てたサーバーからのトークンを設定してください。

Google Homeでのテキストの受け取り

今回はGoogle Homeと同一のネットワークにいるラズパイにソースコードを置き作成しました。google-home-notifierとngrokが便利すぎますね。

var express = require('express');
var googlehome = require('google-home-notifier');
var ngrok = require('ngrok');
var bodyParser = require('body-parser');
var app = express();
const serverPort = 8091; // default port

var deviceName = 'Google Home';
var ip = 'XXX.XXX.XXX.XXX'; // default IP

googlehome.device(deviceName, 'ja').accent('ja').ip(ip); // 日本語で喋ってもらうために必要

var urlencodedParser = bodyParser.urlencoded({ extended: false });

app.post('/google-home-notifier', urlencodedParser, function (req, res) {

  if (!req.body) return res.sendStatus(400)
  console.log(req.body);

  var text = req.body.text;

  if (req.query.ip) {
     ip = req.query.ip;
  }

  var language = 'pl'; // default language code
  if (req.query.language) {
    language;
  }

  googlehome.ip(ip, language);

  if (text){
    try {
      googlehome.notify(text, function(notifyRes) {
        console.log(notifyRes);
        res.send(deviceName + ' will say: ' + text + '\n');
      });
    } catch(err) {
      console.log(err);
      res.sendStatus(500);
      res.send(err);
    }
  }else{
    res.send('Please GET "text=Hello Google Home"');
  }
})

app.listen(serverPort, function () {
  ngrok.connect(serverPort, function (err, url) {
    // GASにngrokのURLを通知する
    request.post('<GASの公開URL>', {form:{token:"BBBBBB...", url: "url"}})
  });
})

まとめ

駆け足でしたが、Google HomeとAkerunを連携する方法を紹介してみました。 実装上はSlackを経由する必要はない例でしたが、Slackにも通知した上でGoogle Homeにも喋って欲しいケースはあるかなと思いこちらの方法を採用しました。手順は多いですが、段階を踏むのでデバッグも便利です。

弊社ではKitayo...じゃなかった、receptionistを使っていて、Slackで受付情報をもらっているので、合わせて執務室内のGoogle Homeに音声で教えてもらうと便利なのかなと思っています(音声でそれを聞いた結果誰がどう受付対応するのかという話が別でありますが)。

ラズパイや不要なPCがあれば、任意のテキストを喋るGoogle Home APIを簡単につくれるので、色々な連携には便利なのかなと思いまいた。 皆様も是非やってみてください。

告知

弊社ではエンジニアを募集しています!

www.wantedly.com

僕が考えるサラリーマンエンジニアに必要な「設計力」

はじめに

こんばんは。Akerunエンジニア @ishturk です

今回はポエムです。

スタートアップで働くサラリーマンエンジニアがソフトウェア開発を実現するために大事だと思う技術について書いてみます。

うそっ 私の技術力、低すぎっ

f:id:photosynth-inc:20180108193938j:plain

(数年前に新卒で入社した頃の僕の話です)

新卒入社したてほやほやの僕は当然、技術ゼロでした。当然自信もへったくれもない。 技術力にあふれるエンジニアがいっぱい。

目をキラキラ(どちらかというとギラギラ)させていた僕は思いました。

「この人達はめちゃめちゃいろんなことを知っているんだろうな。たくさん勉強せねば」

ところがどっこい。入社して数ヶ月の僕は気づきました。

「あれ、(プログラム言語のことなら)知識そんなに変わんなくね?」

しかし、彼らには間違いなくプロダクトを完成させる力があります。僕には無理です。何が違うのでしょう。

製品を完成させるために必要なもの

製品、いわゆるプロダクトやサービスを完成させるには、知識だけでは足りないのです。

いろんな知識を掛け算した「技術」が必要なのです。

たとえば

アルゴリズムに詳しい人は「技術がある」か? 否。「知識がある」ですね。

などなど。

これらはすべて「知識」です。

知識を製品に変える技術 = 設計力

設計と一言にいってもいろいろありますが、僕の経験からは、 「どの知識」を採用して「どう組み合わせるか」を「最適化」したものを「アウトプット」するスキルだと思っています。

ここで「最適化」という言葉をあえて使っているのは理由があって、サラリーマンエンジニアなら、開発対象には必ずプロダクトコンセプトや、納期生存期間があります。

重要な部分は緻密に設計し、納期にミートする内容で設計し、生存期間の長いソフトウェア(またはその一部)の場合はメンテしやすい工夫をする。重要じゃない部分は工数最低限になるように設計する。これが設計力。

そして、「アウトプット」。

形はなんでもいいです。設計書でもUML図だけでもコードスケルトンでも。あ、ソースコードでもいいかな(ガソリン投下)

「アウトプット」がないとどれだけスバラシイ設計でも0点になってしまいます。(ただの妄想だもの)

そして、レベルアップするにはアウトプットを繰り返すことが非常に重要だと僕は感じています。

使う技術

設計するには当然「知識」が必要ですが、設計しているスコープのすべてを完璧に知るのは不可能ですよね。

社内(あるいは委託先)にその道のスペシャリストがいたらもう最高。ぽいっと丸投げしちゃいましょう。

OSSや、ロイヤリティを払ってライブラリを使用するのもいいでしょう。

丸投げできない場合は、有識者じゃなくていいので、複数のエンジニアで意見交換をしましょう。

周りをうまく使うのも大事な技術ですね。(リソース管理の話ではないです。)

重要なのは、無理して自分だけでやろうとしないこと。じっくり煮込んだクソコードが出来上がります。

実装力

「設計できていればその通り実装するだけでしょ」 そう言い放つマネージャー職もいますね。きっと現役時代はクソコードを量産してきたことでしょう。 今日は深く掘りませんが、以下に僕が意識しているキーワードを挙げておきます。

  • 「わかりやすく書く」(短く書くではない)
  • 「バグを潜ませないように書く」
  • 「あらゆるパターンに対応する」
  • 「適度に手を抜く」

自分の技術、確認してみませんか?

僕がいままで一緒に仕事をしてきたエンジニアでイケてる方々はほぼ例外なく、「アウトプット」が上手い人達でした。

なぜなら、「アウトプット」をすると「フィードバック」があるから。そこでブラッシュアップされ、知識が増える。

何度も「アウトプット」をすることでみせ方もうまくなる。

「アウトプット」とあわせて、「レビュー」することは、クオリティをあげる目的だけでなく、技術レベルをあげるのにも非常に有効です。

僕らはスタートアップです

僕は、新卒で入社した大手企業を退職し、現在はスタートアップでエンジニアをやってます。

駆け出しのスタートアップの場合、同じレイヤーのエンジニアが社内にいることは稀でしょう。

それでも(だからこそ)設計レビュー・コードレビューは重視したいと思ってます。毎回、新しい発見があり、

誰かに説明するだけで自身で気づくことも多いです。人間だもの。

ひとりで全部やる時代は終わっています。

社内外のエンジニアと、どうコミュニケーションしていくかでエンジニアライフも、大きく変わると感じています。

告知

弊社ではエンジニアを募集しています!

www.wantedly.com

gitbookで設計書を作成したら最高だった話

こんにちは。Akerunエンジニアの @ishturk です。

Akerun Advent Calendarの記事です。

今日は設計書の話です。

設計書をどんなツールで書くかは、僕らソフトウェアエンジニアの尽きない悩み(楽しみ)ですね。

最近はまったツールが最高に良かったので紹介させてください。

僕のツールに求める要件は以下です。

  • 編集がカジュアルにできる
  • UMLが書ける。あとから編集できる(画像での貼付けは編集できないのでNG)
  • バージョンの管理ができる
  • 好きになれる(重要)

変遷と pros/cons

MS Word

pros

良くも悪くもスタンダードなツールですね。

だれでも編集できるのが強みです。

Visioと組み合わせれば、UMLも後から編集可能です

cons

Visioは標準にするには少々値が張ります。

バイナリ形式なのでバージョン管理はしづらいです。

ページが増えたり画像を貼ったりすると重くなって詰みます。

sphinx

pros

テキストベースなのでバージョン管理しやすいです

マークダウンで書けるのもいいです

色々な記法が用意されているので、巨大な設計書も頑張ればスマートに書けます

plantumlとの親和性が高いです

ちゃんとメンテされている

cons

(主観ですが)カジュアルさがちょっと足りない感じ(ごめんなさい)

Google Docs

pros

Wordライクに編集できるので学習コストが低いです

UMLを扱うにはplantuml gizmoプラグインがgoodです

クラウドなので同時編集ができるのもいいです

バージョン管理は独自機能で(一応)できます

cons

外部サービスなのでそもそも許可してもらえないことが多いですね

こちらも、ページが増えたり画像を貼ったりすると重くなって詰みます

gitbook

pros

テキストベースなのでバージョン管理しやすいです

マークダウンで書けます

plantumlとの親和性が高いです。他のpluginも豊富です

gitとの親和性が高い(gitbookだし)のもいいです

カジュアルさがちょうどいい。僕的にはココがツボ

cons

今のところ不満がないです

gitbook 導入

gitbook とは

  • Markdown で書かれたドキュメントをツリー形式のhtml文書に変換するツールセット
  • ビルド、サーバー機能を持つ
  • ツリーの作り方がシンプル (対 sphinx
  • プラグインに対応
  • node で動く

導入

nvm + node をいれる

node のバージョンは v5.12 推奨(v6系でも動くらしい)

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash
nvm install v5.12
nvm use v5.12

gitbook 導入

npm でinstall します。 npm自体のinstallは省略

npm install -g gitbook-cli

ドキュメントのビルド

tree 構造

.
├── README.md
├── SUMMARY.md
├── book.json
├── docs
└── node_modules
  • README.md : トップページになります。
  • SUMMARY.md : ドキュメントツリーを記載するファイル
  • book.json : 設定ファイル。pluginもココに書く
  • docs : ユーザーファイルを追加するディレクトリ(SUMMARY.mdで自由に決めてね)
  • node_modules : nodeですから

README.md を設定しておくと、githubでみても、READMEとして表示されるので、一元管理できるのもいいです。

ビルド

ディレクトリのルートでビルドします。デフォルトはhtmlです。pdfとかも吐けます。

gitbook build

ファイルの追加

この例では、docs/下に文書を作成、配置します。

SUMMARY.md の例。ネストできます。

1 # SUMMARY
2
3 * [概要設計](docs/README.md)
4   * [ほげらの章](docs/hogera.md)

plugin の追加

plugin の導入自体はnpmで。(ちゃんとやるならbuildした時に不足しているpluginをinstallするようにしてね)

たとえばplantumlだと、

npm install gitbook-plugin-uml

導入したら使用するpluginを、book.json に記載します

 1 {
 2     "plugins": ["uml","-search"],
 3     "pluginsConfig": {
 4         "uml": {
 5             "format": "svg",
 6             "charset" : "UTF-8",
 7             "nailgun": false
 8         }
 9     }
10 }

ドキュメントの配信

ローカルので実行

gitbook serve

とすると、webサーバーになってブラウザで閲覧できるようになります

デモ

f:id:photosynth-inc:20171226105330g:plain

Jenkins + git (github) webhook

gitのコミットでwebhookを引っ掛けてファイルを取得すればドキュメントの自動更新を設定できます。

Jenkinsが導入されているサーバーにgitbookも導入してあげれば、簡単に設定できますね。

gitbookのserver機能を使えば、自前のwebサーバーも不要です。

簡単にチームで設計書を共有できて、最高でした。

おわりに

また新しいものが出たらいろいろ試したいですが、しばらくはgitbookでイイ気がしてます。

告知

弊社ではエンジニアを募集しています!

www.wantedly.com

大人がAkerunでIoT鬼ごっこしてみたら最高に楽しかった

Akerun Advent Calendar21日目の記事です。

※ 本記事は Photosynthエンジニアが主催しているイベント記事です。Akerunを本来の目的以外に使用しないでください。

今回はフォトシンス社員有志で、オトナのガチ鬼ごっこをやってきた報告です。

ところで、フォトシンスはIoTサービスを提供している最先端の会社です。

したがって普通の鬼ごっこで満足できるはずがありません。

鬼ごっこもIoTじゃないとね。ええ。

というわけで

Akerun で 鬼ごっこしてみた

f:id:photosynth-inc:20171224230320j:plain

今回の戦場はこちら

SWEET GLASS @北軽井沢

f:id:photosynth-inc:20171224230842j:plain

f:id:photosynth-inc:20171224231058p:plain

参加者登録

Akerunには、写真と名前を設定する機能があります。

f:id:photosynth-inc:20171224231218j:plain

この機能を使って参加者を登録してみましょう。

参加してくれた猛者たち。

f:id:photosynth-inc:20171225090740p:plain

ルール

  • 鬼は逃げまどう人々のAkerunをアプリであけて捕獲ください
  • 捕獲したらSlackで通知が飛びます
  • 捕獲されたら鬼に変わります。10秒間その場でフリーズして再開してください
  • 15分経過で鬼だった人が負けです

ルール説明です。真面目に聞いてます。

若干ろくろを回しているのがゲームマスターのぼくです。

f:id:photosynth-inc:20171224232138j:plain

やってみた

鬼はスマホ片手に追いかけてます。

f:id:photosynth-inc:20171225151947p:plain

BLEで捕まえるのでこんな光景も。

f:id:photosynth-inc:20171225152022p:plain

捕まったらslackで通知が飛びます。IoTです。ゲームマスターは走らなくても誰が鬼なのか監視できますね。楽でいいですね。

f:id:photosynth-inc:20171224232850p:plain

f:id:photosynth-inc:20171224232741p:plain

やってみた考察

  • 楽しい
  • 走っているとBLEでなかなか接続できない。これは想定外でした。Central、Peripheral双方が移動していることで、掴みが悪くなっていそうです。
  • 大人がAkerunとスマホをもって鬼ごっこをしていると、こどもたちが興味津々にみてくる(が声はかけられない
  • 大人がAkerunとスマホをもって鬼ごっこをしていると、若者たちも興味津々にみてくる(が声はかけられない
  • 楽しい

事件発生

疲れ果ててコテージに向かっていた参加者たちですが、

「あれ、、、鍵がない。。。」

なんと、はしゃいでいるうちに鍵を落としてしまったようです。(実話)

f:id:photosynth-inc:20171224234000p:plain

今回は幸いすぐにみつかりました。

ですが、物理鍵ってこわいですね。

スマホで鍵をあけられたらいいのに。

後付で設置できたらいいのに。

ん? そんなIoT製品あったような?(ステマ

Akerun設置してみた

f:id:photosynth-inc:20171224233714j:plain

f:id:photosynth-inc:20171224233831j:plain

ばっちり設置できました。もちろん原状回復できます。外出時の鍵の受け渡しも不要になりました。最高か。(ステマ

おわりに

軽井沢でもAkerunがばっちり使えることがわかりましたね。また、IoTのエンターテインメント的な可能性を感じました。

あと、SWEET GLASS さんはとっても快適に楽しめたのでぜひ皆様遊びに行ってください。

告知

弊社ではエンジニアを募集しています!

www.wantedly.com

Akerunをクリスマス仕様にする(前編)デザイナーとの懸け橋ツールで捗った話

こちらは Akerun Advent Calendar 2017の記事です。

聖なる夜にこんばんは。 yuyakmです。

クリスマスということで、日々接するAkerun Proをクリスマス仕様にしてみたいと思います。

今回は、クリスマスといえばイルミネーションといういことで、LEDパターンを変えてみたいと思います!

製品の点灯パターンについてはこちらの動画をご覧ください。

youtu.be

Akerun ProのLED仕様

①フルカラーのLEDを4灯搭載

左上                   右上
LED1(R, G, B)         LED4(R, G, B)

左下                   右下
LED2(R, G, B)         LED3(R, G, B)

②各 RGBは8bit(0-255)の幅で明るさを設定することができる

ディスプレイのように任意の色を表現することができます。

スペック上は、256 * 256 * 256 = 16,777,216通りの色が表現できます。

③4灯のLEDの色を個別に更新できる

例えば、20msecおきに色を更新することでリフレッシュレートが50Hzのディスプレイのようにふわっと点灯させたり色をじわーっと変える表現ができます。

点灯パターンを考える

今回は、3つの点灯パターンをこんな感じに変更してみたいと思います。

1. 接続時

→赤・緑のクリスマスカラーでふわっと点灯

2. 施錠時

→赤・黄のイルミネーション風点滅をした後に、サンタ帽イメージカラー(赤・白)で点灯して消える

3. 解錠時

→緑・黄のイルミネーション風点滅をした後に、もみの木イメージカラー(緑・白)で点灯して消える

点灯パターンをつくってみる

@ishturk さんが便利なツールをつくってくれているのでそれを使ってつくります。 タイトな開発スケジュールの中、こういう社内連携用の機能もサクッとつくって提案してくれてホント最高。 f:id:photosynth-inc:20171224220613j:plain

点灯パターン検討の流れ

1. スプレッドシートでデータ作成

自動的にPro用データに変換してくれる!

2. 作成されたPro用データを専用Proに流し込む

確認&調整がエンジニアなしでできる!

3. 完成したら@ishturkさんにOTAイメージをつくってもらって実機で運用

いつも近くにいて一瞬でやってもらえるのもありがたい…

作成データ例

こんな感じでセルに値を入れるだけでできます。

リフレッシュのインターバル時間も入力できるので表現の幅が広がる~ f:id:photosynth-inc:20171224220619j:plain

点灯させてみた

こんな感じになりました

youtu.be

けっこうクリスマスっぽい!雪が積もったもみの木(解錠)とサンタ帽(施錠)に見えないこともない。

色の変化のスピードや微妙なグラデーション変化を何度かトライして改善しました。

また、今回の試行錯誤で24Hz(fps)以下にすると映像と一緒で明確にカクカク感を感じることを実感。

社内向けに適当に作った割には良いのではないでしょうか。

ただし施錠パターンについては、最初はサンタ帽に見えたけど今はモンスターボールにしか見えない…

製品でLED点灯パターンを考える上でのTIPS

今回はネタ記事ですが、TIPS的なことをざっくり紹介します。

そもそもLEDに頼りすぎない

LEDのインジケーターで表示できる情報量には限りがあるので、できるだけシンプルな方が良いです。 アクセシビリティの観点で、色がわからない・光が見えない人でも使えることを考慮しましょう。

微妙な色の違いはユーザーは気づかない前提で考える

例えば、赤と朱色で意味が違うことに気づいてもらうのは難しいです。色にメッセージ性を持たせたい場合は、明確に色が違うと感じるレベルで色を変えると良いです。

色のパターン例

LEDで色に意味を持たせる場合の色の選び方を紹介します。例えば、電話で使い方を説明する場合に言葉で説明しても認識がずれにくいと思います。

<基本>
  • ◯赤(R:100%, G:0%, B:0%)
  • ◯緑(R:0%, G:100%, B:0%)
  • ◯青(R:0%, G:0%, B:100%)
  • ◯黃(R:100%, G:100%, B:0%)
  • △紫(R:100%, G:0%, B:100%)(赤紫や青紫に偏ることがあるので避けた方が無難かも)

これをベースにしてデザイナーの意図する色に微調整すると良いのではないでしょうか。

<NG>
  • ✕白(R:100%, G:100%, B:100%)

→RGBのそれぞれを100%で点灯しても人間の視覚上白に見えるバランスで点灯するとは限らないため 環境光の色温度等によっても影響を受ける(青白く見えたりオレンジ色に見える)ため

  • ✕シアン(R:0%, G:100%, B:100%)

→青と混同されるおそれがあるため

※勿論、グラデーションの表現をしたり微妙な色味を調整するのはOKです

モニタのRGBとLEDの色は違うと認識する

RGBの値が同じなら同じ色になるわけではありません。AkerunProでは実機の発色を見ながら調整しました。

個体差による色のバラつきがあることを認識する

モノなので多かれ少なかれ色のバラつきは生まれます。細かいことを言うと、同じ基板上の4灯のLEDも全く色や明るさで光ることはできません。仕様の時点で色のバラつきの許容度は大きい方が良く、色を管理したい場合は別途検査やキャリブレーションの方法を考えましょう。

少しでも電池持ちを良くするために

*  点灯時間をできるだけ短くする
*  必要最低限の明るさにする
*  消費電力が大きい色は長時間点灯させない

白(255, 255, 255)>黄(255, 255, 0)>青(0, 0, 255)>赤(255, 0, 0)の順番で消費電力が大きい。

まとめ

  • デザイナーとエンジニアの架け橋となるツールをつくることで生産性アップ
  • エンジニアなしで気軽にトライできる環境があることで生まれるものがある

次回は筐体の装飾的にクリスマス感を上げた記事を紹介したいと思います。

求人

フォトシンスでは、他レイヤーと協力しながら一緒にものづくりができるエンジニアを募集しています! www.wantedly.com

google spread sheetでRedmineのチケットを操作してみる

こんにちは。Akerunエンジニアの @ishturk です。

Akerun Advent Calendar17日目の記事です。遅刻です。

弊社ではプロジェクト管理にRedmineを活用しています。

ありますよね?

さて、

チケットの内容をspreadsheetで表示したいと思ったことありませんか?

チケットをspreadsheetから発行したいと思ったことありませんか?

ありますよね?ありまくりますよね?

二重管理になるじゃん、、、と思ったアナタ!Redmineをマスターデータとしていれば二重管理は防げるのです!

たとえばこんな機能

  • チケット番号を入力して、タイトル、内容、担当者が表示する
  • spreadsheetに内容を入力したら「チケット発行」ボタンでチケット発行できる

これは捗りますね!

それ、API + GASでできます

実はRedmineにはREST APIが用意されており、チケットの参照・発行・編集など色々な事ができます。

REST API — Redmine用語解説

google spreadsheetには google apps script(GAS)と連携できます。

developers.google.com

Redmineの設定

上に貼ったリンクにも書いていますが、REST API を使用するにはRedmineのシステム管理者権限で有効にする必要があるので、管理者にお願いをしてください。有効にさえしてもらえば、使うのは一般ユーザーで大丈夫です。

「アクセスキー」が表示されてない場合は、無効になっている可能性が高いです。

チケットを参照するGASを書いてみる

番号からチケットタイトルを取得する

function ticket_name(id){
  var url = "https://redmineのURL/issues/" + id + ".json?key=個人のアクセスキー";
  // basic認証をかけている場合はヘッダに認証情報を入れる
  var user = "ユーザー名";
  var pass = "パスワード";
  var options = {
    "headers" : {"Authorization" : " Basic " + Utilities.base64Encode(user + ":" + pass)}
  };
  var response = UrlFetchApp.fetch(url, options);
  var results = JSON.parse(response.getContentText()); //レスポンスをjson解析してresultsを取り出す
  return results.issue.subject
}

ベーシック認証をかけている場合はヘッダに認証情報を付与します。(自分は素人なのでココでハマりました) アクセスキーを使うので、Redmine自体のユーザーid/passwordは不要です。 取得できる内容は以下を参照してくださいね。

www.redmine.org

チケットを作成する

function createIssue() {
  var redmine_url = 'https://RedmineのURL/issues.json';
  var project_id = プロジェクトのid
  var owner = チケット発行者のid
  var issue = {
    'subject': 'タイトル',
    'description': '説明',
    'tracker_id': トラッカーid
    'assigned_to_id': アサインするユーザーのid,
    'status_id': 7,  セットするステータスのid
  }
  var payload = {
    'issue': issue, 
    'project_id': project_id,
  };
  payload = JSON.stringify(payload);
  var user = "ユーザー名";
  var pass = "パスワード";
  var headers = {
    "Authorization" : " Basic " + Utilities.base64Encode(user + ":" + pass),
    'X-Redmine-API-Key': 個人のアクセスキー,
    'X-Redmine-Switch-User': owner,
    'Content-Type': 'application/json',
  };
  var options = {
    'method': 'POST',
    'headers': headers,
    'payload': payload,
    'contentType': 'application/json',
    'muteHttpExceptions': true
  };
  var response = UrlFetchApp.fetch(redmine_url, options);
  return response;
}

issue変数でチケットの諸々の値を設定しています。この辺の値をセルから取得するようにすれば、任意の内容でチケット発行ができますね。もちろん、カスタムフィールドも設定可能です。

実際に運用しているとチケットオーナーを 指定したいことが多々あるので、指定できるようにしています。この方法もちょっとハマりました。

また、プロジェクトのid、トラッカーのid、ユーザーのidなど、数値で指定しなくてはなりません。 調べる方法はいろいろあるので、またどこかでまとめたいと思います(本記事では割愛します)

チケット参照してみた

f:id:photosynth-inc:20171224203746g:plain

こんな感じでサクサク動きます。 捗りますね。

おわりに

RedmineREST APIや、GASなど、非webエンジニアでも気軽に触れる環境が増えて、とても楽しい今日このごろです。

プロマネも、この辺りのエンジニアリングできると楽しくなるんじゃないでしょうか。躓いたときにwebエンジニアに相談すると会話もはずんでますますプロジェクトが捗りますね。

告知

弊社ではエンジニアを募集しています!

www.wantedly.com

腰に優しいIoTテスト 〜 Akerunつくったエンジニアのそこそこ大規模なIoTプログラミング 〜

こんにちは。Akerunエンジニアの @ishturk です。

Akerun Advent Calendar13日目の記事です。

弊社フォトシンスは、ご存知のようにAkerunProKitというIoTサービスを提供しています。

昨年はラズパイを使った腰に優しい開発方法を紹介しました。

akerun.hateblo.jp

今回はさらに踏み込んで自動テストまで組み込んだ話です。

構成

  • akerun web APIs
  • AkerunProの動作ログをモニタリングする治具
  • ラズパイ
    • Logger
    • テストランナー

f:id:photosynth-inc:20171222175050p:plain

akerun web APIをコールするとAkerun Remote を経由して、指示がAkerun Proに到達して処理を実行します。 Loggerは起動後テキストでファイルに吐き出し続ける構成にしています。 テストランナーでAPIをコールし、Logに期待する結果するまで待つという構成です。 テストランナーはGoを使って書いてみました。

コード

package main

import (
    "fmt"
    "strings"
    "os/exec"
    "strconv"
     "encoding/json"
     "io/ioutil"
     "log"
     "net/http"
     "net/url"
)

func isWait(current int) bool {
    cmdstr := "wc -l autotest_log.log | cut -d \" \" -f 1"
    out, err := exec.Command("sh", "-c", cmdstr).Output()
    _ = err;
    s := string(out)
    s = strings.TrimRight(s, "\n")
    filelen, err := strconv.Atoi(s)
    if (current > filelen) {
        return true
    } else {
        return false
    }
}

func callAPI() {
     values := url.Values{}
     values.Add("param", "hogehoge")
     client := &http.Client{}
     req, err := http.NewRequest("POST", "https://あけるんAPI/hoge/hogera", nil)
     if err != nil {
          log.Fatal(err)
     }
     req.Header.Add("Authorization", "Bearer hogehogehogehogehogehogehogehogehogehogehogehogehogehogehoge")
     req.URL.RawQuery = values.Encode()
     res, err := client.Do(req)
     if err != nil {
          log.Fatal(err)
     }
     defer res.Body.Close()
     if res.StatusCode != http.StatusOK {
          log.Fatal(res)
     }
     body, err := ioutil.ReadAll(res.Body)
     if err != nil {
          log.Fatal(err)
     }
}

func isContain(line int, interval int, str string) bool {
    cmdstr := "sed " + strconv.Itoa(line) + "," + strconv.Itoa(line + interval) + "p autotest_log.log"
    out, err := exec.Command("sh", "-c", cmdstr).Output()
    _ = err;
    if (strings.Contains(string(out), str)) {
        return true
    } else {
        return false
    }
}

func main() {
    line := 0
    interval := 20
    timeout := 6000
    count := 0
    for count < timeout {
        if (isWait(line)) {
            continue
        }
        if (isContain(line, interval, "期待するログ")) {
            break;
        }
        count++
        line += interval
    }
    if (cout < timeout) {
        fmt.Println("PASS")
    else {
        fmt.Println("FAIL")
    }
}

APIは認証ヘッダ、パラメータ付与などしてPOSTしてます。もちろんいろいろできます。ggったらいろいろできるのでお試しあれ。 また、ログファイルの監視は sed コマンドを使って順番にキャプチャする方法で実現しました。無理してます。もっといい方法がある気がします。

おわりに

今回は APIを使ってE2Eテストを書いています。APIさえあればいろんなテストバリエーションを自動化できるのでいいですね。 エンジニアが拘束される作業時間が短くなるのでとても腰に優しいです。

また、Goは初めてコードを書いたのですが、とても書きやすいですね。組み込み畑のエンジニアがAPIをカジュアルに叩きたい場合は、オススメです。

告知

弊社ではエンジニアを募集しています!

www.wantedly.com