added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.seneye</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -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

View File

@@ -0,0 +1,81 @@
# Seneye Binding
This binding integrates the [Seneye aquarium monitoring system](https://www.seneye.com).
## Introduction
The seneye monitor monitors what is happening inside your aquarium to ensure that the aquatic life remains healthy.
The monitor allows you to continuously track the changes in the water parameters, alerting you to the problems before they affect the fish.
At least one Seneye monitor is required ([Home / pond or reef](https://www.seneye.com/devices/compare)) and the measure results must be synced to the seneye cloud by using a seneye web server (see [shop](https://www.seneye.com/store), there is one for wifi and one for a wired network)
Each monitor is represented by one seneye thing.
## Supported Things
This binding provides one thing type: 'seneye'.
You can have multiple seneye devices in your home, just make sure that your aquarium_name is properly set for each seneye thing.
## Discovery
Discovery is not supported, the seneye monitor must be configured manually.
## Thing Configuration
The following settings must be configured in order to make your seneye binding work:
| Setting | |
|----------------------|---------------------------------------------------------------------------------|
| aquarium_name | The name of the aquarium, as specified in [seneye.me](https://www.seneye.me/). |
| | Useful to distinguish multiple seneye installations. |
| username | Your login name for [seneye.me](https://www.seneye.me/) |
| password | Your password for [seneye.me](https://www.seneye.me/) |
| poll_time | How often (in minutes) should the seneye account be checked. |
## Channels
The following channels are supported:
| Channel Type ID | Item Type | Description |
|-------------------------|--------------|------------------------------------------------------------------|
| temperature | String | The water temperature |
| ph | String | The PH level of the water |
| nh3 | String | The level of Ammonia (NH3) in the water |
| nh4 | String | The level of Ammonium (NH4) in the water |
| O2 | String | The level of oxygene in the water |
| lux | String | The lux level of your aquarium lightning, if available |
| par | String | The par level of your aquarium lightning, if available |
| kelvin | String | The kelvin level of your aquarium lightning, if available |
| lastreading | DateTime | The moment when the last readings are received from the monitor |
| slideexpires | DateTime | The moment when the current slide will expire |
| wrongslide | String | The Slide is not valid (normally expired) |
| slideserial | String | The serial number of the Slide |
| outofwater | String | The Slide is reporting being out of the water |
| disconnected | String | The Seneye has not uploaded any updates recently |
## Full example
A manual configuration through a `things/seneye.things` file could look like this:
```
Thing seneye:monitor:mySeneye "Seneye" @ "Living Room" [aquarium_name="MyAquarium", username="mail@example.com", password="xxx", poll_time=5]
```
A manual configuration through a `demo.items` file could look like this:
```
String mySeneye_Temperature "Temp [%s] C" { channel="seneye:monitor:mySeneye:temperature" }
String mySeneye_PH "PH [%s]" { channel="seneye:monitor:mySeneye:ph" }
String mySeneye_NH3 "NH3 [%s]" { channel="seneye:monitor:mySeneye:nh3" }
```
The sitemap could look like this:
```
sitemap home label="My home" {
Frame label="Aquarium" {
Text item=mySeneye_Temperature label="Temperature [%.1f °C]" icon="temperature"
Text item=mySeneye_PH label="PH [%.1f]" icon="water"
Text item=mySeneye_NH3 label="NH3 [%.1f]" icon="water"
}
}
```

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.seneye</artifactId>
<name>openHAB Add-ons :: Bundles :: Seneye Binding</name>
</project>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.seneye-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-seneye" description="Seneye Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.seneye/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* There was an error while communicating with the seneye API.
* This will be mostly temporary communication errors.
*
* @author Niko Tanghe - Initial contribution
*/
public class CommunicationException extends Exception {
private static final long serialVersionUID = -1397248504578142737L;
public CommunicationException(String message) {
super(message);
}
public CommunicationException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* There was an error in the seneye configuration
*
* @author Niko Tanghe - Initial contribution
*/
public class InvalidConfigurationException extends Exception {
private static final long serialVersionUID = -2894268584378662737L;
public InvalidConfigurationException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* Interface for readings updates
*
* @author Niko Tanghe - Initial contribution
*/
public interface ReadingsUpdate {
public void newState(SeneyeDeviceReading devicereadings);
public void invalidConfig();
}

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* Identification of a seneye device
*
* @author Niko Tanghe - Initial contribution
*/
public class Seneye {
public int id;
public String description;
public int type;
public int time_diff;
}

View File

@@ -0,0 +1,57 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
import java.util.Collections;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link SeneyeBinding} class defines common constants, which are
* used across the whole binding.
*
* @author Niko Tanghe - Initial contribution
*/
@NonNullByDefault
public class SeneyeBindingConstants {
public static final String BINDING_ID = "seneye";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_SENEYE = new ThingTypeUID(BINDING_ID, "monitor");
// List of all Channel ids
public static final String CHANNEL_TEMPERATURE = "temperature";
public static final String CHANNEL_PH = "ph";
public static final String CHANNEL_NH3 = "nh3";
public static final String CHANNEL_NH4 = "nh4";
public static final String CHANNEL_O2 = "O2";
public static final String CHANNEL_LUX = "lux";
public static final String CHANNEL_PAR = "par";
public static final String CHANNEL_KELVIN = "kelvin";
public static final String CHANNEL_LASTREADING = "lastreading";
public static final String CHANNEL_SLIDEEXPIRES = "slideexpires";
public static final String CHANNEL_WRONGSLIDE = "wrongslide";
public static final String CHANNEL_SLIDESERIAL = "slideserial";
public static final String CHANNEL_OUTOFWATER = "outofwater";
public static final String CHANNEL_DISCONNECTED = "disconnected";
// List of all Parameters
public static final String PARAMETER_AQUARIUMNAME = "aquariumname";
public static final String PARAMETER_USERNAME = "username";
public static final String PARAMETER_PASSWORD = "password";
public static final String PARAMETER_POLLTIME = "polltime";
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_SENEYE);
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* Contains the configuration parameters for the smappee device.
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeConfigurationParameters {
/** The name of your aquarium. */
public String aquarium_name;
/** The username for My Seneye. */
public String username;
/** The password for My Seneye. */
public String password;
/** How often (in minutes) does the seneye needs to be checked ? */
public int poll_time;
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* The result of a seneye readout
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeDeviceReading {
public SeneyeStatus status;
public SeneyeDeviceReadingTemperature temperature;
public SeneyeDeviceReadingPh ph;
public SeneyeDeviceReadingNh3 nh3;
public SeneyeDeviceReadingNh4 nh4;
public SeneyeDeviceReadingO2 o2;
public SeneyeDeviceReadingLux lux;
public SeneyeDeviceReadingPar par;
public SeneyeDeviceReadingKelvin kelvin;
}

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* The result of a seneye readout - advice which action to take
* Now empty because not sure what this should contain
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeDeviceReadingAdvice {
}

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* The result of a seneye readout - Light intensity in Kelvin
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeDeviceReadingKelvin {
public double curr;
public SeneyeDeviceReadingAdvice[] advices;
}

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* The result of a seneye readout - Light intensity in Lux
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeDeviceReadingLux {
public double curr;
public SeneyeDeviceReadingAdvice[] advices;
}

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* The result of a seneye readout - The NH3 water level
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeDeviceReadingNh3 {
public int trend;
public int critical_in;
public double avg;
public boolean status;
public double curr;
public SeneyeDeviceReadingAdvice[] advices;
}

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* The result of a seneye readout - The NH4 water level
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeDeviceReadingNh4 {
public int trend;
public int critical_in;
public double avg;
public boolean status;
public double curr;
public SeneyeDeviceReadingAdvice[] advices;
}

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* The result of a seneye readout - The O2 water level
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeDeviceReadingO2 {
public int trend;
public int critical_in;
public double avg;
public boolean status;
public double curr;
public SeneyeDeviceReadingAdvice[] advices;
}

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* The result of a seneye readout - Light intensity in Par
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeDeviceReadingPar {
public double curr;
public SeneyeDeviceReadingAdvice[] advices;
}

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* The result of a seneye readout - The PH water level
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeDeviceReadingPh {
public int trend;
public int critical_in;
public double avg;
public boolean status;
public double curr;
public SeneyeDeviceReadingAdvice[] advices;
}

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
/**
* The result of a seneye readout - The water Temperature level
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeDeviceReadingTemperature {
public int trend;
public int critical_in;
public double avg;
public boolean status;
public double curr;
public SeneyeDeviceReadingAdvice[] advices;
}

View File

@@ -0,0 +1,54 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
import static org.openhab.binding.seneye.internal.SeneyeBindingConstants.THING_TYPE_SENEYE;
import java.util.Collections;
import java.util.Set;
import org.openhab.binding.seneye.internal.handler.SeneyeHandler;
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.Component;
/**
* The {@link SeneyeHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Niko Tanghe - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.seneye")
public class SeneyeHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_SENEYE);
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(THING_TYPE_SENEYE)) {
return new SeneyeHandler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,172 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
/**
* The {@link SeneyeService} handles the connection to the Seneye API
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeService {
private final Logger logger = LoggerFactory.getLogger(SeneyeService.class);
private int retry;
private SeneyeConfigurationParameters config;
private String seneyeId;
public int seneyeType;
private boolean isInitialized;
private final Gson gson;
private HttpClient httpClient = new HttpClient(new SslContextFactory());
private ScheduledFuture<?> scheduledJob;
public SeneyeService(SeneyeConfigurationParameters config) throws CommunicationException {
this.config = config;
this.retry = 1;
this.gson = new Gson();
this.isInitialized = false;
if (!httpClient.isStarted()) {
try {
httpClient.setFollowRedirects(false);
httpClient.start();
} catch (Exception e) {
throw new CommunicationException("Cannot start HttpClient!", e);
}
}
}
@Override
public void finalize() {
try {
httpClient.stop();
} catch (Exception e) {
// swallow this
}
httpClient = null;
}
public void startAutomaticRefresh(ScheduledExecutorService scheduledExecutorService,
final ReadingsUpdate readingsUpdate) {
scheduledJob = scheduledExecutorService.scheduleWithFixedDelay(() -> {
readingsUpdate.newState(getDeviceReadings());
}, 0, config.poll_time, TimeUnit.MINUTES);
}
public void stopAutomaticRefresh() {
if (scheduledJob != null) {
scheduledJob.cancel(true);
}
}
public SeneyeDeviceReading getDeviceReadings() {
int currentTry = 0;
do {
try {
String responseState = getData("/" + seneyeId + "/state?" + getCredentials());
String responseReadings = getData("/" + seneyeId + "/exps?" + getCredentials());
SeneyeDeviceReading readings = gson.fromJson(responseReadings, SeneyeDeviceReading.class);
readings.status = gson.fromJson(responseState, SeneyeStatus.class);
logger.debug("seneye '{}' read", this.seneyeId);
return readings;
} catch (Exception se) {
// ok, this readout failed, swallow this error, this is a scheduled task and this is in a retry loop,
// so it will be retried.
logger.debug("failed to read seneye '{}'", se.getMessage());
}
} while (currentTry++ < this.retry);
return null;
}
public void initialize() throws CommunicationException, InvalidConfigurationException {
String response = getData("?" + getCredentials());
Seneye[] seneyeDevices = gson.fromJson(response, Seneye[].class);
for (Seneye seneye : seneyeDevices) {
if (seneye.description.equals(config.aquarium_name)) {
seneyeId = Integer.toString(seneye.id);
seneyeType = (seneye.type);
isInitialized = true;
return;
}
}
throw new InvalidConfigurationException(
"Could not find a seneye with aquarium name '" + config.aquarium_name + "'");
}
public boolean isInitialized() {
return isInitialized;
}
private String getData(String request) throws CommunicationException {
// get devices
// https://api.seneye.com/v1/devices?user=emailaddress&pwd=xxx
// get devicestatus
// https://api.seneye.com/v1/devices/23142/state?user=emailaddress&pwd=xxx
// get readings
// https://api.seneye.com/v1/devices/23142/exps?user=emailaddress&pwd=xxx
// get advices
// https://api.seneye.com/v1/devices/23142/advices/<id>?user=emailaddress&pwd=xxx
String url = "https://api.seneye.com/v1/devices" + request;
Request getMethod = httpClient.newRequest(url);
getMethod.accept("application/json");
try {
ContentResponse response = getMethod.send();
if (response.getStatus() != HttpStatus.OK_200) {
logger.debug("Get readings method failed: {}", response.getReason());
return "";
}
return response.getContentAsString();
} catch (InterruptedException e) {
throw new CommunicationException("Request aborted", e);
} catch (TimeoutException e) {
throw new CommunicationException("Timeout error", e);
} catch (ExecutionException e) {
throw new CommunicationException("Communication error", e.getCause());
}
}
private String getCredentials() {
return "user=" + config.username + "&pwd=" + config.password;
}
}

View File

@@ -0,0 +1,60 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal;
import org.openhab.core.library.types.DateTimeType;
/**
* The Status of the seneye device
*
* @author Niko Tanghe - Initial contribution
*/
public class SeneyeStatus {
public String disconnected;
public String slide_serial;
public String slide_expires;
public String out_of_water;
public String wrong_slide;
public String last_experiment;
public String getLast_experimentDate() {
return getTickAsDate(last_experiment);
}
public String getSlide_expiresDate() {
return getTickAsDate(slide_expires);
}
private String getTickAsDate(String tick) {
String date = new java.text.SimpleDateFormat(DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS_ISO)
.format(new java.util.Date(Long.parseLong(tick) * 1000));
return date;
}
public String getWrong_slideString() {
return wrong_slide;
}
public String getSlide_serialString() {
return slide_serial;
}
public String getOut_of_waterString() {
return out_of_water;
}
public String getDisconnectedString() {
return disconnected;
}
}

View File

@@ -0,0 +1,168 @@
/**
* Copyright (c) 2010-2020 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.seneye.internal.handler;
import static org.openhab.binding.seneye.internal.SeneyeBindingConstants.*;
import java.util.concurrent.TimeUnit;
import org.openhab.binding.seneye.internal.CommunicationException;
import org.openhab.binding.seneye.internal.InvalidConfigurationException;
import org.openhab.binding.seneye.internal.ReadingsUpdate;
import org.openhab.binding.seneye.internal.SeneyeConfigurationParameters;
import org.openhab.binding.seneye.internal.SeneyeDeviceReading;
import org.openhab.binding.seneye.internal.SeneyeService;
import org.openhab.core.cache.ExpiringCache;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SeneyeHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Niko Tanghe - Initial contribution
*/
public final class SeneyeHandler extends BaseThingHandler implements ReadingsUpdate {
private final Logger logger = LoggerFactory.getLogger(SeneyeHandler.class);
private SeneyeService seneyeService;
private ExpiringCache<SeneyeDeviceReading> cachedSeneyeDeviceReading;
public SeneyeHandler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (seneyeService == null || !seneyeService.isInitialized()) {
return;
}
if (command instanceof RefreshType) {
SeneyeDeviceReading readings = cachedSeneyeDeviceReading.getValue();
newState(readings);
} else {
logger.debug("Command {} is not supported for channel: {}", command, channelUID.getId());
}
}
@Override
public void newState(SeneyeDeviceReading readings) {
if (readings != null) {
logger.debug("Updating readings for sensor type {}", seneyeService.seneyeType);
switch (seneyeService.seneyeType) {
case 3:
updateState(CHANNEL_NH4, new DecimalType(readings.nh4.curr));
updateState(CHANNEL_PAR, new DecimalType(readings.par.curr));
updateState(CHANNEL_LUX, new DecimalType(readings.lux.curr));
updateState(CHANNEL_KELVIN, new DecimalType(readings.kelvin.curr));
case 2:
updateState(CHANNEL_O2, new DecimalType(readings.o2.curr));
case 1:
updateState(CHANNEL_TEMPERATURE, new DecimalType(readings.temperature.curr));
updateState(CHANNEL_NH3, new DecimalType(readings.nh3.curr));
updateState(CHANNEL_PH, new DecimalType(readings.ph.curr));
updateState(CHANNEL_LASTREADING, new DateTimeType(readings.status.getLast_experimentDate()));
updateState(CHANNEL_SLIDEEXPIRES, new DateTimeType(readings.status.getSlide_expiresDate()));
updateState(CHANNEL_WRONGSLIDE, new StringType(readings.status.getWrong_slideString()));
updateState(CHANNEL_SLIDESERIAL, new StringType(readings.status.getSlide_serialString()));
updateState(CHANNEL_OUTOFWATER, new StringType(readings.status.getOut_of_waterString()));
updateState(CHANNEL_DISCONNECTED, new StringType(readings.status.getDisconnectedString()));
}
}
}
@Override
public void invalidConfig() {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
}
@Override
public void initialize() {
SeneyeConfigurationParameters config = getConfigAs(SeneyeConfigurationParameters.class);
if (config.aquarium_name == null || config.aquarium_name.isEmpty()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Check configuration, Aquarium name must be provided");
return;
}
if (config.username == null || config.username.isEmpty()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Check configuration, Seneye username must be provided");
return;
}
if (config.password == null || config.password.isEmpty()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Check configuration, Seneye password must be provided");
return;
}
logger.debug("Initializing Seneye API service.");
try {
this.seneyeService = new SeneyeService(config);
} catch (CommunicationException ex) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ex.getMessage());
return; // critical error
}
super.initialize();
// contact Seneye API
scheduler.submit(() -> {
initializeSeneyeService();
});
}
private void initializeSeneyeService() {
try {
seneyeService.initialize();
} catch (CommunicationException ex) {
// try again in 30 secs
scheduler.schedule(() -> {
initializeSeneyeService();
}, 30, TimeUnit.SECONDS);
return;
} catch (InvalidConfigurationException ex) {
// bad configuration, stay offline until user corrects the configuration
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, ex.getMessage());
return;
}
// ok, initialization succeeded
cachedSeneyeDeviceReading = new ExpiringCache<>(TimeUnit.SECONDS.toMillis(10), () -> {
return seneyeService.getDeviceReadings();
});
seneyeService.startAutomaticRefresh(scheduler, this);
updateStatus(ThingStatus.ONLINE);
}
@Override
public void dispose() {
seneyeService.stopAutomaticRefresh();
seneyeService = null;
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="seneye" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>Seneye Binding</name>
<description>The seneye binding polls the seneye API for your aquarium readings.</description>
<author>Niko Tanghe</author>
</binding:binding>

View File

@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="seneye"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="monitor">
<label>Seneye Monitor</label>
<description>Seneye Monitor</description>
<channels>
<channel id="temperature" typeId="temperature"/>
<channel id="ph" typeId="ph"/>
<channel id="nh3" typeId="nh3"/>
<channel id="nh4" typeId="nh4"/>
<channel id="O2" typeId="o2"/>
<channel id="lux" typeId="lux"/>
<channel id="par" typeId="par"/>
<channel id="kelvin" typeId="kelvin"/>
<channel id="lastreading" typeId="lastreading"/>
<channel id="slideexpires" typeId="slideexpires"/>
<channel id="wrongslide" typeId="wrongslide"/>
<channel id="slideserial" typeId="slideserial"/>
<channel id="outofwater" typeId="outofwater"/>
<channel id="disconnected" typeId="disconnected"/>
</channels>
<config-description>
<parameter name="aquarium_name" type="text" required="true">
<label>Aquarium Name</label>
<description>The name of your aquarium</description>
</parameter>
<parameter name="username" type="text" required="true">
<label>Username</label>
<description>The email address used to login to My Seneye</description>
</parameter>
<parameter name="password" type="text" required="true">
<label>Password</label>
<description>The password of My Seneye</description>
<context>password</context>
</parameter>
<parameter name="poll_time" type="integer" required="false" min="1" max="1440">
<label>Polling Time</label>
<description>How often (in minutes) does the seneye needs to be checked ?</description>
<default>5</default>
</parameter>
</config-description>
</thing-type>
<!-- Channels -->
<channel-type id="temperature">
<item-type>Number</item-type>
<label>Temperature</label>
<description>The water temperature</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="ph">
<item-type>Number</item-type>
<label>PH</label>
<description>The PH Level</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="nh3">
<item-type>Number</item-type>
<label>NH3</label>
<description>The NH3 Level</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="nh4">
<item-type>Number</item-type>
<label>NH4</label>
<description>The NH4 Level</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="o2">
<item-type>Number</item-type>
<label>O2</label>
<description>The O2 Level</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="lux">
<item-type>Number</item-type>
<label>LUX</label>
<description>The LUX Light Level</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="par">
<item-type>Number</item-type>
<label>PAR</label>
<description>The PAR Light Level</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="kelvin">
<item-type>Number</item-type>
<label>Kelvin</label>
<description>The Kelvin Light Level</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="lastreading">
<item-type>DateTime</item-type>
<label>Last Reading</label>
<description>The last time your seneye is checked</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="slideexpires">
<item-type>DateTime</item-type>
<label>Slide Expiration</label>
<description>The time your slide expires</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="wrongslide">
<item-type>String</item-type>
<label>Wrong Slide</label>
<description>The Wrong Slide is in use (becomes 1 when the slide has expired)</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="slideserial">
<item-type>String</item-type>
<label>Slide Serial Number</label>
<description>The serial Number of the currently installed slide</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="outofwater">
<item-type>String</item-type>
<label>Out of Water</label>
<description>The Sensor is reporting being out of the water</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="disconnected">
<item-type>String</item-type>
<label>Disconnected</label>
<description>No readings have been uploaded for a while, check connection</description>
<state readOnly="true"/>
</channel-type>
</thing:thing-descriptions>