From a7484a54bbd496bdb5473ef8faa7a04700982549 Mon Sep 17 00:00:00 2001 From: Matt Jones Date: Tue, 19 Mar 2024 14:25:48 -0500 Subject: [PATCH] feat: add support for switchbot plug mini feat: add humidifier monitor combined w/plug mini to refill tank --- VeraAutomationHub.iml | 62 +-- VeraAutomationHub.ipr | 408 ++++++++++++------ pom.xml | 7 +- .../govee/GoveeHumidifierController.java | 109 +++++ .../switchbot/SwitchBotController.java | 28 +- 5 files changed, 464 insertions(+), 150 deletions(-) create mode 100644 src/main/java/com/bigboxer23/lights/controllers/govee/GoveeHumidifierController.java diff --git a/VeraAutomationHub.iml b/VeraAutomationHub.iml index ac26199..f1128e3 100644 --- a/VeraAutomationHub.iml +++ b/VeraAutomationHub.iml @@ -18,7 +18,7 @@ - + @@ -44,27 +44,21 @@ - - - - + + + + - - + + - - + + - - - - - - @@ -107,24 +101,24 @@ - + - - + + - + - - - + + + @@ -182,10 +176,30 @@ - + - + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/VeraAutomationHub.ipr b/VeraAutomationHub.ipr index 8b5ceee..6a89d10 100644 --- a/VeraAutomationHub.ipr +++ b/VeraAutomationHub.ipr @@ -29,8 +29,6 @@ 8.2 JavaOnly - @@ -75,7 +73,6 @@ @@ -318,16 +314,40 @@ - - + + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -438,16 +458,16 @@ - - + + - + - + - + @@ -522,16 +542,28 @@ - - + + - + - + - + + + + + + + + + + + + + @@ -546,16 +578,16 @@ - - + + - + - + - + @@ -606,16 +638,16 @@ - - + + - + - + - + @@ -654,6 +686,18 @@ + + + + + + + + + + + + @@ -666,16 +710,16 @@ - - + + - + - + - + @@ -690,16 +734,28 @@ - - + + - + - + - + + + + + + + + + + + + + @@ -762,18 +818,6 @@ - - - - - - - - - - - - @@ -810,6 +854,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -834,40 +962,52 @@ - - + + - + - + - + - - + + - + - + - + - - + + - + - + - + + + + + + + + + + + + + @@ -918,6 +1058,18 @@ + + + + + + + + + + + + @@ -1326,16 +1478,16 @@ - - + + - + - + - + @@ -1542,28 +1694,28 @@ - - + + - + - + - + - - + + - + - + - + @@ -1602,16 +1754,16 @@ - - + + - + - + - + @@ -1770,6 +1922,18 @@ + + + + + + + + + + + + @@ -1806,40 +1970,40 @@ - - + + - + - + - + - - + + - + - + - + - - + + - + - + - + @@ -1962,28 +2126,28 @@ - - + + - + - + - + - - + + - + - + - + @@ -1998,16 +2162,16 @@ - - + + - + - + - + @@ -2118,16 +2282,16 @@ - - + + - + - + - + diff --git a/pom.xml b/pom.xml index 4d8bbe2..854d63f 100644 --- a/pom.xml +++ b/pom.xml @@ -112,7 +112,12 @@ com.bigboxer23 switchbotapi-java - 1.1.2 + 1.1.3 + + + com.bigboxer23 + govee-java-api + 1.1.3 diff --git a/src/main/java/com/bigboxer23/lights/controllers/govee/GoveeHumidifierController.java b/src/main/java/com/bigboxer23/lights/controllers/govee/GoveeHumidifierController.java new file mode 100644 index 0000000..d18364a --- /dev/null +++ b/src/main/java/com/bigboxer23/lights/controllers/govee/GoveeHumidifierController.java @@ -0,0 +1,109 @@ +package com.bigboxer23.lights.controllers.govee; + +import com.bigboxer23.govee.GoveeApi; +import com.bigboxer23.govee.GoveeEventSubscriber; +import com.bigboxer23.govee.IHumidifierCommands; +import com.bigboxer23.govee.data.GoveeDeviceCommandResponse; +import com.bigboxer23.govee.data.GoveeEvent; +import com.bigboxer23.lights.controllers.switchbot.SwitchBotController; +import com.bigboxer23.switch_bot.IDeviceCommands; +import com.google.gson.*; +import java.io.IOException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Controller; + +/** + * Controller listens for empty events from humidifier and triggers a pump to add water to the tank and turn the humidifier back on + */ +@Controller +public class GoveeHumidifierController implements InitializingBean { + @Value("${govee_api_key}") + private String API_KEY; + + @Value("${humidfier_to_pump_map}") + private String MAP_KEY; + + private JsonObject humidifierToPumpMap; + + private static final Logger logger = LoggerFactory.getLogger(GoveeHumidifierController.class); + + private final SwitchBotController switchbotController; + + public GoveeHumidifierController(SwitchBotController switchbotController) { + this.switchbotController = switchbotController; + } + + private void setupListeners() { + logger.warn("starting govee event listener"); + humidifierToPumpMap = JsonParser.parseString(MAP_KEY).getAsJsonObject(); + GoveeApi.getInstance(API_KEY).subscribeToGoveeEvents(new GoveeEventSubscriber() { + @Override + public void messageReceived(GoveeEvent event) { + if (event.isLackWaterEvent()) { + logger.warn( + "no water: " + event.getModel() + " " + event.getDeviceId() + " " + event.getDeviceName()); + JsonPrimitive pump = humidifierToPumpMap.getAsJsonPrimitive(event.getDeviceId()); + if (pump == null) { + logger.warn("No pump for " + event.getDeviceId()); + return; + } + new Thread(new RefillAction(pump.getAsString(), event.getModel(), event.getDeviceId())).start(); + } + } + }); + } + + @Override + public void afterPropertiesSet() throws Exception { + setupListeners(); + } + + private class RefillAction implements Runnable { + private final String pumpId; + private final String humidifierModel; + private final String humidifierId; + + public RefillAction(String pumpId, String humidifierModel, String humidifierId) { + this.pumpId = pumpId; + this.humidifierModel = humidifierModel; + this.humidifierId = humidifierId; + } + + @Override + public void run() { + try { + logger.info("starting pump " + pumpId); + switchbotController + .getSwitchbotAPI() + .getDeviceApi() + .sendDeviceControlCommands(pumpId, IDeviceCommands.PLUG_MINI_ON); + Thread.sleep(5 * 1000); + + logger.info("starting humidifier " + humidifierId); + GoveeDeviceCommandResponse response = GoveeApi.getInstance(API_KEY) + .sendDeviceCommand(IHumidifierCommands.turnOn(humidifierModel, humidifierId)); + Thread.sleep(2 * 60 * 1000); // 2 min + + logger.info("stopping pump " + pumpId); + switchbotController + .getSwitchbotAPI() + .getDeviceApi() + .sendDeviceControlCommands(pumpId, IDeviceCommands.PLUG_MINI_OFF); + } catch (IOException | InterruptedException e) { + logger.error("error refilling humidifier, attempting to turn off pump " + pumpId, e); + try { + Thread.sleep(5 * 1000); // 5 sec + switchbotController + .getSwitchbotAPI() + .getDeviceApi() + .sendDeviceControlCommands(pumpId, IDeviceCommands.PLUG_MINI_OFF); + } catch (IOException | InterruptedException e2) { + logger.error("error turning off pump " + pumpId, e2); + } + } + } + } +} diff --git a/src/main/java/com/bigboxer23/lights/controllers/switchbot/SwitchBotController.java b/src/main/java/com/bigboxer23/lights/controllers/switchbot/SwitchBotController.java index a7fa9ff..2d5a7a8 100644 --- a/src/main/java/com/bigboxer23/lights/controllers/switchbot/SwitchBotController.java +++ b/src/main/java/com/bigboxer23/lights/controllers/switchbot/SwitchBotController.java @@ -5,6 +5,7 @@ import com.bigboxer23.switch_bot.SwitchBotApi; import com.bigboxer23.switch_bot.data.Device; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; @@ -15,6 +16,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; /** */ @@ -33,7 +35,7 @@ public class SwitchBotController { private SwitchBotApi api; - private SwitchBotApi getSwitchbotAPI() throws IOException { + public SwitchBotApi getSwitchbotAPI() throws IOException { if (api == null) { logger.info("initializing switchbot API"); api = SwitchBotApi.getInstance(token, secret); @@ -62,7 +64,7 @@ private String getCurtainId() throws IOException { }) public void openCurtains() throws IOException { logger.info("open curtain requested"); - getSwitchbotAPI().getDeviceApi().sendDeviceControlCommands(getCurtainId(), IDeviceCommands.OPEN_CURTAIN); + getSwitchbotAPI().getDeviceApi().sendDeviceControlCommands(getCurtainId(), IDeviceCommands.CURTAIN_OPEN); } @GetMapping(value = "/S/switchbot/closeCurtain", produces = MediaType.APPLICATION_JSON_VALUE) @@ -73,6 +75,26 @@ public void openCurtains() throws IOException { }) public void closeCurtains() throws IOException { logger.info("close curtain requested"); - getSwitchbotAPI().getDeviceApi().sendDeviceControlCommands(getCurtainId(), IDeviceCommands.CLOSE_CURTAIN); + getSwitchbotAPI().getDeviceApi().sendDeviceControlCommands(getCurtainId(), IDeviceCommands.CURTAIN_CLOSE); + } + + @GetMapping(value = "/S/switchbot/plugmini/{deviceId}/{command}", produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "control plug mini", description = "call switchbot api to control plug mini") + @ApiResponses({ + @ApiResponse(responseCode = HttpURLConnection.HTTP_BAD_REQUEST + "", description = "Bad request"), + @ApiResponse(responseCode = HttpURLConnection.HTTP_OK + "", description = "success") + }) + public void plugMini( + @Parameter(description = "deviceId to run command on") @PathVariable(value = "deviceId") String deviceId, + @Parameter(description = "command to run. Possible values [0-100, ON, OFF]") + @PathVariable(value = "command") + String command) + throws IOException { + logger.info(deviceId + ":" + command + " plug-mini requested"); + getSwitchbotAPI() + .getDeviceApi() + .sendDeviceControlCommands( + deviceId, + "on".equalsIgnoreCase(command) ? IDeviceCommands.PLUG_MINI_ON : IDeviceCommands.PLUG_MINI_OFF); } }