Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
Supergiovane committed Jun 30, 2023
1 parent a1ea7a1 commit 4cbbdad
Show file tree
Hide file tree
Showing 14 changed files with 732 additions and 452 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@

<p>
<b>Version 2.1.16</b> - June 2023<br/>
- NEW: Hue scene. You can now call a HUE scene.<br/>
- Bump dependencies versions.<br/>
- Increased TTL of dgram socket, from 128 to 250.<br/>
- Set max hop count in tunneling/broadcast, from 6 to 7.<br/>
- Enabled compatibility with KNX Virtual (BETA).<br/>
- Continue migrating the Help from gitHub to the standard Node-Red help box. You could find some discrepancies in help text. Sorry for that.<br/>
- **BREAKING CHANGE*** removed the emulation capability, because it's a complicated thing to mantain. If you don't know what it is, just don't care about that.<br/>
<p>
<b>Version 2.1.15</b> - June 2023<br/>
- Fix an issue with auto discovery of not registered HUE bridges. Now you must first set the IP, then click CONNECT.<br/>
Expand Down
3 changes: 3 additions & 0 deletions KNXEngine/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
.DS_Store
.code-workspace
8 changes: 6 additions & 2 deletions KNXEngine/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
# CHANGELOG

<p>
<b>Version 1.0.38</b> - June 2023<br/>
<b>Version 1.0.41</b> - July 2023<br/>
- Enabled compatibility with KNX Virtual software (BETA).<br/>
</p>
<p>
<b>Version 1.0.39</b> - June 2023<br/>
- Bump dependencies versions.<br/>
- Increased TTL of dgram socket, from 128 to 250.<br/>
- Set max hop count in tunneling/broadcast, from 6 to 7.<br/>
<p>
</p>
<p>
<b>Version 1.0.37</b> - June 2023<br/>
- Dependencies versions bump.<br/>
Expand Down
2 changes: 1 addition & 1 deletion KNXEngine/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "knxultimate",
"description": "KNX IP protocol implementation for Node. This is the ENGINE of Node-Red KNX-Ultimate node.",
"version": "1.0.38",
"version": "1.0.41",
"engines": {
"node": ">=14"
},
Expand Down
76 changes: 44 additions & 32 deletions KNXEngine/src/KNXClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,20 @@ class KNXClient extends EventEmitter {
}

super()

//this._clientTunnelSeqNumber = -1
this._channelID = null
this._connectionState = STATE.DISCONNECTED
this._timerWaitingForACK = null
this._numFailedTelegramACK = 0 // 25/12/2021 Keep count of the failed tunnelig ACK telegrams

this._clientTunnelSeqNumber = -1
this._options = options// Object.assign(optionsDefaults, options);
this._options.connectionKeepAliveTimeout = KNXConstants.KNX_CONSTANTS.CONNECTION_ALIVE_TIME
// this._localPort = null;
this._peerHost = this._options.ipAddr
this._peerPort = this._options.ipPort
this._options.localSocketAddress = options.localSocketAddress
this._connectionTimeoutTimer = null
this._heartbeatFailures = 0
this.max_HeartbeatFailures = 3
Expand Down Expand Up @@ -125,20 +133,21 @@ class KNXClient extends EventEmitter {
this.removeAllListeners()
// 07/12/2021 Based on protocol instantiate the right socket
if (this._options.hostProtocol === 'TunnelUDP') {
let conn = this
this._clientSocket = dgram.createSocket({ type: 'udp4', reuseAddr: false })
this._clientSocket.removeAllListeners() // 12/03/2022 Remove all listeners
this._clientSocket.on(SocketEvents.message, this._processInboundMessage)
this._clientSocket.on(SocketEvents.error, error => this.emit(KNXClientEvents.error, error))
this._clientSocket.on(SocketEvents.close, info => this.emit(KNXClientEvents.close, info))
let conn = this
this._clientSocket.bind({ address: this._options.localIPAddress, port: this._options._peerPort }, function () {
this._clientSocket.bind({ port: null, address: this._options.localIPAddress }, function () {
try {
conn._clientSocket.setTTL(250)
if (conn._options.localSocketAddress === undefined) conn._options.localSocketAddress = conn._clientSocket.address()
} catch (error) {
if (conn.sysLogger !== undefined && conn.sysLogger !== null) conn.sysLogger.error('UDP: Error setting SetTTL ' + error.message || '')
}
conn = null
})
this._clientSocket.on(SocketEvents.message, this._processInboundMessage)
this._clientSocket.on(SocketEvents.error, error => this.emit(KNXClientEvents.error, error))
this._clientSocket.on(SocketEvents.close, info => this.emit(KNXClientEvents.close, info))
} else if (this._options.hostProtocol === 'TunnelTCP') {
// TCP
this._clientSocket = new net.Socket()
Expand Down Expand Up @@ -177,15 +186,10 @@ class KNXClient extends EventEmitter {
return
}
conn = null
// this._localPort = this._clientSocket.address().port;// 07/12/2021 Get the local port used bu the socket
})
}

this._clientTunnelSeqNumber = -1
this._channelID = null
this._connectionState = STATE.DISCONNECTED
this._timerWaitingForACK = null
this._numFailedTelegramACK = 0 // 25/12/2021 Keep count of the failed tunnelig ACK telegrams

}

