xkimi
Published © GPL3+

Affordable Remote Baby Vitals Monitoring/Alert System

Compact Baby Vital Wearable with HR & SPO2 Monitoring & Alert

AdvancedFull instructions provided20 hours3,437

Things used in this project

Story

Read more

Custom parts and enclosures

Autodesk360

Schematics

Baby Guard Schematic

Code

Zephyr main.c

C/C++
Zephyr main structure, need driver to function, check github
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <sys/printk.h>
#include <sys/byteorder.h>
#include <zephyr.h>

#include <drivers/sensor.h>
#include <stdio.h>
#include "max32664.h"

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/conn.h>
#include <bluetooth/uuid.h>
#include <bluetooth/gatt.h>
#include <bluetooth/services/bas.h>
#include <bluetooth/services/hrs.h>

#include <drivers/led_strip.h>
#include <device.h>
#include <drivers/spi.h>
#include <sys/util.h>

#include "sphr.h"

/* size of stack area used by each thread */
#define STACKSIZE 1024

/* scheduling priority used by each thread */
#define PRIORITY 7

/* delay between greetings (in ms) */
#define SLEEPTIME 500
#define STRIP_NUM_LEDS 1

#define DELAY_TIME K_MSEC(40)

#define COLOR_RED 0
#define COLOR_GREEN 1
#define COLOR_BLUE 2
#define COLOR_BLACK 3
#define COLOR_WHITE 4
#define COLOR_ORANGE 4

uint8_t sphr_data[8];

static const struct led_rgb colors[] = {
	{ .r = 0xff, .g = 0x00, .b = 0x00, }, /* red */
	{ .r = 0x00, .g = 0xff, .b = 0x00, }, /* green */
	{ .r = 0x00, .g = 0x00, .b = 0xff, }, /* blue */
	{ .r = 0x00, .g = 0x00, .b = 0x00, }, /* black */
	{ .r = 0xff, .g = 0xff, .b = 0xff, }, /* white */
	{ .r = 165, .g = 165, .b = 0, }, /* orange */
};

static const struct led_rgb black = {
	.r = 0x00,
	.g = 0x00,
	.b = 0x00,
};

struct led_rgb strip_color;

const struct led_rgb *color_at(size_t time, size_t i)
{
	size_t rgb_start = time % STRIP_NUM_LEDS;

	if (rgb_start <= i && i < rgb_start + ARRAY_SIZE(colors)) {
		return &colors[i - rgb_start];
	} else {
		return &black;
	}
}

K_FIFO_DEFINE(my_fifo);



struct data_item_t {
    void *fifo_reserved;   /* 1st word reserved for use by FIFO */
    int hr;
	int spo2;
	int confidence;
	int status;
};

struct data_item_t tx_data;


static const struct bt_data ad[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
	BT_DATA_BYTES(BT_DATA_UUID16_ALL,
		      BT_UUID_16_ENCODE(BT_UUID_HRS_VAL),
		      BT_UUID_16_ENCODE(BT_UUID_BAS_VAL),
		      BT_UUID_16_ENCODE(BT_UUID_DIS_VAL))
};

static void connected(struct bt_conn *conn, uint8_t err)
{
	if (err) {
		printk("Connection failed (err 0x%02x)\n", err);
	} else {
		printk("Connected\n");
	}
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
	printk("Disconnected (reason 0x%02x)\n", reason);
}

static struct bt_conn_cb conn_callbacks = {
	.connected = connected,
	.disconnected = disconnected,
};

static void bt_ready(void)
{
	int err;

	printk("Bluetooth initialized\n");

	err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
	if (err) {
		printk("Advertising failed to start (err %d)\n", err);
		return;
	}

	printk("Advertising successfully started\n");
}

static void auth_cancel(struct bt_conn *conn)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	printk("Pairing cancelled: %s\n", addr);
}

static struct bt_conn_auth_cb auth_cb_display = {
	.cancel = auth_cancel,
};

