ラズベリーパイでIOT試行錯誤 -電力計測-

# 動機

###### はじめに
私は普段、海外生産拠点との貿易事務の仕事をしている非エンジニアです。
身の回りに仕事にしても趣味にしてもプログラミングをしている人はいません。
ふとしたことからラズベリーパイが手元にあったので、何かに使えないかなと思っていました。

SunFounderのRaphaelKitを買って、ラズパイにセンサーやLEDをつなげたり、
pythonのコードをChatAIに丸投げして書かせたりして遊んでいたのですが、
ある時、ラズパイからグーグルのスプレッドシートへ書き込みができるとネットで見つけました。

AWSとかAzureはよくわからないうちに課金状態になるし、パソコンに比べてラズパイは反応が遅いしで、
センサーのデータの置き場所はローカルネットワークのハードディスクくらいしかないから、
外部からデータ確認ができないなら、使い道があんまりないなあと思っていたところだったので、
なにか発展できそうな気がして、IOT機器の体験をしてみようと思い立ちました。

ネットでいろいろ調べてみたところ、CTセンサーを利用した電力計測についての記事があり
電力計測から機械の稼働を追うことができるのは、どんな場所でも汎用性があると思い開発することにしました。

###### 概要
電源コードにセンサーを取り付け、センサーの値からラズパイで電力を推定値を計算して、
スプレッドシートに書き込み、ダッシュボードでグラフにします。

###### 材料
ラズベリーパイゼロWH　
ADS1015　ADコンバータ　pythonライブラリがあるので起用しました。
CTL-10-CLS 超小型クランプ式交流電流センサ
330Ω抵抗
電源コード

###### 回路図
![電力測定_ブレッドボード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764144/4f8db4ec-58b7-11cd-5045-a7b6143cd164.jpeg)


###### グーグルドライブとの連携に必要な、APIと、サービスアカウントの準備
グーグルドライブにあるスプレッドシートへ書き込みをするために、次のステップを進めます。
１．Google Cloud Platformでプロジェクトを作成します。
２．プロジェクトにGoogle Drive APIと　Google Sheets APIを追加します。
３．サービスアカウントを作成して、json形式の秘密鍵を入手します。
４．スプレッドシートの共有設定にサービスアカウントのメールアドレスに編集権限を与えます。


###### コードの説明
計測したセンサーの値を合計して平均を求めて、変換計算することで電力の値としています。
センサーから値を受け取ってリストに入れ続けます。
1秒後にリストの平均を求めて電力値へ変換し、書込み用のリストにタイムスタンプとペアで追加します。
ペアが２つになったらスプレッドシートへ書き込みます。

　3つの関数で構成しています。
　setup関数でGoogleへのアクセス設定をします。ここでできるだけの処理を進めておき、計測が始まってからの処理時間を少なくするようにします。
　get_wat関数が電力の変換計算と日時取得をして書込み用データを用意します。
  get_realwat関数が主となる繰り返しをする関数です。
　センサーから値を受け取り、1秒サイクルでget_wat関数でデータを作り、データが2つになったらスプレッドシートへ書き込むのを繰り返します。

※エラーハンドリングやセキュリティ対策は一切されていないです。
　

###### コード
```python:
import time
import datetime
import Adafruit_ADS1x15

from google.oauth2.service_account import Credentials
import gspread

#ADS1015初期化
ads = Adafruit_ADS1x15.ADS1015()

#ADS1015の設定
GAIN = 1
RANGE = 4.096 * 2
UNIT = RANGE / 4096
#ADSのアナログ入力ピン指定
ads1015_pin = 0
#data_rateはサンプリングレート　3300は設定できる最大値
DATA_RATE = 3300

realAmp = 0
voltage = 100

data = 0
volt = 0

l = []
update_list = []

#電力を計算して日時をセットする関数
def get_wat():
   while True:
      global update_list
      global l
      volt = sum(l)/len(l) * UNIT
      amp = volt * 3000/100
      wat= amp *voltage

      l = []

      # 現在時刻を取得
      now = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
      update = [now,wat]
      update_list.append(update)

      return update_list


#セットアップでできるだけgoogle関連はやっておかないとループ処理に時間がかかる。
def setup():
   # Google Drive APIのスコープと認証ファイルのパスを設定
   SCOPES = ['https://www.googleapis.com/auth/drive',
         'https://www.googleapis.com/auth/spreadsheets']
   creds_file = '/home/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.json'
   SHEET_ID = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'#スプレッドシートのID

   #ダウンロードしたjsonファイル名をクレデンシャル変数に設定。
   credentials = Credentials.from_service_account_file(creds_file, scopes=SCOPES)
   #OAuth2の資格情報を使用してGoogle APIにログイン。
   gc = gspread.authorize(credentials)
   workbook = gc.open_by_key(SHEET_ID)
   global worksheet
   worksheet = workbook.get_worksheet(0)


last_time = time.time()
def get_realwat():
   global update_list
   global last_time
   ads.start_adc(ads1015_pin, gain=GAIN, data_rate=DATA_RATE)#start_adcでADSを連続変換モードで実行
   while True:
      data = ads.get_last_result()#start_adcで変換した値を読むだけ
      data = abs(data)#絶対値で取り扱い
      l.append(data)

      current_time = time.time()

      if current_time - last_time >= 1 :
         update_list = get_wat()
         last_time = current_time

      if len(update_list) >= 2:
         worksheet.append_rows(update_list)
         update_list = []
         last_time = time.time()


setup()
get_realwat()
```


###### コードを書きながら試行錯誤したこと

コードは主に3つの仕事をしなければなりません。
１．センサー値の取得　２．電力への変換計算　３．スプレッドシートへ書き込み
毎秒の記録をしたいので、処理時間について考えました。
１．はセンサーやADコンバータ、ラズパイなどのハードウェアに依存します。
２．は繰り返し処理に計算を持ち込まないようにして単純にしています。
３．がアクセスのため時間がかかります。
上記の3つの仕事をどのタイミングで取り掛かるかを考えて処理時間の調整をしました。
3つの仕事を同時に処理しようとマルチスレッドを試してみたところ、GILによって関数が動いてくれない状況になり、
それを解決するには知識が足らない為、マルチスレッドの起用を取りやめました。
厳密に毎秒の取得にはなりませんが、
1秒間センサーの値を収集する→電力へ変換する→1秒間センサーの値を収集する→電力へ変換する→書き込む→ループ
という形になりました。

・電力の計測をするのでできるだけ精度を高めたいです。それにはセンサーの値の個数が多いほど良いです。
・他の動きを控えて値の取得に集中します。

・電力は波形になっていて、正と負の値があります。
・センサーから出てくる値は±4096の範囲なので、値を全て絶対値へ変換するようにして正の値で処理できるようにしました。

・毎秒の電力を記録したいが、APIの規制があって毎秒スプレッドシートに書き込みはできませんでした。
・電力の取得は毎秒するけどスプレッドシートには２秒に1回、1秒目と2秒目のデータを同時に書き込むことにした。

###### 感想
IOTとは聞くけれど、
身の回りでアナログ情報をシステム化されているものがない、IOTの便利さがよくわからない、
IOTはどんな場所で使えるのか？たくさん金額がかかるのではないか？
そんな疑問が無意識のうちにあったと思います。
web検索だけでまあまあの開発までたどりつくことができました。
ただ出来物の市販品を触るより数段理解ができたと思います。