UNPKG

node-red-contrib-brads-i2c-nodes

Version:
268 lines (231 loc) 9.14 kB
/** * Created by brad on 3/27/17. */ module.exports = function (RED) { "use strict"; // NPM Imports const i2c = require('i2c-bus'); // Local Imports const Util = require('./util.js'); // AAA // 210 // === (A2, A1, A0 bits) const MCP9808Address000 = 0x18; const MCP9808Address001 = 0x19; const MCP9808Address010 = 0x1a; const MCP9808Address011 = 0x1b; const MCP9808Address100 = 0x1c; const MCP9808Address101 = 0x1d; const MCP9808Address110 = 0x1e; const MCP9808Address111 = 0x1f; const REGISTER_CONFIGURATION = 0x01; const REGISTER_ALERT_TEMP_UPPER_BOUNDARY = 0x02; const REGISTER_ALERT_TEMP_LOWER_BOUNDARY = 0x03; const REGISTER_CRITICAL_TEMP_TRIP = 0x04; const REGISTER_TEMPERATURE = 0x05; const REGISTER_MANUFACTURER_ID = 0x06; const REGISTER_DEVICE_ID = 0x07; const REGISTER_RESOLUTION = 0x08; const RESOLUTIONS = new Map(); RESOLUTIONS.set('0', { display: '+/- 0.5 \u2103', displayF: '+/- 0.9 \u2109', timeMs: 30, value: 0.5, decimalPlaces: 1, commandByte: 0 }); RESOLUTIONS.set('1', { display: '+/- 0.25 \u2103', displayF: '+/- 0.45 \u2109', timeMs: 65, value: 0.25, decimalPlaces: 2, commandByte: 1 }); RESOLUTIONS.set('2', { display: '+/- 0.125 \u2103', displayF: '+/- 0.225 \u2109', timeMs: 130, value: 0.125, decimalPlaces: 3, commandByte: 2 }); RESOLUTIONS.set('3', { display: '+/- 0.0625 \u2103', displayF: '+/- 0.1125 \u2109', timeMs: 250, value: 0.0625, decimalPlaces: 4, commandByte: 3 }); // default const dateFormatOptions = { year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: false, timeZone: 'America/New_York' }; let i2cBus = undefined; function mcp9808(config) { RED.nodes.createNode(this, config); let BigNumber = require('bignumber.js'); let node = this; // 1. process config - pull parameter values // 2. initialize sensor // 3. update node.status and begin measuring if wired to. // 1. Process Config node.debugMode = (config && config.debugMode); function debug(msg) { if (node.debugMode) { node.log(msg); } } debug(JSON.stringify(config)); node.address = config.address; if (node.address < MCP9808Address000 || node.address > MCP9808Address111) { node.error(`${node.address} is a bad address - check config.`); node.status({fill: "red", shape: "ring", text: `${node.address} is a bad address - check config.`}); } node.name = `MCP9808 @ 0x${node.address.toString(16)}`; node.resolution = (config && config.resolution) ? RESOLUTIONS.get(config.resolution) : RESOLUTIONS.get('3'); node.units = (config && config.units) ? config.units : 'F'; if (node.debugMode) { node.log(`mcp9808 configuration`); node.log(`name -> ${node.name}`); node.log(`resolution -> ${JSON.stringify(node.resolution)}`); node.log(`address -> ${node.address}`); node.log(`units -> ${node.units}`); node.log(`debugMode -> ${node.debugMode}`); } this.on('deploy', (msg) => { debug(`deploy event received msg -> ${msg}`); }); // 2. Initialize Sensor node.ready = false; node.status({fill: "green", shape: "ring", text: "mcp9808 initializing"}); if (i2cBus == undefined) { // I2C Bus has to be open for device to work so open it synchronously i2cBus = i2c.openSync(1); if (!i2cBus) { node.error(`problem initializing i2c bus 1.`); node.status({fill: "red", shape: "ring", text: `problem initializing i2c bus 1.`}); } } let dp = (node.resolution) ? node.resolution.decimalPlaces : 4; BigNumber.config({DECIMAL_PLACES: dp}); let ip1 = new Promise((resolve, reject) => { i2cBus.readWord(node.address, REGISTER_DEVICE_ID, (err, wordBytes) => { if (err) { let errMsg = `mcp9808 get device ID error: ${err}`; node.status({fill: "red", shape: "ring", text: errMsg}); reject(errMsg); } else { // node.deviceId = ((wordBytes & 0xff00) >> 8); // TODO - on 4/22/2017, the wordBytes seem to be reverse from what I've seen to this point... // TODO - pull ManufacturerId for comparison - should be 0x0054 node.deviceId = wordBytes; debug(`wordBytes => 0x${wordBytes.toString(16)}, B${wordBytes.toString(2)}, deviceId -> ${node.deviceId}`); // if (node.deviceId != 0x04) { // reject(`Bad deviceId (${node.deviceId}) at address 0x${node.address.toString(16)}.`); // } resolve(`Device ID: 0x${node.deviceId.toString(16)}`); } }); }); let ip2 = new Promise((resolve, reject) => { i2cBus.writeByte(node.address, REGISTER_RESOLUTION, node.resolution.commandByte, (err) => { if (err) { let errMsg = `mcp9808 set resolution error: ${err}`; node.status({fill: "red", shape: "ring", text: errMsg}); reject(errMsg); } else { resolve(`mcp9808 resolution set`); } }); }); Promise.all([ip1, ip2]).then((resolve) => { // node.status({fill: "green", shape: "dot", text: "mcp9808 ready"}); node.ready = true; node.emit('sensor_ready', resolve); }, (reject) => { node.status({fill: "red", shape: "ring", text: "mcp9808 check configuration"}); node.error(`${reject}: node.ready -> ${node.ready}: , node.deviceId -> ${node.deviceId}`); }); node.on('sensor_ready', (msg) => { debug(`sensor_ready: msg -> ${msg}`); node.status({fill: "green", shape: "dot", text: "mcp9808 ready"}); }); this.on('input', (msg) => { if (node.ready) { let command = msg.payload; // One of: measure, set_config, get_config, ... TODO - add other input types support if (command) { if ("measure" === command) { let mp1 = new Promise((resolve, reject) => { i2cBus.writeByte(node.address, REGISTER_TEMPERATURE, 0x01, (err) => { setTimeout( () => { if (err) { reject(`mcp9808 set measure temperature error: ${err}`); } else { let buffer = new Uint8Array(2); i2cBus.readI2cBlock(node.address, REGISTER_TEMPERATURE, buffer.length, buffer, (err, bytesRead, buffer) => { if (err) { reject( `mcp9808 get temperature bytes error: ${err}` ); } else { let upperByte = buffer[0] & 0x1f; // ignore other flags let lowerByte = buffer[1]; let posNeg = (upperByte & 0x10) ? -1 : 1; let temperature = new BigNumber(lowerByte).div(16).plus(upperByte * 16); if (posNeg === -1) { upperByte = upperByte & 0x0f; temperature = temperature.neg().plus(256); } let temperatureF = temperature.times(1.8).plus(32.0); let timestamp = new Date().toLocaleString('en-US', dateFormatOptions); debug("temperatureF -> " + temperatureF); resolve( { 'name': node.name, 'timestamp': timestamp, 'Tc': Util.roundValue(temperature), 'Tf': Util.roundValue(temperatureF) } ); } }); } }, node.resolution.timeMs); }); }).then( (resolve) => { debug(JSON.stringify(resolve)); //{ 'name': node.name, 'timestamp': timestamp, 'Tc':Util.roundValue( temperature ), 'Tf':Util.roundValue(temperatureF) } let thingShadow = { state: { "reported": { "device": "sensor", "name": "mcp9808", "temperature": resolve.Tf, "temperatureUnits": "degrees Fahrenheit", "deviceResolution": node.resolution.displayF, "timestamp": resolve.timestamp } } }; node.send([ {topic: 'mcp9808', payload: resolve}, {topic: 'mcp9808', payload: thingShadow} ]); }, (reject) => { node.status({fill: "red", shape: "dot", text: reject}); node.error( reject ); } ); } else if ("some_other_tbd_command" == command) { // TODO - respond to another command } else { // no op } } } }); } RED.nodes.registerType("mcp9808", mcp9808); }