diff --git a/CODEOWNERS b/CODEOWNERS index 79a33f3c15e..dde5c21974c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -115,6 +115,7 @@ /bundles/org.openhab.binding.foobot/ @airboxlab @Hilbrand /bundles/org.openhab.binding.freebox/ @lolodomo /bundles/org.openhab.binding.freeboxos/ @clinique +/bundles/org.openhab.binding.freecurrency/ @J-N-K /bundles/org.openhab.binding.fronius/ @trokohl /bundles/org.openhab.binding.fsinternetradio/ @paphko /bundles/org.openhab.binding.ftpupload/ @paulianttila diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index 44ad3d72de5..761bb476a1d 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -566,6 +566,11 @@ org.openhab.binding.freeboxos ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.freecurrency + ${project.version} + org.openhab.addons.bundles org.openhab.binding.fronius diff --git a/bundles/org.openhab.binding.freecurrency/NOTICE b/bundles/org.openhab.binding.freecurrency/NOTICE new file mode 100644 index 00000000000..38d625e3492 --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/NOTICE @@ -0,0 +1,13 @@ +This content is produced and maintained by the openHAB project. + +* Project home: https://www.openhab.org + +== Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Public License 2.0 which is available at +https://www.eclipse.org/legal/epl-2.0/. + +== Source Code + +https://github.com/openhab/openhab-addons diff --git a/bundles/org.openhab.binding.freecurrency/README.md b/bundles/org.openhab.binding.freecurrency/README.md new file mode 100644 index 00000000000..f44e65bab82 --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/README.md @@ -0,0 +1,40 @@ +# Freecurrency Binding + +The Freecurrency binding connects [Freecurrency API](https://freecurrencyapi.com) to openHAB. +It allows to get exchange rates between supported currencies and acts as a currency provider for openHAB's UoM support. + +The binding automatically updates the exchange rates at 00:01 UTC. +There is a limit of 10 (5.000) free request per minute (month), so a daily refresh (and even some restarts per day) will not get you into trouble. + +## Supported Things + +There is only one thing: `info` which is extensible with exchange rate channels. +You can add as many of these things as you like, but in general one should be sufficient for most use-cases. + +## Binding Configuration + +The binding has two configuration parameters: `apiKey` and `baseCurrency`. + +The `apiKey` is mandatory and can be retrieved from your dashboard after creating a free account at [Freecurrency API website](https://app.freecurrencyapi.com/login). + +The `baseCurrency` defaults to US dollars (`USD`), but can be configured to any other supported currency. +Available currencies are provided as configuration options. +Please note that misconfiguration will result in no exchanges rates being provided. + +## Thing Configuration + +### `info` Thing Configuration + +The thing has no configuration options and is automatically attached to the currency provider. + +## Channels + +| Channel | Channel Type | Item Type | Read/Write | Description | +|----------------|---------------|-----------|------------|----------------------------------------------------------------------------------------------| +| lastUpdate | last-update | DateTime | R/O | The timestamp of the last exchange rate refresh | +| | exchange-rate | Number | R/O | The exchange rate between the configured currency and the base currency (or second currency) | + +The `exchange-rate` channels have two configuration parameters: `currency1` and `currency2`. +Any currency code can be configured for both parameters, but only `currency1` is mandatory. +If you omit `currency2`, the configured base-currency will be used as reference. +Available currencies are provided as configuration options. diff --git a/bundles/org.openhab.binding.freecurrency/pom.xml b/bundles/org.openhab.binding.freecurrency/pom.xml new file mode 100644 index 00000000000..f2c8fef0449 --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/pom.xml @@ -0,0 +1,17 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 4.2.0-SNAPSHOT + + + org.openhab.binding.freecurrency + + openHAB Add-ons :: Bundles :: Freecurrency Binding + + diff --git a/bundles/org.openhab.binding.freecurrency/src/main/feature/feature.xml b/bundles/org.openhab.binding.freecurrency/src/main/feature/feature.xml new file mode 100644 index 00000000000..020f20aacfb --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.freecurrency/${project.version} + + diff --git a/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/ExchangeRateListener.java b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/ExchangeRateListener.java new file mode 100644 index 00000000000..b377012ac8a --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/ExchangeRateListener.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.freecurrency.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link ExchangeRateListener} interface can be implemented to receive a notification when exchange rates have been + * updated. + * + * @author Jan N. Klug - Initial contribution + */ +@NonNullByDefault +public interface ExchangeRateListener { + + void onExchangeRatesChanged(); +} diff --git a/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/FreecurrencyBindingConstants.java b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/FreecurrencyBindingConstants.java new file mode 100644 index 00000000000..4af2bb140e9 --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/FreecurrencyBindingConstants.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.freecurrency.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.type.ChannelTypeUID; + +/** + * The {@link FreecurrencyBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Jan N. Klug - Initial contribution + */ +@NonNullByDefault +public class FreecurrencyBindingConstants { + + private static final String BINDING_ID = "freecurrency"; + + // List of all Thing Type UIDs + public static final ThingTypeUID THING_TYPE_INFO = new ThingTypeUID(BINDING_ID, "info"); + + public static final ChannelTypeUID CHANNEL_TYPE_EXCHANGE_RATE = new ChannelTypeUID(BINDING_ID, "exchange-rate"); + public static final ChannelTypeUID CHANNEL_TYPE_LAST_UPDATE = new ChannelTypeUID(BINDING_ID, "last-update"); +} diff --git a/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/FreecurrencyHandler.java b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/FreecurrencyHandler.java new file mode 100644 index 00000000000..5c07e09f95f --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/FreecurrencyHandler.java @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.freecurrency.internal; + +import static org.openhab.binding.freecurrency.internal.FreecurrencyBindingConstants.CHANNEL_TYPE_EXCHANGE_RATE; +import static org.openhab.binding.freecurrency.internal.FreecurrencyBindingConstants.CHANNEL_TYPE_LAST_UPDATE; + +import java.math.BigDecimal; +import java.time.ZonedDateTime; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.freecurrency.internal.config.FreecurrencyExhangeRateChannelConfig; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.UnDefType; + +/** + * The {@link FreecurrencyHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Jan N. Klug - Initial contribution + */ +@NonNullByDefault +public class FreecurrencyHandler extends BaseThingHandler implements ExchangeRateListener { + private final FreecurrencyProvider freecurrencyProvider; + + public FreecurrencyHandler(Thing thing, FreecurrencyProvider freecurrencyProvider) { + super(thing); + this.freecurrencyProvider = freecurrencyProvider; + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + Channel channel = thing.getChannel(channelUID); + if (RefreshType.REFRESH.equals(command) && channel != null) { + refreshChannel(channel); + } + } + + @Override + public void initialize() { + updateStatus(ThingStatus.ONLINE); + freecurrencyProvider.addListener(this); + } + + @Override + public void dispose() { + freecurrencyProvider.removeListener(this); + } + + private void refreshChannel(Channel channel) { + if (CHANNEL_TYPE_EXCHANGE_RATE.equals(channel.getChannelTypeUID())) { + FreecurrencyExhangeRateChannelConfig config = channel.getConfiguration() + .as(FreecurrencyExhangeRateChannelConfig.class); + BigDecimal val = freecurrencyProvider.getExchangeRate(config.currency1, config.currency2); + updateState(channel.getUID(), val != null ? new DecimalType(val) : UnDefType.UNDEF); + } else if (CHANNEL_TYPE_LAST_UPDATE.equals(channel.getChannelTypeUID())) { + ZonedDateTime lastUpdated = freecurrencyProvider.getLastUpdated(); + updateState(channel.getUID(), lastUpdated == null ? UnDefType.UNDEF : new DateTimeType(lastUpdated)); + } + } + + @Override + public void onExchangeRatesChanged() { + thing.getChannels().forEach(this::refreshChannel); + } +} diff --git a/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/FreecurrencyHandlerFactory.java b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/FreecurrencyHandlerFactory.java new file mode 100644 index 00000000000..b35538908fa --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/FreecurrencyHandlerFactory.java @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.freecurrency.internal; + +import static org.openhab.binding.freecurrency.internal.FreecurrencyBindingConstants.*; + +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * The {@link FreecurrencyHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Jan N. Klug - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.freecurrency", service = ThingHandlerFactory.class) +public class FreecurrencyHandlerFactory extends BaseThingHandlerFactory { + + private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_INFO); + private final FreecurrencyProvider freecurrencyProvider; + + @Activate + public FreecurrencyHandlerFactory(@Reference FreecurrencyProvider freecurrencyProvider) { + this.freecurrencyProvider = freecurrencyProvider; + } + + @Override + public boolean supportsThingType(ThingTypeUID thingTypeUID) { + return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); + } + + @Override + protected @Nullable ThingHandler createHandler(Thing thing) { + ThingTypeUID thingTypeUID = thing.getThingTypeUID(); + + if (THING_TYPE_INFO.equals(thingTypeUID)) { + return new FreecurrencyHandler(thing, freecurrencyProvider); + } + + return null; + } +} diff --git a/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/FreecurrencyProvider.java b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/FreecurrencyProvider.java new file mode 100644 index 00000000000..e7c20e4f899 --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/FreecurrencyProvider.java @@ -0,0 +1,231 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.freecurrency.internal; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.net.URI; +import java.time.Duration; +import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeoutException; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.measure.Unit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.openhab.binding.freecurrency.internal.config.FreecurrencyServiceConfig; +import org.openhab.binding.freecurrency.internal.dto.CurrenciesDTO; +import org.openhab.binding.freecurrency.internal.dto.ExchangeRatesDTO; +import org.openhab.core.config.core.ConfigOptionProvider; +import org.openhab.core.config.core.Configuration; +import org.openhab.core.config.core.ParameterOption; +import org.openhab.core.io.net.http.HttpClientFactory; +import org.openhab.core.library.dimension.Currency; +import org.openhab.core.library.unit.CurrencyProvider; +import org.openhab.core.library.unit.CurrencyUnit; +import org.openhab.core.scheduler.Scheduler; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Modified; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; + +/** + * The {@link FreecurrencyProvider} class implements a {@link CurrencyProvider} based on currencies and dynamic exchange + * rates from Freecurrency API. It also allows to register + * {@link ExchangeRateListener}s for classes that want to be notified about changed exchange rates. + * + * @author Jan N. Klug - Initial contribution + */ +@Component(immediate = true, configurationPid = "binding.freecurrency", configurationPolicy = ConfigurationPolicy.REQUIRE, service = { + CurrencyProvider.class, ConfigOptionProvider.class, FreecurrencyProvider.class }) +@NonNullByDefault +public class FreecurrencyProvider implements CurrencyProvider, ConfigOptionProvider { + private static final CurrencyInformation DEFAULT_CURRENCY_USD = new CurrencyInformation("USD", + new CurrencyUnit("USD", null), "US Dollar"); + private static final Duration REFRESH_OFFSET = Duration.parse("P1DT1M"); + private final Logger logger = LoggerFactory.getLogger(FreecurrencyProvider.class); + private final HttpClient httpClient; + private final Scheduler scheduler; + private final Gson gson = new Gson(); + private @NonNullByDefault({}) FreecurrencyServiceConfig config; + private @Nullable ScheduledFuture refreshJob; + private Map currencies = Map.of(); + private Map, BigDecimal> exchangeRates = Map.of(); + private @Nullable ZonedDateTime lastUpdated = null; + private Set exchangeRateListeners = new HashSet<>(); + + @Activate + public FreecurrencyProvider(@Reference HttpClientFactory httpClientFactory, @Reference Scheduler scheduler, + Map config) { + this.httpClient = httpClientFactory.getCommonHttpClient(); + this.scheduler = scheduler; + modified(config); + } + + @Modified + public void modified(Map config) { + stopRefresh(); + this.config = new Configuration(config).as(FreecurrencyServiceConfig.class); + + if (this.config.apiKey.isBlank()) { + logger.warn("Configuration error: API key must not be blank."); + return; + } + + getCurrencies(); + getExchangeRates(); + } + + @Deactivate + public void deactivate() { + stopRefresh(); + } + + public void addListener(ExchangeRateListener listener) { + exchangeRateListeners.add(listener); + listener.onExchangeRatesChanged(); + } + + public void removeListener(ExchangeRateListener listener) { + exchangeRateListeners.remove(listener); + } + + public @Nullable BigDecimal getExchangeRate(String currency1, String currency2) { + CurrencyInformation info1 = currencies.get(currency1); + CurrencyInformation info2 = currencies.get(currency2.isBlank() ? config.baseCurrency : currency2); + if (info1 == null || info2 == null) { + return null; + } + BigDecimal rate1 = exchangeRates.get(info1.unit()); + BigDecimal rate2 = exchangeRates.get(info2.unit()); + if (rate1 == null || rate2 == null) { + return null; + } + return rate2.divide(rate1, MathContext.DECIMAL128); + } + + public @Nullable ZonedDateTime getLastUpdated() { + return lastUpdated; + } + + private void stopRefresh() { + ScheduledFuture localJob = this.refreshJob; + if (localJob != null) { + localJob.cancel(false); + refreshJob = null; + } + } + + private void getCurrencies() { + String uri = "https://api.freecurrencyapi.com/v1/currencies?apikey=" + config.apiKey; + try { + String currenciesJson = httpClient.GET(uri).getContentAsString(); + CurrenciesDTO currenciesDTO = gson.fromJson(currenciesJson, CurrenciesDTO.class); + currencies = currenciesDTO.data.values().stream() + .map(c -> new CurrencyInformation(c.code, new CurrencyUnit(c.code, null), c.name)) + .collect(Collectors.toMap(CurrencyInformation::code, u -> u)); + logger.debug("Retrieved {} currencies", currencies.size()); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + logger.debug("Failed to request currencies", e); + } + } + + private void getExchangeRates() { + if (!currencies.containsKey(config.baseCurrency)) { + logger.warn("Configuration error: Base currency '{}' is not in list of available currencies {}.", + config.baseCurrency, currencies.keySet()); + return; + } + String uri = "https://api.freecurrencyapi.com/v1/latest?apikey=" + config.apiKey + "&base_currency=" + + config.baseCurrency; + try { + String currenciesJson = httpClient.GET(uri).getContentAsString(); + ExchangeRatesDTO exchangeRatesDTO = gson.fromJson(currenciesJson, ExchangeRatesDTO.class); + Map, BigDecimal> newExchangeRates = new HashMap<>(); + exchangeRatesDTO.data.forEach((k, v) -> { + CurrencyInformation currencyInfo = currencies.get(k); + if (currencyInfo == null) { + logger.debug("Not considering exchange rate for '{}' because it is not supported.", k); + } else { + newExchangeRates.put(currencyInfo.unit, v); + } + }); + exchangeRates = newExchangeRates; + logger.debug("Retrieved exchange rates for {} currencies", newExchangeRates.size()); + lastUpdated = ZonedDateTime.now(); + + // exchange rates are refreshed every day at midnight UTC + // we refresh one minute later to be sure we are not too early. + Instant nextRefresh = Instant.now().truncatedTo(ChronoUnit.DAYS).plus(REFRESH_OFFSET); + refreshJob = scheduler.at(this::getExchangeRates, nextRefresh); + + // notify listeners about changed exchange rates + exchangeRateListeners.forEach(ExchangeRateListener::onExchangeRatesChanged); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + logger.debug("Failed to request currencies", e); + } + } + + @Override + public String getName() { + return "Freecurrency API"; + } + + @Override + public Unit getBaseCurrency() { + return currencies.getOrDefault(config.baseCurrency, DEFAULT_CURRENCY_USD).unit(); + } + + @Override + public Collection> getAdditionalCurrencies() { + return exchangeRates.keySet().stream().filter(c -> !config.baseCurrency.equals(c.getName())).toList(); + } + + @Override + public Function, @Nullable BigDecimal> getExchangeRateFunction() { + return c -> exchangeRates.get(c); + } + + @Override + public @Nullable Collection getParameterOptions(URI uri, String param, @Nullable String context, + @Nullable Locale locale) { + if (("binding:freecurrency".equals(uri.toString()) && "baseCurrency".equals(param)) + || ("channel-type:freecurrency:exchange-rate".equals(uri.toString()) && param.startsWith("currency"))) { + return currencies.values().stream().map(c -> new ParameterOption(c.code(), c.name() + " (" + c.code + ")")) + .toList(); + } + return null; + } + + private record CurrencyInformation(String code, Unit unit, String name) { + } +} diff --git a/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/config/FreecurrencyExhangeRateChannelConfig.java b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/config/FreecurrencyExhangeRateChannelConfig.java new file mode 100644 index 00000000000..4c12784c6fc --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/config/FreecurrencyExhangeRateChannelConfig.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.freecurrency.internal.config; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link FreecurrencyExhangeRateChannelConfig} class defines + * + * @author Jan N. Klug - Initial contribution + */ +@NonNullByDefault +public class FreecurrencyExhangeRateChannelConfig { + public String currency1 = ""; + public String currency2 = ""; +} diff --git a/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/config/FreecurrencyServiceConfig.java b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/config/FreecurrencyServiceConfig.java new file mode 100644 index 00000000000..692fa5ac302 --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/config/FreecurrencyServiceConfig.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.freecurrency.internal.config; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link FreecurrencyServiceConfig} class holds the service configuration + * + * @author Jan N. Klug - Initial contribution + */ +@NonNullByDefault +public class FreecurrencyServiceConfig { + public String apiKey = ""; + public String baseCurrency = "USD"; +} diff --git a/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/dto/CurrenciesDTO.java b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/dto/CurrenciesDTO.java new file mode 100644 index 00000000000..5e33792ea37 --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/dto/CurrenciesDTO.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.freecurrency.internal.dto; + +import java.util.Map; + +import com.google.gson.annotations.SerializedName; + +/** + * The {@link CurrenciesDTO} class is used to retrieve the available currencies + * + * @author Jan N. Klug - Initial contribution + */ +public class CurrenciesDTO { + public Map data; + + public static class CurrencyDTO { + public String symbol; + public String name; + @SerializedName("symbol_native") + public String symbolNative; + @SerializedName("decimal_digits") + public int decimalDigits; + public int rounding; + public String code; + @SerializedName("name_plural") + public String namePlural; + } +} diff --git a/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/dto/ExchangeRatesDTO.java b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/dto/ExchangeRatesDTO.java new file mode 100644 index 00000000000..50596750978 --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/java/org/openhab/binding/freecurrency/internal/dto/ExchangeRatesDTO.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.freecurrency.internal.dto; + +import java.math.BigDecimal; +import java.util.Map; + +/** + * The {@link ExchangeRatesDTO} class is used to retrieve the exchange-rates for all currencies + * + * @author Jan N. Klug - Initial contribution + */ +public class ExchangeRatesDTO { + public Map meta; + public Map data; +} diff --git a/bundles/org.openhab.binding.freecurrency/src/main/resources/OH-INF/addon/addon.xml b/bundles/org.openhab.binding.freecurrency/src/main/resources/OH-INF/addon/addon.xml new file mode 100644 index 00000000000..942caa873c4 --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/resources/OH-INF/addon/addon.xml @@ -0,0 +1,23 @@ + + + + binding + Freecurrency Binding + This is the binding to integrate Freecurrency API as currency provider. + cloud + + + + + The API key retrieved from freecurrencyapi.com + + + + The base currency for this provider. + USD + + + + diff --git a/bundles/org.openhab.binding.freecurrency/src/main/resources/OH-INF/i18n/freecurrency.properties b/bundles/org.openhab.binding.freecurrency/src/main/resources/OH-INF/i18n/freecurrency.properties new file mode 100644 index 00000000000..1a36fb7a54b --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/resources/OH-INF/i18n/freecurrency.properties @@ -0,0 +1,29 @@ +# add-on + +addon.freecurrency.name = Freecurrency Binding +addon.freecurrency.description = This is the binding to integrate Freecurrency API as currency provider. + +# add-on config + +addon.config.freecurrency.apiKey.label = API Key +addon.config.freecurrency.apiKey.description = The API key retrieved from freecurrencyapi.com +addon.config.freecurrency.baseCurrency.label = Base Currency +addon.config.freecurrency.baseCurrency.description = The base currency for this provider. + +# thing types + +thing-type.freecurrency.info.label = Currency Information +thing-type.freecurrency.info.description = Provide exchanges rates between currencies and service status information. + +# channel types + +channel-type.freecurrency.exchange-rate.label = Exchange Rate +channel-type.freecurrency.exchange-rate.description = Exchange rate between two currencies +channel-type.freecurrency.last-update.label = Last Update +channel-type.freecurrency.last-update.description = The timestamp of the last retrieved set of exchange rates. + +# channel types config + +channel-type.config.freecurrency.exchange-rate.currency1.label = Currency 1 +channel-type.config.freecurrency.exchange-rate.currency2.label = Currency 2 +channel-type.config.freecurrency.exchange-rate.currency2.description = Optional, defaults to base currency if not configured. diff --git a/bundles/org.openhab.binding.freecurrency/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.freecurrency/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 00000000000..03e3cbbe095 --- /dev/null +++ b/bundles/org.openhab.binding.freecurrency/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,42 @@ + + + + + + Provide exchanges rates between currencies and service status information. + + + + + + + + + DateTime + + The timestamp of the last retrieved set of exchange rates. + Time + + + + + Number + + Exchange rate between two currencies + + + + + + + + + Optional, defaults to base currency if not configured. + + + + + diff --git a/bundles/pom.xml b/bundles/pom.xml index 14f345d1dfb..f97ad738a32 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -147,6 +147,7 @@ org.openhab.binding.foobot org.openhab.binding.freebox org.openhab.binding.freeboxos + org.openhab.binding.freecurrency org.openhab.binding.fronius org.openhab.binding.fsinternetradio org.openhab.binding.ftpupload