kintone から MQTTS に送信（Subscribe) し Raspberry Pi の遠隔制御結果を表示（Raspberry Pi 側の処理）

## 処理内容
・kintone で 命令を選択し、制御命令レコードを追加すると、MQTTS にコマンドを送信（Publish）します
・MQTTS からコマンドを受信 (Subscribe) した Raspberry Pi が、制御コマンドを受信し、命令の処理（計測・撮影）を行います。
・Raspberry Pi から API 経由で kintone のレコードにデータを PUT して更新します。
・kintone の詳細画面で計測・撮影結果が表示されます。(結果が戻るか、指定回数に到達するまでは ReLoad を繰り返す。)
kintone 側の処理結果は https://qiita.com/yukataoka/items/1c608e2fa2d994068458 を参照
## Raspberry Pi 事前準備
以下のパッケージ、ライブラリィをインストールしておきます。

```
$ sudo apt-get install libopencv-dev python-opencv  python-pip
$ sudo pip install poster AWSIoTPythonSDK
```
## Raspberry Pi 処理順
下のコードで紹介する kintoneCommand.py をバックグランドに常駐させるだけ

## Raspberry Pi コード
### MQTTSコマンドを受信 (Subscribe) 常駐プログラム
kintone から MQTTS 経由で届く制御指示を待つって、制御指示が届いたら該当する処理を実行します。

MQTTSやその処理の実装についての詳細は、以下を参照ください。

MQTTとは
https://kfep.jp/solution/iot-mqtt/mqtt

AWS IoTにPythonでMQTTイベントの送信、受信するまで
https://symfoware.blog.fc2.com/blog-entry-2224.html

AWSIoTPythonSDK
https://s3.amazonaws.com/aws-iot-device-sdk-python-docs/sphinx/html/index.html

```python:kintoneCommand.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient

from sht21              import SHT21
from TakePicture        import TakePicture
from PostFileForKintone import PostFileForKintone
from PostDataForKintone import PostDataForKintone

import sys
import logging
import time
import getopt
import json
import subprocess

# Custom MQTT message callback（制御指示を受信した時の処理）
def customCallback(client, userdata, message):

    print("Received a new message: " + message.payload)
    print("from topic: " + message.topic)
    print("--------------")
    
    jsonData = json.loads(message.payload)

    # 温湿度計測
    if(jsonData["command"] == u"温湿度取得" or jsonData["command"] == u"全て"):
        sht21 = SHT21(1)
        temp = str(round((sht21.read_temperature() * 1), 1))
        hum  = str(round((sht21.read_humidity() * 1), 1))
        
        record = {"temp":{"value":temp},"hum":{"value":hum}}
        posted = PostDataForKintone(jsonData["domain"], jsonData["appid"], jsonData["token"])
        posted.putToKintone(jsonData["key"], record)

    # USBカメラ撮影
    if(jsonData["command"] == u"即時撮影" or jsonData["command"] == u"全て"):
        picture = TakePicture('/home/pi/human/')
        path = picture.TakeForDateTimeName()
        postImage = PostFileForKintone(jsonData["domain"], jsonData["token"], path)
        data = json.loads(postImage.upload());
        fkey = str(data['fileKey']);

        record = {"picture":{"value":[{"fileKey":fkey}]}}
        posted = PostDataForKintone(jsonData["domain"], jsonData["appid"], jsonData["token"])
        posted.putToKintone(jsonData["key"], record)

        command  = "rm "+path
        subprocess.call(command, shell=True)

# Read in command-line parameters
useWebsocket = False
host = "HOST.iot.ap-northeast-1.amazonaws.com"
rootCAPath = "/home/pi/human/key/root-CA.crt"
certificatePath = "/home/pi/key/XXXXXXXXXXX-certificate.pem.crt"
privateKeyPath = "/home/pi/key/XXXXXXXXXXX-private.pem.key"

# Configure logging
logger = logging.getLogger("AWSIoTPythonSDK.core")  # Python 2
#logger.setLevel(logging.DEBUG)

streamHandler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
streamHandler.setFormatter(formatter)
logger.addHandler(streamHandler)

# Init AWSIoTMQTTClient
myAWSIoTMQTTClient = None
myAWSIoTMQTTClient = AWSIoTMQTTClient("RaspiZeroHumanPicture")
myAWSIoTMQTTClient.configureEndpoint(host, 8883)
myAWSIoTMQTTClient.configureCredentials(rootCAPath, privateKeyPath, certificatePath)

# AWSIoTMQTTClient connection configuration
myAWSIoTMQTTClient.configureAutoReconnectBackoffTime(1, 32, 20)
myAWSIoTMQTTClient.configureOfflinePublishQueueing(-1)  # Infinite offline Publish queueing
myAWSIoTMQTTClient.configureConnectDisconnectTimeout(10)  # 10 sec
myAWSIoTMQTTClient.configureMQTTOperationTimeout(5)  # 5 sec

# Connect and subscribe to AWS IoT
myAWSIoTMQTTClient.connect()
myAWSIoTMQTTClient.subscribe("command/picture", 1, customCallback)
time.sleep(2)

# Publish to the same topic in a loop forever
while True:
   time.sleep(1)
```
### I2C温湿度センサSH21用
sh21.py
https://github.com/jaques/sht21_python/blob/master/sht21.py より入手。
### USBカメラで撮影した画像をファイルに保管
Raspberry Pi に取り付けたUSBカメラで静止画を撮影し、ファイルに保管するプログラムです。

