2 * Copyright (c) 2010-2020 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.netatmo.internal.station;
15 import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.*;
16 import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
18 import java.util.ArrayList;
19 import java.util.List;
21 import java.util.Optional;
22 import java.util.concurrent.ConcurrentHashMap;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.openhab.core.i18n.TimeZoneProvider;
26 import org.openhab.core.thing.Thing;
27 import org.openhab.core.types.State;
28 import org.openhab.binding.netatmo.internal.WeatherUtils;
29 import org.openhab.binding.netatmo.internal.handler.NetatmoDeviceHandler;
30 import org.openhab.binding.netatmo.internal.handler.NetatmoModuleHandler;
32 import io.swagger.client.model.NADashboardData;
33 import io.swagger.client.model.NAMain;
36 * {@link NAMainHandler} is the base class for all current Netatmo
37 * weather station equipments (both modules and devices)
39 * @author Gaƫl L'hopital - Initial contribution
40 * @author Rob Nielsen - Added day, week, and month measurements to the weather station and modules
44 public class NAMainHandler extends NetatmoDeviceHandler<NAMain> {
45 private Map<String, Float> channelMeasurements = new ConcurrentHashMap<>();
47 public NAMainHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
48 super(thing, timeZoneProvider);
52 protected Optional<NAMain> updateReadings() {
53 Optional<NAMain> result = getBridgeHandler().flatMap(handler -> handler.getStationsDataBody(getId()))
54 .map(dataBody -> dataBody.getDevices().stream()
55 .filter(device -> device.getId().equalsIgnoreCase(getId())).findFirst().orElse(null));
56 result.ifPresent(device -> {
57 device.getModules().forEach(child -> childs.put(child.getId(), child));
62 childs.keySet().forEach((childId) -> {
63 findNAThing(childId).map(NetatmoModuleHandler.class::cast).ifPresent(naChildModule -> {
64 naChildModule.updateMeasurements();
72 protected void updateProperties(NAMain deviceData) {
73 updateProperties(deviceData.getFirmware(), deviceData.getType());
77 public void updateMeasurements() {
78 updateDayMeasurements();
79 updateWeekMeasurements();
80 updateMonthMeasurements();
83 private void updateDayMeasurements() {
84 List<String> channels = new ArrayList<>();
85 List<String> types = new ArrayList<>();
86 addMeasurement(channels, types, CHANNEL_MIN_CO2, MIN_CO2);
87 addMeasurement(channels, types, CHANNEL_MAX_CO2, MAX_CO2);
88 addMeasurement(channels, types, CHANNEL_MIN_HUMIDITY, MIN_HUM);
89 addMeasurement(channels, types, CHANNEL_MAX_HUMIDITY, MAX_HUM);
90 addMeasurement(channels, types, CHANNEL_MIN_NOISE, MIN_NOISE);
91 addMeasurement(channels, types, CHANNEL_MAX_NOISE, MAX_NOISE);
92 addMeasurement(channels, types, CHANNEL_MIN_PRESSURE, MIN_PRESSURE);
93 addMeasurement(channels, types, CHANNEL_MAX_PRESSURE, MAX_PRESSURE);
94 addMeasurement(channels, types, CHANNEL_DATE_MIN_CO2, DATE_MIN_CO2);
95 addMeasurement(channels, types, CHANNEL_DATE_MAX_CO2, DATE_MAX_CO2);
96 addMeasurement(channels, types, CHANNEL_DATE_MIN_HUMIDITY, DATE_MIN_HUM);
97 addMeasurement(channels, types, CHANNEL_DATE_MAX_HUMIDITY, DATE_MAX_HUM);
98 addMeasurement(channels, types, CHANNEL_DATE_MIN_NOISE, DATE_MIN_NOISE);
99 addMeasurement(channels, types, CHANNEL_DATE_MAX_NOISE, DATE_MAX_NOISE);
100 addMeasurement(channels, types, CHANNEL_DATE_MIN_PRESSURE, DATE_MIN_PRESSURE);
101 addMeasurement(channels, types, CHANNEL_DATE_MAX_PRESSURE, DATE_MAX_PRESSURE);
102 if (!channels.isEmpty()) {
103 getMeasurements(getId(), null, ONE_DAY, types, channels, channelMeasurements);
107 private void updateWeekMeasurements() {
108 List<String> channels = new ArrayList<>();
109 List<String> types = new ArrayList<>();
110 addMeasurement(channels, types, CHANNEL_MIN_CO2_THIS_WEEK, MIN_CO2);
111 addMeasurement(channels, types, CHANNEL_MAX_CO2_THIS_WEEK, MAX_CO2);
112 addMeasurement(channels, types, CHANNEL_MIN_HUMIDITY_THIS_WEEK, MIN_HUM);
113 addMeasurement(channels, types, CHANNEL_MAX_HUMIDITY_THIS_WEEK, MAX_HUM);
114 addMeasurement(channels, types, CHANNEL_MIN_NOISE_THIS_WEEK, MIN_NOISE);
115 addMeasurement(channels, types, CHANNEL_MAX_NOISE_THIS_WEEK, MAX_NOISE);
116 addMeasurement(channels, types, CHANNEL_MIN_PRESSURE_THIS_WEEK, MIN_PRESSURE);
117 addMeasurement(channels, types, CHANNEL_MAX_PRESSURE_THIS_WEEK, MAX_PRESSURE);
118 addMeasurement(channels, types, CHANNEL_MIN_TEMP_THIS_WEEK, MIN_TEMP);
119 addMeasurement(channels, types, CHANNEL_MAX_TEMP_THIS_WEEK, MAX_TEMP);
120 addMeasurement(channels, types, CHANNEL_DATE_MIN_CO2_THIS_WEEK, DATE_MIN_CO2);
121 addMeasurement(channels, types, CHANNEL_DATE_MAX_CO2_THIS_WEEK, DATE_MAX_CO2);
122 addMeasurement(channels, types, CHANNEL_DATE_MIN_HUMIDITY_THIS_WEEK, DATE_MIN_HUM);
123 addMeasurement(channels, types, CHANNEL_DATE_MAX_HUMIDITY_THIS_WEEK, DATE_MAX_HUM);
124 addMeasurement(channels, types, CHANNEL_DATE_MIN_NOISE_THIS_WEEK, DATE_MIN_NOISE);
125 addMeasurement(channels, types, CHANNEL_DATE_MAX_NOISE_THIS_WEEK, DATE_MAX_NOISE);
126 addMeasurement(channels, types, CHANNEL_DATE_MIN_PRESSURE_THIS_WEEK, DATE_MIN_PRESSURE);
127 addMeasurement(channels, types, CHANNEL_DATE_MAX_PRESSURE_THIS_WEEK, DATE_MAX_PRESSURE);
128 addMeasurement(channels, types, CHANNEL_DATE_MIN_TEMP_THIS_WEEK, DATE_MIN_TEMP);
129 addMeasurement(channels, types, CHANNEL_DATE_MAX_TEMP_THIS_WEEK, DATE_MAX_TEMP);
130 if (!channels.isEmpty()) {
131 getMeasurements(getId(), null, ONE_WEEK, types, channels, channelMeasurements);
135 private void updateMonthMeasurements() {
136 List<String> channels = new ArrayList<>();
137 List<String> types = new ArrayList<>();
138 addMeasurement(channels, types, CHANNEL_MIN_CO2_THIS_MONTH, MIN_CO2);
139 addMeasurement(channels, types, CHANNEL_MAX_CO2_THIS_MONTH, MAX_CO2);
140 addMeasurement(channels, types, CHANNEL_MIN_HUMIDITY_THIS_MONTH, MIN_HUM);
141 addMeasurement(channels, types, CHANNEL_MAX_HUMIDITY_THIS_MONTH, MAX_HUM);
142 addMeasurement(channels, types, CHANNEL_MIN_NOISE_THIS_MONTH, MIN_NOISE);
143 addMeasurement(channels, types, CHANNEL_MAX_NOISE_THIS_MONTH, MAX_NOISE);
144 addMeasurement(channels, types, CHANNEL_MIN_PRESSURE_THIS_MONTH, MIN_PRESSURE);
145 addMeasurement(channels, types, CHANNEL_MAX_PRESSURE_THIS_MONTH, MAX_PRESSURE);
146 addMeasurement(channels, types, CHANNEL_MIN_TEMP_THIS_MONTH, MIN_TEMP);
147 addMeasurement(channels, types, CHANNEL_MAX_TEMP_THIS_MONTH, MAX_TEMP);
148 addMeasurement(channels, types, CHANNEL_DATE_MIN_CO2_THIS_MONTH, DATE_MIN_CO2);
149 addMeasurement(channels, types, CHANNEL_DATE_MAX_CO2_THIS_MONTH, DATE_MAX_CO2);
150 addMeasurement(channels, types, CHANNEL_DATE_MIN_HUMIDITY_THIS_MONTH, DATE_MIN_HUM);
151 addMeasurement(channels, types, CHANNEL_DATE_MAX_HUMIDITY_THIS_MONTH, DATE_MAX_HUM);
152 addMeasurement(channels, types, CHANNEL_DATE_MIN_NOISE_THIS_MONTH, DATE_MIN_NOISE);
153 addMeasurement(channels, types, CHANNEL_DATE_MAX_NOISE_THIS_MONTH, DATE_MAX_NOISE);
154 addMeasurement(channels, types, CHANNEL_DATE_MIN_PRESSURE_THIS_MONTH, DATE_MIN_PRESSURE);
155 addMeasurement(channels, types, CHANNEL_DATE_MAX_PRESSURE_THIS_MONTH, DATE_MAX_PRESSURE);
156 addMeasurement(channels, types, CHANNEL_DATE_MIN_TEMP_THIS_MONTH, DATE_MIN_TEMP);
157 addMeasurement(channels, types, CHANNEL_DATE_MAX_TEMP_THIS_MONTH, DATE_MAX_TEMP);
158 if (!channels.isEmpty()) {
159 getMeasurements(getId(), null, ONE_MONTH, types, channels, channelMeasurements);
164 protected State getNAThingProperty(String channelId) {
165 NADashboardData dashboardData = getDevice().map(d -> d.getDashboardData()).orElse(null);
166 if (dashboardData != null) {
169 return toQuantityType(dashboardData.getCO2(), API_CO2_UNIT);
170 case CHANNEL_TEMPERATURE:
171 return toQuantityType(dashboardData.getTemperature(), API_TEMPERATURE_UNIT);
172 case CHANNEL_MIN_TEMP:
173 return toQuantityType(dashboardData.getMinTemp(), API_TEMPERATURE_UNIT);
174 case CHANNEL_MAX_TEMP:
175 return toQuantityType(dashboardData.getMaxTemp(), API_TEMPERATURE_UNIT);
176 case CHANNEL_TEMP_TREND:
177 return toStringType(dashboardData.getTempTrend());
179 return toQuantityType(dashboardData.getNoise(), API_NOISE_UNIT);
180 case CHANNEL_PRESSURE:
181 return toQuantityType(dashboardData.getPressure(), API_PRESSURE_UNIT);
182 case CHANNEL_PRESS_TREND:
183 return toStringType(dashboardData.getPressureTrend());
184 case CHANNEL_ABSOLUTE_PRESSURE:
185 return toQuantityType(dashboardData.getAbsolutePressure(), API_PRESSURE_UNIT);
186 case CHANNEL_TIMEUTC:
187 return toDateTimeType(dashboardData.getTimeUtc(), timeZoneProvider.getTimeZone());
188 case CHANNEL_DATE_MIN_TEMP:
189 return toDateTimeType(dashboardData.getDateMinTemp(), timeZoneProvider.getTimeZone());
190 case CHANNEL_DATE_MAX_TEMP:
191 return toDateTimeType(dashboardData.getDateMaxTemp(), timeZoneProvider.getTimeZone());
192 case CHANNEL_HUMIDITY:
193 return toQuantityType(dashboardData.getHumidity(), API_HUMIDITY_UNIT);
194 case CHANNEL_HUMIDEX:
195 return toDecimalType(
196 WeatherUtils.getHumidex(dashboardData.getTemperature(), dashboardData.getHumidity()));
197 case CHANNEL_HEATINDEX:
198 return toQuantityType(
199 WeatherUtils.getHeatIndex(dashboardData.getTemperature(), dashboardData.getHumidity()),
200 API_TEMPERATURE_UNIT);
201 case CHANNEL_DEWPOINT:
202 return toQuantityType(
203 WeatherUtils.getDewPoint(dashboardData.getTemperature(), dashboardData.getHumidity()),
204 API_TEMPERATURE_UNIT);
205 case CHANNEL_DEWPOINTDEP:
206 Double dewPoint = WeatherUtils.getDewPoint(dashboardData.getTemperature(),
207 dashboardData.getHumidity());
208 return toQuantityType(WeatherUtils.getDewPointDep(dashboardData.getTemperature(), dewPoint),
209 API_TEMPERATURE_UNIT);
214 case CHANNEL_MIN_CO2:
215 case CHANNEL_MIN_CO2_THIS_WEEK:
216 case CHANNEL_MIN_CO2_THIS_MONTH:
217 case CHANNEL_MAX_CO2:
218 case CHANNEL_MAX_CO2_THIS_WEEK:
219 case CHANNEL_MAX_CO2_THIS_MONTH:
220 return toQuantityType(channelMeasurements.get(channelId), API_CO2_UNIT);
221 case CHANNEL_MIN_HUMIDITY:
222 case CHANNEL_MIN_HUMIDITY_THIS_WEEK:
223 case CHANNEL_MIN_HUMIDITY_THIS_MONTH:
224 case CHANNEL_MAX_HUMIDITY:
225 case CHANNEL_MAX_HUMIDITY_THIS_WEEK:
226 case CHANNEL_MAX_HUMIDITY_THIS_MONTH:
227 return toQuantityType(channelMeasurements.get(channelId), API_HUMIDITY_UNIT);
228 case CHANNEL_MIN_NOISE:
229 case CHANNEL_MIN_NOISE_THIS_WEEK:
230 case CHANNEL_MIN_NOISE_THIS_MONTH:
231 case CHANNEL_MAX_NOISE:
232 case CHANNEL_MAX_NOISE_THIS_WEEK:
233 case CHANNEL_MAX_NOISE_THIS_MONTH:
234 return toQuantityType(channelMeasurements.get(channelId), API_NOISE_UNIT);
235 case CHANNEL_MIN_PRESSURE:
236 case CHANNEL_MIN_PRESSURE_THIS_WEEK:
237 case CHANNEL_MIN_PRESSURE_THIS_MONTH:
238 case CHANNEL_MAX_PRESSURE:
239 case CHANNEL_MAX_PRESSURE_THIS_WEEK:
240 case CHANNEL_MAX_PRESSURE_THIS_MONTH:
241 return toQuantityType(channelMeasurements.get(channelId), API_PRESSURE_UNIT);
242 case CHANNEL_MIN_TEMP_THIS_WEEK:
243 case CHANNEL_MIN_TEMP_THIS_MONTH:
244 case CHANNEL_MAX_TEMP_THIS_WEEK:
245 case CHANNEL_MAX_TEMP_THIS_MONTH:
246 return toQuantityType(channelMeasurements.get(channelId), API_TEMPERATURE_UNIT);
247 case CHANNEL_DATE_MIN_CO2:
248 case CHANNEL_DATE_MIN_CO2_THIS_WEEK:
249 case CHANNEL_DATE_MIN_CO2_THIS_MONTH:
250 case CHANNEL_DATE_MAX_CO2:
251 case CHANNEL_DATE_MAX_CO2_THIS_WEEK:
252 case CHANNEL_DATE_MAX_CO2_THIS_MONTH:
253 case CHANNEL_DATE_MIN_NOISE:
254 case CHANNEL_DATE_MIN_NOISE_THIS_WEEK:
255 case CHANNEL_DATE_MIN_NOISE_THIS_MONTH:
256 case CHANNEL_DATE_MAX_NOISE:
257 case CHANNEL_DATE_MAX_NOISE_THIS_WEEK:
258 case CHANNEL_DATE_MAX_NOISE_THIS_MONTH:
259 case CHANNEL_DATE_MIN_HUMIDITY:
260 case CHANNEL_DATE_MIN_HUMIDITY_THIS_WEEK:
261 case CHANNEL_DATE_MIN_HUMIDITY_THIS_MONTH:
262 case CHANNEL_DATE_MAX_HUMIDITY:
263 case CHANNEL_DATE_MAX_HUMIDITY_THIS_WEEK:
264 case CHANNEL_DATE_MAX_HUMIDITY_THIS_MONTH:
265 case CHANNEL_DATE_MIN_PRESSURE:
266 case CHANNEL_DATE_MIN_PRESSURE_THIS_WEEK:
267 case CHANNEL_DATE_MIN_PRESSURE_THIS_MONTH:
268 case CHANNEL_DATE_MAX_PRESSURE:
269 case CHANNEL_DATE_MAX_PRESSURE_THIS_WEEK:
270 case CHANNEL_DATE_MAX_PRESSURE_THIS_MONTH:
271 case CHANNEL_DATE_MIN_TEMP_THIS_WEEK:
272 case CHANNEL_DATE_MIN_TEMP_THIS_MONTH:
273 case CHANNEL_DATE_MAX_TEMP_THIS_WEEK:
274 case CHANNEL_DATE_MAX_TEMP_THIS_MONTH:
275 return toDateTimeType(channelMeasurements.get(channelId), timeZoneProvider.getTimeZone());
278 return super.getNAThingProperty(channelId);
282 protected Optional<Integer> getDataTimestamp() {
283 return getDevice().map(d -> d.getLastStatusStore());
287 protected boolean isReachable() {
288 boolean result = false;
289 Optional<NAMain> device = getDevice();
290 if (device.isPresent()) {
291 Boolean reachable = device.get().getReachable();
292 result = reachable != null ? reachable.booleanValue() : false;