i2c-sensor-am2315
Version:
I2C communication driver for the AOSONG AM2315 temperature and humidity sensor.
428 lines (390 loc) • 13.8 kB
JavaScript
;
// init prerequisites
var I2C = require("i2c-bus");
var CRC = require("crc");
// export the sensor driver
module.exports = function () {
return {
config: {
i2cBusNumber: 1,
deviceAddress: 0x5c,
readCmdRegister: 0x03,
debugMode: false,
},
setI2cBusNumber: function (bus) {
// set a custom bus number
this.config.i2cBusNumber = bus;
return true;
},
setDeviceAddress: function (address) {
// set a custom bus number
this.config.deviceAddress = address;
return true;
},
setReadCmdRegister: function (register) {
// set a custom bus number
this.config.readCmdRegister = register;
return true;
},
setDebugMode: function (mode) {
// set a custom bus number
this.config.debugMode = mode ? true : false;
return true;
},
calcTemperature: function (hiByte, loByte) {
// per http://www.switchdoc.com/wp-content/uploads/2015/07/AM2315-3.pdf
return (
Math.round(((((hiByte & 0x7f) << 8) + loByte) / 10 + 273.15) * 100) /
100
);
},
calcHumidity: function (hiByte, loByte) {
// per http://www.switchdoc.com/wp-content/uploads/2015/07/AM2315-3.pdf
return Math.round((((hiByte << 8) + loByte) / 10.0) * 100) / 100;
},
calcCRC: function (buffer) {
// per http://www.switchdoc.com/wp-content/uploads/2015/07/AM2315-3.pdf
return CRC.crc16modbus(
Buffer.from([
buffer[0],
buffer[1],
buffer[2],
buffer[3],
buffer[4],
buffer[5],
])
);
},
convertKelvinToCelsius: function (input) {
// output
var output;
// the entire output array was passed?
if (
input.temperature !== undefined &&
input.temperatureUnit !== undefined
) {
// clone the object so we leave the input intact
output = JSON.parse(JSON.stringify(input));
// is it a °F unit?
if (input.temperatureUnit === "°F") {
output.temperatureUnit = "K";
output.temperature = this.convertFahrenheitToKelvin(
input.temperature
);
}
// convert units
if (output.temperatureUnit === "K") {
output.temperatureUnit = "°C";
output.temperature =
Math.round((output.temperature - 273.15) * 100) / 100;
}
} else {
// convert value
output = Math.round((input - 273.15) * 100) / 100;
}
// return
return output;
},
convertKelvinToFahrenheit: function (input) {
// output
var output;
// the entire output array was passed?
if (
input.temperature !== undefined &&
input.temperatureUnit !== undefined
) {
// clone the object so we leave the input intact
output = JSON.parse(JSON.stringify(input));
// is it a °C unit?
if (input.temperatureUnit === "°C") {
output.temperatureUnit = "K";
output.temperature = this.convertCelsiusToKelvin(input.temperature);
}
// convert units
if (output.temperatureUnit === "K") {
output.temperatureUnit = "°F";
output.temperature =
Math.round(((output.temperature * 9) / 5 - 459.67) * 100) / 100;
}
} else {
// convert value
output = Math.round(((input * 9) / 5 - 459.67) * 100) / 100;
}
// return
return output;
},
convertFahrenheitToCelsius: function (input) {
// output
var output;
// the entire output array was passed?
if (
input.temperature !== undefined &&
input.temperatureUnit !== undefined
) {
// clone the object so we leave the input intact
output = JSON.parse(JSON.stringify(input));
// is it a K unit?
if (input.temperatureUnit === "K") {
output.temperatureUnit = "°F";
output.temperature = this.convertKelvinToFahrenheit(
input.temperature
);
}
// convert units
if (output.temperatureUnit === "°F") {
output.temperatureUnit = "°C";
output.temperature =
Math.round((output.temperature - 32) * (5 / 9) * 100) / 100;
}
} else {
// convert value
output = Math.round((input - 32) * (5 / 9) * 100) / 100;
}
// return
return output;
},
convertFahrenheitToKelvin: function (input) {
// output
var output;
// the entire output array was passed?
if (
input.temperature !== undefined &&
input.temperatureUnit !== undefined
) {
// clone the object so we leave the input intact
output = JSON.parse(JSON.stringify(input));
// is it a K unit?
if (input.temperatureUnit === "°C") {
output.temperatureUnit = "°F";
output.temperature = this.convertCelsiusToFahrenheit(
input.temperature
);
}
// convert units
if (output.temperatureUnit === "°F") {
output.temperatureUnit = "K";
output.temperature =
Math.round((output.temperature + 459.67) * (5 / 9) * 100) / 100;
}
} else {
// convert value
output = Math.round((input + 459.67) * (5 / 9) * 100) / 100;
}
// return
return output;
},
convertCelsiusToKelvin: function (input) {
// output
var output;
// the entire output array was passed?
if (
input.temperature !== undefined &&
input.temperatureUnit !== undefined
) {
// clone the object so we leave the input intact
output = JSON.parse(JSON.stringify(input));
// is it a K unit?
if (input.temperatureUnit === "°F") {
output.temperatureUnit = "°C";
output.temperature = this.convertCelsiusToFahrenheit(
input.temperature
);
}
// convert units
if (output.temperatureUnit === "°C") {
output.temperatureUnit = "K";
output.temperature =
Math.round((output.temperature + 273.15) * 100) / 100;
}
} else {
// convert value
output = Math.round((input + 273.15) * 100) / 100;
}
// return
return output;
},
convertCelsiusToFahrenheit: function (input) {
// output
var output;
// the entire output array was passed?
if (
input.temperature !== undefined &&
input.temperatureUnit !== undefined
) {
// clone the object so we leave the input intact
output = JSON.parse(JSON.stringify(input));
// is it a K unit?
if (input.temperatureUnit === "K") {
output.temperatureUnit = "°C";
output.temperature = this.convertKelvinToFahrenheit(
input.temperature
);
}
// convert units
if (output.temperatureUnit === "°C") {
output.temperatureUnit = "°F";
output.temperature =
Math.round((output.temperature * (9 / 5) + 32) * 100) / 100;
}
} else {
// convert value
output = Math.round((input * (9 / 5) + 32) * 100) / 100;
}
// return
return output;
},
read: function (callback) {
// this becomes that
var that = this;
// open the i2c bus
var i2cBus = I2C.open(that.config.i2cBusNumber, function (err) {
if (err) {
// log error
if (that.config.debugMode) {
console.error(err, err.stack);
}
// callback
callback(err, null);
} else {
// scan the bus so we can wake up the device
i2cBus.scan(function (err, devices) {
if (err) {
// log error
if (that.config.debugMode) {
console.error(err, err.stack);
}
// callback
callback(err, null);
} else {
// log info
if (that.config.debugMode) {
console.log(devices);
}
// wait ~900 us
setTimeout(function () {
// write to the bus (read command register, start register, and read 4 bytes
i2cBus.i2cWrite(
that.config.deviceAddress,
3,
Buffer.from([that.config.readCmdRegister, 0x00, 0x04]),
function (err, bytesWritten, buffer) {
if (err) {
// log error
if (that.config.debugMode) {
console.error(err, err.stack);
}
// callback
callback(err, null);
} else {
// log info
if (that.config.debugMode) {
console.log(buffer);
}
// wait 10 ms
setTimeout(function () {
// read from the bus
i2cBus.i2cRead(
that.config.deviceAddress,
8,
Buffer.alloc(8),
function (err, bytesRead, buffer) {
if (err) {
// log error
if (that.config.debugMode) {
console.error(err, err.stack);
}
// callback
callback(err, null);
} else {
// log info
if (that.config.debugMode) {
console.log(buffer);
}
// prepare output per http://www.switchdoc.com/wp-content/uploads/2015/07/AM2315-3.pdf
var output = {
temperature: that.calcTemperature(
buffer[4],
buffer[5]
),
temperatureUnit: "K",
humidity: that.calcHumidity(
buffer[2],
buffer[3]
),
humidityUnit: "%RH",
crcCheck:
(buffer[7] << 8) + buffer[6] ==
that.calcCRC(buffer),
validReading: false,
};
// perform a sanity check on the reading (CRC is valid)
if (output.crcCheck) {
// humidity is a percentage so 100 or less
if (
output.humidity >= 0 &&
output.humidity <= 100
) {
// temperature rating is -40 to 125 Celsius
if (
output.temperature >= 273.15 - 40 &&
output.temperature <= 273.15 + 125
) {
// zero temp and humidity is likely a reading error (null)
if (
!(
output.humidity == 0 &&
output.temperature == 273.15
)
) {
// mark reading as valid
output.validReading = true;
}
}
}
}
// close the bus
i2cBus.close(function (err) {
if (err) {
// log error
if (that.config.debugMode) {
console.error(err, err.stack);
}
// callback
callback(err, null);
} else {
// is the reading valid
if (output.validReading) {
// success callback
callback(null, output);
} else {
// error callback
callback("Reading is invalid", output);
}
}
});
}
}
);
}, 10);
}
}
);
}, 1);
}
});
}
});
},
readAsync: function () {
return new Promise((resolve, reject) => {
this.read((err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
},
};
};