Node-RED: How to Store All Bosch Smart Home Devices in the Global Context
Using Node-RED together with your Bosch Smart Home system lets you manage your smart devices like a pro. In this article, I’ll walk you through how to save all your Bosch Smart Home devices in Node-RED’s global context, so you can easily access this info anytime, anywhere within any flow.

Why Should You Save Device Info in the Global Context?
If you’re working with Node-RED and the Bosch Smart Home system, you’ve probably encountered this headache: you have tons of devices, each identified by cryptic IDs like “hdm:ZigBee:12345678.” When building automations, it’s tricky to remember which ID belongs to which device.
By storing all device names in the global context, you get several perks:
- You can access device names in every flow without making an API call each time
- Names are clean and readable, including the room name
- You can utilize this info for dynamic dashboards or complex logic
- You save time developing new flows because device mapping is instantly clear
This approach is especially handy if you have a big setup or multiple people working on your Node-RED flows.
Requirements
Before you dive in, make sure you have the following:
- A working Node-RED installation
- Access to your Bosch Smart Home system via the local REST API
- Room names already saved in the global context (see this guide on saving Bosch room names globally)
The code we’ll use expects the room names to be stored under “roomNames_BSH” in the global context. If you haven’t done that step yet, I recommend checking out the linked article first.
Breaking Down the Code
Here’s the complete script that saves all your Bosch Smart Home devices into the global context. Let’s walk through it bit by bit:
// Initialize an object to store ID-name mappings
let deviceNames_BSH = {};
// Load room names from the global context
let roomNames_BSH = global.get("roomNames_BSH") || {};
// Check if msg.payload is an array
if (Array.isArray(msg.payload)) {
msg.payload.forEach(device => {
let id = device.id;
let name = device.name;
let key = null;
let roomName = "Unknown Room"; // Default if no room found
// Extract the key based on device protocol
if (id.startsWith("hdm:ZigBee:")) {
key = id.substring("hdm:ZigBee:".length);
} else if (id.startsWith("hdm:HomeMaticIP:")) {
key = id.substring("hdm:HomeMaticIP:".length);
}
if (key) {
// Optional: Assuming each device has a room ID, e.g., device.roomId
// Adjust based on your device object's structure
if (device.roomId && roomNames_BSH[device.roomId]) {
roomName = roomNames_BSH[device.roomId];
}
// Replace spaces with dots in roomName and device name
let sanitizedRoomName = roomName.replace(/\s+/g, '.');
let sanitizedName = name.replace(/\s+/g, '.');
// Combine room name and device name
let fullName = `${sanitizedRoomName}.${sanitizedName}`;
deviceNames_BSH[key] = fullName;
}
});
// Save the object in the global context under "deviceNames_BSH"
global.set("deviceNames_BSH", deviceNames_BSH);
// Optional: Log for verification
node.warn("Device names with room names saved in global context under 'deviceNames_BSH'");
} else {
node.error("msg.payload is not an array");
}
return msg;
This code runs inside a Function node. It processes the device data returned by your Bosch Smart Home system. Let’s break down what it does step-by-step.
Initialization and Setup
First, we create an empty object to hold our device name mappings and load existing room names from the global context:
// Initialize an object to store ID-name mappings
let deviceNames_BSH = {};
// Load room names from the global context
let roomNames_BSH = global.get("roomNames_BSH") || {};
The || operator makes sure we get at least an empty object if no room names are stored yet, preventing errors when the “roomNames_BSH” variable doesn’t exist.
Processing Device Data
Next, we check whether msg.payload is an array, and if it is, we process every device:
if (Array.isArray(msg.payload)) {
msg.payload.forEach(device => {
let id = device.id;
let name = device.name;
let key = null;
let roomName = "Unknown Room"; // Default if no room found
// Extract the key based on device protocol
if (id.startsWith("hdm:ZigBee:")) {
key = id.substring("hdm:ZigBee:".length);
} else if (id.startsWith("hdm:HomeMaticIP:")) {
key = id.substring("hdm:HomeMaticIP:".length);
}
// ... further processing
});
}
Here’s what’s happening:
- We pull out the ID and name of each device
- We set a default room name
- We trim the device ID prefix depending on protocol (ZigBee or HomeMaticIP)
Bosch Smart Home device IDs typically start with prefixes like “hdm:ZigBee:” or “hdm:HomeMaticIP:” followed by a unique ID. Removing that prefix gives us a cleaner key to use.
Now we match the device to its room and format the name nicely:
if (key) {
// Optional: Assuming each device has a room ID, e.g., device.roomId
// Adjust based on actual device object structure
if (device.roomId && roomNames_BSH[device.roomId]) {
roomName = roomNames_BSH[device.roomId];
}
// Replace spaces with dots for better compatibility
let sanitizedRoomName = roomName.replace(/\s+/g, '.');
let sanitizedName = name.replace(/\s+/g, '.');
// Combine room and device name
let fullName = `${sanitizedRoomName}.${sanitizedName}`;
deviceNames_BSH[key] = fullName;
}
In this step:
- We check if the device has a room ID and if that room exists in our room names map
- We replace all spaces with periods to make the names compatible with Node-RED and MQTT topic standards
- We build a full name combining room and device name
- We save the sanitized name in our deviceNames_BSH object using the short key
Replacing spaces with dots prevents issues later on, especially when using these names in MQTT topics or Node-RED function nodes where spaces can cause headaches.
Saving to the Global Context
Finally, we save the entire object into the global context and log a confirmation:
// Save the object in the global context under "deviceNames_BSH"
global.set("deviceNames_BSH", deviceNames_BSH);
// Optional: Log for verification
node.warn("Device names with room names saved in global context under 'deviceNames_BSH'");
} else {
node.error("msg.payload is not an array");
}
return msg;
Using global.set() stores the object globally across all flows, and these settings persist even after Node-RED restarts.

