19
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

pepperが撮影した写真をS3にuploadしてslackにUP

Last updated at Posted at 2015-10-23

やりたかったことと実際やったこと

pepperで撮影した画像をslackにUPしたかった。
しかし、botはfileuploadのAPIを叩けないっぽかったので、一回S3に画像をUPして、そのURLをattachmentsに指定するという形でやってみた。
slackAPIを触るのは初めてなので、もしかしたらもっとステキなやり方があるのかもしれない。

使ったもの

  • boto
  • slack_client
  • websocket

アプリのルートに「lib」ディレクトリを作成して、上記ファイルをインポートした。

ボックス内容

Take Pictureボックス

既存のボックスに少し手を入れるだけ
ここの処理はアルデバランアトリエさんの記事を参考にして(http://qiita.com/Atelier-Akihabara/items/833e49a079788af55afb)
アプリのルートに「html」ディレクトリを作成し、ダミーのimage.jpgを設置する。

class MyClass(GeneratedClass):
    def __init__(self):
        GeneratedClass.__init__(self, False)
        self.resolutionMap = {
            '160 x 120': 0,
            '320 x 240': 1,
            '640 x 480': 2,
            '1280 x 960': 3
        }
        self.cameraMap = {
            'Top': 0,
            'Bottom': 1
        }

        self.recordFolder = "/home/nao/recordings/cameras/"

    def onLoad(self):
        self.framemanager = ALProxy("ALFrameManager")
        self.bIsRunning = False
        try:
            self.photoCapture = ALProxy( "ALPhotoCapture" )
        except Exception as e:
            self.photoCapture = None
            self.logger.error(e)

    def onUnload(self):
        pass

    def onInput_onStart(self):
    	 # アプリのルート/html/に画像を保存したいのでディレクトリを指定
        import os
        self.recordFolder = os.path.join(self.framemanager.getBehaviorPath(self.behaviorId), "../html")

        if( self.bIsRunning ):
            return
        self.bIsRunning = True
        resolution = self.resolutionMap[self.getParameter("Resolution")]
        cameraID = self.cameraMap[self.getParameter("Camera")]
        fileName = self.getParameter("File Name")
        if self.photoCapture:
            self.photoCapture.setResolution(resolution)
            self.photoCapture.setCameraID(cameraID)
            self.photoCapture.setPictureFormat("jpg")
            self.photoCapture.takePicture( self.recordFolder, fileName )
        self.bIsRunning = False
        self.onStopped()

S3postボックス(pythonボックス)

新規pythonボックスを作成して、Access KeyとSecret Access Key用の新規変数を追加。(typeは文字列)
中途半端にここだけ変数にしたけど、bucketとかもここで変数にすると後々汎用性があっていいんじゃないかしら。

スクリーンショット 2015-10-22 10.46.51.png

するとこんな感じになるのでIAMで作ったS3アクセス用ユーザーのクレデンシャルを入力する。
スクリーンショット 2015-10-22 10.46.28.png

保存後にS3のURLを次のボックスにお伝えしたいので、onStoppedのTypeを文字列にしておく。
boxのonStoppedの出力端子(って呼び方でいいのかな)が青色になって文字列を出力できるようになる。パターン青、文字列です。
スクリーンショット 2015-10-22 10.58.21.png

class MyClass(GeneratedClass):
    def __init__(self):
        GeneratedClass.__init__(self)

    def onLoad(self):
        self.framemanager = ALProxy("ALFrameManager")
        self.folderName = None

    def onUnload(self):
        import sys
        if self.folderName and self.folderName in sys.path:
            sys.path.remove(self.folderName)
        self.folderName = None

    def onInput_onStart(self, p):
    	# アプリルート以下にlibディレクトリを作って入れる
        import sys, os, time
        self.folderName = os.path.join(
                    self.framemanager.getBehaviorPath(self.behaviorId), "../lib")
        if self.folderName not in sys.path:
            sys.path.append(self.folderName)
        for moduleName in os.listdir(self.folderName):
            if moduleName in sys.modules:
                self.logger.info("Loaded: %s, %s" % (moduleName, sys.modules[moduleName].__file__))
                reload(sys.modules[moduleName])

        rootdir = os.path.join(self.framemanager.getBehaviorPath(self.behaviorId), "../html")
        # 読み込むファイル名(take photoで撮影してアプリルートのhtml以下に保存したお写真)
        load_filename = "image.jpg"
        # 保存する際のファイル名は接頭語+時間にしておいた
        save_filename = "image_"+str(time.time())+".jpg"

        from boto.s3 import connection
        from boto.s3.key import Key

		# ボックスに追加した変数を取得する
        ACCESS_KEY_ID = self.getParameter("AccessKey")
        SECRET_ACCESS_KEY = self.getParameter("SecretAccessKey")
        BUCKET_NAME = "<使用するBUCKET>"

        conn = connection.S3Connection(ACCESS_KEY_ID, SECRET_ACCESS_KEY)
        bucket = conn.get_bucket(BUCKET_NAME)

        k = Key(bucket)
        k.key = save_filename
        k.set_contents_from_filename(rootdir + "/" + load_filename)
        
        # UPしたファイルがslackから閲覧できるように公開にしておく
        k.make_public()
        
        s3Url = k.generate_url(expires_in=0, query_auth=False)
        # 終了の通知を保存したS3ファイルのURLにする
        self.onStopped(s3Url)

    def onInput_onStop(self):
        self.onUnload() #it is recommended to reuse the clean-up as the box is stopped
        self.onStopped() #activate the output of the box

Slackボックス(pythonボックス)

slackボックスのonStartも文字列を受け取れるように変更しておく
スクリーンショット 2015-10-22 11.03.05.png

class MyClass(GeneratedClass):
    def __init__(self):
        GeneratedClass.__init__(self)

    def onLoad(self):
        self.framemanager = ALProxy("ALFrameManager")
        self.folderName = None

    def onUnload(self):
        import sys
        if self.folderName and self.folderName in sys.path:
            sys.path.remove(self.folderName)
        self.folderName = None

    def onInput_onStart(self, s3Url):
        import sys, os
        self.folderName = os.path.join(
                    self.framemanager.getBehaviorPath(self.behaviorId), "../lib")
        if self.folderName not in sys.path:
            sys.path.append(self.folderName)
        for moduleName in os.listdir(self.folderName):
            # モジュールのreload
            if moduleName in sys.modules:
                self.logger.info("Loaded: %s, %s" % (moduleName, sys.modules[moduleName].__file__))
                reload(sys.modules[moduleName])

        post_text = "pepperですよ〜"
        self.logger.info("Slack送信中!... File: %s" % s3Url)

        import json
        from slackclient import SlackClient

        token = "<slackのtoken>"
        channel = "<slackのチャンネル>"
        user = "<botのユーザー名>"
        sc = SlackClient(token)

        att = [{
            "color": "#36a64f",
            "title": "写真です",
            "title_link": s3Url,
            "text": "pepperから愛をこめて",
            "image_url": s3Url
        }]

        self.logger.info(sc.api_call("chat.postMessage", attachments=json.dumps(att), channel=channel, username=user, as_user=user, text=post_text))

        self.onStopped()

    def onInput_onStop(self):
        self.onUnload() #it is recommended to reuse the clean-up as the box is stopped
        self.onStopped() #activate the output of the box
        

最終的なchoregraphe画面

スクリーンショット 2015-10-21 18.51.49.png

という訳で無事にpepperで撮影した画像がS3にUPされ、UPした画像のURLを添付したslack postが実行された。

やってみて悩んだこと

実機テスト時のファイルのやりとり

ワークショップに参加した時にアルデバランアトリエのスタッフさんも「動画ファイルとかテストする時は大変です」と言っていたけど
全ファイルを例のlastUploadedChoregrapheBehaviorから削除→再度全ファイルUPという感じなので
ライブラリとか使っていると、たいへんに重たい。

デバッグ/ログ出力

self.logger.info() でバーチャルロボットはログを確認できたけど、pepper実機では全然出力されなかった。
重大なエラーの場合boxが赤くなってマウスオーバーするとエラーメッセージが見られたけど、そうでもない時はうんともすんとも言わないpepperをドキドキしながら見つめてはコードをチェックしていた。
アトリエのワークショップで、タブレットのログの出し方は教わったけど、他はどう出したらいいのかな〜。
バーチャルロボットと同じようにログを確認したい。

これからやりたいこと

  • 撮影時の盗撮感がすごいので改良したい。とりますよー!3,2,1!みたいな感じで撮影してもらいたい。シャッター音もあったほうがいいかな。
  • パッケージ化?というのか、あのタブレットからタップして起動できる形のアプリを作りたい。
19
16
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?