冬の朝をもっと快適に！GCP×Nature Remoで実現するエアコン自動化プロジェクト

## 1.はじめに
こんにちは。毎日寒い日が続きますね。私は寒さにめっぽう弱く、冬の朝は布団から抜け出すのが本当に大変です。そこで今回は、私が起きる数分前にエアコン（暖房）を自動でONにして、快適な朝を迎える仕組みを作るプロジェクトを立てました。これが実現すれば、布団から出るストレスがぐっと減り、気持ちよく1日をスタートできるはずです。

このプロジェクトでは、スマートリモコン「**Nature Remo**」、Google Cloud Platform（GCP）の「**Cloud Run**」と「**Cloud Scheduler**」を活用します。「あれ？Nature Remoのアプリだけで、スケジュール設定してエアコンをONにできるんじゃない？」と思った方もいるでしょう。その通りです。実際、Nature Remoの公式アプリだけでも時間指定のスケジュール実行は可能です。

では、なぜあえて回り道をするのか？それは、**Cloud Run**と **Cloud Scheduler**を学び、実践するためです。このプロジェクトでは、単にエアコンの自動ON機能を作るだけでなく、クラウドに関する知識を深め、将来的に他の分野への応用の可能性を広げることも目的としています。これらの技術を活用すれば、エアコン以外の家電や、別のシステムにも同様の仕組みを応用できるかもしれません。せっかくの機会なので、あえて「回り道」を選ぶことにしました。

この記事では、Nature Remo を使ったスマート家電の操作方法から、Cloud Run と Cloud Scheduler を活用したクラウドの実践的な手順までを、わかりやすく解説します。少しでも興味を持っていただけたなら、ぜひ最後まで読んでいただけると嬉しいです！

