完善485除湿机

This commit is contained in:
BBIT-Kai
2026-07-03 09:05:50 +08:00
parent 9c49540fe0
commit d5656b028e
16 changed files with 431 additions and 127 deletions
+2
View File
@@ -3,3 +3,5 @@
app/build/ app/build/
.svn/ .svn/
build/ build/
.kotlin/
*.pdf
+2 -2
View File
@@ -10,8 +10,8 @@ android {
applicationId "com.example.iot_controlhost" applicationId "com.example.iot_controlhost"
minSdkVersion 25 minSdkVersion 25
targetSdkVersion 30 targetSdkVersion 30
versionCode 158 versionCode 159
versionName "3.5.0.158" versionName "3.5.0.159"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk { ndk {
moduleName "mcu" moduleName "mcu"
@@ -8,6 +8,7 @@ import com.example.iot_controlhost.utils.global.HardwareSetting;
import com.example.iot_controlhost.utils.log.MyLog; import com.example.iot_controlhost.utils.log.MyLog;
import java.io.File; import java.io.File;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@@ -279,6 +280,35 @@ public class SerialPortUtil {
return false; return false;
} }
public String clearInputBuffer(long waitMs) {
if (!isStart || inputStream == null) {
return "";
}
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
long endTime = System.currentTimeMillis() + Math.max(waitMs, 0);
try {
do {
int available = inputStream.available();
if (available > 0) {
byte[] readData = new byte[available];
int size = inputStream.read(readData);
if (size > 0) {
buffer.write(readData, 0, size);
}
} else if (waitMs > 0) {
Thread.sleep(20);
}
} while (System.currentTimeMillis() < endTime);
} catch (IOException | InterruptedException e) {
if (e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
e.printStackTrace();
}
byte[] readData = buffer.toByteArray();
return readData.length == 0 ? "" : DataUtils.ByteArrToHex(readData);
}
public boolean isStart() { public boolean isStart() {
return isStart; return isStart;
} }
@@ -130,13 +130,12 @@ public class AutoControllerAdapter extends BaseRecyclerAdapter<Controller, ItemC
binding.tvController.setTextColor(Color.parseColor(RoomSetting.isDarkTheme() ? "#FFFFFF" : "#3A3A3A")); binding.tvController.setTextColor(Color.parseColor(RoomSetting.isDarkTheme() ? "#FFFFFF" : "#3A3A3A"));
binding.tvPower.setTextColor(Color.parseColor(RoomSetting.isDarkTheme() ? "#FFFFFF" : "#3A3A3A")); binding.tvPower.setTextColor(Color.parseColor(RoomSetting.isDarkTheme() ? "#FFFFFF" : "#3A3A3A"));
} }
if (device instanceof Dehumidifier485) { if (device instanceof Dehumidifier485 && RoomController.relay.getModel().equals(RoomController.relay.getModels()[2])) {
Dehumidifier485 dehumidifier = (Dehumidifier485) device;
binding.tvPower.setVisibility(View.VISIBLE); binding.tvPower.setVisibility(View.VISIBLE);
binding.tvPower.setText("环境湿度" + dehumidifier.getEnvironmentHumidityText()); binding.tvPower.setText("实时功率" + RoomController.dehumidifier485Relay.getPowerText() + "w");
} else if (device instanceof Relay && RoomController.relay.getModel().equals(RoomController.relay.getModels()[2])) { } else if (device instanceof Relay && RoomController.relay.getModel().equals(RoomController.relay.getModels()[2])) {
binding.tvPower.setVisibility(View.VISIBLE); binding.tvPower.setVisibility(View.VISIBLE);
binding.tvPower.setText("实时功率:" + ((Relay) device).getPower() + "w"); binding.tvPower.setText("实时功率:" + ((Relay) device).getPowerText() + "w");
} else { } else {
binding.tvPower.setVisibility(View.GONE); binding.tvPower.setVisibility(View.GONE);
} }
@@ -106,13 +106,12 @@ public class ManualControllerAdapter extends BaseRecyclerAdapter<Controller, Ite
binding.tvController.setTextColor(Color.parseColor(RoomSetting.isDarkTheme() ? "#FFFFFF" : "#3A3A3A")); binding.tvController.setTextColor(Color.parseColor(RoomSetting.isDarkTheme() ? "#FFFFFF" : "#3A3A3A"));
binding.tvPower.setTextColor(Color.parseColor(RoomSetting.isDarkTheme() ? "#FFFFFF" : "#3A3A3A")); binding.tvPower.setTextColor(Color.parseColor(RoomSetting.isDarkTheme() ? "#FFFFFF" : "#3A3A3A"));
} }
if (device instanceof Dehumidifier485) { if (device instanceof Dehumidifier485 && RoomController.relay.getModel().equals(RoomController.relay.getModels()[2])) {
Dehumidifier485 dehumidifier = (Dehumidifier485) device;
binding.tvPower.setVisibility(View.VISIBLE); binding.tvPower.setVisibility(View.VISIBLE);
binding.tvPower.setText("环境湿度" + dehumidifier.getEnvironmentHumidityText()); binding.tvPower.setText("实时功率" + RoomController.dehumidifier485Relay.getPowerText() + "w");
} else if (device instanceof Relay && RoomController.relay.getModel().equals(RoomController.relay.getModels()[2])) { } else if (device instanceof Relay && RoomController.relay.getModel().equals(RoomController.relay.getModels()[2])) {
binding.tvPower.setVisibility(View.VISIBLE); binding.tvPower.setVisibility(View.VISIBLE);
binding.tvPower.setText("实时功率:" + ((Relay) device).getPower() + "w"); binding.tvPower.setText("实时功率:" + ((Relay) device).getPowerText() + "w");
} else { } else {
binding.tvPower.setVisibility(View.GONE); binding.tvPower.setVisibility(View.GONE);
} }
@@ -3,6 +3,9 @@ package com.example.iot_controlhost.model.controller;
import com.blankj.utilcode.util.StringUtils; import com.blankj.utilcode.util.StringUtils;
import com.example.iot_controlhost.base.SetAddress; import com.example.iot_controlhost.base.SetAddress;
import com.example.iot_controlhost.utils.MMKVUtil; import com.example.iot_controlhost.utils.MMKVUtil;
import com.example.iot_controlhost.utils.global.RoomController;
import com.example.iot_controlhost.utils.global.Variable;
import com.example.iot_controlhost.utils.log.MyLog;
/** /**
* 西奈 485 除湿机控制器。 * 西奈 485 除湿机控制器。
@@ -29,6 +32,7 @@ public class Dehumidifier485 extends Controller implements SetAddress {
private static final int REG_SET_ADDRESS = 0x0009; private static final int REG_SET_ADDRESS = 0x0009;
private static final int REG_SET_BAUD = 0x000E; private static final int REG_SET_BAUD = 0x000E;
private static final int REG_BROADCAST_POWER = 0x00EE; private static final int REG_BROADCAST_POWER = 0x00EE;
private static final long POWER_ON_SERIAL_BUFFER_CLEAR_MS = 500;
private final String TARGET_HUMIDITY = name + "targetHumidity"; private final String TARGET_HUMIDITY = name + "targetHumidity";
private final String TARGET_TEMPERATURE = name + "targetTemperature"; private final String TARGET_TEMPERATURE = name + "targetTemperature";
@@ -54,20 +58,47 @@ public class Dehumidifier485 extends Controller implements SetAddress {
@Override @Override
public boolean setPowerSupply(boolean state) { public boolean setPowerSupply(boolean state) {
if (!isAvailable()) { if (!isAvailable()) {
MyLog.controllerError("485除湿机:未正确配置但尝试开关");
return false; return false;
} }
boolean result; boolean result;
if ("00".equals(getAddress())) { if (state) {
result = sendBroadcastPower(getAddress(), state, true); if (!RoomController.dehumidifier485Relay.isPowerSupply()) {
MyLog.controller("485除湿机物理电源当前为关闭状态,现开启485除湿机物理开关");
if (RoomController.dehumidifier485Relay.setPowerSupply(true)) {
MyLog.controller("485除湿机物理电源打开成功,等待" + Variable.WAIT_START_485_DE / 1000 + "s后发送485开机指令");
try {
Thread.sleep(Variable.WAIT_START_485_DE);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
clearPowerOnSerialBuffer();
} else {
MyLog.controllerError("485除湿机物理电源打开失败");
return false;
}
}
MyLog.controller("485除湿机:开机");
result = writePowerState(true);
} else { } else {
result = writeRegister(getAddress(), REG_POWER, state ? 1 : 0, true); MyLog.controller("485除湿机:关机");
result = writePowerState(false);
} }
if (result) { if (result) {
powerSupply = state; powerSupply = state;
if (!state) {
RoomController.doNotNeedDelayCloseDehumidifier485 = false;
}
} }
return result; return result;
} }
@Override
public boolean isPowerSupply() {
return super.isPowerSupply() && RoomController.dehumidifier485Relay.isPowerSupply();
}
public boolean setTargetHumidity(int humidity) { public boolean setTargetHumidity(int humidity) {
if (humidity < 5 || humidity > 99) { if (humidity < 5 || humidity > 99) {
return false; return false;
@@ -244,7 +275,7 @@ public class Dehumidifier485 extends Controller implements SetAddress {
public String getWorkStatusText() { public String getWorkStatusText() {
if (workStatus == 0) { if (workStatus == 0) {
return "待机"; return "运行中";
} }
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
appendStatus(builder, 0, "除湿"); appendStatus(builder, 0, "除湿");
@@ -256,7 +287,7 @@ public class Dehumidifier485 extends Controller implements SetAddress {
@Override @Override
public boolean isAvailable() { public boolean isAvailable() {
return isEnable() && !StringUtils.isEmpty(getAddress()); return isEnable() && !StringUtils.isEmpty(getAddress()) && RoomController.dehumidifier485Relay.isAvailable();
} }
@Override @Override
@@ -336,10 +367,7 @@ public class Dehumidifier485 extends Controller implements SetAddress {
} }
int power = getRegister(result, 0); int power = getRegister(result, 0);
powerSupply = power == 1; powerSupply = power == 1;
setTargetHumidityCache(getRegister(result, 1)); // 设定项由写入成功后更新缓存,状态帧只刷新运行反馈,避免旧帧覆盖手动选择。
setTargetTemperatureCache(getRegister(result, 2));
setFanSpeedCache(getRegister(result, 3));
setWorkModeCache(getRegister(result, 4));
workStatus = getRegister(result, 5); workStatus = getRegister(result, 5);
int humidity = getRegister(result, 6); int humidity = getRegister(result, 6);
environmentHumidity = humidity == 0x00FF ? null : humidity; environmentHumidity = humidity == 0x00FF ? null : humidity;
@@ -357,8 +385,15 @@ public class Dehumidifier485 extends Controller implements SetAddress {
} }
private int getRegister(String result, int index) { private int getRegister(String result, int index) {
return getRegister(result, index, 0);
}
private int getRegister(String result, int index, int defaultValue) {
int start = 6 + index * 4; int start = 6 + index * 4;
return parseHex(result.substring(start, start + 4), 0); if (result.length() < start + 4) {
return defaultValue;
}
return parseHex(result.substring(start, start + 4), defaultValue);
} }
private boolean writeRegister(String address, int register, int value, boolean checkAvailable) { private boolean writeRegister(String address, int register, int value, boolean checkAvailable) {
@@ -376,6 +411,20 @@ public class Dehumidifier485 extends Controller implements SetAddress {
return serialPortUtil.sendSerialDataNoResponse(this, instruction); return serialPortUtil.sendSerialDataNoResponse(this, instruction);
} }
private boolean writePowerState(boolean state) {
if ("00".equals(getAddress())) {
return sendBroadcastPower(getAddress(), state, true);
}
return writeRegister(getAddress(), REG_POWER, state ? 1 : 0, true);
}
private void clearPowerOnSerialBuffer() {
String droppedData = serialPortUtil.clearInputBuffer(POWER_ON_SERIAL_BUFFER_CLEAR_MS);
if (!StringUtils.isEmpty(droppedData)) {
MyLog.controller("485除湿机:清理上电串口残留 " + droppedData);
}
}
private boolean sendBroadcastPower(String address, boolean state, boolean checkAvailable) { private boolean sendBroadcastPower(String address, boolean state, boolean checkAvailable) {
if (checkAvailable && !isAvailable()) { if (checkAvailable && !isAvailable()) {
return false; return false;
@@ -26,6 +26,7 @@ public class Dehumidifier extends Relay {
// 设置物理开关的方法 // 设置物理开关的方法
return super.setPowerSupply(state); return super.setPowerSupply(state);
} }
@Override @Override
public boolean setPowerSupply(boolean state) { public boolean setPowerSupply(boolean state) {
// 设置红外与物理开的方法 // 设置红外与物理开的方法
@@ -0,0 +1,12 @@
package com.example.iot_controlhost.model.controller.relay;
import com.example.iot_controlhost.R;
/**
* 485除湿机物理电源继电器。
*/
public class Dehumidifier485Relay extends Relay {
public Dehumidifier485Relay(String name) {
super(name, R.mipmap.ven_open, R.mipmap.ven_close);
}
}
@@ -320,6 +320,10 @@ public class Relay extends Controller implements SetAddress {
return power; return power;
} }
public String getPowerText() {
return new DecimalFormat("0.##").format(power);
}
public void setPower(double power) { public void setPower(double power) {
this.power = power; this.power = power;
} }
@@ -191,7 +191,7 @@ public class DebugActivity extends BaseActivity<ActivityDebugBinding, DebugActiv
public void doInUIThread(Boolean aBoolean) { public void doInUIThread(Boolean aBoolean) {
binding.tvSend.setText(SerialPortUtil.T); binding.tvSend.setText(SerialPortUtil.T);
binding.tvReceive.setText(SerialPortUtil.R); binding.tvReceive.setText(SerialPortUtil.R);
binding.tvParse.setText(aBoolean ? setAddress.getTestState() : "数据采集失败"); binding.tvParse.setText(aBoolean ? toSingleLine(setAddress.getTestState()) : "数据采集失败");
hideLoadingDialog(); hideLoadingDialog();
} }
}); });
@@ -256,4 +256,14 @@ public class DebugActivity extends BaseActivity<ActivityDebugBinding, DebugActiv
} }
private String toSingleLine(String text) {
if (text == null) {
return "";
}
return text.replace("\r\n", "")
.replace("\n", "")
.replace("\r", "")
.replaceAll("\\s+", " ");
}
} }
@@ -1,6 +1,8 @@
package com.example.iot_controlhost.ui.dialog; package com.example.iot_controlhost.ui.dialog;
import android.content.Context; import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.transition.Fade; import android.transition.Fade;
import android.transition.TransitionManager; import android.transition.TransitionManager;
import android.view.View; import android.view.View;
@@ -25,7 +27,17 @@ import android_serialport_api.SerialPortUtil;
* 485除湿机控制弹窗。 * 485除湿机控制弹窗。
*/ */
public class Dehumidifier485Dialog extends BaseDialog<DialogDehumidifier485Binding> { public class Dehumidifier485Dialog extends BaseDialog<DialogDehumidifier485Binding> {
private static final long STATE_REFRESH_INTERVAL = 5 * 1000;
private static final String OPERATE_FAIL_MESSAGE = "操作485除湿机失败";
private final Dehumidifier485 dehumidifier; private final Dehumidifier485 dehumidifier;
private final Handler stateRefreshHandler = new Handler(Looper.getMainLooper());
private final Runnable stateRefreshRunnable = new Runnable() {
@Override
public void run() {
refreshStateSilently();
}
};
public Dehumidifier485Dialog(@NonNull Context mContext, Dehumidifier485 dehumidifier) { public Dehumidifier485Dialog(@NonNull Context mContext, Dehumidifier485 dehumidifier) {
super(mContext); super(mContext);
@@ -46,14 +58,29 @@ public class Dehumidifier485Dialog extends BaseDialog<DialogDehumidifier485Bindi
binding.fanHigh.setOnClickListener(v -> changeDehumidifier(7)); binding.fanHigh.setOnClickListener(v -> changeDehumidifier(7));
} }
@Override
public void show() {
super.show();
scheduleStateRefresh(0);
}
private void refreshDehumidifier() { private void refreshDehumidifier() {
TransitionManager.beginDelayedTransition(binding.ll, new Fade()); refreshDehumidifier(true);
binding.tvTargetHumidity.setText(dehumidifier.isPowerSupply() ? String.valueOf(dehumidifier.getTargetHumidity()) : "-"); }
binding.tvEnvironmentHumidity.setText("环境湿度:" + dehumidifier.getEnvironmentHumidityText());
binding.tvEnvironmentTemperature.setText("环境温度:" + dehumidifier.getEnvironmentTemperatureText()); private void refreshDehumidifier(boolean animate) {
binding.tvWorkStatus.setText("状态:" + dehumidifier.getWorkStatusText()); if (animate) {
binding.tvFault.setText("故障:" + dehumidifier.getFaultText()); TransitionManager.beginDelayedTransition(binding.ll, new Fade());
binding.btnPower.setImageDrawable(mContext.getDrawable(dehumidifier.isPowerSupply() ? R.mipmap.open : R.mipmap.close)); }
boolean powerSupply = dehumidifier.isPowerSupply();
binding.tvTargetHumidity.setText(powerSupply ? String.valueOf(dehumidifier.getTargetHumidity()) : "-");
binding.tvEnvironmentTemperature.setText("环境温度:" + (powerSupply ? dehumidifier.getEnvironmentTemperatureText() : "-"));
binding.tvEnvironmentHumidity.setText("环境湿度:" + (powerSupply ? dehumidifier.getEnvironmentHumidityText() : "-"));
binding.tvWorkStatus.setText("目前状态:" + (powerSupply ? dehumidifier.getWorkStatusText() : "-"));
binding.tvFault.setText("故障情况:" + (powerSupply ? dehumidifier.getFaultText() : "-"));
binding.btnPower.setImageDrawable(mContext.getDrawable(powerSupply ? R.mipmap.open : R.mipmap.close));
binding.modeDehumidify.setImageDrawable(mContext.getDrawable(RoomSetting.isDarkTheme() ? R.mipmap.cold_dark : R.mipmap.cold));
binding.modeVentilation.setImageDrawable(mContext.getDrawable(RoomSetting.isDarkTheme() ? R.mipmap.auto_dark : R.mipmap.auto));
binding.ivSelDehumidify.setVisibility(dehumidifier.getWorkMode() == Dehumidifier485.MODE_DEHUMIDIFY ? View.VISIBLE : View.INVISIBLE); binding.ivSelDehumidify.setVisibility(dehumidifier.getWorkMode() == Dehumidifier485.MODE_DEHUMIDIFY ? View.VISIBLE : View.INVISIBLE);
binding.ivSelVentilation.setVisibility(dehumidifier.getWorkMode() == Dehumidifier485.MODE_VENTILATION ? View.VISIBLE : View.INVISIBLE); binding.ivSelVentilation.setVisibility(dehumidifier.getWorkMode() == Dehumidifier485.MODE_VENTILATION ? View.VISIBLE : View.INVISIBLE);
binding.ivSelFanLow.setVisibility(dehumidifier.getFanSpeed() == Dehumidifier485.FAN_LOW ? View.VISIBLE : View.INVISIBLE); binding.ivSelFanLow.setVisibility(dehumidifier.getFanSpeed() == Dehumidifier485.FAN_LOW ? View.VISIBLE : View.INVISIBLE);
@@ -63,51 +90,44 @@ public class Dehumidifier485Dialog extends BaseDialog<DialogDehumidifier485Bindi
private void changeDehumidifier(int type) { private void changeDehumidifier(int type) {
DialogUtil.showLoadingDialog(mContext, mContext.getString(R.string.in_operate)); DialogUtil.showLoadingDialog(mContext, mContext.getString(R.string.in_operate));
MyQueue.start(MyQueue.TYPE_CONTROLLER, new QueueIOUITask<Boolean>() { MyQueue.start(MyQueue.TYPE_CONTROLLER, new QueueIOUITask<OperateResult>() {
@Override @Override
public Boolean doInQueueThread() { public OperateResult doInQueueThread() {
switch (type) { switch (type) {
case 0: case 0:
if (dehumidifier.isPowerSupply()) { if (dehumidifier.isPowerSupply()) {
return dehumidifier.setPowerSupply(false); return OperateResult.from(dehumidifier.setPowerSupply(false), OPERATE_FAIL_MESSAGE);
} }
boolean powerResult = dehumidifier.setPowerSupply(true); return openWithLastSetting();
if (powerResult) {
dehumidifier.setWorkMode(dehumidifier.getWorkMode());
dehumidifier.setFanSpeed(dehumidifier.getFanSpeed());
dehumidifier.setTargetHumidity(dehumidifier.getTargetHumidity());
dehumidifier.setTargetTemperature(dehumidifier.getTargetTemperature());
}
return powerResult;
case 1: case 1:
return dehumidifier.setTargetHumidity(dehumidifier.getTargetHumidity() - 1); return operateAfterPowerOn(() -> dehumidifier.setTargetHumidity(dehumidifier.getTargetHumidity() - 1));
case 2: case 2:
return dehumidifier.setTargetHumidity(dehumidifier.getTargetHumidity() + 1); return operateAfterPowerOn(() -> dehumidifier.setTargetHumidity(dehumidifier.getTargetHumidity() + 1));
case 3: case 3:
return dehumidifier.setWorkMode(Dehumidifier485.MODE_DEHUMIDIFY); return operateAfterPowerOn(() -> dehumidifier.setWorkMode(Dehumidifier485.MODE_DEHUMIDIFY));
case 4: case 4:
return dehumidifier.setWorkMode(Dehumidifier485.MODE_VENTILATION); return operateAfterPowerOn(() -> dehumidifier.setWorkMode(Dehumidifier485.MODE_VENTILATION));
case 5: case 5:
return dehumidifier.setFanSpeed(Dehumidifier485.FAN_LOW); return operateAfterPowerOn(() -> dehumidifier.setFanSpeed(Dehumidifier485.FAN_LOW));
case 6: case 6:
return dehumidifier.setFanSpeed(Dehumidifier485.FAN_MIDDLE); return operateAfterPowerOn(() -> dehumidifier.setFanSpeed(Dehumidifier485.FAN_MIDDLE));
case 7: case 7:
return dehumidifier.setFanSpeed(Dehumidifier485.FAN_HIGH); return operateAfterPowerOn(() -> dehumidifier.setFanSpeed(Dehumidifier485.FAN_HIGH));
case 8: case 8:
return dehumidifier.readState(); return OperateResult.from(dehumidifier.readState(), "读取485除湿机状态失败");
default: default:
return false; return OperateResult.fail(OPERATE_FAIL_MESSAGE);
} }
} }
@Override @Override
public void doInUIThread(Boolean result) { public void doInUIThread(OperateResult result) {
if (result) { if (result.success) {
successTips(dehumidifier.getState()); successTips(dehumidifier.getState());
UserLog.operate("手动:操作485除湿机 " + dehumidifier.getState()); UserLog.operate("手动:操作485除湿机 " + dehumidifier.getState());
} else { } else {
errorTips("操作485除湿机失败"); errorTips(result.message);
UserLog.operateError("手动:操作485除湿机失败"); UserLog.operateError("手动:操作485除湿机失败" + result.message);
} }
refreshDehumidifier(); refreshDehumidifier();
DialogUtil.hideLoadingDialog(); DialogUtil.hideLoadingDialog();
@@ -115,8 +135,101 @@ public class Dehumidifier485Dialog extends BaseDialog<DialogDehumidifier485Bindi
}); });
} }
private void refreshStateSilently() {
if (!isShowing()) {
return;
}
MyQueue.start(MyQueue.TYPE_CONTROLLER, new QueueIOUITask<Boolean>() {
@Override
public Boolean doInQueueThread() {
return dehumidifier.isPowerSupply() && dehumidifier.readState();
}
@Override
public void doInUIThread(Boolean result) {
if (!isShowing()) {
return;
}
refreshDehumidifier(false);
scheduleStateRefresh(STATE_REFRESH_INTERVAL);
}
});
}
private void scheduleStateRefresh(long delay) {
stateRefreshHandler.removeCallbacks(stateRefreshRunnable);
stateRefreshHandler.postDelayed(stateRefreshRunnable, delay);
}
private OperateResult openWithLastSetting() {
OperateResult powerResult = ensurePowerOn();
if (!powerResult.success) {
return powerResult;
}
boolean modeResult = dehumidifier.setWorkMode(dehumidifier.getWorkMode());
boolean fanResult = dehumidifier.setFanSpeed(dehumidifier.getFanSpeed());
boolean humidityResult = dehumidifier.setTargetHumidity(dehumidifier.getTargetHumidity());
boolean temperatureResult = dehumidifier.setTargetTemperature(dehumidifier.getTargetTemperature());
if (modeResult && fanResult && humidityResult && temperatureResult) {
dehumidifier.readState();
return OperateResult.success();
}
return OperateResult.fail("开机成功,参数同步失败");
}
private OperateResult operateAfterPowerOn(DehumidifierOperation operation) {
OperateResult powerResult = ensurePowerOn();
if (!powerResult.success) {
return powerResult;
}
return OperateResult.from(operation.run(), OPERATE_FAIL_MESSAGE);
}
private OperateResult ensurePowerOn() {
if (dehumidifier.isPowerSupply()) {
return OperateResult.success();
}
if (!dehumidifier.setPowerSupply(true)) {
return OperateResult.fail(OPERATE_FAIL_MESSAGE);
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return OperateResult.fail("开机成功,等待设备启动被中断");
}
return OperateResult.success();
}
private interface DehumidifierOperation {
boolean run();
}
private static class OperateResult {
boolean success;
String message;
private OperateResult(boolean success, String message) {
this.success = success;
this.message = message;
}
static OperateResult success() {
return new OperateResult(true, null);
}
static OperateResult fail(String message) {
return new OperateResult(false, message);
}
static OperateResult from(boolean success, String failMessage) {
return success ? success() : fail(failMessage);
}
}
@Override @Override
public void dismiss() { public void dismiss() {
stateRefreshHandler.removeCallbacks(stateRefreshRunnable);
super.dismiss(); super.dismiss();
if (RoomSetting.getMode() == 0) { if (RoomSetting.getMode() == 0) {
RxBusUtils.get().post(RxTag.UPDATE_MANUAL, 0); RxBusUtils.get().post(RxTag.UPDATE_MANUAL, 0);
@@ -121,12 +121,12 @@ public class HumidityController extends Control {
if (autoDehumidifier != null) { if (autoDehumidifier != null) {
MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> { MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> {
MyLog.auto("自动:" + (dehumidifierState ? "开启" : "关闭") + "除湿机--"); MyLog.auto("自动:" + (dehumidifierState ? "开启" : "关闭") + "除湿机--");
if (autoDehumidifier instanceof Dehumidifier485 && dehumidifierState) { boolean operateResult = MyUtil.autoControlOperateThird(autoDehumidifier, dehumidifierState);
if (operateResult && autoDehumidifier instanceof Dehumidifier485 && dehumidifierState) {
Dehumidifier485 dehumidifier485 = (Dehumidifier485) autoDehumidifier; Dehumidifier485 dehumidifier485 = (Dehumidifier485) autoDehumidifier;
dehumidifier485.setWorkMode(Dehumidifier485.MODE_DEHUMIDIFY); dehumidifier485.setWorkMode(Dehumidifier485.MODE_DEHUMIDIFY);
dehumidifier485.setTargetHumidity(dehumidifierTargetHumidity); dehumidifier485.setTargetHumidity(dehumidifierTargetHumidity);
} }
MyUtil.autoControlOperateThird(autoDehumidifier, dehumidifierState);
})); }));
} }
} }
@@ -9,6 +9,7 @@ import com.example.iot_controlhost.model.controller.DehumidifierInfrared;
import com.example.iot_controlhost.model.controller.Floor; import com.example.iot_controlhost.model.controller.Floor;
import com.example.iot_controlhost.model.controller.relay.AirCondition; import com.example.iot_controlhost.model.controller.relay.AirCondition;
import com.example.iot_controlhost.model.controller.relay.Dehumidifier; import com.example.iot_controlhost.model.controller.relay.Dehumidifier;
import com.example.iot_controlhost.model.controller.relay.Dehumidifier485Relay;
import com.example.iot_controlhost.model.controller.relay.Fan; import com.example.iot_controlhost.model.controller.relay.Fan;
import com.example.iot_controlhost.model.controller.relay.FloorRelay; import com.example.iot_controlhost.model.controller.relay.FloorRelay;
import com.example.iot_controlhost.model.controller.relay.Relay; import com.example.iot_controlhost.model.controller.relay.Relay;
@@ -37,7 +38,7 @@ public class RoomController {
"空调", "加湿器", "进气扇", "排气扇", "红光灯",//1-5 "空调", "加湿器", "进气扇", "排气扇", "红光灯",//1-5
"白光灯", "匀风扇", "消毒灯", "空调红外控制器", "继电器",//6-10 "白光灯", "匀风扇", "消毒灯", "空调红外控制器", "继电器",//6-10
"继电器-地暖", "换气扇", "新风", "空调红外控制器2", "除湿机红外控制器",//11-15 "继电器-地暖", "换气扇", "新风", "空调红外控制器2", "除湿机红外控制器",//11-15
"除湿机"// 16 "除湿机", "485除湿电源"// 16-17
}; };
//——————————————————————————————————————————————以下为控制器—————————————————————————————————————————————————— //——————————————————————————————————————————————以下为控制器——————————————————————————————————————————————————
@@ -75,6 +76,10 @@ public class RoomController {
* 继电器-除湿机 * 继电器-除湿机
*/ */
public static Dehumidifier dehumidifier = new Dehumidifier(DEVICE_NAME[16]); public static Dehumidifier dehumidifier = new Dehumidifier(DEVICE_NAME[16]);
/**
* 485除湿机物理电源
*/
public static Dehumidifier485Relay dehumidifier485Relay = new Dehumidifier485Relay(DEVICE_NAME[17]);
/** /**
* 加湿器 * 加湿器
*/ */
@@ -124,7 +129,8 @@ public class RoomController {
*/ */
public static List<Relay> getAllRelayDevice() { public static List<Relay> getAllRelayDevice() {
List<Relay> devices = new ArrayList<>(); List<Relay> devices = new ArrayList<>();
Collections.addAll(devices, relayFloor, airCondition, dehumidifier, humidifier, intakeFan, evenFan, exhaustFan, uvLight, whiteLight, redLight, airExchange); Collections.addAll(devices, relayFloor, airCondition, dehumidifier, dehumidifier485Relay,
humidifier, intakeFan, evenFan, exhaustFan, uvLight, whiteLight, redLight, airExchange);
return devices; return devices;
} }
@@ -172,6 +178,7 @@ public class RoomController {
devices.remove(RoomController.exhaustFan); devices.remove(RoomController.exhaustFan);
devices.remove(RoomController.relayFloor); devices.remove(RoomController.relayFloor);
devices.remove(RoomController.airCondition); devices.remove(RoomController.airCondition);
devices.remove(RoomController.dehumidifier485Relay);
return devices; return devices;
} }
@@ -234,6 +241,8 @@ public class RoomController {
return airExchange; return airExchange;
case 16: case 16:
return dehumidifier; return dehumidifier;
case 17:
return dehumidifier485Relay;
default: default:
//尝试获得名字错误的->继电器 //尝试获得名字错误的->继电器
return null; return null;
@@ -257,13 +266,19 @@ public class RoomController {
//关闭单独设备 //关闭单独设备
MyInfraredUtils.getInstances().setPowerSupply(false); MyInfraredUtils.getInstances().setPowerSupply(false);
RoomController.floor.setPowerSupply(false); RoomController.floor.setPowerSupply(false);
RoomController.dehumidifier485.setPowerSupply(false); if (RoomController.dehumidifier485.isAvailable()) {
RoomController.dehumidifier485.setPowerSupply(false);
}
//关闭继电器下的所有设备 //关闭继电器下的所有设备
List<Relay> devices = getAllAvailableRelays(); List<Relay> devices = getAllAvailableRelays();
//除了空调物理电源 //除了空调物理电源
devices.remove(RoomController.airCondition); devices.remove(RoomController.airCondition);
//除了除湿机物理电源 //除了除湿机物理电源
devices.remove(RoomController.dehumidifier); devices.remove(RoomController.dehumidifier);
if (RoomController.dehumidifier485.isAvailable()) {
//除了485除湿机物理电源
devices.remove(RoomController.dehumidifier485Relay);
}
for (Relay r : devices) { for (Relay r : devices) {
r.setPowerSupply(false); r.setPowerSupply(false);
} }
@@ -282,14 +297,25 @@ public class RoomController {
}); });
// 检查除湿机功率是否与除湿机物理电源状态匹配,时刻监测当前除湿机功率状态,使之与软件开关匹配 // 检查除湿机功率是否与除湿机物理电源状态匹配,时刻监测当前除湿机功率状态,使之与软件开关匹配
// 防止出现软件界面中开启除湿器但实际上除湿器未开启(功率不足100W)的情况 // 防止出现软件界面中开启除湿器但实际上除湿器未开启(功率不足100W)的情况
if (RoomController.dehumidifier.isAvailable()) { if (RoomController.dehumidifier.isAvailable() || RoomController.dehumidifier485Relay.isAvailable()) {
PollingTask.getInstance().startPollingTaskOnIOThread(RxTag.TAG_DEHUMIDIFIER_STATUS, 60, () -> { PollingTask.getInstance().startPollingTaskOnIOThread(RxTag.TAG_DEHUMIDIFIER_STATUS, 60, () -> {
if (RoomController.dehumidifier.isPowerSupply() && RoomController.dehumidifier.getPower() < 100) { if (RoomController.dehumidifier.isAvailable() && RoomController.dehumidifier.isPowerSupply() && RoomController.dehumidifier.getPower() < 100) {
MyLog.controllerError("除湿机电源已开启但功率不足100W,现尝试再次开启除湿机物理电源"); MyLog.controllerError("除湿机电源已开启但功率不足100W,现尝试再次开启除湿机物理电源");
MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> RoomController.dehumidifier.setPowerSupply(true))); MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> RoomController.dehumidifier.setPowerSupplyForOld(true)));
} else if (!RoomController.dehumidifier.isPowerSupply() && RoomController.dehumidifier.getPower() > 100) { } else if (RoomController.dehumidifier.isAvailable() && !RoomController.dehumidifier.isPowerSupply() && RoomController.dehumidifier.getPower() > 100) {
MyLog.controllerError("除湿机电源已关闭但功率大于100W,现尝试再次关闭除湿机物理电源"); MyLog.controllerError("除湿机电源已关闭但功率大于100W,现尝试再次关闭除湿机物理电源");
MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> RoomController.dehumidifier.setPowerSupply(false))); MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> RoomController.dehumidifier.setPowerSupplyForOld(false)));
}
if (RoomController.dehumidifier485Relay.isAvailable()
&& RoomController.dehumidifier485.isPowerSupply()
&& RoomController.dehumidifier485Relay.getPower() < 100) {
MyLog.controllerError("485除湿机电源已开启但功率不足100W,现尝试再次开启485除湿机物理电源");
MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> RoomController.dehumidifier485Relay.setPowerSupply(true)));
} else if (RoomController.dehumidifier485Relay.isAvailable()
&& !RoomController.dehumidifier485.isPowerSupply()
&& RoomController.dehumidifier485Relay.getPower() > 100) {
MyLog.controllerError("485除湿机电源已关闭但功率大于100W,现尝试再次关闭485除湿机物理电源");
MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> RoomController.dehumidifier485Relay.setPowerSupply(false)));
} }
}); });
} }
@@ -305,11 +331,22 @@ public class RoomController {
// MyLog.test("空调后台线程:不采取操作"); // MyLog.test("空调后台线程:不采取操作");
} }
if (dehumidifier.isAvailable() && !dehumidifierInfrared.isPowerSupply() && doNotNeedDelayCloseDehumidifier) { if (dehumidifier.isAvailable()
&& !dehumidifierInfrared.isPowerSupply()
&& doNotNeedDelayCloseDehumidifier) {
MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> RoomController.dehumidifier.setPowerSupplyForOld(false))); MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> RoomController.dehumidifier.setPowerSupplyForOld(false)));
} else { } else {
doNotNeedDelayCloseDehumidifier = true; doNotNeedDelayCloseDehumidifier = true;
} }
if (dehumidifier485Relay.isAvailable()
&& dehumidifier485Relay.isPowerSupply()
&& !dehumidifier485.isPowerSupply()
&& doNotNeedDelayCloseDehumidifier485) {
MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> RoomController.dehumidifier485Relay.setPowerSupply(false)));
} else {
doNotNeedDelayCloseDehumidifier485 = true;
}
}); });
//其他设备,使保持运行状态 //其他设备,使保持运行状态
PollingTask.getInstance().startPollingTaskOnIOThread(RxTag.TAG_CONTROLLER_STATE_CHECK_OTHER, Variable.CHECK_CLOSE_INFRARED, () -> { PollingTask.getInstance().startPollingTaskOnIOThread(RxTag.TAG_CONTROLLER_STATE_CHECK_OTHER, Variable.CHECK_CLOSE_INFRARED, () -> {
@@ -324,6 +361,10 @@ public class RoomController {
RoomController.dehumidifier.setPowerSupplyForOld(RoomController.dehumidifier.isPowerSupply()); RoomController.dehumidifier.setPowerSupplyForOld(RoomController.dehumidifier.isPowerSupply());
continue; continue;
} }
if (relay.getName().equals(RoomController.dehumidifier485Relay.getName())) {
RoomController.dehumidifier485Relay.setPowerSupply(RoomController.dehumidifier485Relay.isPowerSupply());
continue;
}
MyUtil.autoControlOperateThird(relay, relay.isPowerSupply()); MyUtil.autoControlOperateThird(relay, relay.isPowerSupply());
} }
} }
@@ -337,15 +378,21 @@ public class RoomController {
*/ */
public static boolean doNotNeedDelayCloseAirCondition = true; public static boolean doNotNeedDelayCloseAirCondition = true;
public static boolean doNotNeedDelayCloseDehumidifier = true; public static boolean doNotNeedDelayCloseDehumidifier = true;
public static boolean doNotNeedDelayCloseDehumidifier485 = true;
public static void closeAllControllers() { public static void closeAllControllers() {
List<Relay> relays = RoomController.getAllAvailableRelays(); List<Relay> relays = RoomController.getAllAvailableRelays();
MyInfraredUtils.getInstances().setPowerSupply(false); MyInfraredUtils.getInstances().setPowerSupply(false);
RoomController.dehumidifier.setPowerSupply(false); RoomController.dehumidifier.setPowerSupply(false);
RoomController.dehumidifier485.setPowerSupply(false); if (RoomController.dehumidifier485.isAvailable()) {
RoomController.dehumidifier485.setPowerSupply(false);
}
RoomController.floor.setPowerSupply(false); RoomController.floor.setPowerSupply(false);
relays.remove(RoomController.airCondition); relays.remove(RoomController.airCondition);
relays.remove(RoomController.dehumidifier); relays.remove(RoomController.dehumidifier);
if (RoomController.dehumidifier485.isAvailable()) {
relays.remove(RoomController.dehumidifier485Relay);
}
for (Relay r : relays) { for (Relay r : relays) {
r.setPowerSupply(false); r.setPowerSupply(false);
} }
@@ -41,6 +41,11 @@ public class Variable {
* 单位:毫秒 * 单位:毫秒
*/ */
public static final long WAIT_START_INFRARED = 2 * 1000; public static final long WAIT_START_INFRARED = 2 * 1000;
/**
* 开启物理开关后开启空调遥控的等待时间
* 单位:毫秒
*/
public static final long WAIT_START_485_DE = 5 * 1000;
/** /**
* 开启物理开关后开启空调遥控的等待时间 * 开启物理开关后开启空调遥控的等待时间
* 单位:毫秒 * 单位:毫秒
+9 -3
View File
@@ -149,7 +149,9 @@
android:id="@+id/tv_send" android:id="@+id/tv_send"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_weight="4" /> android:layout_weight="4"
android:ellipsize="end"
android:singleLine="true" />
</LinearLayout> </LinearLayout>
@@ -175,7 +177,9 @@
android:id="@+id/tv_receive" android:id="@+id/tv_receive"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_weight="4" /> android:layout_weight="4"
android:ellipsize="end"
android:singleLine="true" />
</LinearLayout> </LinearLayout>
@@ -201,7 +205,9 @@
android:id="@+id/tv_parse" android:id="@+id/tv_parse"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_weight="4" /> android:layout_weight="4"
android:ellipsize="end"
android:singleLine="true" />
</LinearLayout> </LinearLayout>
@@ -13,7 +13,7 @@
<androidx.cardview.widget.CardView <androidx.cardview.widget.CardView
android:layout_width="560dp" android:layout_width="560dp"
android:layout_height="690dp" android:layout_height="730dp"
android:layout_margin="80dp" android:layout_margin="80dp"
app:cardCornerRadius="10dp" app:cardCornerRadius="10dp"
app:cardElevation="40dp" app:cardElevation="40dp"
@@ -82,6 +82,25 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="#F2F0F1"> android:background="#F2F0F1">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_status_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="260dp" />
<TextView
android:id="@+id/tv_target_humidity_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="14dp"
android:text="目标湿度"
android:textColor="#666666"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="@+id/tv_target_humidity"
app:layout_constraintEnd_toStartOf="@+id/tv_target_humidity"
app:layout_constraintTop_toTopOf="@+id/tv_target_humidity" />
<TextView <TextView
android:id="@+id/tv_target_humidity" android:id="@+id/tv_target_humidity"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -107,49 +126,55 @@
<TextView <TextView
android:id="@+id/tv_environment_humidity" android:id="@+id/tv_environment_humidity"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="26dp" android:layout_marginEnd="26dp"
android:gravity="start"
android:text="环境湿度:--" android:text="环境湿度:--"
android:textSize="18sp" android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/tv_environment_temperature" app:layout_constraintBottom_toTopOf="@+id/tv_environment_temperature"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline_status_info" />
<TextView <TextView
android:id="@+id/tv_environment_temperature" android:id="@+id/tv_environment_temperature"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="26dp" android:layout_marginEnd="26dp"
android:gravity="start"
android:text="环境温度:--" android:text="环境温度:--"
android:textSize="18sp" android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/tv_work_status" app:layout_constraintBottom_toTopOf="@+id/tv_work_status"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline_status_info" />
<TextView <TextView
android:id="@+id/tv_work_status" android:id="@+id/tv_work_status"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="26dp" android:layout_marginEnd="26dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="2dp"
android:text="状态:待机" android:gravity="start"
android:text="目前状态:待机"
android:textSize="18sp" android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/tv_fault" app:layout_constraintBottom_toTopOf="@+id/tv_fault"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline_status_info" />
<TextView <TextView
android:id="@+id/tv_fault" android:id="@+id/tv_fault"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="250dp"
android:layout_marginEnd="26dp" android:layout_marginEnd="26dp"
android:layout_marginBottom="18dp" android:layout_marginBottom="18dp"
android:ellipsize="end" android:ellipsize="end"
android:gravity="start"
android:singleLine="true" android:singleLine="true"
android:text="故障:正常" android:text="故障情况:正常"
android:textSize="18sp" android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="@+id/guideline_status_info" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
@@ -157,8 +182,8 @@
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_dehumidifier_control" android:id="@+id/cl_dehumidifier_control"
android:layout_width="450dp" android:layout_width="500dp"
android:layout_height="106dp" android:layout_height="90dp"
android:layout_marginTop="30dp" android:layout_marginTop="30dp"
android:clipChildren="false" android:clipChildren="false"
android:clipToPadding="false" android:clipToPadding="false"
@@ -168,27 +193,29 @@
<androidx.cardview.widget.CardView <androidx.cardview.widget.CardView
android:id="@+id/card_power" android:id="@+id/card_power"
android:layout_width="90dp" android:layout_width="wrap_content"
android:layout_height="90dp" android:layout_height="wrap_content"
app:cardCornerRadius="45dp" android:layout_margin="5dp"
app:cardCornerRadius="40dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<ImageView <ImageView
android:id="@+id/btn_power" android:id="@+id/btn_power"
android:layout_width="match_parent" android:layout_width="80dp"
android:layout_height="match_parent" android:layout_height="80dp"
android:padding="18dp" android:padding="15dp"
android:src="@mipmap/open" /> android:src="@mipmap/open" />
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView <androidx.cardview.widget.CardView
android:id="@+id/card_mode" android:id="@+id/card_mode"
android:layout_width="330dp" android:layout_width="400dp"
android:layout_height="90dp" android:layout_height="match_parent"
app:cardCornerRadius="45dp" android:layout_margin="5dp"
app:cardCornerRadius="40dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
@@ -208,16 +235,16 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_weight="1" android:layout_weight="1"
android:padding="18dp" android:padding="15dp"
android:src="@mipmap/hum_open" /> android:src="@mipmap/cold" />
<ImageView <ImageView
android:id="@+id/mode_ventilation" android:id="@+id/mode_ventilation"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_weight="1" android:layout_weight="1"
android:padding="18dp" android:padding="15dp"
android:src="@mipmap/ven_open" /> android:src="@mipmap/auto" />
</LinearLayout> </LinearLayout>
@@ -253,7 +280,7 @@
<LinearLayout <LinearLayout
android:id="@+id/ll_mode_labels" android:id="@+id/ll_mode_labels"
android:layout_width="450dp" android:layout_width="500dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:orientation="horizontal" android:orientation="horizontal"
@@ -301,38 +328,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/fan_low"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="24dp"
android:src="@mipmap/ven_open" />
<ImageView
android:id="@+id/fan_middle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="20dp"
android:src="@mipmap/ven_open" />
<ImageView
android:id="@+id/fan_high"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="16dp"
android:src="@mipmap/ven_open" />
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -365,6 +360,38 @@
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/fan_low"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="24dp"
android:src="@mipmap/ven_open" />
<ImageView
android:id="@+id/fan_middle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="20dp"
android:src="@mipmap/ven_open" />
<ImageView
android:id="@+id/fan_high"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="16dp"
android:src="@mipmap/ven_open" />
</LinearLayout>
</FrameLayout> </FrameLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>