3000円の体重計で、体重計に乗ったらツイートされるようにする

だいたいこんな感じで動く

体重計→体重系スマホアプリ→fitbit→ifttt→twitter

利点: サーバレス

欠点: 体重計に乗るときはスマホ必須

体重計を買う

MASARUの体重体組成計を買う。 これ、bluetoothで通信できて、専用アプリに記録したり、iOS Healthやfitbitと連携できる。 そんでもって3000円で激安。

www.amazon.co.jp

体重計のスマホアプリをインストールする

MASARUをインストールする。 体組成計なので、結構いろいろ測れて面白い。

f:id:miettal:20190118003238j:plain

fitbitに登録する

fitbitってwearable deviceの印象が強かったけど、健康管理プラットフォームなクラウドもやってるんだー。

www.fitbit.com

体重計のスマホアプリをfitbitに連携する

体重を測るとスマホ経由でfitbitにアップロードされるようになる。

f:id:miettal:20190118003254j:plain

iftttにルールを書く

fitbitに体重がアップロードされたら、それをツイートするルールを書く。 iOS Healthはトリガー対応してないから、fitbitでやらざるを得ないんだよねー。

f:id:miettal:20190118003841p:plain

体重計に乗る

ツイートされる。 おー。

Nature Remoに存在しないボタンを登録する

我が家の照明は、リモコンで操作できる。 なので、Nature Remoからももちろん操作できるのだが、リモコンにあるボタンはON/OFFを切り替えるボタンしかない。 そのため、明示的にONにしたり、OFFにしたりすることはできない。 しかし、同じメーカーの他の照明リモコンを見てみるとONのボタンとOFFのボタンが存在している。 これは推測だが、おそらくプロトコル上、実装上存在しているが、廉価なモデルのリモコンのため省略されていると考えられる。 そこで、Nature RemoのAPIを駆使し、物理的に存在しないが、プロトコル上、実装上存在していると考えられるONボタンとOFFボタンを調査し、Nature Remoから照明のONとOFFを操作できるようにする。

f:id:miettal:20190112150510j:plain
MARUZEN ELECTRIC CO., LTD. MD3

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の変調信号になっている。

プロトコルの詳細は書きを参照されたい。

elm-chan.org

そして、この結果を、ぱっと見た感じ、

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(伏せ字)と表す。

Home

次に、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のボタンが登録された。

f:id:miettal:20190112150706p:plain
Nature Remo App

ぱちぱちぱち

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で使いたい。

やり方

たぶんubuntu, debianでも動く。

$ 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は毎回しないといけない。

よくアクセスのくる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) Google アメリ 検索エンジン
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) Google アメリ 検索エンジン
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 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 Twitter アメリ 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 Google アメリ 検索エンジン
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 Google アメリ 検索エンジン
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,サイト分析

結婚しました

f:id:miettal:20180708090734j:plain

詳細はオフラインで聞いてください。

↓ほしいものリスト

https://www.amazon.co.jp/hz/wishlist/ls/3SX1YMWCRKTS6?&sort=default

@warabanshi さんからフライパンいただきました。ありがとうございます。

@dodododdodo_su_ さんから電動ミルいただきました。ありがとうございます。