From 189084fbf13463b46ebc28226a6c34bcd96bc719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Czomp=C3=B3?= Date: Fri, 11 Aug 2023 00:55:36 +0200 Subject: [PATCH 1/3] Network-side rewrite and remove Android stuffs - Network-side rewrite - From now on, this sdk differentiates clientbound and serverbound packets and packages - Remove Android-related imports - [TEMPORARY] Create `ConcurrentTask` class for seamless translation from `AsyncTask` - Move `DeviceManager` to the root package - Prepare multi device type support by separating AC specific features to separate classes. --- build.gradle | 4 +- gradle.properties | 4 +- gradle/wrapper/gradle-wrapper.properties | 6 + src/main/java/eu/czsoft/greesdk/Crypto.java | 22 +- .../java/eu/czsoft/greesdk/DeviceManager.java | 277 +++++++++++++++++ .../eu/czsoft/greesdk/DeviceManagerEvent.java | 6 + .../greesdk/DeviceManagerEventListener.java | 6 + src/main/java/eu/czsoft/greesdk/Unzipped.java | 4 + src/main/java/eu/czsoft/greesdk/Utils.java | 43 ++- .../AirConditionerAppliance.java} | 72 ++--- .../AirConditionerApplianceImpl.java} | 178 +---------- .../czsoft/greesdk/appliances/Appliance.java | 18 ++ .../greesdk/appliances/ApplianceImpl.java | 135 +++++++++ .../czsoft/greesdk/appliances/Parameter.java | 34 +++ .../appliances/airconditioner/FanSpeed.java | 10 + .../appliances/airconditioner/Mode.java | 10 + .../airconditioner/TemperatureUnit.java | 6 + .../airconditioner/VerticalSwingMode.java | 16 + .../deserializers/PackDeserializer.java | 43 --- .../czsoft/greesdk/device/DeviceManager.java | 279 ------------------ .../device/DeviceManagerEventListener.java | 10 - .../{network => net}/DeviceKeyChain.java | 4 +- .../AsyncCommunicationFinishedListener.java | 2 +- .../communication}/AsyncCommunicator.java | 45 ++- .../net/packets/ClientboundPacket.java | 12 + .../eu/czsoft/greesdk/net/packets/Packet.java | 30 ++ .../net/packets/ServerboundPacket.java | 13 + .../packets/clientbound/ResponsePacket.java | 6 + .../net/packets/packs/ClientboundPack.java | 14 + .../greesdk/{ => net/packets}/packs/Pack.java | 8 +- .../net/packets/packs/ServerboundPack.java | 12 + .../packs/clientbound/BindResponsePack.java | 21 ++ .../packs/clientbound/DeviceResponsePack.java | 39 +++ .../packs/clientbound}/ResultPack.java | 9 +- .../packs/serverbound/BindRequestPack.java | 20 ++ .../serverbound/ChangeOptionRequestPack.java} | 11 +- .../packs/serverbound/CommandRequestPack.java | 21 ++ .../packs/serverbound/StatusResponsePack.java | 17 ++ .../serverbound/ApplicationPacket.java | 17 ++ .../serverbound/ScanAppliancesPacket.java | 13 + .../serverbound}/WifiSettingsPacket.java | 9 +- .../eu/czsoft/greesdk/packets/AppPacket.java | 12 - .../eu/czsoft/greesdk/packets/Packet.java | 20 -- .../eu/czsoft/greesdk/packets/ScanPacket.java | 9 - .../eu/czsoft/greesdk/packs/BindOkPack.java | 16 - .../eu/czsoft/greesdk/packs/BindPack.java | 11 - .../eu/czsoft/greesdk/packs/CommandPack.java | 17 -- .../eu/czsoft/greesdk/packs/DevicePack.java | 25 -- .../eu/czsoft/greesdk/packs/StatusPack.java | 14 - .../serialization/PackDeserializer.java | 38 +++ .../czsoft/greesdk/task/ConcurrentTask.java | 64 ++++ 51 files changed, 984 insertions(+), 748 deletions(-) create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 src/main/java/eu/czsoft/greesdk/DeviceManager.java create mode 100644 src/main/java/eu/czsoft/greesdk/DeviceManagerEvent.java create mode 100644 src/main/java/eu/czsoft/greesdk/DeviceManagerEventListener.java create mode 100644 src/main/java/eu/czsoft/greesdk/Unzipped.java rename src/main/java/eu/czsoft/greesdk/{device/Device.java => appliances/AirConditionerAppliance.java} (50%) rename src/main/java/eu/czsoft/greesdk/{device/DeviceImpl.java => appliances/AirConditionerApplianceImpl.java} (54%) create mode 100644 src/main/java/eu/czsoft/greesdk/appliances/Appliance.java create mode 100644 src/main/java/eu/czsoft/greesdk/appliances/ApplianceImpl.java create mode 100644 src/main/java/eu/czsoft/greesdk/appliances/Parameter.java create mode 100644 src/main/java/eu/czsoft/greesdk/appliances/airconditioner/FanSpeed.java create mode 100644 src/main/java/eu/czsoft/greesdk/appliances/airconditioner/Mode.java create mode 100644 src/main/java/eu/czsoft/greesdk/appliances/airconditioner/TemperatureUnit.java create mode 100644 src/main/java/eu/czsoft/greesdk/appliances/airconditioner/VerticalSwingMode.java delete mode 100644 src/main/java/eu/czsoft/greesdk/deserializers/PackDeserializer.java delete mode 100644 src/main/java/eu/czsoft/greesdk/device/DeviceManager.java delete mode 100644 src/main/java/eu/czsoft/greesdk/device/DeviceManagerEventListener.java rename src/main/java/eu/czsoft/greesdk/{network => net}/DeviceKeyChain.java (93%) rename src/main/java/eu/czsoft/greesdk/{network => net/communication}/AsyncCommunicationFinishedListener.java (69%) rename src/main/java/eu/czsoft/greesdk/{network => net/communication}/AsyncCommunicator.java (73%) create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/ClientboundPacket.java create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/Packet.java create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/ServerboundPacket.java create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/clientbound/ResponsePacket.java create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/packs/ClientboundPack.java rename src/main/java/eu/czsoft/greesdk/{ => net/packets}/packs/Pack.java (57%) create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/packs/ServerboundPack.java create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/packs/clientbound/BindResponsePack.java create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/packs/clientbound/DeviceResponsePack.java rename src/main/java/eu/czsoft/greesdk/{packs => net/packets/packs/clientbound}/ResultPack.java (53%) create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/BindRequestPack.java rename src/main/java/eu/czsoft/greesdk/{packs/DatPack.java => net/packets/packs/serverbound/ChangeOptionRequestPack.java} (51%) create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/CommandRequestPack.java create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/StatusResponsePack.java create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/serverbound/ApplicationPacket.java create mode 100644 src/main/java/eu/czsoft/greesdk/net/packets/serverbound/ScanAppliancesPacket.java rename src/main/java/eu/czsoft/greesdk/{packets => net/packets/serverbound}/WifiSettingsPacket.java (54%) delete mode 100644 src/main/java/eu/czsoft/greesdk/packets/AppPacket.java delete mode 100644 src/main/java/eu/czsoft/greesdk/packets/Packet.java delete mode 100644 src/main/java/eu/czsoft/greesdk/packets/ScanPacket.java delete mode 100644 src/main/java/eu/czsoft/greesdk/packs/BindOkPack.java delete mode 100644 src/main/java/eu/czsoft/greesdk/packs/BindPack.java delete mode 100644 src/main/java/eu/czsoft/greesdk/packs/CommandPack.java delete mode 100644 src/main/java/eu/czsoft/greesdk/packs/DevicePack.java delete mode 100644 src/main/java/eu/czsoft/greesdk/packs/StatusPack.java create mode 100644 src/main/java/eu/czsoft/greesdk/serialization/PackDeserializer.java create mode 100644 src/main/java/eu/czsoft/greesdk/task/ConcurrentTask.java diff --git a/build.gradle b/build.gradle index f1fbee0..4f5fc59 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,8 @@ dependencies { annotationProcessor 'org.projectlombok:lombok:1.18.28' implementation 'com.google.code.gson:gson:2.10.1' + implementation 'org.apache.logging.log4j:log4j-api:2.20.0' + implementation 'org.apache.logging.log4j:log4j-core:2.20.0' } publishing { repositories { @@ -47,7 +49,7 @@ publishing { } pom { name = rootProject.name - description = "An SDK to easily communicate with your Gree appliances. Separated from GreeControlAndroid." + description = "Originally separated from GreeControlAndroid, after that, it got a full network-side rewrite." url = "https://docs.czsoft.eu/greesdk?v=" + rootProject.version developers { developer { diff --git a/gradle.properties b/gradle.properties index 0cd55f2..99c5d5f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ artifactId = greesdk name = GreeSDK -version = 0.1.0 +version = 1.0.0 -mavenUrl = https://maven.czsoft.eu/ +mavenUrl = https://maven.czsoft.eu/ \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..569641c --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jul 28 12:25:52 CEST 2023 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/src/main/java/eu/czsoft/greesdk/Crypto.java b/src/main/java/eu/czsoft/greesdk/Crypto.java index 9ed568e..80f2e40 100644 --- a/src/main/java/eu/czsoft/greesdk/Crypto.java +++ b/src/main/java/eu/czsoft/greesdk/Crypto.java @@ -1,35 +1,37 @@ package eu.czsoft.greesdk; -import android.util.Base64; -import android.util.Log; +import lombok.extern.log4j.Log4j2; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; +import java.util.Base64; +@Log4j2 public class Crypto { - private static final String LOG_TAG = "Crypto"; - public static String GENERIC_KEY = "a3K8Bx%2r8Y7#xDh"; + protected static String GENERIC_KEY = "a3K8Bx%2r8Y7#xDh"; - public static String encrypt(String plainText, String key) { + protected static String encrypt(String plainText, String key) { try { Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKeySpec keySpec = new SecretKeySpec(key.getBytes("ASCII"), "AES"); c.init(Cipher.ENCRYPT_MODE, keySpec); byte[] encrypted = c.doFinal(plainText.getBytes("UTF-8")); - String encoded = new String(Base64.encode(encrypted, Base64.DEFAULT)); + String encoded = new String(Base64.getEncoder().encode(encrypted)); return encoded; } catch (Exception e) { - Log.e(LOG_TAG, "Pack encryption failed. Error: " + e.getMessage()); + LOGGER.error("Pack encryption failed. Error: " + e.getMessage()); } return ""; } - public static String decrypt(String encrypted, String key) { + protected static String decrypt(String encrypted, String key) { try { - byte[] decoded = Base64.decode(encrypted, Base64.DEFAULT); + byte[] decoded = Base64.getDecoder().decode(encrypted); Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding"); SecretKeySpec keySpec = new SecretKeySpec(key.getBytes("ASCII"), "AES"); @@ -38,7 +40,7 @@ public static String decrypt(String encrypted, String key) { byte[] decrypted = c.doFinal(decoded); return new String(decrypted); } catch (Exception e) { - Log.e(LOG_TAG, "Pack decryption failed. Error: " + e.getMessage()); + LOGGER.error("Pack decryption failed. Error: " + e.getMessage()); } return ""; diff --git a/src/main/java/eu/czsoft/greesdk/DeviceManager.java b/src/main/java/eu/czsoft/greesdk/DeviceManager.java new file mode 100644 index 0000000..6919965 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/DeviceManager.java @@ -0,0 +1,277 @@ +package eu.czsoft.greesdk; + +import eu.czsoft.greesdk.appliances.ApplianceImpl; +import eu.czsoft.greesdk.appliances.Appliance; +import eu.czsoft.greesdk.appliances.Parameter; +import eu.czsoft.greesdk.net.DeviceKeyChain; +import eu.czsoft.greesdk.net.communication.AsyncCommunicationFinishedListener; +import eu.czsoft.greesdk.net.communication.AsyncCommunicator; +import eu.czsoft.greesdk.net.packets.Packet; +import eu.czsoft.greesdk.net.packets.packs.clientbound.BindResponsePack; +import eu.czsoft.greesdk.net.packets.packs.clientbound.DeviceResponsePack; +import eu.czsoft.greesdk.net.packets.packs.clientbound.ResultPack; +import eu.czsoft.greesdk.net.packets.packs.serverbound.BindRequestPack; +import eu.czsoft.greesdk.net.packets.packs.serverbound.ChangeOptionRequestPack; +import eu.czsoft.greesdk.net.packets.packs.serverbound.CommandRequestPack; +import eu.czsoft.greesdk.net.packets.packs.serverbound.StatusResponsePack; +import eu.czsoft.greesdk.net.packets.serverbound.ApplicationPacket; +import eu.czsoft.greesdk.net.packets.serverbound.ScanAppliancesPacket; +import eu.czsoft.greesdk.net.packets.serverbound.WifiSettingsPacket; +import lombok.extern.log4j.Log4j2; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +@Log4j2 +public class DeviceManager { + private final int DATAGRAM_PORT = 7000; + + private static DeviceManager instance = null; + + private final HashMap devices = new HashMap<>(); + private final DeviceKeyChain keyChain = new DeviceKeyChain(); + private final ArrayList eventListeners = new ArrayList<>(); + + public static DeviceManager getInstance() { + if (instance == null) + instance = new DeviceManager(); + + return instance; + } + + protected DeviceManager() { + LOGGER.info("Created"); + } + + public Appliance[] getDevices() { + return devices.values().toArray(new Appliance[0]); + } + + public Appliance getDevice(String deviceId) { + if (devices.containsKey(deviceId)) + return devices.get(deviceId); + + return null; + } + + public void registerEventListener(DeviceManagerEventListener listener) { + if (!eventListeners.contains(listener)) + eventListeners.add(listener); + } + + public void unregisterEventListener(DeviceManagerEventListener listener) { + eventListeners.remove(listener); + } + + public void setParameter(ApplianceImpl device, String name, int value) { + HashMap p = new HashMap<>(); + p.put(name, value); + + setParameters(device, p); + } + + public void setParameters(ApplianceImpl device, Map parameters) { + LOGGER.debug(String.format("Setting parameters of %s: %s", device.getId(), parameters)); + + ApplicationPacket packet = new ApplicationPacket(); + packet.targetClientId = device.getId(); + packet.i = 0; + + CommandRequestPack pack = new CommandRequestPack(); + pack.options = parameters.keySet().toArray(new String[0]); + pack.values = parameters.values().toArray(new Integer[0]); + pack.mac = packet.targetClientId; + + packet.pack = pack; + + final AsyncCommunicator comm = new AsyncCommunicator(keyChain); + comm.setCommunicationFinishedListener(new AsyncCommunicationFinishedListener() { + @Override + public void onFinished() { + try { + final Packet[] responses = comm.get(); + + for (Packet response : responses) { + if (devices.containsKey(response.clientId)) { + devices.get(response.clientId).updateWithResultPack((ResultPack) response.pack); + } + } + + sendEvent(DeviceManagerEvent.DEVICE_STATUS_UPDATED); + } catch (Exception e) { + LOGGER.error("Failed to get response of command. Error: " + e.getMessage()); + } + } + }); + comm.execute(new Packet[] { packet }); + } + + public void setWiFi(String ssid, String password){ + + WifiSettingsPacket packet = new WifiSettingsPacket(); + packet.password = password; + packet.ssid = ssid; + + final AsyncCommunicator comm = new AsyncCommunicator(keyChain); + comm.setCommunicationFinishedListener(new AsyncCommunicationFinishedListener() { + @Override + public void onFinished() { + try { + final Packet[] responses = comm.get(); + + for (Packet response : responses) { + if (devices.containsKey(response.clientId)) { + devices.get(response.clientId).updateWithResultPack((ResultPack) response.pack); + } + } + + sendEvent(DeviceManagerEvent.DEVICE_STATUS_UPDATED); + } catch (Exception e) { + LOGGER.error("Failed to get response of command. Error: " + e.getMessage()); + } + } + }); + comm.execute(new Packet[] { packet }); + } + + public void discoverDevices() { + LOGGER.info("Device discovery running..."); + + final AsyncCommunicator comm = new AsyncCommunicator(); + comm.setCommunicationFinishedListener(new AsyncCommunicationFinishedListener() { + @Override + public void onFinished() { + try { + Packet[] responses = comm.get(); + LOGGER.info(String.format("Got %d response(s)", responses.length)); + + bindDevices(responses); + } catch (Exception e) { + LOGGER.debug("Device discovery failed with exception\n" + e); + } + } + }); + + ScanAppliancesPacket sp = new ScanAppliancesPacket(); + + comm.execute(new ScanAppliancesPacket[]{ sp }); + } + + public void updateDevices() { + if (devices.isEmpty()) { + LOGGER.info("No devices to update"); + return; + } + + LOGGER.info(String.format("Updating %d device(s)", devices.size())); + + ArrayList packets = new ArrayList<>(); + + ArrayList keys = new ArrayList<>(); + for (Parameter p : Parameter.values()) { + keys.add(p.toString()); + } + + for (ApplianceImpl device : devices.values()) { + ApplicationPacket packet = new ApplicationPacket(); + packet.targetClientId = device.getId(); + packet.i = 0; + + StatusResponsePack pack = new StatusResponsePack(); + pack.options = keys.toArray(new String[0]); + pack.mac = device.getId(); + packet.pack = pack; + + packets.add(packet); + } + + final AsyncCommunicator comm = new AsyncCommunicator(keyChain); + comm.setCommunicationFinishedListener(new AsyncCommunicationFinishedListener() { + @Override + public void onFinished() { + try { + Packet[] responses = comm.get(); + + for (Packet response : responses) { + if (devices.containsKey(response.clientId)) { + devices.get(response.clientId).updateWithDatPack((ChangeOptionRequestPack) response.pack); + } + } + + sendEvent(DeviceManagerEvent.DEVICE_STATUS_UPDATED); + + } catch (Exception e) { + LOGGER.warn("Failed to get device update result. Error: " + e.getMessage()); + } + } + }); + comm.execute(packets.toArray(new Packet[0])); + } + + private void bindDevices(Packet[] scanResponses) throws IOException { + ArrayList requests = new ArrayList<>(); + + for (int i = 0; i < scanResponses.length; i++) { + Packet response = scanResponses[i]; + + if (!(response.pack instanceof DeviceResponsePack devicePack)) + continue; + + ApplianceImpl device; + + if (!devices.containsKey(response.clientId)) { + device = new ApplianceImpl(devicePack.mac, this); + devices.put(devicePack.mac, device); + } else { + device = devices.get(response.clientId); + } + device.updateWithDevicePack(devicePack); + + if (!keyChain.containsKey(response.clientId)) { + LOGGER.info("Binding device: " + devicePack.name); + + ApplicationPacket request = new ApplicationPacket(); + request.targetClientId = response.clientId; + request.pack = new BindRequestPack(); + request.pack.mac = request.targetClientId; + request.i = 1; + + requests.add(request); + } + } + + final AsyncCommunicator comm = new AsyncCommunicator(keyChain); + comm.setCommunicationFinishedListener(new AsyncCommunicationFinishedListener() { + @Override + public void onFinished() { + try { + Packet[] responses = comm.get(); + storeDevices(responses); + } catch (Exception e) { + LOGGER.debug("Device discovery failed with exception\n" + e); + } + } + }); + comm.execute(requests.toArray(new Packet[0])); + } + + private void storeDevices(Packet[] bindResponses) { + for (Packet response : bindResponses) { + if (!(response.pack instanceof BindResponsePack pack)) + continue; + + LOGGER.info("Storing key for device: " + pack.mac); + keyChain.addKey(pack.mac, pack.deviceKey); + } + + sendEvent(DeviceManagerEvent.DEVICE_LIST_UPDATED); + updateDevices(); + } + + private void sendEvent(DeviceManagerEvent event) { + for (DeviceManagerEventListener listener : eventListeners) + listener.onEvent(event); + } +} diff --git a/src/main/java/eu/czsoft/greesdk/DeviceManagerEvent.java b/src/main/java/eu/czsoft/greesdk/DeviceManagerEvent.java new file mode 100644 index 0000000..c6e745a --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/DeviceManagerEvent.java @@ -0,0 +1,6 @@ +package eu.czsoft.greesdk; + +public enum DeviceManagerEvent { + DEVICE_LIST_UPDATED, + DEVICE_STATUS_UPDATED +} diff --git a/src/main/java/eu/czsoft/greesdk/DeviceManagerEventListener.java b/src/main/java/eu/czsoft/greesdk/DeviceManagerEventListener.java new file mode 100644 index 0000000..d6e6472 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/DeviceManagerEventListener.java @@ -0,0 +1,6 @@ +package eu.czsoft.greesdk; + +public interface DeviceManagerEventListener { + + void onEvent(DeviceManagerEvent event); +} diff --git a/src/main/java/eu/czsoft/greesdk/Unzipped.java b/src/main/java/eu/czsoft/greesdk/Unzipped.java new file mode 100644 index 0000000..fb4e602 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/Unzipped.java @@ -0,0 +1,4 @@ +package eu.czsoft.greesdk; + +public record Unzipped(String[] keys, Integer[] values) { +} diff --git a/src/main/java/eu/czsoft/greesdk/Utils.java b/src/main/java/eu/czsoft/greesdk/Utils.java index 912a2f8..6df87eb 100644 --- a/src/main/java/eu/czsoft/greesdk/Utils.java +++ b/src/main/java/eu/czsoft/greesdk/Utils.java @@ -1,31 +1,22 @@ package eu.czsoft.greesdk; -import android.util.Log; - import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import eu.czsoft.greesdk.net.DeviceKeyChain; +import eu.czsoft.greesdk.net.packets.Packet; +import eu.czsoft.greesdk.net.packets.packs.Pack; +import eu.czsoft.greesdk.net.packets.packs.serverbound.ChangeOptionRequestPack; +import eu.czsoft.greesdk.serialization.PackDeserializer; +import lombok.extern.log4j.Log4j2; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.HashMap; import java.util.Map; -import eu.czsoft.greesdk.deserializers.PackDeserializer; -import eu.czsoft.greesdk.network.DeviceKeyChain; -import eu.czsoft.greesdk.packets.Packet; -import eu.czsoft.greesdk.packs.DatPack; -import eu.czsoft.greesdk.packs.Pack; - +@Log4j2 public class Utils { - public static class Unzipped { - public final String[] keys; - public final Integer[] values; - - public Unzipped(String[] keys, Integer[] values) { - this.keys = keys; - this.values = values; - } - } - public static Map zip(String[] keys, Integer[] values) throws IllegalArgumentException { if (keys.length != values.length) throw new IllegalArgumentException("Length of keys and values must match"); @@ -38,11 +29,11 @@ public static Map zip(String[] keys, Integer[] values) throws I return zipped; } - public static Unzipped unzip(Map map) { + protected static Unzipped unzip(Map map) { return new Unzipped(map.keySet().toArray(new String[0]), map.values().toArray(new Integer[0])); } - public static Map getValues(DatPack pack) { + protected static Map getValues(ChangeOptionRequestPack pack) { return zip(pack.keys, pack.values); } @@ -76,16 +67,16 @@ public static Packet deserializePacket(String jsonString, DeviceKeyChain deviceK return packet; } - private static String getKey(DeviceKeyChain keyChain, Packet packet) { + protected static String getKey(DeviceKeyChain keyChain, Packet packet) { String key = Crypto.GENERIC_KEY; - Log.i("getKey", String.format("packet.cid: %s, packet.tcid: %s", packet.cid, packet.tcid)); + LOGGER.info(String.format("packet.cid: %s, packet.tcid: %s", packet.clientId, packet.targetClientId)); if (keyChain != null) { - if (keyChain.containsKey(packet.cid)) { - key = keyChain.getKey(packet.cid); - } else if (keyChain.containsKey(packet.tcid)) { - key = keyChain.getKey(packet.tcid); + if (keyChain.containsKey(packet.clientId)) { + key = keyChain.getKey(packet.clientId); + } else if (keyChain.containsKey(packet.targetClientId)) { + key = keyChain.getKey(packet.targetClientId); } } diff --git a/src/main/java/eu/czsoft/greesdk/device/Device.java b/src/main/java/eu/czsoft/greesdk/appliances/AirConditionerAppliance.java similarity index 50% rename from src/main/java/eu/czsoft/greesdk/device/Device.java rename to src/main/java/eu/czsoft/greesdk/appliances/AirConditionerAppliance.java index dfe3e81..48e7e35 100644 --- a/src/main/java/eu/czsoft/greesdk/device/Device.java +++ b/src/main/java/eu/czsoft/greesdk/appliances/AirConditionerAppliance.java @@ -1,90 +1,58 @@ -package eu.czsoft.greesdk.device; - -public interface Device { - - enum Mode { - AUTO, - COOL, - DRY, - FAN, - HEAT - } - - enum FanSpeed { - AUTO, - LOW, - MEDIUM_LOW, - MEDIUM, - MEDIUM_HIGH, - HIGH - } - - enum TemperatureUnit { - CELSIUS, - FAHRENHEIT - } - - enum VerticalSwingMode { - DEFAULT, - FULL, - FIXED_TOP, - FIXED_MIDDLE_TOP, - FIXED_MIDDLE, - FIXED_MIDDLE_BOTTOM, - FIXED_BOTTOM, - SWING_BOTTOM, - SWING_MIDDLE_BOTTOM, - SWING_MIDDLE, - SWING_MIDDLE_TOP, - SWING_TOP - } - - String getId(); - - String getName(); - void setName(String name); +package eu.czsoft.greesdk.appliances; + +import eu.czsoft.greesdk.appliances.airconditioner.FanSpeed; +import eu.czsoft.greesdk.appliances.airconditioner.Mode; +import eu.czsoft.greesdk.appliances.airconditioner.TemperatureUnit; +import eu.czsoft.greesdk.appliances.airconditioner.VerticalSwingMode; + +public interface AirConditionerAppliance extends Appliance { Mode getMode(); + void setMode(Mode mode); FanSpeed getFanSpeed(); + void setFanSpeed(FanSpeed fanSpeed); int getTemperature(); - void setTemperature(int value, TemperatureUnit unit); - boolean isPoweredOn(); - void setPoweredOn(boolean poweredOn); + void setTemperature(int value, TemperatureUnit unit); boolean isLightEnabled(); + void setLightEnabled(boolean enabled); boolean isQuietModeEnabled(); + void setQuietModeEnabled(boolean enabled); boolean isTurboModeEnabled(); + void setTurboModeEnabled(boolean enabled); boolean isHealthModeEnabled(); + void setHealthModeEnabled(boolean enabled); boolean isAirModeEnabled(); + void setAirModeEnabled(boolean enabled); boolean isXfanModeEnabled(); + void setXfanModeEnabled(boolean enabled); boolean isSavingModeEnabled(); + void setSavingModeEnabled(boolean enabled); boolean isSleepEnabled(); + void setSleepEnabled(boolean enabled); VerticalSwingMode getVerticalSwingMode(); - void setVerticalSwingMode(VerticalSwingMode mode); - int getParameter(String name); - void setParameter(String name, int value); + void setVerticalSwingMode(VerticalSwingMode mode); - void setWifiDetails(String ssid, String password); } diff --git a/src/main/java/eu/czsoft/greesdk/device/DeviceImpl.java b/src/main/java/eu/czsoft/greesdk/appliances/AirConditionerApplianceImpl.java similarity index 54% rename from src/main/java/eu/czsoft/greesdk/device/DeviceImpl.java rename to src/main/java/eu/czsoft/greesdk/appliances/AirConditionerApplianceImpl.java index ddaa984..07a06f9 100644 --- a/src/main/java/eu/czsoft/greesdk/device/DeviceImpl.java +++ b/src/main/java/eu/czsoft/greesdk/appliances/AirConditionerApplianceImpl.java @@ -1,59 +1,19 @@ -package eu.czsoft.greesdk.device; +package eu.czsoft.greesdk.appliances; -import android.util.Log; +import eu.czsoft.greesdk.appliances.airconditioner.FanSpeed; +import eu.czsoft.greesdk.appliances.airconditioner.Mode; +import eu.czsoft.greesdk.appliances.airconditioner.TemperatureUnit; +import eu.czsoft.greesdk.appliances.airconditioner.VerticalSwingMode; +import eu.czsoft.greesdk.DeviceManager; +import org.apache.logging.log4j.LogManager; import java.util.Map; -import eu.czsoft.greesdk.packs.DatPack; -import eu.czsoft.greesdk.packs.DevicePack; -import eu.czsoft.greesdk.packs.ResultPack; -import eu.czsoft.greesdk.Utils; - -class DeviceImpl implements Device { - private final String deviceId; - private final DeviceManager deviceManager; - private final String logTag; - - public enum Parameter { - POWER ("Pow"), - MODE ("Mod"), - TEMPERATURE ("SetTem"), - TEMPERATURE_UNIT ("TemUn"), - FAN_SPEED ("WdSpd"), - AIR_MODE ("Air"), - XFAN_MODE ("Blo"), - HEALTH_MODE ("Health"), - SLEEP ("SwhSlp"), - SLEEP_MODE ("SlpMod"), - QUIET_MODE ("Quiet"), - TURBO_MODE ("Tur"), - SAVING_MODE ("SvSt"), - LIGHT ("Lig"), - HORIZONTAL_SWING ("SwingLfRig"), - VERTICAL_SWING ("SwUpDn"), - STHT_MODE ("StHt"), - HEAT_COOL_TYPE ("HeatCoolType"), - TEM_REC_MODE ("TemRec") - ; - - private final String param; - - Parameter(final String param) { - this.param = param; - } - - @Override - public String toString() { - return param; - } - } - - private String name = ""; +public class AirConditionerApplianceImpl extends ApplianceImpl implements AirConditionerAppliance { private Mode mode = Mode.AUTO; private FanSpeed fanSpeed = FanSpeed.AUTO; private int temperature = 0; private TemperatureUnit temperatureUnit = TemperatureUnit.CELSIUS; - private boolean poweredOn; private boolean lightEnabled; private boolean quietModeEnabled; private boolean turboModeEnabled; @@ -65,39 +25,10 @@ public String toString() { private boolean sleepModeEnabled; private VerticalSwingMode verticalSwingMode = VerticalSwingMode.DEFAULT; - public DeviceImpl(String deviceId, DeviceManager deviceManager) { - this.deviceId = deviceId; - this.deviceManager = deviceManager; - this.logTag = String.format("DeviceImpl(%s)", deviceId); - - Log.i(this.logTag, "Created"); - } - - public void updateWithDatPack(DatPack pack) { - updateParameters(Utils.zip(pack.keys, pack.values)); - } - - public void updateWithResultPack(ResultPack pack) { - updateParameters(Utils.zip(pack.keys, pack.values)); - } - - public void updateWithDevicePack(DevicePack pack) { - Log.d(logTag, "Updating name: " + pack.name); - name = pack.name; - } - - @Override - public String getId() { - return deviceId; - } - - @Override - public String getName() { - return name; - } + public AirConditionerApplianceImpl(String deviceId, DeviceManager deviceManager) { + super(deviceId, deviceManager); - @Override - public void setName(String name) { + LOGGER = LogManager.getLogger(String.format("AirConditioner(%s)", deviceId)); } @Override @@ -133,16 +64,6 @@ public void setTemperature(int value, TemperatureUnit unit) { ); } - @Override - public boolean isPoweredOn() { - return poweredOn; - } - - @Override - public void setPoweredOn(boolean poweredOn) { - setParameter(Parameter.POWER, poweredOn ? 1 : 0); - } - @Override public boolean isLightEnabled() { return lightEnabled; @@ -233,57 +154,13 @@ public void setVerticalSwingMode(VerticalSwingMode mode) { setParameter(Parameter.VERTICAL_SWING, mode.ordinal()); } - @Override - public int getParameter(String name) { - return 0; - } - - @Override - public void setParameter(String name, int value) { - deviceManager.setParameter(this, name, value); - } - - @Override - public void setWifiDetails(String ssid, String password) { - deviceManager.setWifi(ssid, password); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - DeviceImpl device = (DeviceImpl) o; - - return deviceId.equals(device.deviceId); - } - - @Override - public int hashCode() { - return deviceId.hashCode(); - } - - private void setParameter(Parameter parameter, int value) { - setParameter(parameter.toString(), value); - } - - private void setParameters(Parameter[] parameters, Integer[] values) { - String[] names = new String[parameters.length]; - for (int i = 0; i < parameters.length; i++) { - names[i] = parameters[i].toString(); - } - - deviceManager.setParameters(this, Utils.zip(names, values)); - } - - private void updateParameters(Map parameterMap) { - Log.d(logTag, "Updating parameterMap: " + parameterMap); + void updateParameters(Map parameterMap) { + super.updateParameters(parameterMap); mode = getEnumParameter(parameterMap, Parameter.MODE, Mode.values(), mode); fanSpeed = getEnumParameter(parameterMap, Parameter.FAN_SPEED, FanSpeed.values(), fanSpeed); temperature = getOrdinalParameter(parameterMap, Parameter.TEMPERATURE, temperature); temperatureUnit = getEnumParameter(parameterMap, Parameter.TEMPERATURE_UNIT, TemperatureUnit.values(), temperatureUnit); - poweredOn = getBooleanParameter(parameterMap, Parameter.POWER, poweredOn); lightEnabled = getBooleanParameter(parameterMap, Parameter.LIGHT, lightEnabled); quietModeEnabled = getBooleanParameter(parameterMap, Parameter.QUIET_MODE, quietModeEnabled); turboModeEnabled = getBooleanParameter(parameterMap, Parameter.TURBO_MODE, turboModeEnabled); @@ -296,39 +173,16 @@ private void updateParameters(Map parameterMap) { verticalSwingMode = getEnumParameter(parameterMap, Parameter.VERTICAL_SWING, VerticalSwingMode.values(), verticalSwingMode); } - private static E getEnumParameter(Map parameterMap, Parameter parameter, E[] values, E def) { - if (parameterMap.containsKey(parameter.toString())) { - int ordinal = parameterMap.get(parameter.toString()); - if (ordinal >= 0 && ordinal < values.length) { - return values[ordinal]; - } - } - - return def; - } - - private static int getOrdinalParameter(Map parameterMap, Parameter parameter, int def) { - if (parameterMap.containsKey(parameter.toString())) - return parameterMap.get(parameter.toString()); - return def; - } - - private static boolean getBooleanParameter(Map parameterMap, Parameter parameter, boolean def) { - return getOrdinalParameter(parameterMap, parameter, def ? 1 : 0) == 1; - } - @Override public String toString() { - return "DeviceImpl{" + + return "AirConditionerApplianceImpl{" + "deviceId='" + deviceId + '\'' + - ", deviceManager=" + deviceManager + - ", logTag='" + logTag + '\'' + - ", name='" + name + '\'' + + ", name='" + getName() + '\'' + + ", poweredOn=" + isPoweredOn() + ", mode=" + mode + ", fanSpeed=" + fanSpeed + ", temperature=" + temperature + ", temperatureUnit=" + temperatureUnit + - ", poweredOn=" + poweredOn + ", lightEnabled=" + lightEnabled + ", quietModeEnabled=" + quietModeEnabled + ", turboModeEnabled=" + turboModeEnabled + diff --git a/src/main/java/eu/czsoft/greesdk/appliances/Appliance.java b/src/main/java/eu/czsoft/greesdk/appliances/Appliance.java new file mode 100644 index 0000000..9f190d5 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/appliances/Appliance.java @@ -0,0 +1,18 @@ +package eu.czsoft.greesdk.appliances; + +public interface Appliance { + String getId(); + + String getName(); + + void setName(String name); + + boolean isPoweredOn(); + void setPoweredOn(boolean value); + + int getParameter(String name); + + void setParameter(String name, int value); + + void setWifiDetails(String ssid, String password); +} diff --git a/src/main/java/eu/czsoft/greesdk/appliances/ApplianceImpl.java b/src/main/java/eu/czsoft/greesdk/appliances/ApplianceImpl.java new file mode 100644 index 0000000..7ec9ba7 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/appliances/ApplianceImpl.java @@ -0,0 +1,135 @@ +package eu.czsoft.greesdk.appliances; + +import eu.czsoft.greesdk.Utils; +import eu.czsoft.greesdk.DeviceManager; +import eu.czsoft.greesdk.net.packets.packs.clientbound.DeviceResponsePack; +import eu.czsoft.greesdk.net.packets.packs.clientbound.ResultPack; +import eu.czsoft.greesdk.net.packets.packs.serverbound.ChangeOptionRequestPack; +import org.apache.logging.log4j.Logger; + +import java.util.Map; + +public class ApplianceImpl implements Appliance { + Logger LOGGER; + + final String deviceId; + final DeviceManager deviceManager; + + public ApplianceImpl(String deviceId, DeviceManager deviceManager) { + this.deviceId = deviceId; + this.deviceManager = deviceManager; + } + + private String name = ""; + private boolean poweredOn; + + + public void updateWithDatPack(ChangeOptionRequestPack pack) { + updateParameters(Utils.zip(pack.keys, pack.values)); + } + + public void updateWithResultPack(ResultPack pack) { + updateParameters(Utils.zip(pack.options, pack.values)); + } + + public void updateWithDevicePack(DeviceResponsePack pack) { + LOGGER.debug("Updating name: " + pack.name); + name = pack.name; + } + + @Override + public String getId() { + return deviceId; + } + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + } + + @Override + public boolean isPoweredOn() { + return poweredOn; + } + + @Override + public void setPoweredOn(boolean newState) { + setParameter(Parameter.POWER, newState ? 1 : 0); + } + + @Override + public int getParameter(String name) { + return 0; + } + + @Override + public void setParameter(String name, int value) { + deviceManager.setParameter(this, name, value); + } + + @Override + public void setWifiDetails(String ssid, String password) { + deviceManager.setWiFi(ssid, password); + } + + void setParameter(Parameter parameter, int value) { + setParameter(parameter.toString(), value); + } + + void setParameters(Parameter[] parameters, Integer[] values) { + String[] names = new String[parameters.length]; + for (int i = 0; i < parameters.length; i++) { + names[i] = parameters[i].toString(); + } + + deviceManager.setParameters(this, Utils.zip(names, values)); + } + + + void updateParameters(Map parameterMap) { + LOGGER.debug("Updating parameterMap: " + parameterMap); + + poweredOn = getBooleanParameter(parameterMap, Parameter.POWER, poweredOn); + } + + static E getEnumParameter(Map parameterMap, Parameter parameter, E[] values, E def) { + if (parameterMap.containsKey(parameter.toString())) { + int ordinal = parameterMap.get(parameter.toString()); + if (ordinal >= 0 && ordinal < values.length) { + return values[ordinal]; + } + } + + return def; + } + + static int getOrdinalParameter(Map parameterMap, Parameter parameter, int def) { + if (parameterMap.containsKey(parameter.toString())) + return parameterMap.get(parameter.toString()); + return def; + } + + static boolean getBooleanParameter(Map parameterMap, Parameter parameter, boolean def) { + return getOrdinalParameter(parameterMap, parameter, def ? 1 : 0) == 1; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ApplianceImpl device = (ApplianceImpl) o; + + return deviceId.equals(device.deviceId); + } + + @Override + public int hashCode() { + return deviceId.hashCode(); + } + +} diff --git a/src/main/java/eu/czsoft/greesdk/appliances/Parameter.java b/src/main/java/eu/czsoft/greesdk/appliances/Parameter.java new file mode 100644 index 0000000..94e6de1 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/appliances/Parameter.java @@ -0,0 +1,34 @@ +package eu.czsoft.greesdk.appliances; + +public enum Parameter { + POWER("Pow"), + MODE("Mod"), + TEMPERATURE("SetTem"), + TEMPERATURE_UNIT("TemUn"), + FAN_SPEED("WdSpd"), + AIR_MODE("Air"), + XFAN_MODE("Blo"), + HEALTH_MODE("Health"), + SLEEP("SwhSlp"), + SLEEP_MODE("SlpMod"), + QUIET_MODE("Quiet"), + TURBO_MODE("Tur"), + SAVING_MODE("SvSt"), + LIGHT("Lig"), + HORIZONTAL_SWING("SwingLfRig"), + VERTICAL_SWING("SwUpDn"), + STHT_MODE("StHt"), + HEAT_COOL_TYPE("HeatCoolType"), + TEM_REC_MODE("TemRec"); + + private final String param; + + Parameter(final String param) { + this.param = param; + } + + @Override + public String toString() { + return param; + } +} diff --git a/src/main/java/eu/czsoft/greesdk/appliances/airconditioner/FanSpeed.java b/src/main/java/eu/czsoft/greesdk/appliances/airconditioner/FanSpeed.java new file mode 100644 index 0000000..94940e6 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/appliances/airconditioner/FanSpeed.java @@ -0,0 +1,10 @@ +package eu.czsoft.greesdk.appliances.airconditioner; + +public enum FanSpeed { + AUTO, + LOW, + MEDIUM_LOW, + MEDIUM, + MEDIUM_HIGH, + HIGH +} diff --git a/src/main/java/eu/czsoft/greesdk/appliances/airconditioner/Mode.java b/src/main/java/eu/czsoft/greesdk/appliances/airconditioner/Mode.java new file mode 100644 index 0000000..8554b5b --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/appliances/airconditioner/Mode.java @@ -0,0 +1,10 @@ +package eu.czsoft.greesdk.appliances.airconditioner; + +public enum Mode { + AUTO, + COOL, + DRY, + FAN, + HEAT +} + diff --git a/src/main/java/eu/czsoft/greesdk/appliances/airconditioner/TemperatureUnit.java b/src/main/java/eu/czsoft/greesdk/appliances/airconditioner/TemperatureUnit.java new file mode 100644 index 0000000..ae6dcba --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/appliances/airconditioner/TemperatureUnit.java @@ -0,0 +1,6 @@ +package eu.czsoft.greesdk.appliances.airconditioner; + +public enum TemperatureUnit { + CELSIUS, + FAHRENHEIT +} diff --git a/src/main/java/eu/czsoft/greesdk/appliances/airconditioner/VerticalSwingMode.java b/src/main/java/eu/czsoft/greesdk/appliances/airconditioner/VerticalSwingMode.java new file mode 100644 index 0000000..018e39d --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/appliances/airconditioner/VerticalSwingMode.java @@ -0,0 +1,16 @@ +package eu.czsoft.greesdk.appliances.airconditioner; + +public enum VerticalSwingMode { + DEFAULT, + FULL, + FIXED_TOP, + FIXED_MIDDLE_TOP, + FIXED_MIDDLE, + FIXED_MIDDLE_BOTTOM, + FIXED_BOTTOM, + SWING_BOTTOM, + SWING_MIDDLE_BOTTOM, + SWING_MIDDLE, + SWING_MIDDLE_TOP, + SWING_TOP +} diff --git a/src/main/java/eu/czsoft/greesdk/deserializers/PackDeserializer.java b/src/main/java/eu/czsoft/greesdk/deserializers/PackDeserializer.java deleted file mode 100644 index 808bee3..0000000 --- a/src/main/java/eu/czsoft/greesdk/deserializers/PackDeserializer.java +++ /dev/null @@ -1,43 +0,0 @@ -package eu.czsoft.greesdk.deserializers; - -import eu.czsoft.greesdk.packs.BindOkPack; -import eu.czsoft.greesdk.packs.BindPack; -import eu.czsoft.greesdk.packs.DatPack; -import eu.czsoft.greesdk.packs.DevicePack; -import eu.czsoft.greesdk.packs.Pack; -import eu.czsoft.greesdk.packs.ResultPack; -import eu.czsoft.greesdk.packs.StatusPack; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; - -import java.lang.reflect.Type; - -public class PackDeserializer implements JsonDeserializer { - - @Override - public Pack deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { - JsonObject jsonObject = jsonElement.getAsJsonObject(); - - String packType = jsonObject.get("t").getAsString(); - - if (packType.equalsIgnoreCase(BindOkPack.TYPE)) { - return jsonDeserializationContext.deserialize(jsonObject, BindOkPack.class); - } else if (packType.equalsIgnoreCase(BindPack.TYPE)) { - return jsonDeserializationContext.deserialize(jsonObject, BindPack.class); - } else if (packType.equalsIgnoreCase(DatPack.TYPE)) { - return jsonDeserializationContext.deserialize(jsonObject, DatPack.class); - } else if (packType.equalsIgnoreCase(ResultPack.TYPE)) { - return jsonDeserializationContext.deserialize(jsonObject, ResultPack.class); - } else if (packType.equalsIgnoreCase(StatusPack.TYPE)) { - return jsonDeserializationContext.deserialize(jsonObject, StatusPack.class); - } else if (packType.equalsIgnoreCase(DevicePack.TYPE)) { - return jsonDeserializationContext.deserialize(jsonObject, DevicePack.class); - } - - return null; - } -} diff --git a/src/main/java/eu/czsoft/greesdk/device/DeviceManager.java b/src/main/java/eu/czsoft/greesdk/device/DeviceManager.java deleted file mode 100644 index 29b6e1c..0000000 --- a/src/main/java/eu/czsoft/greesdk/device/DeviceManager.java +++ /dev/null @@ -1,279 +0,0 @@ -package eu.czsoft.greesdk.device; - -import android.util.Log; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import eu.czsoft.greesdk.network.AsyncCommunicationFinishedListener; -import eu.czsoft.greesdk.network.AsyncCommunicator; -import eu.czsoft.greesdk.network.DeviceKeyChain; -import eu.czsoft.greesdk.packets.AppPacket; -import eu.czsoft.greesdk.packets.Packet; -import eu.czsoft.greesdk.packets.ScanPacket; -import eu.czsoft.greesdk.packets.WifiSettingsPacket; -import eu.czsoft.greesdk.packs.BindOkPack; -import eu.czsoft.greesdk.packs.BindPack; -import eu.czsoft.greesdk.packs.CommandPack; -import eu.czsoft.greesdk.packs.DatPack; -import eu.czsoft.greesdk.packs.DevicePack; -import eu.czsoft.greesdk.packs.ResultPack; -import eu.czsoft.greesdk.packs.StatusPack; - -public class DeviceManager { - private final String LOG_TAG = "DeviceManager"; - private final int DATAGRAM_PORT = 7000; - - private static DeviceManager instance = null; - - private final HashMap devices = new HashMap<>(); - private final DeviceKeyChain keyChain = new DeviceKeyChain(); - private final ArrayList eventListeners = new ArrayList<>(); - - public static DeviceManager getInstance() { - if (instance == null) - instance = new DeviceManager(); - - return instance; - } - - protected DeviceManager() { - Log.i(LOG_TAG, "Created"); - } - - public Device[] getDevices() { - return devices.values().toArray(new Device[0]); - } - - public Device getDevice(String deviceId) { - if (devices.containsKey(deviceId)) - return devices.get(deviceId); - - return null; - } - - public void registerEventListener(DeviceManagerEventListener listener) { - if (!eventListeners.contains(listener)) - eventListeners.add(listener); - } - - public void unregisterEventListener(DeviceManagerEventListener listener) { - eventListeners.remove(listener); - } - - public void setParameter(Device device, String name, int value) { - HashMap p = new HashMap<>(); - p.put(name, value); - - setParameters(device, p); - } - - public void setParameters(Device device, Map parameters) { - Log.d(LOG_TAG, String.format("Setting parameters of %s: %s", device.getId(), parameters)); - - AppPacket packet = new AppPacket(); - packet.tcid = device.getId(); - packet.i = 0; - - CommandPack pack = new CommandPack(); - pack.keys = parameters.keySet().toArray(new String[0]); - pack.values = parameters.values().toArray(new Integer[0]); - pack.mac = packet.tcid; - - packet.pack = pack; - - final AsyncCommunicator comm = new AsyncCommunicator(keyChain); - comm.setCommunicationFinishedListener(new AsyncCommunicationFinishedListener() { - @Override - public void onFinished() { - try { - final Packet[] responses = comm.get(); - - for (Packet response : responses) { - if (devices.containsKey(response.cid)) { - devices.get(response.cid).updateWithResultPack((ResultPack) response.pack); - } - } - - sendEvent(DeviceManagerEventListener.Event.DEVICE_STATUS_UPDATED); - } catch (Exception e) { - Log.e(LOG_TAG, "Failed to get response of command. Error: " + e.getMessage()); - } - } - }); - comm.execute(new Packet[] { packet }); - } - - public void setWifi(String ssid, String password){ - - WifiSettingsPacket packet = new WifiSettingsPacket(); - packet.password = password; - packet.ssid = ssid; - - final AsyncCommunicator comm = new AsyncCommunicator(keyChain); - comm.setCommunicationFinishedListener(new AsyncCommunicationFinishedListener() { - @Override - public void onFinished() { - try { - final Packet[] responses = comm.get(); - - for (Packet response : responses) { - if (devices.containsKey(response.cid)) { - devices.get(response.cid).updateWithResultPack((ResultPack) response.pack); - } - } - - sendEvent(DeviceManagerEventListener.Event.DEVICE_STATUS_UPDATED); - } catch (Exception e) { - Log.e(LOG_TAG, "Failed to get response of command. Error: " + e.getMessage()); - } - } - }); - comm.execute(new Packet[] { packet }); - } - - public void discoverDevices() { - Log.i(LOG_TAG, "Device discovery running..."); - - final AsyncCommunicator comm = new AsyncCommunicator(); - comm.setCommunicationFinishedListener(new AsyncCommunicationFinishedListener() { - @Override - public void onFinished() { - try { - Packet[] responses = comm.get(); - Log.i(LOG_TAG, String.format("Got %d response(s)", responses.length)); - - bindDevices(responses); - } catch (Exception e) { - - } - } - }); - - ScanPacket sp = new ScanPacket(); - - comm.execute(new ScanPacket[]{ sp }); - } - - public void updateDevices() { - if (devices.isEmpty()) { - Log.i(LOG_TAG, "No devices to update"); - return; - } - - Log.i(LOG_TAG, String.format("Updating %d device(s)", devices.size())); - - ArrayList packets = new ArrayList<>(); - - ArrayList keys = new ArrayList<>(); - for (DeviceImpl.Parameter p : DeviceImpl.Parameter.values()) { - keys.add(p.toString()); - } - - for (DeviceImpl device : devices.values()) { - AppPacket packet = new AppPacket(); - packet.tcid = device.getId(); - packet.i = 0; - - StatusPack pack = new StatusPack(); - pack.keys = keys.toArray(new String[0]); - pack.mac = device.getId(); - packet.pack = pack; - - packets.add(packet); - } - - final AsyncCommunicator comm = new AsyncCommunicator(keyChain); - comm.setCommunicationFinishedListener(new AsyncCommunicationFinishedListener() { - @Override - public void onFinished() { - try { - Packet[] responses = comm.get(); - - for (Packet response : responses) { - if (devices.containsKey(response.cid)) { - devices.get(response.cid).updateWithDatPack((DatPack) response.pack); - } - } - - sendEvent(DeviceManagerEventListener.Event.DEVICE_STATUS_UPDATED); - - } catch (Exception e) { - Log.w(LOG_TAG, "Failed to get device update result. Error: " + e.getMessage()); - } - } - }); - comm.execute(packets.toArray(new Packet[0])); - } - - private void bindDevices(Packet[] scanResponses) throws IOException { - ArrayList requests = new ArrayList<>(); - - for (int i = 0; i < scanResponses.length; i++) { - Packet response = scanResponses[i]; - - if (!(response.pack instanceof DevicePack)) - continue; - - DevicePack devicePack = (DevicePack) response.pack; - - DeviceImpl device; - - if (!devices.containsKey(response.cid)) { - device = new DeviceImpl(devicePack.mac, this); - devices.put(devicePack.mac, device); - } else { - device = devices.get(response.cid); - } - device.updateWithDevicePack(devicePack); - - if (!keyChain.containsKey(response.cid)) { - Log.i(LOG_TAG, "Binding device: " + devicePack.name); - - AppPacket request = new AppPacket(); - request.tcid = response.cid; - request.pack = new BindPack(); - request.pack.mac = request.tcid; - request.i = 1; - - requests.add(request); - } - } - - final AsyncCommunicator comm = new AsyncCommunicator(keyChain); - comm.setCommunicationFinishedListener(new AsyncCommunicationFinishedListener() { - @Override - public void onFinished() { - try { - Packet[] responses = comm.get(); - storeDevices(responses); - } catch (Exception e) { - - } - } - }); - comm.execute(requests.toArray(new Packet[0])); - } - - private void storeDevices(Packet[] bindResponses) { - for (Packet response : bindResponses) { - if (!(response.pack instanceof BindOkPack)) - continue; - - BindOkPack pack = (BindOkPack) response.pack; - - Log.i(LOG_TAG, "Storing key for device: " + pack.mac); - keyChain.addKey(pack.mac, pack.key); - } - - sendEvent(DeviceManagerEventListener.Event.DEVICE_LIST_UPDATED); - updateDevices(); - } - - private void sendEvent(DeviceManagerEventListener.Event event) { - for (DeviceManagerEventListener listener : eventListeners) - listener.onEvent(event); - } -} diff --git a/src/main/java/eu/czsoft/greesdk/device/DeviceManagerEventListener.java b/src/main/java/eu/czsoft/greesdk/device/DeviceManagerEventListener.java deleted file mode 100644 index 9228d9c..0000000 --- a/src/main/java/eu/czsoft/greesdk/device/DeviceManagerEventListener.java +++ /dev/null @@ -1,10 +0,0 @@ -package eu.czsoft.greesdk.device; - -public interface DeviceManagerEventListener { - enum Event { - DEVICE_LIST_UPDATED, - DEVICE_STATUS_UPDATED - } - - void onEvent(Event event); -} diff --git a/src/main/java/eu/czsoft/greesdk/network/DeviceKeyChain.java b/src/main/java/eu/czsoft/greesdk/net/DeviceKeyChain.java similarity index 93% rename from src/main/java/eu/czsoft/greesdk/network/DeviceKeyChain.java rename to src/main/java/eu/czsoft/greesdk/net/DeviceKeyChain.java index 1d9aa55..9300f7d 100644 --- a/src/main/java/eu/czsoft/greesdk/network/DeviceKeyChain.java +++ b/src/main/java/eu/czsoft/greesdk/net/DeviceKeyChain.java @@ -1,4 +1,4 @@ -package eu.czsoft.greesdk.network; +package eu.czsoft.greesdk.net; import java.util.HashMap; @@ -24,7 +24,7 @@ public String getKey(String deviceId) { public boolean containsKey(String deviceId) { if (deviceId == null) return false; - + return keys.containsKey(deviceId.toLowerCase()); } } diff --git a/src/main/java/eu/czsoft/greesdk/network/AsyncCommunicationFinishedListener.java b/src/main/java/eu/czsoft/greesdk/net/communication/AsyncCommunicationFinishedListener.java similarity index 69% rename from src/main/java/eu/czsoft/greesdk/network/AsyncCommunicationFinishedListener.java rename to src/main/java/eu/czsoft/greesdk/net/communication/AsyncCommunicationFinishedListener.java index b10b4b0..c6c34f5 100644 --- a/src/main/java/eu/czsoft/greesdk/network/AsyncCommunicationFinishedListener.java +++ b/src/main/java/eu/czsoft/greesdk/net/communication/AsyncCommunicationFinishedListener.java @@ -1,4 +1,4 @@ -package eu.czsoft.greesdk.network; +package eu.czsoft.greesdk.net.communication; public abstract class AsyncCommunicationFinishedListener { public abstract void onFinished(); diff --git a/src/main/java/eu/czsoft/greesdk/network/AsyncCommunicator.java b/src/main/java/eu/czsoft/greesdk/net/communication/AsyncCommunicator.java similarity index 73% rename from src/main/java/eu/czsoft/greesdk/network/AsyncCommunicator.java rename to src/main/java/eu/czsoft/greesdk/net/communication/AsyncCommunicator.java index dc11d33..5884b1f 100644 --- a/src/main/java/eu/czsoft/greesdk/network/AsyncCommunicator.java +++ b/src/main/java/eu/czsoft/greesdk/net/communication/AsyncCommunicator.java @@ -1,22 +1,19 @@ -package eu.czsoft.greesdk.network; +package eu.czsoft.greesdk.net.communication; -import android.os.AsyncTask; -import android.util.Log; +import eu.czsoft.greesdk.Utils; +import eu.czsoft.greesdk.net.DeviceKeyChain; +import eu.czsoft.greesdk.net.packets.Packet; +import eu.czsoft.greesdk.net.packets.serverbound.ApplicationPacket; +import eu.czsoft.greesdk.task.ConcurrentTask; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketException; +import java.net.*; import java.util.ArrayList; -import eu.czsoft.greesdk.packets.AppPacket; -import eu.czsoft.greesdk.packets.Packet; -import eu.czsoft.greesdk.Utils; - -public class AsyncCommunicator extends AsyncTask { - private final String LOG_TAG = "AsyncCommunicator"; +public class AsyncCommunicator extends ConcurrentTask { + private final Logger LOGGER = LogManager.getLogger("AsyncCommunicator"); private final int DATAGRAM_PORT = 7000; private final int TIMEOUT_MS = 500; @@ -52,7 +49,7 @@ protected Packet[] doInBackground(Packet[]... args) { broadcastPacket(request); responses = receivePackets(TIMEOUT_MS); } catch (Exception e) { - Log.e(LOG_TAG, "Error: " + e.getMessage()); + LOGGER.error("Error: " + e.getMessage()); } finally { closeSocket(); } @@ -61,8 +58,8 @@ protected Packet[] doInBackground(Packet[]... args) { } @Override - protected void onPostExecute(Packet[] responses) { - super.onPostExecute(responses); + protected void onPostExecute() { + super.onPostExecute(); if (communicationFinishedListener != null) communicationFinishedListener.onFinished(); @@ -71,7 +68,7 @@ protected void onPostExecute(Packet[] responses) { private void broadcastPacket(Packet packet) throws IOException { String data = Utils.serializePacket(packet, keyChain); - Log.d(LOG_TAG, "Broadcasting: " + data); + LOGGER.debug("Broadcasting: " + packet); DatagramPacket datagramPacket = new DatagramPacket( data.getBytes(), data.length(), @@ -96,19 +93,19 @@ private Packet[] receivePackets(int timeout) throws IOException { datagramPackets.add(datagramPacket); } } catch (Exception e) { - Log.w(LOG_TAG, "Exception: " + e.getMessage()); + LOGGER.warn("Exception: " + e.getMessage()); } for (DatagramPacket p : datagramPackets) { String data = new String(p.getData(), 0, p.getLength()); InetAddress address = p.getAddress(); - Log.d(LOG_TAG, String.format("Received response from %s: %s", address.getHostAddress(), data)); + LOGGER.debug(String.format("Received response from %s: %s", address.getHostAddress(), data)); Packet response = Utils.deserializePacket(data, keyChain); - + LOGGER.debug(response); // Filter out packets sent by us - if (response.cid != null && response.cid != AppPacket.CID) + if (response.clientId != null && response.clientId != ApplicationPacket.CLIENT_ID) responses.add(response); } @@ -119,7 +116,7 @@ private boolean createSocket() { try { socket = new DatagramSocket(new InetSocketAddress(DATAGRAM_PORT)); } catch (SocketException e) { - Log.e(LOG_TAG, "Failed to create socket. Error: " + e.getMessage()); + LOGGER.error("Failed to create socket. Error: " + e.getMessage()); return false; } @@ -127,7 +124,7 @@ private boolean createSocket() { } private void closeSocket() { - Log.i(LOG_TAG, "Closing socket"); + LOGGER.info("Closing socket"); socket.close(); socket = null; diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/ClientboundPacket.java b/src/main/java/eu/czsoft/greesdk/net/packets/ClientboundPacket.java new file mode 100644 index 0000000..5a07a78 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/ClientboundPacket.java @@ -0,0 +1,12 @@ +package eu.czsoft.greesdk.net.packets; + +import lombok.ToString; + +/** + * Server->Client
+ * ClientboundPacket means, that it is sent from the Server to the Client, so in this case, from Gree appliance to this Sdk. + */ +@ToString(callSuper = true) +public class ClientboundPacket extends Packet { + +} diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/Packet.java b/src/main/java/eu/czsoft/greesdk/net/packets/Packet.java new file mode 100644 index 0000000..c725a64 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/Packet.java @@ -0,0 +1,30 @@ +package eu.czsoft.greesdk.net.packets; + +import com.google.gson.annotations.SerializedName; +import eu.czsoft.greesdk.net.packets.packs.Pack; +import lombok.ToString; + +/** + * In this documentation, the Sdk is defined as Client and Gree appliances are the Server. + * This interface ties both types of packages together. + */ +@ToString(exclude = {"encryptedPack"}) +public class Packet { + + @SerializedName("t") + public String type; + + @SerializedName("tcid") + public String targetClientId; + @SerializedName("i") + public Integer i; + @SerializedName("uid") + public Integer uid; + @SerializedName("cid") + public String clientId; + + @SerializedName("pack") + public String encryptedPack; + + public transient Pack pack; +} diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/ServerboundPacket.java b/src/main/java/eu/czsoft/greesdk/net/packets/ServerboundPacket.java new file mode 100644 index 0000000..aada1f6 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/ServerboundPacket.java @@ -0,0 +1,13 @@ +package eu.czsoft.greesdk.net.packets; + +import com.google.gson.annotations.SerializedName; +import eu.czsoft.greesdk.net.packets.packs.Pack; +import lombok.ToString; + +/** + * Client->Server
+ * ServerboundPacket means, that it is sent from the Client to the Server, so in this case, from this Sdk to Gree appliance(s). + */ +@ToString(callSuper = true) +public class ServerboundPacket extends Packet { +} diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/clientbound/ResponsePacket.java b/src/main/java/eu/czsoft/greesdk/net/packets/clientbound/ResponsePacket.java new file mode 100644 index 0000000..55f8c87 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/clientbound/ResponsePacket.java @@ -0,0 +1,6 @@ +package eu.czsoft.greesdk.net.packets.clientbound; + +import eu.czsoft.greesdk.net.packets.ClientboundPacket; + +public class ResponsePacket extends ClientboundPacket { +} diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/packs/ClientboundPack.java b/src/main/java/eu/czsoft/greesdk/net/packets/packs/ClientboundPack.java new file mode 100644 index 0000000..6cbb6c1 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/packs/ClientboundPack.java @@ -0,0 +1,14 @@ +package eu.czsoft.greesdk.net.packets.packs; + +import eu.czsoft.greesdk.net.packets.Packet; +import lombok.ToString; + +/** + * Server->Client
+ * ClientboundPacket means, that it is sent from the Server to the Client, so in this case, from Gree appliance to this Sdk. + */ +@ToString(callSuper = true) +public class ClientboundPack extends Pack { + +} + diff --git a/src/main/java/eu/czsoft/greesdk/packs/Pack.java b/src/main/java/eu/czsoft/greesdk/net/packets/packs/Pack.java similarity index 57% rename from src/main/java/eu/czsoft/greesdk/packs/Pack.java rename to src/main/java/eu/czsoft/greesdk/net/packets/packs/Pack.java index a6e7d1e..c315152 100644 --- a/src/main/java/eu/czsoft/greesdk/packs/Pack.java +++ b/src/main/java/eu/czsoft/greesdk/net/packets/packs/Pack.java @@ -1,10 +1,14 @@ -package eu.czsoft.greesdk.packs; +package eu.czsoft.greesdk.net.packets.packs; import com.google.gson.annotations.SerializedName; +import lombok.ToString; +@ToString public class Pack { + @SerializedName("t") public String type; + @SerializedName("mac") public String mac; -} \ No newline at end of file +} diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/packs/ServerboundPack.java b/src/main/java/eu/czsoft/greesdk/net/packets/packs/ServerboundPack.java new file mode 100644 index 0000000..2dd7ea8 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/packs/ServerboundPack.java @@ -0,0 +1,12 @@ +package eu.czsoft.greesdk.net.packets.packs; + +import lombok.ToString; + +/** + * Client->Server
+ * ServerboundPacket means, that it is sent from the Client to the Server, so in this case, from this Sdk to Gree appliance(s). + */ +@ToString(callSuper = true) +public class ServerboundPack extends Pack { + +} diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/packs/clientbound/BindResponsePack.java b/src/main/java/eu/czsoft/greesdk/net/packets/packs/clientbound/BindResponsePack.java new file mode 100644 index 0000000..0ad2d05 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/packs/clientbound/BindResponsePack.java @@ -0,0 +1,21 @@ +package eu.czsoft.greesdk.net.packets.packs.clientbound; + +import com.google.gson.annotations.SerializedName; +import eu.czsoft.greesdk.net.packets.packs.ClientboundPack; +import lombok.ToString; + +@ToString(callSuper = true) +public class BindResponsePack extends ClientboundPack { + public static String TYPE = "bindok"; + + @SerializedName("key") + public String deviceKey; + + @SerializedName("r") + public int resultCode; + + public BindResponsePack() { + type = TYPE; + } +} + diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/packs/clientbound/DeviceResponsePack.java b/src/main/java/eu/czsoft/greesdk/net/packets/packs/clientbound/DeviceResponsePack.java new file mode 100644 index 0000000..899c291 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/packs/clientbound/DeviceResponsePack.java @@ -0,0 +1,39 @@ +package eu.czsoft.greesdk.net.packets.packs.clientbound; + +import com.google.gson.annotations.SerializedName; +import eu.czsoft.greesdk.net.packets.packs.ClientboundPack; +import lombok.ToString; + +@ToString(callSuper = true) +public class DeviceResponsePack extends ClientboundPack { + public static String TYPE = "dev"; + + @SerializedName("cid") + public String clientId; + @SerializedName("bc") + public String brandId; + @SerializedName("brand") + public String brand; + @SerializedName("catalog") + protected String catalog; + @SerializedName("mid") + public String modelId; + @SerializedName("model") + public String model; + @SerializedName("name") + public String name; + @SerializedName("series") + public String series; + @SerializedName("ver") + public String hardwareVersion; + @SerializedName("vender") + public String vendor; + @SerializedName("lock") + public Integer lock; + @SerializedName("hid") + public String firmwareVersion; + + public DeviceResponsePack() { + type = TYPE; + } +} diff --git a/src/main/java/eu/czsoft/greesdk/packs/ResultPack.java b/src/main/java/eu/czsoft/greesdk/net/packets/packs/clientbound/ResultPack.java similarity index 53% rename from src/main/java/eu/czsoft/greesdk/packs/ResultPack.java rename to src/main/java/eu/czsoft/greesdk/net/packets/packs/clientbound/ResultPack.java index 589897f..64690ba 100644 --- a/src/main/java/eu/czsoft/greesdk/packs/ResultPack.java +++ b/src/main/java/eu/czsoft/greesdk/net/packets/packs/clientbound/ResultPack.java @@ -1,15 +1,18 @@ -package eu.czsoft.greesdk.packs; +package eu.czsoft.greesdk.net.packets.packs.clientbound; import com.google.gson.annotations.SerializedName; +import eu.czsoft.greesdk.net.packets.packs.ClientboundPack; +import lombok.ToString; -public class ResultPack extends Pack { +@ToString(callSuper = true) +public class ResultPack extends ClientboundPack { public static String TYPE = "res"; @SerializedName("r") public int resultCode; @SerializedName("opt") - public String[] keys; + public String[] options; @SerializedName("p") public Integer[] values; diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/BindRequestPack.java b/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/BindRequestPack.java new file mode 100644 index 0000000..80efdb3 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/BindRequestPack.java @@ -0,0 +1,20 @@ +package eu.czsoft.greesdk.net.packets.packs.serverbound; + +import com.google.gson.annotations.SerializedName; +import eu.czsoft.greesdk.net.packets.packs.ClientboundPack; +import eu.czsoft.greesdk.net.packets.packs.ServerboundPack; +import lombok.ToString; + +@ToString(callSuper = true) +public class BindRequestPack extends ServerboundPack { + public static String TYPE = "bind"; + + @SerializedName("uid") + public int uid; + + public BindRequestPack() { + type = TYPE; + } +} + + diff --git a/src/main/java/eu/czsoft/greesdk/packs/DatPack.java b/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/ChangeOptionRequestPack.java similarity index 51% rename from src/main/java/eu/czsoft/greesdk/packs/DatPack.java rename to src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/ChangeOptionRequestPack.java index fd75c5e..46f40cf 100644 --- a/src/main/java/eu/czsoft/greesdk/packs/DatPack.java +++ b/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/ChangeOptionRequestPack.java @@ -1,8 +1,11 @@ -package eu.czsoft.greesdk.packs; +package eu.czsoft.greesdk.net.packets.packs.serverbound; import com.google.gson.annotations.SerializedName; +import eu.czsoft.greesdk.net.packets.packs.ServerboundPack; +import lombok.ToString; -public class DatPack extends Pack { +@ToString(callSuper = true) +public class ChangeOptionRequestPack extends ServerboundPack { public static String TYPE = "dat"; @SerializedName("r") @@ -14,7 +17,7 @@ public class DatPack extends Pack { @SerializedName("dat") public Integer[] values; - public DatPack() { + public ChangeOptionRequestPack() { type = TYPE; } -} \ No newline at end of file +} diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/CommandRequestPack.java b/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/CommandRequestPack.java new file mode 100644 index 0000000..ac97e3b --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/CommandRequestPack.java @@ -0,0 +1,21 @@ +package eu.czsoft.greesdk.net.packets.packs.serverbound; + +import com.google.gson.annotations.SerializedName; +import eu.czsoft.greesdk.net.packets.packs.ServerboundPack; +import lombok.ToString; + +@ToString(callSuper = true) +public class CommandRequestPack extends ServerboundPack { + public static String TYPE = "cmd"; + + @SerializedName("opt") + public String[] options; + + @SerializedName("p") + public Integer[] values; + + public CommandRequestPack() { + type = TYPE; + } +} + diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/StatusResponsePack.java b/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/StatusResponsePack.java new file mode 100644 index 0000000..19eeed2 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/StatusResponsePack.java @@ -0,0 +1,17 @@ +package eu.czsoft.greesdk.net.packets.packs.serverbound; + +import com.google.gson.annotations.SerializedName; +import eu.czsoft.greesdk.net.packets.packs.ServerboundPack; +import lombok.ToString; + +@ToString(callSuper = true) +public class StatusResponsePack extends ServerboundPack { + public static String TYPE = "status"; + + @SerializedName("cols") + public String[] options; + + public StatusResponsePack() { + type = TYPE; + } +} diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/ApplicationPacket.java b/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/ApplicationPacket.java new file mode 100644 index 0000000..13c8c36 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/ApplicationPacket.java @@ -0,0 +1,17 @@ +package eu.czsoft.greesdk.net.packets.serverbound; + +import eu.czsoft.greesdk.net.packets.ServerboundPacket; +import lombok.ToString; +import lombok.extern.log4j.Log4j2; + +@ToString(callSuper = true) +public class ApplicationPacket extends ServerboundPacket { + public static String CLIENT_ID = "greesdk"; + public static String TYPE = "pack"; + + public ApplicationPacket() { + clientId = CLIENT_ID; + type = TYPE; + uid = 0; + } +} diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/ScanAppliancesPacket.java b/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/ScanAppliancesPacket.java new file mode 100644 index 0000000..8360ed3 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/ScanAppliancesPacket.java @@ -0,0 +1,13 @@ +package eu.czsoft.greesdk.net.packets.serverbound; + +import eu.czsoft.greesdk.net.packets.ServerboundPacket; +import lombok.ToString; + +@ToString(callSuper = true) +public class ScanAppliancesPacket extends ServerboundPacket { + public static String TYPE = "scan"; + + public ScanAppliancesPacket() { + type = TYPE; + } +} diff --git a/src/main/java/eu/czsoft/greesdk/packets/WifiSettingsPacket.java b/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/WifiSettingsPacket.java similarity index 54% rename from src/main/java/eu/czsoft/greesdk/packets/WifiSettingsPacket.java rename to src/main/java/eu/czsoft/greesdk/net/packets/serverbound/WifiSettingsPacket.java index ae3eb3d..3f33e7e 100644 --- a/src/main/java/eu/czsoft/greesdk/packets/WifiSettingsPacket.java +++ b/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/WifiSettingsPacket.java @@ -1,8 +1,11 @@ -package eu.czsoft.greesdk.packets; +package eu.czsoft.greesdk.net.packets.serverbound; import com.google.gson.annotations.SerializedName; +import eu.czsoft.greesdk.net.packets.ServerboundPacket; +import lombok.ToString; -public class WifiSettingsPacket extends Packet { +@ToString(callSuper = true) +public class WifiSettingsPacket extends ServerboundPacket { public static String TYPE = "wlan"; @SerializedName("psw") @@ -14,4 +17,4 @@ public class WifiSettingsPacket extends Packet { public WifiSettingsPacket() { type = TYPE; } -} \ No newline at end of file +} diff --git a/src/main/java/eu/czsoft/greesdk/packets/AppPacket.java b/src/main/java/eu/czsoft/greesdk/packets/AppPacket.java deleted file mode 100644 index 6ed4401..0000000 --- a/src/main/java/eu/czsoft/greesdk/packets/AppPacket.java +++ /dev/null @@ -1,12 +0,0 @@ -package eu.czsoft.greesdk.packets; - -public class AppPacket extends Packet { - public static String CID = "app"; - public static String TYPE = "pack"; - - public AppPacket() { - cid = CID; - type = TYPE; - uid = 0; - } -} diff --git a/src/main/java/eu/czsoft/greesdk/packets/Packet.java b/src/main/java/eu/czsoft/greesdk/packets/Packet.java deleted file mode 100644 index 8b33986..0000000 --- a/src/main/java/eu/czsoft/greesdk/packets/Packet.java +++ /dev/null @@ -1,20 +0,0 @@ -package eu.czsoft.greesdk.packets; - -import eu.czsoft.greesdk.packs.Pack; - -import com.google.gson.annotations.SerializedName; - -public class Packet { - @SerializedName("t") - public String type; - - public String tcid; - public Integer i; - public Integer uid; - public String cid; - - @SerializedName("pack") - public String encryptedPack; - - public transient Pack pack; -} diff --git a/src/main/java/eu/czsoft/greesdk/packets/ScanPacket.java b/src/main/java/eu/czsoft/greesdk/packets/ScanPacket.java deleted file mode 100644 index 3bc3654..0000000 --- a/src/main/java/eu/czsoft/greesdk/packets/ScanPacket.java +++ /dev/null @@ -1,9 +0,0 @@ -package eu.czsoft.greesdk.packets; - -public class ScanPacket extends Packet { - public static String TYPE = "scan"; - - public ScanPacket() { - type = TYPE; - } -} diff --git a/src/main/java/eu/czsoft/greesdk/packs/BindOkPack.java b/src/main/java/eu/czsoft/greesdk/packs/BindOkPack.java deleted file mode 100644 index d9a8088..0000000 --- a/src/main/java/eu/czsoft/greesdk/packs/BindOkPack.java +++ /dev/null @@ -1,16 +0,0 @@ -package eu.czsoft.greesdk.packs; - -import com.google.gson.annotations.SerializedName; - -public class BindOkPack extends Pack { - public static String TYPE = "bindok"; - - public String key; - - @SerializedName("r") - public int resultCode; - - public BindOkPack() { - type = TYPE; - } -} diff --git a/src/main/java/eu/czsoft/greesdk/packs/BindPack.java b/src/main/java/eu/czsoft/greesdk/packs/BindPack.java deleted file mode 100644 index ded684e..0000000 --- a/src/main/java/eu/czsoft/greesdk/packs/BindPack.java +++ /dev/null @@ -1,11 +0,0 @@ -package eu.czsoft.greesdk.packs; - -public class BindPack extends Pack { - public static String TYPE = "bind"; - - public int uid; - - public BindPack() { - type = TYPE; - } -} \ No newline at end of file diff --git a/src/main/java/eu/czsoft/greesdk/packs/CommandPack.java b/src/main/java/eu/czsoft/greesdk/packs/CommandPack.java deleted file mode 100644 index 1b23e32..0000000 --- a/src/main/java/eu/czsoft/greesdk/packs/CommandPack.java +++ /dev/null @@ -1,17 +0,0 @@ -package eu.czsoft.greesdk.packs; - -import com.google.gson.annotations.SerializedName; - -public class CommandPack extends Pack { - public static String TYPE = "cmd"; - - @SerializedName("opt") - public String[] keys; - - @SerializedName("p") - public Integer[] values; - - public CommandPack() { - type = TYPE; - } -} \ No newline at end of file diff --git a/src/main/java/eu/czsoft/greesdk/packs/DevicePack.java b/src/main/java/eu/czsoft/greesdk/packs/DevicePack.java deleted file mode 100644 index 06f24d5..0000000 --- a/src/main/java/eu/czsoft/greesdk/packs/DevicePack.java +++ /dev/null @@ -1,25 +0,0 @@ -package eu.czsoft.greesdk.packs; - -import com.google.gson.annotations.SerializedName; - -public class DevicePack extends Pack { - public static String TYPE = "dev"; - - public String cid; - public String bc; - public String brand; - public String catalog; - public String mid; - public String model; - public String name; - public String series; - public String ver; - public Integer lock; - - @SerializedName("vender") - public String vendor; - - public DevicePack() { - type = TYPE; - } -} diff --git a/src/main/java/eu/czsoft/greesdk/packs/StatusPack.java b/src/main/java/eu/czsoft/greesdk/packs/StatusPack.java deleted file mode 100644 index 902284f..0000000 --- a/src/main/java/eu/czsoft/greesdk/packs/StatusPack.java +++ /dev/null @@ -1,14 +0,0 @@ -package eu.czsoft.greesdk.packs; - -import com.google.gson.annotations.SerializedName; - -public class StatusPack extends Pack { - public static String TYPE = "status"; - - @SerializedName("cols") - public String[] keys; - - public StatusPack() { - type = TYPE; - } -} \ No newline at end of file diff --git a/src/main/java/eu/czsoft/greesdk/serialization/PackDeserializer.java b/src/main/java/eu/czsoft/greesdk/serialization/PackDeserializer.java new file mode 100644 index 0000000..59aa35f --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/serialization/PackDeserializer.java @@ -0,0 +1,38 @@ +package eu.czsoft.greesdk.serialization; + +import com.google.gson.*; +import eu.czsoft.greesdk.net.packets.packs.Pack; +import eu.czsoft.greesdk.net.packets.packs.clientbound.BindResponsePack; +import eu.czsoft.greesdk.net.packets.packs.clientbound.DeviceResponsePack; +import eu.czsoft.greesdk.net.packets.packs.clientbound.ResultPack; +import eu.czsoft.greesdk.net.packets.packs.serverbound.BindRequestPack; +import eu.czsoft.greesdk.net.packets.packs.serverbound.ChangeOptionRequestPack; +import eu.czsoft.greesdk.net.packets.packs.serverbound.StatusResponsePack; + +import java.lang.reflect.Type; + +public class PackDeserializer implements JsonDeserializer { + + @Override + public Pack deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + JsonObject jsonObject = jsonElement.getAsJsonObject(); + + String packType = jsonObject.get("t").getAsString(); + + if (packType.equalsIgnoreCase(BindRequestPack.TYPE)) { + return jsonDeserializationContext.deserialize(jsonObject, BindRequestPack.class); + } else if (packType.equalsIgnoreCase(BindResponsePack.TYPE)) { + return jsonDeserializationContext.deserialize(jsonObject, BindResponsePack.class); + } else if (packType.equalsIgnoreCase(ChangeOptionRequestPack.TYPE)) { + return jsonDeserializationContext.deserialize(jsonObject, ChangeOptionRequestPack.class); + } else if (packType.equalsIgnoreCase(ResultPack.TYPE)) { + return jsonDeserializationContext.deserialize(jsonObject, ResultPack.class); + } else if (packType.equalsIgnoreCase(StatusResponsePack.TYPE)) { + return jsonDeserializationContext.deserialize(jsonObject, StatusResponsePack.class); + } else if (packType.equalsIgnoreCase(DeviceResponsePack.TYPE)) { + return jsonDeserializationContext.deserialize(jsonObject, DeviceResponsePack.class); + } + + return null; + } +} diff --git a/src/main/java/eu/czsoft/greesdk/task/ConcurrentTask.java b/src/main/java/eu/czsoft/greesdk/task/ConcurrentTask.java new file mode 100644 index 0000000..0aa40d1 --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/task/ConcurrentTask.java @@ -0,0 +1,64 @@ +package eu.czsoft.greesdk.task; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.concurrent.*; + +public abstract class ConcurrentTask { + public static final Logger LOGGER = LogManager.getLogger("AsyncTaskRunner"); + + private static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(5, 128, 1, TimeUnit.SECONDS, new LinkedBlockingQueue()); + + private final ScheduledExecutorService backgroundExecutor = Executors.newSingleThreadScheduledExecutor(); + + private boolean mIsInterrupted = false; + private TResult _result = null; + + protected void onPreExecute(){} + protected abstract TResult doInBackground(TParams... params); + protected void onPostExecute(){} + protected void onCancelled() {} + + public TResult get() { + return _result; + } + + @SafeVarargs + public final void execute(TParams... params) { + THREAD_POOL_EXECUTOR.execute(() -> { + try { + checkInterrupted(); + backgroundExecutor.execute(this::onPreExecute); + + checkInterrupted(); + _result = doInBackground(params); + + checkInterrupted(); + backgroundExecutor.execute(this::onPostExecute); + } catch (InterruptedException ex) { + backgroundExecutor.execute(this::onCancelled); + } catch (Exception ex) { + LOGGER.error("Execution error occurred. Description: " + ex.getMessage() + "\n Exception:\n" + ex.toString()); + } + }); + } + + private void checkInterrupted() throws InterruptedException { + if (isInterrupted()){ + throw new InterruptedException(); + } + } + + public void cancel(boolean mayInterruptIfRunning){ + setInterrupted(mayInterruptIfRunning); + } + + public boolean isInterrupted() { + return mIsInterrupted; + } + + public void setInterrupted(boolean interrupted) { + mIsInterrupted = interrupted; + } +} \ No newline at end of file From 0c44cef37dedcff2b40603c67158372801f4a6ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Czomp=C3=B3?= Date: Fri, 11 Aug 2023 01:02:40 +0200 Subject: [PATCH 2/3] Remove Log4j dependency - Added `ApplianceType` - Moved away from Log4j to built-in Logger - Some code cleanup - Bump version to 1.1.0 --- build.gradle | 4 +--- gradle.properties | 4 ++-- src/main/java/eu/czsoft/greesdk/Crypto.java | 10 ++++------ .../java/eu/czsoft/greesdk/DeviceManager.java | 16 ++++++++-------- src/main/java/eu/czsoft/greesdk/Utils.java | 6 ++---- .../appliances/AirConditionerApplianceImpl.java | 9 +++++++-- .../eu/czsoft/greesdk/appliances/Appliance.java | 4 +++- .../greesdk/appliances/ApplianceImpl.java | 13 +++++++++---- .../greesdk/appliances/ApplianceType.java | 6 ++++++ .../net/communication/AsyncCommunicator.java | 17 ++++++++--------- .../greesdk/net/packets/ServerboundPacket.java | 2 -- .../net/packets/packs/ClientboundPack.java | 1 - .../packs/serverbound/BindRequestPack.java | 1 - .../packets/serverbound/ApplicationPacket.java | 1 - .../eu/czsoft/greesdk/task/ConcurrentTask.java | 7 +++---- 15 files changed, 53 insertions(+), 48 deletions(-) create mode 100644 src/main/java/eu/czsoft/greesdk/appliances/ApplianceType.java diff --git a/build.gradle b/build.gradle index 4f5fc59..ce324fb 100644 --- a/build.gradle +++ b/build.gradle @@ -21,8 +21,6 @@ dependencies { annotationProcessor 'org.projectlombok:lombok:1.18.28' implementation 'com.google.code.gson:gson:2.10.1' - implementation 'org.apache.logging.log4j:log4j-api:2.20.0' - implementation 'org.apache.logging.log4j:log4j-core:2.20.0' } publishing { repositories { @@ -49,7 +47,7 @@ publishing { } pom { name = rootProject.name - description = "Originally separated from GreeControlAndroid, after that, it got a full network-side rewrite." + description = "An SDK to easily communicate with your Gree appliances. Originally separated from GreeControlAndroid, and then got a full rewrite." url = "https://docs.czsoft.eu/greesdk?v=" + rootProject.version developers { developer { diff --git a/gradle.properties b/gradle.properties index 99c5d5f..9d06a5e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ artifactId = greesdk name = GreeSDK -version = 1.0.0 +version = 1.1.0 -mavenUrl = https://maven.czsoft.eu/ \ No newline at end of file +mavenUrl = https://maven.czsoft.eu/ diff --git a/src/main/java/eu/czsoft/greesdk/Crypto.java b/src/main/java/eu/czsoft/greesdk/Crypto.java index 80f2e40..ee284b7 100644 --- a/src/main/java/eu/czsoft/greesdk/Crypto.java +++ b/src/main/java/eu/czsoft/greesdk/Crypto.java @@ -1,14 +1,12 @@ package eu.czsoft.greesdk; -import lombok.extern.log4j.Log4j2; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import lombok.extern.java.Log; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; -@Log4j2 +@Log public class Crypto { protected static String GENERIC_KEY = "a3K8Bx%2r8Y7#xDh"; @@ -23,7 +21,7 @@ protected static String encrypt(String plainText, String key) { return encoded; } catch (Exception e) { - LOGGER.error("Pack encryption failed. Error: " + e.getMessage()); + LOGGER.severe("Pack encryption failed. Error: " + e.getMessage()); } return ""; @@ -40,7 +38,7 @@ protected static String decrypt(String encrypted, String key) { byte[] decrypted = c.doFinal(decoded); return new String(decrypted); } catch (Exception e) { - LOGGER.error("Pack decryption failed. Error: " + e.getMessage()); + LOGGER.severe("Pack decryption failed. Error: " + e.getMessage()); } return ""; diff --git a/src/main/java/eu/czsoft/greesdk/DeviceManager.java b/src/main/java/eu/czsoft/greesdk/DeviceManager.java index 6919965..23826a8 100644 --- a/src/main/java/eu/czsoft/greesdk/DeviceManager.java +++ b/src/main/java/eu/czsoft/greesdk/DeviceManager.java @@ -17,14 +17,14 @@ import eu.czsoft.greesdk.net.packets.serverbound.ApplicationPacket; import eu.czsoft.greesdk.net.packets.serverbound.ScanAppliancesPacket; import eu.czsoft.greesdk.net.packets.serverbound.WifiSettingsPacket; -import lombok.extern.log4j.Log4j2; +import lombok.extern.java.Log; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -@Log4j2 +@Log public class DeviceManager { private final int DATAGRAM_PORT = 7000; @@ -73,7 +73,7 @@ public void setParameter(ApplianceImpl device, String name, int value) { } public void setParameters(ApplianceImpl device, Map parameters) { - LOGGER.debug(String.format("Setting parameters of %s: %s", device.getId(), parameters)); + LOGGER.fine(String.format("Setting parameters of %s: %s", device.getId(), parameters)); ApplicationPacket packet = new ApplicationPacket(); packet.targetClientId = device.getId(); @@ -101,7 +101,7 @@ public void onFinished() { sendEvent(DeviceManagerEvent.DEVICE_STATUS_UPDATED); } catch (Exception e) { - LOGGER.error("Failed to get response of command. Error: " + e.getMessage()); + LOGGER.severe("Failed to get response of command. Error: " + e.getMessage()); } } }); @@ -129,7 +129,7 @@ public void onFinished() { sendEvent(DeviceManagerEvent.DEVICE_STATUS_UPDATED); } catch (Exception e) { - LOGGER.error("Failed to get response of command. Error: " + e.getMessage()); + LOGGER.severe("Failed to get response of command. Error: " + e.getMessage()); } } }); @@ -149,7 +149,7 @@ public void onFinished() { bindDevices(responses); } catch (Exception e) { - LOGGER.debug("Device discovery failed with exception\n" + e); + LOGGER.fine("Device discovery failed with exception\n" + e); } } }); @@ -203,7 +203,7 @@ public void onFinished() { sendEvent(DeviceManagerEvent.DEVICE_STATUS_UPDATED); } catch (Exception e) { - LOGGER.warn("Failed to get device update result. Error: " + e.getMessage()); + LOGGER.warning("Failed to get device update result. Error: " + e.getMessage()); } } }); @@ -250,7 +250,7 @@ public void onFinished() { Packet[] responses = comm.get(); storeDevices(responses); } catch (Exception e) { - LOGGER.debug("Device discovery failed with exception\n" + e); + LOGGER.fine("Device discovery failed with exception\n" + e); } } }); diff --git a/src/main/java/eu/czsoft/greesdk/Utils.java b/src/main/java/eu/czsoft/greesdk/Utils.java index 6df87eb..0fd4194 100644 --- a/src/main/java/eu/czsoft/greesdk/Utils.java +++ b/src/main/java/eu/czsoft/greesdk/Utils.java @@ -7,14 +7,12 @@ import eu.czsoft.greesdk.net.packets.packs.Pack; import eu.czsoft.greesdk.net.packets.packs.serverbound.ChangeOptionRequestPack; import eu.czsoft.greesdk.serialization.PackDeserializer; -import lombok.extern.log4j.Log4j2; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import lombok.extern.java.Log; import java.util.HashMap; import java.util.Map; -@Log4j2 +@Log public class Utils { public static Map zip(String[] keys, Integer[] values) throws IllegalArgumentException { diff --git a/src/main/java/eu/czsoft/greesdk/appliances/AirConditionerApplianceImpl.java b/src/main/java/eu/czsoft/greesdk/appliances/AirConditionerApplianceImpl.java index 07a06f9..933d383 100644 --- a/src/main/java/eu/czsoft/greesdk/appliances/AirConditionerApplianceImpl.java +++ b/src/main/java/eu/czsoft/greesdk/appliances/AirConditionerApplianceImpl.java @@ -5,9 +5,9 @@ import eu.czsoft.greesdk.appliances.airconditioner.TemperatureUnit; import eu.czsoft.greesdk.appliances.airconditioner.VerticalSwingMode; import eu.czsoft.greesdk.DeviceManager; -import org.apache.logging.log4j.LogManager; import java.util.Map; +import java.util.logging.Logger; public class AirConditionerApplianceImpl extends ApplianceImpl implements AirConditionerAppliance { private Mode mode = Mode.AUTO; @@ -28,9 +28,13 @@ public class AirConditionerApplianceImpl extends ApplianceImpl implements AirCon public AirConditionerApplianceImpl(String deviceId, DeviceManager deviceManager) { super(deviceId, deviceManager); - LOGGER = LogManager.getLogger(String.format("AirConditioner(%s)", deviceId)); + LOGGER = Logger.getLogger(String.format("AirConditioner(%s)", deviceId)); } + @Override + public ApplianceType getType() { + return ApplianceType.AC; + } @Override public Mode getMode() { return mode; @@ -177,6 +181,7 @@ void updateParameters(Map parameterMap) { public String toString() { return "AirConditionerApplianceImpl{" + "deviceId='" + deviceId + '\'' + + ", type='" + getType() + '\'' + ", name='" + getName() + '\'' + ", poweredOn=" + isPoweredOn() + ", mode=" + mode + diff --git a/src/main/java/eu/czsoft/greesdk/appliances/Appliance.java b/src/main/java/eu/czsoft/greesdk/appliances/Appliance.java index 9f190d5..5ce5237 100644 --- a/src/main/java/eu/czsoft/greesdk/appliances/Appliance.java +++ b/src/main/java/eu/czsoft/greesdk/appliances/Appliance.java @@ -5,6 +5,8 @@ public interface Appliance { String getName(); + ApplianceType getType(); + void setName(String name); boolean isPoweredOn(); @@ -14,5 +16,5 @@ public interface Appliance { void setParameter(String name, int value); - void setWifiDetails(String ssid, String password); + void setWiFiDetails(String ssid, String password); } diff --git a/src/main/java/eu/czsoft/greesdk/appliances/ApplianceImpl.java b/src/main/java/eu/czsoft/greesdk/appliances/ApplianceImpl.java index 7ec9ba7..7f09ed8 100644 --- a/src/main/java/eu/czsoft/greesdk/appliances/ApplianceImpl.java +++ b/src/main/java/eu/czsoft/greesdk/appliances/ApplianceImpl.java @@ -5,9 +5,9 @@ import eu.czsoft.greesdk.net.packets.packs.clientbound.DeviceResponsePack; import eu.czsoft.greesdk.net.packets.packs.clientbound.ResultPack; import eu.czsoft.greesdk.net.packets.packs.serverbound.ChangeOptionRequestPack; -import org.apache.logging.log4j.Logger; import java.util.Map; +import java.util.logging.Logger; public class ApplianceImpl implements Appliance { Logger LOGGER; @@ -33,7 +33,7 @@ public void updateWithResultPack(ResultPack pack) { } public void updateWithDevicePack(DeviceResponsePack pack) { - LOGGER.debug("Updating name: " + pack.name); + LOGGER.fine("Updating name: " + pack.name); name = pack.name; } @@ -47,6 +47,11 @@ public String getName() { return name; } + @Override + public ApplianceType getType() { + return ApplianceType.UNKNOWN; + } + @Override public void setName(String name) { } @@ -72,7 +77,7 @@ public void setParameter(String name, int value) { } @Override - public void setWifiDetails(String ssid, String password) { + public void setWiFiDetails(String ssid, String password) { deviceManager.setWiFi(ssid, password); } @@ -91,7 +96,7 @@ void setParameters(Parameter[] parameters, Integer[] values) { void updateParameters(Map parameterMap) { - LOGGER.debug("Updating parameterMap: " + parameterMap); + LOGGER.fine("Updating parameterMap: " + parameterMap); poweredOn = getBooleanParameter(parameterMap, Parameter.POWER, poweredOn); } diff --git a/src/main/java/eu/czsoft/greesdk/appliances/ApplianceType.java b/src/main/java/eu/czsoft/greesdk/appliances/ApplianceType.java new file mode 100644 index 0000000..0915e9e --- /dev/null +++ b/src/main/java/eu/czsoft/greesdk/appliances/ApplianceType.java @@ -0,0 +1,6 @@ +package eu.czsoft.greesdk.appliances; + +public enum ApplianceType { + UNKNOWN, + AC, +} diff --git a/src/main/java/eu/czsoft/greesdk/net/communication/AsyncCommunicator.java b/src/main/java/eu/czsoft/greesdk/net/communication/AsyncCommunicator.java index 5884b1f..ef1b393 100644 --- a/src/main/java/eu/czsoft/greesdk/net/communication/AsyncCommunicator.java +++ b/src/main/java/eu/czsoft/greesdk/net/communication/AsyncCommunicator.java @@ -5,15 +5,14 @@ import eu.czsoft.greesdk.net.packets.Packet; import eu.czsoft.greesdk.net.packets.serverbound.ApplicationPacket; import eu.czsoft.greesdk.task.ConcurrentTask; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import lombok.extern.java.Log; import java.io.IOException; import java.net.*; import java.util.ArrayList; +@Log public class AsyncCommunicator extends ConcurrentTask { - private final Logger LOGGER = LogManager.getLogger("AsyncCommunicator"); private final int DATAGRAM_PORT = 7000; private final int TIMEOUT_MS = 500; @@ -49,7 +48,7 @@ protected Packet[] doInBackground(Packet[]... args) { broadcastPacket(request); responses = receivePackets(TIMEOUT_MS); } catch (Exception e) { - LOGGER.error("Error: " + e.getMessage()); + LOGGER.severe("Error: " + e.getMessage()); } finally { closeSocket(); } @@ -68,7 +67,7 @@ protected void onPostExecute() { private void broadcastPacket(Packet packet) throws IOException { String data = Utils.serializePacket(packet, keyChain); - LOGGER.debug("Broadcasting: " + packet); + LOGGER.fine("Broadcasting: " + packet); DatagramPacket datagramPacket = new DatagramPacket( data.getBytes(), data.length(), @@ -93,17 +92,17 @@ private Packet[] receivePackets(int timeout) throws IOException { datagramPackets.add(datagramPacket); } } catch (Exception e) { - LOGGER.warn("Exception: " + e.getMessage()); + LOGGER.warning("Exception: " + e.getMessage()); } for (DatagramPacket p : datagramPackets) { String data = new String(p.getData(), 0, p.getLength()); InetAddress address = p.getAddress(); - LOGGER.debug(String.format("Received response from %s: %s", address.getHostAddress(), data)); + LOGGER.fine(String.format("Received response from %s: %s", address.getHostAddress(), data)); Packet response = Utils.deserializePacket(data, keyChain); - LOGGER.debug(response); + LOGGER.fine(response.toString()); // Filter out packets sent by us if (response.clientId != null && response.clientId != ApplicationPacket.CLIENT_ID) responses.add(response); @@ -116,7 +115,7 @@ private boolean createSocket() { try { socket = new DatagramSocket(new InetSocketAddress(DATAGRAM_PORT)); } catch (SocketException e) { - LOGGER.error("Failed to create socket. Error: " + e.getMessage()); + LOGGER.severe("Failed to create socket. Error: " + e.getMessage()); return false; } diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/ServerboundPacket.java b/src/main/java/eu/czsoft/greesdk/net/packets/ServerboundPacket.java index aada1f6..a455d60 100644 --- a/src/main/java/eu/czsoft/greesdk/net/packets/ServerboundPacket.java +++ b/src/main/java/eu/czsoft/greesdk/net/packets/ServerboundPacket.java @@ -1,7 +1,5 @@ package eu.czsoft.greesdk.net.packets; -import com.google.gson.annotations.SerializedName; -import eu.czsoft.greesdk.net.packets.packs.Pack; import lombok.ToString; /** diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/packs/ClientboundPack.java b/src/main/java/eu/czsoft/greesdk/net/packets/packs/ClientboundPack.java index 6cbb6c1..d958ec9 100644 --- a/src/main/java/eu/czsoft/greesdk/net/packets/packs/ClientboundPack.java +++ b/src/main/java/eu/czsoft/greesdk/net/packets/packs/ClientboundPack.java @@ -1,6 +1,5 @@ package eu.czsoft.greesdk.net.packets.packs; -import eu.czsoft.greesdk.net.packets.Packet; import lombok.ToString; /** diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/BindRequestPack.java b/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/BindRequestPack.java index 80efdb3..a9c33dd 100644 --- a/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/BindRequestPack.java +++ b/src/main/java/eu/czsoft/greesdk/net/packets/packs/serverbound/BindRequestPack.java @@ -1,7 +1,6 @@ package eu.czsoft.greesdk.net.packets.packs.serverbound; import com.google.gson.annotations.SerializedName; -import eu.czsoft.greesdk.net.packets.packs.ClientboundPack; import eu.czsoft.greesdk.net.packets.packs.ServerboundPack; import lombok.ToString; diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/ApplicationPacket.java b/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/ApplicationPacket.java index 13c8c36..b7c4406 100644 --- a/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/ApplicationPacket.java +++ b/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/ApplicationPacket.java @@ -2,7 +2,6 @@ import eu.czsoft.greesdk.net.packets.ServerboundPacket; import lombok.ToString; -import lombok.extern.log4j.Log4j2; @ToString(callSuper = true) public class ApplicationPacket extends ServerboundPacket { diff --git a/src/main/java/eu/czsoft/greesdk/task/ConcurrentTask.java b/src/main/java/eu/czsoft/greesdk/task/ConcurrentTask.java index 0aa40d1..a9667f8 100644 --- a/src/main/java/eu/czsoft/greesdk/task/ConcurrentTask.java +++ b/src/main/java/eu/czsoft/greesdk/task/ConcurrentTask.java @@ -1,12 +1,11 @@ package eu.czsoft.greesdk.task; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import lombok.extern.java.Log; import java.util.concurrent.*; +@Log public abstract class ConcurrentTask { - public static final Logger LOGGER = LogManager.getLogger("AsyncTaskRunner"); private static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(5, 128, 1, TimeUnit.SECONDS, new LinkedBlockingQueue()); @@ -39,7 +38,7 @@ public final void execute(TParams... params) { } catch (InterruptedException ex) { backgroundExecutor.execute(this::onCancelled); } catch (Exception ex) { - LOGGER.error("Execution error occurred. Description: " + ex.getMessage() + "\n Exception:\n" + ex.toString()); + LOGGER.severe("Execution error occurred. Description: " + ex.getMessage() + "\n Exception:\n" + ex.toString()); } }); } From e23db056fa30b1eb490fd8ce4731f594b8a79e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Czomp=C3=B3?= Date: Fri, 11 Aug 2023 01:05:34 +0200 Subject: [PATCH 3/3] Rename WiFi packet and backwards compatibility - Upgrade Gradle to 8.2.1 - Rename `WifiSettingsPacket` to `WiFiSettingsPacket` - Convert Unzipped from record to class for backwards compatibility --- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- src/main/java/eu/czsoft/greesdk/DeviceManager.java | 4 ++-- src/main/java/eu/czsoft/greesdk/Unzipped.java | 10 +++++++++- .../net/packets/serverbound/WifiSettingsPacket.java | 4 ++-- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index 9d06a5e..2c4c12f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ artifactId = greesdk name = GreeSDK -version = 1.1.0 +version = 1.1.3 mavenUrl = https://maven.czsoft.eu/ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 569641c..15fe078 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Fri Jul 28 12:25:52 CEST 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/eu/czsoft/greesdk/DeviceManager.java b/src/main/java/eu/czsoft/greesdk/DeviceManager.java index 23826a8..511d171 100644 --- a/src/main/java/eu/czsoft/greesdk/DeviceManager.java +++ b/src/main/java/eu/czsoft/greesdk/DeviceManager.java @@ -16,7 +16,7 @@ import eu.czsoft.greesdk.net.packets.packs.serverbound.StatusResponsePack; import eu.czsoft.greesdk.net.packets.serverbound.ApplicationPacket; import eu.czsoft.greesdk.net.packets.serverbound.ScanAppliancesPacket; -import eu.czsoft.greesdk.net.packets.serverbound.WifiSettingsPacket; +import eu.czsoft.greesdk.net.packets.serverbound.WiFiSettingsPacket; import lombok.extern.java.Log; import java.io.IOException; @@ -110,7 +110,7 @@ public void onFinished() { public void setWiFi(String ssid, String password){ - WifiSettingsPacket packet = new WifiSettingsPacket(); + WiFiSettingsPacket packet = new WiFiSettingsPacket(); packet.password = password; packet.ssid = ssid; diff --git a/src/main/java/eu/czsoft/greesdk/Unzipped.java b/src/main/java/eu/czsoft/greesdk/Unzipped.java index fb4e602..2f3386d 100644 --- a/src/main/java/eu/czsoft/greesdk/Unzipped.java +++ b/src/main/java/eu/czsoft/greesdk/Unzipped.java @@ -1,4 +1,12 @@ package eu.czsoft.greesdk; -public record Unzipped(String[] keys, Integer[] values) { +public class Unzipped +{ + public final String[] keys; + public final Integer[] values; + + public Unzipped(String[] keys, Integer[] values) { + this.keys = keys; + this.values = values; + } } diff --git a/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/WifiSettingsPacket.java b/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/WifiSettingsPacket.java index 3f33e7e..e74ed36 100644 --- a/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/WifiSettingsPacket.java +++ b/src/main/java/eu/czsoft/greesdk/net/packets/serverbound/WifiSettingsPacket.java @@ -5,7 +5,7 @@ import lombok.ToString; @ToString(callSuper = true) -public class WifiSettingsPacket extends ServerboundPacket { +public class WiFiSettingsPacket extends ServerboundPacket { public static String TYPE = "wlan"; @SerializedName("psw") @@ -14,7 +14,7 @@ public class WifiSettingsPacket extends ServerboundPacket { @SerializedName("ssid") public String ssid; - public WifiSettingsPacket() { + public WiFiSettingsPacket() { type = TYPE; } }