ocoge/local_modules/@ocogeclub/bme280/BME280.js

270 lines
8.6 KiB
JavaScript
Raw Normal View History

'use strict';
// const { strictEqual } = require('assert');
class BME280 {
constructor(options) {
this.pi = require('@ocogeclub/lgpio');
this.i2cBusNo = (options && options.hasOwnProperty('i2cBusNo')) ? options.i2cBusNo : 1;
this.i2cAddress = (options && options.hasOwnProperty('i2cAddress')) ? options.i2cAddress : BME280.BME280_DEFAULT_I2C_ADDRESS();
this.i2cHand = this.pi.i2c_open(this.i2cBusNo, this.i2cAddress);
this.I2C_ADDRESS_B = 0x76;
this.I2C_ADDRESS_A = 0x77;
this.CHIP_ID = 0x58;
this.REGISTER_DIG_T1 = 0x88;
this.REGISTER_DIG_T2 = 0x8A;
this.REGISTER_DIG_T3 = 0x8C;
this.REGISTER_DIG_P1 = 0x8E;
this.REGISTER_DIG_P2 = 0x90;
this.REGISTER_DIG_P3 = 0x92;
this.REGISTER_DIG_P4 = 0x94;
this.REGISTER_DIG_P5 = 0x96;
this.REGISTER_DIG_P6 = 0x98;
this.REGISTER_DIG_P7 = 0x9A;
this.REGISTER_DIG_P8 = 0x9C;
this.REGISTER_DIG_P9 = 0x9E;
this.REGISTER_DIG_H1 = 0xA1;
this.REGISTER_DIG_H2 = 0xE1;
this.REGISTER_DIG_H3 = 0xE3;
this.REGISTER_DIG_H4 = 0xE4;
this.REGISTER_DIG_H5 = 0xE5;
this.REGISTER_DIG_H6 = 0xE7;
this.REGISTER_CHIPID = 0xD0;
this.REGISTER_RESET = 0xE0;
this.REGISTER_CONTROL_HUM = 0xF2;
this.REGISTER_CONTROL = 0xF4;
this.REGISTER_PRESSURE_DATA = 0xF7;
this.REGISTER_TEMP_DATA = 0xFA;
this.REGISTER_HUMIDITY_DATA = 0xFD;
}
init() {
let r;
r = this.pi.i2c_write_byte_data(this.i2cHand, this.REGISTER_CHIPID, 0);
if (r < 0) return r;
let chipId = this.pi.i2c_read_byte_data(this.i2cHand, this.REGISTER_CHIPID);
if (chipId !== BME280.CHIP_ID_BME280() &&
chipId !== BME280.CHIP_ID1_BMP280() &&
chipId !== BME280.CHIP_ID2_BMP280() &&
chipId !== BME280.CHIP_ID3_BMP280()) {
return `Unexpected BMx280 chip ID: 0x${chipId.toString(16).toUpperCase()}`;
}
// console.log(`Found BMx280 chip ID 0x${chipId.toString(16).toUpperCase()} on bus i2c-${this.i2cBusNo}, address 0x${this.i2cAddress.toString(16).toUpperCase()}`);
this.loadCalibration((err) => {
if (err) {
return err;
}
// Humidity 16x oversampling
//
let r = this.pi.i2c_write_byte_data(this.i2cHand, this.REGISTER_CONTROL_HUM, 0b00000101);
if (r < 0) return `Humidity 16x oversampling error: ${r}`;
// Temperture/pressure 16x oversampling, normal mode
//
r = this.pi.i2c_write_byte_data(this.i2cHand, this.REGISTER_CONTROL, 0b10110111);
if (r < 0) return `Temperture/pressure 16x oversampling error: ${r}`;
return 0;
});
}
// reset()
//
// Perform a power-on reset procedure. You will need to call init() following a reset()
//
reset() {
const POWER_ON_RESET_CMD = 0xB6;
let r = this.pi.i2c_write_byte_data(this.i2cHand, this.REGISTER_RESET, POWER_ON_RESET_CMD);
if (r < 0) return `cannot power-on reset: ${r}`;
else return 0;
}
// cancel()
//
// Cancels the sensor and releases resources.
//
cancel() {
if (this.i2cHand >= 0) {
this.pi.i2c_close(this.i2cHand);
this.i2cHand = 0;
}
}
readSensorData() {
if (!this.cal) {
return 'You must first call bme280.init()';
}
// Grab temperature, humidity, and pressure in a single read
//
let [count, buffer] = this.pi.i2c_read_i2c_block_data(this.i2cHand, this.REGISTER_PRESSURE_DATA, 8);
if (!buffer) return `couldn't grab data`;
// Temperature (temperature first since we need t_fine for pressure and humidity)
//
let adc_T = BME280.uint20(buffer[3], buffer[4], buffer[5]);
let tvar1 = ((((adc_T >> 3) - (this.cal.dig_T1 << 1))) * this.cal.dig_T2) >> 11;
let tvar2 = (((((adc_T >> 4) - this.cal.dig_T1) * ((adc_T >> 4) - this.cal.dig_T1)) >> 12) * this.cal.dig_T3) >> 14;
let t_fine = tvar1 + tvar2;
let temperature_C = ((t_fine * 5 + 128) >> 8) / 100;
// Pressure
//
let adc_P = BME280.uint20(buffer[0], buffer[1], buffer[2]);
let pvar1 = t_fine / 2 - 64000;
let pvar2 = pvar1 * pvar1 * this.cal.dig_P6 / 32768;
pvar2 = pvar2 + pvar1 * this.cal.dig_P5 * 2;
pvar2 = pvar2 / 4 + this.cal.dig_P4 * 65536;
pvar1 = (this.cal.dig_P3 * pvar1 * pvar1 / 524288 + this.cal.dig_P2 * pvar1) / 524288;
pvar1 = (1 + pvar1 / 32768) * this.cal.dig_P1;
let pressure_hPa = 0;
if (pvar1 !== 0) {
let p = 1048576 - adc_P;
p = ((p - pvar2 / 4096) * 6250) / pvar1;
pvar1 = this.cal.dig_P9 * p * p / 2147483648;
pvar2 = p * this.cal.dig_P8 / 32768;
p = p + (pvar1 + pvar2 + this.cal.dig_P7) / 16;
pressure_hPa = p / 100;
}
// Humidity (available on the BME280, will be zero on the BMP280 since it has no humidity sensor)
//
let adc_H = BME280.uint16(buffer[6], buffer[7]);
let h = t_fine - 76800;
h = (adc_H - (this.cal.dig_H4 * 64 + this.cal.dig_H5 / 16384 * h)) *
(this.cal.dig_H2 / 65536 * (1 + this.cal.dig_H6 / 67108864 * h * (1 + this.cal.dig_H3 / 67108864 * h)));
h = h * (1 - this.cal.dig_H1 * h / 524288);
let humidity = (h > 100) ? 100 : (h < 0 ? 0 : h);
return {
temperature_C: temperature_C,
humidity: humidity,
pressure_hPa: pressure_hPa
};
}
loadCalibration(callback) {
let [count, buffer] = this.pi.i2c_read_i2c_block_data(this.i2cHand, this.REGISTER_DIG_T1, 24);
// for (let i = 0; i < 24; i++) console.log(parseInt(buffer[i], 16));
if (buffer) {
let h1 = this.pi.i2c_read_byte_data(this.i2cHand, this.REGISTER_DIG_H1);
let h2 = this.pi.i2c_read_word_data(this.i2cHand, this.REGISTER_DIG_H2);
let h3 = this.pi.i2c_read_byte_data(this.i2cHand, this.REGISTER_DIG_H3);
let h4 = this.pi.i2c_read_byte_data(this.i2cHand, this.REGISTER_DIG_H4);
let h5 = this.pi.i2c_read_byte_data(this.i2cHand, this.REGISTER_DIG_H5);
let h5_1 = this.pi.i2c_read_byte_data(this.i2cHand, this.REGISTER_DIG_H5 + 1);
let h6 = this.pi.i2c_read_byte_data(this.i2cHand, this.REGISTER_DIG_H6);
this.cal = {
dig_T1: BME280.uint16(buffer[1], buffer[0]),
dig_T2: BME280.int16(buffer[3], buffer[2]),
dig_T3: BME280.int16(buffer[5], buffer[4]),
dig_P1: BME280.uint16(buffer[7], buffer[6]),
dig_P2: BME280.int16(buffer[9], buffer[8]),
dig_P3: BME280.int16(buffer[11], buffer[10]),
dig_P4: BME280.int16(buffer[13], buffer[12]),
dig_P5: BME280.int16(buffer[15], buffer[14]),
dig_P6: BME280.int16(buffer[17], buffer[16]),
dig_P7: BME280.int16(buffer[19], buffer[18]),
dig_P8: BME280.int16(buffer[21], buffer[20]),
dig_P9: BME280.int16(buffer[23], buffer[22]),
dig_H1: h1,
dig_H2: h2,
dig_H3: h3,
dig_H4: (h4 << 4) | (h5 & 0xF),
dig_H5: (h5_1 << 4) | (h5 >> 4),
dig_H6: h6
};
// console.log('BME280 cal = ' + JSON.stringify(this.cal, null, 2));
callback();
}
}
static BME280_DEFAULT_I2C_ADDRESS() {
return 0x77;
}
static CHIP_ID1_BMP280() {
return 0x56;
}
static CHIP_ID2_BMP280() {
return 0x57;
}
static CHIP_ID3_BMP280() {
return 0x58;
}
static CHIP_ID_BME280() {
return 0x60;
}
static int16(msb, lsb) {
let val = BME280.uint16(msb, lsb);
return val > 32767 ? (val - 65536) : val;
}
static uint16(msb, lsb) {
return msb << 8 | lsb;
}
static uint20(msb, lsb, xlsb) {
return ((msb << 8 | lsb) << 8 | xlsb) >> 4;
}
static convertCelciusToFahrenheit(c) {
return c * 9 / 5 + 32;
}
static convertHectopascalToInchesOfMercury(hPa) {
return hPa * 0.02952998751;
}
static convertMetersToFeet(m) {
return m * 3.28084;
}
static calculateHeatIndexCelcius(temperature_C, humidity) {
return -8.784695 + 1.61139411 * temperature_C + 2.33854900 * humidity +
-0.14611605 * temperature_C * humidity + -0.01230809 * Math.pow(temperature_C, 2) +
-0.01642482 * Math.pow(humidity, 2) + 0.00221173 * Math.pow(temperature_C, 2) * humidity +
0.00072546 * temperature_C * Math.pow(humidity, 2) +
-0.00000358 * Math.pow(temperature_C, 2) * Math.pow(humidity, 2);
}
static calculateDewPointCelcius(temperature_C, humidity) {
return 243.04 * (Math.log(humidity / 100.0) + ((17.625 * temperature_C) / (243.04 + temperature_C))) /
(17.625 - Math.log(humidity / 100.0) - ((17.625 * temperature_C) / (243.04 + temperature_C)));
}
static calculateAltitudeMeters(pressure_hPa, seaLevelPressure_hPa) {
if (!seaLevelPressure_hPa) {
seaLevelPressure_hPa = 1013.25;
}
return (1.0 - Math.pow(pressure_hPa / seaLevelPressure_hPa, (1 / 5.2553))) * 145366.45 * 0.3048;
}
}
module.exports = BME280;
/*
* This code was forked from skylarstein's bme280-sensor: https://github.com/skylarstein/bme280-sensor
*/