Coder Social home page Coder Social logo

knx-go's Introduction

Check GoDoc

knx-go

This repository contains a collection of Go packages that provide the means to communicate with KNX networks.

Packages

Package Description
knx Abstractions to communicate with KNXnet/IP servers
knx/knxnet KNXnet/IP protocol services
knx/dpt Datapoint types
knx/cemi CEMI-encoded frames
cmd/knxbridge Tool to bridge KNX networks between a KNXnet/IP router and gateway

Installation

Simply run the following command.

$ go get -u github.com/vapourismo/knx-go/...

Examples

KNXnet/IP Group Client

If you simply want to send and receive group communication, the GroupTunnel or GroupRouter might be sufficient to you.

package main

import (
	"log"
	"os"

	"github.com/vapourismo/knx-go/knx"
	"github.com/vapourismo/knx-go/knx/cemi"
	"github.com/vapourismo/knx-go/knx/dpt"
	"github.com/vapourismo/knx-go/knx/util"
)

func main() {
	// Setup logger for auxiliary logging. This enables us to see log messages from internal
	// routines.
	util.Logger = log.New(os.Stdout, "", log.LstdFlags)

	// Connect to the gateway.
	client, err := knx.NewGroupTunnel("10.0.0.7:3671", knx.DefaultTunnelConfig)
	if err != nil {
		log.Fatal(err)
	}

	// Close upon exiting. Even if the gateway closes the connection, we still have to clean up.
	defer client.Close()

	// Send 20.5°C to group 1/2/3.
	err = client.Send(knx.GroupEvent{
		Command:     knx.GroupWrite,
		Destination: cemi.NewGroupAddr3(1, 2, 3),
		Data:        dpt.DPT_9001(20.5).Pack(),
	})
	if err != nil {
		log.Fatal(err)
	}

	// Receive messages from the gateway. The inbound channel is closed with the connection.
	for msg := range client.Inbound() {
		var temp dpt.DPT_9001

		err := temp.Unpack(msg.Data)
		if err != nil {
			continue
		}

		util.Logger.Printf("%+v: %v", msg, temp)
	}
}

In case you want to access a KNXnet/IP router instead of a gateway, simply replace

client, err := knx.NewGroupTunnel("10.0.0.7:3671", knx.DefaultTunnelConfig)

with

client, err := knx.NewGroupRouter("224.0.23.12:3671", knx.DefaultRouterConfig)

KNXnet/IP CEMI Client

Use Tunnel or Router for finer control over the communication with a gateway or router.

KNX Bridge

The knxbridge tool (in package cmd/knxbridge) has multiple use cases.

Expose a KNX network behind a gateway at 10.0.0.2:3671 on the multicast group 224.0.23.12:3671. This allows routers and router clients to access the network.

$ knxbridge 10.0.0.2:3671 224.0.23.12:3671

Connect two KNX networks through gateways. In this example one gateway is at 10.0.0.2:3671, the other is at 10.0.0.3:3671.

$ knxbridge 10.0.0.2:3671 10.0.0.3:3671

Discover all KNXnet/IP Servers

The following example shows how to discover all routers/gateways on a network.

package main

import (
	"log"
	"os"
	"time"

	"github.com/kr/pretty"

	"github.com/vapourismo/knx-go/knx"
	"github.com/vapourismo/knx-go/knx/util"
)

func main() {
	// Setup logger for auxiliary logging. This enables us to see log messages from internal
	// routines.
	util.Logger = log.New(os.Stdout, "", log.LstdFlags)

	servers, err := knx.Discover("224.0.23.12:3671", time.Millisecond*750)
	if err != nil {
		log.Fatal(err)
	}

	util.Logger.Printf("%# v", pretty.Formatter(servers))
}

Describe a Single KNXnet/IP Server

The following example shows how to get a description from a single server.

package main

import (
	"log"
	"os"
	"time"

	"github.com/kr/pretty"

	"github.com/vapourismo/knx-go/knx"
	"github.com/vapourismo/knx-go/knx/util"
)

func main() {
	util.Logger = log.New(os.Stdout, "", log.LstdFlags)

	// Describe KNXnet/IP server at given address and default port
	servers, err := knx.DescribeTunnel("192.168.1.254:3671", time.Millisecond*750)
	if err != nil {
		log.Fatal(err)
	}

	util.Logger.Printf("%# v", pretty.Formatter(servers))
}

knx-go's People

Contributors

abergmann avatar annismckenzie avatar bozzo avatar cespedes avatar dependabot[bot] avatar dmnkdmnt avatar doclambda avatar ing-dom avatar mighe avatar mj avatar mobilarte avatar rverst avatar sgrimee avatar stffabi avatar userwithoutpassword avatar vapourismo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

