knxrpc provides a ConnectRPC handler and server for RPCs interacting with a KNX bus in smart homes.
You can either integrate it as a http.Handler
in your own code or
run the included server which has swagger and metrics support.
You can find the protobuf-spec in groupaddressservice.proto.
You can access Swagger UI (if enabled via config) via: http://localhost:8080/swagger.
You can use the generated golang code and helper funcs to build your own API client.
Take this as an example:
package main
import (
"github.com/choopm/knxrpc"
v1 "github.com/choopm/knxrpc/knx/groupaddress/v1"
"github.com/vapourismo/knx-go/knx/dpt"
// ...
)
func main() {
// build ctx
ctx, cancel := context.WithTimeout(context.Background(), time.Second() * 3)
defer cancel()
// construct knxrpc client
client, err := knxrpc.NewClient(knxrpc.ClientConfig{
Host: "127.0.0.1",
Port: 8080,
})
if err != nil {
panic(fmt.Errorf("knxrpc: %s", err))
}
// publish a message
_, err := client.Publish(ctx, connect.NewRequest(&v1.PublishRequest{
GroupAddress: "1/2/3",
Data: dpt.DPT_1002(true).Pack(),
Event: v1.Event_EVENT_WRITE,
}))
if err != nil {
panic(fmt.Errorf("unable to send: %s", err))
}
// connect stream to receive bus messages for specific group addresses
stream, err := client.Subscribe(ctx, connect.NewRequest(&v1.SubscribeRequest{
GroupAddresses: []string{"1/2/3", "4/5/6"},
Event: v1.Event_EVENT_UNSPECIFIED,
}))
if err != nil {
panic(fmt.Errorf("stream open: %s", err))
}
defer stream.Close()
// start receiver loop
for stream.Receive() {
res := stream.Msg()
// TODO handle res message here
fmt.Println(res.GroupAddress)
fmt.Println(res.Event)
fmt.Println(res.Data)
// ...
}
if connectErr := new(connect.Error); errors.As(err, &connectErr) &&
!errors.Is(connectErr, context.Canceled) &&
!errors.Is(connectErr, context.DeadlineExceeded) {
panic(fmt.Errorf("stream closed: %s", stream.Err()))
}
}
Starting the container will run the knxrpc
binary in server mode using the argument server
.
This will provide a ConnectRPC server to handle the RPCs defined at groupaddressservice.proto.
You will have to configure your KNX gatewayHost and port in the YAML config. You can also override the defaults using environment variables whiceh are derived from the YAML path such as:
KNXRPC_KNX_GATWAYHOST=192.168.1.2
KNXRPC_RPC_AUTH_ENABLED=true
KNXRPC_RPC_AUTH_SECRETKEY=password
Note the prefix
KNXRPC
when setting environment variables from YAML paths.
If enabled and configured in knxrpc.yaml, you will be able to use the SwaggerUI for testing RPCs.
When deploying to public or production, make sure to use TLS and authorization as otherwise you would be allowing public access to the KNX bus.
You can also run the subcommands subscribe
or publish
to directly
interact with any running RPC server.
This is useful when you are already running a knxrpc server.
The client commands will use the knxrpc:
section from YAML for connecting to
the knxrpc server.
# send the data '\x01' (hex string) to group address 0/4/0
/usr/bin/knxrpc publish 0/4/0 01
# send the hex-string of 'hello world' to group address 1/2/3
/usr/bin/knxrpc publish 1/2/3 68656c6c6f20776f726c64
# send a read request
/usr/bin/knxrpc publish 0/5/6
# send a response message
/usr/bin/knxrpc publish --event response 0/5/6 fffd
# subscribe to all bus messages by not providing a filter
/usr/bin/knxrpc subscribe
# subscribe to all response messages (which are send as a result to previous read requests)
/usr/bin/knxrpc subscribe --event response
# subscribe to specific group address(es)
/usr/bin/knxrpc subscribe 0/5/6 0/4/0 1/2/3
This example sends BASE64-encoded hex data \x01
to the groupAddress 0/5/6
.
curl -X 'POST' \
'http://localhost:8080/knx.groupaddress.v1.GroupAddressService/Publish' \
-H 'accept: application/json' \
-H 'Authorization: Bearer CHANGEME' \
-H 'Content-Type: application/json' \
-d '{
"groupAddress": "0/5/6",
"event": "EVENT_WRITE",
"data": "AQo="
}'
In this example a read-event is send to the groupAddress 0/5/6
which will
trigger an asynchronous response to be read using the Subscribe-API.
curl -X 'POST' \
'http://localhost:8080/knx.groupaddress.v1.GroupAddressService/Publish' \
-H 'accept: application/json' \
-H 'Authorization: Bearer CHANGEME' \
-H 'Content-Type: application/json' \
-d '{
"groupAddress": "0/5/6",
"event": "EVENT_READ"
}'
Subscription is implemented as a streming RPC and therefore an actual ConnectRPC client is required.
If you really require to use a JSON client for receiving messages, you might use
wrapped SubscribeUnary API. Which internally creates the subscription stream and
collects all event message for a duration of for
.
# receive any messages on the bus for 10s
curl -X 'POST' \
'http://localhost:8080/knx.groupaddress.v1.GroupAddressService/SubscribeUnary' \
-H 'accept: application/json' \
-H 'Authorization: Bearer CHANGEME' \
-H 'Content-Type: application/json' \
-d '{
"subscribeRequest": {
"groupAddresses": [],
"event": "EVENT_UNSPECIFIED"
},
"for": "10s"
}'
If you omit the value of for
, the first event message received will terminate
the stream and your client will see the result immediately.
# receive the first message on the bus (missing for)
curl -X 'POST' \
'http://localhost:8080/knx.groupaddress.v1.GroupAddressService/SubscribeUnary' \
-H 'accept: application/json' \
-H 'Authorization: Bearer CHANGEME' \
-H 'Content-Type: application/json' \
-d '{
"subscribeRequest": {
"groupAddresses": []
}
}'
Open this project in Visual Studio Code and select to reopen it inside a dev container.
If you experience any issues, make sure your IDE supports dev containers: https://code.visualstudio.com/docs/devcontainers/containers
This project uses task.
Run task --list
to list all available tasks.