Using the new Currency Units of Measurement in 4.1

OH 4.1 introduced a new subsystem (for lack of a better word) that supports monetary units. These can be used for things like calculating/estimating the month’s power bill and the like.

Configure the Provider

Currently the support is pretty basic and supports just one currency. But in the future there is a plan to support additional providers with connections to exchanges where values can be converted between currencies using the current exchange rates.

But this means that you have to configure a provider to start. Otherwise your Items will just appear to have unit DEF.

There are two providers supported right now. The “FixedCurrencyProvider” will let you just define what currency you want to use everywhere. The “LocaleBasedCurrencyProvider” will use your regional settings to determine the default currency. The units follow ISO 4217 three letter designations (e.g. USD, EUR, etc.).

  1. Navigate to Settings and under “System Settings” click on “Unit Settings”.
  2. Choose the desired provider and if choosing “FixedCurrencyProvider” supply the default unit.

Configure the Item(s)

There are two new types of Items: Number:Currency and Number:EnergyPrice.

Number:Currency

This Item represents an amount of money. Define the Item as a Number:Currency. As with other units the default representation will be a floating point number followed by the unit, for example 123.456789 $. Therefore you’ll want to configure the State Description pattern to only show two decimal places and show the unit in front of the number (if that’s how it’s usually done for your currency of support).

value: " "
config:
  pattern: $%.2f

Number:EnergyPrice

This type of Item represents the amount of cost per kWh of energy (other per unit cost situations like per gallon/liter are not yet supported). The unit for this Item is going to be DEF/kWh where DEF gets replaced by the provider with your configure currency.

Calculating with Currency

Here I’ll show a simple example of calculating using these Item that takes the monthly energy reading and calculates the monthly bill based on the access rate and per kWh rate.

The Items

Number:Energy      HomeEnergyMeter_ElectricmeterkWh
Number:Currency    HomeEnergyMeter_Access
Number:EnergyPrice HomeEnergyMeter_Rate
Number:Currency    HomeEnergyMeter_CurrentBillEstimate

The first comes from a power meter (a Zwave whole house energy sensor in my case). The second two come from my power bill and are set manually. The last one is the result of the calculation.

The Rule

In JS Scripting:

configuration: {}
triggers:
  - id: "1"
    configuration:
      itemName: HomeEnergyMeter_ElectricmeterkWh
    type: core.ItemStateChangeTrigger
  - id: "2"
    configuration:
      itemName: HomeEnergyMeter_Access
    type: core.ItemStateChangeTrigger
  - id: "3"
    configuration:
      itemName: HomeEnergyMeter_Rate
    type: core.ItemStateChangeTrigger
conditions: []
actions:
  - inputs: {}
    id: "4"
    label: Calculate the power bill and update the Item
    configuration:
      type: application/javascript;version=ECMAScript-2021
      script: >-
        var curr     = items.HomeEnergyMeter_ElectricmeterkWh.quantityState;

        var rate     = items.HomeEnergyMeter_Rate.quantityState;

        var access   = items.HomeEnergyMeter_Access.quantityState;

        var usage = curr.multiply(rate);

        var estimate = access.add((curr.multiply(rate)));

        items.HomeEnergyMeter_CurrentBillEstimate.postUpdate(estimate);
    type: script.ScriptAction

Trigger the rule when any of the Items the calculation depends on changes. First get the three values for the calculation as Quantity types (i.e. don’t throw away the units).

Multiply the current kWh reading by the energy price rate. The kWh units cancel out resulting in just a monetary value. Then add the line access fee to get the total power bill for the month thus far.

In Blockly it would look like the following.

13 Likes

Perfect. Thanks!

For clarity, the term ‘line access fee’ can also be known as ‘base charge’, ‘standing charge’ or ‘fixed charge’…

Since a couple of months I store the hourly energy prices to influx via a rule, so I’m glad the forecast persistence is introduced. And after creating a new persistence configuration, the item shows the correct price, Nice!
Now I was also looking for the the new UOM EnergyPrice. I’ve setup FixedCurrencyProvider and my item now shows the number with €/kWh. Looks good, but I get my hourly prices in €/MWh and I store them as €cent/kWh because prices in Belgium are always showed like this.
Do I simple need to modify the stateDescription to pattern: "%s €cent/kWh"? Or do I need to take another approach?

Unfortunately cents is not supported ATM.

FYI I have created a PR to add this tutorial to the 4.1. release blog post.

3 Likes

A distilled version probably needs to find it’s way into the docs eventually. I muddled through it and just wanted to get something published fast because if I got confused with how to do it, I’m sure others would be too.

2 Likes

Another small example showing the power (pun intended) of this new feature.

Number:Power Omnipower_Active "Current Power [%.0f %unit%]" <energy> (Omnipower) ["Measurement", "Power"] { channel="mqtt:topic:mosquitto:omnipower:active", unit="W" }

Group:Number:EnergyPrice:SUM EnergiDataService_TotalPrice "Total [%.2f kr./kWh]" <price>

