]> git.basschouten.com Git - openhab-addons.git/blob
ee6422b33f20e219081944005cf59c58fc90b35d
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.miio.internal.handler;
14
15 import static org.openhab.binding.miio.internal.MiIoBindingConstants.CHANNEL_COMMAND;
16
17 import java.awt.Color;
18 import java.io.IOException;
19 import java.net.URL;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
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.miio.internal.MiIoBindingConfiguration;
29 import org.openhab.binding.miio.internal.MiIoCommand;
30 import org.openhab.binding.miio.internal.MiIoCryptoException;
31 import org.openhab.binding.miio.internal.MiIoSendCommand;
32 import org.openhab.binding.miio.internal.Utils;
33 import org.openhab.binding.miio.internal.basic.ActionConditions;
34 import org.openhab.binding.miio.internal.basic.CommandParameterType;
35 import org.openhab.binding.miio.internal.basic.Conversions;
36 import org.openhab.binding.miio.internal.basic.MiIoBasicChannel;
37 import org.openhab.binding.miio.internal.basic.MiIoBasicDevice;
38 import org.openhab.binding.miio.internal.basic.MiIoDatabaseWatchService;
39 import org.openhab.binding.miio.internal.basic.MiIoDeviceAction;
40 import org.openhab.binding.miio.internal.basic.MiIoDeviceActionCondition;
41 import org.openhab.binding.miio.internal.transport.MiIoAsyncCommunication;
42 import org.openhab.core.cache.ExpiringCache;
43 import org.openhab.core.library.types.DecimalType;
44 import org.openhab.core.library.types.HSBType;
45 import org.openhab.core.library.types.OnOffType;
46 import org.openhab.core.library.types.PercentType;
47 import org.openhab.core.library.types.StringType;
48 import org.openhab.core.thing.Channel;
49 import org.openhab.core.thing.ChannelUID;
50 import org.openhab.core.thing.Thing;
51 import org.openhab.core.thing.binding.builder.ChannelBuilder;
52 import org.openhab.core.thing.binding.builder.ThingBuilder;
53 import org.openhab.core.thing.type.ChannelTypeRegistry;
54 import org.openhab.core.thing.type.ChannelTypeUID;
55 import org.openhab.core.types.Command;
56 import org.openhab.core.types.RefreshType;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 import com.google.gson.Gson;
61 import com.google.gson.GsonBuilder;
62 import com.google.gson.JsonArray;
63 import com.google.gson.JsonElement;
64 import com.google.gson.JsonIOException;
65 import com.google.gson.JsonObject;
66 import com.google.gson.JsonPrimitive;
67 import com.google.gson.JsonSyntaxException;
68
69 /**
70  * The {@link MiIoBasicHandler} is responsible for handling commands, which are
71  * sent to one of the channels.
72  *
73  * @author Marcel Verpaalen - Initial contribution
74  */
75 @NonNullByDefault
76 public class MiIoBasicHandler extends MiIoAbstractHandler {
77     private final Logger logger = LoggerFactory.getLogger(MiIoBasicHandler.class);
78     private boolean hasChannelStructure;
79
80     private final ExpiringCache<Boolean> updateDataCache = new ExpiringCache<>(CACHE_EXPIRY, () -> {
81         scheduler.schedule(this::updateData, 0, TimeUnit.SECONDS);
82         return true;
83     });
84
85     List<MiIoBasicChannel> refreshList = new ArrayList<>();
86     private Map<String, MiIoBasicChannel> refreshListCustomCommands = new HashMap<>();
87
88     private @Nullable MiIoBasicDevice miioDevice;
89     private Map<ChannelUID, MiIoBasicChannel> actions = new HashMap<>();
90     private ChannelTypeRegistry channelTypeRegistry;
91
92     public MiIoBasicHandler(Thing thing, MiIoDatabaseWatchService miIoDatabaseWatchService,
93             ChannelTypeRegistry channelTypeRegistry) {
94         super(thing, miIoDatabaseWatchService);
95         this.channelTypeRegistry = channelTypeRegistry;
96     }
97
98     @Override
99     public void initialize() {
100         super.initialize();
101         hasChannelStructure = false;
102         isIdentified = false;
103         refreshList = new ArrayList<>();
104         refreshListCustomCommands = new HashMap<>();
105     }
106
107     @Override
108     public void handleCommand(ChannelUID channelUID, Command command) {
109         if (command == RefreshType.REFRESH) {
110             if (updateDataCache.isExpired()) {
111                 logger.debug("Refreshing {}", channelUID);
112                 updateDataCache.getValue();
113             } else {
114                 logger.debug("Refresh {} skipped. Already refreshing", channelUID);
115             }
116             return;
117         }
118         if (channelUID.getId().equals(CHANNEL_COMMAND)) {
119             cmds.put(sendCommand(command.toString()), command.toString());
120             return;
121         }
122         logger.debug("Locating action for channel '{}': '{}'", channelUID.getId(), command);
123         if (!actions.isEmpty()) {
124             if (actions.containsKey(channelUID)) {
125                 int valuePos = 0;
126                 MiIoBasicChannel miIoBasicChannel = actions.get(channelUID);
127                 for (MiIoDeviceAction action : miIoBasicChannel.getActions()) {
128                     @Nullable
129                     JsonElement value = null;
130                     JsonArray parameters = action.getParameters().deepCopy();
131                     for (int i = 0; i < action.getParameters().size(); i++) {
132                         JsonElement p = action.getParameters().get(i);
133                         if (p.isJsonPrimitive() && p.getAsString().toLowerCase().contains("$value$")) {
134                             valuePos = i;
135                             break;
136                         }
137                     }
138                     String cmd = action.getCommand();
139                     CommandParameterType paramType = action.getparameterType();
140                     if (paramType == CommandParameterType.COLOR) {
141                         if (command instanceof HSBType) {
142                             HSBType hsb = (HSBType) command;
143                             Color color = Color.getHSBColor(hsb.getHue().floatValue() / 360,
144                                     hsb.getSaturation().floatValue() / 100, hsb.getBrightness().floatValue() / 100);
145                             value = new JsonPrimitive(
146                                     (color.getRed() << 16) + (color.getGreen() << 8) + color.getBlue());
147                         } else if (command instanceof DecimalType) {
148                             // actually brightness is being set instead of a color
149                             value = new JsonPrimitive(((DecimalType) command).toBigDecimal());
150                         } else if (command instanceof OnOffType) {
151                             value = new JsonPrimitive(command == OnOffType.ON ? 100 : 0);
152                         } else {
153                             logger.debug("Unsupported command for COLOR: {}", command);
154                         }
155                     } else if (command instanceof OnOffType) {
156                         if (paramType == CommandParameterType.ONOFF) {
157                             value = new JsonPrimitive(command == OnOffType.ON ? "on" : "off");
158                         } else if (paramType == CommandParameterType.ONOFFPARA) {
159                             cmd = cmd.replace("*", command == OnOffType.ON ? "on" : "off");
160                             value = new JsonArray();
161                         } else if (paramType == CommandParameterType.ONOFFBOOL) {
162                             boolean boolCommand = command == OnOffType.ON;
163                             value = new JsonPrimitive(boolCommand);
164                         } else if (paramType == CommandParameterType.ONOFFBOOLSTRING) {
165                             value = new JsonPrimitive(command == OnOffType.ON ? "true" : "false");
166                         }
167                     } else if (command instanceof DecimalType) {
168                         value = new JsonPrimitive(((DecimalType) command).toBigDecimal());
169                     } else if (command instanceof StringType) {
170                         if (paramType == CommandParameterType.STRING) {
171                             value = new JsonPrimitive(command.toString().toLowerCase());
172                         } else if (paramType == CommandParameterType.CUSTOMSTRING) {
173                             value = new JsonPrimitive(parameters.get(valuePos).getAsString().replace("$value",
174                                     command.toString().toLowerCase()));
175                         }
176                     } else {
177                         value = new JsonPrimitive(command.toString().toLowerCase());
178                     }
179                     if (paramType == CommandParameterType.EMPTY) {
180                         value = new JsonArray();
181                     }
182                     final MiIoDeviceActionCondition miIoDeviceActionCondition = action.getCondition();
183                     if (miIoDeviceActionCondition != null) {
184                         value = ActionConditions.executeAction(miIoDeviceActionCondition, deviceVariables, value,
185                                 command);
186                     }
187                     // Check for miot channel
188                     if (value != null) {
189                         if (action.isMiOtAction()) {
190                             value = miotActionTransform(action, miIoBasicChannel, value);
191                         } else if (miIoBasicChannel.isMiOt()) {
192                             value = miotTransform(miIoBasicChannel, value);
193                         }
194                     }
195                     if (paramType != CommandParameterType.NONE && paramType != CommandParameterType.ONOFFPARA
196                             && value != null) {
197                         if (parameters.size() > 0) {
198                             parameters.set(valuePos, value);
199                         } else {
200                             parameters.add(value);
201                         }
202                     }
203                     cmd = cmd + parameters.toString();
204                     if (value != null) {
205                         logger.debug("Sending command {}", cmd);
206                         sendCommand(cmd);
207                     } else {
208                         if (miIoDeviceActionCondition != null) {
209                             logger.debug("Conditional command {} not send, condition '{}' not met", cmd,
210                                     miIoDeviceActionCondition.getName());
211                         } else {
212                             logger.debug("Command not send. Value null");
213                         }
214                     }
215                 }
216             } else {
217                 logger.debug("Channel Id {} not in mapping.", channelUID.getId());
218                 if (logger.isTraceEnabled()) {
219                     for (ChannelUID a : actions.keySet()) {
220                         logger.trace("Available entries: {} : {}", a, actions.get(a).getFriendlyName());
221                     }
222                 }
223             }
224             updateDataCache.invalidateValue();
225             scheduler.schedule(() -> {
226                 updateData();
227             }, 3000, TimeUnit.MILLISECONDS);
228         } else {
229             logger.debug("Actions not loaded yet");
230         }
231     }
232
233     private @Nullable JsonElement miotTransform(MiIoBasicChannel miIoBasicChannel, @Nullable JsonElement value) {
234         JsonObject json = new JsonObject();
235         json.addProperty("did", miIoBasicChannel.getChannel());
236         json.addProperty("siid", miIoBasicChannel.getSiid());
237         json.addProperty("piid", miIoBasicChannel.getPiid());
238         json.add("value", value);
239         return json;
240     }
241
242     private @Nullable JsonElement miotActionTransform(MiIoDeviceAction action, MiIoBasicChannel miIoBasicChannel,
243             @Nullable JsonElement value) {
244         JsonObject json = new JsonObject();
245         json.addProperty("did", miIoBasicChannel.getChannel());
246         json.addProperty("siid", action.getSiid());
247         json.addProperty("aiid", action.getAiid());
248         if (value != null) {
249             json.add("in", value);
250         }
251         return json;
252     }
253
254     @Override
255     protected synchronized void updateData() {
256         logger.debug("Periodic update for '{}' ({})", getThing().getUID().toString(), getThing().getThingTypeUID());
257         final MiIoAsyncCommunication miioCom = getConnection();
258         try {
259             if (!hasConnection() || skipUpdate() || miioCom == null) {
260                 return;
261             }
262             checkChannelStructure();
263             if (!isIdentified) {
264                 miioCom.queueCommand(MiIoCommand.MIIO_INFO);
265             }
266             final MiIoBasicDevice midevice = miioDevice;
267             if (midevice != null) {
268                 refreshProperties(midevice);
269                 refreshCustomProperties(midevice);
270                 refreshNetwork();
271             }
272         } catch (Exception e) {
273             logger.debug("Error while updating '{}': ", getThing().getUID().toString(), e);
274         }
275     }
276
277     private void refreshCustomProperties(MiIoBasicDevice midevice) {
278         for (MiIoBasicChannel miChannel : refreshListCustomCommands.values()) {
279             sendCommand(miChannel.getChannelCustomRefreshCommand());
280         }
281     }
282
283     private boolean refreshProperties(MiIoBasicDevice device) {
284         MiIoCommand command = MiIoCommand.getCommand(device.getDevice().getPropertyMethod());
285         int maxProperties = device.getDevice().getMaxProperties();
286         JsonArray getPropString = new JsonArray();
287         for (MiIoBasicChannel miChannel : refreshList) {
288             JsonElement property;
289             if (miChannel.isMiOt()) {
290                 JsonObject json = new JsonObject();
291                 json.addProperty("did", miChannel.getProperty());
292                 json.addProperty("siid", miChannel.getSiid());
293                 json.addProperty("piid", miChannel.getPiid());
294                 property = json;
295             } else {
296                 property = new JsonPrimitive(miChannel.getProperty());
297             }
298             getPropString.add(property);
299             if (getPropString.size() >= maxProperties) {
300                 sendRefreshProperties(command, getPropString);
301                 getPropString = new JsonArray();
302             }
303         }
304         if (getPropString.size() > 0) {
305             sendRefreshProperties(command, getPropString);
306         }
307         return true;
308     }
309
310     private void sendRefreshProperties(MiIoCommand command, JsonArray getPropString) {
311         try {
312             final MiIoAsyncCommunication miioCom = this.miioCom;
313             if (miioCom != null) {
314                 miioCom.queueCommand(command, getPropString.toString());
315             }
316         } catch (MiIoCryptoException | IOException e) {
317             logger.debug("Send refresh failed {}", e.getMessage(), e);
318         }
319     }
320
321     /**
322      * Checks if the channel structure has been build already based on the model data. If not build it.
323      */
324     private void checkChannelStructure() {
325         final MiIoBindingConfiguration configuration = this.configuration;
326         if (configuration == null) {
327             return;
328         }
329         if (!hasChannelStructure) {
330             if (configuration.model == null || configuration.model.isEmpty()) {
331                 logger.debug("Model needs to be determined");
332                 isIdentified = false;
333             } else {
334                 hasChannelStructure = buildChannelStructure(configuration.model);
335             }
336         }
337         if (hasChannelStructure) {
338             refreshList = new ArrayList<>();
339             final MiIoBasicDevice miioDevice = this.miioDevice;
340             if (miioDevice != null) {
341                 for (MiIoBasicChannel miChannel : miioDevice.getDevice().getChannels()) {
342                     if (miChannel.getRefresh()) {
343                         if (miChannel.getChannelCustomRefreshCommand().isBlank()) {
344                             refreshList.add(miChannel);
345                         } else {
346                             String i = miChannel.getChannelCustomRefreshCommand().split("\\[")[0];
347                             refreshListCustomCommands.put(i.trim(), miChannel);
348                         }
349                     }
350                 }
351             }
352
353         }
354     }
355
356     private boolean buildChannelStructure(String deviceName) {
357         logger.debug("Building Channel Structure for {} - Model: {}", getThing().getUID().toString(), deviceName);
358         URL fn = miIoDatabaseWatchService.getDatabaseUrl(deviceName);
359         if (fn == null) {
360             logger.warn("Database entry for model '{}' cannot be found.", deviceName);
361             return false;
362         }
363         try {
364             JsonObject deviceMapping = Utils.convertFileToJSON(fn);
365             logger.debug("Using device database: {} for device {}", fn.getFile(), deviceName);
366             Gson gson = new GsonBuilder().serializeNulls().create();
367             miioDevice = gson.fromJson(deviceMapping, MiIoBasicDevice.class);
368             for (Channel ch : getThing().getChannels()) {
369                 logger.debug("Current thing channels {}, type: {}", ch.getUID(), ch.getChannelTypeUID());
370             }
371             ThingBuilder thingBuilder = editThing();
372             int channelsAdded = 0;
373
374             // make a map of the actions
375             actions = new HashMap<>();
376             final MiIoBasicDevice device = this.miioDevice;
377             if (device != null) {
378                 for (MiIoBasicChannel miChannel : device.getDevice().getChannels()) {
379                     logger.debug("properties {}", miChannel);
380                     if (!miChannel.getType().isEmpty()) {
381                         ChannelUID channelUID = addChannel(thingBuilder, miChannel.getChannel(),
382                                 miChannel.getChannelType(), miChannel.getType(), miChannel.getFriendlyName());
383                         if (channelUID != null) {
384                             actions.put(channelUID, miChannel);
385                             channelsAdded++;
386                         } else {
387                             logger.debug("Channel for {} ({}) not loaded", miChannel.getChannel(),
388                                     miChannel.getFriendlyName());
389                         }
390                     } else {
391                         logger.debug("Channel {} ({}), not loaded, missing type", miChannel.getChannel(),
392                                 miChannel.getFriendlyName());
393                     }
394                 }
395             }
396             // only update if channels were added/removed
397             if (channelsAdded > 0) {
398                 logger.debug("Current thing channels added: {}", channelsAdded);
399                 updateThing(thingBuilder.build());
400             }
401             return true;
402         } catch (JsonIOException | JsonSyntaxException e) {
403             logger.warn("Error parsing database Json", e);
404         } catch (IOException e) {
405             logger.warn("Error reading database file", e);
406         } catch (Exception e) {
407             logger.warn("Error creating channel structure", e);
408         }
409         return false;
410     }
411
412     private @Nullable ChannelUID addChannel(ThingBuilder thingBuilder, @Nullable String channel, String channelType,
413             @Nullable String datatype, String friendlyName) {
414         if (channel == null || channel.isEmpty() || datatype == null || datatype.isEmpty()) {
415             logger.info("Channel '{}', UID '{}' cannot be added incorrectly configured database. ", channel,
416                     getThing().getUID());
417             return null;
418         }
419         ChannelUID channelUID = new ChannelUID(getThing().getUID(), channel);
420
421         // TODO: Need to understand if this harms anything. If yes, channel only to be added when not there already.
422         // current way allows to have no issues when channels are changing.
423         if (getThing().getChannel(channel) != null) {
424             logger.info("Channel '{}' for thing {} already exist... removing", channel, getThing().getUID());
425             thingBuilder.withoutChannel(new ChannelUID(getThing().getUID(), channel));
426         }
427         ChannelBuilder newChannel = ChannelBuilder.create(channelUID, datatype).withLabel(friendlyName);
428         if (!channelType.isBlank()) {
429             ChannelTypeUID channelTypeUID = new ChannelTypeUID(channelType);
430             if (channelTypeRegistry.getChannelType(channelTypeUID) != null) {
431                 newChannel = newChannel.withType(channelTypeUID);
432             } else {
433                 logger.debug("ChannelType '{}' is not available. Check the Json file for {}", channelTypeUID,
434                         getThing().getUID());
435             }
436         }
437         thingBuilder.withChannel(newChannel.build());
438         return channelUID;
439     }
440
441     private @Nullable MiIoBasicChannel getChannel(String parameter) {
442         for (MiIoBasicChannel refreshEntry : refreshList) {
443             if (refreshEntry.getProperty().equals(parameter)) {
444                 return refreshEntry;
445             }
446         }
447         logger.trace("Did not find channel for {} in {}", parameter, refreshList);
448         return null;
449     }
450
451     private void updatePropsFromJsonArray(MiIoSendCommand response) {
452         JsonArray res = response.getResult().getAsJsonArray();
453         JsonArray para = parser.parse(response.getCommandString()).getAsJsonObject().get("params").getAsJsonArray();
454         if (res.size() != para.size()) {
455             logger.debug("Unexpected size different. Request size {},  response size {}. (Req: {}, Resp:{})",
456                     para.size(), res.size(), para, res);
457             return;
458         }
459         for (int i = 0; i < para.size(); i++) {
460             // This is a miot parameter
461             String param;
462             final JsonElement paraElement = para.get(i);
463             if (paraElement.isJsonObject()) { // miot channel
464                 param = paraElement.getAsJsonObject().get("did").getAsString();
465             } else {
466                 param = paraElement.getAsString();
467             }
468             JsonElement val = res.get(i);
469             if (val.isJsonNull()) {
470                 logger.debug("Property '{}' returned null (is it supported?).", param);
471                 continue;
472             } else if (val.isJsonObject()) { // miot channel
473                 val = val.getAsJsonObject().get("value");
474             }
475             MiIoBasicChannel basicChannel = getChannel(param);
476             updateChannel(basicChannel, param, val);
477         }
478     }
479
480     private void updatePropsFromJsonObject(MiIoSendCommand response) {
481         JsonObject res = response.getResult().getAsJsonObject();
482         for (Object k : res.keySet()) {
483             String param = (String) k;
484             JsonElement val = res.get(param);
485             if (val.isJsonNull()) {
486                 logger.debug("Property '{}' returned null (is it supported?).", param);
487                 continue;
488             }
489             MiIoBasicChannel basicChannel = getChannel(param);
490             updateChannel(basicChannel, param, val);
491         }
492     }
493
494     private void updateChannel(@Nullable MiIoBasicChannel basicChannel, String param, JsonElement value) {
495         JsonElement val = value;
496         if (basicChannel == null) {
497             logger.debug("Channel not found for {}", param);
498             return;
499         }
500         final String transformation = basicChannel.getTransfortmation();
501         if (transformation != null) {
502             JsonElement transformed = Conversions.execute(transformation, val);
503             logger.debug("Transformed with '{}': {} {} -> {} ", transformation, basicChannel.getFriendlyName(), val,
504                     transformed);
505             val = transformed;
506         }
507         try {
508             switch (basicChannel.getType().toLowerCase()) {
509                 case "number":
510                     updateState(basicChannel.getChannel(), new DecimalType(val.getAsBigDecimal()));
511                     break;
512                 case "dimmer":
513                     updateState(basicChannel.getChannel(), new PercentType(val.getAsBigDecimal()));
514                     break;
515                 case "string":
516                     updateState(basicChannel.getChannel(), new StringType(val.getAsString()));
517                     break;
518                 case "switch":
519                     updateState(basicChannel.getChannel(), val.getAsString().toLowerCase().equals("on")
520                             || val.getAsString().toLowerCase().equals("true") ? OnOffType.ON : OnOffType.OFF);
521                     break;
522                 case "color":
523                     Color rgb = new Color(val.getAsInt());
524                     HSBType hsb = HSBType.fromRGB(rgb.getRed(), rgb.getGreen(), rgb.getBlue());
525                     updateState(basicChannel.getChannel(), hsb);
526                     break;
527                 default:
528                     logger.debug("No update logic for channeltype '{}' ", basicChannel.getType());
529             }
530         } catch (Exception e) {
531             logger.debug("Error updating {} property {} with '{}' : {}: {}", getThing().getUID(),
532                     basicChannel.getChannel(), val, e.getClass().getCanonicalName(), e.getMessage());
533             logger.trace("Property update error detail:", e);
534         }
535     }
536
537     @Override
538     public void onMessageReceived(MiIoSendCommand response) {
539         super.onMessageReceived(response);
540         if (response.isError()) {
541             return;
542         }
543         try {
544             switch (response.getCommand()) {
545                 case MIIO_INFO:
546                     break;
547                 case GET_VALUE:
548                 case GET_PROPERTIES:
549                 case GET_PROPERTY:
550                     if (response.getResult().isJsonArray()) {
551                         updatePropsFromJsonArray(response);
552                     } else if (response.getResult().isJsonObject()) {
553                         updatePropsFromJsonObject(response);
554                     }
555                     break;
556                 default:
557                     if (refreshListCustomCommands.containsKey(response.getMethod())) {
558                         logger.debug("Processing custom refresh command response for !{}", response.getMethod());
559                         MiIoBasicChannel ch = refreshListCustomCommands.get(response.getMethod());
560                         if (response.getResult().isJsonArray()) {
561                             JsonArray cmdResponse = response.getResult().getAsJsonArray();
562                             final String transformation = ch.getTransfortmation();
563                             if (transformation == null || transformation.isBlank()) {
564                                 updateChannel(ch, ch.getChannel(),
565                                         cmdResponse.get(0).isJsonPrimitive() ? cmdResponse.get(0)
566                                                 : new JsonPrimitive(cmdResponse.get(0).toString()));
567                             } else {
568                                 updateChannel(ch, ch.getChannel(), cmdResponse);
569                             }
570                         } else {
571                             updateChannel(ch, ch.getChannel(), new JsonPrimitive(response.getResult().toString()));
572                         }
573                     }
574                     break;
575             }
576         } catch (Exception e) {
577             logger.debug("Error while handing message {}", response.getResponse(), e);
578         }
579     }
580 }