[WlanThermo] Add support for new ESP32-powered devices [V3.x] (#9579)

* Add support for ESP32 devices
* Add Unit Tests
Ensure Gson objects are NonNull
Generify Handlers
Generify Utils

Signed-off-by: Christian Schlipp <christian@schlipp.de>
This commit is contained in:
CSchlipp 2021-01-19 00:58:20 +01:00 committed by GitHub
parent ce6954a891
commit d8e5a57de9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
72 changed files with 5155 additions and 1403 deletions

View File

@ -13,6 +13,7 @@
package org.openhab.binding.wlanthermo.internal; package org.openhab.binding.wlanthermo.internal;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.ThingTypeUID;
/** /**
@ -27,11 +28,17 @@ public class WlanThermoBindingConstants {
private static final String BINDING_ID = "wlanthermo"; private static final String BINDING_ID = "wlanthermo";
// List of all Thing Type UIDs // List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_WLANTHERMO_NANO = new ThingTypeUID(BINDING_ID, "nano"); public static final ThingTypeUID THING_TYPE_WLANTHERMO_NANO_V1 = new ThingTypeUID(BINDING_ID, "nano");
public static final ThingTypeUID THING_TYPE_WLANTHERMO_MINI = new ThingTypeUID(BINDING_ID, "mini"); public static final ThingTypeUID THING_TYPE_WLANTHERMO_MINI = new ThingTypeUID(BINDING_ID, "mini");
public static final ThingTypeUID THING_TYPE_WLANTHERMO_ESP32 = new ThingTypeUID(BINDING_ID, "esp32");
// ThreadPool // Properties
public static final String WLANTHERMO_THREAD_POOL = "wlanthermo"; public static final String PROPERTY_MODEL = "model";
public static final String PROPERTY_SERIAL = "serial";
public static final String PROPERTY_ESP32_BT_ENABLED = "esp32_bt_enabled";
public static final String PROPERTY_ESP32_PM_ENABLED = "esp32_pm_enabled";
public static final String PROPERTY_ESP32_TEMP_CHANNELS = "esp32_temp_channels";
public static final String PROPERTY_ESP32_PM_CHANNELS = "esp32_pm_channels";
// List of all Channel ids // List of all Channel ids
// System Channels // System Channels
@ -43,16 +50,7 @@ public class WlanThermoBindingConstants {
public static final String SYSTEM_CPU_LOAD = "cpu_load"; public static final String SYSTEM_CPU_LOAD = "cpu_load";
public static final String SYSTEM_CPU_TEMP = "cpu_temp"; public static final String SYSTEM_CPU_TEMP = "cpu_temp";
public static final String CHANNEL0 = "channel0"; public static final String CHANNEL_PREFIX = "channel";
public static final String CHANNEL1 = "channel1";
public static final String CHANNEL2 = "channel2";
public static final String CHANNEL3 = "channel3";
public static final String CHANNEL4 = "channel4";
public static final String CHANNEL5 = "channel5";
public static final String CHANNEL6 = "channel6";
public static final String CHANNEL7 = "channel7";
public static final String CHANNEL8 = "channel8";
public static final String CHANNEL9 = "channel9";
public static final String CHANNEL_NAME = "name"; public static final String CHANNEL_NAME = "name";
public static final String CHANNEL_TYP = "typ"; public static final String CHANNEL_TYP = "typ";
@ -67,6 +65,9 @@ public class WlanThermoBindingConstants {
public static final String CHANNEL_COLOR = "color"; public static final String CHANNEL_COLOR = "color";
public static final String CHANNEL_COLOR_NAME = "color_name"; public static final String CHANNEL_COLOR_NAME = "color_name";
public static final String CHANNEL_PITMASTER_PREFIX = "pit";
public static final String CHANNEL_PITMASTER_1 = "pit1";
public static final String CHANNEL_PITMASTER_2 = "pit2";
public static final String CHANNEL_PITMASTER_ENABLED = "enabled"; // Mini public static final String CHANNEL_PITMASTER_ENABLED = "enabled"; // Mini
public static final String CHANNEL_PITMASTER_CURRENT = "current"; // Mini public static final String CHANNEL_PITMASTER_CURRENT = "current"; // Mini
public static final String CHANNEL_PITMASTER_SETPOINT = "setpoint"; // Mini+Nano public static final String CHANNEL_PITMASTER_SETPOINT = "setpoint"; // Mini+Nano
@ -76,7 +77,12 @@ public class WlanThermoBindingConstants {
public static final String CHANNEL_PITMASTER_STATE = "state"; // Nano public static final String CHANNEL_PITMASTER_STATE = "state"; // Nano
public static final String CHANNEL_PITMASTER_PIDPROFILE = "pid_id"; // Nano public static final String CHANNEL_PITMASTER_PIDPROFILE = "pid_id"; // Nano
public static final String TRIGGER_ALARM_OFF = "OFF"; public static final String TRIGGER_NONE = "";
public static final String TRIGGER_ALARM_MIN = "MIN"; public static final String TRIGGER_ALARM_MIN = "MIN";
public static final String TRIGGER_ALARM_MAX = "MAX"; public static final String TRIGGER_ALARM_MAX = "MAX";
public static final DecimalType SIGNAL_STRENGTH_4 = new DecimalType(4);
public static final DecimalType SIGNAL_STRENGTH_3 = new DecimalType(3);
public static final DecimalType SIGNAL_STRENGTH_2 = new DecimalType(2);
public static final DecimalType SIGNAL_STRENGTH_1 = new DecimalType(1);
} }

View File

@ -18,12 +18,12 @@ import java.net.URISyntaxException;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
/** /**
* The {@link WlanThermoMiniConfiguration} class contains fields mapping thing configuration parameters. * The {@link WlanThermoConfiguration} class contains fields mapping thing configuration parameters.
* *
* @author Christian Schlipp - Initial contribution * @author Christian Schlipp - Initial contribution
*/ */
@NonNullByDefault @NonNullByDefault
public class WlanThermoMiniConfiguration { public class WlanThermoConfiguration {
/** /**
* IP Address of WlanThermo. * IP Address of WlanThermo.

View File

@ -0,0 +1,41 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link WlanThermoException} is thrown if an exception in WlanThermoBinding occurs.
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoException extends Exception {
static final long serialVersionUID = 1L;
public WlanThermoException(String reason) {
super(reason, null);
}
public WlanThermoException(String message, Throwable cause) {
super(message, cause);
}
public WlanThermoException(Throwable cause) {
super(cause);
}
public WlanThermoException() {
}
}

View File

@ -0,0 +1,51 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link WlanThermoExtendedConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoExtendedConfiguration extends WlanThermoConfiguration {
/**
* Username of WlanThermo user.
*/
private String username = "";
/**
* Password of WlanThermo user.
*/
private String password = "";
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@ -0,0 +1,189 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal;
import static org.openhab.binding.wlanthermo.internal.WlanThermoUtil.requireNonNull;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Authentication;
import org.eclipse.jetty.client.api.AuthenticationStore;
import org.eclipse.jetty.client.util.DigestAuthentication;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.openhab.core.thing.*;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
/**
* The {@link WlanThermoHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public abstract class WlanThermoHandler extends BaseThingHandler {
private final boolean extendedConfig;
protected WlanThermoConfiguration config = new WlanThermoConfiguration();
protected final HttpClient httpClient;
protected final Logger logger = LoggerFactory.getLogger(WlanThermoHandler.class);
protected final Gson gson = new Gson();
protected @Nullable ScheduledFuture<?> pollingScheduler;
public WlanThermoHandler(Thing thing, HttpClient httpClient, boolean extendedConfig) {
super(thing);
this.httpClient = httpClient;
this.extendedConfig = extendedConfig;
}
@Override
public void initialize() {
updateStatus(ThingStatus.UNKNOWN);
try {
if (extendedConfig) {
config = getConfigAs(WlanThermoExtendedConfiguration.class);
WlanThermoExtendedConfiguration extendedConfig = (WlanThermoExtendedConfiguration) config;
if (extendedConfig.getUsername().isEmpty() && !extendedConfig.getPassword().isEmpty()) {
AuthenticationStore authStore = httpClient.getAuthenticationStore();
authStore.addAuthentication(new DigestAuthentication(config.getUri(), Authentication.ANY_REALM,
extendedConfig.getUsername(), extendedConfig.getPassword()));
}
} else {
config = getConfigAs(WlanThermoConfiguration.class);
}
pollingScheduler = scheduler.scheduleWithFixedDelay(this::checkConnectionAndUpdate, 0,
config.getPollingInterval(), TimeUnit.SECONDS);
} catch (URISyntaxException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Failed to initialize WlanThermo: " + e.getMessage());
}
}
@Override
public void dispose() {
ScheduledFuture<?> oldScheduler = pollingScheduler;
if (oldScheduler != null) {
boolean stopped = oldScheduler.cancel(true);
logger.debug("Stopped polling: {}", stopped);
}
pollingScheduler = null;
}
protected void checkConnectionAndUpdate() {
if (this.thing.getStatus() != ThingStatus.ONLINE) {
try {
if (httpClient.GET(config.getUri()).getStatus() == 200) {
updateStatus(ThingStatus.ONLINE);
// rerun immediately to update state
checkConnectionAndUpdate();
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"WlanThermo not found under given address.");
}
} catch (URISyntaxException | ExecutionException | TimeoutException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Could not connect to WlanThermo at " + config.getIpAddress() + ": " + e.getMessage());
} catch (InterruptedException e) {
logger.debug("Connection check interrupted. {}", e.getMessage());
}
} else {
pull();
}
}
protected boolean doPost(String endpoint, String json) throws InterruptedException {
try {
URI uri = config.getUri(endpoint);
int status = httpClient.POST(uri).content(new StringContentProvider(json), "application/json")
.timeout(5, TimeUnit.SECONDS).send().getStatus();
if (status == 401) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"No or wrong login credentials provided. Please configure username/password for write access to WlanThermo!");
return false;
} else if (status != 200) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Failed to update channel on device, Statuscode " + status + " on URI " + uri.toString());
logger.debug("Payload sent: {}", json);
// Still continue to try next channel
return true;
} else {
updateStatus(ThingStatus.ONLINE);
return true;
}
} catch (TimeoutException | ExecutionException | URISyntaxException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Failed to update channel on device: " + e.getMessage());
return false;
}
}
protected <T> T doGet(String endpoint, Class<T> object) throws InterruptedException, WlanThermoException {
try {
String json = httpClient.GET(config.getUri(endpoint)).getContentAsString();
logger.debug("Received at {}: {}", endpoint, json);
return requireNonNull(gson.fromJson(json, object));
} catch (URISyntaxException | ExecutionException | TimeoutException | WlanThermoException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Update failed: " + e.getMessage());
for (Channel channel : thing.getChannels()) {
updateState(channel.getUID(), UnDefType.UNDEF);
}
throw new WlanThermoException(e);
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
try {
State s = getState(channelUID);
updateState(channelUID, s);
} catch (WlanThermoException e) {
logger.debug("Could not handle command of type {} for channel {}!",
command.getClass().toGenericString(), channelUID.getId());
}
} else {
if (setState(channelUID, command) && thing.getStatus() == ThingStatus.ONLINE) {
logger.debug("Data updated, pushing changes");
scheduler.execute(this::push);
} else {
logger.debug("Could not handle command of type {} for channel {}!",
command.getClass().toGenericString(), channelUID.getId());
}
}
}
protected abstract void push();
protected abstract void pull();
protected abstract State getState(ChannelUID channelUID)
throws WlanThermoInputException, WlanThermoUnknownChannelException;
protected abstract boolean setState(ChannelUID channelUID, Command command);
}

View File

@ -19,6 +19,9 @@ import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.wlanthermo.internal.api.esp32.WlanThermoEsp32Handler;
import org.openhab.binding.wlanthermo.internal.api.mini.WlanThermoMiniHandler;
import org.openhab.binding.wlanthermo.internal.api.nano.WlanThermoNanoV1Handler;
import org.openhab.core.io.net.http.HttpClientFactory; import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Thing; import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.ThingTypeUID;
@ -40,8 +43,9 @@ import org.osgi.service.component.annotations.Reference;
public class WlanThermoHandlerFactory extends BaseThingHandlerFactory { public class WlanThermoHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<ThingTypeUID>( private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<ThingTypeUID>(
Arrays.asList(WlanThermoBindingConstants.THING_TYPE_WLANTHERMO_NANO, Arrays.asList(WlanThermoBindingConstants.THING_TYPE_WLANTHERMO_NANO_V1,
WlanThermoBindingConstants.THING_TYPE_WLANTHERMO_MINI)); WlanThermoBindingConstants.THING_TYPE_WLANTHERMO_MINI,
WlanThermoBindingConstants.THING_TYPE_WLANTHERMO_ESP32));
private final HttpClient httpClient; private final HttpClient httpClient;
@Activate @Activate
@ -58,10 +62,12 @@ public class WlanThermoHandlerFactory extends BaseThingHandlerFactory {
protected @Nullable ThingHandler createHandler(Thing thing) { protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID(); ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (WlanThermoBindingConstants.THING_TYPE_WLANTHERMO_NANO.equals(thingTypeUID)) { if (WlanThermoBindingConstants.THING_TYPE_WLANTHERMO_NANO_V1.equals(thingTypeUID)) {
return new WlanThermoNanoHandler(thing, httpClient); return new WlanThermoNanoV1Handler(thing, httpClient);
} else if (WlanThermoBindingConstants.THING_TYPE_WLANTHERMO_MINI.equals(thingTypeUID)) { } else if (WlanThermoBindingConstants.THING_TYPE_WLANTHERMO_MINI.equals(thingTypeUID)) {
return new WlanThermoMiniHandler(thing, httpClient); return new WlanThermoMiniHandler(thing, httpClient);
} else if (WlanThermoBindingConstants.THING_TYPE_WLANTHERMO_ESP32.equals(thingTypeUID)) {
return new WlanThermoEsp32Handler(thing, httpClient);
} }
return null; return null;

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link WlanThermoInputException} is thrown if input is invalid or null
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoInputException extends WlanThermoException {
static final long serialVersionUID = 1L;
public static final String INVALID_INPUT_EXCEPTION = "Input Data is invalid!";
public WlanThermoInputException() {
super(INVALID_INPUT_EXCEPTION);
}
public WlanThermoInputException(Throwable cause) {
super(INVALID_INPUT_EXCEPTION, cause);
}
}

View File

@ -1,152 +0,0 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal;
import java.net.URISyntaxException;
import java.util.Objects;
import java.util.concurrent.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.wlanthermo.internal.api.mini.builtin.App;
import org.openhab.binding.wlanthermo.internal.api.mini.builtin.WlanThermoMiniCommandHandler;
import org.openhab.core.common.ThreadPoolManager;
import org.openhab.core.thing.*;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
/**
* The {@link WlanThermoMiniHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoMiniHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(WlanThermoMiniHandler.class);
private final WlanThermoMiniCommandHandler wlanThermoMiniCommandHandler = new WlanThermoMiniCommandHandler();
private WlanThermoMiniConfiguration config = new WlanThermoMiniConfiguration();
private final HttpClient httpClient;
private @Nullable ScheduledFuture<?> pollingScheduler;
private final ScheduledExecutorService scheduler = ThreadPoolManager
.getScheduledPool(WlanThermoBindingConstants.WLANTHERMO_THREAD_POOL);
private final Gson gson = new Gson();
private App app = new App();
public WlanThermoMiniHandler(Thing thing, HttpClient httpClient) {
super(thing);
this.httpClient = httpClient;
}
@Override
public void initialize() {
logger.debug("Start initializing WlanThermo Mini!");
config = getConfigAs(WlanThermoMiniConfiguration.class);
updateStatus(ThingStatus.UNKNOWN);
scheduler.schedule(this::checkConnection, config.getPollingInterval(), TimeUnit.SECONDS);
logger.debug("Finished initializing WlanThermo Mini!");
}
private void checkConnection() {
try {
if (httpClient.GET(config.getUri("/app.php")).getStatus() == 200) {
updateStatus(ThingStatus.ONLINE);
ScheduledFuture<?> oldScheduler = pollingScheduler;
if (oldScheduler != null) {
oldScheduler.cancel(false);
}
pollingScheduler = scheduler.scheduleWithFixedDelay(this::update, 0, config.getPollingInterval(),
TimeUnit.SECONDS);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"WlanThermo not found under given address.");
}
} catch (URISyntaxException | InterruptedException | ExecutionException | TimeoutException e) {
logger.debug("Failed to connect.", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Could not connect to WlanThermo at " + config.getIpAddress());
ScheduledFuture<?> oldScheduler = pollingScheduler;
if (oldScheduler != null) {
oldScheduler.cancel(false);
}
pollingScheduler = scheduler.schedule(this::checkConnection, config.getPollingInterval(), TimeUnit.SECONDS);
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
State s = wlanThermoMiniCommandHandler.getState(channelUID, app);
if (s != null)
updateState(channelUID, s);
}
// Mini is read only!
}
private void update() {
try {
// Update objects with data from device
String json = httpClient.GET(config.getUri("/app.php")).getContentAsString();
app = Objects.requireNonNull(gson.fromJson(json, App.class));
logger.debug("Received at /app.php: {}", json);
// Update channels
for (Channel channel : thing.getChannels()) {
State state = wlanThermoMiniCommandHandler.getState(channel.getUID(), app);
if (state != null) {
updateState(channel.getUID(), state);
} else {
String trigger = wlanThermoMiniCommandHandler.getTrigger(channel.getUID(), app);
if (trigger != null) {
triggerChannel(channel.getUID(), trigger);
}
}
}
} catch (URISyntaxException | InterruptedException | ExecutionException | TimeoutException e) {
logger.debug("Update failed, checking connection", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Update failed, reconnecting...");
ScheduledFuture<?> oldScheduler = pollingScheduler;
if (oldScheduler != null) {
oldScheduler.cancel(false);
}
for (Channel channel : thing.getChannels()) {
updateState(channel.getUID(), UnDefType.UNDEF);
}
checkConnection();
}
}
@Override
public void dispose() {
ScheduledFuture<?> oldScheduler = pollingScheduler;
if (oldScheduler != null) {
boolean stopped = oldScheduler.cancel(true);
logger.debug("Stopped polling: {}", stopped);
}
pollingScheduler = null;
}
}

View File

@ -1,101 +0,0 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal;
import java.net.URI;
import java.net.URISyntaxException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link WlanThermoNanoConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoNanoConfiguration {
/**
* IP Address of WlanThermo.
*/
private String ipAddress = "";
/**
* Username of WlanThermo user.
*/
private @Nullable String username;
/**
* Password of WlanThermo user.
*/
private @Nullable String password;
/**
* Polling interval
*/
private int pollingInterval = 10;
public String getIpAddress() {
return ipAddress;
}
public URI getUri(String path) throws URISyntaxException {
String uri = ipAddress;
if (!uri.startsWith("http://")) {
uri = "http://" + uri;
}
if (!path.startsWith("/") && !uri.endsWith("/")) {
uri = uri + "/";
}
uri = uri + path;
return new URI(uri);
}
public URI getUri() throws URISyntaxException {
return getUri("");
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
@Nullable
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Nullable
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getPollingInterval() {
return pollingInterval;
}
public void setPollingInterval(int pollingInterval) {
this.pollingInterval = pollingInterval;
}
}

View File

@ -1,205 +0,0 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;
import java.util.concurrent.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Authentication;
import org.eclipse.jetty.client.api.AuthenticationStore;
import org.eclipse.jetty.client.util.DigestAuthentication;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.openhab.binding.wlanthermo.internal.api.nano.WlanThermoNanoCommandHandler;
import org.openhab.binding.wlanthermo.internal.api.nano.data.Data;
import org.openhab.binding.wlanthermo.internal.api.nano.settings.Settings;
import org.openhab.core.common.ThreadPoolManager;
import org.openhab.core.thing.*;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
/**
* The {@link WlanThermoNanoHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoNanoHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(WlanThermoNanoHandler.class);
private WlanThermoNanoConfiguration config = new WlanThermoNanoConfiguration();
private WlanThermoNanoCommandHandler wlanThermoNanoCommandHandler = new WlanThermoNanoCommandHandler();
private final HttpClient httpClient;
private @Nullable ScheduledFuture<?> pollingScheduler;
private final ScheduledExecutorService scheduler = ThreadPoolManager
.getScheduledPool(WlanThermoBindingConstants.WLANTHERMO_THREAD_POOL);
private final Gson gson = new Gson();
private Data data = new Data();
private Settings settings = new Settings();
public WlanThermoNanoHandler(Thing thing, HttpClient httpClient) {
super(thing);
this.httpClient = httpClient;
}
@Override
public void initialize() {
logger.debug("Start initializing WlanThermo Nano!");
config = getConfigAs(WlanThermoNanoConfiguration.class);
updateStatus(ThingStatus.UNKNOWN);
try {
if (config.getUsername() != null && !config.getUsername().isEmpty() && config.getPassword() != null
&& !config.getPassword().isEmpty()) {
AuthenticationStore authStore = httpClient.getAuthenticationStore();
authStore.addAuthentication(new DigestAuthentication(config.getUri(), Authentication.ANY_REALM,
config.getUsername(), config.getPassword()));
}
scheduler.schedule(this::checkConnection, config.getPollingInterval(), TimeUnit.SECONDS);
logger.debug("Finished initializing WlanThermo Nano!");
} catch (URISyntaxException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Failed to initialize WlanThermo Nano!");
logger.debug("Failed to initialize WlanThermo Nano!", e);
}
}
private void checkConnection() {
try {
if (httpClient.GET(config.getUri()).getStatus() == 200) {
updateStatus(ThingStatus.ONLINE);
ScheduledFuture<?> oldScheduler = pollingScheduler;
if (oldScheduler != null) {
oldScheduler.cancel(false);
}
pollingScheduler = scheduler.scheduleWithFixedDelay(this::update, 0, config.getPollingInterval(),
TimeUnit.SECONDS);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"WlanThermo not found under given address.");
}
} catch (URISyntaxException | InterruptedException | ExecutionException | TimeoutException e) {
logger.debug("Failed to connect.", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Could not connect to WlanThermo at " + config.getIpAddress());
ScheduledFuture<?> oldScheduler = pollingScheduler;
if (oldScheduler != null) {
oldScheduler.cancel(false);
}
pollingScheduler = scheduler.schedule(this::checkConnection, config.getPollingInterval(), TimeUnit.SECONDS);
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
State s = wlanThermoNanoCommandHandler.getState(channelUID, data, settings);
if (s != null)
updateState(channelUID, s);
} else {
if (wlanThermoNanoCommandHandler.setState(channelUID, command, data)) {
logger.debug("Data updated, pushing changes");
push();
} else {
logger.debug("Could not handle command of type {} for channel {}!",
command.getClass().toGenericString(), channelUID.getId());
}
}
}
private void update() {
try {
// Update objects with data from device
String json = httpClient.GET(config.getUri("/data")).getContentAsString();
data = Objects.requireNonNull(gson.fromJson(json, Data.class));
logger.debug("Received at /data: {}", json);
json = httpClient.GET(config.getUri("/settings")).getContentAsString();
settings = Objects.requireNonNull(gson.fromJson(json, Settings.class));
logger.debug("Received at /settings: {}", json);
// Update channels
for (Channel channel : thing.getChannels()) {
State state = wlanThermoNanoCommandHandler.getState(channel.getUID(), data, settings);
if (state != null) {
updateState(channel.getUID(), state);
} else {
// if we could not obtain a state, try trigger instead
String trigger = wlanThermoNanoCommandHandler.getTrigger(channel.getUID(), data);
if (trigger != null) {
triggerChannel(channel.getUID(), trigger);
}
}
}
} catch (URISyntaxException | InterruptedException | ExecutionException | TimeoutException e) {
logger.debug("Update failed, checking connection", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Update failed, reconnecting...");
ScheduledFuture<?> oldScheduler = pollingScheduler;
if (oldScheduler != null) {
oldScheduler.cancel(false);
}
for (Channel channel : thing.getChannels()) {
updateState(channel.getUID(), UnDefType.UNDEF);
}
checkConnection();
}
}
private void push() {
data.getChannel().forEach(c -> {
try {
String json = gson.toJson(c);
logger.debug("Pushing: {}", json);
URI uri = config.getUri("/setchannels");
int status = httpClient.POST(uri).content(new StringContentProvider(json), "application/json")
.timeout(5, TimeUnit.SECONDS).send().getStatus();
if (status == 401) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"No or wrong login credentials provided. Please configure username/password for write access to WlanThermo!");
} else if (status != 200) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Failed to update channel "
+ c.getName() + " on device, Statuscode " + status + " on URI " + uri.toString());
} else {
updateStatus(ThingStatus.ONLINE);
}
} catch (InterruptedException | TimeoutException | ExecutionException | URISyntaxException e) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Failed to update channel " + c.getName() + " on device!");
logger.debug("Failed to update channel {} on device", c.getName(), e);
}
});
}
@Override
public void dispose() {
ScheduledFuture<?> oldScheduler = pollingScheduler;
if (oldScheduler != null) {
boolean stopped = oldScheduler.cancel(true);
logger.debug("Stopped polling: {}", stopped);
}
pollingScheduler = null;
}
}

View File

@ -0,0 +1,40 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ChannelUID;
/**
* The {@link WlanThermoUnknownChannelException} is thrown if a channel or trigger is unknown
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoUnknownChannelException extends WlanThermoException {
static final long serialVersionUID = 1L;
public static final String UNKNOWN_CHANNEL_EXCEPTION = "Channel or Trigger unknown!";
public WlanThermoUnknownChannelException() {
super(UNKNOWN_CHANNEL_EXCEPTION);
}
public WlanThermoUnknownChannelException(ChannelUID channelUID) {
super(UNKNOWN_CHANNEL_EXCEPTION + "ChannelUID: " + channelUID.toString());
}
public WlanThermoUnknownChannelException(ChannelUID channelUID, Throwable cause) {
super(UNKNOWN_CHANNEL_EXCEPTION + "ChannelUID: " + channelUID.toString(), cause);
}
}

View File

@ -0,0 +1,53 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.library.types.HSBType;
/**
* The {@link WlanThermoUtil} class provides conversion functions for the WlanThermo
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoUtil {
public static String toColorName(String colorHex, Map<String, String> colorMappings, String defaultColorName) {
if (!colorHex.startsWith("#")) {
colorHex = "#" + colorHex;
}
for (Map.Entry<String, String> entry : colorMappings.entrySet()) {
if (entry.getValue().equalsIgnoreCase(colorHex)) {
return entry.getKey();
}
}
return defaultColorName;
}
public static String toHex(HSBType hsb) {
return "#" + String.format("%02X", hsb.getRed().intValue()) + String.format("%02X", hsb.getGreen().intValue())
+ String.format("%02X", hsb.getBlue().intValue());
}
public static <T> T requireNonNull(@Nullable T obj) throws WlanThermoInputException {
if (obj == null)
throw new WlanThermoInputException();
return obj;
}
}

View File

@ -0,0 +1,299 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32;
import static org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants.*;
import static org.openhab.binding.wlanthermo.internal.WlanThermoUtil.requireNonNull;
import java.awt.Color;
import java.math.BigInteger;
import java.util.List;
import javax.measure.Unit;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.wlanthermo.internal.WlanThermoInputException;
import org.openhab.binding.wlanthermo.internal.WlanThermoUnknownChannelException;
import org.openhab.binding.wlanthermo.internal.WlanThermoUtil;
import org.openhab.binding.wlanthermo.internal.api.esp32.dto.data.Channel;
import org.openhab.binding.wlanthermo.internal.api.esp32.dto.data.Data;
import org.openhab.binding.wlanthermo.internal.api.esp32.dto.data.Pm;
import org.openhab.binding.wlanthermo.internal.api.esp32.dto.data.System;
import org.openhab.binding.wlanthermo.internal.api.esp32.dto.settings.Settings;
import org.openhab.core.library.types.*;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* The {@link WlanThermoEsp32CommandHandler} is responsible for mapping the Commands to the respective data fields
* of the API.
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoEsp32CommandHandler {
public static State getState(ChannelUID channelUID, Data data, Settings settings)
throws WlanThermoUnknownChannelException, WlanThermoInputException {
String groupId = requireNonNull(channelUID.getGroupId());
System system = data.getSystem();
Unit<Temperature> unit = "F".equals(system.getUnit()) ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS;
List<Channel> channelList = data.getChannel();
if (SYSTEM.equals(groupId)) {
switch (channelUID.getIdWithoutGroup()) {
case SYSTEM_SOC:
if (system.getSoc() != null) {
return new DecimalType(system.getSoc());
} else {
return UnDefType.UNDEF;
}
case SYSTEM_CHARGE:
if (system.getCharge() != null) {
return OnOffType.from(system.getCharge());
} else {
return UnDefType.UNDEF;
}
case SYSTEM_RSSI_SIGNALSTRENGTH:
int dbm = system.getRssi();
if (dbm >= -80) {
return SIGNAL_STRENGTH_4;
} else if (dbm >= -95) {
return SIGNAL_STRENGTH_3;
} else if (dbm >= -105) {
return SIGNAL_STRENGTH_2;
} else {
return SIGNAL_STRENGTH_1;
}
case SYSTEM_RSSI:
return new QuantityType<>(system.getRssi(), Units.DECIBEL_MILLIWATTS);
}
} else if (channelUID.getId().startsWith(CHANNEL_PREFIX)) {
int channelId = Integer.parseInt(groupId.substring(CHANNEL_PREFIX.length())) - 1;
if (channelList != null && channelList.size() > 0 && channelId < channelList.size()) {
Channel channel = channelList.get(channelId);
switch (channelUID.getIdWithoutGroup()) {
case CHANNEL_NAME:
return new StringType(channel.getName());
case CHANNEL_TYP:
return new StringType(settings.getSensors().get(channel.getTyp()).getName());
case CHANNEL_TEMP:
return channel.getTemp() == 999.0 ? UnDefType.UNDEF
: new QuantityType<>(channel.getTemp(), unit);
case CHANNEL_MIN:
return new QuantityType<>(channel.getMin(), unit);
case CHANNEL_MAX:
return new QuantityType<>(channel.getMax(), unit);
case CHANNEL_ALARM_DEVICE:
return OnOffType.from(BigInteger.valueOf(channel.getAlarm()).testBit(1));
case CHANNEL_ALARM_PUSH:
return OnOffType.from(BigInteger.valueOf(channel.getAlarm()).testBit(0));
case CHANNEL_ALARM_OPENHAB_HIGH:
if (channel.getTemp() != 999 && channel.getTemp() > channel.getMax()) {
return OnOffType.ON;
} else {
return OnOffType.OFF;
}
case CHANNEL_ALARM_OPENHAB_LOW:
if (channel.getTemp() != 999 && channel.getTemp() < channel.getMin()) {
return OnOffType.ON;
} else {
return OnOffType.OFF;
}
case CHANNEL_COLOR:
String color = channel.getColor();
if (color != null && !color.isEmpty()) {
Color c = Color.decode(color);
return HSBType.fromRGB(c.getRed(), c.getGreen(), c.getBlue());
} else {
return UnDefType.UNDEF;
}
case CHANNEL_COLOR_NAME:
String colorHex = channel.getColor();
if (colorHex != null && !colorHex.isEmpty()) {
return new StringType(WlanThermoEsp32Util.toColorName(colorHex));
} else {
return UnDefType.UNDEF;
}
}
}
} else if (channelUID.getId().startsWith(CHANNEL_PITMASTER_PREFIX)) {
int channelId = Integer.parseInt(groupId.substring(CHANNEL_PITMASTER_PREFIX.length())) - 1;
if (settings.getFeatures().getPitmaster() && data.getPitmaster() != null
&& data.getPitmaster().getPm() != null && data.getPitmaster().getPm().size() > channelId) {
Pm pm = data.getPitmaster().getPm().get(channelId);
switch (channelUID.getIdWithoutGroup()) {
case CHANNEL_PITMASTER_CHANNEL_ID:
return new DecimalType(pm.getChannel());
case CHANNEL_PITMASTER_PIDPROFILE:
return new DecimalType(pm.getPid());
case CHANNEL_PITMASTER_DUTY_CYCLE:
return new DecimalType(pm.getValue());
case CHANNEL_PITMASTER_SETPOINT:
return new QuantityType<>(pm.getSet(), unit);
case CHANNEL_PITMASTER_STATE:
return new StringType(pm.getTyp());
}
} else {
return UnDefType.UNDEF;
}
}
throw new WlanThermoUnknownChannelException(channelUID);
}
public static boolean setState(ChannelUID channelUID, Command command, Data data, Settings settings) {
String groupId;
try {
groupId = requireNonNull(channelUID.getGroupId());
} catch (WlanThermoInputException ignore) {
return false;
}
List<Channel> channelList = data.getChannel();
System system = data.getSystem();
Unit<Temperature> unit = "F".equals(system.getUnit()) ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS;
if (channelUID.getId().startsWith(CHANNEL_PREFIX)) {
int channelId = Integer.parseInt(groupId.substring(CHANNEL_PREFIX.length())) - 1;
if (channelList.size() > 0 && channelId < channelList.size()) {
Channel channel = channelList.get(channelId);
switch (channelUID.getIdWithoutGroup()) {
case CHANNEL_NAME:
if (command instanceof StringType) {
channel.setName(command.toFullString());
return true;
}
return false;
case CHANNEL_MIN:
if (command instanceof QuantityType) {
try {
channel.setMin(requireNonNull(((QuantityType<?>) command).toUnit(unit)).doubleValue());
return true;
} catch (WlanThermoInputException ignore) {
return false;
}
}
return false;
case CHANNEL_MAX:
if (command instanceof QuantityType) {
try {
channel.setMax(requireNonNull(((QuantityType<?>) command).toUnit(unit)).doubleValue());
return true;
} catch (WlanThermoInputException ignore) {
return false;
}
}
return false;
case CHANNEL_ALARM_DEVICE:
if (command instanceof OnOffType) {
BigInteger value;
if (command == OnOffType.ON) {
value = BigInteger.valueOf(channel.getAlarm()).setBit(1);
} else {
value = BigInteger.valueOf(channel.getAlarm()).clearBit(1);
}
channel.setAlarm(value.intValue());
return true;
}
return false;
case CHANNEL_ALARM_PUSH:
if (command instanceof OnOffType) {
BigInteger value;
if (command == OnOffType.ON) {
value = BigInteger.valueOf(channel.getAlarm()).setBit(0);
} else {
value = BigInteger.valueOf(channel.getAlarm()).clearBit(0);
}
channel.setAlarm(value.intValue());
return true;
}
return false;
case CHANNEL_COLOR_NAME:
if (command instanceof StringType) {
channel.setColor(WlanThermoEsp32Util.toHex(((StringType) command).toString()));
return true;
}
return false;
case CHANNEL_COLOR:
if (command instanceof HSBType) {
channel.setColor(WlanThermoUtil.toHex((HSBType) command));
return true;
}
return false;
}
}
} else if (channelUID.getId().startsWith(CHANNEL_PITMASTER_PREFIX)) {
int channelId = Integer.parseInt(groupId.substring(CHANNEL_PITMASTER_PREFIX.length())) - 1;
if (settings.getFeatures().getPitmaster() && data.getPitmaster() != null
&& data.getPitmaster().getPm() != null && data.getPitmaster().getPm().size() > channelId) {
Pm pm = data.getPitmaster().getPm().get(channelId);
switch (channelUID.getIdWithoutGroup()) {
case CHANNEL_PITMASTER_CHANNEL_ID:
pm.setChannel(((DecimalType) command).intValue());
return true;
case CHANNEL_PITMASTER_PIDPROFILE:
pm.setPid(((DecimalType) command).intValue());
return true;
case CHANNEL_PITMASTER_SETPOINT:
try {
pm.setSet(requireNonNull(((QuantityType<?>) command).toUnit(unit)).doubleValue());
return true;
} catch (WlanThermoInputException ignore) {
return false;
}
case CHANNEL_PITMASTER_STATE:
String state = ((StringType) command).toString();
if (state.equalsIgnoreCase("off") || state.equalsIgnoreCase("manual")
|| state.equalsIgnoreCase("auto")) {
pm.setTyp(state);
return true;
}
return false;
}
}
}
return false;
}
public static String getTrigger(ChannelUID channelUID, Data data)
throws WlanThermoUnknownChannelException, WlanThermoInputException {
String groupId = requireNonNull(channelUID.getGroupId());
List<Channel> channelList = data.getChannel();
if (channelUID.getId().startsWith(CHANNEL_PREFIX)) {
int channelId = Integer.parseInt(groupId.substring(CHANNEL_PREFIX.length())) - 1;
if (channelList.size() > 0 && channelId < channelList.size()) {
Channel channel = channelList.get(channelId);
if (CHANNEL_ALARM_OPENHAB.equals(channelUID.getIdWithoutGroup())) {
if (channel.getTemp() != 999) {
if (channel.getTemp() > channel.getMax()) {
return TRIGGER_ALARM_MAX;
} else if (channel.getTemp() < channel.getMin()) {
return TRIGGER_ALARM_MIN;
} else {
return TRIGGER_NONE;
}
}
}
}
}
throw new WlanThermoUnknownChannelException(channelUID);
}
}

View File

@ -0,0 +1,124 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32;
import static org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants.TRIGGER_NONE;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.wlanthermo.internal.*;
import org.openhab.binding.wlanthermo.internal.api.esp32.dto.data.Data;
import org.openhab.binding.wlanthermo.internal.api.esp32.dto.settings.Settings;
import org.openhab.core.thing.*;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
/**
* The {@link WlanThermoEsp32Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoEsp32Handler extends WlanThermoHandler {
private Data data = new Data();
private Settings settings = new Settings();
public WlanThermoEsp32Handler(Thing thing, HttpClient httpClient) {
super(thing, httpClient, true);
}
@Override
protected State getState(ChannelUID channelUID) throws WlanThermoInputException, WlanThermoUnknownChannelException {
return WlanThermoEsp32CommandHandler.getState(channelUID, data, settings);
}
@Override
protected boolean setState(ChannelUID channelUID, Command command) {
return WlanThermoEsp32CommandHandler.setState(channelUID, command, data, settings);
}
@Override
protected void push() {
// Push update for sensor channels
for (org.openhab.binding.wlanthermo.internal.api.esp32.dto.data.Channel c : data.getChannel()) {
try {
String json = gson.toJson(c);
if (!doPost("/setchannels", json)) {
break;
}
} catch (InterruptedException e) {
logger.debug("Push interrupted. {}", e.getMessage());
return;
}
}
// push update for pitmaster channels
try {
String json = gson.toJson(data.getPitmaster().getPm());
doPost("/setpitmaster", json);
} catch (InterruptedException e) {
logger.debug("Push interrupted. {}", e.getMessage());
}
}
@Override
protected void pull() {
try {
// Update objects with data from device
data = doGet("/data", Data.class);
settings = doGet("/settings", Settings.class);
// Update Channels if required
Map<String, String> properties = editProperties();
Boolean pmEnabled = settings.getFeatures().getBluetooth();
int pmChannels = pmEnabled ? data.getPitmaster().getPm().size() : 0;
int tempChannels = data.getChannel().size();
// Update properties
properties.putIfAbsent(WlanThermoBindingConstants.PROPERTY_MODEL, settings.getDevice().getDevice());
properties.putIfAbsent(WlanThermoBindingConstants.PROPERTY_SERIAL, settings.getDevice().getSerial());
properties.putIfAbsent(WlanThermoBindingConstants.PROPERTY_ESP32_BT_ENABLED,
settings.getFeatures().getBluetooth().toString());
properties.putIfAbsent(WlanThermoBindingConstants.PROPERTY_ESP32_PM_ENABLED, pmEnabled.toString());
properties.put(WlanThermoBindingConstants.PROPERTY_ESP32_TEMP_CHANNELS, String.valueOf(tempChannels));
properties.put(WlanThermoBindingConstants.PROPERTY_ESP32_PM_CHANNELS, String.valueOf(pmChannels));
updateProperties(properties);
// Update channel state
for (Channel channel : thing.getChannels()) {
try {
State state = WlanThermoEsp32CommandHandler.getState(channel.getUID(), data, settings);
updateState(channel.getUID(), state);
} catch (WlanThermoUnknownChannelException e) {
// if we could not obtain a state, try trigger instead
try {
String trigger = WlanThermoEsp32CommandHandler.getTrigger(channel.getUID(), data);
if (!trigger.equals(TRIGGER_NONE)) {
triggerChannel(channel.getUID(), trigger);
}
} catch (WlanThermoUnknownChannelException e1) {
logger.debug("{}", e.getMessage());
}
}
}
} catch (WlanThermoException ignore) {
// Nothing more to do
} catch (InterruptedException e) {
logger.debug("Update interrupted. {}", e.getMessage());
}
}
}

View File

@ -0,0 +1,74 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.wlanthermo.internal.WlanThermoUtil;
/**
* The {@link WlanThermoEsp32Util} class provides conversion functions for the WlanThermo Nano V3
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoEsp32Util extends WlanThermoUtil {
private static final Map<String, String> COLOR_MAPPINGS = createColorMap();
private static final String DEFAULT_HEX = "#FFFFFF";
private static final String DEFAULT_COLORNAME = "undefined";
private WlanThermoEsp32Util() {
// hidden
}
private static Map<String, String> createColorMap() {
HashMap<String, String> map = new HashMap<>();
map.put("yellow", "#FFFF00");
map.put("dark yellow", "#FFC002");
map.put("green", "#00FF00");
map.put("white", "#FFFFFF");
map.put("pink", "#FF1DC4");
map.put("orange", "#E46C0A");
map.put("olive", "#C3D69B");
map.put("light blue", "#0FE6F1");
map.put("blue", "#0000FF");
map.put("dark green", "#03A923");
map.put("brown", "#C84B32");
map.put("light brown", "#FF9B69");
map.put("dark blue", "#5082BE");
map.put("light pink", "#FFB1D0");
map.put("light green", "#A6EF03");
map.put("dark pink", "#D42A6B");
map.put("beige", "#FFDA8F");
map.put("azure", "#00B0F0");
map.put("dark olive", "#948A54");
return map;
}
/**
* Convert WlanThermo Color Name to Hex
*
* @param colorName the WlanThermo color name
* @return The color as Hex String
*/
public static String toHex(String colorName) {
return COLOR_MAPPINGS.getOrDefault(colorName, DEFAULT_HEX);
}
public static String toColorName(String colorHex) {
return toColorName(colorHex, COLOR_MAPPINGS, DEFAULT_COLORNAME);
}
}

View File

@ -0,0 +1,136 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.data;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Channel {
@SerializedName("number")
@Expose
private Integer number;
@SerializedName("name")
@Expose
private String name;
@SerializedName("typ")
@Expose
private Integer typ;
@SerializedName("temp")
@Expose
private Double temp;
@SerializedName("min")
@Expose
private Double min;
@SerializedName("max")
@Expose
private Double max;
@SerializedName("alarm")
@Expose
private Integer alarm;
@SerializedName("color")
@Expose
private String color;
@SerializedName("fixed")
@Expose
private Boolean fixed;
@SerializedName("connected")
@Expose
private Boolean connected;
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getTyp() {
return typ;
}
public void setTyp(Integer typ) {
this.typ = typ;
}
public Double getTemp() {
return temp;
}
public void setTemp(Double temp) {
this.temp = temp;
}
public Double getMin() {
return min;
}
public void setMin(Double min) {
this.min = min;
}
public Double getMax() {
return max;
}
public void setMax(Double max) {
this.max = max;
}
public Integer getAlarm() {
return alarm;
}
public void setAlarm(Integer alarm) {
this.alarm = alarm;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Boolean getFixed() {
return fixed;
}
public void setFixed(Boolean fixed) {
this.fixed = fixed;
}
public Boolean getConnected() {
return connected;
}
public void setConnected(Boolean connected) {
this.connected = connected;
}
}

View File

@ -0,0 +1,61 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.data;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Data {
@SerializedName("system")
@Expose
private System system;
@SerializedName("channel")
@Expose
private List<Channel> channel = null;
@SerializedName("pitmaster")
@Expose
private Pitmaster pitmaster;
public System getSystem() {
return system;
}
public void setSystem(System system) {
this.system = system;
}
public List<Channel> getChannel() {
return channel;
}
public void setChannel(List<Channel> channel) {
this.channel = channel;
}
public Pitmaster getPitmaster() {
return pitmaster;
}
public void setPitmaster(Pitmaster pitmaster) {
this.pitmaster = pitmaster;
}
}

View File

@ -0,0 +1,50 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.data;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Pitmaster {
@SerializedName("type")
@Expose
private List<String> type = null;
@SerializedName("pm")
@Expose
private List<Pm> pm = null;
public List<String> getType() {
return type;
}
public void setType(List<String> type) {
this.type = type;
}
public List<Pm> getPm() {
return pm;
}
public void setPm(List<Pm> pm) {
this.pm = pm;
}
}

View File

@ -0,0 +1,114 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.data;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Pm {
@SerializedName("id")
@Expose
private Integer id;
@SerializedName("channel")
@Expose
private Integer channel;
@SerializedName("pid")
@Expose
private Integer pid;
@SerializedName("value")
@Expose
private Integer value;
@SerializedName("set")
@Expose
private Double set;
@SerializedName("typ")
@Expose
private String typ;
@SerializedName("set_color")
@Expose
private String setColor;
@SerializedName("value_color")
@Expose
private String valueColor;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getChannel() {
return channel;
}
public void setChannel(Integer channel) {
this.channel = channel;
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public Double getSet() {
return set;
}
public void setSet(Double set) {
this.set = set;
}
public String getTyp() {
return typ;
}
public void setTyp(String typ) {
this.typ = typ;
}
public String getSetColor() {
return setColor;
}
public void setSetColor(String setColor) {
this.setColor = setColor;
}
public String getValueColor() {
return valueColor;
}
public void setValueColor(String valueColor) {
this.valueColor = valueColor;
}
}

View File

@ -0,0 +1,92 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.data;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class System {
@SerializedName("time")
@Expose
private String time;
@SerializedName("unit")
@Expose
private String unit;
@SerializedName("soc")
@Expose
private Integer soc;
@SerializedName("charge")
@Expose
private Boolean charge;
@SerializedName("rssi")
@Expose
private Integer rssi;
@SerializedName("online")
@Expose
private Integer online;
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public Integer getSoc() {
return soc;
}
public void setSoc(Integer soc) {
this.soc = soc;
}
public Boolean getCharge() {
return charge;
}
public void setCharge(Boolean charge) {
this.charge = charge;
}
public Integer getRssi() {
return rssi;
}
public void setRssi(Integer rssi) {
this.rssi = rssi;
}
public Integer getOnline() {
return online;
}
public void setOnline(Integer online) {
this.online = online;
}
}

View File

@ -0,0 +1,37 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.settings;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Api {
@SerializedName("version")
@Expose
private String version;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}

View File

@ -0,0 +1,114 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.settings;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Device {
@SerializedName("device")
@Expose
private String device;
@SerializedName("serial")
@Expose
private String serial;
@SerializedName("cpu")
@Expose
private String cpu;
@SerializedName("flash_size")
@Expose
private Integer flashSize;
@SerializedName("hw_version")
@Expose
private String hwVersion;
@SerializedName("sw_version")
@Expose
private String swVersion;
@SerializedName("api_version")
@Expose
private String apiVersion;
@SerializedName("language")
@Expose
private String language;
public String getDevice() {
return device;
}
public void setDevice(String device) {
this.device = device;
}
public String getSerial() {
return serial;
}
public void setSerial(String serial) {
this.serial = serial;
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public Integer getFlashSize() {
return flashSize;
}
public void setFlashSize(Integer flashSize) {
this.flashSize = flashSize;
}
public String getHwVersion() {
return hwVersion;
}
public void setHwVersion(String hwVersion) {
this.hwVersion = hwVersion;
}
public String getSwVersion() {
return swVersion;
}
public void setSwVersion(String swVersion) {
this.swVersion = swVersion;
}
public String getApiVersion() {
return apiVersion;
}
public void setApiVersion(String apiVersion) {
this.apiVersion = apiVersion;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
}

View File

@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.settings;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Display {
@SerializedName("updname")
@Expose
private String updname;
@SerializedName("orientation")
@Expose
private Integer orientation;
public String getUpdname() {
return updname;
}
public void setUpdname(String updname) {
this.updname = updname;
}
public Integer getOrientation() {
return orientation;
}
public void setOrientation(Integer orientation) {
this.orientation = orientation;
}
}

View File

@ -0,0 +1,94 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.settings;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Ext {
@SerializedName("on")
@Expose
private Integer on;
@SerializedName("token")
@Expose
private String token;
@SerializedName("id")
@Expose
private String id;
@SerializedName("repeat")
@Expose
private Integer repeat;
@SerializedName("service")
@Expose
private Integer service;
@SerializedName("services")
@Expose
private List<String> services = null;
public Integer getOn() {
return on;
}
public void setOn(Integer on) {
this.on = on;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Integer getRepeat() {
return repeat;
}
public void setRepeat(Integer repeat) {
this.repeat = repeat;
}
public Integer getService() {
return service;
}
public void setService(Integer service) {
this.service = service;
}
public List<String> getServices() {
return services;
}
public void setServices(List<String> services) {
this.services = services;
}
}

View File

@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.settings;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Features {
@SerializedName("bluetooth")
@Expose
private Boolean bluetooth;
@SerializedName("pitmaster")
@Expose
private Boolean pitmaster;
public Boolean getBluetooth() {
return bluetooth;
}
public void setBluetooth(Boolean bluetooth) {
this.bluetooth = bluetooth;
}
public Boolean getPitmaster() {
return pitmaster;
}
public void setPitmaster(Boolean pitmaster) {
this.pitmaster = pitmaster;
}
}

View File

@ -0,0 +1,147 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.settings;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Iot {
@SerializedName("PMQhost")
@Expose
private String pMQhost;
@SerializedName("PMQport")
@Expose
private Integer pMQport;
@SerializedName("PMQuser")
@Expose
private String pMQuser;
@SerializedName("PMQpass")
@Expose
private String pMQpass;
@SerializedName("PMQqos")
@Expose
private Integer pMQqos;
@SerializedName("PMQon")
@Expose
private Boolean pMQon;
@SerializedName("PMQint")
@Expose
private Integer pMQint;
@SerializedName("CLon")
@Expose
private Boolean cLon;
@SerializedName("CLtoken")
@Expose
private String cLtoken;
@SerializedName("CLint")
@Expose
private Integer cLint;
@SerializedName("CLurl")
@Expose
private String cLurl;
public String getPMQhost() {
return pMQhost;
}
public void setPMQhost(String pMQhost) {
this.pMQhost = pMQhost;
}
public Integer getPMQport() {
return pMQport;
}
public void setPMQport(Integer pMQport) {
this.pMQport = pMQport;
}
public String getPMQuser() {
return pMQuser;
}
public void setPMQuser(String pMQuser) {
this.pMQuser = pMQuser;
}
public String getPMQpass() {
return pMQpass;
}
public void setPMQpass(String pMQpass) {
this.pMQpass = pMQpass;
}
public Integer getPMQqos() {
return pMQqos;
}
public void setPMQqos(Integer pMQqos) {
this.pMQqos = pMQqos;
}
public Boolean getPMQon() {
return pMQon;
}
public void setPMQon(Boolean pMQon) {
this.pMQon = pMQon;
}
public Integer getPMQint() {
return pMQint;
}
public void setPMQint(Integer pMQint) {
this.pMQint = pMQint;
}
public Boolean getCLon() {
return cLon;
}
public void setCLon(Boolean cLon) {
this.cLon = cLon;
}
public String getCLtoken() {
return cLtoken;
}
public void setCLtoken(String cLtoken) {
this.cLtoken = cLtoken;
}
public Integer getCLint() {
return cLint;
}
public void setCLint(Integer cLint) {
this.cLint = cLint;
}
public String getCLurl() {
return cLurl;
}
public void setCLurl(String cLurl) {
this.cLurl = cLurl;
}
}

View File

@ -0,0 +1,50 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.settings;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Notes {
@SerializedName("fcm")
@Expose
private List<Object> fcm = null;
@SerializedName("ext")
@Expose
private Ext ext;
public List<Object> getFcm() {
return fcm;
}
public void setFcm(List<Object> fcm) {
this.fcm = fcm;
}
public Ext getExt() {
return ext;
}
public void setExt(Ext ext) {
this.ext = ext;
}
}

View File

@ -0,0 +1,180 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.settings;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Pid {
@SerializedName("name")
@Expose
private String name;
@SerializedName("id")
@Expose
private Integer id;
@SerializedName("aktor")
@Expose
private Integer aktor;
@SerializedName("Kp")
@Expose
private Double kp;
@SerializedName("Ki")
@Expose
private Double ki;
@SerializedName("Kd")
@Expose
private Double kd;
@SerializedName("DCmmin")
@Expose
private Double dCmmin;
@SerializedName("DCmmax")
@Expose
private Double dCmmax;
@SerializedName("opl")
@Expose
private Integer opl;
@SerializedName("SPmin")
@Expose
private Double sPmin;
@SerializedName("SPmax")
@Expose
private Double sPmax;
@SerializedName("link")
@Expose
private Integer link;
@SerializedName("tune")
@Expose
private Integer tune;
@SerializedName("jp")
@Expose
private Integer jp;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getAktor() {
return aktor;
}
public void setAktor(Integer aktor) {
this.aktor = aktor;
}
public Double getKp() {
return kp;
}
public void setKp(Double kp) {
this.kp = kp;
}
public Double getKi() {
return ki;
}
public void setKi(Double ki) {
this.ki = ki;
}
public Double getKd() {
return kd;
}
public void setKd(Double kd) {
this.kd = kd;
}
public Double getDCmmin() {
return dCmmin;
}
public void setDCmmin(Double dCmmin) {
this.dCmmin = dCmmin;
}
public Double getDCmmax() {
return dCmmax;
}
public void setDCmmax(Double dCmmax) {
this.dCmmax = dCmmax;
}
public Integer getOpl() {
return opl;
}
public void setOpl(Integer opl) {
this.opl = opl;
}
public Double getSPmin() {
return sPmin;
}
public void setSPmin(Double sPmin) {
this.sPmin = sPmin;
}
public Double getSPmax() {
return sPmax;
}
public void setSPmax(Double sPmax) {
this.sPmax = sPmax;
}
public Integer getLink() {
return link;
}
public void setLink(Integer link) {
this.link = link;
}
public Integer getTune() {
return tune;
}
public void setTune(Integer tune) {
this.tune = tune;
}
public Integer getJp() {
return jp;
}
public void setJp(Integer jp) {
this.jp = jp;
}
}

View File

@ -0,0 +1,59 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.settings;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Sensor {
@SerializedName("type")
@Expose
private Integer type;
@SerializedName("name")
@Expose
private String name;
@SerializedName("fixed")
@Expose
private Boolean fixed;
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getFixed() {
return fixed;
}
public void setFixed(Boolean fixed) {
this.fixed = fixed;
}
}

View File

@ -0,0 +1,149 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.settings;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class Settings {
@SerializedName("device")
@Expose
private Device device;
@SerializedName("system")
@Expose
private System system;
@SerializedName("hardware")
@Expose
private List<String> hardware = null;
@SerializedName("api")
@Expose
private Api api;
@SerializedName("sensors")
@Expose
private List<Sensor> sensors = null;
@SerializedName("features")
@Expose
private Features features;
@SerializedName("pid")
@Expose
private List<Pid> pid = null;
@SerializedName("aktor")
@Expose
private List<String> aktor = null;
@SerializedName("display")
@Expose
private Display display;
@SerializedName("iot")
@Expose
private Iot iot;
@SerializedName("notes")
@Expose
private Notes notes;
public Device getDevice() {
return device;
}
public void setDevice(Device device) {
this.device = device;
}
public System getSystem() {
return system;
}
public void setSystem(System system) {
this.system = system;
}
public List<String> getHardware() {
return hardware;
}
public void setHardware(List<String> hardware) {
this.hardware = hardware;
}
public Api getApi() {
return api;
}
public void setApi(Api api) {
this.api = api;
}
public List<Sensor> getSensors() {
return sensors;
}
public void setSensors(List<Sensor> sensors) {
this.sensors = sensors;
}
public Features getFeatures() {
return features;
}
public void setFeatures(Features features) {
this.features = features;
}
public List<Pid> getPid() {
return pid;
}
public void setPid(List<Pid> pid) {
this.pid = pid;
}
public List<String> getAktor() {
return aktor;
}
public void setAktor(List<String> aktor) {
this.aktor = aktor;
}
public Display getDisplay() {
return display;
}
public void setDisplay(Display display) {
this.display = display;
}
public Iot getIot() {
return iot;
}
public void setIot(Iot iot) {
this.iot = iot;
}
public Notes getNotes() {
return notes;
}
public void setNotes(Notes notes) {
this.notes = notes;
}
}

View File

@ -0,0 +1,136 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32.dto.settings;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* This DTO is used to parse the JSON
* Class is auto-generated from JSON using http://www.jsonschema2pojo.org/
*
* @author Christian Schlipp - Initial contribution
*/
public class System {
@SerializedName("time")
@Expose
private String time;
@SerializedName("unit")
@Expose
private String unit;
@SerializedName("ap")
@Expose
private String ap;
@SerializedName("host")
@Expose
private String host;
@SerializedName("language")
@Expose
private String language;
@SerializedName("version")
@Expose
private String version;
@SerializedName("getupdate")
@Expose
private String getupdate;
@SerializedName("autoupd")
@Expose
private Boolean autoupd;
@SerializedName("prerelease")
@Expose
private Boolean prerelease;
@SerializedName("hwversion")
@Expose
private String hwversion;
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public String getAp() {
return ap;
}
public void setAp(String ap) {
this.ap = ap;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getGetupdate() {
return getupdate;
}
public void setGetupdate(String getupdate) {
this.getupdate = getupdate;
}
public Boolean getAutoupd() {
return autoupd;
}
public void setAutoupd(Boolean autoupd) {
this.autoupd = autoupd;
}
public Boolean getPrerelease() {
return prerelease;
}
public void setPrerelease(Boolean prerelease) {
this.prerelease = prerelease;
}
public String getHwversion() {
return hwversion;
}
public void setHwversion(String hwversion) {
this.hwversion = hwversion;
}
}

View File

@ -0,0 +1,165 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.mini;
import static org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants.*;
import static org.openhab.binding.wlanthermo.internal.WlanThermoUtil.requireNonNull;
import java.awt.*;
import javax.measure.Unit;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants;
import org.openhab.binding.wlanthermo.internal.WlanThermoInputException;
import org.openhab.binding.wlanthermo.internal.WlanThermoUnknownChannelException;
import org.openhab.binding.wlanthermo.internal.api.mini.dto.builtin.*;
import org.openhab.core.library.types.*;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* The {@link WlanThermoMiniCommandHandler} is responsible for mapping the Commands to the respective data fields
* of the API.
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoMiniCommandHandler {
public static final String ERROR = "er";
public static State getState(ChannelUID channelUID, App app)
throws WlanThermoUnknownChannelException, WlanThermoInputException {
String groupId = requireNonNull(channelUID.getGroupId());
Unit<Temperature> unit = "fahrenheit".equals(app.getTempUnit()) ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS;
if (SYSTEM.equals(groupId)) {
switch (channelUID.getIdWithoutGroup()) {
case WlanThermoBindingConstants.SYSTEM_CPU_TEMP:
if (app.getCpuTemp() == null) {
return UnDefType.UNDEF;
} else {
return new DecimalType(app.getCpuTemp());
}
case WlanThermoBindingConstants.SYSTEM_CPU_LOAD:
if (app.getCpuLoad() == null) {
return UnDefType.UNDEF;
} else {
return new DecimalType(app.getCpuLoad());
}
}
} else if (channelUID.getId().startsWith(CHANNEL_PREFIX)) {
int channelId = Integer.parseInt(groupId.substring(CHANNEL_PREFIX.length()));
if (channelId >= 0 && channelId <= 9) {
Channel channel = app.getChannel();
if (channel == null) {
return UnDefType.UNDEF;
}
Data data = channel.getData(channelId);
switch (channelUID.getIdWithoutGroup()) {
case WlanThermoBindingConstants.CHANNEL_NAME:
return new StringType(data.getName());
case WlanThermoBindingConstants.CHANNEL_TEMP:
if (data.getState().equals(ERROR)) {
return UnDefType.UNDEF;
} else {
return new QuantityType<>(data.getTemp(), unit);
}
case WlanThermoBindingConstants.CHANNEL_MIN:
return new QuantityType<>(data.getTempMin(), unit);
case WlanThermoBindingConstants.CHANNEL_MAX:
return new QuantityType<>(data.getTempMax(), unit);
case WlanThermoBindingConstants.CHANNEL_ALARM_DEVICE:
return OnOffType.from(data.getAlert());
case WlanThermoBindingConstants.CHANNEL_ALARM_OPENHAB_HIGH:
if (!data.getState().equals(ERROR) && data.getTemp() > data.getTempMax()) {
return OnOffType.ON;
} else {
return OnOffType.OFF;
}
case WlanThermoBindingConstants.CHANNEL_ALARM_OPENHAB_LOW:
if (!data.getState().equals(ERROR) && data.getTemp() < data.getTempMin()) {
return OnOffType.ON;
} else {
return OnOffType.OFF;
}
case WlanThermoBindingConstants.CHANNEL_COLOR:
Color c = Color.decode(WlanThermoMiniUtil.toHex(data.getColor()));
return HSBType.fromRGB(c.getRed(), c.getGreen(), c.getBlue());
case WlanThermoBindingConstants.CHANNEL_COLOR_NAME:
return new StringType(data.getColor());
}
}
} else if (channelUID.getId().startsWith(CHANNEL_PITMASTER_PREFIX)) {
Pit pit;
if (groupId.equals(CHANNEL_PITMASTER_1)) {
pit = app.getPit();
} else if (groupId.equals(CHANNEL_PITMASTER_2)) {
pit = app.getPit2();
} else {
return UnDefType.UNDEF;
}
if (pit == null || !pit.getEnabled()) {
return UnDefType.UNDEF;
}
switch (channelUID.getIdWithoutGroup()) {
case WlanThermoBindingConstants.CHANNEL_PITMASTER_ENABLED:
return OnOffType.from(pit.getEnabled());
case WlanThermoBindingConstants.CHANNEL_PITMASTER_CURRENT:
return new DecimalType(pit.getCurrent());
case WlanThermoBindingConstants.CHANNEL_PITMASTER_SETPOINT:
return new QuantityType<>(pit.getSetpoint(), unit);
case WlanThermoBindingConstants.CHANNEL_PITMASTER_DUTY_CYCLE:
return new DecimalType(pit.getControlOut());
case WlanThermoBindingConstants.CHANNEL_PITMASTER_LID_OPEN:
return OnOffType.from(pit.getOpenLid().equals("True"));
case WlanThermoBindingConstants.CHANNEL_PITMASTER_CHANNEL_ID:
return new DecimalType(pit.getCh());
}
}
throw new WlanThermoUnknownChannelException(channelUID);
}
public static String getTrigger(ChannelUID channelUID, App app)
throws WlanThermoUnknownChannelException, WlanThermoInputException {
String groupId = requireNonNull(channelUID.getGroupId());
if (channelUID.getId().startsWith(CHANNEL_PREFIX)) {
int channelId = Integer.parseInt(groupId.substring(CHANNEL_PREFIX.length())) - 1;
if (channelId >= 0 && channelId <= 9) {
Channel channel = app.getChannel();
if (channel == null) {
throw new WlanThermoInputException();
}
Data data = channel.getData(channelId);
if (CHANNEL_ALARM_OPENHAB.equals(channelUID.getIdWithoutGroup())) {
if (!data.getState().equals(ERROR)) {
if (data.getTemp() > data.getTempMax()) {
return TRIGGER_ALARM_MAX;
} else if (data.getTemp() < data.getTempMin()) {
return TRIGGER_ALARM_MIN;
} else {
return TRIGGER_NONE;
}
}
}
}
}
throw new WlanThermoUnknownChannelException(channelUID);
}
}

View File

@ -0,0 +1,85 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.mini;
import static org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants.TRIGGER_NONE;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.wlanthermo.internal.*;
import org.openhab.binding.wlanthermo.internal.api.mini.dto.builtin.App;
import org.openhab.core.thing.*;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
/**
* The {@link WlanThermoMiniHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoMiniHandler extends WlanThermoHandler {
private App app = new App();
public WlanThermoMiniHandler(Thing thing, HttpClient httpClient) {
super(thing, httpClient, false);
}
@Override
protected State getState(ChannelUID channelUID) throws WlanThermoInputException, WlanThermoUnknownChannelException {
return WlanThermoMiniCommandHandler.getState(channelUID, app);
}
@Override
protected boolean setState(ChannelUID channelUID, Command command) {
// Mini is read-only!
return false;
}
@Override
protected void push() {
// Unused, Mini is read-only!
}
@Override
protected void pull() {
try {
// Update objects with data from device
app = doGet("/app.php", App.class);
// Update channels
for (Channel channel : thing.getChannels()) {
try {
State state = WlanThermoMiniCommandHandler.getState(channel.getUID(), app);
updateState(channel.getUID(), state);
} catch (WlanThermoUnknownChannelException e) {
// if we could not obtain a state, try trigger instead
try {
String trigger = WlanThermoMiniCommandHandler.getTrigger(channel.getUID(), app);
if (!trigger.equals(TRIGGER_NONE)) {
triggerChannel(channel.getUID(), trigger);
}
} catch (WlanThermoUnknownChannelException e1) {
logger.debug("{}", e.getMessage());
}
}
}
} catch (WlanThermoException ignore) {
// Nothing more to do
} catch (InterruptedException e) {
logger.debug("Update interrupted. {}", e.getMessage());
}
}
}

View File

@ -10,21 +10,25 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.mini.builtin; package org.openhab.binding.wlanthermo.internal.api.mini;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.wlanthermo.internal.WlanThermoUtil;
/** /**
* The {@link UtilMini} class provides conversion functions for the WlanThermo Mini * The {@link WlanThermoMiniUtil} class provides conversion functions for the WlanThermo Mini
* *
* @author Christian Schlipp - Initial contribution * @author Christian Schlipp - Initial contribution
*/ */
public class UtilMini { @NonNullByDefault
public class WlanThermoMiniUtil extends WlanThermoUtil {
private static final Map<String, String> COLOR_MAPPINGS = createColorMap(); private static final Map<String, String> COLOR_MAPPINGS = createColorMap();
private static final String DEFAULT_HEX = "#ffffff"; private static final String DEFAULT_HEX = "#ffffff";
private UtilMini() { private WlanThermoMiniUtil() {
// hidden // hidden
} }

View File

@ -1,164 +0,0 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.mini.builtin;
import java.awt.*;
import org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* The {@link WlanThermoMiniCommandHandler} is responsible for mapping the Commands to the respective data fields
* of the API.
*
* @author Christian Schlipp - Initial contribution
*/
public class WlanThermoMiniCommandHandler {
public State getState(ChannelUID channelUID, App app) {
State state = null;
if ("system".equals(channelUID.getGroupId())) {
switch (channelUID.getIdWithoutGroup()) {
case WlanThermoBindingConstants.SYSTEM_CPU_TEMP:
if (app.getCpuTemp() == null) {
state = UnDefType.UNDEF;
} else {
state = new DecimalType(app.getCpuTemp());
}
break;
case WlanThermoBindingConstants.SYSTEM_CPU_LOAD:
if (app.getCpuLoad() == null) {
state = UnDefType.UNDEF;
} else {
state = new DecimalType(app.getCpuLoad());
}
break;
}
} else if (channelUID.getId().startsWith("channel")) {
int channelId = Integer.parseInt(channelUID.getGroupId().substring("channel".length()));
if (channelId >= 0 && channelId <= 9) {
Channel channel = app.getChannel();
if (channel == null) {
return UnDefType.UNDEF;
}
Data data = channel.getData(channelId);
switch (channelUID.getIdWithoutGroup()) {
case WlanThermoBindingConstants.CHANNEL_NAME:
state = new StringType(data.getName());
break;
case WlanThermoBindingConstants.CHANNEL_TEMP:
if (data.getState().equals("er")) {
state = UnDefType.UNDEF;
} else {
state = new DecimalType(data.getTemp());
}
break;
case WlanThermoBindingConstants.CHANNEL_MIN:
state = new DecimalType(data.getTempMin());
break;
case WlanThermoBindingConstants.CHANNEL_MAX:
state = new DecimalType(data.getTempMax());
break;
case WlanThermoBindingConstants.CHANNEL_ALARM_DEVICE:
state = OnOffType.from(data.getAlert());
break;
case WlanThermoBindingConstants.CHANNEL_ALARM_OPENHAB_HIGH:
if (!data.getState().equals("er") && data.getTemp() > data.getTempMax()) {
state = OnOffType.ON;
} else {
state = OnOffType.OFF;
}
break;
case WlanThermoBindingConstants.CHANNEL_ALARM_OPENHAB_LOW:
if (!data.getState().equals("er") && data.getTemp() < data.getTempMin()) {
state = OnOffType.ON;
} else {
state = OnOffType.OFF;
}
break;
case WlanThermoBindingConstants.CHANNEL_COLOR:
Color c = Color.decode(UtilMini.toHex(data.getColor()));
state = HSBType.fromRGB(c.getRed(), c.getGreen(), c.getBlue());
break;
case WlanThermoBindingConstants.CHANNEL_COLOR_NAME:
state = new StringType(data.getColor());
break;
}
}
} else if (channelUID.getId().startsWith("pit")) {
Pit pit;
if (channelUID.getGroupId().equals("pit1")) {
pit = app.getPit();
} else if (channelUID.getGroupId().equals("pit2")) {
pit = app.getPit2();
} else {
return UnDefType.UNDEF;
}
if (pit == null || !pit.getEnabled()) {
return UnDefType.UNDEF;
}
switch (channelUID.getIdWithoutGroup()) {
case WlanThermoBindingConstants.CHANNEL_PITMASTER_ENABLED:
state = OnOffType.from(pit.getEnabled());
break;
case WlanThermoBindingConstants.CHANNEL_PITMASTER_CURRENT:
state = new DecimalType(pit.getCurrent());
break;
case WlanThermoBindingConstants.CHANNEL_PITMASTER_SETPOINT:
state = new DecimalType(pit.getSetpoint());
break;
case WlanThermoBindingConstants.CHANNEL_PITMASTER_DUTY_CYCLE:
state = new DecimalType(pit.getControlOut());
break;
case WlanThermoBindingConstants.CHANNEL_PITMASTER_LID_OPEN:
state = OnOffType.from(pit.getOpenLid().equals("True"));
break;
case WlanThermoBindingConstants.CHANNEL_PITMASTER_CHANNEL_ID:
state = new DecimalType(pit.getCh());
break;
}
}
return state;
}
public String getTrigger(ChannelUID channelUID, App app) {
String trigger = null;
if (channelUID.getId().startsWith("channel")) {
int channelId = Integer.parseInt(channelUID.getGroupId().substring("channel".length())) - 1;
if (channelId >= 0 && channelId <= 9) {
Channel channel = app.getChannel();
if (channel == null) {
return "";
}
Data data = channel.getData(channelId);
switch (channelUID.getIdWithoutGroup()) {
case "alarm_openhab":
if (!data.getState().equals("er")) {
if (data.getTemp() > data.getTempMax()) {
trigger = WlanThermoBindingConstants.TRIGGER_ALARM_MAX;
} else if (data.getTemp() < data.getTempMin()) {
trigger = WlanThermoBindingConstants.TRIGGER_ALARM_MIN;
}
}
}
}
}
return trigger;
}
}

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.mini.builtin; package org.openhab.binding.wlanthermo.internal.api.mini.dto.builtin;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.mini.builtin; package org.openhab.binding.wlanthermo.internal.api.mini.dto.builtin;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.mini.builtin; package org.openhab.binding.wlanthermo.internal.api.mini.dto.builtin;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.mini.builtin; package org.openhab.binding.wlanthermo.internal.api.mini.dto.builtin;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -1,261 +0,0 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.nano;
import static org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants.*;
import java.awt.*;
import java.math.BigInteger;
import java.util.List;
import org.openhab.binding.wlanthermo.internal.api.nano.data.Channel;
import org.openhab.binding.wlanthermo.internal.api.nano.data.Data;
import org.openhab.binding.wlanthermo.internal.api.nano.data.Pm;
import org.openhab.binding.wlanthermo.internal.api.nano.data.System;
import org.openhab.binding.wlanthermo.internal.api.nano.settings.Settings;
import org.openhab.core.library.types.*;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* The {@link WlanThermoNanoCommandHandler} is responsible for mapping the Commands to the respective data fields
* of the API.
*
* @author Christian Schlipp - Initial contribution
*/
public class WlanThermoNanoCommandHandler {
public State getState(ChannelUID channelUID, Data data, Settings settings) {
State state = null;
System system = data.getSystem();
List<Channel> channel = data.getChannel();
if ("system".equals(channelUID.getGroupId()) && system != null) {
switch (channelUID.getIdWithoutGroup()) {
case SYSTEM_SOC:
state = new DecimalType(system.getSoc());
break;
case SYSTEM_CHARGE:
state = OnOffType.from(system.getCharge());
break;
case SYSTEM_RSSI_SIGNALSTRENGTH:
int dbm = system.getRssi();
if (dbm >= -80) {
state = new DecimalType(4);
} else if (dbm >= -95) {
state = new DecimalType(3);
} else if (dbm >= -105) {
state = new DecimalType(2);
} else {
state = new DecimalType(1);
}
break;
case SYSTEM_RSSI:
state = new DecimalType(system.getRssi());
break;
}
} else if (channelUID.getId().startsWith("channel")) {
int channelId = Integer.parseInt(channelUID.getGroupId().substring("channel".length())) - 1;
if (channel.size() > 0 && channelId <= channel.size()) {
switch (channelUID.getIdWithoutGroup()) {
case CHANNEL_NAME:
state = new StringType(channel.get(channelId).getName());
break;
case CHANNEL_TYP:
state = new StringType(settings.sensors.get(channel.get(channelId).getTyp()));
break;
case CHANNEL_TEMP:
if (channel.get(channelId).getTemp() == 999.0) {
state = UnDefType.UNDEF;
} else {
state = new DecimalType(channel.get(channelId).getTemp());
}
break;
case CHANNEL_MIN:
state = new DecimalType(channel.get(channelId).getMin());
break;
case CHANNEL_MAX:
state = new DecimalType(channel.get(channelId).getMax());
break;
case CHANNEL_ALARM_DEVICE:
state = OnOffType.from(BigInteger.valueOf(channel.get(channelId).getAlarm()).testBit(1));
break;
case CHANNEL_ALARM_PUSH:
state = OnOffType.from(BigInteger.valueOf(channel.get(channelId).getAlarm()).testBit(0));
break;
case CHANNEL_ALARM_OPENHAB_HIGH:
if (channel.get(channelId).getTemp() != 999
&& channel.get(channelId).getTemp() > channel.get(channelId).getMax()) {
state = OnOffType.ON;
} else {
state = OnOffType.OFF;
}
break;
case CHANNEL_ALARM_OPENHAB_LOW:
if (channel.get(channelId).getTemp() != 999
&& channel.get(channelId).getTemp() < channel.get(channelId).getMin()) {
state = OnOffType.ON;
} else {
state = OnOffType.OFF;
}
break;
case CHANNEL_COLOR:
String color = channel.get(channelId).getColor();
if (color != null && !color.isEmpty()) {
Color c = Color.decode(color);
state = HSBType.fromRGB(c.getRed(), c.getGreen(), c.getBlue());
}
break;
case CHANNEL_COLOR_NAME:
String colorHex = channel.get(channelId).getColor();
if (colorHex != null && !colorHex.isEmpty()) {
state = new StringType(UtilNano.toColorName(colorHex));
}
break;
}
}
} else if (channelUID.getId().startsWith("pit1")) {
if (data.getPitmaster() != null && data.getPitmaster().getPm() != null
&& data.getPitmaster().getPm().size() > 0) {
Pm pm = data.getPitmaster().getPm().get(0);
switch (channelUID.getIdWithoutGroup()) {
case CHANNEL_PITMASTER_CHANNEL_ID:
state = new DecimalType(pm.getChannel());
break;
case CHANNEL_PITMASTER_PIDPROFILE:
state = new DecimalType(pm.getPid());
break;
case CHANNEL_PITMASTER_DUTY_CYCLE:
state = new DecimalType(pm.getValue());
break;
case CHANNEL_PITMASTER_SETPOINT:
state = new DecimalType(pm.getSet());
break;
case CHANNEL_PITMASTER_STATE:
state = new StringType(pm.getTyp());
}
} else {
return UnDefType.UNDEF;
}
}
return state;
}
public boolean setState(ChannelUID channelUID, Command command, Data data) {
boolean success = false;
List<Channel> channel = data.getChannel();
if (channelUID.getId().startsWith("channel")) {
int channelId = Integer.parseInt(channelUID.getGroupId().substring("channel".length())) - 1;
if (channel.size() > 0 && channelId <= channel.size()) {
switch (channelUID.getIdWithoutGroup()) {
case CHANNEL_NAME:
if (command instanceof StringType) {
channel.get(channelId).setName(command.toFullString());
success = true;
}
break;
case CHANNEL_MIN:
if (command instanceof QuantityType) {
channel.get(channelId).setMin(((QuantityType) command).doubleValue());
success = true;
}
break;
case CHANNEL_MAX:
if (command instanceof QuantityType) {
channel.get(channelId).setMax(((QuantityType) command).doubleValue());
success = true;
}
break;
case CHANNEL_ALARM_DEVICE:
if (command instanceof OnOffType) {
BigInteger value;
if (command == OnOffType.ON) {
value = BigInteger.valueOf(channel.get(channelId).getAlarm()).setBit(1);
} else {
value = BigInteger.valueOf(channel.get(channelId).getAlarm()).clearBit(1);
}
channel.get(channelId).setAlarm(value.intValue());
success = true;
}
break;
case CHANNEL_ALARM_PUSH:
if (command instanceof OnOffType) {
BigInteger value;
if (command == OnOffType.ON) {
value = BigInteger.valueOf(channel.get(channelId).getAlarm()).setBit(0);
} else {
value = BigInteger.valueOf(channel.get(channelId).getAlarm()).clearBit(0);
}
channel.get(channelId).setAlarm(value.intValue());
success = true;
}
break;
case CHANNEL_COLOR_NAME:
if (command instanceof StringType) {
channel.get(channelId).setColor(UtilNano.toHex(((StringType) command).toString()));
success = true;
}
break;
}
}
} else if (channelUID.getId().equals("pit1")) {
if (data.getPitmaster() != null && data.getPitmaster().getPm() != null
&& data.getPitmaster().getPm().size() > 0) {
Pm pm = data.getPitmaster().getPm().get(0);
switch (channelUID.getIdWithoutGroup()) {
case CHANNEL_PITMASTER_CHANNEL_ID:
pm.setChannel(((QuantityType) command).intValue());
success = true;
break;
case CHANNEL_PITMASTER_PIDPROFILE:
pm.setPid(((QuantityType) command).intValue());
success = true;
break;
case CHANNEL_PITMASTER_SETPOINT:
pm.setSet(((QuantityType) command).doubleValue());
success = true;
break;
case CHANNEL_PITMASTER_STATE:
String state = ((StringType) command).toString();
if (state.equalsIgnoreCase("off") || state.equalsIgnoreCase("manual")
|| state.equalsIgnoreCase("auto")) {
pm.setTyp(state);
success = true;
}
}
}
}
return success;
}
public String getTrigger(ChannelUID channelUID, Data data) {
String trigger = null;
List<Channel> channel = data.getChannel();
if (channelUID.getId().startsWith("channel")) {
int channelId = Integer.parseInt(channelUID.getGroupId().substring("channel".length())) - 1;
if (channel.size() > 0 && channelId <= channel.size()) {
if (CHANNEL_ALARM_OPENHAB.equals(channelUID.getIdWithoutGroup())) {
if (channel.get(channelId).getTemp() != 999) {
if (channel.get(channelId).getTemp() > channel.get(channelId).getMax()) {
trigger = TRIGGER_ALARM_MAX;
} else if (channel.get(channelId).getTemp() < channel.get(channelId).getMin()) {
trigger = TRIGGER_ALARM_MIN;
}
}
}
}
}
return trigger;
}
}

View File

@ -0,0 +1,282 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.nano;
import static org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants.*;
import static org.openhab.binding.wlanthermo.internal.WlanThermoUtil.requireNonNull;
import java.awt.*;
import java.math.BigInteger;
import java.util.List;
import javax.measure.Unit;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.wlanthermo.internal.WlanThermoInputException;
import org.openhab.binding.wlanthermo.internal.WlanThermoUnknownChannelException;
import org.openhab.binding.wlanthermo.internal.api.nano.dto.data.Channel;
import org.openhab.binding.wlanthermo.internal.api.nano.dto.data.Data;
import org.openhab.binding.wlanthermo.internal.api.nano.dto.data.Pm;
import org.openhab.binding.wlanthermo.internal.api.nano.dto.data.System;
import org.openhab.binding.wlanthermo.internal.api.nano.dto.settings.Settings;
import org.openhab.core.library.types.*;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* The {@link WlanThermoNanoV1CommandHandler} is responsible for mapping the Commands to the respective data fields
* of the API.
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoNanoV1CommandHandler {
public static State getState(ChannelUID channelUID, Data data, Settings settings)
throws WlanThermoUnknownChannelException, WlanThermoInputException {
String groupId = requireNonNull(channelUID.getGroupId());
System system = data.getSystem();
Unit<Temperature> unit = "F".equals(system.getUnit()) ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS;
List<Channel> channelList = data.getChannel();
if (SYSTEM.equals(groupId)) {
switch (channelUID.getIdWithoutGroup()) {
case SYSTEM_SOC:
return new DecimalType(system.getSoc());
case SYSTEM_CHARGE:
return OnOffType.from(system.getCharge());
case SYSTEM_RSSI_SIGNALSTRENGTH:
int dbm = system.getRssi();
if (dbm >= -80) {
return SIGNAL_STRENGTH_4;
} else if (dbm >= -95) {
return SIGNAL_STRENGTH_3;
} else if (dbm >= -105) {
return SIGNAL_STRENGTH_2;
} else {
return SIGNAL_STRENGTH_1;
}
case SYSTEM_RSSI:
return new QuantityType<>(system.getRssi(), Units.DECIBEL_MILLIWATTS);
}
} else if (channelUID.getId().startsWith(CHANNEL_PREFIX)) {
int channelId = Integer.parseInt(groupId.substring(CHANNEL_PREFIX.length())) - 1;
if (channelList.size() > 0 && channelId < channelList.size()) {
Channel channel = channelList.get(channelId);
switch (channelUID.getIdWithoutGroup()) {
case CHANNEL_NAME:
return new StringType(channel.getName());
case CHANNEL_TYP:
return new StringType(settings.sensors.get(channel.getTyp()));
case CHANNEL_TEMP:
return channel.getTemp() == 999.0 ? UnDefType.UNDEF
: new QuantityType<>(channel.getTemp(), unit);
case CHANNEL_MIN:
return new QuantityType<>(channel.getMin(), unit);
case CHANNEL_MAX:
return new QuantityType<>(channel.getMax(), unit);
case CHANNEL_ALARM_DEVICE:
return OnOffType.from(BigInteger.valueOf(channel.getAlarm()).testBit(1));
case CHANNEL_ALARM_PUSH:
return OnOffType.from(BigInteger.valueOf(channel.getAlarm()).testBit(0));
case CHANNEL_ALARM_OPENHAB_HIGH:
if (channel.getTemp() != 999 && channel.getTemp() > channel.getMax()) {
return OnOffType.ON;
} else {
return OnOffType.OFF;
}
case CHANNEL_ALARM_OPENHAB_LOW:
if (channel.getTemp() != 999 && channel.getTemp() < channel.getMin()) {
return OnOffType.ON;
} else {
return OnOffType.OFF;
}
case CHANNEL_COLOR:
String color = channel.getColor();
if (color != null && !color.isEmpty()) {
Color c = Color.decode(color);
return HSBType.fromRGB(c.getRed(), c.getGreen(), c.getBlue());
} else {
return UnDefType.UNDEF;
}
case CHANNEL_COLOR_NAME:
String colorHex = channel.getColor();
if (colorHex != null && !colorHex.isEmpty()) {
return new StringType(WlanThermoNanoV1Util.toColorName(colorHex));
} else {
return UnDefType.UNDEF;
}
}
}
} else if (channelUID.getId().startsWith(CHANNEL_PITMASTER_1)) {
if (data.getPitmaster() != null && data.getPitmaster().getPm() != null
&& data.getPitmaster().getPm().size() > 0) {
Pm pm = data.getPitmaster().getPm().get(0);
switch (channelUID.getIdWithoutGroup()) {
case CHANNEL_PITMASTER_CHANNEL_ID:
return new DecimalType(pm.getChannel());
case CHANNEL_PITMASTER_PIDPROFILE:
return new DecimalType(pm.getPid());
case CHANNEL_PITMASTER_DUTY_CYCLE:
return new DecimalType(pm.getValue());
case CHANNEL_PITMASTER_SETPOINT:
return new QuantityType<>(pm.getSet(), unit);
case CHANNEL_PITMASTER_STATE:
return new StringType(pm.getTyp());
}
} else {
return UnDefType.UNDEF;
}
}
throw new WlanThermoUnknownChannelException(channelUID);
}
public static boolean setState(ChannelUID channelUID, Command command, Data data) {
String groupId;
try {
groupId = requireNonNull(channelUID.getGroupId());
} catch (WlanThermoInputException e) {
return false;
}
List<Channel> channelList = data.getChannel();
System system = data.getSystem();
Unit<Temperature> unit = "F".equals(system.getUnit()) ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS;
if (channelUID.getId().startsWith(CHANNEL_PREFIX)) {
int channelId = Integer.parseInt(groupId.substring(CHANNEL_PREFIX.length())) - 1;
if (channelList.size() > 0 && channelId < channelList.size()) {
Channel channel = channelList.get(channelId);
switch (channelUID.getIdWithoutGroup()) {
case CHANNEL_NAME:
if (command instanceof StringType) {
channel.setName(command.toFullString());
return true;
}
return false;
case CHANNEL_MIN:
if (command instanceof QuantityType) {
try {
channel.setMin(requireNonNull(((QuantityType<?>) command).toUnit(unit)).doubleValue());
return true;
} catch (WlanThermoInputException ignore) {
return false;
}
}
return false;
case CHANNEL_MAX:
if (command instanceof QuantityType) {
try {
channel.setMax(requireNonNull(((QuantityType<?>) command).toUnit(unit)).doubleValue());
return true;
} catch (WlanThermoInputException ignore) {
return false;
}
}
return false;
case CHANNEL_ALARM_DEVICE:
if (command instanceof OnOffType) {
BigInteger value;
if (command == OnOffType.ON) {
value = BigInteger.valueOf(channel.getAlarm()).setBit(1);
} else {
value = BigInteger.valueOf(channel.getAlarm()).clearBit(1);
}
channel.setAlarm(value.intValue());
return true;
}
return false;
case CHANNEL_ALARM_PUSH:
if (command instanceof OnOffType) {
BigInteger value;
if (command == OnOffType.ON) {
value = BigInteger.valueOf(channel.getAlarm()).setBit(0);
} else {
value = BigInteger.valueOf(channel.getAlarm()).clearBit(0);
}
channel.setAlarm(value.intValue());
return true;
}
return false;
case CHANNEL_COLOR_NAME:
if (command instanceof StringType) {
channel.setColor(WlanThermoNanoV1Util.toHex(((StringType) command).toString()));
return true;
}
return false;
}
}
} else if (channelUID.getId().startsWith(CHANNEL_PITMASTER_1)) {
if (data.getPitmaster() != null && data.getPitmaster().getPm() != null
&& data.getPitmaster().getPm().size() > 0) {
Pm pm = data.getPitmaster().getPm().get(0);
switch (channelUID.getIdWithoutGroup()) {
case CHANNEL_PITMASTER_CHANNEL_ID:
pm.setChannel(((DecimalType) command).intValue());
return true;
case CHANNEL_PITMASTER_PIDPROFILE:
pm.setPid(((DecimalType) command).intValue());
return true;
case CHANNEL_PITMASTER_SETPOINT:
try {
pm.setSet(requireNonNull(((QuantityType<?>) command).toUnit(unit)).doubleValue());
return true;
} catch (WlanThermoInputException ignore) {
return false;
}
case CHANNEL_PITMASTER_STATE:
String state = ((StringType) command).toString();
if (state.equalsIgnoreCase("off") || state.equalsIgnoreCase("manual")
|| state.equalsIgnoreCase("auto")) {
pm.setTyp(state);
return true;
}
return false;
}
}
}
return false;
}
public static String getTrigger(ChannelUID channelUID, Data data)
throws WlanThermoUnknownChannelException, WlanThermoInputException {
String groupId = requireNonNull(channelUID.getGroupId());
List<Channel> channelList = data.getChannel();
if (channelUID.getId().startsWith(CHANNEL_PREFIX)) {
int channelId = Integer.parseInt(groupId.substring(CHANNEL_PREFIX.length())) - 1;
if (channelList.size() > 0 && channelId < channelList.size()) {
Channel channel = channelList.get(channelId);
if (CHANNEL_ALARM_OPENHAB.equals(channelUID.getIdWithoutGroup())) {
if (channel.getTemp() != 999) {
if (channel.getTemp() > channel.getMax()) {
return TRIGGER_ALARM_MAX;
} else if (channel.getTemp() < channel.getMin()) {
return TRIGGER_ALARM_MIN;
} else {
return TRIGGER_NONE;
}
}
}
}
}
throw new WlanThermoUnknownChannelException(channelUID);
}
}

View File

@ -0,0 +1,106 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.nano;
import static org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants.TRIGGER_NONE;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.wlanthermo.internal.*;
import org.openhab.binding.wlanthermo.internal.api.nano.dto.data.Data;
import org.openhab.binding.wlanthermo.internal.api.nano.dto.settings.Settings;
import org.openhab.core.thing.*;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
/**
* The {@link WlanThermoNanoV1Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
public class WlanThermoNanoV1Handler extends WlanThermoHandler {
private Data data = new Data();
private Settings settings = new Settings();
public WlanThermoNanoV1Handler(Thing thing, HttpClient httpClient) {
super(thing, httpClient, true);
}
@Override
protected State getState(ChannelUID channelUID) throws WlanThermoInputException, WlanThermoUnknownChannelException {
return WlanThermoNanoV1CommandHandler.getState(channelUID, data, settings);
}
@Override
protected boolean setState(ChannelUID channelUID, Command command) {
return WlanThermoNanoV1CommandHandler.setState(channelUID, command, data);
}
@Override
protected void push() {
// push update for sensor channels
for (org.openhab.binding.wlanthermo.internal.api.nano.dto.data.Channel c : data.getChannel()) {
try {
String json = gson.toJson(c);
if (!doPost("/setchannels", json)) {
break;
}
} catch (InterruptedException e) {
logger.debug("Push interrupted. {}", e.getMessage());
return;
}
}
// push update for pitmaster channels
try {
String json = gson.toJson(data.getPitmaster().getPm());
doPost("/setpitmaster", json);
} catch (InterruptedException e) {
logger.debug("Push interrupted. {}", e.getMessage());
}
}
@Override
protected void pull() {
try {
// Update objects with data from device
data = doGet("/data", Data.class);
settings = doGet("/settings", Settings.class);
// Update channels
for (Channel channel : thing.getChannels()) {
try {
State state = WlanThermoNanoV1CommandHandler.getState(channel.getUID(), data, settings);
updateState(channel.getUID(), state);
} catch (WlanThermoUnknownChannelException e) {
// if we could not obtain a state, try trigger instead
try {
String trigger = WlanThermoNanoV1CommandHandler.getTrigger(channel.getUID(), data);
if (!trigger.equals(TRIGGER_NONE)) {
triggerChannel(channel.getUID(), trigger);
}
} catch (WlanThermoUnknownChannelException e1) {
logger.debug("{}", e.getMessage());
}
}
}
} catch (WlanThermoException ignore) {
// Nothing more to do
} catch (InterruptedException e) {
logger.debug("Update interrupted. {}", e.getMessage());
}
}
}

View File

@ -15,18 +15,22 @@ package org.openhab.binding.wlanthermo.internal.api.nano;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.wlanthermo.internal.WlanThermoUtil;
/** /**
* The {@link UtilNano} class provides conversion functions for the WlanThermo Nano * The {@link WlanThermoNanoV1Util} class provides conversion functions for the WlanThermo Nano V1+
* *
* @author Christian Schlipp - Initial contribution * @author Christian Schlipp - Initial contribution
*/ */
public class UtilNano { @NonNullByDefault
public class WlanThermoNanoV1Util extends WlanThermoUtil {
private static final Map<String, String> COLOR_MAPPINGS = createColorMap(); private static final Map<String, String> COLOR_MAPPINGS = createColorMap();
private static final String DEFAULT_HEX = "#ffffff"; private static final String DEFAULT_HEX = "#ffffff";
private static final String DEFAULT_COLORNAME = "niagara"; private static final String DEFAULT_COLORNAME = "niagara";
private UtilNano() { private WlanThermoNanoV1Util() {
// hidden // hidden
} }
@ -56,18 +60,6 @@ public class UtilNano {
} }
public static String toColorName(String colorHex) { public static String toColorName(String colorHex) {
String colorName = null; return toColorName(colorHex, COLOR_MAPPINGS, DEFAULT_COLORNAME);
if (!colorHex.startsWith("#")) {
colorHex = "#" + colorHex;
}
for (Map.Entry<String, String> entry : COLOR_MAPPINGS.entrySet()) {
if (entry.getValue().equalsIgnoreCase(colorHex)) {
colorName = entry.getKey();
}
}
if (colorName == null) {
colorName = DEFAULT_COLORNAME;
}
return colorName;
} }
} }

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.data; package org.openhab.binding.wlanthermo.internal.api.nano.dto.data;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.data; package org.openhab.binding.wlanthermo.internal.api.nano.dto.data;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.data; package org.openhab.binding.wlanthermo.internal.api.nano.dto.data;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.data; package org.openhab.binding.wlanthermo.internal.api.nano.dto.data;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.data; package org.openhab.binding.wlanthermo.internal.api.nano.dto.data;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.settings; package org.openhab.binding.wlanthermo.internal.api.nano.dto.settings;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.settings; package org.openhab.binding.wlanthermo.internal.api.nano.dto.settings;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.settings; package org.openhab.binding.wlanthermo.internal.api.nano.dto.settings;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.settings; package org.openhab.binding.wlanthermo.internal.api.nano.dto.settings;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.settings; package org.openhab.binding.wlanthermo.internal.api.nano.dto.settings;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.settings; package org.openhab.binding.wlanthermo.internal.api.nano.dto.settings;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.settings; package org.openhab.binding.wlanthermo.internal.api.nano.dto.settings;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -10,7 +10,7 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.wlanthermo.internal.api.nano.settings; package org.openhab.binding.wlanthermo.internal.api.nano.dto.settings;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="wlanthermo"
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">
<!-- System Group ESP32 -->
<channel-group-type id="cg_system_esp32">
<label>System Channels</label>
<description>This group contains all system channels</description>
<channels>
<channel id="soc" typeId="system.battery-level"/>
<channel id="charge" typeId="charging"/>
<channel id="rssi" typeId="rssi"/>
<channel id="rssi_signalstrength" typeId="system.signal-strength"/>
</channels>
</channel-group-type>
<!-- Temperature Group ESP32 -->
<channel-group-type id="cg_temperature_esp32">
<label>Temperature Sensor</label>
<category>Sensor</category>
<channels>
<channel id="name" typeId="name"/>
<channel id="typ" typeId="typ"/>
<channel id="temp" typeId="temperature"/>
<channel id="min" typeId="temperature_min"/>
<channel id="max" typeId="temperature_max"/>
<channel id="alarm_device" typeId="alarm_device"/>
<channel id="alarm_push" typeId="alarm_push"/>
<channel id="alarm_openhab" typeId="alarm_openhab"/>
<channel id="alarm_openhab_low" typeId="alarm_openhab_low"/>
<channel id="alarm_openhab_high" typeId="alarm_openhab_high"/>
<channel id="color" typeId="color"/>
<channel id="color_name" typeId="color_name_esp32"/>
</channels>
</channel-group-type>
<!-- Pitmaster ESP32 -->
<channel-group-type id="cg_pitmaster_esp32">
<label>Pitmaster</label>
<category>Sensor</category>
<channels>
<channel id="state" typeId="pitmaster_type"/>
<channel id="setpoint" typeId="temperature_setpoint"/>
<channel id="duty_cycle" typeId="duty_cycle"/>
<channel id="channel_id" typeId="channel_id"/>
<channel id="pid_id" typeId="pid_id"/>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="wlanthermo"
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">
<!-- System Group Mini V1 -->
<channel-group-type id="cg_system_mini">
<label>System Channel</label>
<description>This group contains all system channels</description>
<channels>
<channel id="cpu_load" typeId="cpu_load"/>
<channel id="cpu_temp" typeId="temperature"/>
</channels>
</channel-group-type>
<!-- Channel Group Temperature Mini V1 -->
<channel-group-type id="cg_temperature_mini">
<label>Sensor Mini</label>
<category>Sensor</category>
<channels>
<channel id="name" typeId="name_ro"/>
<channel id="temp" typeId="temperature"/>
<channel id="min" typeId="temperature_min_ro"/>
<channel id="max" typeId="temperature_max_ro"/>
<channel id="alarm_device" typeId="alarm_device_ro"/>
<channel id="alarm_openhab" typeId="alarm_openhab"/>
<channel id="alarm_openhab_low" typeId="alarm_openhab_low"/>
<channel id="alarm_openhab_high" typeId="alarm_openhab_high"/>
<channel id="color" typeId="color_ro"/>
<channel id="color_name" typeId="color_name_mini_ro"/>
</channels>
</channel-group-type>
<!-- Pitmaster Mini V1 -->
<channel-group-type id="cg_pitmaster_mini">
<label>Pitmaster Mini</label>
<category>Sensor</category>
<channels>
<channel id="enabled" typeId="enabled"/>
<channel id="current" typeId="temperature"/>
<channel id="setpoint" typeId="temperature_setpoint_ro"/>
<channel id="duty_cycle" typeId="duty_cycle_ro"/>
<channel id="lid_open" typeId="lid_open"/>
<channel id="channel_id" typeId="channel_id_ro"/>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="wlanthermo"
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">
<!-- System Group Nano -->
<channel-group-type id="cg_system_nano">
<label>System Channel</label>
<description>This group contains all system channels</description>
<channels>
<channel id="soc" typeId="system.battery-level"/>
<channel id="charge" typeId="charging"/>
<channel id="rssi" typeId="rssi"/>
<channel id="rssi_signalstrength" typeId="system.signal-strength"/>
</channels>
</channel-group-type>
<!-- Temperature Group Nano -->
<channel-group-type id="cg_temperature_nano">
<label>Sensor Nano</label>
<category>Sensor</category>
<channels>
<channel id="name" typeId="name"/>
<channel id="typ" typeId="typ"/>
<channel id="temp" typeId="temperature"/>
<channel id="min" typeId="temperature_min"/>
<channel id="max" typeId="temperature_max"/>
<channel id="alarm_device" typeId="alarm_device"/>
<channel id="alarm_push" typeId="alarm_push"/>
<channel id="alarm_openhab" typeId="alarm_openhab"/>
<channel id="alarm_openhab_low" typeId="alarm_openhab_low"/>
<channel id="alarm_openhab_high" typeId="alarm_openhab_high"/>
<channel id="color" typeId="color_ro"/>
<channel id="color_name" typeId="color_name_nano"/>
</channels>
</channel-group-type>
<!-- Pitmaster Nano -->
<channel-group-type id="cg_pitmaster_nano">
<label>Pitmaster Nano</label>
<category>Sensor</category>
<channels>
<channel id="state" typeId="pitmaster_type"/>
<channel id="setpoint" typeId="temperature_setpoint"/>
<channel id="duty_cycle" typeId="duty_cycle"/>
<channel id="channel_id" typeId="channel_id"/>
<channel id="pid_id" typeId="pid_id"/>
</channels>
</channel-group-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,259 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="wlanthermo"
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">
<channel-type id="cpu_load" advanced="true">
<item-type>Number</item-type>
<label>CPU Load</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="name" advanced="false">
<item-type>String</item-type>
<label>Name</label>
<category>Text</category>
</channel-type>
<channel-type id="name_ro" advanced="false">
<item-type>String</item-type>
<label>Name</label>
<category>Text</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="typ" advanced="true">
<item-type>String</item-type>
<label>Type</label>
<category>Text</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="temperature" advanced="false">
<item-type>Number:Temperature</item-type>
<label>Current Temperature</label>
<category>Temperature</category>
<state min="0" pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="temperature_min" advanced="true">
<item-type>Number:Temperature</item-type>
<label>Low Temperature Alarm</label>
<category>Temperature</category>
<state min="0" step="0.1" pattern="%.1f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="temperature_max" advanced="true">
<item-type>Number:Temperature</item-type>
<label>High Temperature Alarm</label>
<category>Temperature</category>
<state min="0" step="0.1" pattern="%.1f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="temperature_min_ro" advanced="true">
<item-type>Number:Temperature</item-type>
<label>Low Temperature Alarm</label>
<category>Temperature</category>
<state min="0" step="0.1" pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="temperature_max_ro" advanced="true">
<item-type>Number:Temperature</item-type>
<label>High Temperature Alarm</label>
<category>Temperature</category>
<state min="0" step="0.1" pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="alarm_device" advanced="true">
<item-type>Switch</item-type>
<label>Alarm Buzzer</label>
<category>Switch</category>
</channel-type>
<channel-type id="alarm_device_ro" advanced="true">
<item-type>Switch</item-type>
<label>Alarm Buzzer</label>
<category>Switch</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="alarm_push" advanced="true">
<item-type>Switch</item-type>
<label>Push-Alarm</label>
<category>Switch</category>
</channel-type>
<channel-type id="alarm_openhab" advanced="true">
<kind>trigger</kind>
<label>OpenHAB Alarm Trigger</label>
<event>
<options>
<option value="MIN">Low Temperature Alarm</option>
<option value="MAX">High Temperature Alarm</option>
</options>
</event>
</channel-type>
<channel-type id="alarm_openhab_low" advanced="false">
<item-type>Switch</item-type>
<label>Low Temperature Alarm</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="alarm_openhab_high" advanced="false">
<item-type>Switch</item-type>
<label>High Temperature Alarm</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="color" advanced="true">
<item-type>Color</item-type>
<label>Color</label>
<category>Colorpicker</category>
</channel-type>
<channel-type id="color_name_nano" advanced="true">
<item-type>String</item-type>
<label>Color</label>
<category>Colorpicker</category>
<state>
<options>
<option value="niagara">Niagara</option>
<option value="rosa">Rosa</option>
<option value="lapis blue">Lapis Blue</option>
<option value="orange">Orange</option>
<option value="lila">Lila</option>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="gold">Gold</option>
<option value="kale">Kale</option>
<option value="brown">Brown</option>
</options>
</state>
</channel-type>
<channel-type id="color_name_esp32" advanced="true">
<item-type>String</item-type>
<label>Color</label>
<category>Colorpicker</category>
<state>
<options>
<option value="#FFFF00">yellow</option>
<option value="#FFC002">dark yellow</option>
<option value="#00FF00">green</option>
<option value="#FFFFFF">white</option>
<option value="#FF1DC4">pink</option>
<option value="#E46C0A">orange</option>
<option value="#C3D69B">olive</option>
<option value="#0FE6F1">light blue</option>
<option value="#0000FF">blue</option>
<option value="#03A923">dark green</option>
<option value="#C84B32">brown</option>
<option value="#FF9B69">light brown</option>
<option value="#5082BE">dark blue</option>
<option value="#FFB1D0">light pink</option>
<option value="#A6EF03">light green</option>
<option value="#D42A6B">dark pink</option>
<option value="#FFDA8F">beige</option>
<option value="#00B0F0">azure</option>
<option value="#948A54">dark olive</option>
</options>
</state>
</channel-type>
<channel-type id="color_ro" advanced="true">
<item-type>Color</item-type>
<label>Color</label>
<category>Colorpicker</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="color_name_mini_ro" advanced="true">
<item-type>String</item-type>
<label>Color Name</label>
<category>Text</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="enabled" advanced="false">
<item-type>Switch</item-type>
<label>Enabled</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="temperature_setpoint_ro" advanced="false">
<item-type>Number:Temperature</item-type>
<label>Setpoint Temperature</label>
<category>Temperature</category>
<state min="0" pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="duty_cycle_ro" advanced="false">
<item-type>Number</item-type>
<label>Duty Cycle / Control Out</label>
<state min="0" max="100" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="lid_open" advanced="false">
<item-type>Switch</item-type>
<label>Lid Open</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="channel_id_ro" advanced="false">
<item-type>Number</item-type>
<label>Channel ID</label>
<state min="0" max="9" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="pitmaster_type" advanced="false">
<item-type>String</item-type>
<label>State</label>
<state>
<options>
<option value="off">Off</option>
<option value="manual">Manual</option>
<option value="auto">Auto</option>
</options>
</state>
</channel-type>
<channel-type id="duty_cycle" advanced="false">
<item-type>Number</item-type>
<label>Duty Cycle / Control Out</label>
<state min="0" max="100" pattern="%d"/>
</channel-type>
<channel-type id="pid_id" advanced="false">
<item-type>Number</item-type>
<label>PID Profile ID</label>
<state pattern="%d"/>
</channel-type>
<channel-type id="temperature_setpoint" advanced="false">
<item-type>Number:Temperature</item-type>
<label>Setpoint Temperature</label>
<category>Temperature</category>
<state min="0" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="channel_id" advanced="false">
<item-type>Number</item-type>
<label>Temperature Channel ID</label>
<state min="1" pattern="%d"/>
</channel-type>
<channel-type id="charging" advanced="true">
<item-type>Switch</item-type>
<label>Charging</label>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="rssi" advanced="true">
<item-type>Number:Power</item-type>
<label>RSSI in dBm</label>
<category>Number</category>
<state readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="wlanthermo"
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="esp32">
<label>WlanThermo Mini V2, Nano V3, Link V1</label>
<description><![CDATA[ WlanThermo device with <b>ESP32 processor</b>, such as Mini V2 (ESP32), Nano V3, Link V1 ]]></description>
<channel-groups>
<channel-group id="system" typeId="cg_system_esp32"/>
<channel-group id="channel1" typeId="cg_temperature_esp32">
<label>Temperature Probe 1</label>
<description>This group contains all channels for temperature probe 1</description>
</channel-group>
<channel-group id="channel2" typeId="cg_temperature_esp32">
<label>Temperature Probe 2</label>
<description>This group contains all channels for temperature probe 2</description>
</channel-group>
<channel-group id="channel3" typeId="cg_temperature_esp32">
<label>Temperature Probe 3</label>
<description>This group contains all channels for temperature probe 3</description>
</channel-group>
<channel-group id="channel4" typeId="cg_temperature_esp32">
<label>Temperature Probe 4</label>
<description>This group contains all channels for temperature probe 4</description>
</channel-group>
<channel-group id="channel5" typeId="cg_temperature_esp32">
<label>Temperature Probe 5</label>
<description>This group contains all channels for temperature probe 5</description>
</channel-group>
<channel-group id="channel6" typeId="cg_temperature_esp32">
<label>Temperature Probe 6</label>
<description>This group contains all channels for temperature probe 6</description>
</channel-group>
<channel-group id="channel7" typeId="cg_temperature_esp32">
<label>Temperature Probe 7</label>
<description>This group contains all channels for temperature probe 7</description>
</channel-group>
<channel-group id="channel8" typeId="cg_temperature_esp32">
<label>Temperature Probe 8</label>
<description>This group contains all channels for temperature probe 8</description>
</channel-group>
<channel-group id="channel9" typeId="cg_temperature_esp32">
<label>Temperature Probe 9</label>
<description>This group contains all channels for temperature probe 9</description>
</channel-group>
<channel-group id="channel10" typeId="cg_temperature_esp32">
<label>Temperature Probe 10</label>
<description>This group contains all channels for temperature probe 10</description>
</channel-group>
<channel-group id="channel11" typeId="cg_temperature_esp32">
<label>Temperature Probe 11</label>
<description>This group contains all channels for temperature probe 11</description>
</channel-group>
<channel-group id="channel12" typeId="cg_temperature_esp32">
<label>Temperature Probe 12</label>
<description>This group contains all channels for temperature probe 12</description>
</channel-group>
<channel-group id="channel13" typeId="cg_temperature_esp32">
<label>Temperature Probe 13</label>
<description>This group contains all channels for temperature probe 13</description>
</channel-group>
<channel-group id="channel14" typeId="cg_temperature_esp32">
<label>Temperature Probe 14</label>
<description>This group contains all channels for temperature probe 14</description>
</channel-group>
<channel-group id="channel15" typeId="cg_temperature_esp32">
<label>Temperature Probe 15</label>
<description>This group contains all channels for temperature probe 15</description>
</channel-group>
<channel-group id="channel16" typeId="cg_temperature_esp32">
<label>Temperature Probe 16</label>
<description>This group contains all channels for temperature probe 16</description>
</channel-group>
<channel-group id="channel17" typeId="cg_temperature_esp32">
<label>Temperature Probe 17</label>
<description>This group contains all channels for temperature probe 17</description>
</channel-group>
<channel-group id="channel18" typeId="cg_temperature_esp32">
<label>Temperature Probe 18</label>
<description>This group contains all channels for temperature probe 18</description>
</channel-group>
<channel-group id="channel19" typeId="cg_temperature_esp32">
<label>Temperature Probe 19</label>
<description>This group contains all channels for temperature probe 19</description>
</channel-group>
<channel-group id="channel20" typeId="cg_temperature_esp32">
<label>Temperature Probe 20</label>
<description>This group contains all channels for temperature probe 20</description>
</channel-group>
<channel-group id="channel21" typeId="cg_temperature_esp32">
<label>Temperature Probe 21</label>
<description>This group contains all channels for temperature probe 21</description>
</channel-group>
<channel-group id="channel22" typeId="cg_temperature_esp32">
<label>Temperature Probe 22</label>
<description>This group contains all channels for temperature probe 22</description>
</channel-group>
<channel-group id="channel23" typeId="cg_temperature_esp32">
<label>Temperature Probe 23</label>
<description>This group contains all channels for temperature probe 23</description>
</channel-group>
<channel-group id="channel24" typeId="cg_temperature_esp32">
<label>Temperature Probe 24</label>
<description>This group contains all channels for temperature probe 24</description>
</channel-group>
<channel-group id="pit1" typeId="cg_pitmaster_esp32">
<label>Pitmaster 1</label>
<description>This group contains all channels for pitmaster channel 1</description>
</channel-group>
<channel-group id="pit2" typeId="cg_pitmaster_esp32">
<label>Pitmaster 2</label>
<description>This group contains all channels for pitmaster channel 2</description>
</channel-group>
</channel-groups>
<properties>
<property name="model">Model</property>
<property name="serial">Serial Number</property>
<property name="esp32_bt_enabled">Bluetooth available</property>
<property name="esp32_pm_enabled">Pitmaster available</property>
<property name="esp32_temp_channels">Temperature channels</property>
<property name="esp32_pm_channels">Pitmaster channels</property>
</properties>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<context>network-address</context>
<label>Network Address</label>
<description>Network address of the WlanThermo Nano.</description>
</parameter>
<parameter name="username" type="text">
<label>Username</label>
<description>Optional, only required for write access. Default: 'admin'</description>
<default>admin</default>
</parameter>
<parameter name="password" type="text">
<context>password</context>
<label>Password</label>
<description>Optional, only required for write access. Default: 'admin'</description>
<default>admin</default>
</parameter>
<parameter name="pollingInterval" type="integer" min="1" step="1" unit="s" required="true">
<label>Polling Interval</label>
<description>Seconds between fetching values from the WlanThermo Nano.</description>
<default>10</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="wlanthermo"
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="mini">
<label>WlanThermo Mini V1/V2</label>
<description><![CDATA[ WlanThermo Mini with <b>Raspberry Pi processor</b>, such as Mini V1/V2 ]]></description>
<channel-groups>
<channel-group id="system" typeId="cg_system_mini"/>
<channel-group id="channel0" typeId="cg_temperature_mini">
<label>Temperature Probe 1</label>
<description>This group contains all channels for temperature probe 1</description>
</channel-group>
<channel-group id="channel1" typeId="cg_temperature_mini">
<label>Temperature Probe 2</label>
<description>This group contains all channels for temperature probe 2</description>
</channel-group>
<channel-group id="channel2" typeId="cg_temperature_mini">
<label>Temperature Probe 3</label>
<description>This group contains all channels for temperature probe 3</description>
</channel-group>
<channel-group id="channel3" typeId="cg_temperature_mini">
<label>Temperature Probe 4</label>
<description>This group contains all channels for temperature probe 4</description>
</channel-group>
<channel-group id="channel4" typeId="cg_temperature_mini">
<label>Temperature Probe 5</label>
<description>This group contains all channels for temperature probe 5</description>
</channel-group>
<channel-group id="channel5" typeId="cg_temperature_mini">
<label>Temperature Probe 6</label>
<description>This group contains all channels for temperature probe 6</description>
</channel-group>
<channel-group id="channel6" typeId="cg_temperature_mini">
<label>Temperature Probe 7</label>
<description>This group contains all channels for temperature probe 7</description>
</channel-group>
<channel-group id="channel7" typeId="cg_temperature_mini">
<label>Temperature Probe 8</label>
<description>This group contains all channels for temperature probe 8</description>
</channel-group>
<channel-group id="channel8" typeId="cg_temperature_mini">
<label>Temperature Probe 9</label>
<description>This group contains all channels for temperature probe 9</description>
</channel-group>
<channel-group id="channel9" typeId="cg_temperature_mini">
<label>Temperature Probe 10</label>
<description>This group contains all channels for temperature probe 10</description>
</channel-group>
<channel-group id="pit1" typeId="cg_pitmaster_mini">
<label>Pitmaster 1</label>
<description>This group contains all channels for pitmaster channel 1</description>
</channel-group>
<channel-group id="pit2" typeId="cg_pitmaster_mini">
<label>Pitmaster 2</label>
<description>This group contains all channels for pitmaster channel 2</description>
</channel-group>
</channel-groups>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<context>network-address</context>
<label>Network Address</label>
<description>Network address of the WlanThermo Mini.</description>
</parameter>
<parameter name="pollingInterval" type="integer" min="1" step="1" unit="s" required="true">
<label>Polling Interval</label>
<description>Seconds between fetching values from the WlanThermo Mini.</description>
<default>10</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="wlanthermo"
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="nano">
<label>WlanThermo Nano</label>
<description>WlanThermo Nano V1/V1+</description>
<channel-groups>
<channel-group id="system" typeId="cg_system_nano"/>
<channel-group id="channel1" typeId="cg_temperature_nano">
<label>Temperature Probe 1</label>
<description>This group contains all channels for temperature probe 1</description>
</channel-group>
<channel-group id="channel2" typeId="cg_temperature_nano">
<label>Temperature Probe 2</label>
<description>This group contains all channels for temperature probe 2</description>
</channel-group>
<channel-group id="channel3" typeId="cg_temperature_nano">
<label>Temperature Probe 3</label>
<description>This group contains all channels for temperature probe 3</description>
</channel-group>
<channel-group id="channel4" typeId="cg_temperature_nano">
<label>Temperature Probe 4</label>
<description>This group contains all channels for temperature probe 4</description>
</channel-group>
<channel-group id="channel5" typeId="cg_temperature_nano">
<label>Temperature Probe 5</label>
<description>This group contains all channels for temperature probe 5</description>
</channel-group>
<channel-group id="channel6" typeId="cg_temperature_nano">
<label>Temperature Probe 6</label>
<description>This group contains all channels for temperature probe 6</description>
</channel-group>
<channel-group id="channel7" typeId="cg_temperature_nano">
<label>Temperature Probe 7</label>
<description>This group contains all channels for temperature probe 7</description>
</channel-group>
<channel-group id="channel8" typeId="cg_temperature_nano">
<label>Temperature Probe 8</label>
<description>This group contains all channels for temperature probe 8</description>
</channel-group>
<channel-group id="pit1" typeId="cg_pitmaster_nano">
<label>Pitmaster 1</label>
<description>This group contains all channels for pitmaster channel 1</description>
</channel-group>
</channel-groups>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<context>network-address</context>
<label>Network Address</label>
<description>Network address of the WlanThermo Nano.</description>
</parameter>
<parameter name="username" type="text">
<label>Username</label>
<description>Optional, only required for write access. Default: 'admin'</description>
<default>admin</default>
</parameter>
<parameter name="password" type="text">
<context>password</context>
<label>Password</label>
<description>Optional, only required for write access. Default: 'admin'</description>
<default>admin</default>
</parameter>
<parameter name="pollingInterval" type="integer" min="1" step="1" unit="s" required="true">
<label>Polling Interval</label>
<description>Seconds between fetching values from the WlanThermo Nano.</description>
<default>10</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@ -1,463 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="wlanthermo"
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="nano">
<label>WlanThermo Nano</label>
<description>WlanThermo Nano V1/V1+</description>
<channel-groups>
<channel-group id="system" typeId="cg_system_nano"/>
<channel-group id="channel1" typeId="cg_temperature_nano">
<label>Temperature Probe 1</label>
<description>This group contains all channels for temperature probe 1</description>
</channel-group>
<channel-group id="channel2" typeId="cg_temperature_nano">
<label>Temperature Probe 2</label>
<description>This group contains all channels for temperature probe 2</description>
</channel-group>
<channel-group id="channel3" typeId="cg_temperature_nano">
<label>Temperature Probe 3</label>
<description>This group contains all channels for temperature probe 3</description>
</channel-group>
<channel-group id="channel4" typeId="cg_temperature_nano">
<label>Temperature Probe 4</label>
<description>This group contains all channels for temperature probe 4</description>
</channel-group>
<channel-group id="channel5" typeId="cg_temperature_nano">
<label>Temperature Probe 5</label>
<description>This group contains all channels for temperature probe 5</description>
</channel-group>
<channel-group id="channel6" typeId="cg_temperature_nano">
<label>Temperature Probe 6</label>
<description>This group contains all channels for temperature probe 6</description>
</channel-group>
<channel-group id="channel7" typeId="cg_temperature_nano">
<label>Temperature Probe 7</label>
<description>This group contains all channels for temperature probe 7</description>
</channel-group>
<channel-group id="channel8" typeId="cg_temperature_nano">
<label>Temperature Probe 8</label>
<description>This group contains all channels for temperature probe 8</description>
</channel-group>
<channel-group id="pit1" typeId="cg_pitmaster_nano">
<label>Pitmaster 1</label>
<description>This group contains all channels for pitmaster channel 1</description>
</channel-group>
</channel-groups>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<context>network-address</context>
<label>Network Address</label>
<description>Network address of the WlanThermo Nano.</description>
</parameter>
<parameter name="username" type="text">
<label>Username</label>
<description>Optional, only required for write access. Default: 'admin'</description>
<default>admin</default>
</parameter>
<parameter name="password" type="text">
<context>password</context>
<label>Password</label>
<description>Optional, only required for write access. Default: 'admin'</description>
<default>admin</default>
</parameter>
<parameter name="pollingInterval" type="integer" min="1" step="1" unit="s" required="true">
<label>Polling Interval</label>
<description>Seconds between fetching values from the WlanThermo Nano.</description>
<default>10</default>
</parameter>
</config-description>
</thing-type>
<thing-type id="mini">
<label>WlanThermo Mini</label>
<description>WlanThermo Mini</description>
<channel-groups>
<channel-group id="system" typeId="cg_system_mini"/>
<channel-group id="channel0" typeId="cg_temperature_mini">
<label>Temperature Probe 1</label>
<description>This group contains all channels for temperature probe 1</description>
</channel-group>
<channel-group id="channel1" typeId="cg_temperature_mini">
<label>Temperature Probe 2</label>
<description>This group contains all channels for temperature probe 2</description>
</channel-group>
<channel-group id="channel2" typeId="cg_temperature_mini">
<label>Temperature Probe 3</label>
<description>This group contains all channels for temperature probe 3</description>
</channel-group>
<channel-group id="channel3" typeId="cg_temperature_mini">
<label>Temperature Probe 4</label>
<description>This group contains all channels for temperature probe 4</description>
</channel-group>
<channel-group id="channel4" typeId="cg_temperature_mini">
<label>Temperature Probe 5</label>
<description>This group contains all channels for temperature probe 5</description>
</channel-group>
<channel-group id="channel5" typeId="cg_temperature_mini">
<label>Temperature Probe 6</label>
<description>This group contains all channels for temperature probe 6</description>
</channel-group>
<channel-group id="channel6" typeId="cg_temperature_mini">
<label>Temperature Probe 7</label>
<description>This group contains all channels for temperature probe 7</description>
</channel-group>
<channel-group id="channel7" typeId="cg_temperature_mini">
<label>Temperature Probe 8</label>
<description>This group contains all channels for temperature probe 8</description>
</channel-group>
<channel-group id="channel8" typeId="cg_temperature_mini">
<label>Temperature Probe 9</label>
<description>This group contains all channels for temperature probe 9</description>
</channel-group>
<channel-group id="channel9" typeId="cg_temperature_mini">
<label>Temperature Probe 10</label>
<description>This group contains all channels for temperature probe 10</description>
</channel-group>
<channel-group id="pit1" typeId="cg_pitmaster_mini">
<label>Pitmaster 1</label>
<description>This group contains all channels for pitmaster channel 1</description>
</channel-group>
<channel-group id="pit2" typeId="cg_pitmaster_mini">
<label>Pitmaster 2</label>
<description>This group contains all channels for pitmaster channel 2</description>
</channel-group>
</channel-groups>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<context>network-address</context>
<label>Network Address</label>
<description>Network address of the WlanThermo Mini.</description>
</parameter>
<parameter name="pollingInterval" type="integer" min="1" step="1" unit="s" required="true">
<label>Polling Interval</label>
<description>Seconds between fetching values from the WlanThermo Mini.</description>
<default>10</default>
</parameter>
</config-description>
</thing-type>
<!-- System Group Nano -->
<channel-group-type id="cg_system_nano">
<label>System Channel</label>
<description>This group contains all system channels</description>
<channels>
<channel id="soc" typeId="system.battery-level"/>
<channel id="charge" typeId="charging"/>
<channel id="rssi" typeId="rssi"/>
<channel id="rssi_signalstrength" typeId="system.signal-strength"/>
</channels>
</channel-group-type>
<channel-type id="charging" advanced="true">
<item-type>Switch</item-type>
<label>Charging</label>
<category>Energy</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="rssi" advanced="true">
<item-type>Number</item-type>
<label>RSSI in dBm</label>
<category>Text</category>
<state readOnly="true"/>
</channel-type>
<!-- System Group Mini -->
<channel-group-type id="cg_system_mini">
<label>System Channel</label>
<description>This group contains all system channels</description>
<channels>
<channel id="cpu_load" typeId="cpu_load"/>
<channel id="cpu_temp" typeId="temperature"/>
</channels>
</channel-group-type>
<channel-type id="cpu_load" advanced="true">
<item-type>Number</item-type>
<label>CPU Load</label>
<state readOnly="true"/>
</channel-type>
<!-- Temperature Group Nano -->
<channel-group-type id="cg_temperature_nano">
<label>Sensor Nano</label>
<category>Sensor</category>
<channels>
<channel id="name" typeId="name"/>
<channel id="typ" typeId="typ"/>
<channel id="temp" typeId="temperature"/>
<channel id="min" typeId="temperature_min"/>
<channel id="max" typeId="temperature_max"/>
<channel id="alarm_device" typeId="alarm_device"/>
<channel id="alarm_push" typeId="alarm_push"/>
<channel id="alarm_openhab" typeId="alarm_openhab"/>
<channel id="alarm_openhab_low" typeId="alarm_openhab_low"/>
<channel id="alarm_openhab_high" typeId="alarm_openhab_high"/>
<channel id="color" typeId="color"/>
<channel id="color_name" typeId="color_name"/>
</channels>
</channel-group-type>
<!-- Channel Group Temperature Mini -->
<channel-group-type id="cg_temperature_mini">
<label>Sensor Mini</label>
<category>Sensor</category>
<channels>
<channel id="name" typeId="name_ro"/>
<channel id="temp" typeId="temperature"/>
<channel id="min" typeId="temperature_min_ro"/>
<channel id="max" typeId="temperature_max_ro"/>
<channel id="alarm_device" typeId="alarm_device_ro"/>
<channel id="alarm_openhab" typeId="alarm_openhab"/>
<channel id="alarm_openhab_low" typeId="alarm_openhab_low"/>
<channel id="alarm_openhab_high" typeId="alarm_openhab_high"/>
<channel id="color" typeId="color_ro"/>
<channel id="color_name" typeId="color_name_ro"/>
</channels>
</channel-group-type>
<!-- Fundamental channel types -->
<channel-type id="name" advanced="false">
<item-type>String</item-type>
<label>Probe Name</label>
<category>Text</category>
</channel-type>
<channel-type id="name_ro" advanced="false">
<item-type>String</item-type>
<label>Probe Name</label>
<category>Text</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="typ" advanced="true">
<item-type>String</item-type>
<label>Probe Type</label>
<category>Text</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="temperature" advanced="false">
<item-type>Number:Temperature</item-type>
<label>Current Temperature</label>
<category>Temperature</category>
<state min="0" pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="temperature_min" advanced="true">
<item-type>Number:Temperature</item-type>
<label>Low Temperature Alarm</label>
<category>Temperature</category>
<state min="0" step="0.1" pattern="%.1f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="temperature_max" advanced="true">
<item-type>Number:Temperature</item-type>
<label>High Temperature Alarm</label>
<category>Temperature</category>
<state min="0" step="0.1" pattern="%.1f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="temperature_min_ro" advanced="true">
<item-type>Number:Temperature</item-type>
<label>Low Temperature Alarm</label>
<category>Temperature</category>
<state min="0" step="0.1" pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="temperature_max_ro" advanced="true">
<item-type>Number:Temperature</item-type>
<label>High Temperature Alarm</label>
<category>Temperature</category>
<state min="0" step="0.1" pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="alarm_device" advanced="true">
<item-type>Switch</item-type>
<label>Alarm Buzzer</label>
<category>Switch</category>
</channel-type>
<channel-type id="alarm_device_ro" advanced="true">
<item-type>Switch</item-type>
<label>Alarm Buzzer</label>
<category>Switch</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="alarm_push" advanced="true">
<item-type>Switch</item-type>
<label>Push-Alarm</label>
<category>Switch</category>
</channel-type>
<channel-type id="alarm_openhab" advanced="true">
<kind>trigger</kind>
<label>Openhab Alarm Trigger</label>
<event>
<options>
<option value="MIN">Low Temperature Alarm</option>
<option value="MAX">High Temperature Alarm</option>
</options>
</event>
</channel-type>
<channel-type id="alarm_openhab_low" advanced="false">
<item-type>Switch</item-type>
<label>Low Temperature Alarm</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="alarm_openhab_high" advanced="false">
<item-type>Switch</item-type>
<label>High Temperature Alarm</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="color" advanced="true">
<item-type>Color</item-type>
<label>Color</label>
<category>Colorpicker</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="color_name" advanced="true">
<item-type>String</item-type>
<label>Probe Color</label>
<category>Colorpicker</category>
<state>
<options>
<option value="niagara">Niagara</option>
<option value="rosa">Rosa</option>
<option value="lapis blue">Lapis Blue</option>
<option value="orange">Orange</option>
<option value="lila">Lila</option>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="gold">Gold</option>
<option value="kale">Kale</option>
<option value="brown">Brown</option>
</options>
</state>
</channel-type>
<channel-type id="color_ro" advanced="true">
<item-type>Color</item-type>
<label>Probe Color</label>
<category>Colorpicker</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="color_name_ro" advanced="true">
<item-type>String</item-type>
<label>Probe Color Name</label>
<category>Text</category>
<state readOnly="true"/>
</channel-type>
<!-- Pitmaster Mini -->
<channel-group-type id="cg_pitmaster_mini">
<label>Pitmaster Mini</label>
<category>Sensor</category>
<channels>
<channel id="enabled" typeId="enabled"/>
<channel id="current" typeId="temperature"/>
<channel id="setpoint" typeId="temperature_setpoint_ro"/>
<channel id="duty_cycle" typeId="duty_cycle_ro"/>
<channel id="lid_open" typeId="lid_open"/>
<channel id="channel_id" typeId="channel_id_ro"/>
</channels>
</channel-group-type>
<channel-type id="enabled" advanced="false">
<item-type>Switch</item-type>
<label>Pitmaster Enabled</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="temperature_setpoint_ro" advanced="false">
<item-type>Number:Temperature</item-type>
<label>Pitmaster Setpoint Temperature</label>
<category>Temperature</category>
<state min="0" pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="duty_cycle_ro" advanced="false">
<item-type>Number</item-type>
<label>Pitmaster Duty Cycle / Control Out</label>
<state min="0" max="100" pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="lid_open" advanced="false">
<item-type>Switch</item-type>
<label>Pitmaster Lid Open</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="channel_id_ro" advanced="false">
<item-type>Number</item-type>
<label>Pitmaster Channel ID</label>
<state min="0" max="9" pattern="%d" readOnly="true"/>
</channel-type>
<!-- Pitmaster Nano -->
<channel-group-type id="cg_pitmaster_nano">
<label>Pitmaster Nano</label>
<category>Sensor</category>
<channels>
<channel id="state" typeId="pitmaster_type"/>
<channel id="setpoint" typeId="temperature_setpoint"/>
<channel id="duty_cycle" typeId="duty_cycle"/>
<channel id="channel_id" typeId="channel_id"/>
<channel id="pid_id" typeId="pid_id"/>
</channels>
</channel-group-type>
<channel-type id="pitmaster_type" advanced="false">
<item-type>String</item-type>
<label>Pitmaster State</label>
<state>
<options>
<option value="off">Off</option>
<option value="manual">Manual</option>
<option value="auto">Auto</option>
<!--<option value="autotune">Autotune</option> Not clear if still supported -->
</options>
</state>
</channel-type>
<channel-type id="duty_cycle" advanced="false">
<item-type>Number</item-type>
<label>Pitmaster Duty Cycle / Control Out</label>
<state min="0" max="100" pattern="%d"/>
</channel-type>
<channel-type id="pid_id" advanced="false">
<item-type>Number</item-type>
<label>PID Profile ID</label>
<state pattern="%d"/>
</channel-type>
<channel-type id="temperature_setpoint" advanced="false">
<item-type>Number:Temperature</item-type>
<label>Pitmaster Setpoint Temperature</label>
<category>Temperature</category>
<state min="0" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="channel_id" advanced="false">
<item-type>Number</item-type>
<label>Pitmaster Channel ID</label>
<state min="1" max="8" pattern="%d"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,224 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.esp32;
import static org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants.*;
import static org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants.TRIGGER_NONE;
import java.awt.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.function.Executable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.openhab.binding.wlanthermo.internal.WlanThermoException;
import org.openhab.binding.wlanthermo.internal.WlanThermoUnknownChannelException;
import org.openhab.binding.wlanthermo.internal.WlanThermoUtil;
import org.openhab.binding.wlanthermo.internal.api.esp32.dto.data.Data;
import org.openhab.binding.wlanthermo.internal.api.esp32.dto.settings.Settings;
import org.openhab.core.library.types.*;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import com.google.gson.Gson;
/**
* The {@link WlanThermoEsp32CommandHandlerTest} class tests the {@link WlanThermoEsp32CommandHandler}
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
class WlanThermoEsp32CommandHandlerTest {
private static final ThingUID THING_UID = new ThingUID("wlanthermo", "esp32", "test");
@Nullable
private Data data;
@Nullable
private Settings settings;
@BeforeEach
void setUp() {
Gson gson = new Gson();
ClassLoader classLoader = Objects.requireNonNull(WlanThermoEsp32CommandHandlerTest.class.getClassLoader());
InputStream dataStream = Objects.requireNonNull(classLoader.getResourceAsStream("esp32/data.json"));
InputStream settingsStream = Objects.requireNonNull(classLoader.getResourceAsStream("esp32/settings.json"));
data = gson.fromJson(new InputStreamReader(dataStream, StandardCharsets.UTF_8), Data.class);
settings = gson.fromJson(new InputStreamReader(settingsStream, StandardCharsets.UTF_8), Settings.class);
}
static Stream<Arguments> getState() {
return Stream.of(
// System channels
Arguments.of(SYSTEM, SYSTEM_SOC, new DecimalType(89), null),
Arguments.of(SYSTEM, SYSTEM_CHARGE, OnOffType.OFF, null),
Arguments.of(SYSTEM, SYSTEM_RSSI_SIGNALSTRENGTH, new DecimalType(4), null),
Arguments.of(SYSTEM, SYSTEM_RSSI, new QuantityType<>(-32, Units.DECIBEL_MILLIWATTS), null),
// All channels
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_NAME, new StringType("Kanal Eins"), null),
Arguments.of(CHANNEL_PREFIX + "2", CHANNEL_NAME, new StringType("Kanal 2"), null),
Arguments.of(CHANNEL_PREFIX + "3", CHANNEL_NAME, new StringType("Kanal 3"), null),
Arguments.of(CHANNEL_PREFIX + "4", CHANNEL_NAME, new StringType("Kanal 4"), null),
Arguments.of(CHANNEL_PREFIX + "5", CHANNEL_NAME, new StringType("Kanal 5"), null),
Arguments.of(CHANNEL_PREFIX + "6", CHANNEL_NAME, new StringType("Kanal 6"), null),
Arguments.of(CHANNEL_PREFIX + "7", CHANNEL_NAME, new StringType("Kanal 7"), null),
Arguments.of(CHANNEL_PREFIX + "8", CHANNEL_NAME, new StringType("Kanal 8"), null),
Arguments.of(CHANNEL_PREFIX + "9", CHANNEL_NAME, new StringType("Kanal 9"), null),
Arguments.of(CHANNEL_PREFIX + "10", CHANNEL_NAME, new StringType("Kanal 10"), null),
// invalid channel number
Arguments.of(CHANNEL_PREFIX + "11", CHANNEL_NAME, UnDefType.UNDEF,
WlanThermoUnknownChannelException.class),
// all channel values
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_NAME, new StringType("Kanal Eins"), null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_TYP, new StringType("1000K/Maverick"), null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_TEMP, new QuantityType<>(23.7, SIUnits.CELSIUS), null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_MIN, new QuantityType<>(17, SIUnits.CELSIUS), null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_MAX, new QuantityType<>(104, SIUnits.CELSIUS), null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_DEVICE, OnOffType.OFF, null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_PUSH, OnOffType.ON, null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_OPENHAB_HIGH, OnOffType.OFF, null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_OPENHAB_LOW, OnOffType.OFF, null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_COLOR,
HSBType.fromRGB(Color.decode("#270000").getRed(), Color.decode("#270000").getGreen(),
Color.decode("#270000").getBlue()),
null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_COLOR_NAME,
new StringType(WlanThermoEsp32Util.toColorName("#270000")), null),
// all pitmaster
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_CHANNEL_ID, new DecimalType(1), null),
Arguments.of(CHANNEL_PITMASTER_2, CHANNEL_PITMASTER_CHANNEL_ID, UnDefType.UNDEF, null),
// all pitmaster values
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_CHANNEL_ID, new DecimalType(1), null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_PIDPROFILE, new DecimalType(1), null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_DUTY_CYCLE, new DecimalType(70), null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_SETPOINT, new QuantityType<>(50, SIUnits.CELSIUS),
null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_STATE, new StringType("manual"), null));
}
static Stream<Arguments> getTrigger() {
return Stream.of(
// all channels
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_OPENHAB, TRIGGER_NONE, null),
Arguments.of(CHANNEL_PREFIX + "2", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "3", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "4", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "5", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "6", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "7", CHANNEL_ALARM_OPENHAB, TRIGGER_NONE, null),
Arguments.of(CHANNEL_PREFIX + "8", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "9", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "10", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
// invalid channel number
Arguments.of(CHANNEL_PREFIX + "11", CHANNEL_ALARM_OPENHAB, "",
WlanThermoUnknownChannelException.class));
}
static Stream<Arguments> setState() {
return Stream.of(
// All channels
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_NAME, new StringType("Kanal Eins"), true),
Arguments.of(CHANNEL_PREFIX + "2", CHANNEL_NAME, new StringType("Kanal 2"), true),
Arguments.of(CHANNEL_PREFIX + "3", CHANNEL_NAME, new StringType("Kanal 3"), true),
Arguments.of(CHANNEL_PREFIX + "4", CHANNEL_NAME, new StringType("Kanal 4"), true),
Arguments.of(CHANNEL_PREFIX + "5", CHANNEL_NAME, new StringType("Kanal 5"), true),
Arguments.of(CHANNEL_PREFIX + "6", CHANNEL_NAME, new StringType("Kanal 6"), true),
Arguments.of(CHANNEL_PREFIX + "7", CHANNEL_NAME, new StringType("Kanal 7"), true),
Arguments.of(CHANNEL_PREFIX + "8", CHANNEL_NAME, new StringType("Kanal 8"), true),
Arguments.of(CHANNEL_PREFIX + "9", CHANNEL_NAME, new StringType("Kanal 9"), true),
Arguments.of(CHANNEL_PREFIX + "10", CHANNEL_NAME, new StringType("Kanal 10"), true),
// invalid channel number
Arguments.of(CHANNEL_PREFIX + "11", CHANNEL_NAME, new StringType("Kanal 11"), false),
// all channel values
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_NAME, new StringType("Kanal Eins"), true),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_TYP, new StringType("1000K/Maverick"), false),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_TEMP, new QuantityType<>(23.7, SIUnits.CELSIUS), false),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_MIN, new QuantityType<>(17, SIUnits.CELSIUS), true),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_MAX, new QuantityType<>(104, SIUnits.CELSIUS), true),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_DEVICE, OnOffType.OFF, true),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_PUSH, OnOffType.ON, true),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_OPENHAB_HIGH, OnOffType.OFF, false),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_OPENHAB_LOW, OnOffType.OFF, false),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_COLOR,
HSBType.fromRGB(Color.decode("#270000").getRed(), Color.decode("#270000").getGreen(),
Color.decode("#270000").getBlue()),
true),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_COLOR_NAME,
new StringType(WlanThermoEsp32Util.toColorName("#270000")), true),
// all pitmaster
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_CHANNEL_ID, new DecimalType(1), true),
Arguments.of(CHANNEL_PITMASTER_2, CHANNEL_PITMASTER_CHANNEL_ID, new DecimalType(1), false),
// all pitmaster values
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_CHANNEL_ID, new DecimalType(1), true),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_PIDPROFILE, new DecimalType(0), true),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_DUTY_CYCLE, new DecimalType(0), false),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_SETPOINT, new QuantityType<>(100, SIUnits.CELSIUS),
true),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_STATE, new StringType("off"), true));
}
@ParameterizedTest
@MethodSource("getTrigger")
void getTrigger(String groupId, String id, String expectedTrigger,
@Nullable Class<WlanThermoException> exceptionClass) {
Executable test = () -> Assertions.assertEquals(expectedTrigger, WlanThermoEsp32CommandHandler
.getTrigger(new ChannelUID(THING_UID, groupId, id), WlanThermoUtil.requireNonNull(data)));
if (exceptionClass != null) {
Assertions.assertThrows(exceptionClass, test);
} else {
Assertions.assertDoesNotThrow(test);
}
}
@ParameterizedTest
@MethodSource("getState")
void getState(String groupId, String id, State expectedState, @Nullable Class<WlanThermoException> exceptionClass) {
Executable test = () -> Assertions.assertEquals(expectedState,
WlanThermoEsp32CommandHandler.getState(new ChannelUID(THING_UID, groupId, id),
WlanThermoUtil.requireNonNull(data), WlanThermoUtil.requireNonNull(settings)));
if (exceptionClass != null) {
Assertions.assertThrows(exceptionClass, test);
} else {
Assertions.assertDoesNotThrow(test);
}
}
@ParameterizedTest
@MethodSource("setState")
void setState(String groupId, String id, Command command, boolean expectedResult) {
Assertions.assertDoesNotThrow(() -> Assertions.assertEquals(expectedResult,
WlanThermoEsp32CommandHandler.setState(new ChannelUID(THING_UID, groupId, id), command,
WlanThermoUtil.requireNonNull(data), WlanThermoUtil.requireNonNull(settings))));
}
}

View File

@ -0,0 +1,160 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.mini;
import static org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants.*;
import java.awt.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.function.Executable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.openhab.binding.wlanthermo.internal.WlanThermoException;
import org.openhab.binding.wlanthermo.internal.WlanThermoUnknownChannelException;
import org.openhab.binding.wlanthermo.internal.WlanThermoUtil;
import org.openhab.binding.wlanthermo.internal.api.mini.dto.builtin.App;
import org.openhab.core.library.types.*;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import com.google.gson.Gson;
/**
* The {@link WlanThermoMiniCommandHandlerTest} class tests the {@link WlanThermoMiniCommandHandler}
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
class WlanThermoMiniCommandHandlerTest {
private static final ThingUID THING_UID = new ThingUID("wlanthermo", "mini", "test");
@Nullable
private App app;
@BeforeEach
void setUp() {
ClassLoader classLoader = Objects.requireNonNull(WlanThermoMiniCommandHandlerTest.class.getClassLoader());
InputStream stream = Objects.requireNonNull(classLoader.getResourceAsStream("mini/app.json"));
app = new Gson().fromJson(new InputStreamReader(stream, StandardCharsets.UTF_8), App.class);
}
static Stream<Arguments> getState() {
return Stream.of(
// System channels
Arguments.of(SYSTEM, SYSTEM_CPU_TEMP, new DecimalType(93.56), null),
Arguments.of(SYSTEM, SYSTEM_CPU_LOAD, new DecimalType(94.267515923567), null),
// all channels
Arguments.of(CHANNEL_PREFIX + "0", CHANNEL_NAME, new StringType("Kanal0"), null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_NAME, new StringType("Kanal1"), null),
Arguments.of(CHANNEL_PREFIX + "2", CHANNEL_NAME, new StringType("Kanal2"), null),
Arguments.of(CHANNEL_PREFIX + "3", CHANNEL_NAME, new StringType("Kanal3"), null),
Arguments.of(CHANNEL_PREFIX + "4", CHANNEL_NAME, new StringType("Kanal4"), null),
Arguments.of(CHANNEL_PREFIX + "5", CHANNEL_NAME, new StringType("Kanal5"), null),
Arguments.of(CHANNEL_PREFIX + "6", CHANNEL_NAME, new StringType("Kanal6"), null),
Arguments.of(CHANNEL_PREFIX + "7", CHANNEL_NAME, new StringType("Kanal7"), null),
Arguments.of(CHANNEL_PREFIX + "8", CHANNEL_NAME, new StringType("Kanal8 - Maverick 1"), null),
Arguments.of(CHANNEL_PREFIX + "9", CHANNEL_NAME, new StringType("Kanal9 - Maverick 2"), null),
// invalid channel number
Arguments.of(CHANNEL_PREFIX + "10", CHANNEL_NAME, UnDefType.UNDEF,
WlanThermoUnknownChannelException.class),
// all channel values
Arguments.of(CHANNEL_PREFIX + "0", CHANNEL_NAME, new StringType("Kanal0"), null),
Arguments.of(CHANNEL_PREFIX + "0", CHANNEL_TEMP, new QuantityType<>(78.28, ImperialUnits.FAHRENHEIT),
null),
Arguments.of(CHANNEL_PREFIX + "0", CHANNEL_MIN, new QuantityType<>(-20, ImperialUnits.FAHRENHEIT),
null),
Arguments.of(CHANNEL_PREFIX + "0", CHANNEL_MAX, new QuantityType<>(200, ImperialUnits.FAHRENHEIT),
null),
Arguments.of(CHANNEL_PREFIX + "0", CHANNEL_ALARM_DEVICE, OnOffType.from("false"), null),
Arguments.of(CHANNEL_PREFIX + "0", CHANNEL_ALARM_OPENHAB_HIGH, OnOffType.OFF, null),
Arguments.of(CHANNEL_PREFIX + "0", CHANNEL_ALARM_OPENHAB_LOW, OnOffType.OFF, null),
Arguments.of(CHANNEL_PREFIX + "0", CHANNEL_COLOR,
HSBType.fromRGB(Color.decode(WlanThermoMiniUtil.toHex("green")).getRed(),
Color.decode(WlanThermoMiniUtil.toHex("green")).getGreen(),
Color.decode(WlanThermoMiniUtil.toHex("green")).getBlue()),
null),
Arguments.of(CHANNEL_PREFIX + "0", CHANNEL_COLOR_NAME, new StringType("green"), null),
// all pitmaster
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_ENABLED, OnOffType.from(true), null),
Arguments.of(CHANNEL_PITMASTER_2, CHANNEL_PITMASTER_ENABLED, UnDefType.UNDEF, null),
// all pitmaster values
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_ENABLED, OnOffType.from(true), null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_CURRENT, new DecimalType(77.86), null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_SETPOINT,
new QuantityType<>(110, ImperialUnits.FAHRENHEIT), null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_DUTY_CYCLE, new DecimalType(100), null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_LID_OPEN, OnOffType.OFF, null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_CHANNEL_ID, new DecimalType(0), null));
}
static Stream<Arguments> getTrigger() {
return Stream.of(
// all channels
Arguments.of(CHANNEL_PREFIX + "0", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_OPENHAB, TRIGGER_NONE, null),
Arguments.of(CHANNEL_PREFIX + "2", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "3", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "4", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "5", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "6", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "7", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "8", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "9", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
// invalid channel number
Arguments.of(CHANNEL_PREFIX + "10", CHANNEL_ALARM_OPENHAB, "",
WlanThermoUnknownChannelException.class));
}
@ParameterizedTest
@MethodSource("getTrigger")
void getTrigger(String groupId, String id, String expectedTrigger,
@Nullable Class<WlanThermoException> exceptionClass) {
Executable test = () -> Assertions.assertEquals(expectedTrigger, WlanThermoMiniCommandHandler
.getTrigger(new ChannelUID(THING_UID, groupId, id), WlanThermoUtil.requireNonNull(app)));
if (exceptionClass != null) {
Assertions.assertThrows(exceptionClass, test);
} else {
Assertions.assertDoesNotThrow(test);
}
}
@ParameterizedTest
@MethodSource("getState")
void getState(String groupId, String id, State expectedState, @Nullable Class<WlanThermoException> exceptionClass) {
Executable test = () -> Assertions.assertEquals(expectedState, WlanThermoMiniCommandHandler
.getState(new ChannelUID(THING_UID, groupId, id), WlanThermoUtil.requireNonNull(app)));
if (exceptionClass != null) {
Assertions.assertThrows(exceptionClass, test);
} else {
Assertions.assertDoesNotThrow(test);
}
}
}

View File

@ -0,0 +1,207 @@
/**
* Copyright (c) 2010-2021 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.wlanthermo.internal.api.nano;
import static org.openhab.binding.wlanthermo.internal.WlanThermoBindingConstants.*;
import java.awt.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.function.Executable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.openhab.binding.wlanthermo.internal.WlanThermoException;
import org.openhab.binding.wlanthermo.internal.WlanThermoUnknownChannelException;
import org.openhab.binding.wlanthermo.internal.WlanThermoUtil;
import org.openhab.binding.wlanthermo.internal.api.nano.dto.data.Data;
import org.openhab.binding.wlanthermo.internal.api.nano.dto.settings.Settings;
import org.openhab.core.library.types.*;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import com.google.gson.Gson;
/**
* The {@link WlanThermoNanoV1CommandHandlerTest} class tests the {@link WlanThermoNanoV1CommandHandler}
*
* @author Christian Schlipp - Initial contribution
*/
@NonNullByDefault
class WlanThermoNanoV1CommandHandlerTest {
private static final ThingUID THING_UID = new ThingUID("wlanthermo", "nano", "test");
@Nullable
private Data data;
@Nullable
private Settings settings;
@BeforeEach
void setUp() {
Gson gson = new Gson();
ClassLoader classLoader = Objects.requireNonNull(WlanThermoNanoV1CommandHandlerTest.class.getClassLoader());
InputStream dataStream = Objects.requireNonNull(classLoader.getResourceAsStream("nanov1/data.json"));
InputStream settingsStream = Objects.requireNonNull(classLoader.getResourceAsStream("nanov1/settings.json"));
data = gson.fromJson(new InputStreamReader(dataStream, StandardCharsets.UTF_8), Data.class);
settings = gson.fromJson(new InputStreamReader(settingsStream, StandardCharsets.UTF_8), Settings.class);
}
static Stream<Arguments> getState() {
return Stream.of(
// System channels
Arguments.of(SYSTEM, SYSTEM_SOC, new DecimalType(32), null),
Arguments.of(SYSTEM, SYSTEM_CHARGE, OnOffType.OFF, null),
Arguments.of(SYSTEM, SYSTEM_RSSI_SIGNALSTRENGTH, new DecimalType(4), null),
Arguments.of(SYSTEM, SYSTEM_RSSI, new QuantityType<>(-47, Units.DECIBEL_MILLIWATTS), null),
// All channels
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_NAME, new StringType("Kanal 1"), null),
Arguments.of(CHANNEL_PREFIX + "2", CHANNEL_NAME, new StringType("Kanal 2"), null),
Arguments.of(CHANNEL_PREFIX + "3", CHANNEL_NAME, new StringType("Kanal 3"), null),
Arguments.of(CHANNEL_PREFIX + "4", CHANNEL_NAME, new StringType("Kanal 4"), null),
Arguments.of(CHANNEL_PREFIX + "5", CHANNEL_NAME, new StringType("Kanal 5"), null),
Arguments.of(CHANNEL_PREFIX + "6", CHANNEL_NAME, new StringType("Kanal 6"), null),
Arguments.of(CHANNEL_PREFIX + "7", CHANNEL_NAME, new StringType("Kanal 7"), null),
Arguments.of(CHANNEL_PREFIX + "8", CHANNEL_NAME, new StringType("Kanal 8"), null),
// invalid channel number
Arguments.of(CHANNEL_PREFIX + "9", CHANNEL_NAME, new StringType("Kanal 9"),
WlanThermoUnknownChannelException.class),
// all channel values
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_NAME, new StringType("Kanal 1"), null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_TYP, new StringType("1000K/Maverick"), null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_TEMP, new QuantityType<>(23.7, SIUnits.CELSIUS), null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_MIN, new QuantityType<>(11, SIUnits.CELSIUS), null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_MAX, new QuantityType<>(155, SIUnits.CELSIUS), null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_DEVICE, OnOffType.OFF, null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_PUSH, OnOffType.ON, null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_OPENHAB_HIGH, OnOffType.OFF, null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_OPENHAB_LOW, OnOffType.OFF, null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_COLOR,
HSBType.fromRGB(Color.decode("#EF562D").getRed(), Color.decode("#EF562D").getGreen(),
Color.decode("#EF562D").getBlue()),
null),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_COLOR_NAME,
new StringType(WlanThermoNanoV1Util.toColorName("#EF562D")), null),
// all pitmaster values
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_CHANNEL_ID, new DecimalType(1), null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_PIDPROFILE, new DecimalType(0), null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_DUTY_CYCLE, new DecimalType(0), null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_SETPOINT, new QuantityType<>(50, SIUnits.CELSIUS),
null),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_STATE, new StringType("off"), null));
}
static Stream<Arguments> getTrigger() {
return Stream.of(
// all channels
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_OPENHAB, TRIGGER_NONE, null),
Arguments.of(CHANNEL_PREFIX + "2", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "3", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "4", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "5", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "6", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
Arguments.of(CHANNEL_PREFIX + "7", CHANNEL_ALARM_OPENHAB, TRIGGER_NONE, null),
Arguments.of(CHANNEL_PREFIX + "8", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class),
// invalid channel number
Arguments.of(CHANNEL_PREFIX + "9", CHANNEL_ALARM_OPENHAB, "", WlanThermoUnknownChannelException.class));
}
static Stream<Arguments> setState() {
return Stream.of(
// All channels
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_NAME, new StringType("Kanal 1"), true),
Arguments.of(CHANNEL_PREFIX + "2", CHANNEL_NAME, new StringType("Kanal 2"), true),
Arguments.of(CHANNEL_PREFIX + "3", CHANNEL_NAME, new StringType("Kanal 3"), true),
Arguments.of(CHANNEL_PREFIX + "4", CHANNEL_NAME, new StringType("Kanal 4"), true),
Arguments.of(CHANNEL_PREFIX + "5", CHANNEL_NAME, new StringType("Kanal 5"), true),
Arguments.of(CHANNEL_PREFIX + "6", CHANNEL_NAME, new StringType("Kanal 6"), true),
Arguments.of(CHANNEL_PREFIX + "7", CHANNEL_NAME, new StringType("Kanal 7"), true),
Arguments.of(CHANNEL_PREFIX + "8", CHANNEL_NAME, new StringType("Kanal 8"), true),
// invalid channel number
Arguments.of(CHANNEL_PREFIX + "9", CHANNEL_NAME, new StringType("Kanal 9"), false),
// all channel values
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_NAME, new StringType("Kanal 1"), true),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_TYP, new StringType("1000K/Maverick"), false),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_TEMP, new QuantityType<>(23.7, SIUnits.CELSIUS), false),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_MIN, new QuantityType<>(11, SIUnits.CELSIUS), true),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_MAX, new QuantityType<>(155, SIUnits.CELSIUS), true),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_DEVICE, OnOffType.OFF, true),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_PUSH, OnOffType.ON, true),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_OPENHAB_HIGH, OnOffType.OFF, false),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_ALARM_OPENHAB_LOW, OnOffType.OFF, false),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_COLOR,
HSBType.fromRGB(Color.decode("#EF562D").getRed(), Color.decode("#EF562D").getGreen(),
Color.decode("#EF562D").getBlue()),
false),
Arguments.of(CHANNEL_PREFIX + "1", CHANNEL_COLOR_NAME,
new StringType(WlanThermoNanoV1Util.toColorName("#EF562D")), true),
// all pitmaster values
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_CHANNEL_ID, new DecimalType(1), true),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_PIDPROFILE, new DecimalType(0), true),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_DUTY_CYCLE, new DecimalType(0), false),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_SETPOINT, new QuantityType<>(50, SIUnits.CELSIUS),
true),
Arguments.of(CHANNEL_PITMASTER_1, CHANNEL_PITMASTER_STATE, new StringType("off"), true)
);
}
@ParameterizedTest
@MethodSource("getTrigger")
void getTrigger(String groupId, String id, String expectedTrigger,
@Nullable Class<WlanThermoException> exceptionClass) {
Executable test = () -> Assertions.assertEquals(expectedTrigger, WlanThermoNanoV1CommandHandler
.getTrigger(new ChannelUID(THING_UID, groupId, id), WlanThermoUtil.requireNonNull(data)));
if (exceptionClass != null) {
Assertions.assertThrows(exceptionClass, test);
} else {
Assertions.assertDoesNotThrow(test);
}
}
@ParameterizedTest
@MethodSource("getState")
void getState(String groupId, String id, State expectedState, @Nullable Class<WlanThermoException> exceptionClass) {
Executable test = () -> Assertions.assertEquals(expectedState,
WlanThermoNanoV1CommandHandler.getState(new ChannelUID(THING_UID, groupId, id),
WlanThermoUtil.requireNonNull(data), WlanThermoUtil.requireNonNull(settings)));
if (exceptionClass != null) {
Assertions.assertThrows(exceptionClass, test);
} else {
Assertions.assertDoesNotThrow(test);
}
}
@ParameterizedTest
@MethodSource("setState")
void setState(String groupId, String id, Command command, boolean expectedResult) {
Assertions.assertDoesNotThrow(() -> Assertions.assertEquals(expectedResult, WlanThermoNanoV1CommandHandler
.setState(new ChannelUID(THING_UID, groupId, id), command, WlanThermoUtil.requireNonNull(data))));
}
}

