• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[SOLVED] Function Node Code to correct non-linear sensor ?
#1
I am reading my fuel/waste/fresh water tank levels using the original resistive senders (0-190 Ohm) configured in a voltage divider.
The output voltage is then read by an ADS1115 ADC connected to an ESP8226 wireless sender running ESPEasy firmware. The ESP8226 sends the data as MQTT over WiFi and is picked up in NodeRed for presentation on my dashboard on the Pi. (All shamelessly copied from others on here Smile

All works just great but I'd like to incorporate some correction for the non-linear nature of the sender.
In OP I know there is the option to do this for a directly connected ADC but not one sending data over MQTT
In the ESPEasy firmware there is the option for "2 point correction" but I need more plots in the curve than just "1024 = full and 0= empty".

I think that what I really need is some JSON code for a NodeRed function node that will take a raw ADC value range and convert it into a value in litres. 
I'd want a small table of 8 such conversions as the sender has 8 or maybe 10 steps.

for example
ADC in        value out
0-99           0
100-299      20
300-499      50
500-699      100
700-799      200
800-999      250
1020+        320

I have no clue how to write JSON code so Im hoping that someone may have addressed this issue before.
Thanks
Steve
  Reply
#2
(02-25-2018, 06:23 PM)affinite Wrote: I am reading my fuel/waste/fresh water tank levels using the original resistive senders (0-190 Ohm) configured in a voltage divider.
The output voltage is then read by an ADS1115 ADC connected to an ESP8226 wireless sender running ESPEasy firmware. The ESP8226 sends the data as MQTT over WiFi and is picked up in NodeRed for presentation on my dashboard on the Pi. (All shamelessly copied from others on here Smile

All works just great but I'd like to incorporate some correction for the non-linear nature of the sender.
In OP I know there is the option to do this for a directly connected ADC but not one sending data over MQTT
In the ESPEasy firmware there is the option for "2 point correction" but I need more plots in the curve than just "1024 = full and 0= empty".

I think that what I really need is some JSON code for a NodeRed function node that will take a raw ADC value range and convert it into a value in litres. 
I'd want a small table of 8 such conversions as the sender has 8 or maybe 10 steps.

for example
ADC in        value out
0-99           0
100-299      20
300-499      50
500-699      100
700-799      200
800-999      250
1020+        320

I have no clue how to write JSON code so Im hoping that someone may have addressed this issue before.
Thanks
Steve

Tried the mapper node? ( I haven't :Smile

https://flows.nodered.org/node/node-red-contrib-mapper
  Reply
#3
(02-25-2018, 06:23 PM)affinite Wrote: I think that what I really need is some JSON code for a NodeRed function node that will take a raw ADC value range and convert it into a value in litres. 
...
I have no clue how to write JSON code so Im hoping that someone may have addressed this issue before.

JSON is a data format! https://en.wikipedia.org/wiki/JSON
Please read and understand.


After that open node red in the browser and scroll down in the list of nodes. You may stumble upon the range node.

I quote node red:
Quote:A simple function node to remap numeric input values to another scale.

Currently only does a linear scaling.

Note: This only operates on numbers. Anything else will try to be made into a number and rejected if that fails.
Scale and limit to target range means that the result will never be outside the range specified within the result range.
Scale and wrap within the target range means that the result will essentially be a "modulo-style" wrap-around within the result range.

Add the range node to your flow and set the input range to 0 - 1024 and the result range to 0 - 320.
et voilà
  Reply
#4
Thanks for the suggestions guys
The range node is indeed linear so unfortunately it doesn't improve on the 2 point calibration in the ESPEasy firmware that generates the "raw" ADC values.
The mapping node looks more promising as it has multiple mapping points but I suspect it wont work because I want to convert a range of values.
Anyway I'll try later and report back.

oh and I'll look up the meaning of "JSON" for future reference  Wink
  Reply
#5
(02-26-2018, 05:25 AM)affinite Wrote: Thanks for the suggestions guys
The range node is indeed linear so unfortunately it doesn't improve on the 2 point calibration in the ESPEasy firmware that generates the "raw" ADC values.
The mapping node looks more promising as it has multiple mapping points but I suspect it wont work because I want to convert a range of values.
Anyway I'll try later and report back.

oh and I'll look up the meaning of "JSON" for future reference  Wink

Sorry I've missed the non-linear.
Why not use a simple function node and an if-else statement?

Code:
if(msg.payload >=0 && msg.payload <=99) msg.payload = 0;
else if(msg.payload >=100 && msg.payload <=299) msg.payload = 20;
...
...
else if(msg.payload >=1020) msg.payload = 320;
return msg;
  Reply
#6
Shark
Thanks, I think that's what I need - looks perfect !!
I'll try it later

PS what is that script/code called (OK not JSON ) ?
  Reply
#7
(02-26-2018, 07:29 AM)affinite Wrote: Shark
Thanks, I think that's what I need - looks perfect !!
I'll try it later

PS what is that script/code called (OK not JSON ) ?

It's javascript. Node-red is written in it as well. The platform used is node.js. So with some basic javascript knowledge you are not depending on any external nodes.

I've created a little example for you, which you can import in node-red.
Code:
[{"id":"63810b10.7d85d4","type":"tab","label":"Flow 2"},{"id":"9a6b5ab9.711118","type":"inject","z":"63810b10.7d85d4","name":"","topic":"","payload":"true","payloadType":"bool","repeat":"5","crontab":"","once":true,"x":145,"y":279,"wires":[["277781e1.7b82b6"]]},{"id":"277781e1.7b82b6","type":"function","z":"63810b10.7d85d4","name":"random","func":"msg.payload = 1+Math.floor(Math.random() * 1024);\nreturn msg;","outputs":1,"noerr":0,"x":301,"y":279,"wires":[["5fb49513.139a1c","812da798.5dffb"]]},{"id":"5fb49513.139a1c","type":"function","z":"63810b10.7d85d4","name":"non-linear range","func":"if(msg.payload >=0 && msg.payload <=99) msg.payload = 0;\nelse if(msg.payload >=100 && msg.payload <=299) msg.payload = 20;\nelse if(msg.payload >=300 && msg.payload <=499) msg.payload = 50;\nelse if(msg.payload >=500 && msg.payload <=699) msg.payload = 100;\nelse if(msg.payload >=700 && msg.payload <=799) msg.payload = 200;\nelse if(msg.payload >=800 && msg.payload <=1019) msg.payload = 250;\nelse if(msg.payload >=1020) msg.payload = 320;\nreturn msg;","outputs":1,"noerr":0,"x":524,"y":277,"wires":[["812da798.5dffb"]]},{"id":"812da798.5dffb","type":"debug","z":"63810b10.7d85d4","name":"","active":true,"console":"false","complete":"false","x":746,"y":194,"wires":[]}]
  Reply
#8
Shark
works just great thanks very much
  Reply
#9
Why don‘t you use the ESP8266 to measure the voltage directly?
The ESP8266-12 has a ADC 0-1Volt input.
  Reply
#10
(02-27-2018, 01:50 AM)Alpenskipper Wrote: Why don‘t you use the ESP8266 to measure the voltage directly?
The ESP8266-12 has a ADC 0-1Volt input.

Because I wanted to measure 3 tanks ie 3 inputs but as you know the ESP only has one built-in ADC and an ADS1115 is a cheap way to get the additional inputs.
I've taken the same approach to monitoring my three battery banks but in that case I used 2 ADS1115s in order to get three differential inputs.
  Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)