calimero-project / calimero-core

Core library for KNX network access and management
Other
129 stars 65 forks source link

How to connect to KNX/IP router with desktop application? #21

Closed AnaKatarina closed 9 years ago

AnaKatarina commented 9 years ago

Hi, I'm Ana Katarina from Croatia and my task is to make a desktop application that will be able to connect with the KNX / IP router and receive telegram from weather station and save that parameters to database. I'm using Schneider knx router and ETS 3 software. My weather station sends rain as a bit- rain/no rain, temperature, brightness value-lux, is it morning or evening also as bit and wind speed in meters per second.

In my university it's unicast, does that make some difference in code? Because when I was looking for the right code for my project it's mulitcast everywhere.

If I only want to connect to router and receive telegrams from weather station I only need class for connection and class for routing?

calimero-project commented 9 years ago

What you want is KNX process communication. There is an example in the introduction repository here. This allows you to read and write datapoints. You can create the different datapoints of your weather station using either several StateDPs, or supply directly the DPTXlator instances of the DPTs you use for translating the KNX data. To listen to incoming changes, add a ProcessListener to the process communicator.

Whether you use routing or tunneling, it does not really make a difference. You only have to select your choice in the IP network link constructor via the service mode parameter. Some differences are that KNX routers often support only one active tunnel connection, in routing mode packets are not acknowledged (in tunneling mode they are). You can easily try both and use what better fits your setup.

AnaKatarina commented 9 years ago

Thank you for the explanation.

Today I tried this code and it's working but only for rain because only that parameter is boolean true/false statement. Do you know how should I write the rest of the code for temperature (data type 9.001 °C), wind speed (data type 9.005 meter per second), brightness (data type 9.004 lux), morning/evening (data type 1.001 switch)? Where could I found that? This library supports these data type right?

package projFiles;

import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.InetAddress; import java.net.InetSocketAddress;

import tuwien.auto.calimero.DetachEvent; import tuwien.auto.calimero.GroupAddress; import tuwien.auto.calimero.KNXAddress; import tuwien.auto.calimero.Priority; import tuwien.auto.calimero.cemi.CEMILData; import tuwien.auto.calimero.datapoint.Datapoint; import tuwien.auto.calimero.dptxlator.DPT; import tuwien.auto.calimero.exception.KNXException; import tuwien.auto.calimero.exception.KNXTimeoutException; import tuwien.auto.calimero.link.KNXLinkClosedException; import tuwien.auto.calimero.link.KNXNetworkLink; import tuwien.auto.calimero.link.KNXNetworkLinkIP; import tuwien.auto.calimero.link.KNXNetworkMonitorIP; import tuwien.auto.calimero.link.NetworkLinkListener; import tuwien.auto.calimero.link.medium.KNXMediumSettings; import tuwien.auto.calimero.link.medium.TPSettings; import tuwien.auto.calimero.process.ProcessCommunicator; import tuwien.auto.calimero.process.ProcessCommunicatorImpl; import tuwien.auto.calimero.process.ProcessEvent; import tuwien.auto.calimero.process.ProcessListener;

public class MainClass {

/**
 * Address of your KNXnet/IP server. Replace the IP address as necessary.
 */
private static final String remoteHost = "192.168.1.220";

/**
 * We will read a boolean from this KNX datapoint group address, replace the address string with
 * one of yours. Make sure this datapoint exists, otherwise you will get a read timeout!
 */
private static final String group = "4/1/2";    

public static void main(String[] args) {
    // TODO Auto-generated method stub

    KNXNetworkLink knxLink = null;
    ProcessCommunicator pc = null;
    try {
        // Create our network link. See other constructors if this one assumes too many
        // default settings.
        knxLink = new KNXNetworkLinkIP(remoteHost, TPSettings.TP1);

        // create a process communicator using that network link
        pc = new ProcessCommunicatorImpl(knxLink);

        System.out.println("read the group value from datapoint " + group);
        // this is a blocking method to read a boolean from a KNX datapoint
        final boolean value = pc.readBool(new GroupAddress(group));
        System.out.println("value read from datapoint " + group + ": " + value);

        pc.addProcessListener(new ProcessListener() {

            @Override
            public void groupWrite(ProcessEvent arg0) {
                // TODO Auto-generated method stub

                //The groupWrite() method of your handler will then be called on every received A_GroupWrite indication, with the received message as a parameter (wrapped in a ProcessEvent). Look at ProcessListenerEx for an example how to decode the payload. 
                System.out.println("groupWrite");
            }

            @Override
            public void detached(DetachEvent arg0) {
                // TODO Auto-generated method stub
                System.out.println("detached");

            }
        });

         Thread.sleep(10000);    

    }    
    catch (final KNXException e) {
        System.out.println("Error reading KNX datapoint: " + e.getMessage());
    }
    catch (final InterruptedException e) {
        System.out.println("Interrupted: " + e.getMessage());
    }
    finally {
        // we don't need the process communicator anymore, detach it from the link
        if (pc != null)
            pc.detach();
        // close the KNX link
        if (knxLink != null)
            knxLink.close();
    }

}

}

The first image shows false because the sensor was dry and then I poured sensor with water and then it was written true. kisa

true

calimero-project commented 9 years ago

DPT 9.x is the KNX 2-byte float. Use pc.readFloat(new GroupAddress(temperature), false) and pc.readFloat(new GroupAddress(windspeed), false), where temperature and windspeed are the corresponding datapoints. This returns you the value as Java type float.

Alternatively, if you want to have a datapoint value formatted as string with the unit of measurement appended, use something like

final Datapoint dp = new StateDP(new GroupAddress(temperature), 
        "Weather station temperature", 0, "9.001");
String s = pc.read(dp);
AnaKatarina commented 9 years ago

Thank you, I did it, can you explain how to catch telegrams from weather station through ProcessListener? I don't understand that part very well

For example, the program is running and then happens some changes and weather station sends telegrams automaticaly

calimero-project commented 9 years ago

You already added the process listener. I would suggest to replace ProcessListener with ProcessListenerEx. This provides you with methods like asFloat, so you can easily convert to, e.g., a Java floating point type.

As a start copy this in all your process listener methods (or create a method for it):

try {
    System.out.println(LocalTime.now() +" " + svc + " " + e.getSourceAddr() + "->"
            + e.getDestination() + ": " + DataUnitBuilder.toHex(e.getASDU(), ""));
}
catch (final KNXFormatException | RuntimeException ex) {}

This prints you for every notification the KNX source/destination, and data of your weather station in hexadecimal format. It works for any datapoint (you basically created a very simple KNX group monitor).

In your case, a straightforward implementation for data formatting, because you know your DPTs, is the following (shown for the temperature datapoint; copy the following code into the try block from above):

if (e.getDestination().equals(new GroupAddress(temperature))) {
    final double v = asFloat(e, false);
    System.out.println("Temperature changed to " + v);
}

Similar for your other datapoints.

HTH, Boris

calimero-project commented 9 years ago

An example of a simple group monitor I put here.

AnaKatarina commented 9 years ago

Thanks for explanation! It works! One more question, which protocol is used for sending telegrams in this library? UDP or TCP/IP?

calimero-project commented 9 years ago

KNXnet/IP uses UDP.