📏 Node-RED Range ノードガイド

📚 目次

📖 1. 概要

Range ノードは、数値を別の範囲にマッピング(変換)するノードです。入力値を指定した入力範囲から出力範囲に線形変換します。

🎚️ ボリュームつまみに例えると:オーディオ機器のボリュームつまみを考えてください。つまみの物理的な回転角度(0〜270度)を、音量(0〜100%)に変換するようなものです。Rangeノードはこのような「ある範囲の値を別の範囲の値に変換する」処理を行います。

数値入力 Range Debug

💡 ポイント:

変換の仕組み

出力値 = (入力値 - 入力最小) × (出力最大 - 出力最小) ÷ (入力最大 - 入力最小) + 出力最小

⚙️ 2. 設定詳細

主要プロパティ

プロパティ説明デフォルト
Property変換対象のプロパティmsg.payload
Action範囲外の値の処理方法Scale
Input Range入力値の範囲(最小〜最大)
Output Range出力値の範囲(最小〜最大)
Round整数に丸めるfalse

Action(範囲外の値の処理)

オプション説明例(入力0-10→出力0-100で入力15の場合)
Scale and limit範囲内に制限(クランプ)100(上限で制限)
Scale and wrap範囲を超えたら折り返し50(15-10=5 → 50)
Scale only制限なしで変換継続150(そのまま変換)

変換例

入力範囲: 0 - 1023(ADC値) 出力範囲: 0 - 100(パーセント) 入力: 0 → 出力: 0 入力: 512 → 出力: 50.05 入力: 1023 → 出力: 100

🔧 3. 実用的な使用パターン

📥 サンプルフローのインポート方法:

  1. 下のサンプルフローJSONをコピー
  2. Node-REDエディタで メニュー → 読み込み を選択
  3. JSONをペーストして「読み込み」をクリック

このサンプルフローには、以下で説明するパターンの実例が含まれています。

📥 サンプルフローJSON(クリックで展開)
[ { "id": "range_sample_tab", "type": "tab", "label": "Range サンプル", "disabled": false, "info": "" }, { "id": "range_comment", "type": "comment", "z": "range_sample_tab", "name": "📏 Range ノード サンプル", "info": "様々なRange変換のデモンストレーション", "x": 160, "y": 40, "wires": [] }, { "id": "inject_50", "type": "inject", "z": "range_sample_tab", "name": "50を送信", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "50", "payloadType": "num", "x": 140, "y": 100, "wires": [["range_basic"]] }, { "id": "range_basic", "type": "range", "z": "range_sample_tab", "minin": "0", "maxin": "100", "minout": "0", "maxout": "255", "action": "scale", "round": true, "property": "payload", "name": "0-100 → 0-255", "x": 340, "y": 100, "wires": [["debug_basic"]] }, { "id": "debug_basic", "type": "debug", "z": "range_sample_tab", "name": "基本変換結果", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "payload", "statusType": "auto", "x": 560, "y": 100, "wires": [] }, { "id": "comment_limit", "type": "comment", "z": "range_sample_tab", "name": "━━━ 範囲制限デモ ━━━", "info": "", "x": 160, "y": 160, "wires": [] }, { "id": "inject_150", "type": "inject", "z": "range_sample_tab", "name": "150を送信(範囲外)", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "150", "payloadType": "num", "x": 170, "y": 220, "wires": [["range_limit", "range_scale", "range_wrap"]] }, { "id": "range_limit", "type": "range", "z": "range_sample_tab", "minin": "0", "maxin": "100", "minout": "0", "maxout": "255", "action": "clamp", "round": true, "property": "payload", "name": "Scale & Limit", "x": 410, "y": 180, "wires": [["debug_limit"]] }, { "id": "debug_limit", "type": "debug", "z": "range_sample_tab", "name": "Limit: 255", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "payload", "statusType": "auto", "x": 590, "y": 180, "wires": [] }, { "id": "range_scale", "type": "range", "z": "range_sample_tab", "minin": "0", "maxin": "100", "minout": "0", "maxout": "255", "action": "scale", "round": true, "property": "payload", "name": "Scale Only", "x": 410, "y": 220, "wires": [["debug_scale"]] }, { "id": "debug_scale", "type": "debug", "z": "range_sample_tab", "name": "Scale: 382", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "payload", "statusType": "auto", "x": 590, "y": 220, "wires": [] }, { "id": "range_wrap", "type": "range", "z": "range_sample_tab", "minin": "0", "maxin": "100", "minout": "0", "maxout": "255", "action": "roll", "round": true, "property": "payload", "name": "Scale & Wrap", "x": 410, "y": 260, "wires": [["debug_wrap"]] }, { "id": "debug_wrap", "type": "debug", "z": "range_sample_tab", "name": "Wrap: 127", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "payload", "statusType": "auto", "x": 590, "y": 260, "wires": [] }, { "id": "comment_temp", "type": "comment", "z": "range_sample_tab", "name": "━━━ 温度変換デモ ━━━", "info": "", "x": 160, "y": 320, "wires": [] }, { "id": "inject_25c", "type": "inject", "z": "range_sample_tab", "name": "25°C", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "25", "payloadType": "num", "x": 130, "y": 380, "wires": [["range_temp"]] }, { "id": "range_temp", "type": "range", "z": "range_sample_tab", "minin": "0", "maxin": "100", "minout": "32", "maxout": "212", "action": "scale", "round": false, "property": "payload", "name": "摂氏→華氏", "x": 310, "y": 380, "wires": [["debug_temp"]] }, { "id": "debug_temp", "type": "debug", "z": "range_sample_tab", "name": "77°F", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "payload", "statusType": "auto", "x": 490, "y": 380, "wires": [] } ]