View File

@ -0,0 +1,151 @@
{
"system": {
"time": "1610894101",
"unit": "C",
"soc": 89,
"charge": false,
"rssi": -32,
"online": 0
},
"channel": [
{
"number": 1,
"name": "Kanal Eins",
"typ": 0,
"temp": 23.7,
"min": 17,
"max": 104,
"alarm": 1,
"color": "#270000",
"fixed": false,
"connected": false
},
{
"number": 2,
"name": "Kanal 2",
"typ": 0,
"temp": 999,
"min": 50,
"max": 95,
"alarm": 0,
"color": "#22B14C",
"fixed": false,
"connected": false
},
{
"number": 3,
"name": "Kanal 3",
"typ": 0,
"temp": 999,
"min": 50,
"max": 95,
"alarm": 0,
"color": "#EF562D",
"fixed": false,
"connected": false
},
{
"number": 4,
"name": "Kanal 4",
"typ": 0,
"temp": 999,
"min": 50,
"max": 95,
"alarm": 0,
"color": "#FFC100",
"fixed": false,
"connected": false
},
{
"number": 5,
"name": "Kanal 5",
"typ": 0,
"temp": 999,
"min": 50,
"max": 95,
"alarm": 0,
"color": "#A349A4",
"fixed": false,
"connected": false
},
{
"number": 6,
"name": "Kanal 6",
"typ": 0,
"temp": 999,
"min": 50,
"max": 95,
"alarm": 0,
"color": "#804000",
"fixed": false,
"connected": false
},
{
"number": 7,
"name": "Kanal 7",
"typ": 0,
"temp": 23.7,
"min": 10,
"max": 95,
"alarm": 0,
"color": "#5587A2",
"fixed": false,
"connected": false
},
{
"number": 8,
"name": "Kanal 8",
"typ": 0,
"temp": 999,
"min": 50,
"max": 95,
"alarm": 0,
"color": "#5C7148",
"fixed": false,
"connected": false
},
{
"number": 9,
"name": "Kanal 9",
"typ": 16,
"temp": 999,
"min": 50,
"max": 95,
"alarm": 0,
"color": "#A349A4",
"fixed": true,
"connected": false
},
{
"number": 10,
"name": "Kanal 10",
"typ": 16,
"temp": 999,
"min": 50,
"max": 95,
"alarm": 0,
"color": "#5587A2",
"fixed": true,
"connected": false
}
],
"pitmaster": {
"type": [
"off",
"manual",
"auto"
],
"pm": [
{
"id": 0,
"channel": 1,
"pid": 1,
"value": 70,
"set": 50,
"typ": "manual",
"set_color": "#ff0000",
"value_color": "#000000"
}
]
}
}

