]> git.basschouten.com Git - openhab-addons.git/blob
50be4a14ca5510b97780edf94b12c6802bdfc07b
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.systeminfo.internal.handler;
14
15 import static org.openhab.binding.systeminfo.internal.SysteminfoBindingConstants.*;
16
17 import java.math.BigDecimal;
18 import java.util.HashSet;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.concurrent.ScheduledFuture;
24 import java.util.concurrent.TimeUnit;
25
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.openhab.binding.systeminfo.internal.model.DeviceNotFoundException;
29 import org.openhab.binding.systeminfo.internal.model.SysteminfoInterface;
30 import org.openhab.core.config.core.Configuration;
31 import org.openhab.core.library.types.PercentType;
32 import org.openhab.core.library.types.QuantityType;
33 import org.openhab.core.library.unit.Units;
34 import org.openhab.core.thing.Channel;
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.ThingStatusDetail;
39 import org.openhab.core.thing.binding.BaseThingHandler;
40 import org.openhab.core.types.Command;
41 import org.openhab.core.types.RefreshType;
42 import org.openhab.core.types.State;
43 import org.openhab.core.types.UnDefType;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * The {@link SysteminfoHandler} is responsible for providing real time information about the system
49  * (CPU, Memory, Storage, Display and others).
50  *
51  * @author Svilen Valkanov - Initial contribution
52  * @author Lyubomir Papzov - Separate the creation of the systeminfo object and its initialization
53  * @author Wouter Born - Add null annotations
54  */
55 @NonNullByDefault
56 public class SysteminfoHandler extends BaseThingHandler {
57     /**
58      * Refresh interval for {@link #highPriorityChannels} in seconds.
59      */
60     private @NonNullByDefault({}) BigDecimal refreshIntervalHighPriority;
61
62     /**
63      * Refresh interval for {@link #mediumPriorityChannels} in seconds.
64      */
65     private @NonNullByDefault({}) BigDecimal refreshIntervalMediumPriority;
66
67     /**
68      * Channels with priority configuration parameter set to High. They usually need frequent update of the state like
69      * CPU load, or information about the free and used memory.
70      * They are updated periodically at {@link #refreshIntervalHighPriority}.
71      */
72     private final Set<ChannelUID> highPriorityChannels = new HashSet<>();
73
74     /**
75      * Channels with priority configuration parameter set to Medium. These channels usually need update of the
76      * state not so oft like battery capacity, storage used and etc.
77      * They are updated periodically at {@link #refreshIntervalMediumPriority}.
78      */
79     private final Set<ChannelUID> mediumPriorityChannels = new HashSet<>();
80
81     /**
82      * Channels with priority configuration parameter set to Low. They represent static information or information
83      * that is updated rare- e.g. CPU name, storage name and etc.
84      * They are updated only at {@link #initialize()}.
85      */
86     private final Set<ChannelUID> lowPriorityChannels = new HashSet<>();
87
88     /**
89      * Wait time for the creation of Item-Channel links in seconds. This delay is needed, because the Item-Channel
90      * links have to be created before the thing state is updated, otherwise item state will not be updated.
91      */
92     public static final int WAIT_TIME_CHANNEL_ITEM_LINK_INIT = 1;
93
94     private SysteminfoInterface systeminfo;
95
96     private @Nullable ScheduledFuture<?> highPriorityTasks;
97     private @Nullable ScheduledFuture<?> mediumPriorityTasks;
98
99     private Logger logger = LoggerFactory.getLogger(SysteminfoHandler.class);
100
101     public SysteminfoHandler(Thing thing, @Nullable SysteminfoInterface systeminfo) {
102         super(thing);
103         if (systeminfo != null) {
104             this.systeminfo = systeminfo;
105         } else {
106             throw new IllegalArgumentException("No systeminfo service was provided");
107         }
108     }
109
110     @Override
111     public void initialize() {
112         if (instantiateSysteminfoLibrary() && isConfigurationValid() && updateProperties()) {
113             groupChannelsByPriority();
114             scheduleUpdates();
115             updateStatus(ThingStatus.ONLINE);
116         } else {
117             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
118                     "Thing cannot be initialized!");
119         }
120     }
121
122     private boolean instantiateSysteminfoLibrary() {
123         try {
124             systeminfo.initializeSysteminfo();
125             logger.debug("Systeminfo implementation is instantiated!");
126             return true;
127         } catch (Exception e) {
128             logger.warn("Cannot instantiate Systeminfo object!", e);
129             return false;
130         }
131     }
132
133     private boolean isConfigurationValid() {
134         logger.debug("Start reading Thing configuration.");
135         try {
136             refreshIntervalMediumPriority = (BigDecimal) this.thing.getConfiguration()
137                     .get(MEDIUM_PRIORITY_REFRESH_TIME);
138             refreshIntervalHighPriority = (BigDecimal) this.thing.getConfiguration().get(HIGH_PRIORITY_REFRESH_TIME);
139
140             if (refreshIntervalHighPriority.intValue() <= 0 || refreshIntervalMediumPriority.intValue() <= 0) {
141                 throw new IllegalArgumentException("Refresh time must be positive number!");
142             }
143             logger.debug("Refresh time for medium priority channels set to {} s", refreshIntervalMediumPriority);
144             logger.debug("Refresh time for high priority channels set to {} s", refreshIntervalHighPriority);
145             return true;
146         } catch (IllegalArgumentException e) {
147             logger.warn("Refresh time value is invalid! Please change the thing configuration!");
148             return false;
149         } catch (ClassCastException e) {
150             logger.debug("Channel configuration cannot be read!");
151             return false;
152         }
153     }
154
155     private boolean updateProperties() {
156         Map<String, String> properties = editProperties();
157         try {
158             properties.put(PROPERTY_CPU_LOGICAL_CORES, systeminfo.getCpuLogicalCores().toString());
159             properties.put(PROPERTY_CPU_PHYSICAL_CORES, systeminfo.getCpuPhysicalCores().toString());
160             properties.put(PROPERTY_OS_FAMILY, systeminfo.getOsFamily().toString());
161             properties.put(PROPERTY_OS_MANUFACTURER, systeminfo.getOsManufacturer().toString());
162             properties.put(PROPERTY_OS_VERSION, systeminfo.getOsVersion().toString());
163             updateProperties(properties);
164             logger.debug("Properties updated!");
165             return true;
166         } catch (Exception e) {
167             logger.debug("Cannot get system properties! Please try to restart the binding.", e);
168             return false;
169         }
170     }
171
172     private void groupChannelsByPriority() {
173         logger.trace("Grouping channels by priority.");
174         List<Channel> channels = this.thing.getChannels();
175
176         for (Channel channel : channels) {
177             Configuration properties = channel.getConfiguration();
178             String priority = (String) properties.get(PRIOIRITY_PARAM);
179             if (priority == null) {
180                 logger.debug("Channel with UID {} will not be updated. The channel has no priority set !",
181                         channel.getUID());
182                 break;
183             }
184             switch (priority) {
185                 case "High":
186                     highPriorityChannels.add(channel.getUID());
187                     break;
188                 case "Medium":
189                     mediumPriorityChannels.add(channel.getUID());
190                     break;
191                 case "Low":
192                     lowPriorityChannels.add(channel.getUID());
193                     break;
194                 default:
195                     logger.debug("Invalid priority configuration parameter. Channel will not be updated!");
196             }
197         }
198     }
199
200     private void changeChannelPriority(ChannelUID channelUID, String priority) {
201         switch (priority) {
202             case "High":
203                 mediumPriorityChannels.remove(channelUID);
204                 lowPriorityChannels.remove(channelUID);
205                 highPriorityChannels.add(channelUID);
206                 break;
207             case "Medium":
208                 lowPriorityChannels.remove(channelUID);
209                 highPriorityChannels.remove(channelUID);
210                 mediumPriorityChannels.add(channelUID);
211                 break;
212             case "Low":
213                 highPriorityChannels.remove(channelUID);
214                 mediumPriorityChannels.remove(channelUID);
215                 lowPriorityChannels.add(channelUID);
216                 break;
217             default:
218                 logger.debug("Invalid priority configuration parameter. Channel will not be updated!");
219         }
220     }
221
222     private void scheduleUpdates() {
223         logger.debug("Schedule high priority tasks at fixed rate {} s.", refreshIntervalHighPriority);
224         highPriorityTasks = scheduler.scheduleWithFixedDelay(() -> {
225             publishData(highPriorityChannels);
226         }, WAIT_TIME_CHANNEL_ITEM_LINK_INIT, refreshIntervalHighPriority.intValue(), TimeUnit.SECONDS);
227
228         logger.debug("Schedule medium priority tasks at fixed rate {} s.", refreshIntervalMediumPriority);
229         mediumPriorityTasks = scheduler.scheduleWithFixedDelay(() -> {
230             publishData(mediumPriorityChannels);
231         }, WAIT_TIME_CHANNEL_ITEM_LINK_INIT, refreshIntervalMediumPriority.intValue(), TimeUnit.SECONDS);
232
233         logger.debug("Schedule one time update for low priority tasks.");
234         scheduler.schedule(() -> {
235             publishData(lowPriorityChannels);
236         }, WAIT_TIME_CHANNEL_ITEM_LINK_INIT, TimeUnit.SECONDS);
237     }
238
239     private void publishData(Set<ChannelUID> channels) {
240         Iterator<ChannelUID> iter = channels.iterator();
241         while (iter.hasNext()) {
242             ChannelUID channeUID = iter.next();
243             if (isLinked(channeUID.getId())) {
244                 publishDataForChannel(channeUID);
245             }
246         }
247     }
248
249     private void publishDataForChannel(ChannelUID channelUID) {
250         State state = getInfoForChannel(channelUID);
251         String channelID = channelUID.getId();
252         updateState(channelID, state);
253     }
254
255     public Set<ChannelUID> getHighPriorityChannels() {
256         return highPriorityChannels;
257     }
258
259     public Set<ChannelUID> getMediumPriorityChannels() {
260         return mediumPriorityChannels;
261     }
262
263     public Set<ChannelUID> getLowPriorityChannels() {
264         return lowPriorityChannels;
265     }
266
267     /**
268      * This method gets the information for specific channel through the {@link SysteminfoInterface}. It uses the
269      * channel ID to call the correct method from the {@link SysteminfoInterface} with deviceIndex parameter (in case of
270      * multiple devices, for reference see {@link #getDeviceIndex(String)}})
271      *
272      * @param channelUID the UID of the channel
273      * @return State object or null, if there is no information for the device with this index
274      */
275     private State getInfoForChannel(ChannelUID channelUID) {
276         State state = null;
277
278         String channelID = channelUID.getId();
279         String channelIDWithoutGroup = channelUID.getIdWithoutGroup();
280         String channelGroupID = channelUID.getGroupId();
281
282         int deviceIndex = getDeviceIndex(channelUID);
283
284         // The channelGroup may contain deviceIndex. It must be deleted from the channelID, because otherwise the
285         // switch will not find the correct method below.
286         // All digits are deleted from the ID
287         if (channelGroupID != null) {
288             channelID = channelGroupID.replaceAll("\\d+", "") + "#" + channelIDWithoutGroup;
289         }
290
291         try {
292             switch (channelID) {
293                 case CHANNEL_MEMORY_HEAP_AVAILABLE:
294                     state = new QuantityType<>(Runtime.getRuntime().freeMemory(), Units.BYTE);
295                     break;
296                 case CHANNEL_MEMORY_USED_HEAP_PERCENT:
297                     state = new QuantityType<>((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())
298                             * 100 / Runtime.getRuntime().maxMemory(), Units.PERCENT);
299                     break;
300                 case CHANNEL_DISPLAY_INFORMATION:
301                     state = systeminfo.getDisplayInformation(deviceIndex);
302                     break;
303                 case CHANNEL_BATTERY_NAME:
304                     state = systeminfo.getBatteryName(deviceIndex);
305                     break;
306                 case CHANNEL_BATTERY_REMAINING_CAPACITY:
307                     state = systeminfo.getBatteryRemainingCapacity(deviceIndex);
308                     break;
309                 case CHANNEL_BATTERY_REMAINING_TIME:
310                     state = systeminfo.getBatteryRemainingTime(deviceIndex);
311                     break;
312                 case CHANNEL_SENSORS_CPU_TEMPERATURE:
313                     state = systeminfo.getSensorsCpuTemperature();
314                     break;
315                 case CHANNEL_SENOSRS_CPU_VOLTAGE:
316                     state = systeminfo.getSensorsCpuVoltage();
317                     break;
318                 case CHANNEL_SENSORS_FAN_SPEED:
319                     state = systeminfo.getSensorsFanSpeed(deviceIndex);
320                     break;
321                 case CHANNEL_CPU_LOAD:
322                     PercentType cpuLoad = systeminfo.getSystemCpuLoad();
323                     state = (cpuLoad != null) ? new QuantityType<>(cpuLoad, Units.PERCENT) : null;
324                     break;
325                 case CHANNEL_CPU_LOAD_1:
326                     state = systeminfo.getCpuLoad1();
327                     break;
328                 case CHANNEL_CPU_LOAD_5:
329                     state = systeminfo.getCpuLoad5();
330                     break;
331                 case CHANNEL_CPU_LOAD_15:
332                     state = systeminfo.getCpuLoad15();
333                     break;
334                 case CHANNEL_CPU_UPTIME:
335                     state = systeminfo.getCpuUptime();
336                     break;
337                 case CHANNEL_CPU_THREADS:
338                     state = systeminfo.getCpuThreads();
339                     break;
340                 case CHANNEL_CPU_DESCRIPTION:
341                     state = systeminfo.getCpuDescription();
342                     break;
343                 case CHANNEL_CPU_NAME:
344                     state = systeminfo.getCpuName();
345                     break;
346                 case CHANNEL_MEMORY_AVAILABLE:
347                     state = systeminfo.getMemoryAvailable();
348                     break;
349                 case CHANNEL_MEMORY_USED:
350                     state = systeminfo.getMemoryUsed();
351                     break;
352                 case CHANNEL_MEMORY_TOTAL:
353                     state = systeminfo.getMemoryTotal();
354                     break;
355                 case CHANNEL_MEMORY_AVAILABLE_PERCENT:
356                     state = systeminfo.getMemoryAvailablePercent();
357                     break;
358                 case CHANNEL_MEMORY_USED_PERCENT:
359                     state = systeminfo.getMemoryUsedPercent();
360                     break;
361                 case CHANNEL_SWAP_AVAILABLE:
362                     state = systeminfo.getSwapAvailable();
363                     break;
364                 case CHANNEL_SWAP_USED:
365                     state = systeminfo.getSwapUsed();
366                     break;
367                 case CHANNEL_SWAP_TOTAL:
368                     state = systeminfo.getSwapTotal();
369                     break;
370                 case CHANNEL_SWAP_AVAILABLE_PERCENT:
371                     state = systeminfo.getSwapAvailablePercent();
372                     break;
373                 case CHANNEL_SWAP_USED_PERCENT:
374                     state = systeminfo.getSwapUsedPercent();
375                     break;
376                 case CHANNEL_DRIVE_MODEL:
377                     state = systeminfo.getDriveModel(deviceIndex);
378                     break;
379                 case CHANNEL_DRIVE_SERIAL:
380                     state = systeminfo.getDriveSerialNumber(deviceIndex);
381                     break;
382                 case CHANNEL_DRIVE_NAME:
383                     state = systeminfo.getDriveName(deviceIndex);
384                     break;
385                 case CHANNEL_STORAGE_NAME:
386                     state = systeminfo.getStorageName(deviceIndex);
387                     break;
388                 case CHANNEL_STORAGE_DESCRIPTION:
389                     state = systeminfo.getStorageDescription(deviceIndex);
390                     break;
391                 case CHANNEL_STORAGE_AVAILABLE:
392                     state = systeminfo.getStorageAvailable(deviceIndex);
393                     break;
394                 case CHANNEL_STORAGE_USED:
395                     state = systeminfo.getStorageUsed(deviceIndex);
396                     break;
397                 case CHANNEL_STORAGE_TOTAL:
398                     state = systeminfo.getStorageTotal(deviceIndex);
399                     break;
400                 case CHANNEL_STORAGE_TYPE:
401                     state = systeminfo.getStorageType(deviceIndex);
402                     break;
403                 case CHANNEL_STORAGE_AVAILABLE_PERCENT:
404                     state = systeminfo.getStorageAvailablePercent(deviceIndex);
405                     break;
406                 case CHANNEL_STORAGE_USED_PERCENT:
407                     state = systeminfo.getStorageUsedPercent(deviceIndex);
408                     break;
409                 case CHANNEL_NETWORK_IP:
410                     state = systeminfo.getNetworkIp(deviceIndex);
411                     break;
412                 case CHANNEL_NETWORK_ADAPTER_NAME:
413                     state = systeminfo.getNetworkDisplayName(deviceIndex);
414                     break;
415                 case CHANNEL_NETWORK_NAME:
416                     state = systeminfo.getNetworkName(deviceIndex);
417                     break;
418                 case CHANNEL_NETWORK_MAC:
419                     state = systeminfo.getNetworkMac(deviceIndex);
420                     break;
421                 case CHANNEL_NETWORK_DATA_SENT:
422                     state = systeminfo.getNetworkDataSent(deviceIndex);
423                     break;
424                 case CHANNEL_NETWORK_DATA_RECEIVED:
425                     state = systeminfo.getNetworkDataReceived(deviceIndex);
426                     break;
427                 case CHANNEL_NETWORK_PACKETS_RECEIVED:
428                     state = systeminfo.getNetworkPacketsReceived(deviceIndex);
429                     break;
430                 case CHANNEL_NETWORK_PACKETS_SENT:
431                     state = systeminfo.getNetworkPacketsSent(deviceIndex);
432                     break;
433                 case CHANNEL_PROCESS_LOAD:
434                     PercentType processLoad = systeminfo.getProcessCpuUsage(deviceIndex);
435                     state = (processLoad != null) ? new QuantityType<>(processLoad, Units.PERCENT) : null;
436                     break;
437                 case CHANNEL_PROCESS_MEMORY:
438                     state = systeminfo.getProcessMemoryUsage(deviceIndex);
439                     break;
440                 case CHANNEL_PROCESS_NAME:
441                     state = systeminfo.getProcessName(deviceIndex);
442                     break;
443                 case CHANNEL_PROCESS_PATH:
444                     state = systeminfo.getProcessPath(deviceIndex);
445                     break;
446                 case CHANNEL_PROCESS_THREADS:
447                     state = systeminfo.getProcessThreads(deviceIndex);
448                     break;
449                 default:
450                     logger.debug("Channel with unknown ID: {} !", channelID);
451             }
452         } catch (DeviceNotFoundException e) {
453             logger.warn("No information for channel {} with device index {} :", channelID, deviceIndex);
454         } catch (Exception e) {
455             logger.debug("Unexpected error occurred while getting system information!", e);
456             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
457                     "Cannot get system info as result of unexpected error. Please try to restart the binding (remove and re-add the thing)!");
458         }
459         return state != null ? state : UnDefType.UNDEF;
460     }
461
462     /**
463      * The device index is an optional part of the channelID - the last characters of the groupID. It is used to
464      * identify unique device, when more than one devices are available (e.g. local disks with names C:\, D:\, E"\ - the
465      * first will have deviceIndex=0, the second deviceIndex=1 ant etc).
466      * When no device index is specified, default value of 0 (first device in the list) is returned.
467      *
468      * @param channelID the ID of the channel
469      * @return natural number (number >=0)
470      */
471     private int getDeviceIndex(ChannelUID channelUID) {
472         String channelGroupID = channelUID.getGroupId();
473         if (channelGroupID == null) {
474             return 0;
475         }
476
477         if (channelGroupID.contains(CHANNEL_GROUP_PROCESS)) {
478             // Only in this case the deviceIndex is part of the channel configuration - PID (Process Identifier)
479             int pid = getPID(channelUID);
480             logger.debug("Channel with UID {} tracks process with PID: {}", channelUID, pid);
481             return pid;
482         }
483
484         char lastChar = channelGroupID.charAt(channelGroupID.length() - 1);
485         if (Character.isDigit(lastChar)) {
486             // All non-digits are deleted from the ID
487             String deviceIndexPart = channelGroupID.replaceAll("\\D+", "");
488             return Integer.parseInt(deviceIndexPart);
489         }
490
491         return 0;
492     }
493
494     /**
495      * This method gets the process identifier (PID) for specific process
496      *
497      * @param channelUID channel unique identifier
498      * @return natural number
499      */
500     private int getPID(ChannelUID channelUID) {
501         int pid = 0;
502         try {
503             Channel channel = this.thing.getChannel(channelUID.getId());
504             if (channel != null) {
505                 Configuration channelProperties = channel.getConfiguration();
506                 BigDecimal pidValue = (BigDecimal) channelProperties.get(PID_PARAM);
507                 if (pidValue == null || pidValue.intValue() < 0) {
508                     throw new IllegalArgumentException("Invalid value for Process Identifier.");
509                 } else {
510                     pid = pidValue.intValue();
511                 }
512             } else {
513                 logger.debug("Channel does not exist ! Fall back to default value.");
514             }
515         } catch (ClassCastException e) {
516             logger.debug("Channel configuration cannot be read ! Fall back to default value.", e);
517         } catch (IllegalArgumentException e) {
518             logger.debug("PID (Process Identifier) must be positive number. Fall back to default value. ", e);
519         }
520         return pid;
521     }
522
523     @Override
524     public void handleCommand(ChannelUID channelUID, Command command) {
525         if (thing.getStatus().equals(ThingStatus.ONLINE)) {
526             if (command instanceof RefreshType) {
527                 logger.debug("Refresh command received for channel {}!", channelUID);
528                 publishDataForChannel(channelUID);
529             } else {
530                 logger.debug("Unsupported command {}! Supported commands: REFRESH", command);
531             }
532         } else {
533             logger.debug("Cannot handle command. Thing is not ONLINE.");
534         }
535     }
536
537     private boolean isConfigurationKeyChanged(Configuration currentConfig, Configuration newConfig, String key) {
538         Object currentValue = currentConfig.get(key);
539         Object newValue = newConfig.get(key);
540
541         if (currentValue == null) {
542             return (newValue != null);
543         }
544
545         return !currentValue.equals(newValue);
546     }
547
548     @Override
549     public void thingUpdated(Thing thing) {
550         logger.trace("About to update thing.");
551         boolean isChannelConfigChanged = false;
552         List<Channel> channels = thing.getChannels();
553
554         for (Channel channel : channels) {
555             ChannelUID channelUID = channel.getUID();
556             Configuration newChannelConfig = channel.getConfiguration();
557             Channel oldChannel = this.thing.getChannel(channelUID.getId());
558
559             if (oldChannel == null) {
560                 logger.warn("Channel with UID {} cannot be updated, as it cannot be found !", channelUID);
561                 continue;
562             }
563             Configuration currentChannelConfig = oldChannel.getConfiguration();
564
565             if (isConfigurationKeyChanged(currentChannelConfig, newChannelConfig, PRIOIRITY_PARAM)) {
566                 isChannelConfigChanged = true;
567
568                 handleChannelConfigurationChange(oldChannel, newChannelConfig, PRIOIRITY_PARAM);
569
570                 String newPriority = (String) newChannelConfig.get(PRIOIRITY_PARAM);
571                 changeChannelPriority(channelUID, newPriority);
572             }
573
574             if (isConfigurationKeyChanged(currentChannelConfig, newChannelConfig, PID_PARAM)) {
575                 isChannelConfigChanged = true;
576                 handleChannelConfigurationChange(oldChannel, newChannelConfig, PID_PARAM);
577             }
578         }
579
580         if (!(isInitialized() && isChannelConfigChanged)) {
581             super.thingUpdated(thing);
582         }
583     }
584
585     private void handleChannelConfigurationChange(Channel channel, Configuration newConfig, String parameter) {
586         Configuration configuration = channel.getConfiguration();
587         Object oldValue = configuration.get(parameter);
588
589         configuration.put(parameter, newConfig.get(parameter));
590
591         Object newValue = newConfig.get(parameter);
592         logger.debug("Channel with UID {} has changed its {} from {} to {}", channel.getUID(), parameter, oldValue,
593                 newValue);
594         publishDataForChannel(channel.getUID());
595     }
596
597     private void stopScheduledUpdates() {
598         ScheduledFuture<?> localHighPriorityTasks = highPriorityTasks;
599         if (localHighPriorityTasks != null) {
600             logger.debug("High prioriy tasks will not be run anymore !");
601             localHighPriorityTasks.cancel(true);
602         }
603
604         ScheduledFuture<?> localMediumPriorityTasks = mediumPriorityTasks;
605         if (localMediumPriorityTasks != null) {
606             logger.debug("Medium prioriy tasks will not be run anymore !");
607             localMediumPriorityTasks.cancel(true);
608         }
609     }
610
611     @Override
612     public void dispose() {
613         stopScheduledUpdates();
614     }
615 }