December 22, 2024

Reading temperature with KNX over IP in NodeJS the easy way

Hey there! I was pretty busy lately with other assignments so the only thing I’ve managed to perform on the blog is plugin update. Sometimes it’s pretty nasty that you don’t really have time for other things that matter to you, so I took a couple of days off and I wanted to write about two KNX IP libraries that I’ve found in NodeJS. I needed to find a good reliable one to use in one of our projects here at Mindgaze.

Getting started

After doing a bit of research, I’ve found two nice KNX IP libraries on NPM:

  1. KNX-IP
  2. KNX

In order to use any of these two, you’ll need a KNX IP Gateway or an KNX IP Router and some KNX network with appliances configured. I’ve had my test rig already configured by a separate team for the temperature sensor so I won’t go into detail about KNX network and stuff like that.

As for the development part, you need to have NodeJS installed on your machine and add both or one of the KNX packages and other dependencies you require according to your project.

In this example, we are going to read a temperature from a sensor and write the desired room temperature to a group address. We have 3 group addresses in total:

  1. read temperature
  2. write temperature
  3. write temperature confirmation (out, only read)

Using KNX-IP

This is actually the first one I’ve tested. It’s straightforward to use and it has support for quite a lot of data points. It also supports monitoring the KNX bus which is great for checking what’s going on under the hood. To start using it, you need to include the basic types and define a KNX client/tunnel socket. The individual address of the router is passed as parameter:

const {KNXTunnelSocket, DataPoints, KNXAddress} = require("knx-ip");

const knxClient = new KNXTunnelSocket("1.1.1");

The next step is to define the addresses, datapoints and binding them to the knx client:

const addressCurrentTemperature = KNXAddress.createFromString("1/0/0", KNXAddress.TYPE_GROUP);
const addressDesiredTemperatureIn = KNXAddress.createFromString("1/0/3", KNXAddress.TYPE_GROUP);
const addressDesiredTemperatureOut = KNXAddress.createFromString("1/0/2", KNXAddress.TYPE_GROUP);

const dataPointCurrentTemperature = new DataPoints.Temperature(addressCurrentTemperature);
const dataPointDesiredTemperatureIn = new DataPoints.Temperature(addressDesiredTemperatureIn);
const dataPointDesiredTemperatureOut = new DataPoints.Temperature(addressDesiredTemperatureOut);

dataPointCurrentTemperature.bind(knxClient);
dataPointDesiredTemperatureIn.bind(knxClient);
dataPointDesiredTemperatureOut.bind(knxClient);

The last step to do is to actually connect to the gateway and start performing operations. This will look like this:

knxClient.connectAsync("192.168.0.125", 3671)
	.then(() => console.log("Connected through channel id ", knxClient.channelID))
	.then(() => console.log("Reading current temp"))
	.then(() => dataPointCurrentTemperature.read())
	.then(current => console.log("Current temp:", current))	
	.then(() => console.log("Reading desired temp"))
	.then(() => dataPointDesiredTemperatureOut.read())
	.then(desired => console.log("Desired temp:", desired))
	.then(() => console.log("Setting desired temp to ", randomDesiredTemp, dataPointDesiredTemperatureIn.value))
	.then(() => dataPointDesiredTemperatureIn.write(randomDesiredTemp))
	.then(() => console.log("Reading desired temp again"))
	.then(() => dataPointDesiredTemperatureOut.read())
	.then(desired => console.log("Desired temp again:", desired))
	.catch(err => {console.log(err);})
        .then(() => {
           knxClient.close();
           process.exit(0);
	});

Basically what it does, is to read the current temperature, read the current desired temperature, write a random desired temperature value and read it back again. The program then exits and any errors are logged to the console. Let’s now see how the same thing would be written with the other library.

Using KNX

This library is very functional and robust. In order to start using it, you’ll need to import the library and define the addresses:

const knx = require('knx');

const addressCurrentTemperature = "1/0/0";
const addressDesiredTemperatureIn = "1/0/2";
const addressDesiredTemperatureOut = "1/0/3";

The last big step is to create a Connection with the right parameters and handlers:

onst connection = new knx.Connection({
    ipAddr: '192.168.0.125',
    ipPort: 3671,
    physAddr: '1.1.1',
    handlers: {
        // wait for connection establishment before sending anything!
        connected: function () {
            console.log('Hurray, I can talk KNX!');

            const dataPointCurrentTemperature = new knx.Datapoint({
                ga: addressCurrentTemperature,
                dpt: 'DPT9'
            });
            const dataPointDesiredTemperatureIn = new knx.Datapoint({
                ga: addressDesiredTemperatureIn,
                dpt: 'DPT9'
            });
            const dataPointDesiredTemperatureOut = new knx.Datapoint({
                ga: addressDesiredTemperatureOut,
                dpt: 'DPT9'
            });

            dataPointCurrentTemperature.bind(connection);
            dataPointDesiredTemperatureIn.bind(connection);
            dataPointDesiredTemperatureOut.bind(connection);

            connection.on(`GroupValue_Write_${addressDesiredTemperatureOut}`, (src, val) => {
                // console.log(`Desired changeto ${val}`);
                dataPointDesiredTemperatureOut.read((src, val) => console.log(`Desired temp is again ${val} \n`));
            })
        },
        // get notified on connection errors
        error: function (connstatus) {
            console.log("**** ERROR: %j", connstatus);
        }
    }
});

As you can see, we are doing quite the same thing as before, but the approach is a bit different. A key difference though, is that you don’t have data point types for Temperature, you need to set DPT9 for that, which is the code that defines the temperature. The supported data points can be checked here.

And the winner is …

Although my intention is not to declare any winner here (just variables 😄 ), I personally noticed that the first one KNX-IP has some reliability issues and was not able to read data because of some errors that I didn’t understand the root cause. Hence, I believe it’s pretty buggy so it’s not suitable for a project where you need to orchestrate KNX network 24/7.

The KNX library is very strong and reliable on the other hand. I didn’t have any issue while testing and I believe it can be used in production scenarios and workloads. It might be tricky setting up those data points, but the documentation seems allright. What do you think? Which one will you use?

You can find the source code on Github

As always

Thanks for reading, I hope you found this article useful and interesting. If you have any suggestions don’t hesitate to contact me. If you found my content useful please consider a small donation. Any support is greatly appreciated! Cheers  😉

afivan

Enthusiast adventurer, software developer with a high sense of creativity, discipline and achievement. I like to travel, I like music and outdoor sports. Because I have a broken ligament, I prefer safer activities like running or biking. In a couple of years, my ambition is to become a good technical lead with entrepreneurial mindset. From a personal point of view, I’d like to establish my own family, so I’ll have lots of things to do, there’s never time to get bored 😂

View all posts by afivan →