View File

@ -0,0 +1,229 @@
{
"device": {
"device": "nano",
"serial": "98f4ab7570c0",
"cpu": "esp32",
"flash_size": 16777216,
"item": "n3j04oA200B",
"hw_version": "v3",
"sw_version": "v1.1.0",
"api_version": "1",
"language": "de"
},
"system": {
"time": "1610894186",
"unit": "C",
"ap": "WLANTHERMO-AP",
"host": "NANO-98f4ab7570c0",
"language": "de",
"version": "v1.1.0",
"getupdate": "false",
"autoupd": true,
"prerelease": true,
"hwversion": "V3"
},
"hardware": [
"V3"
],
"api": {
"version": "1"
},
"sensors": [
{
"type": 0,
"name": "1000K/Maverick",
"fixed": false
},
{
"type": 1,
"name": "Fantast-Neu",
"fixed": false
},
{
"type": 2,
"name": "Fantast",
"fixed": false
},
{
"type": 3,
"name": "100K/iGrill2",
"fixed": false
},
{
"type": 4,
"name": "ET-73",
"fixed": false
},
{
"type": 5,
"name": "Perfektion",
"fixed": false
},
{
"type": 6,
"name": "50K",
"fixed": false
},
{
"type": 7,
"name": "Inkbird",
"fixed": false
},
{
"type": 8,
"name": "100K6A1B",
"fixed": false
},
{
"type": 9,
"name": "Weber_6743",
"fixed": false
},
{
"type": 10,
"name": "Santos",
"fixed": false
},
{
"type": 11,
"name": "5K3A1B",
"fixed": false
},
{
"type": 12,
"name": "PT100",
"fixed": false
},
{
"type": 13,
"name": "PT1000",
"fixed": false
},
{
"type": 14,
"name": "ThermoWorks",
"fixed": false
},
{
"type": 15,
"name": "Typ K",
"fixed": true
},
{
"type": 16,
"name": "Bluetooth",
"fixed": true
},
{
"type": 17,
"name": "Maverick",
"fixed": true
}
],
"features": {
"bluetooth": true,
"pitmaster": true
},
"pid": [
{
"name": "SSR SousVide",
"id": 0,
"aktor": 0,
"Kp": 104,
"Ki": 0.2,
"Kd": 0,
"DCmmin": 0,
"DCmmax": 100,
"opl": 0,
"SPmin": 0,
"SPmax": 0,
"link": 0,
"tune": 0,
"jp": 100
},
{
"name": "TITAN 50x50",
"id": 1,
"aktor": 1,
"Kp": 7,
"Ki": 0.01,
"Kd": 128,
"DCmmin": 25,
"DCmmax": 100,
"opl": 0,
"SPmin": 0,
"SPmax": 0,
"link": 0,
"tune": 0,
"jp": 70
},
{
"name": "Servo MG995",
"id": 2,
"aktor": 2,
"Kp": 104,
"Ki": 0.2,
"Kd": 0,
"DCmmin": 0,
"DCmmax": 100,
"opl": 0,
"SPmin": 25,
"SPmax": 75,
"link": 0,
"tune": 0,
"jp": 100
},
{
"name": "Custom",
"id": 3,
"aktor": 1,
"Kp": 7,
"Ki": 0.2,
"Kd": 0,
"DCmmin": 0,
"DCmmax": 100,
"opl": 0,
"SPmin": 0,
"SPmax": 100,
"link": 0,
"tune": 0,
"jp": 100
}
],
"aktor": [
"SSR",
"FAN",
"SERVO"
],
"display": {
"updname": "",
"orientation": 0
},
"iot": {
"PMQhost": "192.168.2.1",
"PMQport": 1883,
"PMQuser": "",
"PMQpass": "",
"PMQqos": 0,
"PMQon": false,
"PMQint": 30,
"CLon": false,
"CLtoken": "thisisnotatoken",
"CLint": 30,
"CLurl": "cloud.wlanthermo.de/index.html"
},
"notes": {
"fcm": [],
"ext": {
"on": 0,
"token": "",
"id": "",
"repeat": 1,
"service": 0,
"services": [
"telegram",
"pushover"
]
}
}
}

