]> git.basschouten.com Git - openhab-addons.git/commitdiff
[miio] change deviceID to Xiaomi used string (#10951)
authorMarcel <marcel@verpaalen.com>
Tue, 6 Jul 2021 17:42:42 +0000 (19:42 +0200)
committerGitHub <noreply@github.com>
Tue, 6 Jul 2021 17:42:42 +0000 (19:42 +0200)
* [miio] change deviceID to Xiaomi used string

Change the deviceId from the current hexadecimal to the string used by
Xiaomi.
This is needed as we have some devices that have deviceIds that are
non-numeric, hence breaking the current logic.

Note: separately removing the upnp discovery as this has become
irrelevant with cloud discovery and devices supporting the udp regular
discovery.

Signed-off-by: Marcel Verpaalen <marcel@verpaalen.com>
* Update bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoAbstractHandler.java

Signed-off-by: Fabian Wolter <github@fabian-wolter.de>
Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
bundles/org.openhab.binding.miio/README.base.md
bundles/org.openhab.binding.miio/README.md
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/Utils.java
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/CloudConnector.java
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/discovery/MiIoDiscovery.java
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/discovery/MiIoDiscoveryParticipant.java [deleted file]
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoAbstractHandler.java
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/transport/MiIoAsyncCommunication.java

index dc998c7e772236afff69d6ca790ae41c0355b516..ec6771736d597b7b4f7a66c7243b44b0b827cd70 100644 (file)
@@ -76,7 +76,7 @@ However, for devices that are unsupported, you may override the value and try to
 |-----------------|---------|----------|---------------------------------------------------------------------|
 | host            | text    | true     | Device IP address                                                   |
 | token           | text    | true     | Token for communication (in Hex)                                    |
-| deviceId        | text    | true     | Device ID number for communication (in Hex)                         |
+| deviceId        | text    | true     | Device Id (typically a number for normal devices) for communication |
 | model           | text    | false    | Device model string, used to determine the subtype                  |
 | refreshInterval | integer | false    | Refresh interval for refreshing the data in seconds. (0=disabled)   |
 | timeout         | integer | false    | Timeout time in milliseconds                                        |
@@ -86,11 +86,11 @@ Note: Suggest to use the cloud communication only for devices that require it. I
 
 ### Example Thing file
 
-`Thing miio:basic:light "My Light" [ host="192.168.x.x", token="put here your token", deviceId="0326xxxx", model="philips.light.bulb", communication="direct"  ]` 
+`Thing miio:basic:light "My Light" [ host="192.168.x.x", token="put here your token", deviceId="326xxxx", model="philips.light.bulb", communication="direct" ]` 
 
 or in case of unknown models include the model information of a similar device that is supported:
 
-`Thing miio:vacuum:s50 "vacuum" @ "livingroom" [ host="192.168.15.20", token="xxxxxxx", deviceId=“0470DDAA”, model="roborock.vacuum.s4", communication="cloud"]`
+`Thing miio:vacuum:s50 "vacuum" @ "livingroom" [ host="192.168.15.20", token="xxxxxxx", deviceId="326xxxx", model="roborock.vacuum.s4", communication="direct" ]`
 
 # Advanced: Unsupported devices
 
index 13af3ae7186bdaf52826d2b31b110b56b39c210c..75b2dd26b6f02f56656f47ba97399630fe6c47aa 100644 (file)
@@ -76,7 +76,7 @@ However, for devices that are unsupported, you may override the value and try to
 |-----------------|---------|----------|---------------------------------------------------------------------|
 | host            | text    | true     | Device IP address                                                   |
 | token           | text    | true     | Token for communication (in Hex)                                    |
-| deviceId        | text    | true     | Device ID number for communication (in Hex)                         |
+| deviceId        | text    | true     | Device Id (typically a number for normal devices) for communication |
 | model           | text    | false    | Device model string, used to determine the subtype                  |
 | refreshInterval | integer | false    | Refresh interval for refreshing the data in seconds. (0=disabled)   |
 | timeout         | integer | false    | Timeout time in milliseconds                                        |
@@ -86,11 +86,11 @@ Note: Suggest to use the cloud communication only for devices that require it. I
 
 ### Example Thing file
 
-`Thing miio:basic:light "My Light" [ host="192.168.x.x", token="put here your token", deviceId="0326xxxx", model="philips.light.bulb", communication="direct"  ]` 
+`Thing miio:basic:light "My Light" [ host="192.168.x.x", token="put here your token", deviceId="326xxxx", model="philips.light.bulb", communication="direct" ]` 
 
 or in case of unknown models include the model information of a similar device that is supported:
 
-`Thing miio:vacuum:s50 "vacuum" @ "livingroom" [ host="192.168.15.20", token="xxxxxxx", deviceId=“0470DDAA”, model="roborock.vacuum.s4", communication="cloud"]`
+`Thing miio:vacuum:s50 "vacuum" @ "livingroom" [ host="192.168.15.20", token="xxxxxxx", deviceId="326xxxx", model="roborock.vacuum.s4", communication="direct" ]`
 
 # Advanced: Unsupported devices
 
index 00d141f628b4a73fb3faac9719844ea6d113b151..bb7ec557cce7316d68fbf8cb9367119c4aae8c6f 100644 (file)
@@ -127,4 +127,17 @@ public final class Utils {
         }
         return value;
     }