使用パターン

パターン1: 範囲制限モードの比較

サンプルフローの「範囲制限デモ」を参照してください。同じ入力値(150)に対して、3つのモードで異なる結果になります。

150を送信 Scale & Limit 255(上限に制限)

3つのモードの違い:

モード入力150(範囲外)の結果説明
Scale & Limit255出力範囲に制限
Scale Only382そのまま変換(範囲外も許可)
Scale & Wrap127範囲内にラップ(循環)

パターン2: 温度変換(摂氏→華氏)

サンプルフローの「温度変換デモ」を参照してください。

25°C C→F変換 77°F

設定:

📝 4. 演習問題

演習1: 基本的な範囲変換 初級

📋 課題: 0〜100の入力を0〜255のPWM値に変換するフローを作成してください。

🎯 要求仕様:

✅ 成功の条件:

💡 ヒント

Range ノードで Input Range を 0-100、Output Range を 0-255 に設定し、Round をチェックします。

✅ 解答例フロー
[ {"id": "ex1_tab", "type": "tab", "label": "演習1"}, {"id": "ex1_inject", "type": "inject", "z": "ex1_tab", "name": "75%", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "75", "payloadType": "num", "x": 130, "y": 100, "wires": [["ex1_range"]]}, {"id": "ex1_range", "type": "range", "z": "ex1_tab", "minin": "0", "maxin": "100", "minout": "0", "maxout": "255", "action": "scale", "round": true, "property": "payload", "name": "0-100 → 0-255", "x": 320, "y": 100, "wires": [["ex1_debug"]]}, {"id": "ex1_debug", "type": "debug", "z": "ex1_tab", "name": "PWM値", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "payload", "statusType": "auto", "x": 510, "y": 100, "wires": []} ]

演習2: センサー値の正規化 初級

📋 課題: 12bit ADC(0〜4095)の値を0〜100%に正規化してください。

🎯 要求仕様:

✅ 成功の条件:

💡 ヒント

Round をオフにすると小数点以下も保持されます。表示形式の調整には Function ノードを追加できます。

