Skip to content

Commit

Permalink
Initial Commit for Wake On Lan
Browse files Browse the repository at this point in the history
  • Loading branch information
tmrobert8 committed Jun 7, 2017
1 parent 41685ce commit 31191cb
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 0 deletions.
155 changes: 155 additions & 0 deletions device/WakeOnLan/controller.js
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);
}
});
}

55 changes: 55 additions & 0 deletions device/WakeOnLan/index.js
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);
});
}
20 changes: 20 additions & 0 deletions device/WakeOnLan/wol.map
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

0 comments on commit 31191cb

Please sign in to comment.