Gracias Alejandro, ya funciona.
Pongo aquí el código para futuros usuarios:
Node-red
[
{
"id": "587cada3c775303e",
"type": "tab",
"label": "Flow 5",
"disabled": false,
"info": "",
"env": []
},
{
"id": "inject-node",
"type": "inject",
"z": "587cada3c775303e",
"name": "Trigger",
"props": {
"payload": true,
"topic": ""
},
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 870,
"y": 260,
"wires": [
[
"file-in-node"
]
]
},
{
"id": "file-in-node",
"type": "file in",
"z": "587cada3c775303e",
"name": "Read Image",
"filename": "PATH TO THE IMAGE",
"filenameType": "str",
"format": "",
"sendError": true,
"allProps": false,
"x": 1050,
"y": 320,
"wires": [
[
"c65279328c2ca7c8"
]
]
},
{
"id": "function-node",
"type": "function",
"z": "587cada3c775303e",
"name": "Prepare Payload",
"func": "msg.headers = {\n 'Content-Type': 'application/json',\n 'X-Auth-Token': 'TOKEN'\n};\n\nmsg.payload = {\n \"VARIABLE\": {\n \"value\": 1234,\n \"context\": { \"image\": msg.payload }\n }\n};\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1430,
"y": 320,
"wires": [
[
"debug-node",
"http-request-node"
]
]
},
{
"id": "http-request-node",
"type": "http request",
"z": "587cada3c775303e",
"name": "Send to Ubidots",
"method": "POST",
"ret": "txt",
"paytoqs": "ignore",
"url": "https://industrial.api.ubidots.com/api/v1.6/devices/DEVICE/",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 1740,
"y": 260,
"wires": [
[]
]
},
{
"id": "debug-node",
"type": "debug",
"z": "587cada3c775303e",
"name": "Debug",
"active": true,
"tosidebar": true,
"console": true,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 1780,
"y": 380,
"wires": []
},
{
"id": "c65279328c2ca7c8",
"type": "function",
"z": "587cada3c775303e",
"name": "function 4",
"func": "// Assuming msg.payload contains the file buffer (e.g., from a previous node that reads the file)\n\n// Check if msg.payload exists and is a Buffer\nif (msg.payload instanceof Buffer) {\n // Convert Buffer to base64\n let base64Image = msg.payload.toString('base64');\n\n // Optionally, you can attach the base64 string to the message payload\n msg.payload = base64Image;\n\n // Set the content type of the message if needed\n msg.headers = {\n 'Content-Type': 'text/plain' // Adjust content type as per your requirement\n };\n\n return msg;\n} else {\n // Handle error or unexpected input\n node.warn(\"Expected msg.payload to be a Buffer containing image data\");\n return null; // Or handle the error accordingly\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1220,
"y": 320,
"wires": [
[
"function-node"
]
]
}
]
HTML CANVAS
<!DOCTYPE html>
<html>
<head>
<title>Display Image, Context, and Timestamp from Ubidots</title>
<style>
#timestamp {
font-size: 1.2em;
margin-bottom: 10px;
}
#debug, #context {
display: none; /* Hide the debug and context sections */
}
</style>
</head>
<body>
<div id="timestamp">
<!-- Timestamp will be displayed here -->
</div>
<div>
<img id="image" src="" alt="Latest Image" style="max-width: 100%;">
</div>
<div id="context">
<!-- Context data will be displayed here -->
</div>
<div id="debug">
<!-- Debug messages will be displayed here -->
</div>
<script>
async function fetchImage() {
const deviceLabel = 'image_test'; // Replace with your Ubidots device label
const variableLabel = 'image_variable'; // Replace with your Ubidots variable label
const token = 'token'; // Replace with your Ubidots token
const debugDiv = document.getElementById('debug');
function addDebugMessage(message) {
debugDiv.innerHTML += `<p>${message}</p>`;
}
function formatTimestamp(timestamp) {
const date = new Date(timestamp);
return date.toLocaleString();
}
try {
addDebugMessage('Fetching image, context, and timestamp from Ubidots...');
const response = await fetch(`https://industrial.api.ubidots.com/api/v1.6/devices/${deviceLabel}/${variableLabel}`, {
method: 'GET',
headers: {
'X-Auth-Token': token
}
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
addDebugMessage('Data received from Ubidots:');
addDebugMessage(`<pre>${JSON.stringify(data, null, 2)}</pre>`); // Display the entire response for debugging
// Check if data.last_value and data.last_value.context are available and not empty
if (data.last_value) {
const context = data.last_value.context;
const timestamp = data.last_value.created_at;
// Display the timestamp
const timestampDiv = document.getElementById('timestamp');
timestampDiv.innerHTML = `<p>Timestamp: ${formatTimestamp(timestamp)}</p>`;
// Display the context data
if (context) {
const contextDiv = document.getElementById('context');
contextDiv.innerHTML = `<pre>${JSON.stringify(context, null, 2)}</pre>`;
if (context.image) {
// Display the image if image is present in context
const base64Image = context.image;
document.getElementById('image').src = `data:image/jpeg;base64,${base64Image}`;
addDebugMessage('Image displayed successfully.');
} else {
addDebugMessage('No image in context');
document.getElementById('image').alt = 'No image found in context';
}
} else {
addDebugMessage('No context found or empty context');
document.getElementById('image').alt = 'No context found';
}
} else {
addDebugMessage('No last_value found');
document.getElementById('image').alt = 'No last_value found';
}
} catch (error) {
addDebugMessage(`Fetching image failed: ${error.message}`);
document.getElementById('image').alt = 'Error fetching image';
}
}
// Fetch the image, context, and timestamp when the page loads
window.onload = fetchImage;
</script>
</body>
</html>