// Function ノードで動的にファイル名を設定
msg.filename = "/home/pi/logs/sensor_" + new Date().toISOString().slice(0,10) + ".log";
msg.payload = "センサーデータ: " + msg.payload;
return msg;
📥 サンプルフローJSON(クリックで展開)
[
{
"id": "file_sample_tab",
"type": "tab",
"label": "File サンプル",
"disabled": false,
"info": ""
},
{
"id": "file_comment1",
"type": "comment",
"z": "file_sample_tab",
"name": "━━━ ファイルへの書き込み(追記) ━━━",
"info": "",
"x": 200,
"y": 40,
"wires": []
},
{
"id": "file_inject1",
"type": "inject",
"z": "file_sample_tab",
"name": "ログ追記",
"props": [{"p": "payload"}],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "センサー値: 25.5℃",
"payloadType": "str",
"x": 140,
"y": 100,
"wires": [["file_func_timestamp"]]
},
{
"id": "file_func_timestamp",
"type": "function",
"z": "file_sample_tab",
"name": "タイムスタンプ追加",
"func": "var now = new Date().toISOString();\nmsg.payload = now + \" - \" + msg.payload;\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 330,
"y": 100,
"wires": [["file_write_append"]]
},
{
"id": "file_write_append",
"type": "file",
"z": "file_sample_tab",
"name": "ログ追記",
"filename": "/tmp/nodered_sample.log",
"filenameType": "str",
"appendNewline": true,
"createDir": true,
"overwriteFile": "false",
"encoding": "utf8",
"x": 520,
"y": 100,
"wires": [["file_debug1"]]
},
{
"id": "file_debug1",
"type": "debug",
"z": "file_sample_tab",
"name": "書き込み完了",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "payload",
"targetType": "msg",
"statusVal": "\"書き込み完了\"",
"statusType": "str",
"x": 690,
"y": 100,
"wires": []
},
{
"id": "file_comment2",
"type": "comment",
"z": "file_sample_tab",
"name": "━━━ ファイルの読み込み ━━━",
"info": "",
"x": 180,
"y": 180,
"wires": []
},
{
"id": "file_inject2",
"type": "inject",
"z": "file_sample_tab",
"name": "ファイル読み込み",
"props": [],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 160,
"y": 240,
"wires": [["file_read"]]
},
{
"id": "file_read",
"type": "file in",
"z": "file_sample_tab",
"name": "ログ読み込み",
"filename": "/tmp/nodered_sample.log",
"filenameType": "str",
"format": "utf8",
"chunk": false,
"sendError": false,
"encoding": "utf8",
"allProps": false,
"x": 350,
"y": 240,
"wires": [["file_debug2"]]
},
{
"id": "file_debug2",
"type": "debug",
"z": "file_sample_tab",
"name": "ファイル内容",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"x": 530,
"y": 240,
"wires": []
},
{
"id": "file_comment3",
"type": "comment",
"z": "file_sample_tab",
"name": "━━━ 上書き保存 ━━━",
"info": "",
"x": 160,
"y": 320,
"wires": []
},
{
"id": "file_inject3",
"type": "inject",
"z": "file_sample_tab",
"name": "設定を保存",
"props": [],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 150,
"y": 380,
"wires": [["file_func_config"]]
},
{
"id": "file_func_config",
"type": "function",
"z": "file_sample_tab",
"name": "設定オブジェクト",
"func": "msg.payload = JSON.stringify({\n \"appName\": \"My IoT App\",\n \"version\": \"1.0.0\",\n \"settings\": {\n \"interval\": 5000,\n \"threshold\": 30\n },\n \"updatedAt\": new Date().toISOString()\n}, null, 2);\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 330,
"y": 380,
"wires": [["file_write_overwrite"]]
},
{
"id": "file_write_overwrite",
"type": "file",
"z": "file_sample_tab",
"name": "設定ファイル保存",
"filename": "/tmp/nodered_config.json",
"filenameType": "str",
"appendNewline": false,
"createDir": true,
"overwriteFile": "true",
"encoding": "utf8",
"x": 530,
"y": 380,
"wires": [["file_debug3"]]
},
{
"id": "file_debug3",
"type": "debug",
"z": "file_sample_tab",
"name": "保存完了",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "payload",
"targetType": "msg",
"statusVal": "\"設定保存完了\"",
"statusType": "str",
"x": 700,
"y": 380,
"wires": []
},
{
"id": "file_comment4",
"type": "comment",
"z": "file_sample_tab",
"name": "━━━ 動的ファイル名(日付別ログ) ━━━",
"info": "",
"x": 210,
"y": 460,
"wires": []
},
{
"id": "file_inject4",
"type": "inject",
"z": "file_sample_tab",
"name": "イベント発生",
"props": [{"p": "payload"}],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "ボタンが押されました",
"payloadType": "str",
"x": 150,
"y": 520,
"wires": [["file_func_dynamic"]]
},
{
"id": "file_func_dynamic",
"type": "function",
"z": "file_sample_tab",
"name": "日付別ファイル名",
"func": "var today = new Date().toISOString().slice(0, 10);\nmsg.filename = \"/tmp/events_\" + today + \".log\";\n\nvar timestamp = new Date().toISOString();\nmsg.payload = timestamp + \" | \" + msg.payload;\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 330,
"y": 520,
"wires": [["file_write_dynamic"]]
},
{
"id": "file_write_dynamic",
"type": "file",
"z": "file_sample_tab",
"name": "動的ファイル",
"filename": "",
"filenameType": "msg",
"appendNewline": true,
"createDir": true,
"overwriteFile": "false",
"encoding": "utf8",
"x": 520,
"y": 520,
"wires": [["file_debug4"]]
},
{
"id": "file_debug4",
"type": "debug",
"z": "file_sample_tab",
"name": "ファイル名確認",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "filename",
"targetType": "msg",
"statusVal": "filename",
"statusType": "msg",
"x": 700,
"y": 520,
"wires": []
},
{
"id": "file_comment5",
"type": "comment",
"z": "file_sample_tab",
"name": "━━━ エラーハンドリング ━━━",
"info": "",
"x": 170,
"y": 600,
"wires": []
},
{
"id": "file_inject5",
"type": "inject",
"z": "file_sample_tab",
"name": "存在しないファイル",
"props": [{"p": "filename", "v": "/nonexistent/path/file.txt", "vt": "str"}],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 170,
"y": 660,
"wires": [["file_read_error"]]
},
{
"id": "file_read_error",
"type": "file in",
"z": "file_sample_tab",
"name": "読み込み試行",
"filename": "filename",
"filenameType": "msg",
"format": "utf8",
"chunk": false,
"sendError": false,
"encoding": "utf8",
"allProps": false,
"x": 360,
"y": 660,
"wires": [["file_debug5"]]
},
{
"id": "file_debug5",
"type": "debug",
"z": "file_sample_tab",
"name": "読み込み結果",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 540,
"y": 660,
"wires": []
},
{
"id": "file_catch",
"type": "catch",
"z": "file_sample_tab",
"name": "ファイルエラー捕捉",
"scope": ["file_read_error"],
"uncaught": false,
"x": 350,
"y": 720,
"wires": [["file_debug_error"]]
},
{
"id": "file_debug_error",
"type": "debug",
"z": "file_sample_tab",
"name": "エラー内容",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "error.message",
"targetType": "msg",
"statusVal": "error.message",
"statusType": "msg",
"x": 530,
"y": 720,
"wires": []
}
]
演習3: JSON設定ファイルの保存と読み込み 中級
📋 課題: 設定オブジェクトをJSONファイルとして保存し、別のフローで読み込んでオブジェクトとして使用してください。
✅ 成功の条件:
- 「設定保存」ボタンを押すと
/tmp/config.json が作成され、中身が有効なJSON形式である
- 「設定読込」ボタンを押すとデバッグパネルにJavaScriptオブジェクトとして設定が表示される
- ノードステータスに server プロパティの値(例: "localhost")が表示される
💡 ヒント
保存時: JSON.stringify() で文字列化、読み込み時: JSON ノードで解析
✅ 解答例フロー
[
{"id": "ex3_tab", "type": "tab", "label": "演習3"},
{"id": "ex3_inject1", "type": "inject", "z": "ex3_tab", "name": "設定保存", "props": [], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "x": 140, "y": 80, "wires": [["ex3_func1"]]},
{"id": "ex3_func1", "type": "function", "z": "ex3_tab", "name": "設定作成", "func": "msg.payload = JSON.stringify({\n server: \"localhost\",\n port: 8080,\n debug: true\n}, null, 2);\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 290, "y": 80, "wires": [["ex3_file_write"]]},
{"id": "ex3_file_write", "type": "file", "z": "ex3_tab", "name": "JSON保存", "filename": "/tmp/config.json", "filenameType": "str", "appendNewline": false, "createDir": true, "overwriteFile": "true", "encoding": "utf8", "x": 450, "y": 80, "wires": [["ex3_debug1"]]},
{"id": "ex3_debug1", "type": "debug", "z": "ex3_tab", "name": "保存完了", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "\"保存完了\"", "statusType": "str", "x": 620, "y": 80, "wires": []},
{"id": "ex3_inject2", "type": "inject", "z": "ex3_tab", "name": "設定読込", "props": [], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "x": 140, "y": 160, "wires": [["ex3_file_read"]]},
{"id": "ex3_file_read", "type": "file in", "z": "ex3_tab", "name": "JSON読込", "filename": "/tmp/config.json", "filenameType": "str", "format": "utf8", "chunk": false, "sendError": false, "encoding": "utf8", "allProps": false, "x": 290, "y": 160, "wires": [["ex3_json"]]},
{"id": "ex3_json", "type": "json", "z": "ex3_tab", "name": "JSON解析", "property": "payload", "action": "", "pretty": false, "x": 450, "y": 160, "wires": [["ex3_debug2"]]},
{"id": "ex3_debug2", "type": "debug", "z": "ex3_tab", "name": "設定オブジェクト", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "payload", "targetType": "msg", "statusVal": "payload.server", "statusType": "msg", "x": 630, "y": 160, "wires": []}
]
演習4: 日付別ローテーションログ 上級
📋 課題: センサーデータを日付別のファイルに保存し、7日以上前のファイルを自動削除する仕組みを作成してください。
✅ 成功の条件:
- 「センサーデータ」ボタンを押すと
/tmp/sensor_YYYY-MM-DD.log 形式のファイルにデータが追記される
- ノードステータスに現在の保存先ファイルパスが表示される
- 「古いファイル削除」ボタンを押すと7日前の日付のファイルが削除(または削除試行)される
- 毎回ボタンを押すたびにタイムスタンプ付きのデータが同じ日付ファイルに蓄積される
💡 ヒント
msg.filename で動的にファイル名を指定。削除は Action: delete file を使用。
✅ 解答例フロー
[
{"id": "ex4_tab", "type": "tab", "label": "演習4"},
{"id": "ex4_inject", "type": "inject", "z": "ex4_tab", "name": "センサーデータ", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "25.5", "payloadType": "num", "x": 160, "y": 80, "wires": [["ex4_func_write"]]},
{"id": "ex4_func_write", "type": "function", "z": "ex4_tab", "name": "日付別ファイル名", "func": "var today = new Date().toISOString().slice(0,10);\nmsg.filename = \"/tmp/sensor_\" + today + \".log\";\nmsg.payload = new Date().toISOString() + \",\" + msg.payload;\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 350, "y": 80, "wires": [["ex4_file_write"]]},
{"id": "ex4_file_write", "type": "file", "z": "ex4_tab", "name": "ログ追記", "filename": "", "filenameType": "msg", "appendNewline": true, "createDir": true, "overwriteFile": "false", "encoding": "utf8", "x": 530, "y": 80, "wires": [["ex4_debug1"]]},
{"id": "ex4_debug1", "type": "debug", "z": "ex4_tab", "name": "保存先", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "filename", "targetType": "msg", "statusVal": "filename", "statusType": "msg", "x": 690, "y": 80, "wires": []},
{"id": "ex4_inject_del", "type": "inject", "z": "ex4_tab", "name": "古いファイル削除", "props": [], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "x": 170, "y": 160, "wires": [["ex4_func_del"]]},
{"id": "ex4_func_del", "type": "function", "z": "ex4_tab", "name": "7日前のファイル名", "func": "var d = new Date();\nd.setDate(d.getDate() - 7);\nvar oldDate = d.toISOString().slice(0,10);\nmsg.filename = \"/tmp/sensor_\" + oldDate + \".log\";\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 370, "y": 160, "wires": [["ex4_file_del"]]},
{"id": "ex4_file_del", "type": "file", "z": "ex4_tab", "name": "ファイル削除", "filename": "", "filenameType": "msg", "appendNewline": true, "createDir": false, "overwriteFile": "delete", "encoding": "utf8", "x": 550, "y": 160, "wires": [["ex4_debug2"]]},
{"id": "ex4_debug2", "type": "debug", "z": "ex4_tab", "name": "削除結果", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "filename", "targetType": "msg", "statusVal": "\"削除試行\"", "statusType": "str", "x": 700, "y": 160, "wires": []}
]