+
+    /**
+     * Formats the deviceId to a hex string if possible. Otherwise returns the id unmodified.
+     *
+     * @param did
+     * @return did
+     */
+    public static String getHexId(String did) {
+        if (!did.isBlank() && !did.contains(".")) {
+            return toHEX(did);
+        }
+        return did;
+    }
 }
index a64dfae41a9dd86a7ec547492b16778a4f3e2554..9e974d7991448ff1db913233c1b438fe39dcaba6 100644 (file)
@@ -208,10 +208,9 @@ public class CloudConnector {
         if (deviceListState != DeviceListState.AVAILABLE) {
             return null;
         }
-        String did = Long.toString(Long.parseUnsignedLong(id, 16));
         List<CloudDeviceDTO> devicedata = new ArrayList<>();
         for (CloudDeviceDTO deviceDetails : deviceList) {
-            if (deviceDetails.getDid().contentEquals(did)) {
+            if (deviceDetails.getDid().contentEquals(id)) {
                 devicedata.add(deviceDetails);
             }
         }
index 491766eec3243cffa00f368d76eaee28898576aa..66ddd15d51c13d0b7521f7fc3d2bc9d076b6cb17 100644 (file)
@@ -184,7 +184,7 @@ public class MiIoDiscovery extends AbstractDiscoveryService {
         if (cloudConnector.isConnected()) {
             List<CloudDeviceDTO> dv = cloudConnector.getDevicesList();
             for (CloudDeviceDTO device : dv) {
-                String id = Utils.toHEX(device.getDid());
+                String id = device.getDid();
                 if (cloudDiscoveryMode.contentEquals(SUPPORTED)) {
                     if (MiIoDevices.getType(device.getModel()).getThingType().equals(THING_TYPE_UNSUPPORTED)) {
                         logger.warn("Discovered from cloud, but ignored because not supported: {} {}", id, device);
@@ -194,7 +194,7 @@ public class MiIoDiscovery extends AbstractDiscoveryService {
                     logger.debug("Discovered from cloud: {} {}", id, device);
                     cloudDevices.put(id, device.getLocalip());
                     String token = device.getToken();
-                    String label = device.getName() + " " + id + " (" + device.getDid() + ")";
+                    String label = device.getName() + " " + id + " (" + Utils.getHexId(id) + ")";
                     String country = device.getServer();
                     boolean isOnline = device.getIsOnline();
                     String ip = device.getLocalip();
@@ -210,8 +210,9 @@ public class MiIoDiscovery extends AbstractDiscoveryService {
         logger.trace("Discovery responses from : {}:{}", ip, Utils.getSpacedHex(response));
         Message msg = new Message(response);
         String token = Utils.getHex(msg.getChecksum());
-        String id = Utils.getHex(msg.getDeviceId());
-        String label = "Xiaomi Mi Device " + id + " (" + Utils.fromHEX(id) + ")";
+        String hexId = Utils.getHex(msg.getDeviceId());
+        String id = Utils.fromHEX(hexId);
+        String label = "Xiaomi Mi Device " + id + " (" + Utils.getHexId(id) + ")";
         String country = "";
         boolean isOnline = false;
         if (ip.equals(cloudDevices.get(id))) {
@@ -224,7 +225,7 @@ public class MiIoDiscovery extends AbstractDiscoveryService {
             if (cloudInfo != null) {
                 logger.debug("Cloud Info: {}", cloudInfo);
                 token = cloudInfo.getToken();
-                label = cloudInfo.getName() + " " + id + " (" + Utils.fromHEX(id) + ")";
+                label = cloudInfo.getName() + " " + id + " (" + Utils.getHexId(id) + ")";
                 country = cloudInfo.getServer();
                 isOnline = cloudInfo.getIsOnline();
             }
@@ -233,17 +234,17 @@ public class MiIoDiscovery extends AbstractDiscoveryService {
     }
 
     private void submitDiscovery(String ip, String token, String id, String label, String country, boolean isOnline) {
-        ThingUID uid = new ThingUID(THING_TYPE_MIIO, id.replace(".", "_"));
+        ThingUID uid = new ThingUID(THING_TYPE_MIIO, Utils.getHexId(id).replace(".", "_"));
         DiscoveryResultBuilder dr = DiscoveryResultBuilder.create(uid).withProperty(PROPERTY_HOST_IP, ip)
                 .withProperty(PROPERTY_DID, id);
         if (IGNORED_TOKENS.contains(token)) {
-            logger.debug("Discovered Mi Device {} ({}) at {} as {}", id, Utils.fromHEX(id), ip, uid);
+            logger.debug("Discovered Mi Device {} ({}) at {} as {}", id, Utils.getHexId(id), ip, uid);
             logger.debug(
                     "No token discovered for device {}. For options how to get the token, check the binding readme.",
                     id);
             dr = dr.withRepresentationProperty(PROPERTY_DID).withLabel(label);
         } else {
-            logger.debug("Discovered Mi Device {} ({}) at {} as {} with token {}", id, Utils.fromHEX(id), ip, uid,
+            logger.debug("Discovered Mi Device {} ({}) at {} as {} with token {}", id, Utils.getHexId(id), ip, uid,
                     token);
             dr = dr.withProperty(PROPERTY_TOKEN, token).withRepresentationProperty(PROPERTY_DID)
                     .withLabel(label + " with token");
diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/discovery/MiIoDiscoveryParticipant.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/discovery/MiIoDiscoveryParticipant.java
deleted file mode 100644 (file)
index cd9a8c6..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.miio.internal.discovery;
-
-import static org.openhab.binding.miio.internal.MiIoBindingConstants.*;
-
-import java.net.InetAddress;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import javax.jmdns.ServiceInfo;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.binding.miio.internal.MiIoDevices;
-import org.openhab.binding.miio.internal.cloud.CloudConnector;
-import org.openhab.binding.miio.internal.cloud.CloudDeviceDTO;
-import org.openhab.core.config.discovery.DiscoveryResult;
-import org.openhab.core.config.discovery.DiscoveryResultBuilder;
-import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant;
-import org.openhab.core.thing.ThingTypeUID;
-import org.openhab.core.thing.ThingUID;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Reference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Discovers Mi IO devices announced by mDNS
- *
- * @author Marcel Verpaalen - Initial contribution
- *
- */
-@NonNullByDefault
-@Component(service = MDNSDiscoveryParticipant.class)
-public class MiIoDiscoveryParticipant implements MDNSDiscoveryParticipant {
-
-    private final CloudConnector cloudConnector;
-    private Logger logger = LoggerFactory.getLogger(MiIoDiscoveryParticipant.class);
-
-    @Activate
-    public MiIoDiscoveryParticipant(@Reference CloudConnector cloudConnector) {
-        this.cloudConnector = cloudConnector;
-        logger.debug("Start Xiaomi Mi IO mDNS discovery");
-    }
-
-    @Override
-    public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
-        return (NONGENERIC_THING_TYPES_UIDS);
-    }
-
-    @Override
-    public String getServiceType() {
-        return "_miio._udp.local.";
-    }
-
-    @Override
-    public @Nullable ThingUID getThingUID(@Nullable ServiceInfo service) {
-        if (service == null) {
-            return null;
-        }
-        logger.trace("ServiceInfo: {}", service);
-        String id[] = service.getName().split("_miio");
-        if (id.length != 2) {
-            logger.trace("mDNS Could not identify Type / Device Id from '{}'", service.getName());
-            return null;
-        }
-        long did;
-        try {
-            did = Long.parseUnsignedLong(id[1]);
-        } catch (Exception e) {
-            logger.trace("mDNS Could not identify Device ID from '{}'", id[1]);
-            return null;
-        }
-        ThingTypeUID thingType = MiIoDevices.getType(id[0].replaceAll("-", ".")).getThingType();
-        String uidName = String.format("%08X", did);
-        logger.debug("mDNS {} identified as thingtype {} with did {} ({})", id[0], thingType, uidName, did);
-        return new ThingUID(thingType, uidName);
-    }
-
-    private @Nullable InetAddress getIpAddress(ServiceInfo service) {
-        InetAddress address = null;
-        for (InetAddress addr : service.getInet4Addresses()) {
-            return addr;
-        }
-        // Fallback for Inet6addresses
-        for (InetAddress addr : service.getInet6Addresses()) {
-            return addr;
-        }
-        return address;
-    }
-
-    @Override
-    public @Nullable DiscoveryResult createResult(ServiceInfo service) {
-        DiscoveryResult result = null;
-        ThingUID uid = getThingUID(service);
-        if (uid != null) {
-            Map<String, Object> properties = new HashMap<>(2);
-            // remove the domain from the name
-            InetAddress ip = getIpAddress(service);
-            if (ip == null) {
-                logger.debug("Mi IO mDNS Discovery could not determine ip address from service info: {}", service);
-                return null;
-            }
-            String inetAddress = ip.toString().substring(1); // trim leading slash
-            String id = uid.getId();
-            String label = "Xiaomi Mi Device " + id + " (" + Long.parseUnsignedLong(id, 16) + ") " + service.getName();
-            if (cloudConnector.isConnected()) {
-                cloudConnector.getDevicesList();
-                CloudDeviceDTO cloudInfo = cloudConnector.getDeviceInfo(id);
-                if (cloudInfo != null) {
-                    logger.debug("Cloud Info: {}", cloudInfo);
-                    properties.put(PROPERTY_TOKEN, cloudInfo.getToken());
-                    label = label + " with token";
-                    String country = cloudInfo.getServer();
-                    if (!country.isEmpty() && cloudInfo.getIsOnline()) {
-                        properties.put(PROPERTY_CLOUDSERVER, country);
-                    }
-                }
-            }
-            properties.put(PROPERTY_HOST_IP, inetAddress);
-            properties.put(PROPERTY_DID, id);
-            result = DiscoveryResultBuilder.create(uid).withProperties(properties)
-                    .withRepresentationProperty(PROPERTY_DID).withLabel(label).build();
-            logger.debug("Mi IO mDNS Discovery found {} with address '{}:{}' name '{}'", uid, inetAddress,
-                    service.getPort(), label);
-        }
-        return result;
-    }
-}
index 21df3ea3625ef4a13667286117e0c0fc0ca14430..b14d6ddaa1e4480463f8d554238fb0fb2cb8d9f7 100644 (file)
@@ -351,16 +351,21 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi
         }
         @Nullable
         String deviceId = configuration.deviceId;
+        if (deviceId.length() == 8 && deviceId.matches("^.*[a-zA-Z]+.*$")) {
+            logger.warn(
+                    "As per openHAB version 3.2 the deviceId is no longer a string with hexadecimals, instead it is a string with the numeric respresentation of the deviceId. If you continue seeing this message, update deviceId in your thing configuration");
+            deviceId = "";
+        }
         try {
-            if (deviceId.length() == 8 && tokenCheckPass(configuration.token)) {
-                final MiIoAsyncCommunication miioCom = new MiIoAsyncCommunication(configuration.host, token,
-                        Utils.hexStringToByteArray(deviceId), lastId, configuration.timeout, cloudConnector);
+            if (!deviceId.isBlank() && tokenCheckPass(configuration.token)) {
+                final MiIoAsyncCommunication miioCom = new MiIoAsyncCommunication(configuration.host, token, deviceId,
+                        lastId, configuration.timeout, cloudConnector);
                 if (getCloudServer().isBlank()) {
-                    logger.debug("Ping Mi device {} at {}", deviceId, configuration.host);
+                    logger.debug("Ping Mi deviceId '{}' at {}", deviceId, configuration.host);
                     Message miIoResponse = miioCom.sendPing(configuration.host);
                     if (miIoResponse != null) {
-                        logger.debug("Ping response from device {} at {}. Time stamp: {}, OH time {}, delta {}",
-                                Utils.getHex(miIoResponse.getDeviceId()), configuration.host,
+                        logger.debug("Ping response from deviceId '{}' at {}. Time stamp: {}, OH time {}, delta {}",
+                                Utils.fromHEX(Utils.getHex(miIoResponse.getDeviceId())), configuration.host,
                                 miIoResponse.getTimestamp(), LocalDateTime.now(), miioCom.getTimeDelta());
                         miioCom.registerListener(this);
                         this.miioCom = miioCom;
@@ -374,20 +379,17 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi
                     return miioCom;
                 }
             } else {
-                logger.debug("No device ID defined. Retrieving Mi device ID");
-                final MiIoAsyncCommunication miioCom = new MiIoAsyncCommunication(configuration.host, token,
-                        new byte[0], lastId, configuration.timeout, cloudConnector);
+                logger.debug("No deviceId defined. Retrieving Mi deviceId");
+                final MiIoAsyncCommunication miioCom = new MiIoAsyncCommunication(configuration.host, token, "", lastId,
+                        configuration.timeout, cloudConnector);
                 Message miIoResponse = miioCom.sendPing(configuration.host);
                 if (miIoResponse != null) {
-                    logger.debug("Ping response from device {} at {}. Time stamp: {}, OH time {}, delta {}",
-                            Utils.getHex(miIoResponse.getDeviceId()), configuration.host, miIoResponse.getTimestamp(),
-                            LocalDateTime.now(), miioCom.getTimeDelta());
-                    deviceId = Utils.getHex(miIoResponse.getDeviceId());
-                    logger.debug("Ping response from device {} at {}. Time stamp: {}, OH time {}, delta {}", deviceId,
-                            configuration.host, miIoResponse.getTimestamp(), LocalDateTime.now(),
+                    deviceId = Utils.fromHEX(Utils.getHex(miIoResponse.getDeviceId()));
+                    logger.debug("Ping response from deviceId '{}' at {}. Time stamp: {}, OH time {}, delta {}",
+                            deviceId, configuration.host, miIoResponse.getTimestamp(), LocalDateTime.now(),
                             miioCom.getTimeDelta());
-                    miioCom.setDeviceId(miIoResponse.getDeviceId());
-                    logger.debug("Using retrieved Mi device ID: {}", deviceId);
+                    miioCom.setDeviceId(deviceId);
+                    logger.debug("Using retrieved Mi deviceId: {}", deviceId);
                     updateDeviceIdConfig(deviceId);
                     miioCom.registerListener(this);
                     this.miioCom = miioCom;
@@ -396,7 +398,7 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi
                     miioCom.close();
                 }
             }
-            logger.debug("Ping response from device {} at {} FAILED", configuration.deviceId, configuration.host);
+            logger.debug("Ping response from deviceId '{}' at {} FAILED", configuration.deviceId, configuration.host);
             disconnectedNoResponse();
             return null;
         } catch (IOException e) {
@@ -413,7 +415,7 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi
             config.put(PROPERTY_DID, deviceId);
             updateConfiguration(config);
         } else {
-            logger.debug("Could not update config with device ID: {}", deviceId);
+            logger.debug("Could not update config with deviceId: {}", deviceId);
         }
     }
 
@@ -529,10 +531,11 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi
 
     @Override
     public void onMessageReceived(MiIoSendCommand response) {
-        logger.debug("Received response for {} type: {}, result: {}, fullresponse: {}", getThing().getUID().getId(),
-                response.getCommand(), response.getResult(), response.getResponse());
+        logger.debug("Received response for device {} type: {}, result: {}, fullresponse: {}",
+                getThing().getUID().getId(), response.getCommand(), response.getResult(), response.getResponse());
         if (response.isError()) {
-            logger.debug("Error received: {}", response.getResponse().get("error"));
+            logger.debug("Error received for command '{}': {}.", response.getCommandString(),
+                    response.getResponse().get("error"));
             if (MiIoCommand.MIIO_INFO.equals(response.getCommand())) {
                 network.invalidateValue();
             }
index f4ebe2ce2739bcf81d994a9f7de8fcf9d75987bd..bc0335865e21e6b66c01ec05464ec26c017af058 100644 (file)
@@ -65,7 +65,7 @@ public class MiIoAsyncCommunication {
 
     private final String ip;
     private final byte[] token;
-    private byte[] deviceId;
+    private String deviceId;
     private @Nullable DatagramSocket socket;
 
     private List<MiIoMessageListener> listeners = new CopyOnWriteArrayList<>();
@@ -85,7 +85,7 @@ public class MiIoAsyncCommunication {
 
     private ConcurrentLinkedQueue<MiIoSendCommand> concurrentLinkedQueue = new ConcurrentLinkedQueue<>();
 
-    public MiIoAsyncCommunication(String ip, byte[] token, byte[] did, int id, int timeout,
+    public MiIoAsyncCommunication(String ip, byte[] token, String did, int id, int timeout,
             CloudConnector cloudConnector) {
         this.ip = ip;
         this.token = token;
@@ -156,7 +156,7 @@ public class MiIoAsyncCommunication {
                 // Obfuscate part of the token to allow sharing of the logfiles
                 String tokenText = Utils.obfuscateToken(Utils.getHex(token));
                 logger.debug("Command added to Queue {} -> {} (Device: {} token: {} Queue: {}).{}{}",
-                        fullCommand.toString(), ip, Utils.getHex(deviceId), tokenText, concurrentLinkedQueue.size(),
+                        fullCommand.toString(), ip, deviceId, tokenText, concurrentLinkedQueue.size(),
                         cloudServer.isBlank() ? "" : " Send via cloudserver: ", cloudServer);
             }
             if (needPing && cloudServer.isBlank()) {
@@ -165,7 +165,7 @@ public class MiIoAsyncCommunication {
             return cmdId;
         } catch (JsonSyntaxException e) {
             logger.warn("Send command '{}' with parameters {} -> {} (Device: {}) gave error {}", command, params, ip,
-                    Utils.getHex(deviceId), e.getMessage());
+                    deviceId, e.getMessage());
             throw e;
         }
     }
@@ -177,7 +177,7 @@ public class MiIoAsyncCommunication {
             if (miIoSendCommand.getCloudServer().isBlank()) {
                 decryptedResponse = sendCommand(miIoSendCommand.getCommandString(), token, ip, deviceId);
             } else {
-                decryptedResponse = cloudConnector.sendRPCCommand(Utils.getHex(deviceId),
+                decryptedResponse = cloudConnector.sendRPCCommand(Utils.getHexId(deviceId),
                         miIoSendCommand.getCloudServer(), miIoSendCommand);
                 logger.debug("Command {} send via cloudserver {}", miIoSendCommand.getCommandString(),
                         miIoSendCommand.getCloudServer());
@@ -216,16 +216,15 @@ public class MiIoAsyncCommunication {
             logger.debug("{}: {}", errorMsg, decryptedResponse);
         } catch (MiIoCryptoException | IOException e) {
             logger.debug("Send command '{}'  -> {} (Device: {}) gave error {}", miIoSendCommand.getCommandString(), ip,
-                    Utils.getHex(deviceId), e.getMessage());
+                    deviceId, e.getMessage());
             errorMsg = e.getMessage();
         } catch (JsonSyntaxException e) {
             logger.warn("Could not parse '{}' <- {} (Device: {}) gave error {}", decryptedResponse,
-                    miIoSendCommand.getCommandString(), Utils.getHex(deviceId), e.getMessage());
+                    miIoSendCommand.getCommandString(), deviceId, e.getMessage());
             errorMsg = "Received message is invalid JSON";
         } catch (MiCloudException e) {
             logger.debug("Send command '{}'  -> cloudserver '{}' (Device: {}) gave error {}",
-                    miIoSendCommand.getCommandString(), miIoSendCommand.getCloudServer(), Utils.getHex(deviceId),
-                    e.getMessage());
+                    miIoSendCommand.getCommandString(), miIoSendCommand.getCloudServer(), deviceId, e.getMessage());
             errorMsg = e.getMessage();
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
         }
@@ -288,22 +287,23 @@ public class MiIoAsyncCommunication {
         }
     }
 
-    private String sendCommand(String command, byte[] token, String ip, byte[] deviceId)
+    private String sendCommand(String command, byte[] token, String ip, String deviceId)
             throws MiIoCryptoException, IOException {
         byte[] sendMsg = new byte[0];
         if (!command.isBlank()) {
             byte[] encr;
             encr = MiIoCrypto.encrypt(command.getBytes(StandardCharsets.UTF_8), token);
             timeStamp = (int) Instant.now().getEpochSecond();
-            sendMsg = Message.createMsgData(encr, token, deviceId, timeStamp + timeDelta);
+            sendMsg = Message.createMsgData(encr, token, Utils.hexStringToByteArray(Utils.getHexId(deviceId)),
+                    timeStamp + timeDelta);
         }
         Message miIoResponseMsg = sendData(sendMsg, ip);
         if (miIoResponseMsg == null) {
             if (logger.isTraceEnabled()) {
-                logger.trace("No response from device {} at {} for command {}.\r\n{}", Utils.getHex(deviceId), ip,
-                        command, (new Message(sendMsg)).toSting());
+                logger.trace("No response from device {} at {} for command {}.\r\n{}", deviceId, ip, command,
+                        (new Message(sendMsg)).toSting());
             } else {
-                logger.debug("No response from device {} at {} for command {}.", Utils.getHex(deviceId), ip, command);
+                logger.debug("No response from device {} at {} for command {}.", deviceId, ip, command);
             }
             errorCounter++;
             if (errorCounter > MAX_ERRORS) {
@@ -330,7 +330,7 @@ public class MiIoAsyncCommunication {
 
     public @Nullable Message sendPing(String ip) throws IOException {
         for (int i = 0; i < 3; i++) {
-            logger.debug("Sending Ping {} ({})", Utils.getHex(deviceId), ip);
+            logger.debug("Sending Ping to device '{}' ({})", deviceId, ip);
             Message resp = sendData(MiIoBindingConstants.DISCOVER_STRING, ip);
             if (resp != null) {
                 pingSuccess();
@@ -342,14 +342,14 @@ public class MiIoAsyncCommunication {
     }
 
     private void pingFail() {
-        logger.debug("Ping {} ({}) failed", Utils.getHex(deviceId), ip);
+        logger.debug("Ping to device '{}' ({}) failed", deviceId, ip);
         connected = false;
         status = ThingStatusDetail.COMMUNICATION_ERROR;
         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
     }
 
     private void pingSuccess() {
-        logger.debug("Ping {} ({}) success", Utils.getHex(deviceId), ip);
+        logger.debug("Ping to device '{}' ({}) success", deviceId, ip);
         if (!connected) {
             connected = true;
             status = ThingStatusDetail.NONE;
@@ -476,11 +476,11 @@ public class MiIoAsyncCommunication {
         return timeDelta;
     }
 
-    public byte[] getDeviceId() {
+    public String getDeviceId() {
         return deviceId;
     }
 
-    public void setDeviceId(byte[] deviceId) {
+    public void setDeviceId(String deviceId) {
         this.deviceId = deviceId;
     }