[ipp] Added representation property and code improvements (#12039)

* Added representation property

Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
This commit is contained in:
Christoph Weitkamp 2022-01-14 11:32:58 +01:00 committed by GitHub
parent 1ee5906fc7
commit e3e4cd667d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 103 additions and 94 deletions

View File

@ -12,7 +12,6 @@
*/ */
package org.openhab.binding.ipp.internal; package org.openhab.binding.ipp.internal;
import java.util.Collections;
import java.util.Set; import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
@ -39,7 +38,8 @@ public class IppBindingConstants {
public static final String PRINTER_PARAMETER_URL = "url"; public static final String PRINTER_PARAMETER_URL = "url";
public static final String PRINTER_PARAMETER_NAME = "name"; public static final String PRINTER_PARAMETER_NAME = "name";
public static final String PRINTER_PARAMETER_UUID = "uuid";
public static final String PRINTER_PARAMETER_REFRESH_INTERVAL = "refresh"; public static final String PRINTER_PARAMETER_REFRESH_INTERVAL = "refresh";
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(PRINTER_THING_TYPE); public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(PRINTER_THING_TYPE);
} }

View File

@ -12,15 +12,16 @@
*/ */
package org.openhab.binding.ipp.internal.discovery; package org.openhab.binding.ipp.internal.discovery;
import static org.openhab.binding.ipp.internal.IppBindingConstants.*;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.jmdns.ServiceInfo; import javax.jmdns.ServiceInfo;
import org.openhab.binding.ipp.internal.IppBindingConstants; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.config.discovery.DiscoveryResult; import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder; import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant; import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant;
@ -36,13 +37,14 @@ import org.slf4j.LoggerFactory;
* @author Tobias Bräutigam - Initial contribution * @author Tobias Bräutigam - Initial contribution
*/ */
@Component @Component
@NonNullByDefault
public class IppPrinterDiscoveryParticipant implements MDNSDiscoveryParticipant { public class IppPrinterDiscoveryParticipant implements MDNSDiscoveryParticipant {
private final Logger logger = LoggerFactory.getLogger(IppPrinterDiscoveryParticipant.class); private final Logger logger = LoggerFactory.getLogger(IppPrinterDiscoveryParticipant.class);
@Override @Override
public Set<ThingTypeUID> getSupportedThingTypeUIDs() { public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
return Collections.singleton(IppBindingConstants.PRINTER_THING_TYPE); return Set.of(PRINTER_THING_TYPE);
} }
@Override @Override
@ -51,15 +53,11 @@ public class IppPrinterDiscoveryParticipant implements MDNSDiscoveryParticipant
} }
@Override @Override
public ThingUID getThingUID(ServiceInfo service) { public @Nullable ThingUID getThingUID(ServiceInfo service) {
if (service != null) { logger.trace("ServiceInfo: {}", service);
logger.trace("ServiceInfo: {}", service); if (getServiceType().equals(service.getType())) {
if (service.getType() != null) { String uidName = getUIDName(service);
if (service.getType().equals(getServiceType())) { return new ThingUID(PRINTER_THING_TYPE, uidName);
String uidName = getUIDName(service);
return new ThingUID(IppBindingConstants.PRINTER_THING_TYPE, uidName);
}
}
} }
return null; return null;
} }
@ -68,8 +66,7 @@ public class IppPrinterDiscoveryParticipant implements MDNSDiscoveryParticipant
return service.getName().replaceAll("[^A-Za-z0-9_]", "_"); return service.getName().replaceAll("[^A-Za-z0-9_]", "_");
} }
private InetAddress getIpAddress(ServiceInfo service) { private @Nullable InetAddress getIpAddress(ServiceInfo service) {
InetAddress address = null;
for (InetAddress addr : service.getInet4Addresses()) { for (InetAddress addr : service.getInet4Addresses()) {
return addr; return addr;
} }
@ -77,37 +74,36 @@ public class IppPrinterDiscoveryParticipant implements MDNSDiscoveryParticipant
for (InetAddress addr : service.getInet6Addresses()) { for (InetAddress addr : service.getInet6Addresses()) {
return addr; return addr;
} }
return address; return null;
} }
@Override @Override
public DiscoveryResult createResult(ServiceInfo service) { public @Nullable DiscoveryResult createResult(ServiceInfo service) {
DiscoveryResult result = null;
String rp = service.getPropertyString("rp"); String rp = service.getPropertyString("rp");
if (rp == null) { if (rp == null) {
return null; return null;
} }
ThingUID uid = getThingUID(service); ThingUID uid = getThingUID(service);
if (uid != null) { if (uid != null) {
Map<String, Object> properties = new HashMap<>(2);
// remove the domain from the name // remove the domain from the name
InetAddress ip = getIpAddress(service); InetAddress ip = getIpAddress(service);
if (ip == null) { if (ip == null) {
return null; return null;
} }
String inetAddress = ip.toString().substring(1); // trim leading slash String inetAddress = ip.toString().substring(1); // trim leading slash
String label = service.getName(); String label = service.getName();
int port = service.getPort(); int port = service.getPort();
String uuid = service.getPropertyString("UUID");
properties.put(IppBindingConstants.PRINTER_PARAMETER_URL, "http://" + inetAddress + ":" + port + "/" + rp); Map<String, Object> properties = Map.of( //
properties.put(IppBindingConstants.PRINTER_PARAMETER_NAME, label); PRINTER_PARAMETER_URL, "http://" + inetAddress + ":" + port + "/" + rp, //
PRINTER_PARAMETER_NAME, label, //
PRINTER_PARAMETER_UUID, uuid //
);
result = DiscoveryResultBuilder.create(uid).withProperties(properties).withLabel(label).build(); return DiscoveryResultBuilder.create(uid).withProperties(properties)
logger.debug("Created a DiscoveryResult {} for ipp printer on host '{}' name '{}'", result, .withRepresentationProperty(PRINTER_PARAMETER_UUID).withLabel(label).build();
properties.get(IppBindingConstants.PRINTER_PARAMETER_URL), label);
} }
return result; return null;
} }
} }

