2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.ipp.internal.handler;
15 import static org.openhab.binding.ipp.internal.IppBindingConstants.*;
17 import java.math.BigDecimal;
18 import java.net.MalformedURLException;
20 import java.util.Collection;
22 import java.util.concurrent.ScheduledFuture;
23 import java.util.concurrent.TimeUnit;
25 import org.cups4j.CupsPrinter;
26 import org.cups4j.WhichJobsEnum;
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.openhab.core.config.core.Configuration;
30 import org.openhab.core.config.discovery.DiscoveryListener;
31 import org.openhab.core.config.discovery.DiscoveryResult;
32 import org.openhab.core.config.discovery.DiscoveryService;
33 import org.openhab.core.config.discovery.DiscoveryServiceRegistry;
34 import org.openhab.core.library.types.DecimalType;
35 import org.openhab.core.thing.ChannelUID;
36 import org.openhab.core.thing.Thing;
37 import org.openhab.core.thing.ThingStatus;
38 import org.openhab.core.thing.ThingTypeUID;
39 import org.openhab.core.thing.ThingUID;
40 import org.openhab.core.thing.binding.BaseThingHandler;
41 import org.openhab.core.types.Command;
42 import org.openhab.core.types.RefreshType;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
47 * The {@link IppPrinterHandler} is responsible for handling commands, which are sent
48 * to one of the channels.
50 * @author Tobias Braeutigam - Initial contribution
53 public class IppPrinterHandler extends BaseThingHandler implements DiscoveryListener {
56 * Refresh interval defaults to every minute (60s)
58 private static final int DEFAULT_REFRESH_INTERVAL_IN_SECONDS = 60;
60 private final Logger logger = LoggerFactory.getLogger(IppPrinterHandler.class);
62 private @Nullable URL url;
63 private @Nullable CupsPrinter printer;
65 private @Nullable ScheduledFuture<?> refreshJob;
67 private final DiscoveryServiceRegistry discoveryServiceRegistry;
69 public IppPrinterHandler(Thing thing, DiscoveryServiceRegistry discoveryServiceRegistry) {
71 this.discoveryServiceRegistry = discoveryServiceRegistry;
75 public void initialize() {
76 Configuration config = getThing().getConfiguration();
77 String name = (String) config.get(PRINTER_PARAMETER_NAME);
79 Object obj = config.get(PRINTER_PARAMETER_URL);
80 if (obj instanceof URL) {
82 } else if (obj instanceof String) {
83 url = new URL((String) obj);
85 printer = new CupsPrinter(null, url, name);
86 } catch (MalformedURLException e) {
87 logger.error("malformed url {}, printer thing creation failed", config.get(PRINTER_PARAMETER_URL));
90 int refresh = DEFAULT_REFRESH_INTERVAL_IN_SECONDS;
91 Object obj = config.get(PRINTER_PARAMETER_REFRESH_INTERVAL);
93 BigDecimal ref = (BigDecimal) obj;
94 refresh = ref.intValue();
97 updateStatus(ThingStatus.UNKNOWN);
98 deviceOnlineWatchdog(refresh);
99 discoveryServiceRegistry.addDiscoveryListener(this);
103 public void dispose() {
105 logger.debug("IppPrinterHandler {} disposed.", url);
109 private void deviceOnlineWatchdog(int refresh) {
111 refreshJob = scheduler.scheduleWithFixedDelay(() -> {
113 onDeviceStateChanged(printer);
114 } catch (Exception e) {
115 logger.debug("Exception occurred during execution: {}", e.getMessage(), e);
117 }, 0, refresh, TimeUnit.SECONDS);
120 private void stopRefreshJob() {
121 ScheduledFuture<?> localRefreshJob = refreshJob;
122 if (localRefreshJob != null && !localRefreshJob.isCancelled()) {
123 localRefreshJob.cancel(true);
129 public void handleCommand(ChannelUID channelUID, Command command) {
130 if (command instanceof RefreshType) {
131 onDeviceStateChanged(printer);
136 public void onDeviceStateChanged(@Nullable CupsPrinter device) {
137 if (device != null && device.getPrinterURL().equals(url)) {
138 boolean online = false;
140 updateState(JOBS_CHANNEL, new DecimalType(device.getJobs(WhichJobsEnum.ALL, "", false).size()));
142 } catch (Exception e) {
143 logger.debug("error updating jobs channel, reason: {}", e.getMessage());
146 updateState(WAITING_JOBS_CHANNEL,
147 new DecimalType(device.getJobs(WhichJobsEnum.NOT_COMPLETED, "", false).size()));
149 } catch (Exception e) {
150 logger.debug("error updating waiting-jobs channel, reason: {}", e.getMessage());
153 updateState(DONE_JOBS_CHANNEL,
154 new DecimalType(device.getJobs(WhichJobsEnum.COMPLETED, "", false).size()));
156 } catch (Exception e) {
157 logger.debug("error updating done-jobs channel, reason: {}", e.getMessage());
160 updateStatus(ThingStatus.ONLINE);
166 public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
167 if (result.getThingUID().equals(getThing().getUID())) {
168 updateStatus(ThingStatus.ONLINE);
173 public void thingRemoved(DiscoveryService source, ThingUID thingUID) {
174 if (thingUID.equals(getThing().getUID())) {
175 updateStatus(ThingStatus.OFFLINE);
180 public @Nullable Collection<ThingUID> removeOlderResults(DiscoveryService source, long timestamp,
181 @Nullable Collection<ThingTypeUID> thingTypeUIDs, @Nullable ThingUID bridgeUID) {