static void bas_notify(void)
{
	uint8_t battery_level = bt_bas_get_battery_level();

	battery_level--;

	if (!battery_level) {
		battery_level = 100U;
	}

	bt_bas_set_battery_level(battery_level);
}

static void hrs_notify(void)
{
	static uint8_t heartrate = 90U;

	/* Heartrate measurements simulation */
	heartrate++;
	if (heartrate == 160U) {
		heartrate = 90U;
	}
	//printk("mesaured heart rate=%d\n", heartrate);
	bt_hrs_notify(heartrate);
}

K_THREAD_STACK_DEFINE(threadA_stack_area, STACKSIZE);
static struct k_thread threadA_data;


void threadA(void *dummy1, void *dummy2, void *dummy3)
{
	ARG_UNUSED(dummy1);
	ARG_UNUSED(dummy2);
	ARG_UNUSED(dummy3);

	int err;
	struct sensor_value hr;
	struct sensor_value spo2;
	struct sensor_value status;
	struct sensor_value confidence;
	struct sensor_value temp;
	float tempf = 0;
	uint8_t tempBytes[4];
	//struct sensor_value red;
	//struct sensor_value IR;
	const struct device *dev = device_get_binding(DT_LABEL(DT_INST(0, max_max32664)));

	if (dev == NULL) {
		printf("Could not get max32664 device\n");
		return;
	}

	const struct device *devTemp = device_get_binding(DT_LABEL(DT_INST(0, max_max30205)));

	if (devTemp == NULL) {
		printf("Could not get max30205 device\n");
		return;
	}

	err = bt_enable(NULL);
	if (err) {
		printk("Bluetooth init failed (err %d)\n", err);
		return;
	}





	bt_ready();

	bt_conn_cb_register(&conn_callbacks);
	bt_conn_auth_cb_register(&auth_cb_display);

	/* Implement notification. At the moment there is no suitable way
	 * of starting delayed work so we do it here
	 */

	while (1) {
		k_sleep(K_SECONDS(1));



		sensor_sample_fetch(dev);
		sensor_channel_get(dev, SENSOR_CHAN_HEARTRATE, &hr);
		sensor_channel_get(dev, SENSOR_CHAN_SPO2, &spo2);
		sensor_channel_get(dev, SENSOR_CHAN_HR_STATUS, &status);
		sensor_channel_get(dev, SENSOR_CHAN_CONFIDENCE, &confidence);

		sensor_sample_fetch(devTemp);
		sensor_channel_get(devTemp, SENSOR_CHAN_AMBIENT_TEMP, &temp);
		//sensor_channel_get(dev, SENSOR_CHAN_IR, &IR);
		/* Print green LED data*/
		//printf("red=%d\n", red.val1);
		//printf("IR=%d\n", IR.val1);
		printk("hr=%d\n",hr.val1);
		printk("spo2=%d\n",spo2.val1);
		printk("status=%d\n",status.val1);
		printk("confidence=%d\n",confidence.val1);

		printk("temp1=%d\n",temp.val1);
		printk("temp2=%d\n",temp.val2);

		tempf = sensor_value_to_double(&temp);
		/* Heartrate measurements simulation */
		hrs_notify();
		tx_data.hr = hr.val1;
		tx_data.spo2 = spo2.val1;
		tx_data.status = status.val1;
		tx_data.confidence = confidence.val1;

		k_fifo_put(&my_fifo, &tx_data);
		/* Battery level simulation */
		bas_notify();

		sphr_data[0] = (uint8_t)hr.val1;
		sphr_data[1] = (uint8_t)spo2.val1;
		sphr_data[2] = (uint8_t)status.val1;
		sphr_data[3] = (uint8_t)confidence.val1;

		memcpy(sphr_data + 4, &tempf,sizeof(float));
		
		sphr_notify(sphr_data,8);
	}

}

