Finding devices on a user's network has been made easier by the introduction of ManagerDiscovery since Homey v2.5.0.
Currently Homey can automatically find devices on the user's Wi-Fi network using mDNS-SD, SSDP and MAC.
Choosing a discovery strategy
Find out which discovery strategy your device uses. Most devices nowadays use mDNS-SD. On macOS, you can use Discovery and Bonjour browser for Windows.
For other protocols, refer to your device's API documentation.
Discovery Types
mDNS-SD
Multicast-DNS Service Discovery is a widely used protocol to find devices on a network. It is also known as Avahi or Bonjour. A service broadcasts under a name
(as specified by the manufacturer) and a protocol
(tcp
or udp
).
For example, Homey broadcasts with the name homey
using the tcp
protocol.
A DiscoveryResultMDNSSD has a txt
property that contains the (lowercased) TXT values of the broadcast.
/app.json
{
...
"discovery": {
"nanoleaf-aurora": {
"type": "mdns-sd",
"mdns-sd": {
"name": "nanoleafapi",
"protocol": "tcp"
},
"id": "{{txt.id}}",
"conditions": [
[
{
"field": "txt.md",
"match": {
"type": "string",
"value": "NL22"
}
}
]
]
}
}
}
SSDP
Devices using the Simple Service Discovery Protocol can be found by specifying a search
property.
A DiscoveryResultSSDP has a headers
property that contains the (lowercased) headers of the response.
/app.json
{
...
"discovery": {
"denon-heos": {
"type": "ssdp",
"ssdp": {
"search": "urn:schemas-denon-com:device:ACT-Denon:1"
},
"id": "{{headers.usn}}",
"conditions": [
[
{
"field": "headers.st",
"match": {
"type": "string",
"value": "urn:schemas-denon-com:device:ACT-Denon:1"
}
}
]
]
}
}
}
MAC
MAC Address discovery works by specifying the first 3 bytes of a network device's MAC address. These first three bytes are reserved for the manufacturer and can thus be used to find a device on the network using Address Resolution Protocol (ARP).
A DiscoveryResultMAC only has an address
property, which contains the IP address of the device.
For example, to find a device with a MAC address that starts with 00:24:6d
or 00:24:6e
:
/app.json
{
...
"discovery": {
"weinzierl": {
"type": "mac",
"mac": {
"manufacturer": [
[ 0, 36, 109 ],
[ 0, 36, 110 ]
]
}
}
}
}
Note that the MAC address must be specified in decimal numbers.
Defining your discovery strategy
The Discovery Result
Depending on your discovery type, some properties are available to match on. For example, a mDNS-SD discovery type has a txt
object and the SSDP discovery type has an headers
object.
Discovery Result ID
For the mdns-sd
and ssdp
discovery types, the app must define how a DiscoveryResult can be identified when it has been found multiple times, regardless if the IP address has changed.
For the mac
discovery type, the mac address is used as the ID.
Find a unique and consistent property in the DiscoveryResult and define it as id
in the /app.json
. Homey will then be able to match the result to previous results, and notify your app the device has been found again, instead of seeing the device as a new discovery result.
Examples:
"id": "{{txt.id}}"
"id": "{{headers.uuid}}"
All properties available in the DiscoveryResult are available between double curly braces ({{
and }}
).
Discovery Result Conditions
A discovery strategy can have a set of conditions that must be true before the result is sent to the app.
The conditions
property is an Array
with one or more Arrays
in it. This array contains Objects
rules. When all rules within an array are true, the result is considered a match. Using multiple arrays behaves as rulesArray1 OR rulesArray2 OR ...
.
There are two match types available: string
and regex
.
"conditions": [
[
{
"field": "txt.md",
"match": {
"type": "string",
"value": "NL29"
}
},
// AND:
{
"field": "txt.version",
"match": {
"type": "string",
"value": "1"
}
}
],
// OR:
[
{
"field": "txt.md",
"match": {
"type": "regex",
"value": "NL\\d\\d" // double slashes because of JSON
}
}
]
]
Conditions are matched case-insensitive.
Using discovery with a Driver
The recommended way to use Homey's built-in discovery is to link a discovery strategy to a Driver.
To do so, add the discovery
property to your driver's entry in /app.json
.
For example:
/app.json
{
"discovery": {
"my_discovery": {
"type": "mdns-sd",
"mdns-sd": {
"protocol": "tcp",
"name": "my_service"
}
}
},
"drivers": [
{
"id": "my_driver",
"discovery": "my_discovery",
...
}
]
In your driver.js
, you can call this.getDiscoveryStrategy()
to get the current strategy.
/drivers/my_driver/driver.js
module.exports = class MyDriver extends Homey.Driver {
onPairListDevices(data, callback) {
const discoveryStrategy = this.getDiscoveryStrategy();
const discoveryResults = discoveryStrategy.getDiscoveryResults();
const devices = Object.values(discoveryResults).map(discoveryResult => {
return {
name: discoveryResult.txt.name,
data: {
id: discoveryResult.id,
}
};
});
callback(null, devices);
}
}
In your device.js
, overload the methods starting with onDiscovery
.
module.exports = class MyDevice extends Homey.Device {
onDiscoveryResult(discoveryResult) {
// Return a truthy value here if the discovery result matches your device.
return discoveryResult.id === this.getData().id;
}
async onDiscoveryAvailable(discoveryResult) {
// This method will be executed once when the device has been found (onDiscoveryResult returned true)
this.api = new MyDeviceAPI(discoveryResult.address);
await this.api.connect(); // When this throws, the device will become unavailable.
}
onDiscoveryAddressChanged(discoveryResult) {
// Update your connection details here, reconnect when the device is offline
}
onDiscoveryLastSeenChanged(discoveryResult) {
// When the device is offline, try to reconnect here
}
}
Using discovery standalone
Simply call ManagerDiscovery.getDiscoveryStrategy()
with the discovery strategy id as defined in your /app.json
.
const discoveryStrategy = ManagerDiscovery.getDiscoveryStrategy('my_strategy');
discoveryStrategy.on('result', discoveryResult => {
console.log('Got result:', discoveryResult);
});
discoveryStrategy.getDiscoveryResults(); // { "my_result_id": DiscoveryResult }