Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[energidataservice] Add support for reduced electricity tax #15636

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 45 additions & 19 deletions bundles/org.openhab.binding.energidataservice/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ All channels are available for thing type `service`.

### `service` Thing Configuration

| Name | Type | Description | Default | Required |
|----------------|---------|---------------------------------------------------|---------------|----------|
| priceArea | text | Price area for spot prices (same as bidding zone) | | yes |
| currencyCode | text | Currency code in which to obtain spot prices | DKK | no |
| gridCompanyGLN | integer | Global Location Number of the Grid Company | | no |
| energinetGLN | integer | Global Location Number of Energinet | 5790000432752 | no |
| Name | Type | Description | Default | Required |
|-----------------------|---------|----------------------------------------------------------------------|---------------|----------|
| priceArea | text | Price area for spot prices (same as bidding zone) | | yes |
| currencyCode | text | Currency code in which to obtain spot prices | DKK | no |
| gridCompanyGLN | integer | Global Location Number of the Grid Company | | no |
| energinetGLN | integer | Global Location Number of Energinet | 5790000432752 | no |
| reducedElectricityTax | boolean | Reduced electricity tax applies. For electric heating customers only | false | no |

#### Global Location Number of the Grid Company

Expand All @@ -35,6 +36,13 @@ To obtain the Global Location Number of your grid company:
- In column **Owner** you can find the GLN ("Global Location Number").
- Most rows will have this **Owner**. If in doubt, try to look for rows __not__ having 5790000432752 as owner.

#### Reduced electricity tax applies

