]> git.basschouten.com Git - openhab-addons.git/blob
0433ea478b49d8430636e2f7b42c0b5f2b38b82a
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.ecovacs.internal.api.impl;
14
15 import java.util.Optional;
16
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;
32
33 import com.google.gson.Gson;
34 import com.google.gson.JsonSyntaxException;
35
36 /**
37  * @author Danny Baumann - Initial contribution
38  */
39 @NonNullByDefault
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 = "";
46
47     JsonReportParser(EcovacsDevice device, EventListener listener, ProtocolVersion version, Gson gson, Logger logger) {
48         this.device = device;
49         this.listener = listener;
50         this.gson = gson;
51         this.logger = logger;
52     }
53
54     @Override
55     public void handleMessage(String eventName, String payload) throws DataParsingException {
56         JsonResponsePayloadWrapper response;
57         try {
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);
63             response = null;
64         }
65         if (response == null) {
66             return;
67         }
68         if (!lastFirmwareVersion.equals(response.header.firmwareVersion)) {
69             lastFirmwareVersion = response.header.firmwareVersion;
70             listener.onFirmwareVersionChanged(device, lastFirmwareVersion);
71         }
72         if (eventName.startsWith("on")) {
73             eventName = eventName.substring(2);
74         } else if (eventName.startsWith("report")) {
75             eventName = eventName.substring(6);
76         }
77         switch (eventName) {
78             case "battery": {
79                 BatteryReport report = payloadAs(response, BatteryReport.class);
80                 listener.onBatteryLevelUpdated(device, report.percent);
81                 break;
82             }
83             case "chargestate": {
84                 ChargeReport report = payloadAs(response, ChargeReport.class);
85                 listener.onChargingStateUpdated(device, report.isCharging != 0);
86                 break;
87             }
88             case "cleaninfo": {
89                 CleanReport report = payloadAs(response, CleanReport.class);
90                 CleanMode mode = report.determineCleanMode(gson);
91                 if (mode == null) {
92                     throw new DataParsingException("Could not get clean mode from response " + payload);
93                 }
94                 String area = report.cleanState != null ? report.cleanState.areaDefinition : null;
95                 handleCleanModeChange(mode, area);
96                 break;
97             }
98             case "cleaninfo_v2": {
99                 CleanReportV2 report = payloadAs(response, CleanReportV2.class);
100                 CleanMode mode = report.determineCleanMode(gson);
101                 if (mode == null) {
102                     throw new DataParsingException("Could not get clean mode from response " + payload);
103                 }
104                 String area = report.cleanState != null && report.cleanState.content != null
105                         ? report.cleanState.content.areaDefinition
106                         : null;
107                 handleCleanModeChange(mode, area);
108                 break;
109             }
110             case "error": {
111                 ErrorReport report = payloadAs(response, ErrorReport.class);
112                 for (Integer code : report.errorCodes) {
113                     listener.onErrorReported(device, code);
114                 }
115             }
116             case "stats": {
117                 StatsReport report = payloadAs(response, StatsReport.class);
118                 listener.onCleaningStatsUpdated(device, report.area, report.timeInSeconds);
119                 break;
120             }
121             case "waterinfo": {
122                 WaterInfoReport report = payloadAs(response, WaterInfoReport.class);
123                 listener.onWaterSystemPresentUpdated(device, report.waterPlatePresent != 0);
124                 break;
125             }
126             // more possible events (unused for now):
127             // - "evt" -> EventReport
128             // - "lifespan" -> ComponentLifeSpanReport
129             // - "speed" -> SpeedReport
130         }
131     }
132
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(),
136                     areaDefinition);
137         }
138         listener.onCleaningModeUpdated(device, mode, Optional.ofNullable(areaDefinition));
139     }
140
141     private <T> T payloadAs(JsonResponsePayloadWrapper response, Class<T> clazz) throws DataParsingException {
142         @Nullable
143         T payload = gson.fromJson(response.body.payload, clazz);
144         if (payload == null) {
145             throw new DataParsingException("Null payload in response " + response);
146         }
147         return payload;
148     }
149 }