3000円の体重計で、体重計に乗ったらツイートされるようにする
だいたいこんな感じで動く
体重計→体重系スマホアプリ→fitbit→ifttt→twitter
利点: サーバレス
欠点: 体重計に乗るときはスマホ必須
体重計を買う
MASARUの体重体組成計を買う。 これ、bluetoothで通信できて、専用アプリに記録したり、iOS Healthやfitbitと連携できる。 そんでもって3000円で激安。
体重計のスマホアプリをインストールする
MASARUをインストールする。 体組成計なので、結構いろいろ測れて面白い。
fitbitに登録する
fitbitってwearable deviceの印象が強かったけど、健康管理プラットフォームなクラウドもやってるんだー。
体重計のスマホアプリをfitbitに連携する
体重を測るとスマホ経由でfitbitにアップロードされるようになる。
iftttにルールを書く
fitbitに体重がアップロードされたら、それをツイートするルールを書く。 iOS Healthはトリガー対応してないから、fitbitでやらざるを得ないんだよねー。
体重計に乗る
ツイートされる。 おー。
67.5 kilograms (23.93 BMI) January 17, 2019 at 09:15PM via Fitbit
— Hiromasa Ihara(たいしょー) (@miettal) January 17, 2019
Nature Remoに存在しないボタンを登録する
我が家の照明は、リモコンで操作できる。 なので、Nature Remoからももちろん操作できるのだが、リモコンにあるボタンはON/OFFを切り替えるボタンしかない。 そのため、明示的にONにしたり、OFFにしたりすることはできない。 しかし、同じメーカーの他の照明リモコンを見てみるとONのボタンとOFFのボタンが存在している。 これは推測だが、おそらくプロトコル上、実装上存在しているが、廉価なモデルのリモコンのため省略されていると考えられる。 そこで、Nature RemoのAPIを駆使し、物理的に存在しないが、プロトコル上、実装上存在していると考えられるONボタンとOFFボタンを調査し、Nature Remoから照明のONとOFFを操作できるようにする。