get channelID() {
Expand Down Expand Up @@ -238,21 +242,6 @@ class KNXClient extends EventEmitter {
return new KNXDataBuffer(adpu.data, IDataPoint)
}

// bindSocketPortAsync(port = KNXConstants.KNX_CONSTANTS.KNX_PORT, host = '0.0.0.0') {
// return new Promise((resolve, reject) => {
// try {
// this._clientSocket.bind(port, host, () => {
// this._clientSocket.setMulticastInterface(host);
// this._clientSocket.setMulticastTTL(128);
// this._options.localIPAddress = host;
// resolve();
// });
// }
// catch (err) {
// reject(err);
// }
// });
// }
send(knxPacket) {
// Logging
if (this.sysLogger !== undefined && this.sysLogger !== null) {
Expand Down Expand Up @@ -579,7 +568,11 @@ class KNXClient extends EventEmitter {
this._awaitingResponseType = KNXConstants.KNX_CONSTANTS.CONNECT_RESPONSE
this._clientTunnelSeqNumber = -1
try {
this._sendConnectRequestMessage(new TunnelCRI.TunnelCRI(knxLayer))
// 27/06/2023, leave some time to the dgram, do do the bind and read local ip and local port
const t = setTimeout(() => {
this._sendConnectRequestMessage(new TunnelCRI.TunnelCRI(knxLayer))
}, 2000);

} catch (error) { }
} else if (this._options.hostProtocol === 'TunnelTCP') {
// TCP
Expand Down Expand Up @@ -811,11 +804,12 @@ class KNXClient extends EventEmitter {

// 16/03/2022
if (this._timerWaitingForACK !== null) clearTimeout(this._timerWaitingForACK)

this._channelID = knxConnectResponse.channelID
this._connectionState = STATE.CONNECTED
this._numFailedTelegramACK = 0 // 16/03/2022 Reset the failed ACK counter
this._clearToSend = true // 16/03/2022 allow to send

this._connectionState = STATE.CONNECTED
this._channelID = knxConnectResponse.channelID
try {
if (this.sysLogger !== undefined && this.sysLogger !== null) this.sysLogger.debug('Received KNX packet: CONNECT_RESPONSE, ChannelID:' + this._channelID + ' Host:' + this._options.ipAddr + ':' + this._options.ipPort)
} catch (error) { }
Expand Down Expand Up @@ -1007,15 +1001,33 @@ class KNXClient extends EventEmitter {
}

_sendConnectRequestMessage(cri) {
this.send(KNXProtocol.KNXProtocol.newKNXConnectRequest(cri))
try {
const oHPAI = new HPAI.HPAI(this._options.localSocketAddress.address, this._options.localSocketAddress.port, this._options.hostProtocol === 'TunnelTCP' ? KNXConstants.KNX_CONSTANTS.IPV4_TCP : KNXConstants.KNX_CONSTANTS.IPV4_UDP)
this.send(KNXProtocol.KNXProtocol.newKNXConnectRequest(cri, oHPAI, oHPAI))
} catch (error) {
this.send(KNXProtocol.KNXProtocol.newKNXConnectRequest(cri))
}
// this.send(KNXProtocol.KNXProtocol.newKNXConnectRequest(cri))
}

_sendConnectionStateRequestMessage(channelID) {
this.send(KNXProtocol.KNXProtocol.newKNXConnectionStateRequest(channelID))
try {
const oHPAI = new HPAI.HPAI(this._options.localSocketAddress.address, this._options.localSocketAddress.port, this._options.hostProtocol === 'TunnelTCP' ? KNXConstants.KNX_CONSTANTS.IPV4_TCP : KNXConstants.KNX_CONSTANTS.IPV4_UDP)
this.send(KNXProtocol.KNXProtocol.newKNXConnectionStateRequest(channelID, oHPAI))
} catch (error) {
this.send(KNXProtocol.KNXProtocol.newKNXConnectionStateRequest(channelID))
}
//this.send(KNXProtocol.KNXProtocol.newKNXConnectionStateRequest(channelID))
}

_sendDisconnectRequestMessage(channelID) {
this.send(KNXProtocol.KNXProtocol.newKNXDisconnectRequest(channelID))
try {
const oHPAI = new HPAI.HPAI(this._options.localSocketAddress.address, this._options.localSocketAddress.port, this._options.hostProtocol === 'TunnelTCP' ? KNXConstants.KNX_CONSTANTS.IPV4_TCP : KNXConstants.KNX_CONSTANTS.IPV4_UDP)
this.send(KNXProtocol.KNXProtocol.newKNXDisconnectRequest(channelID, oHPAI))
} catch (error) {
this.send(KNXProtocol.KNXProtocol.newKNXDisconnectRequest(channelID))
}
//this.send(KNXProtocol.KNXProtocol.newKNXDisconnectRequest(channelID))
}

_sendDisconnectResponseMessage(channelID, status = KNXConstants.ConnectionStatus.E_NO_ERROR) {
Expand Down
7 changes: 1 addition & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,9 @@ If you import your ETS CSV or ESF file, just begin typing the group address or t
Just pass a normal payload to the node (true, false, a string or any nymber) and just receive a normal payload (true, false, a string or any nymber) to use in your flow.

</details>
<details><summary>As single device, as Universal node or as Emulation of a real KNX device</summary>
<details><summary>As single device, as Universal node.</summary>

The node can act as a single device (for example having Group Address 0/0/1), or can be used as universal node, catching all messages coming from KNX Bus (in this case the node will output a comprehensive msg to the flow, containing group address, device name, automatic decoded payload and other useful infos). The node can act as universal KNX sender as well (you can pass a message to the node, containing the destination group address, the datapont type and the payload).
You can even use the node to emulate a phisically non existent KNX device. The node will behave exactly as a normal KNX Device and will also respond to read requests coming from the KNX bus, by sending the current payload value to the KNX bus.

</details>
<details><summary>Contextual help for formatting input messages</summary>
Expand Down Expand Up @@ -135,11 +134,7 @@ Full support for IP Interfaces as well for IP Routers. It's recommended the use
You can send RAW buffers directly to the bus.

</details>
<details><summary>Gateway simulation</summary>

By putting **EMULATE** in the IP field, the gateway node will not write to the KNX BUS. Useful for simulations and classsrooms.

</details>


## WORKING WITH THE ETS CSV FILE OR WITH ESF FILE
Expand Down
6 changes: 1 addition & 5 deletions nodes/knxUltimate-config.html
Original file line number Diff line number Diff line change
Expand Up @@ -283,10 +283,6 @@
</div>
</div> -->

<div class="form-tips" style="margin-top:11px">
<span data-i18n="knxUltimate-config.advanced.tiphost"></span>
</div>

<br/>
<div class="form-row">
<label for="node-config-input-KNXEthInterface" style="width: 200px">
Expand Down Expand Up @@ -454,7 +450,7 @@ <h3><span data-i18n="knxUltimate-config.properties.ets_import"></span></h3>
|Property|Description|
|--|--|
| Name | Node name. |
| IP/Hostname | ETH/KNX Router multicast address or Interface unicast IP address. If you have an KNX/IP interface, use the interface's IP address, for example 1982.168.1.22, otherwise, if you have a KNX/IP router, put the multicast address 224.0.23.12. You can also type an Hostname instead of an IP. Type **EMULATE** instead of the IP address, to simulate a gateway. In this case, the node will not communicate with the KNX BUS. This option is useful for doing simulations. |
| IP/Hostname | ETH/KNX Router multicast address or Interface unicast IP address. If you have an KNX/IP interface, use the interface's IP address, for example 1982.168.1.22, otherwise, if you have a KNX/IP router, put the multicast address 224.0.23.12. You can also type an **Hostname** instead of an IP. |
| Port | The port. |
| Protocol dropdown | *Tunnel UDP* is for KNX/IP interfaces, *Multicast UDP* is for KNX/IP Routers. |
| Bind to local interface | The Node will use this local interface for communications. Leave "Auto" for automatic selection. If you have more than one lan connection, for example Ethernet and Wifi, it's strongly recommended to manually select the interface, otherwise not all UDP telegram will reach your computer, thus the Node may not work as expected. |
Expand Down
Loading

0 comments on commit 4cbbdad

Please sign in to comment.