K_THREAD_STACK_DEFINE(threadB_stack_area, STACKSIZE);
static struct k_thread threadB_data;


void threadB(void *dummy1, void *dummy2, void *dummy3)
{
	ARG_UNUSED(dummy1);
	ARG_UNUSED(dummy2);
	ARG_UNUSED(dummy3);

	struct data_item_t  *rx_data;

	struct data_item_t  *cur_data;

	int minimum_sleep = 100;
	
	int sleep_time = 1000;

	double sleep_timed = 1000;

	const struct device *strip;
	size_t i, time;

	strip = device_get_binding(DT_LABEL(DT_INST(0, apa_apa102)));
	if (strip) {
		printk("Found LED strip device %s", DT_LABEL(DT_INST(0, apa_apa102)));
	} else {
		printk("LED strip device %s not found", DT_LABEL(DT_INST(0, apa_apa102)));
		return;
	}
	
	int cnt = 0;
	while(1) {

		cur_data = k_fifo_get(&my_fifo, K_NO_WAIT);

		if (cur_data)
		{
			rx_data = cur_data;

			if (rx_data->status == 3)
			{
				// get valid hr data, update sleep time
   			    sleep_timed = 1000.0f * 60.0f / (float)rx_data->hr;
				
				sleep_time = (int)sleep_timed;

				if (sleep_time < 200) sleep_time = 200;

				if (sleep_time > 2000) sleep_time = 2000;

				printk("sleep time=%d\n", sleep_time);
			}

		}

		if (rx_data)
		{
			if (rx_data->status == 0)
			{
				strip_color = colors[COLOR_RED];
				led_strip_update_rgb(strip, &strip_color, STRIP_NUM_LEDS);
				k_sleep(K_MSEC(50));
				strip_color = colors[COLOR_BLACK];
				led_strip_update_rgb(strip, &strip_color, STRIP_NUM_LEDS);
				k_sleep(K_MSEC(2000));
			}
			else if (rx_data->status == 1 || rx_data->status == 2)
			{
				strip_color = colors[COLOR_ORANGE];
				led_strip_update_rgb(strip, &strip_color, STRIP_NUM_LEDS);
				k_sleep(K_MSEC(50));
				strip_color = colors[COLOR_BLACK];
				led_strip_update_rgb(strip, &strip_color, STRIP_NUM_LEDS);
				k_sleep(K_MSEC(1000));
			}
			else
			{
				strip_color = colors[COLOR_GREEN];
				led_strip_update_rgb(strip, &strip_color, STRIP_NUM_LEDS);
				k_sleep(K_MSEC(50));
				strip_color = colors[COLOR_BLACK];
				led_strip_update_rgb(strip, &strip_color, STRIP_NUM_LEDS);
				k_sleep(K_MSEC(sleep_time));
			}
			
		}

		k_sleep(K_MSEC(1));
		
	}

}

void main(void)
{


	k_thread_create(&threadA_data, threadA_stack_area,
			K_THREAD_STACK_SIZEOF(threadA_stack_area),
			threadA, NULL, NULL, NULL,
			PRIORITY, 0, K_FOREVER);
	k_thread_name_set(&threadA_data, "thread_a");

	k_thread_start(&threadA_data);


	k_thread_create(&threadB_data, threadB_stack_area,
			K_THREAD_STACK_SIZEOF(threadB_stack_area),
			threadB, NULL, NULL, NULL,
			PRIORITY, 0, K_FOREVER);
	k_thread_name_set(&threadB_data, "thread_b");

	k_thread_start(&threadB_data);
}

Flutter Main code

Dart
Flutter main code, check github for complete source code.
import 'dart:convert';
import 'dart:io';
import 'dart:math';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/services.dart';
import 'dart:async';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:mqtt_client/mqtt_client.dart';
import 'dart:typed_data';

import 'package:mqtt_client/mqtt_server_client.dart';

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

class HealthData {
  final double value;

  HealthData(this.value);

