node-red-contrib-anolog-to-digital-converter-raspberry-pi
Advanced tools
Comparing version 0.2.13 to 0.4.16
188
ads1x15.js
@@ -17,2 +17,3 @@ | ||
RED.nodes.createNode(this, config); | ||
var globalContext = this.context().global; | ||
var node = this; | ||
@@ -28,2 +29,3 @@ | ||
//Function to Clear user notices, used for timmer | ||
@@ -36,93 +38,145 @@ var status_clear = function() | ||
//clear status icon on deploy | ||
node.status({}); | ||
//used for a sleap timmer in main async function | ||
function sleep(ms) | ||
{ | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
} | ||
this.on("input", function(msg) | ||
this.on("input", async function(msg, send, done) | ||
{ | ||
// If this is pre-1.0, 'send' will be undefined, so fallback to node.send | ||
send = send || function() { node.send.apply(node,arguments) } | ||
//clear status icon every new trigger input | ||
node.status({}); | ||
// Init Raspi | ||
Raspi.init(() => | ||
//Check to see if a job is already waiting in que / drop msg and next job and warn user about trigger rate | ||
var is_que_full = globalContext.get("node_red_contrib_anolog_to_digital_converter_raspberry_pi_"+this.chip+this.i2c_address+this.channel); | ||
if (is_que_full === true) | ||
{ | ||
return node.error('Dropped Request to fetch value from ADC, Chip:'+this.chip+' '+this.i2c_address+' '+this.channel+' , Please increse the ammount of time/rate of trigger when requesting this voltage'); | ||
} | ||
else | ||
{ | ||
//set the is_que_full to true untill the work is done | ||
globalContext.set("node_red_contrib_anolog_to_digital_converter_raspberry_pi_"+this.chip+this.i2c_address+this.channel, true); | ||
// Init Raspi-I2c | ||
const i2c = new I2C(); | ||
//sleep 100ms to drop any extra requests made on this chip,i2c_address, and channel | ||
await sleep(100); | ||
// Init the ADC | ||
const adc = new ADS1x15( | ||
//check to see if ads is busy with another job from another node/tree and wait for job to finish before sending this nodes work | ||
var adc_busy = globalContext.get("adc_is_busy_node_red_contrib_anolog_to_digital_converter_raspberry_pi"); | ||
if (adc_busy === true) | ||
{ | ||
i2c, // i2c interface | ||
chip: ADS1x15.chips.IC_ADS1115, // chip model | ||
address: ADS1x15.address[this.i2c_address], // i2c address on the bus | ||
node.warn('Upstream Treeing of node anolog_to_digital_converter_raspberry_pi detected. Please do not trigger more than one of these nodes at a time as Asynchronous message passing is not recomended; though supported it adds a delay to the output of these nodes. See documentation for this node on treeing'); | ||
while(adc_busy === true) | ||
{ | ||
//Math.floor(Math.random() * (max - min + 1) + min); | ||
var random_number_between_100_200 = Math.floor(Math.random() * (200 - 100 + 1) + 100); | ||
await sleep(random_number_between_100_200); | ||
adc_busy = globalContext.get("adc_is_busy_node_red_contrib_anolog_to_digital_converter_raspberry_pi"); | ||
} | ||
} | ||
// Defaults for future readings | ||
pga: ADS1x15.pga[this.progGainAmp], // power-gain-amplifier range | ||
sps: ADS1x15.spsADS1115[this.samplesPerSecond] // data rate (samples per second) | ||
}); | ||
//now that we have our spot in line set to true so no one else can cut in | ||
globalContext.set("adc_is_busy_node_red_contrib_anolog_to_digital_converter_raspberry_pi", true); | ||
if ( this.channel.includes('CHANNEL') ) | ||
//sleep 100ms to drop any extra requests made to the ads | ||
await sleep(50); | ||
// Init Raspi | ||
Raspi.init(() => | ||
{ | ||
// Get a single-ended reading from channel-X and display the results | ||
adc.readChannel(ADS1x15.channel[this.channel], (err, value, volts) => | ||
// Init Raspi-I2c | ||
const i2c = new I2C(); | ||
// Init the ADC | ||
const adc = new ADS1x15( | ||
{ | ||
if (err) | ||
i2c, // i2c interface | ||
chip: ADS1x15.chips.IC_ADS1115, // chip model | ||
address: ADS1x15.address[this.i2c_address], // i2c address on the bus | ||
// Defaults for future readings | ||
pga: ADS1x15.pga[this.progGainAmp], // power-gain-amplifier range | ||
sps: ADS1x15.spsADS1115[this.samplesPerSecond] // data rate (samples per second) | ||
}); | ||
if ( this.channel.includes('CHANNEL') ) | ||
{ | ||
// Get a single-ended reading from channel-X and display the results | ||
adc.readChannel(ADS1x15.channel[this.channel], (err, value, volts) => | ||
{ | ||
return node.error('Failed to fetch value from ADC', err); | ||
} | ||
else | ||
{ | ||
//send to volts to payload | ||
RED.util.setMessageProperty(msg,node.property,volts); | ||
//send the payload | ||
node.send(msg); | ||
//send status msg | ||
node.status( | ||
if (err) | ||
{ | ||
fill: 'blue', | ||
shape: 'dot', | ||
text: volts + 'v' | ||
}); | ||
// clear/end status msg after 3 seconds | ||
var timmerClear = setTimeout(status_clear, 5000); | ||
} | ||
}); | ||
} | ||
return node.error('Failed to fetch value from ADC', err); | ||
} | ||
else | ||
{ | ||
else if ( this.channel.includes('DIFF') ) | ||
{ | ||
// Get a differential reading from channel-X and display the results | ||
adc.readDifferential(ADS1x15.differential[this.channel], (err, value, volts) => | ||
//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); | ||
//send to volts to payload | ||
RED.util.setMessageProperty(msg,node.property,volts); | ||
send(msg); | ||
} | ||
}); | ||
} | ||
else if ( this.channel.includes('DIFF') ) | ||
{ | ||
if (err) | ||
// Get a differential reading from channel-X and display the results | ||
adc.readDifferential(ADS1x15.differential[this.channel], (err, value, volts) => | ||
{ | ||
return node.error('Failed to fetch value from ADC', err); | ||
} | ||
else | ||
{ | ||
//send to volts to payload | ||
RED.util.setMessageProperty(msg,node.property,volts); | ||
//send the payload | ||
node.send(msg); | ||
//send status msg | ||
node.status( | ||
if (err) | ||
{ | ||
fill: 'blue', | ||
shape: 'dot', | ||
text: volts + 'v' | ||
}); | ||
// clear/end status msg after 3 seconds | ||
var timmerClear = setTimeout(status_clear, 5000); | ||
} | ||
}); | ||
} | ||
return node.error('Failed to fetch value from ADC', err); | ||
} | ||
else | ||
{ | ||
}); | ||
//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); | ||
//send to volts to payload | ||
RED.util.setMessageProperty(msg,node.property,volts); | ||
send(msg); | ||
} | ||
}); | ||
} | ||
}); | ||
await sleep(10); | ||
//set adc_busy and is_que_full to false now that we are done with them | ||
globalContext.set("adc_is_busy_node_red_contrib_anolog_to_digital_converter_raspberry_pi", false); | ||
globalContext.set("node_red_contrib_anolog_to_digital_converter_raspberry_pi_"+this.chip+this.i2c_address+this.channel, false); | ||
done(); | ||
} | ||
}); | ||
} | ||
RED.nodes.registerType("ads1x15-raspi", ads1x15MainFunction); | ||
}; |
{ | ||
"name": "node-red-contrib-anolog-to-digital-converter-raspberry-pi", | ||
"version": "0.2.13", | ||
"version": "0.4.16", | ||
"description": "A node-red node providing access to a ADS1x15 I2C analog to digital converter using a raspberry pi", | ||
@@ -5,0 +5,0 @@ "dependencies": { |
@@ -20,3 +20,6 @@ node-red-contrib-anolog-to-digital-converter-raspberry-pi | ||
* [Example Flows](#example-flows) | ||
* [Example](#example) | ||
* [Simple_Example](#simple_example) | ||
* [advance_example](#advance_example) | ||
* [treeing](#treeing) | ||
* [Dropped_Request](#Dropped_Request) | ||
* [Bugs / Feature request](#bugs--feature-request) | ||
@@ -78,6 +81,6 @@ * [License](#license) | ||
Simple examples showing how to use the voltage_undivider. | ||
Examples showing how to use the voltage_undivider. | ||
### Example | ||
### simple_example | ||
@@ -90,2 +93,33 @@ ![examplenode.png](./doc/examplenode.png) | ||
<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> | ||
### 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 | ||
@@ -110,2 +144,4 @@ 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. | ||
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. | ||
<br> | ||
Thank you to Andre van Amerongen; took the time to let me know about multiple trigger / treeing issue. | ||
@@ -116,2 +152,25 @@ ## release notes ## | ||
version 0.2.13 | ||
<br> | ||
First Public release | ||
<br> | ||
<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> | ||
Sorry, the diff of this file is not supported yet
229288
10
147
172