Files
tuiche/lib/pages/mh_page/device/controller/mht_bluetooth_controller.dart
2025-09-02 14:03:00 +08:00

425 lines
14 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:async';
import 'dart:convert';
import 'package:EasyDartModule/EasyDartModule.dart';
import 'package:easydevice/src/app/thapp.dart';
import 'package:ef/ef.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:vbvs_app/common/color/ServiceConstant.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/common/util/requestWithLog.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/pages/mh_page/device/model/BlueToothDataModel.dart';
import 'package:vbvs_app/pages/mh_page/user/controller/mht_register_controller.dart';
part 'mht_bluetooth_controller.g.dart';
@JsonSerializable()
class MHTBlueToothModel {
bool? bluetooth = false; //蓝牙开关
double? singal = -100;
@JsonKey(ignore: true)
List<BlueToothDataModel>? blueRawData; //蓝牙原始数据
@JsonKey(ignore: true)
List<BlueToothDataModel>? deviceDataStatus; //已经请求过状态的数据
int? read = 0;
int? deviceType; //绑定设备类型
bool wifiPassShow = false;
String? wifiPass;
MHTBlueToothModel();
static MHTBlueToothModel fromJson(Map<String, dynamic> json) =>
_$MHTBlueToothModelFromJson(json);
Map<String, dynamic> toJson() => _$MHTBlueToothModelToJson(this);
}
class MHTBlueToothController extends GetControllerEx<MHTBlueToothModel> {
MHTBlueToothController() {
attr = GetModel(MHTBlueToothModel()).obs;
}
Timer? _statusTimer;
MHTRegisterController registerController = Get.find();
RxString search = "".obs;
RxString currentDeviceMac = "".obs; //当前正在绑定的设备用来显示loading
THapp? currentDevice; //当前连接的设备
BlueToothDataModel? currentFullDevice; //当前连接的设备
RxInt blueConnectFlag = 0.obs; //当前蓝牙连接状态 0.正在连接 1.未连接 2.已连接
RxBool bluetoothStatus = false.obs; //蓝牙开启状态
RxInt connectStatus = 0.obs; //当前wifi连接状态 0未连接 1已连接
RxInt netType = 0.obs; //当前网络类型 0.正在检测 1.wifi 2.4g设备 3.未知
RxInt wifiConnectStatus = 1.obs; //获取wifi状态 0.正在检测 1.已检测完
RxMap selectWifi = {}.obs; //正在连接wifi信息
int returnPage = 0; //0返回首页 1.返回设备列表
RxInt wifiStatus = 0.obs; //wifi连接状态 0未连接 1已连接
RxList wifiList = [].obs;
RxMap connect_wifi = {}.obs;
RxString? cid = "".obs;
RxBool isScanning = false.obs;
Map<String, Map> localUpgradeMac = {}; //mac 进度
void startStatusPolling() {
updateDeviceStatus().then((res) {
if (res.code == HttpStatusCodes.ok) {
updateAll();
} else {
safeShowNotification(res.msg ?? "获取设备状态异常".tr);
EasyDartModule.logger.info("获取设备状态异常: $res");
DailyLogUtils.writeLog("获取设备状态异常: $res");
}
});
if (_statusTimer == null) {
_statusTimer = Timer.periodic(Duration(seconds: 2), (timer) {
updateDeviceStatus().then((res) {
if (res.code == HttpStatusCodes.ok) {
updateAll();
} else {
safeShowNotification(res.msg ?? "获取设备状态异常".tr);
EasyDartModule.logger.info("获取设备状态异常: $res");
DailyLogUtils.writeLog("获取设备状态异常: $res");
}
}).catchError((e, stack) {
print("updateDeviceStatus 执行异常: $e\n$stack");
safeShowNotification("设备状态请求失败".tr);
EasyDartModule.logger.info("设备状态异常: $e");
DailyLogUtils.writeLog("设备状态异常: $e");
});
});
}
}
void stopStatusPolling() {
_statusTimer?.cancel();
_statusTimer = null;
}
var shouldScan = true.obs;
void pauseScanning() {
shouldScan.value = false;
update();
}
// 恢复扫描
void resumeScanning() {
shouldScan.value = true;
update();
}
Future<ApiResponse> updateDeviceStatus() async {
try {
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.get_bluetooth_device_status;
String queryUrl = "$serviceAddress$serviceName$serviceApi";
if (model.blueRawData != null && model.blueRawData!.isNotEmpty) {
final macParams = model.blueRawData!
.map((device) =>
"mac=${Uri.encodeQueryComponent(device.mac!.replaceAll(':', ''))}")
.join("&");
if (queryUrl.contains('?')) {
queryUrl += '&$macParams';
} else {
queryUrl += '?$macParams';
}
String? language = "";
if (mhLanguageController.selectLanguage != null) {
language = mhLanguageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var response = await EasyDartModule.dio.get(queryUrl);
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
if (res.code != HttpStatusCodes.ok) return res;
if (response.data['data'] != null && response.data['data'] is List) {
List<dynamic> responseList = response.data['data'];
// 新建一个 Map便于快速通过 mac 查找返回的设备状态
final Map<String, dynamic> responseMap = {
for (var item in responseList)
item['mac'.tr].toString().toUpperCase(): item
};
// 遍历 blueRawData更新 bind 状态
for (var device in model.blueRawData!) {
final macKey = device.mac!.replaceAll(':', '').toUpperCase();
if (responseMap.containsKey(macKey)) {
var item = responseMap[macKey];
// 更新 device 绑定状态等信息
device.bind = item['bind'] ?? device.bind;
device.mac = item['bindMac'] ?? device.mac;
}
}
model.deviceDataStatus =
List<BlueToothDataModel>.from(model.blueRawData!);
} else {
model.deviceDataStatus = [];
}
updateAll();
return res;
} else {
model.deviceDataStatus = [];
return ApiResponse(code: 1, msg: "".tr);
}
} catch (e) {
print("获取设备状态异常: $e");
EasyDartModule.logger.info("获取设备状态异常: $e");
DailyLogUtils.writeLog("获取设备状态异常: $e");
return ApiResponse(code: -1, msg: "请求失败".tr);
}
return ApiResponse(code: -1, msg: "未知错误".tr);
}
bindDeviceAndMAC(BlueToothDataModel bleDevice, BuildContext context) async {
try {
if ((bleDevice.macA == null || bleDevice.macA.isEmpty) &&
(bleDevice.macB == null || bleDevice.macB.isEmpty)) {
TopSlideNotification.show(context,
text: "传感器mac读取失败".tr, textColor: themeController.currentColor.sc9);
currentDeviceMac.value = "";
return;
}
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_bind;
String queryUrl = "$serviceAddress$serviceName$serviceApi";
var data = {
"deviceType": model.deviceType,
"mac".tr: bleDevice.mac,
"macA": bleDevice.macA,
if (bleDevice.macB != null && bleDevice.macB!.isNotEmpty)
"macB": bleDevice.macB,
if (bleDevice.name != null && bleDevice.name!.isNotEmpty)
'param': {
'name': bleDevice.name,
},
};
var response =
await EasyDartModule.dio.post(queryUrl, data: jsonEncode(data));
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "绑定成功".tr, "绑定成功".tr);
if (res.code == HttpStatusCodes.ok) {
// PersonController personController = Get.find();
// personController.currentPersonId.value = res.data['id'];
//todo 绑定成功需要返回传感器id
currentDeviceMac.value = "";
if (res.data != null) {
if (currentFullDevice != null) {
currentFullDevice!.macAID = res.data['macA'];
currentFullDevice!.macBID = res.data['macB'];
currentFullDevice!.deviceID = res.data['id'];
}
}
return res;
} else {
return res;
}
} else {
return ApiResponse(code: -1, msg: "服务器失败".tr);
}
} catch (e) {
EasyDartModule.logger.info("绑定异常: $e");
DailyLogUtils.writeLog("蓝牙绑定: $e");
}
return ApiResponse(code: -1, msg: "未知错误".tr);
}
saveHabitData(sleepData) async {
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.user_setting;
String type = "sleep_habit_${sleepData['mac']}";
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
var data = {
"type": type,
"mac".tr: sleepData['mac'.tr],
"time": DateTime.now().millisecondsSinceEpoch,
"data": sleepData,
};
await requestWithLog(
logTitle: "更新睡眠习惯".tr,
method: MyHttpMethod.put,
queryUrl: queryUrl,
data: data,
);
}
Future<Map> loadHabitDataApi(String mac, {int time = 3}) async {
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.user_setting;
String type = "sleep_habit_${mac}";
String queryUrl =
"${serviceAddress}${serviceName}${serviceApi}?type=${type}";
// 使用 Future 来等待异步操作完成
Map<String, dynamic> result = {};
await requestWithLog(
logTitle: "更新睡眠习惯".tr,
method: MyHttpMethod.get,
queryUrl: queryUrl,
onSuccess: (res) {
ef.log("加载睡眠习惯成功: ${res.data}");
result = res.data; // 将返回的数据存入 result
},
onFailure: (res) {
ef.log("加载睡眠习惯失败: ${res.msg}");
result = {}; // 如果失败,可以返回空的 Map
},
);
return result; // 在 requestWithLog 完成之后返回 result
}
saveJiYiData(sleepData) async {
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.user_setting;
String type = "sleep_jiyi_${sleepData['mac']}";
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
var data = {
"type": type,
"mac": sleepData['mac'],
"time": DateTime.now().millisecondsSinceEpoch,
"data": sleepData,
};
await requestWithLog(
logTitle: "更新睡眠记忆",
method: MyHttpMethod.put,
queryUrl: queryUrl,
data: data,
);
}
loadJiYiData(String mac, {int time = 3}) async {
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.user_setting;
String type = "sleep_jiyi_${mac}";
String queryUrl =
"${serviceAddress}${serviceName}${serviceApi}?type=${type}";
// 使用 Future 来等待异步操作完成
Map<String, dynamic> result = {};
await requestWithLog(
logTitle: "更新记忆",
method: MyHttpMethod.get,
queryUrl: queryUrl,
onSuccess: (res) {
ef.log("加载记忆成功: ${res.data}");
result = res.data; // 将返回的数据存入 result
},
onFailure: (res) {
ef.log("加载记忆失败: ${res.msg}");
result = {}; // 如果失败,可以返回空的 Map
},
);
return result; // 在 requestWithLog 完成之后返回 result
}
saveMattressTimeData(sleepData) async {
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.user_setting;
String type = "sleep_new_time_${sleepData['mac']}";
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
var data = {
"type": type,
"mac": sleepData['mac'],
"time": DateTime.now().millisecondsSinceEpoch,
"data": sleepData,
};
await requestWithLog(
logTitle: "更新新版倒计时",
method: MyHttpMethod.put,
queryUrl: queryUrl,
data: data,
);
}
loadMattressTimeData(String mac, {int time = 3}) async {
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.user_setting;
String type = "sleep_new_time_${mac}";
String queryUrl =
"${serviceAddress}${serviceName}${serviceApi}?type=${type}";
// 使用 Future 来等待异步操作完成
Map<String, dynamic> result = {};
await requestWithLog(
logTitle: "更新新版倒计时",
method: MyHttpMethod.get,
queryUrl: queryUrl,
onSuccess: (res) {
ef.log("更新新版倒计时成功: ${res.data}");
result = res.data; // 将返回的数据存入 result
},
onFailure: (res) {
ef.log("更新新版倒计时失败: ${res.msg}");
result = {}; // 如果失败,可以返回空的 Map
},
);
return result; // 在 requestWithLog 完成之后返回 result
}
//todo 解绑的时候删除自己所拥有的所有设备的睡眠习惯
}
void safeShowNotification(String msg) {
try {
final ctx = Get.context;
if (ctx != null && ctx.mounted) {
TopSlideNotification.show(
ctx,
text: msg,
textColor: themeController.currentColor.sc9,
);
} else {
print("TopSlideNotification 未显示context 不可用或未挂载".tr);
}
} catch (e, stack) {
// print("TopSlideNotification 显示异常: $e\n$stack");
}
}