Ok so in response to Colin, I have never seen a zero value returned from the cat command. Consequently, I created a function which exactly emulates the 'node-red-contrib-ds18b20-sensor'. It uses 'fs' (specifically 'fs.readdirSync' and ('fs.readFileSync') hoping that this might be more successful than using the DS18B20 node. Here is the function:
/*
DS18B20 function uses fs.readdirSync() method to get device list from system folders
then reads 'devices' files using 'fs.readFileSync'
REQUIRES the following to be added to 'settings.js':
var fs = require("fs");
functionGlobalContext: {
fs : require('fs')
},
*/
const SensorFamily = '28';
const RootFolder = '/sys/bus/w1/devices'; // location of DS18B20 FolderList folders
var SensorReadings = [];
var FolderName;
var fs=global.get("fs"); // import the filesystem module
var FolderList = fs.readdirSync(RootFolder); // get files / folders in RootFolder
//console.log('DS18B20 root folder contents: ' + FolderList); // DEBUG
// loop incoming folder array to get foldername beginning 'w1_' (used later as 'dir' in output array)
for (i = 0; i < FolderList.length; i++) {
if (FolderList[i].substring(0, 3) == 'w1_') {
FolderName = FolderList[i];
//console.log('DS18B20 foldername: ' + FolderName); // DEBUG
{ break; }
}
}
// loop incoming folder array and process sensor folders
for (i = 0; i < FolderList.length; i++) {
if (FolderList[i].substring(0, 3) == (SensorFamily +'-')) {
// compile and read sensor file
var FileName = '/sys/bus/w1/devices/' + FolderList[i] + '/w1_slave';
try {
//console.log('DS18B20 reading file: ' + FileName); // DEBUG
var FileContents
FileContents = fs.readFileSync(FileName, 'utf8');
// console.log('DS18B20 FileContents length:' + FileContents.length); // DEBUG
if (FileContents.length !==0) {
var TempPos = FileContents.search("t=");
if (TempPos !== -1) {
var SensorTemp = FileContents.substring(FileContents.search("t=") + 2) / 1000;
// add new object to SensorReadings
SensorReadings.push({
family : '28',
id : FormatId(FolderList[i]),
dir : FolderName,
file : FolderList[i],
temp : SensorTemp,
})
} else {
// cannot find temperature string in file content
console.log('DS18B20 temperature not present in file: ' + FileName);
console.log(FileContents);
}
} else {
// zero length file read!
console.log('DS18B20 zero length sensor file returned: ' + FileName);
}
}
catch (ex)
{
console.log('DS18B20 read function error for: ' + FileName);
console.log(ex);
}
}
}
if(SensorReadings.length !== 0) {
msg.payload = SensorReadings;
return(msg);
}
return;
function FormatId(file) {
var id = '';
for (k = 0; k <= 6; k++){
//var Byte = file.substring((file.length) - (2 * k), 2);
var Byte = file.substr(file.length - (2 * k), 2);
id = id + Byte;
}
return id.toUpperCase();
}
I dropped it into my flow and it worked fine for some hours, then I started seeing zero length files returned by 'fs.readFileSync'. When it failed, of the four sensor files read ('/sys/bus/w1/devices/' + + '/w1_slave'), the first permanently returned zero length, the second intermittently and the other two were fine - just like the 'node-red-contrib-ds18b20-sensor' that the function replaced! albeit the DS18B20 node returned a perfectly formatted object but with zero for the temperature value.
I then replaced the function with three nodes. The first is a function which uses 'fs.readdirSync' to build a list of sensor filenames and send them to a standard 'file in' node (Node Red in the 'storage' category). The 'file in' node reads the file (in place of the 'fs.readFileSync' function) and passes it to another function which outputs a single message for each file read in a 'node-red-contrib-ds18b20-sensor' like format. In short, three nodes replacing the original DS18B20 node.
[{"id":"35647b33.319794","type":"inject","z":"8369f339.da573","name":"1 Minute","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"60","crontab":"","once":true,"onceDelay":"10","topic":"","payload":"","payloadType":"date","x":120,"y":400,"wires":[["6d36625a.5e26fc"]]},{"id":"6d36625a.5e26fc","type":"function","z":"8369f339.da573","name":"Get Files to Read","func":"/* \n\tFunction uses fs.readdirSync() method to get device list from system folders\n\n\tREQUIRES the following to be added to 'settings.js':\n\tvar fs = require(\"fs\");\n\tfunctionGlobalContext: {\n\t\tfs : require('fs')\n\t},\n*/\n\nconst SensorFamily = '28';\nconst RootFolder = '/sys/bus/w1/devices'; // location of DS18B20 FolderList folders\nvar FolderName;\nvar fs=global.get(\"fs\"); \t\t// import the filesystem module\nvar FolderList = fs.readdirSync(RootFolder);\t\t// get files / folders in RootFolder\n//console.log('DS18B20 root folder contents: ' + FolderList); // DEBUG\n\n// loop incoming folder array to get foldername beginning 'w1_' (used later as 'dir' in output array)\nfor (i = 0; i < FolderList.length; i++) {\n\tif (FolderList[i].substring(0, 3) == 'w1_') {\n\t\tFolderName = FolderList[i];\n// \tconsole.log('DS18B20 foldername: ' + FolderName); // DEBUG\n\t\t{ break; }\n\t}\n}\n\n// loop incoming folder array and send sensor filenames\nfor (i = 0; i < FolderList.length; i++) {\n\tif (FolderList[i].substring(0, 3) == (SensorFamily +'-')) {\n\t\t// compile sensor filename\n\t msg.filename = '/sys/bus/w1/devices/' + FolderList[i] + '/w1_slave';\n\t msg.dir = 'FolderName';\n\t node.send(msg);\n\t}\n}\n\nreturn;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":310,"y":400,"wires":[["c135d16a.8536e"]]},{"id":"c135d16a.8536e","type":"file in","z":"8369f339.da573","name":"Get Sensor File","filename":"","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":520,"y":400,"wires":[["8bf460c1.0a4c6","9db96fa3.6246e","eed5b91.6a1b248"]]},{"id":"9db96fa3.6246e","type":"function","z":"8369f339.da573","name":"Convert to Array","func":"\nvar SensorReadings = [];\nvar FileName = msg.filename.substr(20,15);\nvar FileContents = msg.payload\nif (FileContents.length !==0) {\n\tvar TempPos = FileContents.search(\"t=\");\n\tif (TempPos !== -1) {\n\t\tvar SensorTemp = FileContents.substring(FileContents.search(\"t=\") + 2) / 1000;\n\t\t// add new object to SensorReadings\n\t\tSensorReadings.push({\n\t\t\tfamily : '28', \n\t\t\tid : FormatId(FileName),\n\t\t\tdir : msg.dir,\n\t\t\tfile : FileName,\n\t\t\ttemp : SensorTemp,\n\t\t})\n\t} else {\n\t\t// cannot find temperature string in file content\n\t\tconsole.log('DS18B20 temperature not present in file: ' + FileName);\n\t\tconsole.log(FileContents);\n\t}\n} else {\n\t// zero length file read!\n\tconsole.log('DS18B20 zero length sensor file returned: ' + FileName);\n}\n\nif(SensorReadings.length !== 0) {\n\tmsg.payload = SensorReadings;\n\treturn(msg);\n}\n\nreturn;\n\nfunction FormatId(file) {\n\tvar id = '';\n\tfor (k = 0; k <= 6; k++){\n\t\t//var Byte = file.substring((file.length) - (2 * k), 2);\n\t\tvar Byte = file.substr(file.length - (2 * k), 2);\n\t\tid = id + Byte;\n\t}\n\treturn id.toUpperCase();\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","x":720,"y":400,"wires":[["7ed1a82f.831608","c8f8fdbf.89d52"]]}]
This seems to work just fine - I haven't had any reading errors for many days now! The downside is that it returns an object for each file rather than a single object for all sensors read, meaning more messages to send.
I don't know whether the problem is my implementation of 'fs.readFileSync', whether there is a problem with 'fs.readFileSync' or if the issue is something completely different. In any case, my problem is solved.
Apologies for the long ramble; apologies for the code quality (my skill level is 'Dangerous Amateur') and thanks to Colin and hotNipi for your replies.