  Map<String, dynamic> toJson() => {'value': value};
}

class HealthDataString {
  final String value;

  HealthDataString(this.value);

  Map<String, dynamic> toJson() => {'value': value};
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.dark(),
      home: MyHomePage(title: 'Baby Monitor'),
    );
  }
}

class LineChartDisplay extends StatelessWidget {
  LineChartDisplay({required this.hrInput, required this.sp2Input});

  final List<FlSpot> hrInput;
  final List<FlSpot> sp2Input;
  final List<Color> gradientColors = [
    const Color(0xff23b6e6),
    const Color(0xff02d39a),
  ];

  final List<Color> gradientColors1 = [
    const Color(0xffe623cc),
    const Color(0xffffe67a),
  ];

  double getMinValX(List<FlSpot> d) {
    if (d.isEmpty) return 0;
    double val = d[0].x;

    for (var v in d) {
      if (v.x < val) {
        val = v.x;
      }
    }

    return val;
  }

  double getMinValY(List<FlSpot> d) {
    if (d.isEmpty) return 0;
    double val = d[0].y;

    for (var v in d) {
      if (v.y < val) {
        val = v.y;
      }
    }

    return val;
  }

  double getMaxValY(List<FlSpot> d) {
    print("called");
    if (d.isEmpty) return 0;
    double val = d[0].y;

    for (var v in d) {
      if (v.y > val) {
        val = v.y;
      }
    }
    print('max_y=$val');
    return val;
  }

  double getMaxValX(List<FlSpot> d) {
    if (d.isEmpty) return 0;
    double val = d[0].x;

    for (var v in d) {
      if (v.x > val) {
        val = v.x;
      }
    }

    return val;
  }