View File

@ -10,10 +10,12 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.openhab.binding.ipp.internal; package org.openhab.binding.ipp.internal.factory;
import static org.openhab.binding.ipp.internal.IppBindingConstants.PRINTER_THING_TYPE; import static org.openhab.binding.ipp.internal.IppBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.ipp.internal.handler.IppPrinterHandler; import org.openhab.binding.ipp.internal.handler.IppPrinterHandler;
import org.openhab.core.config.core.Configuration; import org.openhab.core.config.core.Configuration;
import org.openhab.core.config.discovery.DiscoveryServiceRegistry; import org.openhab.core.config.discovery.DiscoveryServiceRegistry;
@ -23,6 +25,7 @@ import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory; import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory; import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -35,49 +38,47 @@ import org.slf4j.LoggerFactory;
* @author Tobias Braeutigam - Initial contribution * @author Tobias Braeutigam - Initial contribution
*/ */
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.ipp") @Component(service = ThingHandlerFactory.class, configurationPid = "binding.ipp")
@NonNullByDefault
public class IppHandlerFactory extends BaseThingHandlerFactory { public class IppHandlerFactory extends BaseThingHandlerFactory {
private final Logger logger = LoggerFactory.getLogger(IppHandlerFactory.class); private final Logger logger = LoggerFactory.getLogger(IppHandlerFactory.class);
private DiscoveryServiceRegistry discoveryServiceRegistry; private final DiscoveryServiceRegistry discoveryServiceRegistry;
@Reference @Activate
protected void setDiscoveryServiceRegistry(DiscoveryServiceRegistry discoveryServiceRegistry) { public IppHandlerFactory(final @Reference DiscoveryServiceRegistry discoveryServiceRegistry) {
this.discoveryServiceRegistry = discoveryServiceRegistry; this.discoveryServiceRegistry = discoveryServiceRegistry;
} }
protected void unsetDiscoveryServiceRegistry(DiscoveryServiceRegistry discoveryServiceRegistry) {
this.discoveryServiceRegistry = null;
}
@Override @Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) { public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return IppBindingConstants.SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
} }
@Override @Override
public Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration, ThingUID thingUID, public @Nullable Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration,
ThingUID bridgeUID) { @Nullable ThingUID thingUID, @Nullable ThingUID bridgeUID) {
logger.trace("createThing({},{},{},{})", thingTypeUID, configuration, thingUID, bridgeUID); logger.trace("createThing({},{},{},{})", thingTypeUID, configuration, thingUID, bridgeUID);
if (IppBindingConstants.PRINTER_THING_TYPE.equals(thingTypeUID)) { if (PRINTER_THING_TYPE.equals(thingTypeUID)) {
ThingUID deviceUID = getIppPrinterUID(thingTypeUID, thingUID, configuration); ThingUID deviceUID = getIppPrinterUID(thingTypeUID, thingUID, configuration);
logger.debug("creating thing {} from deviceUID: {}", thingTypeUID, deviceUID); logger.debug("creating thing {} from deviceUID: {}", thingTypeUID, deviceUID);
return super.createThing(thingTypeUID, configuration, deviceUID, null); return super.createThing(thingTypeUID, configuration, deviceUID, null);
} }
throw new IllegalArgumentException("The thing type {} " + thingTypeUID + " is not supported by the binding."); throw new IllegalArgumentException("The thing type " + thingTypeUID + " is not supported by the binding.");
} }
private ThingUID getIppPrinterUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration) { private ThingUID getIppPrinterUID(ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID,
Configuration configuration) {
if (thingUID == null) { if (thingUID == null) {
String name = (String) configuration.get(IppBindingConstants.PRINTER_PARAMETER_NAME); String name = (String) configuration.get(PRINTER_PARAMETER_NAME);
thingUID = new ThingUID(thingTypeUID, name); return new ThingUID(thingTypeUID, name);
} }
return thingUID; return thingUID;
} }
@Override @Override
protected ThingHandler createHandler(Thing thing) { protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID(); ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(PRINTER_THING_TYPE)) { if (PRINTER_THING_TYPE.equals(thingTypeUID)) {
return new IppPrinterHandler(thing, discoveryServiceRegistry); return new IppPrinterHandler(thing, discoveryServiceRegistry);
} }
return null; return null;