Nature RemoのIPアドレスを調べる
IPアドレスがわからないと、Local APIを叩けないので調べる。
まず、Nature Remoと同じネットワーク(LAN)につなぐ。
つぎに、mDNSでサービスタイプから、インスタンス名を引く。
$ dns-sd -B _remo._tcp
Browsing for _remo._tcp
DATE: ---Sat 12 Jan 2019---
13:33:50.261 ...STARTING...
Timestamp A/R Flags if Domain Service Type Instance Name
13:33:50.413 Add 3 5 local. _remo._tcp. Remo-4A8BDD
13:33:50.413 Add 2 5 local. _remo._tcp. Remo-9086AB
リビングルームとダイニングルームのNature Remoが見つけられる。
最後に、mDNSでインスタンス名からIPv4アドレスを引く。
$ dns-sd -G v4 Remo-4A8BDD.local
DATE: ---Sat 12 Jan 2019---
13:40:19.941 ...STARTING...
Timestamp A/R Flags if Hostname Address
TTL
13:40:19.942 Add 2 5 Remo-4A8BDD.local. 192.168.0.18 120
これでリビングルームのNature RemoのIPアドレスがわかった。
受信した信号を見る
Nature Remoに対して、照明リモコンのON/OFFボタンを押して、赤外線信号を送信する。
Nature Remo Local APIのmessage APIで、Nature Remoが受信した信号を見る。
$ curl -s -X GET 'http://192.168.0.4/messages' -H 'X-Requested-With: curl'
{"format":"us","freq":37,"data":[4675,2627,564,959,572,1850,563,1863,562,958,564,1860,571,1849,566,956,575,949,564,959,571,1849,574,1850,575,952,571,1850,570,1854,572,1849,564,961,571,1847,568,1859,568,951,566,955,573,951,565,955,564,965,562,1854,576,948,567,956,565,957,572,950,571,951,571,953,570,950,572,945,572,16480,4670,2633,565,959,562,1860,572,1848,574,952,571,1849,573,1851,573,949,573,950,564,956,575,1849,576,1850,562,959,575,1848,572,1853,562,1857,566,959,572,1848,567,1859,570,951,571,953,563,956,565,959,570,951,567,1858,571,949,573,951,564,957,572,949,575,949,564,955,574,948,574,944,566,16484,4682,2624,571,951,564,1859,564,1858,572,952,571,1849,569,1855,573,951,571,949,566,960,562,1857,577,1849,570,951,565,1861,569,1850,574,1849,576,946,575,1849,573,1850,571,953,565,955,573,950,574,947,575,946,574,1852,570,953,570,949,566,959,563,956,573,952,563,959,564,960,569,943,574]}
data配列の各要素は、赤外線ONの期間、OFFの期間、ONの期間、OFFの期間、、、、を表している。 厳密には、これは38kHzの変調をデコードしたあとの結果である。実際にはONの期間は38kHzの変調信号になっている。
プロトコルの詳細は書きを参照されたい。
そして、この結果を、ぱっと見た感じ、
NECフォーマット
T=560us
リーダーコード: ON:4T, OFF:8T,
ビット0: ON: 1T, 1.7T
ビット1: ON: 1T, 3.4T
であることがわかる。
プログラムに噛ませて赤外線信号を16進4バイトのデータにデコードする。
$ cat decode.py
import sys
import json
obj_txt = sys.stdin.read()
obj = json.loads(obj_txt)
bit_array = [int(not x < 1100) for x in obj['data'] if 900 < x < 2000]
byte_array = [sum([x<<i for (i, x) in enumerate(x)]) for x in zip(*[iter(bit_array)]*8)]
print(' '.join(["{:02x}".format(x) for x in byte_array]))
$ curl -s -X GET 'http://192.168.0.4/messages' -H 'X-Requested-With: curl' | python decode.py
36 76 83 00 36 76 83 00 36 76 83 00
これで、データがわかった。これをすべてのボタンに対して行い、ボタンに対応するデータの一覧を得る。
(ch1)
Button | Data |
---|---|
豆球 | 36 76 48 00 |
オフタイマー60 | 36 76 80 00 |
オフタイマー30 | 36 76 82 00 |
ON/OFF | 36 76 84 00 |
明るく | 36 76 86 00 |
暗く | 36 76 88 00 |
(ch2)
Button | Data |
---|---|
豆球 | 36 76 47 00 |
オフタイマー60 | 36 76 8f 00 |
オフタイマー30 | 36 76 81 00 |
ON/OFF | 36 76 83 00 |
明るく | 36 76 85 00 |
暗く | 36 76 87 00 |
これらの結果から、おそらく3バイト目が照明の各ボタンの操作に対応していると推察できる。 これから、この3バイト目を書き換えて、赤外線を送信し、ONとOFFに対応するデータを探す。
受信した信号を見る
プログラムに噛ませて16進4バイトのデータを赤外線信号にデコードする。 そして、Nature Remo Local APIのmessage APIで、照明に対して赤外線を送信する。
$ cat encode.py
import sys
import json
byte_array = [int(x, 16) for x in sys.stdin.read().split(' ')]
data = [4668,2636]
for x in byte_array:
for i in range(8):
b = (x>>i)&1
if b == 1:
data += [562, 1877]
else:
data += [562, 951]
data += [548, 16504]
obj = {
'format': 'us',
'freq': 37,
'data': data,
}
obj_txt = json.dumps(obj)
sys.stdout.write(obj_txt)
$ echo "36 76 83 00" | python encode.py | curl -X POST 'http://192.168.0.4/messages' -H 'X-Requested-With: curl' -d @-
無事照明が点いた(消えていたのでON/OFFボタンで点灯した)。
3バイト目を書き換えてみて、動作するボタンと、動作内容の一覧を得る。
(ch1)
Button | Data |
---|---|
ON | 36 76 42 00 |
OFF | 36 76 4a 00 |
(ch2)
Button | Data |
---|---|
ON | 36 76 41 00 |
OFF | 36 76 49 00 |
41がON、49がOFFに対応していることがわかった。 これから、Nature Remo Cloud APIを使って、Nature Remoにボタンを登録する。
信号を登録する
まず、Nature Remo Global APIのアクセス用のトークンを生成し、取得する。以降トークンはXXXX(伏せ字)と表す。
次に、Nature Remo Global APIののappliances APIで、機器の一覧を見る。
$ curl -s -X GET "https://api.nature.global/1/appliances" -H "Authorization: Bearer XXXX" | python -mjson.tool
(snip)
{
"id": "YYYY",
"device": {
"name": "Living Room",
"id": "XXXX",
(snip)
},
"model": null,
"type": "IR",
"nickname": "Living Room Light",
"image": "ico_light",
"settings": null,
"aircon": null,
"signals": [
(snip)
]
},
(snip)
機器のIDがわかる。以降機器のIDはYYYY(伏せ字)とする。
最後に、Nature Remo Global APIののsignals APIで、赤外線信号を登録する。
$ echo "36 76 41 00" | python encode.py | urlencode
%7B%22format%22%3A%20%22us%22%2C%20%22freq%22%3A%2037%2C%20%22data%22...5D%7D
$ curl -s -X POST "https://api.nature.global/1/appliances/YYYY/signals" -H "Authorization: Bearer XXXX" -d "message=ZZZZ&image=ico_on&name=ON"
{"id":"XXXX","name":"ON","image":"ico_on"}
$ echo "36 76 49 00" | python encode.py | urlencode
%7B%22format%22%3A%20%22us%22%2C%20%22freq%22%3A%2037%2C%20%22data%22...5D%7D
$ curl -s -X POST "https://api.nature.global/1/appliances/YYYY/signals" -H "Authorization: Bearer XXXX" -d "message=ZZZZ&image=ico_off&name=OFF"
{"id":"XXXX","name":"OFF","image":"ico_off"}
無事、ONのボタンと、OFFのボタンが登録された。
ぱちぱちぱち
gem install で certificate verify failed と出てgemがインストールできないのを直す
応急処置的だが。
こんなの出る
$ gem install rubocop
ERROR: Could not find a valid gem 'rubocop' (>= 0), here is why:
Unable to download data from https://rubygems.org/ - SSL_connect returned=1 errno=0 state=error: certificate verify failed (https://api.rubygems.or│
g/latest_specs.4.8.gz)
updateもできない
$ gem update --system
ERROR: While executing gem ... (Gem::RemoteFetcher::FetchError)
SSL_connect returned=1 errno=0 state=error: certificate verify failed (https://api.rubygems.org/specs.4.8.gz)
sourceからhttpsを消して、httpを入れる
$ gem sources --remove https://rubygems.org/
https://rubygems.org/ removed from sources
$ gem sources -a http://rubygems.org/
https://rubygems.org is recommended for security over http://rubygems.org/
Do you want to add this insecure source? [yn] y
http://rubygems.org/ added to sources
updateする
$ gem update --system
Updating rubygems-update
(snip)
RubyGems system software updated
sourceからhttpを消して、httpsを入れる
$ gem sources --remove http://rubygems.org/
http://rubygems.org/ removed from sources
$ gem sources -a https://rubygems.org/
https://rubygems.org/ added to sources
直った
$ gem install rubocop
Fetching: jaro_winkler-1.5.1.gem (100%)
(snip)
インターリンクのマイIPで、Raspberry PiにグローバルIPアドレスを割り当てる
インターリンク マイIPとは
pptp, l2tpで接続するとグローバルIPアドレスが振ってくるサービス。月額1080円。 これをRaspberry Piで使いたい。
やり方
$ sudo apt-get install pptp-linux ★1
$ sudo pptpsetup --create myip --server <VPNサーバ(ホスト名、IPアドレスどちらでも)> --username <ユーザー名> -password <パスワード> --encrypt ★2
$ sudo pppd call myip updetach persist ★3
$ sudo ip route del default dev eth0 ★4
$ sudo ip route add default via <割当IPアドレス> ★5
解説
★1 pptpクライアントを入れる
★2 pptpのプロファイルを作成する。myipはプロファイル名
★3 pppセッションを開始する(=> この時点でトンネルが作られる)、persistをつけるとセッション切れてもやり直してくれる。自動で立ち上げたいのならば、rc.dなどにスクリプトを置くと良い。
★4 有線LANのデフォルトゲートウェイの設定を消す
★5 pppセッションの接続をデフォルトゲートウェイにする、pppが切れると消えるので、if-up.dなどにスクリプトを置いて、pppが上がったときにキックするようにすると良い。
★1〜★2は設定なので1回するだけでよし。
★3〜★5は毎回しないといけない。
はてなブログの横幅を変えた
↓を参考に変えた。
/* 全体の横幅 */
#content {
width: 1400px;
}
/* 記事の横幅 */
#main {
width: 1050px;
}
/* サイドバーの横幅 */
#box2 {
width: 300px;
}
よくアクセスのくるUserAgent
追記 上からアクセス数順にソートした。
UserAgent | サービス | 国 | 概要 |
---|---|---|---|
Mozilla/5.0 (compatible; SemrushBot/2~bl; +http://www.semrush.com/bot.html) | Semrush | ドミニカ | SEO,サイト分析 |
Mozilla/5.0 (compatible; MJ12bot/v1.4.8; http://mj12bot.com/) | Majestic | イギリス | SEO,サイト分析 |
Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) | アメリカ | 検索エンジン | |
Mozilla/5.0 (compatible; DotBot/1.1; http://www.opensiteexplorer.org/dotbot, help@moz.com) | Moz | アメリカ | SEO,サイト分析 |
Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm) | Being(Microsoft) | アメリカ | 検索エンジン |
Mozilla/5.0 (compatible; AhrefsBot/5.2; +http://ahrefs.com/robot/) | Ahrefs | シンガポール | SEO,サイト分析 |
Mozilla/5.0 (compatible; MJ12bot/v1.4.7; http://mj12bot.com/) | Majestic | イギリス | SEO,サイト分析 |
NINJA bot | NINJA | 日本 | ソーシャルボタン |
Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) | アメリカ | 検索エンジン | |
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36; 360Spider | Haosou(旧360spider) | 中国 | 検索エンジン |
ICC-Crawler/2.0 (Mozilla-compatible; ; http://ucri.nict.go.jp/en/icccrawler.html) | ICC(NICT) | 日本 | 学術収集 |
Mediapartners-Google | アメリカ | 検索エンジン | |
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.4.2661.102 Safari/537.36; 360Spider | Haosou(旧360spider) | 中国 | 検索エンジン |
Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm) | Being(Microsoft) | アメリカ | 検索エンジン |
Mozilla/5.0 (compatible; proximic; +https://www.comscore.com/Web-Crawler) | comScore | アメリカ | SEO,サイト分析 |
Twitterbot/1.0 | アメリカ | SNS | |
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5 (Applebot/0.1; +http://www.apple.com/go/applebot) | Apple | アメリカ | 検索エンジン |
MauiBot (crawler.feedback+wc@gmail.com) | ? | ? | ? |
Mozilla/5.0 (compatible; AlphaBot/3.2; +http://alphaseobot.com/bot.html) | ? | ? | SEO,サイト分析 |
Mozilla/5.0 (compatible; GrapeshotCrawler/2.0; +http://www.grapeshot.co.uk/crawler.php) | Grapeshot(Oracle) | アメリカ | SEO,サイト分析 |
Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots) | Yandex | ロシア | 検索エンジン |
CCBot/2.0 (http://commoncrawl.org/faq/) | CommonCrawl | アメリカ | 学術収集 |
Java/1.6.0_04 | javaライブラリ | - | - |
IAS crawler (ias_crawler; http://integralads.com/site-indexing-policy/) | IAS | アメリカ | SEO,サイト分析 |
Sogou web spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07) | Sogou | 中国 | 検索エンジン |
Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Googlebot/2.1; +http://www.google.com/bot.html) Safari/537.36 | アメリカ | 検索エンジン | |
Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html) | Baidu | 中国 | 検索エンジン |
python-requests/2.18.4 | pythonライブラリ | - | - |
Mozilla/5.0 (compatible; MegaIndex.ru/2.0; +http://megaindex.com/crawler) | MegaIndex | ? | SEO,サイト分析 |
Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53 BingPreview/1.0b | |||
crawler/1.0 | ? | ? | ? |
Googlebot-Image/1.0 | アメリカ | 検索エンジン | |
bidswitchbot/1.0 | ? | ? | ? |
Mozilla/5.0 (compatible; ExtLinksBot/1.5; +https://extlinks.com/Bot.html) | ? | ? | ? |
ShortLinkTranslate | TrendMicro | 日本 | アンチウイルスソフト |
Mozilla/5.0 (compatible; proximic; +http://www.proximic.com/info/spider.php) | comScore | アメリカ | SEO,サイト分析 |
結婚しました
詳細はオフラインで聞いてください。
↓ほしいものリスト
https://www.amazon.co.jp/hz/wishlist/ls/3SX1YMWCRKTS6?&sort=default
@warabanshi さんからフライパンいただきました。ありがとうございます。
ほしい物リストきたぁー pic.twitter.com/MQTzsZNEq0
— Hiromasa Ihara(たいしょー) (@miettal) 2018年7月7日
@dodododdodo_su_ さんから電動ミルいただきました。ありがとうございます。
ほしい物リストの電動ミルきたぁー pic.twitter.com/rkth1Dmeoi
— Hiromasa Ihara(たいしょー) (@miettal) 2018年7月9日