2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.bsblan.internal.api;
15 import static org.openhab.binding.bsblan.internal.BsbLanBindingConstants.API_TIMEOUT;
17 import java.io.ByteArrayInputStream;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.nio.charset.StandardCharsets;
22 import java.util.stream.Collectors;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiContentDTO;
27 import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterQueryResponseDTO;
28 import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterSetRequestDTO;
29 import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterSetResponseDTO;
30 import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterSetResultDTO;
31 import org.openhab.binding.bsblan.internal.configuration.BsbLanBridgeConfiguration;
32 import org.openhab.core.io.net.http.HttpUtil;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
37 * Utility class to call the BSB-LAN REST API.
39 * @author Peter Schraffl - Initial contribution
42 public class BsbLanApiCaller {
44 private final Logger logger = LoggerFactory.getLogger(BsbLanApiCaller.class);
45 private final BsbLanBridgeConfiguration bridgeConfig;
47 public BsbLanApiCaller(BsbLanBridgeConfiguration config) {
48 bridgeConfig = config;
51 public @Nullable BsbLanApiParameterQueryResponseDTO queryParameter(Integer parameterId) {
52 return queryParameters(Set.of(parameterId));
55 public @Nullable BsbLanApiParameterQueryResponseDTO queryParameters(Set<Integer> parameterIds) {
56 // note: make the request even if parameterIds is empty as
57 // thing OFFLINE/ONLINE detection relies on a response
58 String apiPath = String.format("/JQ=%s",
59 parameterIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
60 return makeRestCall(BsbLanApiParameterQueryResponseDTO.class, "GET", apiPath, null);
63 public boolean setParameter(Integer parameterId, String value, BsbLanApiParameterSetRequestDTO.Type type) {
64 // prepare request content
65 BsbLanApiParameterSetRequestDTO request = new BsbLanApiParameterSetRequestDTO();
66 request.parameter = parameterId.toString();
67 request.value = value;
70 // make REST call and process response
71 BsbLanApiParameterSetResponseDTO setResponse = makeRestCall(BsbLanApiParameterSetResponseDTO.class, "POST",
73 if (setResponse == null) {
74 logger.debug("Failed to set parameter {} to '{}': no response received", parameterId, value);
78 BsbLanApiParameterSetResultDTO result = setResponse.getOrDefault(parameterId, null);
80 logger.debug("Failed to set parameter {} to '{}'': result is null", parameterId, value);
83 if (result.status == null) {
84 logger.debug("Failed to set parameter {} to '{}': status is null", parameterId, value);
87 if (result.status != BsbLanApiParameterSetResultDTO.Status.SUCCESS) {
88 logger.debug("Failed to set parameter {} to '{}': status = {}", parameterId, value, result.status);
94 private String createApiBaseUrl() {
95 final String host = bridgeConfig.host.trim();
96 final String username = bridgeConfig.username.trim();
97 final String password = bridgeConfig.password.trim();
98 final String passkey = bridgeConfig.passkey.trim();
100 StringBuilder url = new StringBuilder();
101 url.append("http://");
102 if (!username.isBlank() && !password.isBlank()) {
103 url.append(username).append(":").append(password).append("@");
106 if (bridgeConfig.port != 80) {
107 url.append(":").append(bridgeConfig.port);
109 if (!passkey.isBlank()) {
110 url.append("/").append(passkey);
112 return url.toString();
116 * @param responseType response class type
117 * @param httpMethod to execute
118 * @param apiPath to request
119 * @param content to add to request
120 * @return the object representation of the json response
122 private <T> @Nullable T makeRestCall(Class<T> responseType, String httpMethod, String apiPath,
123 @Nullable BsbLanApiContentDTO request) {
125 String url = createApiBaseUrl() + apiPath;
126 logger.trace("api request url = '{}'", url);
128 InputStream contentStream = null;
129 String contentType = null;
130 if (request != null) {
131 String content = BsbLanApiContentConverter.toJson(request);
132 logger.trace("api request content: '{}'", content);
133 if (!content.isBlank()) {
134 contentStream = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
135 contentType = "application/json";
139 String response = HttpUtil.executeUrl(httpMethod, url, contentStream, contentType, API_TIMEOUT);
140 if (response == null) {
141 logger.debug("no response returned");
145 logger.trace("api response content: '{}'", response);
146 return BsbLanApiContentConverter.fromJson(response, responseType);
147 } catch (IOException | IllegalStateException e) {
148 logger.debug("Error executing bsb-lan api request: {}", e.getMessage());