You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js TypeError [ERR_INVALID_ARG_TYPE]错误排查求助——IoT设备远程传感器数据采集与控制代码问题

TypeError: "path" argument is undefined when reading Thing Description files in Node.js IoT project

我正在开发一个IoT项目,目标是获取温湿度等传感器数据并远程控制设备,但运行代码时遇到了一个类型错误,反复检查代码都没能定位到问题根源。以下是报错信息:

node:internal/errors:464
ErrorCaptureStackTrace(err);
^
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received undefined
at Object.openSync (node:fs:577:10)
at Object.readFileSync (node:fs:453:35)
at readTd (C:\Users\Mehdi\Desktop\WS2022\IoT_Mehdi\iotrlws2122cons2-ge37vok\6_averageSensors.js:175:24)
at C:\Users\Mehdi\Desktop\WS2022\IoT_Mehdi\iotrlws2122cons2-ge37vok\6_averageSensors.js:201:46
at step (C:\Users\Mehdi\Desktop\WS2022\IoT_Mehdi\iotrlws2122cons2-ge37vok\6_averageSensors.js:33:23)
at Object.next (C:\Users\Mehdi\Desktop\WS2022\IoT_Mehdi\iotrlws2122cons2-ge37vok\6_averageSensors.js:14:53)
at fulfilled (C:\Users\Mehdi\Desktop\WS2022\IoT_Mehdi\iotrlws2122cons2-ge37vok\6_averageSensors.js:5:58)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
code: 'ERR_INVALID_ARG_TYPE'
}

我的完整代码如下:

import { Logger, createLogMessage } from './utils/Logger';
import { AffordanceType, RecipientType, Operation } from './utils/LogTemplate';
import { HttpsClientFactory } from "@node-wot/binding-http";
import ConsumedThing from "@node-wot/core/dist/consumed-thing";
import { Servient } from "@node-wot/core";
import fs = require("fs");
import path = require("path");
import { exit } from "process";
import { ThingDescription } from "wot-typescript-definitions";

const servient = new Servient();

let creds = {
"urn:dev:ops:32473-sensehat-001": {
// Here the username and password I Provided you with
"username": "xxxxxx",
"password": "xxxxxx"
},
"urn:dev:ops:32473-sensehat-002": {
// Here the username and password I Provided you with
"username": "xxxxxx",
"password": "xxxxxx"
},
"urn:dev:ops:32473-sensehat-003": {
// Here the username and password I Provided you with
"username": "xxxxxx",
"password": "xxxxxx"
},
"urn:dev:ops:32473-sensehat-004": {
// Here the username and password I Provided you with
"username": "xxxxxx",
"password": "xxxxxx"
},
"urn:dev:ops:32473-HueIndoorSensor-1": {
// Here the username and password I Provided you with
"username": "xxxxxx",
"password": "xxxxxx"
},
"urn:dev:ops:32473-HueIndoorSensor-2": {
// Here the username and password I Provided you with
"username": "xxxxxx",
"password": "xxxxxx"
},
"urn:dev:ops:32473-HueOutdoorSensor-1": {
// Here the username and password I Provided you with
"username": "xxxxxx",
"password": "xxxxxx"
},
};

servient.addClientFactory(new HttpsClientFactory(null));
servient.addCredentials(creds);

const delay = async (ms: number) => {
await new Promise<void>(resolve => setTimeout(() => resolve(), ms));
}

var logger = new Logger();

async function readLoggedProperty(thing: any, propertyName: string, options?: any): Promise<any> {
var logMsg = createLogMessage(
{ name: propertyName, type: AffordanceType.Property },
1,
Operation.Readproperty,
RecipientType.Thing,
thing.getThingDescription().title,
thing.getThingDescription().id,
null
);
logger.addMessage(logMsg);
// logger.saveMessages("6_averageSensors", "HTTP");

let ret = await thing.readProperty(propertyName, options);

var logMsg = createLogMessage(
{ name: propertyName, type: AffordanceType.Property },
1,
Operation.Invokeaction,
RecipientType.Controller,
thing.getThingDescription().title,
thing.getThingDescription().id,
ret
);
logger.addMessage(logMsg);
// logger.saveMessages("6_averageSensors", "HTTP");

return ret;
}

