-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
230 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
'use strict'; | ||
|
||
const BluePromise = require('bluebird'); | ||
const fs = require('fs') | ||
const readline = require('readline') | ||
const os = require('os'); | ||
const net = require('net'); | ||
const dgram = require('dgram'); | ||
|
||
const PORT_NUMBER = 9; | ||
const DEFAULT_IPADDRESS = '255.255.255.255'; | ||
|
||
let wolMap = "wol.map"; | ||
|
||
/** | ||
* Sets the path to the 'wol.map' file | ||
*/ | ||
module.exports.setMapPath = (mapPath) => { | ||
wolMap = mapPath; | ||
} | ||
|
||
/** | ||
* Handles button presses for WOL | ||
*/ | ||
module.exports.onButtonPressed = (deviceid, name) => { | ||
console.log(`WOL button pressed for ${name}`); | ||
|
||
parseAddr(name) | ||
.then((addr) => { | ||
return Promise.all([addr, getMacBuffer(addr.macAddress)]) | ||
}) | ||
.then((results) => { | ||
let magic = Buffer.alloc(6, 0xff); | ||
for (let i = 0; i < 16; i++) { | ||
magic = Buffer.concat([magic, results[1]]); | ||
} | ||
return Promise.all([results[0], magic]); | ||
}) | ||
.then((results) => { | ||
return sendPacket(results[0].ipAddress, results[1]); | ||
}) | ||
.then((results) => { | ||
console.log("WOL packet sent"); | ||
}) | ||
.catch((err) => { | ||
console.error("Error occurred writing WOL packet. ", err || err.message); | ||
}); | ||
} | ||
|
||
/** | ||
* Returns a promise to send the magic packet to the specified IP address | ||
* @param {any} ipAddress the ipaddress to send to | ||
* @param {any} magic the magic packet to send | ||
*/ | ||
function sendPacket(ipAddress, magic) { | ||
return new BluePromise((resolve, reject) => { | ||
const socket = dgram.createSocket(net.isIPv6(ipAddress) ? 'udp6' : 'udp4') | ||
.on('error', (err) => { | ||
socket.close(); | ||
reject(err); | ||
}) | ||
.once('listening', () => { | ||
socket.setBroadcast(true); | ||
}); | ||
|
||
socket.send(magic, 0, magic.length, PORT_NUMBER, ipAddress, (err, res) => { | ||
socket.close(); | ||
if (err === null || err === undefined) { | ||
resolve(true); | ||
} else { | ||
reject("Exception writing the magic packet: " + err); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Discovers devices from the wolMap file. Please note that validation of the | ||
* address field is not | ||
*/ | ||
module.exports.discoverWolDevices = () => { | ||
console.log('WOL discovery using %s', wolMap); | ||
|
||
return new BluePromise((resolve, reject) => { | ||
const devices = []; | ||
|
||
readline.createInterface({ input: fs.createReadStream(wolMap) }) | ||
.on('line', (line) => { | ||
if (!line.startsWith("#")) { | ||
|
||
const idx = line.indexOf("="); | ||
if (idx >= 0) { | ||
const name = line.substring(0, idx).trim(); | ||
const addr = line.substring(idx + 1).trim().replace(/ /g, '/'); | ||
|
||
parseAddr(addr) | ||
.then((r) => { | ||
return getMacBuffer(r.macAddress); | ||
}) | ||
.then((buffer) => { | ||
console.log('WOL discovery call - found %s at %s', name, addr); | ||
devices.push({ | ||
id: addr, | ||
name: name, | ||
reachable: true | ||
}); | ||
}) | ||
.catch((err) => { | ||
console.log('WOL discovery call - invalid mac address: %s at %s : %s', name, addr, err.message); | ||
}); | ||
} | ||
} | ||
}) | ||
.on('error', (err) => { | ||
reject(err); | ||
}) | ||
.on('close', () => { | ||
resolve(devices); | ||
}); | ||
}); | ||
} | ||
|
||
|
||
|
||
/** | ||
* Parsees the string address (found in the wol.map file) to a macAddress/ipAddress | ||
* @param {any} addr the address field to parse | ||
*/ | ||
function parseAddr(addr) { | ||
const idx = addr.indexOf("/"); | ||
return BluePromise.resolve({ | ||
macAddress: (idx < 0 ? addr : addr.substring(0, idx)).trim(), | ||
ipAddress: (idx < 0 ? DEFAULT_IPADDRESS : addr.substring(idx + 1)).trim(), | ||
}); | ||
} | ||
|
||
/** | ||
* Parses the String (hex) MAC address to a byte array of integers | ||
* @param {any} macAddress the max address | ||
*/ | ||
function getMacBuffer(macAddress) { | ||
return new BluePromise((resolve, reject) => { | ||
const hexArray = macAddress.split(/[-:]+/); | ||
if (hexArray.length === 6) { | ||
const buffer = Buffer.alloc(6); | ||
for (let i = 0; i < 6; i++) { | ||
buffer[i] = parseInt(hexArray[i], 16); | ||
} | ||
resolve(buffer); | ||
} else { | ||
reject("Invalid MAC address: " + macAddress); | ||
} | ||
}); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
'use strict'; | ||
|
||
const neeoapi = require('neeo-sdk'); | ||
|
||
console.log('NEEO SDK Example "WakeOnLan"'); | ||
console.log('------------------------------------------'); | ||
|
||
const controller = require('./controller'); | ||
|
||
/** | ||
* Uncomment the following line to set the path to the wol map file | ||
*/ | ||
controller.setMapPath("device/WakeOnLan/wol.map"); | ||
|
||
const wolDevice = neeoapi.buildDevice('WakeOnLan') | ||
.setManufacturer('NEEO') | ||
.addAdditionalSearchToken('WOL') | ||
.setType('ACCESSOIRE') | ||
.addButton({ name: 'wol', label: 'Wake Up' }) | ||
.addButtonHander(controller.onButtonPressed) | ||
.enableDiscovery({ | ||
headerText: 'WOL Instructions', | ||
description: 'Please make sure you add devices to wol.map' | ||
}, controller.discoverWolDevices); | ||
|
||
function startSdkExample(brain) { | ||
console.log('- Start server'); | ||
neeoapi.startServer({ | ||
brain, | ||
port: 6336, | ||
name: 'wake-on-lan', | ||
devices: [wolDevice] | ||
}) | ||
.then(() => { | ||
console.log('# READY, use the mobile app to search for "WakeOnLan"'); | ||
}) | ||
.catch((error) => { | ||
console.error('ERROR!', error.message); | ||
process.exit(1); | ||
}); | ||
} | ||
|
||
//const brainIp = process.env.BRAINIP; | ||
const brainIp = '192.168.1.29'; | ||
if (brainIp) { | ||
console.log('- use NEEO Brain IP from env variable', brainIp); | ||
startSdkExample(brainIp); | ||
} else { | ||
console.log('- discover one NEEO Brain...'); | ||
neeoapi.discoverOneBrain() | ||
.then((brain) => { | ||
console.log('- Brain discovered:', brain.name); | ||
startSdkExample(brain); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
##################################################################################### | ||
# This file will provide mappings between devices and their MAC address/IP addresses | ||
# | ||
# The format of the file is | ||
# Device Name=MACAddress[/IPAddress] | ||
# | ||
# 1) (Required) The device name will appear on the NEEO remote | ||
# 2) (Required) The MAC address to send the WOL packet to | ||
# 3) (Optional) Slash or space followed by the device IP address | ||
# | ||
# If IP Address is specified, the WOL packet is sent directly to it. If not | ||
# specified, the WOL packet will be broadcast to the network | ||
# | ||
# Please note that if the MACAddress appears twice (or MAC Address/IP Address combo), | ||
# the NEEO app will complain of a duplicate when trying to add a device. | ||
##################################################################################### | ||
|
||
Example=01:02:03:04:05:06 | ||
IP Example=01:02:03:04:05:06 192.168.1.111 | ||
IP Example2=01:02:03:04:05:06/192.168.1.112 |