Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
laki_icu_app
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张宏
laki_icu_app
Commits
96e4c909
Commit
96e4c909
authored
Jun 27, 2026
by
张宏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
服务器下发mqtt指令控制设备
parent
6d1704c6
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
206 additions
and
3 deletions
+206
-3
device_control_bloc.dart
lib/blocs/device_control/device_control_bloc.dart
+7
-0
main.dart
lib/main.dart
+6
-2
laki_mqtt_client.dart
lib/utils/mqtt/laki_mqtt_client.dart
+1
-1
monitoring_index_cubit.dart
lib/views/monitoring/index/cubit/monitoring_index_cubit.dart
+192
-0
No files found.
lib/blocs/device_control/device_control_bloc.dart
View file @
96e4c909
...
...
@@ -1348,3 +1348,10 @@ class DeviceControlBloc
/// [用户调用] 重置设备设置
void
resetSettings
()
=>
add
(
const
DeviceControlResetSettings
());
}
/// 全局 DeviceControlBloc 引用。
///
/// 由 main.dart 在创建时写入。
/// [MonitoringIndexCubit._handleIcuCommandMessage] 通过此引用获取 Bloc 实例,
/// 将 MQTT 下行指令映射为 Bloc Event 并通过蓝牙写入设备。
DeviceControlBloc
?
globalDeviceControlBloc
;
lib/main.dart
View file @
96e4c909
...
...
@@ -87,8 +87,12 @@ class _MyAppState extends State<MyApp> {
storageService:
_storageService
,
);
DeviceControlBloc
get
_deviceControlBlocInstance
=>
_deviceControlBloc
??=
DeviceControlBloc
();
DeviceControlBloc
get
_deviceControlBlocInstance
{
if
(
_deviceControlBloc
!=
null
)
return
_deviceControlBloc
!;
_deviceControlBloc
=
DeviceControlBloc
();
globalDeviceControlBloc
=
_deviceControlBloc
;
return
_deviceControlBloc
!;
}
DeviceThresholdConfigBloc
get
_deviceThresholdConfigBlocInstance
{
if
(
_deviceThresholdConfigBloc
!=
null
)
return
_deviceThresholdConfigBloc
!;
...
...
lib/utils/mqtt/laki_mqtt_client.dart
View file @
96e4c909
...
...
@@ -75,7 +75,7 @@ class LakiMqttTopics {
static
String
icuAlarm
(
String
deviceSn
)
=>
'icu/
$deviceSn
/alarm'
;
// stephen 上行 传感器(设备)异常告警 icu/{SN}/alarm → DeviceAlarmHandler
static
String
icuTo
(
String
deviceSn
)
=>
'icu/
$deviceSn
/to'
;
static
String
icuTo
(
String
deviceSn
)
=>
'icu/
$deviceSn
/to'
;
// stephen 下行,服务端下发指令控制设备
static
String
icuPetBind
(
String
deviceSn
)
=>
'icu/
$deviceSn
/pet/bind'
;
// stephen 下行 宠物 绑定、出舱
...
...
lib/views/monitoring/index/cubit/monitoring_index_cubit.dart
View file @
96e4c909
...
...
@@ -6,8 +6,10 @@ import 'package:laki_icu_app/enums/video_stream_mode_enum.dart';
import
'package:laki_icu_app/models/bo/cabin_detail_response.dart'
;
import
'package:laki_icu_app/utils/date_utils.dart'
;
import
'package:laki_icu_app/blocs/device_control/device_control_bloc.dart'
;
import
'package:laki_icu_app/models/bo/monitoring_bo.dart'
;
import
'package:laki_icu_app/models/bo/camera_alarm_bo.dart'
;
import
'package:laki_icu_app/models/bo/device_control_bo.dart'
;
import
'package:laki_icu_app/services/cabin_service.dart'
;
import
'package:laki_icu_app/services/p2p_video_service.dart'
;
import
'package:laki_icu_app/services/webrtc_service.dart'
;
...
...
@@ -820,6 +822,7 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
}
await
_mqttClient
!.
connect
();
// 订阅
_mqttClient
!
..
subscribeIcuCommands
(
deviceSn
)
..
subscribePetBind
(
deviceSn
)
...
...
@@ -849,6 +852,7 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
}
}
// 解析mqtt订阅消息
void
_listenMqttState
(
LakiMqttClient
client
)
{
_mqttStateSub
=
client
.
stateStream
.
listen
((
status
)
{
if
(
isClosed
)
return
;
...
...
@@ -872,6 +876,12 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
_handlePetBindMessage
(
json
);
return
;
}
if
(
json
!=
null
&&
message
.
topic
==
LakiMqttTopics
.
icuTo
(
_mqttDeviceSn
??
''
))
{
_handleIcuCommandMessage
(
json
);
return
;
}
emit
(
state
.
copyWith
(
mqttMessage:
'MQTT 收到
${message.topic}
:
${message.payload}
'
,
));
...
...
@@ -971,6 +981,188 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
emit
(
state
.
copyWith
(
patientInfo:
patientInfo
));
}
/// 处理 MQTT icu/{SN}/to 服务端下发控制指令
///
/// 服务端下发格式:
/// ```json
/// {
/// "eventId": "...",
/// "deviceId": "CNA75875A",
/// "deviceType": "ICU",
/// "timestamp": 1782365796552,
/// "type": "setting",
/// "data": { "temperatureSetting": 260 }
/// }
/// ```
/// [data] 中每次只带一个维度字段。
void
_handleIcuCommandMessage
(
Map
<
String
,
dynamic
>
json
)
{
if
(
json
[
'type'
]
!=
'setting'
)
return
;
final
data
=
json
[
'data'
];
if
(
data
is
!
Map
<
String
,
dynamic
>
||
data
.
isEmpty
)
return
;
final
bloc
=
globalDeviceControlBloc
;
if
(
bloc
==
null
)
{
debugPrint
(
'[IcuCommand] globalDeviceControlBloc 未初始化,无法处理指令'
);
return
;
}
// data 每次只带一个维度,取第一个 key
final
key
=
data
.
keys
.
first
;
final
rawValue
=
data
[
key
];
if
(
rawValue
is
!
num
)
{
debugPrint
(
'[IcuCommand] 未知指令字段值类型:
$key
=
$rawValue
'
);
return
;
}
final
value
=
rawValue
.
toInt
();
debugPrint
(
'[IcuCommand] 收到指令:
$key
=
$value
'
);
switch
(
key
)
{
// ========== 已有 BLE identifier ==========
// 温度设定值 (MQTT ×10,如 260 → 26.0℃)
case
'temperatureSetting'
:
final
temp
=
(
value
/
10
).
toStringAsFixed
(
1
);
bloc
.
setCabinTempSetValue
(
temp
);
break
;
// 湿度设定值
case
'humiditySetting'
:
bloc
.
setCabinHumiditySetValue
(
'
$value
'
);
break
;
// 氧气设定值
case
'oxygenSetting'
:
bloc
.
setOxygenConcentrationSetValue
(
'
$value
'
);
break
;
// CO2 设定值
case
'co2Setting'
:
bloc
.
setCO2ConcentrationAlarmThreshold
(
'
$value
'
);
break
;
// 风速:0=舒适 / 1=强风 / 2=睡眠
case
'windSet'
:
final
mode
=
_windSpeedModeFromInt
(
value
);
bloc
.
setWindSpeedMode
(
mode
);
break
;
// 护理等级:0=关 / 1=三级 / 2=二级 / 3=一级 / 4=特级
case
'levelLight'
:
final
level
=
_careLevelFromInt
(
value
);
bloc
.
setCareLevel
(
level
);
break
;
// 开放供氧:0=关 / 1=开
case
'openO2'
:
bloc
.
setOpenOxygenSwitch
(
value
==
1
);
break
;
// 内外循环:0=外 / 1=内
case
'internalExternalCycleState'
:
bloc
.
setCirculationMode
(
value
==
0
?
CirculationMode
.
external
:
CirculationMode
.
internal
,
);
break
;
// 照明灯:0=关 / 1=开
case
'floodLight'
:
bloc
.
setIlluminationLightSwitch
(
value
==
1
);
break
;
// 泛光灯/检查灯:0=关 / 1=开
case
'inspectionLamp'
:
bloc
.
setCheckLightSwitch
(
value
==
1
);
break
;
// 蓝光灯:0=关 / 1=开
case
'blueLight'
:
bloc
.
setBlueLightSwitch
(
value
==
1
);
break
;
// 红光灯:0=关 / 1=开
case
'redLight'
:
bloc
.
setRedLightSwitch
(
value
==
1
);
break
;
// ========== 待确认 BLE identifier 的字段 ==========
// TODO: 待确认 BLE identifier 后补充
case
'openO2SettingMax'
:
debugPrint
(
'[IcuCommand] openO2SettingMax=
$value
— 待确认 BLE identifier'
);
break
;
// TODO: 待确认 BLE identifier 后补充
case
'noOpenO2SettingMax'
:
debugPrint
(
'[IcuCommand] noOpenO2SettingMax=
$value
— 待确认 BLE identifier'
);
break
;
// TODO: 待确认 BLE identifier 后补充
case
'co2FastClearSwitch'
:
debugPrint
(
'[IcuCommand] co2FastClearSwitch=
$value
— 待确认 BLE identifier'
);
break
;
// TODO: 待确认 BLE identifier 后补充
case
'wifible'
:
debugPrint
(
'[IcuCommand] wifible=
$value
— 待确认 BLE identifier'
);
break
;
// TODO: 待确认 BLE identifier 后补充
case
'redLightDuration'
:
debugPrint
(
'[IcuCommand] redLightDuration=
$value
— 待确认 BLE identifier'
);
break
;
// TODO: 待确认 BLE identifier 后补充
case
'redLightInterval'
:
debugPrint
(
'[IcuCommand] redLightInterval=
$value
— 待确认 BLE identifier'
);
break
;
// TODO: 待确认 BLE identifier 后补充
case
'airConditioner'
:
debugPrint
(
'[IcuCommand] airConditioner=
$value
— 待确认 BLE identifier'
);
break
;
default
:
debugPrint
(
'[IcuCommand] 未知指令字段:
$key
=
$value
'
);
break
;
}
}
WindSpeedMode
_windSpeedModeFromInt
(
int
value
)
{
switch
(
value
)
{
case
0
:
return
WindSpeedMode
.
comfort
;
case
1
:
return
WindSpeedMode
.
strong
;
case
2
:
return
WindSpeedMode
.
sleep
;
default
:
return
WindSpeedMode
.
sleep
;
}
}
CareLevel
_careLevelFromInt
(
int
value
)
{
switch
(
value
)
{
case
0
:
return
CareLevel
.
off
;
case
1
:
return
CareLevel
.
level3
;
case
2
:
return
CareLevel
.
level2
;
case
3
:
return
CareLevel
.
level1
;
case
4
:
return
CareLevel
.
special
;
default
:
return
CareLevel
.
off
;
}
}
/// 毫秒时间戳 → HH:mm:ss 格式(与 Android 一致)
String
_formatTimestamp
(
int
milliseconds
)
{
final
dateTime
=
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment