I’m trying to use oh_quantity with a custom block library, but I’m not sure how to call the methods against the object passed in (i.e. they don’t seem to exist). I can print out the value of the passed in quantity (e.g. “10 °C”), but can’t otherwise use any functions against it.
I’d ideally like to use quantities as I can be confident I’m doing calculations in the correct unit. Could anybody point me towards a hint as to how to use inputs that have a check type of oh_quantity?
If you are building a block library, what you are doing is mapping a block to one or more lines of JS code. So the first place to look will be JavaScript Scripting - Automation | openHAB
Unlike normal numbers, you must use methods to do math with a Quantity. So to add two Quantity Objects you’d have code along the lines of:
myTemperature.add(Quantity('5 °C'));
The second place to look is the code generated by the existing blocks themselves. There’s an icon at the bottom right that will flip between the rendered JS code and the visual blocks. So you can experiment and try stuff with the blocks and see what the rendered JS looks like as a result.
Ah, I’ve found where it’s going wrong, but I’m not sure why.
I’m successfully capturing the quantity with oh_quantity argument, but when I’m passing that argument through to a utility function I can no longer do a “.float” to get the underlying raw value (docs). So I’ll just have to extract the raw values I want to work with before passing it into the utility function.
When creating a block library, you must define a new block with the value prefilled in. This new block generates the code with the unit hard coded into the JS.
If you want to use Quantity in the first place, why do you need to call .float in the first place? Quantity works best when you stay working with Quantity. As soon as you jump out with a plain number you may as well start with a plain number to begin with. But you can do math with the Quantity Objects themselves.
I use toUnit() to get the value into the correct UoM for the calculation and then pull the number to do my calculation. .float is just a good member to pick as it always returns a value - just not in my case when I pass the object into a utility function, where .float is an undefined member.
But you can just do the calculation. No .toUnit(). No .float. You just stay working within Quantity and it doesn’t matter what the units are as long as they are compatible. It’s one of the major reasons for having Quantity in the first place.
I can’t get my head around that: In the javascript utility function of my code library, I have a passed in variable (e.g. myArg), and I want to apply a formula to say °C, or kph, how would the Quantity object know which unit I wanted to work with?
myTemperature.add(Quantity('5 °C')) // adds 5 °C to myTemperature, works even if myTemperature is °F or K
if(mySpeed.greaterThan(Quantity('60 kph')) { // true when the speed is > 60 kph, works even if mySpeed is mph
let volumeRain = myYardArea.multiply(items.precipitation.quantityType) // knows to change the units since it's an area * a length, results in a volume (e.g. m^3) which could be converted to L or any other volume with just a call to toUnit
So if I wanted to work out the vapour pressure at a given temperature, I’d be expecting to do 6.112 * Math.exp((17.62 * tempC) / (243.12 + tempC)), I still can’t see how I would do that? Sorry, I feel I’m being really dumb here!
Unfortunately it seems exp isn’t implemented in JS (could be a nice addition if you are up to file an issue). So we will have to break out of Quantity for that. I’m also going to split this across multiple lines for clarity. I assume tempC is already a Quantity.
const hPa = Quantity('6.112 hPa');
const tempDenom = Quantity('243.12 °C');
const coefficient = Quantity('17.62'); // a plain number without units as a Quantity
const numerator = coefficient.multiply(tempC);
const denom = tempDenom.add(tempC);
const exponent = numerator.divide(denom).float; // units become cancelled out so we are not losing anything by using .float here which we need to use math.exp
const result = hPa.multiply(Math.exp(exponent)); // result will be in hPa units
Notice, we never care what unit tempC is in. It doesn’t matter. But what will happen is the unit of the first operand will be used in the result so the results will all be in °C for those operations.
However, temperature can be a challenge because 0 K !== 0 °C !== 0 °F so certain math operations do not always work the way you expect them to. Behind the scenes, all temperatures are converted to K to do the operation and then converted back to what ever unit you are using. So double check that the operations involving temperature give the expected result.
I tried your code verbatim, but it doesn’t seem to operate in that way: If through a blockly script I use a Quantity shape to do Quantity(‘1 °C’) and pass it in and then do the same but with Quantity(‘33.8 °F’), I get two different results - so I absolutely do need to be concerned with the unit being used.
But it’s moot now, my problem that I couldn’t access any of the Quantity members when passed into a utility function has melted away - I’m not sure what I did to resolve it as I have no memory of changing the argument configuration. I can now call tempC.toUnit('°C').float and everything can remain concise without the need for interim Quantity objects being created.