## 2.Nature Remoとは？
**Nature Remo**は、Nature株式会社が提供するスマートリモコンです。このリモコンを使うことで、赤外線通信を利用して、エアコンやテレビ、照明などの家電をスマートフォンやタブレットから簡単に操作できるようになります。Nature Remoは、既存の家電をそのまま使用しながら、スマートフォンやタブレットを介して遠隔操作することができるため、手軽に家電をスマート化することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/dde6e984-f95f-4adb-8fe1-cce9178087cd.png)
（引用元: [Nature公式サイト](https://shop.nature.global/products/nature-remo-3)）

Nature Remoには、専用のスマートフォンアプリ（iOS/Android）が用意されており、このアプリを使うことで、家電のオン・オフの操作はもちろん、オートメーション機能を使って特定の時間に自動で家電を操作することも可能です。たとえば、「毎朝7時にエアコンをオンにする」「帰宅時間にエアコンをつける」など、生活リズムに合わせた操作が簡単に実現できます。さらに、Nature RemoはAmazon Alexaといった音声アシスタントとも連携できるため、音声で家電を操作することもできます。

なお、今回はNature Remoの初期設定方法については触れません。初期設定について詳しくは、[公式ページ](https://support.nature.global/hc/ja/articles/900001792563-Nature-Remo-%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E3%83%9E%E3%83%8B%E3%83%A5%E3%82%A2%E3%83%AB-%E5%88%9D%E6%9C%9F%E8%A8%AD%E5%AE%9A%E6%96%B9%E6%B3%95)をご覧ください。

# ソースコード
今回使用したソースコードは下記のレポジトリにあります。ぜひ参考にしてみてください。

https://github.com/Nakkinakki55/GCPNatureRemoAutomation


## 3.Nature Remoの設定方法
### 3-1.アクセストークンを取得する
今回Nature Remoを使ってスマート家電を操作するためには、アクセストークンが必要です。このトークンを取得することで、APIを通じて自分のデバイスを操作できるようになります。以下に、Nature Remoからアクセストークンを取得する手順を解説します。

1.[https://home.nature.global/](https://home.nature.global/)にアクセスし、トークンを取得
2.このような内容のメールが送られるので「ログイン」ボタンを押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/198b3a40-8c2b-1b8f-303e-7d2e7a3b689f.png" width="60%" />
3.「許可する」ボタンを押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/ab009219-5e6e-bdb6-7ffa-8938dfb78b07.png" width="60%" />
4.「Go」ボタンを押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/065cc8a6-8cdc-9855-8af6-ae538a201c3d.png" width="60%" />
5.「Generate access token」ボタンを押下
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/d30dc27d-54c1-2d40-09c8-e418adbb4ba3.png" width="60%" />
6.アクセストークンが生成されました。なおこのトークンは**絶対に外部公開しないでください。**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/aa71bc62-317a-05e0-d0b0-37d07c4022a6.png" width="60%" />
7.まずは動作検証のために、こちらのコマンドを実行して、idと自分の名前を取得してください
```bash
curl -H "Authorization: Bearer <3-1.アクセストークンを取得する で取得したトークン>" ^
-H "accept: application/json" ^
-X GET "https://api.nature.global/1/users/me"
```
なお成功した場合、下記のようなレスポンスがあります。
```json
{
	"id": "×××××××××",
	"nickname": "××××××××"
}
```
### 3-2.Nature Remoを遠隔操作する
#### 3-2-1.登録した家電一覧の取得
まずは、Nature Remoに登録してある家電一覧を取得してください。今回はNode.jsのコードを例に説明しますが、Pythonや他の言語でも同様の処理が可能です。
まず、axios パッケージをインストールしてください。
##### 手順の概要
1.必要なパッケージのインストール
```bash
npm install axios
```
2.Nature Remo APIを使用して家電一覧を取得するコード
```01.get_appliances_list.js
const axios = require('axios');

// Nature Remo　APIを動作させる関数を定義
async function getAppliances() {
    const token = '<3-1.アクセストークンを取得する で取得したトークン>'; // トークンを設定

    try {
        // リクエストを送信し、レスポンスを取得
        const response = await axios.get('https://api.nature.global/1/appliances', {
            headers: {
                'Authorization': `Bearer ${token}`,
                'accept': 'application/json',
            },
        });
        
        // レスポンスのデータを出力
        console.log('Response data:', response.data);
    } catch (error) {
        // エラーが発生した場合
        console.error('Error:', error.message);
    }
}

// 関数を呼び出し
getAppliances();

```
成功した場合、以下のようなレスポンスが返されます。通常、JSONから取得したい項目を指定するコードを書くのですが、登録している家電の数は人によって異なるため、今回は具体的に記述しません。ちなみに、私の場合はまだエアコン1台しか登録していないので、このように表示されます。
```device_list.json
[
	{
		"id": "登録している家電のID",
		"device": {
			"name": "Remo mini",
			"id": "××××××××××××",
			"created_at": "2024-11-25T14:49:12Z",
			"updated_at": "2024-11-25T14:49:17Z",
			"mac_address": "×××××××××ｖ",
			"serial_number": "×××××××××××",
			"firmware_version": "×××××××××××××",
			"temperature_offset": 0,
			"humidity_offset": 0
		},
		"model": {
			"id": "×××××××××××",
			"country": "JP",
			"manufacturer": "Sharp",
			"remote_name": "×××××××××××",
			"series": "",
			"name": "Sharp AC 048",
			"image": "ico_ac_1"
		},
		"type": "AC",
		"nickname": "エアコン",
		"image": "ico_ac_1",
		"settings": {
			"temp": "23",
			"temp_unit": "c",
			"mode": "warm",
			"vol": "auto",
			"dir": "auto",
			"dirh": "",
			"button": "",
			"updated_at": "2024-11-26T14:28:18Z"
		},
		"aircon": {
			"range": {
				"modes": {
```
ちなみに、curlを使って実行すると以下のようになります。
```bash
curl -H "Authorization: Bearer <3-1.アクセストークンを取得する で取得したトークン>" ^
-H "accept: application/json" ^
-X GET "https://api.nature.global/1/appliances"
```
#### 3-2-2.Nature Remoを使った家電の操作方法
ここからは、Nature Remoを使用して家電（エアコン）を操作する方法を説明します。
##### 1.エアコンの電源をONにする
```02.ac_turn_on.js
const axios = require('axios');

// Nature Remo APIを動作させる関数を定義
async function setAirconSettings() {
    const token = '<3-1.アクセストークンを取得する で取得したトークン>'; // トークンを設定
    const deviceId = '<device_list.jsonで取得した登録している家電のID>'; // 家電のIDを設定
    const url = `https://api.nature.global/1/appliances/${deviceId}/aircon_settings`;

    try {
        // POSTリクエストを送信し、レスポンスを取得
        const response = await axios.post(
            url,
            'button=', // データの内容を設定
            {
                headers: {
                    'Authorization': `Bearer ${token}`,
                    'accept': 'application/json',
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
            }
        );

        // ステータスコードが200の場合、レスポンスのデータを出力
        if (response.status === 200) {
            console.log('Nature Remo送信成功!');
            console.log('Response data:', response.data);
        } else {
            console.error('Unexpected status code:', response.status);
        }
    } catch (error) {
        // エラーが発生した場合
        console.error('Error:', error.message);
    }
}

// 関数を呼び出し
setAirconSettings();
```
成功した場合、以下のようなレスポンスが返されます。
```text
Nature Remo送信成功!
Response data: {
  temp: '23',
  temp_unit: 'c',
  mode: 'warm',
  vol: 'auto',
  dir: 'auto',
  dirh: '',
  button: '',
  updated_at: '2024-11-28T13:01:19Z'
}
```
ちなみにcurlで書くと下記の通りになります。
```bash
curl -H "Authorization: Bearer <3-1.アクセストークンを取得する で取得したトークン>" ^
-H "accept: application/json" ^
-X POST "https://api.nature.global/1/appliances/<device_list.jsonで取得した登録している家電のID>/aircon_settings" ^
-H "Content-Type: application/x-www-form-urlencoded" ^
-H "accept: application/json" ^
-d "button="
```

##### 2.エアコンの電源をOFFにする
```03.ac_turn_off.js
const axios = require('axios');

// Nature Remo APIを動作させる関数を定義
async function setAirconSettings() {
    const token = '<3-1.アクセストークンを取得する で取得したトークン>'; // トークンを設定
    const deviceId = '<device_list.jsonで取得した登録している家電のID>'; // 家電のIDを設定
    const url = `https://api.nature.global/1/appliances/${deviceId}/aircon_settings`;

    try {
        // POSTリクエストを送信し、レスポンスを取得
        const response = await axios.post(
            url,
            'button=power-off', // データの内容を設定
            {
                headers: {
                    'Authorization': `Bearer ${token}`,
                    'accept': 'application/json',
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
            }
        );

        // ステータスコードが200の場合、レスポンスのデータを出力
        if (response.status === 200) {
            console.log('Nature Remo送信成功!');
            console.log('Response data:', response.data);
        } else {
            console.error('Unexpected status code:', response.status);
        }
    } catch (error) {
        // エラーが発生した場合
        console.error('Error:', error.message);
    }
}

// 関数を呼び出し
setAirconSettings();
```
成功した場合、以下のようなレスポンスが返されます。
```text
Nature Remo送信成功!
Response data: {
  temp: '24',
  temp_unit: 'c',
  mode: 'warm',
  vol: 'auto',
  dir: 'auto',
  dirh: '',
  button: 'power-off',
  updated_at: '2024-11-28T13:36:56Z'
}
```
ちなみにcurlで書くと下記の通りになります。
```bash
curl -H "Authorization: Bearer <3-1.アクセストークンを取得する で取得したトークン>" ^
-H "accept: application/json" ^
-X POST "https://api.nature.global/1/appliances/<device_list.jsonで取得した登録している家電のID>/aircon_settings" ^
-H "Content-Type: application/x-www-form-urlencoded" ^
-H "accept: application/json" ^
-d "button=power-off"
```
##### 3.エアコンを暖房モードで動作させ、設定温度を24℃に、風量と風向きを自動調整にする場合
```04.ac_set_heating_24_auto.js
const axios = require('axios');

// Nature Remo APIを動作させる関数を定義
async function setAirconSettings() {
    const token = '<3-1.アクセストークンを取得する で取得したトークン>'; // トークンを設定
    const deviceId = '<device_list.jsonで取得した登録している家電のID>'; // 家電のIDを設定
    const url = `https://api.nature.global/1/appliances/${deviceId}/aircon_settings`;

    // 送信するデータ
    const data = new URLSearchParams({
        operation_mode: 'warm',
        temperature: '24',
        temperature_unit: 'c',
        button: '',
        air_volume: 'auto',
        air_direction: 'auto',
        air_direction_h: 'auto',
    });

    try {
        // POSTリクエストを送信し、レスポンスを取得
        const response = await axios.post(
            url,
            data.toString(), // URLエンコードされたデータを送信
            {
                headers: {
                    'Authorization': `Bearer ${token}`,
                    'accept': 'application/json',
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
            }
        );

        // ステータスコードが200の場合、レスポンスのデータを出力
        if (response.status === 200) {
            console.log('Nature Remo送信成功!');
            console.log('Response data:', response.data);
        } else {
            console.error('Unexpected status code:', response.status);
        }
    } catch (error) {
        // エラーが発生した場合
        console.error('Error:', error.message);
    }
}

// 関数を呼び出し
setAirconSettings();

```
成功した場合、以下のようなレスポンスが返されます。
```text
Nature Remo送信成功!
Response data: {
  temp: '24',
  temp_unit: 'c',
  mode: 'warm',
  vol: 'auto',
  dir: 'auto',
  dirh: '',
  button: '',
  updated_at: '2024-11-28T13:39:05Z'
}
```
ちなみにcurlで書くと下記の通りになります。
```bash
curl -H "Authorization: Bearer <3-1.アクセストークンを取得する で取得したトークン>" ^
-H "accept: application/json" ^
-X POST "https://api.nature.global/1/appliances/<device_list.jsonで取得した登録している家電のID>/aircon_settings" ^
-H "Content-Type: application/x-www-form-urlencoded" ^
-H "accept: application/json" ^
-d "operation_mode=warm" ^
-d "temperature=22" ^
-d "temperature_unit=c" ^
-d "button=" ^
-d "air_volume=auto" ^
-d "air_direction=auto" ^
-d "air_direction_h=auto"

```
詳しくは[公式ドキュメント](https://swagger.nature.global/#/default/post_1_appliances__applianceid__aircon_settings)をご覧ください。
### 3-3.実践編
#### 3-3-1.ソースコード
ここからは実際にCloud RunとCloud Scheduler動かすことを想定したコードを書きます。なおコードを書く前に以下のライブラリをインストールしてください。
```text
npm install express
npm install axios
```
以下は、エアコンの暖房を操作するためのコードです。index.js というファイルに記述します。このコードは、初期画面やエアコンの操作が成功した際に、ブラウザに文字が表示されるだけのシンプルな構成です。もちろん、HTMLやCSSを使えば操作画面やメッセージボックスを作成することも可能ですが、今回はシンプルさと分かりやすさを重視して、あえて省略しています。
```index.js
import axios from 'axios';
import express from 'express';
const app = express();

// トークンとデバイスIDを設定
const token = '<3-1.アクセストークンを取得する で取得したトークン>'; // トークンを設定
const deviceId = '<device_list.jsonで取得した登録している家電のID>'; // 家電のIDを設定
const url = `https://api.nature.global/1/appliances/${deviceId}/aircon_settings`;


// 現在の日時を取得してフォーマットするヘルパー関数
function getCurrentDateTime() {
    const now = new Date();
    const options = {
        timeZone: 'Asia/Tokyo',
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
        fractionalSecondDigits: 3,
        hour12: false
    };
    return now.toLocaleString('ja-JP', options).replace(/\//g, '-').replace(',', '');
}

// 暖房をオフにする関数
async function turnHeatingOff(res) {
    const data = new URLSearchParams({
        button: 'power-off', // 電源オフボタン
    });

    try {
        console.log(`[${getCurrentDateTime()}] 暖房をオフにする操作開始...`);
        
        const response = await axios.post(url, data.toString(), {
            headers: {
                'Authorization': `Bearer ${token}`,
                'accept': 'application/json',
                'Content-Type': 'application/x-www-form-urlencoded',
            },
        });

        console.log(`[${getCurrentDateTime()}] 暖房をオフにする操作完了`);

        if (response.status === 200) {
            res.send('暖房をオフにしました!');
            console.log(`[${getCurrentDateTime()}] 操作成功: response.status = ${response.status}`);
            console.log(`[${getCurrentDateTime()}] Response data:`, response.data); // レスポンスデータを出力
        } else {
            res.status(500).send('暖房のオフ操作に失敗しました。');
            console.error(`[${getCurrentDateTime()}] 操作失敗: Unexpected status code ${response.status}`);
            console.error(`[${getCurrentDateTime()}] Response data:`, response.data); // レスポンスデータを出力
        }
    } catch (error) {
        res.status(500).send('暖房のオフ操作中にエラーが発生しました。');
        console.error(`[${getCurrentDateTime()}] エラー: ${error.message}`);
    }
}

// 暖房の温度を設定する関数
async function setHeatingTemperature(res, temperature) {
    const data = new URLSearchParams({
        operation_mode: 'warm',  // 暖房モード
        temperature: temperature.toString(),
        temperature_unit: 'c',
        air_volume: 'auto',
        air_direction: 'auto',
        air_direction_h: 'auto',
    });

    try {
        console.log(`[${getCurrentDateTime()}] 暖房の温度を${temperature}度に設定する操作開始...`);
        
        const response = await axios.post(url, data.toString(), {
            headers: {
                'Authorization': `Bearer ${token}`,
                'accept': 'application/json',
                'Content-Type': 'application/x-www-form-urlencoded',
            },
        });

        console.log(`[${getCurrentDateTime()}] 暖房の温度を${temperature}度に設定する操作完了`);

        if (response.status === 200) {
            res.send(`暖房の温度を${temperature}度に設定しました!`);
            console.log(`[${getCurrentDateTime()}] 操作成功: response.status = ${response.status}`);
            console.log(`[${getCurrentDateTime()}] Response data:`, response.data); // レスポンスデータを出力
        } else {
            res.status(500).send('温度設定に失敗しました。');
            console.error(`[${getCurrentDateTime()}] 操作失敗: Unexpected status code ${response.status}`);
            console.error(`[${getCurrentDateTime()}] Response data:`, response.data); // レスポンスデータを出力
        }
    } catch (error) {
        res.status(500).send('温度設定中にエラーが発生しました。');
        console.error(`[${getCurrentDateTime()}] エラー: ${error.message}`);
    }
}

// ルートエンドポイント
app.get('/', (req, res) => {
    res.send('暖房操作用APIにようこそ!');
});


// 暖房をオフにするルート
app.get('/heating/off', async (req, res) => {
    await turnHeatingOff(res);
});

// 暖房の温度を設定するルート（例：温度25度に設定）
app.get('/heating/temperature/:temp', async (req, res) => {
    const temperature = req.params.temp;
    await setHeatingTemperature(res, temperature);
});

// サーバーをポート8080で起動
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
    console.log(`ac_automation_controller: listening on port ${PORT}`);
});

```
#### 3-3-2.サーバーを実行する方法
1.index.jsがあるディレクトリで、以下のコマンドを実行してサーバーを起動します。
```text
node index.js
```
2.サーバーが正しく起動すると、以下のメッセージが表示されます。
```text
ac_automation_controller: listening on port 8080
```
3.以下のリンクをGoogle Chromeなどのブラウザのアドレスバーに貼り付けて、Enterキーを押してください。
```text
http://localhost:8080/
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/1962654b-18bd-ad9f-11de-d1393cc28443.png)
と成功されたら成功です。もし、暖房をオフにしたい場合は、次のリンクを実行してください。
```text
http://localhost:8080/heating/off
```
暖房を24度に設定したい場合は、次のリンクを実行してください。
```text
http://localhost:8080/heating/temperature/24
```
を実行してください。これで準備完了です。


## 4.Cloud Runの設定方法
3-3. 実践編で紹介したコードは、同じネットワーク内でしか動作しません。つまり、外出先でエアコンを操作したい場合、http://localhost:8080/ では動作しません。これでは困りますよね。しかし、今回紹介する Cloud Run を使えば、その悩みを解決できます。

Cloud Runを使えば、外出先でも自宅のエアコンを操作できるようになります。もちろん、いくつかの方から「同じネットワーク内で動けば十分だ」という意見があるかもしれません。しかし、もしこのステップを踏まないと、Cloud Schedulerからエアコンのスケジュール実行ができなくなってしまいます。そのため、この章は必ず実施してください。基本的には[公式ドキュメント](https://cloud.google.com/run/docs/quickstarts/build-and-deploy/deploy-nodejs-service?hl=ja)の通りに行えば問題なくできますが、今回はその手順をわかりやすく解説します。
### 4-1.Cloud Runの設定
1.まずは[このリンク](https://console.cloud.google.com/welcome?hl=ja)から新規プロジェクトを作成します。今回のプロジェクト名は「ac_automation_controller」にします。!<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/2c449a2e-6496-5565-2713-c0f360419dd5.png" width="60%" />

2.[こちらのページ](https://cloud.google.com/sdk/docs/install?hl=ja)からgcloud CLI をインストールします。

3.gcloud CLIのインストールが成功したらデスクトップ上にこのようなアイコンが出現するのでクリックします。ここからはgcloud CLIのコマンドラインで操作します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/bebf26db-e4b0-4637-a1c3-7725f0b4233e.png)
4.以下のコマンドでgcloud CLI を初期化します
```text
gcloud init
```
成功したら
```text
Pick configuration to use:
 [1] Re-initialize this configuration [default] with new settings
 [2] Create a new configuration
 ```
 と出るので、1を選んでください。
5.以下のように表示されるので使用したいアカウントを選択します。
```text
Select an account:
 [1] ×××××××@gmail.com
 [2] Sign in with a new Google Account
 [3] Skip this step
```
5.現在利用しているプロジェクトが出ます。選択したいプロジェクトを選択してください。
```text
 [1] ××××××××××××××
 [2] Enter a project ID
 [3] Create a new project
```
6.[このリンク](https://console.cloud.google.com/welcome?hl=ja)から今回使用するプロジェクトを選択して、番号とIDをコピーしてください。そしてコマンドでCloud Run サービスのデフォルト プロジェクトを設定します。
```text
gcloud config set project 今回取得したID
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/1ee15de7-7bc6-2d03-01f1-a9f38e652ccc.png" width="60%" />

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/eb8a946d-e79e-8633-8fcb-192ed1ba1b07.png" width="70%" />

7.Cloud Run Admin API と Cloud Build API を有効にします。
```text
gcloud services enable run.googleapis.com cloudbuild.googleapis.com
```
8.Cloud Buildがソースを構築できるようにするためには、次のコマンドを実行して、Compute Engineのデフォルトサービスアカウントに「Cloud Buildサービスアカウント」のロールを付与する必要があります
```text
gcloud projects add-iam-policy-binding 6で取得したID ^
    --member=serviceAccount:6で取得した番号-compute@developer.gserviceaccount.com \
    --role=roles/cloudbuild.builds.builder
```
### 4-2.ソースコードのデプロイ
ここからは実際にソースコードをCloud Runにデプロイする方法を解説します。なお今回使用するコードは3-3.実践編で作成したindex.jsです。

1.フォルダを作成します。なおフォルダ名は英子文字のみを使ってください。
```text
mkdir accontorl
cd accontorl
```
2.前の章である3-3.実践編で作成したindex.jsをaccontorl傘下に配置した後は、以下のライブラリをインストールしてください。
```text
npm install express
npm install axios
```
3.同じディレクトリにpackage.jsonを作ります。なお記載内容は下記の通りにしてください。"name"の箇所は1.で作成したフォルダと同一の名前にしてください。
```package.json
{
  "name": "accontorl",
  "description": "Simple hello world sample in Node",
  "version": "1.0.0",
  "private": true,
  "main": "index.js",
  "type": "module",
  "scripts": {
    "start": "node index.js"
  },
  "engines": {
    "node": ">=16.0.0"
  },
  "author": "Google LLC",
  "license": "Apache-2.0",
  "dependencies": {
    "axios": "^1.7.9",
    "express": "^4.17.1"
  }
}

```
4.ここまでを手順通りにするとaccontorl傘下は以下の構成になっています。いかがでしょうか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/ba3aa79a-4654-a96e-985f-fa6196062e96.png)
5.このコマンドを使用して現在のフォルダをデプロイしてください。
```text
gcloud run deploy --source .
```
コマンドが成功したら
```text
Service name (accontorl):
```
と出るので、今回作成したフォルダ名を入力してください。今回の場合ですと「accontorl」と入力してください。

次にリージョンを選択する必要があります。日本でサービスを利用する場合は、「4」を選択すれば問題ありません。その後、何回は質問がありますが、ひたすらYを入力してください。
```text
Please specify a region:
 [1] africa-south1
 [2] asia-east1
 [3] asia-east2
 [4] asia-northeast1
 [5] asia-northeast2
 ```
 最終的にこのようなメッセージが出力された成功です。これで外出先からでもエアコンの操作ができます。
```text
 Service URL: https://accontorl-××××××.asia-northeast1.run.app
```
### 4-2.動作検証
暖房をオフにしたい場合は、次のリンクを実行してください。
```text
https://accontorl-××××××.asia-northeast1.run.app/heating/off
```
暖房を24度に設定したい場合は、次のリンクを実行してください。
```text
https://accontorl-××××××.asia-northeast1.run.app/heating/temperature/24
```

これで動作に成功したら問題ありません。もし動作しない場合は、もう一度index.jsを確認してください。

## 5.Cloud Schedulerの設定方法
ここまで来たら、あともう一息です！残る作業は、Cloud Schedulerの設定だけです。Cloud Schedulerは、その名の通りスケジュール実行を行うサービスです。実行のタイミングを細かく制御できるため、とても便利です。基本的には[公式ドキュメント](https://cloud.google.com/scheduler/docs/schedule-run-cron-job?hl=ja)に従えば問題ありませんが、今回はより分かりやすく解説します。

1.[このリンク](https://console.cloud.google.com/flows/enableapi?apiid=cloudscheduler.googleapis.com%2Cpubsub.googleapis.com&hl=ja)からCloud Scheduler APIと Pub/Sub APIを有効にします。

2.[公式ドキュメント](https://cloud.google.com/scheduler/docs/schedule-run-cron-job?hl=ja)に「Pub/Sub トピックとサブスクリプションを作成する」という項目がありますが、今回は必要ないのでスキップします。

3.[Cloud Schedulerのページ](https://console.cloud.google.com/cloudscheduler?hl=ja)に移動します。

4.ジョブのスケジュール設定を押下してください
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/deae5017-f4ab-e92c-487f-0bbe7ef170a0.png" width="60%" />
5.以下のように名前を設定して、スケジュールを設定してください。完了したら「続行」ボタンを押下してください。下記の場合だと月曜から金曜日の日本標準時（JST）の10時30分にスケジュールを設定しています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/8f21881a-cade-c107-b6fc-9025e96c20e7.png" width="60%" />
6.スケジュールの設定は、ターゲットタイプをHTTPにし、HTTPメソッドはGET、AUTHヘッダーは「なし」にしてください。設定が完了したら、「続行」ボタンを押してください。この設定により、エアコンは暖房モードで24度に設定され、電源が入ります。なお、電源をOFFにしたい場合は、4-2.動作検証のURLを入力してください。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/280b28ef-f2f9-9639-4e71-2f14dc624852.png" width="60%" />
7.次の画面では特に設定をすることなく「続行」ボタンを押下してください。これで終わりです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561875/ba654001-149c-2e5a-f9e3-bdb432e10e5c.png" width="60%" />

## まとめ
いかがでしたでしょうか？これで、毎日決まった時間にエアコン（暖房）を自動でONにできるようになり、快適な朝を迎えることができるようになりました。今回は、Nature Remo、Cloud Run、Cloud Schedulerの使い方を丁寧に解説したため、少し長文になってしまいましたが、ここまでお付き合いいただき、ありがとうございます。

今回の内容は、あくまでGoogle CloudのCloud RunとCloud Schedulerを使ったエアコンの電源制御に関するものでした。エアコンの電源制御は、仮に仕組みが止まっても大きな問題は起こりませんが、もし業務に関わる重要なシステムで同様の仕組みを導入する場合は、リスクへの備えが必要です。たとえば、今回使用したGoogle CloudのCloud RunやCloud Schedulerだけに依存するのではなく、他のサービスを併用したり、切り替えが可能な構成にするのも一つの方法です。その際は、三大クラウドであるAWS（Amazon Web Services）、Azure（Microsoft Azure）、GCP（Google Cloud Platform）のいずれかを併用するのが効果的です。これらのクラウドサービスは利用者が多いため、トラブル時の情報が入手しやすいというメリットがあります。

今回のプロジェクトではGoogle Cloud Platform（GCP）を使用しましたが、リスク管理を考えるなら、AWSやAzureと併用する方法も検討する価値があります。さらに、クラウドのリージョン（データセンターの地域）も分散させるのがおすすめです。以前に比べてクラウドサービスが停止するリスクは減ったものの、停電や自然災害といった想定外のトラブルが起きる可能性はゼロではありません。そのため、複数のリージョンに分散させることで、トラブル時の影響を最小限に抑えることができます。

ただし、費用面も考慮する必要があります。クラウドサービスの併用やリージョンの分散はコストがかかる可能性があるため、業務の重要度に応じたバランスを考えることが大切です。

ここまで読んでいただき、本当にありがとうございました！少しでも皆さんの役に立つ内容になっていれば幸いです。




## 参考文献
[スマートリモコンの仕組みとは？Natureスタッフが説明してみた。Nature公式サイト](https://shop.nature.global/blogs/nature-store/what_is_smart_remote?srsltid=AfmBOoptTEOKN7T28FizSR3lA9aR1aIWk5YC4LT3HNmXyHmLj_h0C-BV)
[アレクサとNature Remoでできること｜照明やテレビを操作しよう - Nature](https://nature.global/blog/18843/)
[Nature RemoのAPIでターミナルから家電を操作してみた | DevelopersIO](https://dev.classmethod.jp/articles/nature-remo-api/)
[Nature Remo API でエアコンを操作する（Slackでエアコン操作も） | yuu26-memo](https://blog.yuu26.com/nature-remo-api-control/)
[Swagger UI - Nature Remo](https://swagger.nature.global/)
[クイックスタート: Cloud Run に Node.js サービスをデプロイする | Cloud Run Documentation | Google Cloud](https://cloud.google.com/run/docs/quickstarts/build-and-deploy/deploy-nodejs-service?hl=ja)
[プロジェクトの作成と管理 | Resource Manager Documentation |Google Cloud](https://cloud.google.com/resource-manager/docs/creating-managing-projects?hl=ja#identifying_projects)
[クイックスタート: cron ジョブをスケジュールして実行する   | Cloud Scheduler Documentation | Google Cloud](https://cloud.google.com/scheduler/docs/schedule-run-cron-job?hl=ja)