dufourgilles / knx-ip

KNX IP Gateway protocol implementation
30 stars 9 forks source link

Discovery request doesn't respond and all requests respond "Request 0 timed out" #18

Closed muffincolor closed 1 year ago

muffincolor commented 1 year ago

Good day. I faced an issue that I can't send request to knx bus. At first, I copied the code from the example to try to make a simple request (turn on/off light). But, discovery request respond nothing (event handler doesn't work at all).

Then I tried to connect directly (avoiding discovering request). It was successful. I got channelId and there was no error. After connecting I tried to read and write knx group address. But I always got error that is presented below....

Error: Request 0 timed out
    at KNXClient._setTimerAndCallback (/Users/dkononenko/Работа/modbus-controller/node_modules/knx-ip/src/KNXClient.ts:449:28)
    at KNXClient.sendWriteRequest (/Users/dkononenko/Работа/modbus-controller/node_modules/knx-ip/src/KNXClient.ts:198:14)
    at /Users/dkononenko/Работа/modbus-controller/node_modules/knx-ip/src/KNXTunnelSocket.ts:131:29
    at new Promise (<anonymous>)
    at KNXTunnelSocket.writeAsync (/Users/dkononenko/Работа/modbus-controller/node_modules/knx-ip/src/KNXTunnelSocket.ts:130:16)
    at AppController.testHttp (/Users/dkononenko/Работа/modbus-controller/src/app.controller.ts:40:26)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at /Users/dkononenko/Работа/modbus-controller/node_modules/@nestjs/core/router/router-execution-context.js:46:28
    at /Users/dkononenko/Работа/modbus-controller/node_modules/@nestjs/core/router/router-proxy.js:9:17

Also, I've tried to use node-red knx libraries and everything works great. So, that means that knx bus is available and not secured in private network. But, I've seen all my requests (including knx-ip) in ETS5 log. All of them were dark gray color requests. So, that means that request are delivered to knx bus. But nothing happens. I've attached code example below...

export class AppController {
  knxClient: knx.KNXTunnelSocket;

  constructor() {
    this.knxClient = new knx.KNXTunnelSocket('1.1.100');

    this.knxClient.on('error', (err) => {
      console.log(err);
      if (err) {
        console.log(err);
      }
    });

    this.knxClient.on('discover', (info) => {
      const [ip, port] = info.split(':');
      console.log('Connecting to ', ip, port);

      this.knxClient.connectAsync(ip, port).then(() => {
        console.log('Connected through channel id ', this.knxClient.channelID);
      });
    });
  }

  @Get('/test')
  async testHttp() {
    const ip = 'working ip address';
    const port = 3671;

    await this.knxClient.connectAsync(ip, port);

    const knxAddress = knx.KNXAddress.createFromString('0.0.1', knx.KNXAddress.TYPE_GROUP);

    const buf = Buffer.alloc(1);
    buf.writeUInt8(1, 0);

    await this.knxClient.writeAsync(knxAddress, new knx.KNXDataBuffer(buf));

    // this.knxClient.startDiscovery(ip);

    return 'Test';
  }
}

The version of knx-ip (0.2.1)

dufourgilles commented 1 year ago

For discovery, do not connect the client. Start a discovery by specifying the local ip address of the interface you want to use to connect to your knx gateway. This is the ip address of the machine on which you run knx-ip

// start auto discovery on interface with ip 192.168.1.99 knxClient.startDiscovery("192.168.1.99");

Wait for the discover event. The discover event will give you an ip and port that you can use to connect the knxClient.

muffincolor commented 1 year ago

Thank you fot such a quick reply. I've tried to make a discovery request before connecting (your sample example in README). However, there is no response for a long time. I use knx bux that connection to use via TunnelUDP. Is your library support this protocol? Moreover, my requests are delivered to knx bus, but nothing happens. I've attcahed ETS5 request log (however, there is not english lang). But, as you can see, there are delivered requests. Why might nothing happen?

Снимок экрана 2022-09-15 в 12 21 40 Снимок экрана 2022-09-15 в 12 21 50
muffincolor commented 1 year ago

I've tried code below, but it doesn't work too.

const { KNXTunnelSocket } = require('knx-ip');

const start = async () => {
  const knxClient = new KNXTunnelSocket('1.1.162');

  knxClient.once(KNXTunnelSocket.KNXTunnelSocketEvents.error, (err) => {
    if (err) {
      console.warn(err);
    }
  });

  knxClient.once(KNXTunnelSocket.KNXTunnelSocketEvents.discover, (info) => {
    console.log('Discovery', info);
  });

  knxClient.startDiscovery('192.168.25.11', 3671);
};

start();
dufourgilles commented 1 year ago

Hello,

sorry this is not working for you. I loaded your code in my setup ... I just changed the ip to my client ip address - 192.168.1.2 The client is the machine that executes the discovery. It has multiple IP, but it is connected to the KNX network via interface 192.168.1.2. You can see the response from the KNX gateway 192.168.1.46:3671. The KNX Gateway is at IP 192.168.1.46 and listening on UDP port 3671.

I can then connect the client to that ip and port using the connectAsync function

$ node Welcome to Node.js v14.15.3. Type ".help" for more information.

const { KNXTunnelSocket } = require('knx-ip'); undefined

