Skip to content

Commit

Permalink
[miio] jsonify command handling (openhab#7361)
Browse files Browse the repository at this point in the history
* Allow for more flexible parameters setting.
* Prep to use gson to write database files (for future unsupported
handler)
* Apply eclipse formatter to all json db files
* Lower log level during initiation
https://community.openhab.org/t/xiaomi-robot-vacuum-binding/31317/1380

Signed-off-by: Marcel Verpaalen <marcel@verpaalen.com>
Signed-off-by: Eugen Freiter <freiter@gmx.de>
  • Loading branch information
marcelrv authored and Eugen Freiter committed Apr 27, 2020
1 parent 6f53558 commit f2effe4
Show file tree
Hide file tree
Showing 32 changed files with 921 additions and 810 deletions.
Expand Up @@ -29,10 +29,14 @@ public enum MiIoCommand {

// Basic device commands
GET_PROPERTY("get_prop"),
GET_PROPERTIES("get_properties"),
GET_VALUE("get_value"),
SET_PROPERTIES("set_properties"),
SET_MODE_BASIC("set_mode"),
SET_POWER("set_power"),
SET_BRIGHT("set_bright"),
SET_WIFI_LET("set_wifi_led"),
SET_FAVORITE("set_level_favorite"),

// vacuum commands
START_VACUUM("app_start"),
Expand Down
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2010-2020 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;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

/**
* Mapping properties from json for miio info response
*
* @author Marcel Verpaalen - Initial contribution
*/
public class MiIoInfoDTO {
@SerializedName("life")
@Expose
public Integer life;
@SerializedName("cfg_time")
@Expose
public Integer cfgTime;
@SerializedName("token")
@Expose
public String token;
@SerializedName("mac")
@Expose
public String mac;
@SerializedName("fw_ver")
@Expose
public String fwVer;
@SerializedName("hw_ver")
@Expose
public String hwVer;
@SerializedName("uid")
@Expose
public Integer uid;
@SerializedName("model")
@Expose
public String model;
@SerializedName("wifi_fw_ver")
@Expose
public String wifiFwVer;
@SerializedName("mcu_fw_ver")
@Expose
public String mcuFwVer;
@SerializedName("mmfree")
@Expose
public Integer mmfree;
}
Expand Up @@ -26,6 +26,7 @@ public enum CommandParameterType {
ONOFF("onoff"),
ONOFFPARA("onoffpara"),
ONOFFBOOL("onoffbool"),
ONOFFBOOLSTRING("onoffboolstring"),
STRING("string"),
CUSTOMSTRING("customstring"),
NUMBER("number"),
Expand Down
Expand Up @@ -16,6 +16,7 @@
import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.miio.internal.MiIoCommand;

import com.google.gson.annotations.Expose;
Expand All @@ -32,15 +33,15 @@ public class DeviceMapping {
@SerializedName("id")
@Expose
private List<String> id = new ArrayList<>();
@SerializedName("channels")
@Expose
private List<MiIoBasicChannel> miIoBasicChannels = new ArrayList<>();
@SerializedName("propertyMethod")
@Expose
private String propertyMethod = MiIoCommand.GET_PROPERTY.getCommand();
private @Nullable String propertyMethod;
@SerializedName("maxProperties")
@Expose
private int maxProperties = 5;
private @Nullable Integer maxProperties;
@SerializedName("channels")
@Expose
private List<MiIoBasicChannel> miIoBasicChannels = new ArrayList<>();

public List<String> getId() {
return id;
Expand All @@ -51,15 +52,17 @@ public void setId(List<String> id) {
}

public String getPropertyMethod() {
return propertyMethod;
final String propertyMethod = this.propertyMethod;
return propertyMethod != null ? propertyMethod : MiIoCommand.GET_PROPERTY.getCommand();
}

public void setPropertyMethod(String propertyMethod) {
this.propertyMethod = propertyMethod;
}

public int getMaxProperties() {
return maxProperties;
final Integer maxProperties = this.maxProperties;
return maxProperties != null ? maxProperties.intValue() : 5;
}

public void setMaxProperties(int maxProperties) {
Expand Down
Expand Up @@ -15,6 +15,7 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

import com.google.gson.JsonArray;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

Expand Down Expand Up @@ -44,6 +45,16 @@ public class MiIoDeviceAction {
@SerializedName("parameter3")
@Expose
private @Nullable String parameter3;
private @Nullable JsonArray parameters;

public JsonArray getParameters() {
final @Nullable JsonArray parameter = this.parameters;
return parameter != null ? parameter : new JsonArray();
}

public void setParameters(JsonArray parameters) {
this.parameters = parameters;
}

public String getCommand() {
final @Nullable String command = this.command;
Expand Down
Expand Up @@ -16,6 +16,7 @@

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
Expand All @@ -41,6 +42,7 @@
import org.openhab.binding.miio.internal.MiIoCrypto;
import org.openhab.binding.miio.internal.MiIoCryptoException;
import org.openhab.binding.miio.internal.MiIoDevices;
import org.openhab.binding.miio.internal.MiIoInfoDTO;
import org.openhab.binding.miio.internal.MiIoMessageListener;
import org.openhab.binding.miio.internal.MiIoSendCommand;
import org.openhab.binding.miio.internal.Utils;
Expand All @@ -49,6 +51,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

Expand All @@ -61,19 +65,21 @@
@NonNullByDefault
public abstract class MiIoAbstractHandler extends BaseThingHandler implements MiIoMessageListener {
protected static final int MAX_QUEUE = 5;
protected static final Gson GSON = new GsonBuilder().create();

protected @Nullable ScheduledFuture<?> pollingJob;
protected MiIoDevices miDevice = MiIoDevices.UNKNOWN;
protected boolean isIdentified;

protected JsonParser parser;
protected final JsonParser parser = new JsonParser();
protected byte[] token = new byte[0];

protected @Nullable MiIoBindingConfiguration configuration;
protected @Nullable MiIoAsyncCommunication miioCom;
protected int lastId;

protected Map<Integer, String> cmds = new ConcurrentHashMap<>();
protected Map<String, Object> deviceVariables = new HashMap<>();
protected final ExpiringCache<String> network = new ExpiringCache<>(CACHE_EXPIRY_NETWORK, () -> {
int ret = sendCommand(MiIoCommand.MIIO_INFO);
if (ret != 0) {
Expand All @@ -89,7 +95,6 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi

public MiIoAbstractHandler(Thing thing, MiIoDatabaseWatchService miIoDatabaseWatchService) {
super(thing);
parser = new JsonParser();
this.miIoDatabaseWatchService = miIoDatabaseWatchService;
}

Expand Down Expand Up @@ -350,15 +355,22 @@ protected void defineDeviceType(JsonObject miioInfo) {
}

private void updateProperties(JsonObject miioInfo) {
final MiIoInfoDTO info = GSON.fromJson(miioInfo, MiIoInfoDTO.class);
Map<String, String> properties = editProperties();
properties.put(Thing.PROPERTY_MODEL_ID, miioInfo.get("model").getAsString());
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, miioInfo.get("fw_ver").getAsString());
properties.put(Thing.PROPERTY_HARDWARE_VERSION, miioInfo.get("hw_ver").getAsString());
if (miioInfo.get("wifi_fw_ver") != null) {
properties.put("wifiFirmware", miioInfo.get("wifi_fw_ver").getAsString());
if (info.model != null) {
properties.put(Thing.PROPERTY_MODEL_ID, info.model);
}
if (miioInfo.get("mcu_fw_ver") != null) {
properties.put("mcuFirmware", miioInfo.get("mcu_fw_ver").getAsString());
if (info.fwVer != null) {
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, info.fwVer);
}
if (info.hwVer != null) {
properties.put(Thing.PROPERTY_HARDWARE_VERSION, info.hwVer);
}
if (info.wifiFwVer != null) {
properties.put("wifiFirmware", info.wifiFwVer);
}
if (info.mcuFwVer != null) {
properties.put("mcuFirmware", info.mcuFwVer);
}
updateProperties(properties);
}
Expand All @@ -380,15 +392,15 @@ protected boolean updateThingType(JsonObject miioInfo) {
if (miDevice.getThingType().equals(getThing().getThingTypeUID())
&& !(miDevice.getThingType().equals(THING_TYPE_UNSUPPORTED)
&& miIoDatabaseWatchService.getDatabaseUrl(model) != null)) {
logger.info("Mi Device model {} identified as: {}. Matches thingtype {}", model, miDevice.toString(),
logger.debug("Mi Device model {} identified as: {}. Matches thingtype {}", model, miDevice.toString(),
miDevice.getThingType().toString());
return true;
} else {
if (getThing().getThingTypeUID().equals(THING_TYPE_MIIO)
|| getThing().getThingTypeUID().equals(THING_TYPE_UNSUPPORTED)) {
changeType(model);
} else {
logger.warn(
logger.info(
"Mi Device model {} identified as: {}, thingtype {}. Does not matches thingtype {}. Unexpected, unless manual override.",
miDevice.toString(), miDevice.getThingType(), getThing().getThingTypeUID().toString(),
miDevice.getThingType().toString());
Expand Down
Expand Up @@ -61,6 +61,7 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;

/**
Expand Down Expand Up @@ -130,53 +131,65 @@ public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("Locating action for channel {}: {}", channelUID.getId(), command);
if (!actions.isEmpty()) {
if (actions.containsKey(channelUID.getId())) {
String preCommandPara1 = actions.get(channelUID.getId()).getPreCommandParameter1();
preCommandPara1 = ((preCommandPara1 != null && !preCommandPara1.isEmpty()) ? preCommandPara1 + ","
: "");
String para1 = actions.get(channelUID.getId()).getParameter1();
String para2 = actions.get(channelUID.getId()).getParameter2();
String para3 = actions.get(channelUID.getId()).getParameter3();
String para = "" + (para1 != null ? "," + para1 : "") + (para2 != null ? "," + para2 : "")
+ (para3 != null ? "," + para3 : "");
int valuePos = 0;
@Nullable
JsonElement value = null;
MiIoDeviceAction action = actions.get(channelUID.getId());
JsonArray parameters = actions.get(channelUID.getId()).getParameters();
for (int i = 0; i < action.getParameters().size(); i++) {
JsonElement p = action.getParameters().get(i);
if (p.isJsonPrimitive() && p.getAsString().toLowerCase().contains("$value$")) {
valuePos = i;
}
}
String cmd = actions.get(channelUID.getId()).getCommand();
CommandParameterType paramType = actions.get(channelUID.getId()).getparameterType();
if (paramType == CommandParameterType.EMPTY) {
cmd = cmd + "[]";
} else if (paramType == CommandParameterType.NONE) {
logger.trace("NONE command type");
} else if (paramType == CommandParameterType.COLOR) {
if (paramType == CommandParameterType.COLOR) {
if (command instanceof HSBType) {
HSBType hsb = (HSBType) command;
Color color = Color.getHSBColor(hsb.getHue().floatValue() / 360,
hsb.getSaturation().floatValue() / 100, hsb.getBrightness().floatValue() / 100);
cmd = cmd + "[" + preCommandPara1
+ ((color.getRed() * 65536) + (color.getGreen() * 256) + color.getBlue()) + para + "]";
value = new JsonPrimitive(
(color.getRed() * 65536) + (color.getGreen() * 256) + color.getBlue());
} else if (command instanceof DecimalType) {
// actually brightness is being set instead of a color
cmd = "set_bright" + "[" + command.toString().toLowerCase() + "]";
cmd = "set_bright";
value = new JsonPrimitive(((DecimalType) command).toBigDecimal());
} else {
logger.debug("Unsupported command for COLOR: {}", command);
}

} else if (command instanceof OnOffType) {
if (paramType == CommandParameterType.ONOFF) {
cmd = cmd + "[" + preCommandPara1 + "\"" + command.toString().toLowerCase() + "\"" + para + "]";
value = new JsonPrimitive(command == OnOffType.ON ? "on" : "off");
} else if (paramType == CommandParameterType.ONOFFPARA) {
cmd = cmd.replace("*", command.toString().toLowerCase()) + "[]";
cmd = cmd.replace("*", command == OnOffType.ON ? "on" : "off");
} else if (paramType == CommandParameterType.ONOFFBOOL) {
boolean boolCommand = command == OnOffType.ON;
cmd = cmd + "[" + preCommandPara1 + "\"" + boolCommand + "\"" + para + "]";
} else {
cmd = cmd + "[]";
value = new JsonPrimitive(boolCommand);
} else if (paramType == CommandParameterType.ONOFFBOOLSTRING) {
value = new JsonPrimitive(command == OnOffType.ON ? "true" : "false");
}
} else if (command instanceof DecimalType) {
value = new JsonPrimitive(((DecimalType) command).toBigDecimal());
} else if (command instanceof StringType) {
if (paramType == CommandParameterType.STRING) {
cmd = cmd + "[" + preCommandPara1 + "\"" + command.toString() + "\"" + para + "]";
value = new JsonPrimitive(command.toString().toLowerCase());
} else if (paramType == CommandParameterType.CUSTOMSTRING) {
cmd = cmd + "[" + preCommandPara1 + "\"" + command.toString() + para + "]";
value = new JsonPrimitive(parameters.get(valuePos).getAsString().replace("$value",
command.toString().toLowerCase()));
}
} else if (command instanceof DecimalType) {
cmd = cmd + "[" + preCommandPara1 + command.toString().toLowerCase() + para + "]";
} else {
value = new JsonPrimitive(command.toString().toLowerCase());
}
if (paramType != CommandParameterType.NONE && value != null) {
if (parameters.size() > 0) {
parameters.set(valuePos, value);
} else {
parameters.add(value);
}
}
if (paramType != CommandParameterType.EMPTY) {
cmd = cmd + parameters.toString();
}
logger.debug("Sending command {}", cmd);
sendCommand(cmd);
Expand Down

0 comments on commit f2effe4

Please sign in to comment.