For customers using electricity for heating, a reduced electricity tax rate may apply after consuming the first 4000 kWh within a year.
When you are entitled to reduced electricity tax, this option should be set.
This will ensure that thing action calculations use the reduced electricity tax rate when price elements are not explicitly provided.
It will not impact channels, see [Electricity Tax](#electricity-tax) for further information.

## Channels

### Channel Group `electricity`
Expand All @@ -45,6 +53,7 @@ To obtain the Global Location Number of your grid company:
| net-tariff | Number | Current net tariff in DKK per kWh. Only available when `gridCompanyGLN` is configured | no |
| system-tariff | Number | Current system tariff in DKK per kWh | no |
| electricity-tax | Number | Current electricity tax in DKK per kWh | no |
| reduced-electricity-tax | Number | Current reduced electricity tax in DKK per kWh. For electric heating customers only | no |
| transmission-net-tariff | Number | Current transmission net tariff in DKK per kWh | no |
| hourly-prices | String | JSON array with hourly prices from 24 hours ago and onward | yes |

Expand All @@ -56,6 +65,9 @@ This has the following advantages:
- An additional item containing the kWh fee from your electricity supplier can be added also.
- Spot price can be configured in EUR while tariffs are in DKK.

If you want electricity tax included in your total price, please add either `electricity-tax` or `reduced-electricity-tax` to the group - depending on which one applies.
See [Electricity Tax](#electricity-tax) for further information.

#### Value-Added Tax

VAT is not included in any of the prices.
Expand Down Expand Up @@ -107,29 +119,40 @@ _Nord Energi Net:_
| start | StartOfDay |
| offset | -P1D |

#### Electricity Tax

The standard channel for electricity tax is `electricity-tax`.
For customers using electricity for heating, a reduced electricity tax rate may apply (see [Reduced electricity tax applies](#reduced-electricity-tax-applies)).
This reduced rate is made available through channel `reduced-electricity-tax`.

The binding cannot determine or manage rate variations as they depend on metering data.
Usually `reduced-electricity-tax` is preferred when using electricity for heating.

#### Hourly Prices

The format of the `hourly-prices` JSON array is as follows:

```json
[
{
"hourStart": "2023-01-24T15:00:00Z",
"spotPrice": 1.67076001,
"hourStart": "2023-09-19T18:00:00Z",
"spotPrice": 0.0,
"spotPriceCurrency": "DKK",
"netTariff": 0.432225,
"systemTariff": 0.054000,
"electricityTax": 0.008000,
"transmissionNetTariff": 0.058000
"netTariff": 0.0,
"systemTariff": 0.054,
"electricityTax": 0.697,
"reducedElectricityTax": 0.008,
"transmissionNetTariff": 0.058
},
{
"hourStart": "2023-01-24T16:00:00Z",
"spotPrice": 1.859880005,
"hourStart": "2023-09-19T19:00:00Z",
"spotPrice": -0.00052,
"spotPriceCurrency": "DKK",
"netTariff": 1.05619,
"systemTariff": 0.054000,
"electricityTax": 0.008000,
"transmissionNetTariff": 0.058000
"netTariff": 0.0,
"systemTariff": 0.054,
"electricityTax": 0.697,
"reducedElectricityTax": 0.008,
"transmissionNetTariff": 0.058
}
]
```
Expand Down Expand Up @@ -310,14 +333,17 @@ These elements can be requested:
| NetTariff | Net tariff |
| SystemTariff | System tariff |
| ElectricityTax | Electricity tax |
| ReducedElectricityTax | Reduced electricity tax |
| TransmissionNetTariff | Transmission net tariff |

Using `null` as parameter returns the total prices including all price elements.
If **Reduced Electricity Tax** is set in Thing configuration, `ElectricityTax` will be excluded, otherwise `ReducedElectricityTax`.
This logic ensures consistent and comparable results not affected by artifical changes in the rate for electricity tax two times per year.

Example:

```javascript
var priceMap = actions.getPrices("SpotPrice,NetTariff");
var priceMap = actions.getPrices("SpotPrice,NetTariff")
```

## Full Example
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public enum DatahubTariff {
NET_TARIFF(CHANNEL_NET_TARIFF),
SYSTEM_TARIFF(CHANNEL_SYSTEM_TARIFF),
ELECTRICITY_TAX(CHANNEL_ELECTRICITY_TAX),
REDUCED_ELECTRICITY_TAX(CHANNEL_REDUCED_ELECTRICITY_TAX),
TRANSMISSION_NET_TARIFF(CHANNEL_TRANSMISSION_NET_TARIFF);

String channelId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,16 @@ public class EnergiDataServiceBindingConstants {
+ "system-tariff";
public static final String CHANNEL_ELECTRICITY_TAX = CHANNEL_GROUP_ELECTRICITY + ChannelUID.CHANNEL_GROUP_SEPARATOR
+ "electricity-tax";
public static final String CHANNEL_REDUCED_ELECTRICITY_TAX = CHANNEL_GROUP_ELECTRICITY
+ ChannelUID.CHANNEL_GROUP_SEPARATOR + "reduced-electricity-tax";
public static final String CHANNEL_TRANSMISSION_NET_TARIFF = CHANNEL_GROUP_ELECTRICITY
+ ChannelUID.CHANNEL_GROUP_SEPARATOR + "transmission-net-tariff";
public static final String CHANNEL_HOURLY_PRICES = CHANNEL_GROUP_ELECTRICITY + ChannelUID.CHANNEL_GROUP_SEPARATOR
+ "hourly-prices";

public static final Set<String> ELECTRICITY_CHANNELS = Set.of(CHANNEL_SPOT_PRICE, CHANNEL_NET_TARIFF,
CHANNEL_SYSTEM_TARIFF, CHANNEL_ELECTRICITY_TAX, CHANNEL_TRANSMISSION_NET_TARIFF, CHANNEL_HOURLY_PRICES);
CHANNEL_SYSTEM_TARIFF, CHANNEL_ELECTRICITY_TAX, CHANNEL_REDUCED_ELECTRICITY_TAX,
CHANNEL_TRANSMISSION_NET_TARIFF, CHANNEL_HOURLY_PRICES);

// List of all properties
public static final String PROPERTY_REMAINING_CALLS = "remainingCalls";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,22 @@ public class EnergiDataServiceActions implements ThingActions {
private @Nullable EnergiDataServiceHandler handler;

private enum PriceElement {
SPOT_PRICE("spotprice"),
NET_TARIFF("nettariff"),
SYSTEM_TARIFF("systemtariff"),
ELECTRICITY_TAX("electricitytax"),
TRANSMISSION_NET_TARIFF("transmissionnettariff");
SPOT_PRICE("spotprice", null),
NET_TARIFF("nettariff", DatahubTariff.NET_TARIFF),
SYSTEM_TARIFF("systemtariff", DatahubTariff.SYSTEM_TARIFF),
ELECTRICITY_TAX("electricitytax", DatahubTariff.ELECTRICITY_TAX),
REDUCED_ELECTRICITY_TAX("reducedelectricitytax", DatahubTariff.REDUCED_ELECTRICITY_TAX),
TRANSMISSION_NET_TARIFF("transmissionnettariff", DatahubTariff.TRANSMISSION_NET_TARIFF);

private static final Map<String, PriceElement> NAME_MAP = Stream.of(values())
.collect(Collectors.toMap(PriceElement::toString, Function.identity()));

private String name;
private @Nullable DatahubTariff datahubTariff;

private PriceElement(String name) {
private PriceElement(String name, @Nullable DatahubTariff datahubTariff) {
this.name = name;
this.datahubTariff = datahubTariff;
}

@Override
Expand All @@ -90,11 +93,26 @@ public static PriceElement fromString(final String name) {
}
return myEnum;
}

public @Nullable DatahubTariff getDatahubTariff() {
return datahubTariff;
}
}

@RuleAction(label = "@text/action.get-prices.label", description = "@text/action.get-prices.description")
public @ActionOutput(name = "prices", type = "java.util.Map<java.time.Instant, java.math.BigDecimal>") Map<Instant, BigDecimal> getPrices() {
return getPrices(Arrays.stream(PriceElement.values()).collect(Collectors.toSet()));
EnergiDataServiceHandler handler = this.handler;
if (handler == null) {
logger.warn("EnergiDataServiceActions ThingHandler is null.");
return Map.of();
}

boolean isReducedElectricityTax = handler.isReducedElectricityTax();

return getPrices(Arrays.stream(PriceElement.values())
.filter(element -> element != (isReducedElectricityTax ? PriceElement.ELECTRICITY_TAX
: PriceElement.REDUCED_ELECTRICITY_TAX))
.collect(Collectors.toSet()));
}

@RuleAction(label = "@text/action.get-prices.label", description = "@text/action.get-prices.description")
Expand Down Expand Up @@ -236,25 +254,16 @@ private Map<Instant, BigDecimal> getPrices(Set<PriceElement> priceElements) {
prices = new HashMap<>();
}

if (priceElements.contains(PriceElement.NET_TARIFF)) {
Map<Instant, BigDecimal> netTariffMap = handler.getTariffs(DatahubTariff.NET_TARIFF);
mergeMaps(prices, netTariffMap, !spotPricesRequired);
}

if (priceElements.contains(PriceElement.SYSTEM_TARIFF)) {
Map<Instant, BigDecimal> systemTariffMap = handler.getTariffs(DatahubTariff.SYSTEM_TARIFF);
mergeMaps(prices, systemTariffMap, !spotPricesRequired);
}

if (priceElements.contains(PriceElement.ELECTRICITY_TAX)) {
Map<Instant, BigDecimal> electricityTaxMap = handler.getTariffs(DatahubTariff.ELECTRICITY_TAX);
mergeMaps(prices, electricityTaxMap, !spotPricesRequired);
}
for (PriceElement priceElement : PriceElement.values()) {
DatahubTariff datahubTariff = priceElement.getDatahubTariff();
if (datahubTariff == null) {
continue;
}

if (priceElements.contains(PriceElement.TRANSMISSION_NET_TARIFF)) {
Map<Instant, BigDecimal> transmissionNetTariffMap = handler
.getTariffs(DatahubTariff.TRANSMISSION_NET_TARIFF);
mergeMaps(prices, transmissionNetTariffMap, !spotPricesRequired);
if (priceElements.contains(priceElement)) {
Map<Instant, BigDecimal> tariffMap = handler.getTariffs(datahubTariff);
mergeMaps(prices, tariffMap, !spotPricesRequired);
}
}

return prices;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public class DatahubTariffFilterFactory {
private static final String NOTE_NET_TARIFF_C_FLEX_HOUR = NOTE_NET_TARIFF_C_FLEX + " - time";
private static final String NOTE_SYSTEM_TARIFF = "Systemtarif";
private static final String NOTE_ELECTRICITY_TAX = "Elafgift";
private static final String NOTE_REDUCED_ELECTRICITY_TAX = "Reduceret elafgift";
private static final String NOTE_TRANSMISSION_NET_TARIFF = "Transmissions nettarif";

public static final LocalDate N1_CUTOFF_DATE = LocalDate.of(2023, 1, 1);
Expand Down Expand Up @@ -171,6 +172,11 @@ public static DatahubTariffFilter getElectricityTax() {
DateQueryParameter.of(ENERGINET_CUTOFF_DATE));
}

public static DatahubTariffFilter getReducedElectricityTax() {
return new DatahubTariffFilter(Set.of(), Set.of(NOTE_REDUCED_ELECTRICITY_TAX),
DateQueryParameter.of(LocalDate.of(2021, 2, 1)));
}

public static DatahubTariffFilter getTransmissionNetTariff() {
return new DatahubTariffFilter(Set.of(), Set.of(NOTE_TRANSMISSION_NET_TARIFF),
DateQueryParameter.of(ENERGINET_CUTOFF_DATE));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ public class EnergiDataServiceConfiguration {
*/
public String energinetGLN = "5790000432752";

/**
* Reduced electricity tax applies.
* For electric heating customers only.
*/
public boolean reducedElectricityTax;

/**
* Get {@link Currency} representing the configured currency code.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public class EnergiDataServiceHandler extends BaseThingHandler {

private record Price(String hourStart, BigDecimal spotPrice, String spotPriceCurrency,
@Nullable BigDecimal netTariff, @Nullable BigDecimal systemTariff, @Nullable BigDecimal electricityTax,
@Nullable BigDecimal transmissionNetTariff) {
@Nullable BigDecimal reducedElectricityTax, @Nullable BigDecimal transmissionNetTariff) {
}

public EnergiDataServiceHandler(Thing thing, HttpClient httpClient, TimeZoneProvider timeZoneProvider) {
Expand Down Expand Up @@ -246,6 +246,7 @@ private void downloadTariffs(DatahubTariff datahubTariff) throws InterruptedExce
case NET_TARIFF -> getNetTariffFilter();
case SYSTEM_TARIFF -> DatahubTariffFilterFactory.getSystemTariff();
case ELECTRICITY_TAX -> DatahubTariffFilterFactory.getElectricityTax();
case REDUCED_ELECTRICITY_TAX -> DatahubTariffFilterFactory.getReducedElectricityTax();
case TRANSMISSION_NET_TARIFF -> DatahubTariffFilterFactory.getTransmissionNetTariff();
};
cacheManager.putTariffs(datahubTariff, downloadPriceLists(globalLocationNumber, filter));
Expand Down Expand Up @@ -339,9 +340,10 @@ private void updateHourlyPrices() {
BigDecimal netTariff = cacheManager.getTariff(DatahubTariff.NET_TARIFF, hourStart);
BigDecimal systemTariff = cacheManager.getTariff(DatahubTariff.SYSTEM_TARIFF, hourStart);
BigDecimal electricityTax = cacheManager.getTariff(DatahubTariff.ELECTRICITY_TAX, hourStart);
BigDecimal reducedElectricityTax = cacheManager.getTariff(DatahubTariff.REDUCED_ELECTRICITY_TAX, hourStart);
BigDecimal transmissionNetTariff = cacheManager.getTariff(DatahubTariff.TRANSMISSION_NET_TARIFF, hourStart);
targetPrices[i++] = new Price(hourStart.toString(), sourcePrice.getValue(), config.currencyCode, netTariff,
systemTariff, electricityTax, transmissionNetTariff);
systemTariff, electricityTax, reducedElectricityTax, transmissionNetTariff);
}
updateState(CHANNEL_HOURLY_PRICES, new StringType(gson.toJson(targetPrices)));
}
Expand Down Expand Up @@ -399,6 +401,15 @@ public Map<Instant, BigDecimal> getTariffs(DatahubTariff datahubTariff) {
return cacheManager.getTariffs(datahubTariff);
}

/**
* Return whether reduced electricity tax is set in configuration.
*
* @return true if reduced electricity tax applies
*/
public boolean isReducedElectricityTax() {
return config.reducedElectricityTax;
}

private void reschedulePriceUpdateJob() {
ScheduledFuture<?> priceUpdateJob = this.priceUpdateFuture;
if (priceUpdateJob != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@
<advanced>true</advanced>
<default>5790000432752</default>
</parameter>
<parameter name="reducedElectricityTax" type="boolean">
<label>Reduced Electricity Tax</label>
<description>Reduced electricity tax applies. For electric heating customers only.</description>
<default>false</default>
</parameter>
</config-description>

<config-description uri="channel-type:energidataservice:datahub-price">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ thing-type.config.energidataservice.service.priceArea.label = Price Area
thing-type.config.energidataservice.service.priceArea.description = Price area for spot prices (same as bidding zone).
thing-type.config.energidataservice.service.priceArea.option.DK1 = West of the Great Belt
thing-type.config.energidataservice.service.priceArea.option.DK2 = East of the Great Belt
thing-type.config.energidataservice.service.reducedElectricityTax.label = Reduced Electricity Tax
thing-type.config.energidataservice.service.reducedElectricityTax.description = Reduced electricity tax applies. For electric heating customers only.

# channel group types

Expand All @@ -60,6 +62,8 @@ channel-group-type.energidataservice.electricity.channel.electricity-tax.label =
channel-group-type.energidataservice.electricity.channel.electricity-tax.description = Current electricity tax in DKK per kWh.
channel-group-type.energidataservice.electricity.channel.net-tariff.label = Net Tariff
channel-group-type.energidataservice.electricity.channel.net-tariff.description = Current net tariff in DKK per kWh.
channel-group-type.energidataservice.electricity.channel.reduced-electricity-tax.label = Reduced Electricity Tax
channel-group-type.energidataservice.electricity.channel.reduced-electricity-tax.description = Current reduced electricity tax in DKK per kWh. For electric heating customers only.
channel-group-type.energidataservice.electricity.channel.spot-price.label = Spot Price
channel-group-type.energidataservice.electricity.channel.spot-price.description = Current spot price in DKK or EUR per kWh.
channel-group-type.energidataservice.electricity.channel.system-tariff.label = System Tariff
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
<label>Electricity Tax</label>
<description>Current electricity tax in DKK per kWh.</description>
</channel>
<channel id="reduced-electricity-tax" typeId="datahub-price">
<label>Reduced Electricity Tax</label>
<description>Current reduced electricity tax in DKK per kWh. For electric heating customers only.</description>
</channel>
<channel id="transmission-net-tariff" typeId="datahub-price">
<label>Transmission Net Tariff</label>
<description>Current transmission net tariff in DKK per kWh.</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
<channel-group id="electricity" typeId="electricity"/>
</channel-groups>

<properties>
<property name="thingTypeVersion">1</property>
</properties>

<config-description-ref uri="thing-type:energidataservice:service"/>
</thing-type>

Expand Down
Loading