1.3inch LCD HATにCloudWatchメトリクスのグラフを表示する

1.3inch LCD HATにCloudWatchメトリクスのグラフを表示する
公開日時
更新日時

WaveShare 1.3インチ 240×240 IPS LCDディスプレイHAT for RaspberryPiを買ったので、 CloudWatchに保存しているBME280センサ情報を表示してみることにした。

できたもの

  • 現在の不快指数、温度、湿度を表示
rpi1
  • 直近一時間の変化をグラフ表示
rpi2

上記を数分ずつ交互に表示するようにした。

設定方法

apt install awscli
aws configure
  • noto-cjkフォントをインストール
sudo apt install fonts-noto-cjk
  • 現在のセンサ情報とグラフを表示するpythonスクリプトを作成(cloudwatch.py)
# coding:utf-8
import spidev as SPI
import ST7789
import time
import subprocess
import datetime
from pytz import timezone

from PIL import Image,ImageDraw,ImageFont
def metrics_graph():
  try:
    subprocess.check_call("aws cloudwatch get-metric-widget-image --metric-widget file://cloudwatch.json | jq -r '.MetricWidgetImage' | base64 --decode > ./graph.png", shell=True)
  except Exception as e:
    print e

def temp(start, end):
  try:
    cmd = 'aws cloudwatch get-metric-statistics --metric-name RaspberryPiZero2/temperature --period 60 --start-time %s --end-time %s --namespace Home --statistics Maximum | jq -r ".Datapoints[0].Maximum"' % (start, end)
    res = subprocess.check_output(cmd, shell=True).strip()
    if res == 'null':
      return '0'
    else:
      return '0' if res is None else res
  except Exception as e:
    print e
    return '0'

def humidity(start, end):
  try:
    cmd = 'aws cloudwatch get-metric-statistics --metric-name RaspberryPiZero2/humidity --period 60 --start-time %s --end-time %s --namespace Home --statistics Maximum | jq -r ".Datapoints[0].Maximum"' % (start, end)
    res = subprocess.check_output(cmd, shell=True).strip()
    if res == 'null':
      return '0'
    else:
      return '0' if res is None else res
  except Exception as e:
    print e
    return '0'

def di(start, end):
  try:
    cmd = 'aws cloudwatch get-metric-statistics --metric-name RaspberryPiZero2/discomfort_index --period 60 --start-time %s --end-time %s --namespace Home --statistics Maximum | jq -r ".Datapoints[0].Maximum"' % (start, end)
    res = subprocess.check_output(cmd, shell=True).strip()
    if res == 'null':
      return '0'
    else:
      return '0' if res is None else res
  except Exception as e:
    print e
    return '0'

def latest_metrics():
  end = datetime.datetime.utcnow() 
  start = end - datetime.timedelta(minutes=1)
  end_iso = timezone('UTC').localize(end).isoformat()
  start_iso = timezone('UTC').localize(start).isoformat()

  t = temp(start_iso, end_iso)
  h = humidity(start_iso, end_iso)
  d = di(start_iso, end_iso)

  return t, h, d

def main():
  # Raspberry Pi pin configuration:
  RST = 27
  DC = 25
  BL = 24
  bus = 0
  device = 0
  
  # 240x240 display with hardware SPI:
  disp = ST7789.ST7789(SPI.SpiDev(bus, device),RST, DC, BL)
  
  # Initialize library.
  disp.Init()

  font = ImageFont.truetype('/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc', 30)
  
  while True:
    metrics_graph()
    temp, humidity, di = latest_metrics()

    ## Clear display.
    disp.clear()
    
    print "***draw text"
    image1 = Image.new("RGB", (disp.width, disp.height), "WHITE")
    draw = ImageDraw.Draw(image1)
    draw.text((30, 20), str.format('Living', di), fill = "BLACK", font = font)
    draw.text((30, 60), str.format('di  : {:.2f}', float(di)), fill = "BLACK", font = font)
    draw.text((30, 100), str.format('temp: {:.2f}', float(temp)), fill = "ORANGE", font = font)
    draw.text((30, 140), str.format('hum : {:.2f}', float(humidity)), fill = "BLUE", font = font)
    draw.text((30, 180), time.strftime('%H:%M'), fill = "BLACK", font = font)
    disp.ShowImage(image1,0,0)
    time.sleep(300)
    
    print "***draw graph"
    image = Image.open('./graph.png')
    disp.ShowImage(image,0,0)
    time.sleep(300)

main()
  • グラフ画像用のメトリクス定義ファイルを保存(cloudwatch.json)
{
    "metrics": [
        [ "Home", "RaspberryPiZero2/temperature", { "label": "temp", "period": 60 } ],
        [ ".", "RaspberryPiZero2/humidity", { "label": "humidity", "period": 60 } ],
        [ ".", "RaspberryPiZero2/discomfort_index", { "label": "di", "period": 60 } ]
    ],
    "view": "timeSeries",
    "stacked": false,
    "region": "ap-northeast-1",
    "yAxis": {
        "left": {
            "showUnits": false
        },
        "right": {
            "showUnits": false
        }
    },
    "legend": {
        "position": "hidden"
    },
    "title": "BME280",
    "width": 240,
    "height": 240,
    "start": "-PT1H",
    "end": "P0D",
    "timezone": "+0900"
}
  • スクリプト実行
python cloudwatch.py &

参考


Related #raspberry pi

ngrokの代わりにCloudflare Tunnelを使う

botやwebhookを利用するサービスの開発が捗る

Dockerのデータ保存場所を変更する

/etc/docker/daemon.jsonに追記

Alexaにゲーミングマシンと周辺環境を終了してもらう

「Alexa Steamを終了して」ができるようになった

Alexaにゲーミングマシンと周辺環境を起動してもらう

PC起動、TV起動、サウンドバー起動がまとめてできるようになった

docker-compose build時に「no Space Left on Device」が発生

1年前にも同じエラーにハマってた