Comparing version 0.0.2 to 0.0.3
var Heatmiser = require("./lib/heatmiser"); | ||
var hm = new Heatmiser("localhost", "1606"); | ||
var hm = new Heatmiser("192.168.1.80", 1606); | ||
var log = function(data) { | ||
hm.on('success', function(data) { | ||
console.log(data); | ||
}); | ||
hm.on('error', function(data) { | ||
console.log(data); | ||
}); | ||
hm.read_device(); | ||
var dcb; | ||
// set frost mode | ||
dcb = { | ||
runmode: 'frost' | ||
} | ||
hm.read_device(log,log); | ||
hm.write_device(dcb); | ||
// set current date and time | ||
var dcb = { | ||
dcb = { | ||
time: new Date() | ||
} | ||
hm.write_device(dcb, log, log); | ||
hm.write_device(dcb); |
var net = require('net'); | ||
var util = require("util"); | ||
var events = require('events'); | ||
function Heatmiser(host, pin, port) { | ||
function Heatmiser(host, pin, port, model) { | ||
this.host = host; | ||
this.pin = pin; | ||
this.port = (typeof port === "undefined") ? 8068 : port; | ||
this.model = null; | ||
this.model = (typeof model === "undefined") ? null : model; | ||
events.EventEmitter.call(this); | ||
} | ||
util.inherits(Heatmiser, events.EventEmitter); | ||
var crc16 = function(buf){ | ||
@@ -35,3 +40,3 @@ // Thanks to http://code.google.com/p/heatmiser-wifi/ for the algorithm | ||
var parse_dcb = function(dcb_buf){ | ||
this.model = ['DT', 'DT-E', 'PRT', 'PRT-E', 'PRTHW'][dcb_buf.readUInt8(4)]; | ||
var model = ['DT', 'DT-E', 'PRT', 'PRT-E', 'PRTHW'][dcb_buf.readUInt8(4)]; | ||
var version = dcb_buf.readUInt8(3); | ||
@@ -105,3 +110,3 @@ var length = dcb_buf.readUInt16LE(0); | ||
// Construct an arbitrary thermostat command | ||
Heatmiser.prototype.command = function(operation, success, error, data) { | ||
Heatmiser.prototype.command = function(operation, data, callback) { | ||
len = 7 + data.length; | ||
@@ -122,33 +127,30 @@ var buf = new Buffer(5+data.length+2); | ||
client.on('data', function(data) { | ||
success(data); | ||
var obj = parse_response(data); | ||
this.model = obj.dcb.model; | ||
// if callback is set don't emit an event | ||
if (typeof callback === 'undefined') { | ||
this.emit('success', obj); | ||
} else { | ||
callback(obj); | ||
} | ||
client.end(); | ||
}); | ||
}.bind(this)); | ||
client.on('timeout', function(e){ | ||
client.end(); | ||
error((typeof e === 'undefined') ? new Error("Timed out") : e); | ||
}); | ||
this.emit('error', (typeof e === 'undefined') ? new Error("Timed out") : e); | ||
}.bind(this)); | ||
client.on('error', function(e){ | ||
client.end(); | ||
error(e); | ||
}); | ||
this.emit('error', e); | ||
}.bind(this)); | ||
} | ||
Heatmiser.prototype.read_device = function(success, error){ | ||
var check_response = function(data) { | ||
success(parse_response(data)); | ||
} | ||
this.command(0x93, check_response, error, new Buffer([0x00, 0x00, 0xFF, 0xFF])); | ||
Heatmiser.prototype.read_device = function(callback){ | ||
this.command(0x93, new Buffer([0x00, 0x00, 0xFF, 0xFF]), callback); | ||
} | ||
Heatmiser.prototype.write_device = function(data, success, error) { | ||
Heatmiser.prototype.write_device = function(data) { | ||
var self = this; | ||
var write = function() { | ||
var items; | ||
try { | ||
items = status_to_dcb(this.model, data); | ||
} catch(e) { | ||
error(e); | ||
return; | ||
} | ||
var do_write = function(items) { | ||
var buf = Buffer.concat(items); | ||
@@ -160,14 +162,11 @@ // First byte to send is the number of items | ||
var check_response = function(data) { | ||
success(parse_response(data)); | ||
} | ||
self.command(0xa3, buffer); | ||
} | ||
this.command(0xa3, check_response, error, buffer); | ||
}.bind(this); | ||
// ensure the model is set in the first call to write | ||
if (this.model == null) { | ||
this.read_device(write, error); | ||
this.read_device(function(){ | ||
status_to_dcb(this.model, data, do_write); | ||
}); | ||
} else { | ||
write(); | ||
status_to_dcb(this.model, data, do_write); | ||
} | ||
@@ -211,3 +210,3 @@ } | ||
var status_to_dcb = function(model, data) { | ||
var status_to_dcb = function(model, data, callback) { | ||
var items = []; | ||
@@ -243,19 +242,23 @@ | ||
// Run mode (controls heating) | ||
if (model != 'TM1') | ||
if (model != 'TM1') { | ||
items.push(dcb_entry(23, data[key] == 'frost' ? 1 : 0)); | ||
} | ||
break; | ||
case 'awaymode': | ||
// Away mode (controls hot water) | ||
if (model.match(/(HW|TM1)$/)) | ||
if (model.match(/(HW|TM1)$/)) { | ||
items.push(dcb_entry(31, data[key] == 'away' ? 1 : 0)); | ||
} | ||
break; | ||
case 'frostprotect': | ||
// Frost protection (temperature only, cannot disable) | ||
if ('target' in data[key]) | ||
if ('target' in data[key]) { | ||
items.push(dcb_entry(17, data[key]['target'])); | ||
} | ||
break; | ||
case 'floorlimit': | ||
// Floor limit (temperature only, cannot disable) | ||
if (model.match(/-E$/) && ('floormax' in data[key])) | ||
if (model.match(/-E$/) && ('floormax' in data[key])) { | ||
items.push(dcb_entry(19, data[key]['floormax'])); | ||
} | ||
break; | ||
@@ -265,8 +268,10 @@ case 'heating': | ||
if (model != 'TM1') { | ||
if ('target' in data[key]) | ||
if ('target' in data[key]) { | ||
items.push(dcb_entry(18, data[key]['target'])); | ||
if ('hold' in data[key]) | ||
} | ||
if ('hold' in data[key]) { | ||
var buf = new Buffer(2); | ||
buf.writeUInt16LE(data[key]['hold'], 0); | ||
items.push(dcb_entry(32, buf)); | ||
} | ||
} | ||
@@ -277,10 +282,13 @@ break; | ||
if (model.match(/(HW|TM1)$/)) { | ||
if ('boost' in data[key]) | ||
if ('boost' in data[key]) { | ||
var buf = new Buffer(2); | ||
buf.writeUInt16LE(data[key]['boost'], 0); | ||
items.push(dcb_entry(25, buf)); | ||
if ('on' in data[key]) | ||
} | ||
if ('on' in data[key]) { | ||
items.push(dcb_entry(42, data[key]['on'] ? 1 : 2)); | ||
else | ||
} | ||
else { | ||
items.push(dcb_entry(42, 0)); | ||
} | ||
} | ||
@@ -294,3 +302,4 @@ break; | ||
if (days != days_expected) { | ||
throw new Error("Incorrect number of days specified for comfort levels program " + days + ". Expected " + days_expected); | ||
this.emit('error', "Incorrect number of days specified for comfort levels program " + days + ". Expected " + days_expected); | ||
return; | ||
} | ||
@@ -319,3 +328,4 @@ for (var day=0;day<days;day++) { | ||
if (days != days_expected) { | ||
throw new Error("Incorrect number of days specified for hot water control program " + days + ". Expected " + days_expected); | ||
this.emit('error', "Incorrect number of days specified for hot water control program " + days + ". Expected " + days_expected); | ||
return; | ||
} | ||
@@ -343,9 +353,9 @@ for (var day=0;day<days;day++) { | ||
// Feature 12 (16): $status->{config}->{progmode} | ||
throw new Error("Unsupported item for writing: " + key); | ||
this.emit('error', "Unsupported item for writing: " + key); | ||
return; | ||
} | ||
} | ||
return items; | ||
callback(items); | ||
} | ||
module.exports = Heatmiser; |
{ | ||
"name": "heatmiser", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"description": "A node.js app that talks to heatmiser wifi thermostats", | ||
@@ -5,0 +5,0 @@ "main": "lib/heatmiser.js", |
@@ -6,32 +6,38 @@ heatmiser-node | ||
Taken from Ben Pirt heatmiser-js and stripped to leave only the bits to interact with the thermostat | ||
https://github.com/bjpirt/heatmiser-js | ||
Credits | ||
* Ben Pirt for the reading functions in Node https://github.com/bjpirt/heatmiser-js | ||
* heatmiser-wifi Perl project for the overall ideas and algorithms https://code.google.com/p/heatmiser-wifi/ | ||
# Reading the thermostat status | ||
var hm = new Heatmiser('localhost', 1234); | ||
hm.read_device(function(success) { | ||
console.log(success); | ||
}, function(error) { | ||
console.log(error); | ||
hm.on('success', function(data) { | ||
console.log(data); | ||
}); | ||
hm.on('error', function(data) { | ||
console.log(data); | ||
}); | ||
hm.read_device(); | ||
# Writing to the thermostat | ||
var log = function(msg) { | ||
console.log(msg); | ||
var dcb; | ||
// set frost mode | ||
dcb = { | ||
runmode: 'frost' | ||
} | ||
hm.write_device(dcb); | ||
// set the time | ||
hm.write_device({ | ||
// set current date and time | ||
dcb = { | ||
time: new Date() | ||
}, log, log); | ||
} | ||
hm.write_device(dcb); | ||
// set the thermostat to frost mode | ||
hm.write_device({ | ||
runmode: 'frost' | ||
}, log, log); | ||
// set the thermostat hold | ||
hm.write_device({ | ||
dcb = { | ||
heating: { | ||
@@ -41,2 +47,3 @@ target: 20, // C | ||
} | ||
}, log, log); | ||
} | ||
hm.write_device(dcb); |
@@ -11,8 +11,4 @@ #!/usr/bin/env node | ||
// pin in hex little endian: 0xd204 | ||
var hm = new Heatmiser('localhost', 1234); | ||
var hm = new Heatmiser('localhost', 1234, 8068, 'PRT-E'); | ||
// common functions | ||
var success = function(data) { } | ||
var error = function(error) { throw error; } | ||
// stub sockets | ||
@@ -37,3 +33,4 @@ var stub = null; | ||
hm.model = 'PRT-E'; | ||
hm.on('success', function(data) {}); | ||
hm.on('error', function(error) { throw error; }); | ||
}) | ||
@@ -72,3 +69,3 @@ | ||
hm.read_device(success, error); | ||
hm.read_device(); | ||
}) | ||
@@ -99,3 +96,3 @@ | ||
hm.write_device(dcb, success, error); | ||
hm.write_device(dcb); | ||
}) | ||
@@ -122,3 +119,3 @@ | ||
hm.write_device(dcb, success, error); | ||
hm.write_device(dcb); | ||
}) | ||
@@ -154,3 +151,3 @@ | ||
hm.write_device(dcb, success, error); | ||
hm.write_device(dcb); | ||
}) | ||
@@ -157,0 +154,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
18090
456
48
2