Number:EnergyPrice EnergiDataService_SpotPrice "Spot Price [%.2f kr./kWh]" <price> (EnergiDataService_TotalPrice) { channel="energidataservice:service:energidataservice:electricity#spot-price" [profile="transform:VAT"] }
Number:EnergyPrice EnergiDataService_GridTariff "Grid Tarif [%.2f kr./kWh]" <price> (EnergiDataService_TotalPrice) { channel="energidataservice:service:energidataservice:electricity#grid-tariff" [profile="transform:VAT"] }
Number:EnergyPrice EnergiDataService_SystemTariff "System Tarif [%.2f kr./kWh]" <price> (EnergiDataService_TotalPrice) { channel="energidataservice:service:energidataservice:electricity#system-tariff" [profile="transform:VAT"] }
Number:EnergyPrice EnergiDataService_TransmissionGridTariff "Transmission Grid Tarif [%.2f kr./kWh]" <price> (EnergiDataService_TotalPrice) { channel="energidataservice:service:energidataservice:electricity#transmission-grid-tariff" [profile="transform:VAT"] }
Number:EnergyPrice EnergiDataService_ElectricityTax "Electricity Tax [%.2f kr./kWh]" <price> (EnergiDataService_TotalPrice) { channel="energidataservice:service:energidataservice:electricity#electricity-tax" [profile="transform:VAT"] }
Number:EnergyPrice EnergiDataService_ElectricitySupplierFee "Supplier Fee [%.2f kr./kWh]" <price> (EnergiDataService_TotalPrice)

Number Electricity_Hourly_Rate "Current Hourly Rate [%.2f kr./h]" <price>

I have current power usage for the household being updated every 10 seconds (Omnipower_Active) and the current electricity price (with everything included) being updated every hour (EnergiDataService_TotalPrice).

Getting the current rate (in my case DKK per hour) using UoM is as simple as:

rules.when()
    .item("Omnipower_Active").changed()
    .then(event =>
    {
        var currentPower = Quantity(event.newState);
        var currentPrice = items.EnergiDataService_TotalPrice.quantityState;
        var hourlyRate = currentPower.multiply(currentPrice).toUnit("DKK/h");
        items.Electricity_Hourly_Rate.postUpdate(hourlyRate);
    })
    .build("Calculate hourly rate for electricity usage");

The units being multiplied are W and DKK/kWh, so that will become W·DKK/kWh, which can then be converted to DKK/h by dividing by 1000. All handled by UoM automatically.

2 Likes

UoM becomes more useful with every release. Thanks to all involved!

One question though: doesn’t having to specify “€ %.2f” defeat part of the power (:grin:) of UoM? It can already know the currency based on locale, so having to specify that again would be kind of redundant, or will something like %unit% also work?

You don’t specify the currency (to be used in calculations in rules) that way, just how it’s displayed.
Plus, you had to explicitly do it.

I know.
Was just wondering if using %unit% could refer to the locale defined or explicitly configured currency. That way you don’t have to specify something in every Item what ‘the system’ already knows. Having developed code myself (a long time ago in a galaxy far away), I still instinctively look for DRY scenario’s :laughing:

Confirmed. Again I love UoM and how it develops.

I guess I’ll do a little test (unless someone can already confirm or deny).

No, because the power of UoM is in the conversation and calculations.

It does. The problem is unlike all other UoM, the unit for money goes before the number, not after. The UoM subsystem doesn’t understand this (yet?). If you just use %unit% what will be displayed will be 123.4667899 € instead of the expected €123.47.

As in all cases for all units and any other Item types, the state description is used to control how it appears. This is no different.

That should probably be locale dependent. In Germany 5.00 € is perfectly fine and the preferred way.

I figured it was locale dependent. I meant to be clear that the state description part was only needed for those in locales where number space symbol was not the norm but don’t think that point got across.

1 Like

Yeah, when it comes to locale related formatting, things can get quite complicated. There are so many different (but very similar) ways to express the same thing… :grin:
And there is this floating point rounding that gets in the way too, especially when comparing or displaying.

That’s a really tricky problem. What happens when the value is formatted for display (in case of a QuantityType) is:

  1. look at the state description pattern, try to get a unit from there
  2. unit found → convert value to that unit
  3. unit placeholder found → replace with unit of the value (which is the item’s unit since 4.0)
  4. use Java’s String.format to put the plain value (stripped of unit) into the pattern

The problem is at step 1: it assumes the unit is always the last part of the pattern. This has been the case since the introduction of UoM. So a pattern Foo %.2f m/s works fine, %.2f m/s Foo does not, because Foo is not a unit.

Therefore using USD %.2f will not work, because the last part is %.2f, which is not a unit. We could probably change it to “try all tokens, starting from the end” when finding a unit, but that may result in very hard to understand behavior for already existing state descriptions and might also impact performance.

2 Likes

Yes, but in my case that would dispay “1,00 DKK/kWh” rather than “1,00 kr./kWh”, i.e. currency code rather than currency symbol.

I’m still not fully comfortable with this part, since it appears that updating the state requires currency symbol and displaying the state displays currency code. I would intuitively expect the opposite.

For reference:

1 Like

You can always use code, also for updating.

Last I tried that I got: “java.lang.IllegalArgumentException: Invalid Quantity value: 0.33126001 DKK/kWh”. I will have another look with 4.2.

I still have this issue (using LocaleBasedCurrencyProvider):

openhab> openhab:update EnergiDataService_SpotPrice "1 DKK/kWh"
Error: State '1 DKK/kWh' is not valid for item 'Energi_Data_Service_Spot_Price'
Valid data types are: ( DecimalType QuantityType UnDefType )
openhab> openhab:update Energi_Data_Service_Spotpris "1 kr./kWh"
Update has been sent successfully.

Did I get something wrong?