View File

@ -0,0 +1,121 @@
{
"temp_unit": "fahrenheit",
"pit": {
"enabled": true,
"timestamp": "2020-05-29T17:00:54-05:00",
"setpoint": 110,
"current": 77.86,
"control_out": 100,
"ch": 0,
"type": "False",
"open_lid": "False"
},
"pit2": {
"enabled": false
},
"cpu_load": 94.267515923567,
"cpu_temp": 93.56,
"channel": {
"0": {
"temp": 78.28,
"color": "green",
"state": "ok",
"temp_min": -20,
"temp_max": 200,
"name": "Kanal0",
"alert": false,
"show": true
},
"1": {
"temp": 0,
"color": "red",
"state": "er",
"temp_min": -20,
"temp_max": 200,
"name": "Kanal1",
"alert": false,
"show": true
},
"2": {
"temp": 0,
"color": "blue",
"state": "er",
"temp_min": -20,
"temp_max": 200,
"name": "Kanal2",
"alert": false,
"show": true
},
"3": {
"temp": 0,
"color": "olive",
"state": "er",
"temp_min": -20,
"temp_max": 200,
"name": "Kanal3",
"alert": false,
"show": true
},
"4": {
"temp": 0,
"color": "magenta",
"state": "er",
"temp_min": -20,
"temp_max": 200,
"name": "Kanal4",
"alert": false,
"show": true
},
"5": {
"temp": 0,
"color": "yellow",
"state": "er",
"temp_min": -20,
"temp_max": 200,
"name": "Kanal5",
"alert": false,
"show": true
},
"6": {
"temp": 0,
"color": "violet",
"state": "er",
"temp_min": -20,
"temp_max": 200,
"name": "Kanal6",
"alert": false,
"show": true
},
"7": {
"temp": 0,
"color": "purple",
"state": "er",
"temp_min": -20,
"temp_max": 200,
"name": "Kanal7",
"alert": false,
"show": true
},
"8": {
"temp": 0,
"color": "dark-violet",
"state": "er",
"temp_min": -20,
"temp_max": 200,
"name": "Kanal8 - Maverick 1",
"alert": false,
"show": true
},
"9": {
"temp": 0,
"color": "seagreen",
"state": "er",
"temp_min": -20,
"temp_max": 200,
"name": "Kanal9 - Maverick 2",
"alert": false,
"show": true
}
},
"timestamp": "2020-05-29T16:06:00-05:00"
}

