こんにちは、ENGかぴです。
トワイライト(TWELITE)はZigBee通信であり通信の中継機能を持っています。中継機能によって通常では無線通信が届かない範囲の通信ができます。MWSTAGEのライブラリであるNWK_SIMPLEを使って中継機能の効果を確認しました。下記記事のソースコードを流用して動作確認しています。
トワイライトを太陽光パネルで動作させたことやMWSTAGEの環境でソフト開発して無線通信したことなどについてまとめています。
トワイライト(TWELITE)のソフト開発と無線通信でできること
中継機能の動作

親機から子機Bに無線通信を行う例で中継機能を説明します。親機から子機Bまでの距離において無線通信が届かないものとします。親機と子機Bの間に子機A(中継機能あり)を配置すると親機が送信した子機Bへの無線通信が子機Aを経由して子機Bに届くようになります。
子機Aも子機Bと同様に子機として動作させることもできるため親機は子機A及び子機Bの情報を取得できるようになります。中継機能の使用例などの詳細は下記リンクを参考にしてください。
PR:わからないを放置せず、あなたにあった最低限のスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!
共通の設定事項
親機と子機でアプリケーションID・チャンネル番号・アプリ識別のための文字列を共通にする必要があります。
const uint32_t APP_ID = 0x1234abcd; // application ID
const uint8_t CHANNEL = 13; // channel
const char APP_CHAR[] = "COM";
TWENETに上記で定数宣言しているAPP_IDとCHANNELを指定して設定します。
the_twelite
    << TWENET::appid(APP_ID) //アプリケーションID
    << TWENET::channel(CHANNEL) //チャンネル設定
    << TWENET::rx_when_idle(); //無線通信を受信する場合は実装
無線通信を受信する場合はrx_when_idle()を実装する必要があります。子機は親機からの受信が必要なのでrx_when_idle()を実装する必要がありますが、親機で送信専用にする場合は実装の必要はありません。
子機に中継機能を実装する
auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
nwksmpl << NWK_SIMPLE::logical_id(0x01) 
	<< NWK_SIMPLE::repeat_max(1); //default:2
TWENETライブラリのnetwork関数を使用して論理IDの設定を行います。ネットワークのlogical_idに0x01~0xEFもしくはFE(IDの区別がない)をセットすることで子機として動作します。
repeat_max()に1~3を指定すると中継する回数が指定できます。0を指定すると中継機能をもたない子機になります。MWSTAGEのライブラリではデフォルトで2となるため特に指定しなくても中継機能が使用できます。例では中継する回数を1回にしています。
PR:わからないを放置せず、あなたにあったスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!
動作確認

