y5
Version:
simple yamaha remote
237 lines (215 loc) • 7.57 kB
JavaScript
"use strict";
var net = require('net');
var log = undefined; //console.log;
var Y5 = function (ip, timeout, cb) {
if (!(this instanceof Y5)) {
return new Y5(ip, timeout, cb);
}
if (typeof ip === 'function') {
cb = ip;
ip = undefined;
timeout = undefined;
}
if (typeof timeout === 'function') {
cb = timeout;
timeout = undefined;
}
function doCb(v) {
cb && cb(v);
cb = null;
}
this.setlog = this.setLog = function (bo) {
log = (typeof bo === 'function') ? bo : bo ? console.log : undefined;
};
var self = this;
var reconnectCnt = 0;
var interval, client, reconnectTimer, connectTimer;
var re = /@(.*):(.*)=(.*)/;
this.pingMainPowerInterval = 30000;
this.dataReceived = false;
this.onEvent = function (event) {
};
this.onLine = function (line) {
var a = re.exec(line);
if (a && a.length > 3) {
var obj = {
section: a[1],
state: a[2],
value: a[3]
};
this.onEvent(obj);
}
};
this.onData = function (data) {
data = data.toString().replace(/\r\n$/, '');
var ar = data.split('\r\n');
ar.forEach(function (line) {
this.onLine(line);
}.bind(this));
};
this.onTimeout = function () {
};
client = new net.Socket();
client.on('data', function (data) {
log && log('Y5: on data: ' + data.toString().replace(/\r\n$/, ''));
self.dataReceived = true;
self.onData(data);
});
//client.on('end', function() {});
client.on('error', function (error) {
log && log('Y5: error: ' + error.errno + ' ' + error.message);
var to = 3000;
switch (error.errno) { //error.code
case 'ETIMEDOUT':
if (self.onTimeout() === true) return;
to = 0;
break;
//case 'ECONNREFUSED': to = 1000; break;
case 'ECONNRESET':
case 'EPIPE':
//to = reconnectCnt++ < 5 ? 500 : 3000;
to = 2000;
break;
case 'ECANCELED': // called after destroy during connecting.
default:
return;
}
self.setReconnectTimer (to);
});
client.on('close', function (hadError) {
self.dataReceived = false;
log && log('Y5: Connection closed, hadError=' + hadError);
doCb('close');
if (hadError) self.setReconnectTimer(2000);
});
this.close = function (setClient2null) {
clearReconnectTimer ();
clearConnectTimer();
if (interval) {
clearInterval(interval);
interval = null;
}
if (client) {
client.destroy();
//client.end();
}
if (setClient2null !== false) client = null;
self.dataReceived = false;
};
client.on('connect', function() {
clearConnectTimer ();
log && log('Y5: on connect');
reconnectCnt = 0;
self.dataReceived = false;
log && log('Y5: connected! ');
self.send('@MAIN:PWR=?');
self.send('@ZONE2:PWR=?');
if (self.pingMainPowerInterval) interval = setInterval(function () {
self.send('@MAIN:PWR=?');
}, self.pingMainPowerInterval);
doCb();
});
this.connect = function (_ip) {
ip = _ip || ip;
if (!client) return doCb ('client is null');
if (client._connecting) {
log && log('Y5: connect called during connecting. returning now');
return doCb('is already in connection');
}
log && log('Y5: trying to connect... ');
//if (timeout) client.setTimeout(timeout);
if (timeout) self.setConnectTimer(timeout);
client.connect(50000, ip, function () {
// reconnectCnt = 0;
// log && log('Y5: connected! ' + _no);
// self.send('@MAIN:PWR=?');
// self.send('@ZONE2:PWR=?');
// if (self.pingMainPowerInterval) interval = setInterval(function () {
// self.send('@MAIN:PWR=?');
// }, self.pingMainPowerInterval);
// doCb();
});
};
this.send = function (s) {
if (!client.writable) {
log && log('send called with writable=false');
}
client.write(s + '\r\n', function(err,d) {
log && log('Y5: ' + s + ' written');
});
};
this.reconnect = function () {
log && log('Y5: reconnecting... ');
reconnectTimer = null;
this.close(false);
this.connect();
};
function clearReconnectTimer() {
if (reconnectTimer) {
clearTimeout(reconnectTimer);
reconnectTimer = null;
}
}
this.setReconnectTimer = function(to) {
log && log('Y5: setReconnectTimer (' + to + ')');
clearReconnectTimer ();
reconnectTimer = setTimeout(self.reconnect.bind(self), to);
}
function clearConnectTimer() {
if (connectTimer) {
clearTimeout(connectTimer);
connectTimer = null;
}
}
this.setConnectTimer = function(to) {
clearConnectTimer ();
connectTimer = setTimeout(function() {
connectTimer = null;
//self.reconnect.bind(self, 'timeout'), to
log && log('Y5: on timeout');
self.onTimeout();
}, to);
}
this.powerConnected = function () {
self.setReconnectTimer (10000);
//reconnectTimer = setTimeout(this.reconnect.bind(this), 10000);
};
this.getClient = function () {
return client;
};
if (ip) this.connect(ip);
};
module.exports = Y5;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function startListener(ip, port, callback) {
var dgram = require('dgram');
var socket = dgram.createSocket( {type: 'udp4', reuseAddr: true} );
socket.on('error', function (err) {
console.log(err.message);
});
socket.bind(port, '192.168.1.25', function () {
//socket.bind(port, function () {
//socket.setMulticastTTL(128);
socket.setBroadcast(true);
socket.addMembership(ip, '192.168.1.25');
socket.setMulticastLoopback(true);
if (callback) return callback(socket);
});
socket.on('message', function(msg, rinfo) {
//console.log(rinfo.address);
if (rinfo.address != '192.168.1.20') return;
msg = msg.toString();
var ar = msg.split('\r\n');
//console.log(port + ' ' + msg);
//console.log(ip + ':' + port + ' - ' + ar[2] + ' ' + ar[0]);
msg = msg.replace(/\r\n/g, ' - ');
console.log(ip + ':' + port);
console.log(msg);
});
};
// startListener('239.255.255.250', 1900);
// startListener('239.255.255.250', 1902);
// startListener('239.255.255.250', 0);
// startListener('239.255.250.250', 9131);
// startListener('224.0.0.251', 5353);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////