InfiniTimeOrg / InfiniTime

Firmware for Pinetime smartwatch written in C++ and based on FreeRTOS
GNU General Public License v3.0
2.71k stars 926 forks source link

Streaming the data (real-time) from PineTime watch to PC/laptop with InfiniTime? #1364

Closed stevensu1838 closed 1 year ago

stevensu1838 commented 1 year ago

Verification

Pitch us your idea!

Streaming the data (real-time) from PineTime watch to PC/laptop with InfiniTime?

Description

Hi team

I am a researcher from an university, and we've been working on a project aiming to stream live data (such as heart rate data) from Pine Time watch to the PC/laptop. I've learned that the InfiniTime might be a good way to make our goal happen. May I please ask if streaming the data (real-time) from PineTime watch to PC/laptop is doable with InfiniTime? If so, I will give it a try. Cheers

minacode commented 1 year ago

I am a researcher from an university

Are you sure? Sorry, but come on... Every technical help around InfiniTime aside, but if that is what you are researching then you should be able to figure out how to plot two graphs in the same diagram. I am not going to do your job.

stevensu1838 commented 1 year ago

@minacode Hi I think you misunderstood me, I will keep exploring and come back to you. Don't get pissed off by stupid questions. I've learnt a lot from you, you've helped me a lot and I hope you will be happy. Anyway, Let me think about it and come back to you soon. Be happy

minacode commented 1 year ago

Don't get me wrong. I gladly helped you and don't believe in "stupid questions". It's no problem to be inexperienced with Linux and such. We all start somewhere.

How do I plot two data sets, one with regular intervals and the other one with the irregular interval, in the same plotting to compare?

But I don't want to plot or interpret your numbers for you. That is not a technical problem. And its not even difficult. You know that the PineTimes values are constant between the data points, so you can perfectly estimate them.

stevensu1838 commented 1 year ago

@minacode Hi Thanks a lot for your understanding. Please forgive me if I ask the following question wrong. I am plotting the PineTime data your helped me saved and I am plotting it in matlab. I find this example on plotting very similar data. Their data image Our PineTime data image

I can use the their code to plot their example data with no problem. image

However, when I switch to our data PineHeartOutput.csv, it throws the following errors:

image

I don't really understand our data is the same as the example data. The only difference is we don't have AM or PM in the end of timestamps. Sorry if you don't even use matlab. Just feel like you know everything. Thanks a lot for all your help

minacode commented 1 year ago

I am not familiar with Matlab, sorry. The error says that the 2 in y = d(:,2) is too big. I suspect the second column in d is missing. Maybe xlsread is wrong because you do not have an.xls but a .csv. You could try csvread instead, but I am just guessing.

BenjaminMickler commented 1 year ago

In case you are familiar with Python, here's a snippet from a project that I am working on that reads heart rate data from InfiniTime using a library called bleak (https://github.com/hbldh/bleak). It won't work if the watch is already connected to a device. This script will handle the connection. Of course you would want to remove all of the seizure monitor related stuff. Don't worry about the copyright or the licence, you're welcome to use the code however you like.

__author__ = "Benjamin Mickler"
__copyright__ = "Copyright 2022 Benjamin Mickler"
__credits__ = ["Benjamin Mickler"]
__license__ = "GPLv3 or later"
__version__ = "20221126"
__maintainer__ = "Benjamin Mickler"
__email__ = "ben@benmickler.com"

"""
This file is part of The Seizure AI Project.

The Seizure AI Project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.

The Seizure AI Project is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.

You should have received a copy of the GNU General Public License along with
The Seizure AI Project. If not, see <https://www.gnu.org/licenses/>.
"""

import asyncio
from bleak import BleakClient, BleakScanner
import requests
import json
import signal
import traceback

# MAC address: ff:1c:2a:bf:8a:3b

print("A small neural network to try to detect a seizure in 10 heart rate samples. All predictions are done on the server. Please use sparingly as the server only has 1GB of RAM and may not be able to make many predictions at once. It's only an experiment, don't rely on it to alert you to seizures. Copyright © Benjamin Mickler 2022\n")

threshold = input("Threshold (blank for 0.8): ")
if threshold == "":
    threshold = 0.8
else:
    threshold = float(threshold)

name = input("Heart rate monitor name (blank to use InfiniTime): ")
if name == "":
    name = "InfiniTime"
def get_mac_address(name):
    print(f"Searching for {name}")
    from bleak import discover
    devices = asyncio.run(BleakScanner.discover())
    for d in devices:
        if d.name == name:
            return d.address
    return None

readings = []

_models_response = requests.get("https://seizure.ai.benmickler.com/models")
_models = json.loads(_models_response.json())
models = {}

for i, model in enumerate(_models, start=1):
    models[i] = model

service_uuid = "0000180d-0000-1000-8000-00805f9b34fb"
char_uuid = "00002a37-0000-1000-8000-00805f9b34fb"

async def run(address, loop):
    disconnected_event = asyncio.Event()
    def disconnected_callback(client):
        print("Device disconnected")
        disconnected_event.set()
    client = BleakClient(address, loop=loop, disconnected_callback=disconnected_callback)
    try:
        await client.connect()
        print(f"Connected: {client.is_connected}")
        await client.start_notify(char_uuid, callback)
        await disconnected_event.wait()
    except Exception as e:
        #print(traceback.format_exc())
        pass
    finally:
        if client.is_connected:
            print("\nDisconnecting")
            await client.stop_notify(char_uuid)
        await client.disconnect()

def callback(sender, data):
    print("Received: {0}".format(data[-1]))
    readings.append(data[-1])
    if len(readings) >= 10:
        print()
        r = requests.post("https://seizure.ai.benmickler.com/predict", json={"model_name": model, "heart_rate": readings})
        request_json = json.loads(r.json())
        if "error" in request_json:
            print(f"Error: {request_json['error']}")
        else:
            print(f"Result: {request_json['result']}")
            print(f"Seizure: {'yes' if float(request_json['result']) >= threshold else 'no'}")
        readings.pop(0)

if __name__ == "__main__":
    print("Models:")
    for k, v in models.items():
        print(f"{k}: {v}")
    model_input = int(input("Model: "))
    if model_input not in models:
        print("Invalid model")
        exit(1)
    model = models[model_input]
    loop = asyncio.new_event_loop()
    address = get_mac_address(name)
    if address is None:
        print(f"Could not find device with name {name}")
        address = input("Please enter MAC address: ")
    asyncio.run(run(address, loop))
JF002 commented 1 year ago

Let's continue this post in Discussions :-)