ブログ

κυσο βλογ

M2Xの調子が悪い

珍しくM2Xのサーバが落ちている

f:id:XX-Prime:20191005131241p:plain
M2X_down
ほとんど落ちないM2Xのサーバが珍しく停止しているのでメモ。

M2X状態モニタを見る

上の画像でリンクがある、M2X状態モニタにアクセスしてみると、現在の状態とインシデントログを見ることができる。

f:id:XX-Prime:20191005131953p:plain
status-m2x.att.com
こういうながーいスクリーンキャプチャは、chromeのデフォルト機能でできることを今知った。参考リンク
requlog.com

2019年10月3日に障害が発生して一旦収まったものの、問題は悪化しているようだ。
現時点でレスポンスタイムが0に見えるのは、単にサーバが機能していないからである。

まとめ

珍しいこともあるもんだ。
複数サイトへのデータアップロードをしておけばよかった。
今はどのあたりのサイトがいいんだろうか。
M2Xが落ちるという想定はしていなかった。

M2Xで日本時間を扱う

今更だがM2Xはタイムゾーンに対応していた

M2Xで日本時間をうまく扱えるコードとそうでないコードがあってどこに差があるのかわからず不思議でしかたなかったが、今わかったのでメモ。

pythonのM2Xモジュールのサンプルを見てみる

github.com

これの時刻まわりのサンプル部分に

