ihealth_hr 0.0.6 copy "ihealth_hr: ^0.0.6" to clipboard
ihealth_hr: ^0.0.6 copied to clipboard

A Flutter plugin to integrate the iHealth KN-550BT blood pressure monitor.

example/lib/main.dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:ihealth_hr/ihealth_hr.dart';
import 'package:permission_handler/permission_handler.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'iHealth HR Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const IHealthHomePage(),
    );
  }
}

class IHealthHomePage extends StatefulWidget {
  const IHealthHomePage({super.key});

  @override
  State<IHealthHomePage> createState() => _IHealthHomePageState();
}

class _IHealthHomePageState extends State<IHealthHomePage> {
  String connectionStatus = "Waiting for device status...";
  String batteryLevel = "--";
  int offlineHistoryCount = 0;
  String message = "";

  int? latestHeartRate;
  int? latestSys;
  int? latestDia;
  String latestTime = "";
  String deviceTime = "";
  bool? isBackLightOn;
  bool? isClockOn;

  final List<Map<String, dynamic>> historyData = [];

  StreamSubscription? _deviceStatusSubscription;

  @override
  void initState() {
    super.initState();
    requestPermissionsAndStartScan();
  }

  Future<void> requestPermissionsAndStartScan() async {
    // Request all necessary permissions
    Map<Permission, PermissionStatus> statuses =
        await [
          Permission.bluetooth,
          Permission.bluetoothScan,
          Permission.bluetoothConnect,
          Permission.locationWhenInUse,
        ].request();

    // Check if all permissions are granted
    bool allGranted = statuses.values.every((status) => status.isGranted);

    if (allGranted) {
      // Start scan automatically
      IhealthHrPlugin.startScan();
      // Listen to device status events
      _deviceStatusSubscription = IhealthHrPlugin.deviceStatusStream.listen(
        (event) {
          if (event is Map) {
            final Map<dynamic, dynamic> data = Map<dynamic, dynamic>.from(
              event,
            );
            final String eventType = data['event'] ?? '';

            switch (eventType) {
              case 'connectionStateChanged':
                final String status = data['status'] ?? 'unknown';
                setState(() {
                  connectionStatus =
                      status.isNotEmpty
                          ? status[0].toUpperCase() + status.substring(1)
                          : "Unknown";
                });
                break;

              case 'offlineHistoryCount':
                final int count = data['count'] ?? 0;
                final String msg = data['message'] ?? '';
                setState(() {
                  offlineHistoryCount = count;
                  message = msg;
                });
                break;

              case 'historyData':
                setState(() {
                  latestHeartRate = data['heartRate'] as int?;
                  latestSys = data['sys'] as int?;
                  latestDia = data['dia'] as int?;
                  latestTime = data['time'] ?? "";

                  final newEntry = {
                    "time": latestTime,
                    "sys": latestSys,
                    "dia": latestDia,
                    "heartRate": latestHeartRate,
                  };
                  if (!historyData.any((e) => e['time'] == latestTime)) {
                    historyData.add(newEntry);
                  }
                });
                break;

              case 'displayStatus':
                setState(() {
                  isBackLightOn = data['backlightOn'] as bool?;
                  isClockOn = data['clockOn'] as bool?;
                });
                break;

              case 'deviceTime':
                setState(() {
                  deviceTime = data['time'] ?? "";
                });
                break;

              case 'batteryLevel':
                setState(() {
                  batteryLevel = data['level']?.toString() ?? "--";
                });
                break;

              default:
                print("Unknown event type: $eventType");
            }
          } else {
            // Fallback: show raw event
            setState(() {
              message = event.toString();
            });
          }
        },
        onError: (error) {
          setState(() {
            message = "Error receiving data: $error";
          });
        },
      );
    } else {
      setState(() {
        message =
            "Permissions not granted. Please enable Bluetooth and Location permissions in settings.";
      });
    }
  }

  @override
  void dispose() {
    _deviceStatusSubscription?.cancel();
    super.dispose();
  }

  Widget buildHistoryList(double maxHeight) {
    if (historyData.isEmpty) {
      return Padding(
        padding: const EdgeInsets.all(8.0),
        child: Text("No historical data yet.", style: TextStyle(fontSize: 16)),
      );
    }

    return Container(
      constraints: BoxConstraints(maxHeight: maxHeight),
      child: ListView.separated(
        shrinkWrap: true,
        itemCount: historyData.length,
        separatorBuilder: (_, __) => Divider(),
        itemBuilder: (context, index) {
          final item = historyData[index];
          return Padding(
            padding: const EdgeInsets.symmetric(vertical: 6),
            child: Text(
              "Time: ${item['time']}, Sys: ${item['sys']}, Dia: ${item['dia']}, HR: ${item['heartRate']}",
              style: TextStyle(fontSize: 16),
            ),
          );
        },
      ),
    );
  }

  Widget buildStatusText(String title, String value, {Color? color}) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8),
      child: RichText(
        text: TextSpan(
          text: '$title ',
          style: TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
            color: Colors.black,
          ),
          children: [
            TextSpan(
              text: value,
              style: TextStyle(
                fontWeight: FontWeight.normal,
                color: color ?? Colors.black,
                fontSize: 18,
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final screenHeight = MediaQuery.of(context).size.height;
    final maxHistoryHeight =
        screenHeight * 0.3 > 300 ? 300.0 : screenHeight * 0.3;

    return Scaffold(
      appBar: AppBar(title: const Text('iHealth HR Plugin Demo')),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Container(
          constraints: const BoxConstraints(maxWidth: 600),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              buildStatusText(
                'Connection Status:',
                connectionStatus,
                color:
                    connectionStatus.toLowerCase() == 'connected'
                        ? Colors.green
                        : Colors.red,
              ),
              buildStatusText(
                'Battery Level:',
                batteryLevel,
                color: Colors.green,
              ),
              buildStatusText('Offline History Count:', '$offlineHistoryCount'),
              buildStatusText(
                'Latest Heart Rate (BPM):',
                latestHeartRate != null ? '$latestHeartRate' : '--',
                color: Colors.red,
              ),
              buildStatusText(
                'Latest Blood Pressure:',
                (latestSys != null && latestDia != null)
                    ? 'High: $latestSys mmHg, Low: $latestDia mmHg'
                    : '--',
                color: Colors.blue,
              ),
              if (latestTime.isNotEmpty)
                buildStatusText('Measurement Time:', latestTime),
              if (deviceTime.isNotEmpty)
                buildStatusText('Device Reported Time:', deviceTime),
              buildStatusText(
                'Backlight:',
                isBackLightOn == null ? 'N/A' : (isBackLightOn! ? 'ON' : 'OFF'),
                color: isBackLightOn == true ? Colors.green : Colors.grey,
              ),
              buildStatusText(
                'Clock Display:',
                isClockOn == null ? 'N/A' : (isClockOn! ? 'ON' : 'OFF'),
                color: isClockOn == true ? Colors.green : Colors.grey,
              ),
              const Divider(height: 32, thickness: 2),
              const Text(
                'Historical Data:',
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 8),
              buildHistoryList(maxHistoryHeight),
              const SizedBox(height: 32),
              if (message.isNotEmpty)
                Text(
                  'Message: $message',
                  style: const TextStyle(fontSize: 16, color: Colors.blueGrey),
                  textAlign: TextAlign.center,
                ),
            ],
          ),
        ),
      ),
    );
  }
}
2
likes
130
points
19
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin to integrate the iHealth KN-550BT blood pressure monitor.

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

flutter, permission_handler, plugin_platform_interface

More

Packages that depend on ihealth_hr

Packages that implement ihealth_hr