knx-go's Issues

Problem in Telegraf that connection loss from KNX-Router is not recognized

Hello,
I have an issue in Telegraf which use this/your Code.
The problem is the following, when the KNX-Router lost connection (for example during update of switch or router) then Telegraf don't recognize it.
After the connection with the KNX-Router is reablished, telegraf doesn't know it.
It works only after I restart Telegraf manually.

I already opend a Report at the Telegraf Repo.
influxdata/telegraf#13632

There powersj asked me to file here an upstream issue, if there is a way to check when the server goes down via an error?

Missing telegrams in IP KNX tunnel

Hey folks,

honestly I'm not sure if it's a bug or a feature and if the culprit is telegraf or knx-go itself, but maybe you can help me on that.

I use telegraf (w/ kno-go) to monitor measurements points like temperature, CO2, VOC, into influxdb2 & grafana. I realize now with more and more data I log (more GAs) I loose more and more measurements points, meaning that are not show up in the DB.

I debug the issue and I sure the KNX bus itself nor config of the devices and the IP router is the problem. I monitor the bus in the ETS and also w/ xknx on the IP layer on my Mac. Both monitor the same amount of telegrams, but telegraf logs much less. See attachment. Between the the GA 7/3/91 and 7/2/151 that telegraf see back-to-back, xknx logs much much more.

Bildschirmfoto 2022-08-16 um 08 07 41

I scan the relevant parts of telegraf, but I don't see any issue here. It loops in line 128 among the received telegrams in the input queue, which comes from knx-go. So my best guess was that already knx-go miss the telegrams, but I'm not a GO ninja.

Alex

Advice needed

Hi,

I started to add some missing DPTs and to do some clean-up by following the specifications (units, allowed ranges, ...).

I also realized that the MulticastLoopback is disabled by default when using net.ListenMulticastUDP.

What would be the best procedure for you to integrate all these changes? Changes made so far are in this branch. Would you be available to discuss this?

Thank you very much for your help.

Read on command group address

Hi, thanks for the great work, I was succesfull in sending a telegram to an actuator, but I'm not finding a way to read a group addess at request an not only when sent from the actuator. Is there an easy way to read a group address without having it sent ciclically?

Best regards
Nicola

knx-go is writing wrong "source" tag

When Im using DPT 1.005

[[inputs.knx_listener.measurement]]
name = "Alarm"
dpt = "1.005"
addresses = ["0/2/2", # Windalarm (Markise)
"0/2/3", # Windalarm (Raffstores)
"0/2/4"] # Regenalarm

knx-go is writing wrong source tag in some situations.

Situation: my sensor is having PA 1.1.50.
At the same time im using ETS6 connected to my KNX-IP Interface (Gira X1) via tunneling connection, having PA 1.1.6

Now i do a "GroupValue_Read" for example on 0/2/2. my Sensor (1.1.50) is responding via GroupValue_Response with its address. But in telegraf im getting 1.1.6 as source tag, but it has to be 1.1.50 instead.

For now other DPTs dont have this problem. First time I notice this but only with DPT 1.005.

I looks like knx-go is taking the PA from the GroupValue_Read message but the correct address is in the GroupValue_Response message

Filter indications that do not target group addresses

Probably : if !ind.Control2.IsGroupAddr() - ! missing ?

			// Filter indications that do not target group addresses.
			if ind.Control2.IsGroupAddr() {
				util.Log(inbound, "Received L_Data.ind does target a group address")
				continue
			}

Thank you for integrating the read event.

DPT232

Hello!
Please add DPT232 support for RGB

support for knx secure tunnel?

Hi,

I am using a weinzierl device with security enabled. I can query it using the xknx python library and an example similar to this one. This is my working test:

import asyncio
import logging

from xknx import XKNX
from xknx.io import ConnectionConfig, ConnectionType, SecureConfig
from xknx.tools import group_value_write
from xknx.devices import Light

logging.basicConfig(level=logging.INFO)
logging.getLogger("xknx.log").level = logging.DEBUG
logging.getLogger("xknx.knx").level = logging.DEBUG


async def main() -> None:
    """Test connection with IP secure tunnelling."""

    connection_config = ConnectionConfig(
        connection_type=ConnectionType.TUNNELING_TCP_SECURE,
        gateway_ip="192.168.1.44",
        individual_address="1.0.11",
        secure_config=SecureConfig(
            user_id=1,
            device_authentication_password="*******",
            user_password="***********",
        ),
    )
    xknx = XKNX(connection_config=connection_config)

    await xknx.start()
    print("Tunnel connected")

    # Connect to KNX/IP bus, switch on light, wait 2 seconds and switch of off again
    light = Light(xknx, name="TestLight", group_address_switch="1/1/5")
    await light.set_on()
    await asyncio.sleep(2)
    await light.set_off()

    await xknx.stop()


