smarthome.codes

Node-RED: Store Bosch Smart Home Devices in Global Context

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:

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:

  1. An Inject node that triggers on a regular schedule (e.g., once a day)
  2. An HTTP Request node that fetches devices from your Bosch Smart Home system
  3. A Function node containing the code we just discussed
  4. 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":""}]

Adriana

I have been fascinated by everything to do with technology for many years, especially when it comes to making my own home smarter and more comfortable. For me, a smart home is not just a technical gimmick, but above all a real improvement in quality of life. It all started very small with a networked thermostat, but this little experiment quickly turned into a great passion. My home now comprises a sophisticated system of lighting control, heating automation and security solutions that make my everyday life noticeably easier. For me, a smart home is much more than just technology: it means convenience, sustainability and a real improvement in quality of life. It is particularly important to me that systems are intuitive to use and can be easily integrated into everyday life, regardless of brand or manufacturer. My vision is a home that not only reacts to commands, but also thinks and acts with foresight. I dream of a smart home that saves energy, adapts individually to residents and the environment and always puts people at the center.

Here on my blog, I share personal experiences, helpful tips and interesting insights on the topic of smart homes.
I'm particularly looking forward to exchanging ideas with you, whether you're just starting out with your smart home or are already a real pro.

Do you have any questions, suggestions or just want to chat? Then feel free to write me a comment.

Add comment

Donations and Support

PayPal

Donate quickly and securely with PayPal – no registration required.

Patreon

Become a member and support smarthome.codes

Buy Me a Coffee

Support my work with a coffee and a personal message.