*Enfield Cat's Blog: Arduino and other projects.*

RPN stands for "Reverse Polish Notation", or a "stack calculator". Many early HP calculators used rpn notation and it is relatively simple to implement yet powerful which is why it is used in HydraFerret.

The rpn calculator uses the concept of a last in last out (LIFO) stack. Numbers are placed on the stack and then some operation (such as add or subtract) is applied to the numbers on the stack and the result is placed back on the stack. At the end of the calculation there should just be one number left on the stack which is the result. Using this concepts it is possible to specify calculation without having to place terms inside brackets. The downside is many people find the format counter intuative.

- A space is used to separate each term in the expression
- The rpn expression is applied from left to right.
- Any value or variable is pushed on to the stack.
- When an operator is encountered (these will be single characters), the operation is applied the the values at the top of the stack.
- As many items as are required by the operator are popped off the stack
- The result is pushed on to the stack

Here is an example of the an rpn expression in HydraFerret:

bme280.temp 2 - bme280.dewp < bme280.temp 3 < &

This uses 2 variables from the first bm280 sensor, one of which is accessed twice.

- The temperature and a constant are pushed on to the stack.
- The constant is subtracted from the temperature, and the difference is placed on the stack.
- The dew-point is pushed on to the stack
- A comparison is made, and if (the temperature less 2 degrees) is less than the dewpoint 1 is put on the stack, 0 otherwise
- The temperature and another constant is put on the stack
- These are compared and a 1 is put on the stack if the temperature is less than the constant, 0 otherwise
- A logical "and" is performed, if both tests had returned 1 then 1 is left on the stack, or 0 otherwise. ie to get a 1 returned the temprature is within 2 degress of the dewpoint AND the temperature is less than 3 degrees.

Effectively we've created a frost warning calculation.
**NB:** Your frost formation warning conditions may be different!

Let's now see the same calculation performed at the console prompt to step through it. When done like this we can see the operation performed, where a blank prefix show a constant pushed on to the stack and a "~" indicates a variable lookup. This allows us to test if a calculation is valid and performs as we expect before creating an output or alert using it. A trace is given when using the "rpn" command showing each step of the calculation. This trace is not produced for outputs or alerts. The trace shows the stack state after the operation has been performed. In the example the temperature is 22.6 Celsius with a dew-point of 12.2 Celcius. Once confirmed like this the expression could be used to set a warning threshold or control an output.

rpn bme280.temp 2 - bme280.dewp < bme280.temp 3 < & Op Older <-- Stack --> Newer ~ 22.6340 22.6340 2.0000 - 20.6340 ~ 20.6340 12.2120 < 0.0000 ~ 0.0000 22.6340 0.0000 22.6340 3.0000 < 0.0000 0.0000 & 0.0000

Using an index, the following is equivalent to the preceding calculation:

rpn bme280.0.temp 2 - bme280.0.dewp < bme280.0.temp 3 < &

Operation | Operands | description | |
---|---|---|---|

2 number operators | |||

+ | 2 | Add 2 numbers | |

* | 2 | Multiply 2 numbers | |

- | 2 | Subtract a number from the previous number on the stack | |

/ | 2 | Divide the previous number on the stack by the last number on the stack | |

% | 2 | Modulus division, result is the remainder of the previous divided by the last number on the stack | |

^ | 2 | Raise the previous number on the stack by the power of the last number on the stack | |

d | 2 | Return the dewpoint based on temperature in Celcius and relative humidity | |

h | 2 | Return the hypotenuse of the last 2 numbers on the stack | |

Q | 2 | Return the altitude compensated pressure given measure pressure and altitude | |

x | 2 | Exchange the last two numbers on the stack | |

& | 2 | Return 1 if both of the last 2 numbers on the stack are greater than 0, otherwise return 0 | |

| | 2 | Return 1 if either of the last 2 numbers on the stack are greater than 0, otherwise return 0 | |

= | 2 | Return 1 if the last two numbers on the stack are equal, otherwise return 0 | |

< | 2 | Return 1 if the previous number on the stack is less than the last number on the stack | |

> | 2 | Return 1 if the previous number on the stack is greater than the last number on the stack | |

1 number operators | |||

! | 1 | Inverse of the last number on the stack | |

a | 1 | Absolute value of the last number on the stack | |

f F | 1 | Convert the last number on the stack between Fahrenheit and Celcius (Capital to Fahrenheit) | |

i I | 1 | Round to next integer, i next integer nearest 0, I next integer furthest from zero | |

l | 1 | Log base 10 of the last number on the stack | |

