485除湿机

This commit is contained in:
BBIT-Kai
2026-06-29 17:23:42 +08:00
parent 30d8fe4752
commit 9c49540fe0
17 changed files with 1350 additions and 70 deletions
+2 -2
View File
@@ -10,8 +10,8 @@ android {
applicationId "com.example.iot_controlhost"
minSdkVersion 25
targetSdkVersion 30
versionCode 157
versionName "3.5.0.157"
versionCode 158
versionName "3.5.0.158"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
moduleName "mcu"
@@ -247,6 +247,38 @@ public class SerialPortUtil {
return null;
}
/**
* 发送无需设备返回的串口指令。
* 例如部分广播控制命令只写入总线,不会回传响应帧。
*/
public boolean sendSerialDataNoResponse(Device device, String data) {
boolean isSensor = device instanceof Sensor;
if (!isStart || outputStream == null) {
MyLog.appError("串口未打开但尝试发送数据");
return false;
}
try {
byte[] sendData = DataUtils.HexToByteArr(data);
outputStream.write(sendData);
outputStream.flush();
T = "T:" + data;
R = "R:无返回";
if (isSensor) {
MyLog.sensor(T);
MyLog.sensor(R);
} else {
MyLog.controller(T);
MyLog.controller(R);
}
device.setFailTimes(0);
return true;
} catch (IOException e) {
e.printStackTrace();
}
device.addFailTimes();
return false;
}
public boolean isStart() {
return isStart;
}
@@ -10,9 +10,12 @@ import com.example.iot_controlhost.R;
import com.example.iot_controlhost.base.BaseRecyclerAdapter;
import com.example.iot_controlhost.databinding.ItemControllerAutoBinding;
import com.example.iot_controlhost.model.Result;
import com.example.iot_controlhost.model.controller.Controller;
import com.example.iot_controlhost.model.controller.Dehumidifier485;
import com.example.iot_controlhost.model.controller.relay.Relay;
import com.example.iot_controlhost.model.sensor.GasSensor;
import com.example.iot_controlhost.model.thread.QueueIOUITask;
import com.example.iot_controlhost.ui.dialog.Dehumidifier485Dialog;
import com.example.iot_controlhost.utils.DialogUtil;
import com.example.iot_controlhost.utils.MyQueue;
import com.example.iot_controlhost.utils.global.AutoModelSet;
@@ -27,22 +30,18 @@ import java.util.List;
import es.dmoral.toasty.Toasty;
/**
* 手动控制继电器下的设备
* 用于主界面显示
*
* @AuthorDuanKaiji
* 自动页面控制设备列表。
*/
public class AutoControllerAdapter extends BaseRecyclerAdapter<Relay, ItemControllerAutoBinding> {
public class AutoControllerAdapter extends BaseRecyclerAdapter<Controller, ItemControllerAutoBinding> {
Context mContext;
public AutoControllerAdapter(Context context, List<Relay> dataList, Class<ItemControllerAutoBinding> bindingClass) {
public AutoControllerAdapter(Context context, List<Controller> dataList, Class<ItemControllerAutoBinding> bindingClass) {
super(dataList, bindingClass);
mContext = context;
}
@Override
protected void bindData(ItemControllerAutoBinding binding, Relay device) {
protected void bindData(ItemControllerAutoBinding binding, Controller device) {
TransitionManager.beginDelayedTransition(binding.layoutRoot, new Fade());
if ("未配置".equals(device.getName())) {
binding.cardNo.setVisibility(View.VISIBLE);
@@ -59,17 +58,15 @@ public class AutoControllerAdapter extends BaseRecyclerAdapter<Relay, ItemContro
binding.tvInfo.setText(null);
}
changeState(binding, device);
binding.tvController.setText(device.getName());
if (AutoModelSet.isAutoHumidity() && RoomController.DEVICE_NAME[2].equals(device.getName())//加湿器
|| AutoModelSet.isAutoHumidity() && RoomController.DEVICE_NAME[16].equals(device.getName()) //除湿器
|| AutoModelSet.isAutoVentilator() && RoomController.DEVICE_NAME[12].equals(device.getName()) //换气扇
|| AutoModelSet.isAutoEven() && RoomController.DEVICE_NAME[7].equals(device.getName()) //匀风扇
|| AutoModelSet.isAutoDisinfect() && RoomController.DEVICE_NAME[8].equals(device.getName()) //消毒灯
|| !AutoModelSet.getAirExchangeMode().equals(SpinnerList.AIR_EXCHANGE_MODES[0]) && RoomController.DEVICE_NAME[13].equals(device.getName()) //新风
) {
binding.tvController.setText(getDisplayName(device));
if (isAutoControlled(device)) {
binding.cardController.setOnClickListener(v -> Toasty.info(mContext, "该设备由自动控制系统接管中").show());
} else {
binding.cardController.setOnClickListener(view -> {
if (device instanceof Dehumidifier485) {
new Dehumidifier485Dialog(mContext, (Dehumidifier485) device).show();
return;
}
DialogUtil.showLoadingDialog(mContext, mContext.getString(R.string.in_operate));
MyQueue.start(MyQueue.TYPE_CONTROLLER, new QueueIOUITask<Result>() {
@Override
@@ -97,34 +94,85 @@ public class AutoControllerAdapter extends BaseRecyclerAdapter<Relay, ItemContro
}
}
private void changeState(ItemControllerAutoBinding binding, Relay device) {
private boolean isAutoControlled(Controller device) {
return AutoModelSet.isAutoHumidity() && RoomController.DEVICE_NAME[2].equals(device.getName())
|| AutoModelSet.isAutoHumidity() && RoomController.DEVICE_NAME[16].equals(device.getName())
|| AutoModelSet.isAutoHumidity() && device instanceof Dehumidifier485
|| AutoModelSet.isAutoVentilator() && RoomController.DEVICE_NAME[12].equals(device.getName())
|| AutoModelSet.isAutoEven() && RoomController.DEVICE_NAME[7].equals(device.getName())
|| AutoModelSet.isAutoDisinfect() && RoomController.DEVICE_NAME[8].equals(device.getName())
|| !AutoModelSet.getAirExchangeMode().equals(SpinnerList.AIR_EXCHANGE_MODES[0]) && RoomController.DEVICE_NAME[13].equals(device.getName());
}
private void changeState(ItemControllerAutoBinding binding, Controller device) {
if (device.isPowerSupply()) {
binding.tvState.setText("运行中");
binding.ivController.setImageResource(device.getIconOpen());
binding.ivController.setImageResource(getIconOpen(device));
binding.ivPower.setBackground(mContext.getDrawable(R.drawable.bg_controller_open));
binding.ivPower.setImageDrawable(mContext.getDrawable(R.mipmap.switch_on));
binding.cardController.setBackgroundColor(Color.parseColor("#00BDF4"));
binding.ivController.setImageDrawable(mContext.getDrawable(device.getIconOpen()));
binding.cardController.setBackgroundColor(getOpenColor(device));
binding.ivController.setImageDrawable(mContext.getDrawable(getIconOpen(device)));
binding.tvState.setTextColor(Color.parseColor("#FFFFFF"));
binding.tvController.setTextColor(Color.parseColor("#FFFFFF"));
binding.tvPower.setTextColor(Color.parseColor("#FFFFFF"));
} else {
// 地暖在超过最大温度限制后会自动断电,此时状态显示为“高温保护”而非“未启动”
if(device.getName().equals(RoomSetting.getFloorName()) && RoomSensor.getFloorTemperature() > AutoModelSet.getAutoFlorMaxTemp()) {
if (device.getName().equals(RoomSetting.getFloorName()) && RoomSensor.getFloorTemperature() > AutoModelSet.getAutoFlorMaxTemp()) {
binding.tvState.setText("高温保护中");
} else {
binding.tvState.setText("未启动");
}
binding.ivController.setImageResource(device.getIconClose());
binding.ivController.setImageResource(getIconClose(device));
binding.cardController.setBackgroundColor(Color.parseColor(RoomSetting.isDarkTheme() ? "#33DCE3E3" : "#F2F0F1"));
binding.ivPower.setBackground(mContext.getDrawable(R.drawable.bg_controller_close));
binding.ivPower.setImageDrawable(mContext.getDrawable(R.mipmap.switch_off));
binding.ivController.setImageDrawable(mContext.getDrawable(device.getIconClose()));
binding.ivController.setImageDrawable(mContext.getDrawable(getIconClose(device)));
binding.tvState.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.setVisibility(RoomController.relay.getModel().equals(RoomController.relay.getModels()[2]) ? View.VISIBLE : View.GONE);
binding.tvPower.setText("实时功率:" + device.getPower() + "w");
if (device instanceof Dehumidifier485) {
Dehumidifier485 dehumidifier = (Dehumidifier485) device;
binding.tvPower.setVisibility(View.VISIBLE);
binding.tvPower.setText("环境湿度:" + dehumidifier.getEnvironmentHumidityText());
} else if (device instanceof Relay && RoomController.relay.getModel().equals(RoomController.relay.getModels()[2])) {
binding.tvPower.setVisibility(View.VISIBLE);
binding.tvPower.setText("实时功率:" + ((Relay) device).getPower() + "w");
} else {
binding.tvPower.setVisibility(View.GONE);
}
}
private int getIconOpen(Controller device) {
if (device instanceof Relay) {
return ((Relay) device).getIconOpen();
}
if (device instanceof Dehumidifier485) {
return R.mipmap.ven_open;
}
return R.mipmap.open;
}
private int getIconClose(Controller device) {
if (device instanceof Relay) {
return ((Relay) device).getIconClose();
}
if (device instanceof Dehumidifier485) {
return R.mipmap.ven_close;
}
return R.mipmap.close;
}
private int getOpenColor(Controller device) {
if (device instanceof Dehumidifier485) {
return Color.parseColor("#00A1FF");
}
return Color.parseColor("#00BDF4");
}
private String getDisplayName(Controller device) {
if (device instanceof Dehumidifier485) {
return ((Dehumidifier485) device).getDisplayName();
}
return device.getName();
}
}
@@ -8,13 +8,15 @@ import com.example.iot_controlhost.R;
import com.example.iot_controlhost.base.BaseRecyclerAdapter;
import com.example.iot_controlhost.databinding.ItemControllerBinding;
import com.example.iot_controlhost.model.Result;
import com.example.iot_controlhost.model.controller.Controller;
import com.example.iot_controlhost.model.controller.Dehumidifier485;
import com.example.iot_controlhost.model.controller.relay.Relay;
import com.example.iot_controlhost.model.sensor.GasSensor;
import com.example.iot_controlhost.model.thread.QueueIOUITask;
import com.example.iot_controlhost.ui.dialog.Dehumidifier485Dialog;
import com.example.iot_controlhost.utils.DialogUtil;
import com.example.iot_controlhost.utils.MyQueue;
import com.example.iot_controlhost.utils.global.RoomController;
import com.example.iot_controlhost.utils.global.RoomSensor;
import com.example.iot_controlhost.utils.global.RoomSetting;
import com.example.iot_controlhost.utils.log.UserLog;
@@ -23,21 +25,18 @@ import java.util.List;
import es.dmoral.toasty.Toasty;
/**
* 手动控制继电器下的设备
* 用于主界面显示
*
* @AuthorDuanKaiji
* 手动控制设备列表。
*/
public class ManualControllerAdapter extends BaseRecyclerAdapter<Relay, ItemControllerBinding> {
public class ManualControllerAdapter extends BaseRecyclerAdapter<Controller, ItemControllerBinding> {
Context mContext;
public ManualControllerAdapter(Context context, List<Relay> dataList, Class<ItemControllerBinding> bindingClass) {
public ManualControllerAdapter(Context context, List<Controller> dataList, Class<ItemControllerBinding> bindingClass) {
super(dataList, bindingClass);
this.mContext = context;
}
@Override
protected void bindData(ItemControllerBinding binding, Relay device) {
protected void bindData(ItemControllerBinding binding, Controller device) {
if (device.getName().equals(RoomController.fan.getName())) {
binding.tvInfo.setText(GasSensor.getQualityAir());
binding.tvInfo.setTextColor(GasSensor.getQualityAirColor());
@@ -45,8 +44,12 @@ public class ManualControllerAdapter extends BaseRecyclerAdapter<Relay, ItemCont
binding.tvInfo.setText(null);
}
changeState(binding, device);
binding.tvController.setText(device.getName());
binding.tvController.setText(getDisplayName(device));
binding.cardController.setOnClickListener(view -> {
if (device instanceof Dehumidifier485) {
new Dehumidifier485Dialog(mContext, (Dehumidifier485) device).show();
return;
}
DialogUtil.showLoadingDialog(mContext, mContext.getString(R.string.in_operate));
MyQueue.start(MyQueue.TYPE_CONTROLLER, new QueueIOUITask<Result>() {
@Override
@@ -73,7 +76,7 @@ public class ManualControllerAdapter extends BaseRecyclerAdapter<Relay, ItemCont
});
}
private void changeState(ItemControllerBinding binding, Relay device) {
private void changeState(ItemControllerBinding binding, Controller device) {
if ("未配置".equals(device.getName())) {
binding.cardNo.setVisibility(View.VISIBLE);
binding.cardYes.setVisibility(View.GONE);
@@ -84,27 +87,68 @@ public class ManualControllerAdapter extends BaseRecyclerAdapter<Relay, ItemCont
}
if (device.isPowerSupply()) {
binding.tvState.setText("运行中");
binding.ivController.setImageResource(device.getIconOpen());
binding.ivController.setImageResource(getIconOpen(device));
binding.ivPower.setBackground(mContext.getDrawable(R.drawable.bg_controller_open));
binding.ivPower.setImageDrawable(mContext.getDrawable(R.mipmap.switch_on));
binding.cardController.setBackgroundColor(Color.parseColor("#00BDF4"));
binding.ivController.setImageDrawable(mContext.getDrawable(device.getIconOpen()));
binding.cardController.setBackgroundColor(getOpenColor(device));
binding.ivController.setImageDrawable(mContext.getDrawable(getIconOpen(device)));
binding.tvState.setTextColor(Color.parseColor("#FFFFFF"));
binding.tvController.setTextColor(Color.parseColor("#FFFFFF"));
binding.tvPower.setTextColor(Color.parseColor("#FFFFFF"));
} else {
binding.tvState.setText("未启动");
binding.ivController.setImageResource(device.getIconClose());
binding.ivController.setImageResource(getIconClose(device));
binding.cardController.setBackgroundColor(Color.parseColor(RoomSetting.isDarkTheme() ? "#33DCE3E3" : "#F2F0F1"));
binding.ivPower.setBackground(mContext.getDrawable(R.drawable.bg_controller_close));
binding.ivPower.setImageDrawable(mContext.getDrawable(R.mipmap.switch_off));
binding.ivController.setImageDrawable(mContext.getDrawable(device.getIconClose()));
binding.ivController.setImageDrawable(mContext.getDrawable(getIconClose(device)));
binding.tvState.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.setVisibility(RoomController.relay.getModel().equals(RoomController.relay.getModels()[2]) ? View.VISIBLE : View.GONE);
binding.tvPower.setText("实时功率:" + device.getPower() + "w");
if (device instanceof Dehumidifier485) {
Dehumidifier485 dehumidifier = (Dehumidifier485) device;
binding.tvPower.setVisibility(View.VISIBLE);
binding.tvPower.setText("环境湿度:" + dehumidifier.getEnvironmentHumidityText());
} else if (device instanceof Relay && RoomController.relay.getModel().equals(RoomController.relay.getModels()[2])) {
binding.tvPower.setVisibility(View.VISIBLE);
binding.tvPower.setText("实时功率:" + ((Relay) device).getPower() + "w");
} else {
binding.tvPower.setVisibility(View.GONE);
}
}
private int getIconOpen(Controller device) {
if (device instanceof Relay) {
return ((Relay) device).getIconOpen();
}
if (device instanceof Dehumidifier485) {
return R.mipmap.ven_open;
}
return R.mipmap.open;
}
private int getIconClose(Controller device) {
if (device instanceof Relay) {
return ((Relay) device).getIconClose();
}
if (device instanceof Dehumidifier485) {
return R.mipmap.ven_close;
}
return R.mipmap.close;
}
private int getOpenColor(Controller device) {
if (device instanceof Dehumidifier485) {
return Color.parseColor("#00A1FF");
}
return Color.parseColor("#00BDF4");
}
private String getDisplayName(Controller device) {
if (device instanceof Dehumidifier485) {
return ((Dehumidifier485) device).getDisplayName();
}
return device.getName();
}
}
@@ -55,6 +55,17 @@ public abstract class Controller extends Device {
}
}
/**
* 执行不等待设备响应的指令。
*/
protected boolean executeInstructionsNoResponse(String instruction, String operateContent) {
if (!isAvailable()) {
return false;
}
MyLog.controller("操作" + name + "" + operateContent);
return serialPortUtil.sendSerialDataNoResponse(this, instruction);
}
public boolean isPowerSupply() {
return powerSupply;
}
@@ -0,0 +1,434 @@
package com.example.iot_controlhost.model.controller;
import com.blankj.utilcode.util.StringUtils;
import com.example.iot_controlhost.base.SetAddress;
import com.example.iot_controlhost.utils.MMKVUtil;
/**
* 西奈 485 除湿机控制器。
*/
public class Dehumidifier485 extends Controller implements SetAddress {
public static final int MODE_DEHUMIDIFY = 0;
public static final int MODE_VENTILATION = 1;
public static final int FAN_LOW = 0;
public static final int FAN_MIDDLE = 1;
public static final int FAN_HIGH = 2;
public static final String[] BAUD_LIST = {"4800", "9600", "19200", "115200"};
public static final String[] FAN_SPEED_NAMES = {"低风", "中风", "高风"};
public static final String[] WORK_MODE_NAMES = {"除湿", "通风"};
public static final String[] ADDRESS_LIST = buildAddressList();
private static final int REG_POWER = 0x0000;
private static final int REG_TARGET_HUMIDITY = 0x0001;
private static final int REG_TARGET_TEMPERATURE = 0x0002;
private static final int REG_FAN_SPEED = 0x0003;
private static final int REG_WORK_MODE = 0x0004;
private static final int REG_SET_ADDRESS = 0x0009;
private static final int REG_SET_BAUD = 0x000E;
private static final int REG_BROADCAST_POWER = 0x00EE;
private final String TARGET_HUMIDITY = name + "targetHumidity";
private final String TARGET_TEMPERATURE = name + "targetTemperature";
private final String FAN_SPEED = name + "fanSpeed";
private final String WORK_MODE = name + "workMode";
private Integer environmentHumidity;
private Integer environmentTemperature;
private Integer coilTemperature1;
private Integer coilTemperature2;
private int workStatus;
private int faultCode;
private String lastTestState = "未测试";
public Dehumidifier485(String name) {
super(name);
}
public String getDisplayName() {
return "485除湿";
}
@Override
public boolean setPowerSupply(boolean state) {
if (!isAvailable()) {
return false;
}
boolean result;
if ("00".equals(getAddress())) {
result = sendBroadcastPower(getAddress(), state, true);
} else {
result = writeRegister(getAddress(), REG_POWER, state ? 1 : 0, true);
}
if (result) {
powerSupply = state;
}
return result;
}
public boolean setTargetHumidity(int humidity) {
if (humidity < 5 || humidity > 99) {
return false;
}
boolean result = writeRegister(getAddress(), REG_TARGET_HUMIDITY, humidity, true);
if (result) {
setTargetHumidityCache(humidity);
}
return result;
}
public int getTargetHumidity() {
return MMKVUtil.get(TARGET_HUMIDITY, 60);
}
public void setTargetHumidityCache(int humidity) {
MMKVUtil.put(TARGET_HUMIDITY, limit(humidity, 5, 99));
}
public boolean setTargetTemperature(int temperature) {
if (temperature < 5 || temperature > 70) {
return false;
}
boolean result = writeRegister(getAddress(), REG_TARGET_TEMPERATURE, temperature, true);
if (result) {
setTargetTemperatureCache(temperature);
}
return result;
}
public int getTargetTemperature() {
return MMKVUtil.get(TARGET_TEMPERATURE, 26);
}
public void setTargetTemperatureCache(int temperature) {
MMKVUtil.put(TARGET_TEMPERATURE, limit(temperature, 5, 70));
}
public boolean setFanSpeed(int fanSpeed) {
if (fanSpeed < FAN_LOW || fanSpeed > FAN_HIGH) {
return false;
}
boolean result = writeRegister(getAddress(), REG_FAN_SPEED, fanSpeed, true);
if (result) {
setFanSpeedCache(fanSpeed);
}
return result;
}
public int getFanSpeed() {
return MMKVUtil.get(FAN_SPEED, FAN_HIGH);
}
public void setFanSpeedCache(int fanSpeed) {
MMKVUtil.put(FAN_SPEED, limit(fanSpeed, FAN_LOW, FAN_HIGH));
}
public String getFanSpeedName() {
int fanSpeed = getFanSpeed();
return fanSpeed >= FAN_LOW && fanSpeed <= FAN_HIGH ? FAN_SPEED_NAMES[fanSpeed] : "未知";
}
public boolean setWorkMode(int workMode) {
if (workMode < MODE_DEHUMIDIFY || workMode > MODE_VENTILATION) {
return false;
}
boolean result = writeRegister(getAddress(), REG_WORK_MODE, workMode, true);
if (result) {
setWorkModeCache(workMode);
}
return result;
}
public int getWorkMode() {
return MMKVUtil.get(WORK_MODE, MODE_DEHUMIDIFY);
}
public void setWorkModeCache(int workMode) {
MMKVUtil.put(WORK_MODE, limit(workMode, MODE_DEHUMIDIFY, MODE_VENTILATION));
}
public String getWorkModeName() {
int workMode = getWorkMode();
return workMode >= MODE_DEHUMIDIFY && workMode <= MODE_VENTILATION ? WORK_MODE_NAMES[workMode] : "未知";
}
public boolean readState() {
if (!isAvailable() || "00".equals(getAddress())) {
return false;
}
return readState(getAddress());
}
public boolean readState(String address) {
if (StringUtils.isEmpty(address) || "00".equals(address)) {
lastTestState = "00 地址用于广播或读取设备地址,不能读取运行状态";
return false;
}
String str = address + "0300000014";
String instruction = str + getCRC(str);
String result = serialPortUtil.sendAndReceiveSerialData(this, instruction);
if (StringUtils.isEmpty(result)) {
lastTestState = "读取状态失败";
return false;
}
boolean parsed = parseState(result);
lastTestState = parsed ? getDetailState() : "状态数据解析失败";
return parsed;
}
public String readCurrentAddress() {
String str = "002500DF0001";
String instruction = str + getCRC(str);
String result = serialPortUtil.sendAndReceiveSerialData(this, instruction);
if (StringUtils.isEmpty(result) || result.length() < 12) {
return null;
}
try {
return result.substring(6, 8);
} catch (Exception e) {
return null;
}
}
public String getState() {
if (!isAvailable()) {
return "未正确配置";
}
if (!isPowerSupply()) {
return "未启动";
}
String humidityText = environmentHumidity == null ? "" : " 湿度" + environmentHumidity + "%";
return "运行中 " + getWorkModeName() + humidityText + " 目标" + getTargetHumidity() + "%";
}
public String getDetailState() {
return "电源:" + (isPowerSupply() ? "开启" : "关闭")
+ "\n目标湿度:" + getTargetHumidity() + "%"
+ "\n目标温度:" + getTargetTemperature() + ""
+ "\n风速:" + getFanSpeedName()
+ "\n模式:" + getWorkModeName()
+ "\n环境湿度:" + getEnvironmentHumidityText()
+ "\n环境温度:" + getEnvironmentTemperatureText()
+ "\n工作状态:" + getWorkStatusText()
+ "\n故障:" + getFaultText();
}
public String getEnvironmentHumidityText() {
return environmentHumidity == null ? "--" : environmentHumidity + "%";
}
public String getEnvironmentTemperatureText() {
return environmentTemperature == null ? "--" : environmentTemperature + "";
}
public String getFaultText() {
if (faultCode == 0) {
return "正常";
}
StringBuilder builder = new StringBuilder();
appendFault(builder, 0, "温湿度传感器故障");
appendFault(builder, 1, "化霜温度1故障");
appendFault(builder, 2, "化霜温度2故障");
appendFault(builder, 3, "高压保护");
appendFault(builder, 4, "低压保护");
appendFault(builder, 5, "相序保护");
appendFault(builder, 6, "缺相保护");
appendFault(builder, 7, "超温保护");
appendFault(builder, 8, "电源电压超高保护");
appendFault(builder, 9, "水满告警");
appendFault(builder, 10, "漏氟保护");
return builder.length() == 0 ? "未知故障:" + faultCode : builder.toString();
}
public String getWorkStatusText() {
if (workStatus == 0) {
return "待机";
}
StringBuilder builder = new StringBuilder();
appendStatus(builder, 0, "除湿");
appendStatus(builder, 1, "化霜");
appendStatus(builder, 2, "制冷");
appendStatus(builder, 3, "制热");
return builder.length() == 0 ? "运行中" : builder.toString();
}
@Override
public boolean isAvailable() {
return isEnable() && !StringUtils.isEmpty(getAddress());
}
@Override
public String[] getModels() {
return new String[]{"西奈 Z101/Z102/Z103/X86 485除湿机"};
}
@Override
public boolean setAddressToNewAddress(String model, String oldAddress, String oldBaud, String newAddress) {
if (!model.equals(getModels()[0])) {
return false;
}
int addressValue = parseHex(newAddress, -1);
if (addressValue < 1 || addressValue > 99) {
return false;
}
if ("00".equals(oldAddress)) {
return writeRegisterNoResponse(oldAddress, REG_SET_ADDRESS, addressValue);
}
return writeRegister(oldAddress, REG_SET_ADDRESS, addressValue, false);
}
@Override
public boolean setBaudToNewBaud(String model, String oldAddress, String newBaud) {
if (!model.equals(getModels()[0])) {
return false;
}
int baudValue;
switch (newBaud) {
case "4800":
baudValue = 1;
break;
case "9600":
baudValue = 2;
break;
case "19200":
baudValue = 3;
break;
case "115200":
baudValue = 4;
break;
default:
return false;
}
if ("00".equals(oldAddress)) {
return writeRegisterNoResponse(oldAddress, REG_SET_BAUD, baudValue);
}
return writeRegister(oldAddress, REG_SET_BAUD, baudValue, false);
}
@Override
public boolean test(String deviceModel, String deviceAddress) {
if (!deviceModel.equals(getModels()[0])) {
return false;
}
if ("00".equals(deviceAddress)) {
String address = readCurrentAddress();
lastTestState = address == null ? "读取设备地址失败" : "当前设备地址:" + address;
return address != null;
}
return readState(deviceAddress);
}
@Override
public String getTestState() {
return lastTestState;
}
private boolean parseState(String result) {
try {
if (result.length() < 90 || !"03".equals(result.substring(2, 4))) {
return false;
}
int byteCount = parseHex(result.substring(4, 6), -1);
if (byteCount < 40) {
return false;
}
int power = getRegister(result, 0);
powerSupply = power == 1;
setTargetHumidityCache(getRegister(result, 1));
setTargetTemperatureCache(getRegister(result, 2));
setFanSpeedCache(getRegister(result, 3));
setWorkModeCache(getRegister(result, 4));
workStatus = getRegister(result, 5);
int humidity = getRegister(result, 6);
environmentHumidity = humidity == 0x00FF ? null : humidity;
int temperature = getRegister(result, 7);
environmentTemperature = temperature == 0x00FF ? null : toSigned16(temperature);
faultCode = getRegister(result, 8);
int coil1 = getRegister(result, 10);
coilTemperature1 = coil1 == 0x00FF ? null : toSigned16(coil1);
int coil2 = getRegister(result, 11);
coilTemperature2 = coil2 == 0x00FF ? null : toSigned16(coil2);
return true;
} catch (Exception e) {
return false;
}
}
private int getRegister(String result, int index) {
int start = 6 + index * 4;
return parseHex(result.substring(start, start + 4), 0);
}
private boolean writeRegister(String address, int register, int value, boolean checkAvailable) {
if (checkAvailable && !isAvailable()) {
return false;
}
String str = address + "06" + String.format("%04X", register) + String.format("%04X", value);
String instruction = str + getCRC(str);
return instruction.equals(serialPortUtil.sendAndReceiveSerialData(this, instruction));
}
private boolean writeRegisterNoResponse(String address, int register, int value) {
String str = address + "06" + String.format("%04X", register) + String.format("%04X", value);
String instruction = str + getCRC(str);
return serialPortUtil.sendSerialDataNoResponse(this, instruction);
}
private boolean sendBroadcastPower(String address, boolean state, boolean checkAvailable) {
if (checkAvailable && !isAvailable()) {
return false;
}
String str = address + "06" + String.format("%04X", REG_BROADCAST_POWER) + (state ? "00AA" : "0055");
String instruction = str + getCRC(str);
return checkAvailable
? executeInstructionsNoResponse(instruction, state ? "广播开机" : "广播关机")
: serialPortUtil.sendSerialDataNoResponse(this, instruction);
}
private void appendFault(StringBuilder builder, int bit, String text) {
if ((faultCode & (1 << bit)) == 0) {
return;
}
if (builder.length() > 0) {
builder.append("");
}
builder.append(text);
}
private void appendStatus(StringBuilder builder, int bit, String text) {
if ((workStatus & (1 << bit)) == 0) {
return;
}
if (builder.length() > 0) {
builder.append("");
}
builder.append(text);
}
private int parseHex(String hex, int defaultValue) {
try {
return Integer.parseInt(hex, 16);
} catch (Exception e) {
return defaultValue;
}
}
private int toSigned16(int value) {
return value > 0x7FFF ? value - 0x10000 : value;
}
private int limit(int value, int min, int max) {
return Math.max(min, Math.min(max, value));
}
private static String[] buildAddressList() {
String[] result = new String[100];
result[0] = "00";
for (int i = 1; i <= 99; i++) {
result[i] = String.format("%02X", i);
}
return result;
}
}
@@ -9,6 +9,7 @@ import com.example.iot_controlhost.R;
import com.example.iot_controlhost.base.BaseActivity;
import com.example.iot_controlhost.base.SetAddress;
import com.example.iot_controlhost.databinding.ActivityDebugBinding;
import com.example.iot_controlhost.model.controller.Dehumidifier485;
import com.example.iot_controlhost.model.sensor.Sensor;
import com.example.iot_controlhost.model.thread.QueueIOUITask;
import com.example.iot_controlhost.ui.dialog.ConfirmDialog;
@@ -47,6 +48,7 @@ public class DebugActivity extends BaseActivity<ActivityDebugBinding, DebugActiv
List<String> deviceNames = new ArrayList<>();
deviceNames.add(RoomController.relay.getName());
deviceNames.add(RoomController.airConditionInfrared.getName());
deviceNames.add(RoomController.dehumidifier485.getName());
deviceNames.addAll(RoomSensor.getAllSensorNames());
binding.acSensorType.setAdapter(new CustomSpinnerAdapter(mContext, deviceNames.toArray(new String[0])));
binding.acSensorType.addTextChangedListener(new TextWatcher() {
@@ -59,6 +61,7 @@ public class DebugActivity extends BaseActivity<ActivityDebugBinding, DebugActiv
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
//在选择设备类型后,自动选择设备型号
binding.acNewBaud.setAdapter(new CustomSpinnerAdapter(mContext, SpinnerList.BAUD));
if (charSequence.toString().equals(RoomController.relay.getName())) {
setAddress = RoomController.relay;
binding.acSensorModel.setAdapter(new CustomSpinnerAdapter(mContext, new String[]{RoomController.relay.getModels()[1]}));
@@ -66,6 +69,10 @@ public class DebugActivity extends BaseActivity<ActivityDebugBinding, DebugActiv
//调试时,只需要一个空调即可,RoomController.airConditionInfrared
setAddress = RoomController.airConditionInfrared;
binding.acSensorModel.setAdapter(new CustomSpinnerAdapter(mContext, new String[]{RoomController.airConditionInfrared.getModels()[0]}));
} else if (charSequence.toString().equals(RoomController.dehumidifier485.getName())) {
setAddress = RoomController.dehumidifier485;
binding.acSensorModel.setAdapter(new CustomSpinnerAdapter(mContext, RoomController.dehumidifier485.getModels()));
binding.acNewBaud.setAdapter(new CustomSpinnerAdapter(mContext, Dehumidifier485.BAUD_LIST));
} else {
binding.btnReadAndParse.setEnabled(true);
for (Sensor sensor : RoomSensor.getAllSensors()) {
@@ -249,4 +256,4 @@ public class DebugActivity extends BaseActivity<ActivityDebugBinding, DebugActiv
}
}
}
@@ -55,6 +55,7 @@ public class MainActivity extends BaseActivity<ActivityIncubationBinding, MainAc
private long mExitTime;
AppBarViewModel appBarViewModel;
WorkDialog workDialog;
private PasswordDialog lockPasswordDialog;
@Override
public void initView() {
@@ -110,11 +111,7 @@ public class MainActivity extends BaseActivity<ActivityIncubationBinding, MainAc
presenter.getNoticeLiveData().observe(this, integer -> {
switch (integer) {
case 2 ->//锁屏
new PasswordDialog(mContext, "请输入锁屏密码", RoomSetting.getMainActivityLock(), v1 -> {
binding.mainLock.setVisibility(View.GONE);
binding.mainKey.setImageDrawable(getDrawable(R.mipmap.unlock));
refreshLock();
}).show();
showLockPasswordDialog();
case 3 ->//进入设置
new SetBaseDialog(mContext).show();
case 4 -> {//结束登记弹窗
@@ -298,6 +295,19 @@ public class MainActivity extends BaseActivity<ActivityIncubationBinding, MainAc
});
}
private void showLockPasswordDialog() {
if (lockPasswordDialog != null && lockPasswordDialog.isShowing()) {
return;
}
lockPasswordDialog = new PasswordDialog(mContext, "请输入锁屏密码", RoomSetting.getMainActivityLock(), v1 -> {
binding.mainLock.setVisibility(View.GONE);
binding.mainKey.setImageDrawable(getDrawable(R.mipmap.unlock));
refreshLock();
});
lockPasswordDialog.setOnDismissListener(dialogInterface -> lockPasswordDialog = null);
lockPasswordDialog.show();
}
private ScheduledExecutorService mainLockExecutorService;
@Override
@@ -321,4 +331,4 @@ public class MainActivity extends BaseActivity<ActivityIncubationBinding, MainAc
}
}
}
}
@@ -16,6 +16,7 @@ import com.example.iot_controlhost.databinding.ItemSetBinding;
import com.example.iot_controlhost.model.Device;
import com.example.iot_controlhost.model.Set;
import com.example.iot_controlhost.model.controller.AirConditionInfrared;
import com.example.iot_controlhost.model.controller.Dehumidifier485;
import com.example.iot_controlhost.model.controller.DehumidifierInfrared;
import com.example.iot_controlhost.model.controller.Floor;
import com.example.iot_controlhost.model.net.AirConditionList;
@@ -29,6 +30,7 @@ import com.example.iot_controlhost.ui.dialog.AirConditionAddDialog;
import com.example.iot_controlhost.ui.dialog.AirDialog;
import com.example.iot_controlhost.ui.dialog.ConfirmDialog;
import com.example.iot_controlhost.ui.dialog.DehumidityAddDialog;
import com.example.iot_controlhost.ui.dialog.Dehumidifier485Dialog;
import com.example.iot_controlhost.ui.dialog.PasswordDialog;
import com.example.iot_controlhost.ui.dialog.SetDeviceBaseDialog;
import com.example.iot_controlhost.ui.dialog.SetPWMDialog;
@@ -78,6 +80,7 @@ public class SetActivity extends BaseActivity<ActivitySetBinding, SetActivityPre
case 1 -> MyUtil.relaunchApp();
case 2 -> setAirCondition();
case 3 -> setAdvanced();
case 4 -> setDeHumidity();
}
});
presenter.getShowImportAirConditionInstructionDialogLiveData().observe(this,
@@ -99,6 +102,8 @@ public class SetActivity extends BaseActivity<ActivitySetBinding, SetActivityPre
setSensor();
} else if (toMain == 2) {
setAirCondition();
} else if (toMain == 3) {
setDeHumidity();
}
});
}
@@ -276,19 +281,48 @@ public class SetActivity extends BaseActivity<ActivitySetBinding, SetActivityPre
*/
void setDeHumidity() {
toMain = 0;
binding.tvTitle.setText(getText(R.string.set) + " > 除湿机配置");
setList.clear();
setList.add(new Set("485除湿机配置", RoomController.dehumidifier485.toString(), view -> setDehumidifier485()));
setList.add(new Set("红外除湿机配置", RoomController.dehumidifierInfrared.toString(), view -> setDeHumidityInfrared()));
setAdapter.setDataList(setList);
}
void setDehumidifier485() {
toMain = 3;
Dehumidifier485 dehumidifier485 = RoomController.dehumidifier485;
binding.tvTitle.setText(getText(R.string.set) + " > 除湿机配置 > 485除湿机");
setList.clear();
setList.add(new Set("启用485除湿机", dehumidifier485.isEnable(), (compoundButton, b) -> {
dehumidifier485.setEnable(b);
setDehumidifier485();
}));
setList.add(new Set("基础配置", dehumidifier485.toString(), view ->
new SetDeviceBaseDialog(mContext, "485除湿机基础配置", dehumidifier485.getModels(),
getString(R.string.select_model), Dehumidifier485.ADDRESS_LIST, getString(R.string.select_address), (model, address) -> {
dehumidifier485.setModel(model);
dehumidifier485.setAddress(address);
setDehumidifier485();
}).show()));
setList.add(new Set("控制测试", dehumidifier485.getState(), view -> new Dehumidifier485Dialog(mContext, dehumidifier485).show()));
setAdapter.setDataList(setList);
}
void setDeHumidityInfrared() {
toMain = 3;
DehumidifierInfrared deHumidityInfrared = RoomController.dehumidifierInfrared;
binding.tvTitle.setText(getText(R.string.set) + " > 除湿机配置");
setList.clear();
setList.add(new Set(getString(R.string.enable_air_condition_infrared), deHumidityInfrared.isEnable(), (compoundButton, b) -> {
deHumidityInfrared.setEnable(b);
setDeHumidity();
setDeHumidityInfrared();
}));
setList.add(new Set(getString(R.string.set_base_infrared), deHumidityInfrared.toString(), view ->
new SetDeviceBaseDialog(mContext, getString(R.string.set_base_infrared), deHumidityInfrared.getModels(),
getString(R.string.select_model), SpinnerList.ADDRESS, getString(R.string.select_address), (model, address) -> {
deHumidityInfrared.setModel(model);
deHumidityInfrared.setAddress(address);
setDeHumidity();
setDeHumidityInfrared();
}).show()));
setList.add(new Set("导入除湿机指令", "除湿机指令集", view ->
presenter.getAirConditionModelList(-1)));
@@ -547,4 +581,4 @@ public class SetActivity extends BaseActivity<ActivitySetBinding, SetActivityPre
setAdapter.setDataList(setList);
}
}
}
@@ -319,7 +319,7 @@ public class SetActivityPresenter extends BasePresenter {
}
// 只有开机关机两条指令
String openInstruction = instructions.get(0);
boolean result = RoomController.airConditionInfrared.writeInstruction(200, openInstruction);
boolean result = RoomController.dehumidifierInfrared.writeInstruction(200, openInstruction);
if (!result) {
showLoadingDialogInIO("导入" + targetAirCondition + "型空调\n开机指令,指令错误!!!");
MyLog.controller("导入开机指令,云端指令有误");
@@ -327,7 +327,7 @@ public class SetActivityPresenter extends BasePresenter {
return false;
}
String closeInstruction = instructions.get(1);
result = RoomController.airConditionInfrared.writeInstruction(201, closeInstruction);
result = RoomController.dehumidifierInfrared.writeInstruction(201, closeInstruction);
if (!result) {
showLoadingDialogInIO("导入" + targetAirCondition + "型空调\n关机指令,指令错误!!!");
MyLog.controller("导入关机指令,云端指令有误");
@@ -346,7 +346,7 @@ public class SetActivityPresenter extends BasePresenter {
} else {
errorTips("导入空调指令失败");
}
refreshLiveData.setValue(2);
refreshLiveData.setValue(4);
}
});
}
@@ -645,6 +645,10 @@ public class SetActivityPresenter extends BasePresenter {
map.put(RoomController.DEVICE_NAME[15] + Device.ENABLE, RoomController.dehumidifierInfrared.isEnable());
map.put(RoomController.DEVICE_NAME[15] + Device.MODEL, RoomController.dehumidifierInfrared.getModel());
map.put(RoomController.DEVICE_NAME[15] + Device.ADDRESS, RoomController.dehumidifierInfrared.getAddress());
//485除湿机配置
map.put(RoomController.dehumidifier485.getName() + Device.ENABLE, RoomController.dehumidifier485.isEnable());
map.put(RoomController.dehumidifier485.getName() + Device.MODEL, RoomController.dehumidifier485.getModel());
map.put(RoomController.dehumidifier485.getName() + Device.ADDRESS, RoomController.dehumidifier485.getAddress());
//空调2配置
map.put(RoomController.DEVICE_NAME[14] + Device.ENABLE, RoomController.airConditionInfrared2.isEnable());
map.put(RoomController.DEVICE_NAME[14] + Device.MODEL, RoomController.airConditionInfrared2.getModel());
@@ -0,0 +1,127 @@
package com.example.iot_controlhost.ui.dialog;
import android.content.Context;
import android.transition.Fade;
import android.transition.TransitionManager;
import android.view.View;
import androidx.annotation.NonNull;
import com.example.iot_controlhost.R;
import com.example.iot_controlhost.base.BaseDialog;
import com.example.iot_controlhost.databinding.DialogDehumidifier485Binding;
import com.example.iot_controlhost.model.controller.Dehumidifier485;
import com.example.iot_controlhost.model.thread.QueueIOUITask;
import com.example.iot_controlhost.utils.DialogUtil;
import com.example.iot_controlhost.utils.MyQueue;
import com.example.iot_controlhost.utils.global.RoomSetting;
import com.example.iot_controlhost.utils.global.RxTag;
import com.example.iot_controlhost.utils.log.UserLog;
import com.xuexiang.rxutil2.rxbus.RxBusUtils;
import android_serialport_api.SerialPortUtil;
/**
* 485除湿机控制弹窗
*/
public class Dehumidifier485Dialog extends BaseDialog<DialogDehumidifier485Binding> {
private final Dehumidifier485 dehumidifier;
public Dehumidifier485Dialog(@NonNull Context mContext, Dehumidifier485 dehumidifier) {
super(mContext);
this.dehumidifier = dehumidifier;
binding.tvTitle.setText(dehumidifier.getName() + "控制");
if (!SerialPortUtil.getInstance(SerialPortUtil.TYPE_CONTROLLER).openSerialPort()) {
errorTips("串口打开失败");
}
refreshDehumidifier();
binding.cardStatus.setOnClickListener(v -> changeDehumidifier(8));
binding.btnPower.setOnClickListener(v -> changeDehumidifier(0));
binding.btnHumidityReduce.setOnClickListener(v -> changeDehumidifier(1));
binding.btnHumidityPlus.setOnClickListener(v -> changeDehumidifier(2));
binding.modeDehumidify.setOnClickListener(v -> changeDehumidifier(3));
binding.modeVentilation.setOnClickListener(v -> changeDehumidifier(4));
binding.fanLow.setOnClickListener(v -> changeDehumidifier(5));
binding.fanMiddle.setOnClickListener(v -> changeDehumidifier(6));
binding.fanHigh.setOnClickListener(v -> changeDehumidifier(7));
}
private void refreshDehumidifier() {
TransitionManager.beginDelayedTransition(binding.ll, new Fade());
binding.tvTargetHumidity.setText(dehumidifier.isPowerSupply() ? String.valueOf(dehumidifier.getTargetHumidity()) : "-");
binding.tvEnvironmentHumidity.setText("环境湿度:" + dehumidifier.getEnvironmentHumidityText());
binding.tvEnvironmentTemperature.setText("环境温度:" + dehumidifier.getEnvironmentTemperatureText());
binding.tvWorkStatus.setText("状态:" + dehumidifier.getWorkStatusText());
binding.tvFault.setText("故障:" + dehumidifier.getFaultText());
binding.btnPower.setImageDrawable(mContext.getDrawable(dehumidifier.isPowerSupply() ? R.mipmap.open : R.mipmap.close));
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.ivSelFanLow.setVisibility(dehumidifier.getFanSpeed() == Dehumidifier485.FAN_LOW ? View.VISIBLE : View.INVISIBLE);
binding.ivSelFanMiddle.setVisibility(dehumidifier.getFanSpeed() == Dehumidifier485.FAN_MIDDLE ? View.VISIBLE : View.INVISIBLE);
binding.ivSelFanHigh.setVisibility(dehumidifier.getFanSpeed() == Dehumidifier485.FAN_HIGH ? View.VISIBLE : View.INVISIBLE);
}
private void changeDehumidifier(int type) {
DialogUtil.showLoadingDialog(mContext, mContext.getString(R.string.in_operate));
MyQueue.start(MyQueue.TYPE_CONTROLLER, new QueueIOUITask<Boolean>() {
@Override
public Boolean doInQueueThread() {
switch (type) {
case 0:
if (dehumidifier.isPowerSupply()) {
return dehumidifier.setPowerSupply(false);
}
boolean powerResult = dehumidifier.setPowerSupply(true);
if (powerResult) {
dehumidifier.setWorkMode(dehumidifier.getWorkMode());
dehumidifier.setFanSpeed(dehumidifier.getFanSpeed());
dehumidifier.setTargetHumidity(dehumidifier.getTargetHumidity());
dehumidifier.setTargetTemperature(dehumidifier.getTargetTemperature());
}
return powerResult;
case 1:
return dehumidifier.setTargetHumidity(dehumidifier.getTargetHumidity() - 1);
case 2:
return dehumidifier.setTargetHumidity(dehumidifier.getTargetHumidity() + 1);
case 3:
return dehumidifier.setWorkMode(Dehumidifier485.MODE_DEHUMIDIFY);
case 4:
return dehumidifier.setWorkMode(Dehumidifier485.MODE_VENTILATION);
case 5:
return dehumidifier.setFanSpeed(Dehumidifier485.FAN_LOW);
case 6:
return dehumidifier.setFanSpeed(Dehumidifier485.FAN_MIDDLE);
case 7:
return dehumidifier.setFanSpeed(Dehumidifier485.FAN_HIGH);
case 8:
return dehumidifier.readState();
default:
return false;
}
}
@Override
public void doInUIThread(Boolean result) {
if (result) {
successTips(dehumidifier.getState());
UserLog.operate("手动:操作485除湿机 " + dehumidifier.getState());
} else {
errorTips("操作485除湿机失败");
UserLog.operateError("手动:操作485除湿机失败");
}
refreshDehumidifier();
DialogUtil.hideLoadingDialog();
}
});
}
@Override
public void dismiss() {
super.dismiss();
if (RoomSetting.getMode() == 0) {
RxBusUtils.get().post(RxTag.UPDATE_MANUAL, 0);
} else if (RoomSetting.getMode() == 1) {
RxBusUtils.get().post(RxTag.UPDATE_AUTO, 2);
}
}
}
@@ -14,6 +14,7 @@ import com.example.iot_controlhost.base.BaseMode;
import com.example.iot_controlhost.databinding.FragmentModelAutoBinding;
import com.example.iot_controlhost.databinding.ItemControllerAutoBinding;
import com.example.iot_controlhost.model.controller.AirConditionInfrared;
import com.example.iot_controlhost.model.controller.Controller;
import com.example.iot_controlhost.model.controller.Floor;
import com.example.iot_controlhost.model.controller.relay.Relay;
import com.example.iot_controlhost.ui.dialog.AirDialog;
@@ -68,7 +69,7 @@ public class AutoFragment extends BaseFragment<FragmentModelAutoBinding, AutoFra
binding.recycleView.setLayoutManager(new GridLayoutManager(mContext, 2));
binding.recycleView2.setAdapter(manualControllerAdapterTwo);
binding.recycleView2.setLayoutManager(new GridLayoutManager(mContext, 4));
List<Relay> devices = RoomController.getAllControlRelays();
List<Controller> devices = RoomController.getAllControlDevices();
// 第一排显示2个设备
if (devices.size() <= 2) {
int missingCount = 2 - devices.size();
@@ -78,9 +79,9 @@ public class AutoFragment extends BaseFragment<FragmentModelAutoBinding, AutoFra
}
manualControllerAdapter.setDataList(devices);
// 第二排显示剩下的设备
List<Relay> remainingDevices = new ArrayList<>();
List<Controller> remainingDevices = new ArrayList<>();
if (devices.size() > 2) {
List<Relay> tempDevices = devices.subList(2, devices.size());
List<Controller> tempDevices = devices.subList(2, devices.size());
remainingDevices.addAll(tempDevices);
}
if (remainingDevices.size() < 4) {
@@ -150,6 +151,7 @@ public class AutoFragment extends BaseFragment<FragmentModelAutoBinding, AutoFra
private void changeFloorState() {
Floor floor = RoomController.floor;
binding.tvFloor.setText(RoomSetting.getFloorName());
binding.tvStateFloor.setText(floor.getState());
if (floor.isPowerSupply()) {
binding.ivControllerFloor.setImageResource(R.mipmap.floor_open);
@@ -199,4 +201,4 @@ public class AutoFragment extends BaseFragment<FragmentModelAutoBinding, AutoFra
binding.tvPowerAir.setText("实时功率:" + RoomController.airCondition.getPower() + "w");
}
}
}
@@ -12,6 +12,7 @@ import com.example.iot_controlhost.base.BaseMode;
import com.example.iot_controlhost.databinding.FragmentModelManualBinding;
import com.example.iot_controlhost.databinding.ItemControllerBinding;
import com.example.iot_controlhost.model.controller.AirConditionInfrared;
import com.example.iot_controlhost.model.controller.Controller;
import com.example.iot_controlhost.model.controller.Floor;
import com.example.iot_controlhost.model.controller.relay.Relay;
import com.example.iot_controlhost.ui.dialog.AirDialog;
@@ -52,7 +53,7 @@ public class ManualFragment extends BaseFragment<FragmentModelManualBinding, Man
manualControllerAdapter = new ManualControllerAdapter(mContext, null, ItemControllerBinding.class);
binding.recycleView.setAdapter(manualControllerAdapter);
binding.recycleView.setLayoutManager(new GridLayoutManager(mContext, 3));
List<Relay> devices = RoomController.getAllControlRelays();
List<Controller> devices = RoomController.getAllControlDevices();
int size = devices.size();
if (size < 6) {
for (int i = 0; i < 6 - size; i++) {
@@ -151,4 +152,4 @@ public class ManualFragment extends BaseFragment<FragmentModelManualBinding, Man
binding.tvPowerAir.setVisibility(RoomController.relay.getModel().equals(RoomController.relay.getModels()[2]) ? View.VISIBLE : View.GONE);
binding.tvPowerAir.setText("实时功率:" + RoomController.airCondition.getPower() + "w");
}
}
}
@@ -432,6 +432,8 @@ public class MyUtil {
devices.add(RoomController.floor);
devices.add(RoomController.airConditionInfrared);
devices.add(RoomController.airConditionInfrared2);
devices.add(RoomController.dehumidifierInfrared);
devices.add(RoomController.dehumidifier485);
devices.add(RoomController.relayFloor);
// 检查固定传感器
Collections.addAll(devices, RoomSensor.outdoorTHSensor, RoomSensor.consumptionSensor, RoomSensor.airTHSensor, RoomSensor.co2OutdoorSensor);
@@ -1,6 +1,8 @@
package com.example.iot_controlhost.utils.control.humidity;
import com.example.iot_controlhost.model.thread.QueueIOTask;
import com.example.iot_controlhost.model.controller.Controller;
import com.example.iot_controlhost.model.controller.Dehumidifier485;
import com.example.iot_controlhost.utils.MyQueue;
import com.example.iot_controlhost.utils.MyUtil;
import com.example.iot_controlhost.utils.control.Control;
@@ -27,6 +29,7 @@ public class HumidityController extends Control {
* 是否需要开启加湿器直到达到目标湿度
*/
private static boolean needOpenToTarget = false;
private static boolean needDehumidifyToTarget = false;
/**
* 目标湿度
*/
@@ -46,7 +49,7 @@ public class HumidityController extends Control {
@Override
protected boolean startMethod() {
if (!RoomController.humidifier.isAvailable()) {
if (!RoomController.humidifier.isAvailable() && RoomController.getAutoDehumidifier() == null) {
MyLog.autoError("加湿器不可用,无法自动控制");
return false;
}
@@ -76,18 +79,31 @@ public class HumidityController extends Control {
}
// 除湿逻辑新增
if (cur > max) {
if (cur > max || cur > target && needDehumidifyToTarget) {
needDehumidifyToTarget = true;
needDehumidify = true;
} else {
needDehumidifyToTarget = false;
needDehumidify = false;
}
// === 互斥处理 ===
if (needHumidify && needDehumidify) {
// 理论不会发生保险处理
needDehumidify = false;
needDehumidifyToTarget = false;
}
boolean humidifierState = needHumidify;
boolean dehumidifierState = needDehumidify;
Controller autoDehumidifier = RoomController.getAutoDehumidifier();
int dehumidifierTargetHumidity = (int) Math.round(target);
boolean needRefreshDehumidifierSetting = autoDehumidifier instanceof Dehumidifier485
&& dehumidifierState
&& ((Dehumidifier485) autoDehumidifier).getTargetHumidity() != dehumidifierTargetHumidity;
boolean humidifierKeep = !RoomController.humidifier.isAvailable() || RoomController.humidifier.isPowerSupply() == humidifierState;
boolean dehumidifierKeep = autoDehumidifier == null
|| autoDehumidifier.isPowerSupply() == dehumidifierState && !needRefreshDehumidifierSetting;
if (RoomController.humidifier.isPowerSupply() == humidifierState && RoomController.dehumidifier.isPowerSupply() == dehumidifierState) {
if (humidifierKeep && dehumidifierKeep) {
MyLog.auto("湿度-控制维持当前状态");
} else {
// 加湿器控制
@@ -102,10 +118,15 @@ public class HumidityController extends Control {
}));
}
// 除湿器控制新增
if (RoomController.dehumidifier.isAvailable()) {
if (autoDehumidifier != null) {
MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> {
MyLog.auto("自动:" + (dehumidifierState ? "开启" : "关闭") + "除湿机--");
MyUtil.autoControlOperateThird(RoomController.dehumidifier, dehumidifierState);
if (autoDehumidifier instanceof Dehumidifier485 && dehumidifierState) {
Dehumidifier485 dehumidifier485 = (Dehumidifier485) autoDehumidifier;
dehumidifier485.setWorkMode(Dehumidifier485.MODE_DEHUMIDIFY);
dehumidifier485.setTargetHumidity(dehumidifierTargetHumidity);
}
MyUtil.autoControlOperateThird(autoDehumidifier, dehumidifierState);
}));
}
}
@@ -115,8 +136,14 @@ public class HumidityController extends Control {
@Override
protected void stopMethod() {
needOpenToTarget = false;
needDehumidifyToTarget = false;
MyQueue.getInstance(MyQueue.TYPE_CONTROLLER).addTask(new QueueIOTask(() -> {
MyUtil.autoControlOperateThird(RoomController.humidifier);
Controller autoDehumidifier = RoomController.getAutoDehumidifier();
if (autoDehumidifier != null) {
MyUtil.autoControlOperateThird(autoDehumidifier, false);
}
String airExchangeMode = AutoModelSet.getAirExchangeMode();
if (RoomController.airExchange.isAvailable() && airExchangeMode.equals(SpinnerList.AIR_EXCHANGE_MODES[2])) {
MyUtil.autoControlOperateThird(RoomController.airExchange, false);
@@ -3,6 +3,8 @@ package com.example.iot_controlhost.utils.global;
import com.example.iot_controlhost.R;
import com.example.iot_controlhost.model.Device;
import com.example.iot_controlhost.model.controller.AirConditionInfrared;
import com.example.iot_controlhost.model.controller.Controller;
import com.example.iot_controlhost.model.controller.Dehumidifier485;
import com.example.iot_controlhost.model.controller.DehumidifierInfrared;
import com.example.iot_controlhost.model.controller.Floor;
import com.example.iot_controlhost.model.controller.relay.AirCondition;
@@ -59,6 +61,10 @@ public class RoomController {
* 除湿机
*/
public static DehumidifierInfrared dehumidifierInfrared = new DehumidifierInfrared(DEVICE_NAME[15]);
/**
* 485除湿机
*/
public static Dehumidifier485 dehumidifier485 = new Dehumidifier485("485除湿机");
//以下为继电器下设备
/**
@@ -132,6 +138,7 @@ public class RoomController {
devices.add(floor);
devices.add(airConditionInfrared);
devices.add(dehumidifierInfrared);
devices.add(dehumidifier485);
return devices;
}
@@ -174,6 +181,31 @@ public class RoomController {
* @param deviceName 设备名称 需要在 PublicClass.DEVICE_NAME选用
* @return 设备类 可用于设置端口地址等操作
*/
/**
* 获得手动/自动页面可直接控制的设备
*/
public static List<Controller> getAllControlDevices() {
List<Controller> devices = new ArrayList<>();
devices.addAll(getAllControlRelays());
if (dehumidifier485.isAvailable()) {
devices.add(dehumidifier485);
}
return devices;
}
/**
* 湿度自动控制优先使用485除湿机未配置时兼容旧继电器除湿机
*/
public static Controller getAutoDehumidifier() {
if (dehumidifier485.isAvailable()) {
return dehumidifier485;
}
if (dehumidifier.isAvailable()) {
return dehumidifier;
}
return null;
}
public static Relay getRelay(String deviceName) {
for (int i = 0; i < DEVICE_NAME.length; i++) {
if (DEVICE_NAME[i].equals(deviceName)) {
@@ -225,6 +257,7 @@ public class RoomController {
//关闭单独设备
MyInfraredUtils.getInstances().setPowerSupply(false);
RoomController.floor.setPowerSupply(false);
RoomController.dehumidifier485.setPowerSupply(false);
//关闭继电器下的所有设备
List<Relay> devices = getAllAvailableRelays();
//除了空调物理电源
@@ -309,6 +342,7 @@ public class RoomController {
List<Relay> relays = RoomController.getAllAvailableRelays();
MyInfraredUtils.getInstances().setPowerSupply(false);
RoomController.dehumidifier.setPowerSupply(false);
RoomController.dehumidifier485.setPowerSupply(false);
RoomController.floor.setPowerSupply(false);
relays.remove(RoomController.airCondition);
relays.remove(RoomController.dehumidifier);
@@ -316,4 +350,4 @@ public class RoomController {
r.setPowerSupply(false);
}
}
}
}
@@ -0,0 +1,463 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/transparent">
<androidx.cardview.widget.CardView
android:layout_width="560dp"
android:layout_height="690dp"
android:layout_margin="80dp"
app:cardCornerRadius="10dp"
app:cardElevation="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/ll"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/iv_dialog_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="30dp"
android:src="@mipmap/cancel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="10dp"
android:layout_height="40dp"
android:layout_marginTop="30dp"
android:background="#00A1FF"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="90dp"
android:singleLine="true"
android:text="485除湿机控制"
android:textColor="#38ADFF"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.cardview.widget.CardView
android:id="@+id/card_status"
android:layout_width="450dp"
android:layout_height="170dp"
android:layout_marginTop="95dp"
app:cardCornerRadius="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F2F0F1">
<TextView
android:id="@+id/tv_target_humidity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="60"
android:textSize="86sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.35"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="24dp"
android:text="%"
android:textSize="24sp"
app:layout_constraintStart_toEndOf="@+id/tv_target_humidity"
app:layout_constraintTop_toTopOf="@+id/tv_target_humidity" />
<TextView
android:id="@+id/tv_environment_humidity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="26dp"
android:text="环境湿度:--"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/tv_environment_temperature"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/tv_environment_temperature"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="26dp"
android:text="环境温度:--"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/tv_work_status"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/tv_work_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="26dp"
android:layout_marginBottom="16dp"
android:text="状态:待机"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/tv_fault"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/tv_fault"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="250dp"
android:layout_marginEnd="26dp"
android:layout_marginBottom="18dp"
android:ellipsize="end"
android:singleLine="true"
android:text="故障:正常"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_dehumidifier_control"
android:layout_width="450dp"
android:layout_height="106dp"
android:layout_marginTop="30dp"
android:clipChildren="false"
android:clipToPadding="false"
app:layout_constraintEnd_toEndOf="@+id/card_status"
app:layout_constraintStart_toStartOf="@+id/card_status"
app:layout_constraintTop_toBottomOf="@+id/card_status">
<androidx.cardview.widget.CardView
android:id="@+id/card_power"
android:layout_width="90dp"
android:layout_height="90dp"
app:cardCornerRadius="45dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/btn_power"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="18dp"
android:src="@mipmap/open" />
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/card_mode"
android:layout_width="330dp"
android:layout_height="90dp"
app:cardCornerRadius="45dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:layout_width="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/mode_dehumidify"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="18dp"
android:src="@mipmap/hum_open" />
<ImageView
android:id="@+id/mode_ventilation"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:padding="18dp"
android:src="@mipmap/ven_open" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_sel_dehumidify"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="center"
android:src="@mipmap/sel_cold" />
<ImageView
android:id="@+id/iv_sel_ventilation"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="center"
android:src="@mipmap/sel_auto" />
</LinearLayout>
</FrameLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id="@+id/ll_mode_labels"
android:layout_width="450dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="@+id/cl_dehumidifier_control"
app:layout_constraintStart_toStartOf="@+id/cl_dehumidifier_control"
app:layout_constraintTop_toBottomOf="@+id/cl_dehumidifier_control">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="开关"
android:textSize="22sp" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:gravity="center"
android:text="除湿"
android:textSize="22sp" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:gravity="center"
android:text="通风"
android:textSize="22sp" />
</LinearLayout>
<androidx.cardview.widget.CardView
android:id="@+id/card_fan"
android:layout_width="450dp"
android:layout_height="80dp"
android:layout_marginTop="25dp"
app:cardCornerRadius="40dp"
app:layout_constraintEnd_toEndOf="@+id/card_status"
app:layout_constraintStart_toStartOf="@+id/card_status"
app:layout_constraintTop_toBottomOf="@+id/ll_mode_labels">
<FrameLayout
android:layout_width="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
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_sel_fan_low"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="center"
android:src="@mipmap/sel_auto" />
<ImageView
android:id="@+id/iv_sel_fan_middle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="center"
android:src="@mipmap/sel_auto" />
<ImageView
android:id="@+id/iv_sel_fan_high"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="center"
android:src="@mipmap/sel_auto" />
</LinearLayout>
</FrameLayout>
</androidx.cardview.widget.CardView>
<LinearLayout
android:id="@+id/ll_fan_labels"
android:layout_width="450dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="@+id/card_fan"
app:layout_constraintStart_toStartOf="@+id/card_fan"
app:layout_constraintTop_toBottomOf="@+id/card_fan">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="低风"
android:textSize="22sp" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="中风"
android:textSize="22sp" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="高风"
android:textSize="22sp" />
</LinearLayout>
<androidx.cardview.widget.CardView
android:id="@+id/card_humidity"
android:layout_width="450dp"
android:layout_height="80dp"
android:layout_marginTop="25dp"
app:cardCornerRadius="40dp"
app:cardElevation="10dp"
app:layout_constraintEnd_toEndOf="@+id/card_status"
app:layout_constraintStart_toStartOf="@+id/card_status"
app:layout_constraintTop_toBottomOf="@+id/ll_fan_labels">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/btn_humidity_reduce"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="24dp"
android:src="@mipmap/minus"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="目标湿度"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/btn_humidity_plus"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="24dp"
android:src="@mipmap/add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>