The warning message isn’t mandatory but is super helpful for troubleshooting, as it shows up in the debug sidebar confirming the process ran smoothly.
Implementing This in Node-RED
To get this up and running in Node-RED, set up a flow like this:
- An Inject node that triggers on a regular schedule (e.g., once a day)
- An HTTP Request node that fetches devices from your Bosch Smart Home system
- A Function node containing the code we just discussed
- Optional: A Debug node to check the output
Here’s an example of how the full flow might look:
Once your flow is live, it will regularly update the stored device names in the global context. You can check the stored data from any Function node with this simple code snippet:
// Load the saved device names
let deviceNames = global.get("deviceNames_BSH");
node.warn(JSON.stringify(deviceNames, null, 2));
return msg;
This will print the stored device names in the debug pane.
Use Cases
Now that your device names are stored globally, here are some handy ways to use them:
1. Assign Friendly Names in MQTT Messages
When forwarding data from Bosch devices via MQTT, you can swap out device IDs for friendly names like this:
// Load saved device names
let deviceNames = global.get("deviceNames_BSH");
let deviceId = msg.payload.id;
// Extract the relevant part of the ID
let key = null;
if (deviceId.startsWith("hdm:ZigBee:")) {
key = deviceId.substring("hdm:ZigBee:".length);
} else if (deviceId.startsWith("hdm:HomeMaticIP:")) {
key = deviceId.substring("hdm:HomeMaticIP:".length);
}
// Replace ID with friendly name for topic
if (key && deviceNames[key]) {
msg.topic = `bosch/device/${deviceNames[key]}`;
} else {
msg.topic = `bosch/device/unknown/${deviceId}`;
}
return msg;
2. Dynamic Dashboard
You can build a dashboard that displays all your devices organized by room:
// Load saved device names
let deviceNames = global.get("deviceNames_BSH");
let roomDevices = {};
// Group devices by room
Object.keys(deviceNames).forEach(key => {
let fullName = deviceNames[key];
let parts = fullName.split('.');
let roomName = parts;
if (!roomDevices[roomName]) {
roomDevices[roomName] = [];
}
roomDevices[roomName].push({
id: key,
name: parts.slice(1).join('.')
});
});
msg.payload = roomDevices;
return msg;
3. Filtering Events
You can filter incoming events based on room or device name like this:
// Load saved device names
let deviceNames = global.get("deviceNames_BSH");
let deviceId = msg.payload.id;
let key = null;
// Extract ID key
if (deviceId.startsWith("hdm:ZigBee:")) {
key = deviceId.substring("hdm:ZigBee:".length);
} else if (deviceId.startsWith("hdm:HomeMaticIP:")) {
key = deviceId.substring("hdm:HomeMaticIP:".length);
}
// Check if the device is in the living room
if (key && deviceNames[key] && deviceNames[key].startsWith("Wohnzimmer.")) {
return [msg, null]; // First output
} else {
return [null, msg]; // Second output
}
Wrapping Up
Saving Bosch Smart Home device names in Node-RED’s global context is a powerful way to keep your smart home automations clear and efficient. With this setup, you can:
- Use human-readable names in your flows
- Group devices by rooms
- Create complex automations based on room and device names
- Save time when developing new flows
Combined with the previous guide on storing room names globally, you get a solid foundation for your Bosch Smart Home automations in Node-RED.
Don’t forget to run this flow regularly—daily or whenever your setup changes—so your stored info stays up to date.
Complete Flow to Import
[{"id":"c2e8f3a90731af55","type":"http request","z":"f48cf010.9333b","name":"Device Names","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://192.168.178.186:8444/smarthome/devices/","tls":"9b926ab94fdcfb8e","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":3820,"y":1540,"wires":[["6e2c454b350f53ea"]]},{"id":"2161a2331285f08a","type":"inject","z":"f48cf010.9333b","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"00 12 * * *","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":3610,"y":1500,"wires":[["c2e8f3a90731af55"]]},{"id":"6e2c454b350f53ea","type":"function","z":"f48cf010.9333b","name":"deviceNames","func":"// Initialize an object to store ID-name mappings\nlet deviceNames_BSH = {};\n\n// Load room names from the global context\nlet roomNames_BSH = global.get(\"roomNames_BSH\") || {};\n\n // Check if msg.payload is an array\nif (Array.isArray(msg.payload)) {\n msg.payload.forEach(device => {\n let id = device.id;\n let name = device.name;\n let key = null;\n let roomName = \"Unknown Room\"; // Default value if no room is found\n\n // Extract the key based on the device protocol\n if (id.startsWith(\"hdm:ZigBee:\")) {\n key = id.substring(\"hdm:ZigBee:\".length);\n } else if (id.startsWith(\"hdm:HomeMaticIP:\")) {\n key = id.substring(\"hdm:HomeMaticIP:\".length);\n }\n\n if (key) {\n // Optional: Assuming each device has a room ID, e.g., device.roomId\n // Adjust this according to the actual structure of your device object\n if (device.roomId && roomNames_BSH[device.roomId]) {\n roomName = roomNames_BSH[device.roomId];\n }\n\n // Replace all spaces with dots in roomName and name\n let sanitizedRoomName = roomName.replace(/\\s+/g, '.');\n let sanitizedName = name.replace(/\\s+/g, '.');\n\n // Add the room name to the device name\n let fullName = `${sanitizedRoomName}.${sanitizedName}`;\n\n deviceNames_BSH[key] = fullName;\n }\n });\n\n // Save the object in the global context under \"deviceNames_BSH\"\n global.set(\"deviceNames_BSH\", deviceNames_BSH);\n\n // Optional: Output for verification\n node.warn(\"Device names with room names saved in the global context under 'deviceNames_BSH'\");\n} else {\n node.error(\"msg.payload is not an array\");\n}\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":4040,"y":1540,"wires":[["c511faf4d399103b"]]},{"id":"c511faf4d399103b","type":"debug","z":"f48cf010.9333b","name":"debug 18","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":4220,"y":1540,"wires":[]},{"id":"9b926ab94fdcfb8e","type":"tls-config","name":"Controller","cert":"","key":"","ca":"","certname":"client-cert.pem","keyname":"client-key.pem","caname":"","servername":"","verifyservercert":false,"alpnprotocol":""}]
Add comment