Introducing the SCRIPTING Logic Node for Gira X1 and L1
With the SCRIPTING Logic Node you can combine calculations, text processing and custom logic into a single powerful block, replacing multiple formula, formatter and parser modules at once. It can do JavaScript (ECMAScript 5.1), LUA Script 5.4 and even (on X1 only): Python 2.7 with a lot of additional libraries like paho/mqtt, pymodbus, bacnet, urlib2, urllib3, requests, jinja2, flask and more!
The L1 can only do JavaScript and LUA Script, not Python, because it doesn't have enough resources.
The logic Nodes for the L1 and X1 offer a memory, so you can do: STATE.x=STATE.x+1;OUT1=STATE.x; Every time you trigger it, it will count. But even better, they offer a shared memory, so you can interact variables between different blocks! Using SHAREDSTATE.x=1=10; the other blocks can do: OUT1=SHAREDSTATE.x;
Build compact logic flows, reduce wiring complexity and create advanced automations with just a few lines of code. From smart data handling to dynamic text generation and complex conditions: everything runs inside one fast, flexible node.
Finally, real JavaScript/LUA or Python scripting inside your logic project!
This logic node crushes the Formelberechnung, Textformatierer, JSON-Parser and many other logic nodes with it's easy, flexible and lightweight use.
One block. Endless possibilities.
All examples and a code editor can be found here: https://www.roelbroersma.nl/scripting (see there for the very handy code editor which makes your scripts 1-liners)
The logic node has an Auto Update Check (during validation in the GPA) and during operation on the X1/L1 so you will get notified of updates!
Tip: Ask AI for a script (see below!)
Direct Download: https://www.roelbroersma.nl/downloads/Gira_Scripting_Logic_Node_latest.zip
This Logic Node is now also available for Gira Homeserver, see here: https://knx-user-forum.de/forum/%C3%...tyserver-14362
X1_Logic_Node_Scripting.png
How it works:
Sending any value to the Trigger port (bool/number/text, even false or zero) will execute the script.
Output ports will always be set if you trigger the script. If the script doesn’t set have a value for it, it will be 0.
So the following:
will only set the Output port when Input1=5. In any other case it will be 0, the same like below:
Trigger the block when it received something at INPUT1? Do it like this:
(don't worry about timing issues, it will first fill the inputs and then trigger the block)
image.png
Some Javascript examples:
NUMBERS
String manipulation (text)
LOGIC
JSON
Let's take the following sample JSON to explain:
Some LUA Script examples:
Do clamping (minimum value of 0 and maximum value of 100)
Remember the lowest (OUT2) and Highest (OUT3) values in memory and also have the average of those two (OUT1)
Some Python 2.7 + packages Examples (X1 only!):
Using external Libraries (pymodbus, paho (mqtt) and requests with json)
Sending a message to a MQTT server with authentication:
Requests and JSON with Python:
You can even ask AI (ChatGPT, CoPilot or DeepSeek):
"Hello, can you generate JavaScript code for the Gira X1 Scripting Logic Module (see examples at https://www.roelbroersma.nl/scripting)?
I have 2 inputs and 1 output.
CHANGE LOG
v0.2.000000 (19-mar-2026)
v0.1.000025 (23-feb-2026)
v0.1.000024 (02-feb-2026)
v0.1.000018 (01-feb-2026)
With the SCRIPTING Logic Node you can combine calculations, text processing and custom logic into a single powerful block, replacing multiple formula, formatter and parser modules at once. It can do JavaScript (ECMAScript 5.1), LUA Script 5.4 and even (on X1 only): Python 2.7 with a lot of additional libraries like paho/mqtt, pymodbus, bacnet, urlib2, urllib3, requests, jinja2, flask and more!
The L1 can only do JavaScript and LUA Script, not Python, because it doesn't have enough resources.
The logic Nodes for the L1 and X1 offer a memory, so you can do: STATE.x=STATE.x+1;OUT1=STATE.x; Every time you trigger it, it will count. But even better, they offer a shared memory, so you can interact variables between different blocks! Using SHAREDSTATE.x=1=10; the other blocks can do: OUT1=SHAREDSTATE.x;
Build compact logic flows, reduce wiring complexity and create advanced automations with just a few lines of code. From smart data handling to dynamic text generation and complex conditions: everything runs inside one fast, flexible node.
Finally, real JavaScript/LUA or Python scripting inside your logic project!
This logic node crushes the Formelberechnung, Textformatierer, JSON-Parser and many other logic nodes with it's easy, flexible and lightweight use.
One block. Endless possibilities.
All examples and a code editor can be found here: https://www.roelbroersma.nl/scripting (see there for the very handy code editor which makes your scripts 1-liners)
The logic node has an Auto Update Check (during validation in the GPA) and during operation on the X1/L1 so you will get notified of updates!
Tip: Ask AI for a script (see below!)
Direct Download: https://www.roelbroersma.nl/downloads/Gira_Scripting_Logic_Node_latest.zip
This Logic Node is now also available for Gira Homeserver, see here: https://knx-user-forum.de/forum/%C3%...tyserver-14362
X1_Logic_Node_Scripting.png
How it works:
Sending any value to the Trigger port (bool/number/text, even false or zero) will execute the script.
Output ports will always be set if you trigger the script. If the script doesn’t set have a value for it, it will be 0.
So the following:
PHP-Code:
if (IN1=5) OUT1=1;
PHP-Code:
if (IN1=5) OUT1=1;else OUT1=0;
(don't worry about timing issues, it will first fill the inputs and then trigger the block)
image.png
Some Javascript examples:
NUMBERS
PHP-Code:
OUT1 = IN1 * 1.19; // Multiply with Mwst.
OUT1 = IN1 + IN2 + IN3 + (IN4+2) // Set Output sum.
OUT1 = IN1 + IN2; OUT2 = IN1 - IN2; // Set multiple outputs in one time
OUT1 = (IN1 / 255) * 100; // Devide and use ( and )
OUT1 = Math.round(IN1 * 100) / 100; // Math.round will always round on whole number, to have two decimals, device by 100.
OUT1 = Math.min(Math.max(IN1, 0), 100); // Limit the Input between 0 and 100
OUT1 = Math.abs(IN1); // Inverse: -5 -> 5
OUT1 = -IN1; // Also 5 -> -5
OUT1 = Math.pow(IN1, 2); // (power of 2): IN1²
OUT1 = Math.sqrt(IN1); // (taking the root): √IN1
String manipulation (text)
PHP-Code:
OUT1 = "Hello there!"; // Set a simple text to Output1
OUT1 = "Value is: " + IN1; // Set combined text+value. Example: "Value is: 10"
OUT1 = "My " + IN1 + " has " + IN2 + " homes"; // Concatenate Strings. Example: "My Son has 2 homes"
OUT1 = IN1.toString().substring(0, 5); // Take the first 5 characters (start at character 0)
OUT1 = IN1.toString().substring(0, 5); // Trim spaces
if (IN1.length > 10) OUT1 = IN1.substring(0, 10) + "..."; // Shorten text to 10 characters + "..."
else OUT1 = IN1;
OUT1 = IN1.toString().substring(0, 5); // Take the first 5 characters (start at character 0)
OUT1 = IN1.replace(/,/g,"."); // Replace all commas by dots.
OUT1 = IN1.slice(-3); // Remove last 3 characters
LOGIC
PHP-Code:
if (IN1=1) OUT1=1 // Use If to set output ONLY if IN1=1, otherwise do NOT set the output.
var temp = IN1; // Declare a variable and use it or
OUT1 = tempt;
i=1;
OUT1 = this["IN"+1] // Computed variabe: OUT1=IN1
if (IN1 >= 50) OUT1 = 1; // Use if else
else OUT1 = 0;
if (IN1==1) OUT1 = 1; // Use if, elseif, else
else if (IN2==1) OUT1 = 2;
else if (IN3==1) OUT1 = 3;
else OUT1 = 0;
if (OUT1==1 && IN2==0) OUT2 = 123; // Read the value of OUT1
switch(IN1) { // Switch Logic (easier than if/elseif/else)
case 0: OUT1 = "OFF"; break;
case 1: OUT1 = "AUTO"; break;
case 2: OUT1 = "MANUAL"; break;
default: OUT1 = "UNKNOWN";
}
for (var i = 1; i <= 5; i++) { // A FOR Loop
if (this["IN" + i] == true) { // The computed variable IN1...IN5
OUT1 = i;
break;
}
}
JSON
Let's take the following sample JSON to explain:
PHP-Code:
{
"device": {
"name": "LivingRoomController",
"status": "online",
"metrics": {
"temperature": 21.6,
"humidity": 48,
"power": 312.4
},
"modes": [
{ "id": 1, "name": "Auto", "active": true },
{ "id": 2, "name": "Eco", "active": false },
{ "id": 3, "name": "Boost", "active": false }
]
}
}
PHP-Code:
var obj = JSON.parse(IN1); // Read Input1 as JSON
OUT1 = obj.device.name; // "LivingRoomController"
OUT2 = obj.device.metrics.temperature; // 21.6
OUT3 = obj.device.modes[0].name; // "Auto"
OUT4 = obj.device.modes[2].active; // false
OUT5 = obj.device.modes.length; // 3
OUT6 = obj.device.status + " / " + obj.device.metrics.power + "W";
Some LUA Script examples:
Do clamping (minimum value of 0 and maximum value of 100)
PHP-Code:
STATE.on = STATE.on or 0
local t = IN1 or 0
if t < 20 then STATE.on = 1 end
if t > 22 then STATE.on = 0 end
OUT1 = STATE.on
Remember the lowest (OUT2) and Highest (OUT3) values in memory and also have the average of those two (OUT1)
PHP-Code:
STATE.min = STATE.min or (IN1 or 0)
STATE.max = STATE.max or (IN1 or 0)
local v = IN1 or 0
if v < STATE.min then STATE.min = v end
if v > STATE.max then STATE.max = v end
OUT1 = (STATE.min+STATE.max)/2 -- AVERAGE BETWEEN MIN AND MAX
OUT2 = STATE.min -- The minimum value ever measured
OUT3 = STATE.max -- The maximum value ever measured
Some Python 2.7 + packages Examples (X1 only!):
Using external Libraries (pymodbus, paho (mqtt) and requests with json)
PHP-Code:
Get two values from Modbus Holding Registers, do some calculations on it and write them to OUT1 and OUT2:
# Get 2 values from a Modbus Holding Registers and write them to OUT1 and OUT2.
from pymodbus.client.sync import ModbusTcpClient
c = ModbusTcpClient("192.168.1.50", port=502)
c.connect()
raw1 = c.read_holding_registers(300, 1, unit=1).registers[0]
raw2 = c.read_holding_registers(301, 1, unit=1).registers[0]
OUT1 = raw1 / 10.0
OUT2 = raw2 / 10.0
c.close()
Sending a message to a MQTT server with authentication:
PHP-Code:
# Send IN1 as Text to an MQTT Server
import paho.mqtt.publish as publish
publish.single(
"home/scripting/test",
payload=str(IN1), # send as text
hostname="192.168.1.60",
port=1883,
auth={"username": "mqttuser", "password": "mqttpass"}
)
OUT1 = 1 # ok
Requests and JSON with Python:
PHP-Code:
# Get a website, parse it to JSON and get a value from it.
import requests
try:
r = requests.get("https://httpbin.org/json", timeout=5)
data = r.json()
OUT1 = r.status_code # mostly 200
OUT2 = data["slideshow"]["title"] # "Sample Slide Show"
except Exception as e:
You can even ask AI (ChatGPT, CoPilot or DeepSeek):
"Hello, can you generate JavaScript code for the Gira X1 Scripting Logic Module (see examples at https://www.roelbroersma.nl/scripting)?
I have 2 inputs and 1 output.
- IN1 = weather information as text
- IN2 = expected afternoon temperature (number)
- Output format: Temp: XX°C - DESCRIPTION
- DESCRIPTION must be truncated to 20 characters and end with .. if longer
- Use only plain JavaScript compatible with Jint
- Assign the result to OUT1"
CHANGE LOG
v0.2.000000 (19-mar-2026)
- Separated module for X1 and L1.
- Both modules now support LUA Scripting!
- X1 Module supports Python 2.7 with all basic libraries and paho/mqtt, requests, urllib2, urllib3, pymodbus, schedule, jinja2, flask, websocket, yaml, bacpipes (BacNet!) and much more.
- Completely re-engineerd system for including packages.
- Completely re-engineered separated worker process for Lua and Python scripting.
- Timeout can be 0 (zero), for endless processes like receiving mqtt or a webserver!
- Number of Inputs and Outputs can be 0 – 50 (instead of 1-50), so you can start a webserver or script without any input or output.
- Triggering the Clear function will release the Worker process (handy when using timeout=0)
- Implemented STATE memory (memory within the same block, so you can do: STATE.x = STATE.x+1; OUT1=STATE.x; to create a counter every time you trigger.
- Implemented SHAREDSTATE memory (memory between multiple blocks!), so you can do: SHAREDSTATE.x = 5 in one block and use OUT1=SHAREDSTATE.x in another block.
v0.1.000025 (23-feb-2026)
- Feature: Set script timeout and see Execution time. Test it with a script like: for (i=1;i>0;i++) {let x=5;}
v0.1.000024 (02-feb-2026)
- Fix: Update Notification in GPA (didn't work!).
- Fix: You couldn't Trigger the block when not all inputs are set, fixed by pre-filling with 0 (zero).
- Fix: A lot of small fixes ans possible NullPointerExceptions.
- Feature: Implemented great Debug logging (enable Debug to see what's happening).
- Feature: Debugging shows script execution time. (a hard limit is set at 200ms).
v0.1.000018 (01-feb-2026)
- Initial version
- Tested on Gira GPA v6.0. X1: v3.0.52 and L1: v2.5.149, but may work on lower versions.




)
More powerfull than ever!
Kommentar