k | 1 | retreive the numbered constant value. | |

n | 1 | Natural log of the last number on the stack | |

q | 1 | Cubed root of the last number on the stack | |

r R | 1 | Convert the last number on the stacki between radians and degrees and reverse (Capital to Radians) | |

v | 1 | Square root of the last number on the stack | |

s S | 1 | Sin of the last number on the stack, or Capital for inverse | |

c C | 1 | Cos of the last number on the stack, or Capital for inverse | |

t T | 1 | Tan of the last number on the stack, or Capital for inverse | |

Constants | |||

e | 0 | e | |

g | 0 | Earth gravitaional acceleration 9.8066 m/s/s | |

p | 0 | Pi |

The general format for variables in HydraFerret is <sensor><index><measurement> where the index numbers start from zero, but can be omitted for the zero-ith sensor of the type. The measurement is normally limited to the first 4 characters of the variable. This may seem long winded, yet terse. But allow variables to be very specific. The "memory" sensor refers to internal measurements of the HydraFerret unit, and allow for time dependency to be built in to calculations.

Variable Name | Description |
---|---|

memory.free | Total free heap size, note the largest available block of memory may be much smaller. |

memory.minf | The minimum free heap size seen since system start |

memory.size | The size of the system heap memory |

memory.time | The system up-time in minutes |

memory.freq | The processor speed |

memory.xtal | The system crystal speed |

memory.year | The current year |

memory.mont | The month: Jan=1, Dec=12 |

memory.dow | The day of week: Sun=0, Sat=6 |

memory.dom | The day of month |

memory.doy | The day of year |

memory.hour | The hour of day: 00 - 23 |

memory.min | The minute of the hour: 00 - 59 |

memory.mind | The minute of day: 0 - 1439 |

memory.secs | The seconds of the minute: 00 - 59 |

There are a number of varibales which are not explicitly documented per server. In the table below "xxxx" indicates the device type (and number), while "*" indicates the first letter a a variable name, eg "t" for temperature. These variables will be included when running: list vars

Variable name | description |
---|---|

xxxx.dev | The count of the number of "xxxx" devices attached to the unit. |

xxxx.las* | The last reading taken on the device. This is updated on evry monitoring interval, and may be used for calculations where the latest measurement is required, eg to set an output variable, or diagnosing issues at the connsole. |

xxxx.*sta | The status from the last 5 minute period. 0 = OK, 1 = Warning, 2 = Critical, 3 = Extreme. The numeric value can be used as a mutiplier for a hysteresis value to be added to warning or critical threshold to prevent "flapping" in and out of warning and critical states. |

NB: These are shown in their abbreviated form eg bme280.temp, rather than the longer form with device index, eg: bme280.0.temp or bme280.1.temp. The abbreviated form refers to device index 0.

Variable Name | Description |
---|---|

adc.val | Averaged reading from last 5 minute interval |

adc.mult | multiplier for raw values |

adc.offs | offset to add to raw values, typically left at 0.000 |

bh1750.lux | Light level in Lux (Lumins / m^{2}) |

bh1750.opac | Window opacity, 1.2 = no window |

bme280.alti | Altitude in meters |

bme280.dewp | Dewpoint in centigrade/Celcius |

bme280.humi | Relative humidity |

bme280.pres | Pressure in hectoPascals |

bme280.unco | Uncompensated pressure in hectoPascals |

bme280.sos | Speed of sound in meters per second. Speed of sound varies with temperature |

bme280.temp | Temperature in Centigrade/Celcuis |

counter.diff | Reading difference is last 5 minute period |

counter.tota | Total count from reset to last period |

counter.mult | multiplier for raw values |

counter.offs | offset to add to raw values, typically left at 0.000 |

css811.co2 | CO2 levels in parts per million |

css811.tvoc | tvoc (Total Volatile Organic Compound) levels in parts per billion |

hdc1080.dewp | Dewpoint in centigrade/Celcius |

hdc1080.humi | Relative humidity |

hdc1080.sos | Speed of sound in meters per second. Speed of sound varies with temperature |

hdc1080.temp | Temperature in Centigrade/Celcuis |

ina2xx.amps | Current in amps |

ina2xx.shun | Shunt resistor in milli-ohms |

ina2xx.volt | Bus voltage level |

ina2xx.watt | wattage reading |

output.val | The result of an output calculation |

veml6075.uva | UVA component |

veml6075.uvb | UVB component |

veml6075.uvi | UV index |

Thank you for visiting camelthorn.cloud | Home |