thing-it-device-radio-thermostat
Version:
[thing-it-node] Device Plugin for Radio Thermostat WiFi Edition
550 lines (482 loc) • 15 kB
JavaScript
module.exports = {
metadata: {
plugin: "radioThermostat",
label: "Radio Thermostat",
role: "device",
family: "radioThermostat",
tangible: true,
deviceTypes: [],
services: [
{id: "incrementSetpoint", label: "Increment Setpoint"},
{id: "decrementSetpoint", label: "Decrement Setpoint"},
{id: "holdOn", label: "Hold On"},
{id: "holdOff", label: "Hold Off"},
{id: "holdToggle", label: "Hold Toggle"},
{
id: "changeMode", label: "Change Mode", parameters: [{
id: "mode", label: "Mode", type: {id: "string"}
}]
},
{id: "modeOff", label: "Mode Off"},
{id: "modeHeat", label: "Mode Heat"},
{id: "modeCool", label: "Mode Cool"},
{id: "modeAuto", label: "Mode Auto"},
{id: "changeFanMode", label: "Change Mode"},
{id: "fanModeAuto", label: "Fan Mode Auto"},
{id: "fanModeAutoCirculate", label: "Fan Mode Auto Circulate"},
{id: "fanModeOn", label: "Fan Mode On"},
],
state: [{
id: "mode", label: "Mode",
type: {
id: "string"
}
}, {
id: "operatingState", label: "Operating State",
type: {
id: "string"
}
}, {
id: "setpoint", label: "Setpoint",
type: {
id: "decimal"
}
}, {
id: "temperature", label: "Temperature",
type: {
id: "decimal"
}
}, {
id: "fanMode", label: "Fan Mode",
type: {
id: "string"
}
}, {
id: "fanState", label: "Fan State",
type: {
id: "string"
}
}, {
id: "hold", label: "Hold",
type: {
id: "boolean"
}
}, {
id: "override", label: "Overrride",
type: {
id: "boolean"
}
}],
configuration: [
{
label: "Host",
id: "host",
type: {
id: "string"
},
defaultValue: ""
},
{
label: "Name",
id: "name",
type: {
id: "name"
},
defaultValue: ""
},
{
label: "Update Interval",
id: "updateInterval",
type: {
id: "integer"
},
defaultValue: "3000"
},
]
},
create: function () {
return new RadioThermostat();
}
};
var q = require('q');
var request;
var tstat = "/tstat";
var updating = false;
/**
*
*/
function RadioThermostat() {
/**
*
*/
RadioThermostat.prototype.start = function () {
var deferred = q.defer();
this.state = {};
if (this.isSimulated()) {
this.state = {
temperature: 64,
mode: "HEAT",
setpoint: 64,
operatingState: "OFF",
fmode: "OFF",
hold: false,
override: false,
};
this.simulationInterval = setInterval(function () {
if (this.state.mode == "HEAT") {
if (this.state.operatingState == "OFF") {
this.state.temperature -= 0.5;
if (this.state.temperature < (this.state.setpoint - 1)) {
this.state.operatingState = "ON";
}
} else {
this.state.temperature += 0.5;
if (this.state.temperature > (this.state.setpoint + 1)) {
this.state.operatingState = "OFF";
}
}
} else {
if (this.state.operatingState == "ON") {
this.state.temperature -= 0.5;
if (this.state.temperature < (this.state.setpoint - 1)) {
this.state.operatingState = "OFF";
}
} else {
this.state.temperature += 0.5;
if (this.state.temperature > (this.state.setpoint + 1)) {
this.state.operatingState = "ON";
}
}
}
this.publishStateChange();
}.bind(this), 10000);
} else {
this.state = {};
this.pollState();
this.pollInterval = setInterval(function () {
this.pollState();
}.bind(this), 30000);
}
deferred.resolve();
return deferred.promise;
};
/**
*
*/
RadioThermostat.prototype.stop = function () {
var deferred = q.defer();
if (this.pollInterval) {
clearInterval(this.pollInterval);
}
if (this.simulationInterval) {
clearInterval(this.simulationInterval);
}
deferred.resolve();
return deferred.promise;
};
/**
*
*/
RadioThermostat.prototype.getState = function () {
return this.state;
};
/**
*
*/
RadioThermostat.prototype.setState = function (state) {
//TODO implement properly
};
RadioThermostat.prototype.pollState = function (callback) {
this.logDebug("Polling state for Radio Thermostat with name " + this.configuration.name + " located at " + this.configuration.host);
var url = "http://" + this.configuration.host + tstat;
if (!request) {
request = require('request');
}
request.get({
url: url
}, function (error, response, body) {
if (!updating) {
if (error) {
this.logError("Error communicating to Radio Thermostat.", error, body);
if (callback) {
callback(error, null);
}
}
else {
var thermostatState = JSON.parse(body);
this.state.temperature = thermostatState.temp;
switch (thermostatState.tmode) {
case 0:
this.state.mode = "OFF";
break;
case 1:
this.state.mode = "HEAT";
this.state.setpoint = thermostatState.t_heat;
break;
case 2:
this.state.mode = "COOL";
this.state.setpoint = thermostatState.t_cool;
break;
case 3:
this.state.mode = "AUTO";
if (thermostatState.t_heat) {
this.state.setpoint = thermostatState.t_heat;
} else if (thermostatState.t_cool) {
this.state.setpoint = thermostatState.t_cool;
}
break;
}
switch (thermostatState.tstate) {
case 0:
this.state.operatingState = "OFF";
break;
case 1:
this.state.operatingState = "HEAT";
break;
case 2:
this.state.operatingState = "COOL";
break;
}
switch (thermostatState.fmode) {
case 0:
this.state.fanMode = "AUTO";
break;
case 1:
this.state.fanMode = "AUTO/CIRCULATE";
break;
case 2:
this.state.fanMode = "ON";
break;
}
switch (thermostatState.fstate) {
case 0:
this.state.fanState = "AUTO";
break;
case 1:
this.state.fanState = "AUTO/CIRCULATE";
break;
case 2:
this.state.fanState = "ON";
break;
}
switch (thermostatState.hold) {
case 0:
this.state.hold = false;
break;
case 1:
this.state.hold = true;
break;
}
switch (thermostatState.override) {
case 0:
this.state.override = false;
break;
case 1:
this.state.override = true;
break;
}
this.logDebug("State", this.state);
this.publishStateChange();
}
} else {
this.logDebug("Ignoring stale update.");
}
}.bind(this));
}
/**
*
*/
RadioThermostat.prototype.setSetpoint = function (targetTemperature) {
this.state.setpoint = targetTemperature;
var body;
if (this.state.mode == "HEAT") {
body = '{"it_heat":' + targetTemperature + '}';
} else if (this.state.mode == "COOL") {
body = '{"it_cool":' + targetTemperature + '}';
} else {
// Cannot set temperature in auto mode
}
if (body) {
this.sendPostRequest(body);
}
}
/**
*
*/
RadioThermostat.prototype.incrementSetpoint = function () {
this.logDebug("Called incrementSetpoint()");
this.setSetpoint(this.state.setpoint + 1);
};
/**
*
*/
RadioThermostat.prototype.decrementSetpoint = function () {
this.logDebug("Called decrementSetpoint()");
this.setSetpoint(this.state.setpoint - 1);
};
/**
*
*/
RadioThermostat.prototype.setHold = function (hold) {
var body;
this.state.hold = hold;
if (hold) {
body = '{"hold":1}';
} else {
body = '{"hold":0}';
}
this.sendPostRequest(body);
}
/**
*
*/
RadioThermostat.prototype.holdOn = function () {
this.setHold(true);
}
/**
*
*/
RadioThermostat.prototype.holdOff = function () {
this.setHold(false);
}
/**
*
*/
RadioThermostat.prototype.holdToggle = function () {
if (this.state.hold) {
this.holdOff();
} else {
this.holdOn();
}
}
/**
*
* @param parameters
*/
RadioThermostat.prototype.changeFanMode = function (parameters) {
this.logDebug("ChangeFanMode called: ", parameters);
this.setFanMode(parameters.fanMode);
}
/**
*
*/
RadioThermostat.prototype.setFanMode = function (fanMode) {
var body;
this.state.mode = fanMode;
if (fanMode == "AUTO") {
body = '{"fmode":0}';
} else if (fanMode == "AUTO/CIRCULATE") {
body = '{"fmode":1}';
} else if (fanMode == "ON") {
body = '{"fmode":2}';
}
this.sendPostRequest(body);
}
/**
*
*/
RadioThermostat.prototype.fanModeAuto = function (fanMode) {
this.setFanMode("AUTO");
}
/**
*
*/
RadioThermostat.prototype.fanModeAutoCirculate = function (fanMode) {
this.setFanMode("AUTO/CIRCULATE");
}
/**
*
*/
RadioThermostat.prototype.fanModeOn = function (fanMode) {
this.setFanMode("ON");
}
/**
*
* @param parameters
*/
RadioThermostat.prototype.changeMode = function (parameters) {
this.logDebug("ChangeMode called: ", parameters);
this.setMode(parameters.mode);
}
/**
*
*/
RadioThermostat.prototype.setMode = function (mode) {
var body;
this.state.mode = mode;
if (mode == "OFF") {
body = '{"tmode":0}';
} else if (mode == "HEAT") {
body = '{"tmode":1}';
} else if (mode == "COOL") {
body = '{"tmode":2}';
} else if (mode == "AUTO") {
body = '{"tmode":3}';
} else {
this.logDebug("Unrecognized mode.", mode);
}
this.sendPostRequest(body);
}
/**
*
*/
RadioThermostat.prototype.modeOff = function () {
this.setMode("OFF");
}
/**
*
*/
RadioThermostat.prototype.modeHeat = function () {
this.setMode("HEAT");
}
/**
*
*/
RadioThermostat.prototype.modeCool = function () {
this.setMode("COOL");
}
/**
*
*/
RadioThermostat.prototype.modeAuto = function () {
this.setMode("AUTO");
}
/**
*
*/
RadioThermostat.prototype.sendPostRequest = function (body, callback) {
this.publishStateChange();
if (this.isSimulated()) {
} else {
updating = true;
var url = "http://" + this.configuration.host + tstat;
var updatingTimeout = setTimeout(function () {
updating = false;
}, 10000);
if (body) {
if (!request) {
request = require('request');
}
request.post({
url: url,
method: 'POST',
body: body
}, function (error, response, body) {
updating = false;
if (error) {
this.logError("Error communicating to Radio Thermostat.", error, body);
}
else {
this.pollState();
if (callback) {
callback(body);
}
}
if (updatingTimeout) {
clearTimeout(updatingTimeout);
}
}.bind(this));
}
}
}
};