Hello community,
there was only one thing missing in my pimatic configuration. The possibility to control my Pioneer AVR.
After a few investigations, I found out, that the AVR talks Telnet.
Some tests later, the idea for a new plugin was born, because the Marantz/Denon AVRs talk another “language” an so, the existing plugin isn’t really usable for me.
After two evenings full of frustration and curses regarding coffeescript, I’m using pure JS now. During the day I’m Java programmer by profession, so it’s some kind of turnaround for me.
At the moment my plugin is running and the first actions could be triggered as well, but everytime I call an action, an exception is thrown. I think it has something to do with callbacks/promises and my execute action needs some improvements.
With respect to my rookie JS skills it would be great, if someone could have a look on it.
The Plugin:
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
module.exports = function(env) {
var M, Promise, PioRemotePlugin, PioRemoteActionProvider, PioRemoteActionHandler, assert, pioRemotePlugin, pioRemoteActionHandler;
var client;
M = env.matcher;
Promise = env.require('bluebird');
assert = env.require('cassert');
var net = env.require('net');
var util = env.require('util');
/**
* THE PLUGIN ITSELF
**/
PioRemotePlugin = (function(_super) {
__extends(PioRemotePlugin, _super);
function PioRemotePlugin() {
this.init = __bind(this.init, this);
return PioRemotePlugin.__super__.constructor.apply(this, arguments);
}
PioRemotePlugin.prototype.init = function(app, framework, config) {
this.framework = framework;
this.config = config;
this.framework.ruleManager.addActionProvider(new PioRemoteActionProvider(this.framework));
return env.logger.info('Initialising done');
};
return PioRemotePlugin;
})(env.plugins.Plugin);
pioRemotePlugin = new PioRemotePlugin;
/**
* THE ACTION PROVIDER
**/
PioRemoteActionProvider = (function(_super) {
__extends(PioRemoteActionProvider, _super);
function PioRemoteActionProvider(framework, config) {
this.framework = framework;
this.config = config;
this.connectAction = __bind(this.connectAction, this);
this.myOptionKeys = ['connect'];
//this.configWithDefaults = _.assign(config.__proto__, config);
}
/**
*This function handles action in the form of `sendAvr "some string"`
**/
PioRemoteActionProvider.prototype.parseAction = function(input, context) {
var commandTokens, fullMatch, m, match, onEnd, retVal, setCommand;
retVal = null;
commandTokens = null;
fullMatch = false;
setCommand = (function(_this) {
return function(m, tokens) {
return commandTokens = tokens;
};
})(this);
onEnd = (function(_this) {
return function() {
return fullMatch = true;
};
})(this);
m = M(input, context).match("sendAvr ").matchStringWithVars(setCommand);
if (m.hadMatch()) {
match = m.getFullMatch();
return {
token: match,
nextInput: input.substring(match.length),
actionHandler: new PioRemoteActionHandler(this.framework, commandTokens)
};
} else {
return null;
}
};
return PioRemoteActionProvider;
})(env.actions.ActionProvider);
/**
* THE ACTION HANDLER
**/
PioRemoteActionHandler = (function(_super) {
__extends(PioRemoteActionHandler, _super);
function PioRemoteActionHandler(framework, commandTokens) {
this.framework = framework;
this.commandTokens = commandTokens;
this.executeAction = __bind(this.executeAction, this);
this.connect = __bind(this.connect, this);
this.disconnect = __bind(this.disconnect, this);
}
PioRemoteActionHandler.prototype.connect = function(callback) {
if(!client) {
env.logger.info('Client is undefined, establish new connection...');
client = new net.Socket();
client.on('data', function(data) {
env.logger.info('Received: ' + data);
});
client.on('close', function() {
if(client) {
env.logger.info('Connection closed');
client.disconnect();
}
});
client.connect(23, '192.168.0.15', function() {
env.logger.info('Connected');
});
} else {
env.logger.info('Client already connected, nothing to do.');
}
callback();
};
PioRemoteActionHandler.prototype.disconnect = function(callback) {
if(client) {
env.logger.info('Closing telnet session...');
client.destroy();
client = undefined;
env.logger.info('done');
} else {
env.logger.info('Nothing to disconnect from.');
}
callback();
};
/*
This function handles action in the form of `execute "some string"`
*/
PioRemoteActionHandler.prototype.executeAction = function() {
return this.framework.variableManager.evaluateStringExpression(this.commandTokens).then((function(_this) {
return function(command) {
switch(command) {
case 'connect':
pioRemoteActionHandler.connect(function() {
});
break;
case 'disconnect':
pioRemoteActionHandler.disconnect(function() {});
break;
default:
return __('Unknown Command');
}
};
})(this));
};
return PioRemoteActionHandler;
})(env.actions.ActionHandler);
pioRemoteActionHandler = new PioRemoteActionHandler;
module.exports.PioRemoteActionProvider = PioRemoteActionProvider;
return pioRemotePlugin;
};
The exception:
20:23:17.715 [pimatic] Listening for HTTP-request on port 80...
20:23:25.059 [pimatic-my-plugin] Client is undefined, establish new connection...
20:23:25.095 [pimatic] rule connect error executing an action: Array.isArray result
20:23:25.096 [pimatic] AssertionError: Array.isArray result
20:23:25.096 [pimatic]> at /home/psc/pimatic-dev/node_modules/pimatic/lib/rules.coffee:897:15
20:23:25.096 [pimatic]> at tryCatcher (/home/psc/pimatic-dev/node_modules/pimatic/node_modules/bluebird/js/main/util.js:26:23)
20:23:25.096 [pimatic]> at Promise._settlePromiseFromHandler (/home/psc/pimatic-dev/node_modules/pimatic/node_modules/bluebird/js/main/promise.js:507:31)
20:23:25.096 [pimatic]> at Promise._settlePromiseAt (/home/psc/pimatic-dev/node_modules/pimatic/node_modules/bluebird/js/main/promise.js:581:18)
20:23:25.096 [pimatic]> at Async._drainQueue (/home/psc/pimatic-dev/node_modules/pimatic/node_modules/bluebird/js/main/async.js:128:12)
20:23:25.096 [pimatic]> at Async._drainQueues (/home/psc/pimatic-dev/node_modules/pimatic/node_modules/bluebird/js/main/async.js:133:10)
20:23:25.096 [pimatic]> at Async.drainQueues (/home/psc/pimatic-dev/node_modules/pimatic/node_modules/bluebird/js/main/async.js:15:14)
20:23:25.096 [pimatic]> at process._tickDomainCallback (node.js:459:13)
20:23:25.113 [pimatic-my-plugin] Connected
20:23:44.070 [pimatic-my-plugin] Closing telnet session...
20:23:44.071 [pimatic-my-plugin] done
20:23:44.075 [pimatic] rule disconnect error executing an action: Array.isArray result
20:23:44.077 [pimatic] AssertionError: Array.isArray result
20:23:44.077 [pimatic]> at /home/psc/pimatic-dev/node_modules/pimatic/lib/rules.coffee:897:15
20:23:44.077 [pimatic]> at tryCatcher (/home/psc/pimatic-dev/node_modules/pimatic/node_modules/bluebird/js/main/util.js:26:23)
20:23:44.077 [pimatic]> at Promise._settlePromiseFromHandler (/home/psc/pimatic-dev/node_modules/pimatic/node_modules/bluebird/js/main/promise.js:507:31)
20:23:44.077 [pimatic]> at Promise._settlePromiseAt (/home/psc/pimatic-dev/node_modules/pimatic/node_modules/bluebird/js/main/promise.js:581:18)
20:23:44.077 [pimatic]> at Async._drainQueue (/home/psc/pimatic-dev/node_modules/pimatic/node_modules/bluebird/js/main/async.js:128:12)
20:23:44.077 [pimatic]> at Async._drainQueues (/home/psc/pimatic-dev/node_modules/pimatic/node_modules/bluebird/js/main/async.js:133:10)
20:23:44.077 [pimatic]> at Async.drainQueues (/home/psc/pimatic-dev/node_modules/pimatic/node_modules/bluebird/js/main/async.js:15:14)
20:23:44.077 [pimatic]> at process._tickDomainCallback (node.js:459:13)
^C20:23:46.447 [pimatic] Flushing database to disk, please wait...
20:23:46.557 [pimatic] Flushing database to disk, please wait... Done.
20:23:46.558 [pimatic] exiting...
Best regards,
Paul