475 lines
16 KiB
Dart
475 lines
16 KiB
Dart
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/FirmwareVersionService.dart';
|
||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||
import 'package:vbvs_app/common/util/base64Tool.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;
|
||
RxMap<String, Map> localUpgradeMac = <String, Map>{}.obs; //mac 进度
|
||
String? currentUpgradeVersion; //最新版本号
|
||
String? currentUpgradeName; //最新固件名
|
||
String? currentUpgradeUrl; //最新固件下载地址
|
||
List<FirmwareVersionInfo> firmwareList = []; //固件版本列表
|
||
RxBool allSelect = false.obs; //升级是否全选
|
||
RxBool autoUpgrade = false.obs; //是否自动升级
|
||
|
||
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,
|
||
},
|
||
};
|
||
EasyDartModule.logger.info("绑定传感器数据: $data");
|
||
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);
|
||
}
|
||
|
||
Future<bool> saveHabitData(sleepData) async {
|
||
bool resFlag = false;
|
||
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,
|
||
onSuccess: (res) {
|
||
resFlag = true;
|
||
},
|
||
onFailure: (res) {
|
||
resFlag = false;
|
||
},
|
||
);
|
||
return resFlag;
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
//下发wifi指令
|
||
sendCommand(Map<String, dynamic> commandData) async {
|
||
if (commandData == null || commandData.isEmpty) {
|
||
throw "指令数据不能为空";
|
||
}
|
||
commandData['data'] = Base64Tool.encode(commandData['data']);
|
||
if (Base64Tool.decode(commandData['data']) != "FFFFFFFF00031000010014FD" &&
|
||
Base64Tool.decode(commandData['data']).length <= 24) {
|
||
ef.log("下发指令: ${Base64Tool.decode(commandData['data'])}");
|
||
} else {
|
||
// ef.log("下发指令: ${Base64Tool.decode(commandData['data'])}");
|
||
}
|
||
ef.log("全部指令");
|
||
commandData['wfr'] = false;
|
||
commandData['type'] = 0; //0 base64数据 1 二进制数据
|
||
String serviceAddress = ServiceConstant.service_address;
|
||
String serviceName = ServiceConstant.server_service;
|
||
String serviceApi = ServiceConstant.sendWifiCommand;
|
||
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
|
||
await requestWithLog(
|
||
logTitle: "下发wifi控制指令",
|
||
method: MyHttpMethod.post,
|
||
queryUrl: queryUrl,
|
||
data: commandData,
|
||
onSuccess: (res) {
|
||
ef.log("下发指令成功: ${res.msg}");
|
||
},
|
||
onFailure: (res) {
|
||
ef.log("下发指令失败: ${res.msg}");
|
||
throw "下发wifi控制指令失败: ${res.msg}";
|
||
},
|
||
);
|
||
}
|
||
|
||
//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");
|
||
}
|
||
}
|