GASでGoogle ToDoリストにデイリーミッションを追加する
タイトルがちょっと何言ってるかわからないかもしれない
毎日の自己研鑽タイムでやることが最近偏ってきてるなと思ったので、やることをランダムで決めてもらうことにした
そのプロトタイプ的なものをGASで作ってみた
仕様 🔗
- 毎日Tasks APIを使って4つ選んでToDoリストに追加する
- 前日分の消化していないミッションは最初に消す
コード 🔗
function myFunction() {
const list_id = 'hogehoge';
const missions = [
'読書',
'エンジニア学習',
'英語学習',
'ブログ活動',
'筋トレ',
'ウォーキング'
]
const response = Tasks.Tasks.list(list_id)
const tasks = response.items
if(tasks) {
tasks.forEach(function(task){
Tasks.Tasks.remove(list_id, task.id)
});
}
sample(missions, 4).forEach(function(mission){
Tasks.Tasks.insert({ title: mission }, list_id)
});
}
function shuffle([...array]) {
for (let i = array.length - 1; i >= 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
function sample(array, num) {
return shuffle(array).slice(0, num);
}
結果 🔗
こんな感じに
補足 🔗
list_id(リストID)はTasks.Tasklists.list()
で取得できる
Logger.log(Tasks.Tasklists.list());
参考 🔗
【RuboCop】Gemspec/RequiredRubyVersionの警告の対応
問題 🔗
作っているGemのGitHub ActionsでRuboCopのジョブがコケた
switchbot.gemspec:15:32: C: Gemspec/RequiredRubyVersion: required_ruby_version (2.5, declared in switchbot.gemspec) and TargetRubyVersion (2.4, which may be specified in .rubocop.yml) should be equal.
spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
原因 🔗
GemがRuby 2.5以上を必要としているのに対し、RuboCopの対象Rubyバージョンが2.4を指定しているためコケていた
ローカルではなぜか警告が出ていなかった
解決方法 🔗
.rubocop.ymlにTargetRubyVersionの設定を追加して無事解決
AllCops:
TargetRubyVersion: 2.5
補足 🔗
RuboCopのデフォルトの設定項目は以下ファイルで確認することができる
https://github.com/rubocop/rubocop/blob/master/config/default.yml
参考 🔗
Hugoでブログを作り直した
t1 🔗
できるといいな
puts :hoge
aaaa
Test aaa text.
t1.1 🔗
aaaa
t1.2 🔗
aaaa
t1.2.1 🔗
aaaa
t1.2.2 🔗
aaaa
t2 🔗
aaaa
t3 🔗
- One
/ testing some code /
- Two
- Three
超宽显示 var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";var a = "text";
超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示超宽显示 var a = "text";
GAS(JavaScript)で配列からランダムで指定した数の要素を取り出す
GASで配列からランダムにいくつか取り出したいという状況があり、調べてもこれが正解というものに出会えなかったので自分の中での結論をメモしておく
Rubyでいうsampleメソッドにあたるものを実現する
Rubyのsampleメソッド 🔗
items = ['Item1', 'Item2', 'Item3', 'Item4', 'Item5']
p items.sample(3)
#=> ["Item5", "Item4", "Item2"]
GAS(JavaScript)の場合 🔗
function myFunction() {
const items = ['Item1', 'Item2', 'Item3', 'Item4', 'Item5'];
Logger.log(sample(items, 3));
}
const shuffle = ([...array]) => {
for (let i = array.length - 1; i >= 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
const sample = (array, num) => {
return shuffle(array).slice(0, num);
}
実行ログ 🔗
20:47:06 お知らせ 実行開始
20:47:06 情報 [Item2, Item1, Item5]
20:47:06 情報 [Item3, Item4, Item2]
20:47:06 情報 [Item1, Item4, Item5]
20:47:06 情報 [Item3, Item2, Item1]
20:47:06 情報 [Item4, Item2, Item5]
参考 🔗
【Ruby/Rails】JSONのキーをキャメルケースからスネークケースに、文字列からシンボルに変換する
問題 🔗
APIを叩いて返ってきたレスポンスがJSON形式でキーがキャメルケースの文字列だった
普通にJSON.parseしても問題ないが、Rubyだったらできればスネークケースのシンボルで扱いたい
SwitchBotのAPIレスポンス 🔗
{
"statusCode": 100,
"body": {
"deviceList": [
{
"deviceId": "500291B269BE",
"deviceName": "Living Room Humidifier",
"deviceType": "Humidifier",
"enableCloudService": true,
"hubDeviceId": "000000000000"
}
],
"infraredRemoteList": [
{
"deviceId": "02-202008110034-13",
"deviceName": "Living Room TV",
"remoteType": "TV",
"hubDeviceId": "FA7310762361"
}
]
},
"message": "success"
}
JSON.parseした結果 🔗
JSON.parse(File.open('devices.json').read)
#=> {"statusCode"=>100, "body"=>{"deviceList"=>[{"deviceId"=>"500291B269BE", "deviceName"=>"Living Room Humidifier", "deviceType"=>"Humidifier", "enableCloudService"=>true, "hubDeviceId"=>"000000000000"}], "infraredRemoteList"=>[{"deviceId"=>"02-202008110034-13", "deviceName"=>"Living Room TV", "remoteType"=>"TV", "hubDeviceId"=>"FA7310762361"}]}, "message"=>"success"}
解決方法 🔗
deep_transform_keys(&:underscore)
でスネークケースにして、deep_symbolize_keys
でシンボルにする
require 'json'
require 'active_support/all' # Rubyの場合
JSON.parse(File.open('devices.json').read).deep_transform_keys(&:underscore).deep_symbolize_keys
#=> {:status_code=>100, :body=>{:device_list=>[{:device_id=>"500291B269BE", :device_name=>"Living Room Humidifier", :device_type=>"Humidifier", :enable_cloud_service=>true, :hub_device_id=>"000000000000"}], :infrared_remote_list=>[{:device_id=>"02-202008110034-13", :device_name=>"Living Room TV", :remote_type=>"TV", :hub_device_id=>"FA7310762361"}]}, :message=>"success"}
解説的なもの 🔗
キーを文字列からシンボルにする方法 🔗
方法は2つある
【Redshift】テーブルのコピー
Sinatra関連の小ネタ
Sinatraに関する小ネタを随時更新していく
小ネタ 🔗
開発環境か本番環境か 🔗
get '/' do
if settings.development?
"development!"
else
"not development!"
end
end
ホットリロード 🔗
source 'https://rubygems.org'
ruby '2.7.2'
gem 'sinatra'
+ gem 'sinatra-contrib'
require 'sinatra'
+ require 'sinatra/reloader'
get '/' do
'Hello, World!!'
end
CORS の設定 🔗
404 Not Found のエラーハンドリング 🔗
【Sinatra】404 Not Found のエラーハンドリング | 高木のブログ
コントローラーを分割する 🔗
【Sinatra】Rack::URLMap を使ってコントローラーを分割する | 高木のブログ
参考 🔗
【Git】git addしたあとに差分を確認する
git add
したあとにgit diff
しても差分を確認することができないが、
オプション(--cached
)付けたら確認することができる。
$ git diff --cached
変更ファイルだけじゃなく新規ファイルの中身も確認できるので便利。
$ git diff --cached
diff --git a/.env.sample b/.env.sample
index ac2557a..117f039 100644
--- a/.env.sample
+++ b/.env.sample
@@ -1,4 +1,3 @@
-RACK_ENV=
NATURE_REMO_API_TOKEN=
NATURE_REMO_LIGHT_ON_SIGNAL=
NATURE_REMO_LIGHT_OFF_SIGNAL=
diff --git a/deploy.sh b/deploy.sh
index 7bed751..18f5c2b 100755
--- a/deploy.sh
+++ b/deploy.sh
@@ -7,5 +7,5 @@ cd ~/workspace/home_api
docker-compose down
git pull
docker-compose build
-docker-compose up -d
+docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
EOS
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
new file mode 100644
index 0000000..de49e49
--- /dev/null
+++ b/docker-compose.prod.yml
@@ -0,0 +1,6 @@
+version: '3'
+services:
+ web:
+ environment:
+ - APP_ENV=production
+ restart: always
diff --git a/docker-compose.yml b/docker-compose.yml
index 90231e8..3d63903 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -9,4 +9,3 @@ services:
- .:/app
env_file:
- .env
- restart: always
mackerel-agentのアップデート
Amazon Linuxで使っているmackrel-agentのバージョンが古かったのでアップデートをした
$ /usr/bin/mackerel-agent version
mackerel-agent version 0.32.2 (rev b9a3ef3) [linux amd64 go1.6.2]
手順 🔗
アップデート 🔗
$ sudo yum update mackerel-agent
バージョン確認 🔗
$ /usr/bin/mackerel-agent version
mackerel-agent version 0.71.1 (rev de40822) [linux amd64 go1.14.13]
再起動 🔗
$ sudo service mackerel-agent restart
Stopping mackerel-agent: [ OK ]
Starting mackerel-agent: [ OK ]
参考 🔗
【Mac】Touch BarからEscキーが消えた時の解決方法
【Mac】mkfileでダミーファイルを作成する
サンプルのために大きめのファイルが欲しかったので探したら、標準で入っているmkfileというコマンドでできるらしい。
手順 🔗
使い方の確認 🔗
$ mkfile --help
mkfile: illegal option -- -
usage: mkfile [-nv] size[b|k|m|g] filename ...
オプションの詳細は参考リンクを
1GBのテキストファイルを作成 🔗
$ mkfile -nv 1g 1g.txt
1g.txt 1073741824 bytes
1GBあるかの確認 🔗
$ ls -lh 1g.txt
-rw------- 1 TAKAGI staff 1.0G 2 8 21:43 1g.txt
参考 🔗
【Pixela】グラフのバックアップを取るスクリプト
以前ブログに書いとおり、Togglで記録した作業時間をPixelaで可視化している。
昨年の7月くらいから毎日続けることができて、可処分時間を無駄にしないで済んでいるのは間違いなくPixelaのおかげである。
今回は、うっかり操作ミスなどをしてグラフのデータがおかしくなってしまったら辛いので、そうなる前にバックアップを取ることにした。
※ちなみに今回の場合はTogglに元データはあるので復元は可能である。ただバックアップをやってみたかっただけ。
完成品 🔗
実行 🔗
ちゃんとした実行方法は、README.md を参照
$ bundle exec ruby app.rb task-durations td-backup
195/195
結果 🔗
グラフID以外全く同じのグラフを作ることができた。
オリジナルのグラフ 🔗
バックアップしてできたグラフ 🔗
振り返り 🔗
-
copy_graphメソッドで既にグラフがあった場合など、エラーになるがrescueで握りつぶした
もちろん良くはないけど、使い捨て予定だったスクリプトにしては全体的にちゃんと書いた方だと思うので良しとする -
進捗がわかるように何ピクセル中何ピクセルまで終わったかプログレス?的なのを入れてみた
-
1ピクセルごとAPIを叩くことになるので、1秒のスリープを入れた。(ドキュメントに制限のルールは見つからなかったけど念の為)
1ピクセルに付き最低1秒はかかってしまうので一気に送れたら時間短縮できて良いのになと思った -
バックアップのグラフIDを本当は「task-durations-backup」にしたかったけど、16文字の制限があったっぽい
もう少し緩めにしてほしい。。。- Validation rule:
^[a-z][a-z0-9-]{1,16}
(Document )
- Validation rule:
-
最近追加されたエンドポイントを早速使う時がきた
Gem(sue445/pixela )も既に対応してて良き -
こういう使い方していいのかわからない
- 怒られたら消します
【Ruby】minitestを実行する方法
とあるGemにプルリクを出すためにminitestを実行したいのにやり方が分からず、ググっても意外とすぐに出てこなかったのでメモ。
どこのリポジトリか忘れたが、GitHub Actionsで実行している記述を見つけて無事解決した。
$ bundle exec rake test
Run options: --seed 31456
# Running:
....
Finished in 0.041567s, 96.2302 runs/s, 96.2302 assertions/s.
4 runs, 4 assertions, 0 failures, 0 errors, 0 skips
SwitchBotのスマート加湿器が止まっていたら起動させるスクリプト
SwitchBotのスマート加湿器が振動によって安全装置が作動したのか、一定時間連続起動していると止まるのかわからないが、気がついたら止まっていることがある。
ということで、止まっていたら起動させるシェルスクリプトを書いて、Raspberry Piで動かすことにした。
さっそく実際にAPIを使って操作する事例ができた。 (SwitchBotのスマート加湿器をAPIで操作する )
完成物 🔗
リポジトリ 🔗
コード 🔗
シェルスクリプトはあまり書きなれていないからこれでいいのかわからん。
#!/bin/bash
set -eu
SCRIPT_DIR=$(cd $(dirname $0); pwd)
source "${SCRIPT_DIR}/.env"
power=$(
curl -s https://api.switch-bot.com/v1.0/devices/${SWITCHBOT_DEVICE_ID}/status \
-H "Authorization: ${SWITCHBOT_API_TOKEN}" \
| jq .body.power -r
)
if [[ $power = off ]]; then
curl -s -X POST https://api.switch-bot.com/v1.0/devices/${SWITCHBOT_DEVICE_ID}/commands \
-H "Authorization: ${SWITCHBOT_API_TOKEN}" \
-H 'Content-Type: application/json' \
-d '{"command": "turnOn","parameter": "default","commandType": "command"}' \
-o /dev/null
fi
使い方 🔗
リポジトリのREADMEを参照。
Upptimeでブログの死活監視をする
SwitchBotのスマート加湿器をAPIで操作する
SwitchBotのスマート加湿器
を買ったので、ご多分に漏れずAPIで操作してみる。
ちなみに買ったメインの目的が加湿器をAPIを使って操作してみたいという理由だけだけど、加湿器の機能としても大変満足している。
手順 🔗
ドキュメント: SwitchBotAPI/README.md at main · OpenWonderLabs/SwitchBotAPI
APIトークンを取得する 🔗
公式アプリから取得できる。(iPhoneでしか確認していないが、Androidも変わらないはず)
- 「プロフィール」をタップ
- 「設定」をタップ
- 「アプリバージョン」を10回タップ(「開発者向けオプション」が表示される)
- 「開発者向けオプション」をタップ(トークンが生成される)
デバイスを取得する 🔗
リクエスト 🔗
curl -X GET -H 'Authorization: token' https://api.switch-bot.com/v1.0/devices
レスポンス 🔗
{
"statusCode": 100,
"body": {
"deviceList": [
{
"deviceId": "AC0123456789",
"deviceName": "リビング加湿器",
"deviceType": "Humidifier",
"enableCloudService": true,
"hubDeviceId": "000000000000"
},
{
"deviceId": "XX0123456789",
"deviceName": "リビング温湿度計",
"deviceType": "Meter",
"enableCloudService": false,
"hubDeviceId": "000000000000"
}
],
"infraredRemoteList": []
},
"message": "success"
}
デバイスのステータスを取得する 🔗
リクエスト 🔗
$ curl -H 'Authorization: token' https://api.switch-bot.com/v1.0/devices/AC0123456789/status
レスポンス 🔗
{
"statusCode": 100,
"body": {
"deviceId": "AC0123456789",
"deviceType": "Humidifier",
"hubDeviceId": "000000000000",
"nebulizationEfficiency": 1,
"humidity": 43,
"auto": true,
"childLock": false,
"sound": true,
"power": "off",
"temperature": "19.9"
},
"message": "success"
}
デバイスにコマンドを送信する 🔗
https://github.com/OpenWonderLabs/SwitchBotAPI/blob/main/README.md#command-set-for-physical-devices
Nature RemoのローカルAPIを叩いて家電を操作する
Nature Remoはアプリなどから操作した際、たとえ家に居たとしてもクラウドAPIを経由して実行される仕様になっている
この仕様のせいで、Nature Remoのクラウドで障害が起きたときに電気が消すことができなくて不便な思いをしたので、次に障害が起きても問題ないようにローカルAPI経由でも家電を操作できるようにしておく
手順 🔗
公式ドキュメント: https://local-swagger.nature.global/
Nature RemoのIPアドレスを確認 🔗
Instance Nameを特定する 🔗
$ dns-sd -B _remo._tcp
Browsing for _remo._tcp
DATE: ---Thu 14 Jan 2021---
21:00:16.807 ...STARTING...
Timestamp A/R Flags if Domain Service Type Instance Name
21:00:21.766 Add 2 6 local. _remo._tcp. Remo-XXXXXX
IPアドレスを確認 🔗
Instance Nameに.local
を追加
$ dns-sd -G v4 Remo-XXXXXX.local
DATE: ---Thu 14 Jan 2021---
21:00:47.557 ...STARTING...
Timestamp A/R Flags if Hostname Address TTL
21:00:47.557 Add 40000002 6 Remo-XXXXXX.local. 192.168.10.3 120
赤外線信号の受信 🔗
Nature Remo本体にリモコンで信号を送ったあとに以下を実行する
$ curl -X GET http://192.168.10.3/messages -H "X-Requested-With: curl" -H "Expect:"
{"format":"us","freq":36,"data":[3401,1821,353,516,358,1387,356,506,361,509,360,509,360,510,383,482,353,516,353,516,358,508,358,510,360,509,358,511,350,1391,358,513,363,517,347,524,359,515,358,516,358,516,357,517,361,511,354,519,361,1386,355,517,360,510,348,514,353,516,363,507,358,507,386,483,360,509,359,1384,352,516,380,1361,350,1391,360,1387,361,1384,448,419,358,510,357,1383,360,509,442,1302,394,1354,356,1380,354,1392,358,509,353,1390,392,65535,0,8885,3403,1821,360,506,354,1390,359,509,359,511,358,506,363,507,353,516,360,82,65535,427,356,508,361,510,357,511,454,410,365,504,363,1382,348,524,352,521,352,525,357,520,355,518,356,517,356,515,359,514,361,513,362,1385,351,518,359,512,349,514,360,510,359,510,357,511,454,414,360,507,358,1384,352,517,359,1379,361,1382,360,1387,361,1383,354,515,350,518,360,1383,351,513,353,1392,358,1386,361,1384,358,1385,356,510,382,1360,357,65535,0,8923,3403,1825,349,523,359,1391,356,506,361,511,413,456,358,509,357,510,359,508,352,517,358,507,351,518,360,510,383,486,357,1381,362,508,350,518,358,511,355,511,359,509,353,518,356,511,358,507,361,510,358,1384,359,510,357,509,358,87,65535,422,362,506,361,508,359,507,359,512,358,508,352,1393,356,515,405,1343,358,1385,358,1382,354,1388,360,515,358,516,359,1390,355,511,358,1384,351,1392,358,1385,350,1394,360,509,362,1380,351]}
赤外線信号の送信 🔗
受信時に受け取ったものをそのままPOSTで送ってあげればよい
$ curl -X POST http://192.168.10.3/messages -H "X-Requested-With: curl" -H "Expect:" -d '{"format":"us","freq":36,"data":[3401,1821,353,516,358,1387,356,506,361,509,360,509,360,510,383,482,353,516,353,516,358,508,358,510,360,509,358,511,350,1391,358,513,363,517,347,524,359,515,358,516,358,516,357,517,361,511,354,519,361,1386,355,517,360,510,348,514,353,516,363,507,358,507,386,483,360,509,359,1384,352,516,380,1361,350,1391,360,1387,361,1384,448,419,358,510,357,1383,360,509,442,1302,394,1354,356,1380,354,1392,358,509,353,1390,392,65535,0,8885,3403,1821,360,506,354,1390,359,509,359,511,358,506,363,507,353,516,360,82,65535,427,356,508,361,510,357,511,454,410,365,504,363,1382,348,524,352,521,352,525,357,520,355,518,356,517,356,515,359,514,361,513,362,1385,351,518,359,512,349,514,360,510,359,510,357,511,454,414,360,507,358,1384,352,517,359,1379,361,1382,360,1387,361,1383,354,515,350,518,360,1383,351,513,353,1392,358,1386,361,1384,358,1385,356,510,382,1360,357,65535,0,8923,3403,1825,349,523,359,1391,356,506,361,511,413,456,358,509,357,510,359,508,352,517,358,507,351,518,360,510,383,486,357,1381,362,508,350,518,358,511,355,511,359,509,353,518,356,511,358,507,361,510,358,1384,359,510,357,509,358,87,65535,422,362,506,361,508,359,507,359,512,358,508,352,1393,356,515,405,1343,358,1385,358,1382,354,1388,360,515,358,516,359,1390,355,511,358,1384,351,1392,358,1385,350,1394,360,509,362,1380,351]}'
{}
参考 🔗
Nature Remo E用のGem作った
Nature Remo E / E lite用のAPIクライアント用のGemを作った。E liteでしか動作確認していないけど、Eでも使えるはず。
作った理由 🔗
- 単純にGemを作ってみたかった
- Nature RemoのGemは既に存在しているが、スマートメーターの値だけを取るだけなのにコードが長くなってしまうので、それ専用にGemを作ってコードを短くしたかった。
コードを短くすることができた具体例 🔗
【Nature Remo E lite】瞬時電力計測値をAmbientでグラフ化する で書いたコード
Before 🔗
require 'dotenv/load'
require 'nature_remo'
require 'ruby-ambient'
client = NatureRemo::Client.new(ENV['NATURE_REMO_API_TOKEN'])
response = client.appliances
appliances = JSON.parse(response.body, symbolize_names: true)
el_smart_meter = appliances.find { |appliance| appliance[:type] == 'EL_SMART_METER' }
echonetlite_properties = el_smart_meter[:smart_meter][:echonetlite_properties].each_with_object({}) do |echonetlite_property, hash|
hash[echonetlite_property[:name].to_sym] = echonetlite_property[:val].to_i
end
ambient = Ambient.new(ENV['AMBIENT_CHANNEL_ID'], write_key: ENV['AMBIENT_WRITE_KEY'])
ambient.send({ d1: echonetlite_properties[:measured_instantaneous] })
After 🔗
require 'dotenv/load'
require 'nature_remo_e'
require 'ruby-ambient'
client = NatureRemoE::Client.new(ENV['NATURE_REMO_API_TOKEN'])
ambient = Ambient.new(ENV['AMBIENT_CHANNEL_ID'], write_key: ENV['AMBIENT_WRITE_KEY'])
ambient.send({ d1: client.measured_instantaneous })
できること 🔗
- ECHONETプロパティ全てをHashクラスで取得できる
- ECHONETプロパティを個別に取得できる
名前 | プロパティ |
---|---|
normal_direction_cumulative_electric_energy | 積算電力量計測値(正方向) |
reverse_direction_cumulative_electric_energy | 積算電力量計測値(逆方向) |
coefficient | 係数 |
cumulative_electric_energy_unit | 積算電力量単位 |
cumulative_electric_energy_effective_digits | 積算電力量有効桁数 |
measured_instantaneous | 瞬時電力計測値 |
この名前はNature社が独自に命名したもので、将来的に変わる可能性があるとのこと。
【Nature Remo E lite】瞬時電力計測値をAmbientでグラフ化する
半年くらい前にNature Remo E lite
を買って放置していたが、せっかくなのでAmbient
に値を投げてグラフ化してみることにした。
Nature Remoの公式アプリでグラフは見れるので、正直何も意味はない。
API
でいろいろ値は取れるが、ばっと見、意味がわかるのは瞬時電力計測値くらいなのでそれを使う。
手順 🔗
コード 🔗
source 'https://rubygems.org'
git_source(:github) {|repo_name| 'https://github.com/#{repo_name}' }
gem 'dotenv'
gem 'nature_remo'
gem 'ruby-ambient'
NATURE_REMO_API_TOKEN=
AMBIENT_CHANNEL_ID=
AMBIENT_WRITE_KEY=
require 'dotenv/load'
require 'nature_remo'
require 'ruby-ambient'
client = NatureRemo::Client.new(ENV['NATURE_REMO_API_TOKEN'])
response = client.appliances
appliances = JSON.parse(response.body, symbolize_names: true)
el_smart_meter = appliances.find { |appliance| appliance[:type] == 'EL_SMART_METER' }
echonetlite_properties = el_smart_meter[:smart_meter][:echonetlite_properties].each_with_object({}) do |echonetlite_property, hash|
hash[echonetlite_property[:name].to_sym] = echonetlite_property[:val].to_i
end
ambient = Ambient.new(ENV['AMBIENT_CHANNEL_ID'], write_key: ENV['AMBIENT_WRITE_KEY'])
ambient.send({ d1: echonetlite_properties[:measured_instantaneous] })
Raspberry Piで動かす 🔗
GitHub Actionsで1分毎動かすのはちょっと気が引けたので、Raspberry Piで動かすことにした。
* * * * * cd /home/pi/workspace/nature_remo_e_lite_to_ambient/ && /home/pi/.rbenv/shims/bundle exec ruby app.rb
bundleだけだと、bundle: not found
になってしまったので、フルパスで呼び出した。
crontab何もわからん。
RubyでAmbientにデータを送信してグラフ化する
Ambient というIoTデータ向けの可視化サービスを見つけたので、RubyからAmbientにデータを送ってグラフを作るところまでをやってみた。
手順 🔗
1. ユーザー登録 🔗
2. チャネル作成 🔗
様々なグラフを表示するボードみたいなもの。(多分)
「チャネルを作る」ボタンを押すだけで生成される。
3. データ送信 🔗
ruby-ambientというGemがあったのでそれを使わせてもらう。
3.1 gemのインストール 🔗
$ gem install ruby-ambient
3.2 コード 🔗
require 'ruby-ambient'
am = Ambient.new('チャネルID', write_key: 'ライトキー')
am.send( { d1: 1, d2: 2.5 } )
# => #<Net::HTTPOK 200 OK readbody=true>
データはd1からd8まで8種類まで送ることができる。
最短の送信間隔は5秒。
4. グラフ作成 🔗
チャネル一覧画面のチャネル名をクリックするとボードが表示されるので、そこでグラフ追加のアイコンを押したらグラフを作れる。
データは最大1年分保持される。
参考 🔗
RustでHello, World!
Rustも触っておきたいなと思ったので、取り急ぎのHello, World!をやってみた。
手順 🔗
事前準備 🔗
RustのDockerイメージを取得し、コンテナに入る 🔗
$ docker pull rust:1.48.0
$ docker run -it --rm rust:1.48.0 bash
root@6819088df44e:/#
Vimのインストール 🔗
root@6819088df44e:/# apt update
root@6819088df44e:/# apt install -y vim
作業用ディレクトリを作成し、移動 🔗
root@6819088df44e:/# mkdir hello_world
root@6819088df44e:/# cd hello_world
root@6819088df44e:/hello_world#
Rustファイル作成 🔗
root@6819088df44e:/hello_world# vim main.rs
fn main() {
println!("Hello, World!");
}
コンパイル 🔗
root@6819088df44e:/hello_world# rustc main.rs
root@6819088df44e:/hello_world# ls
total 3136
-rwxr-xr-x 1 root root 3205040 Dec 30 12:41 main
-rw-r--r-- 1 root root 45 Dec 30 12:40 main.rs
mainという名前の実行可能ファイルができている。
実行 🔗
root@6819088df44e:/hello_world# ./main
Hello, world!
参考 🔗
Raspberry Pi上にDocker ComposeでHomebridgeを起動する
Raspberry Pi上にDocker ComposeでHomebridgeを起動する手順。
手順 🔗
ディレクトリを作成し、移動 🔗
$ mkdir /path/to/homebridge
$ cd /path/to/homebridge
docker-compose.ymlを作成 🔗
$ vim docker-compose.yml
version: '3'
services:
homebridge:
image: oznu/homebridge:raspberry-pi
restart: always
network_mode: host
volumes:
- ./config:/homebridge
environment:
- PGID=1000
- PUID=1000
- HOMEBRIDGE_CONFIG_UI=1
- HOMEBRIDGE_CONFIG_UI_PORT=8080
起動 🔗
$ docker-compose up -d
起動ログ 🔗
$ docker-compose logs -f
...
homebridge_1 | Enter this code with your HomeKit app on your iOS device to pair with Homebridge:
homebridge_1 |
homebridge_1 | ┌────────────┐
homebridge_1 | │ XXX-XX-XXX │
homebridge_1 | └────────────┘
homebridge_1 |
homebridge_1 | [12/26/2020, 10:14:29 PM] Homebridge v1.2.4 is running on port 51393.
homebridge_1 | [12/26/2020, 10:14:31 PM] [Homebridge UI] Homebridge Config UI X v4.36.0 is listening on :: port 8080
homebridge_1 | [12/26/2020, 10:14:32 PM] [Homebridge UI] Added new user: admin
homebridge_1 | [12/26/2020, 10:14:32 PM] [Homebridge UI] Username and password have been set to default:
homebridge_1 | [12/26/2020, 10:14:32 PM] [Homebridge UI] Username: admin
homebridge_1 | [12/26/2020, 10:14:32 PM] [Homebridge UI] Password: admin
確認 🔗
http://192.168.10.2:8080
にアクセスする。
RailsにTailwindCSSを導入する
Rails6.1にTailwind CSS v1.9.6を導入した手順。
Tailwind CSSのv2系はまだ対応していない部分が多いため、v1.9.6にした。
参考: https://tailwindcss.com/docs/installation#post-css-7-compatibility-build
環境 🔗
- Ruby: 2.7.2
- Rails: 6.1.0
- Node.js: v12.20.0
- Yarn: 1.22.5
手順 🔗
Tailwind CSSの導入 🔗
$ yarn add [email protected]
$ yarn tailwindcss init # tailwind.config.jsというファイルが生成される
$ mkdir app/javascript/css
$ vim app/javascript/css/tailwindcss.css
$ vim app/javascript/packs/application.js
$ vim app/views/layouts/application.html.erb
$ vim postcss.config.js
module.exports = {
purge: [],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"
+ import "../css/tailwindcss.css";
Rails.start()
Turbolinks.start()
ActiveStorage.start()
<head>
<title>App</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
- <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
+ <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
module.exports = {
plugins: [
+ require('tailwindcss'),
+ require('autoprefixer'),
require('postcss-import'),
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
})
]
}
動作確認 🔗
適当のページを作って確認する。
Raspberry PiにDockerとDocker Composeをインストールする
Raspberry PiにDockerとDocker Composeをインストールした。
$ cat /etc/debian_version
10.6
Docker 🔗
1. ダウンロードとインストール 🔗
$ curl -sSL https://get.docker.com | sh
2. 権限を追加 🔗
$ sudo usermod -aG docker pi
3. Dockerサービスの有効化 🔗
$ sudo systemctl enable docker
4. 再起動 🔗
$ sudo reboot
確認 🔗
$ docker -v
Docker version 20.10.1, build 831ebea
Docker Compose 🔗
1. GitHubからClone、ブランチ切り替え 🔗
$ git clone https://github.com/docker/compose.git
$ cd compose/
$ git checkout 1.27.4
現時点で最新版の1.27.4のブランチに切り替え。
2. ビルド 🔗
$ ./script/build/linux
約20分くらい掛かった。
distディレクトリが作られ、その中にバイナルができる。
この状態で一応動作確認。
$ ./dist/docker-compose-Linux-armv7l -v
docker-compose version 1.27.4, build 40524192
3. /usr/local/binにコピー 🔗
$ sudo cp dist/docker-compose-Linux-armv7l /usr/local/bin/docker-compose
4. 所有者をrootに変更 🔗
$ sudo chown root:root /usr/local/bin/docker-compose
5. 実行権限を追加 🔗
$ sudo chmod +x /usr/local/bin/docker-compose
確認 🔗
$ docker-compose -v
docker-compose version 1.27.4, build 40524192
参考 🔗
Raspberry Piを使ってSwitchBot 温湿度計のデータをMackerelで可視化する
この記事は、「Raspberry Pi Advent Calendar 2020 」16日目の記事です。
はじめに 🔗
最近、SwitchBot 温湿度計を購入しました。
いろいろ連携させるためには別でSwitchBotハブというものが必要みたいで、急遽代わりにRaspberry Piも購入しました。
(SwitchBotハブではなくRaspberry Piを購入した理由は、スマートリモコンはNature Remoを使っているのでいらなかったのとRaspberry Piなら他にも有効活用できると思ったので。)
今回はRaspberry Piを使って温度や湿度をMackerelで可視化してみたという記事です。
SwitchBot 温湿度計 🔗
SwitchBot(スイッチボット) 温湿度計,スマホで温湿度管理,スマート家電, Alexa, GoogleHome, IFTTT対応
手順 🔗
各種バージョン 🔗
- Raspberry Pi OS: 10.6
- Python: 3.7.3
- pip: 18.1
- mackerel-agent: 0.70.3
1. SwitchBot 温湿度計のデータを読み取るスクリプトを作成する 🔗
既に実装されている方がいらしたので、参考にさせていただきました。(参考にリンク貼ってあります。)
そのままmackerel-agentで使えるフォーマットで値を出力しています。
{metric name}\t{metric value}\t{epoch seconds}
1.1. 必要なパッケージをインストール 🔗
$ sudo apt-get install libglib2.0-dev
1.2. bluepyのインストール 🔗
$ pip3 install bluepy
1.3. bluepy-helperにsudo権限を付与する 🔗
$ sudo setcap 'cap_net_raw,cap_net_admin+eip' bluepy-helper
1.4. SwitchBot 温湿度計のMACアドレスを確認する 🔗
SwitchBot公式アプリで確認することができます。別記事で書いたのでそちらを参照してください。1