✅ 解答例フロー
[ {"id": "ex2_tab", "type": "tab", "label": "演習2"}, {"id": "ex2_inject", "type": "inject", "z": "ex2_tab", "name": "2048 (50%)", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "2048", "payloadType": "num", "x": 150, "y": 100, "wires": [["ex2_range"]]}, {"id": "ex2_range", "type": "range", "z": "ex2_tab", "minin": "0", "maxin": "4095", "minout": "0", "maxout": "100", "action": "clamp", "round": false, "property": "payload", "name": "ADC→%", "x": 330, "y": 100, "wires": [["ex2_func"]]}, {"id": "ex2_func", "type": "function", "z": "ex2_tab", "name": "小数点1桁", "func": "msg.payload = Math.round(msg.payload * 10) / 10;\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 500, "y": 100, "wires": [["ex2_debug"]]}, {"id": "ex2_debug", "type": "debug", "z": "ex2_tab", "name": "%表示", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "payload", "statusType": "auto", "x": 670, "y": 100, "wires": []} ]

演習3: 範囲制限の活用 中級

📋 課題: モーター制御で、入力が範囲外でも安全な値に制限するフローを作成してください。

🎯 要求仕様:

✅ 成功の条件:

💡 ヒント

Action を「Scale and limit」に設定すると、範囲外の値は自動的に制限されます。

✅ 解答例フロー
[ {"id": "ex3_tab", "type": "tab", "label": "演習3"}, {"id": "ex3_inject1", "type": "inject", "z": "ex3_tab", "name": "50(正常)", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "50", "payloadType": "num", "x": 150, "y": 80, "wires": [["ex3_range"]]}, {"id": "ex3_inject2", "type": "inject", "z": "ex3_tab", "name": "150(範囲外)", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "150", "payloadType": "num", "x": 160, "y": 120, "wires": [["ex3_range"]]}, {"id": "ex3_inject3", "type": "inject", "z": "ex3_tab", "name": "-50(負の値)", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "-50", "payloadType": "num", "x": 160, "y": 160, "wires": [["ex3_range"]]}, {"id": "ex3_range", "type": "range", "z": "ex3_tab", "minin": "-100", "maxin": "100", "minout": "0", "maxout": "255", "action": "clamp", "round": true, "property": "payload", "name": "速度→PWM(制限付き)", "x": 400, "y": 120, "wires": [["ex3_debug"]]}, {"id": "ex3_debug", "type": "debug", "z": "ex3_tab", "name": "PWM出力", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "payload", "statusType": "auto", "x": 620, "y": 120, "wires": []} ]

演習4: 温度スケール変換 中級

📋 課題: 摂氏温度を華氏温度に変換するフローを作成してください。

🎯 要求仕様:

✅ 成功の条件:

💡 ヒント

入力範囲を -40〜100(摂氏)、出力範囲を -40〜212(華氏)に設定。-40度は摂氏と華氏で同じ値です。

✅ 解答例フロー
[ {"id": "ex4_tab", "type": "tab", "label": "演習4"}, {"id": "ex4_inject1", "type": "inject", "z": "ex4_tab", "name": "0°C", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "0", "payloadType": "num", "x": 130, "y": 80, "wires": [["ex4_range"]]}, {"id": "ex4_inject2", "type": "inject", "z": "ex4_tab", "name": "25°C", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "25", "payloadType": "num", "x": 130, "y": 120, "wires": [["ex4_range"]]}, {"id": "ex4_inject3", "type": "inject", "z": "ex4_tab", "name": "100°C", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "100", "payloadType": "num", "x": 140, "y": 160, "wires": [["ex4_range"]]}, {"id": "ex4_range", "type": "range", "z": "ex4_tab", "minin": "0", "maxin": "100", "minout": "32", "maxout": "212", "action": "scale", "round": false, "property": "payload", "name": "摂氏→華氏", "x": 330, "y": 120, "wires": [["ex4_debug"]]}, {"id": "ex4_debug", "type": "debug", "z": "ex4_tab", "name": "華氏温度", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "payload", "statusType": "auto", "x": 520, "y": 120, "wires": []} ]

✅ 5. まとめ

🎯 重要ポイント:

⚠️ 注意事項:

🔧 6. トラブルシューティング

問題原因解決方法
出力が NaN になる入力が数値でないChange ノードで数値型に変換
期待通りの値にならない範囲設定ミス入力/出力範囲を確認
小数が出力されるRound が無効Round にチェックを入れる
範囲外の値が出力されるAction が Scale OnlyScale and Limit に変更

🏭 7. 実務活用例

ケース1: IoTセンサーの値変換

アナログセンサーの生データを人間が理解しやすい単位に変換。例:ADC値→温度、電圧→圧力など。

ケース2: モーター/LED制御

UIのスライダー値(0-100)をPWMデューティ比(0-255)に変換して、モーターやLEDを制御。

ケース3: データの正規化

異なるスケールのセンサーデータを統一した範囲に正規化して、比較や可視化を容易に。

ケース4: プロトコル変換

異なる機器間でのデータ形式変換。例:0-10Vアナログ信号を0-100%のデジタル値に変換。

📚 Node-RED 公式ドキュメント

🏠