mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-25 14:55:55 +01:00
[unifi] Fix bug with combination of other data/ports (#14060)
- It seems to throw an exception when updating internal cache. It can happen if you have a switch that has both PoE ports and other PoE ports or data in the port override. - Fixed logout, should be POST instead of GET. - Fixed typo in channel-type.config.unifi.poeEnable.mode.option.pasv24 should be without appending v. - Removed compiler warnings. Signed-off-by: Hilbrand Bouwkamp <hilbrand@h72.nl>
This commit is contained in:
parent
2d5402656e
commit
202a8647e0
@ -14,18 +14,17 @@ package org.openhab.binding.unifi.internal.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverrideJsonElement;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverrideJsonObject;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiClient;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiDevice;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiUnknownClient;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiWiredClient;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiWirelessClient;
|
||||
@ -42,6 +41,7 @@ import org.slf4j.LoggerFactory;
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* The {@link UniFiController} is the main communication point with an external instance of the Ubiquiti Networks
|
||||
@ -94,7 +94,7 @@ public class UniFiController {
|
||||
.registerTypeAdapter(UniFiWiredClient.class, clientInstanceCreator)
|
||||
.registerTypeAdapter(UniFiWirelessClient.class, clientInstanceCreator).create();
|
||||
this.poeGson = new GsonBuilder()
|
||||
.registerTypeAdapter(UnfiPortOverrideJsonElement.class, new UnfiPortOverrideJsonElementDeserializer())
|
||||
.registerTypeAdapter(UnfiPortOverrideJsonObject.class, new UnfiPortOverrideJsonElementDeserializer())
|
||||
.create();
|
||||
}
|
||||
|
||||
@ -133,7 +133,7 @@ public class UniFiController {
|
||||
|
||||
public void logout() throws UniFiException {
|
||||
csrfToken = "";
|
||||
final UniFiControllerRequest<Void> req = newRequest(Void.class, HttpMethod.GET, gson);
|
||||
final UniFiControllerRequest<Void> req = newRequest(Void.class, HttpMethod.POST, gson);
|
||||
req.setPath(unifios ? "/api/auth/logout" : "/logout");
|
||||
executeRequest(req);
|
||||
}
|
||||
@ -153,7 +153,7 @@ public class UniFiController {
|
||||
return cache;
|
||||
}
|
||||
|
||||
public @Nullable Map<Integer, UniFiPortTuple> getSwitchPorts(@Nullable final String deviceId) {
|
||||
public @Nullable UniFiSwitchPorts getSwitchPorts(@Nullable final String deviceId) {
|
||||
return cache.getSwitchPorts(deviceId);
|
||||
}
|
||||
|
||||
@ -175,10 +175,9 @@ public class UniFiController {
|
||||
refresh();
|
||||
}
|
||||
|
||||
public boolean poeMode(final UniFiDevice device, final List<UnfiPortOverrideJsonElement> data)
|
||||
throws UniFiException {
|
||||
public boolean poeMode(final UniFiDevice device, final List<JsonObject> data) throws UniFiException {
|
||||
// Safety check to make sure no empty data is send to avoid corrupting override data on the device.
|
||||
if (data.isEmpty() || data.stream().anyMatch(p -> p.getJsonObject().entrySet().isEmpty())) {
|
||||
if (data.isEmpty() || data.stream().anyMatch(p -> p.entrySet().isEmpty())) {
|
||||
logger.info("Not overriding port for '{}', because port data contains empty json: {}", device.getName(),
|
||||
poeGson.toJson(data));
|
||||
return false;
|
||||
@ -225,7 +224,7 @@ public class UniFiController {
|
||||
throws UniFiException {
|
||||
T result;
|
||||
try {
|
||||
result = request.execute();
|
||||
result = (T) request.execute();
|
||||
csrfToken = request.getCsrfToken();
|
||||
} catch (final UniFiExpiredSessionException e) {
|
||||
if (fromLogin) {
|
||||
@ -234,11 +233,11 @@ public class UniFiController {
|
||||
throw new UniFiCommunicationException(e);
|
||||
} else {
|
||||
login();
|
||||
result = executeRequest(request);
|
||||
result = (T) executeRequest(request);
|
||||
}
|
||||
} catch (final UniFiNotAuthorizedException e) {
|
||||
logger.warn("Not Authorized! Please make sure your controller credentials have administrator rights");
|
||||
result = null;
|
||||
result = (T) null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -124,14 +124,14 @@ class UniFiControllerRequest<T> {
|
||||
}
|
||||
|
||||
public @Nullable T execute() throws UniFiException {
|
||||
T result = null;
|
||||
T result = (T) null;
|
||||
final String json = getContent();
|
||||
// mgb: only try and unmarshall non-void result types
|
||||
if (!Void.class.equals(resultType)) {
|
||||
final JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
|
||||
|
||||
if (jsonObject.has(PROPERTY_DATA) && jsonObject.get(PROPERTY_DATA).isJsonArray()) {
|
||||
result = gson.fromJson(jsonObject.getAsJsonArray(PROPERTY_DATA), resultType);
|
||||
result = (T) gson.fromJson(jsonObject.getAsJsonArray(PROPERTY_DATA), resultType);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -106,7 +106,9 @@ abstract class UniFiCache<T extends @Nullable HasId> {
|
||||
logger.debug("Put #{} entries in {}: {}", values.length, getClass().getSimpleName(),
|
||||
lazyFormatAsList(values));
|
||||
for (final T value : values) {
|
||||
put(value.getId(), value);
|
||||
if (value != null) {
|
||||
put(value.getId(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
package org.openhab.binding.unifi.internal.api.cache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@ -23,12 +22,11 @@ import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverrideJsonElement;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiClient;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiDevice;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiPortTable;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiWlan;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -49,7 +47,7 @@ public class UniFiControllerCache {
|
||||
private final UniFiDeviceCache devicesCache = new UniFiDeviceCache();
|
||||
private final UniFiClientCache clientsCache = new UniFiClientCache();
|
||||
private final UniFiClientCache insightsCache = new UniFiClientCache();
|
||||
private final Map<String, Map<Integer, UniFiPortTuple>> devicesToPortTables = new ConcurrentHashMap<>();
|
||||
private final Map<String, UniFiSwitchPorts> devicesToPortTables = new ConcurrentHashMap<>();
|
||||
|
||||
public void clear() {
|
||||
sitesCache.clear();
|
||||
@ -94,23 +92,23 @@ public class UniFiControllerCache {
|
||||
devicesCache.putAll(devices);
|
||||
if (devices != null) {
|
||||
Stream.of(devices).filter(Objects::nonNull).forEach(d -> {
|
||||
Stream.ofNullable(d.getPortTable()).flatMap(pt -> Stream.of(pt)).filter(UniFiPortTable::isPortPoe)
|
||||
.forEach(p -> {
|
||||
final Map<Integer, UniFiPortTuple> tupleTable = devicesToPortTables
|
||||
.computeIfAbsent(d.getMac(), tt -> new HashMap<>());
|
||||
final UniFiPortTuple tuple = tupleTable.computeIfAbsent(p.getPortIdx(),
|
||||
t -> new UniFiPortTuple());
|
||||
Stream.ofNullable(d.getPortTable()).forEach(pt -> {
|
||||
final UniFiSwitchPorts switchPorts = devicesToPortTables.computeIfAbsent(d.getMac(),
|
||||
p -> new UniFiSwitchPorts());
|
||||
|
||||
tuple.setDevice(d);
|
||||
tuple.setTable(p);
|
||||
});
|
||||
Stream.of(pt).forEach(p -> {
|
||||
@SuppressWarnings("null")
|
||||
final UniFiPortTuple tuple = switchPorts.computeIfAbsent(p.getPortIdx());
|
||||
|
||||
tuple.setDevice(d);
|
||||
tuple.setTable(p);
|
||||
});
|
||||
});
|
||||
Stream.ofNullable(d.getPortOverrides()).forEach(po -> {
|
||||
final Map<Integer, UniFiPortTuple> tupleTable = devicesToPortTables.get(d.getMac());
|
||||
final UniFiSwitchPorts tupleTable = devicesToPortTables.get(d.getMac());
|
||||
|
||||
if (tupleTable != null) {
|
||||
Stream.of(po).filter(pof -> !pof.getAsJsonObject().entrySet().isEmpty())
|
||||
.map(UnfiPortOverrideJsonElement::new).forEach(p -> tupleTable
|
||||
.computeIfAbsent(p.getPortIdx(), t -> new UniFiPortTuple()).setJsonElement(p));
|
||||
Stream.of(po).forEach(p -> tupleTable.setOverride(p));
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -121,11 +119,12 @@ public class UniFiControllerCache {
|
||||
return devicesCache.get(id);
|
||||
}
|
||||
|
||||
public Map<Integer, UniFiPortTuple> getSwitchPorts(@Nullable final String deviceId) {
|
||||
return deviceId == null ? Map.of() : devicesToPortTables.getOrDefault(deviceId, Map.of());
|
||||
public UniFiSwitchPorts getSwitchPorts(@Nullable final String deviceId) {
|
||||
return deviceId == null ? new UniFiSwitchPorts()
|
||||
: devicesToPortTables.getOrDefault(deviceId, new UniFiSwitchPorts());
|
||||
}
|
||||
|
||||
public Collection<Map<Integer, UniFiPortTuple>> getSwitchPorts() {
|
||||
public Collection<UniFiSwitchPorts> getSwitchPorts() {
|
||||
return devicesToPortTables.values();
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,8 @@ class UniFiDeviceCache extends UniFiCache<UniFiDevice> {
|
||||
switch (prefix) {
|
||||
case MAC:
|
||||
return device.getMac();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
*/
|
||||
package org.openhab.binding.unifi.internal.api.dto;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
@ -22,7 +21,7 @@ import com.google.gson.JsonObject;
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
public class UnfiPortOverrideJsonElement {
|
||||
public class UnfiPortOverrideJsonObject {
|
||||
|
||||
private static final String PORT_IDX = "port_idx";
|
||||
private static final String PORT_CONF_ID = "port_conf_id";
|
||||
@ -30,14 +29,18 @@ public class UnfiPortOverrideJsonElement {
|
||||
|
||||
private final JsonObject jsonObject;
|
||||
|
||||
public UnfiPortOverrideJsonElement(final JsonElement element) {
|
||||
this.jsonObject = element.getAsJsonObject();
|
||||
public UnfiPortOverrideJsonObject(final JsonObject Object) {
|
||||
this.jsonObject = Object.getAsJsonObject();
|
||||
}
|
||||
|
||||
public JsonObject getJsonObject() {
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
public static boolean hasPortIdx(final JsonObject jsonObject) {
|
||||
return jsonObject.has(PORT_IDX);
|
||||
}
|
||||
|
||||
public int getPortIdx() {
|
||||
return jsonObject.get(PORT_IDX).getAsInt();
|
||||
}
|
@ -15,7 +15,7 @@ package org.openhab.binding.unifi.internal.api.dto;
|
||||
import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
|
||||
import org.openhab.binding.unifi.internal.api.util.UniFiTidyLowerCaseStringDeserializer;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
@ -44,7 +44,7 @@ public class UniFiDevice implements HasId {
|
||||
|
||||
private UniFiPortTable[] portTable;
|
||||
|
||||
private JsonElement[] portOverrides;
|
||||
private JsonObject[] portOverrides;
|
||||
|
||||
public UniFiDevice(final UniFiControllerCache cache) {
|
||||
this.cache = cache;
|
||||
@ -75,7 +75,7 @@ public class UniFiDevice implements HasId {
|
||||
return portTable;
|
||||
}
|
||||
|
||||
public JsonElement[] getPortOverrides() {
|
||||
public JsonObject[] getPortOverrides() {
|
||||
return portOverrides;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ package org.openhab.binding.unifi.internal.api.dto;
|
||||
|
||||
/**
|
||||
* Tuple to store both the {@link UniFiPortTable}, which contains the all information related to the port,
|
||||
* and the {@link UnfiPortOverrideJsonElement}, which contains the raw json data of the port override.
|
||||
* and the {@link UnfiPortOverrideJsonObject}, which contains the raw json data of the port override.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@ -24,7 +24,7 @@ public class UniFiPortTuple {
|
||||
|
||||
private UniFiPortTable table;
|
||||
|
||||
private UnfiPortOverrideJsonElement jsonElement;
|
||||
private UnfiPortOverrideJsonObject jsonElement;
|
||||
|
||||
public UniFiDevice getDevice() {
|
||||
return device;
|
||||
@ -46,11 +46,11 @@ public class UniFiPortTuple {
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
public UnfiPortOverrideJsonElement getJsonElement() {
|
||||
public UnfiPortOverrideJsonObject getJsonElement() {
|
||||
return jsonElement;
|
||||
}
|
||||
|
||||
public void setJsonElement(final UnfiPortOverrideJsonElement jsonElement) {
|
||||
public void setJsonElement(final UnfiPortOverrideJsonObject jsonElement) {
|
||||
this.jsonElement = jsonElement;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,122 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.unifi.internal.api.dto;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* Data object to keep track of all port data, including all port_override data (both for ports and additional data) on
|
||||
* a switch device.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class UniFiSwitchPorts {
|
||||
|
||||
/**
|
||||
* Port data grouped by port id.
|
||||
*/
|
||||
private final Map<Integer, UniFiPortTuple> ports = new HashMap<>();
|
||||
/**
|
||||
* Additional none port specific override data. Keep track to send to device when updating override data.
|
||||
*/
|
||||
private final Set<JsonObject> otherOverrides = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Return port data for the given port
|
||||
*
|
||||
* @param portIdx port to get the data for
|
||||
* @return Return port data for the given port
|
||||
*/
|
||||
public @Nullable UniFiPortTuple getPort(final int portIdx) {
|
||||
return ports.get(portIdx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return port data for the given port or if none exists set a new data object and return it.
|
||||
*
|
||||
* @param portIdx port to get the data for
|
||||
* @return Return port data for the given port or if none exists set a new data object and return it.
|
||||
*/
|
||||
public UniFiPortTuple computeIfAbsent(final int portIdx) {
|
||||
final UniFiPortTuple tuple = ports.computeIfAbsent(portIdx, t -> new UniFiPortTuple());
|
||||
if (tuple == null) {
|
||||
// This should never happen because ports can never contain a null value, and computeIfAbsent should never
|
||||
// return null. However to satisfy the compiler a check for null was added.
|
||||
throw new IllegalStateException("UniFiPortTuple is null for portIdx " + portIdx);
|
||||
}
|
||||
return tuple;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the list of PoE Ports.
|
||||
*/
|
||||
public List<UniFiPortTuple> getPoePorts() {
|
||||
return ports.values().stream().filter(e -> e.getTable().isPortPoe()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the override data as list with json objects after calling the updateMethod on the data for the given
|
||||
* portIdx.
|
||||
* The update method changes the data in the internal structure.
|
||||
*
|
||||
* @param portIdx port to call updateMethod for
|
||||
* @param updateMethod method to call to update data for a specific port
|
||||
* @return Returns a list of json objects of all override data
|
||||
*/
|
||||
public List<JsonObject> updatedList(final int portIdx, final Consumer<UnfiPortOverrideJsonObject> updateMethod) {
|
||||
@SuppressWarnings("null")
|
||||
final List<UnfiPortOverrideJsonObject> updatedList = ports.entrySet().stream()
|
||||
.map(e -> e.getValue().getJsonElement()).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
|
||||
updatedList.stream().filter(p -> p.getPortIdx() == portIdx).findAny().ifPresent(updateMethod::accept);
|
||||
|
||||
return Stream
|
||||
.concat(otherOverrides.stream(), updatedList.stream().map(UnfiPortOverrideJsonObject::getJsonObject))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the port override object. If it's for a specific port set bind it to the port data, otherwise store it as
|
||||
* generic data.
|
||||
*
|
||||
* @param jsonObject json object to set
|
||||
*/
|
||||
public void setOverride(final JsonObject jsonObject) {
|
||||
if (UnfiPortOverrideJsonObject.hasPortIdx(jsonObject)) {
|
||||
final UnfiPortOverrideJsonObject po = new UnfiPortOverrideJsonObject(jsonObject);
|
||||
final UniFiPortTuple tuple = ports.get(po.getPortIdx());
|
||||
|
||||
if (tuple == null) {
|
||||
otherOverrides.add(jsonObject);
|
||||
} else {
|
||||
tuple.setJsonElement(po);
|
||||
}
|
||||
} else {
|
||||
otherOverrides.add(jsonObject);
|
||||
}
|
||||
}
|
||||
}
|
@ -15,22 +15,22 @@ package org.openhab.binding.unifi.internal.api.util;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverrideJsonElement;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverrideJsonObject;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
/**
|
||||
* Serializer for {@link UnfiPortOverrideJsonElement}. Returns the content of the jsonObject in the class.
|
||||
* Serializer for {@link UnfiPortOverrideJsonObject}. Returns the content of the jsonObject in the class.
|
||||
*
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class UnfiPortOverrideJsonElementDeserializer implements JsonSerializer<UnfiPortOverrideJsonElement> {
|
||||
public class UnfiPortOverrideJsonElementDeserializer implements JsonSerializer<UnfiPortOverrideJsonObject> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(final UnfiPortOverrideJsonElement src, final Type typeOfSrc,
|
||||
public JsonElement serialize(final UnfiPortOverrideJsonObject src, final Type typeOfSrc,
|
||||
final JsonSerializationContext context) {
|
||||
return src.getJsonObject();
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ public abstract class UniFiBaseThingHandler<E, C> extends BaseThingHandler {
|
||||
return;
|
||||
}
|
||||
// mgb: derive the config class from the generic type
|
||||
@SuppressWarnings("null")
|
||||
final Class<?> clazz = (Class<?>) (((ParameterizedType) getClass().getGenericSuperclass())
|
||||
.getActualTypeArguments()[1]);
|
||||
final C config = (C) getConfigAs(clazz);
|
||||
@ -99,7 +100,7 @@ public abstract class UniFiBaseThingHandler<E, C> extends BaseThingHandler {
|
||||
logger.debug("Handling command = {} for channel = {}", command, channelUID);
|
||||
// mgb: only handle commands if we're ONLINE
|
||||
if (getThing().getStatus() == ONLINE) {
|
||||
final E entity = getEntity();
|
||||
final @Nullable E entity = getEntity();
|
||||
final UniFiController controller = getController();
|
||||
|
||||
if (command == REFRESH) {
|
||||
@ -128,13 +129,13 @@ public abstract class UniFiBaseThingHandler<E, C> extends BaseThingHandler {
|
||||
protected final void refresh() {
|
||||
// mgb: only refresh if we're ONLINE
|
||||
if (getThing().getStatus() == ONLINE) {
|
||||
final E entity = getEntity();
|
||||
final @Nullable E entity = getEntity();
|
||||
|
||||
getThing().getChannels().forEach(channel -> updateState(entity, channel.getUID()));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateState(final E entity, final ChannelUID channelUID) {
|
||||
private void updateState(final @Nullable E entity, final ChannelUID channelUID) {
|
||||
final String channelId = channelUID.getId();
|
||||
final State state = Optional.ofNullable(entity).map(e -> getChannelState(e, channelId))
|
||||
.orElseGet(() -> getDefaultState(channelId));
|
||||
|
@ -39,6 +39,7 @@ import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder;
|
||||
import org.openhab.core.types.Command;
|
||||
@ -107,13 +108,15 @@ public class UniFiControllerThingHandler extends BaseBridgeHandler {
|
||||
@Override
|
||||
public void dispose() {
|
||||
cancelRefreshJob();
|
||||
final UniFiController controller = this.controller;
|
||||
|
||||
if (controller != null) {
|
||||
try {
|
||||
controller.stop();
|
||||
} catch (final UniFiException e) {
|
||||
// mgb: nop as we're in dispose
|
||||
}
|
||||
controller = null;
|
||||
this.controller = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,8 +191,10 @@ public class UniFiControllerThingHandler extends BaseBridgeHandler {
|
||||
uc.refresh();
|
||||
// mgb: then refresh all the client things
|
||||
getThing().getThings().forEach((thing) -> {
|
||||
if (thing.getHandler() instanceof UniFiBaseThingHandler) {
|
||||
((UniFiBaseThingHandler) thing.getHandler()).refresh();
|
||||
final ThingHandler handler = thing.getHandler();
|
||||
|
||||
if (handler instanceof UniFiBaseThingHandler) {
|
||||
((UniFiBaseThingHandler<?, ?>) handler).refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -25,11 +25,6 @@ import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_P
|
||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_PORT_POE_VOLTAGE;
|
||||
import static org.openhab.core.library.unit.MetricPrefix.MILLI;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.measure.quantity.ElectricCurrent;
|
||||
import javax.measure.quantity.ElectricPotential;
|
||||
import javax.measure.quantity.Power;
|
||||
@ -40,14 +35,15 @@ import org.openhab.binding.unifi.internal.UniFiPoePortThingConfig;
|
||||
import org.openhab.binding.unifi.internal.api.UniFiController;
|
||||
import org.openhab.binding.unifi.internal.api.UniFiException;
|
||||
import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverrideJsonElement;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiDevice;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiPortTable;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
@ -64,8 +60,7 @@ import org.slf4j.LoggerFactory;
|
||||
* @author Hilbrand Bouwkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class UniFiPoePortThingHandler
|
||||
extends UniFiBaseThingHandler<Map<Integer, UniFiPortTuple>, UniFiPoePortThingConfig> {
|
||||
public class UniFiPoePortThingHandler extends UniFiBaseThingHandler<UniFiSwitchPorts, UniFiPoePortThingConfig> {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(UniFiPoePortThingHandler.class);
|
||||
|
||||
@ -84,20 +79,30 @@ public class UniFiPoePortThingHandler
|
||||
"@text/error.thing.poe.offline.configuration_error");
|
||||
return false;
|
||||
}
|
||||
final String channelConfigPoeEnableMode = (String) getThing().getChannel(CHANNEL_PORT_POE_ENABLE)
|
||||
.getConfiguration().get(CHANNEL_ENABLE_PARAMETER_MODE);
|
||||
poeEnableMode = channelConfigPoeEnableMode.isBlank() ? CHANNEL_ENABLE_PARAMETER_MODE_AUTO
|
||||
: channelConfigPoeEnableMode;
|
||||
return true;
|
||||
return initPoeEnableMode();
|
||||
}
|
||||
|
||||
private boolean initPoeEnableMode() {
|
||||
final Channel channel = getThing().getChannel(CHANNEL_PORT_POE_ENABLE);
|
||||
|
||||
if (channel == null) {
|
||||
return false;
|
||||
} else {
|
||||
final String channelConfigPoeEnableMode = (String) channel.getConfiguration()
|
||||
.get(CHANNEL_ENABLE_PARAMETER_MODE);
|
||||
poeEnableMode = channelConfigPoeEnableMode.isBlank() ? CHANNEL_ENABLE_PARAMETER_MODE_AUTO
|
||||
: channelConfigPoeEnableMode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Map<Integer, UniFiPortTuple> getEntity(final UniFiControllerCache cache) {
|
||||
protected @Nullable UniFiSwitchPorts getEntity(final UniFiControllerCache cache) {
|
||||
return cache.getSwitchPorts(config.getMacAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected State getChannelState(final Map<Integer, UniFiPortTuple> ports, final String channelId) {
|
||||
protected State getChannelState(final UniFiSwitchPorts ports, final String channelId) {
|
||||
final UniFiPortTuple portTuple = getPort(ports);
|
||||
|
||||
if (portTuple == null) {
|
||||
@ -143,30 +148,30 @@ public class UniFiPoePortThingHandler
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
|
||||
private @Nullable UniFiPortTuple getPort(final Map<Integer, UniFiPortTuple> ports) {
|
||||
return ports.get(config.getPortNumber());
|
||||
private @Nullable UniFiPortTuple getPort(final UniFiSwitchPorts ports) {
|
||||
return ports.getPort(config.getPortNumber());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handleCommand(final UniFiController controller, final Map<Integer, UniFiPortTuple> ports,
|
||||
protected boolean handleCommand(final UniFiController controller, final UniFiSwitchPorts ports,
|
||||
final ChannelUID channelUID, final Command command) throws UniFiException {
|
||||
final String channelID = channelUID.getIdWithoutGroup();
|
||||
|
||||
switch (channelID) {
|
||||
case CHANNEL_PORT_POE_ENABLE:
|
||||
if (command instanceof OnOffType) {
|
||||
return handleModeCommand(controller, ports, getPort(ports),
|
||||
return handleModeCommand(controller, ports,
|
||||
OnOffType.ON == command ? poeEnableMode : CHANNEL_ENABLE_PARAMETER_MODE_OFF);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_PORT_POE_MODE:
|
||||
if (command instanceof StringType) {
|
||||
return handleModeCommand(controller, ports, getPort(ports), command.toFullString());
|
||||
return handleModeCommand(controller, ports, command.toFullString());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_PORT_POE_CMD:
|
||||
if (command instanceof StringType) {
|
||||
return handleCmd(controller, getPort(ports), command.toFullString());
|
||||
return handleCmd(controller, ports, command.toFullString());
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
@ -174,39 +179,39 @@ public class UniFiPoePortThingHandler
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean handleModeCommand(final UniFiController controller, final Map<Integer, UniFiPortTuple> ports,
|
||||
final @Nullable UniFiPortTuple uniFiPortTuple, final String poeMode) throws UniFiException {
|
||||
final UniFiDevice device = controller.getCache().getDevice(config.getMacAddress());
|
||||
private boolean handleModeCommand(final UniFiController controller, final UniFiSwitchPorts ports,
|
||||
final String poeMode) throws UniFiException {
|
||||
final @Nullable UniFiDevice device = controller.getCache().getDevice(config.getMacAddress());
|
||||
|
||||
if (device == null || uniFiPortTuple == null) {
|
||||
logger.info("Could not change the PoE port state for thing '{}': device {} or portToUpdate {} null",
|
||||
getThing().getUID(), device, uniFiPortTuple);
|
||||
} else {
|
||||
final List<UnfiPortOverrideJsonElement> updatedList = ports.entrySet().stream()
|
||||
.map(e -> e.getValue().getJsonElement()).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
|
||||
updatedList.stream().filter(p -> p.getPortIdx() == uniFiPortTuple.getPortIdx()).findAny()
|
||||
.ifPresent(p -> p.setPoeMode(poeMode));
|
||||
controller.poeMode(device, updatedList);
|
||||
if (canUpdate(device, ports) && device != null) {
|
||||
controller.poeMode(device, ports.updatedList(config.getPortNumber(), p -> p.setPoeMode(poeMode)));
|
||||
// No refresh because UniFi device takes some time to update. Therefore a refresh would only show the
|
||||
// old state.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleCmd(final UniFiController controller, @Nullable final UniFiPortTuple portToUpdate,
|
||||
final String command) throws UniFiException {
|
||||
final UniFiDevice device = controller.getCache().getDevice(config.getMacAddress());
|
||||
if (device == null || portToUpdate == null) {
|
||||
logger.info("Could not change the PoE port state for thing '{}': device {} or portToUpdate {} null",
|
||||
getThing().getUID(), device, portToUpdate);
|
||||
} else {
|
||||
private boolean handleCmd(final UniFiController controller, final UniFiSwitchPorts ports, final String command)
|
||||
throws UniFiException {
|
||||
final @Nullable UniFiDevice device = controller.getCache().getDevice(config.getMacAddress());
|
||||
|
||||
if (canUpdate(device, ports) && device != null) {
|
||||
if (CHANNEL_PORT_POE_CMD_POWER_CYCLE.equalsIgnoreCase(command.replaceAll("[- ]", ""))) {
|
||||
controller.poePowerCycle(device, portToUpdate.getPortIdx());
|
||||
controller.poePowerCycle(device, config.getPortNumber());
|
||||
} else {
|
||||
logger.info("Unknown command '{}' given to PoE port for thing '{}': device {} or portToUpdate {} null",
|
||||
command, getThing().getUID(), device, portToUpdate);
|
||||
command, getThing().getUID(), device, ports);
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean canUpdate(final @Nullable UniFiDevice device, final UniFiSwitchPorts ports) {
|
||||
if (device == null || getPort(ports) == null) {
|
||||
logger.info("Could not change the PoE port state for thing '{}': device {} or portToUpdate {} null",
|
||||
getThing().getUID(), device, config.getPortNumber());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import static org.openhab.binding.unifi.internal.UniFiBindingConstants.PARAMETER
|
||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.PARAMETER_WIFI_NAME;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -34,6 +33,7 @@ import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiClient;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
|
||||
import org.openhab.binding.unifi.internal.api.dto.UniFiWlan;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
@ -161,9 +161,8 @@ public class UniFiThingDiscoveryService extends AbstractDiscoveryService
|
||||
}
|
||||
|
||||
private void discoverPoePorts(final UniFiControllerCache cache, final ThingUID bridgeUID) {
|
||||
for (final Map<Integer, UniFiPortTuple> uc : cache.getSwitchPorts()) {
|
||||
for (final Entry<Integer, UniFiPortTuple> sp : uc.entrySet()) {
|
||||
final UniFiPortTuple pt = sp.getValue();
|
||||
for (final UniFiSwitchPorts uc : cache.getSwitchPorts()) {
|
||||
for (final UniFiPortTuple pt : uc.getPoePorts()) {
|
||||
final String deviceMac = pt.getDevice().getMac();
|
||||
final String id = deviceMac.replace(":", "") + "_" + pt.getPortIdx();
|
||||
final ThingUID thingUID = new ThingUID(UniFiBindingConstants.THING_TYPE_POE_PORT, bridgeUID, id);
|
||||
|
@ -127,7 +127,7 @@ channel-type.unifi.wpaMode.description = WPA Mode of the Wi-Fi network
|
||||
channel-type.config.unifi.poeEnable.mode.label = On Mode
|
||||
channel-type.config.unifi.poeEnable.mode.description = The value to set when setting PoE on.
|
||||
channel-type.config.unifi.poeEnable.mode.option.auto = Auto
|
||||
channel-type.config.unifi.poeEnable.mode.option.pasv24v = 24V
|
||||
channel-type.config.unifi.poeEnable.mode.option.pasv24 = 24V
|
||||
channel-type.config.unifi.poeEnable.mode.option.passthrough = Passthrough
|
||||
|
||||
# status messages
|
||||
|
Loading…
Reference in New Issue
Block a user