Raspberry PiのデータをGCPに送ってみた（無料）

# Raspberry PiのデータをGCPに送ってみた（無料）
Raspberry PiのデータをMySQLに格納し、Web上で確認できる仕組みを作りたかった。
VPSにサーバーを立てて、データのやり取りをしたい人向け。

※本記事は、Rasberry Pi上で気温データを取得し、送信することを目的としています。

### 開発環境
- Windows10 Pro
- Powershell
- Windows Subsystem for Linux(Ubuntu)

## GCPについて
Google Cloud Platformの略称で、Googleが提供しているクラウドコンピューティングサービスである。
>https://cloud.google.com/?hl=ja

GCPの始め方はこちらを参考に
>https://cloud.google.com/gcp/getting-started/?hl=ja

## Windows Subsystem for Linux(WSL)について
- Ubuntu(バージョン明記なし)をMicrosoft Storeからインストール
    - どうやら自動的に最新版になるらしい
- ホームディレクトリは`/home/[作成ユーザー名]/`になっている
    - Powershellは`/mnt/c/Users/[ユーザー名]/`
- `/mnt/c/Users/[ユーザー名]/`にcdコマンドで移動して作業開始

## Webサーバを立てる
- GCPプロジェクトの作成
- 好きなOSのVMを立てる（筆者は、Ubuntu 18.04 LTS）

※無償枠で作成する場合はこちらを参考に作成してください。
>https://cloud.google.com/free/docs/gcp-free-tier?hl=ja

- SSH認証を行う（Windowsからアクセスする用）

※補足：公開鍵をscpで送りたい場合

```
scp ~/.ssh/[公開鍵] [ユーザー名]@[転送先サーバのIP]:~/.ssh/
```

- apache2のインストール

```
sudo apt-get update
sudo apt-get install apache2 -y
curl http://[外部IP]
```

※外部IPはGoogle Cloud Platform -> Computer Engine -> VMインスタンス

- ファイアーフォールの設定 （ufwのインストールと設定）

```
#有効化
sudo ufw enable
#使っているTCP/UDPポートを調べる
sudo ufw status
#nmapでも可能
sudo nmap -sTU localhost
#ポートの解放（ルールの登録）
sudo ufw allow [許可したいポート番号]
#ルールの削除
sudo ufw status numbered
sudo ufw delete [number]
#無効化
sudo ufw disable
```

## DBの構築(MySQL)

```
sudo apt install mysql-server mysql-client
#サービスの起動確認
sudo service mysql status
#MySQLの初期設定
sudo mysql_secure_installation
#コンソールからMySQLサーバへ接続
sudo mysql -u root -p
```

- MySQLのユーザー情報の確認等

```
#状態表示
mysql> status
#データベース一覧表示
mysql> show database;
#ユーザー一覧表示
mysql> select user, host from mysql.user;
#特定ユーザの権限確認（ex) ユーザー：root, ホスト名：localhost）
mysql> show grants for 'root'@'localhost';
#終了
mysql> exit
```
>https://www.yokoweb.net/2018/05/13/ubuntu-18_04-server-mysql/

- 実際に構築をする
    - 今回は、取得時間と気温データの2つのフィールドを作成する

```
sudo mysql
#データベースの作成
mysql> create database [db_name]
mysql> show databases;
#データベースの移動
mysql> use [db_name]
#テーブルの作成（シングルコートいらない）
mysql> create table [tbl_name] ( id int(11) NOT NULL AUTO_INCREMENT, 
    -> ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    -> temp float NOT NULL,
    -> PRIMARY KEY(id)) ENGINE=MyISAM
#確認
mysql> show tables from [db_name];
mysql> show columns from [tbl_name];
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type      | Null | Key | Default           | Extra                       |
+-------+-----------+------+-----+-------------------+-----------------------------+
| id    | int(11)   | NO   | PRI | NULL              | auto_increment              |
| ts    | timestamp | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| temp  | float     | NO   |     | NULL              |                             |
+-------+-----------+------+-----+-------------------+-----------------------------+
3 rows in set
```
※トランザクション処理は行わないので、MyISAM。上記コードは温度データのみ格納用。
>http://zetcode.com/databases/mysqltutorial/storageengines/

- 外部から直接MySQLにアクセスするやり方もあるらしいです
    - https://qiita.com/yoshiokaCB/items/df4ae185be7cbc4f03ac

## プログラムの作成
### PHPの環境設定
- PHPをインストール

```
#最新版でなければこれでOK（最新はver7.3、aptの場合ver7.2）
sudo apt install php
```
- ドキュメントルート（apacheがブラウザに送信するHTML）は`/var/www/html/`
- パーミッションを変更
- PHPの動作確認はphpinfoで可能

```php
<?php phpinfo(); ?>
```

### PHPからDB(MySQL)へのアクセス確認
- PHP Data Objects(PDO)　※今回はPDOを使用
    - PHPからデータベースのアクセスを抽象的にやってくれる
- mysqli
    - MySQL改良版拡張モジュール

```php

<?php
try{
// PDOクラスのオブジェクトを作成
$pdo = new PDO('mysql:host=localhost;dbname=[db_name];charset=utf8', '[ユーザー名]', '[パスワード]', array(PDO::ATTR_EMULATE_PREPARES => false));
}catch(PDOException $e){
exit('データベース接続失敗。'.$e->getMessage());
}
// DB処理
switch ($_SERVER['REQUEST_METHOD']) {
    case 'GET':
        $st = $pdo->query("select * from [テーブル名]");
        echo json_encode($st->fetchAll(PDO::FETCH_ASSOC));
        break;

    case 'POST':
        $data = json_decode(file_get_contents('php://input'), true);
        $st = $pdo->prepare("insert into [テーブル名](ts, temp) values (:datetime,:temp)");
        $st->execute($data);
        header('Content-Type: application/json');
        echo json_encode("end");
        break;
}
?>
```
### Raspberry PiからPHPへのデータ送信処理(Python)

```python
# coding: utf-8
import requests
import json
from datetime import datetime

def main():

    url = 'http://[外部IP]/[プログラム名].php'
    #気温取得の処理
    ...
    temp = #値

    data = {'datetime':datetime.now().strftime("%Y/%m/%d %H:%M:%S"),'temp':temp}
    #JSON形式にdataをエンコード
    print(json.dumps(data))
    #JSON形式でPOSTリクエストを送信する(json形式のレスポンスが欲しいため、Content-type指定)
    response = requests.post(url, json.dumps(data), headers={'Content-type': 'application/json'})    #正しく返された場合にresponseに値が入る
    print(response.json())
    pass

if __name__ == '__main__':
    main()
``` 


センサーデータをうまく利活用し、クラウドとの連携をしていきたい…