TWELite を使った無線温湿度計

ホーム 目次に戻る

TWELite とは

TWELite とは、モノワイヤレス社が提供する、物理層に ZigBee を利用した(IEEE 802.15.4)無線通信マイコンです。

予めアプリケーションがインストールされた状態で出荷されますが、ホームページにSDKへのリンクがあり、ユーザが内容を自由に書き換えることが可能です。

今回の工作では、受信は行わないので受信ロジックを外し、EEPROM のモード7で規定された時間周期(デフォルトは60秒)で温湿度を報告するアプリケーションを作ってみます。

なお、2018年5月のバージョンから開発環境が Visual Studio Code に変更されました。今までは Eclipse 付きでしたが、本バージョンから Visual Studio Code は別途ダウンロードする必要があるため、注意が必要です。(ここからダウンロード可能です
また、C/C++ 拡張機能もダウンロードする必要があることに注意してください。(使用中にダウンロードするか聞かれると思います。)

TWELite には親機と子機が必要ですが、子機は工作のしやすい TWELite-DIP を使用し、親機は Raspberry Pi と親和性の高い MONO-STICK を使用することにします。
SHT31接続図

なお、プログラムは GitHub に置いてあります。


温湿度計センサー SHT31

温湿度センサーには、秋月電子通商で販売されている Sensirion 社製 SHT31 モジュールを使用しました。

AM2302 など他のセンサーでも試しましたが、全個体が正しく校正されているセンサーで扱いやすく、比較的価格が安いセンサーというとほぼ SHT31 一択になるようです。

SHT31 には色々な測定モードが用意されていますが、今回は低繰り返し精度、ワンショット動作を利用します。繰り返し回数を多くすると精度は上がりますが、測定時間が長くなり、電池の消費も激しくなります。


TWELite-DIP (BLUE) に SHT31 をつなぐ

SHT31 の通信インタフェースは I2C です。この点は扱いやすいのですが、 という理由から独自に I2C プログラムを組んでいます。

通信プロトコル

通信プロトコルは標準アプリケーションのものを流用し、以下としました。
:<送信元デバイスID><86><デバイス種別><部屋番号><ステータス(8ビット)><温度(16ビット)><湿度(16ビット)><チェックサム>
記号 意味 サンプル
: データ送信を開始することを示す。 :
<送信元デバイスID> MONO-STICK への送信を行った送信元 TWELite-DIP のデバイスID。
通常部屋番号と同一の番号を付与する。
TWELite の番号体系の制限から 0x01 から 0x6f までが利用可能。
3c(10進数で60)
<86>(16進数) MONO-STICK への独自の出力であることを示すタグ
タグの中には MONO-STICK 等で特殊な動作をするものがあるため、
新たに独自のタグ番号を付与した。
86
<デバイス種別> デバイスを区別する番号。SHT31 は 0x04 固定。 04
<部屋番号> 発信元の部屋を区別する番号。通常 0x01〜0x6fを設定し、
デバイス番号と合わせる。
3c(10進数で60)
<スタータス> SHT31 のアラーム状態。ビット定義で以下のようになっている。
  • ビット7: アラーム状態なら1
  • ビット6: ヒーターオンなら1
  • ビット5: 温度アラーム状態なら1
  • ビット4: 湿度アラーム状態なら1
  • ビット3: リセット履歴ありなら1
  • ビット2: 未定義(常に0)
  • ビット1: コマンド無効なら1
  • ビット0: 書き込みデータのチェックサム無効なら1
88(10進数で136)=リセット履歴あり
<温度> 生の温度データ。ビッグエンディアンとなる。実際の温度は \[ T = -45 + 175\frac{Temperature Data}{2^{16} - 1} \] となる。 6c3f(温度29℃)
<湿度> 生の湿度データ。ビッグエンディアンとなる。実際の湿度は \[ H = 100 \frac{Humidity Data}{2^{16} - 1} \] となる。 7fff(湿度50%Rh)

オプションビットの構成

TWELite-DIP のオプションビットは以下の構成とします。
オプション名説明デフォルト
アプリケーションID 同じアプリケーション ID を持つ物同士のみが通信できる。 67720102
デバイス論理ID このデバイスの役割を示す ID を付与します。
  • 0: 親機
  • 0x01 - 0x79: 子機
など。
--(なし)
部屋番号 この温湿度計が置かれる部屋の部屋番号です。SQLite3 DB に予め登録しておく必要があります。 3c(10進数で60)
デバイス種別 SHT31 デバイスを識別する番号です。SQLite3 DB に予め登録しておく必要があります。
この番号はデバイスごとに固定です。
0x04
モード7送信間隔(秒) 親機への送信間隔です。必要がなければデフォルトのままとしてください。 60
オプションビット TWELite の詳細動作を制御するビットです。本アプリケーションでは 0x36 を設定してください。 0x00000000
上記以外のオプションは表示されますが、使用されていません。

TWELite-DIP 側のプログラムの概要

親機から受信するプログラムを削ります。
ただし、TWELite-R はモード0で起動するため、モード0とモード7を起動時に判別するロジックは残しました。
EEPROM の書き込みはモード0で起動した時のみ可能です。

Cold Start/Warm Start すると一定時間待機し、ハードウェアを初期化します。
このとき、使わないモジュールは初期化しないようにします。
SCK, SDA は SHT31 モジュール側でプルアップされているため、プルアップを外します。
またモード CONF ピンは GND 接地であるため、プルアップを外すようにします。

ハードウェアを初期化したら I2C バスを初期化して SHT31 に測定コマンドを送ります。
正常に測定できたらデータ列を整列して親機に送信します。
送信が正常に完了したらモード7動作間隔で指定された秒数(通常は60秒)スリープします。
RAM 状態は今回は保持しません。
ウェイクアップタイマーが発火したら Cold Start からやり直します。


MONO-STICK 側のプログラムの概要

MONO-STICK 側のプログラムは python で書かれ、/dev/ttyUSB0 からの受信とインターネットサーバへの報告パケット送信を行います。
通信速度は 115200 bps (8N1) 固定です。
インターネットサーバの負担を軽くするため、送信は60秒毎にまとめて行います。

Python スクリプトは受信すると /tmp にモニター出力を行います。フォーマットは JSON です(JSON のままインターネットサーバに送信されます)。
このままでは /tmp が溢れてしまうため、1日に1回 crontab から rotatelog.sh を起動してログを回転させるようにします。

実際には python スクリプトはその実行を監視する bash スクリプトから起動されます。
bash スクリプトは python スクリプトが異常終了した場合、5秒後に再起動します。


インターネットサーバによるデータ収集と表示

インターネットサーバは MONO-STICK のデータを受信する部分(appenddb.php)と、
受信したデータを表示するページ(tracker.html)、API(retrievedb.php)から構成されています。
今回、DB には手軽に利用できるファイルベースの RDMS である、SQLite3 を使用しました。

DB スキーマ

DB スキーマは以下のようになっています。
SENSOR_TYPE(センサータイプ定義)
フィールド意味
idint (primary key)ID番号
typeintセンサータイプ(1: 温度のみ 2: 湿度のみ 3: 温湿度)
namevarchar(40)センサー名: JSON のセンサータイプ名称がこのフィールドに等しいことを仮定している
descriptionvarchar(255)センサーの説明文章
ROOM(部屋番号定義)
フィールド意味
idint (primary key)部屋番号: JSON で示される部屋番号に等しいことを仮定している
namevarchar(40)部屋名称: 表示画面で部屋選択肢に表示される
descriptionvarchar(255)部屋の説明文章
SUMMARY (テーブルサマリー)
フィールド意味
idint (primary key)ID 番号: クエリを構成するときに使用する
tablenamevarchar(40)実際のデータが配置されるテーブルの名前
namevarchar(40)テーブル説明サマリー: グラフのタイトルに表示される文章
descriptionvarchar(255)テーブル説明
roomreferences ROOM(id)部屋番号
sensor_typereferences SENSOR_TYPE(id)センサータイプ
DATAx (センサーの個数分存在するテーブル)
フィールド意味
elapsedint(64) (primary key)測定日時: 1970-1-1日 00:00:00 UTC からの経過秒
elapsed_hourint (64)elapsed を1時間で割った値
elapsed_dayint (64)elapsed を1日で割った値
datetimedatetime測定日時
statusintセンサーが報告してきた status バイトの値
temperatureintセンサーが報告してきた温度
humidityintセンサーが報告してきた湿度
THRESHOLD (警告メールの判定スレッショルド値の定義)
フィールド意味
idint (primary key)定義 ID
roomint部屋番号
currentint(1)アラーム発生状態なら1、そうでないなら0
threshold1real警告状態に入るスレッショルド値
threshold2real警告状態を解くスレッショルド値
modevarchar(10)up: 上昇方向、down: 下降方向
CONFIGURATION (各種動作設定値)
フィールド意味
namevarchar(255) (primary key)設定キー
valuetext設定値
CONFIGURATION パラメータとして、以下が定義されている。
設定キー意味設定値(例)
from警告メールの from アドレスpostmaster@example.com
to警告メールの to アドレスuser@example.com
mail-to警告メールの実際の送信先user@example.com
subject警告メールタイトルSensor threshold warning
mail-body警告メール本文Sensor detected threshold warning

MONO-STICK からのデータ受信

MONO-STICK からは JSON フォーマットのリストデータが生のまま送られてきます。
(www-url-form-encoded等ではない。)
フォーマットは以下のようになっています。(実際は以下のリストになっていることに注意!)
MONO-STICK から受信する JSON フォーマット
キー意味サンプル
current1970-1-1 00:00:00 からの経過秒1530827610
datetime測定日時2018-07-06 06:53:30
from部屋番号60
presenceセンサーが存在していれば128128
statusセンサーの警告状態136
temperature温度(℃)27.889295796139464
humidity湿度(%Rh)53.04951552605478

受信データはSQL 文に変換し、DB に入力していきます。

表示用 API の機能

表示部では、Google グラフチャート API を利用して温湿度データをグラフ化します。
表示に必要なフォーマットとデータ取得プログラム(JavaScript)は tracker.html に記述されています。
retrievedb.php は REST ライクな API で、GET 操作に対して CSV を返す API です。type 値によって機能を切り替えます。
offset は最新がオフセット0と定義されます。

retrievedb.php の機能
機能IDパラメータ説明
ROOM(なし)定義済み部屋番号と部屋名称を返す。
COUNTroom: 部屋番号登録件数を返す。
TRACK
  • mode: minutes: 分単位、hour: 時間単位、day: 日単位
  • offset: オフセット番号
  • limit: 上限数
  • year: 検索開始日時(年)
  • month: 検索開始日時(月)
  • day: 検索開始日時(日)
  • hour: 検索開始日時(時)
  • minutes: 検索開始日時(分)
測定データ(日時、温度、湿度)を返す。
検索開始日時が指定されている場合、offset に優先する。
STATUS
  • room: 部屋番号
  • offset: オフセット番号
指定のオフセット位置から60分間のステータス状態を返す。
UPTIMEroom: 部屋番号センサーの起動時間を、日:時:分:秒で返す。
THRESHOLDroom: 部屋番号センサーの警告スレッショルド値を返す。

表示 URL の tracker.html では、部屋ごとのデータの他、時間・日にちごとの平均の推移、特定時間以前の状態の入力ができるようにしています。 温度表示例


Copyright (c) 2017-2018 by TeqStock.tokyo