Retrieve the Device Information from the Border Router using CoAP#
Install libcoap2-bin
on the Border Router#
The application requires libcoap binaries to be installed on the Border Router, so install the
-bin
package.If using CoAP notifications instead of UDP notifications,
coap-server
will be used, and requires the-d
option to define the max number of resources the coap-server can listen to. This is only available inlibcoap
as fromlibcoap2
, so installlibcoap
as follows:
sudo apt-get install libcoap2-bin
Check the installed binaries using:
ls -al /usr/bin/coap*
-rwxr-xr-x 1 root root 26236 Nov 9 2019 /usr/bin/coap-client
-rwxr-xr-x 1 root root 26236 Nov 9 2019 /usr/bin/coap-client-gnutls
-rwxr-xr-x 1 root root 26236 Nov 9 2019 /usr/bin/coap-client-openssl
-rwxr-xr-x 1 root root 18016 Nov 9 2019 /usr/bin/coap-rd
-rwxr-xr-x 1 root root 18016 Nov 9 2019 /usr/bin/coap-rd-gnutls
-rwxr-xr-x 1 root root 18016 Nov 9 2019 /usr/bin/coap-rd-openssl
-rwxr-xr-x 1 root root 22124 Nov 9 2019 /usr/bin/coap-server
-rwxr-xr-x 1 root root 22124 Nov 9 2019 /usr/bin/coap-server-gnutls
-rwxr-xr-x 1 root root 22124 Nov 9 2019 /usr/bin/coap-server-openssl
The example uses coap-client
and optionally coap-server
(if using COAP notifications).
List Connected Devices' IPv6 Addresses#
wsbrd_cli status
returns the connected devices' MAC addresses, while CoAP requires the IPv6 addresses.
The dbus resources related to the Wi-SUN Border Router are available to dbus as com.silabs.Wisun.BorderRouter
:
busctl introspect SERVICE OBJECT [INTERFACE]
busctl introspect com.silabs.Wisun.BorderRouter /com/silabs/Wisun/BorderRouter com.silabs.Wisun.BorderRouter
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
com.silabs.Wisun.BorderRouter interface - - -
.IeCustomClear method - - -
.IeCustomInsert method yyayay - -
.InstallGtk method ay - -
.InstallLgtk method ay - -
.JoinMulticastGroup method ay - -
.LeaveMulticastGroup method ay - -
.RevokeGroupKeys method ayay - -
.RevokePairwiseKeys method ay - -
.SetModeSwitch method ayi - -
.SetSlotAlgorithm method y - -
.Gaks property aay 4 16 54 182 30 129 250 196 136 180 3 24… emits-change
.Gtks property aay 4 16 0 16 32 48 64 80 96 112 128 144 16… emits-change
.HwAddress property ay 8 144 253 159 255 254 0 51 58 -
.Lgaks property aay 3 16 159 29 31 16 211 121 13 120 93 104… emits-change
.Lgtks property aay 3 16 205 198 155 180 84 17 14 130 116 6… emits-change
.Nodes property a(aya{sv}) 3 8 144 253 159 255 254 0 51 58 3 "is_b… emits-invalidation"
.WisunChanPlanId property u 3 const
.WisunClass property u 0 const
.WisunDomain property s "BZ" const
.WisunFanVersion property y 2 const
.WisunMode property u 0 const
.WisunNetworkName property s "Linux_BZ_3_8" const
.WisunPanId property q 59418 const
.WisunPhyModeId property u 8 const
.WisunSize property s "CERT" const
org.freedesktop.DBus.Introspectable interface - - -
.Introspect method - s -
org.freedesktop.DBus.Peer interface - - -
.GetMachineId method - s -
.Ping method - - -
org.freedesktop.DBus.Properties interface - - -
.Get method ss v -
.GetAll method s a{sv} -
.Set method ssv - -
.PropertiesChanged signal sa{sv}as - -
What you are looking for is the Nodes
property, which you can 'get' using:
busctl introspect com.silabs.Wisun.BorderRouter /com/silabs/Wisun/BorderRouter com.silabs.Wisun.BorderRouter Nodes
a(aya{sv}) 3 8 144 253 159 255 254 0 51 58 3 "is_border_router" b true "node_role" y 0 "ipv6" aay 2 16 254 128 0 0 0 0 0 0 146 253 159 255 254 0 51 58 16 253 0 97 114 109 0 0 0 146 253 159 255 254 0 51 58 8 96 164 35 255 254 55 168 255 8 "is_authenticated" b true "node_role" y 1 "parent" ay 8 144 253 159 255 254 0 51 58 "is_neighbor" b true "rssi" i -46 "rsl" i -41 "rsl_adv" i -37 "ipv6" aay 2 16 254 128 0 0 0 0 0 0 96 164 35 255 254 55 168 255 16 253 0 97 114 109 0 0 0 98 164 35 255 254 55 168 255 8 96 164 35 255 254 55 169 1 4 "is_authenticated" b true "node_role" y 1 "parent" ay 8 96 164 35 255 254 55 165 29 "ipv6" aay 2 16 254 128 0 0 0 0 0 0 96 164 35 255 254 55 169 1 16 253 0 97 114 109 0 0 0 98 164 35 255 254 55 169 1
The underlying structure is detailed in wsbrd-br-linux/DBUS.md:
- `ay`: EUI64
- `a{sv}`: list of properties identified by a string, as described in the
following table. Not all properties are guaranteed to be present per node
(ex: a node without parent has no `parent` field)
| Key |Signature| Comment |
|------------------|---------|--------------------------------------------------------------------------|
|`is_border_router`|`b` |Deprecated. Use `node_role` instead. |
|`node_role` |`y` |Semantics from Wi-SUN (`0`: BR, `1`: FFN-FAN1.1, `2`: LFN, none: FFN-FAN1.0)|
|`ipv6` |`aay` |Array of IPv6 addresses (usually link-local and GUA) |
|`parent` |`ay` |EUI-64 of the preferred parent |
|`is_authenticated`|`b` | |
|`is_neighbor` |`b` |Only nodes that use direct unicast traffic to the border router are listed|
|`rssi` |`i` |Received Signal Strength Indication (RSSI) of the last packet received in dBm (neighbor only)|
|`rsl` |`i` |Exponentially Weighted Moving Average (EWMA) of the Received Signal Level (RSL) in dBm (neighbor only)|
|`rsl_adv` |`i` |EWMA of the RSL in dBm advertised by the node in RSL-IE (neighbor only) |
Although it's possible, using the above to retrieve IPv6 addresses is quite complex, and is better done using the pydbus
Python package and a short script.
Install pydbus
Python Package#
pip3 install pydbus
get_nodes_ipv6_address.py
Python Script#
from pydbus import SystemBus
import re
"""
get_nodes_ipv6_address.py
Prints the IPv6 address of each node connected to the running WSBRD instance.
USAGE:
python3 get_nodes_ipv6_address.py
NOTES:
- This script can only be used with the WSBRD + RCP setup and must be executed on the host.
"""
bus = SystemBus()
proxy = bus.get("com.silabs.Wisun.BorderRouter", "/com/silabs/Wisun/BorderRouter")
nodes = proxy.Nodes
def sliceIPv6(source):
return [source[i : i + 4] for i in range(0, len(source), 4)]
for node in nodes:
if len(node[1]["ipv6"]) != 2:
continue
if "parent" not in node[1] and (
"node_role" not in node[1] or node[1]["node_role"] != 2
):
continue
ipv6 = bytes(node[1]["ipv6"][1]).hex()
ipv6 = ":".join(sliceIPv6(ipv6))
ipv6 = re.sub("0000:", ":", ipv6)
ipv6 = re.sub(":{2,}", "::", ipv6)
print(ipv6)
For a more convenient use from bash, this Python script can be called from the ipv6s
bash script.
#!/bin/bash
# usage: listing IPv6 addresses of all nodes currently connected
# ./ipv6s
ipv6s=$(python /home/pi/get_nodes_ipv6_address.py)
for ipv6 in $ipv6s
do
echo $ipv6
done
This script needs to be set as an executable using chmod a+x ipv6s
.
Use ipv6s
#
./ipv6s
fd00:6172:6d00::62a4:23ff:fe37:a8ff
fd00:6172:6d00::62a4:23ff:fe37:a901
NOTE: The IPv6 addresses obtained from wsbrd via DBus reflect the vision of the network from wsbrd.
It takes a while for a device lifetime to expire, so even after a device is switched off, it may still appear as part of the network from wsbrd's perspective. If a device is off for a while and then turned on in a relatively short term, it may even reconnect before wsbrd considers it as disconnected. With the initial connection message in the demonstration application, you will know this because:
You will receive a notification when the device will reconnect.
You can ask via CoAP for the device status and statistics, which will tell you when the reconnection occurred.
Typical CoAP 'get' Request#
coap-client
uses port 5683
by default. This is the default CoAP UDP port, and is set in the application code.
An abstract of coap-client --help
with the options used in the example is:
coap-client v4.2.1 -- a small CoAP implementation
Copyright (C) 2010-2019 Olaf Bergmann <bergmann@tzi.org> and others
TLS Library: None
Usage: coap-client [-e text] [-m method] [-N] [-B seconds] URI
URI can be an absolute URI or a URI prefixed with scheme and host
General Options
-e text Include text as payload (use percent-encoding for non-ASCII characters)
-m method Request method (get|put|post|delete|fetch|patch|ipatch), default is 'get'
-N Send NON-confirmable message
-B seconds Break operation after waiting given seconds (default is 90)
The typical coap-client
request for the example application takes the following form:
coap-client -m get -N -B 3 coap://[<IPV6>]:5683<COAP_URI> [-e <PAYLOAD>]
where COAP_URI
is the CoAP resource, starting with /
Discover CoAP Resources#
When a device supports CoAP, it generally supports discovery using the /.well-known/core
URI:
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::62a4:23ff:fe37:a901]:5683/.well-known/core
</settings>;ct=40,</statistics>;ct=40,</status>;ct=40,</info>;ct=40,</settings/auto_send>;rt="sec";if="settings",</statistics/stack/regulation>;rt="json";if="regulation",</statistics/stack/network>;rt="json";if="network",</statistics/stack/wisun>;rt="json";if="wisun",</statistics/stack/fhss>;rt="json";if="fhss",</statistics/stack/mac>;rt="json";if="mac",</statistics/stack/phy>;rt="json";if="phy",</history>;rt="text";if="node",</statistics/app/availability>;rt="ratio";if="node",</statistics/app/connected_total>;rt="dhms";if="node",</statistics/app/connections>;rt="int";if="node",</statistics/app/disconnected_total>;rt="dhms";if="node",</statistics/app/join_states_sec>;rt="array";if="node",</statistics/app/all>;rt="json";if="node",</status/connected>;rt="dhms";if="node",</status/neighbor>;rt="json";if="node",</status/parent>;rt="tag";if="node",</status/running>;rt="dhms";if="node",</status/all>;rt="json";if="node",</info/version>;rt="text";if="node",</info/application>;rt="text";if="node",</info/chip>;rt="tag";if="node",</info/device>;rt="tag";if="node",</info/all>;rt="json";if="node"
The above shows four groups of resources (splitting on ,
, with ct=40
):
</settings>;ct=40,
</statistics>;ct=40,
</status>;ct=40,
</info>;ct=40,
And the resources you can access for each group (splitting the remaining text on ,
):
</settings/auto_send>;rt="sec";if="settings",
</statistics/stack/regulation>;rt="json";if="regulation",
</statistics/stack/network>;rt="json";if="network",
</statistics/stack/wisun>;rt="json";if="wisun",
</statistics/stack/fhss>;rt="json";if="fhss",
</statistics/stack/mac>;rt="json";if="mac",
</statistics/stack/phy>;rt="json";if="phy",
</history>;rt="text";if="node",
</statistics/app/availability>;rt="ratio";if="node",
</statistics/app/connected_total>;rt="dhms";if="node",
</statistics/app/connections>;rt="int";if="node",
</statistics/app/disconnected_total>;rt="dhms";if="node",
</statistics/app/join_states_sec>;rt="array";if="node",
</statistics/app/all>;rt="json";if="node",
</status/connected>;rt="dhms";if="node",
</status/neighbor>;rt="json";if="node",
</status/parent>;rt="tag";if="node",
</status/running>;rt="dhms";if="node",
</status/all>;rt="json";if="node",
</info/version>;rt="text";if="node",
</info/application>;rt="text";if="node",
</info/chip>;rt="tag";if="node",
</info/device>;rt="tag";if="node",
</info/all>;rt="json";if="node"
These match what the application provides, since it's filled by the CoAP Resource Manager based on registered CoAP resources.
Send a CoAP Request to All Connected Devices#
The coap_all
bash script can be used to send the same request to all devices. It uses get_nodes_ipv6_addresses.py
to get the IPv6 addresses and traces the CoAP command, such that you can easily copy/paste it for a specific device if needed.
./coap_all /settings/auto_send
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::62a4:23ff:fe37:a51c]:5683/settings/auto_send : auto_send_sec: 60
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::62a4:23ff:fe37:a51d]:5683/settings/auto_send : auto_send_sec: 60
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::62a4:23ff:fe37:a527]:5683/settings/auto_send : auto_send_sec: 60
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::62a4:23ff:fe37:a8ff]:5683/settings/auto_send : auto_send_sec: 60
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::62a4:23ff:fe37:a901]:5683/settings/auto_send : auto_send_sec: 60
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::b635:22ff:fe98:2191]:5683/settings/auto_send : auto_send_sec: 60
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::b635:22ff:fe98:2527]:5683/settings/auto_send : auto_send_sec: 60
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::b635:22ff:fe98:2853]:5683/settings/auto_send : auto_send_sec: 60
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::b6e3:f9ff:fec5:8486]:5683/settings/auto_send : auto_send_sec: 60
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::b6e3:f9ff:fec5:8493]:5683/settings/auto_send : auto_send_sec: 60
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::b6e3:f9ff:fec5:8503]:5683/settings/auto_send : auto_send_sec: 60
Based on the coap_callback_auto_send()
implementation in the Wi-SUN device, coap_all
can also be used to change the auto_send
period for all nodes in a row:
./coap_all /settings/auto_send -e 120
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::62a4:23ff:fe37:a51c]:5683/settings/auto_send -e 120 : auto_send_sec: 120
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::62a4:23ff:fe37:a51d]:5683/settings/auto_send -e 120 : auto_send_sec: 120
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::62a4:23ff:fe37:a527]:5683/settings/auto_send -e 120 : auto_send_sec: 120
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::62a4:23ff:fe37:a8ff]:5683/settings/auto_send -e 120 : auto_send_sec: 120
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::62a4:23ff:fe37:a901]:5683/settings/auto_send -e 120 : auto_send_sec: 120
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::b635:22ff:fe98:2191]:5683/settings/auto_send -e 120 : auto_send_sec: 120
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::b635:22ff:fe98:2527]:5683/settings/auto_send -e 120 : auto_send_sec: 120
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::b635:22ff:fe98:2853]:5683/settings/auto_send -e 120 : auto_send_sec: 120
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::b6e3:f9ff:fec5:8486]:5683/settings/auto_send -e 120 : auto_send_sec: 120
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::b6e3:f9ff:fec5:8493]:5683/settings/auto_send -e 120 : auto_send_sec: 120
coap-client -m get -N -B 3 coap://[fd00:6172:6d00::b6e3:f9ff:fec5:8503]:5683/settings/auto_send -e 120 : auto_send_sec: 120