async function invokeLoggedAction(thing: any, actionName: string, params?: any, options?: any): Promise<any> {
var logMsg = createLogMessage(
{ name: actionName, type: AffordanceType.Action },
1,
Operation.Invokeaction,
RecipientType.Thing,
thing.getThingDescription().title,
thing.getThingDescription().id,
params
);
logger.addMessage(logMsg);
// logger.saveMessages("6_averageSensors", "HTTP");

await thing.invokeAction(actionName, params, options).then(function (ret) {
var logMsg = createLogMessage(
{ name: actionName, type: AffordanceType.Action },
1,
Operation.Invokeaction,
RecipientType.Controller,
thing.getThingDescription().title,
thing.getThingDescription().id,
ret
);
logger.addMessage(logMsg);
logger.saveMessages("6_averageSensors", "HTTP");
return ret;
})
}

let td_sensHats1: ThingDescription;

function readTd (tdPath: string){
let read_file = fs.readFileSync(tdPath);
var td = JSON.parse(read_file.toString());
return td;
}

var ConsumedthingsHat=[]
var ConsumedthingsHue=[]

async function main() {
var array_SenseHat = ["SenseHat1.json","SenseHat2.json","SenseHat3.json","SenseHat4.json"]; //declaration
var array_Hue=["Hue Indoor Sensor 1.json","Hue Indoor Sensor 2.json","Hue Outdoor Sensor.json"]; //declaration

await servient.start().then(async (WoT) => {
for (let m = 0 ; m < 5; m ++) {
var td = readTd(array_SenseHat[m]);
const thing = await WoT.consume(td) as ConsumedThing;
console.log(thing)
ConsumedthingsHat.push(thing);
}

for (let m = 0 ; m < 4; m ++) {
var td = readTd(array_Hue[m]);
const thing = await WoT.consume(td) as ConsumedThing;
console.log(thing)
ConsumedthingsHue.push(thing);
}

// await servient.start().then(async (WoT) => {
const thing1 = await WoT.consume(ConsumedthingsHat[0]);

// Average Teamperature
let array_tempvalues: number[] = [];
for (let j = 0; j < 5; j++) {
// var td = await readTd(array_SenseHat[j]);
// const temp_Value = await WoT.consume(td) as ConsumedThing;
let temp = await readLoggedProperty(ConsumedthingsHat[j], "temperature");
await array_tempvalues.push(temp);
}

let avgTemp = array_tempvalues.reduce((total, actual_TempValue, index, array) => {
return (total + actual_TempValue) / array.length;
})

let payload1 = { "avgTmp": avgTemp.toFixed(2) };
await invokeLoggedAction(thing1, "showMessage", payload1);

// Avg pressure on hat2
const thing2 = await WoT.consume(ConsumedthingsHat[1]);
let arrayPressureValues: number[] = [];
for (let j = 0; j < 5; j++) {
// const element = await WoT.consume(ConsumedthingsHat[j]);
let pressure = await readLoggedProperty(ConsumedthingsHat[j], "pressure");
arrayPressureValues.push(pressure);
}

let avgPress = arrayPressureValues.reduce((total, actual_Pressure, ind, array) => {
return (total + actual_Pressure) / array.length;
})

let payload2 = { "avgPressure": avgPress.toFixed(2) };
await invokeLoggedAction(thing2, "showMessage", payload2);

// Avg humidity on hat2
let arrayHumidity: number[] = [];
const thing3 = await WoT.consume(ConsumedthingsHat[2]);
for (let j = 0; j <5; j++) {
// const element = await WoT.consume(ConsumedthingsHat[j]);
let humid = await readLoggedProperty(ConsumedthingsHat[j], "humidity");
arrayHumidity.push(humid);
}

let avgHumid = arrayHumidity.reduce((total, actual_Humidity, ind, array) => {
return (total + actual_Humidity) / array.length;
})

let payload3 = { "textString": avgHumid.toFixed(2) };
await invokeLoggedAction(thing3, "showMessage", payload3);

// Avg humidity on hat2
let arrayLight: number[] = [];
const thing4 = await WoT.consume(ConsumedthingsHue[0]);
for (let j = 0; j < 5; j++) {
// const element = await WoT.consume(ConsumedthingsHue[j]);
let info = await readLoggedProperty(ConsumedthingsHat[j], "lightInformation");
arrayLight.push(info["state"]["lightlevel"]);
}

let avgLight = arrayLight.reduce((total, actual_Light, ind, array) => {
return (total + actual_Light) / array.length;
})

let payload4 = { "textString": avgLight.toFixed(2) };
await invokeLoggedAction(thing4, "showMessage", payload4);

await delay(5000).then(async () => {
for (let j = 0; j < 5; j++) {
const element1= array_SenseHat[j];
await invokeLoggedAction(element1,"clear");
console.log("Nothing Displayed");
}
})
})
}

