]> git.basschouten.com Git - openhab-addons.git/blob
6198f13e1cd677be993580e1f6a2be335f0c26c8
[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.seneye.internal.handler;
14
15 import static org.openhab.binding.seneye.internal.SeneyeBindingConstants.*;
16
17 import java.util.concurrent.TimeUnit;
18
19 import org.openhab.binding.seneye.internal.CommunicationException;
20 import org.openhab.binding.seneye.internal.InvalidConfigurationException;
21 import org.openhab.binding.seneye.internal.ReadingsUpdate;
22 import org.openhab.binding.seneye.internal.SeneyeConfigurationParameters;
23 import org.openhab.binding.seneye.internal.SeneyeDeviceReading;
24 import org.openhab.binding.seneye.internal.SeneyeService;
25 import org.openhab.core.cache.ExpiringCache;
26 import org.openhab.core.library.types.DateTimeType;
27 import org.openhab.core.library.types.DecimalType;
28 import org.openhab.core.library.types.StringType;
29 import org.openhab.core.thing.ChannelUID;
30 import org.openhab.core.thing.Thing;
31 import org.openhab.core.thing.ThingStatus;
32 import org.openhab.core.thing.ThingStatusDetail;
33 import org.openhab.core.thing.binding.BaseThingHandler;
34 import org.openhab.core.types.Command;
35 import org.openhab.core.types.RefreshType;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * The {@link SeneyeHandler} is responsible for handling commands, which are
41  * sent to one of the channels.
42  *
43  * @author Niko Tanghe - Initial contribution
44  */
45 public final class SeneyeHandler extends BaseThingHandler implements ReadingsUpdate {
46
47     private final Logger logger = LoggerFactory.getLogger(SeneyeHandler.class);
48     private SeneyeService seneyeService;
49     private ExpiringCache<SeneyeDeviceReading> cachedSeneyeDeviceReading;
50
51     public SeneyeHandler(Thing thing) {
52         super(thing);
53     }
54
55     @Override
56     public void handleCommand(ChannelUID channelUID, Command command) {
57         if (seneyeService == null || !seneyeService.isInitialized()) {
58             return;
59         }
60
61         if (command instanceof RefreshType) {
62             SeneyeDeviceReading readings = cachedSeneyeDeviceReading.getValue();
63             newState(readings);
64         } else {
65             logger.debug("Command {} is not supported for channel: {}", command, channelUID.getId());
66         }
67     }
68
69     @Override
70     public void newState(SeneyeDeviceReading readings) {
71         if (readings != null) {
72             logger.debug("Updating readings for sensor type {}", seneyeService.seneyeType);
73             switch (seneyeService.seneyeType) {
74                 case 3:
75                     updateState(CHANNEL_NH4, new DecimalType(readings.nh4.curr));
76                     updateState(CHANNEL_PAR, new DecimalType(readings.par.curr));
77                     updateState(CHANNEL_LUX, new DecimalType(readings.lux.curr));
78                     updateState(CHANNEL_KELVIN, new DecimalType(readings.kelvin.curr));
79                 case 2:
80                     updateState(CHANNEL_O2, new DecimalType(readings.o2.curr));
81                 case 1:
82                     updateState(CHANNEL_TEMPERATURE, new DecimalType(readings.temperature.curr));
83                     updateState(CHANNEL_NH3, new DecimalType(readings.nh3.curr));
84                     updateState(CHANNEL_PH, new DecimalType(readings.ph.curr));
85                     updateState(CHANNEL_LASTREADING, new DateTimeType(readings.status.getLast_experimentDate()));
86                     updateState(CHANNEL_SLIDEEXPIRES, new DateTimeType(readings.status.getSlide_expiresDate()));
87                     updateState(CHANNEL_WRONGSLIDE, new StringType(readings.status.getWrong_slideString()));
88                     updateState(CHANNEL_SLIDESERIAL, new StringType(readings.status.getSlide_serialString()));
89                     updateState(CHANNEL_OUTOFWATER, new StringType(readings.status.getOut_of_waterString()));
90                     updateState(CHANNEL_DISCONNECTED, new StringType(readings.status.getDisconnectedString()));
91             }
92         }
93     }
94
95     @Override
96     public void invalidConfig() {
97         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
98     }
99
100     @Override
101     public void initialize() {
102         SeneyeConfigurationParameters config = getConfigAs(SeneyeConfigurationParameters.class);
103
104         if (config.aquarium_name == null || config.aquarium_name.isEmpty()) {
105             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
106                     "Check configuration, Aquarium name must be provided");
107             return;
108         }
109         if (config.username == null || config.username.isEmpty()) {
110             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
111                     "Check configuration, Seneye username must be provided");
112             return;
113         }
114         if (config.password == null || config.password.isEmpty()) {
115             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
116                     "Check configuration, Seneye password must be provided");
117             return;
118         }
119
120         logger.debug("Initializing Seneye API service.");
121         try {
122             this.seneyeService = new SeneyeService(config);
123         } catch (CommunicationException ex) {
124             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ex.getMessage());
125             return; // critical error
126         }
127
128         updateStatus(ThingStatus.ONLINE);
129
130         // contact Seneye API
131         scheduler.submit(() -> {
132             initializeSeneyeService();
133         });
134     }
135
136     private void initializeSeneyeService() {
137         try {
138             seneyeService.initialize();
139         } catch (CommunicationException ex) {
140             // try again in 30 secs
141             scheduler.schedule(() -> {
142                 initializeSeneyeService();
143             }, 30, TimeUnit.SECONDS);
144
145             return;
146         } catch (InvalidConfigurationException ex) {
147             // bad configuration, stay offline until user corrects the configuration
148             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, ex.getMessage());
149
150             return;
151         }
152
153         // ok, initialization succeeded
154         cachedSeneyeDeviceReading = new ExpiringCache<>(TimeUnit.SECONDS.toMillis(10),
155                 () -> seneyeService.getDeviceReadings());
156
157         seneyeService.startAutomaticRefresh(scheduler, this);
158
159         updateStatus(ThingStatus.ONLINE);
160     }
161
162     @Override
163     public void dispose() {
164         seneyeService.stopAutomaticRefresh();
165         seneyeService = null;
166     }
167 }