日没10分前に照明をつける SwitchBot × GoogleMaps × OpenWeatherMap

## はじめに
お留守番ネコの様子をXとLINEで分かるようにする記事を前に書きました。

https://qiita.com/dmackey_2128/items/7a7e01ea47e745913fcb

でも・・・

<blockquote class="twitter-tweet"><p lang="zxx" dir="ltr"><a href="https://t.co/95YmfUiuJZ">pic.twitter.com/95YmfUiuJZ</a></p>&mdash; まっきー🐈‍⬛ (@dmackey_2139) <a href="https://twitter.com/dmackey_2139/status/1735920505428041856?ref_src=twsrc%5Etfw">December 16, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625818/e096b250-f124-3ff2-2f0c-797f3b8c8afa.png">

暗い(笑)

赤外線リモコンをコントロールする製品で、１８時に部屋の明かりを付けるようにしてたけど、冬になって暗くなるのが早くなってた。季節による日の入り時刻の違いを吸収できないかなと思ってやってみた。

## SwitchBot シーリングライト プロ
を買う。SwitchBotハブミニの代わりにもなるらしい。最初からこれ買えばよかったぜ
https://www.switchbot.jp/products/switchbot-ceiling-light

## 処理概要
プログラムを実行させるのは前と同じ、AWSで利用するAmazon Linux 2023
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625818/82ce913e-d758-1957-7434-ac839590db80.png)



## Google Maps APIの利用
googleのAPIを利用する。無料ではないが、かなり使ってもどうせ０円か１円なので気にしない。
実行してみて、名称の緯度と経度が取得できることを確認する。スカイツリーとか一蘭 浅草店とか、なんでも大体いけるの面白い。

```python:posi_from_name.py
import googlemaps

# パラメータの設定
GOOGLE_APIKEY = 'あなたのキー'

def geocode_address(name, iti):
    gmaps = googlemaps.Client(key=GOOGLE_APIKEY)
    geocode_result = gmaps.geocode(name)

    if not geocode_result:
        return False

    # 緯度と経度を返却
    iti['lat'] = geocode_result[0]["geometry"]["location"]["lat"]
    iti['lon'] = geocode_result[0]["geometry"]["location"]["lng"]
    return True

def Main():

    city_name = 'スカイツリー'
    iti = {}
    if not geocode_address(city_name, iti ):
        print('ない。。。')
        return
    print( city_name, iti )

if __name__ == "__main__":
    Main()
```

## OpenWeatherMapのAPI利用
無料の天気情報取得APIを利用して、緯度と経度から天気情報を取得する。
取得情報はたくさんあるけど、今回使うのはsunset(=日没)情報だけ。

```python:weather.py
import json
import requests

WEATHER_API_KEY = 'あなたのキー'

# One Call API 3.0
def otenki_info( h_lat, h_lon ):
    api = 'https://api.openweathermap.org/data/3.0/onecall?lat={lat}&lon={lon}&appid={key}'
    url = api.format(lat = h_lat, lon = h_lon, key = WEATHER_API_KEY)
    response = requests.get(url)
    data = response.json()
    return data

def main():
    tenki = otenki_info(34.000, 135.000)
    print(tenki)

if __name__ == "__main__":
    main()

```

## スマホのSwitchBotアプリ
スマホにSwitchBotのアプリを入れて、シーリングライト プロと紐づける。
さらにこのアプリからトークンキーとシークレットキーを入手する。この辺はググったり、Qiitaの他の方の記事を参考にする！(笑)

## SwitchBot API1.1の利用
制御したいシーリングライトプロのデバイスIDが知りたいので、以下プログラムのデバイス一覧取得関数を実行する。