asyncio.run(main())

I would like to query the same device using telegraf to push some metrics to influxdb but I couldn't find any config example to connect to a secure tunnel. Does knx-go supports connecting to a secure tunnel? In case it's supported, can you share an example config?

How to retry if not connected

Hello,
I have a N148/21 interface, that only supports 1 tunnelling connection.

When the connection is already taken, the interface returns a "NO_MORE_CONNECTIONS" error (code 0x24)
With the default configuration it times out after a 10 secs

Is it possible to detect it and retry after 1 min?

Thanks

Communicating directly with a KNX serial gateway

This library currently supports only KNXnet/IP. I am interested in extending the support for my application, which should also be able to directly communicate to serial KNX gateway/devices (which are mounted on a system as a /dev/tty* device).

My question is: How would I go about doing that?

I've noticed in the code that the Socket interface might be the solution. To just replace the current TunnelSocket implementation with one that writes directly to a local serial device. But I'm not sure if it's just as simple as replacing the interface implementaiton. Does the rest of the library exclusively depend on the fact that it is KNXnet/IP?

From you experience with KNX, would this work? Is there anything that needs to be added to correctly send the []byte payloads? Because I see there are some Pack and Unpack methods that handle enriching and extracting the data). Would something similar need to be done if I want to send directly to a serial device?

Implement DESCRIPTION_REQUEST

I want to send a DESCRIPTION_REQUEST over IP Gateway.
I can't find an implementation, did you implemented it ? If no, I can help

KNX virtual crash when Write Command send

