Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notify on keydown #9

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
7 changes: 7 additions & 0 deletions lutron-config.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
},
timeout: {
value: 45000
},
includeAction: {
value: false
}
},
label: function () {
Expand Down Expand Up @@ -99,6 +102,10 @@
<label for="node-config-input-timeout"><i class="fa fa-globe"></i> Timeout (ms)</label>
<input type="text" id="node-config-input-timeout" placeholder="30000"></input>
</div>
<div class="form-row">
<label for="node-config-input-includeAction"><i class="fa fa-plus-circle"></i> Action Data</label>
<input type="checkbox" id="node-config-input-includeAction"></input>
</div>
<!-- Table Class -->
<h2 style="color:brown; margin-left:490px;margin-top:0px;">Device mapping table</h2>

Expand Down
79 changes: 67 additions & 12 deletions lutron-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ module.exports = function (RED) {
function LutronConfigNode(config) {
RED.nodes.createNode(this, config);
this.lutronLoc = config.ipaddress;
var node = this;
const node = this;
node.connected = false;
node.telnet = new Telnet();
node.port = 23;
this.deviceMap = config.deviceMap;
node.deviceMap = config.deviceMap;
node.devices = {};
node.lutronEvent = new events.EventEmitter();
var params = {
node.statusEvent = new events.EventEmitter();
node.includeAction = config.includeAction;
const params = {
host: this.lutronLoc,
port: this.port,
shellPrompt: 'GNET>',
Expand All @@ -31,27 +33,70 @@ module.exports = function (RED) {
var str = '?OUTPUT,' + devId + ',1';
this.telnet.getSocket().write(str + '\n');
};

const updateStatus = (connected, msg) => {
node.statusEvent.emit('update', {
fill: connected ? 'green' : 'red',
shape: 'dot',
text: msg
});
};

const reconnect = () => {
// Try reconnecting in 1 minute
node.log('reconnecting telnet')
setTimeout(() => this.telnet.connect(params), 60000);
}

// Telnet handlers
this.telnet.on('data', (function (self, pkt) {
self.lutronRecv(pkt);
}).bind(null, node));
this.telnet.on('connect', function () {
this.connected = true;
console.log('telnet connect');
node.connected = true;
node.log('telnet connect');
updateStatus(true, 'connected');
});
this.telnet.on('close', function () {
this.connected = false;
console.log('telnet close');
if (node.connected) {
node.log('telnet close');
}
node.connected = false;
updateStatus(false, 'closed');
});
this.telnet.on('error', function () {
console.log('telent error');
if (node.connected) {
node.warn('telnet error');
}
updateStatus(false, 'telnet error');
});
this.telnet.on('failedlogin', function () {
console.log('telent failed login');
node.warn('telnet failed login');
updateStatus(false, 'login failed');
});
this.telnet.on('timeout', function () {
if (node.connected) {
node.log('telnet timeout');
}
});
this.telnet.on('end', function () {
let status = 'ended';
if (node.connected) {
// This happens periodically (on bridge updates?)
// so try reconnecting afterwards
node.warn('telnet remote ended connection');
status = 'reconnecting';
reconnect();
}

updateStatus(false, status);
});

// Lutron handlers
this.lutronSend = function (msg, fn) {
this.telent.getSocket().write(msg + '\n', fn);
this.telnet.getSocket().write(msg + '\n', fn);
}
this.lutrongUpdate = function (deviceId, fn) {
this.lutronUpdate = function (deviceId, fn) {
this.lutronSend('?OUTPUT,' + deviceId + ',1', fn);
}
this.lutronSend = function (deviceId, val, fn) {
Expand All @@ -66,7 +111,7 @@ module.exports = function (RED) {
var deviceId = parseInt(cs[1])
var action = parseInt(cs[2])
var param = parseFloat(cs[3])
// console.log('[',cmd,',', type, ',',deviceId,
// this.log('[',cmd,',', type, ',',deviceId,
// ',', action,',', param,']')
this.lutronEvent.emit('data', {
cmd: cmd,
Expand All @@ -86,6 +131,16 @@ module.exports = function (RED) {
}
}
}

// Cleanup on close
node.on('close', function(done) {
node.log('Node shutting down');
node.connected = false;
node.telnet.end()
.catch(() => this.telnet.destroy())
.finally(done);
});

this.telnet.connect(params);
}
RED.nodes.registerType('lutron-config', LutronConfigNode);
Expand Down
2 changes: 1 addition & 1 deletion lutron-control.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@

<div class="form-row">
<label for="node-input-device_name"><i class="fa fa-tag"></i> Device Name</label>
<select id="node-input-device_name" style="width:200px; font-size: 10px !importnat; height: 24px; padding: 0;">
<select id="node-input-device_name" style="width:200px; font-size: 10px !important; height: 24px; padding: 0;">
<option value="foo">foo</option>
<option value="bar">bar</bar>
</select>
Expand Down
28 changes: 20 additions & 8 deletions lutron-status.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = function (RED) {
var configNode = RED.nodes.getNode(status.confignode);
this.devName = status.name;
this.devId = parseInt(configNode.deviceMap[this.devName]);
this.sendObj = !!configNode.includeAction;
// register a callback on config node so that it can call this
// node
// then it will call the this.send(msg), msg = {payload: "hi"}
Expand All @@ -17,20 +18,20 @@ module.exports = function (RED) {
/*
for dimmer action is always 1
for pico action.param
FullOn => a=2, p=4
up => a=5, p=4
down => a=6 p=4
off => a=4, p=4
FullOn => a=2, p=3
up => a=5, p=3
down => a=6 p=3
off => a=4, p=3
Comment on lines +21 to +24

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-existing issue, but this is missing Button 2 (a=3), and it's also missing the buttons for the PJ2-4B model (8/9/10/11), which is rather a problem as that's the model I have 😅

for on off switch
action =1 p=0 or 100
*/
if (action == '1') {
// either dimmre of switch
node.send({
payload: value
payload: node.sendObj ? d : value
});
} else if (value === 4) {
var m = '';
} else if (value === 3 || node.sendObj) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should likely test || (value === 4 && node.sendObj). I know the only documented actions for pico remotes are 3 and 4 but that's no reason to make assumptions.

var m = action;
if (action === 2)
m = 'on';
else if (action === 5)
Expand All @@ -39,8 +40,11 @@ module.exports = function (RED) {
m = 'down';
else if (action === 4)
m = 'off';

d.action = m;
d.param = value === 3 ? 'keydown' : 'keyup';
node.send({
payload: m
payload: node.sendObj ? d : m
});
}
}
Expand All @@ -50,6 +54,14 @@ module.exports = function (RED) {
});
}
}).bind(null, this));

const statusHandler = status => this.status(status);

// Update node status
configNode.statusEvent.on('update', statusHandler);

// Cleanup on close
this.on('close', () => configNode.statusEvent.removeListener('update', statusHandler));
}
RED.nodes.registerType('lutron-status', LutronStatusNode);
}