Scripts
Scripts are programs that are created via the integrated web interface. The HomeKit bridge for KNX runs the scripts automatically as soon as there is access to the KNX network.
Scripts contain statements that are executed one after the other. These instructions (program code) must correspond to a certain notation (syntax).
There are also pre-built packages available for a script. A package contains frequently used functions and calculations. For example, the hkknx package is used to receive and send telegrams from the KNX bus. You can find a list of all available packages below.
Syntax
The scripting language is based on the Go programming language.
Hello Word
The following program code calls the function println to write the text “Hello World” to the log.
1println("Hello World")
Values
1println("Home" + "Kit") // "HomeKit"
2
3println("1+1=", 1+1) // "1+1=2"
4println("7/3=", 7/3) // "7/3= 2.3333333333333335"
5
6println(true && false) // false
7println(true || false) // true
8println(!true) // false
Variables
var
declares one or more variables
1// Variables
2var a = "string"
3println(a) // "string"
4
5var b, c = 1, 2
6println(b, c) // "1 2"
7
8var d = true
9println(d) // "true"
The short form also works without var
.
1e = 4
2println(e) // "4"
Loops
1var i = 1
2for i <= 3 {
3println(i) // "1", "2", "3"
4i = i + 1
5}
6
7for {
8 println("loop") // "loop"
9 break // stop the loop
10}
If/Else
1if 7%2 == 0 {
2 println("7 is even")
3} else {
4 println("7 is uneven") // 7 is uneven
5}
6if 8%4 == 0 {
7 println("8 is dividable by 4") // 8 is dividable by 4
8}
9
10var num = 9
11if num < 0 {
12 println(num, "is negative")
13} else if num < 10 {
14 println(num, "has 1 digit") // 9 has 1 digit
15} else {
16println(num, "has multiple digits")
17}
Switch
1var i = 2
2printf("Write %d as ", i)
3switch i {
4case 1:
5 println("one")
6case 2:
7 println("two")
8case 3:
9 println("three")
10}
Since the scripting language is very similar to the Go programming language, you can also learn the scripting language by reading Go code examples. Go by Example has a lot of good examples. And on the Go-Playground website you can test Go directly in the browser.
Create Script
The following example shows how to create and run a script in the HomeKit bridge for KNX.
The logic shown in this script is actually quite simple. The script synchronizes the values from the group address 0/0/1 with the group address 0/0/2. This means that if the value 1 (or 0) is sent to the group address 0/0/1 via the KNX bus, then the script also sends the value to the group address 0/0/2.
Flowchart
The following flowchart shows the logic again graphically.
After the script starts, a for loop is created. The loop waits until values from the group address 0/0/1 are received. The received value is then sent to the group address 0/0/2. After sending, it jumps back to the beginning of the for loop.
As you can see, there is no end to the script - the statements within the for loop are executed over and over again. This concept is very important especially for programming logic that is executed over and over again.
Programming
To create a new script, go to the Script tab in the web interface and create a new script. A new page opens. The name of the script can now be entered in the input field provided - e.g. First script.
Below the input field for the name there is an area to enter the script code. There you can enter the following script code.
1// Import the hkknx package.
2var hkknx = import("hkknx")
3
4// Define the variable *ch*. This variable returns
5// boolean values sent to the group address 0/0/1 with
6// sent in a group write telegram.
7ch = hkknx.GroupWriteBoolNotify("0/0/1")
8
9for {
10 // Wait until *ch* returns a value. The value will
11 // cached in the *value* variable.
12 value = <-ch
13
14 // Output the received value via the log.
15 println(value)
16
17 // Send the received value with a
18 // Group write telegram to 0/0/2.
19 hkknx.GroupWrite(value, "0/0/2")
20}
Now save the script.
Testing
Once the script has been saved, it is initially inactive and will not be executed yet. To test the script, click Run. The script is now started and runs until it is ends. You can end the script by clicking Exit.
Now wait until a value is received from the group address 0/0/1.
When this happens, the println(value)
statement prints either true or false to the log.
So you have successfully received and cached a value.
Activate script
In order for the script to be executed automatically when the HomeKit bridge for KNX starts, it must be activated. To do this, click on the Scripts tab to see all scripts. Then select the checkbox in the Active column for your script. As soon as the script is running, the activity display will be visible in the Status column.
Access the KNX bus
The HomeKit bridge for KNX provides a large number of packages. A package contains functions and types that can be used by a script.
The hkknx package is available for communication with the KNX bus. This package provides functions to send values to a group address, read them and respond to read requests.
You can find out how to use the hkknx package in the following examples. You can try these examples yourself by copying and pasting the code into a new script using the web interface. Then click Run to run the script.
Send Telegram
In the following example, 1 bit is sent to the group address 0/0/1 using the function GroupWrite.
1// Import the hkknx package.
2var hkknx = import("hkknx")
3
4// Write a bool value *true* to 0/0/1.
5// Behind the scenes the value is converted to the bit *1*.
6var err = hkknx.GroupWrite(true, "0/0/1")
7if err != nil {
8 println(err)
9}
With the GroupWrite function, data can be sent not only to one but also to several group addresses. For this purpose, the group addresses are separated by a comma. This means that bit 1 can be sent to the group addresses 0/0/1, 0/0/2 and 0/0/3.
1var hkknx = import("hkknx")
2
3// Write a bool value *true* to 0/0/1, 0/0/2, 0/0/3.
4var err = hkknx.GroupWrite(true, "0/0/1", "0/0/2", "0/0/3")
5if err != nil {
6 println(err)
7}
In the previous examples only one bit (i.e. 0 or 1) was sent. Integer and floating point numbers must be encoded into bytes before sending. The conversion of a value into bytes depends on the KNX data type. The hkknx package contains functions that can be used for conversion.
For example, to send the value 50% as data type 5.004 (DPST-5-4) to the KNX bus, the function DPT5004 is used.
1var hkknx = import("hkknx")
2
3// Send 50%
4hkknx.GroupWrite(hkknx.DPT5004(50), "0/0/2")
Since each data type has a different encoding, it is important to use the correct data type. Otherwise there may be inaccuracies and, as a result, unexpected errors. For example, with the data type 5.001 it is not possible to send the value 21%. However, with the data type 5.004 it does.
1var hkknx = import("hkknx")
2
3// DPT 5.001 has a resolution of 0.4%.
4// Therefore a value of 21% cannot be represented.
5println(hkknx.DPT5001(21)) // "20.8%"
6
7// DPT 5.004 has a resolution of 1%.
8println(hkknx.DPT5004(21)) // "21%"
If you are unclear, the official documentation of the KNX data types will help.
Read Group Address
The GroupRead function is used to read the value from a group address. This function returns the bytes received or an error if the reading was not successful.
1var hkknx = import("hkknx")
2
3// Read the value from 0/1/1.
4var buf, err = hkknx.GroupRead("0/1/1")
5if err != nil {
6 println(err)
7} else {
8 println(buf)
9}
Depending on the data type, the bytes received represent a different value.
To do this, use the Parse...([]byte)
functions from the hkknx package.
1var hkknx = import("hkknx")
2
3buf = []byte{0xFF}
4println(hkknx.ParseDPT5001(buf)) // 100
5println(hkknx.ParseDPT5003(buf)) // 360
6println(hkknx.ParseDPT5004(buf)) // 255
If a boolean value is read, then you can use the function GroupReadBool. This function directly converts the received bit into a boolean value.
1var hkknx = import("hkknx")
2
3// Read a bool value from 0/1/1.
4var val, err = hkknx.GroupReadBool("0/1/1")
5if err != nil {
6 println(err)
7} else {
8 println(val) // "true" or "false"
9}
Read Telegram
A script can also receive read telegrams and respond to them with a response telegram. The function GroupReadNotify is used for this. This function provides a channel, which delivers incoming read telegrams.
In the following example, a read telegram for the group address 0/1/1 is waited in a loop. Then the answer is 1 bit.
1var hkknx = import("hkknx")
2
3// Declare a channel which delivers group read telegrams.
4var ch = hkknx.GroupReadNotify("0/1/1")
5
6for {
7 // Wait for read telegram to arrive.
8 <-ch
9 // Respond with the value *true*.
10 hkknx.GroupResponse(true, "0/1/1")
11}
In addition to communication with the KNX bus, the hkknx package provides additional functions. The documentation of all functions is here.
Packages
A number of packages are available to a script. Each package contains types and functions to complete specific tasks.
hkknx
The hkknx package provides functions for creating automations.
With AtTime, AtSunrise and AtSunset actions can be carried out at specific times. To calculate the sunrise and sunset times, the position in the form of longitude and latitude is required. The position is set via the web interface in the settings.
Communicate with the KNX bus using GroupWrite, GroupRead and GroupResponse.
Push Notifications
Notifications are messages sent to an Apple device to keep users up to date on current and relevant events. For example, a notification can be sent when the doorbell has been pressed.
In order to receive notifications, the respective Apple devices must be registered beforehand. Registering Apple devices and receiving notifications is done via the Configurator app.
Which devices can receive notifications?
Notifications can only be received from an iPhone and iPad. If your iPhone is locked, the notifications will also appear on your Apple Watch and in CarPlay.
When sending a message, you can specify which devices should receive the message. This makes it easy to send messages only to specific people or devices.
How are messages sent?
Notifications are sent in scripts with the function SendNotification.
1var hkknx = import("hkknx")
2hkknx.SendNotification("Doorbell", "The doorbell at the front door was rung.")
The message is then forwarded to the Apple Push Notification Service (APNS) via a specially developed notification service. An internet connection is therefore required to send messages. In order to cover the costs of operating the messaging service, a subscription must be taken out to use it.
How do you enroll Apple devices?
The following steps can be used to register an Apple device to receive notifications.
- Install the Configurator app on the Apple device
- On the Apple device, open the web interface of the HomeKit bridge for KNX and go to Settings → Apple Devices.
- Tap on Register this device and open the Configurator app
After successful registration, a registration confirmation appears. The device will now appear in the list of registered devices. If necessary, the device can be renamed.
Weather Data
Scripts can query weather data and use it for weather-dependent automation or weather alerts. Current weather data as well as hourly and daily forecasts are available.
The data includes
- Temperature
- Air pressure
- Humidity
- Degree of cloudiness
- Wind speed (+ gusts)
- Wind direction
- Amount of rain
- Amount of snow
In the web interface under the settings, the location is entered as longitude and latitude for the weather query.
How is the weather data queried?
The GetCurrentWeather function is available for the current weather. For hourly and daily forecasts, the GetHourlyWeather and GetDailyWeather functions are used.
Where does the weather data come from?
The weather data is downloaded from the Internet by our own weather service. The HomeKit bridge for KNX must therefore be connected to the internet. In order to cover the costs of operating the weather service, a subscription must be taken out for use.
mqtt
The mqtt package can be used to send and receive MQTT messages. The package is available since hkknx v2.7.0 and supports MQTT v3.1.1.
Send Message
A Publisher is used to send messages. As the name suggests, a publisher can send (“publish”) messages. An MQTT message contains the payload data (bytes) and the topic. The method Publish is available for sending a message.
1var mqtt = import("mqtt")
2
3// Create new configuration and the address
4// specify the broker.
5var config = new(mqtt.Config)
6config.Addr = "broker.emqx.io:1883"
7// Username and password are at
8// not required for this broker
9// config.Username = "..."
10// config.Password = "..."
11
12var publisher, err = mqtt.NewPublisher(config)
13if err != nil {
14 println(err)
15 return
16}
17
18var msg = make(mqtt.Message)
19msg.Bytes = "Hello"
20msg.Topic = "hello/world"
21err = publisher.Publish(msg)
22if err != nil {
23 println(err)
24}
This example establishes a connection to the broker broker.emqx.io
on port 1883
and sends the message “Hello” to the topic “hello/world”.
The Publish method sends the message to the broker with Quality of Service (QoS) 0. Additional methods are available for higher service qualities. You can read more about this on the documentation page.
Receive messages
A Subscriber is used to receive messages. A subscriber can subscribe to messages from one or more topics. The broker then forwards messages to the subscriber.
In the following example, a connection is reestablished to the broker broker.emqx.io
on port 1883
.
The topic hello/world
is then subscribed and waited in the for loop until a message is received.
1var mqtt = import("mqtt")
2
3// Create new configuration and the address
4// specify the broker.
5var config = new(mqtt.Config)
6config.Addr = "broker.emqx.io:1883"
7// Username and password are at
8// not required for this broker
9// config.Username = "..."
10// config.Password = "..."
11
12subscriber, err = mqtt.NewSubscriber(config)
13if err != nil {
14 println(err)
15 return
16}
17
18err = subscriber.Subscribe("hello/world")
19if err != nil {
20 println(err)
21return
22}
23
24for {
25msg = <-subscriber.C()
26if msg == nil { // nil means that the connection is down
27 println(subscriber.Err())
28return // stop execution
29}
30
31printf("%s %s\n", msg.Topic, msg.Bytes)
32}