親機と子機(論理ID:0x02)は同軸ケーブルアンテナタイプのTWELITE DIPを使用しています。同軸ケーブルアンテナを実装しなければ電波の全く飛ばないモジュールになります。親機と子機(論理ID:0x02)を離して通信できないように配置します。
親機と子機(論理ID:0x02)の間に子機(論理ID:0x01)を配置して中継機能の動作を確認します。
親機は下表のように15、16ピンをGNDに接続するパターンで送信先を選択しSW1を押すと無線通信を行います。子機は親機からの無線通信を受けてLEDを点灯/消灯します。
| DOのパターン DO(15):DO(16) | 子機の送信先 | 
|---|---|
| LOW:LOW | 0xFE | 
| HIGH:LOW | 0x01 | 
| LOW:HIGH | 0x02 | 
親機の送信先を0x02にしてSW1を押すと電波が届く範囲であれば子機(論理ID:0x02)のLEDが点灯/消灯します。動作を確認しながら子機(論理ID:0x02)のLEDが点灯/消灯しない位置に配置します。
子機(論理ID:0x01)を親機と子機(論理ID:0x02)の間に配置すると子機(論理ID:0x01)の中継機能によって子機(論理ID:0x02)のLEDが点灯/消灯することが確認できました。
子機(論理ID:0x01)の中継機能をNWK_SIMPLE::repeat_max(0)を指定して中継しない設定にすると子機(論理ID:0x02)のLEDが点灯/消灯しないことが確認できました。
PR:スキマ時間で自己啓発!スマホで学べる人気のオンライン資格講座【スタディング】まずは気になる講座を無料で体験しよう!
ソースコード全体
ソースコードは記事作成時点において動作確認できていますが、使用しているライブラリの更新により動作が保証できなくなる可能性があります。また、ソースコードを使用したことによって生じた不利益などの一切の責任を負いかねます。参考資料としてお使いください。
TWELITE(子機)のソースコード:
#include <TWELITE>
#include <NWK_SIMPLE>
#define CNG_ID
#define TIME_UP 0
#define TIME_OFF -1
#define ZIG_WAIT_MAX 100
const uint8_t DI_SW = mwx::PIN_DIGITAL::DIO12;
const uint8_t DI_MD0 = mwx::PIN_DIGITAL::DIO15;
const uint8_t DI_MD1 = mwx::PIN_DIGITAL::DIO16;
const uint32_t APP_ID = 0x1234abcd; // application ID
const uint8_t CHANNEL = 13; // channel
const char APP_CHAR[] = "COM";
int16_t timzigwait = TIME_OFF;
uint8_t do_out;
/*** function prototype */
MWX_APIRET transmit(void);
/*** the setup procedure (called on boot) */
void setup() {
    pinMode(DI_SW,INPUT_PULLUP);
    pinMode(DI_MD0,INPUT_PULLUP);
    pinMode(DI_MD1,INPUT_PULLUP);
    the_twelite
	<< TWENET::appid(APP_ID)    
	<< TWENET::channel(CHANNEL) 
	<< TWENET::rx_when_idle();
    auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
    nwksmpl << NWK_SIMPLE::logical_id(0x00);
    the_twelite.begin(); // start twelite!
}
/*** the loop procedure (called every event) */
void loop() {
    if( TickTimer.available()){
        if(timzigwait > TIME_UP){
            --timzigwait;
        }
    }
    if( timzigwait == TIME_UP ){
        timzigwait = TIME_OFF;
        transmit();
    }
    if( digitalRead(DI_SW) == LOW ){
	timzigwait = ZIG_WAIT_MAX;
    }
}
/* transmit a packet */
MWX_APIRET transmit(void) {
    uint8_t txadrs;
    if(digitalRead(DI_MD0) == LOW && digitalRead(DI_MD1) == LOW ){
	txadrs = 0xFE;
    }
    else if( digitalRead(DI_MD0) == HIGH && digitalRead(DI_MD1) == LOW){
	txadrs = 0x01;
    }
    else if( digitalRead(DI_MD0) == LOW && digitalRead(DI_MD1) == HIGH){
	txadrs = 0x02;
    }
    if (auto&& pkt = the_twelite.network.use<NWK_SIMPLE>().prepare_tx_packet()) {
        pkt << tx_addr(txadrs)  
	    << tx_retry(0x3) 
	    << tx_packet_delay(0,0,2);
 
	if( do_out){
	    do_out = 0;
	}
	else{
	    do_out = 1;
	}
        pack_bytes(pkt.get_payload(), make_pair(APP_CHAR, 3));//ヘッダー
        pack_bytes(pkt.get_payload(),do_out);
	
	return pkt.transmit();
    }
    return MWX_APIRET(false, 0);
}
TWELITE(親機)のソースコード:
#include <TWELITE>
#include <NWK_SIMPLE>
//#define CNG_ID
const uint8_t DO_COM = mwx::PIN_DIGITAL::DIO12;
const uint32_t APP_ID = 0x1234abcd; // application ID
const uint8_t CHANNEL = 13; // channel
const uint8_t LID
#ifdef CNG_ID
= 0x01
#else
= 0x02
#endif
;
const char APP_CHAR[] = "COM";
void receive();
/*** the setup procedure (called on boot) */
void setup() {
    pinMode(DO_COM,OUTPUT);
    the_twelite
	<< TWENET::appid(APP_ID)    
	<< TWENET::channel(CHANNEL) 
	<< TWENET::rx_when_idle();
    auto&& nwksmpl = the_twelite.network.use<NWK_SIMPLE>();
    nwksmpl << NWK_SIMPLE::logical_id(LID) 
            << NWK_SIMPLE::repeat_max(1); //default:2
	
    the_twelite.begin(); // start twelite!
}
/*** the loop procedure (called every event) */
void loop() {
    while (the_twelite.receiver.available()) {
	receive();
    }
}
/* 無線通信を受信して処理する */
void receive() {
    char chk[4];
    uint8_t set;
    auto&& rx = the_twelite.receiver.read();
    auto&& np = expand_bytes(rx.get_payload().begin(), rx.get_payload().end()
		,make_pair(chk,3)); 
		
    if( strncmp(chk, APP_CHAR, 3)){ return; } // check header
        np = expand_bytes(np,rx.get_payload().end(),set );
    if( set == 1){
        digitalWrite(DO_COM,HIGH);
    }
    else{
        digitalWrite(DO_COM,LOW);
    }
}
TWELITEのソースコードはMWSTAGEのアクトに組み込んで使用してください。子機のソースコードのNWK_SIMPLE::repeat_max(1)の引数を0にすると中継機能が停止します。
関連リンク
トワイライトを太陽光パネルで動作させたことやMWSTAGEの環境でソフト開発して無線通信したことなどについてまとめています。
トワイライト(TWELITE)のソフト開発と無線通信でできること
PR:わからないを放置せず、あなたにあった最低限のスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!
最後まで、読んでいただきありがとうございました。
 


App_Wingsが提供されていますがMWSTAGEのACTを使用した方が開発しやすいためて大掛かりなシステムで中継しない限りMWSTAGEのACTによる中継で問題ないと思います。