]> git.basschouten.com Git - openhab-addons.git/blob
4078fcb3ed3e7b7b9cecb52ed5e53723c7240724
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.surepetcare.internal.handler;
14
15 import static org.openhab.binding.surepetcare.internal.SurePetcareConstants.*;
16
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.Map;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.surepetcare.internal.AuthenticationException;
26 import org.openhab.binding.surepetcare.internal.SurePetcareAPIHelper;
27 import org.openhab.binding.surepetcare.internal.discovery.SurePetcareDiscoveryService;
28 import org.openhab.binding.surepetcare.internal.dto.SurePetcareBridgeConfiguration;
29 import org.openhab.binding.surepetcare.internal.dto.SurePetcareDevice;
30 import org.openhab.binding.surepetcare.internal.dto.SurePetcareHousehold;
31 import org.openhab.binding.surepetcare.internal.dto.SurePetcarePet;
32 import org.openhab.core.library.types.OnOffType;
33 import org.openhab.core.thing.Bridge;
34 import org.openhab.core.thing.ChannelUID;
35 import org.openhab.core.thing.Thing;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingStatusDetail;
38 import org.openhab.core.thing.ThingUID;
39 import org.openhab.core.thing.binding.BaseBridgeHandler;
40 import org.openhab.core.thing.binding.ThingHandler;
41 import org.openhab.core.thing.binding.ThingHandlerService;
42 import org.openhab.core.types.Command;
43 import org.openhab.core.types.RefreshType;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * The {@link SurePetcareBridgeHandler} is responsible for handling the bridge things created to use the Sure Petcare
49  * API. This way, the user credentials may be entered only once.
50  *
51  * It also spawns 2 background polling threads to update the more static data (topology) and the pet locations at
52  * different time intervals.
53  *
54  * @author Rene Scherer - Initial Contribution
55  */
56 @NonNullByDefault
57 public class SurePetcareBridgeHandler extends BaseBridgeHandler {
58
59     private final Logger logger = LoggerFactory.getLogger(SurePetcareBridgeHandler.class);
60
61     private final SurePetcareAPIHelper petcareAPI;
62     private @Nullable ScheduledFuture<?> topologyPollingJob;
63     private @Nullable ScheduledFuture<?> petStatusPollingJob;
64
65     public SurePetcareBridgeHandler(Bridge bridge, SurePetcareAPIHelper petcareAPI) {
66         super(bridge);
67         this.petcareAPI = petcareAPI;
68     }
69
70     @Override
71     public void initialize() {
72         logger.debug("Initializing Sure Petcare bridge handler.");
73         SurePetcareBridgeConfiguration config = getConfigAs(SurePetcareBridgeConfiguration.class);
74
75         if (config.username != null && config.password != null) {
76             updateStatus(ThingStatus.UNKNOWN);
77             try {
78                 logger.debug("Login to SurePetcare API with username: {}", config.username);
79                 petcareAPI.login(config.username, config.password);
80                 logger.debug("Login successful, updating topology cache");
81                 petcareAPI.updateTopologyCache();
82                 logger.debug("Cache update successful, setting bridge status to ONLINE");
83                 updateStatus(ThingStatus.ONLINE);
84                 updateThings();
85             } catch (AuthenticationException e) {
86                 logger.debug("Authentication exception during initializing", e);
87                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
88                         "@text/offline.conf-error-authentication");
89                 return;
90             }
91         } else {
92             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
93                     "@text/offline.conf-error-missing-username-or-password");
94             return;
95         }
96
97         ScheduledFuture<?> job = topologyPollingJob;
98         if (job == null || job.isCancelled()) {
99             topologyPollingJob = scheduler.scheduleWithFixedDelay(() -> {
100                 petcareAPI.updateTopologyCache();
101                 updateThings();
102             }, config.refreshIntervalTopology, config.refreshIntervalTopology, TimeUnit.SECONDS);
103             logger.debug("Bridge topology polling job every {} seconds", config.refreshIntervalTopology);
104         }
105
106         job = petStatusPollingJob;
107         if (job == null || job.isCancelled()) {
108             petStatusPollingJob = scheduler.scheduleWithFixedDelay(this::pollAndUpdatePetStatus,
109                     config.refreshIntervalStatus, config.refreshIntervalStatus, TimeUnit.SECONDS);
110             logger.debug("Pet status polling job every {} seconds", config.refreshIntervalStatus);
111         }
112     }
113
114     @Override
115     public Collection<Class<? extends ThingHandlerService>> getServices() {
116         return Collections.singleton(SurePetcareDiscoveryService.class);
117     }
118
119     @Override
120     public void dispose() {
121         ScheduledFuture<?> job = topologyPollingJob;
122         if (job != null && !job.isCancelled()) {
123             job.cancel(true);
124             topologyPollingJob = null;
125             logger.debug("Stopped topology background polling process");
126         }
127         job = petStatusPollingJob;
128         if (job != null && !job.isCancelled()) {
129             job.cancel(true);
130             petStatusPollingJob = null;
131             logger.debug("Stopped pet status background polling process");
132         }
133     }
134
135     @Override
136     public void handleCommand(ChannelUID channelUID, Command command) {
137         if (command instanceof RefreshType) {
138             updateState(BRIDGE_CHANNEL_REFRESH, OnOffType.OFF);
139         } else {
140             switch (channelUID.getId()) {
141                 case BRIDGE_CHANNEL_REFRESH:
142                     if (OnOffType.ON.equals(command)) {
143                         petcareAPI.updateTopologyCache();
144                         updateThings();
145                         updateState(BRIDGE_CHANNEL_REFRESH, OnOffType.OFF);
146                     }
147                     break;
148             }
149         }
150     }
151
152     public ThingUID getUID() {
153         return thing.getUID();
154     }
155
156     public Iterable<SurePetcareHousehold> listHouseholds() {
157         return petcareAPI.getTopology().households;
158     }
159
160     public Iterable<SurePetcarePet> listPets() {
161         return petcareAPI.getTopology().pets;
162     }
163
164     public Iterable<SurePetcareDevice> listDevices() {
165         return petcareAPI.getTopology().devices;
166     }
167
168     protected synchronized void updateThings() {
169         logger.debug("Updating {} connected things", getThing().getThings().size());
170         // update existing things
171         for (Thing th : getThing().getThings()) {
172             String tid = th.getUID().getId();
173             Map<String, String> properties = null;
174             ThingHandler handler = th.getHandler();
175             if (handler instanceof SurePetcarePetHandler) {
176                 ((SurePetcarePetHandler) handler).updateThing();
177                 SurePetcarePet pet = petcareAPI.getTopology().getById(petcareAPI.getTopology().pets, tid);
178                 if (pet != null) {
179                     properties = pet.getThingProperties();
180                 }
181             } else if (handler instanceof SurePetcareHouseholdHandler) {
182                 ((SurePetcareHouseholdHandler) handler).updateThing();
183                 SurePetcareHousehold household = petcareAPI.getTopology().getById(petcareAPI.getTopology().households,
184                         tid);
185                 if (household != null) {
186                     properties = household.getThingProperties();
187                 }
188             } else if (handler instanceof SurePetcareDeviceHandler) {
189                 ((SurePetcareDeviceHandler) handler).updateThing();
190                 SurePetcareDevice device = petcareAPI.getTopology().getById(petcareAPI.getTopology().devices, tid);
191                 if (device != null) {
192                     properties = device.getThingProperties();
193                 }
194             }
195             if ((properties != null) && (handler instanceof SurePetcareBaseObjectHandler)) {
196                 ((SurePetcareBaseObjectHandler) handler).updateProperties(properties);
197             }
198         }
199     }
200
201     private synchronized void pollAndUpdatePetStatus() {
202         petcareAPI.updatePetStatus();
203         for (Thing th : getThing().getThings()) {
204             if (th.getThingTypeUID().equals(THING_TYPE_PET)) {
205                 ThingHandler handler = th.getHandler();
206                 if (handler != null) {
207                     ((SurePetcarePetHandler) handler).updateThing();
208                 }
209             }
210         }
211     }
212 }