Skip to content

Commit

Permalink
[miio] add new custom refresh methods (openhab#10957)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
marcelrv authored and computergeek1507 committed Jul 13, 2021
1 parent 2ad05d3 commit 3ac3602
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ public String sendRPCCommand(String device, String country, MiIoSendCommand comm
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 {
logger.debug("Getting vacuum map {} from Xiaomi cloud server: '{}'", mapId, country);
String mapCountry;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ public List<CloudDeviceDTO> getDevices(String country) {
public String getDeviceString(String country) {
String resp;
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);
if (resp.length() > 2) {
CloudUtil.saveDeviceInfoFile(resp, country, logger);
Expand All @@ -260,7 +260,7 @@ public String request(String urlPart, String country, Map<String, String> params
String url = urlPart.trim();
url = getApiUrl(country) + (url.startsWith("/app") ? url.substring(4) : url);
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;
}

Expand All @@ -270,7 +270,7 @@ public String request(String url, Map<String, String> params) throws MiCloudExce
}
loginFailedCounterCheck();
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.agent(USERAGENT);
request.header("x-xiaomi-protocal-flag-cli", "PROTOCAL-HTTP2");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ public MiIoAbstractHandler(Thing thing, MiIoDatabaseWatchService miIoDatabaseWat

protected boolean handleCommandsChannels(ChannelUID channelUID, Command command) {
if (channelUID.getId().equals(CHANNEL_COMMAND)) {
cmds.put(sendCommand(command.toString(), ""), command.toString());
cmds.put(sendCommand(command.toString()), channelUID.getId());
return true;
}
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 false;
Expand Down Expand Up @@ -553,12 +553,11 @@ public void onMessageReceived(MiIoSendCommand response) {
break;
}
if (cmds.containsKey(response.getId())) {
if (response.getCloudServer().isBlank()) {
updateState(CHANNEL_COMMAND, new StringType(response.getResponse().toString()));
} else {
updateState(CHANNEL_RPC, new StringType(response.getResponse().toString()));
String channel = cmds.get(response.getId());
if (channel != null && (CHANNEL_COMMAND.contentEquals(channel) || CHANNEL_RPC.contentEquals(channel))) {
updateState(channel, new StringType(response.getResponse().toString()));
cmds.remove(response.getId());
}
cmds.remove(response.getId());
}
} catch (Exception e) {
logger.debug("Error while handing message {}", response.getResponse(), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,17 @@ private void refreshCustomProperties(MiIoBasicDevice midevice) {
getThing().getUID());
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());
}
}
}
}

Expand Down Expand Up @@ -515,6 +525,16 @@ private boolean buildChannelStructure(String deviceName) {
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) {
JsonArray res = response.getResult().getAsJsonArray();
JsonArray para = JsonParser.parseString(response.getCommandString()).getAsJsonObject().get("params")
Expand Down Expand Up @@ -679,10 +699,11 @@ public void onMessageReceived(MiIoSendCommand response) {
}
break;
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(),
response.getResult());
final MiIoBasicChannel ch = refreshListCustomCommands.get(response.getMethod());
final MiIoBasicChannel ch = getCustomRefreshChannel(channel);
if (ch != null) {
if (response.getResult().isJsonArray()) {
JsonArray cmdResponse = response.getResult().getAsJsonArray();
Expand All @@ -698,6 +719,7 @@ public void onMessageReceived(MiIoSendCommand response) {
updateChannel(ch, ch.getChannel(), new JsonPrimitive(response.getResult().toString()));
}
}
cmds.remove(response.getId());
}
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,17 @@ public int queueCommand(String command, String params, String cloudServer)
if (cmdId > MAX_ID) {
id.set(0);
}
fullCommand.addProperty("id", cmdId);
fullCommand.addProperty("method", command);
fullCommand.add("params", JsonParser.parseString(params));
if (command.startsWith("{") && command.endsWith("}")) {
fullCommand = JsonParser.parseString(command).getAsJsonObject();
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,
cloudServer);
concurrentLinkedQueue.add(sendCmd);
Expand All @@ -163,7 +171,7 @@ public int queueCommand(String command, String params, String cloudServer)
sendPing(ip);
}
return cmdId;
} catch (JsonSyntaxException e) {
} catch (JsonSyntaxException | IllegalStateException e) {
logger.warn("Send command '{}' with parameters {} -> {} (Device: {}) gave error {}", command, params, ip,
deviceId, e.getMessage());
throw e;
Expand All @@ -177,11 +185,24 @@ MiIoSendCommand sendMiIoSendCommand(MiIoSendCommand miIoSendCommand) {
if (miIoSendCommand.getCloudServer().isBlank()) {
decryptedResponse = sendCommand(miIoSendCommand.getCommandString(), token, ip, deviceId);
} else {
decryptedResponse = cloudConnector.sendRPCCommand(Utils.getHexId(deviceId),
miIoSendCommand.getCloudServer(), miIoSendCommand);
logger.debug("Command {} send via cloudserver {}", miIoSendCommand.getCommandString(),
miIoSendCommand.getCloudServer());
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
if (!miIoSendCommand.getMethod().startsWith("/")) {
decryptedResponse = cloudConnector.sendRPCCommand(Utils.getHexId(deviceId),
miIoSendCommand.getCloudServer(), miIoSendCommand);
logger.debug("Command {} send via cloudserver {}", miIoSendCommand.getCommandString(),
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
decryptedResponse = decryptedResponse.replace(",,", ",");
Expand Down

0 comments on commit 3ac3602

Please sign in to comment.