const start = async () => { ... const knxClient = new KNXTunnelSocket('1.1.162'); ... ... knxClient.once(KNXTunnelSocket.KNXTunnelSocketEvents.error, (err) => { ... if (err) { ..... console.warn(err); ..... } ... }); ... ... knxClient.once(KNXTunnelSocket.KNXTunnelSocketEvents.discover, (info) => { ... console.log('Discovery', info); ... }); ... knxClient.startDiscovery('192.168.1.2'); ... } undefined start(); Promise { undefined } _sendSearchRequestMessage 192.168.1.2 null Discovery 192.168.1.46:3671

let client = new KNXTunnelSocket('1.1.200'); client.connectAsync('192.168.1.46', 3671).then(() => console.log("connected")).catch((e) => console.log(e)); Promise { }

connected

dufourgilles commented 1 year ago

If it still does not work for you, please capture a trace with Wireshark filtering on port 3671 and upload to this thread. Thanks

gautampanchal94 commented 1 year ago

I have same error. Whenever I request read/write.

gautampanchal94 commented 1 year ago
import { DataPoints, KNXAddress, KNXDataBuffer, KNXTunnelSocket } from "knx-ip";
import { DataPoint } from "knx-ip/lib/DataPoints/DataPoint";

class KnxClient {

    client: KNXTunnelSocket;

    constructor(
        readonly host: string,
    ) {
        this.client = new KNXTunnelSocket("1.1.100");

        // Handle Connecting error
        this.client.on(KNXTunnelSocket.KNXTunnelSocketEvents.error, (err) => {
            if (err) {
                this.logger.error(`${err}`);
            }
        });

        this.discoverCB(this.host, 3671)
    }

    handleBusEvent(srcAddress: any, dstAddress: any, npdu: any) {
        // ?Query: What are the values of srcAddress, dstAddress, npdu
        console.log(`${srcAddress.toString()} -> ${dstAddress.toString()} :`, String(Math.ceil(parseInt(npdu.dataValue.toString('hex'), 16) / 2.55)));
    }

    discoverCB(ip: string, port: number) {
        console.log(`Connecting to ${ip}:${port}`);
        this.client.connectAsync(ip, port).then(() => {
            this.logger.info('Staring bus monitoring');
            this.client.on("indication", this.handleBusEvent);
            this.client.monitorBus();
        }).catch((e) => { console.log(e) })
    }

    public WriteDPT1(addr: string, val: boolean) {
        const write_swt = new DataPoints.Switch(KNXAddress.createFromString(addr, KNXAddress.TYPE_GROUP));
        write_swt.bind(this.client);
        if (val === true) {
            write_swt.setOn();
        } else {
            write_swt.setOff();
        }
    }

    public ReadDPT1(addr: string) {
        const read_swt = new DataPoints.Switch(KNXAddress.createFromString(addr, KNXAddress.TYPE_GROUP));
        read_swt.bind(this.client);
        return read_swt.read();
    }  
}

export { KnxClient }

After this I am using WriteDPT1/ReadDPT1 method for write/read request.

dufourgilles commented 1 year ago

There is a lot of errors in your code. Main issue is that you did not start the auto discovery and simply call a discovery callback function with your own IP. The output of the error is clearly showing an attempt to connect to yourself. Review the README correctly.

dufourgilles commented 1 year ago

Here is the fixed code and showing that it does work once fixed. Don't forget the connectAsync function is a PRomise.... You must await before you can do anything with the socket.

$ node lib/index.js Connecting to 192.168.1.46:3671 Staring bus monitoring done 1.1.15 -> 1/2/12 : 1 ^C gdufour@gdnet2:/mnt/raid/Node/test$ cat src/index.ts import { DataPoints, KNXAddress, KNXDataBuffer, KNXTunnelSocket } from "knx-ip"; import { DataPoint } from "knx-ip/lib/DataPoints/DataPoint";

class KnxClient {

client: KNXTunnelSocket;

constructor(
    readonly host: string,
) {
    this.client = new KNXTunnelSocket("1.1.100");

    // Handle Connecting error
    this.client.on(KNXTunnelSocket.KNXTunnelSocketEvents.error, (err) => {
        if (err) {
            console.log(`${err}`);
        }
    });

//this.discoverCB(this.host, 3671)
}

handleBusEvent(srcAddress: any, dstAddress: any, npdu: any) {
    // ?Query: What are the values of srcAddress, dstAddress, npdu
    console.log(`${srcAddress.toString()} -> ${dstAddress.toString()} :`, String(Math.ceil(parseInt(npdu.dataValue.toString('hex'), 16) / 2.55)));
}

public async discoverCB(ip: string, port: number) {
    console.log(`Connecting to ${ip}:${port}`);
    return this.client.connectAsync(ip, port).then(() => {
        console.log('Staring bus monitoring');
        this.client.on("indication", this.handleBusEvent);
        this.client.monitorBus();
    }).catch((e) => { console.log(e) })
}

public WriteDPT1(addr: string, val: boolean) {
    const write_swt = new DataPoints.Switch(KNXAddress.createFromString(addr, KNXAddress.TYPE_GROUP));
    write_swt.bind(this.client);
    if (val === true) {
        write_swt.setOn();
    } else {
        write_swt.setOff();
    }
}

public ReadDPT1(addr: string) {
    const read_swt = new DataPoints.Switch(KNXAddress.createFromString(addr, KNXAddress.TYPE_GROUP));
    read_swt.bind(this.client);
    return read_swt.read();
}

}

const client = new KnxClient("192.168.1.46"); client.discoverCB("192.168.1.46", 3671).then(() => { client.WriteDPT1("1.1.12", true); console.log("done"); });

gautampanchal94 commented 1 year ago

I have read the README but maybe I misunderstood it. Thank You so much for fixing it.