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.max.internal.handler;
15 import static org.openhab.binding.max.internal.MaxBindingConstants.*;
16 import static org.openhab.core.library.unit.SIUnits.CELSIUS;
18 import java.math.BigDecimal;
19 import java.text.DateFormat;
20 import java.text.SimpleDateFormat;
21 import java.util.Calendar;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.HashMap;
26 import java.util.Map.Entry;
27 import java.util.concurrent.ScheduledFuture;
28 import java.util.concurrent.TimeUnit;
30 import org.openhab.binding.max.internal.actions.MaxDevicesActions;
31 import org.openhab.binding.max.internal.command.CCommand;
32 import org.openhab.binding.max.internal.command.QCommand;
33 import org.openhab.binding.max.internal.command.SConfigCommand;
34 import org.openhab.binding.max.internal.command.SConfigCommand.ConfigCommandType;
35 import org.openhab.binding.max.internal.command.ZCommand;
36 import org.openhab.binding.max.internal.device.Device;
37 import org.openhab.binding.max.internal.device.DeviceType;
38 import org.openhab.binding.max.internal.device.EcoSwitch;
39 import org.openhab.binding.max.internal.device.HeatingThermostat;
40 import org.openhab.binding.max.internal.device.ShutterContact;
41 import org.openhab.binding.max.internal.device.ThermostatModeType;
42 import org.openhab.core.config.core.Configuration;
43 import org.openhab.core.library.types.DecimalType;
44 import org.openhab.core.library.types.OpenClosedType;
45 import org.openhab.core.library.types.QuantityType;
46 import org.openhab.core.library.types.StringType;
47 import org.openhab.core.thing.Bridge;
48 import org.openhab.core.thing.ChannelUID;
49 import org.openhab.core.thing.Thing;
50 import org.openhab.core.thing.ThingStatus;
51 import org.openhab.core.thing.ThingStatusDetail;
52 import org.openhab.core.thing.ThingStatusInfo;
53 import org.openhab.core.thing.ThingUID;
54 import org.openhab.core.thing.binding.BaseThingHandler;
55 import org.openhab.core.thing.binding.ThingHandler;
56 import org.openhab.core.thing.binding.ThingHandlerService;
57 import org.openhab.core.types.Command;
58 import org.openhab.core.types.RefreshType;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
63 * The {@link MaxDevicesHandler} is responsible for handling commands, which are
64 * sent to one of the channels.
66 * @author Marcel Verpaalen - Initial contribution
68 public class MaxDevicesHandler extends BaseThingHandler implements DeviceStatusListener {
70 private final Logger logger = LoggerFactory.getLogger(MaxDevicesHandler.class);
71 private MaxCubeBridgeHandler bridgeHandler;
73 private String maxDeviceSerial;
74 private String rfAddress;
75 private boolean propertiesSet;
76 private boolean configSet;
78 // actual refresh variables
79 public static final int REFRESH_ACTUAL_MIN_RATE = 10; // minutes
80 public static final int REFRESH_ACTUAL_DURATION = 120; // seconds
81 private static final long COMMUNICATION_DELAY_TIME = 120;
82 private int refreshActualRate;
83 private boolean refreshingActuals;
84 private ScheduledFuture<?> refreshActualsJob;
85 private double originalSetTemp;
86 private ThermostatModeType originalMode;
88 public MaxDevicesHandler(Thing thing) {
93 public void initialize() {
95 final Configuration config = getThing().getConfiguration();
96 final String configDeviceId = (String) config.get(Thing.PROPERTY_SERIAL_NUMBER);
99 refreshActualRate = ((BigDecimal) config.get(PROPERTY_REFRESH_ACTUAL_RATE)).intValueExact();
100 } catch (Exception e) {
101 refreshActualRate = 0;
104 if (configDeviceId != null) {
105 maxDeviceSerial = configDeviceId;
107 if (maxDeviceSerial != null) {
108 logger.debug("Initialized MAX! device handler for {}.", maxDeviceSerial);
110 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
111 "Initialized MAX! device missing serialNumber configuration");
113 propertiesSet = false;
115 getMaxCubeBridgeHandler();
116 } catch (Exception e) {
117 logger.debug("Exception occurred during initialize : {}", e.getMessage(), e);
118 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
123 public void dispose() {
124 logger.debug("Disposing MAX! device {} {}.", getThing().getUID(), maxDeviceSerial);
125 if (refreshingActuals) {
126 refreshActualsRestore();
128 if (refreshActualsJob != null && !refreshActualsJob.isCancelled()) {
129 refreshActualsJob.cancel(true);
130 refreshActualsJob = null;
132 if (bridgeHandler != null) {
133 logger.trace("Clear MAX! device {} {} from bridge.", getThing().getUID(), maxDeviceSerial);
134 bridgeHandler.clearDeviceList();
135 bridgeHandler.unregisterDeviceStatusListener(this);
136 bridgeHandler = null;
138 logger.debug("Disposed MAX! device {} {}.", getThing().getUID(), maxDeviceSerial);
143 public void thingUpdated(Thing thing) {
145 super.thingUpdated(thing);
149 public void handleConfigurationUpdate(Map<String, Object> configurationParameters) {
150 logger.debug("MAX! Device {}: Configuration update received", getThing().getUID());
151 boolean temperaturePropertyUpdateNeeded = false;
152 final Device device = getMaxCubeBridgeHandler().getDevice(maxDeviceSerial);
154 final Map<String, Object> deviceProperties = device == null ? new HashMap<>() : device.getProperties();
155 final Configuration configuration = editConfiguration();
156 for (final Entry<String, Object> configurationParameter : configurationParameters.entrySet()) {
157 logger.debug("MAX! Device {}: Configuration update {} to {}", getThing().getUID(),
158 configurationParameter.getKey(), configurationParameter.getValue());
160 // Test if it is a part of the configuration properties.
161 // With the update all parameters are sends, so we need to determine which ones really changed.
162 if (deviceProperties.containsKey(configurationParameter.getKey())) {
163 if (deviceProperties.get(configurationParameter.getKey()).equals(configurationParameter.getValue())) {
164 logger.trace("Device {} Property {} value {} unchanged.", getThing().getUID(),
165 configurationParameter.getKey(), configurationParameter.getValue());
166 } else if (configurationParameter.getValue().getClass() == BigDecimal.class
167 && ((BigDecimal) deviceProperties.get(configurationParameter.getKey()))
168 .compareTo((BigDecimal) configurationParameter.getValue()) == 0) {
169 logger.trace("Device {} Property {} value {} unchanged.", getThing().getUID(),
170 configurationParameter.getKey(), configurationParameter.getValue());
172 logger.debug("Device {} Property {} value {} -> {} changed.", getThing().getUID(),
173 configurationParameter.getKey(), deviceProperties.get(configurationParameter.getKey()),
174 configurationParameter.getValue());
175 temperaturePropertyUpdateNeeded = true;
178 if (configurationParameter.getKey().equals(PROPERTY_DEVICENAME)
179 || configurationParameter.getKey().equals(PROPERTY_ROOMID)) {
180 updateDeviceName(configurationParameter);
182 if (configurationParameter.getKey().startsWith("action-")) {
183 if (configurationParameter.getValue().toString().equals(BUTTON_ACTION_VALUE)) {
184 configurationParameter.setValue(BigDecimal.valueOf(BUTTON_NOACTION_VALUE));
185 if (configurationParameter.getKey().equals(ACTION_DEVICE_DELETE)) {
190 configuration.put(configurationParameter.getKey(), configurationParameter.getValue());
192 // Persist changes and restart with new parameters
193 updateConfiguration(configuration);
194 if (temperaturePropertyUpdateNeeded) {
195 sendPropertyUpdate(configurationParameters, deviceProperties);
200 public Collection<Class<? extends ThingHandlerService>> getServices() {
201 return Collections.singleton(MaxDevicesActions.class);
204 private void sendPropertyUpdate(Map<String, Object> configurationParameters, Map<String, Object> deviceProperties) {
205 if (getMaxCubeBridgeHandler() == null) {
206 logger.debug("MAX! Cube LAN gateway bridge handler not found. Cannot handle update without bridge.");
211 Device device = getMaxCubeBridgeHandler().getDevice(maxDeviceSerial);
212 rfAddress = device.getRFAddress();
213 int roomId = device.getRoomId();
214 BigDecimal tempComfort = (BigDecimal) configurationParameters.getOrDefault(PROPERTY_THERMO_COMFORT_TEMP,
215 deviceProperties.get(PROPERTY_THERMO_COMFORT_TEMP));
216 BigDecimal tempEco = (BigDecimal) configurationParameters.getOrDefault(PROPERTY_THERMO_ECO_TEMP,
217 deviceProperties.get(PROPERTY_THERMO_ECO_TEMP));
218 BigDecimal tempSetpointMax = (BigDecimal) configurationParameters.getOrDefault(
219 PROPERTY_THERMO_MAX_TEMP_SETPOINT, deviceProperties.get(PROPERTY_THERMO_MAX_TEMP_SETPOINT));
220 BigDecimal tempSetpointMin = (BigDecimal) configurationParameters.getOrDefault(
221 PROPERTY_THERMO_MIN_TEMP_SETPOINT, deviceProperties.get(PROPERTY_THERMO_MIN_TEMP_SETPOINT));
222 BigDecimal tempOffset = (BigDecimal) configurationParameters.getOrDefault(PROPERTY_THERMO_OFFSET_TEMP,
223 deviceProperties.get(PROPERTY_THERMO_OFFSET_TEMP));
224 BigDecimal tempOpenWindow = (BigDecimal) configurationParameters.getOrDefault(
225 PROPERTY_THERMO_WINDOW_OPEN_TEMP, deviceProperties.get(PROPERTY_THERMO_WINDOW_OPEN_TEMP));
226 BigDecimal durationOpenWindow = (BigDecimal) configurationParameters.getOrDefault(
227 PROPERTY_THERMO_WINDOW_OPEN_DURATION, deviceProperties.get(PROPERTY_THERMO_WINDOW_OPEN_DURATION));
228 SConfigCommand cmd = new SConfigCommand(rfAddress, roomId, tempComfort.doubleValue(), tempEco.doubleValue(),
229 tempSetpointMax.doubleValue(), tempSetpointMin.doubleValue(), tempOffset.doubleValue(),
230 tempOpenWindow.doubleValue(), durationOpenWindow.intValue());
231 bridgeHandler.queueCommand(new SendCommand(maxDeviceSerial, cmd, "Update Thermostat Properties"));
233 } catch (Exception e) {
234 logger.debug("Exception occurred during execution: {}", e.getMessage(), e);
239 * Trigger update by sending C command.
240 * This command is delayed as it takes time to have the updates back from the thermostat
242 private void sendCCommand() {
243 scheduler.schedule(() -> {
244 CCommand cmd = new CCommand(rfAddress);
245 bridgeHandler.queueCommand(new SendCommand(maxDeviceSerial, cmd, "Refresh Thermostat Properties"));
247 }, COMMUNICATION_DELAY_TIME, TimeUnit.SECONDS);
251 * sends the T command to the Cube to disassociate the device from the MAX! Cube.
253 public void deviceDelete() {
254 MaxCubeBridgeHandler maxCubeBridge = getMaxCubeBridgeHandler();
255 if (maxCubeBridge != null) {
256 maxCubeBridge.sendDeviceDelete(maxDeviceSerial);
262 * Updates the device & roomname
264 private void updateDeviceName(Entry<String, Object> configurationParameter) {
266 final Device device = getMaxCubeBridgeHandler().getDevice(maxDeviceSerial);
267 if (device == null) {
268 logger.debug("MAX! Cube LAN gateway bridge handler not found. Cannot handle update without bridge.");
271 switch (configurationParameter.getKey()) {
272 case PROPERTY_DEVICENAME:
273 final String name = configurationParameter.getValue().toString();
274 if (!name.equals(device.getName())) {
275 logger.debug("Updating device name for {} to {}", getThing().getUID(), name);
276 device.setName(name);
277 bridgeHandler.sendDeviceAndRoomNameUpdate(name);
278 bridgeHandler.queueCommand(new SendCommand(maxDeviceSerial, new QCommand(), "Reload Data"));
282 case PROPERTY_ROOMID: // fall-through
283 case PROPERTY_ROOMNAME:
284 final int roomId = ((BigDecimal) configurationParameter.getValue()).intValue();
285 if (roomId != device.getRoomId()) {
286 logger.debug("Updating room for {} to {}", getThing().getUID().getAsString(), roomId);
287 device.setRoomId(roomId);
288 // TODO: handle if a room has no more devices, probably should be deleted. Also handle if room
290 // is no longer valid as the related device is movd to another room
291 bridgeHandler.sendDeviceAndRoomNameUpdate(Integer.toString(roomId));
292 SendCommand sendCommand = new SendCommand(maxDeviceSerial,
293 ZCommand.wakeupDevice(device.getRFAddress()),
294 "WakeUp device" + getThing().getUID().getAsString());
295 bridgeHandler.queueCommand(sendCommand);
296 sendCommand = new SendCommand(maxDeviceSerial,
297 new SConfigCommand(device.getRFAddress(), roomId, ConfigCommandType.SetRoom),
299 bridgeHandler.queueCommand(sendCommand);
301 sendCommand = new SendCommand(maxDeviceSerial, new QCommand(), "Reload Data");
302 bridgeHandler.queueCommand(sendCommand);
306 } catch (Exception e) {
307 logger.debug("Exception occurred during execution: {}", e.getMessage(), e);
311 private synchronized MaxCubeBridgeHandler getMaxCubeBridgeHandler() {
312 if (this.bridgeHandler == null) {
313 final Bridge bridge = getBridge();
314 if (bridge == null) {
315 logger.debug("Required bridge not defined for device {}.", maxDeviceSerial);
318 final ThingHandler handler = bridge.getHandler();
319 if (!(handler instanceof MaxCubeBridgeHandler)) {
320 logger.debug("No available bridge handler found for {} bridge {} .", maxDeviceSerial, bridge.getUID());
323 this.bridgeHandler = (MaxCubeBridgeHandler) handler;
324 this.bridgeHandler.registerDeviceStatusListener(this);
326 return this.bridgeHandler;
330 public void handleCommand(ChannelUID channelUID, Command command) {
331 final MaxCubeBridgeHandler maxCubeBridge = getMaxCubeBridgeHandler();
332 if (maxCubeBridge == null) {
333 logger.debug("MAX! Cube LAN gateway bridge handler not found. Cannot handle command without bridge.");
336 if (command instanceof RefreshType) {
337 maxCubeBridge.handleCommand(channelUID, command);
340 if (maxDeviceSerial == null) {
341 logger.warn("Serial number missing. Can't send command to device '{}'", getThing());
344 switch (channelUID.getId()) {
345 case CHANNEL_SETTEMP:
346 if (refreshingActuals) {
347 refreshActualsRestore();
349 maxCubeBridge.queueCommand(new SendCommand(maxDeviceSerial, channelUID, command));
352 if (refreshingActuals) {
353 refreshActualsRestore();
355 maxCubeBridge.queueCommand(new SendCommand(maxDeviceSerial, channelUID, command));
358 logger.warn("Setting of channel '{}' not possible, channel is read-only.", channelUID);
364 public void onDeviceStateChanged(ThingUID bridge, Device device) {
365 if (!device.getSerialNumber().equals(maxDeviceSerial)) {
368 if (device.isError() || device.isLinkStatusError()) {
369 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR);
370 } else if (!refreshingActuals) {
371 updateStatus(ThingStatus.ONLINE);
373 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, "Updating Actual Temperature");
375 if (!propertiesSet) {
376 setProperties(device);
379 setDeviceConfiguration(device);
381 if (refreshActualRate >= REFRESH_ACTUAL_MIN_RATE && (device.getType() == DeviceType.HeatingThermostat
382 || device.getType() == DeviceType.HeatingThermostatPlus)) {
383 refreshActualCheck((HeatingThermostat) device);
385 logger.debug("Updating states of {} {} ({}) id: {}", device.getType(), device.getName(),
386 device.getSerialNumber(), getThing().getUID());
387 switch (device.getType()) {
388 case WallMountedThermostat: // fall-through
389 case HeatingThermostat: // fall-through
390 case HeatingThermostatPlus:
391 updateState(new ChannelUID(getThing().getUID(), CHANNEL_LOCKED),
392 ((HeatingThermostat) device).isPanelLocked() ? OpenClosedType.CLOSED : OpenClosedType.OPEN);
393 updateState(new ChannelUID(getThing().getUID(), CHANNEL_SETTEMP),
394 new QuantityType<>(((HeatingThermostat) device).getTemperatureSetpoint(), CELSIUS));
395 updateState(new ChannelUID(getThing().getUID(), CHANNEL_MODE),
396 new StringType(((HeatingThermostat) device).getModeString()));
397 updateState(new ChannelUID(getThing().getUID(), CHANNEL_BATTERY),
398 ((HeatingThermostat) device).getBatteryLow());
399 updateState(new ChannelUID(getThing().getUID(), CHANNEL_VALVE),
400 new DecimalType(((HeatingThermostat) device).getValvePosition()));
401 double actualTemp = ((HeatingThermostat) device).getTemperatureActual();
402 if (actualTemp != 0) {
403 updateState(new ChannelUID(getThing().getUID(), CHANNEL_ACTUALTEMP),
404 new QuantityType<>(actualTemp, CELSIUS));
408 updateState(new ChannelUID(getThing().getUID(), CHANNEL_CONTACT_STATE),
409 ((ShutterContact) device).getShutterState());
410 updateState(new ChannelUID(getThing().getUID(), CHANNEL_BATTERY),
411 ((ShutterContact) device).getBatteryLow());
414 updateState(new ChannelUID(getThing().getUID(), CHANNEL_BATTERY), ((EcoSwitch) device).getBatteryLow());
417 logger.debug("Unhandled Device {}.", device.getType());
420 device.setUpdated(false);
423 private void refreshActualCheck(HeatingThermostat device) {
424 if (device.getActualTempLastUpdated() == null) {
425 Calendar t = Calendar.getInstance();
426 t.add(Calendar.MINUTE, REFRESH_ACTUAL_MIN_RATE * -1);
427 device.setActualTempLastUpdated(t.getTime());
428 logger.debug("Actual date reset for {} {} ({}) id: {}", device.getType(), device.getName(),
429 device.getSerialNumber(), getThing().getUID());
431 long timediff = Calendar.getInstance().getTime().getTime() - device.getActualTempLastUpdated().getTime();
432 if (timediff > ((long) refreshActualRate) * 1000 * 60) {
433 if (!refreshingActuals) {
434 logger.debug("Actual needs updating for {} {} ({}) id: {}", device.getType(), device.getName(),
435 device.getSerialNumber(), getThing().getUID());
437 originalSetTemp = device.getTemperatureSetpoint();
438 originalMode = device.getMode();
440 if (originalMode == ThermostatModeType.MANUAL || originalMode == ThermostatModeType.AUTOMATIC) {
441 double tempSetTemp = originalSetTemp + 0.5;
442 logger.debug("Actuals Refresh: Setting Temp {}", tempSetTemp);
443 handleCommand(new ChannelUID(getThing().getUID(), CHANNEL_SETTEMP),
444 new QuantityType<>(tempSetTemp, CELSIUS));
445 refreshingActuals = true;
447 logger.debug("Defer Actuals refresh. Only manual refresh for mode AUTOMATIC & MANUAL");
448 device.setActualTempLastUpdated(Calendar.getInstance().getTime());
451 if (refreshingActuals) {
452 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, "Updating Actual Temperature");
454 if (refreshActualsJob == null || refreshActualsJob.isCancelled()) {
455 refreshActualsJob = scheduler.schedule(this::refreshActualsRestore, REFRESH_ACTUAL_DURATION,
459 device.setActualTempLastUpdated(Calendar.getInstance().getTime());
462 logger.debug("Actual Refresh in progress for {} {} ({}) id: {}", device.getType(), device.getName(),
463 device.getSerialNumber(), getThing().getUID());
465 if (logger.isTraceEnabled()) {
466 final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
467 logger.trace("Actual date for {} {} ({}) : {}", device.getType(), device.getName(),
468 device.getSerialNumber(), dateFormat.format(device.getActualTempLastUpdated().getTime()));
474 * Send the commands to restore the original settings for mode & temperature
475 * to end the automatic update cycle
477 private synchronized void refreshActualsRestore() {
479 refreshingActuals = false;
480 if (originalMode == ThermostatModeType.AUTOMATIC || originalMode == ThermostatModeType.MANUAL) {
481 logger.debug("Finished Actuals Refresh: Restoring Temp {}", originalSetTemp);
482 handleCommand(new ChannelUID(getThing().getUID(), CHANNEL_SETTEMP),
483 new QuantityType<>(originalSetTemp, CELSIUS));
486 if (refreshActualsJob != null && !refreshActualsJob.isCancelled()) {
487 refreshActualsJob.cancel(true);
488 refreshActualsJob = null;
490 } catch (Exception e) {
491 logger.debug("Exception occurred during Actuals Refresh : {}", e.getMessage(), e);
496 public void onDeviceRemoved(MaxCubeBridgeHandler bridge, Device device) {
497 if (device.getSerialNumber().equals(maxDeviceSerial)) {
498 bridgeHandler.unregisterDeviceStatusListener(this);
499 bridgeHandler = null;
500 updateStatus(ThingStatus.OFFLINE);
505 public void onDeviceAdded(Bridge bridge, Device device) {
509 * Set the properties for this device
511 private void setProperties(Device device) {
513 logger.debug("MAX! {} {} properties update", device.getType(), device.getSerialNumber());
514 Map<String, String> properties = editProperties();
515 properties.put(Thing.PROPERTY_MODEL_ID, device.getType().toString());
516 properties.put(Thing.PROPERTY_SERIAL_NUMBER, device.getSerialNumber());
517 properties.put(Thing.PROPERTY_VENDOR, PROPERTY_VENDOR_NAME);
518 updateProperties(properties);
519 logger.debug("properties updated");
520 propertiesSet = true;
521 } catch (Exception e) {
522 logger.debug("Exception occurred during property edit: {}", e.getMessage(), e);
527 public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
528 logger.debug("Bridge Status updated to {} for device: {}", bridgeStatusInfo.getStatus(), getThing().getUID());
529 if (!bridgeStatusInfo.getStatus().equals(ThingStatus.ONLINE)) {
530 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
535 * Set the Configurable properties for this device
537 private void setDeviceConfiguration(Device device) {
539 boolean config_changed = false;
540 logger.debug("MAX! {} {} configuration update", device.getType(), device.getSerialNumber());
541 Configuration configuration = editConfiguration();
542 if (!device.getRoomName().equalsIgnoreCase((String) getConfig().get(PROPERTY_ROOMNAME))) {
543 configuration.put(PROPERTY_ROOMNAME, device.getRoomName());
544 config_changed = true;
546 if (getConfig().get(PROPERTY_ROOMID) == null || !(new BigDecimal(device.getRoomId())
547 .compareTo((BigDecimal) getConfig().get(PROPERTY_ROOMID)) == 0)) {
548 configuration.put(PROPERTY_ROOMID, new BigDecimal(device.getRoomId()));
549 config_changed = true;
551 if (!device.getName().equalsIgnoreCase((String) getConfig().get(PROPERTY_DEVICENAME))) {
552 configuration.put(PROPERTY_DEVICENAME, device.getName());
553 config_changed = true;
555 if (!device.getRFAddress().equalsIgnoreCase((String) getConfig().get(PROPERTY_RFADDRESS))) {
556 configuration.put(PROPERTY_RFADDRESS, device.getRFAddress());
557 config_changed = true;
559 for (Map.Entry<String, Object> entry : device.getProperties().entrySet()) {
560 configuration.put(entry.getKey(), entry.getValue());
562 if (config_changed) {
563 updateConfiguration(configuration);
564 logger.debug("Config updated: {}", configuration.getProperties());
566 logger.debug("MAX! {} {} no updated required.", device.getType(), device.getSerialNumber());
569 } catch (Exception e) {
570 logger.debug("Exception occurred during configuration edit: {}", e.getMessage(), e);
575 public void onDeviceConfigUpdate(Bridge bridge, Device device) {
576 if (device.getSerialNumber().equals(maxDeviceSerial)) {
577 setDeviceConfiguration(device);