排程浇水历史记录

This commit is contained in:
fengjignqi
2026-06-01 15:54:06 +08:00
parent 694b74cda7
commit b7ab2e69a4
21 changed files with 953 additions and 34 deletions

View File

@@ -0,0 +1,489 @@
package com.ckkj.water.device;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.AnimationDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import com.ckkj.water.ConstantUtil;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.databinding.AddDeviceLayoutBinding;
import com.ckkj.water.device.mvp.DeviceContract;
import com.ckkj.water.device.mvp.DeviceImpl;
import com.ckkj.water.device.mvp.DevicePresenter;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.utils.manager.ActivityManager;
import com.ckkj.water.utils.manager.ThemeManager;
import com.ckkj.water.utils.show.ToastUtil;
import com.gyf.immersionbar.ImmersionBar;
import com.maning.mlkitscanner.scan.MNScanManager;
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat;
import no.nordicsemi.android.support.v18.scanner.ScanCallback;
import no.nordicsemi.android.support.v18.scanner.ScanFilter;
import no.nordicsemi.android.support.v18.scanner.ScanResult;
import no.nordicsemi.android.support.v18.scanner.ScanSettings;
import pub.devrel.easypermissions.EasyPermissions;
/**
* 添加设备页面
*/
public class AddDeviceActivity_copy extends BaseActivity<AddDeviceLayoutBinding, DevicePresenter>
implements DeviceContract.DeviceView, EasyPermissions.PermissionCallbacks {
// 蓝牙相关
private BluetoothAdapter bluetoothAdapter;
private static final int REQUEST_ENABLE_BT = 1001;
private static final int REQUEST_BLUETOOTH_PERMISSION = 1002;
private List<BluetoothDevice> discoveredDevices = new ArrayList<>();
private AlertDialog deviceListDialog;
@Override
public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl());
}
@Override
public void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
ActivityManager.addActivity(this,getClass().getSimpleName() + "_" + ConstantUtil.ADD_DEVICE_FLAG);
ImmersionBar.with(this)
.statusBarColor(R.color.mainBackgroundColor) // 设置状态栏颜色
.statusBarDarkFont(ThemeManager.isAppThemeLight(mContext)) // 设置状态栏字体为黑色
.titleBar(viewBinding.rlTitle)
.init();
viewBinding.includedTitle.tvTitle.setText(R.string.add_device_title);
if(checkBluetoothPermissions()){
// 初始化蓝牙适配器
initBluetooth();
BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
ScanSettings settings = new ScanSettings.Builder()
.setLegacy(false)
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setReportDelay(5000)
.setUseHardwareBatchingIfSupported(true)
.build();
List<ScanFilter> filters = new ArrayList<>();
scanner.startScan(null, settings, new ScanCallback() {
@Override
public void onScanResult(int callbackType, @NonNull ScanResult result) {
super.onScanResult(callbackType, result);
}
@Override
public void onBatchScanResults(@NonNull List<ScanResult> results) {
super.onBatchScanResults(results);
if(results != null){
int a = 0;
}
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
});
}
// 启动帧动画
ImageView ivScanAnimation = viewBinding.ivScanAnimation;
if (ivScanAnimation.getDrawable() instanceof AnimationDrawable) {
AnimationDrawable animationDrawable = (AnimationDrawable) ivScanAnimation.getDrawable();
animationDrawable.start();
}
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// 停止帧动画
ImageView ivScanAnimation = viewBinding.ivScanAnimation;
if (ivScanAnimation.getDrawable() instanceof AnimationDrawable) {
AnimationDrawable animationDrawable = (AnimationDrawable) ivScanAnimation.getDrawable();
if (animationDrawable.isRunning()) {
animationDrawable.stop();
viewBinding.ivScanAnimation.setVisibility(GONE);
viewBinding.imgDeviceItem.setVisibility(VISIBLE);
}
}
}
},3000);
initListener();
}
/**
* 初始化蓝牙适配器
*/
private void initBluetooth() {
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetoothManager != null) {
bluetoothAdapter = bluetoothManager.getAdapter();
}
if (bluetoothAdapter == null) {
ToastUtil.showShort(mContext, "设备不支持蓝牙");
return;
}
// 检查蓝牙是否开启
if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
/**
* 检查蓝牙权限
*/
private boolean checkBluetoothPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
String[] readPermission = new String[]{
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.ACCESS_FINE_LOCATION
};
if (!hasRecordPermission(readPermission)) {
// 没有权限只在ACTION_DOWN时去申请
getMorePermissionRequst(readPermission,"蓝牙扫描权限申请",
"智能浇水需要您的授权,获取蓝牙权限添加设备",REQUEST_EVENT_CODE_10003);
return false;
}
} else {
// Android 12 以下需要位置权限才能扫描蓝牙
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{
Manifest.permission.ACCESS_FINE_LOCATION
}, REQUEST_BLUETOOTH_PERMISSION);
return false;
}
}
return true;
}
/**
* 开始扫描蓝牙设备
*/
private void startBleScan() {
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
ToastUtil.showShort(mContext, "请先开启蓝牙");
return;
}
if (!checkBluetoothPermissions()) {
return;
}
discoveredDevices.clear();
showLoadingDialog();
// 获取已配对设备
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices != null && !pairedDevices.isEmpty()) {
discoveredDevices.addAll(pairedDevices);
}
// 开始扫描
new Handler().postDelayed(() -> {
stopBleScan();
showDeviceListDialog();
}, 10000); // 10秒后自动停止扫描
}
/**
* 停止扫描
*/
private void stopBleScan() {
hideDialogLoading();
}
/**
* 显示设备列表对话框
*/
private void showDeviceListDialog() {
if (discoveredDevices.isEmpty()) {
ToastUtil.showShort(mContext, "未发现蓝牙设备");
return;
}
String[] deviceNames = new String[discoveredDevices.size()];
for (int i = 0; i < discoveredDevices.size(); i++) {
BluetoothDevice device = discoveredDevices.get(i);
String name = device.getName();
if (name == null || name.isEmpty()) {
name = "未知设备";
}
deviceNames[i] = name + "\n" + device.getAddress();
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("发现 " + discoveredDevices.size() + " 个设备");
builder.setItems(deviceNames, (dialog, which) -> {
BluetoothDevice selectedDevice = discoveredDevices.get(which);
connectToDevice(selectedDevice);
});
builder.setNegativeButton("取消", null);
deviceListDialog = builder.show();
}
/**
* 连接蓝牙设备
*/
private void connectToDevice(BluetoothDevice device) {
showLoadingDialog();
String deviceName = device.getName();
if (deviceName == null || deviceName.isEmpty()) {
deviceName = "未知设备";
}
ToastUtil.showShort(mContext, "正在连接: " + deviceName);
// TODO: 这里可以调用 DeviceBleManager 进行连接
// DeviceBleManager bleManager = new DeviceBleManager(this);
// bleManager.connect(device);
// 模拟连接成功
String finalDeviceName = deviceName;
new Handler().postDelayed(() -> {
hideDialogLoading();
ToastUtil.showShort(mContext, "连接成功: " + finalDeviceName);
// 获取设备信息
getDeviceInfo(device);
}, 2000);
}
/**
* 获取蓝牙设备信息
*/
private void getDeviceInfo(BluetoothDevice device) {
String deviceName = device.getName();
String deviceAddress = device.getAddress();
if (deviceName == null || deviceName.isEmpty()) {
deviceName = "未知设备";
}
ToastUtil.showShort(mContext, "设备名称: " + deviceName + "\n设备地址: " + deviceAddress);
// TODO: 将设备信息传递给后续业务逻辑
// 例如跳转到下一个页面或保存设备信息
}
private void initListener() {
setClick(viewBinding.includedTitle.imgBack);
setClick(viewBinding.tvScanAdd);
setClick(viewBinding.btnBleScan);
setClick(viewBinding.imgDeviceItem);
}
private void setClick(View view) {
view.setOnClickListener(this::onClick);
}
public void onClick(View v){
switch (v.getId()){
case R.id.img_back:
finish();
break;
case R.id.img_device_item:
Bundle bundle = new Bundle();
bundle.putInt(ConstantUtil.ACTIVITY_NAVIGATE_FLAG,100);
goTo(mContext, SelectWifiActivity.class,bundle);
break;
case R.id.tv_scan_add:
//检测有无相机权限
String readPermission = Manifest.permission.CAMERA;
if(!hasRecordPermission(readPermission)){
getPermissionRequst(readPermission,"权限申请",
"智能浇水需要您的授权访问相机,并使用扫一扫",REQUEST_EVENT_CODE_10001);
}else{
scanQrcode();
}
break;
case R.id.btn_ble_scan:
// 扫描蓝牙设备
startBleScan();
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == RESULT_OK) {
ToastUtil.showShort(mContext, "蓝牙已开启");
} else {
ToastUtil.showShort(mContext, "请开启蓝牙以扫描设备");
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull @NotNull String[] permissions, @NonNull @NotNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
hidePermissionDialog();
if (requestCode == REQUEST_BLUETOOTH_PERMISSION) {
boolean allGranted = true;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
break;
}
}
if (allGranted) {
// 初始化蓝牙适配器
initBluetooth();
startBleScan();
} else {
ToastUtil.showShort(mContext, "需要蓝牙权限才能扫描设备");
}
}
}
private void scanQrcode() {
//默认扫描
MNScanManager.startScan(mContext, new MNScanCallback() {
@Override
public void onActivityResult(int resultCode, Intent data) {
switch (resultCode) {
case MNScanManager.RESULT_SUCCESS:
ArrayList<String> results = data.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS);
if(results != null){
ToastUtil.showShort(mContext,results.get(0).toString());
}
break;
case MNScanManager.RESULT_FAIL:
String resultError = data.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR);
break;
case MNScanManager.RESULT_CANCLE:
ToastUtil.showShort(mContext,"取消扫码");
break;
}
}
});
}
@Override
protected void onPause() {
super.onPause();
// 停止帧动画
ImageView ivScanAnimation = viewBinding.ivScanAnimation;
if (ivScanAnimation.getDrawable() instanceof AnimationDrawable) {
AnimationDrawable animationDrawable = (AnimationDrawable) ivScanAnimation.getDrawable();
if (animationDrawable.isRunning()) {
animationDrawable.stop();
}
}
}
@Override
public int getLayoutResId(Bundle savedInstanceState) {
return 0;
}
@Override
public void showError(String message) {
}
@Override
public void logOut(BaseBean bean) {
}
@Override
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
hidePermissionDialog();
if (requestCode == REQUEST_EVENT_CODE_10001) {
scanQrcode();
}
}
@Override
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
}
@Override
public void addDeviceSuccess(BaseBean bean) {
}
@Override
public void getDeviceDetailInfo(WaterDeviceEntity bean) {
}
@Override
public void editDeviceInfoSuccess(BaseBean bean) {
}
@Override
public void deleteDeviceSuccess(BaseBean bean) {
}
@Override
public void turnOnOffDeviceSuccess(BaseBean bean) {
}
@Override
protected void onDestroy() {
super.onDestroy();
BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
scanner.stopScan(new ScanCallback() {
@Override
public void onScanResult(int callbackType, @NonNull ScanResult result) {
super.onScanResult(callbackType, result);
}
@Override
public void onBatchScanResults(@NonNull List<ScanResult> results) {
super.onBatchScanResults(results);
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
});
}
}

