/
sampleSecure.ts
151 lines (129 loc) · 8.11 KB
/
sampleSecure.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { getDecodedKeyring, KNXClient, KNXClientEvents, dptlib, KNXClientOptions } from "../src";
import keyring from "../src/KNXsecureKeyring";
// This is the content of the ETS Keyring file obtained doing this: https://www.youtube.com/watch?v=OpR7ZQTlMRU
let rawjKNXSecureKeyring = `<?xml version="1.0" encoding="utf-8"?>
<Keyring Project="KNX Secure" CreatedBy="ETS 5.7.6 (Build 1398)" Created="2021-11-17T07:43:08" Signature="V279vCe6oJXL/6a06Ys2yQ==" xmlns="http://knx.org/xml/keyring/1">
<Backbone MulticastAddress="224.0.23.12" Latency="2000" Key="CRL14M51oI9pKhzMGGjO1g==" />
<Interface IndividualAddress="3.1.2" Type="Tunneling" Host="3.1.1" UserID="2" Password="gF8N8lKGU9cD3TNMLEvu50SbI48qI5EeC8WeciL53Zg=" Authentication="jHW6k+R/b+GOfdaNzXXildWI4BrqHkAoa6lUtWCGGDI=" />
<Interface IndividualAddress="3.1.3" Type="Tunneling" Host="3.1.1" UserID="3" Password="HbvdOCahzdmjhSaMBeFb/2x8+CwYxF1865N3Nrg485o=" Authentication="XtQMiHSX7cwgB3SJL+CZuCePx434JL1p9cZfjLiGfg4=" />
<Interface IndividualAddress="3.1.4" Type="Tunneling" Host="3.1.1" UserID="4" Password="VPlMEqpC/COz/szs1qsGLg63giJ/E5DbN8MIBgsLYyQ=" Authentication="zmn+tKNmoO+5jiKXeqeDruvC/OA/zNbOdhiWPFQ1+0g=" />
<Interface IndividualAddress="3.1.5" Type="Tunneling" Host="3.1.1" UserID="5" Password="Dqeea+bKaoe7pk/czGgKdLT5ucuOfwMJmpJ/0Q32woY=" Authentication="glxFMw43J7cUAklu38GVga2AjEcz4PgOc2aTEKpjXEI=" />
<Interface IndividualAddress="3.1.6" Type="Tunneling" Host="3.1.1" UserID="6" Password="teB74cgZdQL6CR81pyrWmSHUR8wlDw6PXM5oLlAPLyM=" Authentication="vRKBbWxwF1jsvi5oS64YGT3HaPog9Dcg+cVelgay3vY=" />
<Interface IndividualAddress="3.1.7" Type="Tunneling" Host="3.1.1" UserID="7" Password="BbGlEV5JGosOs2bl6d63rnYDax8S1pMqf5pKluV0l54=" Authentication="3U49RFQAM7pFD40y5zJg2ebcXKCh1cgx41DGzzAZzZE=" />
<Interface IndividualAddress="3.1.8" Type="Tunneling" Host="3.1.1" UserID="8" Password="8O2/pOsUgxQuTtspPZ2wIo4HQxvcrECaHLtoyUY0CZk=" Authentication="/4XvMBmc60edJUKUzpCrpy+MRfQJR5jN673I/Qa5V5o=" />
<Interface IndividualAddress="3.1.9" Type="Tunneling" Host="3.1.1" UserID="9" Password="8hIlqwHsQjRGd8sYRiXG/OyPDQObevIDuKRhVQcXxoc=" Authentication="USfsg+wsH0hwoeLq/GqLcPtfGk5XPW3aAjVgwQjYpQs=" />
<GroupAddresses>
<Group Address="16384" Key="CreHKeXp+5U2qMLVU0XWxw==" />
<Group Address="16385" Key="4N4QIW0wJiRitgxvX4s7ow==" />
<Group Address="16386" Key="AOqADeC4y2u4kYCtBclCtg==" />
</GroupAddresses>
<Devices>
<Device IndividualAddress="3.1.1" ToolKey="T770+Sebf2zpx3X3A0S64A==" ManagementPassword="6LPLJeu+XxuGpn6tOqt9fw4NuSa/jIQCYXzFVDwPUiU=" Authentication="rywptqDB0/UNF/5VmlTs5YnrIqO9FJ3YGGEIm08Z1UQ=" SequenceNumber="121960556295" />
<Device IndividualAddress="3.1.10" ToolKey="t8SSY7LxrVgNvXwLqus4Pg==" SequenceNumber="121960675276" />
<Device IndividualAddress="3.1.11" ToolKey="VMpB+1fIuP4UFaDVQSjNHQ==" SequenceNumber="121960725775" />
</Devices>
</Keyring>`;
// Set the properties
let knxUltimateClientProperties: KNXClientOptions = {
ipAddr: "192.168.1.54",
ipPort: 3671,
physAddr: "1.1.100",
suppress_ack_ldatareq: false,
loglevel: "debug", // or "debug" is the default
localEchoInTunneling: true, // Leave true, forever.
hostProtocol: "TunnelTCP", // "Multicast" in case you use a KNX/IP Router, "TunnelUDP" in case of KNX/IP Interface, "TunnelTCP" in case of secure KNX/IP Interface (not yet implemented)
isSecureKNXEnabled: true, // Leave "false" until KNX-Secure has been released
localIPAddress: "", // Leave blank, will be automatically filled by KNXUltimate
jKNXSecureKeyring: "", // This is the unencrypted Keyring file content (see below)
};
async function LoadKeyringFile(_keyring, _password) {
return keyring.load(_keyring, _password);
}
async function go() {
// Load the Keyring, decrypt it and put it in the jKNXSecureKeyring property.
// The password "banana" has been used to encrypt the keyring file during export form ETS.
// Again, see this https://www.youtube.com/watch?v=OpR7ZQTlMRU
knxUltimateClientProperties.jKNXSecureKeyring = await LoadKeyringFile(rawjKNXSecureKeyring, "banana");
// Log some infos
console.log("KNX-Secure: Keyring for ETS proj " + knxUltimateClientProperties.jKNXSecureKeyring.ETSProjectName + ", created by " + knxUltimateClientProperties.jKNXSecureKeyring.ETSCreatedBy + " on " + knxUltimateClientProperties.jKNXSecureKeyring.ETSCreated + " succesfully validated with provided password");
// Instantiate the client
var knxUltimateClient = new KNXClient(knxUltimateClientProperties);
// This contains the decrypted keyring file, accessible to all .js files referencing the "index.js" module.
console.log(getDecodedKeyring());
// Setting handlers
// ######################################
knxUltimateClient.on(KNXClientEvents.indication, handleBusEvents);
knxUltimateClient.on(KNXClientEvents.error, err => {
// Error event
console.log("Error", err)
});
knxUltimateClient.on(KNXClientEvents.ackReceived, (knxMessage, info) => {
// In -->tunneling mode<-- (in ROUTING mode there is no ACK event), signals wether the last KNX telegram has been acknowledge or not
// knxMessage: contains the telegram sent.
// info is true it the last telegram has been acknowledge, otherwise false.
console.log("Last telegram acknowledge", knxMessage, info)
});
knxUltimateClient.on(KNXClientEvents.disconnected, (reason) => {
// The client is cisconnected
console.log("Disconnected", reason)
});
knxUltimateClient.on(KNXClientEvents.close, () => {
// The client physical net socket has been closed
console.log("Closed")
});
knxUltimateClient.on(KNXClientEvents.connected, info => {
// The client is connected
console.log("Connected. On Duty", info)
// Write something to the BUS
if (knxUltimateClient.clearToSend) knxUltimateClient.write("0/1/1", false, "1.001");
});
knxUltimateClient.on(KNXClientEvents.connecting, info => {
// The client is setting up the connection
console.log("Connecting...", info)
});
// ######################################
// Handle BUS events
// ---------------------------------------------------------------------------------------
function handleBusEvents(_datagram, _echoed) {
// This function is called whenever a KNX telegram arrives from BUS
// Get the event
let _evt = "";
let dpt = "";
let jsValue;
if (_datagram.cEMIMessage.npdu.isGroupRead) _evt = "GroupValue_Read";
if (_datagram.cEMIMessage.npdu.isGroupResponse) _evt = "GroupValue_Response";
if (_datagram.cEMIMessage.npdu.isGroupWrite) _evt = "GroupValue_Write";
// Get the source Address
let _src = _datagram.cEMIMessage.srcAddress.toString();
// Get the destination GA
let _dst = _datagram.cEMIMessage.dstAddress.toString()
// Get the RAW Value
let _Rawvalue = _datagram.cEMIMessage.npdu.dataValue;
// Decode the telegram.
if (_dst === "0/1/1") {
// We know that 0/1/1 is a boolean DPT 1.001
const config = dptlib.resolve("1.001");
jsValue = dptlib.fromBuffer(_Rawvalue, config)
} else if (_dst === "0/1/2") {
// We know that 0/1/2 is a boolean DPT 232.600 Color RGB
const config = dptlib.resolve("232.600");
jsValue = dptlib.fromBuffer(_Rawvalue, config)
} else {
// All others... assume they are boolean
const config = dptlib.resolve("1.001");
jsValue = dptlib.fromBuffer(_Rawvalue, config)
if (jsValue === null) {
// Is null, try if it's a numerical value
const config = dptlib.resolve("5.001");
jsValue = dptlib.fromBuffer(_Rawvalue, config)
}
}
console.log("src: " + _src + " dest: " + _dst, " event: " + _evt, " value: " + jsValue);
}
knxUltimateClient.Connect();
// Wait some seconds, just for fun
await new Promise((resolve, reject) => setTimeout(resolve, 10000));
// Disconnects
if (knxUltimateClient.isConnected()) knxUltimateClient.Disconnect();
}
go();