View File

@ -0,0 +1,109 @@
{
"system": {
"time": "1610899485",
"unit": "C",
"soc": 32,
"charge": false,
"rssi": -47,
"online": 0
},
"channel": [
{
"number": 1,
"name": "Kanal 1",
"typ": 0,
"temp": 23.7,
"min": 11,
"max": 155,
"alarm": 1,
"color": "#EF562D"
},
{
"number": 2,
"name": "Kanal 2",
"typ": 3,
"temp": 999,
"min": 0,
"max": 48,
"alarm": 0,
"color": "#22B14C"
},
{
"number": 3,
"name": "Kanal 3",
"typ": 3,
"temp": 999,
"min": 10,
"max": 35,
"alarm": 0,
"color": "#EF562D"
},
{
"number": 4,
"name": "Kanal 4",
"typ": 3,
"temp": 999,
"min": 10,
"max": 54,
"alarm": 0,
"color": "#FFC100"
},
{
"number": 5,
"name": "Kanal 5",
"typ": 3,
"temp": 999,
"min": 0,
"max": 69,
"alarm": 0,
"color": "#A349A4"
},
{
"number": 6,
"name": "Kanal 6",
"typ": 0,
"temp": 999,
"min": 150,
"max": 170,
"alarm": 0,
"color": "#804000"
},
{
"number": 7,
"name": "Kanal 7",
"typ": 0,
"temp": 23.6,
"min": 0,
"max": 54,
"alarm": 0,
"color": "#5587A2"
},
{
"number": 8,
"name": "Kanal 8",
"typ": 0,
"temp": 999,
"min": 10,
"max": 35,
"alarm": 0,
"color": "#5C7148"
}
],
"pitmaster": {
"type": [
"off"
],
"pm": [
{
"id": 0,
"channel": 1,
"pid": 0,
"value": 0,
"set": 50,
"typ": "off",
"set_color": "#ff0000",
"value_color": "#000000"
}
]
}
}