```python:switchbot.py
import json
import time
import hashlib
import hmac
import base64
import uuid

import requests

TOKEN  = 'あなたのトークンキー'
SECRET = 'あなたのシークレットキー'

LIGHT_PRO_DEVICE_ID = 'シーリングライトプロのデバイスID'

# githubのリファレンスより、How to Sign
def create_header():

    # Declare empty header dictionary
    apiHeader = {}
    nonce = uuid.uuid4()
    t = int(round(time.time() * 1000))
    string_to_sign = '{}{}{}'.format(TOKEN, t, nonce)

    string_to_sign = bytes(string_to_sign, 'utf-8')
    secret = bytes(SECRET, 'utf-8')

    sign = base64.b64encode(hmac.new(secret, msg=string_to_sign, digestmod=hashlib.sha256).digest())

    #Build api header JSON
    apiHeader['Authorization']=TOKEN
    apiHeader['Content-Type']='application/json'
    apiHeader['charset']='utf8'
    apiHeader['t']=str(t)
    apiHeader['sign']=str(sign, 'utf-8')
    apiHeader['nonce']=str(nonce)

    return  apiHeader

# デバイス一覧取得
def deviceid_view():
    # ヘッダ作成
    header =create_header()
    response = requests.get("https://api.switch-bot.com/v1.1/devices", headers=header)
    print(response.text.replace('}', '}\n'))

# Ceiling Light Pro デバイス操作
def ceiling_light_pro_execute(bodys):

    # ヘッダ作成
    header =create_header()

    for body in bodys:
        url = 'https://api.switch-bot.com/v1.1/devices/' + LIGHT_PRO_DEVICE_ID + '/commands'
        print(requests.post( url, headers=header, data=json.dumps(body) ))
        # 連続要求するとなぜか設定が戻るので間隔を開けるためにスリープ
        time.sleep(5)

# Ceiling Light Pro
def ceiling_light_pro_main():

    # ライトOn、照明を最小、色温度を最小
    list_body = [
        {"command" : "turnOn", "comandType": "command"},
        {"command" : "setBrightness", "parameter" : "1", "comandType": "command"},
        {"command" : "setColorTemperature", "parameter" : "2700", "comandType": "command"}
    ]
    ceiling_light_pro_execute(list_body)

def main():
    # デバイス一覧取得
    deviceid_view()

if __name__ == "__main__":
    main()
```
ライトを付けるプログラムもここで書いてるので、動作確認する。個人的に夜はめちゃくちゃ暗くして過ごしたい派なので、たぶん最も暗い設定にしてる。

★☆★ 出来るエンジニアは公式リファレンスをよく読む ★☆★
https://github.com/OpenWonderLabs/SwitchBotAPI

## メインプログラム
やりたいことのパーツは揃ったので、メインとなるプログラムを書く

```python:light_on.py
'''
    ・cronから毎日15時に起動される前提！
    ・指定名称 → 緯度経度を取得 → 日の入り時間を取得
      日の入りN分前になるまでスリープしてから、部屋の照明をONする。
'''

import time
import weather
import posi_from_name
import switchbot

# お住まいの場所
CITY = '東京都新宿区'

# 日の入り何分前にライトを付けるか
CD_MINUTE = 10

def main():

    # 名称から位置情報を取得
    iti = {}
    if not posi_from_name.geocode_address(CITY, iti):
        print(CITY, 'の位置情報取得失敗')
        return

    # 位置情報から天気情報を取得
    tenki = weather.otenki_info(iti['lat'], iti['lon'])

    # 日の入りN分前まであと何秒か計算
    sunset_sec = tenki['current']['sunset'] - int(time.time()) - CD_MINUTE * 60

    # 21時(=15 + 6)になれば日本はどこでも日の入りしてるはずなので、ざっくりチェック
    if sunset_sec > 0 and sunset_sec < 3600 * 6:
        print(sunset_sec)
        time.sleep(sunset_sec)

    # switchbotを使って寝室の照明ON
    switchbot.ceiling_light_pro_main()

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

まずは手動で動かしてみて、スリープ秒数と現在時間を足して、目的時間になるか確認する。
スリープを簡単に使ってるのが恥ずかしいけど、サクっとお手軽なことをやってるのでしょうがない。と自分に言い聞かせる。
本当の日の入り時間を調べるのは以下サイトが便利だった。
https://hinode.pics/


## 自動実行
cronで毎日15時に起動するように設定する。
rootで「crontab -e」コマンド実行し、中身を以下にする。

```
# 毎日15時
0 15 * * * cd /home/ec2-user/project/switchbot; python3 light_on.py
```

## いい感じに点灯
暗めだけどｗ
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625818/b8c1b72c-bfe0-a54e-df9a-6aaadc825f14.png">



## おわりに
日の出と日の入時刻が関東と関西で20～30分も違うのを知ったのはわりと最近だし、夏と冬で2時間以上も違うのを知ったのはこの記事を書き始めてからだったｗｗｗ 常識を知る良い機会ｗｗｗ

でも野生の猫は夜暗いとこで過ごしてるよね・・？ ほんの小さな明かりでも十分見えてるって何かで読んだし、猫にとって本当にベストな明るさと時刻ってなんなんだろう。一言でいいから希望を言ってくれないかなぁ