node-red-contrib-ads1x15_i2c
Advanced tools
Comparing version 0.0.3 to 0.0.11
253
ads1x15.js
module.exports = function(RED) | ||
{ | ||
//Licensed under the Apache License, Version 2.0 | ||
@@ -9,88 +7,209 @@ // 2021 David L Burrows | ||
//"use strict"; | ||
//const i2c = require('i2c-bus'); | ||
module.exports = function(RED) { | ||
const ads1x15 = require('ads1x15'); | ||
function ads1x15MainFunction(config) | ||
{ | ||
function ads1x15MainFunction(config) { | ||
RED.nodes.createNode(this, config); | ||
var globalContext = this.context().global; | ||
var node = this; | ||
// config | ||
this.property = config.property||"payload"; | ||
this.chip = config.chip || "IC_ADS1115"; | ||
this.i2c_address = config.i2c_address || "ADDRESS_0x48"; | ||
this.channel = config.channel || "CHANNEL_0"; | ||
this.samplesPerSecond1 = config.samplesPerSecond1 || "SPS_128"; | ||
this.samplesPerSecond0 = config.samplesPerSecond0 || "SPS_920"; | ||
this.progGainAmp = config.progGainAmp || "PGA_4_096V"; | ||
this.i2c_device_number = parseInt(config.i2c_device_number, 10); | ||
this.chip = config.chip; | ||
this.i2c_address = config.i2c_address; | ||
this.inputsForChannel = config.inputsForChannel; | ||
this.singleEndedChannel0 = config.singleEndedChannel0; | ||
this.singleEndedChannel1 = config.singleEndedChannel1; | ||
this.singleEndedChannel2 = config.singleEndedChannel2; | ||
this.singleEndedChannel3 = config.singleEndedChannel3; | ||
this.differentialChannel0_1 = config.differentialChannel0_1; | ||
this.differentialChannel0_3 = config.differentialChannel0_3; | ||
this.differentialChannel1_3 = config.differentialChannel1_3; | ||
this.differentialChannel2_3 = config.differentialChannel2_3; | ||
this.samplesPerSecond1 = config.samplesPerSecond1; //tied to ads1115 | ||
this.samplesPerSecond0 = config.samplesPerSecond0; //tied to ads1015 | ||
this.progGainAmp = config.progGainAmp; | ||
var dply_rdy = true; | ||
//FORMAT | ||
//convert hexadec i2c chip and address to a number | ||
const number_of_chip = Number(this.chip); | ||
var format_number_of_chip; | ||
var format_samplesPerSeconds; | ||
if (number_of_chip === 1) { | ||
format_number_of_chip = 'ads1115'; | ||
format_samplesPerSeconds = Number(this.samplesPerSecond1); | ||
} | ||
else { | ||
format_number_of_chip = 'ads1015'; | ||
format_samplesPerSeconds = Number(this.samplesPerSecond0); | ||
} | ||
const number_of_i2c_address = Number(this.i2c_address); | ||
const format_number_of_i2c_address = this.i2c_address; | ||
const format_i2c_device_number = '/dev/i2c-' + this.i2c_device_number.toString(); | ||
const format_inputsForChannel = this.inputsForChannel; | ||
const format_progGainAmp = Number(this.progGainAmp); | ||
//populate channels_array_of_objects | ||
var channels_array_of_objects = []; | ||
if (format_inputsForChannel === 'singleEnded') { | ||
if (this.singleEndedChannel0 === true || this.singleEndedChannel1 === true || this.singleEndedChannel2 === true || this.singleEndedChannel3 === true) { | ||
if (this.singleEndedChannel0 === true) { | ||
channels_array_of_objects.push({channel: 0, programmable_gain_amplifier: format_progGainAmp, samples_per_second: format_samplesPerSeconds}); | ||
} | ||
if (this.singleEndedChannel1 === true) { | ||
channels_array_of_objects.push({channel: 1, programmable_gain_amplifier: format_progGainAmp, samples_per_second: format_samplesPerSeconds}); | ||
} | ||
if (this.singleEndedChannel2 === true) { | ||
channels_array_of_objects.push({channel: 2, programmable_gain_amplifier: format_progGainAmp, samples_per_second: format_samplesPerSeconds}); | ||
} | ||
if (this.singleEndedChannel3 === true) { | ||
channels_array_of_objects.push({channel: 3, programmable_gain_amplifier: format_progGainAmp, samples_per_second: format_samplesPerSeconds}); | ||
} | ||
} | ||
else { | ||
this.warn("No Single Ended Channels Selected: Please Select a Channel"); | ||
dply_rdy = "No Single Ended Channels Selected: Please Select a Channel"; | ||
} | ||
} | ||
if (format_inputsForChannel === 'differential') { | ||
if (this.differentialChannel0_1 === true || this.differentialChannel0_3 === true || this.differentialChannel1_3 === true || this.differentialChannel2_3 === true) { | ||
if (this.differentialChannel0_1 === true) { | ||
channels_array_of_objects.push({channelPositive: 0, channelNegative: 1, programmable_gain_amplifier: format_progGainAmp, samples_per_second: format_samplesPerSeconds}); | ||
} | ||
if (this.differentialChannel0_3 === true) { | ||
channels_array_of_objects.push({channelPositive: 0, channelNegative: 3, programmable_gain_amplifier: format_progGainAmp, samples_per_second: format_samplesPerSeconds}); | ||
} | ||
if (this.differentialChannel1_3 === true) { | ||
channels_array_of_objects.push({channelPositive: 1, channelNegative: 3, programmable_gain_amplifier: format_progGainAmp, samples_per_second: format_samplesPerSeconds}); | ||
} | ||
if (this.differentialChannel2_3 === true) { | ||
channels_array_of_objects.push({channelPositive: 2, channelNegative: 3, programmable_gain_amplifier: format_progGainAmp, samples_per_second: format_samplesPerSeconds}); | ||
} | ||
} | ||
else { | ||
this.warn("No Differential Channels Selected: Please Select a Channel"); | ||
dply_rdy = "No Differential Channels Selected: Please Select a Channel"; | ||
} | ||
} | ||
//clear status icon if one is hanging about wehn you deploy the node | ||
node.status({}); | ||
//Function to Clear user notices, used for timmer | ||
var status_clear = function() | ||
{ | ||
//clear status icon | ||
node.status({}); | ||
var status_clear = function() { | ||
//clear status icon | ||
node.status({}); | ||
}; | ||
//used for a sleap timmer in main async function | ||
function sleep(ms) | ||
{ | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
function sleep(ms) { | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
} | ||
//setup the ads | ||
const adc = new ads1x15(number_of_chip, number_of_i2c_address); | ||
try { | ||
const adc = new ads1x15(number_of_chip, number_of_i2c_address); | ||
} | ||
catch (error) { | ||
this.warn("Load const adc: " + error); | ||
this.status({ | ||
fill: 'red', | ||
shape: 'dot', | ||
text: "detected error" | ||
}); | ||
} | ||
this.on("input", async function(msg, send, done) | ||
{ | ||
//is Bus ready - load device address number | ||
var bus_ready; //error check of bus_ready | ||
Promise.resolve (adc.openBus(this.i2c_device_number)) | ||
.then( bus_ready = true ) | ||
.catch(error => { | ||
bus_ready = ("adc.openBus: " + error), | ||
this.warn(bus_ready), | ||
this.status({ | ||
fill: 'red', | ||
shape: 'dot', | ||
text: "detected error" | ||
}); | ||
}); | ||
// For maximum backwards compatibility, check that send exists. | ||
// If this node is installed in Node-RED 0.x, it will need to | ||
// fallback to using `node.send` | ||
send = send || function() { node.send.apply(node,arguments); }; | ||
//user error function | ||
function notify_user_errors(err) | ||
{ | ||
if (done) | ||
{ | ||
// Node-RED 1.0 compatible | ||
done(err); | ||
//DO STUFF WHEN TRIGGERED | ||
this.on("input", async function(msg, send, done) { | ||
// For maximum backwards compatibility, check that send exists. | ||
// If this node is installed in Node-RED 0.x, it will need to | ||
// fallback to using `node.send` | ||
send = send || function() { node.send.apply(node,arguments); }; | ||
//user error function | ||
function notify_user_errors(err) { | ||
if (done) { | ||
// Node-RED 1.0 compatible | ||
done(err); | ||
} | ||
else { | ||
// Node-RED 0.x compatible | ||
node.error(err, msg); | ||
} | ||
} | ||
else | ||
{ | ||
// Node-RED 0.x compatible | ||
node.error(err, msg); | ||
} | ||
} | ||
if ( true ) //is falsy | ||
{ | ||
notify_user_errors("error test"); | ||
} | ||
//send status msg | ||
//node.status( | ||
//{ | ||
// fill: 'blue', | ||
// shape: 'dot', | ||
// text: volts + 'v' | ||
//}); | ||
// clear/end status msg after 3 seconds | ||
//var timmerClear = setTimeout(status_clear, 5000); | ||
//return node.error('Unable to connect to ADC and Failed to fetch value from Chipset:'+this.chip+" "+this.channel+" "+this.i2c_address, err); | ||
//clear status icon every new trigger input | ||
node.status({}); | ||
if (dply_rdy !== true) { | ||
notify_user_errors(dply_rdy); | ||
this.status({ | ||
fill: 'red', | ||
shape: 'dot', | ||
text: "detected error" | ||
}); | ||
if (done) { done(); } | ||
} | ||
else { | ||
// create object to store voltage values | ||
var voltage_output_object = {}; | ||
voltage_output_object[format_i2c_device_number] = {}; | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip] = {}; | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip][format_number_of_i2c_address] = {}; | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip][format_number_of_i2c_address][format_inputsForChannel] = {}; | ||
//define samplesPerSecond to a var based on user selection that is based on chipset | ||
var samples_per_second = "SPS_250"; //value that works for both chips ..... | ||
send(msg); | ||
if (done) { | ||
done(); | ||
if (format_inputsForChannel === 'singleEnded') { | ||
for await (let request of channels_array_of_objects) { | ||
try { | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip][format_number_of_i2c_address][format_inputsForChannel]['channel_'+request.channel] = {}; | ||
const measure = await adc.readSingleEnded({ | ||
channel: request.channel, | ||
pga: request.programmable_gain_amplifier, | ||
sps: request.samples_per_second | ||
}); | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip][format_number_of_i2c_address][format_inputsForChannel]['channel_'+request.channel]['Volts'] = measure / 1e3; | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip][format_number_of_i2c_address][format_inputsForChannel]['channel_'+request.channel]['miliVolts'] = measure; | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip][format_number_of_i2c_address][format_inputsForChannel]['channel_'+request.channel]['samples_sec'] = request.samples_per_second; | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip][format_number_of_i2c_address][format_inputsForChannel]['channel_'+request.channel]['gain'] = request.programmable_gain_amplifier; | ||
} | ||
catch (error) { notify_user_errors(error); } | ||
} | ||
} | ||
if (format_inputsForChannel === 'differential') { | ||
for await (let request of channels_array_of_objects) { | ||
try { | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip][format_number_of_i2c_address][format_inputsForChannel]['channel_'+request.channelPositive+'_'+request.channelNegative] = {}; | ||
const measure = await adc.readSingleEnded({ | ||
channelPositive: request.channelPositive, | ||
channelNegative: request.channelNegative, | ||
pga: request.programmable_gain_amplifier, | ||
sps: request.samples_per_second | ||
}); | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip][format_number_of_i2c_address][format_inputsForChannel]['channel_'+request.channelPositive+'_'+request.channelNegative]['Volts'] = measure / 1e3; | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip][format_number_of_i2c_address][format_inputsForChannel]['channel_'+request.channelPositive+'_'+request.channelNegative]['miliVolts'] = measure; | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip][format_number_of_i2c_address][format_inputsForChannel]['channel_'+request.channelPositive+'_'+request.channelNegative]['samples_sec'] = request.samples_per_second; | ||
voltage_output_object[format_i2c_device_number][format_number_of_chip][format_number_of_i2c_address][format_inputsForChannel]['channel_'+request.channelPositive+'_'+request.channelNegative]['gain'] = request.programmable_gain_amplifier; | ||
} | ||
catch (error) { notify_user_errors(error); } | ||
} | ||
} | ||
//send voltage_output_object to payload | ||
RED.util.setMessageProperty(msg,node.property,voltage_output_object); | ||
send(msg); | ||
if (done) { done(); } | ||
} | ||
@@ -97,0 +216,0 @@ }); |
{ | ||
"name": "node-red-contrib-ads1x15_i2c", | ||
"version": "0.0.3", | ||
"version": "0.0.11", | ||
"description": "A node-red node providing access to a ADS1x15 I2C analog to digital converter", | ||
@@ -5,0 +5,0 @@ "dependencies": { |
118
readme.md
@@ -1,2 +0,2 @@ | ||
node-red-contrib-anolog-to-digital-converter-raspberry-pi | ||
node-red-contrib-ads1x15_i2c | ||
================================== | ||
@@ -19,7 +19,2 @@ | ||
* [Gain](#Gain) | ||
* [Example Flows](#example-flows) | ||
* [Simple_Example](#simple_example) | ||
* [advance_example](#advance_example) | ||
* [treeing](#treeing) | ||
* [Dropped_Request](#Dropped_Request) | ||
* [Bugs / Feature request](#bugs--feature-request) | ||
@@ -39,3 +34,3 @@ * [License](#license) | ||
``` | ||
npm install node-red-contrib-anolog-to-digital-converter-raspberry-pi | ||
npm install node-red-contrib-ads1x15_i2c | ||
``` | ||
@@ -48,3 +43,3 @@ | ||
![example1.png](./doc/example1.png) | ||
![example1.jpg](./doc/example1.jpg) | ||
@@ -69,5 +64,5 @@ | ||
### Channel | ||
### Inputs | ||
The Channel may be used for Single-ended measurements (A0-GND) or Differential measurements (A0-A1). Single-ended measurements measure voltages relative to a shared reference point which is almost always the main units ground. Differential measurements are “floating”, meaning that it has no reference to ground. The measurement is taken as the voltage difference between the two wires. Example: The voltage of a battery can be taken by connecting A0 to one terminal and A1 to the other. | ||
Inputs may be used for Single-ended measurements (A0-GND) or Differential measurements (A0-A1). Single-ended measurements measure voltages relative to a shared reference point which is almost always the main units ground. Differential measurements are “floating”, meaning that it has no reference to ground. The measurement is taken as the voltage difference between the two wires. Example: The voltage of a battery can be taken by connecting A0 to one terminal and A1 to the other. | ||
@@ -80,54 +75,8 @@ ### Samples | ||
I Select the Gain you want. To increase accuracy of smaller voltage signals, the gain can be adjusted to a lower range. Do NOT input voltages higher than the range or device max voltage, pi 3.3v use a voltage devider to lover input voltages as needed. | ||
I Select the Gain you want. To increase accuracy of smaller voltage signals, the gain can be adjusted to a lower range. Do NOT input voltages higher than the range or device max voltage, pi 3.3v use a voltage devider to lower input voltages as needed. | ||
## Example Flows | ||
Examples showing how to use the voltage_undivider. | ||
### simple_example | ||
![examplenode.png](./doc/examplenode.png) | ||
``` | ||
[{"id":"2cd25fcc.2e978","type":"inject","z":"95ed73ce.f4c49","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":380,"y":300,"wires":[["16a39eb9.adf799"]]},{"id":"16a39eb9.adf799","type":"ads1x15-raspi","z":"95ed73ce.f4c49","property":"ffff","name":"","chip":"IC_ADS1115","i2c_address":"ADDRESS_0x48","channel":"DIFF_1_3","samplesPerSecond":"SPS_250","progGainAmp":"PGA_4_096V","x":560,"y":300,"wires":[["1c612a9f.05f2f5"]]},{"id":"1c612a9f.05f2f5","type":"debug","z":"95ed73ce.f4c49","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":730,"y":300,"wires":[]}] | ||
``` | ||
<br> | ||
### advance_example | ||
![examplenode2.png](./doc/examplenode2.png) | ||
``` | ||
[{"id":"9fa062dc.6e1b6","type":"inject","z":"a074224d.a6b91","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":240,"wires":[["2bfc185d.72ddd8"]]},{"id":"2bfc185d.72ddd8","type":"ads1x15-raspi","z":"a074224d.a6b91","property":"x48_A0-GND","name":"x48_A0-GND","chip":"IC_ADS1115","i2c_address":"ADDRESS_0x48","channel":"CHANNEL_0","samplesPerSecond":"SPS_250","progGainAmp":"PGA_4_096V","x":350,"y":140,"wires":[["e219cd74.4ea59"]]},{"id":"edb67462.6fbb88","type":"debug","z":"a074224d.a6b91","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":550,"y":220,"wires":[]},{"id":"e219cd74.4ea59","type":"ads1x15-raspi","z":"a074224d.a6b91","property":"x48_A1-GND","name":"x48_A1-GND","chip":"IC_ADS1115","i2c_address":"ADDRESS_0x48","channel":"CHANNEL_1","samplesPerSecond":"SPS_250","progGainAmp":"PGA_4_096V","x":350,"y":200,"wires":[["bc5b5300.34dc1"]]},{"id":"bc5b5300.34dc1","type":"ads1x15-raspi","z":"a074224d.a6b91","property":"x48_A2-GND","name":"x48_A2-GND","chip":"IC_ADS1115","i2c_address":"ADDRESS_0x48","channel":"CHANNEL_2","samplesPerSecond":"SPS_250","progGainAmp":"PGA_4_096V","x":350,"y":260,"wires":[["6a55c7a6.54e078"]]},{"id":"6a55c7a6.54e078","type":"ads1x15-raspi","z":"a074224d.a6b91","property":"x48_A3-GND","name":"x48_A3-GND","chip":"IC_ADS1115","i2c_address":"ADDRESS_0x48","channel":"CHANNEL_3","samplesPerSecond":"SPS_250","progGainAmp":"PGA_4_096V","x":350,"y":320,"wires":[["edb67462.6fbb88"]]}] | ||
``` | ||
<br> | ||
Please import this flow as an example of how to use. | ||
NOTE: Make sure you name your msg.payload for each node or it will be deleted by the next. Again please import the example above. | ||
<br> | ||
### treeing | ||
![treeing.png](./doc/treeing.png) | ||
<br> | ||
<br> | ||
This is supported but highly discouraged. A warning message will display when this method is used. | ||
<br> | ||
The ADS1X15 cannot process more than one task at a time. To support this a delay is added to each trigger and while loop is used to check when a slot is available. This adds overhead that is not needed if the user just daisy-chain the nodes and sets the msg.payload to a more appropriate name. | ||
<br> | ||
Please import and use the advance example above if you need direction. | ||
<br> | ||
### Dropped_Request | ||
If you try to get more than one voltage reading in 100ms, from the same address, and channel, the node will drop the msg triggering the event.<br> To stop this error just lower the amount of trigger events your sending to the node. | ||
## Bugs / Feature request | ||
Please [report](https://github.com/meeki007/node-red-contrib-ads1x15-raspi/issues) bugs and feel free to [ask](https://github.com/node-red-contrib-ads1x15-raspi/issues) for new features directly on GitHub. | ||
Please [report](https://github.com/meeki007/node-red-contrib-ads1x15_i2c/issues) bugs and feel free to [ask](https://github.com/node-red-contrib-ads1x15_i2c/issues) for new features directly on GitHub. | ||
@@ -149,5 +98,4 @@ | ||
Thanks to [Kevin Fitzgerald AKA kfitzgerald](https://github.com/kfitzgerald/raspi-kit-ads1x15#readme) for his work on raspi-kit-ads1x15. It made making this node for node-red possible. | ||
Thanks to [Kevin Felix D Rodriguez Perez AKA felixdrp](https://github.com/felixdrp/ads1x15) for his work on ads1x15. It made making this node for node-red possible. | ||
<br> | ||
Thank you to Andre van Amerongen; took the time to let me know about multiple trigger / treeing issue. | ||
@@ -157,3 +105,3 @@ ## release notes ## | ||
version 0.2.13 | ||
version 0.0.11 | ||
<br> | ||
@@ -163,49 +111,1 @@ First Public release | ||
<br> | ||
version 0.3.13 | ||
<br> | ||
Updated node to support the input event callback function, and add Backwards compatibility | ||
<br> | ||
more info found here: [https://nodered.org/blog/2019/09/20/node-done](https://nodered.org/blog/2019/09/20/node-done) | ||
<br> | ||
<br> | ||
version 0.4.15 | ||
<br> | ||
Bug fix: no error msg when treeing node / triggering multiple nodes at the same time | ||
<br> | ||
New feature: added Asynchronous Function to handle treeing<br> | ||
Also added duplicate trigger drop on same msg triggering the same chip, address, and channel in less than 100ms | ||
<br> | ||
<br> | ||
version 0.4.16 | ||
<br> | ||
Updated Documentation | ||
<br> | ||
<br> | ||
<br> | ||
version 0.4.19 | ||
<br> | ||
Added more verbose statment for faild connection to ADC. To tell user on what chip, address and channel. | ||
<br> | ||
Fixed chip selction being stuck and unable to select ads1015. No longer stuck on ADS1115 mode. | ||
<br> | ||
<br> | ||
<br> | ||
version 0.4.23 | ||
<br> | ||
Fixed Samples Per second issue. Users unable to set and keep value wanted. | ||
<br> | ||
Fixed a timeout issue that crashed node-red proper. THIS WAS BAD. But a rare case if a user had 4 ADC's connected and polled them at a rate of less than 100ms. Thankyou odd balls. never thought people would go pushing the limits of this node. | ||
<br> | ||
<br> | ||
<br> | ||
version 0.4.24 | ||
<br> | ||
Docker fix patch | ||
<br> | ||
<br> | ||
<br> | ||
<br> | ||
version 0.4.25 | ||
<br> | ||
Changed msg object to a better format | ||
<br> |
Sorry, the diff of this file is not supported yet
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
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
231503
203
104
1