View File

@@ -2,6 +2,7 @@ package com.ckkj.water.device;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.Nullable;
@@ -10,6 +11,7 @@ import com.chad.library.adapter.base.BaseQuickAdapter;
import com.ckkj.water.EventMessage;
import com.ckkj.water.R;
import com.ckkj.water.base.BaseActivity;
import com.ckkj.water.base.BaseFragment;
import com.ckkj.water.custom.GridSpacingItemDecoration;
import com.ckkj.water.custom.view.CustomBubbleAttachPopup;
import com.ckkj.water.databinding.DeviceControlLayoutBinding;
@@ -19,6 +21,7 @@ import com.ckkj.water.device.mvp.DeviceImpl;
import com.ckkj.water.device.mvp.DevicePresenter;
import com.ckkj.water.index.entity.WaterDeviceEntity;
import com.ckkj.water.network.BaseBean;
import com.ckkj.water.plan.entity.WaterPlanWeekEntity;
import com.ckkj.water.utils.show.ToastUtil;
import com.gyf.immersionbar.ImmersionBar;
import com.lxj.xpopup.XPopup;
@@ -38,6 +41,8 @@ public class DeviceControlActivity extends BaseActivity<DeviceControlLayoutBindi
private List<String> mTimeList = new ArrayList<>();
private WaterDeviceEntity mDeviceEntity;
private DeviceTimeSelectAdapter mAdapter;
//用户自定义的浇水时长
private int mCustomDuration = 0;
@Override
public DevicePresenter createPresenter() {
return new DevicePresenter(new DeviceImpl());
@@ -81,8 +86,15 @@ public class DeviceControlActivity extends BaseActivity<DeviceControlLayoutBindi
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
mAdapter.setOnSelPosition(position);
mCustomDuration = 0;
viewBinding.tvWorkDuartion.setHint(getString(R.string.device_custom_work_time));
viewBinding.tvWorkDuartion.setText("");
}
});
//用户自定义时间
if(mCustomDuration == 0){
viewBinding.tvWorkDuartion.setHint(getString(R.string.device_custom_work_time));
}
initListener();
}
@@ -94,6 +106,7 @@ public class DeviceControlActivity extends BaseActivity<DeviceControlLayoutBindi
setClick(viewBinding.linearWifi);
setClick(viewBinding.linearBat);
setClick(viewBinding.tvConfirm);
setClick(viewBinding.tvWorkDuartion);
}
private void setClick(View view) {
@@ -130,12 +143,105 @@ public class DeviceControlActivity extends BaseActivity<DeviceControlLayoutBindi
.show();
break;
case R.id.tv_work_duartion:
inputDuration(mCustomDuration);
break;
case R.id.tv_confirm:
showCenterTipDialog(R.mipmap.icon_dialog_success,"开始浇水");
if(mCustomDuration == 0 && mAdapter.getmSelPostion() == -1){
ToastUtil.showShort(mContext,"请选择浇水时长");
return;
}
showCenterTipDialog(R.mipmap.icon_dialog_success,"开始浇水");//
String status = mDeviceEntity.getStatus();
if(status.equals("1")){
status = "0";
}else{
status = "1";
}
mPresenter.switchDeviceWork(mDeviceEntity.getId(),status,
mCustomDuration == 0 ? convertToMinutes(mTimeList.get(mAdapter.getmSelPostion()))
: mCustomDuration);
break;
}
}
/**
* 输入浇水时间
* @param currentDuration
*/
private void inputDuration(int currentDuration) {
showEditDialog(getString(R.string.device_work_times_title),
getString(R.string.input_water_plan_time),
currentDuration == 0 ? "" : currentDuration + "",
true,
getString(R.string.cancel_text),
getString(R.string.confirm_text),
INPUT_TYPE_NUMBER,
new BaseActivity.OnDialogClick() {
@Override
public void onCancelClick() {}
@Override
public void onConfirmClisk() {}
@Override
public void onConfirmClisk(String content) {
if (Integer.parseInt(content) <= 0) {
ToastUtil.showShort(mContext, getString(R.string.input_water_plan_time_error));
return;
}
viewBinding.tvWorkDuartion.setText(content);
mCustomDuration = Integer.parseInt(content);
if(mAdapter != null){
mAdapter.setOnSelPosition(-1);
}
}
@Override
public void onView1Click() {
}
});
}
/**
* 将时间字符串转换为分钟数
*
* 1min -> 1
* 10min -> 10
* 1h -> 60
* 2h -> 120
*
* @param timeValue 时间字符串
* @return 分钟数
*/
public static int convertToMinutes(String timeValue) {
if (TextUtils.isEmpty(timeValue)) {
return 0;
}
try {
if (timeValue.endsWith("min")) {
return Integer.parseInt(
timeValue.substring(0, timeValue.length() - 3)
);
}
if (timeValue.endsWith("h")) {
return Integer.parseInt(
timeValue.substring(0, timeValue.length() - 1)
) * 60;
}
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);

View File

@@ -81,7 +81,9 @@ public class DeviceSettingsActivity extends BaseActivity<DeviceSettingsLayoutBin
mDeviceEntity.getDeviceName(),
true,
getString(R.string.cancel_text),
getString(R.string.confirm_text), new OnDialogClick() {
getString(R.string.confirm_text),
BaseActivity.INPUT_TYPE_NORMAL,
new OnDialogClick() {
@Override
public void onCancelClick() {
}

View File

@@ -17,7 +17,16 @@ public class DeviceTimeSelectAdapter extends BaseQuickAdapter<String, BaseViewHo
private List<String> mDatas = new ArrayList<>();
private int mSelPostion = -1;
public DeviceTimeSelectAdapter(Context context,int layoutResId, @Nullable List<String> data) {
public int getmSelPostion() {
return mSelPostion;
}
public void setmSelPostion(int mSelPostion) {
this.mSelPostion = mSelPostion;
}
public DeviceTimeSelectAdapter(Context context, int layoutResId, @Nullable List<String> data) {
super(layoutResId, data);
this.mContext = context;
this.mDatas = data;

View File

@@ -166,8 +166,43 @@ public class DeviceImpl implements DeviceContract.DataModel{
}
}
/**
* 手动开启关闭设备
* @param json
* @param callBack
*/
@Override
public void turnOnOffDevice(JSONObject json, IndexContract.CallBack callBack) {
try {
NetWorkManager.getRequest().switchDevice(NetWorkManager.getToken(), NetWorkManager.toRequestBody(json))
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<BaseBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull BaseBean bean) {
if (bean.getCode() == 200) {
callBack.success(bean,0);
} else {
callBack.fail(bean.getMessage());
}
}
@Override
public void onError(@NonNull Throwable e) {
callBack.fail(e.getMessage());
}
@Override
public void onComplete() {
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -129,4 +129,37 @@ public class DevicePresenter extends BasePresenter<DeviceContract.DeviceView> {
}
});
}
/**
* 开启/关闭浇水
* @param id
* @param status
* @param duration
*/
public void switchDeviceWork(String id, String status, int duration) {
try {
JSONObject json = new JSONObject();
json.put("id",id);
json.put("workStatus",status);
// json.put("startTime","09:50");
json.put("durationMin",duration + "");
impl.turnOnOffDevice(json, new IndexContract.CallBack<BaseBean>() {
@Override
public void success(BaseBean bean,int total) {
if(DevicePresenter.this.getView() != null){
DevicePresenter.this.getView().turnOnOffDeviceSuccess(bean);
}
}
@Override
public void fail(String msg) {
if(DevicePresenter.this.getView() != null){
DevicePresenter.this.getView().showError( msg);
}
}
});
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
}