View File

@ -0,0 +1,117 @@
{
"device": {
"device": "nano",
"serial": "33e8bb",
"item": "n2E04o42000",
"hw_version": "v2",
"sw_version": "v1.0.6",
"api_version": "1",
"language": "de"
},
"system": {
"time": "1610899506",
"unit": "C",
"ap": "NANO-AP",
"host": "NANO-33e8bb",
"language": "de",
"version": "v1.0.6",
"getupdate": "false",
"autoupd": true,
"hwversion": "V1+",
"god": 0
},
"hardware": [
"V1",
"V1+"
],
"api": {
"version": "1"
},
"sensors": [
"1000K/Maverick",
"Fantast-Neu",
"Fantast",
"100K/iGrill2",
"ET-73",
"Perfektion",
"50K",
"Inkbird",
"100K6A1B",
"Weber_6743",
"Santos",
"5K3A1B"
],
"pid": [
{
"name": "SSR SousVide",
"id": 0,
"aktor": 0,
"Kp": 104,
"Ki": 0.2,
"Kd": 0,
"DCmmin": 0,
"DCmmax": 100,
"opl": 0,
"tune": 0,
"jp": 100
},
{
"name": "TITAN 50x50",
"id": 1,
"aktor": 1,
"Kp": 3.8,
"Ki": 0.01,
"Kd": 128,
"DCmmin": 25,
"DCmmax": 100,
"opl": 0,
"tune": 0,
"jp": 70
},
{
"name": "Kamado 50x50",
"id": 2,
"aktor": 1,
"Kp": 7,
"Ki": 0.02,
"Kd": 630,
"DCmmin": 25,
"DCmmax": 100,
"opl": 0,
"tune": 0,
"jp": 70
}
],
"aktor": [
"SSR",
"FAN",
"SERVO"
],
"iot": {
"PMQhost": "192.168.2.1",
"PMQport": 1883,
"PMQuser": "",
"PMQpass": "",
"PMQqos": 0,
"PMQon": false,
"PMQint": 30,
"CLon": false,
"CLtoken": "thisisnotatoken",
"CLint": 30,
"CLurl": "cloud.wlanthermo.de/index.html"
},
"notes": {
"fcm": [],
"ext": {
"on": 0,
"token": "",
"id": "",
"repeat": 1,
"service": 0,
"services": [
"telegram",
"pushover"
]
}
}
}