  LineChartData mainData(List<FlSpot> hrData, List<FlSpot> sp2Data) {
    return LineChartData(
      gridData: FlGridData(
        show: false,
        drawVerticalLine: true,
        drawHorizontalLine: true,
        checkToShowHorizontalLine: (value) {
          //print(value);
          return true;
        },
        checkToShowVerticalLine: (value) {
          //print(value);
          return true;
        },
        getDrawingHorizontalLine: (value) {
          //print(value);
          return FlLine(
            color: const Color(0xff37434d),
            strokeWidth: 1,
          );
        },
        getDrawingVerticalLine: (value) {
          return FlLine(
            color: const Color(0xff37434d),
            strokeWidth: 1,
          );
        },
      ),
      titlesData: FlTitlesData(
        show: true,
        bottomTitles: SideTitles(
          showTitles: false,
          interval: 2,
          reservedSize: 22,
          getTextStyles: (value) => const TextStyle(
              color: Color(0xff68737d),
              fontWeight: FontWeight.bold,
              fontSize: 16),
          getTitles: (value) {
            return value.toString();
          },
          margin: 8,
        ),
        leftTitles: SideTitles(
          showTitles: true,
          interval: 10,
          getTextStyles: (value) => const TextStyle(
            color: Color(0xff67727d),
            fontWeight: FontWeight.bold,
            fontSize: 15,
          ),
          getTitles: (value) {
            //print(value)
            return value.toString();
          },
          reservedSize: 22,
          margin: 20,
        ),
      ),
      borderData: FlBorderData(
          show: true,
          border: Border.all(color: const Color(0xff37434d), width: 1)),
      minX: getMinValX(hrData),
      maxX: getMaxValX(hrData),
      minY: 40,
      maxY: 150,
      lineBarsData: [
        LineChartBarData(
          spots: hrData,
          isCurved: true,
          colors: gradientColors,
          barWidth: 2,
          isStrokeCapRound: true,
          dotData: FlDotData(
            show: false,
          ),
          belowBarData: BarAreaData(
            show: false,
            colors:
                gradientColors.map((color) => color.withOpacity(0.3)).toList(),
          ),
        ),
        LineChartBarData(
          spots: sp2Data,
          isCurved: true,
          colors: gradientColors1,
          barWidth: 2,
          isStrokeCapRound: true,
          dotData: FlDotData(
            show: false,
          ),
          belowBarData: BarAreaData(
            show: false,
            colors:
                gradientColors1.map((color) => color.withOpacity(0.3)).toList(),
          ),
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 1.23,
      child: Container(
        decoration: const BoxDecoration(
          borderRadius: BorderRadius.all(Radius.circular(18)),
          gradient: LinearGradient(
            colors: [
              Color(0xff2c274c),
              Color(0xff46426c),
            ],
            begin: Alignment.bottomCenter,
            end: Alignment.topCenter,
          ),
        ),
        child: Stack(
          children: <Widget>[
            Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                const SizedBox(
                  height: 4,
                ),
                const Text(
                  'Heart Rate - SPO2 Chart',
                  style: TextStyle(
                      color: Colors.white,
                      fontSize: 28,
                      fontWeight: FontWeight.bold,
                      letterSpacing: 2),
                  textAlign: TextAlign.center,
                ),
                const SizedBox(
                  height: 37,
                ),
                Expanded(
                  child: Padding(
                    padding: const EdgeInsets.only(right: 16.0, left: 20.0),
                    child: LineChart(
                      mainData(hrInput, sp2Input),
                      swapAnimationDuration: const Duration(milliseconds: 250),
                    ),
                  ),
                ),
                const SizedBox(
                  height: 10,
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class AwsMQTT {
  late MqttServerClient client;

  Future<void> init() async {
    print("init aws mqtt");

    ByteData caData = await rootBundle.load('certs/AmazonRootCA.pem');
    ByteData certData =
        await rootBundle.load('certs/awsiot-certificate.pem.crt');
    ByteData privateKeyData =
        await rootBundle.load('certs/awsiot-private.pem.key');

    var _iotEndpoint = 'a3e4d2huogr3x6-ats.iot.us-east-1.amazonaws.com';
    var _clientId = '123123';

    client = MqttServerClient.withPort(_iotEndpoint, _clientId, 8883,
        maxConnectionAttempts: 5);
    client.logging(on: true);
    client.keepAlivePeriod = 20;
    client.secure = true;

    final securityContext = SecurityContext.defaultContext;

    securityContext.useCertificateChainBytes(certData.buffer.asUint8List());
    securityContext.setClientAuthoritiesBytes(caData.buffer.asUint8List());
    securityContext.usePrivateKeyBytes(privateKeyData.buffer.asUint8List());

    client.securityContext = securityContext;
    client.setProtocolV311();

    // final MqttConnectMessage connMess = MqttConnectMessage()
    //     .withClientIdentifier(_clientId)
    //     .startClean()
    //     .keepAliveFor(30);

    // client.connectionMessage = connMess;

    try {
      print('MQTTClientWrapper::Mosquitto client connecting....');
      await client.connect();
    } on Exception catch (e) {
      print('MQTTClientWrapper::client exception - $e');
      client.disconnect();
    }
  }

  awsMQTT() {}

  Future<void> publish(String topic, String msg) async {
    if (client.connectionStatus!.state == MqttConnectionState.connected) {
      final builder1 = MqttClientPayloadBuilder();

      builder1.addString(msg);

      client.publishMessage(topic, MqttQos.atLeastOnce, builder1.payload!);
    } else {
      print(
          'MQTTClientWrapper::ERROR Mosquitto client connection failed - disconnecting, status is ${client.connectionStatus}');
      client.disconnect();
    }
  }

  void uninit() {
    client.disconnect();
  }
}

class _MyHomePageState extends State<MyHomePage> {
  int _hr = 0;
  int _sp2 = 0;
  int _sensorStatus = 0;
  int _confidence = 0;
  int _counter = 0;
  double _temp = 0;
  FlutterBlue flutterBlue = FlutterBlue.instance;
  late BluetoothDevice bleDevice;
  bool isFound = false;
  List<FlSpot> hrData = [];
  List<FlSpot> sp2Data = [];
  late Timer _timer;
  var rng = new Random();
  String _strBleStatus = 'N/A';
  String _strSensorStatus = 'N/A';
  int isInit = 0;
  AwsMQTT awsClient = new AwsMQTT();

  Future<int> publishStatus(String status) async {
    awsClient.publish(
        'babyAlert/string/sensorStatus', jsonEncode(HealthDataString(status)));

    return 0;
  }

  Future<int> publishTemp(double temp) async {
    awsClient.publish(
        'babyAlert/double/bodyTemp', jsonEncode(HealthData(temp.toDouble())));

    return 0;
  }

  Future<int> publishData(
      int hr, int spo2, int sensorStatus, int confidence) async {
    awsClient.publish(
        'babyAlert/int/hr', jsonEncode(HealthData(hr.toDouble())));

    awsClient.publish(
        'babyAlert/int/spo2', jsonEncode(HealthData(spo2.toDouble())));

    awsClient.publish('babyAlert/int/status',
        jsonEncode(HealthData(sensorStatus.toDouble())));

    awsClient.publish(
        'babyAlert/int/conf', jsonEncode(HealthData(confidence.toDouble())));

    return 0;
  }

  Future<void> connectDevice(BluetoothDevice dev) async {
    await dev.connect();
    print("connected");
    List<BluetoothService> services = await dev.discoverServices();
    services.forEach((service) {
      print('service=${service.uuid.toString()}');
      if (service.uuid.toString() == '12345678-1234-5678-1234-56789abcdef0') {
        print("found heart rate service");

        for (var char in service.characteristics) {
          print('char=${char.uuid.toString()}');
          if (char.uuid.toString() == '12345678-1234-5678-1234-56789abcdef1') {
            print("found characteristic");
            char.setNotifyValue(true).whenComplete(() {
              char.value.listen((event) {
                if (event.length == 8) {
                  print('heart rate = ${event[0]}');
                  print('spo2 = ${event[1]}');
                  print('status = ${event[2]}');
                  print('confidence = ${event[3]}');

                  ByteData fdata = new ByteData(4);

                  fdata.setUint8(0, event[7]);

                  fdata.setUint8(1, event[6]);
                  fdata.setUint8(2, event[5]);
                  fdata.setUint8(3, event[4]);

                  _temp = fdata.getFloat32(0);

                  print('temp = $_temp');

                  publishTemp(_temp);

                  setState(() {
                    _hr = event[0];
                    _sp2 = event[1];
                    _sensorStatus = event[2];
                    _confidence = event[3];

                    _strBleStatus = 'Connected';

                    switch (_sensorStatus) {
                      case 0:
                        _strSensorStatus = 'No Contact';
                        break;
                      case 1:
                        _strSensorStatus = 'Contact';
                        break;
                      case 2:
                      case 3:
                        _strSensorStatus = 'Stable';
                        break;
                    }

                    publishStatus(_strSensorStatus);

                    if (_sensorStatus == 3 &&
                        _hr > 40 &&
                        _hr < 180 &&
                        _sp2 > 80 &&
                        _sp2 <= 100) {
                      // valid data
                      _counter++;
                      var hrspot =
                          new FlSpot(_counter.toDouble(), _hr.toDouble());
                      hrData.add(hrspot);
                      var sp2spot =
                          new FlSpot(_counter.toDouble(), _sp2.toDouble());

                      sp2Data.add(sp2spot);

                      publishData(_hr, _sp2, _sensorStatus, _confidence);
                    }
                  });
                }
              });
            });
          }
        }
      }
      // do something with service
    });
  }

  @override
  initState() {
    super.initState();

    // _timer = new Timer.periodic(Duration(seconds: 1), (timer) {
    //   setState(() {
    //     _counter++;
    //     _hr = rng.nextDouble() * 50 + 50;
    //     var hr = new FlSpot(_counter.toDouble(), _hr);
    //     if (hrData.length > 20) {
    //       hrData.removeAt(0);
    //     }

    //     hrData.add(hr);

    //     _sp2 = rng.nextDouble() * 10 + 90;
    //     var sp2 = new FlSpot(_counter.toDouble(), _sp2);
    //     if (sp2Data.length > 20) {
    //       sp2Data.removeAt(0);
    //     }

    //     sp2Data.add(sp2);
    //   });
    // });
    //
    isFound = false;

    setState(() {
      _strBleStatus = 'Scanning';
    });

    flutterBlue.startScan(timeout: Duration(seconds: 5)).whenComplete(() => {
          if (isFound)
            awsClient.init().whenComplete(() => connectDevice(bleDevice))
        });

    flutterBlue.scanResults.listen((results) {
      // do something with scan results
      for (ScanResult r in results) {
        print('device=${r.device.id.id}');
        if (r.device.id.id == 'EC:E3:26:B6:EA:A0') {
          print("found device");
          setState(() {
            _strBleStatus = 'Found Device';
          });
          bleDevice = r.device;
          isFound = true;

          break;
        }
      }
    });
  }

  @override
  void dispose() {
    super.dispose();
    bleDevice.disconnect();
    awsClient.uninit();
    print("disposed1");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.only(
                  right: 18.0, left: 12.0, top: 24, bottom: 12),
              child: LineChartDisplay(hrInput: hrData, sp2Input: sp2Data),
            ),
            Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
              Column(
                children: [
                  Text(
                    'Heart Rate',
                    style: TextStyle(fontSize: 18),
                  ),
                  Text(
                    _hr.toStringAsFixed(0),
                    style: Theme.of(context).textTheme.headline2,
                  ),
                ],
              ),
              Column(
                children: [
                  Text(
                    'Oxygen',
                    style: TextStyle(fontSize: 18),
                  ),
                  Text(
                    _sp2.toStringAsFixed(0),
                    style: Theme.of(context).textTheme.headline2,
                  ),
                ],
              ),
              Column(
                children: [
                  Text(
                    'Body Temp',
                    style: TextStyle(fontSize: 18),
                  ),
                  Text(
                    _temp.toStringAsFixed(1),
                    style: Theme.of(context).textTheme.headline2,
                  ),
                ],
              )
            ]),
            Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
              Column(
                children: [
                  Text(
                    'Sensor Status:',
                    style: TextStyle(fontSize: 15),
                  ),
                  Text(
                    _strSensorStatus,
                    style: Theme.of(context).textTheme.headline4,
                  )
                ],
              ),
              Column(
                children: [
                  Text(
                    'BLE Status:',
                    style: TextStyle(fontSize: 15),
                  ),
                  Text(
                    _strBleStatus,
                    style: Theme.of(context).textTheme.headline4,
                  )
                ],
              )
            ])
          ],
        ),
      ),
    );
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<Timer>('_timer', _timer));
  }
}

nrf5340dk overlay file

ActionScript
&i2c1 {
	status = "okay";
	sda-gpios = <&gpio0 30 0>;
	scl-gpios = <&gpio0 31 0>;
    max32664@55{
        status = "okay";
        compatible = "max,max32664";
        reg = < 0x55 >;
        label = "MAX32664";
        rst-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
        mfio-gpios = <&gpio1 9 GPIO_PULL_UP>;
    };

    max30205@48{
        status = "okay";
        compatible = "max,max30205";
        reg = < 0x48 >;
        label = "MAX30205";
    };
};

&arduino_spi {
    status = "okay";
	apa102@0 {
		compatible = "apa,apa102";
		reg = <0>;
		spi-max-frequency = <5250000>;
		label = "APA102";
	};
};

Baby Guard Github Repo

Contains Zephy code, Flutter Code, Schematics

Credits

xkimi

xkimi

3 projects • 8 followers

Comments