2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.ecovacs.internal.api.impl;
15 import java.util.Optional;
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.openhab.binding.ecovacs.internal.api.EcovacsDevice;
20 import org.openhab.binding.ecovacs.internal.api.EcovacsDevice.EventListener;
21 import org.openhab.binding.ecovacs.internal.api.impl.dto.response.deviceapi.json.BatteryReport;
22 import org.openhab.binding.ecovacs.internal.api.impl.dto.response.deviceapi.json.ChargeReport;
23 import org.openhab.binding.ecovacs.internal.api.impl.dto.response.deviceapi.json.CleanReport;
24 import org.openhab.binding.ecovacs.internal.api.impl.dto.response.deviceapi.json.CleanReportV2;
25 import org.openhab.binding.ecovacs.internal.api.impl.dto.response.deviceapi.json.ErrorReport;
26 import org.openhab.binding.ecovacs.internal.api.impl.dto.response.deviceapi.json.StatsReport;
27 import org.openhab.binding.ecovacs.internal.api.impl.dto.response.deviceapi.json.WaterInfoReport;
28 import org.openhab.binding.ecovacs.internal.api.impl.dto.response.portal.PortalIotCommandJsonResponse.JsonResponsePayloadWrapper;
29 import org.openhab.binding.ecovacs.internal.api.model.CleanMode;
30 import org.openhab.binding.ecovacs.internal.api.util.DataParsingException;
31 import org.slf4j.Logger;
33 import com.google.gson.Gson;
34 import com.google.gson.JsonSyntaxException;
37 * @author Danny Baumann - Initial contribution
40 class JsonReportParser implements ReportParser {
41 private final EcovacsDevice device;
42 private final EventListener listener;
43 private final Gson gson;
44 private final Logger logger;
45 private String lastFirmwareVersion = "";
47 JsonReportParser(EcovacsDevice device, EventListener listener, ProtocolVersion version, Gson gson, Logger logger) {
49 this.listener = listener;
55 public void handleMessage(String eventName, String payload) throws DataParsingException {
56 JsonResponsePayloadWrapper response;
58 response = gson.fromJson(payload, JsonResponsePayloadWrapper.class);
59 } catch (JsonSyntaxException e) {
60 // The onFwBuryPoint-bd_sysinfo sends a JSON array instead of the expected JsonResponsePayloadBody object.
61 // Since we don't do anything with it anyway, just ignore it
62 logger.debug("{}: Got invalid JSON message payload, ignoring: {}", device.getSerialNumber(), payload, e);
65 if (response == null) {
68 if (!lastFirmwareVersion.equals(response.header.firmwareVersion)) {
69 lastFirmwareVersion = response.header.firmwareVersion;
70 listener.onFirmwareVersionChanged(device, lastFirmwareVersion);
72 if (eventName.startsWith("on")) {
73 eventName = eventName.substring(2);
74 } else if (eventName.startsWith("report")) {
75 eventName = eventName.substring(6);
79 BatteryReport report = payloadAs(response, BatteryReport.class);
80 listener.onBatteryLevelUpdated(device, report.percent);
84 ChargeReport report = payloadAs(response, ChargeReport.class);
85 listener.onChargingStateUpdated(device, report.isCharging != 0);
89 CleanReport report = payloadAs(response, CleanReport.class);
90 CleanMode mode = report.determineCleanMode(gson);
92 throw new DataParsingException("Could not get clean mode from response " + payload);
94 String area = report.cleanState != null ? report.cleanState.areaDefinition : null;
95 handleCleanModeChange(mode, area);
98 case "cleaninfo_v2": {
99 CleanReportV2 report = payloadAs(response, CleanReportV2.class);
100 CleanMode mode = report.determineCleanMode(gson);
102 throw new DataParsingException("Could not get clean mode from response " + payload);
104 String area = report.cleanState != null && report.cleanState.content != null
105 ? report.cleanState.content.areaDefinition
107 handleCleanModeChange(mode, area);
111 ErrorReport report = payloadAs(response, ErrorReport.class);
112 for (Integer code : report.errorCodes) {
113 listener.onErrorReported(device, code);
117 StatsReport report = payloadAs(response, StatsReport.class);
118 listener.onCleaningStatsUpdated(device, report.area, report.timeInSeconds);
122 WaterInfoReport report = payloadAs(response, WaterInfoReport.class);
123 listener.onWaterSystemPresentUpdated(device, report.waterPlatePresent != 0);
126 // more possible events (unused for now):
127 // - "evt" -> EventReport
128 // - "lifespan" -> ComponentLifeSpanReport
129 // - "speed" -> SpeedReport
133 private void handleCleanModeChange(CleanMode mode, @Nullable String areaDefinition) {
134 if (mode == CleanMode.CUSTOM_AREA) {
135 logger.debug("{}: Custom area cleaning stated with area definition {}", device.getSerialNumber(),
138 listener.onCleaningModeUpdated(device, mode, Optional.ofNullable(areaDefinition));
141 private <T> T payloadAs(JsonResponsePayloadWrapper response, Class<T> clazz) throws DataParsingException {
143 T payload = gson.fromJson(response.body.payload, clazz);
144 if (payload == null) {
145 throw new DataParsingException("Null payload in response " + response);