main()

请求协助排查该错误的根源并提供解决方法。


问题根源分析

从报错信息可以看到,错误发生在readTd函数调用fs.readFileSync(tdPath)时,传入的tdPath是undefined。追踪代码可以发现两个核心问题:

  1. 循环次数与数组长度不匹配:

    • 你的array_SenseHat数组只有4个元素,但第一个for循环写的是m < 5,当m=4时,array_SenseHat[4]就是undefined,传给readTd就会导致路径参数无效。
    • 同理,array_Hue数组只有3个元素,但第二个for循环写的是m < 4,当m=3时,array_Hue[3]也是undefined,同样触发错误。
  2. 后续循环存在相同的越界问题:
    计算平均温度、压力、湿度的循环都写了j <5,但ConsumedthingsHat数组最多只有4个有效元素,后续也会出现访问undefined元素的问题。另外最后一个清除显示的循环,还错误地把文件路径字符串传给了需要ConsumedThing实例的invokeLoggedAction函数。

解决方法

1. 修正循环终止条件,使用数组长度而非硬编码数字

把所有循环的终止条件改成依赖数组的length属性,这样无论数组元素数量变化,循环都不会越界:

// 修正SenseHat循环
for (let m = 0 ; m < array_SenseHat.length; m ++) {
  var td = readTd(array_SenseHat[m]);
  const thing = await WoT.consume(td) as ConsumedThing;
  console.log(thing)
  ConsumedthingsHat.push(thing);
}

// 修正Hue循环
for (let m = 0 ; m < array_Hue.length; m ++) {
  var td = readTd(array_Hue[m]);
  const thing = await WoT.consume(td) as ConsumedThing;
  console.log(thing)
  ConsumedthingsHue.push(thing);
}

// 修正温度平均值循环
for (let j = 0; j < ConsumedthingsHat.length; j++) {
  let temp = await readLoggedProperty(ConsumedthingsHat[j], "temperature");
  array_tempvalues.push(temp);
}

// 同理修正压力、湿度、光照的循环,都使用ConsumedthingsHat.length或ConsumedthingsHue.length

2. 给readTd函数添加参数校验(可选但推荐)

在readTd函数开头添加参数检查,提前抛出更明确的错误,方便后续调试:

function readTd (tdPath: string){
  if (!tdPath) {
    throw new Error(`Failed to read Thing Description: path is undefined. Check if your device array has enough elements.`);
  }
  let read_file = fs.readFileSync(tdPath);
  var td = JSON.parse(read_file.toString());
  return td;
}

3. 修正最后一个清除显示的循环

最后一个循环里,你把array_SenseHat[j](字符串路径)传给了invokeLoggedAction,但这个函数需要接收一个ConsumedThing实例,不是路径。应该改成:

await delay(5000).then(async () => {
  for (let j = 0; j < ConsumedthingsHat.length; j++) {
    await invokeLoggedAction(ConsumedthingsHat[j],"clear");
    console.log("Nothing Displayed");
  }
})

额外优化建议

  • 避免在await servient.start().then(...)里面嵌套过多异步逻辑,改用async/await的链式写法,代码会更易读。
  • 可以给ConsumedthingsHat和ConsumedthingsHue添加类型注解,符合TypeScript的规范,比如:const ConsumedthingsHat: ConsumedThing[] = [];

内容的提问来源于stack exchange,提问作者Spearitch502

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 10:58:14