Hi,
I am doing POC with this library for one of the upcoming project.
I have a KNX virtual running ( https://www.knx.org/knx-en/for-professionals/get-started/knx-virtual/index.php ) in windows box.
When i try to use this package and control a switch group, KNX virtual is crashing. I dont see any issue when i try with Python library . ( https://xknx.io/ )

Can it be a problem with Virutal device which unable to intercept go request ? Will there be similar impact when we deal with real devices ?. For business reasons, we have to use go language. Any comment or help on this ?

Go Code:
data := dpt.DPT_1001(true).Pack()
err = client.Send(knx.GroupEvent{
Command: knx.GroupWrite,
Destination: cemi.NewGroupAddr3(1, 1, 1),
Data: data,
})

Python Code:
switch = Switch(xknx,name='ch1',group_address='1/1/1')
await switch.set_on()
await xknx.stop()

Thanks,

All DPT1.xxx are boolean

Why are there Strings defined like "On" "Off" or "Up" "Down"

`// DPT_1001 represents DPT 1.001 (G) / DPT_Switch.
type DPT_1001 bool

func (d DPT_1001) Pack() []byte {
return []byte{packB1(bool(d))}
}

func (d *DPT_1001) Unpack(data []byte) error {
return unpackB1(data, (*bool)(d))
}

func (d DPT_1001) Unit() string {
return ""
}

func (d DPT_1001) String() string {
if d {
return "On"
} else {
return "Off"
}
}`

but in influxdb all DPT1.xxx are boolean with values "true" oder "false"

I would expect seeing these Strings filled into the field "_value"

New DPT types

Hello, is there a list with supported DPT types?
I found only DPT1 and DPT9 at dpt package.
Thank you

Get Write, Read and Response messages

Hello,
Thank you very much for sharing your great work on knx in go !

i wanted to get the cemi.GroupValueRead events, so i modified groups.go this way :

// GroupComm represents a group communication.
type GroupComm struct {
	Source      cemi.IndividualAddr
	Destination cemi.GroupAddr
	Data        []byte
	Command     cemi.APCI
}
if app, ok := ind.Data.(*cemi.AppData); ok && (app.Command == cemi.GroupValueResponse || app.Command == cemi.GroupValueWrite || app.Command == cemi.GroupValueRead) {
	outbound <- GroupComm{
		Source:      ind.Source,
		Destination: cemi.GroupAddr(ind.Destination),
		Data:        app.Data,
		Command:     app.Command,
	}
} else {
	util.Log(inbound, "Received L_Data.ind frame does not contain application data")
}

I'm really new to your code and don't know if it has negative side effects.

Is it possible to get more events, on may be to have a subscription mechanism ?
Regards
Alexandre

knx read first value

Hello,
I would like an example to read the initial values from the gateway with sensors in C # (Visual Studio).
I found an example that only gives the new values (after the values are changed), but I also need the first values.
Many Thanks
Fariz

more example

i try connect to knx virtual in another machine, code below
` client, err := knx.NewGroupTunnel("224.0.23.12:3671", knx.DefaultTunnelConfig)

if err != nil {
	log.Errorf(err)
}

defer client.Close()

for msg := range client.Inbound() {
	fmt.Println(msg.Data)
}`

when my long press button,knx virtual display light is on,but code not print anything,what's matter?

Question regarding AppData.pack

tpdu.go contains the following lines in func (app *AppData) Pack(buffer []byte):

buffer[2] &= 63
buffer[2] |= byte(app.Command&3) << 6

What do they do?

I wanted to implement DPT 16.000/16.001.
Because of copy(buffer[2:], app.Data), buffer[2:16] contain a 14 Byte String.
The mentioned lines overwrite the first byte in buffer[2].

I guess, I lack knowledge on the basics of assembling KNX datagrams.

Thanks for your reply.

Query value-status of a group address

Hi!

Is it possible to implement a status query of all group addresses connected to the gateway? Or, for example, without waiting for the status change, just request the current value of the group address?

At the moment, we get the status value only by changing it.

short telegrams

Hello,

with eibd / knxd, to send a datagram i have groupwrite and groupswrite

knxtool groupwrite ip:localhost 1/1/1 01 will send a normal telegram

knxtool groupswrite ip:localhost 1/1/1 01 will send a short telegram

and knxd will give the information on reception too.

Layer 1(7F88EB404110,596802CF) Recv L_Data low from 0.0.1 to 1/1/1 hops: 05 T_DATA_XXX_REQ A_GroupValue_Write (small) 01 

Is it possible to send short telegrams in knx-go ?
And is it possible to know if an incoming telegram is short or not ?
Thank you

make a cemi.GroupAddr form an a/b or a/b/c string

I needed this function, may be it can be useful to others

// NewGroupAddrFromString returns a cemi.GroupAddr from a group address string a/b or a/b/c
func NewGroupAddrFromString(groupAddress string) (cemi.GroupAddr, error) {
	parts := strings.Split(groupAddress, "/")
	if len(parts) < 2 || len(parts) > 3 {
		return 0, fmt.Errorf("%s is not a valid group address", groupAddress)
	}
	n := make([]int, 0, len(parts))
	for _, part := range parts {
		p, err := strconv.Atoi(part)
		if err != nil {
			return 0, fmt.Errorf("%s is not a valid group address", groupAddress)
		}
		n = append(n, p)
	}
	if len(n) == 2 {
		return cemi.NewGroupAddr2(uint8(n[0]), uint8(n[1])), nil
	}
	return cemi.NewGroupAddr3(uint8(n[0]), uint8(n[1]), uint8(n[2])), nil
}

MessageCode differs on GOARM 5

The received message on the inbound seems to be different on different architecture. So on my Mac (AMD64) the casting to LDataInd works for all incoming messages. On my BeagleBoneBlack I use the ARM 5 architecture, which receives some messages of type LDataCon.

Build options:
GOOS=linux GOARCH=arm GOARM=5

Function:
func serveGroupInbound(inbound <-chan cemi.Message, outbound chan<- GroupEvent)

Code:
if ind, ok := msg.(*cemi.LDataInd); ok

Workaround: Adding additional check like...
if con, ok := msg.(*cemi.LDataCon); ok

Is this an appropriate solution?

DPTs other than ValueTemp

Hello,
in example

// Send 20.5°C to group 1/2/3.
err = client.Send(0, 2563, dpt.ValueTemp(20.5).Pack())

How to convert address "1/2/3" to uint (2563)?
Can we use another DPTs (not only for temperature)?

How to achieve resilience

Hello,

I have another question, I hope this is the right place to ask.

As I previously mentioned on another ticket, I have a N148/21 with only one tunnel connection.

If the gateway connection is not available (it can happen if the previous connection is not properly disconnected) the gateway will be unavailable for 1 min.
So I'm using ResendInterval: 60 * time.Second,

But because the gateway and the go app are not on the same network, the connection might be lost for several minutes.
So I'm using ResponseTimeout: 1 * time.Hour to any (temporary) network issue

But does the lib try to reconnect automatically if the connection is lost?

Thanks,

DPT 251.600

Hi,
will there be a support for DPT 251.600, 6 bytes. It's a RGBW LED connected through a DALI KNX adapter from Hager (TXA664D).
Thanks,
Mitch

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.