```python:TakePicture.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import time
import cv2

class TakePicture:

    def __init__(self, path = "./"):
        self.path = path

    def TakeForDateTimeName(self):
        capture  = cv2.VideoCapture(0)
        ret, frame = capture.read()
        path = self.path + time.strftime('%Y%m%d_%H%M%S.jpg')
        cv2.imwrite(path, frame)
        return path
    
    def Take(self, fileName='image.jpg'):
        capture  = cv2.VideoCapture(0)
        ret, frame = capture.read()
        path = self.path + fileName
        cv2.imwrite(path,frame)
        return path

if __name__ == "__main__":
    takePicture = TakePicture()
    print takePicture.TakeForDateTimeName()
    print takePicture.Take('picture.jpg')
```
### kintone に画像ファイルをアップロードする
kintone に画像ファイルを API でアップロードするプログラムです。

```python:PostFileForKintone.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
import urllib2
import json

class PostFileForKintone:

    def __init__(self, subdomain, token, file):
        self.subdomain = subdomain
        self.token = token
        self.file = file
        
    def upload(self):
        register_openers()
        with open(self.file, "rb") as fp:
            datagen, headers = multipart_encode({"file": fp})
            request = urllib2.Request("https://"+self.subdomain+".cybozu.com/k/v1/file.json", datagen, headers)
            request.add_header('X-Cybozu-API-Token', self.token)
            
            response = urllib2.urlopen(request)
            # print "---------- RESPONSE HEAD ----------"
            # print response.info()
            # print "---------- RESPONSE BODY ----------"
            return response.read()
```
### kintone のデータを更新する
kintone に制御結果を API 経由で更新するプログラムです。

```python:PostDataForKintone.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import httplib
import json
import time

class PostDataForKintone:

    def __init__(self, subdomain, appId, token):
        self.subdomain = subdomain
        self.appId = appId
        self.token = token
        
    def registToKintone(self, record):
        request = {"app":self.appId,"record":record}
        requestJson = json.dumps(request)
        headers = {"X-Cybozu-API-Token": self.token, "Content-Type" : "application/json"}
        connect = httplib.HTTPSConnection(self.subdomain + ".cybozu.com:443")
        connect.request("POST", "/k/v1/record.json", requestJson, headers)
        response = connect.getresponse()
        return response

    def putToKintone(self, id, record):
        request = {"app":self.appId,"id":id,"record":record}
        requestJson = json.dumps(request)
        headers = {"X-Cybozu-API-Token": self.token, "Content-Type" : "application/json"}
        connect = httplib.HTTPSConnection(self.subdomain + ".cybozu.com:443")
        connect.request("PUT", "/k/v1/record.json", requestJson, headers)
        response = connect.getresponse()
        return response
```