[miio] add new custom refresh methods (#10957)
* Improve matching the command responses to the sending channel * Use newer method to get device list using `device_list_page` * Adding the ability to send custom requests to cloud * Adding the ability to send custom commands with additional elements in the json Signed-off-by: Marcel Verpaalen <marcel@verpaalen.com>
This commit is contained in:
parent
c0ab022e4e
commit
072a6045c2
@ -124,6 +124,14 @@ public class CloudConnector {
|
|||||||
return cl.sendRPCCommand(device, country.trim().toLowerCase(), command.getCommandString());
|
return cl.sendRPCCommand(device, country.trim().toLowerCase(), command.getCommandString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String sendCloudCommand(String urlPart, String country, String parameters) throws MiCloudException {
|
||||||
|
final @Nullable MiCloudConnector cl = this.cloudConnector;
|
||||||
|
if (cl == null || !isConnected()) {
|
||||||
|
throw new MiCloudException("Cannot execute request. Cloud service not available");
|
||||||
|
}
|
||||||
|
return cl.request(urlPart, country, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
public @Nullable RawType getMap(String mapId, String country) throws MiCloudException {
|
public @Nullable RawType getMap(String mapId, String country) throws MiCloudException {
|
||||||
logger.debug("Getting vacuum map {} from Xiaomi cloud server: '{}'", mapId, country);
|
logger.debug("Getting vacuum map {} from Xiaomi cloud server: '{}'", mapId, country);
|
||||||
String mapCountry;
|
String mapCountry;
|
||||||
|
|||||||
@ -237,7 +237,7 @@ public class MiCloudConnector {
|
|||||||
public String getDeviceString(String country) {
|
public String getDeviceString(String country) {
|
||||||
String resp;
|
String resp;
|
||||||
try {
|
try {
|
||||||
resp = request("/home/device_list", country, "{\"getVirtualModel\":false,\"getHuamiDevices\":0}");
|
resp = request("/home/device_list_page", country, "{\"getVirtualModel\":false,\"getHuamiDevices\":1}");
|
||||||
logger.trace("Get devices response: {}", resp);
|
logger.trace("Get devices response: {}", resp);
|
||||||
if (resp.length() > 2) {
|
if (resp.length() > 2) {
|
||||||
CloudUtil.saveDeviceInfoFile(resp, country, logger);
|
CloudUtil.saveDeviceInfoFile(resp, country, logger);
|
||||||
@ -260,7 +260,7 @@ public class MiCloudConnector {
|
|||||||
String url = urlPart.trim();
|
String url = urlPart.trim();
|
||||||
url = getApiUrl(country) + (url.startsWith("/app") ? url.substring(4) : url);
|
url = getApiUrl(country) + (url.startsWith("/app") ? url.substring(4) : url);
|
||||||
String response = request(url, params);
|
String response = request(url, params);
|
||||||
logger.debug("Request to {} server {}. Response: {}", country, urlPart, response);
|
logger.debug("Request to '{}' server '{}'. Response: '{}'", country, urlPart, response);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +270,7 @@ public class MiCloudConnector {
|
|||||||
}
|
}
|
||||||
loginFailedCounterCheck();
|
loginFailedCounterCheck();
|
||||||
startClient();
|
startClient();
|
||||||
logger.debug("Send request: {} to {}", params.get("data"), url);
|
logger.debug("Send request to {} with data '{}'", url, params.get("data"));
|
||||||
Request request = httpClient.newRequest(url).timeout(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
Request request = httpClient.newRequest(url).timeout(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||||
request.agent(USERAGENT);
|
request.agent(USERAGENT);
|
||||||
request.header("x-xiaomi-protocal-flag-cli", "PROTOCAL-HTTP2");
|
request.header("x-xiaomi-protocal-flag-cli", "PROTOCAL-HTTP2");
|
||||||
|
|||||||
@ -112,11 +112,11 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi
|
|||||||
|
|
||||||
protected boolean handleCommandsChannels(ChannelUID channelUID, Command command) {
|
protected boolean handleCommandsChannels(ChannelUID channelUID, Command command) {
|
||||||
if (channelUID.getId().equals(CHANNEL_COMMAND)) {
|
if (channelUID.getId().equals(CHANNEL_COMMAND)) {
|
||||||
cmds.put(sendCommand(command.toString(), ""), command.toString());
|
cmds.put(sendCommand(command.toString()), channelUID.getId());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (channelUID.getId().equals(CHANNEL_RPC)) {
|
if (channelUID.getId().equals(CHANNEL_RPC)) {
|
||||||
cmds.put(sendCommand(command.toString(), cloudServer), command.toString());
|
cmds.put(sendCommand(command.toString(), cloudServer), channelUID.getId());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -553,12 +553,11 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (cmds.containsKey(response.getId())) {
|
if (cmds.containsKey(response.getId())) {
|
||||||
if (response.getCloudServer().isBlank()) {
|
String channel = cmds.get(response.getId());
|
||||||
updateState(CHANNEL_COMMAND, new StringType(response.getResponse().toString()));
|
if (channel != null && (CHANNEL_COMMAND.contentEquals(channel) || CHANNEL_RPC.contentEquals(channel))) {
|
||||||
} else {
|
updateState(channel, new StringType(response.getResponse().toString()));
|
||||||
updateState(CHANNEL_RPC, new StringType(response.getResponse().toString()));
|
cmds.remove(response.getId());
|
||||||
}
|
}
|
||||||
cmds.remove(response.getId());
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.debug("Error while handing message {}", response.getResponse(), e);
|
logger.debug("Error while handing message {}", response.getResponse(), e);
|
||||||
|
|||||||
@ -328,7 +328,17 @@ public class MiIoBasicHandler extends MiIoAbstractHandler {
|
|||||||
getThing().getUID());
|
getThing().getUID());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sendCommand(miChannel.getChannelCustomRefreshCommand());
|
String cmd = miChannel.getChannelCustomRefreshCommand();
|
||||||
|
if (!cmd.startsWith("/")) {
|
||||||
|
cmds.put(sendCommand(miChannel.getChannelCustomRefreshCommand()), miChannel.getChannel());
|
||||||
|
} else {
|
||||||
|
if (cloudServer.isBlank()) {
|
||||||
|
logger.debug("Cloudserver empty. Skipping refresh for {} channel '{}'", getThing().getUID(),
|
||||||
|
miChannel.getChannel());
|
||||||
|
} else {
|
||||||
|
cmds.put(sendCommand(cmd, cloudServer), miChannel.getChannel());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,6 +525,16 @@ public class MiIoBasicHandler extends MiIoAbstractHandler {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private @Nullable MiIoBasicChannel getCustomRefreshChannel(String channelName) {
|
||||||
|
for (MiIoBasicChannel refreshEntry : refreshListCustomCommands.values()) {
|
||||||
|
if (refreshEntry.getChannel().equals(channelName)) {
|
||||||
|
return refreshEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.trace("Did not find channel for {} in {}", channelName, refreshList);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void updatePropsFromJsonArray(MiIoSendCommand response) {
|
private void updatePropsFromJsonArray(MiIoSendCommand response) {
|
||||||
JsonArray res = response.getResult().getAsJsonArray();
|
JsonArray res = response.getResult().getAsJsonArray();
|
||||||
JsonArray para = JsonParser.parseString(response.getCommandString()).getAsJsonObject().get("params")
|
JsonArray para = JsonParser.parseString(response.getCommandString()).getAsJsonObject().get("params")
|
||||||
@ -679,10 +699,11 @@ public class MiIoBasicHandler extends MiIoAbstractHandler {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (refreshListCustomCommands.containsKey(response.getMethod())) {
|
String channel = cmds.get(response.getId());
|
||||||
|
if (channel != null) {
|
||||||
logger.debug("Processing custom refresh command response for '{}' - {}", response.getMethod(),
|
logger.debug("Processing custom refresh command response for '{}' - {}", response.getMethod(),
|
||||||
response.getResult());
|
response.getResult());
|
||||||
final MiIoBasicChannel ch = refreshListCustomCommands.get(response.getMethod());
|
final MiIoBasicChannel ch = getCustomRefreshChannel(channel);
|
||||||
if (ch != null) {
|
if (ch != null) {
|
||||||
if (response.getResult().isJsonArray()) {
|
if (response.getResult().isJsonArray()) {
|
||||||
JsonArray cmdResponse = response.getResult().getAsJsonArray();
|
JsonArray cmdResponse = response.getResult().getAsJsonArray();
|
||||||
@ -698,6 +719,7 @@ public class MiIoBasicHandler extends MiIoAbstractHandler {
|
|||||||
updateChannel(ch, ch.getChannel(), new JsonPrimitive(response.getResult().toString()));
|
updateChannel(ch, ch.getChannel(), new JsonPrimitive(response.getResult().toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cmds.remove(response.getId());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -146,9 +146,17 @@ public class MiIoAsyncCommunication {
|
|||||||
if (cmdId > MAX_ID) {
|
if (cmdId > MAX_ID) {
|
||||||
id.set(0);
|
id.set(0);
|
||||||
}
|
}
|
||||||
fullCommand.addProperty("id", cmdId);
|
if (command.startsWith("{") && command.endsWith("}")) {
|
||||||
fullCommand.addProperty("method", command);
|
fullCommand = JsonParser.parseString(command).getAsJsonObject();
|
||||||
fullCommand.add("params", JsonParser.parseString(params));
|
fullCommand.addProperty("id", cmdId);
|
||||||
|
if (!fullCommand.has("params") && !params.isBlank()) {
|
||||||
|
fullCommand.add("params", JsonParser.parseString(params));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fullCommand.addProperty("id", cmdId);
|
||||||
|
fullCommand.addProperty("method", command);
|
||||||
|
fullCommand.add("params", JsonParser.parseString(params));
|
||||||
|
}
|
||||||
MiIoSendCommand sendCmd = new MiIoSendCommand(cmdId, MiIoCommand.getCommand(command), fullCommand,
|
MiIoSendCommand sendCmd = new MiIoSendCommand(cmdId, MiIoCommand.getCommand(command), fullCommand,
|
||||||
cloudServer);
|
cloudServer);
|
||||||
concurrentLinkedQueue.add(sendCmd);
|
concurrentLinkedQueue.add(sendCmd);
|
||||||
@ -163,7 +171,7 @@ public class MiIoAsyncCommunication {
|
|||||||
sendPing(ip);
|
sendPing(ip);
|
||||||
}
|
}
|
||||||
return cmdId;
|
return cmdId;
|
||||||
} catch (JsonSyntaxException e) {
|
} catch (JsonSyntaxException | IllegalStateException e) {
|
||||||
logger.warn("Send command '{}' with parameters {} -> {} (Device: {}) gave error {}", command, params, ip,
|
logger.warn("Send command '{}' with parameters {} -> {} (Device: {}) gave error {}", command, params, ip,
|
||||||
deviceId, e.getMessage());
|
deviceId, e.getMessage());
|
||||||
throw e;
|
throw e;
|
||||||
@ -177,11 +185,24 @@ public class MiIoAsyncCommunication {
|
|||||||
if (miIoSendCommand.getCloudServer().isBlank()) {
|
if (miIoSendCommand.getCloudServer().isBlank()) {
|
||||||
decryptedResponse = sendCommand(miIoSendCommand.getCommandString(), token, ip, deviceId);
|
decryptedResponse = sendCommand(miIoSendCommand.getCommandString(), token, ip, deviceId);
|
||||||
} else {
|
} else {
|
||||||
decryptedResponse = cloudConnector.sendRPCCommand(Utils.getHexId(deviceId),
|
if (!miIoSendCommand.getMethod().startsWith("/")) {
|
||||||
miIoSendCommand.getCloudServer(), miIoSendCommand);
|
decryptedResponse = cloudConnector.sendRPCCommand(Utils.getHexId(deviceId),
|
||||||
logger.debug("Command {} send via cloudserver {}", miIoSendCommand.getCommandString(),
|
miIoSendCommand.getCloudServer(), miIoSendCommand);
|
||||||
miIoSendCommand.getCloudServer());
|
logger.debug("Command {} send via cloudserver {}", miIoSendCommand.getCommandString(),
|
||||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
|
miIoSendCommand.getCloudServer());
|
||||||
|
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
|
||||||
|
} else {
|
||||||
|
String data = miIoSendCommand.getParams().isJsonArray()
|
||||||
|
&& miIoSendCommand.getParams().getAsJsonArray().size() > 0
|
||||||
|
? miIoSendCommand.getParams().getAsJsonArray().get(0).toString()
|
||||||
|
: "";
|
||||||
|
logger.debug("Custom cloud request send to url '{}' with data '{}'", miIoSendCommand.getMethod(),
|
||||||
|
data);
|
||||||
|
decryptedResponse = cloudConnector.sendCloudCommand(miIoSendCommand.getMethod(),
|
||||||
|
miIoSendCommand.getCloudServer(), data);
|
||||||
|
miIoSendCommand.setResponse(JsonParser.parseString(decryptedResponse).getAsJsonObject());
|
||||||
|
return miIoSendCommand;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// hack due to avoid invalid json errors from some misbehaving device firmwares
|
// hack due to avoid invalid json errors from some misbehaving device firmwares
|
||||||
decryptedResponse = decryptedResponse.replace(",,", ",");
|
decryptedResponse = decryptedResponse.replace(",,", ",");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user