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.seneye.internal;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.ScheduledExecutorService;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
19 import java.util.concurrent.TimeoutException;
21 import org.eclipse.jetty.client.HttpClient;
22 import org.eclipse.jetty.client.api.ContentResponse;
23 import org.eclipse.jetty.client.api.Request;
24 import org.eclipse.jetty.http.HttpStatus;
25 import org.eclipse.jetty.util.ssl.SslContextFactory;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
29 import com.google.gson.Gson;
32 * The {@link SeneyeService} handles the connection to the Seneye API
34 * @author Niko Tanghe - Initial contribution
37 public class SeneyeService {
39 private final Logger logger = LoggerFactory.getLogger(SeneyeService.class);
41 private SeneyeConfigurationParameters config;
42 private String seneyeId;
43 public int seneyeType;
44 private boolean isInitialized;
45 private final Gson gson;
46 private HttpClient httpClient = new HttpClient(new SslContextFactory.Client());
47 private ScheduledFuture<?> scheduledJob;
49 public SeneyeService(SeneyeConfigurationParameters config) throws CommunicationException {
54 this.gson = new Gson();
56 this.isInitialized = false;
58 if (!httpClient.isStarted()) {
60 httpClient.setFollowRedirects(false);
62 } catch (Exception e) {
63 throw new CommunicationException("Cannot start HttpClient!", e);
69 public void finalize() {
72 } catch (Exception e) {
78 public void startAutomaticRefresh(ScheduledExecutorService scheduledExecutorService,
79 final ReadingsUpdate readingsUpdate) {
80 scheduledJob = scheduledExecutorService.scheduleWithFixedDelay(() -> {
81 readingsUpdate.newState(getDeviceReadings());
82 }, 0, config.poll_time, TimeUnit.MINUTES);
85 public void stopAutomaticRefresh() {
86 if (scheduledJob != null) {
87 scheduledJob.cancel(true);
91 public SeneyeDeviceReading getDeviceReadings() {
95 String responseState = getData("/" + seneyeId + "/state?" + getCredentials());
96 String responseReadings = getData("/" + seneyeId + "/exps?" + getCredentials());
98 SeneyeDeviceReading readings = gson.fromJson(responseReadings, SeneyeDeviceReading.class);
99 readings.status = gson.fromJson(responseState, SeneyeStatus.class);
100 logger.debug("seneye '{}' read", this.seneyeId);
103 } catch (Exception se) {
104 // ok, this readout failed, swallow this error, this is a scheduled task and this is in a retry loop,
105 // so it will be retried.
106 logger.debug("failed to read seneye '{}'", se.getMessage());
108 } while (currentTry++ < this.retry);
113 public void initialize() throws CommunicationException, InvalidConfigurationException {
114 String response = getData("?" + getCredentials());
116 Seneye[] seneyeDevices = gson.fromJson(response, Seneye[].class);
118 for (Seneye seneye : seneyeDevices) {
119 if (seneye.description.equals(config.aquarium_name)) {
120 seneyeId = Integer.toString(seneye.id);
121 seneyeType = (seneye.type);
122 isInitialized = true;
126 throw new InvalidConfigurationException(
127 "Could not find a seneye with aquarium name '" + config.aquarium_name + "'");
130 public boolean isInitialized() {
131 return isInitialized;
134 private String getData(String request) throws CommunicationException {
136 // https://api.seneye.com/v1/devices?user=emailaddress&pwd=xxx
139 // https://api.seneye.com/v1/devices/23142/state?user=emailaddress&pwd=xxx
142 // https://api.seneye.com/v1/devices/23142/exps?user=emailaddress&pwd=xxx
145 // https://api.seneye.com/v1/devices/23142/advices/<id>?user=emailaddress&pwd=xxx
147 String url = "https://api.seneye.com/v1/devices" + request;
149 Request getMethod = httpClient.newRequest(url);
150 getMethod.accept("application/json");
153 ContentResponse response = getMethod.send();
154 if (response.getStatus() != HttpStatus.OK_200) {
155 logger.debug("Get readings method failed: {}", response.getReason());
159 return response.getContentAsString();
160 } catch (InterruptedException e) {
161 throw new CommunicationException("Request aborted", e);
162 } catch (TimeoutException e) {
163 throw new CommunicationException("Timeout error", e);
164 } catch (ExecutionException e) {
165 throw new CommunicationException("Communication error", e.getCause());
169 private String getCredentials() {
170 return "user=" + config.username + "&pwd=" + config.password;