>>> from datetime import datetime
>>> device = client.device('188a0afb3adc379706e780a4eafbd153')
<m2x.v2.devices.Device at 0x1652fd0>
>>> device.post_updates(values={
    'stream1': [
        {
            'timestamp': datetime.now(),
            'value': 100
        }, {

と書いてあり、エラーもなく実行できるが9時間前のUTC時刻としてデータが記録されて、グラフ表示も9時間前のデータポイントとして表示される。そんなもんか、と納得していたが、node.jsのM2Xモジュールでアップロードしたデータをグラフで見ると、ちゃんと日本時間で記録されたデータポイントとして表示される。上手くいってるnode.jsの方の時刻指定は以下のような感じである。

  var at = new Date().toISOString();
  var values = {
    temperature_enocean: [
      { value: message['value']['temperature'], timestamp: at } ],
    humidity_enocean: [
      { value: message['value']['humidity'], timestamp: at } ],
    enocean_rssi: [
      { value: message['dbm'], timestamp: at } ]
  };
  m2x_client.devices.postUpdates(
    M2X_DEVICE_ID, { values: values }, function(result) {
      console.log(result);
      if (result.isError()) {
        // Stop the update loop if an error occurs.
        //stopLoop();
        console.log(JSON.stringify(response.error()));
      }
    }
  );

つまり、toISOString()でISO8601形式に変換した文字列をセットしている。これをpythonでも真似て

            now = datetime.datetime.utcnow().isoformat()
            m2xDevice.post_updates(values={
                'temperature': [
                    {
                        'timestamp': now,
                        'value': sensor.data.temperature
                    }
                ],
                'humidity': [
                    {
                        'timestamp': now,
                        'value': sensor.data.humidity
                    }
                ],
                'pressure': [
                    {
                        'timestamp': now,
                        'value': sensor.data.pressure
                    }
                ],
                'air_quality_score': [
                    {
                        'timestamp': now,
                        'value': air_quality_score
                    }
                ]
            })

とやった所、日本時間でデータを表示できるようになった。下図はisoformat()を追加してから時刻が正常になって9時間分未来に飛んだ様子である。
f:id:XX-Prime:20180709214810p:plain

まとめ

pythonのM2Xモジュールを使っていてデータを日本時間で表示できない場合は、時刻指定でisoformat()を追加すると正常になる。

Xively personal が2018年の1月15日に停止する

メールでXively personal停止のお知らせが来た

2018年の1月15日 午後12:00(たぶんUTC) にxively personalが消滅するというお知らせメールが2017年の12月22日の午前2時(JST)に来た。
サービス消滅まで1ヶ月もない突然のお知らせというのはなかなか例が無い。

メールで推奨されている選択肢は2つ

有料のXively Enterprise に移行

ねえな。

他の無料サービスに移行

xivelyがおすすめしている無料サービスは以下の3つ

  1. Adafruit https://learn.adafruit.com/category/adafruit-io
  2. Thingspeak https://thingspeak.com/
  3. SparkFun https://www.sparkfun.com/

どれも試したことがないのでコメントできない。

データは貴重

何もしないとこれまでアップロードしてきたデータが全て消えてしまう。
特に、長い期間データをため続けてきた場合、欠損値も含めて極めて貴重な実測データなので、このまま消えて無くなるのはあまりに損失が大きい。
気の利いたマトモなサービス屋だと、サービス停止までには3ヶ月から半年程度の猶予と、データをエクスポートする手段も提供するが、xivelyを買収したlogmeinはそうではなく一ヶ月も猶予無くデータを消すよ、と言っておる。鬼畜だね。
よってデータをエクスポートするコードを自分で作る必要がある。一気に全て持ってこようとすると、apiのアクセス制限に引っかかるだろうから、少しずつgetするコードが必要だろう。
まずapiの制限を調べて、制限の元で動くエクスポートプログラムを書かないといけない。2018年の1月15日までに全データをgetできるように。うわめんどくせ。

メール本文

サービスのダメダメな終わり方の貴重な資料として、メール本文を以下に記録しておこう:

After careful consideration, LogMeIn has made the decision to retire Xively Personal from its current line of products effective January 15, 2018 at 12:00PM ET . Please note that LogMeIn will continue to offer our Xively Enterprise edition – there is no change to that edition and we will continue to support that platform as part of our IoT business.

Retiring a product is never an easy decision, and we recognize it does introduce potential challenges to active users. So we want to make sure you have all the information you need to make as seamless a transition as possible.

Access to your account:
Your Xively Personal account will remain active until January 15th. Please note that devices will not be accessible via the Xively Personal service once it is retired.

Transferring your products to another IoT service:
Should you choose to switch to another service, there are essentially two options.

1) Migrate to Xively Enterprise: The latest Enterprise version of Xively is built on a more modern and reliable architecture, which brings the benefits of pre-built hardware integrations, identity and device management features, MQTT messaging, and best-in-class security, but it may require some reconfiguring of your current devices. We do offer a 30 day free trial of Xively Enterprise should you want to try it out for yourself.

2) Migrate to another free service: If your use is primarily for experimenting and personal projects, there are several free IoT platform options on the market, such as Adafruit, Thingspeak, or SparkFun.

Please note that while no changes will be made to your account or service until January 15th, we recommend taking action to start your transition at your earliest convenience.

If you have questions, you can reach out to our team at xivelypersonal@logmein.com

The Xively Team

まとめ

完成度の高かったサービスだけに終了は残念だ。が、無料でよくここまで続いたという見方もできる。終わらせ方は最低の部類と言える。

Withings Activité Steel にCR2032を入れたら約10ヶ月稼働した

はじめに

この記事はメーカー推奨の電池ではない電池を入れて使うという鬼畜の所業について書き記したものである。万が一、マネをして生じたいかなる故障・事故などについて当方は一切責任を負わない。無用なトラブルを避けて平穏に人生を送りたい賢い人たちはこの先は読まないはずである。トラブル万歳の賢くない鬼畜だけ続きをどうぞ。

Activité Steel とは

かつて存在した、おフランスのメーカーWithings社が販売していて、今はNokiaに買収されたのでNokiaブランドで売られている活動量計つきの腕時計である。
health.nokia.com
めんどくさいので詳細は省略。

Activité Steel の電池

support.health.nokia.com

を見ると、メーカー推奨の電池はCR2025ということになっている。

Nokiaの時計を最適にご利用いただけるよう、ご使用いただく電池はパナソニック製やRENATA製のボタン電池を推奨いたします。

という一文は全く意味不明で、何らかの業界政治的な意図しか感じられない。

CR XX XX とかの意味

最初の二文字が、電池の化学組成と形状を表している。詳しくは:
電池の種類がわからない方|一般社団法人 電池工業会
CRはリチウム一次電池(使い切り・充電不可能)で、コイン型を意味している。

次の2025は
www.sony.jp
によると

※寸法が4桁の場合は前2桁が外径、後ろ2桁が高さ

とのことなので、直径が20mmで厚みが2.5mmということになる。

Activité Steel に CR2032を入れてみると

f:id:XX-Prime:20171123173401j:plain

こんな感じで僅かに出っ張っているようにも見えるが普通に入る。蓋を装着して押し込むとパチンという音とともに普通に閉まる。もしここで蓋が閉まらない個体は諦めた方が良いだろう。たぶん水没させると壊れるよ。

電池寿命

メーカーが推奨する電池がCR2025で、最長8ヶ月の電池寿命と謳っている。
今回私は2017年の1月28日にSONY製のCR2032を入れて、本日2017年の11月23日に動作を停止した。よって、約10ヶ月の電池寿命であった。
なお、バイブレーションアラームはほぼ使用していない。

評価

コイン電池の直径が同じ場合、電池の内部エネルギーは厚みに比例するという大雑把な仮説を採用して、CR2025とCR2032の違いを評価してみる。CR2032はCR2025の1.28倍のエネルギー(容量)を持つので、メーカーが謳う最長電池寿命の8ヶ月を1.28倍してみると10.24ヶ月となり、そこそこの精度で今回の結果を説明できると言えるだろう。

もっと厚みのある電池はないのか

Activité Steel の蓋の裏には紙のようなスペーサーがあって、もうすこし厚い電池でも無理やり入りそうな雰囲気がある。が、残念ながらCR20XXシリーズで最も厚みのある規格がCR2032で、それより容量の大きなものはCR2354やCR2450などの、直径が大きなものになってしまう。さすがにそれらは入らない。

まとめ

おれはCR2032をこれからも使う。メーカーがCR2025を指定している理由はわからない。CR2032を入れると蓋が閉まらなかったり、電極が正常に機能しなかったりといった個体差があるのかもしれない。

Switch Bot が届いたのでSingle Board Computerから操作してみた

Switch Botとは

実世界の物理スイッチを押すためのIoTデバイスである。プロジェクトページのURLには「世界最小の無線ロボット」(switch-bot-the-worlds-smallest-remote-robot)という文字が埋め込まれている。

www.kickstarter.com

KICKSTARTERで出資していたものが製品となって届いた。素晴らしい。2個で59US$(7077円)だった。
amazonで探すと、一個7000円くらいで売ってる転売屋が見つかるけど、今なら上の公式サイトから飛べる
https://www.indiegogo.com/projects/switch-bot-the-world-s-smallest-remote-robot#/
で1個25US$で注文できる。量産効果でだんだん価格が下がっているようだ。
公式サイトの The journey of Switch Bot, please find more in our gallery.という写真↓
https://ksr-ugc.imgix.net/assets/014/378/118/10d8a35cf74342236b38988a76e63285_original.jpg?w=680&fit=max&v=1478196260&auto=format&q=92&s=ec09861a971e3700ec29d2330e0a5b3b
から試行錯誤と進歩の歴史が垣間見られて興味深い。

開封

Switch Bot本体2個と、お礼の紙、クイックスタートガイド、固定用両面テープ(交換用)二枚が頑丈な紙のケースに入ってきた。この紙ケースは小物の収納に使えそうなので捨てない。
f:id:XX-Prime:20170701202437j:plain

どうでもいいがお礼の紙にCEOの手書きサイン(の印刷)があるが、きったなすぎて何と書いてあるのか全く読めないw
f:id:XX-Prime:20170701202541j:plain
b~???

サイン追記

中の人によると、本人以外には誰も読めないそうであるw

スマートフォンアプリで動作テスト

バッテリー絶縁用のテープを引き抜くとSwitch Botが起動する。この状態でSwitch Bot用のスマートフォンプリを開くと、自動的にBLE Scanが行われてスマートフォンのBLE通信範囲内にあるSwith Botがアプリ上に表示される。

f:id:XX-Prime:20170701202047p:plain

バイスアイコンをタップすると数秒のラグの後にモーターが動作して腕(?)が一回動作する。モーターのトルクはかなり強く、硬めのスイッチでも問題なく操作できそうである。スイッチを押すことだけに特化しているので、このあたりの調整はかなりの経験の蓄積を感じさせる。
バイスアイコンの下にある歯車マークで詳細設定を行える。デバイスの名前を変えられるので、操作対象をデバイス名にすると分かりやすい。上のイメージでわかるように、デバイス名には日本語を入力しても正しく表示される。
設定を変更するとDFU(たぶんDevice Firmware Updateの略)と表示されて通信が開始される。
詳細設定からBattery Levelも確認できるが、これは詳細設定ではなくデバイスリストに直接表示したほうが良いと思う。つまりBLEアドバタイズにBattery Levelを含ませてしまった方が良いと思う。

セキュリティ

工場出荷状態ではスマートフォンアプリをインストールして、BLE通信範囲内に入れば誰でもSwitch Botを操作できるようになっている。このままでは、悪意のある第三者においしいモーニングコーヒーを淹れられる事案が発生したりする恐れがある。
これでは問題がある場合は、スマートフォンアプリからデバイスにパスワードを設定できる。パスワードを知らないデバイスは操作できないので、一応のセキュリティは確保できている。
パスワード設定でどの程度の暗号化が行われるかは未調査。

Single Board Computerから動作テスト

むしろこっちが私にとっては本命の操作方法である。公式にpythonオープンソースライブラリが用意されているのでBLE信号を傍受して解読する手間は要らない。
github.com
日本の企業にもこのオープン性は見習って欲しいと思う。

GithubページにはRaspberry Pi3がデバイス例として挙げられているが、情報追加の目的でBeaglebone Green Wireless(BBGW)でやってみる。

$ sudo apt-get install python-pexpect
$ git clone https://github.com/OpenWonderLabs/python-host.git
$ cd python-host/

では実行!

$ sudo python switchbot.py
Scanner inited
Start scanning...
scan timeout
No SwitchBot nearby, exit

(しーん)
はい動かないー。ばんざーい。
試しにRaspberry Pi3でもやってみたが同様にscanに失敗して動作しない。
仕方ないのでswitchbot.pyの中身を少し見てみる。

    def scan_loop(self):
        self.con = pexpect.spawn('hciconfig')
        pnum = self.con.expect(["hci0",pexpect.EOF,pexpect.TIMEOUT])
        if pnum==0:
            self.con = pexpect.spawn('hcitool lescan')
            self.con.expect('LE Scan ...', timeout=10)
            print "Start scanning..."
        else:
            raise Error("no bluetooth error")
        exit_counter=0
        #some bluetooth dongles may upload duplicates
        repeat_counter=0
        dev_list  = []
        while True:
            pnum = self.con.expect(["WoHand",pexpect.EOF,pexpect.TIMEOUT], timeout=5)

lescanをしてWoHandという文字列を含む応答が返ってくることを期待しているようである。
試しにlescanしてみる。

$ sudo hcitool lescan
LE Scan ...
AA:BB:CC:DD:EE:FF (unknown)
AA:BB:CC:DD:EE:FF (unknown)
FF:EE:DD:CC:BB:AA (unknown)
FF:EE:DD:CC:BB:AA (unknown)

これら2つはSwitch Botなのだが、BBGWでやってもPi3でやっても同様にunknownになっている。それは先に進まんわけだ。
scan自体には成功しているので、Switch Botの腕(?)を動かすメソッドで直接BLEアドレスを指定してやれば動きそうである。
switchbot.pyの当該部分は以下の通りである。

def trigger_device(add):
    print 'Start to control'
    con = pexpect.spawn('gatttool -b ' + add + ' -t random -I')
    con.expect('\[LE\]>')
    print "Preparing to connect."
    con.sendline('connect')
    #To compatible with different Bluez versions
    con.expect(['\[CON\]','Connection successful.*\[LE\]>'])
    print 'Write command'
    con.sendline('char-write-cmd 0x0016 570100')
    con.expect('\[LE\]>')
    con.sendline('quit')
    print 'Trigger complete'

なるほど。ではまずgatttoolで直接やってみよう。

$ gatttool -b AA:BB:CC:DD:EE:FF -t random -I
[AA:BB:CC:DD:EE:FF][LE]> connect
Attempting to connect to AA:BB:CC:DD:EE:FF
Connection successful
[AA:BB:CC:DD:EE:FF][LE]> char-write-cmd 0x0016 570100
Command Failed: Disconnected

うーん失敗。connectしてからコマンドを手で入力しているうちに切断されているような感じである。よってconnectの後にConnection successfulが返ってきた直後にchar-write-cmdを実行してみると

[AA:BB:CC:DD:EE:FF][LE]> connect
Attempting to connect to AA:BB:CC:DD:EE:FF
Connection successful
[AA:BB:CC:DD:EE:FF][LE]> char-write-cmd 0x0016 570100

(ちゅぃーん)
成功した!よって、trigger_device(add)に直接アドレスを指定するように、switchbot.pyを以下のように変えてみた。

def main():
    trigger_device('AA:BB:CC:DD:EE:FF')
    sys.exit()

これで実行すると

$ sudo python switchbot.py
Start to control
Preparing to connect.
Write command
Trigger complete

(ちゅいーん)
成功した!ただし、正常終了しない場合は永久に待ち状態になってしまうので適切にタイムアウトを設定する必要がある。

このように、switchbot.pyはまだまだα版のような状態なので、適切なメソッド群だけをライブラリとして別ファイルに追い出したり、スキャンの方法を変えたりと色々と改善の余地がある。Switch Bot用のvendor idが分かれば、Switch Botのみをスキャンすることができるはずで、恐らくスマートフォンアプリはその方法を採用しているはずである。
とは言え骨格部分はすでに完成しているので修正や改善は困難な仕事ではない。
が、バッテリーレベルの取得コマンドやセキュリティまわりが不明なので、それを自力で解明しようとするのはやや大変そうである。

スキャン失敗の追記(2017/07/03)

中の人にコメントを送ってみた所、

Oops, the github project is out of date now and unable to find bots since the SwitchBot broadcast format has been changed... We will fix this later...

Regards
Wonderlabs

と返信があり、問題は把握済みで直す予定とのことである。

追記の追記

中の人によると、以下のコードも見てみてね、とのことである。

http://codegist.net/snippet/python/switchbot_bluepypy_aerialist_python

gatoolもpexpectも使わずに、より簡潔に制御できるのでこっちのほうがいいね。

Single Board Computer を持ってない普通の人専用デバイス

こんな所まで読み進めてきたド変態はSingle Board Computerの数枚や数十枚なら持っているだろうけど、そうでない正常な人用にはSwitch-LinkというBLE/Wi-Fiゲートウェイが公式に用意されている。
https://ksr-ugc.imgix.net/assets/014/448/371/cc3b44fc97d42800453826c8a2b97db1_original.png?w=680&fit=max&v=1478698927&auto=format&lossless=true&s=32cd3aca41e2b33d5ab25b37ae13f729

固定方法の提案

モーターのトルクに負けないようにかなり強力な両面テープ(剥離紙には3MのVHBと書いてある)で固定するようになっているが、これは剥がすのがなかなか大変で、最悪の場合壁面を破壊する恐れがある。
そこで私はこれ↓を固定に使うことを提案する。
コマンド™ タブ
3Mのコマンドタブは、強力に接着できる両面テープであるが、タブを引っ張っていくときれいに無理なく剥がせるという製品である。これの開発者は相当賢い。脳の一部を分けてもらいたい。
家の中、勤務先、工場内などで色々なものをこれで固定してきたが、今のところ問題が起きたことはない。天井にEnOceanのモーションセンサをコマンドタブで固定して2年以上経過したが、落ちてくる気配は今のところない。
Switch Botには一番小さいタイプSSを二枚か、タイプSを一枚で適切に固定できるはずである。
タブが見えると気になって発狂するという人には透明タイプのコマンドタブもあるよ。

応用

IFTTTと連携させるといくらでも複雑なことをできそうだし、Amazon Dashをわざわざこれで押すというネタで一笑い取るというのもアリ。
個人的な例では、温湿度センサと連動して換気扇を自動操作したいので早速実用を開始している。

感想

既存機器をIoT化できる製品としての完成度は高い。スマートフォンアプリも良くできていて、説明書を読まずに誰でも使える水準に達している。
価格は正直に言ってまだまだ高いとは思うが、あらゆるモノを遠隔操作できる可能性について少しでも考える人であれば購入するに足るものだと思う。しかし転売屋から一個7000円というボッタクリ価格で買うのは馬鹿げている。
最後に、スイッチが動作したことを確認する手段が無いので、生命維持用途とかには使わないほうがいいだろう。

esp32のBLE scanでRSSIを表示する

esp32のBLE scanでRSSIが取得できるか?

現時点で "esp32 ble scan RSSI" でweb検索すると、上手くいかないとか、変な値が取得できるといった情報ばかりが見つかる。そこで、本当にできないのか試してみたら上手くいったのでメモ。

開発環境の準備

まずesp-idfの開発環境を揃える。esp-idfはWindowsよりLinuxで開発したほうが色々と捗るので、WindowsVirtualboxdebian linuxを動作させ、その中でesp-idfの開発環境をセットアップした。特にハマる点もないので詳細な手順は省略。検索すればすぐ見つかる。

次に、ソースを見る際に grep -r しまくっても良いが、IDEの方がなにかと便利なので、eclipseからesp-idfを扱えるようにセットアップした。ついでにeclipseからbuild→flashまでできるようにした。これも簡単なので詳細な手順は省略。

一点だけハマる可能性があるのは、Virtualboxにesp32開発ボードのUSB-Serialのインターフェイスをアタッチする所で、何かの拍子に乱暴に切断してしまった後だと再アタッチが失敗することがある。そんな場合は、windowsのデバイスマネージャの「ポート(COMとLPT)」にあるCOMポートを削除してから開発ボードを接続して再アタッチするとうまくいく。これに気づくまではいちいちwindows自体を再起動させていた。

BLE scanできるサンプルソース

esp-idf/examples/bluetooth/gatt_client/

がそれ。昔はexample 15_gatt_clientと呼ばれていたもののようだ。

このプロジェクトをeclispeにインポートして色々と探ってみると、rssiはesp_gap_ble_api.hで定義されているesp_ble_gap_cb_param_tという共用体にintとして入っており、gattc_demo.cのesp_gap_cbというコールバック関数の中でアクセスできることがわかる。よって、この関数の中で

    case ESP_GAP_BLE_SCAN_RESULT_EVT: {
        esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
        switch (scan_result->scan_rst.search_evt) {
        case ESP_GAP_SEARCH_INQ_RES_EVT:
            for (int i = 0; i < 6; i++) {
                ESP_LOGI(GATTC_TAG, "%x:", scan_result->scan_rst.bda[i]);
            }
            ESP_LOGI(GATTC_TAG, "\n");
            adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv,
                                                ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
            ESP_LOGI(GATTC_TAG, "Searched Device Name Len %d\n", adv_name_len);

            ESP_LOGI(GATTC_TAG, "RSSI: %d\n", scan_result->scan_rst.rssi);  //これを追加。以下省略。

とRSSIを出力するようにしてみた。

簡単なテスト

使ったesp32デバイスはdoitの開発ボードと、秋月でも買えるespressifの開発ボードで、両方とも同じ動作をした。
変更したプログラムをビルドしてesp32にflashして、適当なシリアルモニタ(LinuxのCuteComが使いやすかった)で出力を見てみると、BLEタグ(スマートフォンで代用。BLE Peripheral Simulatorを使用。)がesp32の数十cm程度の近くにあるときは

\0x1b[0;32mI (9350) GATTC_DEMO: RSSI: -64

程度で、数メートル離すと

\0x1b[0;32mI (7260) GATTC_DEMO: RSSI: -85

程度となったので、正常な値を取得できているようだ。ただ、当然だがesp32の向きが変わると値が大きく変動するので、色々と工夫してタグの接近・離脱を判断する必要はある。

まとめ

安価な据え置き型ble scanner(wifiへのゲートウェイ)としての利用可能性が薄ぼんやりと見えた。その用途では、これまではRaspberry PiやEdisonなどを使うしかなかったが、esp32で代用できれば色々と可能性が広がる。