View File

@ -12,17 +12,20 @@
*/ */
package org.openhab.binding.ipp.internal.handler; package org.openhab.binding.ipp.internal.handler;
import static org.openhab.binding.ipp.internal.IppBindingConstants.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Set;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.cups4j.CupsPrinter; import org.cups4j.CupsPrinter;
import org.cups4j.WhichJobsEnum; import org.cups4j.WhichJobsEnum;
import org.openhab.binding.ipp.internal.IppBindingConstants; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.config.core.Configuration; import org.openhab.core.config.core.Configuration;
import org.openhab.core.config.discovery.DiscoveryListener; import org.openhab.core.config.discovery.DiscoveryListener;
import org.openhab.core.config.discovery.DiscoveryResult; import org.openhab.core.config.discovery.DiscoveryResult;
@ -46,36 +49,34 @@ import org.slf4j.LoggerFactory;
* *
* @author Tobias Braeutigam - Initial contribution * @author Tobias Braeutigam - Initial contribution
*/ */
@NonNullByDefault
public class IppPrinterHandler extends BaseThingHandler implements DiscoveryListener { public class IppPrinterHandler extends BaseThingHandler implements DiscoveryListener {
/**
* Refresh interval defaults to every minute (60s)
*/
private static final int DEFAULT_REFRESH_INTERVAL_IN_SECONDS = 60;
private final Logger logger = LoggerFactory.getLogger(IppPrinterHandler.class); private final Logger logger = LoggerFactory.getLogger(IppPrinterHandler.class);
private URL url; private @Nullable URL url;
private String name; private @Nullable CupsPrinter printer;
private CupsPrinter printer;
private int refresh = 60; // refresh every minute as default private @Nullable ScheduledFuture<?> refreshJob;
ScheduledFuture<?> refreshJob;
private DiscoveryServiceRegistry discoveryServiceRegistry; private final DiscoveryServiceRegistry discoveryServiceRegistry;
public IppPrinterHandler(Thing thing, DiscoveryServiceRegistry discoveryServiceRegistry) { public IppPrinterHandler(Thing thing, DiscoveryServiceRegistry discoveryServiceRegistry) {
super(thing); super(thing);
if (discoveryServiceRegistry != null) { this.discoveryServiceRegistry = discoveryServiceRegistry;
this.discoveryServiceRegistry = discoveryServiceRegistry;
}
} }
@Override @Override
public void initialize() { public void initialize() {
Configuration config = getThing().getConfiguration(); Configuration config = getThing().getConfiguration();
String name = (String) config.get(PRINTER_PARAMETER_NAME);
try { try {
Object obj = config.get(IppBindingConstants.PRINTER_PARAMETER_URL); Object obj = config.get(PRINTER_PARAMETER_URL);
name = (String) config.get(IppBindingConstants.PRINTER_PARAMETER_NAME);
if (config.get(IppBindingConstants.PRINTER_PARAMETER_REFRESH_INTERVAL) != null) {
BigDecimal ref = (BigDecimal) config.get(IppBindingConstants.PRINTER_PARAMETER_REFRESH_INTERVAL);
refresh = ref.intValue();
}
if (obj instanceof URL) { if (obj instanceof URL) {
url = (URL) obj; url = (URL) obj;
} else if (obj instanceof String) { } else if (obj instanceof String) {
@ -83,36 +84,45 @@ public class IppPrinterHandler extends BaseThingHandler implements DiscoveryList
} }
printer = new CupsPrinter(url, name, false); printer = new CupsPrinter(url, name, false);
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
logger.error("malformed url {}, printer thing creation failed", logger.error("malformed url {}, printer thing creation failed", config.get(PRINTER_PARAMETER_URL));
config.get(IppBindingConstants.PRINTER_PARAMETER_URL));
} }
// until we get an update put the Thing offline
updateStatus(ThingStatus.OFFLINE); int refresh = DEFAULT_REFRESH_INTERVAL_IN_SECONDS;
deviceOnlineWatchdog(); Object obj = config.get(PRINTER_PARAMETER_REFRESH_INTERVAL);
if (this.discoveryServiceRegistry != null) { if (obj != null) {
this.discoveryServiceRegistry.addDiscoveryListener(this); BigDecimal ref = (BigDecimal) obj;
refresh = ref.intValue();
} }
updateStatus(ThingStatus.UNKNOWN);
deviceOnlineWatchdog(refresh);
discoveryServiceRegistry.addDiscoveryListener(this);
} }
@Override @Override
public void dispose() { public void dispose() {
if (refreshJob != null && !refreshJob.isCancelled()) { stopRefreshJob();
refreshJob.cancel(true);
refreshJob = null;
}
logger.debug("IppPrinterHandler {} disposed.", url); logger.debug("IppPrinterHandler {} disposed.", url);
super.dispose(); super.dispose();
} }
private void deviceOnlineWatchdog() { private void deviceOnlineWatchdog(int refresh) {
Runnable runnable = () -> { stopRefreshJob();
refreshJob = scheduler.scheduleWithFixedDelay(() -> {
try { try {
onDeviceStateChanged(printer); onDeviceStateChanged(printer);
} catch (Exception e) { } catch (Exception e) {
logger.debug("Exception occurred during execution: {}", e.getMessage(), e); logger.debug("Exception occurred during execution: {}", e.getMessage(), e);
} }
}; }, 0, refresh, TimeUnit.SECONDS);
refreshJob = scheduler.scheduleWithFixedDelay(runnable, 0, refresh, TimeUnit.SECONDS); }
private void stopRefreshJob() {
ScheduledFuture<?> localRefreshJob = refreshJob;
if (localRefreshJob != null && !localRefreshJob.isCancelled()) {
localRefreshJob.cancel(true);
refreshJob = null;
}
} }
@Override @Override
@ -123,25 +133,24 @@ public class IppPrinterHandler extends BaseThingHandler implements DiscoveryList
} }
} }
public void onDeviceStateChanged(CupsPrinter device) { public void onDeviceStateChanged(@Nullable CupsPrinter device) {
if (device.getPrinterURL().equals(url)) { if (device != null && device.getPrinterURL().equals(url)) {
boolean online = false; boolean online = false;
try { try {
updateState(new ChannelUID(getThing().getUID(), IppBindingConstants.JOBS_CHANNEL), updateState(JOBS_CHANNEL, new DecimalType(device.getJobs(WhichJobsEnum.ALL, "", false).size()));
new DecimalType(device.getJobs(WhichJobsEnum.ALL, "", false).size()));
online = true; online = true;
} catch (Exception e) { } catch (Exception e) {
logger.debug("error updating jobs channel, reason: {}", e.getMessage()); logger.debug("error updating jobs channel, reason: {}", e.getMessage());
} }
try { try {
updateState(new ChannelUID(getThing().getUID(), IppBindingConstants.WAITING_JOBS_CHANNEL), updateState(WAITING_JOBS_CHANNEL,
new DecimalType(device.getJobs(WhichJobsEnum.NOT_COMPLETED, "", false).size())); new DecimalType(device.getJobs(WhichJobsEnum.NOT_COMPLETED, "", false).size()));
online = true; online = true;
} catch (Exception e) { } catch (Exception e) {
logger.debug("error updating waiting-jobs channel, reason: {}", e.getMessage()); logger.debug("error updating waiting-jobs channel, reason: {}", e.getMessage());
} }
try { try {
updateState(new ChannelUID(getThing().getUID(), IppBindingConstants.DONE_JOBS_CHANNEL), updateState(DONE_JOBS_CHANNEL,
new DecimalType(device.getJobs(WhichJobsEnum.COMPLETED, "", false).size())); new DecimalType(device.getJobs(WhichJobsEnum.COMPLETED, "", false).size()));
online = true; online = true;
} catch (Exception e) { } catch (Exception e) {
@ -155,21 +164,21 @@ public class IppPrinterHandler extends BaseThingHandler implements DiscoveryList
@Override @Override
public void thingDiscovered(DiscoveryService source, DiscoveryResult result) { public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
if (result.getThingUID().equals(this.getThing().getUID())) { if (result.getThingUID().equals(getThing().getUID())) {
updateStatus(ThingStatus.ONLINE); updateStatus(ThingStatus.ONLINE);
} }
} }
@Override @Override
public void thingRemoved(DiscoveryService source, ThingUID thingUID) { public void thingRemoved(DiscoveryService source, ThingUID thingUID) {
if (thingUID.equals(this.getThing().getUID())) { if (thingUID.equals(getThing().getUID())) {
updateStatus(ThingStatus.OFFLINE); updateStatus(ThingStatus.OFFLINE);
} }
} }
@Override @Override
public Collection<ThingUID> removeOlderResults(DiscoveryService source, long timestamp, public @Nullable Collection<ThingUID> removeOlderResults(DiscoveryService source, long timestamp,
Collection<ThingTypeUID> thingTypeUIDs, ThingUID bridgeUID) { @Nullable Collection<ThingTypeUID> thingTypeUIDs, @Nullable ThingUID bridgeUID) {
return Collections.emptyList(); return Set.of();
} }
} }

View File

@ -11,6 +11,9 @@
<channel id="waitingJobs" typeId="waitingJobs"/> <channel id="waitingJobs" typeId="waitingJobs"/>
<channel id="doneJobs" typeId="doneJobs"/> <channel id="doneJobs" typeId="doneJobs"/>
</channels> </channels>
<representation-property>uuid</representation-property>
<config-description> <config-description>
<parameter name="name" type="text" required="true"> <parameter name="name" type="text" required="true">
<label>Name</label> <label>Name</label>
@ -32,19 +35,19 @@
<item-type>Number</item-type> <item-type>Number</item-type>
<label>Total Jobs</label> <label>Total Jobs</label>
<description>Total number of print jobs on the printer</description> <description>Total number of print jobs on the printer</description>
<state readOnly="true"></state> <state readOnly="true"/>
</channel-type> </channel-type>
<channel-type id="waitingJobs"> <channel-type id="waitingJobs">
<item-type>Number</item-type> <item-type>Number</item-type>
<label>Waiting Jobs</label> <label>Waiting Jobs</label>
<description>Number of waiting print jobs on the printer</description> <description>Number of waiting print jobs on the printer</description>
<state readOnly="true"></state> <state readOnly="true"/>
</channel-type> </channel-type>
<channel-type id="doneJobs" advanced="true"> <channel-type id="doneJobs" advanced="true">
<item-type>Number</item-type> <item-type>Number</item-type>
<label>Done Jobs</label> <label>Done Jobs</label>
<description>Number of completed print jobs on the printer</description> <description>Number of completed print jobs on the printer</description>
<state readOnly="true"></state> <state readOnly="true"/>
</channel-type> </channel-type>
</thing:thing-descriptions> </thing:thing-descriptions>